您的位置:首页 > 汽车 > 时评 > 中国纪检监察报记者电话_桂林网站制作公司华彩_最近一周新闻大事件_百度快照怎么打开

中国纪检监察报记者电话_桂林网站制作公司华彩_最近一周新闻大事件_百度快照怎么打开

2025/3/13 16:58:12 来源:https://blog.csdn.net/qq_30479517/article/details/143706613  浏览:    关键词:中国纪检监察报记者电话_桂林网站制作公司华彩_最近一周新闻大事件_百度快照怎么打开
中国纪检监察报记者电话_桂林网站制作公司华彩_最近一周新闻大事件_百度快照怎么打开

MCU与CPLD可以通过AHB或APB总线进行数据交互。APB总线通常连接低速设备,如串口,而AHB总线则用于连接高速设备,如RAM等。由于我们需要高速采集大量数据,因此选择使用AHB总线与CPLD进行交互。

地址范围

在地址设计中,CPLD的地址区间设定为:0x60000000 ~ 0x7FFFFFFF。当MCU访问这个地址区间时,实际上是在访问CPLD内部的寄存器。

AHB介绍

https://blog.csdn.net/weixin_46022434/article/details/104987905

REG <-> MCU

MCU侧读写操作

MCU通过全局寻址机制来访问CPLD,其读写CPLD寄存器的方式与访问RAM(例如地址为0x20000000)相同。在C代码中,CPLD的访问操作可以通过如下方式实现

  • 读CPLD寄存器:
    int cpRdReg = *((int *)0x60000000);
    
  • 写CPLD寄存器:
    *((int *)0x60000004) = cpWtReg;
    

MCU侧的读写非常简便,直接使用上述方式即可完成操作。

CPLD侧读写

相关信号定义

assign slave_ahb_hready  = 1'b1;
reg hreadyout_reg;
reg hreadyout_del;
assign mem_ahb_hreadyout = hreadyout_reg;

信号hreadyout_del是信号hreadyout_reg延迟一个时钟周期的状态,主要用于协调AHB总线握手过程中的写操作。它确保从设备在准备好接收数据时进行操作,避免竞争条件的发生,从而确保数据正确写入hwdata_reg寄存器。

CPLD从AHB读数据

MCU执行写操作时,C代码示例如下:

*((int *)0x60000000) = value;

CPLD中相应的硬件逻辑如下:

//mcu的写操作响应
//mcu端用C语言:*((int *)0x60000000) = value;
reg [7:0] hwdata_reg;                                         //定义32位的hwdata_reg
always @(posedge sys_clock or negedge resetn) begin          //clk上升沿触发if (!resetn) begin//led3reg <= 1'b1;hreadyout_reg <= 1'b1;end else if(mem_ahb_htrans == 2'b10 && hreadyout_reg) begin //写地址为0x60000000(cpld内部用相对偏移)。hreadyout_reg <= 1'b0;//led3reg <= 1'b0;end else if(!hreadyout_del &&                          //cpld已ready状态,ahb上数据可以写过来了mem_ahb_hwrite &&                        //写 (0 读,1 写)mem_ahb_haddr[23:0] == 'h00) beginhwdata_reg <= mem_ahb_hwdata;        //把收到的数据给到hwdata_reghreadyout_reg <= 1'b1;//led3reg <= 1'b1;end else beginhreadyout_reg <= 1'b1;end
endalways @ (posedge sys_clock or negedge resetn) beginif (!resetn) beginhreadyout_del <= 1'b1;end else beginhreadyout_del <= hreadyout_reg;end
end

通过这些代码,我们确保了MCU写入0x60000000的数据能够准确地传输到CPLD。

CPLD向AHB写数据

MCU的读操作C代码如下:

int value = *((int *)0x60000004);

CPLD中对应的逻辑如下:

//mcu的读操作响应
//mcu端用C语言:int value = *((int *)0x60000004);
reg [7:0] hrdata_reg;                                         //定义32位的hrdata_reg
always @(posedge sys_clock or negedge resetn) begin          //clk上升沿触发if (!resetn) begin//led4reg <= 1'b1;end else if (mem_ahb_htrans == 2'b10 &&          //NONSEQ状态,第一次传输mem_ahb_hready &&                                  //master已ready,可以给数据线写入了!mem_ahb_hwrite &&                        //读 (0 读,1 写)mem_ahb_haddr[23:0] == 'h04)         //读地址为0x60000004(cpld内部用相对偏移)。beginhrdata_reg <= hwdata_reg;                //把另一准备好的数据给到hrdata_reg//led4reg <= 1'b0;end
end
assign mem_ahb_hrdata = hrdata_reg;        //绑定hrdata_reg到读的数据线上

通过这些代码,我们确保了MCU能够从CPLD准确读取0x60000004的数据。

FIFO IP <-> AHB

我们在设计中创建了一个FIFO IP核,并将其挂载到AHB总线上,以实现MCU对FIFO的读写访问。

FIFO IP配置

FIFO是先入先出,设计如下:

FIFO的设计为先入先出队列,配置如下:

  • 位宽设置为8位
  • 存储深度设置为4096,以充分利用4个M9K存储块
  • 其余参数保持默认配置,不使用emptyusedw信号。

值得注意的是,FIFO的读写时序上,读取数据时输出会滞后一个时钟周期。
在这里插入图片描述

FPGA代码设计

参考cpld-fpga文档中的5.mcu读写cpld寄存器

