Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 4 of 4

Thread: ADS1299 SPI with Teensy 4.1 and SD card

  1. #1
    Junior Member
    Join Date
    Oct 2022
    Posts
    4

    ADS1299 SPI with Teensy 4.1 and SD card

    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.

    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.

  2. #2
    Quote Originally Posted by clareto74 View Post
    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.
    You don't have to configure SPI2 to use the SD card. Just use SD.begin(BUILTIN_SDCARD), and then you are ready to open a file to read or write. The code below is from the ReadWrite example for the SD library. See this example.

    Code:
      Serial.print("Initializing SD card...");
    
      if (!SD.begin(chipSelect)) {
        Serial.println("initialization failed!");
        return;
      }
      Serial.println("initialization done.");
      
      // open the file. 
      myFile = SD.open("test.txt", FILE_WRITE);
      
      // if the file opened okay, write to it:
      if (myFile) {
        Serial.print("Writing to test.txt...");
        myFile.println("testing 1, 2, 3.");
    	// close the file:
        myFile.close();
        Serial.println("done.");
      } else {
        // if the file didn't open, print an error:
        Serial.println("error opening test.txt");
      }
      
      // re-open the file for reading:
      myFile = SD.open("test.txt");
      if (myFile) {
        Serial.println("test.txt:");
        
        // read from the file until there's nothing else in it:
        while (myFile.available()) {
        	Serial.write(myFile.read());
        }
        // close the file:
        myFile.close();
      } else {
      	// if the file didn't open, print an error:
        Serial.println("error opening test.txt");
      }

  3. #3
    Junior Member
    Join Date
    Oct 2022
    Posts
    4
    Ok I have managed to write to my SD card, but I have an issue. I am opening and closing my file every time I change the SPI mode communication (CStoHIGH/LOW). I'm guessing every time I put the SD CS pin to HIGH to communicate with the ADS I have to close the file...
    Would it be possible to communicate with the SD module on another SPI bus so I would have to separate SPI communication ?
    Here is the code I modified. I put the changes into comment cause if I run the program for a long time the acquiring rate decrease
    Code:
    void ADS1299::CStoLOW(void)
    {
      //MyFile.close();
      //digitalWrite(SD_SS, HIGH);
      digitalWrite(ADS_SS, LOW);
    }
    
    void ADS1299::CStoHIGH(void)
    {
      digitalWrite(ADS_SS, HIGH);
      //digitalWrite(SD_SS, LOW);
      //MyFile = SD.open(fileName, FILE_WRITE);
    }

  4. #4
    Senior Member
    Join Date
    Feb 2018
    Location
    Corvallis, OR
    Posts
    383
    If you are initializing your SD card with SD.begin(BUILTIN_SDCARD), it will not interfere with the SPI port using pins 10,11,12 and 13. Once you have initialized the SD card and have opened your data file, there is no need to close the file until you are finished collecting your data. Since you're not using SPI for the SD card, you should not be changing the SD_CS pin. You should only be changing the SPI mode if you are using more than one device on the SPI port. If your ADS1299 is the only SPI device, you should be able to set it up once at the start of your program.

    NOTE: if you're going to collect to a single file for a long time (hours to days), you may want to call the sync() function every few minutes or so to update the directory information for the file. This will ensure that you can recover data up the time of the last sync() call if you lose power or trip over a cord and disconnect the system.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •