分享到plurk 分享到twitter 分享到facebook

版本 d750504099f902162e02c089c980337285c5b649

embedded/Flash

Changes from d750504099f902162e02c089c980337285c5b649 to bdf31b85fa8d548e6b4e5c67c6929ee34e4bf6fa

---
title: Flash
categories: STM32F4
...

1.Flash 簡介
============

1.1 簡介
-------------

- 快閃記憶體(Flash Memory、閃存),主要用於一般性資料儲存,以及在電腦及其他數位產品間交換傳輸資料。如記憶卡、隨身碟等。快閃記憶體是一種特殊的、以大區塊抹寫的EEPROM(電子抹除式可複寫唯讀記憶體)。

- 快閃記憶體晶片的低階介面通常與透過支援外界的定址匯流排行隨機存取的DRAM、ROM、EEPROM等記憶體不同。 NOR Flash本身為讀取操作(支援隨機存取)提供外部定址匯流排;至於解鎖、抹除與寫入則須以區塊-區塊(Block-by-block)的方式進行,典型的區塊大小為64、128或256位元組。NAND Flash所有的動作都必須以區塊性基礎(Block-wise fashion)執行,包含讀、寫、解鎖與抹除。

- `快閃記憶體(wiki)<http://zh.wikipedia.org/wiki/%E5%BF%AB%E9%96%83%E8%A8%98%E6%86%B6%E9%AB%94>`_

- NOR Flash Structure :

.. image:: /NOR flash.JPG

- NAND Flash Structure :

.. image:: /NAND flash.JPG

**關於NAND Flash 與 NOR Flash的比較可參考** http://www.8051faq.com.cn/manager/download/20077633203664115781250.PDF

2.Flash 記憶體架構介紹
====================

.. image:: /Flash_system_architecture.JPG

圖中一些縮寫的解釋如下:

- I-Code bus : Instruction bus.這條bus由Cortex-M4F連至BusMatrix,核心透過這個bus取出指令。
- D-Code bus : Data bus.這條bus由Cortex-M4F 與 64-Kbyte CCM data RAM 連至BusMatrix,核心透過這個bus讀取字母(literal)與除錯。
- AHB : Advanced High-performance Bus.
- APB : Advanced Peripheral Bus.

關於AHB與APB差異可參考 `Difference Between AHB and APB<http://www.differencebetween.net/technology/difference-between-ahb-and-apb/>`_

關於AMBA的介紹可參考 `Advanced Microcontroller Bus Architecture (AMBA)<http://en.wikipedia.org/wiki/AMBA_High-performance_Bus>`_

- DMA : Direct Memory Access. DMA提供周邊裝置與記憶體、記憶體與記憶體間高速的傳輸,而不須經由CPU的動作。
- CCM : Core Coupled Memory.給core專用的全速64KB RAM,在沒有經過BusMatrix的情況下與core直接連結。
- FLITF : Flash memory interface.

Bus Matrix:

.. image:: /bus_matrix.JPG

Flash模組的組成如下:

