[活动专区] 【开源活动】-基于国民N32G45x的SD卡IAP升级开发

[复制链接]
 楼主| xiong57785 发表于 2023-4-2 13:58 | 显示全部楼层 |阅读模式
本帖最后由 xiong57785 于 2023-4-2 14:25 编辑

@安小芯  @21IC  感谢国民技术举办的项目,感谢21ic提供的平台,让我学到不少知识,很抱歉,最后一天才提交,抱歉抱歉!话不多说,开始正题。


基于国民技术N32G45x的SD卡IAP升级开发活动
1. 活动规则
功能:
1.   插入储存固件的SD卡
2.   自动/手动完成固件升级,通过LED灯或者打印反馈升级结果
要求:基于N32G45x系列芯片完成上述功能,提交内容需要包含详细的文字或者图片描述,如原理讲解、测试环境、操作流程、代码配置、代码演示、应用场景等,必要时需要视频演示成果。
2 IAP升级的原理
a. 不包含boot的启动流程
    N32G45x 的内部闪存(FLASH)地址起始于 0x08000000,一般情况下,程序文件就从此地址开始写入。此外 N32G45x 是基于 Cortex-M4F 内核的微控制器,其内部通过一张“中断向量表”来响应中断,程序启动后,将首先从“中断向量表”取出复位中断向量执行复位中断程序完成启动,而这张“中断向量表”的起始地址是 0x08000004,当中断来临,N32G45x 的内部硬件机制亦会自动将 PC 指针定位到中断向量表处,并根据中断源取出对应的中断向量执行中断服务程序。
1.jpg
  图2-1 不包含boot的app运行逻辑

如上图,N32G45x 在复位后,先从 0X08000004 地址取出复位中断向量的地址,并跳转到复位中断服务程序,如图标号 ① 所示;在复位中断服务程序执行完之后,会跳转到 main 函数,如图标号 ② 所示;而 main 函数一般都是一个死循环,在 main 函数执行过程中,如果收到中断请求(发生重中断),此时 N32G45x 强制将 PC 指针指回中断向量表处,如图标号 ③ 所示;然后,根据中断源进入相应的中断服务程序,如图标号 ④ 所示;在执行完中断服务程序以后,程序再次返回 main 函数执行,如图标号 ⑤ 所示。这些跳转逻辑的代码就是在startup_n32g45x中实现的,举例如下:

  1. __Vectors       DCD     __initial_sp               ; Top of Stack        // 对应0x8000000,栈顶
  2.                 DCD     Reset_Handler              ; Reset Handler       // 对应复位中断向量表
  3.                 DCD     NMI_Handler                ; NMI Handler
  4.                 DCD     HardFault_Handler          ; Hard Fault Handler
  5.                 DCD     MemManage_Handler          ; MPU Fault Handler
  6.                 .....
  7. ; Reset handler
  8. Reset_Handler   PROC                                                      ; // 对应复位中断程序入口地址
  9.                 EXPORT  Reset_Handler             [WEAK]
  10.                 IMPORT  __main
  11.                 IMPORT  SystemInit
  12.                 LDR     R0, =SystemInit
  13.                 BLX     R0               
  14.                 LDR     R0, =__main                                        ;// 跳转到__main函数,__main函数中会调用main函数
  15.                 BX      R0
  16.                 ENDP                     

b. 包含boot的启动流程

  图2-2 包含boot的app运行逻辑

N32G45x 复位后,还是从 0X08000004 地址取出复位中断向量的地址,并跳转到复位中断服务程序,在运行完复位中断服务程序之后跳转到 IAP 的 main 函数,如图标号 ① 所示,此部分同正常执行的程序一样;在执行完 IAP 以后(即将新的 APP 代码写入 N32G45x 的 FLASH,灰底部分。新程序的复位中断向量起始地址为 0X08000004+N+M),跳转至新写入程序的复位向量表,取出新程序的复位中断向量的地址,并跳转执行新程序的复位中断服务程序,随后跳转至新程序的 main 函数,如图标号 ② 和 ③ 所示,同样 main 函数为一个死循环,并且注意到此时 N32G45x 的 FLASH,在不同位置上,共有两个中断向量表。

