打印
[活动专区]

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

[复制链接]
707|25
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 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 指针定位到中断向量表处,并根据中断源取出对应的中断向量执行中断服务程序。
  图2-1 不包含boot的app运行逻辑

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

__Vectors       DCD     __initial_sp               ; Top of Stack        // 对应0x8000000,栈顶
                DCD     Reset_Handler              ; Reset Handler       // 对应复位中断向量表
                DCD     NMI_Handler                ; NMI Handler
                DCD     HardFault_Handler          ; Hard Fault Handler
                DCD     MemManage_Handler          ; MPU Fault Handler
                .....
; Reset handler
Reset_Handler   PROC                                                      ; // 对应复位中断程序入口地址
                EXPORT  Reset_Handler             [WEAK]
                IMPORT  __main
                IMPORT  SystemInit
                LDR     R0, =SystemInit
                BLX     R0               
                LDR     R0, =__main                                        ;// 跳转到__main函数,__main函数中会调用main函数
                BX      R0
                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跳转代码
static int Goto_App(uint32_t add_address)
{
        typedef  void (*pfun)(void);
        
        pfun jum_to_app = NULL;
        
    /* Check if the stack top pointer is in the range 0x20000000 - 0x20024000 */
                                    
        if (((*(__IO uint32_t*)add_address) <= 0x20024000) && ((*(__IO uint32_t*)add_address) >= 0x20000000))
        {
                /* disable irq */
                __disable_irq();
                /* Jump to user application */
                jum_to_app = (pfun) *(__IO uint32_t*) (add_address + 4);
                /* Initialize user application's Stack Pointer */
                __set_MSP(*(__IO uint32_t*) add_address);               
                jum_to_app();
        }
        else
        {
                printf("Error: Stack top address is 0x%x\n", (*(__IO uint32_t*)add_address));
        }
        return -1;
}
app中重新设计中断向量表:
#ifdef APP_WITH_BOOT        
        SCB->VTOR = FLASH_BASE | APP_START_ADDR;
#endif
app中设置程序的起始地址,可以通过修改keil中下图:
图2-3 :启动地址设置


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

LR_IROM1 0x08011000 0x00010000  {    ; load region size_region
  ER_IROM1 0x08011000 0x00010000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$Sections)
   .ANY (+RO)
  }
  RW_IRAM1 0x20000000 0x00024000  {  ; RW data
   .ANY (+RW +ZI)
  }
}


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方式,电路图如下:

图3-1 原理图
图3-2仿真图

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



图3-3 实物图1



图3-4 实物图2




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

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

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

