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).
/*********************************************************
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