I'm using ESP8266 at speed of 160 MHz to record ADC results into SD card, I need to do this at rate of 8 KHz. Means that i should save it on the SD Card or i'll run out of memory before 4 Sec passes. I used timer1 to trigger sampling, but my problem is that surprisingly ESP8266 can not do this fast enough and the maximum sampling rate i get is about 7 KHz. I also tried to write data in ESP8266 Flash using littleFS in hope of acceleration but there was no luck. Here is my code:
#include <SPI.h>
#include <SD.h>
File dataFile;
int flag = 0;
int count = 0, level = 0, se_count = 0;
void inline analogReader() // Sampling and Recording processed which is done sequentially :(
{
uint16_t dataByte = (uint16_t) analogRead(A0);
dataFile.write((uint8_t*) &adcBuf, 2);
}
void ICACHE_RAM_ATTR onTimerISR() { // Timer sets the flag every 0.125 MS
flag = 1;
}
void setup() {
pinMode(A0, INPUT);
pinMode(D0, OUTPUT);
Serial.begin(115200);
if (!SD.begin(D0)) {
Serial.println("Card failed, or not present");
// don't do anything more:
return;
}
Serial.println("card initialized.");
File root = SD.open("/");
if (SD.exists("real_test.bin"))
{
SD.remove("real_test.bin");
}
dataFile = SD.open("real_test.bin", FILE_WRITE);
if (dataFile) {
Serial.println("File created!");
}
else
{
Serial.println("Failed to create file!");
return;
}
// Setting the timer so that timer interrupt fires every 0.125 MS
timer1_attachInterrupt(onTimerISR);
timer1_enable(TIM_DIV1/*from 80 Mhz*/, TIM_EDGE/*TIM_LEVEL*/, TIM_LOOP/*TIM_SINGLE*/);
timer1_write(10000); /* ( 80 / 1 ) * 125 */
}
void loop() {
if (flag) // To check whether its time to sampling or not, because of the low speed of the process
{ // The flag is set again before one iteration ends.
flag = 0;
if (se_count < 10)
analogReader();
count++;
if (count == 8000) // When 8000 sample & write process done notify using serial monitor. (it is
always more that 1 Sec. for example 1.3 Sec.)
{
count = 0;
level = !level;
Serial.println(level);
se_count++;
if (se_count == 10) // When we done 8000 * 10 sample & write we close the file. it supposed to
// be done in almost 10 sec. but it takes more time in practice. for
// example 13 Sec.
{
dataFile.close();
Serial.println("Write ended");
}
}
}
}
I even used a faster method system_adc_read_fast(buf, num, clk_div) that is available in ESP-SDK, So i'm desperately seeking for one or two of approaches bellow if possible:
- To use a non-blocking approach: If there is any possibility to hand SD writing to DMA so that i only fill the ADC buffer for DMA, or an interrupt for ADC complete so that i write to SD and when interrupt fired put the result in the buffer and return back to SD writing.
- Yet faster approach for both ADC sampling and writing: Can i increase the SD write speed of SD library? for example by configuring SPI for maximum speed rate.
I also tried SDFat library but it does not recognize my SD Card. The whole process is odd to me that even by using a 160 MHz CPU and hardware i can not record ADC data at rate of 8000 Sample/S. I have TIME limitation so please help me.
Any suggestion is appreciated. Thanks in advance.
loop()
is good. Your lineint flag = 0;
should bevolatile int flag = 0;
. This lets the compiler know thatflag
may change unexpectedly, so it will know to reload it from memory more often. Otherwiseflag
might change and the loop code might miss it because the value is cached in a register.