F28377S_EMIF_异步读写FPGA

本文介绍如何使用TMS320F28377S DSP通过EMIF接口实现与FPGA的异步读写操作。在成功执行写入和读取数据后,通过LED状态验证通信的正确性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

DSP芯片:TMS320F28377SPTPS

基于已有的FPGA程序与板子,操作DSP读取FPGA内的数据。如果写入、读取成功,则点亮LED。



//
// Included Files
//
#include "F28x_Project.h"




#define TEST_PASS            0xABCDABCD
#define TEST_FAIL            0xDEADDEAD
#define ASRAM_CS2_START_ADDR 0x100000
#define ASRAM_CS2_SIZE       0x8000
#define EMIF1                0
#define EMIF2                1
#define MEM_D_WIDTH          1            // 16Bit Memory Interface
#define TURN_AROUND_TIME     0            // Turn Around time of 2 Emif Clock
#define RD_SETUP_TIME        0            // Read Setup time of 1 Emif Clock
#define RD_STROBE_TIME       3            // Read Strobe time of 4 Emif Clock
#define RD_HOLD_TIME         0            // Read Hold time of 1 Emif Clock
#define WR_SETUP_TIME        0            // Write Hold time of 1 Emif Clock
#define WR_STROBE_TIME       0            // Write Setup time of 1 Emif Clock
#define WR_HOLD_TIME         0            // Write Hold time of 1 Emif Clock
#define EXTEND_WAIT          0            // Disable Extended Wait
#define STROBE_SEL           0            // Disable Strobe Mode.
#define WAIT_POLAR_INV       0
#define WAIT_COUNT           0

//#define cpu_sel           0
//
// Globals

Uint16  ErrCount = 0;
Uint32  TEST_STATUS;
int i;

//
// EMIF引脚设置
//
extern void setup_emif1_pinmux_async_16bit(Uint16 cpu_sel)
{
	GPIO_SetupPinMux(31,0,2);//第31个引脚,第1个CPU,第3个功能;写入使能
	//GPIO_SetupPinMux(33,0,2);//DF_EMIF_RNW,未使用,外部存储器接口 1 读/不写
	GPIO_SetupPinMux(35,0,2);//DF_EMIF_CSn片选信号
	GPIO_SetupPinMux(37,0,2);//	DF_EMIF_RDn读取使能

	GPIO_SetupPinMux(91,0,0);//BA0,以普通IO作为BA0*
	GPIO_SetupPinMux(92,0,3);//BA1,*

	GPIO_SetupPinMux(93,0,0);//外部中断输出到DSP  32.5us一次
	GPIO_SetupPinMux(62,0,0);//外部中断输出到DSP  32.5us一次

    for (i=38; i<=52; i++)//a0 -a12
    {
        if ((i != 42) && (i != 43))
        {
            GPIO_SetupPinMux(i,cpu_sel,2);
        }
    }
    GPIO_SetupPinMux(86,cpu_sel,2);//A13-A15
    GPIO_SetupPinMux(87,cpu_sel,2);
    GPIO_SetupPinMux(88,cpu_sel,2);

    for (i=69; i<=85; i++)//D0 -D15
    {
        if (i != 84)
        {
            GPIO_SetupPinMux(i,cpu_sel,2);
        }
    }

    for (i=69; i<=85; i++)
    {
        if (i != 84)
        {
            GPIO_SetupPinOptions(i,0,0x31); // GPIO_ASYNC||GPIO_PULLUP
        }
    }

}


//读取值
Uint16 Read_FPGA(long Read_ADD){

	unsigned int Read_data = *((volatile unsigned int *)Read_ADD);

return(Read_data);
}

//写入值
void Write_FPGA(long Write_ADD,long Write_DATA)
{
	*((volatile unsigned int *)Write_ADD)= Write_DATA;
}


