cancel
Showing results for 
Search instead for 
Did you mean: 

How to read and write to SD the iis3dwb sensor at maximum rate?

JTLGE
Associate II

Hi,

I'm using the STEVAL-STWINKT1B development board to read the iis3dwb accellerometer and write to the sd as in the HSdatalog example.

To do this I use freertos and fatfs.

I created the project first on CubeMx where I set the parameters to read SPI, write and read from SD and activated the interrupts for the accelerometer pion.

To do this I created 2 threads and used 2 semaphores as shown in the example below.

/* Definitions for defaultTask */

osThreadId_t defaultTaskHandle;

const osThreadAttr_t defaultTask_attributes = {

 .name = "defaultTask",

 .stack_size = 256 * 4,

 .priority = (osPriority_t) osPriorityNormal,

};

/* Definitions for myTask02 */

osThreadId_t myTask02Handle;

const osThreadAttr_t myTask02_attributes = {

 .name = "myTask02",

 .stack_size = 256 * 4,

 .priority = (osPriority_t) osPriorityLow,

};

/* Definitions for myBinarySem01 */

osSemaphoreId_t myBinarySem01Handle;

const osSemaphoreAttr_t myBinarySem01_attributes = {

 .name = "myBinarySem01"

};

/* Definitions for myBinarySem02 */

osSemaphoreId_t myBinarySem02Handle;

const osSemaphoreAttr_t myBinarySem02_attributes = {

 .name = "myBinarySem02"

};

/* USER CODE BEGIN PV */

static uint8_t whoamI;

stmdev_ctx_t dev_ctx;

static uint8_t iis3dwb_mem[256 * 7];

/* USER CODE END PV */

/* USER CODE END Header_StartDefaultTask */

void StartDefaultTask(void *argument)

{

 /* USER CODE BEGIN 5 */

osSemaphoreAcquire(myBinarySem01Handle, osWaitForever);

osSemaphoreAcquire(myBinarySem02Handle, osWaitForever);

/* Initialize mems driver interface */

dev_ctx.write_reg = acc_write;

dev_ctx.read_reg = acc_read;

dev_ctx.handle = &hspi3;

/* Init test platform */

HAl_Delay(1010);

/* Check device ID */

iis3dwb_device_id_get(&dev_ctx, &whoamI);

if (whoamI != IIS3DWB_ID)

while (1){

}

iis3dwb_reset_set(&dev_ctx, 1);

iis3dwb_xl_full_scale_set(&dev_ctx, IIS3DWB_2g);

iis3dwb_xl_data_rate_set(&dev_ctx, IIS3DWB_XL_ODR_26k7Hz);

/*Set fifo in continuous / stream mode*/

iis3dwb_i2c_interface_set(&dev_ctx, IIS3DWB_I2C_DISABLE);

iis3dwb_fifo_mode_set(&dev_ctx, IIS3DWB_STREAM_MODE);

/*Set watermark*/

iis3dwb_fifo_watermark_set(&dev_ctx, 256);

/* FIFO_WTM_IA routing on pin INT1 */

iis3dwb_pin_int1_route_t pin_int1_route;

pin_int1_route.boot=0;

pin_int1_route.drdy_xl=0;

pin_int1_route.fifo_bdr=0;

pin_int1_route.fifo_full=0;

pin_int1_route.fifo_ovr=0;

pin_int1_route.fifo_th=1;

pin_int1_route.sleep_change=0;

pin_int1_route.sleep_status=0;

pin_int1_route.wake_up=0;

iis3dwb_pin_int1_route_set(&dev_ctx, &pin_int1_route);

/*Enable writing to FIFO*/

iis3dwb_fifo_xl_batch_set(&dev_ctx, IIS3DWB_XL_BATCHED_AT_26k7Hz);

/* Infinite loop */

for(;;)

{

osSemaphoreAcquire(myBinarySem01Handle, osWaitForever);

uint16_t val;

iis3dwb_fifo_data_level_get(&dev_ctx, &val)

iis3dwb_read_reg(&dev_ctx, IIS3DWB_FIFO_DATA_OUT_TAG, (uint8_t *)iis3dwb_mem, val * 7);

osSemaphoreRelease(myBinarySem02Handle);

}

 /* USER CODE END 5 */

}

