IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> SPI代码详解FPGA-verilog部分(FPGA+STM32)(三) -> 正文阅读

[嵌入式]SPI代码详解FPGA-verilog部分(FPGA+STM32)(三)

声明:本篇文章面向在已对SPI的四种时序有所了解的人

我们采用SPI3模式以及将FPGA作从机,STM32作主机的方式讲解,在STM32控制部分采用的是半双工模式,但其实半双工与全双工区别不大,
稍加修改即可


本片文章是接续上篇文章的,如果未浏览上一篇文章的,可以在此跳转SPI驱动代码详解SPI代码详解FPGA-verilog部分(FPGA+STM32)(二)


本文是FPGA通过SPI接收的数据做出应答的模块,比如改变ADC采样率,将ADC采集的数据放在RAM中和从RAM中取出再发送给单片机


module samplingCtrl (
        input clk,
        input rstn,
        input [31:0] FCW, //频率控制字,是由单片机发送过来的
        input en,		//采样使能控制信号,是由单片机发送过来的
        input [11:0] AD9226_Din_0, //AD9226模块0采样后转换出来的数字量
        input [11:0] AD9226_Din_1, //AD9226模块1采样后转换出来的数字量
        input [11:0] AD9226_Din_2, //AD9226模块2采样后转换出来的数字量
        input [6:0] rd_addr,       //读RAM地址,是由单片机发送过来的
        output reg clk_sampling_1, //AD9226模块0时钟,由频率控制字控制
        output reg clk_sampling_2, //AD9226模块1时钟,由频率控制字控制
        output reg clk_sampling_0, //AD9226模块2时钟,由频率控制字控制
        output reg [11:0] AD9226_Dout_0, //从RAM0中读出的AD9226模块0采集的数据,将来发送给STM32
        output reg [11:0] AD9226_Dout_1, //从RAM1中读出的AD9226模块1采集的数据,将来发送给STM32
        output reg [11:0] AD9226_Dout_2, //从RAM2中读出的AD9226模块2采集的数据,将来发送给STM32
        output reg busy 				//判断一组采样(设置的是1024个点或者512个点)是否完成
    );


    localparam OFFSET_VALID = 7'd0;   //RAM偏移地址可以过滤掉采集的前几个不太正常的数据,但是一般数据都是正常的,这个功能暂时不开启

    wire clk_sampling;   //ADC模块的采样时钟
    reg [1:0] r_en;
    wire pos_en;
    reg [1:0] r_clk_sampling;
    wire pos_clk_sampling;
    wire neg_clk_sampling;

    reg wr_en;
    reg [6:0] wr_addr;

    wire [15:0] ram_dout0;
    wire [15:0] ram_dout1;
    wire [15:0] ram_dout2;

    //
    always @(posedge clk , negedge rstn)
    begin
        if(!rstn)
            r_en <= 2'd0;
        else
            r_en <= {r_en[0], en};
    end

    assign pos_en = (!r_en[1]) &(r_en[0]);

    always @(posedge clk , negedge rstn)
    begin
        if(!rstn)
            r_clk_sampling <= 2'd0;
        else
            r_clk_sampling <= {r_clk_sampling[0], clk_sampling};
    end

    assign pos_clk_sampling = (!r_clk_sampling[1]) &(r_clk_sampling[0]);
    assign neg_clk_sampling = (r_clk_sampling[1])  &(!r_clk_sampling[0]);


    //
    reg [3:0] state_c;
    reg [3:0] state_n;

    localparam s_idle    = 4'b0001;
    localparam s_waitPos = 4'b0010;
    localparam s_store   = 4'b0100;
    localparam s_addAddr = 4'b1000;

    wire idle_2_waitPos;
    wire waitPos_2_store;
    wire store_2_addAddr;
    wire addAddr_2_waitPos;
    wire addAddr_2_idle;

    always @(posedge clk , negedge rstn)
    begin
        if(!rstn)
            state_c <= s_idle;
        else
            state_c <= state_n;
    end

    //! fsm_extract   以下是三段式状态机
    /***
		第一段用来进行状态的变换
		第二段是用来判断什么时候进行状态的变换
		第三段是逻辑输出,处于什么状态输出什么样的逻辑值

	***/
    always @(*)
    begin
        case (state_c)
            s_idle:
                if(idle_2_waitPos)
                    state_n <= s_waitPos;
                else
                    state_n <= state_c;
            s_waitPos:
                if(waitPos_2_store)
                    state_n <= s_store;
                else
                    state_n <= state_c;
            s_store:
                if(store_2_addAddr)
                    state_n <= s_addAddr;
                else
                    state_n <= state_c;
            s_addAddr:
                if(addAddr_2_waitPos)
                    state_n <= s_waitPos;
                else if(addAddr_2_idle)
                    state_n <= s_idle;
                else
                    state_n <= state_c;
            default:
                state_n = s_idle;
        endcase
    end

    assign idle_2_waitPos    = (state_c == s_idle)    &&(pos_en);//使能采样后,进入等待状态,等待第一个采样上升沿到来
    assign waitPos_2_store   = (state_c == s_waitPos) &&(pos_clk_sampling);//当第一个上升沿到来的时候,进入存储状态
    assign store_2_addAddr   = (state_c == s_store)   &&(neg_clk_sampling);	//采样时钟下降进入地址移位状态
    assign addAddr_2_waitPos = (state_c == s_addAddr) &&(wr_addr < (64 + OFFSET_VALID) );//如果此时还没超过设定存储大小,由地址移位状态进入等待上升沿状态
    assign addAddr_2_idle    = (state_c == s_addAddr) &&(wr_addr >= (64 + OFFSET_VALID) );//如果此时已经超过设定存储大小,由地址移位状态进入空闲状态

    always @(posedge clk , negedge rstn)
    begin
        if(!rstn)
        begin
            busy <= 1'b0;
            wr_en <= 1'b0;
            wr_addr <= 7'd0;
        end
        else
        case (state_n)
            s_idle:                //在空闲状态时,busy = 0表示告知单片机现在不处于采样存储阶段,w_en = 0表示现在还不允许对RAM写入adc采样数据
            begin
                busy <= 1'b0;
                wr_en <= 1'b0;
                wr_addr <= 7'd0;
            end
            s_waitPos:				 //在等待上升沿状态时,busy = 1表示告知单片机现在处于采样存储阶段,w_en = 0表示现在还不允许对RAM写入adc采样数据
            begin
                busy <= 1'b1;
                wr_en <= 1'b0;
                wr_addr <= wr_addr;
            end
            s_store:				// 在存储状态时,busy = 1表示告知单片机现在处于采样存储阶段,w_en = 1表示现在允许对RAM写入adc采样数据
            begin
                busy <= 1'b1;
                wr_en <= 1'b1;
                wr_addr <= wr_addr;
            end
            s_addAddr:               //在地址增加状态时,busy = 1表示告知单片机现在处于采样存储阶段,w_en = 0表示现在不允许对RAM写入adc采样数据,wr_addr 增加
            begin
                busy <= 1'b1;
                wr_en <= 1'b0;
                wr_addr <= wr_addr + 7'd1;
            end
            default:
            begin
                busy <= 1'b0;
                wr_en <= 1'b0;
                wr_addr <= 7'd0;
            end
        endcase
    end


    always @(posedge clk , negedge rstn)
    begin
        if(!rstn)
        begin
            clk_sampling_0 <= 1'b0;
            clk_sampling_1 <= 1'b0;
            clk_sampling_2 <= 1'b0;
        end
        else
        begin
            clk_sampling_0 <= clk_sampling;
            clk_sampling_1 <= clk_sampling;
            clk_sampling_2 <= clk_sampling;
        end
    end

    always @(posedge clk , negedge rstn)
    begin
        if(!rstn)
        begin
            AD9226_Dout_0 <= 12'd0;
            AD9226_Dout_1 <= 12'd0;
            AD9226_Dout_2 <= 12'd0;
        end
        else
        begin
            AD9226_Dout_0 <= ram_dout0[11:0];
            AD9226_Dout_1 <= ram_dout1[11:0];
            AD9226_Dout_2 <= ram_dout2[11:0];
        end
    end


    clkSamplingGen clkSamplingGen_inst(
                       .clk_50M(clk),
                       .rstn(rstn),
                       .pos_en(pos_en),
                       .FCW(FCW),
                       .clk_sampling(clk_sampling)
                   );

    ram_2p	ram_2p_inst0 (
               .clock ( clk ),
               .data ( {4'd0, AD9226_Din_0} ),
               .rdaddress ( rd_addr ),
               .wraddress ( wr_addr[6:0] ),
               .wren ( wr_en ),
               .q ( ram_dout0 )
           );

    ram_2p	ram_2p_inst1 (
               .clock ( clk ),
               .data ( {4'd0, AD9226_Din_1} ),
               .rdaddress ( rd_addr ),
               .wraddress ( wr_addr[6:0] ),
               .wren ( wr_en ),
               .q ( ram_dout1 )
           );

    ram_2p	ram_2p_inst2 (
               .clock ( clk ),
               .data ( {4'd0, AD9226_Din_2} ),
               .rdaddress ( rd_addr ),
               .wraddress ( wr_addr[6:0] ),
               .wren ( wr_en ),
               .q ( ram_dout2 )
           );


endmodule

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-08-29 09:31:07  更:2021-08-29 09:32:46 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 22:50:17-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码