cancel
Showing results for 
Search instead for 
Did you mean: 

Why does the CubeMX-generated USB HID device send the wrong data when both endpoint and PMA address are changed?

CDew.1
Associate III

This is a cross-post from https://stackoverflow.com/questions/59856541/stm32f3-cubemx-generated-usb-hid-device-sends-wrong-data-when-both-endpoint-and

I'm debugging a problem with a composite device that I'm creating, and have recreated the issue in freshly-CubeMX-generated HID-only code, to make it easier to resolve. 

I've added small amount of code to `main()` to let me send ISB HID mouse-clicks, and flash an LED, when the blue-button is pressed.

   ...

   uint8_t click_report[CLICK_REPORT_SIZE] = {0};

   extern USBD_HandleTypeDef hUsbDeviceFS;

   ...

   int main(void)

   {

     ...

     while (1)

     {

         /* USER CODE END WHILE */

         /* USER CODE BEGIN 3 */

         if(HAL_GPIO_ReadPin(B1_GPIO_Port, B1_Pin) == GPIO_PIN_SET){

             HAL_GPIO_WritePin(LD4_GPIO_Port, LD4_Pin, GPIO_PIN_SET);

             click_report[0] = 1; // send button press

             USBD_HID_SendReport(&hUsbDeviceFS, click_report, CLICK_REPORT_SIZE);

             HAL_Delay(50);

             click_report[0] = 0; // send button release

             USBD_HID_SendReport(&hUsbDeviceFS, click_report, CLICK_REPORT_SIZE);

             HAL_Delay(200);

             HAL_GPIO_WritePin(LD4_GPIO_Port, LD4_Pin, GPIO_PIN_RESET);

         }

     }

I am using Wireshark and usbmon (on Ubuntu 16.04) to look at the packets which my STM32F3DISCOVERY board sends.

With this freshly-generated code, I can see `URB_INTERRUPT` packets being sent from 3.23.1. (Only the last part of that address, the endpoint, is relevant.)

The packet contents are:

   01 00 00 00

   00

   00 00 00 00

   00

as expected.

(The 5-byte messages are fragmented into 4-byte and 1-byte messages, as there is a 4-byte maximum packet size for HID.)

I then changed `HID_EPIN_ADDR` in `usdb_hid.h` from `0x81` to `0x83`, to make the device use endpoint 3 for HID messages, instead of endpoint 1.

   //#define HID_EPIN_ADDR                0x81U

   #define HID_EPIN_ADDR                0x83U

With this change, everything continued to work, with the expected change that packets are being sent from x.x.3. The packets still contain:

   01 00 00 00

   00

   00 00 00 00

   00

As far as I can see, this should *not* work, as I haven't yet allocated an address for endpoint 3 (`0x83`) in the PMA (packet memory area).

I do this, by editing usb_conf.c:

     /* USER CODE BEGIN EndPoint_Configuration */

     HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x00 , PCD_SNG_BUF, 0x18);

     HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x80 , PCD_SNG_BUF, 0x58);

     /* USER CODE END EndPoint_Configuration */

     /* USER CODE BEGIN EndPoint_Configuration_HID */

     //HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x81 , PCD_SNG_BUF, 0x100);

     HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x83 , PCD_SNG_BUF, 0x180);

     /* USER CODE END EndPoint_Configuration_HID */

     return USBD_OK;

   }

Now, when I send the same `01 00 00 00 00` and `00 00 00 00 00` `click_reports` I see packet contents of:

   58 00 2c 00

   58

   58 00 2c 00

   58

I have traced the contents of the non-PMA buffer right down to `USB_WritePMA` in `stm32f3xx_ll_usb`.

The sending code (in `stm32f3xx_ll_usb`) is:

     /* IN endpoint */

     if (ep->is_in == 1U)

     {

       /*Multi packet transfer*/

       if (ep->xfer_len > ep->maxpacket)

       {

         len = ep->maxpacket;

         ep->xfer_len -= len;

       }

       else

       {

         len = ep->xfer_len;

         ep->xfer_len = 0U;

       }

       /* configure and validate Tx endpoint */

       if (ep->doublebuffer == 0U)

       {

         USB_WritePMA(USBx, ep->xfer_buff, ep->pmaadress, (uint16_t)len);

         PCD_SET_EP_TX_CNT(USBx, ep->num, len);

       }

       else

       {

Why is the data on the wire not the data that I give `USB_WritePMA`, once I've added `HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x83 , PCD_SNG_BUF, 0x180);`?

1 ACCEPTED SOLUTION

Accepted Solutions
CDew.1
Associate III

This was answered on Stack Overflow: https://stackoverflow.com/a/59960393/129805

---

The TX address of EP3 is being overwritten by an incoming USB packet because it is located at the same offset in PMA as the RX buffer for the control EP0. The original code works okay because it only uses EP1.

How exactly these offsets are set depends on what's in the layers of STMCube, and my copy seems to be different, but this appears where the offsets of RX and TX buffers in EP0 are set in the OP's code:

   HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x00 , PCD_SNG_BUF, 0x18);

   HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x80 , PCD_SNG_BUF, 0x58);

These constants need to be changed to 0x40 and 0x80 (for example).

In my version, these offsets are defined in a header file and there is also EP_NUM constant, but how it's used is unclear.

Everything else seems to be just distractions.

---

Thanks for all your help. This was exactly correct. (I also pushed EP3's buffer up from 0x100 to 0x128, to be consistent.)

View solution in original post

1 REPLY 1
CDew.1
Associate III

This was answered on Stack Overflow: https://stackoverflow.com/a/59960393/129805

---

The TX address of EP3 is being overwritten by an incoming USB packet because it is located at the same offset in PMA as the RX buffer for the control EP0. The original code works okay because it only uses EP1.

How exactly these offsets are set depends on what's in the layers of STMCube, and my copy seems to be different, but this appears where the offsets of RX and TX buffers in EP0 are set in the OP's code:

   HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x00 , PCD_SNG_BUF, 0x18);

   HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x80 , PCD_SNG_BUF, 0x58);

These constants need to be changed to 0x40 and 0x80 (for example).

In my version, these offsets are defined in a header file and there is also EP_NUM constant, but how it's used is unclear.

Everything else seems to be just distractions.

---

Thanks for all your help. This was exactly correct. (I also pushed EP3's buffer up from 0x100 to 0x128, to be consistent.)