在 main 函数执行过程中,如果 CPU 得到一个中断请求,PC 指针仍强制跳转到地址 0X08000004 中断向量表处,而不是新程序的中断向量表,如图标号 ⑤  所示;(这里如果我们没有设置新的中断向量表,则就会跳到boot的中断向量表,执行boot的函数,从而程序就会出错)程序再根据我们设置的中断向量表偏移量,跳转到对应中断源新的中断服务程序中,如图标号 ⑥ 所示;在执行完中断服务程序后,程序返回 main 函数继续运行,如图标号 所示。

综上:boot中需设计跳转到app,app中需要设计中断向量表的位置 。   
boot跳转代码
  1. static int Goto_App(uint32_t add_address)
  2. {
  3.         typedef  void (*pfun)(void);
  4.         
  5.         pfun jum_to_app = NULL;
  6.         
  7.     /* Check if the stack top pointer is in the range 0x20000000 - 0x20024000 */
  8.                                     
  9.         if (((*(__IO uint32_t*)add_address) <= 0x20024000) && ((*(__IO uint32_t*)add_address) >= 0x20000000))
  10.         {
  11.                 /* disable irq */
  12.                 __disable_irq();
  13.                 /* Jump to user application */
  14.                 jum_to_app = (pfun) *(__IO uint32_t*) (add_address + 4);
  15.                 /* Initialize user application's Stack Pointer */
  16.                 __set_MSP(*(__IO uint32_t*) add_address);               
  17.                 jum_to_app();
  18.         }
  19.         else
  20.         {
  21.                 printf("Error: Stack top address is 0x%x\n", (*(__IO uint32_t*)add_address));
  22.         }
  23.         return -1;
  24. }
app中重新设计中断向量表:
  1. #ifdef APP_WITH_BOOT        
  2.         SCB->VTOR = FLASH_BASE | APP_START_ADDR;
  3. #endif
app中设置程序的起始地址,可以通过修改keil中下图:
1680156261686-340dc97b-1633-43ba-a94e-77a6747c2fca.png
图2-3 :启动地址设置


也可以通过修改分散加载文件的方法:

  1. LR_IROM1 0x08011000 0x00010000  {    ; load region size_region
  2.   ER_IROM1 0x08011000 0x00010000  {  ; load address = execution address
  3.    *.o (RESET, +First)
  4.    *(InRoot$Sections)
  5.    .ANY (+RO)
  6.   }
  7.   RW_IRAM1 0x20000000 0x00024000  {  ; RW data
  8.    .ANY (+RW +ZI)
  9.   }
  10. }


3 测试环境
主控芯片采用的是N32G455VEL7,其内核是ARM Cortex-M4F, 主频144MHz, 内部flash为512KB,SRAM 144KB。
软件编译采用MDK-ARM V5.23,画图采用:A**D V22.0.2 。
SD卡采用MicroSD卡,也就是手机上用的TF卡(目前手头上只有2GB SD卡)。
SD接口采用SDIO方式,电路图如下:

1680229388954-9d8f6c3e-73ba-4dc6-9a6c-92f59c9e3f67.png
图3-1 原理图
1680080845188-19a778e3-49ac-4add-9302-00b164ca5b3b.png
图3-2仿真图

花了亿点点时间画个电路板,打样,贴片,实物如下(修修补补,焊接的不太好,冏):


1680229439579-05b6913b-c269-4b04-848a-a2b05705509f.jpeg

图3-3 实物图1


1680406727482-e2d39425-1efc-4996-86c9-b456706eb062.jpeg

图3-4 实物图2




这个版本的电路ch340有点问题,可能还需要再打一板,修改后的电路图放附件了,有需要的自取。@—@.

