FSMC總線通信簡介
FSMC是STM32系列采用的一種新型存儲器擴(kuò)展技術(shù)。在外部存儲器擴(kuò)展方面具有獨(dú)特的優(yōu)勢,可根據(jù)系統(tǒng)的應(yīng)用需要,方便進(jìn)行不
同類型大容量靜態(tài)存儲器的擴(kuò)展。
FSMC的特點(diǎn):
(1)支持不同位寬的異步讀寫操作。
(2)不同的BANK在映射地址空間中是獨(dú)立的,可用于擴(kuò)展不同的存儲器。
(3)支持代碼從FSMC擴(kuò)展的外部存儲器中直接運(yùn)行。
兩種工作方式:地址獨(dú)立模式和地址復(fù)用模式
FSMC協(xié)議分析
FSMC協(xié)議的幾個(gè)主要信號:
CSn(片選信號):低電平片選信號有效,高電平失能(默認(rèn)狀態(tài)為高:失能)
NADV(地址有效信號):上升沿鎖存地址的低位
RDn(讀信號):低電平讀信號有效,上升沿鎖存數(shù)據(jù),高電平失能(默認(rèn)狀態(tài)為高:失能)
WRn(寫信號):低電平寫信號有效,上升沿鎖存數(shù)據(jù),高電平失能(默認(rèn)狀態(tài)為高:失能)
FSMC讀/寫操作時(shí)序:

STM32F407 上自帶 FSMC 控制器,通過 FSMC 總線的地址復(fù)用模式實(shí)現(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)行驗(yàn)證。原理圖如下圖所示:

內(nèi)部存儲器IP核的參數(shù)設(shè)置
單端口RAM參數(shù)介紹


創(chuàng)建IP核

①框是設(shè)置輸出數(shù)據(jù)端口的位寬,②框是設(shè)置存儲器容量的大小,這兩個(gè)選項(xiàng)大家可根據(jù)實(shí)際的設(shè)計(jì)進(jìn)行設(shè)置。這里我們設(shè)置數(shù)據(jù)位寬 16bit,存儲容量為 512words,即我們設(shè)置的 RAM 的最大存儲量為 512 個(gè) 16bit 數(shù)據(jù)。
③框是存儲單元類型的選擇,這里我們保持 Auto(軟件自動選擇)即可。
④框中是選擇使用的時(shí)鐘模式,可選擇單時(shí)鐘或雙時(shí)鐘。選擇單時(shí)鐘時(shí):用一個(gè)時(shí)鐘信號控制存儲塊的所有寄存器。選擇雙時(shí)鐘時(shí):輸入時(shí)鐘控制地址寄存器,輸出時(shí)鐘控制數(shù)據(jù)輸出寄存器。大家可根據(jù)設(shè)計(jì)需求進(jìn)行選擇,這里我們選擇默認(rèn)選項(xiàng) Single clock(單時(shí)鐘)。
設(shè)置完之后點(diǎn)擊 Next 進(jìn)入下一界面:

①框是選擇是否輸出“q”輸出寄存器。這里把輸出端口的寄存器去掉(如果不去掉的話,就會使輸出延遲一拍。如果沒有特別的需求的話我們是不需要延遲這一拍的,所以這里我們把它去掉)。
②框是詢問我們是否選擇為時(shí)鐘信號創(chuàng)建響應(yīng)的使能信號,這里我們不需要,不勾選。
③框是詢問我們?yōu)槎丝贏創(chuàng)建字節(jié)使能,這里我們不需要,不勾選。
④框是選擇是否創(chuàng)建“aclr”異步復(fù)位信號以及是否創(chuàng)建“rden”讀使能信號,大家可根據(jù)實(shí)際的設(shè)計(jì)需求進(jìn)行勾選,這里我們把它們都勾選上。設(shè)置完之后點(diǎn)擊 Next 進(jìn)入下一界面:

