Forum Rule: Always post complete source code & details to reproduce any issue!
Page 2 of 2 FirstFirst 1 2
Results 26 to 40 of 40

Thread: Teensy 4.1 + ADS1256

  1. #26
    With the program above, I tested an input sine wave with frequency = 60 Hz, amplitude = 0.2 Vpp, and offset = 0 V. The data from the ADS1256 looks good. At 30 kSPS, the period of the sine wave is 500 samples, max = 0.1, min = -0.1

    The total time for 30000 samples is 0.999825 us, very similar to what you measured with the mbilsky sketch.

    One important note. In READ_ADC(), you had delayMicroseconds(6) between sending the RDATA command and reading the 3-byte value. The delay must be >= 5 us to get good data. With a delay < 5 us, the data is garbage.

    The main reason you could not reach 30 kSPS was the unnecessary SYNC and WAKEUP commands and the large delays after those commands in READ_ADC(). Because CS was HIGH until after those commands were sent, the ADS1256 was ignoring them, so I commented them out.

    I have not looked at the mbilsky sketch to see why it wasn't working. I think one problem was that it sets the PGA to a high gain (64), and that was probably causing the A/D converter to saturate.
    Last edited by joepasquariello; 05-02-2022 at 07:22 PM.

  2. #27
    Member
    Join Date
    Nov 2020
    Location
    Czech Republic
    Posts
    88
    Seems OK, but what do you mean about signal 12kHz and FFT 14kHz?

    Sine 50Hz 0.1V
    Click image for larger version. 

Name:	sine50Hz-0.1V.jpg 
Views:	9 
Size:	138.0 KB 
ID:	28253

    Sine 12000Hz 0.1V
    Click image for larger version. 

Name:	sine12000Hz-0.1V zoom.jpg 
Views:	5 
Size:	149.9 KB 
ID:	28254

    FFT 14000Hz
    Click image for larger version. 