4 软件实现4.1 软件需求
实现通过SD卡完成系统升级,升级过程中出现任何问题,在不采用线刷的情况下,保证系统可恢复。
4.2 软件方案(操作流程)
•            系统每次复位或重启,Boot中一开始就检测是否插入SD卡,如果插入SD卡,且升级文件(APP.bin)存在,则升级,升级完成后,启动系统。
这个方案比较简单,存储flash被分为Boot区域+Flag区域+APP区域。
1680230793161-263fcd2a-6339-497c-981f-127a8d1bfbe4.png
图4-1 存储划分

Boot中一开始就检测按键KEY1是否被按下,是否插入SD卡,如果按键KEY1被按下且插入SD卡,且升级文件(APP.bin)存在,则升级,升级完成后,这里没有直接跳转APP,因为APP需要一个比较干净的启动环境(gpio都复位,中断清零,释放关闭等等),这里为了方便就重新软复位,然后跳转到APP。

43.png

图4-2 流程图


app中只需要设置中断向量表即可。

4.3 代码配置
存储配置:
为了方便测试:BootAPP都分配了64KFlashFlag分配了4KFlash
Boot: 0x08000000 - (0x08010000-1)
Flag: 0x08010000 - (0x08011000-1)

App: 0x08110000 - (0x08021000-1)
4.3.1 boot
Boot主函数:
  1. int main(void)
  2. {
  3.         int status = 0, flag = 0;
  4.         
  5.         /* LED Init */
  6.         LedInit(LED_PORT, LED1_PIN | LED2_PIN);
  7.         LedOff(LED_PORT, LED1_PIN | LED2_PIN);        
  8.         /* Key Init */
  9.         KeyInit(KEY_PORT, KEY1_PIN | KEY2_PIN);         
  10.     /* USART Init */
  11.     USART_Config();
  12.         /* SD scan init */
  13.         SDScanInit();
  14.         
  15.         printf("\n\n=====Boot Start!=====\n");
  16.         if(KeyRead(KEY_PORT, KEY1_PIN) == 0)
  17.         {
  18.                 Delay(0x28FFFF);
  19.                 if(KeyRead(KEY_PORT, KEY1_PIN) == 0)
  20.                 {
  21.                         if(SD_UpdateApp() == 0)
  22.                         {
  23.                                 printf("Update system OK\n");
  24.                         }
  25.                         else
  26.                         {
  27.                                 printf("Update system failed\n");
  28.                         }
  29.                         LedOn(LED_PORT, LED1_PIN | LED2_PIN);
  30.                         /* wait for key released */
  31.                         while(KeyRead(KEY_PORT, KEY1_PIN) == 0);
  32.                         Delay(0x28FFFF);
  33.                         while(KeyRead(KEY_PORT, KEY1_PIN) == 0);
  34.                         
  35.                         /* Software reset!!! */        
  36.                         NVIC_SystemReset();         
  37.                 }
  38.         }
  39.         
  40.         flag = (*(__IO uint32_t*)(FLAG_START_ADDR));
  41.         if (flag == FLAG_APP) /* check and jump to APP */
  42.         {
  43.                 printf("=====Boot End!=====\n");
  44.                 status = Goto_App(APP_START_ADDR);
  45.                 if(status == -1)
  46.                 {
  47.                         printf("Jum to app failed!\n");
  48.                         Goto_Alarm();
  49.                 }               
  50.         }        
  51.         else
  52.         {
  53.                 printf("No APP, Wait for SD insert with app.bin inside!\n");
  54.                 while(1)
  55.                 {
  56.                         if(SD_UpdateApp() == 0)
  57.                         {
  58.                                 LedOn(LED_PORT, LED1_PIN | LED2_PIN);
  59.                                 printf("Update system OK!, please restart the board\n");
  60.                                 while(1);
  61.                         }                                
  62.                 }
  63.         }
  64. }

