FLASH閃存(擦除、編譯)

FLASH閃存

文章目錄

  • FLASH閃存
    • 1.存儲器映像位置
    • 2.FLASH簡介
    • 3.閃存模塊組織
      • 3.2閃存的共性:
    • 4.FLASH基本結構
      • 4.1FLASH解鎖
      • 4.2使用指針訪問寄存器
    • 5.選項字節
      • 5.1選項字節編程
      • 5.2選項字節擦除
    • 6.相關函數介紹
    • 7.讀取內部FLASH(實操)
      • 7.1接線圖
      • 7.2工程結構
      • 7.3代碼
    • 8.讀取芯片ID(實操)
      • 8.1接線圖
      • 8.2代碼

閃存是一個通用的名詞,表示一種非易失性,掉電不丟失的存儲器。比如PSI的W25Q64芯片。

本節的內容是stm32的內部閃存,也就是我們下載程序的時候,這個程序所存儲的地方。

1.存儲器映像位置

存儲器映像

類型起始地址存儲器用途
ROM0x0800 0000程序存儲器Flash存儲C語言編譯后的程序代碼
0x1FFF F000系統存儲器存儲BootLoader,用于串口下載
0x1FFF F800選項字節存儲一些獨立于程序代碼的配置參數
RAM0x2000 0000運行內存SRAM存儲運行過程中的臨時變量
0x4000 0000外設寄存器存儲各個外設的配置參數
0xE000 0000內核外設寄存器存儲內核各個外設的配置參數

其中程序存儲器是空間最大,最主要的部分,稱作主存儲器。

2.FLASH簡介

  • STM32F1系列的FLASH包含程序存儲器、系統存儲器和選項字節三個部分,通過閃存存儲器接口(外設)可以對程序存儲器和選項字節進行擦除和編程
  • 讀寫FLASH的用途:
    • **利用程序存儲器的剩余空間來保存掉電不丟失的用戶數據 **
    • 通過在程序中編程(IAP),實現程序的自我更新
  • 在線編程(In-Circuit Programming – ICP)用于更新程序存儲器的全部內容,它通過JTAG、SWD協議或系統加載程序(Bootloader)下載程序
  • 在程序中編程(In-Application Programming – IAP)可以使用微控制器支持的任一種通信接口下載程序

JTAG、SWD協議就是仿真器下載程序,就是目前使用的ST_Link使用SWD下載程序。每次下載都是把整個程序完全更新掉。

Bootloader串口下載,也是更新整個程序,這就是ICP下載方式。

3.閃存模塊組織

C8T6的閃存容量是64K,屬于中容量產品。

閃存組織模塊

啟動程序代碼:系統存儲器,存放的是原廠寫入的Bootloader,用于串口下載

用戶選擇字節:也就是選項字節,存放一些獨立的參數

閃存存儲器接口寄存器,實際上并不屬于閃存,地址都是40開頭的,說明這個存儲器接口寄存器,就是一個普通的外設和GPIO、定時器,串口等等都是一個性質的東西,都是SARM。

簡言之,閃存存儲器接口寄存器就是上面那些閃存的管理員,這些寄存器就是用來控制擦除和編程這個過程的

閃存的基本單位為頁,共128K,而C8T6只有一半,為64頁,共64K。所說的閃存的容量也只是主存儲器的容量。

3.2閃存的共性:

  1. 寫入前必須擦除
  2. 擦除必須以最小單位進行
  3. 擦除后數據位全變為1
  4. 數據只能1寫0,不能0寫1
  5. 擦除和寫入之后都需要等待忙

4.FLASH基本結構

分為程序存儲器,系統存儲器和選項字節三部分。

FLASH基本結構

