STM32与FPGA Cyclone IV芯片fsmc通信

前言

本文介绍STM32与FPGA通过fsmc通信的实现方法。

一、fsmc介绍

FSMC(Flexible Static Memory Controller,可变静态存储控制器)是STM32系列采用的一种新型的存储器扩展技术。在外部存储器扩展方面具有独特的优势,可根据系统的应用需要,方便地进行不同类型大容量静态存储器的扩展。

该使用方法本质是将FPGA当做SRAM来驱动,支持的存储器类型有SRAM、PSRAM、NOR/ONENAND、ROM、LCD接口(支持8080和6800模式)、NANDFlash和16位的PCCard。

二、平台说明

本次例程使用的处理芯片:STM32F407和Cyclone IV   EP4CE22E144。

三、硬件部分

1.FPGA部分连接方式

2.STM32部分连接方式

STM32引脚连接使用的是复用fsmc功能引脚。

四、软件部分

1.STM32软件部分

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);

 2.FPGA软件部分

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总线通信模块。

  • 11
    点赞
  • 108
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
FPGA FSMC STM32指的是在FPGASTM32芯片之间使用FSMC通信功能的方法。FSMC是指外部存储器接口,用于连接外部设备和微控制器。在这种情况下,FPGASTM32之间通过FSMC进行通信。 具体而言,为了实现FPGASTM32之间的通信,需要编写一个fsmc转avalon总线通信模块。这个模块的作用是将FSMC信号转换为Avalon总线信号,以便FPGASTM32之间进行数据传输。这个模块可以通过定义输入和输出端口的方式进行编写。其中,输入端口包括时钟信号、FSMC写信号、FSMC读信号、FSMC片选信号、FSMC地址总线信号和FSMC数据总线信号,输出端口包括FSMC的NADV信号。 例如,一个fsmc_ctrl模块可以定义如下: module fsmc_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 在硬件部分,通常会使用STM32F407Cyclone IV EP4CE22E144作为处理芯片。具体的连接方式可以根据具体的设计需求进行选择和配置。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [STM32FPGA Cyclone IV芯片fsmc通信](https://blog.csdn.net/zhang421412170/article/details/111904087)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值