0

I am using Arduino UNO to Read 8-channel, 24-bits resolution Analog signals using ADS1299 Analog-fornt-end. ADS1299 use SPI interface to talk with Arduino. Currently, I can record the analog signal with arduino based on the SPI protocol and send the data via serial port to the PC.

The ADS1299 has 8 channels with 24-bits resolutions. The sampling rate can be defined from 250s/s to 16Ks/s. As you can see in the below code, when the data is ready I put the device in reading data mode and store 8-bits (1-byte) in each run and concatenate 3 bytes to make a full sample. I repeat these procedures to obtain the whole samples of all channels. At the end I have sent a sample of one channel to the serial port using serial.print command.

Here is my problem: If I want to increase the sampling rate of device to e.g 10 Ks/s the arduino fails to provide this sampling rate due to delay produced by Serial.println command. Is is possible to store the data into a big array and then send the whole array via serial port? Is it possible that other types of microcontroller such as ARM types handle this issue? Generally how it is possible to avoid the delay of serial print?

    #include <SPI.h>
    #define WAKEUP 0x02
    #define STANDBY 0x04
    #define RESET 0x06
    #define START 0x08
    #define STOP 0x0a
    #define RDATAC 0x10
    #define SDATAC 0x11
    #define RDATA 0x12
    #define TESTaa 0xaa
    #define TEST55 0x55

    #define CONFIG1 0x01
    #define CONFIG2 0x02
    #define CONFIG3 0x03
    #define CH1SET 0x05
    #define CH2SET 0x06
    #define CH3SET 0x07
    #define CH4SET 0x08
    #define CH5SET 0x09
    #define CH6SET 0x0A
    #define CH7SET 0x0B
    #define CH8SET 0x0C




      const int PIN_START = 7;
      const int IPIN_DRDY = 9;
      const int PIN_CS = 10; 

      const int DOUT = 12;
      const int DIN = 11;
      const int PIN_SCLK = 13;  
      const int PIN_RESET = 8;


      byte chSet;
      byte chSet2;
      boolean flag = false;
      long t0, t;


    void setup(){


      // You can use serial communication for debugging
      Serial.begin(2000000);
      Serial.flush();
      delayMicroseconds(100);
      // You have to set SPI communication according to datasheet  
      SPI.setDataMode(SPI_MODE1);
      //SPI.setClockDivider(SPI_CLOCK_DIV16);
      SPI.setBitOrder(MSBFIRST);
      SPI.begin();

      pinMode(DOUT, OUTPUT);
      pinMode(PIN_SCLK, OUTPUT);
      pinMode(PIN_CS, OUTPUT);
      pinMode(PIN_START, OUTPUT);
      pinMode(IPIN_DRDY, INPUT);
      pinMode(PIN_RESET, OUTPUT);

      //reset communication, see datasheet
        digitalWrite(PIN_SCLK, LOW);
        digitalWrite(DIN, LOW);
        digitalWrite(PIN_CS, HIGH);


      digitalWrite(PIN_CS, LOW); //Low to communicated
      SPI.transfer(RESET); 
      digitalWrite(PIN_CS, HIGH); //Low to communicated


      // Wait longer for TI chip to start
      delay(500);
      send_command(SDATAC);
      delay(10);
      chSet = read_byte(0x00);
      Serial.println("-- ID CHIP is:" + hex_to_char(chSet) );


      // Write Config 1 and 2: see datasheet page 47
      // Config 1: Bits 7 6 5 4 3 2 1 0 --- 1 DAISY_EN=1 CLK_EN=0 1 0 DR[2:0] (110-- 250 Sample/S)  --->   0b11010110    
      // Config 2: Bits 7 6 5 4 3 2 1 0 ----  1 1 0 INT_CAL=1(Int/Ext test sig) 0 CAL_AMP=(calibration signal amplitude)
      // CAL_FREQ[1:0] (calibration signal frequency)  ----->  0b11010100


      // for normal operation write to config1 0x02, config2 0xA0. For test signal write 0xA3 to config2
      write_byte(CONFIG1, 0x96);   // Daisy chain Enabled: D6 , Daisy chain Disabled: 96 
      delay(10);

      write_byte(CONFIG2, 0xD1);   // Test signal Enabled: D0   Test signal  Disabpled: C0  
      delay(10);

      write_byte(CONFIG3, 0xE0);   // INT Reference Enabled: E0    else  INT Reference Disabled: 60

      delay(1000);
      //this part is just to check if you send and read correct data
      Serial.println("Check Configs");
      chSet = read_byte(CONFIG1);
      Serial.println("CONFIG1: Received " + hex_to_char(chSet) );
      chSet = read_byte(CONFIG2);
      Serial.println("CONFIG2: Received "  + hex_to_char(chSet) );
      chSet = read_byte(CONFIG3);
      Serial.println("CONFIG3: Received "  + hex_to_char(chSet) );

      //remember that ch1 is used for respiration! use channel 2 for ECG measurements

       // Ch1 Setting: Bits 7 6 5 4 3 2 1 0 ---  PDn(channel power mode) GAINn[2:0] (PGA gain-- 101:  12 110 : 24)
       //SRB2 (SRB2 connection) MUXn[2:0] (channel input selection: 000 : Normal electrode input , 101 : Test signal )

       /// Input Channel Shorted  ---> 0b00000001 0X01;   Test signal Activated ---> 0b00000101 0X05; 
      delay(1000);

      write_byte(CH1SET, 0x05); //
      write_byte(CH2SET, 0x05); //
      write_byte(CH3SET, 0x05); //
      write_byte(CH4SET, 0x05); //
      write_byte(CH5SET, 0x05); //
      write_byte(CH6SET, 0x05); //
      write_byte(CH7SET, 0x05); //
      write_byte(CH8SET, 0x05); //


      Serial.println("Check Channel Settings");
      chSet = read_byte(CH1SET);
      Serial.println("Ch1: Received " + hex_to_char(chSet) );
      chSet = read_byte(CH2SET);
      Serial.println("Ch2: Received  " +   hex_to_char(chSet) );
      chSet = read_byte(CH7SET);
      Serial.println("Ch7: Received  " +   hex_to_char(chSet) );
      chSet = read_byte(CH8SET);
      Serial.println("Ch8: Received  " +   hex_to_char(chSet) );

      // Start communication, you can use RDATAC or RDATA according to datasheet
      send_command(RDATAC);
      digitalWrite(PIN_START, LOW);
      delay(150);
      send_command(START);  
    //  digitalWrite(PIN_CS, LOW); //Low to communicated
    //  SPI.transfer(START); 
    //  digitalWrite(PIN_CS, HIGH); //Low to communicated

    }

    boolean gActiveChan [2];
    int nChannels = 1;
    int gMaxChan=1;



    void loop(){

    // Based on the Page. 36 For the 8-channel ADS1299, the number of data outputs is
    //[(24 status bits + 24 bits × 8 channels) = 216 bits].

      delayMicroseconds(10); 

         if(digitalRead(IPIN_DRDY) == LOW){
          t0 = micros();

            digitalWrite(PIN_CS, LOW);

            long output[9];
            long dataPacket;
            for(int i = 0; i<9; i++){
                for(int j = 0; j<3; j++){
                    byte dataByte = SPI.transfer(0x00);
                    dataPacket = (dataPacket<<8) | dataByte;
                }

                output[i] = dataPacket;
                dataPacket = 0;
            }

            digitalWrite(PIN_CS, HIGH);
            Serial.println(output[1]);

    // t = micros()-t0;  // calculate elapsed time
   // Serial.print(1000000/float(t));
    //Serial.println(" samples per second");
    //delay(200);


     }

            }


        String hex_to_char(int hex_in) {
      int precision = 2;
      char tmp[16];
      char format[128];
      sprintf(format, "0x%%.%dX", precision);
      sprintf(tmp, format, hex_in);
      //Serial.print(tmp);
      return(String(tmp));
    }

    // see datasheet 38
    int read_byte(int reg_addr){
      int out = 0;
      digitalWrite(PIN_CS, LOW);
      SPI.transfer(0x20 | reg_addr);
      delayMicroseconds(5);
      SPI.transfer(0x00);
      delayMicroseconds(5);
      out = SPI.transfer(0x00);
      delayMicroseconds(1);
      digitalWrite(PIN_CS, HIGH);


      return(out);
    }

    void send_command(uint8_t cmd) {
      digitalWrite(PIN_CS, LOW);
      delayMicroseconds(5); 
      SPI.transfer(cmd);
      delayMicroseconds(10);
      digitalWrite(PIN_CS, HIGH);
    }

    //see page 38
    void write_byte(int reg_addr, int val_hex) {
      digitalWrite(PIN_CS, LOW);
      delayMicroseconds(5);
      SPI.transfer(0x40 | reg_addr);
      delayMicroseconds(5);
      SPI.transfer(0x00);
      delayMicroseconds(5);
      SPI.transfer(val_hex);
      delayMicroseconds(10);
      digitalWrite(PIN_CS, HIGH);

    }
