Menu Close

STARTUPE2 在spi flash 上的使用

STARTUPE2 在spi flash 上的使用

7 series fpga CCLK 使用

当我们使用spartan 7 fpga 时, 需要fpga 逻辑对spi flash 进行读写操作, 就会使用fpga 指定的pin。包括bank0 当中的CCLK, BANK14 中的 D[00], DIN/D[01], FCS_B, D[02],D[03] 等。

在之前的fpga 中(spartan 3, spartan 6), CCLK 启动时,有FPGA自主控制,产生时钟(不论fpga 是否被编程过)当从flash 中读取需要配置的数据后, CCLK pin 可以当中普通的gpio ,有用户编程使用。在7 series fpga 中, 由于CCLK 是特定的pin, 不能被用户当作普通的gpio 使用, 也不能设置约束文件。(例如xdc)

如图所示:

%title插图%num

或者

%title插图%num

但在很多开发板中, 我们即需要使用CCLK 用来启动fpga (从spi flash 中读取数据来配置fpga )又希望在fpga 启动后, 我们依然可以操作CCLK pin ,为用户自己定义的spi controller来对spi flash 进行读写。

%title插图%num

在我们的prx100t开发板中,不但连接了7 series bank 0 当中的CCLK,同时又有一个gpio pin 和spi flash 相连。

%title插图%num

这样,就可以避免使用STARTUPE2原语配置spi flash。原因, 启动时,fpga 自主从CCLK 输出时钟, 驱动spi  flash。 在启动后, 如果用户需要使用spi flash ,可以驱动gpio_pin 来实现。(这时,CCLK 处于高组态)。

如果使用的其他的开发板,或者硬件设计没有预留gpio 连接spi flash,那么,我们必须是由STARTUPE2 原语控制CCLK。在阅读UG470 文档 (7 Series FPGA Configuration User Guide) 中有关 CCLK的使用时,发现CCLK 是Dedicated pin , 而不是Multi-function pin。 也就是说CCLK 不能被fpga 内部逻辑直接使用,也不能在xdc 文件中对CCLK 进行约束。需要使用STARTUPE2 这个原语来实现。即fpga 内部逻辑可以控制STARTUPE2 原语, 而STARTUPE2 原语可以驱动CCLK。

%title插图%num

STARTUPE2 原语使用

在spartan 6 fpga 中CCLK 是一个multi-function pin 。 可以被fpga 内部逻辑直接驱动。在7 series fpga 中CCLK pin 是Dedicated pin,不能被fpga 直接驱动,所以需要使用STARTUPE2原语间接驱动CCLK。

通过分析STARTUPE2的原语使用,我们发现在系统启动后需要3个USRCCLKO 的时钟后,才能正常的使用CCLK

%title插图%num

为此, 我们设计了一个简单的仿真程序,测试STARTUPE2 的相关功能。

STARTUPE2 仿真工程:

首先, 我们模拟一个基本的spi flash 的操作过程 , fpga 正常驱动spi_cs, spi_clk, spi_mosi 等。状态机 0 直接跳转到状态机6。 spi_clk 用来驱动STARTUPE2 primitive 中的 USRCCLKO pin。

工程代码: (vivado)