Name:	FFT14000Hz.jpg 
Views:	7 
Size:	49.3 KB 
ID:	28255

  3. #28
    With 30-kHz sampling of a 12-kHz sine wave, your raw data won't look like a sine wave (only 2.5 samples per period), but theoretically the FFT is okay up to sample freq / 2 = 15 kHz.

    Here is another update, with a lot more cleanup. For example

    - more constants and less magic numbers in code
    - move code from SAMPLE_ADC() to loop()
    - in READ_ADC() simplify conversion from raw data to volts and return value
    - in START_SPI(), after SELFCAL command, wait for DRDY low, then DRDY high, per datasheet
    - in waitDRDY(), remove disable/enable interrupts (not necessary)

    Code:
    #include <SPI.h>
    
    // PIN assignements
    #define CS_PIN    21
    #define DRDY_PIN  22 
    #define RST_PIN   8 
    
    // SPI
    #define SPISPEED 1950000               
    
    // ADS1256 registers
    #define STATUS_REG   0x00
    #define MUX_REG      0x01
    #define ADCON_REG    0x02
    #define DRATE_REG    0x03
    
    // ADS1256 commands
    #define WAKEUP_CMD   0x00  // completes SYNC and exits standby mode
    #define RDATA_CMD    0x01  // read data
    #define RREG_CMD     0x10  // read register (register ID in low nibble)
    #define WREG_CMD     0x50  // write register (register ID in low nibble)
    #define SELFCAL_CMD  0xF0  // offset and gain self-calibration
    #define SYNC_CMD     0xFC  // synchronize the A/D conversion
    #define STANDBY_CMD  0xFD  // begin standby mode
    #define RESET_CMD    0xFE  // reset to power-up values
    
    #define VREF            (2.5)   // for conversion of raw ADC data to Volts
    #define BUFFER_SIZE     (30000) // samples
    
    #define DRATE_15K       (0xE0)  // 15 kSPS
    #define DRATE_30K       (0xF0)  // 30 kSPS
    
    #define STATUS_REG_0x01 (0x01)  // MSB first, Auto-Cal Dsbl, Input Buffer Dsbl
    #define STATUS_REG_0x03 (0x03)  // MSB first, Auto-Cal Dsbl, Input Buffer Enbl
    #define STATUS_REG_0x07 (0x07)  // MSB first, Auto-Cal Enbl, Input Buffer Enbl
    #define ADCON_REG_VALUE (0x21)  // 0 01 00 001 => Clock Out Freq = fCLKIN, 
                                    //             Sensor Detect OFF, gain 2 7.68MHz  
    #define DRATE_REG_VALUE (BUFFER_SIZE==15000 ? DRATE_15K : DRATE_30K)  
    #define MUX_REG_VALUE   (B00001000) // AINCOM
    
    volatile int DRDY_state = HIGH;
    
    float adc_volt[BUFFER_SIZE];
    float adc_g[BUFFER_SIZE];
    
    void writeRegister(uint8_t address, uint8_t value)
    {
      SPI.transfer( WREG_CMD | address ); 
      SPI.transfer( 0x00 ); 
      SPI.transfer( value );
      delayMicroseconds( 100 );
    }
    
    void setup()
    { 
      Serial.begin( 9600 ); // USB data rate is always max
      while (!Serial) {} // wait for USB serial ready
      Serial.println( "ADS1256 test program" );
      START_SPI();
      attachInterrupt( DRDY_PIN, DRDY_Interrupt, FALLING );
    }
    
    void loop()
    {
      uint32_t t0 = micros();  
      for (int i=0; i < BUFFER_SIZE; i++) {    
        waitDRDY();
        adc_volt[i] = READ_ADC(); 
      }
      Serial.printf( "Read %1d samples in %1lu us\n", BUFFER_SIZE, micros()-t0 );
    
      if (Serial.available() > 0) {
        char inChar = Serial.read();
        for (int i=0; i<BUFFER_SIZE; i++) {
          #if (1)
          Serial.printf( "%5d  %8.3f\n", i, adc_volt[i] );
          #else
          byte *b = (byte *)&adc_volt[i];
          Serial.write(b[0]);
          Serial.write(b[1]);
          Serial.write(b[2]);
          Serial.write(b[3]);
          #endif
        }
      }
    }
    
    float READ_ADC()
    {
      int32_t adc_raw;   
      SPI.beginTransaction(SPISettings(SPISPEED, MSBFIRST, SPI_MODE1));                             
      digitalWriteFast(CS_PIN, LOW);    
       
      SPI.transfer( RDATA_CMD ); 
      delayMicroseconds(5); // delay MUST be >= 5 us      
      adc_raw = 0;    
      adc_raw |= SPI.transfer(0); 
      adc_raw <<= 8;                 
      adc_raw |= SPI.transfer(0); 
      adc_raw <<= 8;                
      adc_raw |= SPI.transfer(0);    
       
      digitalWriteFast(CS_PIN, HIGH);     
      SPI.endTransaction();  
    
      if (adc_raw & (1<<23)) {    // if 24-bit MSB == 1
        adc_raw |= 0xFF000000;    //   value is negative, sign-extend to 32 bits
      }
      float v = adc_raw * (float)(VREF / (1<<23));
      return( v );
    }  
    
    // DRDY falling-edge interrupt function
    void DRDY_Interrupt()
    {
      DRDY_state = LOW;
    }
     
    void waitDRDY() 
    {
      // wait for DRDY_state to be LOW
      while (DRDY_state == HIGH) {
        continue;
      }
      // then set it back to HIGH
      DRDY_state = HIGH;
    }
    
    void START_SPI ()
    {
      // configure I/O pins
      pinMode(CS_PIN, OUTPUT);
      digitalWrite(CS_PIN, HIGH); // init CS high (disable)
      pinMode(DRDY_PIN, INPUT);
      pinMode(RST_PIN, OUTPUT);
      
      // hardware reset ADS1256 by toggling pin LOW then HIGH
      digitalWrite(RST_PIN, LOW);
      delay(1); 
      digitalWrite(RST_PIN, HIGH); 
      delay(500);
      
      // start the spi-bus
      SPI.begin(); 
      delay(500);
      
      // wait for DRDY signal LOW
      while (digitalRead(DRDY_PIN)) {}
       
      SPI.beginTransaction(SPISettings(SPISPEED, MSBFIRST, SPI_MODE1)); 
      digitalWriteFast(CS_PIN, LOW);
      delayMicroseconds(100);   
    
      // reset to power-up state
      SPI.transfer( RESET_CMD );
      delay(5);
    
      // configure registers
      writeRegister( STATUS_REG, STATUS_REG_0x03 );
      writeRegister( ADCON_REG, ADCON_REG_VALUE );
      writeRegister( DRATE_REG, DRATE_REG_VALUE );
      writeRegister( MUX_REG, MUX_REG_VALUE ); 
    
      // auto-calibrate (send command, wait DRDY = LOW, then wait DRDY = HIGH)
      SPI.transfer( SELFCAL_CMD );
      uint32_t t0 = micros();
      while (digitalReadFast(DRDY_PIN)!=LOW && micros()-t0 < 10000) {}
      while (digitalReadFast(DRDY_PIN)!=HIGH && micros()-t0 < 10000) {}
      
      digitalWriteFast(CS_PIN, HIGH);
      SPI.endTransaction(); 
    }

  4. #29
    Seems OK, but what do you mean about signal 12kHz and FFT 14kHz?
    On T4.1, I get total time of 999825 us for 30000 samples. That means sample rate = 30000/0.999825 = 30005.25

    When you do your FFT, instead of specifying your sample rate as 30000 Hz, specify it as 30005.25 or whatever you compute. By specifying the true sample rate, I think the FFT will report the peak at 14000, which seems to be what you want.

  5. #30
    Member
    Join Date
    Nov 2020
    Location
    Czech Republic
    Posts
    88
    Great. I wil test it more.

    Just one question - any idea why is there peak at 0Hz? It is there for all frequencies.

    For 12kHz:

    Click image for larger version. 

