首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

FPGA的SPI从机模块实现(2)

FPGA的SPI从机模块实现(2)

3. SPI接收部分        SPI接收部分使用有限状态机:状态1:等待SCK上跳沿,并将MOSI的数据移入移位寄存器byte_received,接收位数寄存器bit_received_cnt记录接收到的数据位数,接收到8位数据后转入状态2;
状态2:保存移位寄存器byte_received数据到接收缓存器rec_data,接收标志位/接收缓存器非空标志位rec_flag置高4个clk时钟周期后转入状态3;
状态3:清除rec_flag并转入状态1。
reg[7:0] byte_received;        reg[3:0] bit_received_cnt;        reg rec_flag;        reg[1:0] rec_status;  //SPI接收部分状态机        reg[7:0] rec_data;        reg[2:0] rec_flag_width;  //SPI接收完成标志位脉冲宽度寄存器        always @ (posedge clk or negedge nrst)  //每次sck都会接收数据,spi的顶端模块状态机决定是否取用        begin                if(~nrst)                begin                        byte_received <= 8'h00;                        bit_received_cnt <= 4'h0;                        rec_flag <= 1'b0;                        rec_status <= 2'b00;                        rec_flag_width <= 3'b000;                end                else                begin                        if(~ncs)                        begin                                case (rec_status)                                2'b00: begin                                        if(sck_riseedge)                                        begin                                                byte_received <= {byte_received[6:0], mosi};                                                if(bit_received_cnt == 4'h7)                                                begin                                                        bit_received_cnt <= 4'b0000;                                                        rec_status <= 2'b01;                                                end                                                else                                                begin                                                        bit_received_cnt <= bit_received_cnt+1;                                                end                                        end                                end                                2'b01: begin                                        rec_data <= byte_received;                                        rec_flag <= 1'b1;                                        if(rec_flag_width==3'b100) begin                                                rec_flag_width <= 3'b000;                                                rec_status <= 2'b11;                                        end                                        else begin                                                rec_flag_width <= rec_flag_width+1;                                        end                                end                                2'b11: begin                                        rec_flag <= 1'b0;                                        rec_status <= 2'b00;                                end                                endcase                        end                                end        end
    这里,使用rec_flag的原因是通知另一个模块处理接收数据(后面将会提到),rec_data若在下一次数据传输完成前不做处理则会丢失。
4. SPI发送部分        SPI从机一般在解析主机发送的命令后,主动发出主机所需数据,所以,SPI发送部分,需要其他模块的触发,并将数据送往MISO管脚。
  SPI发送部分也离不开状态机:
状态1:等待发送触发标志位send_flag置高,一旦标志位send_flag置高,发送移位寄存器byte_sended存储外部触发模块的数据send_data,miso管脚输出发送数据最高位send_data[7],置位正在发送标志位sending_flag,转入状态2;
状态2:等待SCK上跳沿,即等待主机接收数据最高位后进入状态3;(其实这个状态可有可无的状态)
状态3:在SCK下跳沿,将发送移位寄存器byte_sended最高位移入miso管脚,当发送移位寄存器被移空,清除正在发送标志位sending_flag,进入状态4;
状态4:置低miso管脚,转入状态1。
reg miso;        reg sending_flag;  //正在发送标志位        reg[7:0] byte_sended;  //发送移位寄存器        reg[3:0] bit_sended_cnt;  //SPI发送位计数器        reg[1:0] send_status;  //SPI发送部分状态机        always @ (posedge clk or negedge nrst)        begin                if(~nrst)                begin                        byte_sended <= 8'h00;                        bit_sended_cnt <= 4'b0000;                        send_status <= 2'b00;                        sending_flag <= 1'b0;                end                else                begin                        if(~ncs)                        begin                                case (send_status)                                2'b00: begin                                        if(send_flag)                                         begin  //锁存发送数据                                                send_status <= 2'b01;  //2'b01;                                                byte_sended <= send_data;                                                sending_flag <= 1'b1;                                                miso <= send_data[7];                                        end                                end                                2'b01: begin  //发送数据移入移位寄存器                                        if(sck_riseedge) begin                                                //miso <= byte_sended[7];                                                //byte_sended <= {byte_sended[6:0], 1'b0};                                                send_status <= 2'b11;                                        end                                end                                2'b11: begin  //根据sck下降沿改变数据                                        miso <= byte_sended[7];                                        if(sck_falledge)   ///---------------------------------------这里多移了一位                                        begin                                                //miso <= byte_sended[7];                                                byte_sended <= {byte_sended[6:0], 1'b0};                                                if(bit_sended_cnt == 4'b0111)                                                begin                                                        send_status <= 2'b10;                                                        bit_sended_cnt <= 4'b0000;                                                        sending_flag <= 1'b0;                                                end                                                else                                                begin                                                        bit_sended_cnt <= bit_sended_cnt+1;                                                end                                        end                                end                                2'b10: begin  //数据发送完毕                                        send_status <= 2'b00;                                        //sending_flag <= 1'b0;                                        miso <= 1'b0;                                end                                endcase                        end                end        end
经过实测,SCK频率低于clk频率8倍以上,通信可靠稳定,测试芯片为XC3S50-TQ144,平台为ISE,clk为25MHz。
继承事业,薪火相传
返回列表