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: Getting no output when using test signal

Part Number: ADS1299
Other Parts Discussed in Thread: ADS1292

Hello,

I am currently using an ADS1299 to develop an EEG device for a University project. I have designed the acquisition circuit that I attach following the schematic of the ADS1299 kit and the advices given by the datasheet. I am communicating with a computer by means of an Arduino Nano (I also attach the code).

3443.CircuitDesign.pdf

/*********************************************************
                    TESIS DE GRADO
                       EEG v1.0
            Instituto de Ingenieria Biomedica 
    Facultad de Ingenieria, Universidad de Buenos Aires

        Brian Daniel Santillan, Florencia Grosso.
           Tutors: Sergio Lew. Ariel Burman.

Code description: 
This code controls the IC ADS1299 through an Arduino NANO
*********************************************************/

// Libraries
#include <SPI.h>

// Clock
#define tCLK 0.0005 //clock de 2MHz, 500ns

// Commands
// System commands
#define WAKEUP 0x02
#define STANDBY 0x04
#define RESET 0x06
#define START 0x08
#define STOP 0x0A

// Data Read Commands
#define RRDATAC 0x10
#define SSDATAC 0x11
#define RRDATA 0x12

// Register Read Commands
#define RREG 0x20
#define WREG 0x40

// Registers
#define ID 0x00
#define CONFIG1 0x01
#define CONFIG2 0x02
#define CONFIG3 0x03
//#define LOFF 0x04
#define CH1SET 0x05
#define CH2SET 0x06
#define CH3SET 0x07
#define CH4SET 0x08
#define CH5SET 0x09
#define CH6SET 0x0A
#define CH7SET 0x0B
#define CH8SET 0x0C
//#define BIAS_SENSP 0x0D
//#define BIAS_SENSN 0x0E
//#define LOFF_SENSP 0x0F
//#define LOFF_SENSN 0x10
//#define LOFF_FLIP 0x11
//#define LOFF_STATP 0x12
//#define LOFF_STATN 0x13
//#define GPIO 0x14
//#define MISC1 0x15
//#define MISC2 0x16
#define CONFIG4 0x17

// Pins for the arduino board
const int PIN_DRDY = 2;
const int PIN_START = 5;
const int PIN_SS = 10;
const int PIN_MOSI = 11; // DIN
const int PIN_MISO = 12; // DOUT
const int PIN_SCK = 13;
const int PIN_RESET = 4;

// Prototypes of used functions
void wake_up();
void send_command(uint8_t command);
void send_command_and_wait(uint8_t command, float time_to_wait);
byte fRREG(byte address);
void fWREG(byte address, byte data);
void getDeviceID();
void reset_communication(void);

// Global variables
boolean power_up = true;
boolean verbose = true;
byte deviceID = 0;

void setup() {
  /* Initialization routine for SPI bus */

  // Initalize communication with computer. 
  // Open serial port (USB), max rate 115bps
  Serial.begin(115200);
  // Wait until data transmission through serial port is completed (in case there's a transmission going on)
  Serial.flush(); 
  Serial.println("Conexi�n con PC establecida");
  delay(2000);
  
  // Set SPI communication. 2 MHz clock, MSB first, Mode 0.
  // MODE 0 = Output Edge: Falling - Data Capture: Rising (pag. 38)
  // MODE 1 = Output Edge: Rising - Data Capture: Falling (pag. 38)
  SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE1));
  // Initialize SPI.
  SPI.begin();

  // Set Pin modes
  pinMode(PIN_START, OUTPUT);
  pinMode(PIN_DRDY, INPUT);
  pinMode(PIN_SS, OUTPUT);
  pinMode(PIN_MOSI, OUTPUT);
  pinMode(PIN_MISO, INPUT);
  pinMode(PIN_SCK, OUTPUT);

  reset_communication;
  
  // Set pin initial value
  digitalWrite(PIN_START, LOW);
  digitalWrite(PIN_SS, HIGH);
  
  /* Follow initial flow at power-up (page 62) */

  // Delay>tPOR in ms (make sure thatVCAP1 1.1v = ok)
  delay(300);
  // Reset the device
  send_command_and_wait(RESET, 18*tCLK);  // (Datasheet, p.35)
  // Cancel RDATAC mode after reset
  send_command_and_wait(SSDATAC, 4*tCLK); // (Datasheet, p.42)

  /* TEST 1 */
  // Read ADS1299 ID to check that it receives data and there's communication
  while(deviceID == 0) {
      getDeviceID();
  }

  // Switch internal reference on (p.48)
  fWREG(CONFIG3,0xE0); // 0x60 -> enable internal ref, 0xE0 -> power down internal ref

  // Define the Data rate (p.46)
  // [it is set at minimum always, then changed by the desired value] 
  fWREG(CONFIG1,0x96); // 16kSPS -> 0x90, 8kSPS -> 0x91, ..., 250SPS -> 0x96

  // Define test signals (p.47)
  fWREG(CONFIG2,0xD4); // external test signal -> 0xC0, internal test signal -> 0xD0 
                       // 0 always ; 0  1*-(VREFP-VREFN)/2400) 1 2*-(VREFP-VREFN)/2400) - 00 fclk/2^21  01 fclk/2^20  11 at dc

  /* TEST 2 */
  // Read the written registers and print data
  if (verbose) {
     Serial.println("Check config regs:"); 
     Serial.print("CONFIG1: ");
     Serial.println(fRREG(CONFIG1), HEX);      
     Serial.print("CONFIG2: ");
     Serial.println(fRREG(CONFIG2), HEX);      
     Serial.print("CONFIG3: ");
     Serial.println(fRREG(CONFIG3), HEX);      
  }

  // Set all channels (p.50)
  //0x01 normal operation, unity gain & input shorted
  //0x81 power-down, unity gain & input shorted
  //0x05 normal operation, unity gain & test signal
  fWREG(CH1SET,0x05); 
  
  fWREG(CH2SET,0x81); 
  fWREG(CH3SET,0x81);
  fWREG(CH4SET,0x81);
  fWREG(CH5SET,0x81);
  fWREG(CH6SET,0x81);
  fWREG(CH7SET,0x81);
  fWREG(CH8SET,0x81);

  /* TEST 3 */
  // Read written registers
    // read the written registers and print data
  if (verbose) {
     Serial.println("Check channels:"); 
     Serial.print("CH1SET: ");
     Serial.println(fRREG(CH1SET), HEX);      
     Serial.print("CH4SET: ");  
     Serial.println(fRREG(CH4SET), HEX);// we may have trouble here since it has to print a binary, if not use print(xxx, BIN)
  }
}