4.1FLASH解鎖

  • FPEC共有三個鍵值:
    • RDPRT鍵 = 0x000000A5
    • KEY1 = 0x45670123
    • KEY2 = 0xCDEF89AB
  • 解鎖:
    • 復位后,FPEC被保護,不能寫入FLASH_CR
    • 在FLASH_KEYR先寫入KEY1,再寫入KEY2,解鎖
    • 錯誤的操作序列會在下次復位前鎖死FPEC和FLASH_CR
  • 加鎖: 設置FLASH_CR中的LOCK位鎖住FPEC和FLASH_CR(就是LOCK位寫入1就好了)

4.2使用指針訪問寄存器

  • 使用指針讀指定地址下的存儲器:
    • uint16_t Data = *((__IO uint16_t *)(0x08000000));
  • 使用指針寫指定地址下的存儲器:
    • *((__IO uint16_t *)(0x08000000)) = 0x1234;
  • 其中:
    • #define __IO volatile

讀直接讀寫入,寫需要先解鎖。

5.選項字節

選項字節

  • RDP:寫入RDPRT鍵(0x000000A5)后解除讀保護
  • USER:配置硬件看門狗和進入停機/待機模式是否產生復位
  • Data0/1:用戶可自定義使用
  • WRP0/1/2/3:配置寫保護,每一個位對應保護4個存儲頁(中容量)

寫入RDP存儲器時,要在對應的存儲器寫入反碼。(寫入RDP時要在nRDP寫入對應的反碼)。如果不是反碼的關系,則代表數據無效,對應功能不執行。

5.1選項字節編程

  • 檢查FLASH_SR的BSY位,以確認沒有其他正在進行的編程操作
  • 解鎖FLASH_CR的OPTWRE位
  • 設置FLASH_CR的OPTPG位為1
  • 寫入要編程的半字到指定的地址
  • 等待BSY位變為0
  • 讀出寫入的地址并驗證數據*

5.2選項字節擦除

  • 檢查FLASH_SR的BSY位,以確認沒有其他正在進行的閃存操作
  • 解鎖FLASH_CR的OPTWRE位
  • 設置FLASH_CR的OPTER位為1
  • 設置FLASH_CR的STRT位為1等待BSY位變為0
  • 讀出被擦除的選擇字節并做驗證

6.相關函數介紹

void FLASH_SetLatency(uint32_t FLASH_Latency);
void FLASH_HalfCycleAccessCmd(uint32_t FLASH_HalfCycleAccess);
void FLASH_PrefetchBufferCmd(uint32_t FLASH_PrefetchBuffer);
//與內核運行代碼有關不需要太多了解。
void FLASH_Unlock(void);//解鎖
void FLASH_Lock(void);//加鎖,LOCK位設置為1
FLASH_Status FLASH_ErasePage(uint32_t Page_Address);//閃存擦除某一頁,參數給一頁的起始地址,返回值為執行狀態
FLASH_Status FLASH_EraseAllPages(void);//全擦除操作
FLASH_Status FLASH_EraseOptionBytes(void);//擦除選項字節
FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data);//指定地址寫入字
FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data);//指定地址寫入半字
FLASH_Status FLASH_ProgramOptionByteData(uint32_t Address, uint8_t Data); //自定義的data0和data1
FLASH_Status FLASH_EnableWriteProtection(uint32_t FLASH_Pages);//寫保護
FLASH_Status FLASH_ReadOutProtection(FunctionalState NewState);//讀保護
FLASH_Status FLASH_UserOptionByteConfig(uint16_t OB_IWDG, uint16_t OB_STOP, uint16_t OB_STDBY);//用戶選項的三個配置位
//上面4個是選項字節的寫入
//對主閃存和選項字節,進行擦除和編程的函數
uint32_t FLASH_GetUserOptionByte(void);//獲取用戶選項的三個配置位
uint32_t FLASH_GetWriteProtectionOptionByte(void);//獲取寫保護狀態
FlagStatus FLASH_GetReadOutProtectionStatus(void);//獲取讀保護狀態
//獲取選項字節當前的狀態
FlagStatus FLASH_GetPrefetchBufferStatus(void);//獲取預取緩沖區狀態
void FLASH_ITConfig(uint32_t FLASH_IT, FunctionalState NewState);//中斷使能
FlagStatus FLASH_GetFlagStatus(uint32_t FLASH_FLAG);//獲取標志位
void FLASH_ClearFlag(uint32_t FLASH_FLAG);//清除標志位
FLASH_Status FLASH_GetStatus(void);//獲取狀態
FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout);//等待上一次操作,系統內部會調用,所以不用單獨調用

