STM32固件升級設計——SD卡升級固件

目錄

概述

一、功能描述?

1、BootLoader部分:

2、APP部分:

二、BootLoader程序制作

1、分區定義

2、 主函數

3、SD卡升級文件檢測和更新

4、程序跳轉

三、APP程序制作

四、工程配置(默認KEIL5)

五、運行測試?

結束語


概述

????????IAP(In Application Programming)即在應用中編程,允許在應用程序運行時更新或切換固件。STM32通過修改MSP(主堆棧指針)和PC(程序計數器)實現從不同地址啟動,包括Flash或RAM地址。默認情況下,嵌入式程序以連續二進制形式燒錄到STM32的可尋址Flash區域。若Flash容量足夠存儲多個完整程序,每個程序獨立且完整,上電后可通過修改MSP值選擇不同程序入口,從而實現多固件切換或升級。

?????????BootLoader(引導加載程序)是嵌入式系統或計算機啟動時運行的一段小型程序,負責初始化硬件、加載操作系統內核并將其控制權移交。它是系統從關機狀態到操作系統完全運行之間的橋梁。

????????所以,固件升級的基本思路是將stm32的flash劃分為若干個區域,其中包括BootLoader區域和APP區等,將各自的程序寫到對應的flash區域里,本文將采用讀取SD卡的文件來更新固件,只重實踐不講原理。

一、功能描述?

????????使用STM32的SDIO總線驅動microSD卡實現SD卡升級程序。將FLASH分為2個部分。
分區介紹:
????????本文使用stm32f407zgt6,flash是1M,sector是不固定的(在讀寫擦除flash時需要特別注意),詳細看下圖STM32F4系列的FLASH結構。

????????BootLoader整個代碼編譯下來有36K左右,所以使用0x08000000~0x0000FFFF,剩下的FLASH全部用來存放APP,使用0x08010000~0x080F0000。

區域起始地址區域大小功能
BOOT0x080000000x00010000(64k)存放BootLoader程序
APP0x080100000x000F0000(960k)存放產品主程序

tips:?選擇以上分區方式的好處是在上電瞬間可以觸發升級,只要SD卡里面根目錄有正確的程序都可以更新固件,所以就沒必要用到SETTING區域在存更新觸發標志位了。

1、BootLoader部分:

????????運行時首先會初始化SD卡,如果初始化成功并且檢測到存在SD卡,就查找根目錄是否有firmware.bin文件,如果有就升級,沒有就直接進入APP,檢測不到SD卡也會直接進入APP。

2、APP部分:

????????該部分需要在程序起始設置中斷向量跳轉指針,剩下的就是自己寫的主程序。

二、BootLoader程序制作

????????主要包含了YMODEM協議的驅動代碼。

1、分區定義
#define FLASH_SECTOR_SIZE           1024
#define FLASH_SECTOR_NUM            1024    // 1024K
#define FLASH_START_ADDR            ((uint32_t)0x8000000)
#define FLASH_END_ADDR              ((uint32_t)(0x8000000 + FLASH_SECTOR_NUM * FLASH_SECTOR_SIZE))//flash sector addr
#define ADDR_FLASH_SECTOR_0         ((uint32_t)0x08000000) 	//sector0 addr, 16 Kbytes  
#define ADDR_FLASH_SECTOR_1         ((uint32_t)0x08004000) 	//sector1 addr, 16 Kbytes  
#define ADDR_FLASH_SECTOR_2         ((uint32_t)0x08008000) 	//sector2 addr, 16 Kbytes  
#define ADDR_FLASH_SECTOR_3         ((uint32_t)0x0800C000) 	//sector3 addr, 16 Kbytes  
#define ADDR_FLASH_SECTOR_4         ((uint32_t)0x08010000) 	//sector4 addr, 64 Kbytes  
#define ADDR_FLASH_SECTOR_5         ((uint32_t)0x08020000) 	//sector5 addr, 128 Kbytes  
#define ADDR_FLASH_SECTOR_6         ((uint32_t)0x08040000) 	//sector6 addr, 128 Kbytes  
#define ADDR_FLASH_SECTOR_7         ((uint32_t)0x08060000) 	//sector7 addr, 128 Kbytes  
#define ADDR_FLASH_SECTOR_8         ((uint32_t)0x08080000) 	//sector8 addr, 128 Kbytes  
#define ADDR_FLASH_SECTOR_9         ((uint32_t)0x080A0000) 	//sector9 addr, 128 Kbytes  
#define ADDR_FLASH_SECTOR_10        ((uint32_t)0x080C0000) 	//sector10 addr,128 Kbytes  
#define ADDR_FLASH_SECTOR_11        ((uint32_t)0x080E0000) 	//sector11 addr,128 Kbytes  #define BOOT_SECTOR_ADDR            0x08000000
#define BOOT_SECTOR_SIZE            0x10000
#define APP_SECTOR_ADDR             0x08010000     // APP sector start address  
#define APP_SECTOR_SIZE             0xF0000        // APP sector size    #define BOOT_ERASE_SECTORS_NUM      4  // 64k
#define APP_ERASE_SECTORS_NUM       8  // 64k+128k+128k+128k+128k+128k+128k+128ktypedef enum 
{NONE,START_PROGRAM,UPDATE_PROGRAM,UPDATE_SUCCESS,
} process_status;
2、 主函數

