本帖最后由 jobszheng 于 2023-4-4 17:29 编辑
#申请原创# @21小跑堂
【开源活动】-基于国民N32G45x的SD卡IAP升级开发
由于众所周知的原因,笔者也在做MCU产品的国产化替代方案。N32系列是我的首选方案。
闲话少说,回归正题。我们本次介绍如何基于N32G455VE使用SD卡做为数据媒介完成IAP升级的项目分享。
首先,我们先了解一下什么是IAP?百度百科的解释如下:
IAP是In Application Programming的首字母缩写,IAP是用户自己的程序在运行过程中对User Flash的部分区域进行烧写,目的是为了在产品发布后可以方便地通过预留的通信口对产品中的固件程序进行更新升级。
短短几句之中,关键技术点全部包含。我们本次的帖子也将以为为“线”介绍N32的IAP升级过程。
我们首先介绍“用户自己的程序”,我们通常称为“bootloader”,这个技术点。
bootloader,引导程序,在MCU启动首先执行的程序,其也为我们自己编写的程序,但其并不完成项目的任务工作,而是更新或引导app的任务。其主要功能及运行程序流程如下:
- step0: bootloader启动,与普通程序一样,声明变量,配置外设等
- step1: 检查是否需要IAP更新
- step2: 如果不需要更新,则跳转到step4
- step3: 执行更新操作
- step4: 运行app程序
经常会被问到:又是bootloader,又是APP程序,这两个和我们平时的程序有什么区别呢?
无论是bootloader还是APP,都是是我们平时编写的程序,它们运行各自的逻辑任务,外设配置与内存读取操作完全一样。仅有一点点儿不同,却非常重要——中断向量表。MCU程序在启动之后,main()函数之前,主要工作是初始化堆栈和配置中断向量表。我们从N32官方的源代码可以看到:
当我们的程序没有bootloader时,即单一程序,则宏的值为默认值0x00,在我们本次有Bootloader程序下,其宏值需要修改为0x4000,即,APP的起始地址为0x08000000+0x4000。
为了可以在线调试,我们需要修改keil的linker文件,通过keil的工程选项配置完成,如图所示:
有人会问,为什么是0x08000000,其实道理很简单!因为ARM的spec规定的。咱们平时开发时,也确实没啥必要看得这么深入,这么具体。
程序启动,bootloader,这个步骤我们完成了,接下来就是如何检查是否需要IAP更新了。先放上程序的流程图:
本次我采取的IAP更新策略是“检查SD卡根目录是否有update.bin文件”?如果有,则进入IAP在线更新程序。否则,直接跳转到已烧入到Flash中的APP。
不过,讲到这里,又引入了另外两个概念:SD卡读写与文件系统。
SD卡读写
SD卡的硬件接口,我本次使用SPI外设接口。SPI的初始化,我们参照N32官方的示例——示例里面写得非常全,超实用。我配置SPI外设参数如下:
- /**
- * @brief:
- *
- * @param:
- * @return:
- * @note:
- */
- void bsp_spi_init(void)
- {
- GPIO_InitType GPIO_InitStructure;
- SPI_InitType SPI_InitStructure;
- /* PCLK2 = HCLK/2 */
- RCC_ConfigPclk2(RCC_HCLK_DIV2);
- RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA | RCC_APB2_PERIPH_SPI1 | RCC_APB2_PERIPH_AFIO, ENABLE);
- /* Configure SPIy pins: SCK, MISO and MOSI ---------------------------------*/
- GPIO_InitStructure.Pin = GPIO_PIN_5 | GPIO_PIN_7;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
- GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
- GPIO_InitStructure.Pin = GPIO_PIN_6;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
- GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
- /* SPI1 Config -------------------------------------------------------------*/
- SPI_InitStructure.DataDirection = SPI_DIR_DOUBLELINE_FULLDUPLEX;
- SPI_InitStructure.SpiMode = SPI_MODE_MASTER;
- SPI_InitStructure.DataLen = SPI_DATA_SIZE_8BITS;
- SPI_InitStructure.CLKPOL = SPI_CLKPOL_HIGH;
- SPI_InitStructure.CLKPHA = SPI_CLKPHA_SECOND_EDGE;
- SPI_InitStructure.NSS = SPI_NSS_SOFT;
- SPI_InitStructure.BaudRatePres = SPI_BR_PRESCALER_256;
- SPI_InitStructure.FirstBit = SPI_FB_MSB;
- SPI_InitStructure.CRCPoly = 7;
- SPI_Init(SPI1, &SPI_InitStructure);
- /* Enable SPIy */
- SPI_Enable(SPI1, ENABLE);
- }
SD卡的初始化过程的状态流转图
文件系统
这里不过多解释什么是文件系统。本次采用开源,免费的FatFS协议栈来实现FAT/FAT32文件系统。
FAT文件系统的实现并不复杂,文档内容也不多,建议每个网友们都应该阅读一下,我们按照移植过程说明文档一步一步地实现即可。
还有一个问题我们需要解决:bootloader程序的资源受限。因此,我们对FatFS进行裁减,保留读文件功能,关闭掉其它功能。(这里请参照文末源代码ffconf.h)
说了这么多,在引用内容里面还有一个动词我没有谈及——“烧写”。
在国民技术MCU系列里面N32G455系列的Flash擦除是全片擦除和按页擦除,由于我们Flash的低16KB保存了我们Bootloader程序,全片擦除显示不合适了。在本项目中,我采用了按需擦除的技术方案,用多少擦多少,节约升级操作的时间。核心代码如下:
- for (i = 0; i < 256; i++)
- {
- log_buf_len = sprintf(log_buf, "page[%d] is programed, left [%d] bytes\r\n", i, btr);
- bsp_uart_send(log_buf, log_buf_len);
- if (btr < FLASH_PAGE_SIZE)
- {
- fr = f_read(&fil, buf, btr, &br);
- ret = iap_flash_page_write((uint32_t *)buf, FLASH_START_ADDR + i * FLASH_PAGE_SIZE);
- break;
- }
- else
- {
- fr = f_read(&fil, buf, FLASH_PAGE_SIZE, &br);
- ret = iap_flash_page_write((uint32_t *)buf, FLASH_START_ADDR + i * FLASH_PAGE_SIZE);
- btr -= FLASH_PAGE_SIZE;
- }
- }
下面是本次项目bootloader的资源使用情况:
- ==============================================================================
- Code (inc. data) RO Data RW Data ZI Data Debug
- 8732 630 700 40 9640 425493 Grand Totals
- 8732 630 700 40 9640 425493 ELF Image Totals
- 8732 630 700 40 0 0 ROM Totals
- ==============================================================================
- Total RO Size (Code + RO Data) 9432 ( 9.21kB)
- Total RW Size (RW Data + ZI Data) 9680 ( 9.45kB)
- Total ROM Size (Code + RO Data + RW Data) 9472 ( 9.25kB)
- ==============================================================================
最后,我们来看看实验的成果:
在文章的最后show一下这几天和我一起奋斗的小伙伴们!
我自行设计的N32G455VE开发板,说实话,挺骄傲的。但这次费时最多的居然是硬件焊接的问题~~ 555..
我这可怜的焊接功底可见一班了吧! 555...
我本次使用的是MMC,32MB的,再说肯定就暴露年龄了~~
n32g455在线升级bootloader.zip
(1.17 MB, 下载次数: 34)
致谢
感谢国民技术公司与21ic论坛的支持!
感谢安小芯妹纸的大力鼓励与督促!
感谢我参考的网友们的资料!
本次实验的讲解与演示视频
|