// Operation loop for the Arduino.
void loop() {  
  // Activate conversion
  send_command_and_wait(START, 20); //(Settling time, p.34)

  // Continuous conversion of data (p. 40)
  send_command(RRDATAC);

  digitalWrite(SS, LOW);

  // Read data
  // Serial.print("Data Ready printer");
  if (digitalRead(PIN_DRDY) == LOW) {
    Serial.print("There is Data Ready ");
    byte read_out  = SPI.transfer(0x00);
    Serial.println(read_out, HEX);
  }
}

/* SYSTEM COMMANDS */

// TODO: This should be sent as a command too. Though we must figure out how to handle
// the intermediate delay.
// Wake-up from standby mode
void wake_up() {
  // Set SS low to communicate with device.
  digitalWrite(SS, LOW); 
  SPI.transfer(WAKEUP);
  // Must wait at least 4 tCLK cycles (Datasheet, pg. 40)
  delay(4*tCLK);
  // SS high to end communication
  digitalWrite(SS, HIGH); 
}

// Send a command to the ADS 1299. Requires no delay.
void send_command(uint8_t command) {  
  digitalWrite(SS, LOW);
  SPI.transfer(command);
  digitalWrite(SS, HIGH);
}

// Send a command to the ADS 1299. Issues a delay afterwards 
void send_command_and_wait(uint8_t command, float time_to_wait) {  
  digitalWrite(SS, LOW);
  SPI.transfer(command);
  digitalWrite(SS, HIGH);
  delay(time_to_wait);
}

/* REGISTER READ/WRITE COMMANDS */

// Read from register. Shouldn't it be returning the byte read?
// @param address: the starting register address.
// @param numberRegMinusOne: number of register to read - 1. (reads only 1 for now)
byte fRREG(byte address) {
  // RREG expects 001rrrrr where rrrrr = _address
  byte op_code = RREG + address; 
  digitalWrite(SS, LOW); 
  // send_command_and_wait(SSDATAC, 4*tCLK); 
  SPI.transfer(op_code);
  SPI.transfer(0x00);
  byte data = SPI.transfer(0x00);
  // Close SPI
  digitalWrite(SS, HIGH);
  delay(1);
  return data;
}

// Write to register.
// @param address: the starting register address. 
// @param data: value to write.
// @param numberRegMinusOne: number of register to write - 1. (we fix it to 0x00 for now)
void fWREG(byte address, byte data) {
  // WREG expects 001rrrrr where rrrrr = _address
  // Open SPI.
  byte op_code = WREG + address;
  digitalWrite(SS, LOW);
  // send_command_and_wait(SSDATAC, 4*tCLK);
  SPI.transfer(op_code);
  // Write only one register
  SPI.transfer(0x00);
  SPI.transfer(data);
  // Close SPI
  digitalWrite(SS, HIGH); 
  if (verbose) {
    Serial.print("Register 0x");
    Serial.print(address, HEX);
    Serial.println(" modified.");
  }
  delay(1);
}

