久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

標題: 基于藍牙的STM32 IAP在線升級 [打印本頁]

作者: 13125378297    時間: 2019-3-24 12:10
標題: 基于藍牙的STM32 IAP在線升級
最近開發(fā)的一個小項目需要支持藍牙在線升級,今天便詳細地了解一番。藍牙在線升級的方式,流程如圖
流程解釋:產品的最新程序放在云端的服務器上,并將程序更新的提醒通過手機APP推送給用戶,當用戶點擊程序更新時,APP將程序下載至手機上,并通過藍牙傳輸?shù)絊TM32上,這時單片機解析到的指令為程序更新,便觸發(fā)IAP在線刷新程序。

要實現(xiàn)這一功能,必須通過單片機的串口IAP在線升級功能。
1.什么是IAP?

       IAP(In Application Programming)即在應用編程,IAP 是用戶自己的程序在運行過程中對User Flash 的部分區(qū)域進行燒寫,目的是為了在產品發(fā)布后可以方便地通過預留的通信口對產品中的固件程序進行更新升級。

        所以要實現(xiàn)IAP功能,固件程序須分為兩個代碼,即引導程序(BootLoader)和用戶程序(APP)。
1.引導程序(BootLoader):只執(zhí)行串口數(shù)據(jù)的接收、燒寫程序并將程序執(zhí)行地址跳轉至用戶程序段(此代碼只能通過JTAG或SWD燒寫)
2.用戶程序(APP):執(zhí)行用戶所要實現(xiàn)的程序(此代碼通過串口接收,IAP燒寫入單片機flash中)

2.STM32程序的啟動方式

        為什么能將程序分成兩個程序分別下載,要理解這個,我們有必要了解一下STM32的啟動方式,因為我用的是STM32F103C8T6,所以就以這個型號為例:
STM32上電或者復位后,代碼區(qū)始終從0x00000000開始,三種啟動模式其實就是將各自存儲空間的地址映射到0x00000000中。其啟動模式由BOOT0和BOOT1引腳的電平高低來控制。
    1、BOOT1=x BOOT0=0:從Flash啟動,將主Flash地址0x08000000映射到0x00000000,這樣代碼啟動之后就相當于從0x08000000開始,這是正常的工作模式。
    2、BOOT1=0 BOOT0=1:從系統(tǒng)存儲器啟動。首先控制BOOT0 BOOT1管腳,復位后,STM32與上述兩種方式類似,從系統(tǒng)存儲器地址0x1FFF F000開始執(zhí)行代碼,這種模式啟動的程序功能由廠家設置。
    3、BOOT1=1 BOOT0=1:從RAM啟動,將RAM地址0x20000000映射到0x00000000,這樣代碼啟動之后就相當于從0x20000000開始,這種模式可以用于調試。
    這里,我默認使用的模式是主閃存控制器啟動,也就是從Flash啟動。

3. Flash在STM32內存空間的定義

STM32單片機內存空間有明確的定義,
       查看STM32F103C8T6可知,其Flash是分配在空間從0x0800 0000到0x0801FFFF,最大的空間為127KByte。所以在主閃存控制器啟動模式下,STM32一上電,單片機先將0x0800 0000映射到代碼區(qū),然后從0x0800 0000開始執(zhí)行程序。
        在進入main函數(shù)前,單片機還做了以下處理(不需要自己編寫代碼,由單片機內部自動執(zhí)行)
        Cortex-M3上電后來到復位中斷(已將前4個字節(jié)的值存入MSP堆棧指針),轉到__main標號,完成RW段的移動、ZI段的初始化,建立堆棧,初始化庫函數(shù),然后跳轉到main函數(shù),自此就開始執(zhí)行我們編寫的C程序。

4.引導程序和用戶程序內存空間的劃分

        我們知道,單片機默認是從0x0800 0000開始執(zhí)行的,其過程:
    1.STM32 在復位后,先從 0X08000004 地址取出復位中斷向量的地址,并跳轉到復位中斷服務程序,如圖標號①所示;
    2.在復位中斷服務程序執(zhí)行完之后,會跳轉到我們的main 函數(shù),如圖標號②所示;
    3.而我們的 main 函數(shù)一般都是一個死循環(huán),在 main 函數(shù)執(zhí)行過程中,如果收到中斷請求(發(fā)生重中斷),此時 STM32 強制將 PC 指針指回中斷向量表處,如圖標號③所示;
    4.然后,根據(jù)中斷源進入相應的中斷服務程序,如圖標號④所示;
    5.在執(zhí)行完中斷服務程序以后,程序再次返回 main 函數(shù)執(zhí)行,如圖標號⑤所示。
        我們將FLash的內存空間分為引導程序和用戶程序,其0x0800 0000~0x0800 2000,8KByte的空間作為BootLoader,將0x0800 2000 ~0x0801 FFFF,共120KByte作為用戶空間(STM32F103C8T6實際只有64KByteFlash,用戶空間為56KByte)。

        通過此種方式后,STM32執(zhí)行程序的流程變?yōu)椋?/font>
    1.STM32 復位后,還是從 0X08000004 地址取出復位中斷向量的地址,并跳轉到復位中斷服務程序,在運行完復位中斷服務程序之后跳轉到 IAP 的 main 函數(shù),如圖標號①所示。
    2.此部分同圖 47.1.1 一樣;在執(zhí)行完 IAP 以后(即將新的 APP 代碼寫入 STM32的 FLASH,灰底部分。
    3.新程序的復位中斷向量起始地址為 0X08000004+N+M),跳轉至新寫入程序的復位向量表,取出新程序的復位中斷向量的地址,并跳轉執(zhí)行新程序的復位中斷服務程序,隨后跳轉至新程序的 main 函數(shù),如圖標號②和③所示,
    4.同樣 main 函數(shù)為一個死循環(huán),并且注意到此時 STM32 的 FLASH,在不同位置上,共有兩個中斷向量表。

