天天看點

《嵌入式 – GD32開發實戰指南》第20章 GD32的存儲結構

開發環境:

MDK:Keil 5.30

開發闆:GD32F207I-EVAL

MCU:GD32F207IK

20.1 GD32存儲結構的工作原理

20.1.1 Cortex-M核心的存儲器映射

存儲器映射是指把晶片中或晶片外的FLASH,RAM,外設,BOOTBLOCK等進行統一編址。即用位址來表示對象。這個位址絕大多數是由廠家規定好的,使用者隻能用而不能改。使用者隻能在挂外部RAM或FLASH的情況下可進行自定義。

如下圖,是Cortex-M3存儲器映射結構圖。

《嵌入式 – GD32開發實戰指南》第20章 GD32的存儲結構

Cortex-M3是32位的核心,是以其PC指針可以指向2^32=4G的位址空間,也就是0x0000_0000 - 0xFFFF_FFFF這一大塊空間。根據圖中描述,Cortex-M3核心将0x0000_0000 - 0xFFFF_FFFF這塊4G大小的空間分成8大塊:代碼、SRAM、外設、外部RAM、外部裝置、專用外設總線-内部、專用外設總線-外部、特定廠商等,是以使用該核心的設計者必須按照這個進行各自晶片的存儲器結構設計。

20.1.2 GD32存儲器結構

首先,我們對比一下Cortex-M3存儲器結構和GD32存儲器結構:

《嵌入式 – GD32開發實戰指南》第20章 GD32的存儲結構

圖中可以很清晰的看到,GD32的存儲器結構和Cortex-M3的很相似,不同的是,GD32加入了很多實際的東西,如:Flash、SRAM等。隻有加入了這些東西,才能成為一個擁有實際意義的、可以工作的處理晶片-GD32。

GD32的存儲器位址空間被劃分為大小相等的8塊區域,每塊區域大小為512MB。

對GD32存儲器知識的掌握,實際上就是對Flash和SRAM這兩個區域知識的掌握。

20.2 FLASH讀寫資料

20.2.1 GD32的Flash

GD32的Flash,嚴格說,應該是Flash子產品。該Flash子產品包括:Flash主存儲區(Main memory)、Flash資訊區(Information block),以及Flash存儲接口寄存器區(Flash memory interface)。三個組成部分分别在0x0000 0000 - 0xFFFF FFFF不同的區域,GD32F2的Flash結構如下表所示。

《嵌入式 – GD32開發實戰指南》第20章 GD32的存儲結構

【注】資訊塊存儲了boot loader,不能被使用者程式設計或擦除。

GD32的閃存子產品由:主存儲閃存塊、資訊塊和選項位元組塊3部分組成。

主存儲器,該部分用來存放代碼和資料常數(如加const類型的資料)。對于主存儲閃存容量不多于512KB的GD32F20x_CL,閃存頁大小為2KB。對于主存儲閃存容量不少于768KB的GD32F20x_CL,使用了兩片閃存;前512KB容量在第一片閃存(bank0)中,後續的容量在第二片閃存(bank1)中。其中bank0的閃存頁大小為2KB, bank1的閃存頁大小為4KB。主存儲閃存的每頁都可以單獨擦除。

資訊塊,是用來存儲GD自帶的啟動程式,用于序列槽下載下傳,當B0接3.3V,B1接GND時,運作的就這部分代碼,使用者選擇位元組,則一般用于配置保護等功能。

選項位元組塊,該部分用于控制閃存儲器讀取等,是整個閃存儲器的控制機構。

對于主存儲器和資訊塊的寫入有内嵌的閃存程式設計管理;程式設計與擦除的高壓由内部産生。

在執行閃存寫操作時,任何對閃存的讀操作都會鎖定總線,在寫完成後才能正确進行,在進行讀取或擦除操作時,不能進行代碼或者資料的讀取操作。

下面對GD32的存儲器進行總結。

《嵌入式 – GD32開發實戰指南》第20章 GD32的存儲結構

圖中淡藍色就是你需要知道的。

 Peripherals:外設的存儲器映射,對該區域操作,就是對相應的外設進行操作;

 SRAM:運作時臨時存放代碼的地方;

 Flash:存放代碼的地方;

 System Memory:GD32出廠時自帶的你隻能使用,不能寫或擦除;

 Option Bytes:可以按照使用者的需要進行配置(如配置看門狗為硬體實作還是軟體實作);

今後,你的編寫代碼、程式運作、寄存器設定、ICP、IAP都依靠這些東西。

20.2.2 FLASH讀寫實作

GD32F20x 系列産品的片上 Flash 起始位址時 0x0800 0000,最大容量可達 3072 KB。讀操作為 0 等待,可支援位元組、半字(16 bits)和字(32 bits)通路。 Flash 程式設計以半字(16 bits)或字(32bits)為機關。擦除可以以頁(page)為機關,也可以進行全片擦除(information blocks 除外)。

Flash的寄存器有很多,當時GD的工程師已經封裝好了,直接用就可以,我這裡就不在貼出來了。

Flash操作很簡單,我們将資料寫入到Flash中,再将其讀出來。主要有以下步驟:

