来源:公众号【鱼鹰谈单片机】ID :emOsprey
最近鱼鹰在搞调试器,折腾了好多天终于理解了 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;
}
……
}
这下串口助手一下子丝滑了,舒服!