Conficts between '_ux_device_class_hid_receiver_thread' and CDC_ACM variables
Platform: STM32U575xx-EV board
Modules: USBX, ThreadX, HID Custom, CDC ACM virtual com
Summary: I use stm32u575xx as a usb device to communicate with host(PC). Now, i have realized the following functions:
- device report data to host
- host send data to device
- cdc acm could print some logs like USART
/**
* @brief USBD_CDC_ACM_Activate
* This function is called when insertion of a CDC ACM device.
* @param cdc_acm_instance: Pointer to the cdc acm class instance.
* @retval none
*/
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;
}
Problem: The problem is that after i send a packet from host to device, the cdc acm function is killed. And that could not be resumed.
Analysis: I traced the thread after the host sends packet to device. After the interrupt detected, the '_ux _device _class _hid _receiver thread' is called.
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);
}
}
When _ux__utility_memory_copy(buffer, transfer->ux_slave_transfer_request_data_pointer, temp) is excuted, the address of 'buffer' is 0x20004A90 and the cdc_acm_user's address is 0x20004AA0. Therefore, the value of cdc_acm_user is modified, and the function of cdc acm is invalided.
So, could you please have a review on this problem? Maybe there is configuration that should be considered.