Other Parts Discussed in Thread: ADS1299
Hi,
This is my first time posting on the forum, so please bear with me if I leave information out.
I have read some of the other posts on how to obtain the internal test signals and I am struggling to get the square signal. I am using the ADS1299-4 with an ESP32 as an MCU. I will post my code below and the output I keep getting at the bottom. I followed the start-up procedure as stated in the datasheet and able to read and write the registers correctly. At first, I am only trying to get the test signals from channel 1 and shorten the other three channels. I am using Arduino IDE and built a custom PCB. As a reference, I followed openBCI schematic and opensource code to build the PCB.
The problem I have is the output of the test signals. As you can see in the figure below, the output is quite weird and not square as it should be. I don't know if I am just not configuring the registers correctly or maybe my SPI clock is just incorrect. The figure below is what I am getting on the Serial Plotter and on the Serial Monitor I get negative answers around -6000.
Can somebody please help me by showing me what I am doing wrong and what I can do to fix it? It would be much appreciated!
Here is the Serial Plotter output I got.
Here are some snippets of my code with my full code afterward:
This is how I write to the registers:
Update channel data:
And here is the function of how I want to print the data:
Full-text file containing the code.
#include "EEG.h" #include "EEG_Definitions.h" #include <SoftwareSerial.h> #include <SPI.h> // start of simulation declarations #define ISR_TRIGGER_GPIO 39 #define PULSE_OUTPUT_GPIO 32 // Scale factor for data #define GAIN 1 #define scaleFactor 1000000*((4.5/(2^23)-1)/GAIN) #define testScale 0.001*4.5/2.4 // Clock Signal #define tCLK 0.0005 // 2 MHz Clock signal, 500 ns int sampleFreq = 250; // to 500. A value of 128 will give 512 samples int factor = 1000/sampleFreq/2; // generate output pulses to emulate DRDY from ADS // this should be placed in multiple places to emulate an unsynchronised DRDY #define GENERATE_DRDY digitalWrite(PULSE_OUTPUT_GPIO, (millis() / factor) % 2); //#define GENERATE_DRDY digitalWrite(PULSE_OUTPUT_GPIO, HIGH) // end of simulation declarations EEG board; // Functions const int WAKEUP = 0x02; // Wake-up from standby mode const byte STANDBY = 0b00000100; // Enter Standby mode const byte RESET = 0b00000110; // Reset the device const byte START = 0b00001000; // Start and restart (synchronize) conversions const byte STOP = 0b00001010; // Stop conversion const byte RDATAC = 0b00010000; // Enable Read Data Continuous mode (default mode at power-up) const byte SDATAC = 0b00010001; // Stop Read Data Continuous mode const byte RDATA = 0b00010010; // Read data by command; supports multiple read back const byte TEST1 = 0b00000000; const byte RREG = 0x20;// (also = 00100000) is the first opcode that the address must be added to for RREG communication const byte WREG = 0x40;// 01000000 in binary (Datasheet, pg. 35) double data; const byte led = 2; byte registerData[24]; // array is used to mirror register data byte channelDataRaw[24]; long channelData[5]; long ads[5]; int sampleCounter = 0; /* //SPI pin numbers: SCK 18 // Serial Clock. MISO 19 // Master In Slave Out. (DOUT) MOSI 23 // Master Out Slave In. (DIN) SS 5 // Slave Select*/ //ADS1299-X Control Pin Declarations const int STARTPIN = 14; const int DRDYPIN = 4; const int RESETPIN = 0; const int PWDNPIN = 3; void IRAM_ATTR ADS_DRDY_Service() { if (bitRead(ESP32_DRDY, 0) == 0) { board.channelDataAvailable = true; } } int devicebyte = 0; void setup() { Serial.begin(115200); Serial.flush(); delay(2000); while(!Serial); //SPI Communication Setup with ADS1299-X // Chip Select Pin pinMode(CS_ADS, OUTPUT); digitalWrite(CS_ADS, HIGH); //Start Pin -- Pull Start Pin High in order to access ADS1299-X data - DRDY toggles at 250Hz pinMode(ADS_Start, OUTPUT); digitalWrite(ADS_Start, HIGH); //DRDY Pin - Drops LOW if Data is ready pinMode(ADS_DRDY, INPUT); // Set up SPI SPI.begin(); SPI.setFrequency(4000000); // Set 4 MHz for ADS SPI.setDataMode(SPI_MODE1); //Powering Up Sequence // Serial.println("Powering up Device..."); DeviceStartUp(); Serial.println("Device power up complete..."); delayMicroseconds(2); // Get Device ID devicebyte = getDeviceID(); // Serial.print("Device ID is: "); // Serial.print(devicebyte, BIN); Serial.println(); // Print default settings for registers board.printADSregisters(CS_ADS); //Writing Channel Configuration // Serial.println("Writing Channel Settings..."); writeRegisterConfig(); // Serial.println("Writing Channel Settings complete..."); delayMicroseconds(2); // Set up interrupt service routine pinMode(ADS_DRDY, INPUT_PULLUP); pinMode(ISR_TRIGGER_GPIO,INPUT_PULLUP); // simulation - set up the pin for output of pulses that emulate DRDY from ADS pinMode(PULSE_OUTPUT_GPIO, OUTPUT); attachInterrupt(ADS_DRDY, ADS_DRDY_Service, FALLING); attachInterrupt(ISR_TRIGGER_GPIO, ADS_DRDY_Service, FALLING); digitalWrite(CS_ADS, LOW); SPI.transfer(_START); // KEEP ON-BOARD AND ON-DAISY IN SYNC digitalWrite(CS_ADS, HIGH); delay(30); digitalWrite(CS_ADS, LOW); SPI.transfer(_RDATAC); // read data continuous digitalWrite(CS_ADS, HIGH); delay(1); testSignals(); } // --------------------------- LOOP --------------------------------------------------- void loop() { // Serial.println((0.001*4.5/2.4),DEC); // while(ADS_DRDY == LOW){ GENERATE_DRDY updateChannelData(); // printChannelData(); GENERATE_DRDY // } } // ------------------------- Device Start up Procedure ------------------------------------- void DeviceStartUp(){ //PWDN and RESET PIN set HIGH pinMode(ADS_RST, OUTPUT); digitalWrite(ADS_RST, HIGH); pinMode(PWDN, OUTPUT); digitalWrite(PWDN, HIGH); //Delay for 1 second, for power up sequence delay(1000); //RESET PULSE digitalWrite(ADS_RST,LOW); delayMicroseconds(1); //2 tclk cycles digitalWrite(ADS_RST,HIGH); //Wait to Settle 16-18 tclk delayMicroseconds(18*tCLK); //Send SDATAC SPI.beginTransaction(SPISettings(2000000,MSBFIRST,SPI_MODE1)); digitalWrite(CS_ADS,LOW); //Pull CS LOW to start communication SPI.transfer(SDATAC); delayMicroseconds(4*tCLK); //delay 4 tCLK cycles digitalWrite(CS_ADS,HIGH); //Pull CS HIGH to stop communication SPI.endTransaction(); } // ----------------------- Retrieving Device ID function --------------------------------------------------- int getDeviceID(){ //Delay delay(100); // Begin SPI SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE1)); digitalWrite(CS_ADS,LOW); //Pull CS low to communicate SPI.transfer(RREG); // Read Register 00100000 delayMicroseconds(2); SPI.transfer(ID_REG); //0x00 ID register 00000000 delayMicroseconds(2); byte data = SPI.transfer(ADS_ID); // Binary value for device ID, 4CH = 0b???11100 delayMicroseconds(2); digitalWrite(CS_ADS, HIGH); // Pull CS HIGH to disable communication between Teensy and ADS1299-X SPI.endTransaction(); return data; } // ------------------------- Write Registers Configuration ------------------------------------- void writeRegisterConfig() { // ADS1299-4 Datasheet pg 62: SPI.beginTransaction(SPISettings(4000000,MSBFIRST,SPI_MODE1)); digitalWrite(CS_ADS,LOW); //Pull CS LOW to start communication // SPI.transfer(SDATAC); // delayMicroseconds(4*tCLK); //delay 4 tCLK cycles //Using internal reference i.e BIASREF siganl (AVDD + AVSS)/2 WREGConf(CONFIG3, 0xE0); delayMicroseconds(2); // Set Device for f_mod/4096 (250 SPS) WREGConf(CONFIG1, 0x96); WREGConf(CONFIG2, 0xC0); // Set Channels to Input Short WREGConf(CH1SET, 0x01); WREGConf(CH2SET, 0x01); WREGConf(CH3SET, 0x01); WREGConf(CH4SET, 0x01); delayMicroseconds(2); board.RREGS(ID_REG, CONFIG4, CS_ADS); delayMicroseconds(2); digitalWrite(CS_ADS,HIGH); //Pull CS HIGH to stop communication } // --------------------------- Write channel configuration procedure-------------------------- void WREGConf(byte _address, byte _regValue){ byte opcodeW = _address + 0x40; // Write to one register with address (WREG = 0x40), WREG expects 010rrrrr where rrrrr = _address SPI.transfer(opcodeW); // Send WREG command and address SPI.transfer(0x00); // Send dummy byte to ADS. Send number of registers to read -1 SPI.transfer(_regValue); // Write register value registerData[_address] = _regValue; // Update mirror array } // -------------------------------- Setup Test Signals ----------------------------------------- void testSignals(){ // SPI.beginTransaction(SPISettings(4000000,MSBFIRST,SPI_MODE1)); digitalWrite(CS_ADS,LOW); //Pull CS LOW to start communication SPI.transfer(SDATAC); delayMicroseconds(4*tCLK); //delay 4 tCLK cycles // Set Device for f_mod/4096 (250 SPS) WREGConf(CONFIG2, 0xD0); // Set Channels to Test Signals WREGConf(CH1SET, 0x15); WREGConf(CH2SET, 0x01); WREGConf(CH3SET, 0x01); WREGConf(CH4SET, 0x01); // Lead Off Dectection WREGConf(LOFF, 0x00); // Bias WREGConf(BIAS_SENSP, 0x01); // CH2 set as BIAS WREGConf(BIAS_SENSN, 0x00); // Disable all negative input //CONFIG3 WREGConf(CONFIG3, 0xEC); // Internal reference buffer & BIASREF signal generated internally SPI.transfer(RDATAC); delayMicroseconds(4*tCLK); //delay 4 tCLK cycles digitalWrite(CS_ADS, HIGH); // Pull CS HIGH to disable communication between Teensy and ADS1299-X // SPI.endTransaction(); } // ------------------------------- Update Channel Data ------------------------------------- void updateChannelData(){ byte inByte; int byteCounter = 0; int numChan = 4; //assume 4 channel. If needed, it automatically changes to 16 automatically in a later block. int stat_1, stat_2; long channelDat; digitalWrite(CS_ADS, LOW); // open SPI // READ CHANNEL DATA FROM FIRST ADS for(int i=0; i<3; i++){ // read 3 byte status register from ADS 1 (1100+LOFF_STATP+LOFF_STATN+GPIO[7:4]) inByte = SPI.transfer(0x00); stat_1 = (stat_1<<8) | inByte; } for(int i = 0; i < numChan; i++){ for(int j=0; j < 3; j++){ // read 24 bits of channel data from 1st ADS in 8 3 byte chunks inByte = SPI.transfer(0x00); // channelDataRaw[byteCounter] = inByte; // Raw data array // byteCounter++; channelData[i] = (channelData[i]<<8) | inByte; // Int data array } } digitalWrite(CS_ADS, HIGH); // close SPI //reformat the numbers for(int i = 0; i < numChan; i++){ // convert 3 byte 2's compliment to 4 byte 2's compliment if(bitRead(channelData[i],23) == 1){ channelData[i] |= 0xFF000000; ads[i] = channelData[i]; }else{ channelData[i] &= 0x00FFFFFF; ads[i] = channelData[i]; } } printChannelData(); } // ------------------------------- Print Channel Data ------------------------------------- void printChannelData(){ // Serial.println(" "); for(int i = 0; i < 4; i++){ Serial.println(channelData[i],DEC); // ads[i] = channelData[i]; // Serial.println(ads[i], DEC); // Serial.println(ads[i]*(4.5/(2^23 -1)),DEC); // if(ads[i] != 0){ // Serial.println(ads[i],DEC); // Serial.println(ads[0]*(4.5/(2^23 -1)), DEC); // } } }