7 years, 1 month ago.

High speed data buffering 3k sps to store in sd card

Hello ,

I would like to read my 3-axis sensor data with sampling rate of 3200 sps in to sd card. I am using stm32 M0+ controller with 4 MHz external clock frequency. I tried to log the adxl sensor data directly in to sd card and observed that due to lag in sd card write, am unable to achieve the desired samples. So got to read few articles that write operation to sd card takes nearly 200ms. And in mean time there would be loss of data. Now I had implemented the buffered way of writing like buffer swapping 2 buffers, first one is filled and transfer to other buffer. First buffer is written to sd card when the buffer full flag is raised. I hereby attach the method i had implemented. The problem is that i am unable to achieve the desired samples what would be the reason. Still there are samples missing. With adxl sampling rate 800 i am able to achieve 1188 (each axis is int16_t of xyz axis) samples that means nearly 396 readings of (xyz) are achieved. Could you please provide me the best example or any suggestion how do i read and write the data in to sd card using buffered filling method. Is 4 Mhz external controller frequency enough for achieving 3200 samples? Thank you.

BufferIntialization

// Double buffer 
uint16_t buffer[2][256];
int buf_len= sizeof(buffer[0]) ;
char EMPTY = 0xff ;
char inbuffer = 0 ;
char outbuffer = EMPTY ;
int count = 0 ;

ISR

ISR() 
{
    // Write to current buffer
    read.accelerometer(&buffer[inbuffer][count] );
    count++ ;

    // If buffer full...
    if( count >= buf_len)
    {
        // Signal to loop() that data available (not EMPTY)
        outbuffer = inbuffer ;  

        // Toggle input buffer
        inbuffer = inbuffer == 0 ? 1 : 0 ;
        count = 0 ;
    }
}

Mainloop

void loop() 
{
    // If buffer available...
    if( outbuffer != EMPTY ) 
    {
        // Write buffer
        File.open("test.txt", w);
        for( int i = 0; i < buf_len; i++) 
        {
            File.print(buffer[outbuffer][i]);    
        }
        File.close();

        // Set the buffer to empty
        outbuffer = EMPTY ;
    }
}

1 Answer

7 years, 1 month ago.

I think your code is on the right track. The use of dual buffers is an excellent method. However, the choke point that I see is how you are accessing the SD card and writing the data.

Here is a look at my code that is doing the same thing. I have the SD clock operating at 1MHZ IIRC. That may not be allowable if you are really run the core at 4MHz (really??? - not just the input clock?).

                case cmd_write_buf:
                    if(sdcard){
                        if (file->write(&logBuffer[pingpong][0], sizeof(logBuffer)/2) != (sizeof(logBuffer)/2)) {
                            printf("write error!\n");
                        }
                        else {
                            if (file->fsync()) {
                                printf("sync error!\n");
                            }
                            else pc.printf("Log %d=%dus\n",logCount++,sysTime.read_us()- parm);
                        }
                    }
                    break;

Use "write" and "sync" to move chunks of data. Use an sprintf to an output buffer if you want it in ASCII (which is what I used to do). Then move the sprintf buffer to the SD card via "write". Sync flushes any unwritten data and updates the FAT tables which will guard that the written data is stored immediately in case of power failure.

Bill

Accepted Answer