STM32 Flash

目錄

1:Flash簡介

2:嵌入式Flash特性

3:Flash 閃存的讀取

4:閃存擦除

5:代碼實現


1:Flash簡介

FLASH存儲器是閃速存儲器,它的主要特點是在不加電的情況下能長期保持存儲的信息。就其本質而言,Flash Memory屬於EEPROM(電擦除可編程只讀存儲器)類型。它既有ROM的特點,又有很高的存取速度,而且易於擦除和重寫, 功耗很小。

2:嵌入式Flash特性

  • 對於 STM32F40x 和 STM32F41x,容量高達 1 MB;對於 STM32F42x 和 STM32F43x,容量高達 2 MB
  • 128 位寬數據讀取
  • 字節、半字、字和雙字數據寫入
  • 扇區擦除與全部擦除
  • 低功耗模式

 STM32F40x和STM32F41x Flash 模塊構成

可以看到 

  1. 主存儲器

該部分用來存放代碼和數據常數(如const類型的數據)。分爲12個扇區,前4個扇區爲16KB大小,然後扇區4是64KB大小,扇區5~11是128K大小,從上圖可以看出主存儲器的起始地址就是0X0800 0000,B0、B1都接GND的時候,就是從0X0800 0000開始運行代碼

   2.系統存儲器

這個主要用來存放STM32F4的bootloader代碼,此代碼是出廠的時候就固化在STM32F4裏面了,專門來給主存儲器下載代碼的。當B0接3.3V,B1接GND的時候,從該存儲器啓動(即進入串口下載模式)。

  3.OTP區域

即一次性可編程區域,共528字節,被分成兩個部分,前面512字節(32字節爲1塊,分成16塊),可以用來存儲一些用戶數據(一次性的,寫完一次,永遠不可以擦除!!),後面16字節,用於鎖定對應塊。

 4.選項字節

用於配置讀保護、BOR級別、軟件/硬件看門狗以及器件處於待機或停止模式下的復位。

3:Flash 閃存的讀取

STM23F4的FLASH讀取是很簡單的。例如,我們要從地址addr,讀取一個字(字節爲8位,半字爲16位,字爲32位),可以通過如下的語句讀取:

data=*(vu32*)addr;

將addr強制轉換爲vu32指針,然後取該指針所指向的地址的值,即得到了addr地址的值。類似的,將上面的vu32改爲vu16,即可讀取指定地址的一個半字。

 在執行閃存寫操作時,任何對閃存的讀操作都會鎖住總線,在寫操作完成後讀操作才能正確地進行;既在進行寫或擦除操作時,不能進行代碼或數據的讀取操作。

STM32F4的閃存編程由6個32位寄存器控制,他們分別是

  1. FLASH訪問控制寄存器(FLASH_ACR)
  2. FLASH祕鑰寄存器(FLASH_KEYR)
  3. FLASH選項祕鑰寄存器(FLASH_OPTKEYR)
  4. FLASH狀態寄存器(FLASH_SR)
  5. FLASH控制寄存器(FLASH_CR)
  6. FLASH選項控制寄存器(FLASH_OPTCR)

其中祕鑰寄存器中有兩個鍵值KEY1=0X45670123  KEY2=0XCDEF89AB

STM32F4 Flash標準編程的步驟如下

  • 檢查FLASH_SR中的BSY位,確保當前未執行任何FLASH操作。
  • 將FLASH_CR寄存器中的PG位置1,激活FLASH編程。
  • 針對所需存儲器地址(主存儲器塊或OTP區域內)執行數據寫入操作:      

         —並行位數爲x8時按字節寫入(PSIZE=00)      

        —並行位數爲x16時按半字寫入(PSIZE=01)      

        —並行位數爲x32時按字寫入(PSIZE=02)      

        —並行位數爲x64時按雙字寫入(PSIZE=03)

  •  等待BSY位清零,完成一次編程。

按以上四步操作,就可以完成一次FLASH編程。不過有幾點要注意:1,編程前,要確保要寫入地址的FLASH已經擦除。2,要先解鎖(否則不能操作FLASH_CR)。3,編程操作對OPT區域也有效,方法一模一樣。

4:閃存擦除

FLASH編程的時候,要先判斷所寫地址是否被擦除了,STM32F4的閃存擦除分爲兩種

  • 扇區擦除
  • 整片擦除

 