SD卡升级的函数:
  1. static FATFS fs = {0};        
  2. static FILINFO fno;
  3. static FIL fil;        /* File object */
  4. static BYTE buffer[FLASH_PAGE_SIZE] = {0};   /* File copy buffer */
  5.         
  6. static int SD_UpdateApp(void)
  7. {
  8.         FRESULT fr;
  9.         UINT br;         /* File read/write count */
  10.         int status = 0, app_flag = 0, sd_insert = 0;
  11.         uint32_t app_addr = 0;

  12.         if(KeyRead(SD_SCAN_PORT, SD_SCAN_PIN) == 0)
  13.         {
  14.                 Delay(0x28FFFF);
  15.                 if(KeyRead(SD_SCAN_PORT, SD_SCAN_PIN) == 0)
  16.                 {
  17.                         sd_insert = 1;
  18.                 }
  19.         }        
  20.         
  21.         if(sd_insert == 0)
  22.         {
  23.                 return -1;
  24.         }

  25.          /* mount file system */
  26.         fr = f_mount(&fs, "1:", 0);        /* Mount a logical drive, 1:DEV_MMC */
  27.         if (fr != FR_OK)
  28.         {
  29.                 printf("mount file system error!\n");
  30.                 return -2;
  31.         }

  32.         /* search APP.bin */
  33.         fr = f_stat("1:app.bin", &fno);
  34.         if(fr == FR_OK)
  35.         {
  36.                 printf("Start update system...\n");
  37.                 fr = f_open(&fil, "1:app.bin", FA_READ);
  38.                 if(fr) /* error */
  39.                 {
  40.                         printf("open 1:app.bin error!\n");
  41.                         f_unmount("1:");
  42.                         return -3;
  43.                 }               

  44.                 status = flash_erase(FLAG_START_ADDR, 4);
  45.                 if(status == -1)
  46.                 {
  47.                         printf("Erase flag error!\n");
  48.                         f_close(&fil);
  49.                         f_unmount("1:");
  50.                         return -4;
  51.                 }
  52.         
  53.                 app_addr = APP_START_ADDR;
  54.                 for (;;)
  55.                 {
  56.                         memset(buffer, 0, FLASH_PAGE_SIZE);
  57.                         fr = f_read(&fil, buffer, FLASH_PAGE_SIZE, &br); /* Read a chunk of data from the source file */
  58.                         if (br == 0)
  59.                                 break; /* error or eof */
  60.                         status = flash_write(app_addr, br, buffer);
  61.                         if(status == -1)
  62.                         {
  63.                                 printf("Wrie app(addr:0x%x) error!\n", app_addr);
  64.                                 f_close(&fil);
  65.                                 f_unmount("1:");
  66.                                 return -5;
  67.                         }                        
  68.                         app_addr += br;
  69.                 }

  70.                 app_flag = FLAG_APP;
  71.                 status = flash_write(FLAG_START_ADDR, 4, (uint8_t *)&app_flag);
  72.                 if(status == -1)
  73.                 {
  74.                         printf("reset flag app1 error!\n");
  75.                         f_close(&fil);
  76.                         f_unmount("1:");                        
  77.                         return -6;
  78.                 }        

  79.                 f_close(&fil);
  80.                 f_unmount("1:");                                
  81.                 return 0;
  82.         }        

  83.         f_unmount("1:");
  84.         return -7;
  85. }

