I'm try to interface the three components in the title to make a data-logger capable of sampling physiological signals directly. To minimise the number of connections, the ADC and the SD card are to share the SPI bus. The problem I've encountered is that if I initialise and setup the files on the SD card first, then access the ADC and then write the data to the card I get an error during the sd.card()->writeData(pCache) stage (see snippets below). When I then plug the card into my computer and check file contents, it's full of garbage, i.e. the file is filled with ˇ characters (exactly 512 of these). I tested the ADC+Teensy and SD+Teensy (with sdfatlib) separately and they work as expected. I tried tracing the error and it seems like the card doesn't respond with the correct code after the data is sent, m_status in Sd2Card::writeData stays at 0xFF. I also checked the activity on the MOSI pin and I can see that something is being sent to the SD card.
From what I've found so far one cannot access SPI bus during multiple block write (http://forum.arduino.cc/index.php?topic=50010.0). My assumption is that what's meant is that when the data is actually being sent to the SD card one cannot access SPI bus, which is fine, but then another interpretation is that one cannot access SPI bus between sd.card()->writeStart() and sd.card()->writeStop() commands. So which one is correct? If the latter is correct is software SPI for ADC the only way forward?
Components used:
Teensy 3.1
ADS1294
Swissbit 1GB microSD card (http://www.mouser.com/ds/2/615/S-200u_data_sheet_SD-NxBN_Rev110-263222.pdf)
The connections between the components are as follows:
ADC connections to Teensy
ADC MOSI -> pin 11 Teensy
ADC MISO -> pin 12 Teensy
ADC SCK -> pin 13 Teensy
ADC SS -> pin 10 Teensy
ADC PWDN -> pin 2 Teensy
ADC RESET -> pin 3 Teensy
ADC START -> pin 4 Teensy
ADC DRDY -> pin 5 Teensy
ADC CLKSEL -> pin 6 Teensy
SD card connections to Teensy
SD MOSI -> pin 11 Teensy
SD MISO -> pin 12 Teensy
SD SCK -> pin 13 Teensy
SD SS -> pin 9 Teensy
The exact sequence of steps I'm following is below:
Basically if I do steps 3 and 6 one after another, then everything works as expected and I don't get any errors, but as soon as I try to access ADC in between those steps I get the write error.
I tried running this procedure on a setup without the ADC, i.e. just an SD card connected to Teensy and it still throws the same error (I had to modify the adcSetup() function to not read ID register at the end). So running the SDSetup(), then sending some data through the SPI (albeit to a non-existent, not connected module) and then finally writing dummy data to the SD card fails.
Here's the setup() function and all the relevant code snippets:
Code for adcSetup() function which runs successfully:
Code for SDsetup() function:
Code for sendSDdata (bool dummy) function which throws error 6:
I don't fully understand the SD card operation and that's the most likely reason my setup doesn't work, so I'd really appreciate if someone could point out any problems with this setup and the sequence of steps I'm following.
From what I've found so far one cannot access SPI bus during multiple block write (http://forum.arduino.cc/index.php?topic=50010.0). My assumption is that what's meant is that when the data is actually being sent to the SD card one cannot access SPI bus, which is fine, but then another interpretation is that one cannot access SPI bus between sd.card()->writeStart() and sd.card()->writeStop() commands. So which one is correct? If the latter is correct is software SPI for ADC the only way forward?
Components used:
Teensy 3.1
ADS1294
Swissbit 1GB microSD card (http://www.mouser.com/ds/2/615/S-200u_data_sheet_SD-NxBN_Rev110-263222.pdf)
The connections between the components are as follows:
ADC connections to Teensy
ADC MOSI -> pin 11 Teensy
ADC MISO -> pin 12 Teensy
ADC SCK -> pin 13 Teensy
ADC SS -> pin 10 Teensy
ADC PWDN -> pin 2 Teensy
ADC RESET -> pin 3 Teensy
ADC START -> pin 4 Teensy
ADC DRDY -> pin 5 Teensy
ADC CLKSEL -> pin 6 Teensy
SD card connections to Teensy
SD MOSI -> pin 11 Teensy
SD MISO -> pin 12 Teensy
SD SCK -> pin 13 Teensy
SD SS -> pin 9 Teensy
The exact sequence of steps I'm following is below:
- Initialise standard SPI.
- Initialise ADC by first sending SDATAC command to stop continuous data output, then writing to the configuration registers and finally getting the ID of the ADC indicating number of channels.
- Initialise SD card, create contiguous file, get its range, erase, setup buffer and write start.
- Change SPI mode to MODE1, since SD card uses MODE0 while ADC uses MODE1.
- Repeat ADC initialisation.
- Send 512 byte block of dummy data to the card and write stop.
Basically if I do steps 3 and 6 one after another, then everything works as expected and I don't get any errors, but as soon as I try to access ADC in between those steps I get the write error.
I tried running this procedure on a setup without the ADC, i.e. just an SD card connected to Teensy and it still throws the same error (I had to modify the adcSetup() function to not read ID register at the end). So running the SDSetup(), then sending some data through the SPI (albeit to a non-existent, not connected module) and then finally writing dummy data to the SD card fails.
Here's the setup() function and all the relevant code snippets:
Code:
void setup()
{
using namespace ADS1298;
// Setup I/O pins
pinMode(IPIN_DRDY, INPUT);
pinMode(IPIN_CS, OUTPUT);
pinMode(chipSelect, OUTPUT);
pinMode(PIN_START, OUTPUT);
pinMode(PIN_CLKSEL, OUTPUT);
pinMode(IPIN_RESET, OUTPUT);
pinMode(IPIN_PWDN, OUTPUT);
// Set output pins to safe defaults
digitalWrite(PIN_START, LOW);
digitalWrite(IPIN_CS, HIGH);
digitalWrite(chipSelect, HIGH);
// Start serial port
Serial.begin(115200);
while (Serial.read() >= 0) {} //http://forum.arduino.cc/index.php?topic=134847.0
// Start Arduino SPI to interface with ADC
SPI.begin();
SPI.setBitOrder(MSBFIRST);
SPI.setClockDivider(SPI_CLOCK_DIV2); //http://forum.pjrc.com/threads/1156-Teensy-3-SPI-Basic-Clock-Questions
SPI.setDataMode(SPI_MODE1);
// Setup ADC
uint8_t gMaxChan = adcSetup();
// If ADC is not detected print "ADC Error" every 1 s to the serial terminal
if (gMaxChan == 0) {
while(1) {
Serial.println("ADC Error");
delay(1000);
}
}
Serial.print("ADC detected has ");
Serial.print(gMaxChan);
Serial.print(" channels\n");
// Setup SD card and print error # if setup fails
SDSetup();
Serial.print("error is ");
Serial.print(error);
Serial.print("\n");
// Change SPI mode to MODE1 since that's the mode used by ADC
SPI.setDataMode(SPI_MODE1);
// Setup ADC
gMaxChan = adcSetup();
// If ADC is not detected print "ADC Error" every 1 s to the serial terminal
if (gMaxChan == 0) {
while(1) {
Serial.println("ADC Error");
delay(1000);
}
}
Serial.print("ADC detected has ");
Serial.print(gMaxChan);
Serial.print(" channels\n");
// Send dummy data to the SD card and print error # if it fails
sendSDdata(true);
Serial.print("error is ");
Serial.print(error);
Serial.print("\n");
}
Code for adcSetup() function which runs successfully:
Code:
uint8_t adcSetup()
{
using namespace ADS1298;
// Power-up sequence for ADS129x
digitalWrite(IPIN_PWDN, LOW);
digitalWrite(PIN_CLKSEL, HIGH);
digitalWrite(IPIN_PWDN, HIGH);
digitalWrite(IPIN_RESET, HIGH);
delay(1000);
digitalWrite(IPIN_RESET, LOW);
delayMicroseconds(1);
digitalWrite(IPIN_RESET, HIGH);
delayMicroseconds(9);
adc_send_command(SDATAC);
delayMicroseconds(5);
// FOR RLD: Power up the internal reference
adc_wreg(CONFIG3, RLDREF_INT | PD_RLD | PD_REFBUF | CONFIG3_const);
// Only use channels IN1P and IN1N for the RLD Measurement
adc_wreg(RLD_SENSP, 0x01);
adc_wreg(RLD_SENSN, 0x01);
// All GPIO set to output 0x0000: (floating CMOS inputs can flicker on and off, creating noise)
adc_wreg(GPIO, 0x00);
// Set ADC to work at high resolution 1 KS/s sampling rate
adc_wreg(CONFIG1, HIGH_RES_1k_SPS);
// Generate internal test signal
adc_wreg(CONFIG2, INT_TEST);
// Set the first channel as differential input with x12 gain
adc_wreg(CH1SET, ELECTRODE_INPUT | GAIN_12X);
// adc_wreg(CH1SET, TEST_SIGNAL | GAIN_12X); //create square wave
// Power down and short all the rest of the channels since they aren't used
for (int i = 2; i <= 4; i++) {
adc_wreg(CHnSET + i, PDn | SHORTED);
}
// Get ADC ID
int IDval = adc_rreg(ID) ;
switch (IDval & B00011111 ) { //5 least significant bits report channels
case B10000:
return 4; //ADS1294
break;
case B10001:
return 6; //ADS1296
break;
case B10010:
return 8; //ADS1298
break;
case B11110:
return 8; //ADS1299
break;
default:
return 0;
}
}
Code for SDsetup() function:
Code:
void SDSetup()
{
if (!sd.begin(chipSelect, SPI_FULL_SPEED)) {
error = 1;
sd.initErrorHalt();
}
// Delete possible existing file
sd.remove("RAW.TXT");
// Create a contiguous file
if (!file.createContiguous(sd.vwd(), "RAW.TXT", CACHE_SIZE*BLOCK_COUNT)) error = 2;
// Set the location of the file's blocks
if (!file.contiguousRange(&bgnBlock, &endBlock)) error = 3;
file.close();
// memset(pCache, '-', CACHE_SIZE);
// Tell card to setup for multiple block write with pre-erase
if (!sd.card()->erase(bgnBlock, endBlock)) error = 4;
pCache = (uint8_t*)sd.vol()->cacheClear();
if (!sd.card()->writeStart(bgnBlock, BLOCK_COUNT)) error = 5;
}
Code for sendSDdata (bool dummy) function which throws error 6:
Code:
void sendSDdata(bool dummy)
{
if (dummy) {
// Populate cache with dummy data
uint32_t adc_dat = 4276803;
for (int iii = 1; iii < 511; iii += 6) {
pCache[iii - 1] = adc_dat;
pCache[iii] = adc_dat >> 8;
pCache[iii + 1] = adc_dat >> 16;
pCache[iii + 2] = 'X';
pCache[iii + 3] = '\r';
pCache[iii + 4] = '\n';
}
for (int iii = 1; iii < 511; iii += 6) {
Serial.print(pCache[iii - 1], DEC);
Serial.print(",");
Serial.print(pCache[iii], DEC);
Serial.print(",");
Serial.print(pCache[iii + 1], DEC);
Serial.print(",");
Serial.print(pCache[iii + 2], DEC);
Serial.print(",");
Serial.print(pCache[iii + 3], DEC);
Serial.print(",");
Serial.print(pCache[iii + 4], DEC);
Serial.print("\n");
}
}
// Send data to the SD card and measure latency
uint32_t tw = micros();
if (!sd.card()->writeData(pCache)) error = 6;
tw = micros() - tw;
delay(1000);
if (!sd.card()->writeStop()) error = 7;
// file.close();
latency[block_count-1] = tw;
}
I don't fully understand the SD card operation and that's the most likely reason my setup doesn't work, so I'd really appreciate if someone could point out any problems with this setup and the sequence of steps I'm following.
Last edited: