This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

ADS1299: Interfacing ADS1299 with Arduino Due(UDOO Board) Sampling Frequency Problem

Part Number: ADS1299
Other Parts Discussed in Thread: ADS1298, ADS1294, ADS1296

We are currently working with the ADS1299 and using the SPI interface to communicate with an Arduino Due. Apart from CONFIG1 register, in which 0x94h is written (corresponding to 1K SPS) every register is set at the default value. The device is set to RDATAC mode and bytes are received when DRDY becomes low and CS is set to high. However we are able to receive only about 166 samples per second per channel even though the lowest sampling rate possible is 250 SPS.
This is the part of the code that is receiving the samples from the SPI interface, which is continuously called in the void loop method.
int sendOsc(void)
{
  if ((!isRDATAC) || (gNumActiveChan < 1) )  return (10); //device should be in RDATAC mode
  if (digitalRead(IPIN_DRDY) == HIGH) return (20);
  digitalWrite(IPIN_CS, LOW);
  delayMicroseconds(1);
  int numSerialBytes = 1 + (3 * gNumActiveChan);
  WiredSerial.println(numSerialBytes); //8-bits header plus 24-bits per ACTIVE channel
  unsigned char serialBytes[numSerialBytes];
  int i = 0;
  int Vref = 4.5;
  long val;
  serialBytes[i++] = SPI.transfer(0);
  SPI.transfer(0); //skip 2nd byte of header
  SPI.transfer(0); //skip 3rd byte of header
 
 
  for (int ch = 1; ch <= gNumActiveChan; ch++)
  {
 
    if (gActiveChan[ch])
    {      
     
      serialBytes[i++] = SPI.transfer(0);  //read 3 bytes per channel
    
      serialBytes[i++] = SPI.transfer(0);
 
      serialBytes[i++] = SPI.transfer(0);
     
      int k = i - 2;
      if (serialBytes[k] & 0x80)
        val = ((0xFF << 24) | ((serialBytes[k] & 0xFF) << 16) | ((serialBytes[k + 1] & 0xFF) << 8) | ((serialBytes[k + 2] & 0xFF) << 0));
      else
        val = ((0x00 << 24) | ((serialBytes[k] & 0xFF) << 16) | ((serialBytes[k + 1] & 0xFF) << 8) | ((serialBytes[k + 2] & 0xFF) << 0));
 
         double voltage = val * (Vref / (pow(2, 23) - 1) / 12 * 1000000); //convert to micro volts
            WiredSerial.print(voltage);
             WiredSerial.print(" ");
    }
 
           
  }
  WiredSerial.println();
  delayMicroseconds(1);
  digitalWrite(IPIN_CS, HIGH);
  return (50);
}
 
 
 
 
The setup code is as follows –
 
void adsSetup()
{
 // using namespace ADS1298;
  adc_wreg(GPIO, 0);
  adc_wreg(CONFIG3, PD_REFBUF | CONFIG3_const);
  //FOR RLD: Power up the internal reference and wait for it to settle
  // adc_wreg(CONFIG3, RLDREF_INT | PD_RLD | PD_REFBUF | VREF_4V | CONFIG3_const);
  // delay(150);
  adc_wreg(CONFIG1, 0x94h);
delay(150);
  for (int i = 1; i <= 8; ++i)
  {
    adc_wreg(CHnSET + i, ELECTRODE_INPUT | GAIN_12X); //report this channel with x12 gain
  }
  digitalWrite(PIN_START, HIGH);
}
 
void setup()
{
  pinMode(IPIN_CS, OUTPUT);
  pinMode(PIN_START, OUTPUT);
  pinMode(IPIN_DRDY, INPUT);
  SPI.begin();
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(SPI_MODE1);
  delay(1000); //wait for the ads129n to be ready - it can take a while to charge caps
  adc_send_command(RESET);
  delay(10);  //need to wait 18 tclk minimum
  adc_send_command(SDATAC);
  delay(10);
  // Determine model number and number of channels available
  IDval = adc_rreg(ID) ;
  switch (IDval & B00011111 )
  { //least significant bits reports channels
    case  B10000: //16
      gMaxChan = 4; //ads1294
      break;
    case B10001: //17
      gMaxChan = 6; //ads1296
      break;
    case B10010: //18
      gMaxChan = 8; //ads1298
      break;
    case B11110: //30
      gMaxChan = 8; //ads1299
      break;
    default:
      gMaxChan = 0;
  }
  WiredSerial.begin(BAUD_RATE);
  while (WiredSerial.read() >= 0)
  delay(200);  // Catch Due reset problem
  if (gMaxChan == 0)
  {
    pinMode(kPIN_LED, OUTPUT);
    while (1)
    { //loop forever
      digitalWrite(kPIN_LED, HIGH);   // turn the LED on
      delay(500);              
      digitalWrite(kPIN_LED, LOW);    // turn the LED off
      delay(500);
    }
  } //error mode
  adsSetup();
  gNumActiveChan = detectActiveChannels();
  adc_send_command(RDATAC);
  delay(10);
  isRDATAC = true;
}
 
Please refer to the attached file below. The code contains how we are reading and writing to the registers.
 

 
  • Hello Vaibhav,

    Thanks for your post and welcome to our forum!

    It would be much easier to debug the problem if we could look at a scope capture or logic analyzer output showing your SPI signals (DIN, DOUT, SCLK, /CS) as well as the /DRDY interrupt. After you configure the data rate to 1 kSPS, do you see consistent /DRDY interrupts without reading data?


    Best Regards,
  • Hi Ryan,

    Thanks for your reply. We tried checking using a DSO and found DRDY was toggling with respect to DOUT when data is getting transmitted while we applied a test signal through the software. However, when we upload the above code, we found that during the transmission of the channel bytes through SPI, DRDY was toggling in between and doesn't seem synchronized, i.e it isn't latched to high during transmission and low otherwise. Also the header bytes do not recur properly after every 24 bytes. Is there a problem with the SCLK synchronizing with the internal clock? What are the necessary register configurations that need to be made to get the required number of samples through RDATAC mode?

  • Hello Vaibhav,

    You cannot allow for /DRDY to transition high-to-low while you are reading data in RDATAC mode. The data in the output shift register will immediately be overwritten with new data. Remember that /DRDY is not latched - after the /DRDY falling edge, the first SCLK falling edge will force /DRDY to clear and return high.

    SCLK and CLK do not need to be synchronous. In fact, the SPI interface in the ADS1299 is an asynchronous interface. The intention is for you to monitor the status of the /DRDY pin with a GPIO. When /DRDY goes low, the MCU should enter an interrupt service routine (ISR) to collect the data. This involves bringing the /CS pin low, toggling SCLK until all data is received, and bringing /CS high again. The ISR must be completed before the next conversion is ready (i.e. before the next /DRDY falling edge). The period between consecutive /DRDY falling edges will be equal to the configured data rate.

    If you cannot read the data fast enough, you must either reduce the data rate or increase the SCLK frequency. Alternatively, RDATA mode allows you to read the most recent conversion result on demand by sending the RDATA SPI opcode whenever you wish to read data.

    Best Regards,