`timescale 1ns / 1ps

module TOP#
(
    parameter SIM_CCLK_FREQ = 0.0
)
(
    input  OSC_20M,
//    output FLASH_CLK,
    output FLASH_CS, 
    output FLASH_MOSI,
    input  FLASH_MISO,
    
    input reset 
);

//=======================================================================================

wire FLASH_CLK;

 STARTUPE2 #(
      .PROG_USR("FALSE"),  // Activate program event security feature. Requires encrypted bitstreams.
      .SIM_CCLK_FREQ(SIM_CCLK_FREQ)  // Set the Configuration Clock Frequency(ns) for simulation.
   )
   STARTUPE2_inst (
      .CFGCLK(),       // 1-bit output: Configuration main clock output
      .CFGMCLK(),     // 1-bit output: Configuration internal oscillator clock output
      .EOS(),             // 1-bit output: Active high output signal indicating the End Of Startup.
      .PREQ(),           // 1-bit output: PROGRAM request to fabric output
      .CLK(0),             // 1-bit input: User start-up clock input
      .GSR(0),             // 1-bit input: Global Set/Reset input (GSR cannot be used for the port name)
      .GTS(0),             // 1-bit input: Global 3-state input (GTS cannot be used for the port name)
      .KEYCLEARB(1), // 1-bit input: Clear AES Decrypter Key input from Battery-Backed RAM (BBRAM)
      .PACK(1),           // 1-bit input: PROGRAM acknowledge input
      .USRCCLKO(FLASH_CLK),   // 1-bit input: User CCLK input
                             // For Zynq-7000 devices, this input must be tied to GND
      .USRCCLKTS(0), // 1-bit input: User CCLK 3-state enable input
                             // For Zynq-7000 devices, this input must be tied to VCC
      .USRDONEO(1),   // 1-bit input: User DONE pin output control
      .USRDONETS(1)  // 1-bit input: User DONE 3-state enable output
   );

//=======================================================================================
reg [7:0] spi_cmd = 8'h39;  // test data

reg spi_clk = 0;
reg spi_mosi = 0;
reg spi_cs = 1;
wire spi_miso;

reg [4:0] spi_cnt = 0;
reg [3:0] spi_st = 0;
always @ (posedge  OSC_20M or posedge reset)
if(reset)
begin
    spi_cnt <= 0;
    spi_cs <= 1;
    spi_st <= 0;
end
else case (spi_st)
0:
begin
    spi_cs <= 1;
    spi_clk <= 0;
    spi_st <= 1;   // add  3 usrcclko for startupe2 primitive
//    spi_st <= 6;     // normal spi operation including drive spi_clk, spi_cs, spi_mosi
end
1: // add  3 usrcclko for startupe2 primitive 
begin
    spi_clk <= 1;
    spi_st <= 2;
end
2:
begin
    spi_clk <= 0;
    spi_st <= 3;
end
3:
begin
    spi_clk <= 1;
    spi_st <= 4;
end
4:
begin
    spi_clk <= 0;
    spi_st <= 5;
end
5:
begin
    spi_clk <= 1;
    spi_st <= 6;
end
6: // siumlate a spi flash operation , drive spi_clk,  spi_cs, spi_mosi
begin
    spi_cs <= 1;
    spi_clk <= 0;
    
    spi_cnt <= spi_cnt + 1;
    if(&spi_cnt)
    begin
        spi_cnt <= 7;
        spi_st <= 7;
    end
end
7:
begin
    spi_cs <= 0;
    spi_mosi <= spi_cmd[spi_cnt];
    spi_st <= 8;
end
8:
begin
    spi_clk <= 1;
    if(spi_cnt == 0) spi_st <= 10;
    else
    begin
        spi_cnt <= spi_cnt - 1; 
        spi_st <= 9;
    end
end
9:
begin
    spi_clk <= 0;
    spi_mosi <= spi_cmd[spi_cnt];
    spi_st <= 8;
end
10:
begin
    spi_clk <= 0;
    spi_st <= 11;
end
11:
begin
    spi_cs <= 1;
    spi_cnt <= 0;
    spi_st <= 6;
end
default: spi_st <= 0;
endcase
//=======================================================================================

//=======================================================================================


assign  FLASH_CLK = spi_clk;
assign  FLASH_CS = spi_cs; 
assign  FLASH_MOSI = spi_mosi;
assign  spi_miso = FLASH_MISO;
    
endmodule

 

仿真文件:

`timescale 1ns / 1ps


module tb_sim(

    );
    
reg clk = 0;
always clk = #25 ~clk;

reg reset = 1;
initial
begin
    reset = 1;
    # 100;
    reset = 0;
    #10000;
    $stop;
end

wire FLASH_CS; 
wire FLASH_MOSI;
reg FLASH_MISO = 0;
 
TOP # (.SIM_CCLK_FREQ(10.0))
top_inst
(
    .OSC_20M    (clk),
    .FLASH_CS   (FLASH_CS), 
    .FLASH_MOSI (FLASH_MOSI),
    .FLASH_MISO (FLASH_MISO),
    
    .reset      (reset)
);

//==================================================================
endmodule

仿真波形:

%title插图%num

在第一次输出spi_clk 时, 我们发现在真实的CCLK 上缺少2 个时钟。

解决方案:

根据UG470 文档的介绍, 只要spi 使用前, 在USRCCLKO 上增加3个clk 后, USRCCLKO 就可以正常的输出到CCLK 上了。

修改状态机:

0:
begin
    spi_cs <= 1;
    spi_clk <= 0;
    spi_st <= 1; // add 3 usrcclko for startupe2 primitive
    // spi_st <= 6; // normal spi operation including drive spi_clk, spi_cs, spi_mosi
end

仿真波形:

%title插图%num

结论

如果使用STARTUPE2 来驱动CCLK pin , 就要在spi controller 使用之前, 增加3个USRCCLKO 时钟,之后, STARTUPE2 primitive 就可以正常使用了。

参考文档:

https://www.xilinx.com/content/dam/xilinx/support/documentation/application_notes/xapp1313-spartan-spi-config.pdf

https://www.xilinx.com/content/dam/xilinx/support/documentation/user_guides/ug470_7Series_Config.pdf

https://support.xilinx.com/s/article/63174?language=en_US

https://www.xilinx.com/content/dam/xilinx/support/documentation/application_notes/xapp586-spi-flash.pdf

Posted in FPGA, FPGA 教材教案, Verilog, 教材与教案, 文章

发表回复

相关链接