当端点和PMA地址都改变时,CubeMX生成的USB HID设备发送错误数据

当端点和PMA地址都改变时,CubeMX生成的USB HID设备发送错误数据,usb,stm32,cubemx,stm32f3,Usb,Stm32,Cubemx,Stm32f3,我正在调试我正在创建的复合设备的一个问题,并在新生成的CubeMX生成的HID-only代码中重新创建了该问题,以使其更容易解决 我在main()中添加了少量代码,以便在按下蓝色按钮时发送USB HID鼠标点击,并闪烁LED ... uint8_t click_report[CLICK_REPORT_SIZE] = {0}; extern USBD_HandleTypeDef hUsbDeviceFS; ... int main(void) { ... while (1) {

我正在调试我正在创建的复合设备的一个问题,并在新生成的CubeMX生成的HID-only代码中重新创建了该问题,以使其更容易解决

我在
main()
中添加了少量代码,以便在按下蓝色按钮时发送USB HID鼠标点击,并闪烁LED

...
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上)查看我的STM32F3发现板发送的数据包

通过这个新生成的代码,我可以看到从3.23.1发送的
URB\u中断
数据包。(只有该地址的最后一部分端点是相关的。)

数据包内容包括:

01 00 00 00
00
00 00 00 00
00
正如所料

(由于HID的最大数据包大小为4字节,因此5字节的
点击报告将分为4字节和1字节的消息。)

然后,我将
usdb_HID.h
中的
HID_EPIN_ADDR
0x81
更改为
0x83
,使设备将端点3用于HID消息,而不是端点1

//#define HID_EPIN_ADDR                 0x81U
#define HID_EPIN_ADDR                 0x83U
有了此更改,一切都继续工作,数据包从x.x.3发送的预期更改。数据包仍然包含:

01 00 00 00
00
00 00 00 00
00
就我所见,这不应该起作用,因为我还没有为PMA(数据包内存区域)中的端点3(
0x83
)分配地址

我通过编辑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
单击报告时,我会看到以下数据包内容:

58 00 2c 00
58
58 00 2c 00
58
我在
stm32f3xx\u ll\u USB
中跟踪了非PMA缓冲区的内容,直到
USB\u WritePMA

发送代码(在
stm32f3xx\u ll\u usb
中)为:

当我为端点地址
0x83
添加了
HAL\u PCDEx\u PMAConfig(…
)后,为什么线路上的数据不是我提供的数据


更新:

如果我更改
usb_conf.c
让端点地址
0x83
使用通常由
0x81
使用的PMA地址:

  /* 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
):

输出按预期工作:

01 00 00 00
00
00 00 00 00
00

更新2:

我在
stm32f3xx\u ll\u USB.c
USB\u ActivateEndpoint()中添加了一个断点

令人惊讶的是,这只对端点0调用过

因此,
ep->pmaddress
(sic)永远不会“写入硬件”,而只用于更高级别的代码

这一定意味着端点的
pmaddress
值被设置为某个默认值,我不知道端点
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);
  }
出乎意料的是,这些看起来是正确的

0x100
是端点3的txaddr,尽管刚刚第一次调用了
USB\u ActivateEndpoint()

通过大量的搜索,我发现
PCD\u SET\u EP\u TX\u ADDRESS
(在
stm32f3xx\u hal\u PCD.h
中)不仅直接用于
USB\u activatedpoint()
,而且还用于来自stm32f3xx\u hal\u PCD.h的
PCD\u SET\u EP\u DBUF0\u ADDR宏中

PCD\u SET\u EP\u DBUF0\u 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寄存器

我可以从
rxaddr[3]
(端点3)中出现的
0x00
推断它们成对出现(因为没有调用
HAL\u PCDEx\u PMAConfig((PCD\u HandleTypeDef*)pdev->pData,0x3,PCD\u SNG\u BUF,0x0);


更新4:

在将设备更改为再次使用端点1后,TXADRS[3]中的
0x100
值仍然存在。它只是上次运行时的值,这消除了一些混淆


更新5:

这是BTABLE问题。BTABLE寄存器的值为0x00,将BTABLE放在PMA的开头

PMA如下所示: 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

这表明端点
0x81
0x82
工作,因为
pma[4]
pma[8]
都设置为
0x100

端点
0x83
不工作,因为
pma[12]
设置为
0x0

这与值为
58 00 2c 00
的损坏数据一致-USB硬件正在读取
pma[12]
,因此从
pma[0]
发送uint16,该uint16是
0x0058 0x002c
,由于端点较小而反向发送。(注意:PMA只有16位宽,因此每个地址只有两个字节。)

调用
HAL\u PCDEx\u PMAConfig((PCD\u HandleTypeDef*)pdev->pData,0x82,PCD\u SNG\u BUF,0x100);
不会将b表指针设置在
pma[12]
,它只注意到要复制到的pma地址


现在我只需要找到btable的内容被写入的位置…

一个解决方法是将下面的两行添加到
//correct PMA btable
HAL\u PCD\u EP\u Transmit()
中的
stm32f3xx\u HAL\u 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;
  ...
这会导致在每次写入之前对端点3的TX缓冲区的位置进行更正。这是浪费,但设置一次是不够的,因为正在覆盖
pma[12]
中的值

我已经使用此解决方法成功创建了复合CDC(串行)和HID设备


为了正确地解决这个问题,我需要一个答案:

EP3的发送地址正在被传入的USB pac覆盖
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 */
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
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;
  ...
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x00 , PCD_SNG_BUF, 0x18);
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x80 , PCD_SNG_BUF, 0x58);