关于#fpga spi从机发送数据左移了1bit#的问题,如何解决?

fpga spi从机发送数据左移了1bit

module spi_slave(
    input               rst_n,      // 复位信号
    input               clk_20M,    // 输入20Mhz时钟
    input                SS,            // 从机选择信号,低电平有效     
    input               SCLK,       // SCLK输入
    input                MOSI,        // MOSI输入
    input      [7:0]    tx_data,    // 要发送的数据

    output reg            MISO,        // MISO输出
    output reg [7:0]    rx_data,    // 接收到的数据
    output reg          rx_done,    // 接收完成标识
    output reg          tx_done     // 发送完成标识
);

reg  [3:0]  rx_status;       // 接收过程状态机
reg  [3:0]  tx_status;       // 发送过程状态机
reg  [3:0]  rx_cnt;          // 接收bit计数
reg  [3:0]  tx_cnt;          // 发送bit计数
reg  [7:0]  rx_shift_reg;    // 接收移位寄存器,接收完成后数据转存至rx_data
reg  [7:0]  tx_shift_reg;    // 发送移位寄存器,tx_data数据转存至tx_shift_reg
reg  [1:0]  SS_sync;         // SS状态捕捉
reg  [1:0]  SCLK_sync;       // SCLK状态捕捉
wire        SS_fal;          // SS下降沿
wire        SCLK_ris;        // SCLK上升沿
wire        SCLK_fal;        // SCLK下降沿


// ---- main code ----
assign SS_fal = SS_sync[1:0] == 2'b10;  // SS由1变成0,判断SS为下降沿
assign SCLK_ris = SCLK_sync[1:0] == 2'b01; // SCLK由0变成1,判断SCLK为上升沿
assign SCLK_fal = SCLK_sync[1:0] == 2'b10; // SCLK由1变成0,判断SCLK为下降沿


// 边沿检测过程块,所有边沿检测均在此执行
always @(posedge clk_20M or negedge rst_n) begin
    if(!rst_n) begin
        SS_sync <= 2'b11;  //SS时钟空闲状态位高电平
        SCLK_sync <= 2'b00;  //SCLK时钟空闲状态位低电平,CPOL=0,CPHA=0
    end
    else begin
        SS_sync <= {SS_sync[0], SS};
        SCLK_sync <= {SCLK_sync[0], SCLK};
    end
end

// 功能描述:SPI接收字节过程块,FPGA运行过程中,不停判断SS低电平,
//          若有数据传输,则接收,当接收满一个字节后置位接收完成标识.
always @(posedge clk_20M or negedge rst_n) begin
    if(!rst_n) begin
        rx_shift_reg <= 8'd0;
        rx_cnt <= 4'd0;
        rx_done <= 1'b0;
        rx_data <= 1'b0;
        rx_status <= 4'd0;
    end
    else begin
        if (SS_fal) begin  // SS下降沿
            rx_shift_reg <= 8'd0;
            rx_cnt <= 4'd0;
            rx_data <= 1'b0;
            rx_done <= 1'b0;
            rx_status <= 4'd0;
        end
        else begin
            if (!SS) begin
                case (rx_status)
                    4'd0: begin  // 接收数据准备
                        rx_shift_reg <= 8'd0;
                        rx_cnt <= 4'd0;
                        rx_done <= 1'b0;
                        rx_status <= 4'd1;
                    end
                    4'd1: begin
                        if (SCLK_ris) begin // SCLK上升沿读取MOSI,移位写入8bit数据
                            rx_shift_reg <= {rx_shift_reg[6:0], MOSI}; // 上升沿读数据,左移
                            if(rx_cnt == 4'd7) begin
                                rx_cnt <= 4'd0;
                                rx_status <= 4'd2;
                            end
                            else begin
                                rx_cnt <= rx_cnt + 4'd1;
                            end
                        end
                    end
                    4'd2: begin
                        rx_data <= rx_shift_reg; // 接收8 bits完成,数据转存至rx_data
                        rx_done <= 1'b1;  // 接收完成标识置1
                        rx_status <= 4'd3;
                    end
                    4'd3: begin
                        rx_done <= 1'b0;
                        rx_status <= 4'd0; 
                    end 
                endcase
            end // if (!SS) begin
        end
    end
end

// 功能描述:SPI字节发送过程块,当有数据需要发送时,发送send_data数据
always @(posedge clk_20M or negedge rst_n) begin
    if(!rst_n) begin
        tx_cnt <= 4'd0;
        tx_done <= 1'b0;
        tx_shift_reg <= 8'd0;
        MISO <= 1'b0;
        tx_status <= 4'd0;
    end
    else begin
        if (SS_fal) begin  // SS下降沿
            tx_cnt <= 4'd0;
            tx_done <= 1'b0;
            tx_shift_reg <= 8'd0;
            MISO <= 1'b0;
            tx_status <= 4'd0;
        end
        else begin
            if (!SS) begin
                case (tx_status)
                    4'd0: begin  // 开始准备发送,等待发送标识控制高电平

                            tx_done <= 1'b0;
                            tx_cnt <= 4'd0;
                            tx_shift_reg <= tx_data;  // 转送数据,避免其他模块改写导致数据变化
                            tx_status <= 4'd1;


                    end
                    4'd1: begin
                            tx_status <= 4'd2;                         
                    end
                    4'd2: begin  // 每一个SCLK下降沿向MISO写入一个bit
                        if (SCLK_fal) begin  // 等待时钟下降沿
                            MISO <= tx_shift_reg[4'd7 - tx_cnt];
                           if(tx_cnt == 4'd7) begin
                                tx_cnt <= 4'd0;
                                tx_done <= 1'b1;
                                tx_status <= 4'd3;
                            end
                            else begin
                                tx_cnt <= tx_cnt + 4'd1;
                            end
                        end
                    end
                    4'd3: begin
                          tx_status <= 4'd4;
                          tx_done <= 1'b0;
                    end
                    4'd4: tx_status <= 4'd0;
                endcase
            end //if (!SS) begin
        end
    end
end


endmodule

这是spi发送数据左移1bit的仿真图,正确的应该是在第2bit结束时发送。

img

我的解答思路和尝试过的方法 :
我发现可能是我发送的状态机问题,我想更改一下我发送的状态机,但是一直达不到我想要的结果。
我想要达到的结果:

img

你这个 SPI 应该接受完后再启动发送
把接受的时序做好,所有的数据接收完成后再启动发送