close

6

SRAMFlash記憶體存取

 

6.1 STM32內建SRAM記憶體簡介

  SIOC內的處理器(STM32F103C8T6)內含Embedded SRAM20K ByteSRAM最主要的目的是存放暫存變數的地方,如宣告一個整數變數int a;,系統就會在SRAM中配置一個區塊給變數a使用,而處理器是透過32bitDBus(Data Bus)SRAM進行存取的動作,如下圖一所示:

image002    

 

處理器傳送資料是透過Data Bus,在存取資料之前要先找到SRAM的位址是在哪裡,因此透過Memory Mapping的方式來找到SRAMSRAM的起始位址在0x2000 0000,結束位址為0x2000 5000,如下圖二所示:

image004  

 

若是透過Keil軟體來撰寫程式的話,那麼在Keil環境設定如下圖三所示:

image006  

 

(圖三)

 

圖中的IRAM1StartSize欄位即為設定SRAM的起始位址和記憶體大小,

 

圖中的RAM1~RAM3是設定外部SRAM的地方,因為SIOC沒有外部SRAM,因此這個地方不用做任何設定。

 

 

 

 

 

6.2  加速SRAM資料存取的方法

 

  SIOC可外接其他周邊,而大部分的周邊的通訊協定每次都只能傳8bit資料,如UARTI2C,而SIOC內含32bit處理器、32bit Data Bus32bit Address Bus,因為每筆資料只有8bit,因此在進行傳輸的動作時Data bus24bit將會沒有使用造成浪費(32 bit Data bus8bit資料,會將剩下24bit mask)

  為了提高Data bus的使用率,可以用下列程式寫作技巧來改善

 

 u8 A[128],B[128];

 

  u8 *temp1=&A[0],*temp2=&B[0];

 

  u32 *temp3=(u32 *)A,*temp4=(u32 *)B;      

 

  int i;

 

  printf("Matrix A= \r\n");

 

  for(i=0;i<128;i++){

 

     *(temp2+i)=1;

 

     printf(“%2d”,*(temp2+i));  }

 

  printf("\r\n");

 

 

printf("8bit \r\n");

 

  for(i=0;i<512;i++){

 

           *(temp2+i)=*(temp1+i);

 

           State_flag = 1;

 

           Stopwatch_counter();}

 

  printf("\r\n");

(法一)

 

 

printf("32bit \r\n");

 

  for(i=0;i<128;i++){

 

           *(temp4+i)=*(temp3+i);

 

           State_flag = 2;

 

           Stopwatch_counter();}

 

  printf("\r\n");

 

 

 

(法二)

 

 

  假設我們要對同訊協定為I2CCMOS Senser先取得影像後再將RGB格式的圖片轉成YUV格式的圖片,在上述程式中的A陣列為原始圖片(RGB格式)B陣列為轉換後圖片(YUV格式),兩個陣列每筆資料皆為8bit,一般作法會使用法一的方式,也就是不透過任何技巧,每次都是搬移8bit資料,共要搬512次,才能夠把A陣列的資料搬到B陣列中,為了提高Data Bus的使用率,可以透過法二的方式,先宣告兩個指標temp3temp4,兩者型態皆為32bit,透過型態轉換後,在進行搬移資料的動作,從下列結果就可以看出,只要搬128次就可以結束。

 

 

 

image009  

 

(圖四)  

 

  圖四中的for 1代表法一搬移資料的次數共512次,而for 2就是代表法二搬移資料的次數共128次,由此可知採用法二可以提升Data Bus和處理器的使用率,提升整體速度。

 

 

 

6.3  STM32內建Flash記憶體簡介

 

  SIOC內的處理器(STM32F103C8T6)內含Embedded Flash,大小為128K ByteFlash主要是用來存放DFU程式、程式碼、資料,Flash最大的特性就是可以重複讀寫、電源關閉後資料不會消失和保護資料的功能。

 

  SIOC的內部結構圖如下圖一所示:

image011  

 

(圖一)

 

  處理器要存取FLASH之前,必須先透過圖中的flash interface來存取flash資料,而flash interface就具備保護的功能,當我們保護flash的某些page時,如外界要對這些page存取時,就會被flash interface擋下。

 

  一開始有提到,程式碼是放在flash裡,當CPU要透過Ibus(Instruction Bus)存取指令時,所存取的位址如下圖二所示:

image013  

 

由圖二可得知Flash的起始位址為0x0800 0000結束位址為0x0801FFF,若將此部分更加細分來看,如圖三所示:

image014  

 

(圖三)

 

