LPC1788微控制器间歇性不发送USB消息

LPC1788微控制器间歇性不发送USB消息,c,usb,microcontroller,lpc,C,Usb,Microcontroller,Lpc,我正在为NXP LPC1788微控制器开发代码,我的部分工作是使基于它的产品与USB兼容。大部分的腿部工作都完成了,一般来说,通过USB进行的通信几乎和通过CAN进行的通信一样有效 然而,我遇到的一个问题是,当从微控制器产生一个恒定的USB消息输出,这些消息被发送得非常近时,其中一些消息偶尔会被丢弃 我正在使用基于WinUSB编写的自定义驱动程序在PC端接收消息,我最初怀疑问题出在接收端。然而,使用USBLyzer,我现在确信问题出在发送端——USBLyzer日志与我从WinUsb_ReadPi

我正在为NXP LPC1788微控制器开发代码,我的部分工作是使基于它的产品与USB兼容。大部分的腿部工作都完成了,一般来说,通过USB进行的通信几乎和通过CAN进行的通信一样有效

然而,我遇到的一个问题是,当从微控制器产生一个恒定的USB消息输出,这些消息被发送得非常近时,其中一些消息偶尔会被丢弃

我正在使用基于WinUSB编写的自定义驱动程序在PC端接收消息,我最初怀疑问题出在接收端。然而,使用USBLyzer,我现在确信问题出在发送端——USBLyzer日志与我从WinUsb_ReadPipe()获得的日志完全匹配

LPC1788使用USB 2.0全速协议,我已经确认,信息正在使用探头以大约12 MHz的频率发送和接收,这是它应该的

设备配置为使用两个端点:逻辑端点2输入和逻辑端点2输出。这两者都配置为批量传输,最大数据包大小为64字节

我认为消息的发送间隔至少在500-600微秒左右(我在线程中引入了一个人工的500毫秒延迟,消息传输所需的时间应该比这个要少得多)。这是关于我上周得到的;我现在无法检查,因为我的调试工具出了问题

这是微控制器的USB初始化代码:

void USBInit()
{  
  // Configure USB pins.
  PINSEL_ConfigPin(0, 29, 1); // USB_D+1
  PINSEL_ConfigPin(0, 30, 1); // USB_D-1
  PINSEL_ConfigPin(1, 18, 1); // USB_UP_LED1
  PINSEL_ConfigPin(2,  9, 1); // USB_CONNECT1
  PINSEL_ConfigPin(1, 30, 2); // USB_VBUS 

  // Turn on power and clock
  CLKPWR_ConfigPPWR(CLKPWR_PCONP_PCUSB, ENABLE);

  PINSEL_SetPinMode(1, 30, PINSEL_BASICMODE_PLAINOUT);

  // Set DEV_CLK_EN and AHB_CLK_EN.
  LPC_USB->USBClkCtrl |= 0x12;

  // Wait until change is reflected in clock status register.
  while((LPC_USB->USBClkSt & 0x12) != 0x12);

  // Enable NVIC USB interrupts.
  NVIC_EnableIRQ(USB_IRQn);

  // Reset the USB.
  USBReset();

  // Set device address to 0x0 and enable device & connection.
  USBSetAddress(0);
}
这是微控制器用于通过USB发送消息的代码:

uint32_t USB_Send(uint32_t endpoint, uint8_t *pData, uint32_t count)
{
  // Convert into a form that can be sent successfully using USB.  
  uint8_t data[USB_MAX_PACKET_SIZE];

  for(int i=0; i < count; i++)
  {
    data[i*2] = hex[(pData[i] >> 4)];
    data[(i*2)+1] = hex[(pData[i] & 0xF)];
  }

  return USBWriteEndpoint(endpoint, data, count*2);
}

