STM32自己沒有自帶EEPROM,可是STM32具備IAP(在應用編程)功能,因此咱們能夠把它的FLASH當成EEPROM來使用。 編程
不 同型號的STM32,其FLASH容量也有所不一樣,最小的只有16K字節,最大的則達到了1024K字節。 electron
STM32的閃存模塊由:主存儲器、信息塊和閃存存儲器接口寄存器等3部分組成。 函數
主存儲器,該部分用來存放代碼和數據常數(如const類型的數據)。對於大容量產品,其被劃分爲256頁,每頁2K字節。注意,小容量和中容量產品則每頁 只有1K字節。從上圖能夠看出主存儲器的起始地址就是0X08000000, B0、B1都接GND的時候,就是從0X08000000開始運行代碼的。 lua
信息塊,該部分分爲2個小部分,其中啓動程序代碼,是用來存儲ST自帶的啓動程序,用於串口下載代碼,當B0接V3.3,B1接GND的時候,運行的就是這部分代碼。用戶選擇字節,則通常用於配置寫保護、讀保護等功能,本章不做介紹。 spa
閃存存儲器接口寄存器,該部分用於控制閃存讀寫等,是整個閃存模塊的控制機構。 設計
對主存儲器和信息塊的寫入由內嵌的閃存編程/擦除控制器(FPEC)管理;編程與擦除的高電壓由內部產生。 指針
在執行閃存寫操做時,任何對閃存的讀操做都會鎖住總線,在寫操做完成後讀操做才能正確地進行;既在進行寫或擦除操做時,不能進行代碼或數據的讀取操做。 code
閃存的讀取內置閃存模塊能夠在通用地址空間直接尋址,任何32位數據的讀操做都能訪問閃存模塊的內容並獲得相應的數據。讀接口在閃存端包含一個讀控制器,還包含一個 AHB接口與CPU銜接。這個接口的主要工做是產生讀閃存的控制信號並預取CPU要求的指令塊,預取指令塊僅用於在I-Code總線上的取指操做,數據常 量是經過D-Code總線訪問的。這兩條總線的訪問目標是相同的閃存模塊,訪問D-Code將比預取指令優先級高。 接口
這裏要特別留意一個閃存等待時間,由於CPU運行速度比FLASH快得多,STM32F103的FLASH最快訪問速度≤24Mhz,若是CPU頻率超過這 個速度,那麼必須加入等待時間,好比咱們通常使用72Mhz的主頻,那麼FLASH等待週期就必須設置爲2,該設置經過FLASH_ACR寄存器設置。 ip
例如,咱們要從地址addr,讀取一個半字(半字爲16爲,字爲32位),能夠經過以下的語句讀取:
data=*(vu16*)addr;
將 addr強制轉換爲vu16指針,而後取該指針所指向的地址的值,即獲得了addr地址的值。相似的,將上面的vu16該位vu8,便可讀取指定地址的一 個字節。相對FLASH讀取來講,STM32 FLASH的寫就複雜一點了,下面咱們介紹STM32閃存的編程和擦除。
閃存的編程和擦除
STM32的閃存編程是由FPEC(閃存編程和擦除控制器)模塊處理的,這個模塊包含7個32位寄存器,他們分別是:
l FPEC鍵寄存器(FLASH_KEYR)
l 選擇字節鍵寄存器(FLASH_OPTKEYR)
l 閃存控制寄存器(FLASH_CR)
l 閃存狀態寄存器(FLASH_SR)
l 閃存地址寄存器(FLASH_AR)
l 選擇字節寄存器(FLASH_OBR)
l 寫保護寄存器(FLASH_WRPR)
其中FPEC鍵寄存器總共有3個鍵值:
RDPRT鍵=0X000000A5
KEY1=0X45670123
KEY2=0XCDEF89ABSTM32復位後,FPEC模塊是被保護的,不能寫入FLASH_CR寄存器;經過寫入特定的序列到FLASH_KEYR寄存器能夠打開FPEC模塊(即寫入KEY1和KEY2),只有在寫保護被解除後,咱們才能操做相關寄存器。
STM32閃存的編程每次必須寫入16位(不能單純的寫入8位數據哦!),當FLASH_CR寄存器的PG位爲’1’時,在一個閃存地址寫入一個半字將啓動一次編程;寫入任何非半字的數據,FPEC都會產生總線錯誤。在編程過程當中(BSY位爲’1’),任何讀寫閃存的操做都會使CPU暫停,直到這次閃存編程結束。
一樣,STM32的FLASH在編程的時候,也必需要求其寫入地址的FLASH是被擦除了的(也就是其值必須是0XFFFF),不然沒法寫入,在FLASH_SR寄存器的PGERR位將獲得一個警告。
STM23的FLASH編程過程如圖所示:
從上圖能夠獲得閃存的編程順序以下:
l 檢查FLASH_CR的LOCK是否解鎖,若是沒有則先解鎖
l 檢查FLASH_SR寄存器的BSY位,以確認沒有其餘正在進行的編程操做
l 設置FLASH_CR寄存器的PG位爲’1’
l 在指定的地址寫入要編程的半字
l 等待BSY位變爲’0’
l 讀出寫入的地址並驗證數據
前面提到,咱們在STM32的FLASH編程的時候,要先判斷縮寫地址是否被擦除了,因此,咱們有必要再紹一下STM32的閃存擦除,STM32的閃存擦除分爲兩種:頁擦除和整片擦除。頁擦除過程以下圖所示
從上圖能夠看出,STM32的頁擦除順序爲:
l 檢查FLASH_CR的LOCK是否解鎖,若是沒有則先解鎖
l 檢查FLASH_SR寄存器的BSY位,以確認沒有其餘正在進行的閃存操做
l 設置FLASH_CR寄存器的PER位爲’1’
l 用FLASH_AR寄存器選擇要擦除的頁
l 設置FLASH_CR寄存器的STRT位爲’1’
l 等待BSY位變爲’0’
l 讀出被擦除的頁並作驗證軟件設計:
#include "Flash.h" u32 StartAddr = 0x0801F800; //要寫入Flash的數據的首地址--FLASH起始地址 u32 EndAddr = 0x0801FFFF; //要寫入Flash的數據的末地址--FLASH結束地址 u32 FlashAddress=0x00;//Flash的內部地址 vu32 NbrOfPage = 0x00; //要擦除的頁面數量 u32 data = 0; //u32 *p=(u32 *)0x08008000; //定義指針指向要傳送的數據的地址 volatile FLASH_Status FLASHStatus; volatile TestStatus MemoryProgramStatus; ErrorStatus HSEStartUpStatus; /******************************************************************************* * Function Name : Writeflash * Description : 寫函數 把數據從CPU寫到FLASH中 * * Input : u8 Erasenumber,u32 *Data,輸入要擦除的頁面和要寫入的數據的地址 * Output : None * Return : None *******************************************************************************/ void Writeflash(u8 Erasenumber ,u32 *p,u8 start,u8 end) { int i = start; FLASHStatus = FLASH_COMPLETE; MemoryProgramStatus = PASSED; /* Unlock the Flash Program Erase controller */ FLASH_Unlock(); //FLASH解鎖 /* Clear All pending flags */ FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);//清標誌位 //擦除後寫數據 //******************************************************************************* //一次擦除1頁 /* Define the number of page to be erased *///定義要擦出的頁面的數量 NbrOfPage = (EndAddr - StartAddr) / FLASH_PAGE_SIZE; /* Erase the FLASH pages *///頁面擦除子程序 FLASHStatus = FLASH_ErasePage(StartAddr + (FLASH_PAGE_SIZE * NbrOfPage)); //寫數據 FlashAddress = StartAddr+4*start; while((FlashAddress < EndAddr) && (FLASHStatus == FLASH_COMPLETE) && i<end) { FLASHStatus = FLASH_ProgramWord(FlashAddress, *(p+i));//*p); i++; FlashAddress = FlashAddress + 4; } } /******************************************************************************* * Function Name : Readflash * Description : 讀數據,從FLASH中讀出須要的數據 * * Input : None * Output : Data輸出要取出的數據 * Return : None *******************************************************************************/ void Readflash(u32 *p,u8 start,u8 end) // { int j = start; FlashAddress = StartAddr+4*start; //讀數據 while(j<end) { *(p+j) = *(u32*)(FlashAddress+4*j); j++; } }
#ifndef _FLASH_H #define _FLASH_H /* Includes ------------------------------------------------------------------*/ #include "stm32f10x_flash.h" /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ /* Uncomment the line corresponding to the STMicroelectronics evaluation board used to run the example */ #if !defined (STM32_DK_128K) && !defined (STM32_EK) //#define USE_STM3210B_EVAL #define STM32_EK #endif /* Define the STM32F10x hardware depending on the used evaluation board */ #ifdef STM32_DK_128K #define FLASH_PAGE_SIZE ((u16)0x400) //1024 1K #elif defined STM32_EK #define FLASH_PAGE_SIZE ((u16)0x800) //2048 2K #endif /* USE_STM3210B_EVAL */ /* Private typedef -----------------------------------------------------------*/ typedef enum {FAILED = 0, PASSED = !FAILED} TestStatus; /* Private define ------------------------------------------------------------*/ /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ void Writeflash(u8 Erasenumber ,u32 *p,u8 start,u8 end); void Readflash(u32 *p,u8 start,u8 end) ; /* Exported macro ------------------------------------------------------------*/ /* Exported functions ------------------------------------------------------- */ #endif /* __PLATFORM_CONFIG_H */
Writeflash(0,Var_Compensate,0,6); Readflash(Var_Compensate,0,6)