flash擦除、写函数:
  1. int flash_write(uint32_t start_addr, uint32_t size, uint8_t *pvalue)
  2. {
  3.         int i = 0;
  4.         
  5.     /* Unlocks the FLASH Program Erase Controller */
  6.     FLASH_Unlock();

  7.     /* Erase */
  8.         for(i=0; i<size; i+=FLASH_PAGE_SIZE)
  9.         {
  10.                 if (FLASH_COMPL != FLASH_EraseOnePage(start_addr + i))
  11.                 {
  12.                         printf("Flash EraseOnePage Error. Please Deal With This Error Promptly\r\n");
  13.                         return -1;
  14.                 }               
  15.         }
  16.         
  17.     /* Program */
  18.     for (i = 0; i < size; i += 4)
  19.     {
  20.         if (FLASH_COMPL != FLASH_ProgramWord(start_addr + i, (*(__IO uint32_t*)(pvalue + i))))
  21.         {
  22.                         printf("Flash ProgramWord Error. Please Deal With This Error Promptly\r\n");
  23.                         return -1;
  24.         }
  25.     }        
  26.         
  27.     /* Locks the FLASH Program Erase Controller */
  28.     FLASH_Lock();        
  29.         
  30.     /* Check */
  31.     for (i = 0; i < size; i += 4)
  32.     {
  33.         if ( (*(__IO uint32_t*)(pvalue + i)) != (*(__IO uint32_t*)(start_addr + i)))
  34.         {
  35.             printf("Flash Program Test Failed\r\n");
  36.             return -1;
  37.         }
  38.     }
  39.         
  40.         return 0;
  41. }

  42. int flash_erase(uint32_t start_addr, uint32_t size)
  43. {
  44.         int i = 0;
  45.         
  46.     /* Unlocks the FLASH Program Erase Controller */
  47.     FLASH_Unlock();

  48.     /* Erase */
  49.         for(i=0; i<size; i+=FLASH_PAGE_SIZE)
  50.         {
  51.                 if (FLASH_COMPL != FLASH_EraseOnePage(start_addr + i))
  52.                 {
  53.                         printf("Flash EraseOnePage Error. Please Deal With This Error Promptly\r\n");
  54.                         return -1;
  55.                 }               
  56.         }
  57.         
  58.     /* Locks the FLASH Program Erase Controller */
  59.     FLASH_Lock();        
  60.         
  61.         return 0;
  62. }

4.3.2 app
主函数,比较简单,就是开头设置中断向量表,然后启动任务前打开全局中断
  1. /**
  2. * [url=home.php?mod=space&uid=247401]@brief[/url]  Main program.
  3. */
  4. int main(void)
  5. {
  6. #ifdef APP_WITH_BOOT        
  7.         SCB->VTOR = FLASH_BASE | APP_START_ADDR;
  8. #endif
  9.         LedInit(LED_PORT, LED1_PIN | LED2_PIN);
  10.     /*Turn off Led1, Led2*/        
  11.         LedOff(LED_PORT, LED1_PIN | LED2_PIN);
  12.         KeyInit(KEY_PORT, KEY1_PIN | KEY2_PIN);
  13.         SDScanInit();
  14.     /* USART Init */
  15.     USART_Config();
  16.         OLED_Init();
  17.         printf("\n\n=====App Start!=====\n");
  18.         xQueueKey = xQueueCreate( 4, sizeof( int ) );
  19.         xTaskCreate( vLEDBlinkTask,  "LEDx",  ledSTACK_SIZE,   NULL, ledTASK_PORI,   ( TaskHandle_t * ) NULL );
  20.         xTaskCreate( vKEYScanTask,   "KEY1",  keySTACK_SIZE,   NULL, keyTASK_PORI,   ( TaskHandle_t * ) NULL );
  21.         xTaskCreate( vKEYHandleTask, "KEY2",  8*keySTACK_SIZE, NULL, keyTASK_PORI+1, ( TaskHandle_t * ) NULL );
  22.         xTaskCreate( vSDScanTask,    "SDx",   sdSTACK_SIZE,    NULL, sdTASK_PORI,    ( TaskHandle_t * ) NULL );
  23.         xTaskCreate( vOLEDTask,      "OLEDx", oledSTACK_SIZE,  NULL, oledTASK_PORI,  ( TaskHandle_t * ) NULL );
  24.         __enable_irq();
  25.         vTaskStartScheduler();
  26.     while (1)
  27.     {
  28.                 vTaskDelay( 500 );
  29.     }
  30. }