7.讀取內部FLASH(實操)

7.1接線圖

讀寫內部FLASH

7.2工程結構

這里打算弄兩個底層模塊:

最底層叫MY_FLASH:這里實現閃存最基本的三個功能:讀取、擦除和編程

上面層叫STORE:實現參數數據的讀寫和數據管理,定義一個SRAM數組,需要掉電不丟失的參數就寫到SRAM數組里,最后調用保存的函數,這個SRAM數組就自動備份到閃存里,上電后store初始化,會自動再把閃存里的數據讀回到SRAM數組里

最終實現的功能是:任意讀寫參數,并且這些參數是掉電不丟失的

7.3代碼

代碼部分主要就是對封裝完的庫函數進行調用。將數據封裝到,數組,再將數組的內容寫到閃存,在重新上電后再寫回去實現掉電不丟失。

主程序main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "LED.h"
#include "KEY.h"
#include "OLED.h"
//#include "OLED_Font.h"
#include "Store.h"uint16_t KeyNum = 0;int main(void)
{/*模塊初始化*/OLED_Init();				//OLED初始化Key_Init();					//按鍵初始化Store_Init();				//參數存儲模塊初始化,在上電的時候將閃存的數據加載回Store_Data,實現掉電不丟失/*顯示靜態字符串*/OLED_ShowString(1, 1, "Flag:");OLED_ShowString(2, 1, "Data:");while (1){KeyNum = Key_getNum();		//獲取按鍵鍵碼if (KeyNum == 1)			//按鍵1按下{Store_Data[1] ++;		//變換測試數據Store_Data[2] += 2;Store_Data[3] += 3;Store_Data[4] += 4;Store_Save();			//將Store_Data的數據備份保存到閃存,實現掉電不丟失}if (KeyNum == 2)			//按鍵2按下{Store_Clear();			//將Store_Data的數據全部清0}OLED_ShowHexNum(1, 6, Store_Data[0], 4);	//顯示Store_Data的第一位標志位OLED_ShowHexNum(3, 1, Store_Data[1], 4);	//顯示Store_Data的有效存儲數據OLED_ShowHexNum(3, 6, Store_Data[2], 4);OLED_ShowHexNum(4, 1, Store_Data[3], 4);OLED_ShowHexNum(4, 6, Store_Data[4], 4);}
}

Store.c

#include "stm32f10x.h"                  // Device header
#include "MyFLASH.h"#define STORE_START_ADDRESS 0x0800FC00 //存儲的起始地址
#define STORE_COUNT			512		   //存儲數據的個數uint16_t Store_Data[STORE_COUNT];void Store_Init(void){//判斷是不是第一次使用if(MyFLASH_ReadHalfWord(STORE_START_ADDRESS)!=0xA5A5){//A5A5不是固定的,只是判斷是不是某個你設置的值,唯一,標志,IDMyFLASH_ErasePage(STORE_START_ADDRESS);MyFLASH_ProgramHalfWord(STORE_START_ADDRESS,0xA5A5);for(uint16_t i = 1;i<STORE_COUNT;i++){MyFLASH_ProgramHalfWord(STORE_START_ADDRESS+i*2,0x0000);}}for(uint16_t i = 0;i<STORE_COUNT;i++){Store_Data[i] = MyFLASH_ReadHalfWord(STORE_START_ADDRESS+i*2);}
}//保存:擦除界面后將數組的數據讀取到閃存界面
void Store_Save(void){MyFLASH_ErasePage(STORE_START_ADDRESS);//擦除指定頁for(uint16_t i = 0;i<STORE_COUNT;i++){MyFLASH_ProgramHalfWord(STORE_START_ADDRESS+i*2,Store_Data[i]);//將數組數據備份到閃存}
}//手動清除操作
void Store_Clear(void){for(uint16_t i = 1;i<STORE_COUNT;i++){Store_Data[i] = 0x0000;}Store_Save();
}

