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 USB 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 click_report s 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(... for endpoint address 0x83 ?

Update:

If I change usb_conf.c to let endpoint address 0x83 use the PMA address that is normally used by 0x81 :

/* 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, 0x100); /* USER CODE END EndPoint_Configuration_HID */

the packets on the wire are still corrupted:

58 00 2c 00 58 58 00 2c 00 58

If I return usb_conf.c to its initial, generated, state (where 0x83 has no PMA address, and 0x81 uses 0x100 ):

/* 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, 0x100); /* USER CODE END EndPoint_Configuration_HID */

the output works as expected:

01 00 00 00 00 00 00 00 00 00

Update 2:

I added a break-point in USB_ActivateEndpoint() in stm32f3xx_ll_usb.c .

Surprisingly this is only ever called for endpoint 0.

Therefore, the ep->pmaadress (sic) is never "written into hardware", and only used in higher-level code.

This must mean that the values of pmaadress for the endpoints are set to some default value, and I do not know the default value for endpoint 0x83 and so can't set it.

When I return to work on Friday, I will add debugging to read-out the default values. If they do not exist, I will be very confused.

Update 3:

I added the following debugging:

uint16_t *tx_addr_ptr(USB_TypeDef *USBx, uint8_t ep_num) { register uint16_t *_wRegValPtr; register uint32_t _wRegBase = (uint32_t)USBx; _wRegBase += (uint32_t)(USBx)->BTABLE; _wRegValPtr = (uint16_t *)(_wRegBase + 0x400U + (((uint32_t)(ep_num) * 8U) * 2U)); return _wRegValPtr; } uint16_t *rx_addr_ptr(USB_TypeDef *USBx, uint8_t ep_num) { register uint16_t *_wRegValPtr; register uint32_t _wRegBase = (uint32_t)USBx; _wRegBase += (uint32_t)(USBx)->BTABLE; _wRegValPtr = (uint16_t *)(_wRegBase + 0x400U + ((((uint32_t)(ep_num) * 8U) + 4U) * 2U)); return _wRegValPtr; } ... HAL_StatusTypeDef USB_ActivateEndpoint(USB_TypeDef *USBx, USB_EPTypeDef *ep) { ... int txaddrs[8] = {0}; int rxaddrs[8] = {0}; for (int i = 0; i < 8; ++i) { txaddrs[i] = *tx_addr_ptr(USBx, i); rxaddrs[i] = *rx_addr_ptr(USBx, i); }

This showed me the following values (in the debugger):

txaddrs: 0: 0x58 1: 0xf5c4 2: 0xc1c2 3: 0x100 rxaddrs: 0: 0x18 1: 0xfa9b 2: 0xcb56 3: 0x0

These, unexpectedly, look correct.

0x100 is the txaddr of endpoint 3, even though USB_ActivateEndpoint() has only just been called for the first time.

With a lot of grepping, I found that PCD_SET_EP_TX_ADDRESS (in stm32f3xx_hal_pcd.h ) is not only used directly in USB_ActivateEndpoint() , but also in the PCD_SET_EP_DBUF0_ADDR macro from `stm32f3xx_hal_pcd.h.

PCD_SET_EP_DBUF0_ADDR does not appear to be used, so I do not know how the (changed) values from usbd_conf.c:

USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev) { ... /* 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, 0x100); /* USER CODE END EndPoint_Configuration_HID */

get into the memory-mapped USB registers.

I can infer, from the presence of a 0x00 in rxaddr[3] (endpoint 3) that they happen in pairs (as there is no call to HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x3 , PCD_SNG_BUF, 0x0); ).

Update 4:

After changing the device to use endpoint 1 again, the value of 0x100 in txaddrs[3] remained. It was simply there from the last run, which removes a little confusion.

Update 5:

It's a BTABLE problem. The BTABLE register has a value of 0x00, putting the btable at the start of the PMA.

The PMA looks like this: and the start of the PMA is the btable.

I found:

PMAAddr + BASEADDR_BTABLE + 0x00000000 : EP0_TX_ADDR PMAAddr + BASEADDR_BTABLE + 0x00000002 : EP0_TX_COUNT PMAAddr + BASEADDR_BTABLE + 0x00000004 : EP0_RX_ADDR PMAAddr + BASEADDR_BTABLE + 0x00000006 : EP0_RX_COUNT PMAAddr + BASEADDR_BTABLE + 0x00000008 : EP1_TX_ADDR PMAAddr + BASEADDR_BTABLE + 0x0000000A : EP1_TX_COUNT PMAAddr + BASEADDR_BTABLE + 0x0000000C : EP1_RX_ADDR PMAAddr + BASEADDR_BTABLE + 0x0000000E : EP1_RX_COUNT PMAAddr + BASEADDR_BTABLE + 0x00000010 : EP2_TX_ADDR PMAAddr + BASEADDR_BTABLE + 0x00000012 : EP2_TX_COUNT PMAAddr + BASEADDR_BTABLE + 0x00000014 : EP2_RX_ADDR PMAAddr + BASEADDR_BTABLE + 0x00000016 : EP2_RX_COUNT

on https://community.st.com/s/question/0D50X00009XkaUASAZ/stm32-usb-endpoint-configuration-clarification-questions

This shows that endpoints 0x81 and 0x82 work because both pma[4] and pma[8] are set to 0x100 .

Endpoint 0x83 does not work because pma[12] is set to 0x0 .

This is consistent with the corrupted data having the value 58 00 2c 00 - the USB hardware was reading pma[12] and therefore sending the uint16_t's from pma[0] , which are 0x0058 0x002c , sent reversed because of little-endianness. (Note: the PMA is only 16-bits wide, so there are only two bytes at each address here.)

The call to HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x82, PCD_SNG_BUF, 0x100); does not set up the btable pointer at pma[12] , it just notes that PMA address to copy-to.

Now I just need to find where the content of the btable is being written...