/* USER CODE BEGIN Header_StartTask02 */

/**

 * @brief Function implementing the myTask02 thread.

 * @param argument: Not used

 * @retval None

 */

/* USER CODE END Header_StartTask02 */

void StartTask02(void *argument)

{

 /* USER CODE BEGIN StartTask02 */

FRESULT fres;

uint32_t byteswritten, bytesread; /* File write/read counts */

fres = f_mount(&SDFatFS, (TCHAR const*)SDPath, 1);

/* Infinite loop */

for(;;)

{

osSemaphoreAcquire(myBinarySem02Handle, osWaitForever);

fres = f_open(&SDFile, "TEST.csv", FA_CREATE_ALWAYS | FA_WRITE);

fres = f_write(&SDFile, iis3dwb_mem, strlen((char *)iis3dwb_mem), (void *)&byteswritten);

fres = f_close(&SDFile);

}

 /* USER CODE END StartTask02 */

}

/* USER CODE BEGIN 4 */

/**

 * @brief EXTI line detection callback.

 * @param GPIO_Pin Specifies the port pin connected to corresponding EXTI line.

 * @retval None

 */

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)

{

osSemaphoreRelease(myBinarySem01Handle);

}

4 REPLIES 4

For speed you'd need to be writing large aligned blocks of data, perhaps 8KB or so.

Opening, writing small unaligned sentences, and closing will be incredibly inefficient.​

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
JTLGE
Associate II

Hello,

thank you very much for the help.

in my case using the accelerometer iis3dwb that has an output data rate of 26KHZ and a fifo of 512 words (1 word = 7bytes), the accelerometer raises an interrupt every time the fifo reaches a threshold of 256 words or every (37.5 microseconds X 256 = 9600 microseconds or 9.6 ms).

Having set a clock speed spi of 15 MBits / s should take about 3ms to read the fifo or 256 * 7 * 8 = 14,336 bits.

Before having another interrupt I should have about 8 milliseconds to save 14kbit on the SD.

how can i write bigger words on the sd, i tried not to reopen and close the file every time but it doesn't work (with debug i see that it goes into hard fault)?

how can i synchronize the processes and write on the sd all the data of the accellerometer without losing any data?

Isn't this binary data, surely strlen() is not appropriate ? Data is typically not ASCII, nor comma delimited unless that's how you're generating it.

fres = f_write(&SDFile, iis3dwb_mem, strlen((char *)iis3dwb_mem), (void *)&byteswritten);

>>how can i write bigger words on the sd..

You'd buffer things, perhaps using a spill-buffer, such that all writes are 8KB, and excess is spilled to the front of the next buffer, but at least 512 Bytes.

If you don't do aligned operations the card's going to be doing a lot of reading and writing to accommodate you spanning sectors, and if you're doing single sectors this all gets very slow as there is reasonably significant communications costs.

Time/benchmark what you're doing so you can see the ramifications or small/random vs large/aligned approaches.

>>.. without losing any data?

Well there are significant costs there too, f_close() or f_sync() cause a lot of interaction with the media to flush the file system structures. Doing it for every write will be particularly expensive and cause a lot of wear to the media. Perhaps do so every few seconds.

>>with debug i see that it goes into hard fault

With a half decent Hard Fault Handler you can output diagnostics and understand the exact point of failure very quickly. Tends to flag gross failures, often with errant pointer, buffer overflows, stack corruption, etc.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

thank you very much for the explanation.

Currently I have modified the code in the following way I have a thread that reads how many data are in the fifo of the accelerometer (val) and then I'm going to read them and another thread that goes to write the values of the array on SD, in this case each time I should write with f_write about 300x7 bytes (2kB) .