4.3.3 移植相关
文件系统采用的是fatfs,移植就是实现diskio.c中的初始化和读写函数,具体如下:
  1. int MMC_disk_status(void)
  2. {
  3.         return 0;
  4. }

  5. int MMC_disk_initialize(void)
  6. {
  7.     Status = SD_Init(0, 3, 4);
  8.     if (Status != SD_OK)
  9.     {
  10.         log_debug("SD Card initialization failed!\r\n");
  11.         return -1;
  12.     }
  13. //   SD_Info(&SDCardInfo);        
  14.         return 0;
  15. }

  16. int MMC_disk_read(uint8_t *buff, uint32_t sector, uint32_t count)
  17. {
  18.         long long read_addr = 0;
  19.         int n = 0;
  20.         SD_Error Status = SD_OK;
  21.         
  22.         read_addr = sector << 9; /* = sector * SD_BLOCK_SIZE */
  23.         
  24.         if(((uint32_t)buff%4) != 0)
  25.         {
  26.                  for(n=0; n<count; n++)
  27.                 {
  28.                          Status = SD_ReadBlock(Buf_RX, read_addr+SD_BLOCK_SIZE*n, SD_BLOCK_SIZE);
  29.                         
  30.                         Status = SD_WaitReadOperation();
  31.                         while (SD_GetStatus() != SD_TRANSFER_OK);
  32.                         if (Status != SD_OK)
  33.                         {
  34.                                 log_debug("SD Card read block failed!\r\n");
  35.                                 return -1;
  36.                         }
  37.                         
  38.                         memcpy(buff, Buf_RX, SD_BLOCK_SIZE);
  39.                         buff += SD_BLOCK_SIZE;
  40.                 }
  41.         }
  42.         else
  43.         {
  44.                 if(count == 1)
  45.                         Status = SD_ReadBlock(buff, read_addr, SD_BLOCK_SIZE);     
  46.                 else
  47.                         Status = SD_ReadMultiBlocks(buff, read_addr, SD_BLOCK_SIZE, count);
  48.                
  49.                 Status = SD_WaitReadOperation();
  50.                 while (SD_GetStatus() != SD_TRANSFER_OK);
  51.                 if (Status != SD_OK)
  52.                 {
  53.                         log_debug("SD Card read block failed!\r\n");
  54.                         return -1;
  55.                 }               
  56.         }        

  57.         return 0;
  58. }

  59. int MMC_disk_write(const uint8_t *buff, uint32_t sector, uint32_t count)
  60. {
  61.         long long write_addr = 0;
  62.         int n = 0;
  63.         SD_Error Status = SD_OK;
  64.         
  65.         write_addr = sector << 9; /* = sector * SD_BLOCK_SIZE */
  66.         if(((uint32_t)buff%4) != 0)
  67.         {
  68.                  for(n=0; n<count; n++)
  69.                 {
  70.                         memcpy(Buf_TX, buff, SD_BLOCK_SIZE);
  71.                         Status = SD_WriteBlock(Buf_TX, write_addr+SD_BLOCK_SIZE*n, SD_BLOCK_SIZE);
  72.                         buff += SD_BLOCK_SIZE;
  73.                         
  74.                         Status = SD_WaitWriteOperation();
  75.                         while (SD_GetStatus() != SD_TRANSFER_OK);
  76.                         if (Status != SD_OK)
  77.                         {
  78.                                 log_debug("SD Card write block failed!\r\n");
  79.                                 return -1;
  80.                         }                                
  81.                 }
  82.         }        
  83.         else
  84.         {
  85.                 if(count == 1)
  86.                         Status = SD_WriteBlock((uint8_t *)buff, write_addr, SD_BLOCK_SIZE);            
  87.                 else
  88.                         Status = SD_WriteMultiBlocks((uint8_t *)buff, write_addr, SD_BLOCK_SIZE, count);
  89.                
  90.                 while (SD_GetStatus() != SD_TRANSFER_OK);
  91.                 if (Status != SD_OK)
  92.                 {
  93.                         log_debug("SD Card write block failed!\r\n");
  94.                         return -1;
  95.                 }               
  96.         }        
  97.         
  98.         return 0;
  99. }

app中还移植了freertos,可以参照之前的一篇文章:【N32G430开发板试用】体验+移植Freertos+开关机记录 - - 21ic电子技术开**坛

4.4 其他解释
a.如何确定boot的大小是否合适
关于bootapp的大小如何设置,解释如下:
先编写了个Boot,编译得到boot.map, 最下面内容如下:
  1. Total RO Size (Code + RO Data) 2848 (2.78kB)
  2. Total RW Size (RW Data + ZI Data) 5384 ( 5.26kB)
  3. Total ROM Size (Code + RO Data + RW Data) 2856 ( 2.79kB)
