NORDIC DFU使用外部 FLASH作为交换区

本文深入解析NORDIC SDK中的BOOTLOADER程序,对比DUALBANK与SINGLEBANK版本,阐述通过UART和BLE进行固件更新的机制。重点分析DFU状态机,探讨在资源受限的MCU中如何优化固件空间,提出将SWAP区移至SPIFLASH的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 编写目的

NORDIC的SDK中提供了一个BOOTLOADER程序(以下简称BT),BT有两个版本,分别为DUAL BANK和SINGLE BANK,DUAL BANK的BT有一个固件交换区,新固件的接收先存放到SWAP区,接收完成后再进行校验,然后写入主程序区。SINGLE BANK的BT则不带SWAP区,新固件直接写入固件区,由于没有SWAP区,因此如果升级中途失败的话,固件就无法正常启动,只能一直停留在BT中,等待再次进行升级。另外DUAL还支持SOFTDEVICE和BOOTLOADER自身的更新,SINGLE只支持固件升级,这个是之前FAE的回复,具体我自己没有验证过。

DUAL的优势显而易见,在如今ANDROID机型众多的情况下,由于兼容性、稳定性问题导致的升级失败也可以重新运行旧固件。但缺点也是明显的,就是需要一个与固件空间一样大小的备份区,在资源紧张的MCU中无疑是致命的。

NORDIC提供的SDK提供了两种通过方式的BT,分别为UART和BLE,UART为有线,BLE为无线,另外支持ANT版本的还有ANT BT,由于没有使用到,也不太了解,就不进行描述了。其中,BLE的BT只支持DUAL BANK模式,可能也是NORDIC考虑到BLE的不稳定因素吧,UART的BT则有DUAL和SINGLE两个版本。虽然BLE只有DUAL版本,但是通过替换掉UART SINGLE的dfu_single_bank.c文件,可以很轻易的实现一个SINGLE BANK的BLE BT。

BLE使用了DUAL BAN的BT,无疑留给固件的代码空间是大大缩水了,去掉SOFTDEVICE和BT本身的代码空间,再除去SWAP区,在NRF51822上可以使用的固件代码空间是少之又少。考虑到DUAL BANK的重要性,唯一的办法是将SWAP区移到外部的SPI FLASH上,这样可以预留出多一倍的空间给固件代码。想要改造BT,那必须得对它进行一定的了解才行,本文主要是对NORDIC的BT进行分析,了解其工作机制,方便对其进行SWAP区修改。

  • BOOTLOADER分析

本文使用的SDK版本为nRF5_SDK_11.0.0_89a8197,目前最新的稳定SDK应该已经出到了12,为什么选用SDK 11也是有原因的,因为SDK 12之后对BT进行了比较大的修改,使用了一个外部的CRC校验,没有集成到SDK里,使用起来比较麻烦,据说是为了更加安全,在我实际的应用中,SDK 11的BT也是一直挺稳定的,所以就沿用SDK 11进行分析,对安全性较高的应用可以试下SDK 12。

由于目的只是为了进行SWAP区的修改,本文的分析可能并没有深入对BT进行分析,只是分析可能相关的部分,可能更加贴切来说应该叫DFU(device firmware update )分析吧。另外为了分析简单,直接到修改的BLE SINGLE进行分析,因为增加SWAP区的也是应该会在BLE SINGLE的基础上增加,后期如果要对BLE DUAL进行修改,应该也是相同的道理。

结合SDK文档进行分析,SDK文档链接地址如下。

http://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.sdk%2Fdita%2Fsdk%2Fnrf5_sdk.html

直接查看SDK文档的DFU state machine部分,描述了DFU程序是事件驱动型的,所以必须了解各种状态和事件,从下图可以看出,DFU的入口是dfu_init(...)函数,初始化相关数据并将状态设置为IDLE,空闲状态。

dfu_transport_ble.c主要是负责BLE的通讯,然后根据不同的状态调用dfu_single_bank.c里面相应的事件处理函数。经分析,主要的事件处理函数和调用的方法函数主要有以下几个:

  1. uint32_t dfu_start_pkt_handle(dfu_update_packet_t * p_packet)