5
  • Yes (though limited by the small SRAM), yes (the ones faster than the Uno) and have you tried using higher baudrates? What baudrate are you actually using? And maybe dont print, but write them to Serial
    – chrisl
    Aug 6, 2019 at 10:25
  • Please provide the full code. And why are you printing only the second element of output?
    – chrisl
    Aug 6, 2019 at 10:27
  • @chris: could you help me how can I store the output[1] in the loop and serial print the big array after a specified time. in this code I am just printing one channel, but I can print the whole channel separated by a comma and then retrieve them in the host PC.
    – Abed
    Aug 6, 2019 at 10:58
  • @chris I tried to send the whole code but the text does not seem great. Is it possible to upload the code separately?
    – Abed
    Aug 6, 2019 at 11:00
  • @chrisl I figure out and add the whole code. I checked with different baudrate but I could not see any obvious effect on the sampling rate
    – Abed
    Aug 6, 2019 at 11:16

1 Answer 1

0

Try changing the order of these:

  SPI.setDataMode(SPI_MODE1);
  //SPI.setClockDivider(SPI_CLOCK_DIV16);
  SPI.setBitOrder(MSBFIRST);
  SPI.begin();

I think SPI.begin() needs to be started before the other two calls.

Instead of digitalWrite to control the chip select, use Direct Port Manipulation, much faster.