1.Flash解鎖操作

2.清除Flash标志

3.頁擦除

4.讀寫操作

5.鎖定

核心代碼如下:

#define FLASH_ADR 0x0807F800

/**
  * @brief  flash test
  * @param  WriteAddr, InData
  * @retval OutData
  */
uint32_t flash_test(uint32_t WriteAddr, uint32_t InData)
{
    uint32_t OutData = 0;

    //解鎖
    fmc_unlock();
    //清除标志位
    fmc_flag_clear(FMC_FLAG_BANK0_PGERR | FMC_FLAG_BANK0_WPERR | FMC_FLAG_BANK0_END | FMC_FLAG_BANK1_PGERR | FMC_FLAG_BANK1_WPERR | 
  FMC_FLAG_BANK1_END);
    //要擦出頁的起始位址
    fmc_page_erase(WriteAddr);
    //寫資料
    fmc_word_program(WriteAddr, InData);

    //鎖定
    fmc_lock();
  
    OutData=(*(__IO uint32_t*)(WriteAddr));
    return OutData;
}      

程式就不講了,這裡需要注意一個C語言的知識點。

OutData=(*(__IO uint32_t*)(WriteAddr));      

這一句很多新手很懵逼,也就是從一個位址中讀取資料,多看看指針相關的知識就好了解了。

主函數如下:

/*
    brief      main function
    param[in]  none
    param[out] none
    retval     none
*/
int main(void)
{
    uint32_t InData = 12345678;
    uint32_t OutData;

    // systick init
    sysTick_init();

    // UART1 init
    com_init(COM1);

    // led1 init
    led_init(LED1);

    printf("InData = %d\r\n",InData);

    // flash test
    OutData= flash_test(FLASH_ADR, InData);

    printf("OutData = %d\r\n",OutData);

    if(OutData == InData)
    {
        printf("Flash test success !\r\n");
    }
    else
    {
        printf("Flash test fail !\r\n");
    }
    while(1)
    {
        led_on(LED1);              // 亮
        delay_ms(1000);
        led_off(LED1);          // 滅 
        delay_ms(1000);        
    }
}      

20.2.3實驗結果

将程式邊看一完成後下載下傳到闆子中,通過序列槽助手,按下闆子的複位按鍵可以看到如下現象。

《嵌入式 – GD32開發實戰指南》第20章 GD32的存儲結構

20.3 SRAM啟動

20.3.1 GD32的啟動模式

首先要回顧一下GD32的啟動模式,因為啟動模式決定了向量表的位置,GD32有三種啟動模式:

1)主閃存存儲器(Main Flash)啟動:從GD32内置的Flash啟動(0x0800 0000-0x0807 FFFF),一般我們使用JTAG或者SWD模式下載下傳程式時,就是下載下傳到這個裡面,重新開機後也直接從這啟動程式。以0x08000000 對應的記憶體為例,則該塊記憶體既可以通過0x00000000 操作也可以通過0x08000000 操作,且都是操作的同一塊記憶體。

2)系統存儲器(System Memory)啟動:從系統存儲器啟動(0x1FFFF000 - 0x1FFF F7FF),這種模式啟動的程式功能是由廠家設定的。一般來說,我們選用這種啟動模式時,是為了從序列槽下載下傳程式,因為在廠家提供的ISP程式中,提供了序列槽下載下傳程式的固件,可以通過這個ISP程式将使用者程式下載下傳到系統的Flash中。以0x1FFFFFF0對應的記憶體為例,則該塊記憶體既可以通過0x00000000 操作也可以通過0x1FFFFFF0操作,且都是操作的同一塊記憶體。

3)片上SRAM啟動:從内置SRAM啟動(0x2000 0000-0x3FFFFFFF),既然是SRAM,自然也就沒有程式存儲的能力了,這個模式一般用于程式調試。SRAM 隻能通過0x20000000進行操作,與上述兩者不同。從SRAM 啟動時,需要在應用程式初始化代碼中重新設定向量表的位置。

使用者可以通過設定BOOT0和BOOT1的引腳電平狀态,來選擇複位後的啟動模式。如下圖所示:

《嵌入式 – GD32開發實戰指南》第20章 GD32的存儲結構

啟動模式隻決定程式燒錄的位置,加載完程式之後會有一個重映射(映射到0x00000000位址位置);真正産生複位信号的時候,CPU還是從開始位置執行。

值得注意的是GD32上電複位以後,代碼區都是從0x00000000開始的,三種啟動模式隻是将各自存儲空間的位址映射到0x00000000中。

20.3.2 GD32的SRAM

不同類型的Cortex-M單片機的SRAM大小是不一樣的,但是他們的起始位址都是0x2000 0000,終止位址都是0x2000 0000+其固定的容量大小。

SRAM的了解比較簡單,其作用是用來存取各種動态的輸入輸出資料、中間計算結果以及與外部存儲器交換的資料和暫存資料。裝置斷電後,SRAM中存儲的資料就會丢失。

