C2000基于EMIF总线扩展FPGA-Anlogic-安路社区-FPGA CPLD-ChipDebug

C2000基于EMIF总线扩展FPGA

看了一下网上基于C2000系列DSP的EMIF扩展FPGA的例子还是比较少的,学习了一下。这里分享一个基于8位EMIF的C2000系列DSP扩展FPGA的例子供大家参考。

        开头说一下我的设备,DSP是C2000系列的F28388D ControlCARD,FPGA用的黑鹰科技的S604模块(淘宝购买,200来块钱不带仿真器,基于Xlinx Spartan6 的 XC6SLX16)。

图片[1]-C2000基于EMIF总线扩展FPGA-Anlogic-安路社区-FPGA CPLD-ChipDebug

        另外再说一下28388控制卡为了扩展Ethernet和EtherCAT,失去了一些EMIF总线的Address与Data引脚,只支持8位数据宽度与有限的地址宽度,下图是官方论坛的一个解释。还有关于低成本FPGA的话我更推荐使用Altera的FPGA,因为Spartan6系列的FPGA用的Xlinx旧的开发环境Xlinx ISE,win11不支持,win10下载也比较繁琐,我是装了个win7的虚拟机才把ISE下载成功的。

图片[2]-C2000基于EMIF总线扩展FPGA-Anlogic-安路社区-FPGA CPLD-ChipDebug


OK,开始正文。在我的项目中,我的DSP需要读取AD芯片采样后传给FPGA的采样值。换句话说,可以把FPGA看作一个存储器,FPGA存储了AD芯片的采样值。DSP通过EMIF总线去读取FPGA这个存储器中的数值。

我们先稍微了解一下EMIF总线的通信。EMIF总线的通信分为同步通信和异步通信,TI手册(SPRAC96A )中明确提到了,与FPGA的通信属于异步通信(很好,可以少看一半的手册)。

图片[3]-C2000基于EMIF总线扩展FPGA-Anlogic-安路社区-FPGA CPLD-ChipDebug

        再来看看,异步通信下EMIF总线都有哪些信号(这些信号中DQM和RNW这两个信号具体有什么用我也不是很清楚)。由于只涉及到读(嘿嘿,又能少看不少),所以只需要关注数据线(D),地址线(A),扩展地址线(BA),读使能(OE)、片选信号(CS)以及时钟信号(CLK)即可。

图片[4]-C2000基于EMIF总线扩展FPGA-Anlogic-安路社区-FPGA CPLD-ChipDebug

        再来看看手册中正常模式(Normal Mode,还有一个Strobe Mode)下读取操作的时序流程,不管是读操作还是写操作都会分为Setup-Strobe-Hold这样三个序列,Setup阶段,地址总线与扩展地址线的会生成对应地址的信号,在Strobe阶段结束时,DSP会对数据信号对应的引脚采样,读取数据。另外需要注意的时是对小于数据总线宽度的设备发出额外的读取操作,以便完成整个32位数据的访问。像我使用了8位地址总线,那么每次读取操作会自动生成4个Setup-Strobe-Hold序列去完成整个数据的读取。

图片[5]-C2000基于EMIF总线扩展FPGA-Anlogic-安路社区-FPGA CPLD-ChipDebug

        那么这些EMIF信号是怎么生成的呢?

完成初始化配置后直接对对应地址进行进行读写操作就行,可以在下图中看到异步通信的起始地址位是0x100000,那么程序中对0x100000地址读取,DSP自动会在对应的引脚生成片选信号,读信号,地址信号与扩展地址信号的电平状态。
图片[6]-C2000基于EMIF总线扩展FPGA-Anlogic-安路社区-FPGA CPLD-ChipDebug
看到这里,可以大致分析出FPGA要做哪些事了,也就是根据地址信号在把数据总线的二进制电平信号输出在FPGA的引脚上让DSP读取就行
看一下DSP处的主要代码,也是根据TI的例程修改的,初始化后,将0x100000-0x100009的数据赋值给数组ReadDemo:

uint32_t ReadDemo[5]={0};
uint32_t a=0;
 
void setupEMIF1PinmuxAsync8Bit(void);
 