在上图中dfu_init(...)后先有个duf_image_size_set(...)的操作,就是在这个事件中处理的,此函数中判断新固件的长度是否合法,再将返回值通过dfu_transport_ble.c返回给主机。如果长度合法,再设置m_functions函数的prepare方法和cleared方法。

prepare方法用于格式化固件区,并设置DFU状态为DFU_STATE_PREPARING。在DUAL BANK中,此方法 是格式化交换区。

cleared方法 用于格式化固件信息区,此区保存固件的校验码等信息,用于启动时校验固件是否有效。在DUAL BANK中,此方法 是格式化交换区固件信息。

在回调的后面,由于处于IDLE状态,因此会马上调用prepare方法进行固件区域清空。实际上是调用pstorage的方法进行ERASE操作,pstorage操作完成后,会调用pstorage_callback_handler()回调进行DFU状态设置为DFU_STATE_RDY。准备进入下一步操作。

在修改BT支持SPI FLASH的时候,就要在prepare操作里面进行一个修改,进行SPI FLASH的SWAP区格式化。由于没有使用pstorage,所以还要手动调用一次pstorage_callback_handler()回调。

  1. uint32_t dfu_init_pkt_handle(dfu_update_packet_t * p_packet)

进入DFU_STATE_RDY状态后,主要调用该事件函数进行处理。主要用于设置新固件的信息,包括CRC、版本、HASH之类的信息,这里无需再详细分析。

  1. uint32_t dfu_init_pkt_complete(void)

INIT数据传输完成后,调用该事件将INIT参数设置到dfu_init_template.c里面,再将DFU状态设置为DFU_STATE_RX_DATA_PKT,准备进行数据包接收。

  1. uint32_t dfu_data_pkt_handle(dfu_update_packet_t * p_packet)

在该事件处理函数中进行固件数据包的接收,并通过pstorage写入到FLASH中,写入完成后通过pstorage_callback_handler()调用dfu_transport_ble.c中的dfu_cb_handler()回调,告诉主机接收完成。并且在dfu_cb_handler()回调中进行是否接收完最后一个包的判断,通过if (mp_final_packet == p_data)语句进行判断,以进入下一步处理。

在修改BT支持SPI FLASH的时候,这个事件函数也是要进行修改的。修改为将固件数据写入到SPI FLASH中,同样是由于使用了pstorage模块,所以还要手动调用一次pstorage_callback_handler()回调,注意调用的参数需要不同。

另外还要重点注意的是,由于dfu_cb_handler()是通过mp_final_packet进行是否接收完成的判断的,而mp_final_packet的赋值又是在调用dfu_data_pkt_handle()之后的,所以这里可能需要增加一个标志的处理。

  1. uint32_t dfu_image_validate()

固件数据接收完成后,主机发送BLE_DFU_VALIDATE命令调用此函数进行固件的校验。在SINGLE中是通过dfu_init_postvalidate()函数直接校验固件区的程序的,如果校验错误,则返回错误码,正确则将DFU状态设置为DFU_STATE_WAIT_4_ACTIVATE,在SINGLE中是将新固件参数进行写入。

在修改BT支持SPI FLASH的时候,这个地方也是要进行修改的。在这里将SPI FLASH里面的固件读取出来进行CRC校验,并与刚开始INIT参数的CRC进行比较,如果相等则说明固件校验成功。

  1. static uint32_t dfu_activate_app(void)

最后通过dfu_activate_app()进行固件的写入。在SINGLE BANK中,此函数实际不进行固件的写入,只是将固件参数进行更新。在DUAL BANK中,则会将交换区数据移动到固件区后,再进行参数更新。

此函数也是重点要修改的地方,可以建一个缓存数据,将SPI FLASH的数据分批读取出来,再通过pstorage操作写入固件区,可以通过pstorage的回调进行重复调用该函数,分批将数据写入,所有数据写入完成后再将参数进行更新。

  • 总结

上述分析的红色标注文字基本上是需要修改的地方,理解DFU流程后修改起来应该是比较容易的,注意的是要进行多次测试才能用于量产产品中,而且要对最大长度的固件进行测试。

另外为了不改变其它源文件的内容,可以使用定时器模拟pstorage的回调,主要是不需要修改mp_final_packet的判断是否最终包。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值