Skip to main content
Associate
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!

 

2 replies

Chris21
Associate II
September 19, 2025

What is your RTOS configTICK_RATE_HZ?

Para033Author
Associate
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.

 

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.Best regards,FBL