Flash(閃存)是一種可擦除的只讀存儲器,按照實現方式和運行特性Flash一般還會分為NOR和NAND兩種。其中NOR Flash支持隨機地址的讀取方式,在讀取操作上類似于RAM,比較適合程序的直接讀取運行,而NAND Flash讀取是基于頁的方式,一般無法隨機讀取。在MCU中,Flash需要支持程序和數據的存儲,所以實現方式上也都是NOR Flash。
基本特性
YTM32系列MCU中Flash的控制是通過EFM(Embedded Flash Module)控制的,這里以ME0x系列MCU為例,EFM模塊支持如下的一些功能:
- 512KB * 2 的程序存儲區域,帶有ECC功能,Sector大小為2K
- 256KB 單獨的數據存儲塊,帶有ECC功能,Sector大小為1K
- 4KB的NVR區域,帶有ECC功能,Sector大小為1K
- 支持Flash按區域(16KB單位)的寫保護功能
- 支持調試器禁用
- 支持Flash命令執行結束和異常中斷
- 支持Block Swap的OTA升級功能
- 支持ECC錯誤地址記錄和單比特、多比特中斷
- 支持OTP(One Time Program,一次可編程)區域
- 支持HCU 密鑰存儲(可擦寫,不可讀取)
- 支持塊擦除、扇區(sector)擦除和整個chip的擦除操作
- 寫入頁大小為8Bytes
Flash的基本術語約定
為了便于理解,這里整理一下Flash使用中常用的一些基本術語:
- PFlash,程序Flash,實際也可以保存數據,屬于基于應用場景的一種約定名稱
- DFlash,數據Flash,實際也可以運行程序,同樣屬于基于應用場景的一種約定名稱
- Block,Flash塊,表示物理上的一個Flash塊,不同物理塊的flash可以支持Read While Write(RWW)特性
- Sector,扇區,這個是Flash擦除的最小單位,屬于Flash的物理特性,軟件無法修改
- Page,Flash 編程的最小單位,同樣屬于Flash物理特性,軟件無法修改
- RWW,Read While Write,指的是Flash在運行擦除或者編程操作時候支持Flash的讀取操作
- ECC校驗,糾錯算法的一種,可以糾正單比特錯誤,檢測多比特錯誤
Memory Map定義
這里以ME0x為例,芯片系統存儲的memory map如下
Name | Start Address | End Address | Size(KB) | Block | Protect |
---|---|---|---|---|---|
PFlash0 | 0x0000_0000 | 0x0007_FFFF | 512 | 0 | ADDR_PROT0 |
PFlash1 | 0x0008_0000 | 0x000F_FFFF | 512 | 1 | ADDR_PROT1 |
DFlash | 0x0010_0000 | 0x0013_FFFF | 256 | 2 | ADDR_PROT2 |
AES_NVR | 0x1000_0000 | 0x1000_03FF | 1 | 0 | No Read + Customer Key |
OTP_NVR | 0x1001_0000 | 0x1001_03FF | 1 | 0 | No Erase |
BOOT_NVR | 0x1002_0000 | 0x1002_03FF | 1 | 1 | SWAP CMD only |
CUS_NVR | 0x1003_0000 | 0x1003_03FF | 1 | 1 | Customer Key |
上述表格中PFlash0和PFlash1是用于存儲用戶程序的,當使用OTA功能的時候,這兩個Block可以通過物理地址的重映射互換,實現應用升級。
AES_NVR
主要用于保存HCU中使用的密鑰,該部分占用1KB空間,可以實現32*256Bit的密鑰存儲。該部分區域支持用戶的Program和Erase,但是不支持讀取操作,可以保證密鑰的安全。當HCU需要使用密鑰的時候,軟件可以直接調用Flash的命令將需要用到的Key直接load到HCU中使用,整個過程軟件只能選擇key而不能讀取或者修改key。注意program和erase AES key區域需要用customer key解鎖。
OTP_NVR
該部分可以用于保存一次可編程數據,OTP(One Time Program)區域的特點是只能一次program,不支持擦寫和重新program。應用中可以在該部分保存一些產品ID信息或者其它不能希望后續修改的信息。注意該部分的讀取并沒有限制。
BOOT_NVR
這部分用來保存和OTA升級相關的數據,軟件應該避免對該區域進行操作,需要使用OTA Swap功能的時候,軟件需要發送SWAP命令實現Flash的Block Swap。
CUS_NVR
這部分區域包含Flash擦寫保護配置和Debugger禁用Tag,用戶可以向該區域的特定地址program特定值來實現對Flash的擦寫保護和調試端口禁用。CUS_NVR
的剩余部分是用戶可以自由使用的,對CUS_NVR
的讀寫操作需要先通過寫入customer key
來解鎖。
Flash的讀寫擦操作
讀取、寫入和擦除是Flash的基本操作,Flash的特性是擦除之后bit變成1,寫入操作是將相應的bit改寫成0,不過因為有ECC的限制,YTM32系列MCU都不支持Reprogram,也就是不支持Flash 頁數據有非1情況下的頁編程,EFM模塊在執行Program命令之前會先從Flash中讀取頁數據并驗證數據為全1,驗證失敗則該頁無法編程。
另外Flash的物理塊同一個時間只能執行讀取、寫入或者擦除的任一操作,這就限制了我們在對一個物理塊(Block)進行寫入或者擦除操作時候不能讀取Flash內容。這也意味著Flash在執行寫入或者擦除的時候,處理器不能從Flash中繼續讀取程序執行代碼,否則EFM模塊會直接產生bus error(M0+中對應為hardfault)。這也是L系列MCU在進行Flash操作(包括DFlash)的時候必須關閉中斷的原因。
在ME0x MCU中總共有3個物理Block,在使用過程中,按照上述原則,處理器在不能對同一個block同時進行讀寫操作,所以典型的使用方式有如下幾種:
- PFlash0和PFlash1用于保存程序和運行數據,DFlash用于保存Bootloader程序和模擬EEPROM的代碼,這樣在boot模式下,軟件可以直接對兩塊PFlash進行讀寫操作而不必禁用系統中斷;而在應用軟件運行過程中,軟件可以直接操作模擬EEPROM區域而不必禁用系統中斷。
- 在上述配置的基礎上使用OTA功能,PFlash0和PFlash1分別保存一套程序代碼,通過SWAP指令決定下次復位之后從哪個block啟動。當使用OTA功能的時候,當前Block運行的程序可以直接對另一個Block的Flash進行擦寫操作而不用關閉中斷,因為這個時候軟件是不會跳轉到另外一個block運行的,當然如果軟件在操作另外一個block的時候,同時對這個block進行讀操作也是不允許的。
當前EFM設計中,為了方便軟件使用,對于Flash的編程操作是直接將數據寫入Flash對應的地址(數據都需要4字節對齊),EFM模塊會從寫入操作捕獲寫入操作的地址和數據信息。在這種設計下,軟件對Flash地址的寫操作并不會產生錯誤,這個和Flash不支持直接寫操作是有一定沖突的,所以嚴格來說軟件需要通過MPU模塊對不需要編程的Flash進行禁止寫操作保護。注意Flash的寫保護操作只能保護Flash內容不被擦除和重新編程,處理器直接對這些地址進行寫操作的時候,EFM模塊并不會報錯,只有軟件Launch了扇區擦寫(Sector Erase)或者頁編程(Program)命令的時候,EFM模塊才會檢查當前區域時候被保護,如果為保護區域,EFM會abort命令并返回access error錯誤。
Flash command流程
對于Flash的操作都是基于Command來操作的,ME0x支持的command列表如下:
Code | Description | Need Address |
---|---|---|
0x02 | Program 64 bits | Y |
0x03 | Program 64bits and read back verify | Y |
0x10 | Sector erase | Y |
0x11 | Sector erase and verify | Y |
0x12 | Erase block (only main array) | |
Y | ||
0x13 | Erase block and then verify (only main array) | Y |
0x1E | Erase chip | |
N | ||
0x20 | Load AES Key | |
N (Y in MD1) | ||
0x30 | Boot Swap | |
N | ||
0x40 | Program NVR | |
Y | ||
0x41 | Erase NVR | |
Y | ||
0x42 | Read NVR | Y |
以Flash Program為例,Program一個64 bits并verify的command流程如下:
- 確認EFM的Prescaler參數設置正確
- 跳轉到RAM中執行代碼,并根據需要決定是否需要關閉全局中斷
- 讀取EFM_STS寄存器,判斷當前EFM是否正在執行命令
- 向需要PROGRAM的flash地址寫入64bit長度數據
- 寫
0xfd9573f5
到EFM_CMD_UNLOCK
解鎖FLASH command - 寫0x03到EFM_CMD開始執行command
- 輪詢讀取EFM_STS寄存器等待命令執行結束
- 讀取EFM_STS驗證command執行結果
EFM寄存器介紹
EFM對Flash的所有操作都是通過寄存器接口實現的,這里對EFM寄存器的主要域做一個簡單介紹。
CTRL寄存器
CTRL寄存器用于配置EFM操作的基礎配置,比如低功耗模式是否關閉Flash,選擇HCU的KEY,EFM模塊的時鐘基準,是否開啟數據預取加速,數據讀取的等待周期和各種中斷源的開關。
EFM CTRL寄存器
AES_KEY_SEL
用于選擇load到HCU中AES key的ID,這個操作后續都換成Flash 命令操作了,僅在ME0x中有該域。
PRESCALER
是Flash操作的一個基礎分頻,軟件初始化的時候需要將PRESCALER設置為主頻/2MHz,比如Core時鐘為120MHz,那么,EFM模塊會根據這個值來產生program和erase的時間,如果這個值設置不準確(主要是偏小)可能會導致Flash編程或者擦除異常。SDK中在時鐘初始化的時候自動適配該值。
RWS
是Flash讀操作的等待周期,ME0x中Flash的最高頻率是40MHz,當主頻為120MHz時候,,RWS設置過大會導致系統性能下降,過小則會導致Flash讀取數據異常。RWS通過時鐘的.flashDiv = *SCU_SYS_CLK_DIV_BY_3
* 配置,SCU_SYS_CLK_DIV_BY_3
表示3分頻,RWS=2。
STS寄存器
STS寄存器保存了Flash操作的狀態信息,包含Flash當前是否在執行命令,當前的啟動Block,Flash命令的執行結果和錯誤原因以及ECC錯誤的標志位。
CMD寄存器
軟件通過向CMD寫入命令來啟動flash的相關操作,為了保護CMD不被意外觸發,對CMD操作之前需要向CMD_UNLOCK
寄存器寫入0xfd9573f5
來解鎖,解鎖后軟件必須立即寫入CMD而不能進行其他寄存器訪問,否則CMD會產生Access Error。
TIMING1和TIMING2寄存器
這兩個寄存器是用來做Flash命令的時序微調,當CTRL_PRESCALER
域正確配置時,這兩個寄存器保持復位值就可以了,錯誤的修改這兩個值會導致Flash擦寫異常。
NVR_ADDR和NVR_DATA
這一組寄存器用來傳遞NVR操作的地址和數據信息。
ADDR_PROT寄存器
ADDR_PROT
是一組寄存器,ME0x中是3個32位的寄存器,每個寄存器保護一個block,ADDR_PROT
的所有bit只能由1寫0,bit為1表示對應區域是未保護的,為0則表示對應區域不能進行擦除和寫入操作,ADDR_PROT
上電時會自動從CFG_NVR
的特定地址載入。
ADDR_PROT0
:定義了Block0(PFlash0)的保護區域,每個bit保護16KB。
ADDR_PROT1
:定義了Block1(PFlash1)的保護區域,每個bit保護16KB。
ADDR_PROT0
:定義了Block0(DFlash)的保護區域,每個bit保護8KB。
ECC_ERR_ADDR寄存器
該寄存器保存了發生ECC錯誤的地址,軟件可以配合ECC錯誤的STS標志實現對Flash ECC錯誤的定位。
Flash操作時間
軟件應用中對于Flash的編程和擦寫的時間一般比較敏感,這里將Flash一些基本操作的時間列舉如下:
操作 | M系列 | L系列 |
---|---|---|
Sector Erase | 16ms | 4.5ms |
Block Erase | 16ms | 35ms |
Chip Erase | 16ms | 35ms |
Page Program | 45us | 50us |
因為Flash操作時間和Prescaler和TIMING寄存器配置有關,上述表格的數據是在Prescaler正確配置和TIMING保持默認值下的數據。
M系列擦除的時間都是16ms,Flash array支持多扇區同時擦寫,所以整個block甚至整個芯片的擦除時間都是16ms,當采用erase retry的擦除方式時,EFM會按照800us的周期對flash進行擦除嘗試,這種方式下擦寫的時間是800us~16ms。Erase retry僅支持單個sector的擦寫。
L系列因為只有一個Block的緣故,Block Erase和Chip Erase并沒有什么區別,也不支持erase retry功能,另外L系列的Dflash實際和Pflash屬于相同的block,所以對Dflash進行擦寫操作時候,也不支持對PFlash進行讀操作。因此用Dflash模擬EEPROM的時候還是需要禁用系統中斷的。
調試禁用和Flash保護
為了保護用戶的軟件代碼,ME0x系列支持通過Flash禁用芯片調試端口,這個過程是在芯片初始化過程中通過硬件實現的。同樣為了避免程序在運行過程中對Flash進行意外操作,Flash同樣支持基于地址的擦寫保護,應用程序可以根據實際應用需求限制。
在YTM32B1ME0x中,CUS_NVR
的起始地址是0x1001_0000U
,這部分NVR區域中數據定義如下:
Region(32bits) | Address | Description |
---|---|---|
Debugger Disable Tag 0 | 0x10010000 | TAG=0x5a5a5a5a Disable debugger |
Debugger Disable Tag 1 | 0x10010004 | TAG=0x5a5a5a5a Disable debugger |
PROT0 Tag | 0x10010008 | TAG=0x5a5a5a5a |
PROT0 Value | 0x1001000C | ADDR_PROT0 Init value |
PROT1 Tag | 0x10010010 | TAG=0x5a5a5a5a |
PROT1 Value | 0x10010014 | ADDR_PROT1 Init value |
PROT2 Tag | 0x10010018 | TAG=0x5a5a5a5a |
PROT2 Value | 0x1001001C | ADDR_PROT2 Init value |
User NVR | User can use other left space |
因為NVR區域的頁大小也是8 Bytes(64bits),實際單次至少寫入兩個words。比如當希望在上電后禁用調試端口,那么只需要向0x10010000U
地址寫入0x5a5a5a5a
, 0x5a5a5a5a
,那么下次芯片復位之后調試端口默認就不會開啟了。
PROT相應的tag和value也是一起編程的,當tag匹配的時候,下次上電對應的value就會自動load到相應的寄存器實現Flash的保護。
HCU KEY區域
ME0x芯片內置HCU加速模塊,可以實現硬件的AES/SHA/SM4運算加速,FLASH模塊支持存儲32組長度為256bit的AES KEY,軟件在使用這些key的時候可以直接將KEY load到HCU模塊,這個過程中軟件無法讀取KEY的值,可以保證KEY的安全性。
在ME0x中,HCU的KEY是通過EFM_CTRL_AES_KEY_SEL
域來選擇然后發Flash命令讀取的,不過后續項目中將這個操作統一成標準Flash command,用戶直接給出KEY存儲的地址,然后直接通過命令load。因為KEY的load本身也是一個Flash操作,所以執行該命令的時候同樣不支持RWW操作,軟件需要關閉中斷,并在RAM中執行該命令。
NVR操作注意事項
因為NVR區域和block有一定的對應關系,并且block swap還會改動這個對應關系,除非明確軟件和NVR不在一個block,否則對于NVR區域的操作還是需要關中斷和在RAM中執行。
對于NVR區域的擦除和寫入操作的時間與Main Array一致。
-
mcu
+關注
關注
146文章
17123瀏覽量
350992 -
閃存
+關注
關注
16文章
1782瀏覽量
114895 -
寄存器
+關注
關注
31文章
5336瀏覽量
120231 -
FlaSh
+關注
關注
10文章
1633瀏覽量
147943 -
存儲器
+關注
關注
38文章
7484瀏覽量
163765
發布評論請先 登錄
相關推薦
評論