Store.h

#ifndef __STORE_H
#define __STORE_Hextern uint16_t Store_Data[];void Store_Init(void);
void Store_Save(void);
void Store_Clear(void);#endif

MyFLASH.c

#include "stm32f10x.h"                  // Device header//獲取32位的字
uint32_t MyFLASH_ReadWord(uint32_t Address){//stm32的地址都是32位的return *((__IO uint32_t * )(Address));
}//獲取16位的半字
uint16_t MyFLASH_ReadHalfWord(uint32_t Address){return *((__IO uint16_t * )(Address));
}
//獲取一字節
uint8_t MyFLASH_ReadByte(uint32_t Address){return *((__IO uint8_t * )(Address));//使用指針訪問
}//全擦除
void MyFLASH_EraseAllPages(void){FLASH_Unlock();//解鎖FLASH_EraseAllPages();//全擦除FLASH_Lock();//加鎖
}//頁擦除
void MyFLASH_ErasePage(uint32_t PageAddress){FLASH_Unlock();FLASH_ErasePage(PageAddress);FLASH_Lock();
}//寫入32位字
void MyFLASH_ProgramWord(uint32_t Address,uint32_t Data){FLASH_Unlock();FLASH_ProgramWord(Address,Data);FLASH_Lock();
}//寫入16位半字
void MyFLASH_ProgramHalfWord(uint32_t Address,uint16_t Data){FLASH_Unlock();FLASH_ProgramHalfWord(Address,Data);FLASH_Lock();
}

MyFLASH.h

#ifndef __MY_FLASH
#define __MY_FLASHuint32_t MyFLASH_ReadWord(uint32_t Address);
uint16_t MyFLASH_ReadHalfWord(uint32_t Address);
uint8_t MyFLASH_ReadByte(uint32_t Address);void MyFLASH_EraseAllPages(void);
void MyFLASH_ErasePage(uint32_t PageAddress);void MyFLASH_ProgramWord(uint32_t Address, uint32_t Data);
void MyFLASH_ProgramHalfWord(uint32_t Address, uint16_t Data);#endif

8.讀取芯片ID(實操)

8.1接線圖

讀取芯片ID

8.2代碼

主程序部分主要是讀取 STM32F10x 系列微控制器的唯一設備標識符(UID)并通過 OLED 顯示。

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "LED.h"
#include "KEY.h"
#include "OLED.h"
//#include "OLED_Font.h"int main(void){OLED_Init();OLED_ShowHexNum(1,8,*((__IO uint16_t *)(0x1FFFF7E0)),4);OLED_ShowString(2,1,"U_ID:");OLED_ShowHexNum(2,6,*((__IO uint16_t *)(0x1FFFF7E8)),4);OLED_ShowHexNum(2, 11, *((__IO uint16_t *)(0x1FFFF7E8 + 0x02)), 4);OLED_ShowHexNum(3, 1, *((__IO uint32_t *)(0x1FFFF7E8 + 0x04)), 8);OLED_ShowHexNum(4, 1, *((__IO uint32_t *)(0x1FFFF7E8 + 0x08)), 8);while(1){}
}

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

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

相關文章

PostgreSQL 序列(Sequence) 與 Oracle 序列對比

PostgreSQL 序列(Sequence) 與 Oracle 序列對比 PostgreSQL 和 Oracle 都提供了序列(Sequence)功能&#xff0c;但在實現細節和使用方式上存在一些重要差異。以下是兩者的詳細對比&#xff1a; 一 基本語法對比 1.1 創建序列 PostgreSQL: CREATE [ { TEMPORARY | TEMP } |…