5.引導程序的設計
(1)首先,實現(xiàn)串口中斷函數(shù),藍牙通過串口將數(shù)據(jù)傳輸?shù)絾纹瑱C上,因為STM32F103C8T6的RAM只有8KByte,所以上位機每次發(fā)送的數(shù)據(jù)為1KByte,單片機燒寫完后再發(fā)送下1KByte數(shù)據(jù)。

extern uint8_t usart_buf[1024+8];
//數(shù)據(jù)長度(2B)  數(shù)據(jù)(1KB)  序號(2B)  [CRC(4B)]
extern uint16_t buf_cnt;
extern uint8_t bootStatus;

void USART1_IRQHandler(void)
{
    uint8_t temp = 0;
    if( (USART_GetFlagStatus(USART1, USART_IT_RXNE) != RESET) )
    {
            temp = (uint8_t)USART_ReceiveData(USART1);
            if(++buf_cnt < (1024+8)  && ((buf_cnt & 0x8000) != 0x8000))
            {
                    usart_buf[buf_cnt - 1] = temp;
             }
            else buf_cnt |= 0x8000;
        }
}
(2)在main函數(shù)中,對接收到的數(shù)據(jù)進行判斷

if(flag)      //是否串口是否有接收到數(shù)據(jù)
{
    printf("開始更新固件r\n");
    // 判斷APP程序的起始地址是否為0X08XXXXXX
     if(((*(vu32*)(0X20001000+4))&0xFF000000)==0x08000000)
    {
        iap_write_appbin(FLASH_APP1_ADDR,USART_RX_BUF,applenth);//更新FLASHFLASH代碼
        printf("固件更新成功\r\n");
    }
    else
    {
        printf("非固件程序\r\n");
    }
    flag = 0;
}

(3)如果檢測到APP程序,進入FLASH燒寫函數(shù)

// 從addr起燒錄程序
void Iap_Write(uint32_t addr)
{
    uint16_t temp = 0;
    uint16_t data_size = 0;    //燒錄大小
    uint16_t data_len = 0;   //數(shù)據(jù)長度
    uint16_t index = 0;         //數(shù)據(jù)塊索引
    uint32_t addr_now = addr;    //寫入地址
    uint8_t data_write[1024] = {0};//數(shù)據(jù)緩沖
    //準備燒錄,數(shù)據(jù)大小為1K
    while(1)
    {
        while((buf_cnt & 0x8000) == 0);//等待數(shù)據(jù)接收完畢
        //解析數(shù)據(jù)
        data_len = (uint16_t)usart_buf[1] << 8 | usart_buf[0];//獲取data有效長度
        for(temp = 2; temp < data_len + 2; temp++)//從第二位開始拷貝數(shù)據(jù)
        {
            data_write[temp - 2] = usart_buf[temp];
        }
        index = usart_buf[1024 + 3] << 8 + usart_buf[1024 + 2];//獲取索引
        //開始寫數(shù)據(jù)
        if(data_len < 1024)//寫入剩下的數(shù)據(jù)
        {
            if(data_len % 2 != 0)data_len += 1;
            STMFLASH_Write(addr_now, (uint16_t *)data_write, data_len / 2);//
            data_size += 1;
            STMFLASH_Write(IAP_INFO, &data_len, 1);
            putString("OK\n");
            break;
        }
        else
        {
            STMFLASH_Write(addr_now, (uint16_t*)data_write, data_len / 2);
            data_size += 1;
            addr_now += 1024;//下一個1K
            buf_cnt = 0;
            for(temp = 0; temp < USART_BUF_SIZE; temp++)
                usart_buf[temp] = 0;
            putString("Next\n");
        }
    }//燒錄完成
    //清空串口緩存
    buf_cnt = 0;
    for(temp = 0; temp < USART_BUF_SIZE; temp++)usart_buf[temp] = 0;
}