图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主函数:
int main(void)
{
        int status = 0, flag = 0;
        
        /* LED Init */
        LedInit(LED_PORT, LED1_PIN | LED2_PIN);
        LedOff(LED_PORT, LED1_PIN | LED2_PIN);        
        /* Key Init */
        KeyInit(KEY_PORT, KEY1_PIN | KEY2_PIN);         
    /* USART Init */
    USART_Config();
        /* SD scan init */
        SDScanInit();
        
        printf("\n\n=====Boot Start!=====\n");
        if(KeyRead(KEY_PORT, KEY1_PIN) == 0)
        {
                Delay(0x28FFFF);
                if(KeyRead(KEY_PORT, KEY1_PIN) == 0)
                {
                        if(SD_UpdateApp() == 0)
                        {
                                printf("Update system OK\n");
                        }
                        else
                        {
                                printf("Update system failed\n");
                        }
                        LedOn(LED_PORT, LED1_PIN | LED2_PIN);
                        /* wait for key released */
                        while(KeyRead(KEY_PORT, KEY1_PIN) == 0);
                        Delay(0x28FFFF);
                        while(KeyRead(KEY_PORT, KEY1_PIN) == 0);
                        
                        /* Software reset!!! */        
                        NVIC_SystemReset();         
                }
        }
        
        flag = (*(__IO uint32_t*)(FLAG_START_ADDR));
        if (flag == FLAG_APP) /* check and jump to APP */
        {
                printf("=====Boot End!=====\n");
                status = Goto_App(APP_START_ADDR);
                if(status == -1)
                {
                        printf("Jum to app failed!\n");
                        Goto_Alarm();
                }               
        }        
        else
        {
                printf("No APP, Wait for SD insert with app.bin inside!\n");
                while(1)
                {
                        if(SD_UpdateApp() == 0)
                        {
                                LedOn(LED_PORT, LED1_PIN | LED2_PIN);
                                printf("Update system OK!, please restart the board\n");
                                while(1);
                        }                                
                }
        }
}

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

        if(KeyRead(SD_SCAN_PORT, SD_SCAN_PIN) == 0)
        {
                Delay(0x28FFFF);
                if(KeyRead(SD_SCAN_PORT, SD_SCAN_PIN) == 0)
                {
                        sd_insert = 1;
                }
        }        
        
        if(sd_insert == 0)
        {
                return -1;
        }

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

        /* search APP.bin */
        fr = f_stat("1:app.bin", &fno);
        if(fr == FR_OK)
        {
                printf("Start update system...\n");
                fr = f_open(&fil, "1:app.bin", FA_READ);
                if(fr) /* error */
                {
                        printf("open 1:app.bin error!\n");
                        f_unmount("1:");
                        return -3;
                }               

                status = flash_erase(FLAG_START_ADDR, 4);
                if(status == -1)
                {
                        printf("Erase flag error!\n");
                        f_close(&fil);
                        f_unmount("1:");
                        return -4;
                }
        
                app_addr = APP_START_ADDR;
                for (;;)
                {
                        memset(buffer, 0, FLASH_PAGE_SIZE);
                        fr = f_read(&fil, buffer, FLASH_PAGE_SIZE, &br); /* Read a chunk of data from the source file */
                        if (br == 0)
                                break; /* error or eof */
                        status = flash_write(app_addr, br, buffer);
                        if(status == -1)
                        {
                                printf("Wrie app(addr:0x%x) error!\n", app_addr);
                                f_close(&fil);
                                f_unmount("1:");
                                return -5;
                        }                        
                        app_addr += br;
                }

                app_flag = FLAG_APP;
                status = flash_write(FLAG_START_ADDR, 4, (uint8_t *)&app_flag);
                if(status == -1)
                {
                        printf("reset flag app1 error!\n");
                        f_close(&fil);
                        f_unmount("1:");                        
                        return -6;
                }        

                f_close(&fil);
                f_unmount("1:");                                
                return 0;
        }        

        f_unmount("1:");
        return -7;
}

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

    /* Erase */
        for(i=0; i<size; i+=FLASH_PAGE_SIZE)
        {
                if (FLASH_COMPL != FLASH_EraseOnePage(start_addr + i))
                {
                        printf("Flash EraseOnePage Error. Please Deal With This Error Promptly\r\n");
                        return -1;
                }               
        }
        
    /* Program */
    for (i = 0; i < size; i += 4)
    {
        if (FLASH_COMPL != FLASH_ProgramWord(start_addr + i, (*(__IO uint32_t*)(pvalue + i))))
        {
                        printf("Flash ProgramWord Error. Please Deal With This Error Promptly\r\n");
                        return -1;
        }
    }        
        
    /* Locks the FLASH Program Erase Controller */
    FLASH_Lock();        
        
    /* Check */
    for (i = 0; i < size; i += 4)
    {
        if ( (*(__IO uint32_t*)(pvalue + i)) != (*(__IO uint32_t*)(start_addr + i)))
        {
            printf("Flash Program Test Failed\r\n");
            return -1;
        }
    }
        
        return 0;
}

int flash_erase(uint32_t start_addr, uint32_t size)
{
        int i = 0;
        
    /* Unlocks the FLASH Program Erase Controller */
    FLASH_Unlock();

    /* Erase */
        for(i=0; i<size; i+=FLASH_PAGE_SIZE)
        {
                if (FLASH_COMPL != FLASH_EraseOnePage(start_addr + i))
                {
                        printf("Flash EraseOnePage Error. Please Deal With This Error Promptly\r\n");
                        return -1;
                }               
        }
        
    /* Locks the FLASH Program Erase Controller */
    FLASH_Lock();        
        
        return 0;
}

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

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

