Problem between '_ux_device_class_hid_receiver_thread(ULONG hid_instance)' and CDC ACM application
Platform: STM32U575AIIQ-EV Board
Modules: USBX, ThreadX, HID Custom, CDC ACM Virtual Com
Purpose: Using stm32u575 as a device to report data to host(PC), receive data from host, and print logs as a virtual COM.
Summary: The functions of reporting data to host, receiving data from host and print logs as a virtual COM have been realized. But if i send a packet from host to device, the virtual COM is killed.
Analysis:
- The following code is the function of CDC ACM activation:
VOID USBD_CDC_ACM_Activate(VOID *cdc_acm_instance)
{
/* USER CODE BEGIN USBD_CDC_ACM_Activate */
/* Save the CDC instance */
cdc_acm_user = (UX_SLAVE_CLASS_CDC_ACM*) cdc_acm_instance;
/* Configure the UART peripheral */
USBX_APP_UART_Init(&uart_handler);
/* Get default UART parameters */
CDC_VCP_LineCoding.ux_slave_class_cdc_acm_parameter_baudrate = uart_handler->Init.BaudRate;
/* Set the UART data type : only 8bits and 9bits are supported */
switch (uart_handler->Init.WordLength)
{
case UART_WORDLENGTH_8B:
{
/* Set UART data bit to 8 */
CDC_VCP_LineCoding.ux_slave_class_cdc_acm_parameter_data_bit = VCP_WORDLENGTH8;
break;
}
case UART_WORDLENGTH_9B:
{
/* Set UART data bit to 9 */
CDC_VCP_LineCoding.ux_slave_class_cdc_acm_parameter_data_bit = VCP_WORDLENGTH9;
break;
}
default :
{
/* By default set UART data bit to 8 */
CDC_VCP_LineCoding.ux_slave_class_cdc_acm_parameter_data_bit = VCP_WORDLENGTH8;
break;
}
}
/* Get UART Parity */
CDC_VCP_LineCoding.ux_slave_class_cdc_acm_parameter_parity = uart_handler->Init.Parity;
/* Get UART StopBits */
CDC_VCP_LineCoding.ux_slave_class_cdc_acm_parameter_stop_bit = uart_handler->Init.StopBits;
/* Set device class_cdc_acm with default parameters */
if (ux_device_class_cdc_acm_ioctl(cdc_acm_user, UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_LINE_CODING,
&CDC_VCP_LineCoding) != UX_SUCCESS)
{
Error_Handler();
}
/* Receive an amount of data in interrupt mode */
if (HAL_UART_Receive_IT(uart_handler, (uint8_t *)UserTxBufferFS, 1) != HAL_OK)
{
/* Transfer error in reception process */
Error_Handler();
}
/* USER CODE END USBD_CDC_ACM_Activate */
return;
}
I created 'cdc_acm_user' as the CDC_ACM instance which is the input in other APIs. And using the MDK to observe the program, its memory address is 0x20004AA0.
- When host sends a packet to device, after the interrupt handle function the device will enter the thread of '_ux_device_calss_hid_receiver_thread(ULONG hid_instance)', as is shown in following code:
VOID _ux_device_class_hid_receiver_thread(ULONG hid_instance)
{
UX_SLAVE_CLASS_HID *hid;
UX_SLAVE_DEVICE *device;
UX_DEVICE_CLASS_HID_RECEIVER *receiver;
UX_DEVICE_CLASS_HID_RECEIVED_EVENT *pos;
UCHAR *next_pos;
UX_SLAVE_TRANSFER *transfer;
UINT status;
UCHAR *buffer;
ULONG temp;
/* Cast properly the hid instance. */
UX_THREAD_EXTENSION_PTR_GET(hid, UX_SLAVE_CLASS_HID, hid_instance)
/* Get the pointer to the device. */
device = &_ux_system_slave -> ux_system_slave_device;
/* Get receiver instance. */
receiver = hid -> ux_device_class_hid_receiver;
/* This thread runs forever but can be suspended or resumed. */
while(1)
{
/* Check device state. */
if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED)
{
/* We need to suspend ourselves. We will be resumed by the device enumeration module. */
_ux_utility_thread_suspend(&receiver -> ux_device_class_hid_receiver_thread);
continue;
}
/* Check if there is buffer available. */
pos = receiver -> ux_device_class_hid_receiver_event_save_pos;
if (pos -> ux_device_class_hid_received_event_length != 0)
{
/* Wait before check again. */
status = _ux_utility_event_flags_get(
&hid -> ux_device_class_hid_event_flags_group,
UX_DEVICE_CLASS_HID_RECEIVER_RESTART,
UX_OR_CLEAR, &temp, 100);
if (status != UX_SUCCESS)
{
/* Keep checking before a good state. */
continue;
}
}
/* Event buffer available, issue request to get data. */
transfer = &hid -> ux_device_class_hid_read_endpoint -> ux_slave_endpoint_transfer_request;
/* Protect read. */
_ux_device_mutex_on(&hid -> ux_device_class_hid_read_mutex);
/* Issue the transfer request. */
status = _ux_device_stack_transfer_request(transfer,
receiver -> ux_device_class_hid_receiver_event_buffer_size,
receiver -> ux_device_class_hid_receiver_event_buffer_size);
/* Check status and ignore ZLPs. */
if ((status != UX_SUCCESS) ||
(transfer -> ux_slave_transfer_request_actual_length == 0))
{
_ux_device_mutex_off(&hid -> ux_device_class_hid_read_mutex);
continue;
}
/* Save received event data and length. */
buffer = (UCHAR *)&pos -> ux_device_class_hid_received_event_data;
temp = transfer -> ux_slave_transfer_request_actual_length;
_ux_utility_memory_copy(buffer,
transfer -> ux_slave_transfer_request_data_pointer,
temp); /* Use case of memcpy is verified. */
/* Unprotect read. */
_ux_device_mutex_off(&hid -> ux_device_class_hid_read_mutex);
/* Advance the save position. */
next_pos = (UCHAR *)pos + receiver -> ux_device_class_hid_receiver_event_buffer_size + sizeof(ULONG);
if (next_pos >= (UCHAR *)receiver -> ux_device_class_hid_receiver_events_end)
next_pos = (UCHAR *)receiver -> ux_device_class_hid_receiver_events;
receiver -> ux_device_class_hid_receiver_event_save_pos = (UX_DEVICE_CLASS_HID_RECEIVED_EVENT *)next_pos;
/* Save received data length (it's valid now). */
pos -> ux_device_class_hid_received_event_length = temp;
/* Notify application that a event is received. */
if (receiver -> ux_device_class_hid_receiver_event_callback)
receiver -> ux_device_class_hid_receiver_event_callback(hid);
}
}
In the part of '/* Save received event data and length. */', the address of 'buffer' is 0x20004A90. Therefore, after the execution of '_ux_utility_memory_copy( , , )', the memory of 'cdc_acm_user' is modified at the same time. That's why the CDC_ACM Virtual Com cannot work anymore.
My question is how to solve this problem to avoid the case of memory being modified.