Генерируемое CubeMX устройство USB HID отправляет неверные данные при изменении конечной точки и адреса PMA - PullRequest
2 голосов
/ 22 января 2020

Я отлаживаю проблему с созданным композитным устройством и воссоздаю проблему в только что сгенерированном CubeMX HID-только коде, чтобы его было легче решить.

Я добавил небольшое количество кода к main(), чтобы позволить мне отправлять щелчки мыши USB HID, и индикатор sh, когда синяя кнопка нажата.

...
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);
      }
  }

Я использую Wireshark и usbmon (в Ubuntu 16.04) для просмотра пакетов, которые отправляет моя плата STM32F3DISCOVERY.

С этим недавно сгенерированным кодом я вижу URB_INTERRUPT пакетов, отправляемых из 3.23. 1. (Только последняя часть этого адреса, конечная точка, имеет значение.)

Содержимое пакета:

01 00 00 00
00
00 00 00 00
00

, как и ожидалось.

(5-байтовый click_report s фрагментированы в 4-байтовые и 1-байтовые сообщения, поскольку максимальный размер пакета для HID составляет 4 байта.)

Затем я изменил HID_EPIN_ADDR в usdb_hid.h с 0x81 на 0x83, чтобы устройство использовало конечную точку 3 для сообщений HID вместо конечной точки 1.

//#define HID_EPIN_ADDR                 0x81U
#define HID_EPIN_ADDR                 0x83U

С этим изменением все продолжало работать, с ожидаемым изменением, что пакеты отправляются из xx3 , Пакеты по-прежнему содержат:

01 00 00 00
00
00 00 00 00
00

Насколько я вижу, это должно не работать, так как я еще не выделил адрес для конечной точки 3 (0x83) в PMA (область памяти пакетов).

Я делаю это, редактируя 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;
}

Теперь, когда я отправляю те же 01 00 00 00 00 и 00 00 00 00 00 click_reports Я вижу содержимое пакета:

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

Я проследил содержимое буфера без PMA вплоть до USB_WritePMA в stm32f3xx_ll_usb.

Код отправки (в stm32f3xx_ll_usb):

  /* 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
    {

Почему данные на проводе не являются данными, которые я даю USB_WritePMA, как только я добавил HAL_PCDEx_PMAConfig(... для адреса конечной точки 0x83?


Обновление:

Если я изменю usb_conf.c, чтобы разрешить адресу конечной точки 0x83 использовать адрес PMA, который обычно используется 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 */

пакеты на проводе все еще повреждены:

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

Если я верну usb_conf.c в его начальное, сгенерированное состояние (где 0x83 не имеет адреса PMA, а 0x81 использует 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 */

вывод работает как expec ted:

01 00 00 00
00
00 00 00 00
00

Обновление 2:

Я добавил точку останова в USB_ActivateEndpoint() в stm32f3xx_ll_usb.c.

Удивительно, но это когда-либо вызывалось для конечной точки 0.

Следовательно, ep->pmaadress (si c) никогда не "записывается в аппаратное обеспечение" и используется только в коде более высокого уровня.

Это должно означать, что значения pmaadress для конечных точек установлены на некоторое значение по умолчанию, и я не знаю значения по умолчанию для конечной точки 0x83 и поэтому не могу установить его.

Когда я вернусь к работе в пятницу, Я добавлю отладку для считывания значений по умолчанию. Если они не существуют, я буду очень смущен.


Обновление 3:

Я добавил следующую отладку:

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);
  }

Это показало мне следующее значения (в отладчике):

txaddrs:
  0: 0x58
  1: 0xf5c4
  2: 0xc1c2
  3: 0x100

rxaddrs:
  0: 0x18
  1: 0xfa9b
  2: 0xcb56
  3: 0x0

Они неожиданно выглядят корректно.

0x100 - это txaddr конечной точки 3, хотя USB_ActivateEndpoint() только что был вызван только в первый раз.