????????這部分包含了升級的所有狀態,該框架可以說對比上一篇文章是完全不變的,主要是SD卡初始化沒問題就成功一大半了,具體看代碼。

static void iap_process(void)
{switch (bootupdate_process) {case NONE:break;case START_PROGRAM:printf("start app...\r\n");delay_ms(50);if ((((*(vu32*)(APP_SECTOR_ADDR+4))&0xFF000000)==0x08000000)&&(!iap_load_app(APP_SECTOR_ADDR))) {printf("no program\r\n");delay_ms(1000);}printf("start app failed\r\n");break;case UPDATE_PROGRAM:if(SD_Init()==0){printf("檢測到SD卡\r\n");show_sdcard_info();	//打印SD卡相關信息sd_update();}else{printf("沒檢測到SD卡\r\n");}bootupdate_process = UPDATE_SUCCESS;break;case UPDATE_SUCCESS:bootupdate_process = START_PROGRAM;
//			NVIC_SystemReset();break;default:break;}
}int main(void)
{        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//設置系統中斷優先級分組2delay_init(168);  //初始化延時函數uart_init(115200);		//初始化串口波特率為115200LED_Init();					//初始化LED bootupdate_process=UPDATE_PROGRAM;while(1){delay_ms(200);		 			   LED0=!LED0;iap_process();} 
}
3、SD卡升級文件檢測和更新

? ? ? ? 關于SD卡和FATFS文件系統的移植我是參考正點原子的,主要是將malloc用全局變量代替,其它需要注意的是SD卡的扇區需要選擇512字節。

本來是存放在堆區的,現改為存放在棧區

#define?? ?_USE_LFN?? ?2?? ??? ?/* 0 to 3 */

????????掛載SD卡,判斷sd卡根目錄下是否有firmware.bin文件,有的話就獲取一下該固件占用了多少個扇區,對應去擦除扇區,然后就可以復制固件到APP起始地址了。不存在該固件的話就直接退出進入APP。

void sd_update(void) 
{u8 file_buffer[512]={0};   uint32_t flash_addr = APP_SECTOR_ADDR;unsigned long total_bytes_read = 0;UINT bytes_read;fres=f_mount(&fs[0],"0:",1); 				//掛載FLASH.	if(fres==FR_OK)                             //FLASH磁盤,FAT文件系統正常{printf("Flash disk OK!\r\n");}// 判斷sd卡根目錄下是否有firmware.bin文件fres = f_stat("0:/firmware.bin", &fno);if(fres == FR_OK){printf("0:/firmware.bin”文件信息:\n");printf("》文件大小: %ld(字節)\n", fno.fsize);printf("sector_num=%d\r\n",get_mcu_flash_sector(flash_addr+(u32)fno.fsize)/8-4+1);mcu_flash_erase(flash_addr, get_mcu_flash_sector(flash_addr+(u32)fno.fsize)/8-4+1);}else{printf("firmware.bin not found!\r\n");}if(fres == FR_OK) {// 文件存在printf("firmware.bin found, size: %lu bytes\r\n", fno.fsize);printf("開始更新固件...\r\n");// 打開固件文件fres = f_open(&firmware_file, "0:/firmware.bin", FA_READ);if(fres == FR_OK) {// 循環讀取文件內容while (total_bytes_read < fno.fsize){// 讀取數據塊到緩沖區fres = f_read(&firmware_file, file_buffer, 512, &bytes_read);if (fres != FR_OK || bytes_read == 0){// 讀取出錯或到達文件末尾printf("讀取文件失敗或文件已結束,錯誤碼: %d\r\n", fres);break;}// 寫入到FLASHprintf("正在寫入地址 0x%08X,大小: %u 字節\r\n", flash_addr, bytes_read);mcu_flash_write(flash_addr, file_buffer, bytes_read);// 更新計數器和地址total_bytes_read += bytes_read;flash_addr += bytes_read;// 顯示進度printf("更新進度: %lu/%lu bytes\r\n", total_bytes_read, fno.fsize);}// 關閉文件f_close(&firmware_file);if (total_bytes_read == fno.fsize) {printf("固件更新完成! 共寫入 %lu 字節\r\n", total_bytes_read);} else {printf("固件更新未完成! 已寫入 %lu/%lu 字節\r\n", total_bytes_read, fno.fsize);}}}	else {// 文件不存在printf("firmware.bin not found!\r\n");}
}
4、程序跳轉

????????跳轉這部分網上也很多,基本沒什么區別,語句很少,建議每一步都去查一下大概意思。

tips:本文的開發環境有128k ram,所以下列語句需要判斷跳轉地址是否超出。

if (((*(__IO uint32_t*)appxaddr) & 0x2FFE0000 ) == 0x20000000)

詳細參考以下文章:

關于STM32單片機IAP升級中if(((*(__IO uint32_t*)ulAddr_App) & 0x2FFE0000) == 0x20000000)語句的理解-CSDN博客

iapfun jump2app;uint8_t iap_load_app(uint32_t app_addr) 
{uint32_t jump_addr;if (((*(__IO uint32_t*)app_addr) & 0x2FFE0000 ) == 0x20000000) {  jump_addr = *(__IO uint32_t*) (app_addr + 4);  jump2app = (iapfun)jump_addr;  __set_MSP(*(__IO uint32_t*)app_addr);  jump2app();return 1;} return 0;
}

三、APP程序制作

????????這部分只需要設置一下flash的偏移量。

NVIC_SetVectorTable (NVIC_VectTab_FLASH, 0x08010000);	//向量重定向	

四、工程配置(默認KEIL5)

BootLoader部分:0x08000000~0x0800FFFF

?

APP部分:0x08010000~0x080F0000

五、運行測試?

(1)首先將firmware.bin固件存放到SD卡的根目錄。? ? ??

(2)沒插上SD卡的情況,直接進入APP程序。

(3)上電前插入SD卡后啟動的情況,可以看到檢測到SD卡并且打印SD卡的基礎信息,找到firmware.bin文件后就開始按512字節寫入APP的起始地址,寫完后進入新的APP程序。之后需要拔出SD卡,不然每次上電都會執行更新程序步驟。?

?

結束語

????????以上SD卡升級stm32單片機功能已實現,思路和我前面寫的文章一模一樣,思路理解了就能一直套娃了,所以便一股腦移植SD卡了,建議大家在移植的時候對照著文檔或者SDK直接移植過來,當然用HAL庫更好。后面大家看到的也希望可以得到大家的指點或者互動,感謝各位亦菲彥祖們了。

完整代碼下載地址:SD卡升級stm32固件資源-CSDN下載

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/89099.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/89099.shtml
英文地址,請注明出處:http://en.pswp.cn/web/89099.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

基于Python的圖像文字識別系統

主要語言&#xff1a;Python數據庫&#xff1a;SQLiteUI界面&#xff1a;PYQT5文字識別模型&#xff1a;Tesseract OCR&#xff08;本地搭建&#xff09;主要功能&#xff1a;登錄注冊&#xff1a;登錄注冊功能。圖片管理&#xff1a;單張/多張上傳、圖片列表、預覽、刪除、切換…

028_分布式部署架構

028_分布式部署架構 概述 本文檔介紹如何設計和實現Claude應用的分布式部署架構&#xff0c;包括負載均衡、緩存策略、服務發現、容錯機制等。 微服務架構設計 1. 服務拆分策略 from abc import ABC, abstractmethod from typing import Dict, Any, Optional import asyncio im…

duckdb和pyarrow讀寫arrow格式的方法

arrow格式被多種分析型數據引擎廣泛采用&#xff0c;如datafusion、polars。duckdb有一個arrow插件&#xff0c;原來是core插件&#xff0c;1.3版后被廢棄&#xff0c;改為社區級插件&#xff0c;名字改為nanoarrow, 別名還叫arrow。 安裝 D install arrow from community; D…

機器人位姿變換的坐標系相對性:左乘法則與右乘法則解析?

文章目錄1. 全局坐標系下機器人位姿更新的左乘法則?2. 局部坐標系下機器人位姿增量更新的右乘法則?3. 相對位姿的計算3.1. 基于世界坐標系&#xff08;全局變換&#xff09;3.2. 基于 t1t_1t1? 時刻相機的局部坐標系&#xff08;局部變換&#xff09;3.3. 兩者區別設機器人當…

代碼隨想錄算法訓練營65期第20天

代碼隨想錄算法訓練營65期第20天 本文中使用到一些代碼隨想錄里面的圖片或者鏈接&#xff0c;在這里致敬程序員Carl 二叉搜索樹的最近公共祖先 相對于 二叉樹的最近公共祖先 本題就簡單一些了&#xff0c;因為 可以利用二叉搜索樹的特性。 題目鏈接&#xff1a;代碼隨想錄&…

LLaMA.cpp HTTP 服務參數: --pooling 嵌入模型 池化類型詳解

LLaMA.cpp HTTP 服務參數: --pooling 嵌入模型 池化類型詳解 --pooling {none,mean,cls,last,rank} 在 llama.cpp 的 embedding server 中&#xff0c;--pooling {none,mean,cls,last,rank} 參數用于指定 如何將輸入文本的 token 級嵌入向量聚合為句向量。以下是各選項的詳細解…

「日拱一碼」027 深度學習庫——PyTorch Geometric(PyG)

目錄 數據處理與轉換 數據表示 數據加載 數據轉換 特征歸一化 添加自環 隨機擾動 組合轉換 圖神經網絡層 圖卷積層&#xff08;GCNConv&#xff09; 圖注意力層&#xff08;GATConv&#xff09; 池化 全局池化&#xff08;Global Pooling&#xff09; 全局平均池…

IoC容器深度解析:架構、原理與實現

&#x1f31f; IoC容器深度解析&#xff1a;架構、原理與實現 引用&#xff1a; .NET IoC容器原理與實現等巫山的雲彩都消散撒下的碧色如何看淡 &#x1f50d; 一、引言&#xff1a;從服務定位器到IoC的演進 #mermaid-svg-BmRIuI4iMgiUqFVN {font-family:"trebuchet ms&…

從零開始學前端html篇3

表單基本結構表單是 HTML 中用于創建用戶輸入區域的標簽。它允許用戶輸入數據&#xff08;例如文本、選擇選項、文件等&#xff09;&#xff0c;并將這些數據提交到服務器進行處理。<form>&#xff0c;表單標簽&#xff0c;用于創建表單常用屬性&#xff1a;action&#…

Linux系統調優和工具

Linux系統調優和問題定位需要掌握一系列強大的工具&#xff0c;涵蓋系統監控、性能分析、故障排查等多個方面。以下是一些核心工具和它們的典型應用場景&#xff0c;分類整理如下&#xff1a; 一、系統資源監控&#xff08;實時概覽&#xff09;top / htop 功能&#xff1a; 實…

如何快速有效地在WordPress中添加Instagram動態

在當今社交媒體的時代&#xff0c;通過展示Instagram的最新動態&#xff0c;可以有效吸引讀者的目光&#xff0c;同時豐富網站內容。很多人想知道&#xff0c;如何把自己精心運營的Instagram內容無縫嵌入WordPress網站呢&#xff1f;別擔心&#xff0c;操作并不復雜&#xff0c…

spring容器加載工具類

在Spring框架中&#xff0c;工具類通常不需要被Spring容器管理&#xff0c;但如果確實需要獲取Spring容器中的Bean實例&#xff0c;可以通過靜態方法設置和獲取ApplicationContext。下面是一個典型的Spring容器加載工具類的實現&#xff1a;這個工具類通過實現ApplicationConte…

定時器更新中斷與串口中斷

問題&#xff1a;我想把打印姿態傳感器的角度&#xff0c;但是重定向的打印函數突然打印不出來。嘗試&#xff1a;我懷疑是優先級的問題&#xff0c;故調整了串口&#xff0c;定時器&#xff0c;dma的優先級可是發現調了還是沒有用&#xff0c;最終發現&#xff0c;我把定時器中…

用Python向PDF添加文本:精確插入文本到PDF文檔

PDF 文檔的版式特性使其適用于輸出不可變格式的報告與合同。但若要在此類文檔中插入或修改文本&#xff0c;常規方式難以實現。借助Python&#xff0c;我們可以高效地向 PDF 添加文本&#xff0c;實現從文檔生成到內容管理的自動化流程。 本文將從以下方面介紹Python實現PDF中…

Quick API:賦能能源行業,化解數據痛點

隨著全球能源結構的轉型和數字化的深入推進&#xff0c;能源行業正面臨前所未有的機遇與挑戰。海量的實時數據、復雜的業務系統、以及對數據安全和高效利用的迫切需求&#xff0c;都成為了能源企業在數字化轉型道路上的核心痛點。本文將深入探討麥聰Quick API如何憑借其獨特優勢…

Google Chrome V8< 13.6.86 類型混淆漏洞

【高危】Google Chrome V8< 13.6.86 類型混淆漏洞 漏洞描述 Google Chrome 是美國谷歌&#xff08;Google&#xff09;公司的一款Web瀏覽器&#xff0c;V8 是 Google 開發的高性能開源 JavaScript 和 WebAssembly 引擎&#xff0c;廣泛應用于 Chrome 瀏覽器和 Node.js 等環…

力扣經典算法篇-23-環形鏈表(哈希映射法,快慢指針法)

1、題干 給你一個鏈表的頭節點 head &#xff0c;判斷鏈表中是否有環。 如果鏈表中有某個節點&#xff0c;可以通過連續跟蹤 next 指針再次到達&#xff0c;則鏈表中存在環。 為了表示給定鏈表中的環&#xff0c;評測系統內部使用整數 pos 來表示鏈表尾連接到鏈表中的位置&…

HarmonyOS DevEco Studio 小技巧 42 - 鴻蒙單向數據流

在鴻蒙應用開發中&#xff0c;狀態管理是構建響應式界面的核心支柱&#xff0c;而 單向數據流&#xff08;Unidirectional Data Flow, UDF&#xff09;作為鴻蒙架構的重要設計原則&#xff0c;貫穿于組件通信、狀態更新和界面渲染的全流程。本文將結合鴻蒙 ArkUI 框架特性&…

【LeetCode 3136. 有效單詞】解析

目錄LeetCode中國站原文原始題目題目描述示例 1&#xff1a;示例 2&#xff1a;示例 3&#xff1a;提示&#xff1a;講解化繁為簡&#xff1a;如何優雅地“盤”邏輯判斷題第一部分&#xff1a;算法思想 —— “清單核對”與“一票否決”第二部分&#xff1a;代碼實現 —— 清晰…

前端面試專欄-算法篇:24. 算法時間與空間復雜度分析

&#x1f525; 歡迎來到前端面試通關指南專欄&#xff01;從js精講到框架到實戰&#xff0c;漸進系統化學習&#xff0c;堅持解鎖新技能&#xff0c;祝你輕松拿下心儀offer。 前端面試通關指南專欄主頁 前端面試專欄規劃詳情 算法時間與空間復雜度分析&#xff1a;從理論到實踐…