Skip to main content
Visitor II
September 19, 2025
Question

STM32F401RET6: collecting accelerometer data via USB

  • September 19, 2025
  • 2 replies
  • 315 views

Hello,

I am currently trying to collect acceleration data at 16 kHz from a USB accelerometer using an STM32F401RET6 in USB Host mode.
I created two tasks: vUSBInitTask and vUSBReadTask as shown below.

 

void vUSBInitTask(void *pvParameters)
{
 MX_USB_HOST_Init();
 for (;;)
 {
 MX_USB_HOST_Process();
 vTaskDelay(pdMS_TO_TICKS(10));
 }
}

void vUSBReadTask(void *pvParameters)
{
 AUDIO_HandleTypeDef *audio_handle;
 uint8_t *buf;
 char msg[64];

 static int32_t sample_buffer[SAMPLES_TO_SAVE];
 int collected_samples = 0;

 while (Appli_state != APPLICATION_READY) // wait until USB is ready
 {
 vPrintString("Waiting for USB ready...\r\n");
 vTaskDelay(pdMS_TO_TICKS(500));
 }

 for (;;)
 {
 audio_handle = (AUDIO_HandleTypeDef *)hUsbHostFS.pActiveClass->pData;

 if (audio_handle && audio_handle->microphone.supported) {
 buf = audio_handle->microphone.buf;

 if (buf) {
 USBH_StatusTypeDef status = USBH_IsocReceiveData(&hUsbHostFS,
 buf,
 audio_handle->microphone.frame_length,
 audio_handle->microphone.Pipe);
 if (status == USBH_OK) {
 int frames_in_buf = audio_handle->microphone.frame_length / FRAME_SIZE;

 for (int i = 0; i < frames_in_buf; i += DOWNSAMPLE_FACTOR)
 {
 if (collected_samples < SAMPLES_TO_SAVE)
 {
 int32_t sample_val = convert24bitToInt32(&buf[i * FRAME_SIZE]);
 sample_buffer[collected_samples++] = sample_val;
 }

 if (collected_samples >= SAMPLES_TO_SAVE) {
 for (int i = 0; i < SAMPLES_TO_SAVE; i++) {
 float sample_val = (float)sample_buffer[i] * SCALE_FACTOR;
 uint8_t packet[6]; // header 2 + float 4
 packet[0] = 0xAA;
 packet[1] = 0x55;
 memcpy(&packet[2], &sample_val, sizeof(float));
 HAL_UART_Transmit(&huart2, packet, sizeof(packet), HAL_MAX_DELAY);
 }
 collected_samples = 0;
 }
 }
 }
 }
 }
 vTaskDelay(pdMS_TO_TICKS(10));
 }
}

 

Below is my main.c initialization (simplified):

int main(void)
{
 HAL_Init();
 SystemClock_Config();
 MX_GPIO_Init();
 MX_USART2_UART_Init();

 const char *boot = "[BOOT] UART ready\r\n";
 HAL_UART_Transmit(&huart2, (uint8_t*)boot, strlen(boot), 100);

 MX_I2C1_Init();
 lcd_init();

 xBinarySemaphore = xSemaphoreCreateBinary();
 if (xBinarySemaphore != NULL) {
 xTaskCreate(vUSBInitTask, "USB Task", 512, NULL, 1, NULL);
 xTaskCreate(vUSBReadTask, "USBRead", 1024, NULL, 2, NULL);

 vTaskStartScheduler();
 }

 while (1) {
 // MX_USB_HOST_Process();
 }
}

The problem:

  • With vTaskDelay(pdMS_TO_TICKS(10)) inside vUSBReadTask, the actual sampling rate is only ~1600 Hz, far below the target 16 kHz.

  • When I change it to pdMS_TO_TICKS(5), I only get repeated identical data values.

  • When I change it to pdMS_TO_TICKS(1), I only get a single sample.

So it seems that the sampling rate strongly depends on the task delay, and the behavior becomes inconsistent.

If anyone has experience with USB Audio Class accelerometers on STM32 (especially STM32F4 series), could you please help me understand the root cause of this issue? Is it a problem with how I am handling isochronous transfers, buffering, or scheduling in FreeRTOS?

Any advice or guidance would be greatly appreciated. Thank you so much!

 

    This topic has been closed for replies.

    2 replies

    Graduate
    September 19, 2025

    What is your RTOS configTICK_RATE_HZ?

    Para033Author
    Visitor II
    September 20, 2025

    It is 1000

    Technical Moderator
    October 1, 2025

    Hi @Para033 

    Did you follow recommendations provided in the article How to configure USB FIFO over USB OTG controller.