int MMC_disk_initialize(void)
{
    Status = SD_Init(0, 3, 4);
    if (Status != SD_OK)
    {
        log_debug("SD Card initialization failed!\r\n");
        return -1;
    }
//   SD_Info(&SDCardInfo);        
        return 0;
}

int MMC_disk_read(uint8_t *buff, uint32_t sector, uint32_t count)
{
        long long read_addr = 0;
        int n = 0;
        SD_Error Status = SD_OK;
        
        read_addr = sector << 9; /* = sector * SD_BLOCK_SIZE */
        
        if(((uint32_t)buff%4) != 0)
        {
                 for(n=0; n<count; n++)
                {
                         Status = SD_ReadBlock(Buf_RX, read_addr+SD_BLOCK_SIZE*n, SD_BLOCK_SIZE);
                        
                        Status = SD_WaitReadOperation();
                        while (SD_GetStatus() != SD_TRANSFER_OK);
                        if (Status != SD_OK)
                        {
                                log_debug("SD Card read block failed!\r\n");
                                return -1;
                        }
                        
                        memcpy(buff, Buf_RX, SD_BLOCK_SIZE);
                        buff += SD_BLOCK_SIZE;
                }
        }
        else
        {
                if(count == 1)
                        Status = SD_ReadBlock(buff, read_addr, SD_BLOCK_SIZE);     
                else
                        Status = SD_ReadMultiBlocks(buff, read_addr, SD_BLOCK_SIZE, count);
               
                Status = SD_WaitReadOperation();
                while (SD_GetStatus() != SD_TRANSFER_OK);
                if (Status != SD_OK)
                {
                        log_debug("SD Card read block failed!\r\n");
                        return -1;
                }               
        }        

        return 0;
}

int MMC_disk_write(const uint8_t *buff, uint32_t sector, uint32_t count)
{
        long long write_addr = 0;
        int n = 0;
        SD_Error Status = SD_OK;
        
        write_addr = sector << 9; /* = sector * SD_BLOCK_SIZE */
        if(((uint32_t)buff%4) != 0)
        {
                 for(n=0; n<count; n++)
                {
                        memcpy(Buf_TX, buff, SD_BLOCK_SIZE);
                        Status = SD_WriteBlock(Buf_TX, write_addr+SD_BLOCK_SIZE*n, SD_BLOCK_SIZE);
                        buff += SD_BLOCK_SIZE;
                        
                        Status = SD_WaitWriteOperation();
                        while (SD_GetStatus() != SD_TRANSFER_OK);
                        if (Status != SD_OK)
                        {
                                log_debug("SD Card write block failed!\r\n");
                                return -1;
                        }                                
                }
        }        
        else
        {
                if(count == 1)
                        Status = SD_WriteBlock((uint8_t *)buff, write_addr, SD_BLOCK_SIZE);            
                else
                        Status = SD_WriteMultiBlocks((uint8_t *)buff, write_addr, SD_BLOCK_SIZE, count);
               
                while (SD_GetStatus() != SD_TRANSFER_OK);
                if (Status != SD_OK)
                {
                        log_debug("SD Card write block failed!\r\n");
                        return -1;
                }               
        }        
        
        return 0;
}

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

4.4 其他解释
a.如何确定boot的大小是否合适
关于bootapp的大小如何设置,解释如下:
先编写了个Boot,编译得到boot.map, 最下面内容如下:
Total RO Size (Code + RO Data) 2848 (2.78kB)
Total RW Size (RW Data + ZI Data) 5384 ( 5.26kB)
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如下:
Total RO Size (Code + RO Data) 10140 (9.90kB)
Total RW Size (RW Data + ZI Data) 82568 ( 80.63kB)
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工程中创建多个配置,每个配置参数可以不一样,还可以添加些宏定义,区分工程。

图4-3 多工程配置
b. 如何生成bin文件
keil中下图加入:$K\ARM\ARMCC\bin\fromelf.exe --bin --output=Bin\@L.bin !L
图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 文件系统。

