ADC writing to SD card strange issue - help please

Polly

Member
Hello,

I am writing a code that monitors a pin (which is attached to a signal generator) using the ADC i am using the ADC library written by pedvide and am using a Teensy 4.1. The code then writes the signal to a .csv file on an SD card.

I need this to happen as fast as the Teensy can manage as I am trying to recording ultrasound upto about 350kHz. What I am seeing (and will include below) is that it doesn't seem to be using the 10bit range and is cutting the signal up into steps which are effect y-axis resolution. Each of these steps is sampled either 16 or 17 times and then the next point is sampled. On the lower frequency signals (10kHz I know this isn't ultrasound frequency I just needed to sanity check a few things) the sine wave is coming out fairly smooth but as I move faster (50kHz and 100kHz) it becomes more and more prone to the stepping effect (which makes sense).

My question is why is this stepping occuring and what could I try to make the signals recorded smoother. Code is below, along with some pictures of the graphs I can create afterwards, I can't upload my result files (these are .csv, but I have changed the extension to .txt and .xls and neither will upload so I think that might be due to file size for some reason?

Many thanks

Polly

My code:
Code:
#include <Wire.h>
#include <TimeLib.h>
#include <SPI.h>
#include <SD.h>
#include <ADC.h>
#include <ADC_util.h>
#include <ADC_Module.h>

const int BuffSize = 110000;
int value[BuffSize]; 

ADC *adc = new ADC(); 

void setup()
{
    pinMode(16, INPUT_DISABLE); 
    pinMode (A2, INPUT); 
    
    Serial.begin(9600);

    adc->adc1->setReference(ADC_REFERENCE::REF_3V3);
    adc->adc1->enableInterrupts(adc1_isr);
    adc->adc1->setAveraging(1); // set number of averages
    adc->adc1->setResolution(10); // set bits of resolution
    adc->adc1->setConversionSpeed(ADC_CONVERSION_SPEED::HIGH_SPEED); // change the conversion speed
    adc->adc1->setSamplingSpeed(ADC_SAMPLING_SPEED::VERY_HIGH_SPEED); // change the sampling speed
    adc->adc1->startContinuous(A2);
    
    !SD.begin(BUILTIN_SDCARD);
  
}

void loop()
{
  for(int i=0; i<BuffSize;i++)
  {
  value[i] = (uint16_t)adc->adc1->analogReadContinuous();
  }
   
  //Open a file and write to it. 
  File dataFile = SD.open("File001.csv", FILE_WRITE); // *** name is in 8.3 format *** add date to this some how, perhaps make it automatic??
  if (dataFile)
  {
    for(int i=0; i<BuffSize;i++)
    {
    dataFile.print(micros()); // i added this after to check it was reading at different time points and not just writing the same time point over and over again
    dataFile.print(",");
    dataFile.println(value[i]);
    }
    dataFile.close(); //Data isn't actually written until we close the connection!
    }
   else{} 
   delay(0.1);
}

void adc1_isr(void) {
    adc->adc1->analogReadContinuous();
    }

10kHzsinefirst10000samples.jpg
50kHzsinefirst10000samples.jpg
100kHzsinefirst10000samples.jpg
 
I think your problem is that the foreground loop that is storing the ADC values is running much faster than the ADC is converting. analogReadContinuous is a very short inline function that simply returns the value in the ADC data register. When the ADC is converting continuously, it will take longer to read and convert the value than it does to simply read the result register in your foreground loop.

You have two options:

1. Don't bother with the interrupts and in your foreground loop wait for a new conversion to occur :
Code:
for(int i=0; i< BuffSize; i++){
while( !adc->adc1->isComplete()){};   // wait until a new conversion is complete
value[i] = idc->adc1->analogReadSingle() ;    // like analogReadContinuous, just reads the result register
} // end of for loop

2. Put the data collection into the background and have it collected in the interrupt handler. This is often done when you need to collect continuously in the background and write the results in the foreground. To get the foreground loop to write to SD as fast as you are collecting may require writing binary data records. I think there are some sample programs in the forum using that technique. Search for a thread "1MSPS on a T4"

There's a lot of issues to consider if you want to collect 12-bit data at high rates. The "1 MSPS" thread covers many of them with a lot of sample code.
 
Hi, Thank you for your help! I am working through all the 1 MSPS thread at the moment. I will do a proper reply when I have it all working. Thank you so much I have been struggling with this for ages now. Polly
 
Back
Top