//
// Main
//
void main(void)
{
	//memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t)&RamfuncsLoadSize);
	 InitGpio();
	 GPIO_SetupPinMux(34, GPIO_MUX_CPU1, 0);
	 GPIO_SetupPinOptions(34, GPIO_OUTPUT, GPIO_PUSHPULL);
	 GPIO_WritePin(34, 0);//D8L

	//以上LED需要,D8=GPIO34,低电平亮



//
// Initialize system control
//
    InitSysCtrl();

    DINT;

//
//  Initialize the PIE control registers to their default state.
//  The default state is all PIE interrupts disabled and flags
//  are cleared.
    //将PIE控制寄存器初始化为其默认状态。
    //默认状态是禁用所有PIE中断并清除标志。
    //  This function is found in the F2837xS_PieCtrl.c file.
//
    InitPieCtrl();

//
// Disable CPU interrupts and clear all CPU interrupt flags:
//
    EALLOW;
    IER = 0x0000;
    IFR = 0x0000;
    EDIS;

//
// Initialize the PIE vector table with pointers to the shell Interrupt
// GService Routines (ISR).
// This will populate the entire table, even if the interrupt
// is not used in this example.  This is useful for debug purposes.
// The shell ISR routines are found in F2837xS_DefaultIsr.c.
// This function is found in F2837xS_PieVect.c.
//
   InitPieVectTable();

//
//Configure to run EMIF1 on full Rate (EMIF1CLK = CPU1SYSCLK)
//配置为以全速率运行EMIF1(EMIF1CLK=CPU1SYSCLK)
//
  EALLOW;
  ClkCfgRegs.PERCLKDIVSEL.bit.EMIF1CLKDIV = 0x1;//EMIF时钟配置,设置EM1模块运行速度
  EDIS;


//
//Disable Access Protection (CPU_FETCH/CPU_WR/DMA_WR)
//// 禁止EMIF1模块读写保护
  EALLOW;
  Emif1ConfigRegs.EMIF1ACCPROT0.all = 0x0;
  if(Emif1ConfigRegs.EMIF1ACCPROT0.all != 0x0)
  {
      ErrCount++;
  }

//
// Commit the configuration related to protection. Till this bit remains set
// content of EMIF1ACCPROT0 register can't be changed.
////提交与保护相关的配置。在该位保留之前,EMIF1ACCPROT0寄存器的设置内容不能更改????
  // 锁定寄存器配置
  Emif1ConfigRegs.EMIF1COMMIT.all = 0x1;
  if(Emif1ConfigRegs.EMIF1COMMIT.all != 0x1)
  {
     ErrCount++;
  }

//
// Lock the configuration so that EMIF1COMMIT register can't be
// changed any more.
  // 锁定寄存器配置
//
  Emif1ConfigRegs.EMIF1LOCK.all = 0x1;
  if(Emif1ConfigRegs.EMIF1LOCK.all != 1)
  {
      ErrCount++;
  }

  EDIS;

//
//配置cpu 0 的EMIF模块引脚
//
  setup_emif1_pinmux_async_16bit(0);

//
//Configure the access timing for CS2 space配置CS2空间的访问定时
//根据实际引脚配置CS,这里是CS3
//
  Emif1Regs.ASYNC_CS3_CR.all =  (EMIF_ASYNC_ASIZE_16    | // 16Bit Memory
                                                          // Interface
                                 EMIF_ASYNC_TA_2        | // Turn Around time
                                                          // of 2 Emif Clock
                                 EMIF_ASYNC_RHOLD_1     | // Read Hold time
                                                          // of 1 Emif Clock
                                 EMIF_ASYNC_RSTROBE_4   | // Read Strobe time
                                                          // of 4 Emif Clock
                                 EMIF_ASYNC_RSETUP_1    | // Read Setup time
                                                          // of 1 Emif Clock
                                 EMIF_ASYNC_WHOLD_1     | // Write Hold time
                                                          // of 1 Emif Clock
                                 EMIF_ASYNC_WSTROBE_3   | // Write Strobe time
                                                          // of 1 Emif Clock
                                 EMIF_ASYNC_WSETUP_1    | // Write Setup time
                                                          // of 1 Emif Clock
                                 EMIF_ASYNC_EW_DISABLE  | // Extended Wait
                                                          // Disable.
                                 EMIF_ASYNC_SS_DISABLE    // Strobe Select Mode
                                                          // Disable.
                                );

  //地址===值,读写状态
  //0x30_0106===0x5555,r
  //0x30_0107===0xaaaa,r
  //0x30_0115===0x0000,r&w

  Write_FPGA(0x300115,4567);
  Uint16 TEMP =Read_FPGA(0x300115);

  if(TEMP==4567 && Read_FPGA(0x300106)==0x5555 && Read_FPGA(0x300107)==0xaaaa)
      {
    	  GPIO_WritePin(34, 0);//读写正常则led亮
      }
      else
      {
    	  GPIO_WritePin(34, 1);
      }




  while (1);
}

//
// End of file
//

 

 

