STM32F4讀寫內部FLASH【使用庫函數】

STM32F4Discovery開發幫使用的STM32F407VGT6芯片,內部FLASH有1M之多。平時寫的代碼,燒寫完以後還有大量的剩餘。有效利用這剩餘的FLASH能存儲很多數據。所以研究了一下STM32F4讀寫內部FLASH的一些操做。編程

【STM32F4 內部Flash的一些信息】函數

STM32F407VG的內部FLASH的地址是:0x08000000,大小是0x00100000。網站

寫FLASH的時候,若是發現寫入地址的FLASH沒有被擦出,數據將不會寫入。FLASH的擦除操做,只能按Sector進行。不能單獨擦除一個地址上的數據。所以在寫數據以前須要將地址所在Sector的全部數據擦除。ui

在STM32F4的編程手冊上可找到FLASH的Sector劃分,咱們如今只操做Main memory:this

image

參考Demo中的例子,將FLASH的頁的其實地址(基地址)可定義以下:3d

/* Base address of the Flash sectors */
#define ADDR_FLASH_SECTOR_0     ((uint32_t)0x08000000) /* Base @ of Sector 0, 16 Kbytes */
#define ADDR_FLASH_SECTOR_1     ((uint32_t)0x08004000) /* Base @ of Sector 1, 16 Kbytes */
#define ADDR_FLASH_SECTOR_2     ((uint32_t)0x08008000) /* Base @ of Sector 2, 16 Kbytes */
#define ADDR_FLASH_SECTOR_3     ((uint32_t)0x0800C000) /* Base @ of Sector 3, 16 Kbytes */
#define ADDR_FLASH_SECTOR_4     ((uint32_t)0x08010000) /* Base @ of Sector 4, 64 Kbytes */
#define ADDR_FLASH_SECTOR_5     ((uint32_t)0x08020000) /* Base @ of Sector 5, 128 Kbytes */
#define ADDR_FLASH_SECTOR_6     ((uint32_t)0x08040000) /* Base @ of Sector 6, 128 Kbytes */
#define ADDR_FLASH_SECTOR_7     ((uint32_t)0x08060000) /* Base @ of Sector 7, 128 Kbytes */
#define ADDR_FLASH_SECTOR_8     ((uint32_t)0x08080000) /* Base @ of Sector 8, 128 Kbytes */
#define ADDR_FLASH_SECTOR_9     ((uint32_t)0x080A0000) /* Base @ of Sector 9, 128 Kbytes */
#define ADDR_FLASH_SECTOR_10    ((uint32_t)0x080C0000) /* Base @ of Sector 10, 128 Kbytes */
#define ADDR_FLASH_SECTOR_11    ((uint32_t)0x080E0000) /* Base @ of Sector 11, 128 Kbytes */code

在庫裏邊,FLASH的Sector編號定義以下,這是供庫裏邊的幾個函數使用的。須要將地址轉換成Sector編號:blog

#define FLASH_Sector_0     ((uint16_t)0x0000) /*!< Sector Number 0 */
#define FLASH_Sector_1     ((uint16_t)0x0008) /*!< Sector Number 1 */
#define FLASH_Sector_2     ((uint16_t)0x0010) /*!< Sector Number 2 */
#define FLASH_Sector_3     ((uint16_t)0x0018) /*!< Sector Number 3 */
#define FLASH_Sector_4     ((uint16_t)0x0020) /*!< Sector Number 4 */
#define FLASH_Sector_5     ((uint16_t)0x0028) /*!< Sector Number 5 */
#define FLASH_Sector_6     ((uint16_t)0x0030) /*!< Sector Number 6 */
#define FLASH_Sector_7     ((uint16_t)0x0038) /*!< Sector Number 7 */
#define FLASH_Sector_8     ((uint16_t)0x0040) /*!< Sector Number 8 */
#define FLASH_Sector_9     ((uint16_t)0x0048) /*!< Sector Number 9 */
#define FLASH_Sector_10    ((uint16_t)0x0050) /*!< Sector Number 10 */
#define FLASH_Sector_11    ((uint16_t)0x0058) /*!< Sector Number 11 */內存

Demo中有將地址轉換成Sector的代碼:開發