Total ROM Size就是所占用的Flash大小,不到3k,据此设定bootflash大小分配为8k, Start=0x08000000Size=0x2000
flag区域设计为4k(根据flashpage0x800,想当然设置为page的两倍O(∩∩)O,反正flash够大), 即:Start=0x08002000Size=0x1000
app编译后,查看app.map如下:
  1. Total RO Size (Code + RO Data) 10140 (9.90kB)
  2. Total RW Size (RW Data + ZI Data) 82568 ( 80.63kB)
  3. Total ROM Size (Code + RO Data + RW Data) 10328 ( 10.09kB)
据此设计app大小为64k.
app1 Start=0x08003000Size=0x10000; app2 : Start=0x08013000Size=0x10000
需要注意的是:每个区域最好是FlashPage的整数倍,方便对FlashPage的擦除,N32G45xFlash_Page大小为0x800
小技巧:这里可以在一个mdk工程中创建多个配置,每个配置参数可以不一样,还可以添加些宏定义,区分工程。

1680080590623-721b7086-691c-411e-b9a8-aa387c8bf0a3.png
图4-3 多工程配置
b. 如何生成bin文件
keil中下图加入:$K\ARM\ARMCC\bin\fromelf.exe --bin --output=Bin\@L.bin !L
1680229182630-2a7aa4f1-f971-4aeb-9199-1bb617402a2a.png
图4-4 bin文件生成
c. SD卡的分类
关于SD卡的区别如下:
•            SDSC:Standard Capacity SD Memory Card,最高支持 2GB 容量,使用 FAT12,FAT16 文件系统。
•            SDHC:High Capacity SD Memory Card,支持 4GB~32GB 容量,使用 FAT32 文件系统。
•            SDXC:Extended Capacity SD Memory Card,支持 64GB~2TB 容量,使用 exFAT 文件系统。

1680157628508-dc9f7b4f-b089-4402-bd5f-286bc9090da5.png
图4-5 SD卡分类
由于手头只有SD 2G的小卡,属于SDSC,等后面有了大容量SD卡,再测试SDHC是否也可以。
c. 其他方案
    其实也有其他方案:比如APP划分两个,APP1和APP2, 在APP1中升级APP2, 在APP2中升级APP1, boot只用来做跳转就行,这个适合网口升级,缺点是占用flash,APP1和APP2的分散加载文件不一样,升级时需要注意。
   另一个方案是把升级和操作flash的代码放到ram中运行,这样就可以实现app自己擦除自己,自己更新自己, 这个用NXP测试过可以,N32的芯片后面有时间了,再试试。
