当端点和PMA地址都改变时,CubeMX生成的USB HID设备发送错误数据
我正在调试我正在创建的复合设备的一个问题,并在新生成的CubeMX生成的HID-only代码中重新创建了该问题,以使其更容易解决 我在当端点和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) {
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);