С большим вниманием я обнаружил, что PCD_SET_EP_TX_ADDRESS ( в stm32f3xx_hal_pcd.h) используется не только непосредственно в USB_ActivateEndpoint(), но и в макросе PCD_SET_EP_DBUF0_ADDR из `stm32f3xx_hal_pcd.h.

PCD_SET_EP_DBUF0_ADDR не используется, поэтому я не знаю как (измененные) значения из 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 */

попадают в USB-регистры с отображением в памяти.

Я могу вывести из наличия 0x00 в rxaddr[3] (конечная точка 3), что они происходят парами (так как нет вызова HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x3 , PCD_SNG_BUF, 0x0);).


Обновление 4:

После изменения устройства для использования конечной точки 1 опять значение 0x100 в txaddrs [3] осталось. Это было просто там с последнего запуска, что устраняет небольшую путаницу.


Обновление 5:

Это СТАБИЛЬНАЯ проблема. Регистр BTABLE имеет значение 0x00, что ставит btable в начало PMA.

PMA выглядит следующим образом: BTABLE и начало PMA - btable.

Я нашел:

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

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

Это показывает, что конечные точки 0x81 и 0x82 работают, потому что pma[4] и pma[8] установлены на 0x100.

Конечная точка 0x83 не работает, потому что pma[12] установлена ​​на 0x0.

Это согласуется с поврежденными данными, имеющими значение 58 00 2c 00 - оборудование USB считывало pma[12] и, следовательно, отправляло uint16_t из pma[0], которые 0x0058 0x002c, отправлены в обратном порядке из-за порядка байтов. (Примечание: ширина PMA составляет всего 16 бит, поэтому здесь для каждого адреса есть только два байта.)

При вызове HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x82, PCD_SNG_BUF, 0x100); не не устанавливается указатель btable на pma[12], он просто отмечает, что адрес PMA для копирования в.

Теперь мне просто нужно найти, где пишется содержимое btable ...

Ответы [ 2 ]

1 голос
/ 29 января 2020

TX-адрес EP3 перезаписывается входящим USB-пакетом, поскольку он находится в том же смещении в PMA, что и RX-буфер для управляющего EP0. Исходный код работает нормально, потому что он использует только EP1.

Как именно установлены эти смещения, зависит от того, что находится в слоях STMCube, и моя копия кажется другой, но это появляется там, где смещения RX и TX буферы в EP0 устанавливаются в коде OP:

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

Эти константы необходимо изменить на 0x40 и 0x80 (например).

В моей версии эти смещения определены в заголовочный файл и есть также константа EP_NUM, но как она используется, неясно.

Все остальное кажется просто отвлечением.

0 голосов
/ 28 января 2020

Обходным решением является добавление двух строк, следующих за // correct PMA BTABLE к HAL_PCD_EP_Transmit() в stm32f3xx_hal_pcd.c:

HAL_StatusTypeDef HAL_PCD_EP_Transmit(PCD_HandleTypeDef *hpcd, uint8_t ep_addr, uint8_t *pBuf, uint32_t len)
{
  PCD_EPTypeDef *ep;

  ep = &hpcd->IN_ep[ep_addr & EP_ADDR_MSK];

  /*setup and start the Xfer */
  ep->xfer_buff = pBuf;
  ep->xfer_len = len;
  ep->xfer_count = 0U;
  ep->is_in = 1U;
  ep->num = ep_addr & EP_ADDR_MSK;

  // correct PMA BTABLE
  uint32_t *btable = (uint32_t *) USB_PMAADDR;
  btable[ep->num * 4] = ep->pmaadress;
  ...

Это приводит к исправлению расположения буфера TX конечной точки 3 перед каждые пишите. Это расточительно, но этого было недостаточно, чтобы установить его один раз, так как значение в pma[12] было перезаписано.

Я использовал этот обходной путь для успешного создания составного CD C (serial) и HID device.

Для правильного решения этой проблемы мне нужен ответ: Что инициализирует содержимое USB BTABLE STM32, когда макрос __HAL_RCC_USB_CLK_ENABLE () выполняется в HAL_PCD_MspInit ()?

...