running it with the debug everything seems to work in fact it returns FR_OK on writing but then when I go to open the file on the sd it returns empty.

To do f_close I use the interrupt of the user button.

stmdev_ctx_t dev_ctx;

uint8_t iis3dwb_mem[512 * 7];

uint16_t val;

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)

{

osSemaphoreAcquire(myBinarySem01Handle, osWaitForever);

osSemaphoreAcquire(myBinarySem02Handle, osWaitForever);

f_close(&SDFile);

}

void StartDefaultTask(void *argument)

{

 /* USER CODE BEGIN 5 */

/* Infinite loop */

osSemaphoreAcquire(myBinarySem01Handle, osWaitForever);

FRESULT fres;

uint32_t byteswritten, bytesread; /* File write/read counts */

fres = f_mount(&SDFatFS, (TCHAR const*)SDPath, 1);

fres = f_open(&SDFile, "TEST.DAT", FA_CREATE_ALWAYS | FA_WRITE);

for(;;)

{

osSemaphoreAcquire(myBinarySem01Handle, osWaitForever);

sprintf(wtext,"%d \n\r",val);

HAL_UART_Transmit(&huart2, wtext, strlen(wtext),HAL_MAX_DELAY);

fres = f_write(&SDFile, iis3dwb_mem, val*7, (void *)&byteswritten);

osSemaphoreRelease(myBinarySem02Handle);

}

 /* USER CODE END 5 */

}

void StartTask02(void *argument)

{

 /* USER CODE BEGIN StartTask02 */

/* Initialize mems driver interface */

uint8_t whoamI;

dev_ctx.write_reg = acc_write;

dev_ctx.read_reg = acc_read;

dev_ctx.handle = &hspi3;

/* Init test platform */

HAL_Delay(1010);

/* Check device ID */

iis3dwb_device_id_get(&dev_ctx, &whoamI);

if (whoamI != IIS3DWB_ID)

while (1){

}

/* Restore default configuration */

iis3dwb_reset_set(&dev_ctx, PROPERTY_ENABLE);

/* Enable Block Data Update */

iis3dwb_block_data_update_set(&dev_ctx, PROPERTY_ENABLE);

/* Set Output Data Rate */

iis3dwb_xl_full_scale_set(&dev_ctx, IIS3DWB_2g);

iis3dwb_xl_data_rate_set(&dev_ctx, IIS3DWB_XL_ODR_26k7Hz);

/*Set fifo in continuous / stream mode*/

iis3dwb_i2c_interface_set(&dev_ctx, IIS3DWB_I2C_DISABLE);

iis3dwb_fifo_mode_set(&dev_ctx, IIS3DWB_STREAM_MODE);

iis3dwb_timestamp_set(&dev_ctx, PROPERTY_ENABLE);

iis3dwb_fifo_timestamp_decimation_set(&dev_ctx,IIS3DWB_DEC_1);

//iis3dwb_xl_filt_path_on_out_set(&dev_ctx, IIS3DWB_LP_ODR_DIV_100);

/*Enable writing to FIFO*/

iis3dwb_fifo_xl_batch_set(&dev_ctx, IIS3DWB_XL_BATCHED_AT_26k7Hz);

/* Infinite loop */

for(;;)

{

osSemaphoreAcquire(myBinarySem02Handle, osWaitForever);

iis3dwb_fifo_data_level_get(&dev_ctx, &val);

//memset(iis3dwb_mem, 0x00, (512*7) * sizeof(uint8_t));

iis3dwb_read_reg(&dev_ctx, IIS3DWB_FIFO_DATA_OUT_TAG, (uint8_t *)iis3dwb_mem, val * 7);

osSemaphoreRelease(myBinarySem01Handle);

}

 /* USER CODE END StartTask02 */

}

now the data that I'm going to write on the SD I do not use strlen() but I pass directly the number of bytes that I read from the accelerometer.

could you suggest me some examples or documentation to learn a better management of write/read operations on SD?