// Method to retrieve device ID
void getDeviceID() {
  // Halt SPI data transfer and start reading
  delay(500);
  send_command_and_wait(SSDATAC, 4*tCLK);
  delay(10);
  byte data = fRREG(ID);
  // If retrieved ID is valid, then no power up is needed
  deviceID = data;
  if(verbose) {
    Serial.println("Device ID: ");
    Serial.println(deviceID, BIN);
  }
}

void reset_communication(void){
//Resetea la comunicaci�n (datasheet p.30)
  digitalWrite(PIN_SS, HIGH);
  digitalWrite(PIN_RESET, HIGH);
  delay(1000);
  digitalWrite(PIN_RESET, LOW);
  delay(1000);
  digitalWrite(PIN_RESET, HIGH);
  delay(100);  
  digitalWrite(PIN_SS, LOW);
  delay(1000);
  digitalWrite(PIN_SS, HIGH);
}


I am being able to read the registers after writing them, checking that the correct data has been written, but the problem is when I try to use the test signal. I have no triggering of the DRDY output and thus I have no output at all. Occasionally I was able to make it trigger but got all 0's. I have double checked the code comparing it to other works for thesis using the same or similar parts (ADS1292), I have double checked the code and the circuit with the datasheet, but I have no results. 

If you could please help me to see what I'm missing or doing wrong, I would really appreciate it, since I am running out of ideas.

Thank you.

Best,

Florencia

  • Hello Florencia,

    Welcome to our E2E forum!

    How are you treating the START pin during your start-up sequence? I see that it is connected to your MCU. In order for the ADC to convert, either the START pin must be pulled high to DVDD, or it must be pulled low and you must send the START SPI op-code. By default, the ADS1299 powers-up in Continuous Conversion Mode, so as soon as START is pulled high or the SPI command is sent, you should see /DRDY pulsing at the default data rate.

    Do you /DRDY pulsing at the default data rate before configuring your registers?

    Best Regards,
  • Hi Ryan,

    Thanks for your answer, it was really helpful to solve one of the issues. I've reordered the commands so as to pullstart pin low and then, when I finish writing all registers, send the RDATAC op-code followed by the START op-code through SPI. Now /DRYD pulses as it should though the reading is always 0 and not the voltages corresponding to the test signal.

    Here is the piece of code where I configure the channel and read the data:

    // Set all channels (p.50)
    fWREG(CH1SET,0x05);
    
    /* TEST 3 */
    // Read written channels
    if (verbose) {
    Serial.println("Check channels:"); 
    Serial.print("CH1SET: ");
    }
    
    send_command(RRDATAC);
    digitalWrite(PIN_START, LOW);
    delay(150);
    send_command(START);
    
    }
    
    // Operation loop for the Arduino.
    void loop() {
    
    // Read data
    while (digitalRead(PIN_DRDY) == HIGH);
    Serial.print("There is Data Ready ");
    delay(1);
    
    byte read_out = 0;
    // Ignore header
    digitalWrite(SS, LOW);
    SPI.transfer(0x00);
    SPI.transfer(0x00);
    SPI.transfer(0x00);
    
    read_out = SPI.transfer(0x00); 
    Serial.print(read_out, HEX);
    read_out = SPI.transfer(0x00); 
    Serial.print(read_out, HEX);
    read_out = SPI.transfer(0x00); 
    Serial.println(read_out, HEX);
    
    
    digitalWrite(SS, HIGH);
    
    }
    


    I don't see why isn't the test signal working. I have already written 0xD4 to CONFIG2 succesfully and the CH1 too. I have also tested writing 0x81 to the remaining channels which are not used, but I had no results neither.

    Could you please tell me if there's something I'm missing or doing wrong?

    Thanks!

    Best,

    Florencia

  • Hello Florencia,

    After sending the RDATAC command, you cannot send any more SPI commands. Please send the START command and configure all registers before enabling RDATAC Mode.

    Otherwise, the register settings look correct in "EEG_main.txt" and "ADSTestSignal.txt."

    What does the raw data look like when you try to measure the internal test signal? Are you sending enough SCLKs to reads the STATUS word + 8 channels of 24-bit data? If you could please send a sample of the data you collect (preferably in hexadecimal format), we could take a look and see if the data makes any sense.

    Best Regards,

  • Hello Ryan,

    Thanks for your answer. Yes, you are right, I have to switch orders between START and RDATAC commands.  To read the data we are using SPI.transfer(), does the issue with RDATAC extends to it too?

    We are actually getting all 0's when /DRDY triggers, not a single byte with a different value, that's why it is so weird. Not even the headers, all is 0.

    Best,

    Florencia

  • Hi Florencia,

    Did you manage to solve your issue?

    DOUT will not output data unless you send SCLK. If the device is in Continuous Conversion Mode and also RDATAC Mode, then conversions will be completed automatically at the set data rate and the results will be updated in the output shift register each time. When SCLK is received, the contents of the output shift register will be shifted out.

    Best Regards,