void main(void)
{
    EMIF_AsyncTimingParams tparam;
    
    Device_init();                  // Initialize device clock and peripherals.
 
    DINT;
    Device_initGPIO();              // Setup GPIO by disabling pin locks and enabling pullups.
 
    Interrupt_initModule();         // Initialize PIE and clear PIE registers. Disables CPU interrupts.
    Interrupt_initVectorTable();    // Initialize the PIE vector table
 
    SysCtl_setEMIF1ClockDivider(SYSCTL_EMIF1CLK_DIV_2);         // Configure to run EMIF1 on full Rate. (EMIF1CLK = CPU1SYSCLK)
    EMIF_selectMaster(EMIF1CONFIG_BASE, EMIF_MASTER_CPU1_G);    // Grab EMIF1 For CPU1.
    EMIF_setAccessProtection(EMIF1CONFIG_BASE, 0x0);            // Disable Access Protection. (CPU_FETCH/CPU_WR/DMA_WR)
 
    EMIF_commitAccessConfig(EMIF1CONFIG_BASE);      // Commit the configuration related to protection.
    EMIF_lockAccessConfig(EMIF1CONFIG_BASE);        // Lock the configuration so that EMIF1COMMIT register
 
    setupEMIF1PinmuxAsync8Bit();                    // Configure GPIO pins for EMIF1.
    EMIF_setAsyncMode(EMIF1_BASE, EMIF_ASYNC_CS2_OFFSET,EMIF_ASYNC_NORMAL_MODE);             // Configures Normal Asynchronous Mode of Operation.
    EMIF_disableAsyncExtendedWait(EMIF1_BASE, EMIF_ASYNC_CS2_OFFSET);                        // Disables Extended Wait Mode.
    EMIF_setAsyncDataBusWidth(EMIF1_BASE, EMIF_ASYNC_CS2_OFFSET,EMIF_ASYNC_DATA_WIDTH_8);   // Configure EMIF1 Data Bus Width.
 
    tparam.rSetup = 2;      // Read Setup Cycles
    tparam.rStrobe = 3;     // Read Strobe Cycles
    tparam.rHold = 2;       // Read Hold Cycles
    tparam.turnArnd = 0;    // Write Setup Cycles
    tparam.wSetup = 0;      // Write Strobe Cycles
    tparam.wStrobe = 1;     // Write Hold Cycles
    tparam.wHold = 0;       // TurnAround Cycles
    EMIF_setAsyncTimingParams(EMIF1_BASE, EMIF_ASYNC_CS2_OFFSET, &tparam);    // Configure the access timing for CS2 space.
 
    while(1)
   {
        for(a=0;a<5;a++)
            ReadDemo[a]=*(uint32_t *)(0x100000+a*2);
   }
}
 
//配置EMIF引脚
void setupEMIF1PinmuxAsync8Bit(void)
{
    uint16_t i;
 
 
    GPIO_setPinConfig(GPIO_30_EMIF1_CLK);
    GPIO_setPinConfig(GPIO_32_EMIF1_OEN);
    GPIO_setPinConfig(GPIO_34_EMIF1_CS2N);
    //GPIO_setPinConfig(GPIO_31_EMIF1_WEN);
    //GPIO_setPinConfig(GPIO_33_EMIF1_RNW);
 
    //
    // Selecting address lines.
    //
    GPIO_setPinConfig(GPIO_35_EMIF1_A0);
    GPIO_setPinConfig(GPIO_36_EMIF1_A1);
    GPIO_setPinConfig(GPIO_37_EMIF1_A2);
    GPIO_setPinConfig(GPIO_38_EMIF1_A3);
    GPIO_setPinConfig(GPIO_39_EMIF1_A4);
    GPIO_setPinConfig(GPIO_49_EMIF1_A5);
    GPIO_setPinConfig(GPIO_50_EMIF1_A6);
 
    //
    // Selecting data lines.
    //
    GPIO_setPinConfig(GPIO_77_EMIF1_D7);
    GPIO_setPinConfig(GPIO_78_EMIF1_D6);
    GPIO_setPinConfig(GPIO_79_EMIF1_D5);
    GPIO_setPinConfig(GPIO_80_EMIF1_D4);
    GPIO_setPinConfig(GPIO_81_EMIF1_D3);
    GPIO_setPinConfig(GPIO_82_EMIF1_D2);
    GPIO_setPinConfig(GPIO_83_EMIF1_D1);
    GPIO_setPinConfig(GPIO_85_EMIF1_D0);
 
    //
    // Setting DQM and Bank Select lines.
    //
    GPIO_setPinConfig(GPIO_88_EMIF1_DQM0);
    GPIO_setPinConfig(GPIO_89_EMIF1_DQM1);
    GPIO_setPinConfig(GPIO_90_EMIF1_DQM2);
    GPIO_setPinConfig(GPIO_91_EMIF1_DQM3);
    GPIO_setPinConfig(GPIO_92_EMIF1_BA1);
    GPIO_setPinConfig(GPIO_93_EMIF1_BA0);
 
    //
    // Setup async mode and enable pull-ups for Data pins.
    //
    for(i=69; i<=85;i++)
    {
        if(i != 84)
        {
            GPIO_setPadConfig(i, GPIO_PIN_TYPE_PULLUP);
            GPIO_setQualificationMode(i, GPIO_QUAL_ASYNC);
        }
    }
 }