(4)燒錄好APP程序后,引導程序將PC指針地址指向APP程序的起始地址,即0x0800 2000;要對PC指針進行操作,需使用MSR匯編指令來操作。

//設置棧頂?shù)刂?/font>
//addr:棧頂?shù)刂?/font>
__asm void MSR_MSP(u32 addr)
{
    MSR MSP, r0 //set Main Stack value
    BX r14
}

然后執(zhí)行PC指針跳轉函數(shù)

void Iap_load(uint32_t addr)
{
    if(((*(vu32*)addr) & 0x2FFE0000) == 0x20000000)
    {
        jump = (iapfun) *(vu32*)(addr + 4);//強制轉化為函數(shù)
        MSR_MSP(*(vu32*)addr);
        jump();
    }
    else
    {
        printf("Error\n");
        while(1);
    }
}

(5)最后,main函數(shù)的實現(xiàn)就很簡單了,以輪詢的方式讀取串口數(shù)據(jù),然后燒寫FLASH,最后跳轉至APP程序

while(1)
{
     while((readBootTime() != 0)  && (flag == 0))//以輪詢的方式讀取串口
     {
         if(Iap_wait() == 8)
        {
            USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
            flag = 1;
        }
    }
    if(flag)
    {
        IAP_WRITE();
        flag = 0;
    }
    else
        IAP_LOAD();       //跳轉至APP程序
}

6.用戶程序APP的實現(xiàn)

        用戶程序實現(xiàn)比較簡單,只需要對地址進行設計一下就可以,所以我就使用點亮LED來作為APP程序
        圖中 IROM1 的起始地址(Start)一般為 0X08000000,大小(Size)為 0X10000,即從 0X08000000 開始的64K 空間為我們的程序存儲(因為我們STM32F103C8T6 的 FLASH大小是 64K)。而圖中,我們設置起始地址(Start)為 0X0800 2000,即偏移量為 0X2000字節(jié)),因而,留給 APP 用的 FLASH 空間(Size)只有0X8000(56K 字節(jié))大小了。設置好 Start 和 Szie,就完成 APP 程序的起始地址設置。

(2) 設置APP程序的中斷向量表的偏移量
        在 systemInit 函數(shù)中的,設置中斷向量表的偏移量

SCB->VTOR = FLASH_BASE | 0x2000;

以上設置完成之后,點擊rebuild按鈕重新編譯,生成LED.hex
(3)生成APP程序bin文件
我們通過 MDK 自帶的格式轉換工具 fromelf.exe,來實現(xiàn).axf 文件到.bin 文件的轉換。該工具在 MDK 的安裝目錄\ARM\BIN40 文件夾里面
我們就可以在 MDK 編譯成功之后,調用 fromelf.exe,根據(jù)當前工程的 LED.axf,生成一個 LED.bin 的文件。

7.APP程序的藍牙在線升級

        由于公司云端服務器還沒搭好,我就先自己的電腦藍牙與產品藍牙連接,然后通過用QT寫的串口調試助手發(fā)送至STM32中,完成APP程序的升級。
        至此,基于藍牙的STM32  IAP在線升級就完成了!


作者: jiahanjia    時間: 2020-10-22 13:59
你好,請問這個IAP有完整的程序嗎?
作者: n_n    時間: 2021-5-25 17:39
你好,請問可以分享IAP有完整的程序嗎?




歡迎光臨 (http://www.zg4o1577.cn/bbs/) Powered by Discuz! X3.1
主站蜘蛛池模板: 欧美99 | 亚洲国产精品一区二区www | 免费激情 | 欧美aaa一级片 | 黄久久久| av毛片| 日韩在线综合 | 91日韩| 国产精品一区二区久久久久 | 91久久精品国产免费一区 | 中文字幕第一页在线 | 欧美大片一区二区 | 欧美精品片 | 毛片a| 久久精品中文字幕 | 国产一区不卡 | 国产目拍亚洲精品99久久精品 | 中文字幕一区二区三区四区 | 日韩av大片免费看 | 国产va| 国产欧美日韩在线观看 | 九一精品 | 精品国产乱码久久久久久图片 | 免费黄色录像视频 | 成人在线视频观看 | 天堂va在线 | 亚洲天堂网站 | 国产精品亚洲精品日韩已方 | 99热精品久久 | 国产精品一区二区三区久久久 | 免费观看www | 国产成人精品一区二区三区网站观看 | 99精品在线观看 | 国产一区二区在线免费观看 | 一区二区精品视频 | 天天影视网天天综合色在线播放 | 亚洲精品一区二区三区在线 | 国产亚洲欧美日韩精品一区二区三区 | 欧美色综合一区二区三区 | 成人av一区二区在线观看 | 本道综合精品 |