Does the ADC support 8 MHz SPI clock? From 7.6 & 7.7 of the datasheet, I would say yes. You can get rid of all the delayMicroseconds(5), (1), (10), as well, they are not doing anything for you.

"Unpack" this and just do 3 SPI.transfers in a row to read the data, doing it in a loop slows it down:

        for(int i = 0; i<9; i++){
            for(int j = 0; j<3; j++){
                byte dataByte = SPI.transfer(0x00);
                dataPacket = (dataPacket<<8) | dataByte;
            }

I would go so far as to do all 27 in a row even, then do the array manipulation/data combining when all 27 bytes are captured.

3
  • Thank you, How can I put the the whole 27 bytes in an array?
    – Abed
    Aug 6, 2019 at 14:06
  • dataByte[0] = SPI.transfer(0x00); dataByte[1] = SPI.transfer(0x00); dataByte[2] = SPI.transfer(0x00); ... dataByte[25] = SPI.transfer(0x00); dataByte[26] = SPI.transfer(0x00);
    – CrossRoads
    Aug 6, 2019 at 14:46
  • Thank you for your assistance. I managed to store bunch of bytes (e.g 270 bytes) at the reading part and send the big size array in the next part. But, the problem is that during sending the big array, I lose new incoming data. Is there any way to define an interrupt and do multi-task (Sending and receiving)?
    – Abed
    Aug 7, 2019 at 7:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.