0

I have used STM32CubeMX/IDE to generate a USB HID project for the STM32F3DISCOVERY board.

The USB BTABLE register is zero, indicating that the BTABLE is at the start of the Packet Memory Area.

(I zero the whole PMA at program start, to avoid stale values.)

Just before the execution of the __HAL_RCC_USB_CLK_ENABLE macro (in HAL_PCD_MspInit() in usbd_conf.c) the values of the BTABLE (at index zero onwards, in the PMA are:

BTABLE before

After that macro is executed, the values are:

BTABLE after

The macro expands to:

do { \
    volatile uint32_t tmpreg; \
    ((((RCC_TypeDef *) ((0x40000000UL + 0x00020000UL) + 0x00001000UL))->APB1ENR) |= ((0x1UL << (23U))));\
    /* Delay after an RCC peripheral clock enabling */ \
    tmpreg = ((((RCC_TypeDef *) ((0x40000000UL + 0x00020000UL) + 0x00001000UL))->APB1ENR) & ((0x1UL << (23U))));\
    (void)tmpreg; \
} while(0U)

How does this macro cause the BTABLE to be initialised?

(I need pma[12] to be 0x100 instead of 0x0 as I want to use endpoint 3 for the HID interface in a composite device. I am using this simple HID device to test the use of a different endpoint. Changing 0x81 to 0x83 in USBD_LL_Init() and #define HID_EPIN_ADDR are not sufficient to change the value of pma[12]. The incorrect TX pointer at pma[12] is used and corrupt data is observed in wireshark.)


Update:

If I add code to manually set pma[12] to 0x100:

HAL_StatusTypeDef  HAL_PCDEx_PMAConfig(PCD_HandleTypeDef *hpcd,
                                       uint16_t ep_addr,
                                       uint16_t ep_kind,
                                       uint32_t pmaadress)
  ...
  /* Here we check if the endpoint is single or double Buffer*/
  if (ep_kind == PCD_SNG_BUF)
  {
    /* Single Buffer */
    ep->doublebuffer = 0U;
    /* Configure the PMA */
    ep->pmaadress = (uint16_t)pmaadress;

    // correct PMA BTABLE
    uint32_t *btable = (uint32_t *) USB_PMAADDR; // Test this.
    if (ep->is_in) {
        btable[ep->num * 4] = pmaadress;
    }
  }

The value at pam[12] does get set, but it later gets overwritten:

BTABLE updated

fadedbee
  • 42,671
  • 44
  • 178
  • 308
  • I have developed a work-around for this issue, but I cannot be sure of its reliability: https://stackoverflow.com/a/59951272/129805 – fadedbee Jan 28 '20 at 14:54
  • 1
    PMA is memory shared between the CPU and USB peripheral. When you call __HAL_RCC_USB_CLK_ENABLE(), the USB peripheral is enabled and starts working. It can write to the PMA at any time, even if the CPU does is stopped. If the USB interrupt is already set up at that time of the initialization, it might also interrupt you program and call the interrupt handler. So chances are that (1) the USB peripheral overwrites it at initialization, (2) your PMA is incorrectly configured and part of the PMA is overwritten by received data, or (3) the interrupt handler is called and modifies the data. – Codo Jan 29 '20 at 16:02

1 Answers1

2

__HAL_RCC_USB_CLK_ENABLE() enables clocks for the USB block. Before it is enabled, all peripheral locations are read as zeroes. After clock is enabled, the actual PMA content becomes visible, whatever was written there before reset or random garbage left after the power up. So executing __HAL_RCC_USB_CLK_ENABLE() has nothing to do with your problem.

I don't know where the TX buffer address for endpoint 3 gets overwritten, but I guess it is the Cube sets it when it decides to send data on the endpoint. I am not familiar with the Cube, does it have an API to send a USB packet?

Also, double-check that your pma array has the right definition. On F1 and I likely F3, there is a 2-byte value at each of the 32-bit location.

UPD: Sorry, I saw this question first, but your real problem is why TX addr gets overwritten or not set up correctly.

A.K.
  • 839
  • 6
  • 13
  • What code, in which function, actually writes the BTABLE values, when the USB clock is enabled? – fadedbee Jan 29 '20 at 10:54
  • The PMA is 16-bit memory. My PMA array is just for viewing while debugging. I could have used an array of uint16s, with every other one being 0/inaccessible, or an array of uin32s, with the top 16 bits being 0/inaccessible. I thought the latter was easier to read in the debugger. – fadedbee Jan 29 '20 at 10:57