赞
踩
前言
本文介绍STM32与FPGA通过fsmc通信的实现方法。
FSMC(Flexible Static Memory Controller,可变静态存储控制器)是STM32系列采用的一种新型的存储器扩展技术。在外部存储器扩展方面具有独特的优势,可根据系统的应用需要,方便地进行不同类型大容量静态存储器的扩展。
该使用方法本质是将FPGA当做SRAM来驱动,支持的存储器类型有SRAM、PSRAM、NOR/ONENAND、ROM、LCD接口(支持8080和6800模式)、NANDFlash和16位的PCCard。
本次例程使用的处理芯片:STM32F407和Cyclone IV EP4CE22E144。
STM32引脚连接使用的是复用fsmc功能引脚。
STM32 FSMC初始化
- /* Includes ------------------------------------------------------------------*/
- #include "fsmc.h"
-
- #include "gpio.h"
-
- /* USER CODE BEGIN 0 */
-
- /* USER CODE END 0 */
-
- SRAM_HandleTypeDef hsram1;
-
- /* FSMC initialization function */
- void MX_FSMC_Init(void)
- {
- FSMC_NORSRAM_TimingTypeDef Timing;
-
- HAL_FSMC_MspInit();
-
- /** Perform the SRAM1 memory initialization sequence
- */
- hsram1.Instance = FSMC_NORSRAM_DEVICE;
- hsram1.Extended = FSMC_NORSRAM_EXTENDED_DEVICE;
- /* hsram1.Init */
- hsram1.Init.NSBank = FSMC_NORSRAM_BANK1;
- hsram1.Init.DataAddressMux = FSMC_DATA_ADDRESS_MUX_ENABLE;
- hsram1.Init.MemoryType = FSMC_MEMORY_TYPE_PSRAM;
- hsram1.Init.MemoryDataWidth = FSMC_NORSRAM_MEM_BUS_WIDTH_16;
- hsram1.Init.BurstAccessMode = FSMC_BURST_ACCESS_MODE_DISABLE;
- hsram1.Init.WaitSignalPolarity = FSMC_WAIT_SIGNAL_POLARITY_LOW;
- hsram1.Init.WrapMode = FSMC_WRAP_MODE_DISABLE;
- hsram1.Init.WaitSignalActive = FSMC_WAIT_TIMING_BEFORE_WS;
- hsram1.Init.WriteOperation = FSMC_WRITE_OPERATION_ENABLE;
- hsram1.Init.WaitSignal = FSMC_WAIT_SIGNAL_DISABLE;
- hsram1.Init.ExtendedMode = FSMC_EXTENDED_MODE_DISABLE;
- hsram1.Init.AsynchronousWait = FSMC_ASYNCHRONOUS_WAIT_ENABLE;
- hsram1.Init.WriteBurst = FSMC_WRITE_BURST_DISABLE;
- hsram1.Init.PageSize = FSMC_PAGE_SIZE_NONE;
- /* Timing */
- Timing.AddressSetupTime = 1;
- Timing.AddressHoldTime = 1;
- Timing.DataSetupTime = 5;
- Timing.BusTurnAroundDuration = 1;
- Timing.CLKDivision = 16;
- Timing.DataLatency = 17;
- Timing.AccessMode = FSMC_ACCESS_MODE_A;
- /* ExtTiming */
-
- if (HAL_SRAM_Init(&hsram1, &Timing, NULL) != HAL_OK)
- {
- _Error_Handler(__FILE__, __LINE__);
- }
-
- }
-
- static uint32_t FSMC_Initialized = 0;
-
- static void HAL_FSMC_MspInit(void){
- /* USER CODE BEGIN FSMC_MspInit 0 */
-
- /* USER CODE END FSMC_MspInit 0 */
- GPIO_InitTypeDef GPIO_InitStruct;
- if (FSMC_Initialized) {
- return;
- }
- FSMC_Initialized = 1;
- /* Peripheral clock enable */
- __HAL_RCC_FSMC_CLK_ENABLE();
-
- /** FSMC GPIO Configuration
- PE7 ------> FSMC_DA4
- PE8 ------> FSMC_DA5
- PE9 ------> FSMC_DA6
- PE10 ------> FSMC_DA7
- PE11 ------> FSMC_DA8
- PE12 ------> FSMC_DA9
- PE13 ------> FSMC_DA10
- PE14 ------> FSMC_DA11
- PE15 ------> FSMC_DA12
- PD8 ------> FSMC_DA13
- PD9 ------> FSMC_DA14
- PD10 ------> FSMC_DA15
- PD14 ------> FSMC_DA0
- PD15 ------> FSMC_DA1
- PD0 ------> FSMC_DA2
- PD1 ------> FSMC_DA3
- PD3 ------> FSMC_CLK
- PD4 ------> FSMC_NOE
- PD5 ------> FSMC_NWE
- PD6 ------> FSMC_NWAIT
- PD7 ------> FSMC_NE1
- PB7 ------> FSMC_NL
- PE0 ------> FSMC_NBL0
- PE1 ------> FSMC_NBL1
- */
- /* GPIO_InitStruct */
- GPIO_InitStruct.Pin = 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_PIN_0|GPIO_PIN_1;
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
- GPIO_InitStruct.Alternate = GPIO_AF12_FSMC;
-
- HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
-
- /* GPIO_InitStruct */
- GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_14
- |GPIO_PIN_15|GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_3
- |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
- GPIO_InitStruct.Alternate = GPIO_AF12_FSMC;
-
- HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
-
- /* GPIO_InitStruct */
- GPIO_InitStruct.Pin = GPIO_PIN_7;
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
- GPIO_InitStruct.Alternate = GPIO_AF12_FSMC;
-
- HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
-
- /* USER CODE BEGIN FSMC_MspInit 1 */
-
- /* USER CODE END FSMC_MspInit 1 */
- }
-
- void HAL_SRAM_MspInit(SRAM_HandleTypeDef* sramHandle){
- /* USER CODE BEGIN SRAM_MspInit 0 */
-
- /* USER CODE END SRAM_MspInit 0 */
- HAL_FSMC_MspInit();
- /* USER CODE BEGIN SRAM_MspInit 1 */
-
- /* USER CODE END SRAM_MspInit 1 */
- }
-
- static uint32_t FSMC_DeInitialized = 0;
-
- static void HAL_FSMC_MspDeInit(void){
- /* USER CODE BEGIN FSMC_MspDeInit 0 */
-
- /* USER CODE END FSMC_MspDeInit 0 */
- if (FSMC_DeInitialized) {
- return;
- }
- FSMC_DeInitialized = 1;
- /* Peripheral clock enable */
- __HAL_RCC_FSMC_CLK_DISABLE();
-
- /** FSMC GPIO Configuration
- PE7 ------> FSMC_DA4
- PE8 ------> FSMC_DA5
- PE9 ------> FSMC_DA6
- PE10 ------> FSMC_DA7
- PE11 ------> FSMC_DA8
- PE12 ------> FSMC_DA9
- PE13 ------> FSMC_DA10
- PE14 ------> FSMC_DA11
- PE15 ------> FSMC_DA12
- PD8 ------> FSMC_DA13
- PD9 ------> FSMC_DA14
- PD10 ------> FSMC_DA15
- PD14 ------> FSMC_DA0
- PD15 ------> FSMC_DA1
- PD0 ------> FSMC_DA2
- PD1 ------> FSMC_DA3
- PD4 ------> FSMC_NOE
- PD5 ------> FSMC_NWE
- PD6 ------> FSMC_NWAIT
- PD7 ------> FSMC_NE1
- PB7 ------> FSMC_NL
- PE0 ------> FSMC_NBL0
- PE1 ------> FSMC_NBL1
- */
- HAL_GPIO_DeInit(GPIOE, 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_PIN_0|GPIO_PIN_1);
-
- HAL_GPIO_DeInit(GPIOD, GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_14
- |GPIO_PIN_15|GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_4
- |GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7);
-
- HAL_GPIO_DeInit(GPIOB, GPIO_PIN_7);
-
- /* USER CODE BEGIN FSMC_MspDeInit 1 */
-
- /* USER CODE END FSMC_MspDeInit 1 */
- }
-
- void HAL_SRAM_MspDeInit(SRAM_HandleTypeDef* sramHandle){
- /* USER CODE BEGIN SRAM_MspDeInit 0 */
-
- /* USER CODE END SRAM_MspDeInit 0 */
- HAL_FSMC_MspDeInit();
- /* USER CODE BEGIN SRAM_MspDeInit 1 */
-
- /* USER CODE END SRAM_MspDeInit 1 */
- }
STM32通信部分代码:
- /* USER CODE END Prototypes */
- #define fpga_write(addr_base,data) *((uint16_t *const volatile)(0x60000000 + addr_base)) = (uint16_t)data
-
- #define fpga_read(offset) *((uint16_t *const volatile)(0x60000000 + offset))
- //#define fpga_read(offset) *((volatile int32_t* )(0x60000000 + offset))
-
- void fsmc_fpga_write(int addr_base,uint16_t* data,int lenth);
- void fsmc_fpga_read(int offset,uint16_t* data,int lenth);
FPGA内部使用avalon总线接口。因此,需要实现fsmc转avalon桥接模块的程序。程序如下:
fsmc_to_avmm
- module fsmc_to_avmm(
- input csi_clk,
- input csi_clk_4x,
- input csi_reset_n,
-
- output reg [15 : 0] avm_address,
- output reg avm_read_n,
- input [15 : 0] avm_readdata,
- output reg avm_write_n,
- output [15 : 0] avm_writedata,
- (* direct_enable = 1 *)
- input avm_waitrequest,
- output [1 : 0] avm_byteenable,
-
- input coe_nadv,
- (* direct_enable = 1 *)
- input coe_ne,
- input coe_noe,
- input coe_nwe,
- input [1 : 0] coe_nbl,
- output reg coe_nwait,
- inout [15 : 0] coe_addr_data_bus
- );
-
- reg [1 : 0] meta_nadv;
- reg [1 : 0] meta_ne;
- reg [1 : 0] meta_noe;
- reg [1 : 0] meta_nwe;
- reg stb_nadv;
- reg stb_ne;
- reg stb_noe;
- reg stb_nwe;
-
- reg [15 : 0] fsmc_data_out;
- reg [15 : 0] addr_latch;
- (* direct_enable = 1 *)
- reg [15 : 0] write_addr_latch;
- reg [15 : 0] data_latch;
- reg [1 : 0] byteenable_wr_latch;
-
- reg fifo_wrreq;
- reg fifo_rdreq;
- wire fifo_almostfull;
- wire fifo_empty;
- wire fifo_full;
- wire [35 : 0] fifo_dout;
- wire [7 : 0] fifo_usedw;
-
- (* direct_enable = 1 *)
- reg [15 : 0] avm_read_address;
- wire [15 : 0] avm_write_address;
- reg [15 : 0] avm_readdata_latch;
-
- assign coe_addr_data_bus = (stb_noe) ? 16'bz : fsmc_data_out;
- always @ (posedge csi_clk_4x or negedge csi_reset_n)
- begin
- if (!csi_reset_n) begin
- meta_nadv <= 2'b11;
- meta_ne <= 2'b11;
- meta_noe <= 2'b11;
- meta_nwe <= 2'b11;
- stb_nadv <= 1;
- stb_ne <= 1;
- stb_noe <= 1;
- stb_nwe <= 1;
- end
- else begin
- meta_nadv <= {meta_nadv[0],coe_nadv};
- meta_ne <= {meta_ne[0],coe_ne};
- meta_noe <= {meta_noe[0],coe_noe};
- meta_nwe <= {meta_nwe[0],coe_nwe};
- stb_nadv <= coe_nadv;
- stb_ne <= coe_ne;
- stb_noe <= coe_noe;
- stb_nwe <= coe_nwe;
- end
- end
- always @ (posedge coe_nadv or negedge csi_reset_n)
- begin
- if (!csi_reset_n) begin
- addr_latch <= 16'b0;
- end
- else begin
- if (!coe_ne) begin
- addr_latch <= coe_addr_data_bus;
- // Should add constraints between addr_latch and csi_clk clock regions
- // Recommended to use set_max_delay or set_multicycle_path
- end
- else begin
- addr_latch <= addr_latch;
- end
- end
- end
-
- always @ (posedge coe_nwe or negedge csi_reset_n)
- begin
- if (!csi_reset_n) begin
- data_latch <= 16'b0;
- end
- else begin
- if (!coe_ne) begin
- data_latch <= coe_addr_data_bus;
- byteenable_wr_latch <= ~coe_nbl;
- // Should add constraints between data_latch and csi_clk clock regions
- // Recommended to use set_max_delay or set_multicycle_path
- end
- else begin
- data_latch <= data_latch;
- byteenable_wr_latch <= byteenable_wr_latch;
- end
- end
- end
- reg [2 : 0] fsmc_state;
- reg [2 : 0] fsmc_next_state;
- localparam FSMC_IDLE = 3'b1;
- localparam FSMC_READ = 3'b10;
- localparam FSMC_WRITE = 3'b100;
-
- always @ (posedge csi_clk or negedge csi_reset_n)
- begin
- if (!csi_reset_n) begin
- fsmc_state <= FSMC_IDLE;
- end
- else begin
- fsmc_state <= fsmc_next_state;
- end
- end
-
- always @ (*)
- begin
- case (fsmc_state)
- FSMC_IDLE : begin
- casez ({ stb_ne, stb_noe, stb_nwe }) // synthesis full_case
- 3'b001 : begin
- fsmc_next_state = FSMC_READ;
- end
- 3'b010 : begin
- fsmc_next_state = FSMC_WRITE;
- end
- 3'b011 : begin
- fsmc_next_state = FSMC_IDLE;
- end
- 3'b1?? : begin
- fsmc_next_state = FSMC_IDLE;
- end
- endcase
- end
- FSMC_READ : begin
- if (stb_noe) begin
- fsmc_next_state = FSMC_IDLE;
- end
- else begin
- fsmc_next_state = FSMC_READ;
- end
- end
- FSMC_WRITE : begin
- if (stb_nwe) begin
- fsmc_next_state = FSMC_IDLE;
- end
- else begin
- fsmc_next_state = FSMC_WRITE;
- end
- end
- default : begin
- fsmc_next_state = FSMC_IDLE;
- end
- endcase
- end
-
- always @ (posedge csi_clk or negedge csi_reset_n)
- begin
- if (!csi_reset_n) begin
- avm_read_n <= 1;
- avm_readdata_latch <= 0;
- fifo_wrreq <= 0;
- end
- else begin
- case (fsmc_state)
- FSMC_IDLE : begin
- fifo_wrreq <= 0;
-
- casez ({ stb_ne, stb_noe, stb_nwe }) // synthesis full_case
- 3'b001 : begin // read
- avm_read_n <= 0;
- end
- 3'b010 : begin // write
-
- end
- 3'b011 : begin
- avm_read_n <= 1;
- end
- 3'b1?? : begin // idle
- avm_read_n <= 1;
- end
- endcase
- end
- FSMC_READ : begin
- if (avm_waitrequest) begin
-
- end
- else if (avm_read_n == 0) begin
- // if (avm_read_n) begin
- // fsmc_data_out <= avm_readdata;
- // end
- // else begin
- // fsmc_data_out <= fsmc_data_out;
- // end
- avm_read_n <= 1;
- avm_readdata_latch <= avm_readdata;
- end
- else begin
-
- end
- end
- FSMC_WRITE : begin
- if (stb_nwe) begin
- fifo_wrreq <= 1;
- end
- else begin
- fifo_wrreq <= fifo_wrreq;
- end
- end
- endcase
- end
- end
-
- always @ (posedge csi_clk or negedge csi_reset_n)
- begin
- if (!csi_reset_n) begin
- avm_read_address <= 0;
- write_addr_latch <= 0;
- end
- else begin
- if (!stb_noe) begin
- avm_read_address <= addr_latch;
- end
- else begin
- avm_read_address <= avm_read_address;
- end
-
- if (!stb_nwe) begin
- write_addr_latch <= addr_latch;
- // Set a false path or multicycle or max delay from stb_nwe to write_addr_latch
- end
- else begin
- write_addr_latch <= write_addr_latch;
- end
- end
- end
-
-
- always @ (*)
- begin
- if (avm_read_n) begin
- fsmc_data_out = avm_readdata;//avm_readdata_latch;
- end
- else begin
- fsmc_data_out = avm_readdata_latch;//avm_readdata;
- end
- end
-
- always @ (*)
- begin
- if (avm_write_n) begin
- avm_address = avm_read_address;
- end
- else begin
- avm_address = avm_write_address;
- end
- end
-
- always @ (*)
- begin
- if ((fifo_empty == 0) && (avm_read_n == 1)) begin
- avm_write_n = 0;
- if (avm_waitrequest == 0) begin
- fifo_rdreq = 1;
- end
- else begin
- fifo_rdreq = 0;
- end
- end
- else begin
- fifo_rdreq = 0;
- avm_write_n = 1;
- end
- end
-
- /* always @ (*)
- begin
- (* full_case *)
- case(fsmc_state)
- FSMC_IDLE : begin
- coe_nwait = 1;
- end
- FSMC_READ : begin
- coe_nwait = ~avm_waitrequest;
- end
- FSMC_WRITE : begin
- coe_nwait = ~fifo_almostfull;
- end
- endcase
- end */
- always @ (*)
- begin
- case({ avm_read_n, coe_nwe }) // synthesis full_case
- 2'b01 : begin
- coe_nwait = ~avm_waitrequest;
- end
- 2'b10 : begin
- coe_nwait = ~fifo_almostfull;
- end
- 2'b11 : begin
- coe_nwait = 0;
- end
- endcase
- end
- assign {avm_byteenable, avm_write_address, avm_writedata} = avm_write_n ? {2'b11, 16'b0, 16'b0} : fifo_dout;
-
- scfifo scfifo_component (
- .clock (csi_clk),
- .data (
- {2'b00, // Reserved for checksum
- byteenable_wr_latch,
- write_addr_latch,
- data_latch}),
- .rdreq (fifo_rdreq),
- .sclr (!csi_reset_n),
- .wrreq (fifo_wrreq),
- .almost_full (fifo_almostfull),
- .empty (fifo_empty),
- .full (fifo_full),
- .q (fifo_dout),
- .usedw (fifo_usedw),
- .aclr (),
- .almost_empty (),
- .eccstatus ());
- defparam
- scfifo_component.add_ram_output_register = "ON",
- scfifo_component.almost_full_value = 250,
- scfifo_component.intended_device_family = "Cyclone IV E",
- scfifo_component.lpm_hint = "RAM_BLOCK_TYPE=M9K",
- scfifo_component.lpm_numwords = 256,
- scfifo_component.lpm_showahead = "ON",
- scfifo_component.lpm_type = "scfifo",
- scfifo_component.lpm_width = 36,
- scfifo_component.lpm_widthu = 8,
- scfifo_component.overflow_checking = "ON",
- scfifo_component.underflow_checking = "ON",
- scfifo_component.use_eab = "ON";
- endmodule
fsmc_ctrl
- module fmsc_ctrl(
- input clk,
- input fmsc_WR, //FSMC写信号
- input fmsc_RD, //FSMC读信号
- input fmsc_CS0, //FSMC片选
- input[24:16] fmsc_adress, //FSMC地址总线
- input[15:0] fmsc_data, //FSMC数据总线
- input fmsc_NADV //FSMC的NADV
- );
-
-
- endmodule
qsys内部配置如下:
STM32部分使用标准fsmc通信功能,FPGA内部使用avalon总线进行通信,因此编写fsmc转avalon总线通信模块。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。