最近在搞调试器,折腾了好多天才终于理解了 MDK 、下载算法、调试器、MCU 之间的关系。简单来说就是,调试器作为 USB 转 SWD 协议的转换工具,MDK 通过 USB 驱动这个工具,下载算法包含了一些 MCU 内部 FLASH 擦除、编程代码,和普通代码不同的是,该代码可以下载在任意位置运行。如果需要校验,还会加入 CRC 校验代码,扇区检测代码。MDK 首先通过调试器将算法写入内部 RAM,然后把需要写入的固件程序写入 RAM,再由 MDK 控制(通过调试器) MCU 执行相应代码(擦除或写入扇区),通过 MCU 的寄存器和设定软件断点得到执行结果,如此来回搬运,就可完成固件下载。说起来简单,但做起来很麻烦(调试器工具功能简单,只做协议转换,如何控制通过 MDK),这里点到为止,有时间会好好整理分享一下。之后准备 USB 相关的工作,发现总是没有满意的 USB CORE 库,官方的库感觉还不错,可惜被封装了,看不到源码,放弃。之前给大家分享过虚拟串口的代码,于是下载下来使用,发现竟然在 GD32 中用不了,当初明明 ST 测试没问题的。还以为是 GD 芯片问题,然后使用之前的 USB 双缓冲读卡器代码,发现没有问题。只能在线调试比较差异,借助逻辑分析仪,总算解决了这两个 BUG,顺利自发自收。BUG 1
枚举失败。
通过逻辑分析仪发现,电脑发送控制帧给 USB 设备,竟然没有任何回应,即没有 NAK,也米有 STALL,更不用说 ACK 了。通过调试发现,该端点接收状态为 0,禁用状态,再参考可用代码,发现在复位之后,应该设置为接收有效才对。因此修改如下:void USBD_Reset (void)
{
………………
……
……
EPxREG(0) = EP_CONTROL | EP_RX_VALID; // 除了设定端点类型外,还要使能接收
DADDR = DADDR_EF | 0; /* Enable USB Default Address */
}
很奇怪的是,ST 我以前测试是没问题的,可能也是两者之间的差异吧。BUG 2
枚举成功后,又出现另外一个问题,就是串口只能发送第一帧数据,第二次卡死……经过逻辑分析仪发现,发送的数据会被 NAK。后来才发现下面的语句不满足,直接没有读 USB 数据包,从而没有恢复接收有效状态,导致串口助手卡死。这段官方代码也确实比较迷,没有最大利用缓存空间(最少需要满一包的空间,但实际可能不满一包),不过按下不表。那就是第一次收到的数据未读呗,在 main() 函数里面发现根本没进来,发现竟然一直在 USB 中断执行……void main()
{
while(1)
{
……
if (usb_rx_ch == -1)
usb_rx_ch = USBD_CDC_ACM_GetChar();
……
}
}
然后看到这个标志一直在,未清除导致。
但很奇怪的事,该代码在 ST 里面跑的挺好的。不管它,加上处理:void USB_LP_CAN1_RX0_IRQHandler(void) {
……
if (istr & ISTR_ESOF)
{
if (USBD_P_Error_Event)
{
USBD_P_Error_Event(3);
}
ISTR = ~ISTR_ESOF;
}
……
}