如上圖所示,是進(jìn)行 Read During Write Operation 項(xiàng)配置,選擇某個(gè)地址即將被寫入數(shù)據(jù)時(shí)讀該地址的數(shù)據(jù)輸出類型:有 Don’t Care(不關(guān)心)、 New Data(寫入的新數(shù)據(jù))和Old Data(原有數(shù)據(jù)),我們保持默認(rèn)的 New Data 即可,也就是說,某個(gè)地址將被寫入新數(shù)據(jù)時(shí),同時(shí)進(jìn)行讀操作會讀出新的數(shù)據(jù)。點(diǎn)擊 Next 進(jìn)入下一頁面:

①框是選擇是否為存儲器配置初始化文件,與 ROM 不同的是,RAM 可以選擇不配置初始化文件,這里我們選擇不配置初始化文件。
②框是選擇是否允許系統(tǒng)內(nèi)存儲器內(nèi)容編輯器在于與系統(tǒng)時(shí)鐘無關(guān)的情況下捕獲和更新存儲器的內(nèi)容,這里我們不勾選。
設(shè)置完后點(diǎn)擊 Next 進(jìn)入下一界面:

如上圖所示,該界面沒有什么要配置的參數(shù),但顯示了我們在仿真 ROM IP 核時(shí)所需要的 Altera 仿真庫,這里提示了我們單獨(dú)使用第三方仿真工具時(shí)需要添加名為“altera_mf”的庫。這里保持默認(rèn),直接點(diǎn)擊“Next”。

RAM 輸出的文件,除了灰色必選文件,默認(rèn)還勾選上了rom_256x8_bb.v,這里我們?nèi)サ?rom_256x8_bb.v 文件,加入my_ram_ints.v(例化模板文件)即可。最后點(diǎn)擊“Finish”完成整個(gè) IP 核的創(chuàng)建。接下來 Quartus II 軟件會在我們創(chuàng)建的 IP 核文件目錄下生成 RAM IP 文件。
FPGA代碼
使用RAM IP核構(gòu)成FSMC,可以從示意圖中看出 我們恰好對得上,需要地址線和數(shù)據(jù)線、讀寫使能線以及,將IP核的分配到實(shí)在的引腳
模塊
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;//時(shí)鐘 input RST_n; //復(fù)位 input nadv; //復(fù)用功能 wire rd; wire wr; assign rd = (csn | rdn);//使能和讀使能共同有效時(shí) assign wr = (csn | wrn);//使能和寫使能共同有效時(shí) wire [15:0]DB_OUT; assign db = !rd ? DB_OUT : 16'hzzzz;//在讀數(shù)據(jù)的時(shí)候,將端口全部設(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};//提取寫時(shí)鐘 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個(gè)周期后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時(shí)鐘 //------------------------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; //時(shí)鐘使能 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ù)用時(shí),NADV是訪問地址和數(shù)據(jù)的區(qū)別信號,你只需要配合時(shí)序參數(shù),芯片會自動識別的。
-
FPGA
+關(guān)注
關(guān)注
1664文章
22508瀏覽量
639504 -
通信
+關(guān)注
關(guān)注
18文章
6457瀏覽量
140282 -
STM32
+關(guān)注
關(guān)注
2313文章
11195瀏覽量
374745 -
FSMC
+關(guān)注
關(guān)注
0文章
55瀏覽量
39204
原文標(biāo)題:FPGA與STM32_FSMC總線通信實(shí)驗(yàn)
文章出處:【微信號:gh_9d70b445f494,微信公眾號:FPGA設(shè)計(jì)論壇】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
STM32如何通過FSMC點(diǎn)亮LCD
求助100腳STM32的FSMC用法 與FPGA的FIFO通信
STM32的FSMC接口讀取FPGA的FIFO
STM32與FPGA通過fsmc通信的實(shí)現(xiàn)方法
STM32的FSMC是如何驅(qū)動8080總線的液晶的?
如何使用STM32的FSMC接口驅(qū)動LCD屏
基于FPGA和STM32的FSMC通信
FPGA MCU FSMC通信接口——NAND Flash模式
AN4761_通過STM32L476、486的FSMC外設(shè)驅(qū)動外部存儲器
FPGA與STM32通過FSMC總線通信的實(shí)驗(yàn)
評論