12.2.2 allocator類

allocator類將分配內存空間、調用構造函數、調用析構函數、釋放內存空間這4部分操作分開&#xff0c;全部交給程序員來執行&#xff0c;不像new和delete #include <iostream> #include <string>int main() {const int n 10;std::allocator<std::string> al…

Android 中 Handler (創建時)內存泄漏問題及解決方案

一、Handler 內存泄漏核心原理 真題 1&#xff1a;分析 Handler 內存泄漏場景 題目描述&#xff1a; 在 Activity 中使用非靜態內部類 Handler 發送延遲消息&#xff0c;旋轉屏幕后 Activity 無法釋放&#xff0c;分析原因并給出解決方案。 內存泄漏鏈路分析&#xff1a; 引…

SSTI記錄

SSTI(Server-Side Template Injection&#xff0c;服務器段模板注入) 當前使用的一些框架&#xff0c;如python的flask、php的tp、java的spring&#xff0c;都采用成熟的MVC模式&#xff0c;用戶的輸入會先進入到Controller控制器&#xff0c;然后根據請求的類型和請求的指令發…

探索邊緣計算:賦能物聯網的未來

摘要 隨著物聯網&#xff08;IoT&#xff09;技術的飛速發展&#xff0c;越來越多的設備接入網絡&#xff0c;產生了海量的數據。傳統的云計算模式在處理這些數據時面臨著延遲高、帶寬不足等問題&#xff0c;而邊緣計算的出現為解決這些問題提供了新的思路。本文將深入探討邊緣…

tabs切換#

1、html <el-tabs v-model"tabValue" tab-change"handleTabClick"><el-tab-pane label"集群" name"1"></el-tab-pane><el-tab-pane label"節點" name"2"></el-tab-pane></el-ta…

JSON 實體屬性映射的最佳實踐

一、結構與命名規范 ?保持字段命名一致性? JSON 字段名與實體屬性名應遵循統一的命名規則&#xff08;如駝峰命名或下劃線分隔&#xff09;&#xff0c;避免因大小寫差異導致映射失敗。 // 使用 JsonProperty 顯式指定映射關系&#xff08;Jackson&#xff09; public class …

hiveserver2與beeline進行遠程連接hive配置及遇到的問題

1、hiveserver2 參與用戶模擬功能&#xff0c;因為開啟后才能保證各用戶之間的權限隔離。 1.1、配置 $HADOOP_HOME/etc/hadoop/core-site.xml <!--配置所有節點的root用戶都可作為代理用戶--> <property><name>hadoop.proxyuser.root.hosts</name>&…

硅基計劃2.0 學習總結 壹 Java初階

一、初見Java &#xff08;1&#xff09;Java簡介 首先不得不承認Java是一門優秀的程序設計語言 其系列的計算機軟件和跨平臺體系包括國內的生態鏈完善是C/C語言難以彌補的 &#xff08;2&#xff09;Java SE 全稱Java Standard Edition&#xff0c;是Java體系的基礎 &am…

nRF5_SDK_17.1.0_ddde560之ble_app_uart_c 出錯

Error #541: ARM::CMSIS:CORE:5.3.0 component is missing (previously found in pack ARM.CMSIS.5.6.0) Error #541: NordicSemiconductor::Device:Startup:8.40.3 component is missing (previously found in pack NordicSemiconductor.nRF_DeviceFamilyPack.8.40.3) 下載n…

基于大模型預測的多發性硬化綜合診療方案研究報告大綱

目錄 一、引言二、文獻綜述三、大模型預測系統構建四、術前預測與手術方案制定五、術中監測與決策支持六、術后護理與并發癥預測七、麻醉方案智能優化八、統計分析與技術驗證九、實驗驗證與證據支持十、健康教育與指導系統十一、結論與展望一、引言 (一)研究背景與意義 多發…

bootstrap自助(抽樣)法

一&#xff0c;概念 一言以蔽之&#xff1a;從訓練集中有放回的均勻抽樣——》本質就是有放回抽樣&#xff1b; 自助法&#xff08;bootstrap&#xff09;是一種通過從數據集中重復抽樣來估計統計量分布的非參數方法。它可用于構建假設檢驗&#xff0c;當對參數模型的假設存在…

用1W字講透數據預處理,數據增強

大家好&#xff01;我是我不是小upper~ 今天咱們來聊聊數據增強 —— 這個在機器學習領域堪稱 “數據魔法” 的實用技術&#xff01; 在深度學習的世界里&#xff0c;數據就像模型的 “養分”。數據的質量和數量&#xff0c;直接決定了模型最終能達到的 “高度”。當數據不足時…

無人機空中物流優化:用 Python 打造高效配送模型

友友們好! 我是Echo_Wish,我的的新專欄《Python進階》以及《Python!實戰!》正式啟動啦!這是專為那些渴望提升Python技能的朋友們量身打造的專欄,無論你是已經有一定基礎的開發者,還是希望深入挖掘Python潛力的愛好者,這里都將是你不可錯過的寶藏。 在這個專欄中,你將會…

C++核心編程解析:模板、容器與異常處理全指南

文章目錄 一、模板1.1 定義1.2 作用1.3 函數模版1.3.1 格式 1.4 類模版1.4.1 格式1.4.2 代碼示例1.4.3 特性 二、容器2.1 概念2.2 容器特性2.3 分類2.4 向量vector2.4.1 特性2.4.2 初始化與操作2.4.3 插入刪除 2.5 迭代器2.6 列表&#xff08;list&#xff09;2.6.1 遍歷方式2.…

JWT的介紹與在Fastapi框架中的應用

什么是JWT JWT (JSON Web Token) 是一個開放標準 ( RFC 7519 )&#xff0c;它定義了一種緊湊且自包含的方式&#xff0c;用于在各方之間安全地以 JSON 對象的形式傳輸信息。由于這些信息經過數字簽名&#xff0c;因此可以被驗證和信任。JWT 可以使用密鑰&#xff08;采用HMAC算…

dfs第二次加訓 詳細題解 下

目錄 B4158 [BCSP-X 2024 12 月小學高年級組] 質數補全 思路 B4279 [藍橋杯青少年組國賽 2023] 數獨填數、 思路 P5198 [USACO19JAN] Icy Perimeter S 思路 P5429 [USACO19OPEN] Fence Planning S 思路 P6111 [USACO18JAN] MooTube S 思路 P6207 [USACO06OCT] Cows …

配置Hadoop集群環境準備

&#xff08;一&#xff09;Hadoop的運行模式 一共有三種&#xff1a; 本地運行。偽分布式完全分布式 &#xff08;二&#xff09;Hadoop的完全分布式運行 要模擬這個功能&#xff0c;我們需要做好如下的準備。 1&#xff09;準備3臺客戶機&#xff08;關閉防火墻、靜態IP、…

Python60日基礎學習打卡D12【蟲豸版】

退火算法 物理現象&#xff1a;退火現象指物體逐漸降溫的物理現象&#xff0c;溫度愈低&#xff0c;物體的能量狀態會低&#xff1b;溫度足夠低后&#xff0c;液體開始冷凝與結晶&#xff0c;在結晶狀態時&#xff0c;系統的能量狀態最低。大自然在緩慢降溫(即退火)時&#xf…

1.3.1 Linux音頻框架alsa詳細介紹

ALSA作為對舊OSS系統的替代方案&#xff0c;始于1998年。當時OSS還閉源商業化&#xff0c;因此社區開始開發開源的ALSA。經過多年的發展&#xff0c;ALSA成為Linux內核中音頻架構的標準。 結構和架構 ALSA由以下幾個主要部分組成&#xff1a; 內核模塊&#xff1a; 這是ALSA的…