这里的设计需要参考AHB的时序图,由于AHB总在线上升沿进行数据读写操作,而FIFO也是在上升沿进行操作,因此我们将系统时钟反相后输入FIFO,以确保时序的一致性。

此外,AHB在传输数据时,数据与地址并非处于同一时钟周期内,数据会滞后一个时钟周期,因此我们给hreadyout 一个时钟周期的延时,从而确保AHB传输过来的数据被正确接收。此外,由于FIFO是在sys_clk下降沿进行数据读写,所以会滞后AHB数据读取一个周期,因此需要对wr_en进行一个周期的延时操作。

而在读取FIFO数据时,不需要hreadyout,FIFO的数据输出直接提供给AHB总线。

module user_ip (input              sys_clock,input              bus_clock,input              resetn,input              stop,input       [1:0]  mem_ahb_htrans,input              mem_ahb_hready,input              mem_ahb_hwrite,input       [31:0] mem_ahb_haddr,input       [2:0]  mem_ahb_hsize,input       [2:0]  mem_ahb_hburst,input       [31:0] mem_ahb_hwdata,output tri1        mem_ahb_hreadyout,output tri0        mem_ahb_hresp,output tri0 [31:0] mem_ahb_hrdata,output tri0        slave_ahb_hsel,output tri1        slave_ahb_hready,input              slave_ahb_hreadyout,output tri0 [1:0]  slave_ahb_htrans,output tri0 [2:0]  slave_ahb_hsize,output tri0 [2:0]  slave_ahb_hburst,output tri0        slave_ahb_hwrite,output tri0 [31:0] slave_ahb_haddr,output tri0 [31:0] slave_ahb_hwdata,input              slave_ahb_hresp,input       [31:0] slave_ahb_hrdata,output tri0 [3:0]  ext_dma_DMACBREQ,output tri0 [3:0]  ext_dma_DMACLBREQ,output tri0 [3:0]  ext_dma_DMACSREQ,output tri0 [3:0]  ext_dma_DMACLSREQ,input       [3:0]  ext_dma_DMACCLR,input       [3:0]  ext_dma_DMACTC,output tri0 [3:0]  local_int
);assign slave_ahb_hready  = 1'b1; reg hreadyout_reg;
reg hreadyout_del;assign mem_ahb_hreadyout = hreadyout_reg;// Internal signals
reg [7:0] data_in;
wire [7:0] data_out;
reg wr_en;
reg wr_en_del;
reg rd_en;assign mem_ahb_hrdata = {24'b0, data_out}; // Zero-padding upper bitsreg [1:0] state;//addr phase 00:idel 01:write 10:read// AHB state machine
always @(posedge sys_clock or negedge resetn) begin          //clk上升沿触发if (!resetn) beginhreadyout_reg <= 1'b1;wr_en <= 1'b0;end else if(mem_ahb_htrans == 2'b10 && hreadyout_reg) begin //写地址为0x60000000(cpld内部用相对偏移)。hreadyout_reg <= 1'b0;//led3reg <= 1'b0;end else if(!hreadyout_del &&                          //cpld已ready状态,ahb上数据可以写过来了mem_ahb_hwrite &&                        //写 (0 读,1 写)mem_ahb_haddr[23:0] == 'h00)beginhreadyout_reg <= 1'b1;data_in <= mem_ahb_hwdata[7:0];wr_en <= 1'b1;end else beginhreadyout_reg <= 1'b1;wr_en <= 1'b0;end
endalways @ (posedge sys_clock or negedge resetn) beginif (!resetn) beginhreadyout_del <= 1'b1;wr_en_del <= 1'b0;end else beginhreadyout_del <= hreadyout_reg;wr_en_del <=wr_en;end
end//mcu的读操作响应
//mcu端用C语言:int value = *((int *)0x60000004);
//reg [7:0] hrdata_reg;                                         //定义32位的hrdata_reg
always @(posedge sys_clock or negedge resetn) begin          //clk上升沿触发if (!resetn) beginrd_en <= 1'b0;end else if (mem_ahb_htrans == 2'b10 &&          //NONSEQ状态,第一次传输mem_ahb_hready &&                                  //master已ready,可以给数据线写入了!mem_ahb_hwrite &&                        //读 (0 读,1 写)mem_ahb_haddr[23:0] == 'h04)         //读地址为0x60000004(cpld内部用相对偏移)。begin//hrdata_reg <= hwdata_reg;                //把另一准备好的数据给到hrdata_regrd_en <= 1'b1;end else beginrd_en <= 1'b0;end
end
//assign mem_ahb_hrdata = hrdata_reg;        //绑定hrdata_reg到读的数据线上fifo_ip        fifo_ip_inst (.clock (~sys_clock),.data ( data_in ),.rdreq ( rd_en ),.wrreq ( wr_en_del ),.full ( full_sig ),.q ( data_out ));endmodule

最后综合出来的rtl网表如下图所示:
在这里插入图片描述

MCU代码

为了测试FIFO是否能正常工作,我们通过USB串口写入16个数据,然后读取并验证数据是否正确:

if ( tud_cdc_available() ){// read dataunsigned char buf[16] = {0};uint32_t count = tud_cdc_read(buf, sizeof(buf));(void) count;for(int i = 0; i < 16; i++){*((char *)0x60000000) = buf[i];//asm("nop");}unsigned char buf2[16] = {0};for(int i = 0; i < 16; i++){buf2[i] = *((char *)0x60000004);//asm("nop");}cdc_transfer(buf2, 16);}

从输出结果可以看到,接收到的数据与我们写入的数据完全一致,说明FIFO功能正常。
在这里插入图片描述

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com