qjfun

基于FPGA的SPI

0
阅读(2888)

spi最早由motorola提出

是一个种duplex、synchronous、serial通信方式

主要管脚信号:

mosi: master output, slave input

miso: master input, slave output
        sclk:  serial clock

ss_n: select signal


两个关键控制位

CPOL----SPI Clock Polarity Bit

SPI modules must have the identical CPOL value.

1 == Active-low clocks selected, in idle state SCLK is high.

0 == Active-high clocks selected, in idle state SCLK is low.


CPHA ---- Slave Select Output Enable

1 == Sampling of data occurs at even edges(2,4,6...) of the SCLK clock.

0 == Sampling of data occurs at odd edges(1,3,5...) of the SCLK clock.


// 计数


always @( posedge clk_80M or posedge rst )
    begin
        if ( rst == 1'b1 )
            cnt_bit <= 4'd7;
        else 
        begin
            if ( ss_n_s == 1'b1 )
                cnt_bit <= 4'd7;
            else if ( ( sclk_s == 1'b0 ) & ( sclk_t == 1'b1 ))//( ( sclk_s == 1'b0 ) & ( sclk_t == 1'b1 ))
            begin
                if ( cnt_bit > 0 )
                   cnt_bit <= cnt_bit - 1'b1;
                else
                    cnt_bit <= 4'd7;
            end
        end
    end



/**************** SPI receiver *********************/



always @( posedge clk_80M or posedge rst )
begin
    if ( rst == 1'b1 )
    begin
        shift_in <= 7'd0;
        byte_in <= 8'd0;
    end
    else
    begin
        if ( ss_n_s == 1'b1 )
            shift_in <= 7'd0;
        else if ( ( sclk_s == 1'b0 ) & ( sclk_t == 1'b1 ))//( ( sclk_s == 1'b1 ) & ( sclk_t == 1'b0 ))
        begin
            if( cnt_bit > 0 )
                shift_in <= { shift_in[5:0], mosi_s };
            else
                byte_in <= { shift_in, mosi_s };
        end
    end
end


/**************** SPI transmitter   *****************/


always @( posedge clk_80M or posedge rst )
begin
    if ( rst == 1'b1 )
        load <= 1'b0;
    else
    begin
        if ( ( sclk_s == 1'b1 ) & ( sclk_t == 1'b0 ) )//( ( sclk_s == 1'b1 ) & ( sclk_t == 1'b0 ) )
        begin
            if ( cnt_bit == 0 )
                load <= 1'b1;
            else
                load <= 1'b0;
        end
    end
end

// transmitting shift register - output section
always @( posedge clk_80M or posedge rst )
begin
    if ( rst == 1'b1 )
        shift_out <= 7'd0;
    else
    begin
        if ( ss_n_s == 1'b1 )
            shift_out <= byte_out;
        else if ( ( ss_n_s == 1'b0 ) & ( ss_n_t == 1'b1 ) )
            shift_out <= byte_out;
        else if ( ( sclk_s == 1'b0 ) & ( sclk_t == 1'b1 ) ) //rising edge send data
        begin
            if ( load == 1'b1 )
                shift_out <= byte_out;
            else
                shift_out <= { shift_out[6:0], 1'b0 };
        end
    end
end

always @( posedge clk_80M or posedge rst )
begin
    if ( rst == 1'b1 )
        miso <= 1'b0;
    else
    begin
        if ( ss_n_s == 1'b1 )
            i_miso <= 1'b0;
        else if ( ( sclk_s == 1'b1 ) & ( sclk_t == 1'b0 ) )//( ( sclk_s == 1'b1 ) & ( sclk_t == 1'b0 ) )
            miso <= shift_out[7];
    end
end



//若为master,则需产生SCLK,以及ss_n

 
//----- generate sclk ----------
always @( posedge clk or posedge rst )
begin
    if( rst )
        sclk <= 1'b0;
    else if( !ss_n )
    begin
        if( sclk_cnt == SCLK_CNT_NUM )
            sclk <= ~sclk;
    end
    else
        sclk <= 1'b0;
end

always @( posedge clk or posedge rst )
begin
    if( rst )
        sclk_cnt <= 8'd0;
    else if( !ss_n )
    begin
        if( sclk_cnt == SCLK_CNT_NUM )
            sclk_cnt <= 8'd0;
        else
            sclk_cnt <= sclk_cnt + 1'b1;
    end
    else
        sclk_cnt <= 8'd0;
end

// --------- generate ss_n---------------

always @( posedge clk or posedge rst )
begin
    if( rst )
    begin
        wr_ss_n <= 1'b1;
    end
    else if( send_addr_en && ( !send_addr_en_q ))
    begin
        wr_ss_n <= 1'b0;
    end
    else if( send_addr_done )
    begin
        wr_ss_n <= 1'b1;
    end
end


后续发送及接受数据额外添加~

CPOL = 1'b0; CPHA = 1'b1;

上升沿发送数据,下降沿采样,

同时主机在下降沿时移位。