扇區擦除步驟

  1. 檢查FLASH_CR的LOCK是否解鎖,如果沒有則先解鎖
  2. 檢查FLASH_SR寄存器中的BSY 位,確保當前未執行任何FLASH操作
  3. 在FLASH_CR寄存器中,將SER位置1,並從主存儲塊的12個扇區中選擇要擦除的扇區 (SNB)
  4. 將FLASH_CR寄存器中的STRT位置1,觸發擦除操作 等待BSY位清零

 

整片擦除步驟

  1. 檢查 FLASH_SR 寄存器中的 BSY 位,以確認當前未執行任何 Flash 操作
  2. FLASH_CR 寄存器中的 MER 位置 1(STM32F405xx/07xx STM32F415xx/17xx 器件)
  3. FLASH_CR 寄存器中的 MER MER1 位置 1STM32F42xxx STM32F43xxx 器件)
  4. FLASH_CR 寄存器中的 STRT 位置 1
  5. 等待 BSY 位清零

5:代碼實現

講幾個重要的函數

void FLASH_Unlock(void)
{
  if((FLASH->CR & FLASH_CR_LOCK) != RESET)
  {
    /* Authorize the FLASH Registers access */
    FLASH->KEYR = FLASH_KEY1;
    FLASH->KEYR = FLASH_KEY2;
  }  
}
//解鎖用的,先查詢CR寄存器的位31,看是否上鎖,若上鎖,則再給KEYR密鑰寄存器寫入兩個密鑰值進行解鎖
void FLASH_DataCacheCmd(FunctionalState NewState)
{
  /* Check the parameters */
  assert_param(IS_FUNCTIONAL_STATE(NewState));
  
  if(NewState != DISABLE)
  {
    FLASH->ACR |= FLASH_ACR_DCEN;
  }
  else
  {
    FLASH->ACR &= (~FLASH_ACR_DCEN);
  }
}
//FLASH擦除期間,必須禁止數據緩存,操作ACR訪問控制寄存器的位10
uint16_t STMFLASH_GetFlashSector(u32 addr);
//根據要操作的地址,來查詢處在哪個扇區

再來看看 FLASH_EraseSector扇區擦除函數中的核心部分

    /* if the previous operation is completed, proceed to erase the sector */
    FLASH->CR &= CR_PSIZE_MASK;
    FLASH->CR |= tmp_psize;
    FLASH->CR &= SECTOR_MASK;
    FLASH->CR |= FLASH_CR_SER | FLASH_Sector;
    FLASH->CR |= FLASH_CR_STRT;
    
    /* Wait for last operation to be completed */
    status = FLASH_WaitForLastOperation();
    
    /* if the erase operation is completed, disable the SER Bit */
    FLASH->CR &= (~FLASH_CR_SER);
    FLASH->CR &= SECTOR_MASK; 
  1. CR控制寄存器位8、9置0
  2. 根據VCC來操作CR寄存器的位8、9
  3. CR寄存器位3~7置0
  4. 操作CR寄存器位3~6來選擇要擦除的扇區,並置位1,激活扇區擦除
  5. 操作CR寄存器的位16來觸發擦除操作
  6. 等待操作並查詢SR寄存器,查詢操作的狀態
  7. 操作完成後,清除掉一些相應位

寫入函數FLASH_ProgramWord

    FLASH->CR &= CR_PSIZE_MASK;
    FLASH->CR |= FLASH_PSIZE_WORD;
    FLASH->CR |= FLASH_CR_PG;
  
    *(__IO uint32_t*)Address = Data;
        
    /* Wait for last operation to be completed */
    status = FLASH_WaitForLastOperation();

    /* if the program operation is completed, disable the PG Bit */
    FLASH->CR &= (~FLASH_CR_PG);
  1. CR控制寄存器位8、9置0
  2. 操作CR寄存器位8、9,來確定編程並行位數
  3. 操作CR寄存器的位0,來激活編程
  4. 把寫入的數據放進扇區地址中
  5. 等待操作並查詢SR寄存器,查詢操作的狀態
  6. 操作完成後,清除掉CR寄存器位0

至於讀函數STMFLASH_ReadWord,那就很簡單了

//讀取指定地址的半字(16位數據) 
//faddr:讀地址 
//返回值:對應數據.
u32 STMFLASH_ReadWord(u32 faddr)
{
	return *(vu16*)faddr; 
}  

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章