图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)
N32CPU.pdf (536.14 KB)
电路.zip (5.04 MB)
Boot.zip (1.79 MB)
App.zip (2.07 MB)



使用特权

评论回复
沙发
primojones| | 2023-4-4 20:38 | 只看该作者
参考基于IAP实现的STM32F系列固件升级

使用特权

评论回复
板凳
xiaoyaodz| | 2023-4-4 20:44 | 只看该作者
如何确定哪个固件是最新的?              

使用特权

评论回复
地板
modesty3jonah| | 2023-4-4 21:00 | 只看该作者
可在实际项目中直接使用?              

使用特权

评论回复
5
timfordlare| | 2023-4-4 21:17 | 只看该作者
这个iap升级速度很快吗。              

使用特权

评论回复
6
mollylawrence| | 2023-4-4 21:40 | 只看该作者
是否需要编写一个bootloader?

使用特权

评论回复
7
benjaminka| | 2023-4-4 22:05 | 只看该作者
是否可以实现远程升级程序和代码呢

使用特权

评论回复
8
olivem55arlowe| | 2023-4-4 22:11 | 只看该作者
支持IAP功能的芯片都有哪些呢              

使用特权

评论回复
9
xiong57785|  楼主 | 2023-4-6 08:40 | 只看该作者
olivem55arlowe 发表于 2023-4-4 22:11
支持IAP功能的芯片都有哪些呢

只需要芯片厂商能提供芯片flash的擦除读写,中断向量表的修改即可

使用特权

评论回复
10
xiong57785|  楼主 | 2023-4-6 08:41 | 只看该作者
benjaminka 发表于 2023-4-4 22:05
是否可以实现远程升级程序和代码呢

没有联网所以远程升级不了,可以发送bin文件给客户,让其自行升级。

使用特权

评论回复
11
xiong57785|  楼主 | 2023-4-6 08:41 | 只看该作者
mollylawrence 发表于 2023-4-4 21:40
是否需要编写一个bootloader?

bootloader就是文章提到的boot

使用特权

评论回复
12
xiong57785|  楼主 | 2023-4-6 08:42 | 只看该作者
timfordlare 发表于 2023-4-4 21:17
这个iap升级速度很快吗。

还是很快的,也就2-3秒,具体还要看程序大小

使用特权

评论回复
13
xiong57785|  楼主 | 2023-4-6 08:43 | 只看该作者
modesty3jonah 发表于 2023-4-4 21:00
可在实际项目中直接使用?

我是用在自己的另一个项目中,但也没有长期测过是否还有隐藏bug.

使用特权

评论回复
14
xiong57785|  楼主 | 2023-4-6 08:44 | 只看该作者
xiaoyaodz 发表于 2023-4-4 20:44
如何确定哪个固件是最新的?

本文的方案不需要确定哪个是最新的,至于提到的替他方案,则需要通过打印或指示灯来进行判断当前是运行的啊app1还是app2

使用特权

评论回复
15
wilhelmina2| | 2023-4-7 10:12 | 只看该作者
是否需要修改BootLoader呢

使用特权

评论回复
16
eefas| | 2023-4-7 10:19 | 只看该作者
N32G45X用SD卡进行IAP升级,,省去了很多的麻烦。

使用特权

评论回复
17
uytyu| | 2023-4-7 22:36 | 只看该作者
将APP程序从SD卡搬运到MCU中 首先从sd卡通过FAFTS文件操作系统打开程序文件,然后记录下复制开始地址和程序文件大小 1

使用特权

评论回复
18
lihuami| | 2023-4-7 22:43 | 只看该作者
是插入SD卡的时候,自动识别的吗

使用特权

评论回复
19
jonas222| | 2023-4-7 22:50 | 只看该作者
制作一个基于SD卡的文件系统工程

使用特权

评论回复
20
wangdezhi| | 2023-4-7 22:56 | 只看该作者
研究了一下sd卡的iap升级固件的方法

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

7

主题

55

帖子

2

粉丝