<think>嗯,用户想了解如何在FPGA中实现EMIF的连续读写操作。首先,我需要回忆一下EMIF的基本概念。EMIF是外部存储器接口,用来连接FPGA和外部存储器,比如SDRAM或者DDR。根据引用[1]提到的,FPGA可以通过接口设计连接到EMIF,支持同步或异步方式。接下来,用户需要的是连续读写的具体方法和示例,所以得拆解实现步骤。 首先,EMIF接口设计的关键点应该包括时钟同步、地址控制和数据缓冲。根据引用[3]中的BFM仿真,可能需要验证模块的功能,所以在设计过程中仿真测试也很重要。然后,用户可能需要知道如何配置EMIF控制器,包括时钟频率、时序参数设置,这可能涉及到FPGA厂商提供的IP核,比如Xilinx的MIG或者Altera的EMIF IP。 然后,连续读写的实现通常需要状态机来控制读写流程。比如,初始化存储器后,进入写模式,连续写入数据,然后切换到读模式,读取数据并验证。需要处理地址递增、数据生成和校验。另外,数据缓冲和FIFO的使用可能也是关键,引用[1]提到FPGA可以用作同步或异步FIFO,这可能用于数据流的缓冲,确保连续读写时的数据稳定性。 接下来,用户可能需要示例代码。虽然用户的问题是关于EMIF,但具体的代码可能依赖于FPGA型号和开发工具。例如,使用Verilog或VHDL编写状态机,控制地址总线和数据总线。同时,时序的严格遵循是关键,比如建立和保持时间,这需要参考存储器的数据手册来配置正确的时序参数。 可能还需要考虑时钟域的问题,特别是当FPGA和外部存储器的时钟不同步时,需要跨时钟域处理,比如使用异步FIFO,如引用[1]和[3]提到的。此外,性能优化方面,比如突发传输、预取机制,可能也是用户关心的问题,但用户的问题主要是连续读写的实现方法,所以可能需要先聚焦在基础实现上。 最后,验证部分,使用仿真工具如ModelSim或Vivado的仿真器,通过BFM仿真来验证设计的正确性,如引用[3]所述。生成测试激励,模拟存储器的响应,确保读写操作的正确性。 总结步骤的话,应该是:接口配置、状态机设计、时序控制、数据缓冲、仿真验证。需要将这些步骤用清晰的结构呈现给用户,并给出示例代码框架,可能用Verilog或VHDL。同时,提醒用户注意时序约束和仿真测试的重要性。</think>### FPGA EMIF连续读写实现方法及示例 #### 一、EMIF接口基本原理 EMIF(External Memory Interface)是FPGA与外部存储器(如SDRAM、DDR等)通信的关键接口,其核心功能包括: 1. **地址控制**:通过地址总线定位存储单元 2. **数据通道**:双向数据总线实现读写传输 3. **时序同步**:采用时钟信号对齐操作时序 4. **控制信号**:包括读写使能、片选、字节使能等[^1] #### 二、实现步骤 1. **接口配置** - 使用Vivado/Qtus的IP核配置工具生成EMIF控制器 - 设置存储器类型(如SDRAM/DDR3) - 定义总线宽度(8-64位)及时序参数(tRCD、tRP等) 2. **状态机设计** ```verilog typedef enum {IDLE, WRITE_START, WRITE_DATA, READ_START, READ_DATA} state_t; reg [2:0] current_state; reg [31:0] addr_counter; // 地址计数器 ``` 3. **连续写操作实现** - 写时序控制: ``` 时钟周期 | 操作 ------------------------- T0 | 置位写使能(WE) T1 | 输出地址(ADDR) T2 | 输出数据(DATA) T3 | 撤销WE ``` - Verilog示例: ```verilog always @(posedge clk) begin if (current_state == WRITE_DATA) begin emif_we <= 1'b1; emif_addr <= addr_counter; emif_data <= data_buffer[addr_counter]; addr_counter <= addr_counter + 1; end end ``` 4. **连续读操作实现** - 读时序优化: $$ t_{AC} < t_{CLK} - t_{SU} $$ 其中$t_{AC}$为存储器访问时间,$t_{SU}$为FPGA输入建立时间 - 使用流水线读取: ```verilog always @(negedge clk) begin if (emif_oe) begin read_pipeline[0] <= emif_data; read_pipeline[1] <= read_pipeline[0]; end end ``` #### 三、关键优化技术 1. **突发传输模式** 通过配置EMIF控制器的Burst Length参数,实现单指令多数据传输: ```c #define BURST_LENGTH 8 // 设置突发长度 emif_ctrl_reg |= (BURST_LENGTH << 3); ``` 2. **数据缓冲设计** 使用双端口Block RAM作为读写缓冲区: ```verilog bram_dp #(.DWIDTH(64)) data_buffer ( .clka(clk), .wea(wr_en), .addra(wr_addr), .dina(wr_data), .clkb(clk), .addrb(rd_addr), .doutb(rd_data) ); ``` 3. **时序收敛保障** 在XDC约束文件中添加: ``` set_input_delay -clock emif_clk 1.5 [get_ports emif_data*] set_output_delay -clock emif_clk 1.2 [get_ports emif_addr*] ``` #### 四、验证方法 1. **功能仿真** 使用BFM(Block-based Flow Manager)搭建验证环境[^3]: ```systemverilog task automatic burst_write; input [31:0] start_addr; input [63:0] data[]; foreach(data[i]) begin bfm_write(start_addr + i*8, data[i]); end endtask ``` 2. **板级测试** 通过SignalTap II/ChipScope捕获实时信号: - 验证地址连续递增 - 检查数据一致性 - 测量实际带宽
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值