Hi everyone
I am trying to get the ADS1299 data on an SD card on my teensy 4.1. I am using the included SD port provided by the teensy. The ADS uses SPI mode 1 while the SD card uses SPI mode 0.
When I run my code, the file is created but nothing is written in it. I can get the ADS data over the Serial but as soon as I try to save the data in the SD card it seems like it never enter mu RDATA_Update function.
and here is the ADS.cpp
I use the normal SPI pins exept for CS of ADS -> pin 37
And for SD card I use BUILTIN_SDCARD
Does anyone know what could be the probleme ? I know it might be the SPI communication that must switch between mode 0 and 1 but I do that in my CStoLOW and HIGH function.
I am trying to get the ADS1299 data on an SD card on my teensy 4.1. I am using the included SD port provided by the teensy. The ADS uses SPI mode 1 while the SD card uses SPI mode 0.
When I run my code, the file is created but nothing is written in it. I can get the ADS data over the Serial but as soon as I try to save the data in the SD card it seems like it never enter mu RDATA_Update function.
Code:
/* main.cpp
* This file contains demo code to test the ADS1299
*
* Check configs.h file for configurations that can be set
*
* Authors: Mingye Chen
*/
#include <Arduino.h>
#include <SPI.h>
#include "CochlEEG.h"
#include "ADS1299.h"
#include <SD.h>
CochlEEG cochleeg;
ADS1299 ads;
int mode = 0; // 0=stopped, 1=recording, 2=playing
void setup() {
Serial.begin(115200);
Serial.println();
Serial.println("Serial starting");
SPI.begin();
SPI.setDataMode(SPI_MODE1); // use SPI mode for ADS
SPI.setClockDivider(4000000);
SPI2.begin();
SPI2.setDataMode(SPI_MODE0);
// Initialize the SD card
if (!(SD.begin(BUILTIN_SDCARD))) {
// stop here if no SD card, but print a message
while (1) {
Serial.println("Unable to access the SD card");
delay(500);
}
}
ads.initialize();
ads.desactiveChannel(2);
ads.desactiveChannel(3);
ads.desactiveChannel(4);
ads.desactiveChannel(5);
ads.desactiveChannel(6);
ads.desactiveChannel(7);
ads.printAllRegisters();
delay(2000);
}
void loop() {
if (Serial.available() > 0) {
char inChar = Serial.read();
switch (inChar) {
case 'r':
Serial.println("Record Button Press");
if (mode == 0) {
ads.startRecording();
}
break;
case 's':
Serial.println("Stop Button Press");
if (mode == 1) ads.stopRecording();
break;
}
}
// If we're playing or recording, carry on...
if (mode == 1) {
ads.RDATA_update();
}
}
and here is the ADS.cpp
Code:
/* ADS1299.cpp
* This file contains the implementation of functions found in ADS1299.h
* It is a driver library for the ADS1299 EEG/EMG/ECG signal aquisition chip from TI
*
* Authors: Mingye Chen
*/
#include "ADS1299.h"
#include "configs.h"
//Other Global Variables :
const uint8_t BASE_NAME_SIZE = sizeof(FILE_BASE_NAME) - 1;
char fileName[] = FILE_BASE_NAME "00.txt";
File MyFile;
void ADS1299::initialize(){
pinMode(SD_SS,OUTPUT);
digitalWrite(SD_SS,HIGH);
pinMode(ADS_SS, OUTPUT);
digitalWrite(ADS_SS,HIGH);
pinMode(ADS_DRDY, INPUT);
delay(50);
pinMode(ADS_RST, OUTPUT);
digitalWrite(ADS_RST, LOW);
delay(4);
delay(40);
digitalWrite(8, HIGH);
delay(1000);
// reset pulse
digitalWrite(ADS_RST,LOW);
delayMicroseconds(15);
digitalWrite(ADS_RST, HIGH);
delay(40);
RESET();
SDATAC();
delay(100);
// DEFAULT CHANNEL SETTINGS FOR ADS
defaultChannelSettings[POWER_DOWN] = NO; // on = NO, off = YES
defaultChannelSettings[GAIN_SET] = ADS_GAIN24; // Gain setting
defaultChannelSettings[INPUT_TYPE_SET] = ADSINPUT_NORMAL;// input muxer setting
defaultChannelSettings[BIAS_SET] = YES; // add this channel to bias generation
defaultChannelSettings[SRB2_SET] = YES; // connect this P side to SRB2
defaultChannelSettings[SRB1_SET] = YES; // don't use SRB1
for(int i=0; i<8; i++){
for(int j=0; j<6; j++){
channelSettings[i][j] = defaultChannelSettings[j];
}
}
for(int i=0; i<8; i++){
useInBias[i] = true; // keeping track of inputs used for Bias Generation
useSRB2[i] = true; // keeping track of inputs using SRB2
}
useSRB1 = false;
writeChannelSettings();
WREG(CONFIG3,0b11101100); delay(1); // enable internal reference drive and etc.
for(int i=0; i<8; i++){ // turn off the impedance measure signal
leadOffSettings[i][PCHAN] = OFF;
leadOffSettings[i][NCHAN] = OFF;
}
verbosity = false; // when verbosity is true, there will be Serial feedback
startADS();
}
void ADS1299::startRecording(){
while (SD.exists(fileName)) {
if (fileName[BASE_NAME_SIZE + 1] != '9') {
fileName[BASE_NAME_SIZE + 1]++;
}
else if (fileName[BASE_NAME_SIZE] != '9') {
fileName[BASE_NAME_SIZE + 1] = '0';
fileName[BASE_NAME_SIZE]++;
}
else {
Serial.println(F("Can't create file name"));
return;
}
}
MyFile = SD.open(fileName, FILE_WRITE);
MyFile.println("Chn1,Chn2,Chn3,Chn4,Chn5,Chn6,Chn7,Chn8");
_record = true;
}
void ADS1299::stopRecording(){
_record = false;
MyFile.close();
}
// <<<<<<<<<<<<<<<<<<<<<<<<< START OF ADS1299 FUNCTIONS >>>>>>>>>>>>>>>>>>>>>>>>>
void ADS1299::CStoLOW(void)
{
digitalWrite(SD_SS,HIGH);
digitalWrite(ADS_SS, LOW);
}
void ADS1299::CStoHIGH(void)
{
digitalWrite(ADS_SS, HIGH);
digitalWrite(SD_SS,LOW);
}
void ADS1299::reportDefaultChannelSettings(void){
Serial.write(defaultChannelSettings[POWER_DOWN] + '0'); // on = NO, off = YES
Serial.write((defaultChannelSettings[GAIN_SET] >> 4) + '0'); // Gain setting
Serial.write(defaultChannelSettings[INPUT_TYPE_SET] +'0');// input muxer setting
Serial.write(defaultChannelSettings[BIAS_SET] + '0'); // include in bias generation
Serial.write(defaultChannelSettings[SRB2_SET] + '0'); // connect this P side to SRB2
Serial.write(defaultChannelSettings[SRB1_SET] + '0'); // don't use SRB1
}
void ADS1299::writeChannelSettings(void){
byte setting;
boolean use_SRB1 = false;
//proceed...first, disable any data collection
SDATAC(); delay(1); // exit Read Data Continuous mode to communicate with ADS
for(byte i=0; i<8; i++){ // write 8 channel settings
setting = 0x00;
if(channelSettings[i][POWER_DOWN] == YES) {setting |= 0x80;}
setting |= channelSettings[i][GAIN_SET]; // gain
setting |= channelSettings[i][INPUT_TYPE_SET]; // input code
if(channelSettings[i][SRB2_SET] == YES){
setting |= 0x08; // close this SRB2 switch
useSRB2[i] = true;
}else{
useSRB2[i] = false;
}
WREG(CH1SET+i, setting); // write this channel's register settings
// add or remove from inclusion in BIAS generation
setting = RREG_return(BIAS_SENSP); //get the current P bias settings
if(channelSettings[i][BIAS_SET] == YES){
bitSet(setting,i); //set this channel's bit to add it to the bias generation
useInBias[i] = true;
}else{
bitClear(setting,i); // clear this channel's bit to remove from bias generation
useInBias[i] = false;
}
WREG(BIAS_SENSP,setting); delay(1); //send the modified byte back to the ADS
setting = RREG_return(BIAS_SENSN); //get the current N bias settings
if(channelSettings[i][BIAS_SET] == YES){
bitSet(setting,i); //set this channel's bit to add it to the bias generation
}else{
bitClear(setting,i); // clear this channel's bit to remove from bias generation
}
WREG(BIAS_SENSN,setting); delay(1); //send the modified byte back to the ADS
if(channelSettings[i][SRB1_SET] == YES){
useSRB1 = true;
}
}
if(useSRB1){
for(int i=0; i<8; i++){
channelSettings[i][SRB1_SET] = YES;
}
WREG(MISC1,0x20); // close all SRB1 swtiches
}else{
for(int i=0; i<8; i++){
channelSettings[i][SRB1_SET] = NO;
}
WREG(MISC1,0x00);
}
}
void ADS1299::writeChannelSettings(int N){
byte setting;
if ((N < 1) || (N > 8)) return; // must be a legit channel number
N = constrain(N-1,0,7); //subtracts 1 so that we're counting from 0, not 1
//proceed...first, disable any data collection
SDATAC(); delay(1); // exit Read Data Continuous mode to communicate with ADS
setting = 0x00;
if(channelSettings[N][POWER_DOWN] == YES) {setting |= 0x80;}
setting |= channelSettings[N][GAIN_SET]; // gain
setting |= channelSettings[N][INPUT_TYPE_SET]; // input code
if(channelSettings[N][SRB2_SET] == YES){
setting |= 0x08; // close this SRB2 switch
useSRB2[N] = true; // keep track of SRB2 usage
}else{
useSRB2[N] = false;
}
WREG(CH1SET+N, setting); // write this channel's register settings
// add or remove from inclusion in BIAS generation
setting = RREG_return(BIAS_SENSP); //get the current P bias settings
if(channelSettings[N][BIAS_SET] == YES){
useInBias[N] = true;
bitSet(setting,N); //set this channel's bit to add it to the bias generation
}else{
useInBias[N] = false;
bitClear(setting,N); // clear this channel's bit to remove from bias generation
}
WREG(BIAS_SENSP,setting); delay(1); //send the modified byte back to the ADS
setting = RREG_return(BIAS_SENSN); //get the current N bias settings
if(channelSettings[N][BIAS_SET] == YES){
bitSet(setting,N); //set this channel's bit to add it to the bias generation
}else{
bitClear(setting,N); // clear this channel's bit to remove from bias generation
}
WREG(BIAS_SENSN,setting); delay(1); //send the modified byte back to the ADS
if(channelSettings[N][SRB1_SET] == YES){
for(int i=0; i<8; i++){
channelSettings[i][SRB1_SET] = YES;
}
useSRB1 = true;
WREG(MISC1,0x20); // close all SRB1 swtiches
}
if((channelSettings[N][SRB1_SET] == NO) && (useSRB1 == true)){
for(int i=0; i<8; i++){
channelSettings[i][SRB1_SET] = NO;
}
useSRB1 = false;
WREG(MISC1,0x00);
}
}
void ADS1299::desactiveChannel(int N){
byte setting;
if ((N < 1) || (N > 8)) return; //check the inputs
//proceed...first, disable any data collection
SDATAC(); delay(1); // exit Read Data Continuous mode to communicate with ADS
//shut down the channel
N = constrain(N-1,0,7); //subtracts 1 so that we're counting from 0, not 1
// reg = CH1SET+(byte)N; // select the current channel
setting = RREG_return(CH1SET+(byte)N); delay(1); // get the current channel settings
bitSet(setting,7); // set bit7 to shut down channel
channelSettings[N][POWER_DOWN] = YES; // keep track of channel on/off state
bitClear(setting,3); // clear bit3 to disclude from SRB2
WREG(CH1SET+(byte)N,setting); delay(1); // write the new value to disable the channel
//remove the channel from the bias generation...
setting = RREG_return(BIAS_SENSP); delay(1); //get the current bias settings
bitClear(setting,N); //clear this channel's bit to remove from bias generation
WREG(BIAS_SENSP,setting); delay(1); //send the modified byte back to the ADS
setting = RREG_return(BIAS_SENSN); delay(1); //get the current bias settings
bitClear(setting,N); //clear this channel's bit to remove from bias generation
WREG(BIAS_SENSN,setting); delay(1); //send the modified byte back to the ADS
leadOffSettings[N][0] = leadOffSettings[N][1] = NO; // stop lead off detection
changeChannelLeadOffDetection();
}
void ADS1299::activateChannel(int N){
byte setting;
if ((N < 1) || (N > 8)) return; //check the inputs
N = constrain(N-1,0,7); //shift down by one
//proceed...first, disable any data collection
SDATAC(); delay(1); // exit Read Data Continuous mode to communicate with ADS
setting = 0x00;
channelSettings[N][POWER_DOWN] = NO; // keep track of channel on/off state
setting |= channelSettings[N][GAIN_SET]; // gain
setting |= channelSettings[N][INPUT_TYPE_SET]; // input code
if(useSRB2[N] == true){channelSettings[N][SRB2_SET] = YES;}else{channelSettings[N][SRB2_SET] = NO;}
if(channelSettings[N][SRB2_SET] == YES) bitSet(setting,3); // close this SRB2 switch
WREG(CH1SET+N, setting);
// add or remove from inclusion in BIAS generation
if(useInBias[N]){channelSettings[N][BIAS_SET] = YES;}else{channelSettings[N][BIAS_SET] = NO;}
setting = RREG_return(BIAS_SENSP); //get the current P bias settings
if(channelSettings[N][BIAS_SET] == YES){
bitSet(setting,N); //set this channel's bit to add it to the bias generation
}else{
bitClear(setting,N); // clear this channel's bit to remove from bias generation
}
WREG(BIAS_SENSP,setting); delay(1); //send the modified byte back to the ADS
setting = RREG_return(BIAS_SENSN); //get the current N bias settings
if(channelSettings[N][BIAS_SET] == YES){
bitSet(setting,N); //set this channel's bit to add it to the bias generation
}else{
bitClear(setting,N); // clear this channel's bit to remove from bias generation
}
WREG(BIAS_SENSN,setting); delay(1); //send the modified byte back to the ADS
setting = 0x00;
if(useSRB1) setting = 0x20;
WREG(MISC1,setting); // close all SRB1 swtiches if desired
}
// Query to see if data is available from the ADS1299...return TRUE is data is available
boolean ADS1299::isDataAvailable(void)
{
return (!(digitalRead(ADS_DRDY)));
}
void ADS1299::RDATA_update(){
CStoLOW();
// RDATA command - ONLY DIFFERENCE BETWEEN THIS FUNC AND THE updateDATA()
SPI.transfer(_RDATA);
long output[9];
uint32_t dataPacket;
for(int i = 0; i<9; i++){
for(int j = 0; j<3; j++){
byte dataByte = SPI.transfer(0x00);
dataPacket = (dataPacket<<8) | dataByte; // constructing the 24 bit binary
}
output[i] = dataPacket;
dataPacket = 0;
}
CStoHIGH();
for(int i=1; i<9; i++){
if(bitRead(output[i],23) == 1){ // convert 3 byte 2's compliment to 4 byte 2's compliment
output[i] |= 0xFF000000;
}
else{
output[i] &= 0x00FFFFFF;
}
}
// conversions to microvolts
double outputvolts[9];
for(int i = 1; i < 9; i++){
outputvolts[i] = 1000* double(output[i])*2*4.5/24/(pow(2,24));
}
// changed to get data from 4 channels of ads1299-4
// i=0;i<9 was original
for (int i=1;i<9; i++) {
Serial.print(outputvolts[i]);
MyFile.print(outputvolts[i]);
MyFile.print(",");
//Serial.print(output[i]);
if(i!=8) Serial.print("\t");
}
Serial.println();
MyFile.println();
}
//write as binary each channel's 3 bytes of data
void ADS1299::writeADSchannelData(void)
{
for (int i=0;i<8; i++) {
Serial.print(channelData[i]);
if(i!=8) Serial.print("\t");
}
Serial.println();
}
void ADS1299::changeChannelLeadOffDetection(void){
byte P_setting = RREG_return(LOFF_SENSP);
byte N_setting = RREG_return(LOFF_SENSN);
for(int i=0; i<8;i++){
if(leadOffSettings[i][0] == YES){
bitSet(P_setting,i);
}else{
bitClear(P_setting,i);
}
if(leadOffSettings[i][1] == YES){
bitSet(N_setting,i);
}else{
bitClear(N_setting,i);
}
}
WREG(LOFF_SENSP,P_setting);
WREG(LOFF_SENSN,N_setting);
}
void ADS1299::configureLeadOffDetection(byte amplitudeCode, byte freqCode)
{
amplitudeCode &= 0b00001100; //only these two bits should be used
freqCode &= 0b00000011; //only these two bits should be used
byte setting = 0x00;
setting = ADS1299::RREG_return(LOFF); //get the current bias settings
//reconfigure the byte to get what we want
setting &= 0b11110000; //clear out the four ls bits
setting |= amplitudeCode; //set the amplitude
setting |= freqCode; //set the frequency
//send the config byte back to the hardware
ADS1299::WREG(LOFF,setting); delay(1); //send the modified byte back to the ADS
}
//Configure the test signals that can be inernally generated by the ADS1299
void ADS1299::configureInternalTestSignal(byte amplitudeCode, byte freqCode)
{
if (amplitudeCode == ADSTESTSIG_NOCHANGE) amplitudeCode = (RREG_return(CONFIG2) & (0b00000100));
if (freqCode == ADSTESTSIG_NOCHANGE) freqCode = (RREG_return(CONFIG2) & (0b00000011));
freqCode &= 0b00000011; //only the last two bits are used
amplitudeCode &= 0b00000100; //only this bit is used
byte message = 0b11010000 | freqCode | amplitudeCode; //compose the code
WREG(CONFIG2,message); delay(1);
}
// <<<<<< SYSTEM COMMANDS >>>>>>
void ADS1299::RESET() {
CStoLOW();
SPI.transfer(_RESET);
delay(10);
// delay(18.0*tCLK); //must wait 18 tCLK cycles to execute this command (Datasheet, pg. 35)
CStoHIGH();
}
void ADS1299::START() {
CStoLOW();
SPI.transfer(_START);
CStoHIGH();
}
void ADS1299::STOP() {
CStoLOW();
SPI.transfer(_STOP);
CStoHIGH();
}
//Data Read Commands
void ADS1299::RDATAC() {
CStoLOW();
SPI.transfer(_RDATAC);
CStoHIGH();
}
void ADS1299::SDATAC() {
CStoLOW();
SPI.transfer(_SDATAC);
CStoHIGH();
}
void ADS1299::RDATA() {
CStoLOW();
SPI.transfer(_RDATA);
CStoHIGH();
}
void ADS1299::resetADS(void)
{
RESET(); // send RESET command to default all registers
SDATAC(); // exit Read Data Continuous mode to communicate with ADS
delay(100);
}
// Stop the continuous data acquisition
void ADS1299::stopADS(void)
{
STOP();
delay(1); // start the data acquisition
SDATAC();
delay(1); // exit Read Data Continuous mode to communicate with ADS
isRunning = false;
}
// Start continuous data acquisition
void ADS1299::startADS(void)
{
RDATAC();
delay(1); // enter Read Data Continuous mode
START(); // start the data acquisition
delay(1);
isRunning = true;
}
// REGISTER READ/WRITE COMMANDS
byte ADS1299::RREG_return(byte _address) { // reads ONE register at _address
byte opcode1 = _address + 0x20; // RREG expects 001rrrrr where rrrrr = _address
CStoLOW(); // open SPI
SPI.transfer(opcode1); // opcode1
SPI.transfer(0x00); // opcode2
regData[_address] = SPI.transfer(0x00);// update mirror location with returned byte
CStoHIGH(); // close SPI
if (verbosity){ // verbosity output
printRegisterName(_address);
printHex(_address);
Serial.print(F(", "));
printHex(regData[_address]);
Serial.print(F(", "));
for(byte j = 0; j<8; j++){
Serial.print(bitRead(regData[_address], 7-j));
if(j!=7) Serial.print(F(", "));
}
Serial.println();
}
return regData[_address]; // return requested register value
}
void ADS1299::RREG(byte _address, byte _numRegistersMinusOne) {
byte opcode1 = _RREG + _address; //001rrrrr; _RREG = 00100000 and _address = rrrrr
CStoLOW(); //Low to communicated
SPI.transfer(_SDATAC); //SDATAC
SPI.transfer(opcode1); //RREG
SPI.transfer(_numRegistersMinusOne); //opcode2
for(byte i = 0; i <= _numRegistersMinusOne; i++){
byte data = SPI.transfer(0x00); // returned byte should match default of register map unless previously edited manually (Datasheet, pg.39)
printRegisterName(i);
Serial.print("0x");
if(i<16) Serial.print("0"); //lead with 0 if value is between 0x00-0x0F to ensure 2 digit format
Serial.print(i, HEX);
Serial.print(", ");
Serial.print("0x");
if(data<16) Serial.print("0"); //lead with 0 if value is between 0x00-0x0F to ensure 2 digit format
Serial.print(data, HEX);
Serial.print(", ");
for(byte j = 0; j<8; j++){
Serial.print(bitRead(data, 7-j), BIN);
if(j!=7) Serial.print(", ");
}
Serial.println();
}
SPI.transfer(_RDATAC); //turn read data continuous back on
CStoHIGH(); //High to end communication
}
void ADS1299::WREG(byte _address, byte _value) {
byte opcode1 = _WREG + _address; //001rrrrr; _RREG = 00100000 and _address = rrrrr
CStoLOW(); //Low to communicated
SPI.transfer(_SDATAC); //SDATAC
SPI.transfer(opcode1);
SPI.transfer(0x00);
SPI.transfer(_value);
SPI.transfer(_RDATAC);
CStoHIGH(); //Low to communicated
Serial.print("Register 0x");
Serial.print(_address, HEX);
Serial.println(" modified.");
}
//Register Read/Write Commands
void ADS1299::getID() {
CStoLOW(); //Low to communicated
SPI.transfer(_SDATAC); //SDATAC
SPI.transfer(_RREG); //RREG
SPI.transfer(0x00); //Asking for 1 byte
byte data = SPI.transfer(0x00); // byte to read (hopefully 0b???11110)
SPI.transfer(_RDATAC); //turn read data continuous back on
CStoHIGH(); //Low to communicated
Serial.println(data, BIN);
}
//print out the state of all the control registers
void ADS1299::printAllRegisters(void)
{
boolean wasRunning = false;
boolean prevverbosityState = verbosity;
if (isRunning){ stopADS(); wasRunning = true; }
verbosity = true; // set up for verbosity output
RREG(0x00,0x17); // read out the first registers
// delay(10); // stall to let all that data get read by the PC
// RREGS(0x11,0x17-0x11); // read out the rest
verbosity = prevverbosityState;
if (wasRunning){ startADS(); }
}
// String-Byte converters for RREG and WREG
void ADS1299::printRegisterName(byte _address) {
if(_address == ID){
Serial.print("ID, ");
}
else if(_address == CONFIG1){
Serial.print("CONFIG1, ");
}
else if(_address == CONFIG2){
Serial.print("CONFIG2, ");
}
else if(_address == CONFIG3){
Serial.print("CONFIG3, ");
}
else if(_address == LOFF){
Serial.print("LOFF, ");
}
else if(_address == CH1SET){
Serial.print("CH1SET, ");
}
else if(_address == CH2SET){
Serial.print("CH2SET, ");
}
else if(_address == CH3SET){
Serial.print("CH3SET, ");
}
else if(_address == CH4SET){
Serial.print("CH4SET, ");
}
else if(_address == CH5SET){
Serial.print("CH5SET, ");
}
else if(_address == CH6SET){
Serial.print("CH6SET, ");
}
else if(_address == CH7SET){
Serial.print("CH7SET, ");
}
else if(_address == CH8SET){
Serial.print("CH8SET, ");
}
else if(_address == BIAS_SENSP){
Serial.print("BIAS_SENSP, ");
}
else if(_address == BIAS_SENSN){
Serial.print("BIAS_SENSN, ");
}
else if(_address == LOFF_SENSP){
Serial.print("LOFF_SENSP, ");
}
else if(_address == LOFF_SENSN){
Serial.print("LOFF_SENSN, ");
}
else if(_address == LOFF_FLIP){
Serial.print("LOFF_FLIP, ");
}
else if(_address == LOFF_STATP){
Serial.print("LOFF_STATP, ");
}
else if(_address == LOFF_STATN){
Serial.print("LOFF_STATN, ");
}
else if(_address == GPIO){
Serial.print("GPIO, ");
}
else if(_address == MISC1){
Serial.print("MISC1, ");
}
else if(_address == MISC2){
Serial.print("MISC2, ");
}
else if(_address == CONFIG4){
Serial.print("CONFIG4, ");
}
}
// Used for printing HEX in verbosity feedback mode
void ADS1299::printHex(byte _data){
Serial.print(F("0x"));
if(_data < 0x10) Serial.print(F("0"));
Serial.print(_data, HEX);
}
I use the normal SPI pins exept for CS of ADS -> pin 37
And for SD card I use BUILTIN_SDCARD
Does anyone know what could be the probleme ? I know it might be the SPI communication that must switch between mode 0 and 1 but I do that in my CStoLOW and HIGH function.