FPGA的代码,先初始化存储单元,给5个地址单元赋值分别为0,1,2,3,4,之后根据地址总线与扩展地址线的逻辑值将数据从数据总线输出:

module emif_memory (
  input wire clk,                 // EMIF 输入时钟信号 (100MHz/200MHz)
  input wire [6:0] emif_addr,     // EMIF 地址总线输入
  input wire [1:0] emif_BA,       // EMIF 扩展地址线输入
  input wire emif_oe_n,           // EMIF 输出使能信号 (低电平有效)
  input wire emif_cs_n,           // EMIF 片选信号 (低电平有效)
  output reg [7:0] emif_data      // EMIF 数据总线输出
);
 
  reg [31:0] memory [0:99];	// 定义存储器数组,32 位数据位宽,100 个存储位置
  reg [6:0] memory_index;		// 地址总线中的地址
  reg [31:0] selected_data;	// 根据地址总线选择的信号
  reg [7:0] trans_data;			// 根据扩展地址总线选择的发送的8位数据
  
  integer i;
  
  initial begin		// 初始化存储器,为每个地址写初值
    for (i = 0; i <= 99; i = i + 1) begin
      memory[i] = i;
    end
  end
 
  always @(posedge clk) begin
    
    if (!emif_cs_n && emif_oe_n) begin				//CS低,OE高时(setup与hold阶段)    
		memory_index <= emif_addr;
      selected_data <= memory[memory_index];	// 将地址总线的值作为存储器索引
		end
   
    else if (!emif_cs_n && !emif_oe_n) begin		//CS低,OE低时(strobe阶段)
      case (emif_BA)		// 根据扩展地址线输出数据的相应部分
        2'b00: begin
					emif_data[7] <= selected_data[0];
					emif_data[6] <= selected_data[1];
					emif_data[5] <= selected_data[2];
					emif_data[4] <= selected_data[3];
					emif_data[3] <= selected_data[4];
					emif_data[2] <= selected_data[5];
					emif_data[1] <= selected_data[6];
					emif_data[0] <= selected_data[7];
					end
        2'b01: begin
					emif_data[7] <= selected_data[8];
					emif_data[6] <= selected_data[9];
					emif_data[5] <= selected_data[10];
					emif_data[4] <= selected_data[11];
					emif_data[3] <= selected_data[12];
					emif_data[2] <= selected_data[13];
					emif_data[1] <= selected_data[14];
					emif_data[0] <= selected_data[15];
					end				
        2'b10: begin
					emif_data[7] <= selected_data[16];
					emif_data[6] <= selected_data[17];
					emif_data[5] <= selected_data[18];
					emif_data[4] <= selected_data[19];
					emif_data[3] <= selected_data[20];
					emif_data[2] <= selected_data[21];
					emif_data[1] <= selected_data[22];
					emif_data[0] <= selected_data[23];
					end
        2'b11: begin
					emif_data[7] <= selected_data[24];
					emif_data[6] <= selected_data[25];
					emif_data[5] <= selected_data[26];
					emif_data[4] <= selected_data[27];
					emif_data[3] <= selected_data[28];
					emif_data[2] <= selected_data[29];
					emif_data[1] <= selected_data[30];
					emif_data[0] <= selected_data[31];
					end
        default: emif_data <= 8'b0; // 默认情况下输出零
      endcase	
    end 
	 
	else begin			//CS高,OE高时
      emif_data <= 8'b0; // 如果 EMIF 输出未使能,输出零
		selected_data <= 32'b0;
    end
  end
	
endmodule

看看DSP调试的结果,与在FPGA中初始化的数值一样:

图片[7]-C2000基于EMIF总线扩展FPGA-Anlogic-安路社区-FPGA CPLD-ChipDebug

再看看ISE chipscope扫描FPGA引脚的结果:

图片[8]-C2000基于EMIF总线扩展FPGA-Anlogic-安路社区-FPGA CPLD-ChipDebug

请登录后发表评论

    没有回复内容