uint32_t USBWriteEndpoint(uint32_t endpoint, uint8_t *pData, uint32_t count)
{
  uint32_t i;

  LPC_USB->Ctrl = ((endpoint & 0xF) << 2) | CTRL_WR_EN;

  LPC_USB->TxPLen = count;

  for(i=0; i < (count+3)/4; i++)
  {
    LPC_USB->TxData = *((__packed uint32_t *)pData);
    pData += 4;
  }

  LPC_USB->Ctrl = 0;
  USBValidateEndpoint(endpoint);
  return count;
}

void USBValidateEndpoint(uint32_t endpoint)
{
  writeSIEEndpointCommand(endpoint, CMD_VALID_BUF);
}

void writeSIECommandData(uint32_t cmd, uint32_t data)
{
  LPC_USB->DevIntClr = CCEMTY_INT;
  LPC_USB->CmdCode = cmd;
  while((LPC_USB->DevIntSt & CCEMTY_INT) == 0);
  LPC_USB->DevIntClr = CCEMTY_INT;
  LPC_USB->CmdCode = data;
  while((LPC_USB->DevIntSt & CCEMTY_INT) == 0);
}
我应该在以下周期内接收消息:

0000000D...   
0000010D...
0000020D...
0000030D...
您可以从该日志中看到,该周期中的某些消息被跳过

编辑2

以下是USBLyzer生成的原始和过滤捕获日志的摘录。原始日志主要由取消的请求组成,因为我的驱动程序是轮询驱动的,并且使用超时

原始日志:

USBlyzer Report

Capture List

Type    Seq Time    Elapsed Duration    Request Request Details Raw Data    I/O C:I:E   Device Object   Device Name Driver Name IRP Status
START   0001    11:09:15.413                                                
URB 0002    11:09:18.484    3.071197 s      Bulk or Interrupt Transfer  10 bytes data   30 30 30 30 30 30 31 46...  out 01:00:02    FFFFFA800FC98440h   USBPDO-11   usbhub  FFFFFA801142FAB0h   
00000000  30 30 30 30 30 30 31 46 30 31                    0000001F01      
URB 0003    11:09:18.484    3.071212 s      Bulk or Interrupt Transfer  64 bytes buffer     in  01:00:82    FFFFFA800FC98440h   USBPDO-11   usbhub  FFFFFA8010E965A0h   
URB 0004-0002   11:09:18.484    3.071371 s  174 us  Bulk or Interrupt Transfer  10 bytes buffer     out 01:00:02    FFFFFA800FC98440h   USBPDO-11   usbhub  FFFFFA801142FAB0h   Success (Success)
URB 0005-0003   11:09:18.485    3.071586 s  374 us  Bulk or Interrupt Transfer          in  01:00:82    FFFFFA800FC98440h   USBPDO-11   usbhub  FFFFFA8010E965A0h   Cancelled (Canceled)
URB 0006    11:09:18.485    3.071608 s      Bulk or Interrupt Transfer  64 bytes buffer     in  01:00:82    FFFFFA800FC98440h   USBPDO-11   usbhub  FFFFFA8010E965A0h   
URB 0007-0006   11:09:18.486    3.072582 s  974 us  Bulk or Interrupt Transfer          in  01:00:82    FFFFFA800FC98440h   USBPDO-11   usbhub  FFFFFA8010E965A0h   Cancelled (Canceled)
URB 0008    11:09:18.486    3.072603 s      Bulk or Interrupt Transfer  64 bytes buffer     in  01:00:82    FFFFFA800FC98440h   USBPDO-11   usbhub  FFFFFA8010E965A0h   
URB 0009-0008   11:09:18.487    3.073598 s  996 us  Bulk or Interrupt Transfer          in  01:00:82    FFFFFA800FC98440h   USBPDO-11   usbhub  FFFFFA8010E965A0h   Cancelled (Canceled)
URB 0010    11:09:18.487    3.073630 s      Bulk or Interrupt Transfer  64 bytes buffer     in  01:00:82    FFFFFA800FC98440h   USBPDO-11   usbhub  FFFFFA8010E965A0h   
URB 0011-0010   11:09:18.488    3.074601 s  970 us  Bulk or Interrupt Transfer          in  01:00:82    FFFFFA800FC98440h   USBPDO-11   usbhub  FFFFFA8010E965A0h   Cancelled (Canceled)
[...]
URB 2504-2501   11:09:19.734    4.320666 s  161 us  Bulk or Interrupt Transfer  14 bytes buffer     out 01:00:02    FFFFFA800FC98440h   USBPDO-11   usbhub  FFFFFA800CF662D0h   Success (Success)
URB 2505-2503   11:09:19.734    4.320785 s  192 us  Bulk or Interrupt Transfer  24 bytes data   30 30 30 30 30 30 30 44...  in  01:00:82    FFFFFA800FC98440h   USBPDO-11   usbhub  FFFFFA8010E965A0h   Success (Success)
00000000  30 30 30 30 30 30 30 44 30 46 46 46 30 30 31 36  0000000D0FFF0016
00000010  30 30 33 31 30 30 31 42                          0031001B        
筛选日志:

