2026-03-10 7:49 PM - last edited on 2026-03-11 12:57 AM by mƎALLEm
Hi Forum!
----------------------------------------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/** Usb HID report descriptor. */
__ALIGN_BEGIN static uint8_t CUSTOM_HID_ReportDesc_FS[USBD_CUSTOM_HID_REPORT_DESC_SIZE] __ALIGN_END =
{
/* USER CODE BEGIN 0 */
0x06,0xFF,0x00, // USAGE_PAGE (Vendor Page: 0xFF00)
0x09,0x01, // USAGE (Vendor Usage 1)
0xA1,0x01, // COLLECTION (Application)
0x15,0x00, // LOGICAL_MINIMUM (0)
0x26,0xFF,0x00, // LOGICAL_MAXIMUM (255)
0x75,0x08, // REPORT_SIZE (8)
0x95,0x40, // REPORT_COUNT (64)
0x09,0x02, // USAGE (Vendor Usage 2)
0x81,0x02, // INPUT (Data,Var,Abs)
0x09,0x03, // USAGE (Vendor Usage 3)
0x91,0x02, // OUTPUT (Data,Var,Abs)
0x0A,0x00,0xFF, // UsageS(0xFF00)
0x0B1,0x02,
/* USER CODE END 0 */
0xC0 /* END_COLLECTION */
};
#define USBD_CUSTOMHID_OUTREPORT_BUF_SIZE 64
/*---------- -----------*/
#define USBD_CUSTOM_HID_REPORT_DESC_SIZE 30
#define CUSTOM_HID_EPIN_ADDR 0x81U
#endif /* CUSTOM_HID_EPIN_ADDR */
#ifndef CUSTOM_HID_EPIN_SIZE
#define CUSTOM_HID_EPIN_SIZE 0x40//0x02U
#endif /* CUSTOM_HID_EPIN_SIZE */
#ifndef CUSTOM_HID_EPOUT_ADDR
#define CUSTOM_HID_EPOUT_ADDR 0x02U//0x01U
#endif /* CUSTOM_HID_EPOUT_ADDR */
#ifndef CUSTOM_HID_EPOUT_SIZE
#define CUSTOM_HID_EPOUT_SIZE 0x40//0x02U
//add variable
/* USER CODE BEGIN INCLUDE */
extern uint8_t report_buffer[64];
extern uint8_t volatile flag_rx;
/* USER CODE END INCLUDE */
//modify the custom hid outevnet fs
static int8_t CUSTOM_HID_OutEvent_FS(uint8_t event_idx, uint8_t state)
{
/* USER CODE BEGIN 6 */
USBD_CUSTOM_HID_HandleTypeDef *hhid = (USBD_CUSTOM_HID_HandleTypeDef *)hUsbDeviceFS.pClassData;
memcpy(report_buffer, hhid->Report_buf, 64);
flag_rx = 1;
return (USBD_OK);
/* USER CODE END 6 */
}
/* USER CODE BEGIN Includes */
#include "usbd_customhid.h"
#include "string.h"
#include "bno055_stm32.h"
/* USER CODE END Includes */
/* USER CODE BEGIN PM */
uint8_t tx_buffer[64];
uint8_t report_buffer[64];
uint8_t volatile flag_rx = 0;
extern USBD_HandleTypeDef hUsbDeviceFS;
int32_t data_to_send[4];
/* USER CODE END PM */
/* USER CODE BEGIN 2 */
HAL_Delay(2000);
bno055_assignI2C(&hi2c1);
bno055_setup();
bno055_setOperationModeNDOF();
/* USER CODE END 2 */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if(flag_rx==1)
{
report_buffer[63] = '\0';
flag_rx=0;
char cmd[10];
int duty=0;
if(sscanf((char*)report_buffer,"%s %d",cmd,&duty)==2)
{
HAL_Delay(2);
if(strcmp(cmd,"LM3435")==0)
{
sprintf((char*)tx_buffer, "OK! Duty set to %d", duty);
USBD_CUSTOM_HID_SendReport(&hUsbDeviceFS, tx_buffer, 64);
}
}
memset(report_buffer,0,64);
}
USBD_CUSTOM_HID_HandleTypeDef *hhid = (USBD_CUSTOM_HID_HandleTypeDef*)hUsbDeviceFS.pClassData;
if (hhid->state == CUSTOM_HID_IDLE)
{
bno055_vector_t v = bno055_getVectorQuaternion();
data_to_send[0] = (int32_t)(v.w * 1000000);
data_to_send[1] = (int32_t)(v.x * 1000000);
data_to_send[2] = (int32_t)(v.y * 1000000);
data_to_send[3] = (int32_t)(v.z * 1000000);
memset(tx_buffer, 0, 64);
memcpy(tx_buffer, data_to_send, sizeof(data_to_send));
USBD_CUSTOM_HID_SendReport(&hUsbDeviceFS, tx_buffer, 64);
}
HAL_Delay(10); // BNO055 100Hz,
}
/* USER CODE END 3 */
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Result:
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Reference:
1. micro lib to solve the LDR R0, =SystemInit
https://community.st.com/t5/stm32-mcus-products/stm32f4-random-hard-faults-solved/td-p/516713
2. how to use Custom hid 1
https://blog.csdn.net/qq_36347513/article/details/127694257
3. how to use Custom hid 2
https://lungtenghsu.blogspot.com/2024/11/stm32usb-custom-hid.html
4. HID Learning
https://www.youtube.com/watch?v=umkD1piCNvc
5.BNO055 Library
https://github.com/ivyknob/bno055_stm32
6. MATA OCULUS Tracking
https://msl.cs.illinois.edu/~lavalle/papers/LavYerKatAnt14.pdf
Solved! Go to Solution.
2026-04-21 6:14 PM
Hi
After some testing,
The problem is from function "USBD_CUSTOM_HID_DataOut()"
static uint8_t USBD_CUSTOM_HID_DataOut(...)
{
// ... callback after
return (uint8_t)USBD_OK;
// did not called, USBD_CUSTOM_HID_ReceivePacket()!
// OUT endpoint will not preprare to receive the new data
// the second data send from host, stm will lock in NAK
// SimpleHIDWrite timeout ->software crash
}
I found the problem that I forget to add this
static uint8_t USBD_CUSTOM_HID_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum)
{
UNUSED(epnum);
USBD_CUSTOM_HID_HandleTypeDef *hhid;
if (pdev->pClassDataCmsit[pdev->classId] == NULL)
{
return (uint8_t)USBD_FAIL;
}
hhid = (USBD_CUSTOM_HID_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId];
#ifdef USBD_CUSTOMHID_REPORT_BUFFER_EVENT_ENABLED
((USBD_CUSTOM_HID_ItfTypeDef *)pdev->pUserData[pdev->classId])->OutEvent(hhid->Report_buf);
#else
((USBD_CUSTOM_HID_ItfTypeDef *)pdev->pUserData[pdev->classId])->OutEvent(hhid->Report_buf[0],
hhid->Report_buf[1]);
#endif
/* add this line */
(void)USBD_CUSTOM_HID_ReceivePacket(pdev);
return (uint8_t)USBD_OK;
}
1.This file is not in user code part (this is STM32 HAL middleware), if CUBEMX re-generate, these code will be overwritten.
2.After this step, I can receive and transmit the data from BNO055 to STM32 and get these data via USB HID.
-------------------------------------------------------------
the main part
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
if (flag_rx == 1)
{
flag_rx = 0;
char cmd[16] = {0};
int duty = 0;
if (sscanf((char*)report_buffer, "%15s %d", cmd, &duty) == 2)
{
if (strcmp(cmd, "LM3435") == 0)
{
memset(tx_buffer, 0, 64);
snprintf((char*)tx_buffer, 64, "OK! Duty set to %d", duty);
HID_SafeSend(tx_buffer, 64);
}
}
memset(report_buffer, 0, 64);
}
bno055_vector_t v = bno055_getVectorQuaternion();
int32_t data_to_send[4];
data_to_send[0] = (int32_t)(v.w * 1000000);
data_to_send[1] = (int32_t)(v.x * 1000000);
data_to_send[2] = (int32_t)(v.y * 1000000);
data_to_send[3] = (int32_t)(v.z * 1000000);
memset(tx_buffer, 0, 64);
memcpy(tx_buffer, data_to_send, 16);
HID_SafeSend(tx_buffer, 64);
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_0);//testing that if loop is still on-work or broken
HAL_Delay(10);
}
/* USER CODE END 3 */
/********************************/
/* USER CODE BEGIN 4 */
uint8_t HID_SafeSend(uint8_t *buf, uint16_t len)
{
USBD_CUSTOM_HID_HandleTypeDef *hhid =
(USBD_CUSTOM_HID_HandleTypeDef*)hUsbDeviceFS.pClassData;
uint32_t tick = HAL_GetTick();
while (hhid->state != CUSTOM_HID_IDLE)
{
if ((HAL_GetTick() - tick) > 10)
{
return USBD_FAIL; //
}
}
return USBD_CUSTOM_HID_SendReport(&hUsbDeviceFS, buf, len);
}
/* USER CODE END 4 */
Thank you
Best Regard Steve
2026-03-11 3:49 AM
Hi @steve feng
I assume the descriptor you posted in CUSTOM_HID_ReportDesc_FS has an issue with
0x0B1,0x02,
0x0B1 is not a valid hex byte; and if you meant 0xB1, it’s still not valid in this context and will corrupt the descriptor parse in the host HID stack. Then instead of hard coded size to 30, set
#define USBD_CUSTOM_HID_REPORT_DESC_SIZE (sizeof(CUSTOM_HID_ReportDesc_FS))
The issue seems endpoint / report descriptor mismatch.
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.
2026-03-11 3:25 PM - edited 2026-03-11 3:26 PM
@steve feng While NotebookLM and other AI tricks are cool, a real human may be still a better locomotive to success.
You can find helping hands for your project here; and use AI to formulate the tasks.
2026-03-17 1:34 AM - edited 2026-03-17 1:36 AM
Hi FBL
Thank you for advice, I try to correct my code.
0xB1,0x02, //orginal 0x0B1,0x02,the result is as as previous experiments, when the second time, host sending the data to EVK, the SimpleHIDWrite exe will be crash.
2026-04-21 6:14 PM
Hi
After some testing,
The problem is from function "USBD_CUSTOM_HID_DataOut()"
static uint8_t USBD_CUSTOM_HID_DataOut(...)
{
// ... callback after
return (uint8_t)USBD_OK;
// did not called, USBD_CUSTOM_HID_ReceivePacket()!
// OUT endpoint will not preprare to receive the new data
// the second data send from host, stm will lock in NAK
// SimpleHIDWrite timeout ->software crash
}
I found the problem that I forget to add this
static uint8_t USBD_CUSTOM_HID_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum)
{
UNUSED(epnum);
USBD_CUSTOM_HID_HandleTypeDef *hhid;
if (pdev->pClassDataCmsit[pdev->classId] == NULL)
{
return (uint8_t)USBD_FAIL;
}
hhid = (USBD_CUSTOM_HID_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId];
#ifdef USBD_CUSTOMHID_REPORT_BUFFER_EVENT_ENABLED
((USBD_CUSTOM_HID_ItfTypeDef *)pdev->pUserData[pdev->classId])->OutEvent(hhid->Report_buf);
#else
((USBD_CUSTOM_HID_ItfTypeDef *)pdev->pUserData[pdev->classId])->OutEvent(hhid->Report_buf[0],
hhid->Report_buf[1]);
#endif
/* add this line */
(void)USBD_CUSTOM_HID_ReceivePacket(pdev);
return (uint8_t)USBD_OK;
}
1.This file is not in user code part (this is STM32 HAL middleware), if CUBEMX re-generate, these code will be overwritten.
2.After this step, I can receive and transmit the data from BNO055 to STM32 and get these data via USB HID.
-------------------------------------------------------------
the main part
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
if (flag_rx == 1)
{
flag_rx = 0;
char cmd[16] = {0};
int duty = 0;
if (sscanf((char*)report_buffer, "%15s %d", cmd, &duty) == 2)
{
if (strcmp(cmd, "LM3435") == 0)
{
memset(tx_buffer, 0, 64);
snprintf((char*)tx_buffer, 64, "OK! Duty set to %d", duty);
HID_SafeSend(tx_buffer, 64);
}
}
memset(report_buffer, 0, 64);
}
bno055_vector_t v = bno055_getVectorQuaternion();
int32_t data_to_send[4];
data_to_send[0] = (int32_t)(v.w * 1000000);
data_to_send[1] = (int32_t)(v.x * 1000000);
data_to_send[2] = (int32_t)(v.y * 1000000);
data_to_send[3] = (int32_t)(v.z * 1000000);
memset(tx_buffer, 0, 64);
memcpy(tx_buffer, data_to_send, 16);
HID_SafeSend(tx_buffer, 64);
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_0);//testing that if loop is still on-work or broken
HAL_Delay(10);
}
/* USER CODE END 3 */
/********************************/
/* USER CODE BEGIN 4 */
uint8_t HID_SafeSend(uint8_t *buf, uint16_t len)
{
USBD_CUSTOM_HID_HandleTypeDef *hhid =
(USBD_CUSTOM_HID_HandleTypeDef*)hUsbDeviceFS.pClassData;
uint32_t tick = HAL_GetTick();
while (hhid->state != CUSTOM_HID_IDLE)
{
if ((HAL_GetTick() - tick) > 10)
{
return USBD_FAIL; //
}
}
return USBD_CUSTOM_HID_SendReport(&hUsbDeviceFS, buf, len);
}
/* USER CODE END 4 */
Thank you
Best Regard Steve