FSMC總線通信簡介
FSMC是STM32系列采用的一種新型存儲器擴展技術。在外部存儲器擴展方面具有獨特的優(yōu)勢,可根據(jù)系統(tǒng)的應用需要,方便進行不
同類型大容量靜態(tài)存儲器的擴展。
FSMC的特點:
(1)支持不同位寬的異步讀寫操作。
(2)不同的BANK在映射地址空間中是獨立的,可用于擴展不同的存儲器。
(3)支持代碼從FSMC擴展的外部存儲器中直接運行。
兩種工作方式:地址獨立模式和地址復用模式
FSMC協(xié)議分析
FSMC協(xié)議的幾個主要信號:
- CSn(片選信號):低電平片選信號有效,高電平失能(默認狀態(tài)為高:失能)
- NADV(地址有效信號):上升沿鎖存地址的低位
- RDn(讀信號):低電平讀信號有效,上升沿鎖存數(shù)據(jù),高電平失能(默認狀態(tài)為高:失能)
- WRn(寫信號):低電平寫信號有效,上升沿鎖存數(shù)據(jù),高電平失能(默認狀態(tài)為高:失能)
FSMC讀/寫操作時序:
STM32F407 上自帶 FSMC 控制器,通過 FSMC 總線的地址復用模式實現(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ù)并進行驗證。原理圖如下圖所示:
內(nèi)部存儲器IP核的參數(shù)設置
單端口RAM參數(shù)介紹
創(chuàng)建IP核
①框是設置輸出數(shù)據(jù)端口的位寬,②框是設置存儲器容量的大小,這兩個選項大家可根據(jù)實際的設計進行設置。這里我們設置數(shù)據(jù)位寬 16bit,存儲容量為 512words,即我們設置的 RAM 的最大存儲量為 512 個 16bit 數(shù)據(jù)。
③框是存儲單元類型的選擇,這里我們保持 Auto(軟件自動選擇)即可。
④框中是選擇使用的時鐘模式,可選擇單時鐘或雙時鐘。選擇單時鐘時:用一個時鐘信號控制存儲塊的所有寄存器。選擇雙時鐘時:輸入時鐘控制地址寄存器,輸出時鐘控制數(shù)據(jù)輸出寄存器。大家可根據(jù)設計需求進行選擇,這里我們選擇默認選項 Single clock(單時鐘)。
設置完之后點擊 Next 進入下一界面:
①框是選擇是否輸出“q”輸出寄存器。這里把輸出端口的寄存器去掉(如果不去掉的話,就會使輸出延遲一拍。如果沒有特別的需求的話我們是不需要延遲這一拍的,所以這里我們把它去掉)。
②框是詢問我們是否選擇為時鐘信號創(chuàng)建響應的使能信號,這里我們不需要,不勾選。
③框是詢問我們?yōu)槎丝贏創(chuàng)建字節(jié)使能,這里我們不需要,不勾選。
④框是選擇是否創(chuàng)建“aclr”異步復位信號以及是否創(chuàng)建“rden”讀使能信號,大家可根據(jù)實際的設計需求進行勾選,這里我們把它們都勾選上。設置完之后點擊 Next 進入下一界面:
如上圖所示,是進行 Read During Write Operation 項配置,選擇某個地址即將被寫入數(shù)據(jù)時讀該地址的數(shù)據(jù)輸出類型:有 Don’t Care(不關心)、 New Data(寫入的新數(shù)據(jù))和Old Data(原有數(shù)據(jù)),我們保持默認的 New Data 即可,也就是說,某個地址將被寫入新數(shù)據(jù)時,同時進行讀操作會讀出新的數(shù)據(jù)。點擊 Next 進入下一頁面:
①框是選擇是否為存儲器配置初始化文件,與 ROM 不同的是,RAM 可以選擇不配置初始化文件,這里我們選擇不配置初始化文件。
②框是選擇是否允許系統(tǒng)內(nèi)存儲器內(nèi)容編輯器在于與系統(tǒng)時鐘無關的情況下捕獲和更新存儲器的內(nèi)容,這里我們不勾選。
設置完后點擊 Next 進入下一界面:
如上圖所示,該界面沒有什么要配置的參數(shù),但顯示了我們在仿真 ROM IP 核時所需要的 Altera 仿真庫,這里提示了我們單獨使用第三方仿真工具時需要添加名為“altera_mf”的庫。這里保持默認,直接點擊“Next”。
RAM 輸出的文件,除了灰色必選文件,默認還勾選上了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核構成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; //復位
input nadv; //復用功能
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ù)的時候,將端口全部設置成高阻態(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
復位模塊
//--------------------Timescale------------------------------//
`timescale 1 ns / 1 ps
//--------------------RST_Ctrl------------------------//
module RST_Ctrl(
input FPGA_CLK, //輸入板載晶振FPGA_CLK,25M
output RST_n //輸出全局復位信號
);
//--------------------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);//復位信號,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_Ctrl U2(
.FPGA_CLK(FPGA_CLK),
.RST_n(RST_n)
); //例化RST_Ctrl模塊,輸出全局復位信號RST_n
//-------------------------FSMC_Ctrl ------------------------------//
FSMC_Ctrl U3( //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標準庫的程序
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 "..\include\fsmc.h"
#include "..\fwlib\inc\stm32f4xx_rcc.h"
#include "..\fwlib\inc\stm32f4xx_gpio.h"
#include "..\fwlib\inc\stm32f4xx_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 "..\include\led.h"
#include "..\fwlib\inc\stm32f4xx_gpio.h"
#include "..\fwlib\inc\stm32f4xx_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; //設置連接三色LED燈的IO端口
GPIO_uInitStructure.GPIO_Mode = GPIO_Mode_OUT; //設置端口為輸出模式
GPIO_uInitStructure.GPIO_OType = GPIO_OType_PP; //推挽輸出
GPIO_uInitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_uInitStructure.GPIO_Speed = GPIO_Speed_100MHz; //設置速度為第三級
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)
//藍燈<----->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亮,表示測試失敗,測試結束*/
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);
}
}
}
}
復用模式說明文章來源:http://www.zghlxwxcb.cn/news/detail-754215.html
地址和數(shù)據(jù)線復用時,NADV是訪問地址和數(shù)據(jù)的區(qū)別信號,你只需要配合時序參數(shù),芯片會自動識別的。文章來源地址http://www.zghlxwxcb.cn/news/detail-754215.html
到了這里,關于FPGA與STM32_FSMC總線通信實驗的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!