Conficts between '_ux_device_class_hid_receiver_thread' and CDC_ACM variables

明泉 张 20 Reputation points
2023-09-26T11:00:32.17+00:00

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:

  1. device report data to host
  2. host send data to device
  3. 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.

Azure RTOS
Azure RTOS
An Azure embedded development suite including a small but powerful operating system for resource-constrained devices.
331 questions
{count} votes

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.