GD32F20x 系列産品的片上 SRAM 起始位址是 0x2000 0000,最大容量可達 384KB,可支援位元組、半字(16bits)和字(32bits)通路。 片上 SRAM 被分為 SRAM0、 SRAM1 和 SRAM2 等三個子產品,且每個子產品都有一個與 AHB 總線矩陣連接配接的專用接口,這意味着它們可以被同時通路。

子產品 容量 位址範圍
SRAM1 112KB 0x2000 0000 ~ 0x2001 BFFF
SRAM2 16KB 0x2001 C000 ~ 0x2001 FFFF
SRAM3 256KB 0x2002 0000 ~ 0x2005 FFFF

20.3.3片上SRAM啟動實作

在使用片上SRAM調試之前,需要了解為何要使用片上SARM來啟動程式,是以GD32的片上Flash的擦寫次數有限,若超過最大擦除次數則會損壞内部Flash,是以在平時的程式調試階段,最好使用SRAM啟動。

總的來說,SRAM啟動程式有如下用途:

1.調試階段,需要頻繁更新程式,可以SRAM啟動,加快調試,減少flash擦寫損耗

2.程式SWD/JTAG接口已經配置為普通端口,程式啟動後無法程式更新,可在SRAM中啟動後,再更新flash程式

3.程式已經開啟了讀保護,可在SRAM啟動後,進行讀保護關閉

片上SRAM啟動實作的方法很簡單,這裡以GDF207+Keil5舉例,實作方法如下:

1.修改記憶體配置設定

修改了記憶體配置設定,也就是修改分散加載檔案xxx.sct檔案。

《嵌入式 – GD32開發實戰指南》第20章 GD32的存儲結構

修改後再次生成工程,分散檔案也會修改。

《嵌入式 – GD32開發實戰指南》第20章 GD32的存儲結構

下面談談SRAM參數的配置設定,首先确定MCU的RAM大小,筆者使用的MCU是GD32F207,是以SRAM大小是256KB,然後還需要根據程式的編譯大小來配置設定SRAM空間。

《嵌入式 – GD32開發實戰指南》第20章 GD32的存儲結構

如果想友善點可以直接看MAP檔案。

《嵌入式 – GD32開發實戰指南》第20章 GD32的存儲結構

FLASH和RAM的大小分别如下:

Flash = Code + RO Data + RW Data = 3.88KB(3968)

RAM = RW-data + ZI-data=8.07KB(8264)

是以筆者這裡配置設定空間如下:

IROM1位址為0x2000 0000, 大小是0x10000=65536=64kB

IRAM1位址為0x2000 3000, 大小是0x20000=131072=128kB

當然啦,SRAM空間配置設定需要根據自己的 MCU來決定。

2.修改debug配置

建立RAM.ini檔案,配置如下:

/*----------------------------------------------------------------------------
 * Name:    RAM.ini
 * Purpose: RAM Debug Initialization File
 * Note(s):
 *----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
  Setup()  configure PC & SP for RAM Debug
 *----------------------------------------------------------------------------*/
FUNC void Setup (void) {
  SP = _RDWORD(0x20000000);          // Setup Stack Pointer
  PC = _RDWORD(0x20000004);          // Setup Program Counter
  _WDWORD(0xE000ED08, 0x20000000);   // Setup Vector Table Offset Register
}

FUNC void OnResetExec (void)  {      // executes upon software RESET
  Setup();                           // Setup for Running
}

load %L incremental

Setup();                             // Setup for Running

g,      

然後加載進來。

《嵌入式 – GD32開發實戰指南》第20章 GD32的存儲結構

RAM.ini檔案主要是初始化SP和PC指針。Cortex-M3複位時會從0x00000000和0x00000004的相對位置取出MSP初值以及将複位向量位址賦給PC,在SRAM中的絕對位置就是0x20000000和0x20000004。GD32F207需要手動配置。

《嵌入式 – GD32開發實戰指南》第20章 GD32的存儲結構

3.修改下載下傳配置

需要把程式下載下傳到SRAM,修改相應的下載下傳位址。

《嵌入式 – GD32開發實戰指南》第20章 GD32的存儲結構

4.修改中斷向量表指針

由啟動檔案可知,程式啟動首先執行Reset_Handler函數,SRAM啟動硬體強制将PC指針指派為0x200001E0,PC指針加1開始執行啟動檔案,故Reset_Handler函數的運作位址需為0x200001E1才行,否則程式就會跑飛。

是以需要在中斷向量表的末尾添加SPACE 0x96。

《嵌入式 – GD32開發實戰指南》第20章 GD32的存儲結構

同時在在main函數中添加設定中斷向量表以及系統初化函數。

nvic_vector_table_set(NVIC_VECTTAB_RAM,0x00);
SystemInit();      

5.修改啟動模式

這裡選擇SRAM啟動,是以BOOT0->1 BOOT1->1。

最後編譯下載下傳程式,然後就可以運作程式了。

《嵌入式 – GD32開發實戰指南》第20章 GD32的存儲結構

歡迎通路我的網站

​​BruceOu的哔哩哔哩​​​​​​

​​BruceOu的首頁​​

​​BruceOu的部落格​​

​​​BruceOu的簡書​​

資源擷取方式