STM32 uses FSMC to communicate with FPGA

It is very convenient to use the AXI bus in ZYNQ to interact between PS and PL. STM32 can use FSMC to simulate AXI interaction. The ones are 16-bit. Initialize FSMC first

#include "fsmc.h"



void FSMC_init(void)
{<!-- -->
GPIO_InitTypeDef GPIO_InitStructure;
FSMC_NORSRAMInitTypeDef FSMC_NORSRAMInitStructure;
FSMC_NORSRAMTimingInitTypeDef readWriteTiming;
\t
\t
//clock enable
RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FSMC, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOE | RCC_AHB1Periph_GPIOG, ENABLE);
\t
//IO initialization
GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_FSMC);
\t
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);
\t
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_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_Init(GPIOE, & GPIO_InitStructure);
\t
GPIO_PinAFConfig(GPIOG, GPIO_PinSource13, GPIO_AF_FSMC);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_Init(GPIOG, & GPIO_InitStructure);
\t
//FSMC initialization
readWriteTiming.FSMC_AddressSetupTime = 1;
readWriteTiming.FSMC_AddressHoldTime = 0;
readWriteTiming.FSMC_DataSetupTime = 4;
readWriteTiming.FSMC_BusTurnAroundDuration = 0;
readWriteTiming.FSMC_CLKDivision = 0;
readWriteTiming.FSMC_DataLatency = 0;
readWriteTiming.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 = &readWriteTiming;
FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &readWriteTiming;

FSMC_NORSRAMInit( & FSMC_NORSRAMInitStructure);
//FSMC Bank1_SRAM1 Bank enable
FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM1, ENABLE);
}

The corresponding FPGA module is as follows

 module fsmc(
ab,
db,
wrn,
rdn,
csn,
PLL_100M,
RST_n,
nadv
 );
\t
input [8:0]ab;
inout [15:0]db;
input wrn;
input rdn;
input csn;
input PLL_100M;
input RST_n;
input nadv;
\t
wire rd;
wire wr;
\t
assign rd = (csn | rdn);
assign wr = (csn | wrn);
\t
wire [15:0]DB_OUT;
\t
assign db = !rd ? DB_OUT : 16'hzzzz;

reg wr_clk1, wr_clk2;
\t
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}; //Extract write clock
end
\t\t
reg rd_clk;
\t
always @(posedge PLL_100M or negedge RST_n)
begin
if(!RST_n)
rd_clk <= 1'd1;
else
rd_clk <= rd; // extract read clock
end
\t\t
wire clk = (!wr_clk2 | !rd);
\t\t\t\t
\t\t
\t\t
my_ram u1( //ram block instantiation
.address(ab),
.clock(clk),
.data(db),
.wren(!wr),
.rden(!rd),
.q(DB_OUT),
);
\t
\t
endmodule

The interactive core code is just one sentence, but it should be noted that it is said in the “STM32F4XX Chinese Reference Manual”

Because the 16-bit data width is used, the bus will automatically shift one bit to the right, so we shift one bit to the left

#define FPGA_OFFSET_ADDR(reg) *((volatile unsigned short int *)(0x60000000 + ((reg) << 17)))