[原创] Verilog *2* SPI-立创逻辑派G1测试-1

xutong   2025-7-19 18:11 楼主

  

经过上一篇文章https://bbs.eeworld.com.cn/thread-1319828-1-1.html,我们已经通过仿真把这个搞出来了,但是实际上在电路上是啥样还没看过,不动手的话总归还是纸上谈兵,仿真只是为了让搞实际电路更快一点,切不可本末倒置。

首先我们看一下逻辑派G1的图纸,以下是JLC的逻辑派G1的图纸,用网页可以直接打开。但在这里方便大家查看,我截个图,如图1所示。

https://pro.lceda.cn/editor#id=61327d881e5f4f0c834908cf28c3eb08,tab=1199dcbe5a844fe5a8a074140edc99f8|*1199dcbe5a844fe5a8a074140edc99f8@61327d881e5f4f0c834908cf28c3eb08

 

75VCOKRBABQAM?

 

图1:FPGA引出的IO

有了图1,咱们就可以开整了!

新建工程

File->New

 

5JHBOMJBADQAW?

 

FPGA Design Project ->OK

 

GRBRQMJBADQFC?

 

1.Name->取个名

2.Create in -> 文件地址

3.OK

 

2D3BSMJBAAAGI?

 

接下来是选型:

 

GYFR6MJBAAAEI?

 

截止目前 GW2A下面就一个型号,选择完以后直接Next工程建立完成。

 

SK6B6MJBADQBM?

 

拷贝代码

module SPI (
    input  clk,
    input  rst,
    input  transFlag,
    output reg cs,
    output reg mosi,
    output reg sclk
);

// 定义状态
// localparam 只在模块内有效,`define 是全局有效
localparam IDLE = 1'b1;
localparam Trans = 1'b0;

reg [1:0] Current_S;
reg [1:0] Next_S;
reg [4:0] Trans_Cnt;
reg [1:0] sclk_status;
reg [7:0] Data;
reg [4:0] clk_div_cnt; // 时钟分频计数器
reg spi_clk; // 分频后的时钟信号