Flash每個page size1Kbyte,共有128page可以使用,Main是用來存放DFU程式、程式碼、資料的地方,而Information block是給flash interface使用。

 

SIOC也提供了一些Registerflash interface使用,如下圖四所示:

image015  

 

(圖四)

 

Register細部內容可以參考http://140.115.155.53/~miat/roger/FLASH.pdf

 

這份Data Sheet23~29頁。

 

  ST提供了一些library function讓程式開發人員能夠更容易存取flash,如下圖五所示:

image016  

image017  

(圖五)

最常使用的function分別為:

FLASH_Unlock(打開controller清除的功能)

FLASH_Lock(關閉controller清除的功能)

Flash_ErasePage(指定特定Page進行清除的動作)

Flash_EraseOptionBytes(清除掉OptionByte內容)

FLAH_ProgramWorld(寫入一筆1world資料到FLASH的特定位址內)

FLASH_EnableWriteProtection(對某page進行寫入的保護)

FLASH_ReadOutProtection(對某page進行讀取的保護)

FLASH_ProgramHalfWorld(寫入一筆16bit資料到FLASH的特定位址內)的流程圖如圖六所示:

image018  

 

(圖六)

 

Grafcet:

image019  

 

此流程圖一開始是檢查FLASH controller是否lock住,若有則離開,否則就繼續往下執行,接著將FLASH_CR_PG設定為1(要對某page進行存取的動作),然後就可以將半個world(16 bit資料)寫入到指定位址中,再寫的時候,為了避免還沒寫完就離開這種情形發生,所以透過FLASH_SR_BSYCPU知道現在是否已經將資料寫入完畢,若還沒則繼續等,否則就完成寫入動作。

 

  其他Function的流程圖在http://140.115.155.53/~miat/roger/FLASH.pdf

 

這份data sheet裡面有,請讀者自行參考

 

 

 

6.4  立即演練

 

實驗1flash memory資料存取

 

實驗說明:將資料0x1504197寫入到FLASH指定位址中。

1.      Grafcet:

image020 

2.    程式說明:

 

 

 

#define StartAddr  ((u32)0x08008000)                            [ 區塊一]

#define EndAddr    ((u32)0x0800C000)

u32 EraseCounter = 0x00, Address = 0x00;

u32 Data;

vu32 NbrOfPage = 0x00;

volatile FLASH_Status FLASHStatus;

volatile TestStatus MemoryProgramStatus;

void NVIC_Configuration(void);

int main(void)

{ u32 *temp;

  Set_System();

  /*pause*/

  getchar();

  printf("start \r\n");

  FLASHStatus = FLASH_COMPLETE;

  MemoryProgramStatus = PASSED;

  Data = 0x15041925;                                                     [ 區塊二 ]

  /* NVIC configuration */

  NVIC_Configuration();

/* Unlock the Flash Program Erase controller */

FLASH_Unlock();

 /* Define the number of page to be erased */

  NbrOfPage = (EndAddr - StartAddr) / FLASH_PAGE_SIZE;

 /* Clear All pending flags */

FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);     

/* Erase the FLASH pages */

for(EraseCounter = 0; (EraseCounter < NbrOfPage) &&

(FLASHStatus == FLASH_COMPLETE); EraseCounter++)     [ 區塊三 ]

{FLASHStatus = FLASH_ErasePage(StartAddr +

(FLASH_PAGE_SIZE * EraseCounter));}

/*  FLASH Word program of data 0x15041979 at addresses defined by

StartAddr and EndAddr*/

 Address = StartAddr;

while((Address < EndAddr) && (FLASHStatus == FLASH_COMPLETE))

{  FLASHStatus = FLASH_ProgramWord(Address, Data);

    temp=(u32 *)Address;                                                                      [ 區塊四 ]

    printf("0x%x data is 0x%x \r\n",Address,*temp);

    Address = Address + 4;

}

 

區塊一的主要目的在於設定資料要寫在FLASH的哪裡到哪裡,而我們資料要寫入FLASH必須要注意不可以覆蓋到DFU程式和主程式的部分

 

0x0800 0000~0x0800 2FFFDFU程式碼區段

 

0x0800 3000~0x0800 5C10(假設程式結束位址在0x0800 5C10)為主程式區段

 

而資料就必須放在0x0800 5C10資後,所以資料的StartAddr可設定為

 

0x0800 5C14(範例中是設定0x0800 8000,會浪費0x0800 5C14~0x0800 7FFF這段FLASH)

 

程式結束位址算法如下:

 