USBlyzer Report

Capture List

Type    Seq Time    Elapsed Duration    Request Request Details Raw Data    I/O C:I:E   Device Object   Device Name Driver Name IRP Status
URB 0004-0002   11:09:18.484    3.071371 s  174 us  Bulk or Interrupt Transfer  10 bytes buffer     out 01:00:02    FFFFFA800FC98440h   USBPDO-11   usbhub  FFFFFA801142FAB0h   Success (Success)
URB 2504-2501   11:09:19.734    4.320666 s  161 us  Bulk or Interrupt Transfer  14 bytes buffer     out 01:00:02    FFFFFA800FC98440h   USBPDO-11   usbhub  FFFFFA800CF662D0h   Success (Success)
URB 2505-2503   11:09:19.734    4.320785 s  192 us  Bulk or Interrupt Transfer  24 bytes data   30 30 30 30 30 30 30 44...  in  01:00:82    FFFFFA800FC98440h   USBPDO-11   usbhub  FFFFFA8010E965A0h   Success (Success)
00000000  30 30 30 30 30 30 30 44 30 46 46 46 30 30 31 36  0000000D0FFF0016
00000010  30 30 33 31 30 30 31 42                          0031001B        
URB 2507-2506   11:09:19.734    4.321309 s  459 us  Bulk or Interrupt Transfer  24 bytes data   30 30 30 30 30 31 30 44...  in  01:00:82    FFFFFA800FC98440h   USBPDO-11   usbhub  FFFFFA8010E965A0h   Success (Success)
00000000  30 30 30 30 30 31 30 44 30 30 32 44 30 30 30 34  0000010D002D0004
00000010  30 30 31 46 30 30 32 44                          001F002D        
URB 2511-2510   11:09:19.735    4.321931 s  311 us  Bulk or Interrupt Transfer  24 bytes data   30 30 30 30 30 32 30 44...  in  01:00:82    FFFFFA800FC98440h   USBPDO-11   usbhub  FFFFFA8010E965A0h   Success (Success)
00000000  30 30 30 30 30 32 30 44 30 30 32 38 30 30 32 38  0000020D00280028
00000010  30 30 31 42 30 30 33 31                          001B0031        
URB 2513-2512   11:09:19.735    4.322306 s  332 us  Bulk or Interrupt Transfer  12 bytes data   30 30 30 30 30 33 30 44...  in  01:00:82    FFFFFA800FC98440h   USBPDO-11   usbhub  FFFFFA8010E965A0h   Success (Success)
00000000  30 30 30 30 30 33 30 44 30 30 30 44              0000030D000D    
URB 2725-2724   11:09:19.840    4.426662 s  89 us   Bulk or Interrupt Transfer  24 bytes data   30 30 30 30 30 30 30 44...  in  01:00:82    FFFFFA800FC98440h   USBPDO-11   usbhub  FFFFFA8010E965A0h   Success (Success)
00000000  30 30 30 30 30 30 30 44 30 46 46 46 30 30 31 36  0000000D0FFF0016
00000010  30 30 33 31 30 30 31 42                          0031001B        
URB 2727-2726   11:09:19.840    4.427183 s  471 us  Bulk or Interrupt Transfer  24 bytes data   30 30 30 30 30 31 30 44...  in  01:00:82    FFFFFA800FC98440h   USBPDO-11   usbhub  FFFFFA8010E965A0h   Success (Success)
00000000  30 30 30 30 30 31 30 44 30 30 32 44 30 30 30 34  0000010D002D0004
00000010  30 30 31 46 30 30 32 44                          001F002D        
URB 2731-2730   11:09:19.841    4.427803 s  209 us  Bulk or Interrupt Transfer  24 bytes data   30 30 30 30 30 32 30 44...  in  01:00:82    FFFFFA800FC98440h   USBPDO-11   usbhub  FFFFFA8010E965A0h   Success (Success)
00000000  30 30 30 30 30 32 30 44 30 30 32 38 30 30 32 38  0000020D00280028
00000010  30 30 31 42 30 30 33 31                          001B0031        