// 25 倍时钟分频逻辑
always @(posedge clk or negedge rst) begin
    if (!rst) begin
        clk_div_cnt <= 5'b0;
        spi_clk <= 1'b0;
    end else begin
        if (clk_div_cnt == 5'd24) begin // 计数到 24 时重置计数器
            clk_div_cnt <= 5'b0;
            spi_clk <= ~spi_clk; // 翻转分频后的时钟信号
        end else begin
            clk_div_cnt <= clk_div_cnt + 1'b1;
        end
    end
end

initial begin
    sclk <= 1'b0;
    Trans_Cnt <= 5'b0;
    sclk_status <= 2'b00;
    Data <= 8'h55;
    mosi <= 1'b0;
    Current_S <= IDLE;
    cs <= 1'b1;
    Next_S <= IDLE;
end

// 使用分频后的时钟信号进行状态转移
always @(posedge spi_clk or negedge rst) begin
    if (!rst) begin
        // 跳转到 IDLE 状态
        Current_S <= IDLE;
    end
    // 跳转到下个状态
    else begin
        Current_S <= Next_S;
    end
end

// 使用分频后的时钟信号进行状态机逻辑
always @(posedge spi_clk or negedge rst) begin
    if (!rst) begin
        // 复位逻辑
        cs <= 1'b1;
        sclk <= 1'b0;
        Trans_Cnt <= 5'b0;
        sclk_status <= 2'b00;
        Data <= 8'h55;
        Next_S <= IDLE;
    end else begin
        case(Current_S)
            Trans: begin
                cs <= 1'b0;
                // 每次上升沿发送一位数据 sclk 状态+1
                case(sclk_status)
                    2'b00: begin
                        sclk <= 1'b1;
                        sclk_status <= sclk_status + 1'b1;
                    end
                    2'b01: begin
                        mosi <= Data[7];
                        Data <= Data << 1;
                        sclk_status <= sclk_status + 1'b1;
                    end
                    2'b10: begin
                        sclk <= 1'b0;
                        sclk_status <= 2'b00;
                        Trans_Cnt <= Trans_Cnt + 1'b1;
                    end
                endcase
                // 如果来了 8 个时钟 下个周期跳转到 idle
                if(Trans_Cnt == 5'd8) begin
                    Next_S <= IDLE;
                    Trans_Cnt <= 5'b0;
                end
            end 
            IDLE: begin
                cs <= 1'b1;
                sclk <= 1'b0;
                Trans_Cnt <= 5'b0;
                sclk_status <= 2'b00;
                // when clk posedge jump to next status
                if (transFlag) begin
                    Next_S <= Trans;
                    Data <= 8'h55;
                end else begin
                    Next_S <= IDLE;
                end
            end
            default: Next_S <= IDLE;
        endcase
    end
end

endmodule

综合以及引脚绑定

4.1确定引脚任选一个做为复位引脚:

按钮SW2--D11_IOL22A

按钮SW3--F10_IOL11A

晶振 XTAL-- T7_IOR29A

 

 

EEWORLDIMGTK6

EEWORLDIMGTK7

4.2确定IO type

不同的IO TYPE特性如下(通义千问生成):

  1. LVCMOS (Low Voltage CMOS):这是一种低电压互补金属氧化物半导体技术,适用于多种不同的供电电压,如1.2V, 1.5V, 1.8V, 2.5V, 和3.3V等。它广泛应用于消费电子产品中。
  2. LVTTL (Low Voltage Transistor-Transistor Logic):类似于LVCMOS,但遵循TTL逻辑电平标准,主要用于需要兼容传统TTL逻辑电平的应用中。
  3. SSTL (Stub Series Terminated Logic):专为高速内存接口设计,如DDR SDRAM,通过减少信号反射来提高信号完整性。
  4. HSTL (High-Speed Transceiver Logic):一种用于高速数据传输的标准,常用于内存接口和通信总线。
  5. PCIe (Peripheral Component Interconnect Express):一种高速串行计算机扩展总线标准,用于连接主板上的多个外围设备。
  6. GTX/GTH/GTY:这些都是Xilinx FPGA系列中的高速串行收发器,用于支持非常高的数据速率,适合于以太网、光纤通道、SONET等应用。
  7. MIPI (Mobile Industry Processor Interface):针对移动行业处理器接口的标准,包括CSI(摄像头串行接口)和DSI(显示器串行接口),用于移动设备的摄像头和显示模块。
  8. JESD204:这是一种用于数据转换器与FPGA之间高速串行接口的标准,特别适用于ADC(模数转换器)和DAC(数模转换器)的数据传输。

因为一会要测试的用3.3V的UART,所以这里我们选LVCMOS33

EEWORLDIMGTK8

测试结果

EEWORLDIMGTK9

观察测试结果下降沿发是没有问题了但是CS和SCLK之间没有间隔看起来怪怪的,在加点东西进去调一下。

修正后的代码:

module SPI (
    input  clk,
    input  rst,
    input  transFlag,
    output reg cs,
    output reg mosi,
    output reg sclk
);

// 定义状态
// localparam 只在模块内有效,`define 是全局有效
localparam IDLE = 1'b1;
localparam Trans = 1'b0;

reg [1:0] Current_S;
reg [1:0] Next_S;
reg [4:0] Trans_Cnt;
reg [1:0] sclk_status;
reg [7:0] Data;
reg [4:0] clk_div_cnt; // 时钟分频计数器
reg spi_clk; // 分频后的时钟信号
reg [4:0] delay_cnt; // 延时计数器
reg delay_start; // 延时开始标志

// 25 倍时钟分频逻辑
always @(posedge clk or negedge rst) begin
    if (!rst) begin
        clk_div_cnt <= 5'b0;
        spi_clk <= 1'b0;
    end else begin
        if (clk_div_cnt == 5'd24) begin // 计数到 24 时重置计数器
            clk_div_cnt <= 5'b0;
            spi_clk <= ~spi_clk; // 翻转分频后的时钟信号
        end else begin
            clk_div_cnt <= clk_div_cnt + 1'b1;
        end
    end
end

initial begin
    sclk <= 1'b0;
    Trans_Cnt <= 5'b0;
    sclk_status <= 2'b00;
    Data <= 8'h55;
    mosi <= 1'b0;
    Current_S <= IDLE;
    cs <= 1'b1;
    Next_S <= IDLE;
    delay_cnt <= 5'b0;
    delay_start <= 1'b0;
end

// 使用分频后的时钟信号进行状态转移
always @(posedge clk or negedge rst) begin
    if (!rst) begin
        // 跳转到 IDLE 状态
        Current_S <= IDLE;
    end
    // 跳转到下个状态
    else begin
        Current_S <= Next_S;
    end
end

// 使用分频后的时钟信号进行状态机逻辑
always @(posedge spi_clk or negedge rst) begin
    if (!rst) begin
        // 复位逻辑
        cs <= 1'b1;
        sclk <= 1'b0;
        Trans_Cnt <= 5'b0;
        sclk_status <= 2'b00;
        Data <= 8'h55;
        Next_S <= IDLE;
    end else begin
        case(Current_S)
            Trans: begin
                // 如果来了 8 个时钟 下个周期跳转到 idle
                if(Trans_Cnt > 5'd7) begin
                    Next_S <= IDLE;
                    Trans_Cnt <= 5'b0;
                end
                else begin
                // 每次上升沿发送一位数据 sclk 状态+1
                case(sclk_status)
                    2'b00: begin
                        sclk <= 1'b1;
                        sclk_status <= sclk_status + 1'b1;
                    end
                    2'b01: begin
                        mosi <= Data[7];
                        Data <= Data << 1;
                        sclk_status <= sclk_status + 1'b1;
                    end
                    2'b10: begin
                        sclk <= 1'b0;
                        sclk_status <= 2'b00;
                        Trans_Cnt <= Trans_Cnt + 1'b1;
                    end
    
                endcase
                end
            end 
            IDLE: begin
                cs <= 1'b1;
                sclk <= 1'b0;
                Trans_Cnt <= 5'b0;
                sclk_status <= 2'b00;
                // when clk posedge jump to next status
                if (transFlag) begin
                    delay_start<=1'b1;
                end 
                if(delay_start) begin
                    
                    if (delay_cnt<5'd2) begin
                        delay_cnt <= delay_cnt + 1'b1;
                    end
                    else begin
                        cs <= 1'b0;
                        Next_S <= Trans;
                        Data <= 8'h55;
                        delay_cnt <= 5'b0;
                        delay_start <= 1'b0;
                    end
                end
                else begin
                    Next_S <= IDLE;
                end
            end
            default: Next_S <= IDLE;
        endcase
    end
end

endmodule

修正后代码测试结果

 

25KMSZRBADQC4?

 

 

SOU4SZRBAAQF4?

 

 

MNAMUZRBAAQGE?

 

主要修改部分:

                // Change transmission standard bit to delay flag bit
                // 修改传输标志位为延时标记位
                if (transFlag) begin
                    delay_start<=1'b1;
                end 
                    if(delay_start) begin
                        // Setting delay counter
                        // 设置延迟计数器
                        if (delay_cnt<5'd2) begin
                            delay_cnt <= delay_cnt + 1'b1;
                        end
                        else begin
                            //jump to Send
                            // 跳转到发送
                            cs <= 1'b0;
                            Next_S <= Trans;
                            Data <= 8'h55;
                            delay_cnt <= 5'b0;
                            delay_start <= 1'b0;
                        end
                    end
                else begin
                    Next_S <= IDLE;
                end

每个时钟都跳转到Next_Status

always @(posedge clk or negedge rst) begin
    if (!rst) begin
        // 跳转到 IDLE 状态
        Current_S <= IDLE;
    end
    // 跳转到下个状态
    else begin
        Current_S <= Next_S;
    end
end

 

 

参考文档:

https://mp.weixin.qq.com/s/jY0BIhtX8UtWXFMW-xcK2g

 

本帖最后由 xutong 于 2025-7-19 18:12 编辑
希望做一些大家觉得好用的东西!

回复评论

暂无评论,赶紧抢沙发吧
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复