Name:	noise1.jpg 
Views:	2 
Size:	70.4 KB 
ID:	28269


    Zoomed:

    Click image for larger version. 

Name:	noise2.jpg 
Views:	2 
Size:	28.6 KB 
ID:	28270

  6. #31
    Can you show the time series chart? The 0th element of the FFT is simply the mean value. If you have your function generator set up to produce a sine wave with 0 offset, the mean of your signal should be 0. If your mean is not 0, you can either ignore it, or start plotting from element 1 (instead of 0), or make sure the mean of your signal is 0 by subtracting the mean from all values in the time domain. That means:

    1) collect data
    2) compute mean
    3) subtract mean from each data value
    4) compute the FFT on the modified values

    The FFT should look exactly the same except that value at 0 Hz will be 0.

  7. #32
    Member
    Join Date
    Nov 2020
    Location
    Czech Republic
    Posts
    88
    Here is time wave for 12kHz:

    Click image for larger version. 

Name:	time1.jpg 
Views:	2 
Size:	46.5 KB 
ID:	28273

    Zoomed:

    Click image for larger version. 

Name:	time1-zoom.jpg 
Views:	1 
Size:	146.3 KB 
ID:	28274


    If I understand well, I have to calculate average value of all samples and then deduct this average from every sample, right?

  8. #33
    Yes, that's correct.

    Can you please show a time series chart and FFT chart for a lower frequency, such as 50 or 100 Hz? I think you have a bias in the time series of the higher frequencies because the sample rate is not very high compared to the frequency of the sine wave.

  9. #34
    Member
    Join Date
    Nov 2020
    Location
    Czech Republic
    Posts
    88
    50Hz time:

    Click image for larger version. 

Name:	Time-50Hz.jpg 
Views:	2 
Size:	143.7 KB 
ID:	28275


    FFT 50Hz:

    Click image for larger version. 

Name:	FFT-50Hz.jpg 
Views:	2 
Size:	28.2 KB 
ID:	28276


    FFT 50Hz zoomed:

    Click image for larger version. 