你们有硬件USB分析仪吗?我不确定USBLyzer是如何工作的,但我认为它仍然在最低级别使用Windows USB子系统。我使用Windows USB子系统的经验是,它的bug非常多-一个特别的例子是,当传输的数据是最大帧大小的精确倍数时,它不工作。我并不是说这是你的问题-我们的症状与你报告的不同-但在你的鞋子里,我会看到a)改变传输端在一帧中发送的最大数据量,因此它不是帧大小的精确倍数,b)使用硬件USB分析仪查看线路上的实际情况。

问题可能是USB IRQHandler中断了您的写入功能。这将使USB处于不同的状态,因此写入失败

您可以临时禁用IRQ作为解决方法:

uint32_t USBWriteEndpoint(uint32_t endpoint, uint8_t *pData, uint32_t count)
{
  uint32_t i;
  NVIC_DisableIRQ(USB_IRQn);    // USB IRQ handlaer must not run ...
  LPC_USB->Ctrl = ((endpoint & 0xF) << 2) | CTRL_WR_EN;

  LPC_USB->TxPLen = count;

  for(i=0; i < (count+3)/4; i++)
  {
    LPC_USB->TxData = *((__packed uint32_t *)pData);
    pData += 4;
  }

  LPC_USB->Ctrl = 0;
  USBValidateEndpoint(endpoint);
  NVIC_EnableIRQ(USB_IRQn); // ... until we are here. Enable USB IRQ again
  return count;
}
uint32\u t USBWriteEndpoint(uint32\u t endpoint,uint8\u t*pData,uint32\u t count)
{
uint32_t i;
NVIC_DisableIRQ(USB_IRQn);//USB IRQ手柄不能运行。。。
LPC_USB->Ctrl=((端点&0xF)TxPLen=count;
对于(i=0;i<(计数+3)/4;i++)
{
LPC_USB->TxData=*(((uu-packed-uint32_-t*)pData);
pData+=4;
}
LPC_USB->Ctrl=0;
USBValidateEndpoint(端点);
NVIC_EnableIRQ(USB_IRQn);/…直到我们来到这里。再次启用USB IRQ
返回计数;
}

我想我已经设法在微控制器发送USB信息的方式上做了一些重大改进

在的第400页,我看到了关于如何正确处理使用批量输入端点将数据从设备发送到主机的描述。非常幸运的是,我最终偶然发现了它,因为它在本章的DMA部分(我没有使用DMA,所以直到现在我都忽略了它)

根据我在那里读到的内容,我添加了以下方法:

// Params:      endpoint - the logical endpoint number.
// Returns:     TRUE if at least one write buffer is free,
//              FALSE otherwise.
// Description: Checks that the IN endpoint has a free write buffer.
uint8_t USBCheckInEndpointFree(uint32_t endpoint)
{
  uint16_t data;
  uint32_t physicalEndpoint = getEndpointPhysicalAddress(endpoint);

  writeSIECommand(CMD_SEL_EP(physicalEndpoint));
  data = readSIECommandData(DAT_SEL_EP(physicalEndpoint));

  return (data & 0x1) == 0;
}
我将
USBWriteEndpoint
更改为以下内容:

uint32_t USBWriteEndpoint(uint32_t endpoint, uint8_t *pData, uint32_t count)
{
  uint32_t i = 0;
  NVIC_DisableIRQ(USB_IRQn);

  if((endpoint & 0xF) != 0)
  {
    while(getSendMessageFlag(endpoint & 0xF) != 0);
    setSendMessageFlag(endpoint & 0xF);
  }

  while(!USBCheckInEndpointFree(endpoint))
  {
    uint32_t physicalEndpoint = getEndpointPhysicalAddress(endpoint);

    writeSIECommand(CMD_SEL_EP(physicalEndpoint));
    ITM_EVENT32_WITH_PC(3, readSIECommandData(DAT_SEL_EP(physicalEndpoint)));
  }

  LPC_USB->Ctrl = ((endpoint & 0xF) << 2) | CTRL_WR_EN;

  LPC_USB->TxPLen = count;

  for(i=0; i < (count+3)/4; i++)
  {
    LPC_USB->TxData = *((__packed uint32_t *)(pData+i*4));
    //pData += 4;
  }

  ITM_EVENT32_WITH_PC(4, (pData[4] << 24) | (pData[5] << 16) | (pData[6] << 8) | pData[7]);

  LPC_USB->Ctrl = 0;
  USBValidateEndpoint(endpoint);

  NVIC_EnableIRQ(USB_IRQn);
  return count;
}
通过一组良好的日志,我得到了以下输出:

usbLogGood1.txt: 93.70%
usbLogGood2.txt: 92.50%
usbLogGood3.txt: 92.60%

Average performance: 92.93%
Standard deviation: 0.67
对于糟糕的一组,我得到了这个:

usbLogBad1.txt: 16.60%
usbLogBad2.txt: 13.80%
usbLogBad3.txt: 14.10%

Average performance: 14.83%
Standard deviation: 1.54
通过增加额外的检查以确保写缓冲区是空闲的,我设法将USB的“性能”提高了78.1%左右(100%意味着USB消息的完美循环:1,2,3,4,1,2,3,4,1,2,3,4…)

除此之外,我发现当我签入时,消息吞吐量大约翻了一番,尽管与等待while循环相关的延迟

92.93%仍然不是完美的,但手册谈到检查主机的ACK以及自由写入端点。我之前尝试过这样做(没有明显的成功),但这是在我尝试此检查之前。希望如果我同时实现这两个功能,我可以使USB性能与can相媲美

编辑:等待确认的东西不起作用,但是如果我在发送消息之间强制1毫秒的延迟,我可以得到99.99%的性能

这不是一个理想的解决方案,因为1ms是一个相当长的时间来延迟,所以我现在把这个问题留在这里

编辑


现在我坚信问题主要出在我编写的PC端驱动程序上。它的读取速度不够快。

谢谢你的回复,Vicky。我会在某个时候考虑购买硬件USB分析仪。关于最大帧大小-与最大数据包大小相同吗,64字节?很明显,两个endp的最大数据包大小我使用的点是64字节,但我从未向任何方向发送超过24字节的数据。是的,对不起,我在那里交替使用帧和数据包。一次只发送24字节有助于避免此类错误,但根据缓冲,它们可能会被包装为单个USB帧中的多批24字节?我知道USBlyzer的输出会告诉你是否发生过这种情况。看看捕获的列表,我不知道
usbLogGood1.txt: 93.70%
usbLogGood2.txt: 92.50%
usbLogGood3.txt: 92.60%

Average performance: 92.93%
Standard deviation: 0.67
usbLogBad1.txt: 16.60%
usbLogBad2.txt: 13.80%
usbLogBad3.txt: 14.10%

Average performance: 14.83%
Standard deviation: 1.54