最近想研究下rt的BootLoader,就看到了ymodem的应用。

组件开启得很少,就只有ota_downloader和fal抽象层,用于将文件通过串口写入W25Q的download分区。

xyzmodem传输文件 xmodem传文件失败_丢包


直接按照官方的wiki走,输入ymodem_ota指令后就可以通过XShell的Ymodem协议传输文件了,但是提示Update firmware fail.错误。网上有各种说比如传输时不能有日志输出,我把ymodem换到了UART3,和控制台的UART1区分开,并且把波特率也降低到了9600,数据传输成功,以下是起始帧传输完对buffer的监视。

xyzmodem传输文件 xmodem传文件失败_串口_02


上图可以看到,SOH后需要跟随128字节的数据块,依次是:

0x01,SOH头,代表后面128字节的起始帧;

0x00FF,帧序号,表示第一个数据帧;

后面接128字节的正文,包含rtthread.rbl(’\0’结尾),文件大小53520字节(‘ ’结尾);后面的两个ASCII字串内容不清楚(‘ ’结尾);剩下空间补零;

最后两个字节的校验位0x8064。

含SOH共133字节数据。现在分析错误原因,把波特率调回115200,连续测试两次:

xyzmodem传输文件 xmodem传文件失败_字节数_03


xyzmodem传输文件 xmodem传文件失败_xyzmodem传输文件_04

两次都是超时退出的,期间共收到129字节,都收到了头和尾,但中间有明显的缺失,第一次100644字串编程了10064,第二次文件大小53520变成了3520,两次都有丢包出现,丢包的位置是随机的,丢包的尺寸是一样的,初步推断是周期性的其他调度和优先级问题导致的。

此时仅有4个线程在运行。

xyzmodem传输文件 xmodem传文件失败_串口_05


传输过程中MSH无操作,则仅有用于系统调度的滴答时钟中断和接受数据的串口中断在运行,在适当的位置修改优先级让串口优先:

HAL_NVIC_SetPriority(SysTick_IRQn, 4, 0);
HAL_NVIC_SetPriority(uart->config->irq_type, 1, 0);

再次Debug:

xyzmodem传输文件 xmodem传文件失败_丢包_06

共收到132字节数据,有一定的改善,看来系统调度有一定的干扰。

虽然main线程没有任何操作,干脆直接提前结束。

xyzmodem传输文件 xmodem传文件失败_字节数_07


再次测试:

xyzmodem传输文件 xmodem传文件失败_xyzmodem传输文件_08

起始帧接收完毕。

把中断优先级再改回去:

HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
//HAL_NVIC_SetPriority(uart->config->irq_type, 1, 0);

再次调试,收到130字节数据。

xyzmodem传输文件 xmodem传文件失败_串口_09

按理说,ymodem在运行时直接接管了串口中断函数,期间也没有别的操作,不至于那么大的开销,考虑到工程直接使用的内部时钟,外设和主频都比较低:

xyzmodem传输文件 xmodem传文件失败_丢包_10


修改为外部时钟:

xyzmodem传输文件 xmodem传文件失败_串口_11


接收正常。

出现问题是ymodem传输过快,单片机处理过慢的问题导致的,降低波特率和提升主频都是一种处理方式。
但值得深思的是,此时几乎没有任务调度,没有其他线程参与,串口参数为115200/8/1/N,字符传输速度差不多11.52K字节/每秒,使用内部时钟时,外设频率和系统时钟都为16Mhz,这接近1000倍的时间差。
如果是中断现场保护恢复、信号量通知和系统调度等操作占用时间过长,超过了2字节的传输间隔差不多100us,也就是说这些操作要使用1388个时钟周期,那RT-Thread在STM32上的开销就真的太大了。