FSMC總線通信簡介
FSMC是STM32系列采用的一種新型存儲器擴(kuò)展技術(shù)。在外部存儲器擴(kuò)展方面具有獨特的優(yōu)勢,可根據(jù)系統(tǒng)的應(yīng)用需要,方便進(jìn)行不
同類型大容量靜態(tài)存儲器的擴(kuò)展。
FSMC的特點:
(1)支持不同位寬的異步讀寫操作。
(2)不同的BANK在映射地址空間中是獨立的,可用于擴(kuò)展不同的存儲器。
(3)支持代碼從FSMC擴(kuò)展的外部存儲器中直接運行。
兩種工作方式:地址獨立模式和地址復(fù)用模式
FSMC協(xié)議分析
FSMC協(xié)議的幾個主要信號:
CSn(片選信號):低電平片選信號有效,高電平失能(默認(rèn)狀態(tài)為高:失能)
NADV(地址有效信號):上升沿鎖存地址的低位
RDn(讀信號):低電平讀信號有效,上升沿鎖存數(shù)據(jù),高電平失能(默認(rèn)狀態(tài)為高:失能)
WRn(寫信號):低電平寫信號有效,上升沿鎖存數(shù)據(jù),高電平失能(默認(rèn)狀態(tài)為高:失能)
FSMC讀/寫操作時序:
STM32F407 上自帶 FSMC 控制器,通過 FSMC 總線的地址復(fù)用模式實現(xiàn)STM32 與 FPGA 之間的通信,F(xiàn)PGA 內(nèi)部建立 RAM 塊,F(xiàn)PGA 橋接 STM32 和 RAM 塊,通過 FSMC 總線從 STM32 向 RAM 塊中寫入數(shù)據(jù)(數(shù)據(jù)為 0 到 511),然后讀取 RAM出來的數(shù)據(jù)并進(jìn)行驗證。原理圖如下圖所示:
內(nèi)部存儲器IP核的參數(shù)設(shè)置
單端口RAM參數(shù)介紹
創(chuàng)建IP核
①框是設(shè)置輸出數(shù)據(jù)端口的位寬,②框是設(shè)置存儲器容量的大小,這兩個選項大家可根據(jù)實際的設(shè)計進(jìn)行設(shè)置。這里我們設(shè)置數(shù)據(jù)位寬 16bit,存儲容量為 512words,即我們設(shè)置的 RAM 的最大存儲量為 512 個 16bit 數(shù)據(jù)。
③框是存儲單元類型的選擇,這里我們保持 Auto(軟件自動選擇)即可。
④框中是選擇使用的時鐘模式,可選擇單時鐘或雙時鐘。選擇單時鐘時:用一個時鐘信號控制存儲塊的所有寄存器。選擇雙時鐘時:輸入時鐘控制地址寄存器,輸出時鐘控制數(shù)據(jù)輸出寄存器。大家可根據(jù)設(shè)計需求進(jìn)行選擇,這里我們選擇默認(rèn)選項 Single clock(單時鐘)。
設(shè)置完之后點擊 Next 進(jìn)入下一界面:
①框是選擇是否輸出“q”輸出寄存器。這里把輸出端口的寄存器去掉(如果不去掉的話,就會使輸出延遲一拍。如果沒有特別的需求的話我們是不需要延遲這一拍的,所以這里我們把它去掉)。
②框是詢問我們是否選擇為時鐘信號創(chuàng)建響應(yīng)的使能信號,這里我們不需要,不勾選。
③框是詢問我們?yōu)槎丝贏創(chuàng)建字節(jié)使能,這里我們不需要,不勾選。
④框是選擇是否創(chuàng)建“aclr”異步復(fù)位信號以及是否創(chuàng)建“rden”讀使能信號,大家可根據(jù)實際的設(shè)計需求進(jìn)行勾選,這里我們把它們都勾選上。設(shè)置完之后點擊 Next 進(jìn)入下一界面:
如上圖所示,是進(jìn)行 Read During Write Operation 項配置,選擇某個地址即將被寫入數(shù)據(jù)時讀該地址的數(shù)據(jù)輸出類型:有 Don’t Care(不關(guān)心)、 New Data(寫入的新數(shù)據(jù))和Old Data(原有數(shù)據(jù)),我們保持默認(rèn)的 New Data 即可,也就是說,某個地址將被寫入新數(shù)據(jù)時,同時進(jìn)行讀操作會讀出新的數(shù)據(jù)。點擊 Next 進(jìn)入下一頁面:
①框是選擇是否為存儲器配置初始化文件,與 ROM 不同的是,RAM 可以選擇不配置初始化文件,這里我們選擇不配置初始化文件。
②框是選擇是否允許系統(tǒng)內(nèi)存儲器內(nèi)容編輯器在于與系統(tǒng)時鐘無關(guān)的情況下捕獲和更新存儲器的內(nèi)容,這里我們不勾選。
設(shè)置完后點擊 Next 進(jìn)入下一界面:
如上圖所示,該界面沒有什么要配置的參數(shù),但顯示了我們在仿真 ROM IP 核時所需要的 Altera 仿真庫,這里提示了我們單獨使用第三方仿真工具時需要添加名為“altera_mf”的庫。這里保持默認(rèn),直接點擊“Next”。
RAM 輸出的文件,除了灰色必選文件,默認(rèn)還勾選上了rom_256x8_bb.v,這里我們?nèi)サ?rom_256x8_bb.v 文件,加入my_ram_ints.v(例化模板文件)即可。最后點擊“Finish”完成整個 IP 核的創(chuàng)建。接下來 Quartus II 軟件會在我們創(chuàng)建的 IP 核文件目錄下生成 RAM IP 文件。
FPGA代碼
使用RAM IP核構(gòu)成FSMC,可以從示意圖中看出 我們恰好對得上,需要地址線和數(shù)據(jù)線、讀寫使能線以及,將IP核的分配到實在的引腳
模塊
FSMC模塊
module FSMC_Ctrl( ab, db, wrn, rdn, csn, PLL_100M, RST_n, nadv ); input [8:0]ab;//地址 inout [15:0]db;//數(shù)據(jù) input wrn;//寫使能 input rdn;//讀使能 input csn;//使能 input PLL_100M;//時鐘 input RST_n; //復(fù)位 input nadv; //復(fù)用功能 wire rd; wire wr; assign rd = (csn | rdn);//使能和讀使能共同有效時 assign wr = (csn | wrn);//使能和寫使能共同有效時 wire [15:0]DB_OUT; assign db = !rd ? DB_OUT : 16'hzzzz;//在讀數(shù)據(jù)的時候,將端口全部設(shè)置成高阻態(tài) reg wr_clk1,wr_clk2; always @(posedge PLL_100M or negedge RST_n) begin if(!RST_n) begin wr_clk1 <= 1'd1; wr_clk2 <= 1'd1; end else {wr_clk2,wr_clk1} <= {wr_clk1,wr};//提取寫時鐘 end wire clk = (!wr_clk2 | !rd); my_ram u1(//ram塊例化 .address(ab), .clock(clk), .data(db), .wren(!wr), .rden(!rd), .q(DB_OUT), ); endmodule
復(fù)位模塊
//--------------------Timescale------------------------------// `timescale 1 ns / 1 ps //--------------------RST_Ctrl------------------------// module RST_Ctrl( input FPGA_CLK,//輸入板載晶振FPGA_CLK,25M output RST_n//輸出全局復(fù)位信號 ); //--------------------RST_n----------------------------------// reg [3:0] cnt_rst = 4'd0; always @(posedge FPGA_CLK) if (cnt_rst == 4'd10) cnt_rst <= 4'd10; else cnt_rst <= cnt_rst + 1'd1; assign RST_n = (cnt_rst == 4'd10);//復(fù)位信號,10個周期后RST_n為1 //--------------------endmodule------------------------------// endmodule
頂層文件
//-------------------------Timescale----------------------------// `timescale 1 ns / 1 ps //--------------------FSMC_SIG---------------------// module FSMC_INDEP( FPGA_CLK,//輸入板載晶振GPGA_CLK,25M FPGA_LEDR, FPGA_LEDG, FPGA_LEDB, WR,//FSMC寫信號 RD,//FSMC讀信號 CS0,//FSMC片選 A,//FSMC地址總線 DB,//FSMC數(shù)據(jù)總線 NADV,//FSMC的NADV ); input FPGA_CLK,NADV; input WR,RD,CS0; inout [15:0]DB; input [24:16]A; output FPGA_LEDB,FPGA_LEDG,FPGA_LEDR; assign FPGA_LEDR = 1'd1; assign FPGA_LEDG = 1'd0; assign FPGA_LEDB = 1'd1; //-------------------------MY_PLL-------------------------------// wire PLL_100M; MY_PLL U1( .inclk0(FPGA_CLK), .c0(PLL_100M) );//例化MY_PLL模塊,輸出50M時鐘 //------------------------RST_Ctrl-----------------------------// wire RST_n; RST_CtrlU2( .FPGA_CLK(FPGA_CLK), .RST_n(RST_n) );//例化RST_Ctrl模塊,輸出全局復(fù)位信號RST_n //-------------------------FSMC_Ctrl ------------------------------// FSMC_CtrlU3(//FSMC總線測試模塊 .ab(A[24:16]), .db(DB), .wrn(WR), .rdn(RD), .csn(CS0), .PLL_100M(PLL_100M), .RST_n(RST_n), .nadv(NADV) ); //------------------------enmodule ---------------------------// endmodule
STM32標(biāo)準(zhǔn)庫的程序
fsmc.h
//------------------------define---------------------------// #ifndef __fsmc_h__ #define __fsmc_h__ //---------------------Include files-----------------------// //----------------------- Define --------------------------// #define fpga_write(offset,data)*((volatile unsigned short int *)(0x60000000 + (offset << 17))) = data #define fpga_read(offset)*((volatile unsigned short int *)(0x60000000 + (offset << 17))) //----------------- Typedef -----------------------------// typedef struct{ int (* initialize)(void); }FSMC_T; //---------------- Extern -------------------------------// extern FSMC_T fsmc; #endif //__fsmc_h__
fsmc.c
/* * FILE: fsmc.c * DESCRIPTION: This file is iCore3 fsmc driver. * Author: XiaomaGee@Gmail.com * Copyright: * * History * -------------------- * Rev: 0.00 * Date: 01/03/2016 * * create. * -------------------- */ //---------------- Include files ------------------------// #include "..includefsmc.h" #include "..fwlibincstm32f4xx_rcc.h" #include "..fwlibincstm32f4xx_gpio.h" #include "..fwlibincstm32f4xx_fsmc.h" //---------------- Function Prototype -------------------// static int initialize(void); //---------------- Variable -----------------------------// FSMC_T fsmc = { .initialize = initialize }; //-----------------Function------------------------------// /* * Name: initialize * Description: --- * Author: XiaomaGee. * * History * ---------------------- * Rev: 0.00 * Date: 01/03/2016 * * create. * ---------------------- */ static int initialize(void) { GPIO_InitTypeDef GPIO_InitStructure; FSMC_NORSRAMInitTypeDef FSMC_NORSRAMInitStructure; FSMC_NORSRAMTimingInitTypeDef p; //時鐘使能 RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FSMC, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOE | RCC_AHB1Periph_GPIOG, ENABLE); //IO初始化 GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_FSMC); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_PinAFConfig(GPIOD, GPIO_PinSource0, GPIO_AF_FSMC); GPIO_PinAFConfig(GPIOD, GPIO_PinSource1, GPIO_AF_FSMC); GPIO_PinAFConfig(GPIOD, GPIO_PinSource3, GPIO_AF_FSMC); GPIO_PinAFConfig(GPIOD, GPIO_PinSource4, GPIO_AF_FSMC); GPIO_PinAFConfig(GPIOD, GPIO_PinSource5, GPIO_AF_FSMC); GPIO_PinAFConfig(GPIOD, GPIO_PinSource6, GPIO_AF_FSMC); GPIO_PinAFConfig(GPIOD, GPIO_PinSource7, GPIO_AF_FSMC); GPIO_PinAFConfig(GPIOD, GPIO_PinSource8, GPIO_AF_FSMC); GPIO_PinAFConfig(GPIOD, GPIO_PinSource9, GPIO_AF_FSMC); GPIO_PinAFConfig(GPIOD, GPIO_PinSource10, GPIO_AF_FSMC); GPIO_PinAFConfig(GPIOD, GPIO_PinSource11, GPIO_AF_FSMC); GPIO_PinAFConfig(GPIOD, GPIO_PinSource12, GPIO_AF_FSMC); GPIO_PinAFConfig(GPIOD, GPIO_PinSource13, GPIO_AF_FSMC); GPIO_PinAFConfig(GPIOD, GPIO_PinSource14, GPIO_AF_FSMC); GPIO_PinAFConfig(GPIOD, GPIO_PinSource15, GPIO_AF_FSMC); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | 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; GPIO_Init(GPIOD, &GPIO_InitStructure); GPIO_PinAFConfig(GPIOE, GPIO_PinSource2 , GPIO_AF_FSMC); GPIO_PinAFConfig(GPIOE, GPIO_PinSource3 , GPIO_AF_FSMC); GPIO_PinAFConfig(GPIOE, GPIO_PinSource4 , GPIO_AF_FSMC); GPIO_PinAFConfig(GPIOE, GPIO_PinSource5 , GPIO_AF_FSMC); GPIO_PinAFConfig(GPIOE, GPIO_PinSource6 , GPIO_AF_FSMC); GPIO_PinAFConfig(GPIOE, GPIO_PinSource7 , GPIO_AF_FSMC); GPIO_PinAFConfig(GPIOE, GPIO_PinSource8 , GPIO_AF_FSMC); GPIO_PinAFConfig(GPIOE, GPIO_PinSource9 , GPIO_AF_FSMC); GPIO_PinAFConfig(GPIOE, GPIO_PinSource10, GPIO_AF_FSMC); GPIO_PinAFConfig(GPIOE, GPIO_PinSource11, GPIO_AF_FSMC); GPIO_PinAFConfig(GPIOE, GPIO_PinSource12, GPIO_AF_FSMC); GPIO_PinAFConfig(GPIOE, GPIO_PinSource13, GPIO_AF_FSMC); GPIO_PinAFConfig(GPIOE, GPIO_PinSource14, GPIO_AF_FSMC); GPIO_PinAFConfig(GPIOE, GPIO_PinSource15, GPIO_AF_FSMC); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | 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; GPIO_Init(GPIOE, &GPIO_InitStructure); GPIO_PinAFConfig(GPIOG, GPIO_PinSource13, GPIO_AF_FSMC); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; GPIO_Init(GPIOG, &GPIO_InitStructure); //FSMC初始化 p.FSMC_AddressSetupTime = 1; p.FSMC_AddressHoldTime = 0; p.FSMC_DataSetupTime = 4; p.FSMC_BusTurnAroundDuration = 0; p.FSMC_CLKDivision = 0; p.FSMC_DataLatency = 0; p.FSMC_AccessMode = FSMC_AccessMode_A; FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM1; FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Enable; FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_SRAM; FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b; FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable; FSMC_NORSRAMInitStructure.FSMC_AsynchronousWait = FSMC_AsynchronousWait_Disable; FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low; FSMC_NORSRAMInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable; FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState; FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable; FSMC_NORSRAMInitStructure.FSMC_WaitSignal = FSMC_WaitSignal_Disable; FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable; FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable; FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &p; FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &p; FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure); //FSMC Bank1_SRAM1 Bank使能 FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM1, ENABLE); return 0; }
led.c
//--------------------------- Include ---------------------------// #include "..includeled.h" #include "..fwlibincstm32f4xx_gpio.h" #include "..fwlibincstm32f4xx_rcc.h" //--------------------- Function Prototype ----------------------// static int initialize(void); //--------------------------- Variable --------------------------// LED_T led = { .initialize = initialize }; //--------------------------- Function --------------------------// /* * Name : initialize * Description : --- * Author : ysloveivy. * * History * -------------------- * Rev : 0.00 * Date : 01/03/2016 * * create. * -------------------- */ static int initialize(void) { GPIO_InitTypeDef GPIO_uInitStructure; //LED IO初始化 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOI,ENABLE); GPIO_uInitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; //設(shè)置連接三色LED燈的IO端口 GPIO_uInitStructure.GPIO_Mode = GPIO_Mode_OUT; //設(shè)置端口為輸出模式 GPIO_uInitStructure.GPIO_OType = GPIO_OType_PP; //推挽輸出 GPIO_uInitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉 GPIO_uInitStructure.GPIO_Speed = GPIO_Speed_100MHz; //設(shè)置速度為第三級 GPIO_Init(GPIOI,&GPIO_uInitStructure); //PI5、PI6、PI7接三色LED燈,PI5、PI6、PI7置高電位,燈熄滅 GPIO_SetBits(GPIOI,GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7); return 0; }
led.h
#ifndef __led_h__ #define __led_h__ //--------------------------- Define ---------------------------// //紅燈<----->PI5 #define LED_RED_OFF GPIO_SetBits(GPIOI,GPIO_Pin_5) #define LED_RED_ON GPIO_ResetBits(GPIOI,GPIO_Pin_5) //綠燈<----->PI6 #define LED_GREEN_OFF GPIO_SetBits(GPIOI,GPIO_Pin_6) #define LED_GREEN_ON GPIO_ResetBits(GPIOI,GPIO_Pin_6) //藍(lán)燈<----->PI7 #define LED_BLUE_OFF GPIO_SetBits(GPIOI,GPIO_Pin_7) #define LED_BLUE_ON GPIO_ResetBits(GPIOI,GPIO_Pin_7) //----------------------- Include files ------------------------// //-------------------------- Typedef----------------------------// typedef struct { int (* initialize)(void); }LED_T; //--------------------------- Extern ---------------------------// extern LED_T led; #endif //__led_h__
主函數(shù)
int main(void) { int i; unsigned short int fsmc_read_data; /*初始化*/ led.initialize(); fsmc.initialize(); LED_GREEN_ON; /*綠色led亮,表示測試正常 紅色led亮,表示測試失敗,測試結(jié)束*/ while(1){ for(i = 0;i < 512;i++){ fpga_write(i,i); //向FPGA寫入數(shù)據(jù) } for(i = 0;i < 512;i++){ fsmc_read_data = fpga_read(i); //從FPGA讀數(shù)據(jù) if(fsmc_read_data != i){ LED_GREEN_OFF; LED_RED_ON; while(1); } } } }
復(fù)用模式說明
地址和數(shù)據(jù)線復(fù)用時,NADV是訪問地址和數(shù)據(jù)的區(qū)別信號,你只需要配合時序參數(shù),芯片會自動識別的。
-
FPGA
+關(guān)注
關(guān)注
1629文章
21736瀏覽量
603385 -
通信
+關(guān)注
關(guān)注
18文章
6032瀏覽量
135993 -
STM32
+關(guān)注
關(guān)注
2270文章
10900瀏覽量
356008 -
FSMC
+關(guān)注
關(guān)注
0文章
55瀏覽量
38152
原文標(biāo)題:FPGA與STM32_FSMC總線通信實驗
文章出處:【微信號:gh_9d70b445f494,微信公眾號:FPGA設(shè)計論壇】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論