25.1實驗內容
通過本實驗主要學習以下內容:
25.2實驗原理
MCU的片內SRAM空間有限,在做一些大量數據處理、GUI顯示等應用中片內SRAM容量無法滿足應用需求,而外部SRAM器件讀寫速度快,不需要自刷新,工作穩定,是性能最優的外擴RAM選擇之一。MCU通過EXMC接口可以實現外部SRAM的接口通信協議,同時可映射到內部地址實現和內部ram相同的操作方式。
25.2.1EXMC外設原理
EXMC是MCU的外部存儲控制器,可以配置實現各類片外設備的通信協議,包括SRAM、PSRAM、NOR FLASH、NAND FLASH等,也可以通過配置實現一些其他通信協議,如8080接口的LCD驅動、FPGA通信等,可靈活的實現很多異步同步信號輸入輸出,時序時間可配置。更重要的是EXMC可通過地址映射方式實現MCU內部總線協議到外部器件通信的轉換,實現高效的數據讀取和輸出能力。
- EXMC系統架構如下圖所示,外部SRAM使用NOR-Flash/PSRAM控制器實現通信協議,使用NWE、NOE、EXMC_Dx、EXMC_Ax、EXMC_NBLx、EXMC_NEx引腳和SRAM器件進行連接。
EXMC根據不同存儲器類型,對應有4個BANK,每個BANK各256MB占用了不同地址空間。訪問對應BANK區的地址時EXMC會自動按對應改區存儲類型的時序和配置進行通信。
25.2.2EXMC NOR/SRAM模式介紹
如SRAM/NOR類型對應區域為BANK0總計256MB空間。而BANK0其中有分了4個Regions各64MB,每個Regions分別對應NE0——NE4引腳連接的器件,可以連接4個64MB SRAM就可以組成256MB的連續SRAM地址空間,也可以連接4個NOR或者2個NOR和2個SRAM的組合方式。
- 訪問外部SRAM時,采用了EXMC SRAM異步訪問模式A,讀寫開始時NE先拉低,接著地址先建立并保持,同時其他信號根據當前訪問方向等進行信號對應輸出,接下來MCU或器件輸出數據信號建立,在輸出使能的邊沿進行采樣,讀寫結束NE拉高。讀寫信號時序如下圖:
在這個時序過程中,很多參數可以進行配置調節,其中主要是地址建立和保持、數據建立的參數,一般根據速率要求、硬件信號斜率限制來平衡這個參數,目標為達到一個滿足穩定性的最高速率參數。相關參數如下表所示:
25.2.3外部SRAM器件原理
sram存儲模型可以使用下圖說明:
SRAM內部包含的存儲陣列,和表格查找一樣,指定一個行地址和列地址,就可以精確地找到目標BIT單元格,這是SRAM芯片尋址的基本原理。這樣的每個單元格被稱為存儲單元,而這樣的表則被稱為存儲矩陣。地址譯碼器把N根地址線轉換成2的N次方根信號線,每根信號線對應一行或一列存儲單元,通過地址線找到具體的存儲單元,實現尋址。如果存儲陣列比較大,地址線會分成行和列地址,或者行、列分時復用同一地址總線,訪問數據尋址時先用地址線傳輸行地址再傳輸列地址。
在外部SRAM上,列地址對應了數據寬度,如例程所用的IS62WV51216BLL為16位寬度,故而行地址范圍是19,對應了IS62WV51216BLL的A0-A19引腳,主控芯片通過A0-A19引腳即可實現對行地址進行尋址訪問到對應的16BIT數據。
如下圖所示為外部SRAM接口信號,主控通過特定接口按時序即可時序地址發送、數據發送和讀取,實現對指定地址數據的讀寫。
25.3硬件設計
如下是IS62WV51216BLL的原理圖設計,MCU通過EXMC相關對應接口連接到SRAM。
- SRAM作為敏感器件,需要保證電源的穩定、減少噪聲,串接了磁珠后供電,同時對sram的vdd引腳必須就近放置0.1uf去耦電容,若整個系統中存在較多其他負載,可以再增加較大電容穩定電源。
- SRAM的CS引腳通過MCU EXMC_NEx引腳控制,由于片選信號較為關鍵,避免MCU在EXMC多器件時懸空信號不穩定導致誤操作,需要增加上拉電阻;在這里,上拉電阻應當靠近SRAM放置,減少連接回路上的耦合干擾。
25.4代碼解析
EXMC在初始化后,基本上通過程序的地址映射就可以進行操作了,需要根據外部器件的要求進行exmc相關參數配置,exmc可配置參數有很多,但選定好一個模式后實際在這個模式下需要配置的參數是有限的,一些結構體成員只需要按默認參數配置即可。
25.4.1EXMC SRAM模式初始化
- 在sram訪問時,可能會調整的exmc參數如下:
- 整個SRAM配置過程主要包含:GPIO和EXMC外設接口時鐘、GPIO配置、EXMC相關參數配置,完整代碼如下:
C /*! * 說明 emxc nor/sram模式初始化 * 輸入[1] norsram_region: @EXMC_BANK0_NORSRAM_REGION0/EXMC_BANK0_NORSRAM_REGION1/EXMC_BANK0_NORSRAM_REGION2/EXMC_BANK0_NORSRAM_REGION3 * 返回值 無 */ void driver_exmc_sram_init(uint32_t norsram_region) { exmc_norsram_parameter_struct nor_init_struct; exmc_norsram_timing_parameter_struct nor_timing_init_struct; /* EXMC clock enable */ rcu_periph_clock_enable(RCU_EXMC); /* EXMC enable */ rcu_periph_clock_enable(RCU_GPIOB); rcu_periph_clock_enable(RCU_GPIOD); rcu_periph_clock_enable(RCU_GPIOE); rcu_periph_clock_enable(RCU_GPIOF); rcu_periph_clock_enable(RCU_GPIOG); /* configure EXMC_D[0~15]*/ /* PD14(EXMC_D0), PD15(EXMC_D1),PD0(EXMC_D2), PD1(EXMC_D3), PD8(EXMC_D13), PD9(EXMC_D14), PD10(EXMC_D15) */ gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0 | GPIO_PIN_1| GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15); /* PE7(EXMC_D4), PE8(EXMC_D5), PE9(EXMC_D6), PE10(EXMC_D7), PE11(EXMC_D8), PE12(EXMC_D9), PE13(EXMC_D10), PE14(EXMC_D11), PE15(EXMC_D12) */ gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15); /* configure NBL0(PE0) and NBL1(PE1) */ gpio_init(GPIOG, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_9 | GPIO_PIN_10); /* configure NBL0(PE0) and NBL1(PE1) */ gpio_init(GPIOF, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15); exmc_norsram_struct_para_init(&nor_init_struct); /* config timing parameter */ nor_timing_init_struct.asyn_access_mode = EXMC_ACCESS_MODE_A; nor_timing_init_struct.syn_data_latency = EXMC_DATALAT_2_CLK; nor_timing_init_struct.syn_clk_division = EXMC_SYN_CLOCK_RATIO_2_CLK; nor_timing_init_struct.bus_latency = 0; nor_timing_init_struct.asyn_data_setuptime = 8; nor_timing_init_struct.asyn_address_holdtime = 8; nor_timing_init_struct.asyn_address_setuptime = 8; /* config EXMC bus parameters */ nor_init_struct.norsram_region = norsram_region; nor_init_struct.write_mode = EXMC_ASYN_WRITE; nor_init_struct.extended_mode = DISABLE; nor_init_struct.asyn_wait = DISABLE; nor_init_struct.nwait_signal = DISABLE; nor_init_struct.memory_write = ENABLE; nor_init_struct.nwait_config = EXMC_NWAIT_CONFIG_BEFORE; nor_init_struct.wrap_burst_mode = DISABLE; nor_init_struct.nwait_polarity = EXMC_NWAIT_POLARITY_LOW; nor_init_struct.burst_mode = DISABLE; nor_init_struct.databus_width = EXMC_NOR_DATABUS_WIDTH_16B; nor_init_struct.memory_type = EXMC_MEMORY_TYPE_SRAM; nor_init_struct.address_data_mux = DISABLE; nor_init_struct.read_write_timing = &nor_timing_init_struct; nor_init_struct.write_timing = &nor_timing_init_struct; exmc_norsram_init(&nor_init_struct); /* enable the EXMC bank0 NORSRAM */ exmc_norsram_enable(norsram_region); } |
25.4.2初始化調用
- 紅楓派開發板中SRAM的CS連接引腳為EXMC_NE0引腳,故而對應EXMC BANK0 Region0區,調用初始化時我們傳入參數EXMC_BANK0_NORSRAM_REGION0即可。
C //初始化exmc norsram region0 driver_exmc_norsram_init(EXMC_BANK0_NORSRAM_REGION0); |
25.4.3地址映射訪問方式
- 初始化好后EXMC BANK0 Region0區的地址可以理解就和外部SRAM形成了映射關系,讀寫這些地址時EXMC會先拉低NE0選擇SRAM進行通信和交互;
exmc驅動的頭文件中定義好了BANK的4個Region地址,我們對Region0地址讀寫即可實現外部SRAM的數據讀寫。
- 同樣我們也可以直接在編譯器里定義外部sram地址范圍,直接讓編譯器把定義的變量和數組放在外部sram中,我們不用再關心其具體地址;但我們需要在main函數之前初始化好exmc,可以在啟動文件中調用exmc初始化。
25.4.4main函數設計
mian函數中通過指針方式以8位、16位、32位寫并讀取校驗了外部SRAM數據
C int main(void) { uint32_t writereadstatus = 0; //延時和公共驅動部分初始化 driver_init(); //打印串口初始化 bsp_uart_init(&BOARD_UART); //初始化LED組 bsp_led_group_init(); bsp_led_off(&LED0); bsp_led_off(&LED1); //初始化exmc norsram region0 driver_exmc_norsram_init(EXMC_BANK0_NORSRAM_REGION0); delay_ms(100); printf("External sram read and write examples.\r\n"); //以32位讀寫校驗 printf("32-bit read/write check.\r\n"); writereadstatus=0; for(uint32_t index = 0; index < EXMC_SRAM_SIZE; index++ ){ REG32(EXMC_BANK0_NORSRAM_REGION0_ADDR+index*4)=0xa55aa55a; } for(uint32_t index = 0; index < EXMC_SRAM_SIZE; index++ ){ if(0xa55aa55a!=REG32(EXMC_BANK0_NORSRAM_REGION0_ADDR+index*4)){ writereadstatus++; break; } } if(writereadstatus){ bsp_led_on(&LED0); printf("\r\n32-bit read/write SRAM test failed!"); }else{ bsp_led_on(&LED1); printf("\r\n32-bit read/write SRAM test successed!"); } //以16位讀寫校驗 printf("16-bit read/write check.\r\n"); writereadstatus=0; for(uint32_t index = 0; index < EXMC_SRAM_SIZE; index++ ){ REG16(EXMC_BANK0_NORSRAM_REGION0_ADDR+index*2)=0xaaaa; } for(uint32_t index = 0; index < EXMC_SRAM_SIZE; index++ ){ if(0xaaaa!=REG16(EXMC_BANK0_NORSRAM_REGION0_ADDR+index*2)){ writereadstatus++; break; } } if(writereadstatus){ bsp_led_on(&LED0); printf("\r\n16-bit read/write SRAM test failed!"); }else{ bsp_led_on(&LED1); printf("\r\n16-bit read/write SRAM test successed!"); } //以8位讀寫校驗 printf("8-bit read/write check.\r\n"); writereadstatus=0; for(uint32_t index = 0; index < EXMC_SRAM_SIZE; index++ ){ REG8(EXMC_BANK0_NORSRAM_REGION0_ADDR+index)=0x55; } for(uint32_t index = 0; index < EXMC_SRAM_SIZE; index++ ){ if(0x55!=REG8(EXMC_BANK0_NORSRAM_REGION0_ADDR+index)){ writereadstatus++; break; } } if(writereadstatus){ bsp_led_on(&LED0); printf("\r\n8-bit read/write SRAM test failed!"); }else{ bsp_led_on(&LED1); printf("\r\n8-bit read/write SRAM test successed!"); } while (1) { } } |
25.5實驗結果
連接USB轉串口,將打印讀寫校驗結果。
-
單片機
+關注
關注
6032文章
44525瀏覽量
633256 -
sram
+關注
關注
6文章
764瀏覽量
114638 -
開發板
+關注
關注
25文章
4959瀏覽量
97214 -
GD32
+關注
關注
7文章
403瀏覽量
24235 -
EXMC
+關注
關注
0文章
7瀏覽量
5185
發布評論請先 登錄
相關推薦
評論