(1)   撰寫程式然後進行compiler的動作

 

(2)   Compiler之後會產生.hex的十六進制檔案(MDK-ARM\STM3210B-EVAL\STM3210B-EVAL.hex)

 

(3)   依照下列格式

Untitled  

其中:代表這行是十六進制資料

aaaa即為FLSH位址的後四碼

例如:

:020000040800F2

:10300000100E002001310008913E0008DD3D00084F

………

:105C00001A4497292829106908011B3C020406CC74

:0C5C10002D0102030404850607080900AA

:04000005080030EDD2

:00000001FF

STM3210B-EVAL.hex的倒數第三行即為程式碼的最後一行

對照上述格式,可以求出程式碼最後一行放在FLASH0x0800 5C10

因此資料必須重0x0800 5C14開始放,才不會覆蓋到主程式碼.

區塊的主要目的在於設定資料要寫data

區塊的主要目的在於清除FLASHPAGE內容

區塊的主要目的在於在起始和結束地址間入內容

3.      執行結果:

image029  

實驗2非揮發性資料寫入

實驗說明:檢查電源關閉後,FLASH內容是否存在。

1.      Grafect:

 image030  

2.      程序說明:

  /* Erase the FLASH pages */

  for(EraseCounter = 0; (EraseCounter < NbrOfPage) && (FLASHStatus ==    

  FLASH_COMPLETE); EraseCounter++)

  {

 

      //  FLASHStatus = FLASH_ErasePage(StartAddr + (FLASH_PAGE_SIZE *

      EraseCounter));

  }

 

  /*  FLASH Word program of data 0x15041979 at addresses defined by StartAddr and EndAddr*/

  Address = StartAddr;

  while((Address < EndAddr) && (FLASHStatus == FLASH_COMPLETE))

  {

                //       FLASHStatus = FLASH_ProgramWord(Address, Data);

                      temp=(u32 *)Address;

                       printf("0x%x data is 0x%x \r\n",Address,*temp);

                       Address = Address + 4;

  }

 

 

程序中橙色部分為與實驗一相比程序修改的部分

3.  實驗步驟:

(1)   先將實驗一完成,即是將資料寫入到0x0800 8000~0x0800 C000

(2)   修改實驗一的程式,將區塊三(清除page)刪除,以及區塊四的

FLASH_ProgramWord(Address, Data);刪除

(3)   重新燒入修改過的程式,即可將先前寫入的資料讀出來,並且檢查是否存在

 

 

實驗3 flash資料寫入鎖定

實驗說明:保護FLASH內的資料。

1.      程式說明:

 

 #ifdef WriteProtection_Disable

  printf("WriteProtection_Disable \r\n");

  if (ProtectedPages == 0x00)

  {/* Pages are write protected */

    /* Disable the write protection */

    FLASHStatus = FLASH_EraseOptionBytes();

    /* Generate System Reset to load the new option byte values */

    NVIC_GenerateSystemReset(); }

#else

 #ifdef WriteProtection_Enable

  printf("WriteProtection_Enable \r\n");

  if (ProtectedPages != 0x00)

  {/* Pages not write protected */

    /* Disable the write protection */

    FLASHStatus = FLASH_EraseOptionBytes();

    /* Enable the pages write protection */

    //FLASHStatus = FLASH_EnableWriteProtection(FLASH_WRProt_Pages12to13 |FLASH_WRProt_Pages14to15);         // 0x00006000 / 0x800 =12         0x0000 8000 / 0x800=                16

    FLASHStatus = FLASH_EnableWriteProtection(FLASH_WRProt_Pages24to27 |FLASH_WRProt_Pages28to31);      // 0x00006000   / 0x400 =            24  0x0000 8000 / 0x400 =           32

                /* Generate System Reset to load the new option byte values */

    NVIC_GenerateSystemReset();

 

  }

 

 #endif

 

#endif

 

 

定義上述巨集對特定Page進行寫入保護的動作

範例中是以一個page為2K來計算,因為SIOC的一個page為

1K,因此0x00006000/ 0x400 =24,若要保護0x00006000之後的資料,

就必須對page24進行寫入的保護,請讀者自行求出實驗一的資料是在那些Page,然後對那些page進行寫入的保護

請使用預設0x08006000之後的位置,避免覆蓋DFU與使用者程式碼區塊

更改寫入位置測試寫入鎖定時需同時更改   FLASH_EnableWriteProtection鎖定之Page

 

 

 

 

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 youboook 的頭像
    youboook

    youboook的部落格

    youboook 發表在 痞客邦 留言(0) 人氣()