uint32_t GetSector(uint32_t Address)
{
  uint32_t sector = 0;
 
  if((Address < ADDR_FLASH_SECTOR_1) && (Address >= ADDR_FLASH_SECTOR_0))
  {
    sector = FLASH_Sector_0; 
  }
  else if((Address < ADDR_FLASH_SECTOR_2) && (Address >= ADDR_FLASH_SECTOR_1))
  {
    sector = FLASH_Sector_1; 
  }
  else if((Address < ADDR_FLASH_SECTOR_3) && (Address >= ADDR_FLASH_SECTOR_2))
  {
    sector = FLASH_Sector_2; 
  }
  else if((Address < ADDR_FLASH_SECTOR_4) && (Address >= ADDR_FLASH_SECTOR_3))
  {
    sector = FLASH_Sector_3; 
  }
  else if((Address < ADDR_FLASH_SECTOR_5) && (Address >= ADDR_FLASH_SECTOR_4))
  {
    sector = FLASH_Sector_4; 
  }
  else if((Address < ADDR_FLASH_SECTOR_6) && (Address >= ADDR_FLASH_SECTOR_5))
  {
    sector = FLASH_Sector_5; 
  }
  else if((Address < ADDR_FLASH_SECTOR_7) && (Address >= ADDR_FLASH_SECTOR_6))
  {
    sector = FLASH_Sector_6; 
  }
  else if((Address < ADDR_FLASH_SECTOR_8) && (Address >= ADDR_FLASH_SECTOR_7))
  {
    sector = FLASH_Sector_7; 
  }
  else if((Address < ADDR_FLASH_SECTOR_9) && (Address >= ADDR_FLASH_SECTOR_8))
  {
    sector = FLASH_Sector_8; 
  }
  else if((Address < ADDR_FLASH_SECTOR_10) && (Address >= ADDR_FLASH_SECTOR_9))
  {
    sector = FLASH_Sector_9; 
  }
  else if((Address < ADDR_FLASH_SECTOR_11) && (Address >= ADDR_FLASH_SECTOR_10))
  {
    sector = FLASH_Sector_10; 
  }
  else/*(Address < FLASH_END_ADDR) && (Address >= ADDR_FLASH_SECTOR_11))*/
  {
    sector = FLASH_Sector_11; 
  }

  return sector;
}

 

有了這些定義以後,咱們就能夠開始正式操做FLASH了

首先,要向FLASH寫入數據須要先將FLASH解鎖。根據手冊定義,解鎖FLASH須要先向寄存器FLASH_KEYR寫入0x45670123以後再向這個寄存器寫入0xCDEF89AB。這兩個數據在庫中已經定義成了:FLASH_KEY1和FLASH_KEY2.

使用庫函數不用這麼麻煩,函數FLASH_Unlock()便可完成對FLASH的解鎖。

解鎖FLASH以後,使用函數FLASH_ClearFlag清除FLASH的狀態寄存器。而後就能夠對FLASH進行寫操做了。我按照示例工程,擦除兩塊FLASH。

下邊是操做FLASH的代碼,首先擦除兩塊FLASH,而後向這兩塊FLASH中寫入數據。最後進行校驗:

要寫入的數據定義:

#define DATA_32                 ((uint32_t)0x12345678)

開始FLASH操做:

  FLASH_Unlock(); //解鎖FLASH後才能向FLASH中寫數據。


  FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |
                  FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR);

  /* Get the number of the start and end sectors */
  StartSector = GetSector(FLASH_USER_START_ADDR);  //獲取FLASH的Sector編號
  EndSector = GetSector(FLASH_USER_END_ADDR);
 
  //擦除FLASH
  for (i = StartSector; i < EndSector; i += 8)  //每次FLASH編號增長8,可參考上邊FLASH Sector的定義。
  {
    /* Device voltage range supposed to be [2.7V to 3.6V], the operation will
       be done by word */
    if (FLASH_EraseSector(i, VoltageRange_3) != FLASH_COMPLETE)
    {
      while (1)
      {
      }
    }
  }
 
  /*擦除完畢*/
  /*開始寫入*/
  Address = FLASH_USER_START_ADDR;
 
    while (Address < FLASH_USER_END_ADDR)
  {
    if (FLASH_ProgramWord(Address, DATA_32) == FLASH_COMPLETE)   //將DATA_32寫入相應的地址。
    {
      Address = Address + 4;
    }
    else
    {
      /* Error occurred while writing data in Flash memory.
         User can add here some code to deal with this error */
      while (1)
      {
      }
    }
  }
 
  FLASH_Lock();  //讀FLASH不須要FLASH處於解鎖狀態。
 
//讀出數據 檢查寫入值是否正確
  Address = FLASH_USER_START_ADDR;
  MemoryProgramStatus = 0x0;
   while (Address < FLASH_USER_END_ADDR)
  {
    data32 = *(__IO uint32_t*)Address;   //讀FLASH中的數據,直接給出地址就好了。跟從內存中讀數據同樣。

    if (data32 != DATA_32)
    {
      MemoryProgramStatus++; 
    }

    Address = Address + 4;
  } 
 

下邊是使用STLink Utility讀出的數據,檢查一下,確實寫進去數據了:

image

參考文檔是ST的 STM32F40xxx and STM32F41xxx Flash programming manual。可在ST網站下載。文檔編號:PM0081。FLASH的有很多寄存器,各個含義手冊上有詳細介紹。我只是簡單地看了下。使用庫函數操做,好像不大須要詳細理解這些寄存器了。

 

PS:這個實驗主要代碼來自ST的Demo。這裏我只是加入了我的的註釋。不當之處,望高人指點。

相關文章
相關標籤/搜索