4.5 代码演示
Boot上电会打印Booot Start,LED1LED2全灭。
app1.bin(升级程序1)会Blink LED1, 周期500ms
app2.bin(升级程序2)会Blink LED2, 周期500ms
升级完成会常亮LED1,LED2, 出错会LED1LED2同时快闪,周期100ms
1.         程序默认运行在APP1,Blink LED1。
2.         将app2.bin重命名为app.bin放到SD卡,插上SD卡,按Key1,按复位,等待升级结束,观测LED。
3.         将app1.bin重命名为app.bin放到SD卡,插上SD卡,按Key1,按复位,等待升级结束,观测LED。
视频链接(https://www.bilibili.com/video/BV1424y1j7oG/):
  

5. 应用场景
目前该程序结合了电机控制一块来实现,可通过SD卡升级电机控制程序,方便以后产品封壳后升级的方便。
6. 一些坑
1.         pack安装不上,提示:Cannot install PackNationstech.N32G45x_DFP.1.0.5: Cannot find PDSC file at root directory of Packarchive
              将Nationstech.N32G45xDFP.1.0.5.pack修改为Nationstech.N32G45xDFP.1.0.5.pack.zip, 然后解压缩,然后再压缩,然后再将压缩文件重命名为:Nationstech.N32G45x_DFP.1.0.5.pack就可以安装了。
2.         boot转到app需要注意,要提供给app一个相对干净的启动环境,gpio还好,主要是中断相关的一定要关闭,否则就可能导致调到app就hardfault,如果不想一个个检查,可以像我一样,重新软启动下。

国民技术SD卡升级文档.pdf (1.93 MB, 下载次数: 62)
N32CPU.pdf (536.14 KB, 下载次数: 43)
电路.zip (5.04 MB, 下载次数: 49)
Boot.zip (1.79 MB, 下载次数: 63)
App.zip (2.07 MB, 下载次数: 60)



primojones 发表于 2023-4-4 20:38 | 显示全部楼层
参考基于IAP实现的STM32F系列固件升级
xiaoyaodz 发表于 2023-4-4 20:44 | 显示全部楼层
如何确定哪个固件是最新的?              
modesty3jonah 发表于 2023-4-4 21:00 | 显示全部楼层
可在实际项目中直接使用?              
timfordlare 发表于 2023-4-4 21:17 | 显示全部楼层
这个iap升级速度很快吗。              
mollylawrence 发表于 2023-4-4 21:40 | 显示全部楼层
是否需要编写一个bootloader?
benjaminka 发表于 2023-4-4 22:05 | 显示全部楼层
是否可以实现远程升级程序和代码呢
olivem55arlowe 发表于 2023-4-4 22:11 | 显示全部楼层
支持IAP功能的芯片都有哪些呢              
 楼主| xiong57785 发表于 2023-4-6 08:40 | 显示全部楼层
olivem55arlowe 发表于 2023-4-4 22:11
支持IAP功能的芯片都有哪些呢

只需要芯片厂商能提供芯片flash的擦除读写,中断向量表的修改即可
 楼主| xiong57785 发表于 2023-4-6 08:41 | 显示全部楼层
benjaminka 发表于 2023-4-4 22:05
是否可以实现远程升级程序和代码呢

没有联网所以远程升级不了,可以发送bin文件给客户,让其自行升级。
 楼主| xiong57785 发表于 2023-4-6 08:41 | 显示全部楼层
mollylawrence 发表于 2023-4-4 21:40
是否需要编写一个bootloader?

bootloader就是文章提到的boot
 楼主| xiong57785 发表于 2023-4-6 08:42 | 显示全部楼层
timfordlare 发表于 2023-4-4 21:17
这个iap升级速度很快吗。

还是很快的,也就2-3秒,具体还要看程序大小
 楼主| xiong57785 发表于 2023-4-6 08:43 | 显示全部楼层
modesty3jonah 发表于 2023-4-4 21:00
可在实际项目中直接使用?

我是用在自己的另一个项目中,但也没有长期测过是否还有隐藏bug.
 楼主| xiong57785 发表于 2023-4-6 08:44 | 显示全部楼层
xiaoyaodz 发表于 2023-4-4 20:44
如何确定哪个固件是最新的?

本文的方案不需要确定哪个是最新的,至于提到的替他方案,则需要通过打印或指示灯来进行判断当前是运行的啊app1还是app2
wilhelmina2 发表于 2023-4-7 10:12 | 显示全部楼层
是否需要修改BootLoader呢
eefas 发表于 2023-4-7 10:19 | 显示全部楼层
N32G45X用SD卡进行IAP升级,,省去了很多的麻烦。
uytyu 发表于 2023-4-7 22:36 | 显示全部楼层
将APP程序从SD卡搬运到MCU中 首先从sd卡通过FAFTS文件操作系统打开程序文件,然后记录下复制开始地址和程序文件大小 1
lihuami 发表于 2023-4-7 22:43 | 显示全部楼层
是插入SD卡的时候,自动识别的吗
jonas222 发表于 2023-4-7 22:50 | 显示全部楼层
制作一个基于SD卡的文件系统工程
wangdezhi 发表于 2023-4-7 22:56 | 显示全部楼层
研究了一下sd卡的iap升级固件的方法
您需要登录后才可以回帖 登录 | 注册

本版积分规则

7

主题

55

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部