Name:	FFT-50Hz-zoom.jpg 
Views:	3 
Size:	46.7 KB 
ID:	28277

  10. #35
    Okay, good. Your 0 value is closer to 0 for the lower frequency sine wave because your time series offset is close to 0. You will ALWAYS have a non-zero value at 0 Hz if you have ANY offset, and there is almost always some offset. If you want the FFT value at 0 Hz to be exactly 0, you will have to subtract the mean from all values. You can also just ignore it!

  11. #36
    Member
    Join Date
    Nov 2020
    Location
    Czech Republic
    Posts
    88
    Removed mean - FFT seem ok:

    Click image for larger version. 

Name:	removed-mean.jpg 
Views:	2 
Size:	38.1 KB 
ID:	28278

    About frequency shift:
    "On T4.1, I get total time of 999825 us for 30000 samples. That means sample rate = 30000/0.999825 = 30005.25"

    Where I have to change sample rate to 30005.25?

    My FFT Python:
    Code:
            yf = scipy.fftpack.fft(self.ydata5)
            xf = np.linspace(0.0, 1.0/(2.0*T), SPS//2)
            self.canvas.axes.cla()
            self.canvas.axes.set_ylabel("Amplitude in g")
            self.canvas.axes.set_xlabel("Frequency in Hz")
            self.canvas.axes.plot(xf, 1.0/SPS * np.abs(yf[:SPS//2]), 'b')
    Because there is FFT from self.ydata5 = array from Teensy.
    SPS = 30000
    T = 1.0 / SPS

    Anyway, thanks a lot for help.

  12. #37
    You're welcome. "SPS" is probably 30000, and this value must already be part of "ydata5". When the FFT is computed, you need to tell it the actual samples per second, which is 30005.25. Pseudo-code would look something like this:

    SPS = 30000
    ActualSPS = 30005.25
    ydata.SPS = ActualSPS (so it uses 30005.25)
    FFT(ydata5)
    plot(SPS) (so it uses 30000)

    Remember that 30005.25 is based on MY measurement of 999825 us, and 30000/0.999825 = 30005.25

    You should compute the value based on your own measurement.

  13. #38
    Member
    Join Date
    Nov 2020
    Location
    Czech Republic
    Posts
    88
    But ActualSPS (30005) I need from Teensy, right? And tehre I have buffer 30000. I can not use 30005 in Python because I receive only 30k samples. Or I can add to array in Python 5 items with zero value...

  14. #39
    When you run the sketch, it tell you the time for 30000 samples. Yes, you have 30000 samples, but these are read in slightly less than 1 second, so your SPS (samples PER SECOND) is not 30000

    SPS = 30000 samples / 0.999825 seconds = 30005.25 samples/second

    Your FFT needs to know (a) how many samples, and (b) total time (seconds) or frequency (Hz) or time for one sample (seconds). Look for references to ydata5 before the call to fft()

  15. #40
    Member
    Join Date
    Nov 2020
    Location
    Czech Republic
    Posts
    88
    Hi,
    I am testing it with my app in Python.
    But I can see lot of noise:

    Click image for larger version. 

Name:	DATA ADXL NOISE.jpg 
Views:	2 
Size:	95.1 KB 
ID:	28458

    If I have connected signal generator, I have no problem with noise and no problem witth all range of frequencies from 0-15000Hz:

    Click image for larger version. 

Name:	generator-off-noise.jpg 
Views:	3 
Size:	92.3 KB 
ID:	28459

    If I connect ADXL1005 eval board I measure quite OK values from lower frequencies (a bit noisy but OK)

    Click image for larger version. 

Name:	motor34Hz-OK with another analyzer.jpg 
Views:	0 
Size:	122.1 KB 
ID:	28460

    But for example if I start motor for 78Hz, I can see nonsenses - values are two times lower than on profi analyzer.

    Click image for larger version. 

Name:	motor-78Hz-PROBLEM.jpg 
Views:	0 
Size:	113.1 KB 
ID:	28461

    Question is - is possible to lower noise?
    Can it be there problem with "anti-aliasing"?

    Thanks for any advice!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •