女人自慰AV免费观看内涵网,日韩国产剧情在线观看网址,神马电影网特片网,最新一级电影欧美,在线观看亚洲欧美日韩,黄色视频在线播放免费观看,ABO涨奶期羡澄,第一导航fulione,美女主播操b

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

STM32速成筆記(15)—串口IAP

冬至子 ? 來源:二土電子 ? 作者:二土電子 ? 2023-10-24 17:19 ? 次閱讀

一、串口IAP簡介

1.1 什么是IAP

IAP,英文全稱In Application Programming,在應用中編程。很好理解,就是在程序運行過程中我們進行程序的燒寫,或者叫升級。

1.2 STM32下載程序

我們都知道,STM32可以利用串口下載程序,這是因為ST公司在產線上就在產品中內嵌了自舉程序。所謂的自舉程序,實際就是支持我們通過串口下載程序的代碼。自舉程序被存放在系統存儲區,因此如果我們需要通過串口下載程序,需要將Boot0接高電平,Boot1接低電平,讓程序從系統存儲器開始運行,運行自舉程序。下載完成后我們再將Boot0接地,讓程序從主閃存存儲器開始運行。自舉程序是我們用戶無法修改的。

二、串口IAP有什么作用

上面我們介紹了什么是IAP,那么這個IAP到底有什么作用呢?

首先介紹兩個詞——BootloaderApplication 。Bootloader實際就是一段引導程序,單片機上電后先執行Bootloader程序,然后再執行用戶編寫的應用程序Application。介紹完這兩個詞,我們來介紹一下IAP有什么作用。比如我們生產了A,B兩款產品。A產品是某個精密器件的一部分,B產品是一款物聯網產品。我們的產品銷售范圍很廣,遠銷海外。

某天A產品的某個客戶反映了一個Bug,我們編寫好了程序,需要進行程序更新,或者叫升級。利用IAP,我們可以在程序運行時,通過預留的通信接口直接燒寫程序。而不需要再把整個設備拆開,像我們調試時那樣下載程序。甚至我們可以直接給客戶郵寄一個小設備,客戶直接進行傻瓜式升級。

又過了一段時間,B產品的程序出現了一個Bug,風險等級比較低,但是依舊需要全體升級程序。我們總不能挨個產品派人去升級,成本極大。這時候又輪到我們的IAP出場了。它可以在所有設備在線運行的情況下,直接通過網絡下發升級程序,實現在線升級,節約了大量的人力成本。

通過上面這兩個例子,大家應該能夠基本了解IAP的用處,使用IAP讓我們不需要再使用調試器進行下載,甚至實現設備的在線升級。

三、啟動流程

在介紹如何實現IAP之前,我們先來簡單了解以下STM32的啟動流程。

3.1 正常啟動流程

這里的正常啟動流程指的是,沒有添加IAP的流程。

圖片

正常啟動流程

程序啟動時首先開辟棧空間,配置棧頂指針。然后配置堆空間。配置完成后,建立中斷向量表,在中斷向量表中找到復位中斷,開始執行復位中斷服務函數,然后跳轉到main函數中,執行用戶代碼。當用戶代碼中有中斷請求時,會回到中斷向量表,根據中斷源執行相應的中斷服務函數。

3.2 加入IAP后的啟動流程

下面是加入IAP之后的啟動流程。

圖片

加入IAP啟動流程

可以看到,與上面不同的是,加入IAP后,執行完復位中斷服務函數后直接進入IAP的main函數。在執行完IAP之后,跳轉至新寫入程序的復位向量表,取出新程序的復位中斷向量的地址,并跳轉執行新程序的復位中斷服務程序,隨后跳轉至新程序的main 函數。

由上面的兩個啟動過程我們可以看出

  • ? 新程序必須在 IAP 程序之后的某個偏移量為 x 的地址開始。

  • ? 必須將新程序的中斷向量表相應的移動,移動的偏移量為 x。

    四、必備知識

    44.1 修改程序運行起始地址

點擊魔術棒,選擇“Target”,修改運行起始地址和代碼大小。

圖片

修改App運行起始地址

4.2 設置中斷向量表偏移

VTOR 寄存器存放的是中斷向量表的起始地址。如果要設置中斷向量表偏移,只需要在main函數最開始添加如下語句即可

SCB- >VTOR = FLASH BASE | 偏移量:

4.3 生成.bin文件

點擊魔術棒,選擇“User”,按照如下配置,輸入下面的內容

fromelf --bin -o "$L@L.bin" "#L"

圖片

生成.bin文件配置

點擊編譯,不報錯就可以,去設置的輸出文件夾中就可以找到對應的.bin文件。

圖片

編譯提示

五、串口IAP實現

本次的目標是實現一個串口IAP,也就是編寫Bootloader,在程序運行過程中實現程序的下載。Bootloader程序應該可以通過串口接收上位機發來的.bin文件(App程序),檢查后將.bin文件寫入到Flash特定位置,然后跳轉到App程序運行。

5.1 串口中斷服務函數

本次的串口中斷服務函數與之前不同,這里單獨貼出來。需要定義一個接收數組,接收數組的起始地址限制為0X20001000。接收數組最多可以接收55K字節,可以根據需要調整。但是需要注意的是,數組的大小需要比App程序要大,而且不能超過芯片的SRAM空間大小。

/*
 *==============================================================================
 *函數名稱:USART1_IRQHandler
 *函數功能:USART1中斷服務函數
 *輸入參數:無
 *返回值:無
 *備  注:無
 *==============================================================================
 */
u32 gReceCount = 0;   // 接收計數變量
// 接收數組
// 限制起始地址為0X20001000
// 保證偏移量為 0X200的倍數
// 是為了給App留SRAM空間
u8 gReceFifo[USART_RECE_MAX_LEN]__attribute__ ((at(0X20001000)));

void USART1_IRQHandler(void)  
{
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)   //接收到一個字節  
    {
        if (gReceCount < USART_RECE_MAX_LEN)
        {
            gReceFifo[gReceCount++] = USART1- >DR;
        }
        else
        {
            printf ("APP code out of memory!rn");
        }
    }
}

5.2 Flash寫入程序

關于Flash程序,這里就不在贅述,只是貼一下帶檢查的寫入程序。其他具體內容可以到博主STM32速成筆記專欄查看。

/*
 *==============================================================================
 *函數名稱:Med_Flash_Write
 *函數功能:從指定地址開始寫入指定長度的數據
 *輸入參數:WriteAddr:寫入起始地址;pBuffer:數據指針;
                        NumToRead:寫入(半字)數
 *返回值:無
 *備  注:對內部Flash的操作是以半字為單位,所以讀寫地址必須是2的倍數
 *==============================================================================
 */

// 根據中文參考手冊,大容量產品的每一頁是2K字節
#if STM32_FLASH_SIZE < 256
    #define STM32_SECTOR_SIZE   1024   // 字節
#else 
    #define STM32_SECTOR_SIZE   2048
#endif

// 一個扇區的內存
u16 STM32_FLASH_BUF[STM32_SECTOR_SIZE / 2];

void Med_Flash_Write (u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)
{
    u32 secpos;   // 扇區地址
    u16 secoff;   // 扇區內偏移地址(16位字計算)
    u16 secremain;   // 扇區內剩余地址(16位計算)    
     u16 i;    
    u32 offaddr;   // 去掉0X08000000后的地址
    
    // 判斷寫入地址是否在合法范圍內
    if (WriteAddr < STM32_FLASH_BASE || (WriteAddr >= (STM32_FLASH_BASE + 1024 * STM32_FLASH_SIZE)))
    {
        return;   // 非法地址
    }
    
    FLASH_Unlock();   // 解鎖
    offaddr = WriteAddr - STM32_FLASH_BASE;   // 實際偏移地址
    secpos = offaddr / STM32_SECTOR_SIZE;   // 扇區地址
    secoff = (offaddr % STM32_SECTOR_SIZE) / 2;   // 在扇區內的偏移(2個字節為基本單位)
    secremain = STM32_SECTOR_SIZE / 2 - secoff;   // 扇區剩余空間大小
    
    if (NumToWrite <= secremain)
    {
        secremain = NumToWrite;   // 不大于該扇區范圍
    }
    
    while (1) 
    {
        // 讀出整個扇區的內容
        Med_Flash_Read(secpos * STM32_SECTOR_SIZE + STM32_FLASH_BASE,STM32_FLASH_BUF,STM32_SECTOR_SIZE / 2);
        
        // 校驗數據
        for (i = 0;i < secremain;i ++)
        {
            // 需要擦除 
            if (STM32_FLASH_BUF[secoff + i] != 0XFFFF)
            {
                break; 
            }    
        }
        // 需要擦除
        if (i < secremain)
        {
            FLASH_ErasePage(secpos * STM32_SECTOR_SIZE + STM32_FLASH_BASE);   // 擦除這個扇區
            
            // 復制
            for (i = 0;i < secremain;i ++)
            {
                STM32_FLASH_BUF[i + secoff] = pBuffer[i];   
            }
            
            // 寫入整個扇區
            Med_Flash_Write_NoCheck(secpos * STM32_SECTOR_SIZE + STM32_FLASH_BASE,STM32_FLASH_BUF,STM32_SECTOR_SIZE / 2);
        }
        else
        {
            // 寫已經擦除了的,直接寫入扇區剩余區間
            Med_Flash_Write_NoCheck(WriteAddr,pBuffer,secremain);
        }
        
        if (NumToWrite == secremain)
        {
            break;   // 寫入結束了
        }
        // 寫入未結束
        else
        {
            secpos ++;   // 扇區地址增1
            secoff = 0;   // 偏移位置為0   
            pBuffer += secremain;   // 指針偏移
            WriteAddr += secremain;   // 寫地址偏移    
            NumToWrite -= secremain;   // 字節(16位)數遞減
            if (NumToWrite > (STM32_SECTOR_SIZE / 2))
            {
                secremain = STM32_SECTOR_SIZE / 2;   // 下一個扇區還是寫不完
            }
            else
            {
                secremain = NumToWrite;   // 下一個扇區可以寫完了
            }
        }  
    } 
    FLASH_Lock();   // 上鎖
}

5.3 IAP程序

IAP程序包含兩部分,一部分是將接收到的.bin文件寫入Flash,另一部分是跳轉到App執行。

/*
 *==============================================================================
 *函數名稱:iap_write_appbin
 *函數功能:寫入.bin文件
 *輸入參數:appxaddr:App程序起始地址;appbuf:緩存App程序的數組;
                        appsize:App程序大小
 *返回值:無
 *備  注:無
 *==============================================================================
 */
 // 對Flash操作的最小單位是16位
 u16 iapbuf[1024];   // 要寫入Flash的內容
 
void iap_write_appbin (u32 appxaddr,u8 *appbuf,u32 appsize)
{
    u16 t;   // 臨時循環變量
    u16 i = 0;   // 自增索引
    u16 temp;   // 臨時計算變量
    
    u32 fwaddr = appxaddr;   // 當前寫入的地址
    u8 *dfu = appbuf;   // 指向App代碼數組首地址的指針
    
    // for循環,2K為單位進行寫入
    for(t = 0;t < appsize;t += 2)
    {  
        temp = (u16)dfu[1] < < 8;
        temp += (u16)dfu[0];   
        dfu += 2;   // 偏移2個字節
        iapbuf[i++] = temp;     
        if(i == 1024)
        {
            i = 0;
            Med_Flash_Write (fwaddr,iapbuf,1024); 
            fwaddr += 2048;   // 偏移2048  16=2*8所以要乘以2
        }
    }
    if(i)
    {
        Med_Flash_Write (fwaddr,iapbuf,i);   // 將最后的一些內容字節寫進去
    }
}
/*
 *==============================================================================
 *函數名稱:iap_load_app
 *函數功能:跳轉到App
 *輸入參數:appxaddr:App程序起始地址
 *返回值:無
 *備  注:無
 *==============================================================================
 */
iapfun jump2app;

void iap_load_app (u32 appxaddr)
{
    if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000)   // 檢查棧頂地址是否合法
    { 
        jump2app=(iapfun)*(vu32*)(appxaddr+4);   // 用戶代碼區第二個字為程序開始地址(復位地址)  
        MSR_MSP(*(vu32*)appxaddr);   // 初始化APP堆棧指針(用戶代碼區的第一個字用于存放棧頂地址)
        jump2app();   // 跳轉到APP
    }
}

5.4 main函數

main函數設計如下

int main(void)
{
    u32 curRecCunt = 0;   // 當前接收數量
    
    // 設置NVIC中斷分組2:2位搶占優先級,2位響應優先級
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    delay_init();   // 延時初始化
    uart_init(115200);   // 串口初始化
    
    printf ("Enter the Bootloader Code!rn");
    
    while(1)
  {
        // 如果接收到內容且傳輸完成
        if (curRecCunt == gReceCount && gReceCount != 0)
        {
            printf ("App Code reception complete!rn");
            printf ("The length of the received App code is %d!rn",gReceCount);
            
            // 開始準備寫入Flash
            if(((*(vu32*)(0X20001000+4)) & 0xFF000000) == 0x08000000)   // 判斷是否為0X08XXXXXX.
            {
                iap_write_appbin(FLASH_APP1_ADDR,gReceFifo,gReceCount);   // 更新FLASH代碼  
                gReceCount = 0;   // 清零接收計數變量
                printf("Update complete!rn");
            }
            else 
            { 
                printf("Update error!rn");
            }
            
            // 準備跳轉App執行
            if(((*(vu32*)(FLASH_APP1_ADDR+4))&0xFF000000)==0x08000000)   //判斷是否為0X08XXXXXX.
            {
                printf("Enter App!rn");
                iap_load_app(FLASH_APP1_ADDR);   //執行FLASH APP代碼
            }else 
            {
                printf("Enter error!rn");
            } 
        }
        else   // 未傳輸完成
        {
            curRecCunt = gReceCount;   // 更新當前接收數量
            // 延時一定要有,給串口中斷留出時間
            // 如果沒有會導致接收不完全
            delay_ms(10);
        }
    }
}

六、注意事項

需要注意的是,上面的程序中App程序是從0x8010000開始,需要配置好程序起始地址和中斷向量表偏移

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 寄存器
    +關注

    關注

    31

    文章

    5419

    瀏覽量

    123241
  • STM32
    +關注

    關注

    2289

    文章

    11010

    瀏覽量

    362179
  • 上位機
    +關注

    關注

    27

    文章

    960

    瀏覽量

    55560
  • 中斷向量
    +關注

    關注

    0

    文章

    14

    瀏覽量

    9071
  • flash內存
    +關注

    關注

    0

    文章

    5

    瀏覽量

    2236
收藏 人收藏

    評論

    相關推薦
    熱點推薦

    基于STM32串口環形隊列IAP調試

    基于STM32串口環形隊列IAP調試心得
    的頭像 發表于 09-18 15:33 ?1912次閱讀
    基于<b class='flag-5'>STM32</b>的<b class='flag-5'>串口</b>環形隊列<b class='flag-5'>IAP</b>調試

    STM32L152的IAP移植筆記

    本文將針對STML152的IAP移植過程作一個筆記。首先得下載AN3310的示例代碼,下載完成后,我們需要做些修改,我們將在NUCLEO-L152RE板子上進行驗證測試。由于
    發表于 03-26 14:39

    STM32是如何實現IAP功能的

    STM32實現IAP功能的學習筆記最近因項目需求要實現STM32的在線升級即IAP功能,先將這幾天的學習體會和
    發表于 08-11 08:07

    求大佬分享STM32F4串口IAP學習筆記

    求大佬分享STM32F4串口IAP學習筆記
    發表于 12-08 06:41

    STM32F103學習筆記串口通信

    STM32F103學習筆記串口通信
    發表于 11-25 09:06 ?71次下載
    <b class='flag-5'>STM32</b>F103學習<b class='flag-5'>筆記</b>三   <b class='flag-5'>串口</b>通信

    STM32--STM32F051 IAP的實現

    一、IAP原理及過程《正點原子--STM32F10x串口IAP實驗》《stm32f030 IAP
    發表于 11-29 15:06 ?33次下載
    <b class='flag-5'>STM32--STM32</b>F051 <b class='flag-5'>IAP</b>的實現

    [筆記]|[stm32]|[寄存器存儲器區別]|[PWM]|[串口]|[Timer]stm32f103筆記

    [筆記]|[stm32]|[寄存器存儲器區別]|[PWM]|[串口]|[Timer]stm32f103筆記
    發表于 12-06 18:51 ?10次下載
    [<b class='flag-5'>筆記</b>]|[<b class='flag-5'>stm32</b>]|[寄存器存儲器區別]|[PWM]|[<b class='flag-5'>串口</b>]|[Timer]<b class='flag-5'>stm32</b>f103<b class='flag-5'>筆記</b>

    STM32實現IAP功能的學習筆記

    最近因項目需求要實現STM32的在線升級即IAP功能,先將這幾天的學習體會和IAP的具體實現總結出來,分享給大家,希望對同樣實現IAP的童鞋有所幫助,文中
    發表于 12-27 18:41 ?12次下載
    <b class='flag-5'>STM32</b>實現<b class='flag-5'>IAP</b>功能的學習<b class='flag-5'>筆記</b>

    基于STM32F103的IAP串口升級源碼

    基于STM32F103的IAP串口升級源碼代碼,共兩個工程,bl+app分享
    發表于 09-23 17:08 ?56次下載

    N32WB452系列芯片串口IAP升級應用筆記

    N32WB452系列芯片串口IAP升級應用筆記
    發表于 11-10 19:51 ?0次下載
    N32WB452系列芯片<b class='flag-5'>串口</b><b class='flag-5'>IAP</b>升級應用<b class='flag-5'>筆記</b>

    N32G4FR系列芯片串口IAP升級應用筆記

    N32G4FR系列芯片串口IAP升級應用筆記
    發表于 11-10 19:51 ?10次下載
    N32G4FR系列芯片<b class='flag-5'>串口</b><b class='flag-5'>IAP</b>升級應用<b class='flag-5'>筆記</b>

    N32G457系列芯片串口IAP升級應用筆記

    N32G457系列芯片串口IAP升級應用筆記
    發表于 11-10 19:51 ?1次下載
    N32G457系列芯片<b class='flag-5'>串口</b><b class='flag-5'>IAP</b>升級應用<b class='flag-5'>筆記</b>

    N32G455系列芯片串口IAP升級應用筆記

    N32G455系列芯片串口IAP升級應用筆記
    發表于 11-10 19:51 ?9次下載
    N32G455系列芯片<b class='flag-5'>串口</b><b class='flag-5'>IAP</b>升級應用<b class='flag-5'>筆記</b>

    N32G452系列芯片串口IAP升級應用筆記

    N32G452系列芯片串口IAP升級應用筆記
    發表于 11-10 19:51 ?5次下載
    N32G452系列芯片<b class='flag-5'>串口</b><b class='flag-5'>IAP</b>升級應用<b class='flag-5'>筆記</b>

    AN3965 STM32F40x和STM32F41x基于串口IAP

    AN3965 STM32F40x和STM32F41x基于串口IAP
    發表于 11-24 08:31 ?0次下載
    AN3965 <b class='flag-5'>STM32</b>F40x和<b class='flag-5'>STM32</b>F41x基于<b class='flag-5'>串口</b>的<b class='flag-5'>IAP</b>