- Main memory : 4個16Kbytes Sector、1個64Kbytes Sector及7個128Kbytes Sector,一共1024Kbytes.
- System memory : bootloader code 放置的地方,30Kbytes.
- OTP (One-Time Programmable) : 一次性寫入的空間,共528Kbytes,可參考(http://forum.eepw.com.cn/thread/120354/1)
- Option byte : 用來設定讀寫保護、電壓level、軟硬體看門狗與Standby or Stop模式下的重置,共16Kbytes.

.. image:: /flash module organization.JPG


3 Flash 操作
============
**讀取:**

- 要正確的從Flash中讀取資料,必須在FLASH_ACR中依據CPU clock(HCLK)頻率與供應的電壓來設定正確的WS(Wait State)。
- WS與HCLK關係如下表所示 :

.. image:: /ws_hclk.JPG

- 在Reset之後,HCLK為16MHz,而FLASH_ACR中的ws為0。
- 官方文件建議用以下方法(增加/減少CPU frequency),依據CPU frequency調試存取Flash所需的ws數。

**增加CPU frequency**

1. 在FLASH_ACR中的LATENCY bits設定新的ws值。

::

  000: 0ws(1 CPU cycle)
  001: 1ws(2 CPU cycle)
  010: 2ws(3 CPU cycle)
  011: 3ws(4 CPU cycle)
  100: 4ws(5 CPU cycle)
  101: 5ws(6 CPU cycle)
  110: 6ws(7 CPU cycle)
  111: 7ws(8 CPU cycle)


2. 透過讀取FLASH_ACR確認新的ws值有被設定成功。
3. 透過寫入RCC_CFGR(Reset and Clock Control Configuration Register)中的SW(System clock switch) bits來修正 CPU clock source.

::

  sw : 
  00 : HSI (High Speed Internal)
  01 : HSE (High Speed External)
  10 : PLL (Phase Lock Loop)
  11 : not allowed

- 當離開Stop或Standby模式時,或者當HSE Failure時,將由硬體強制轉為HSI。

可參考(http://blog.csdn.net/joji_h/article/details/5581340)

4. 如果需要的話,可透過寫入RCC_CFGR中的HPRE(AHB Prescaler) bits來修改CPU clock prescaler.

::

  HPRE bits:
  0xxx : System clock not divided
  1000 : System clock divided by 2
  1001 : System clock divided by 4
  1010 : System clock divided by 8
  ...
  1111 : System clock divided by 512


5. 透過讀取讀取RCC_CFGR中的SWS(System clock switch status) bits 來確認新的sw有被設定成功;透過讀取RCC_CFGR中的HPRE bits來確定新的HPRE值有被設定成功。

**減少CPU frequency**

1. 修正RCC_CFGR中SW bits.
2. 如果需要的話,可透過寫入RCC_CFGR中的HPRE bits來修改CPU clock prescaler.
3. 透過讀取讀取RCC_CFGR中的SWS bits 來確認新的sw有被設定成功;透過讀取RCC_CFGR中的HPRE bits來確定新的HPRE值有被設定成功。
4. 在FLASH_ACR中的LATENCY bits設定新的ws值。
5. 透過讀取FLASH_ACR確認新的ws值有被設定成功。

**抹除與寫入:**


在做抹除與寫入動作之前,必須先設定Flash control register(FLASH_CR),然而在Reset之後,FLASH_CR是不可寫入的。因此必須透過以下方法解鎖:

1. 在Flash key register(FLASH_KEYR)中寫入0x45670123。
2. 在Flash key register(FLASH_KEYR)中寫入0xCDEF89AB。

 **必須連續執行1與2才會解鎖**

此外,FLASH_CR在FLASH_SR的BSY值為1時是同樣不可寫入的。

**抹除步驟:**

- **區塊抹除(Sector Erase)**:

1. 檢查Flash status register(FLASH_SR)中BSY(Busy) bit是否為0。(0代表目前沒有其他的Flash操作,1代表有其他Flash操作正在進行中)
2. 設定FLASH_CR中SER(Sector Erase) bit告知啟用區塊抹除,並設定SNB(Sector number) bit告知欲抹除的區塊。

::

  0000 sector 0
  0001 sector 1
  ...
  1011 sector 11
  不得超過此範圍。

3. 設定FLASH_CR中的STRT(Start) bit。
4. 等待FLASH_SR中的BSY清空。

- **大量抹除(Mass Erase)**:

1. 檢查FLASH_SR中BSY bit是否為0。
2. 設定FLASH_CR中的MER(Mass Erase) bit。
3. 設定FLASH_CR中的STRT bit。
4. 等待FLASH_SR中的BSY清空。

**寫入步驟:**

1. 檢查FLASH_SR中BSY bit是否為0。
2. 設定FLASH_CR中的PG(Programming)。
3. 在指定的位置(主要記憶體區塊或OTP區塊)執行資料寫入的動作。(關於記憶體區塊將於下一節介紹)

- 以下是各種型態單次寫入時所需的大小
- **Byte : x8**
- **Half-word : x16**
- **Word : x32**
- **Double-word : x64**

- 而寫入之前必須於FLASH_CR中指定對應的PSIZE,如下表所示:

.. image:: /parallelism.JPG


**當bit寫入由1寫成0時,不需要先Erase;但若將0寫為1時,則需要先Erase才能寫。**

4. 等待FLASH_SR中的BSY清空。

3.1 關於寫入保護(Write Protections) :
----------------------------------

在12個User Sector中(請見5.Flash記憶體架構介紹),Flash memory可以設為保護狀態來避免非預期的寫入操作造成的數據遺失問題。當FLASH_OPTCR中的nWRPi(non-write protection) bit (0 <= i <= 11)為0時,i所對應的sector就不能夠被寫入或抹除。同樣地,在大量抹除中,只要在抹除範圍內有任何一個Sector是寫入保護的狀態,就不能夠進行抹除。

若嘗試在寫入保護的區域中進行寫入/抹除的行為,將會在FLASH_SR中設置WRPERR(Write protection error flag)。



4.Flash interface registers
===========================

3.1 Flash access control register (FLASH_ACR)
-----------------------------------------------

Address offset : 0x00, Reset value: 0x0000 0000.

.. image:: /Flash_acr.JPG

::

  Bits 31:11 保留位置,必須保持淨空。
  Bit 12 DCRST : Data cache reset. 0: not reset; 1: reset. (當D cache未啟用時才可寫入)
  Bit 11 ICRST : Instruction cache reset. 0: not reset ; 1: reset. (當I cache未啟用時才可寫入)
  Bit 10 DCEN : Data cache enable. 0: disabled; 1: enabled.
  Bit 9 ICEN : Instruction cache enable. 0: disabled; 1: enabled.
  Bit 8 PRFTEN : Prefetch enable. 0: disabled; 1: enabled;
  Bits 7:3 保留位置,必須保持淨空。
  Bits 2:0 LATENCY : Latency.

3.2 Flash key register (FLASH_KEYR)
-------------------------------------

Address offset : 0x04, Reset value: 0x0000 0000.

.. image:: /flash_keyr.JPG

::

  Bits 31:0 FKEYR : FPEC key. 解鎖用,前方已經描述過如何解鎖FLASH_CR,在此不贅述。

3.3 Flash status register (FLASH_SR)
-------------------------------------

Address offset : 0x0C, Reset value: 0x0000 0000.

.. image:: /flash_sr.JPG

::

  Bits 31:17 保留位置,必須保持淨空。
  Bit 16 BSY : Busy. 0: 無其他記憶體操作; 1: 其他記憶體操作進行中。
  Bits 15:8 保留位置,必須保持淨空。
  Bit 7 PGSERR : Programming sequence error. 當程式出現錯誤時會設值。若寫入1則清空。
  Bit 6 PGPERR : Programming parallelism error. 當程式寫入大小與型態不符(對照PSIZE)時會設值。若寫入1則清空。
  Bit 5 PGAERR : Programming alignment error. 當資料寫入時無法塞入128-bit的Flash memory row會設值。若寫入1則清空。
  Bit 4 WRPERR : Write protection error. 當嘗試寫入/抹除一個寫入保護的Flash memory區域時會設值。若寫入1則清空。
  Bit 3:2 保留位置,必須保持淨空。
  Bit 1 OPERR : Operation error. 當任何的Flash操作失效時設值,但這個bit只會在ERRIE(Error Interrupts)啟用時生效。
  Bit 0 EOP : End of Operation. 當一或多個Flash操作成功完成時設值,這個bit只會在EOPIE(End of Operation Interrupts)啟用時生效。若寫入1則清空。

3.4 Flash control register (FLASH_CR)
-------------------------------------

Address offset : 0x10, Reset value: **0x8000** 0000.

.. image:: /flash_cr.JPG

::

  Bit 31 LOCK : Lock. 只能寫為1,當值為1時,FLASH_CR將鎖住不可更改,唯有偵測到解鎖序列才會清除。
  Bits 30:26 保留位置,必須保持淨空。
  Bit 25 ERRIE: Error interrupt enable. 0: Disabled; 1: Enabled.
  Bit 24 EOPIE: End of operation interrupt enable. 0: Disabled; 1: Enabled.
  Bits 23:17 保留位置,必須保持淨空。
  Bit 16 STRT: Start. 只能由軟體設置,且在BSY bit清空時會一併清空。
  Bits 15:10 保留位置,必須保持淨空。
  Bits 9:8 PSIZE: Program size. 前方有提過PSIZE的設置,在此不贅述。
  Bits 6:3 SNB: Sector number. 前方有提過SNB的設置,在此不贅述。
  Bit 2 MER: Mass Erase.
  Bit 1 SER: Sector Erase.
  Bit 0 PG: Programming.

3.5 Flash option control register (FLASH_OPTCR)
-----------------------------------------------

Address offset : 0x14, Reset value: **0x0FFF AAED**.

.. image:: /flash_optcr.JPG

::

  Bits 31:28 保留位置,必須保持淨空。
  Bits 27:16 nWRP: Not write protect. 0: write protection active; 1: write protection not active.
  Bits 15:8 RDP: Read protect. 0xAA : Level 0, read protection not active; 0xCC : Level 2, chip read protection active; Others : Level 1, read protection of memories active.
  Bits 7:5 USER: User option bytes
  Bit 4 保留位置,必須保持淨空。
  Bits 3:2 BOR_Level: BOR reset level.
    00 : BOR level 3, 電壓 2.70~3.60V
    01 : BOR level 2, 電壓 2.40~2.70V
    10 : BOR level 1, 電壓 2.10~2.40V
    11 : BOR off, 電壓 1.80~2.10V
  Bit 1 OPTSTRT: Option start.
  Bit 0 OPTLOCK: Option lock.


5.Example
=================

4.1 LED LEGEND
--------------

**GREEN : FLASH is unlocked.**
**BLUE  : FLASH is writing.**
**RED   : FLASH is erasing.**
**YELLOW: FLASH is reading.**

4.2 git repository
------------------
 
-git repo: https://gitcafe.com/xturtle/NCKU-Embedded-2012-Flash-Demo

4.3 operation flow
------------------

- 1 FLASH_UNLOCK
- 2 GREEN LED ON

::

  FLASH_Unlock();
  STM_EVAL_LEDOn(LED4);
  FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | 
                  FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR); 

- 3 WRITE FROM SECTOR 2 TO SECTOR 5 AS "12345678"
- 4 BLUE LED ON
- 5 FINISHED WRITE PROCESS
- 6 BLUE LED OFF

::

  while (Address < FLASH_USER_END_ADDR){
    STM_EVAL_LEDOn(LED6);
    if (FLASH_ProgramWord(Address, DATA_32) == FLASH_COMPLETE) Address = Address + 4;
    else{
      /* Error occurred while writing data in Flash memory. 
         User can add here some code to deal with this error */
      STM_EVAL_LEDOn(LED3);
    }
    STM_EVAL_LEDOff(LED6);
  }

- 7 FLASH_LOCK
- 8 GREEN LED OFF

::

  FLASH_Lock(); 
  STM_EVAL_LEDOff(LED4);

- 9 VERIFICATION

::

  while (Address < FLASH_USER_END_ADDR){
    STM_EVAL_LEDOn(LED3);
    data32 = *(__IO uint32_t*)Address;
    STM_EVAL_LEDOff(LED3);
    if (data32 != DATA_32){
      MemoryProgramStatus++;  
    }
    Address = Address + 4;
  } 

6.STM32F407VG 硬體介紹
=====================

- STM32F407VG版子外觀與模組如下圖所示:

.. image:: /STM32F4_2.jpg

- 上方USB Programmer/Debugger為ST-Link
- 石英晶體震盪器(Crystal),可參考(http://zh.wikipedia.org/zh-tw/%E7%9F%B3%E8%8B%B1%E6%99%B6%E4%BD%93%E8%B0%90%E6%8C%AF%E5%99%A8)
- 中央的晶片為ARM® Cortex™-M4F core with embedded Flash and SRAM,其內部結構如Figure 5所示。
- 三軸加速度感知器(3-axis Accelerometer)
- 音頻數位類比轉換(Audio DAC)
- 麥克風晶片(Chip Microphone)
- USB On The Go (http://forum.slime.com.tw/thread180246.html)
- 音效輸出(Audio Jack)
- 此外,板子上有兩顆按鈕,藍色按鈕為User Button,黑色按鈕為Reset。

.. image:: /block_diag_1.JPG

.. image:: /block_diag_2.JPG

7.Software STM32F4 Lib
======================

.. image:: /lib_1.JPG

8. gdb指令介紹 : 
===============

檔案處理
-------

- file a.elf                 載入可執行檔a.elf
- path                       告訴gdb obj code在那
- directory                  告訴gdb source code在那裡

SHELL
-----

- shell ls                   就會執行ls了


流程控制
-------

- break		設定中斷點 

::
  
  break                         在目前位置設中斷點
  break 100                     在100行中斷
  break main                    在main()中斷
  break +100                    目前位置+100行中斷
  break *0x08048123             在這位址中斷
  break file.c:100              因為如果是多個c檔案時指定file.c
  tbreak                        同break的寫法 不過中斷一次後 此中斷點就失效
  break 100 if (var == 5)       條件中斷: 如果var=5就在line 100中斷

- delete		清除中斷點

::

  delete 1                      刪除編號為1的中斷點
  delete                        刪除所有中斷點

- disable		暫時使中斷失效
- enable		把失效的中斷恢復

::

  disable 3                  暫時使3號中斷點沒作用  後面是中斷點流水編號
  enable 2                   使2號中斷點作用  後面是中斷點流水編號
  
condition   進一步設中斷點的條件 如果條件為true則中斷

::

  condition 3 (var > 3)      設3號中斷點的條件 如果條件為true則中斷
  condition 3                清除3號中斷點的條件
  
- commands    如果中斷發生了則執行commands與end中的一連串gdb命令

::
  
  break 100                     在第100行中斷並且執行command...end中的gdb命令
  commands
    p/x var
  end
  
- run                        開始跑程式
- continue                   中斷後繼續跑
- next                       往下一步: 如果有副程式 執行完整個副程式
- step                       往下一步: 如果有副程式 追進副程式
- until                      跳離一個while for迴圈
- nexti                      往下一步CPU組語的指令(Instruction)執行完整個副程式
- stepi                      往下一步CPU組語的指令(Instruction)追進副程式


訊息觀看與設定
------------

- list                       看原始碼

::

  list x 從第x行的source code印出,x不寫則印出目前中斷點前後的code
  list *addr  秀出addr所在source code的行
              可以先用info program找出目前PC的值
              再用list *addr
  search REGEXP 在目前source code用正規表示式搜尋

- whatis var                 告訴我var的資料型別是啥 int, char or double
- ptype var                  告訴我var的資料型別是啥 這用來看struct用的
- set                        設定gdb, 系統的控制變數值(這些變數不是program內的)

::

  set listsize xx  設定要看xx行source code
  set $pc xx       把PC設到 xx
  set convenience可以自己設變數
						   
程式變數值(data)處理
------------------
- print var                  看var的值
- print &var                 印出var的位址
- print *var                 印出位於位址var的值
- display var                display會每次step, next時都會印出值來, print只印一次
- print (var=value)          設var的值為value
- p/x

::

  p/x 表示印16進位值
  p/u 表示unsigned digit
  p/d signed digit
  p/t 二進位值
                           
                           
- x/3uh 0x8000000          印出記憶體

::

  其中
  3表示看3個 (0x8000000 - 0x8000003)
  u      unsigned digit(跟上面p命令一樣意義) 
  h      halfword就是2bytes(bhwg分別是1248bytes)

- Debug設定(TCP/IP) : 
---------------------

.. image:: /gdb_1.JPG

- Debug流程主要為 :

(1) 在Target(MCU)端開啟App與gdbserver。如果已經將程式燒入flash, 要透過MCU內建的gdb server來debug, 則必須使用st-util:

::

  st-util -p 3333

(2) 開啟Host端的gdb:

::

  arm-none-eabi-gdb your_elf_image.elf

(3) 連接到Target端的gdbserver,如

::

  target extended-remote : 3333 

(4) 當應用程式就緒後,可指定中斷點,接著按c,就會在指定的中斷點停下來。

- 可參考(http://www.codeproject.com/Articles/14983/Remote-Debugging-using-GDB)

9.reference
8.reference
===========

- http://wiki.csie.ncku.edu.tw/embedded/learn-stm32-part-1.pdf
- http://wiki.csie.ncku.edu.tw/embedded/learn-stm32-part-6.pdf
- http://www.triplespark.net/elec/pdev/arm/stm32.html
- http://www.codeproject.com/Articles/14983/Remote-Debugging-using-GDB
- http://cms.mcuapps.com/products/stm32f4-discovery/README.html
- http://cms.mcuapps.com/techinfo/toolchains/openocd/
- http://www.st.com/internet/mcu/product/252140.jsp
- http://zh.wikipedia.org/wiki/%E9%97%AA%E5%AD%98