当前位置: 首页 > news >正文

AD7606芯片驱动-FPGA实现

        简介

        AD7606是一款16位ADC芯片,可实现8通道并行采集,每通道最大速度可达1M,可实现多种模式数据采集。

        介绍

        本次FPGA使用的是8通道串行采样模式,设计中所用到的AD7606引脚说明如下:

名称定义
CONVST同步采集转换开始信号
BUSYADC忙碌状态信号
RD/SCLK采样/寄存器工作时钟
CS片选使能
DOUTA~DOUTH

ADC 8通道串行输出

SDI寄存器数据输入

 本次采用的寄存器读写时序如下图所示:

 1、寄存器读写第一位默认为0;

2、第二位代表寄存器读写位,0代表写寄存器,1代表读寄存器;

3、6个地址位,具体寄存器定义查阅芯片手册;

4、如果是写操作,后面8bit为寄存器值,如果是读操作则通过DoutA接口读取返回的寄存器数据。

5、该芯片支持CRC模式,本次设计默认不启动CRC模式,所以后面8bitCRC在普通模式下不存在。

采样时序如下图所示:

                        

本时序图发现如下两个问题:

1、DoutA~DoutH输出的应该是V1~V7数据,上图中标识有错误;

2、上图未标识CONVST和BUSY信号,显然这两个信号是必须存在的;

另外芯片引脚OS0~OS2都接高点平,进入Enters software mode模式。

代码

FPGA驱动代码如下:

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2024/08/05 15:39:27
// Design Name: 
// Module Name: ADC_SLAVE_DRI_TOP
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//module ADC_SLAVE_DRI_TOP(input sys_clk,input sys_rst_n,output reg ADC_CONVST,input ADC_BUSY,output ADC_SCLK,output ADC_CS,input ADC_FRSTDATA,input[7:0] ADC_DATA,[7]:a [6]:b [5]:c ......output ADC_SDI,reg setinput[15:0] adc_frame_length,input[15:0] adc_tdata_reg,input[15:0] adc_sample_rate_h,input[15:0] adc_sample_rate_l,	ADC REC REG DATAoutput[7:0] adc_rec_reg_data,output adc_rec_reg_data_en,input[3:0] adc_rw_set,//[1]:sample [0]:reg w/rinput[15:0] adc_sample_rate_reg,input[15:0] adc_sample_channel_en_reg,ADC SAMPLE DATA	output[15:0] rx_data_length,output [7:0] axis_adc_data,output  axis_adc_tvalid,output  axis_adc_tlast	);parameter ADC_CONVST_num = 'd100;	reg[7:0] spi_tdata;
reg spi_tvalid;
reg tx_reg_en_r1;
wire[31:0] ADC_SAMPLE_RATE;
reg[31:0]sample_cnt;
reg tx_reg_wr_r1;
reg tx_reg_rd_r1;
wire tx_reg_wr;
wire tx_reg_rd;
wire sample_en;
reg ADC_BUSY_r1;
reg ADC_BUSY_r2;
reg ADC_BUSY_r3;
reg ADC_BUSY_r4;
reg ADC_BUSY_r5;
wire ADC_BUSY_neg;reg[15:0]rec_adc_a_sample_data;
reg[15:0]rec_adc_b_sample_data;
reg[15:0]rec_adc_c_sample_data;
reg[15:0]rec_adc_d_sample_data;
reg[15:0]rec_adc_e_sample_data;
reg[15:0]rec_adc_f_sample_data;
reg[15:0]rec_adc_g_sample_data;
reg[15:0]rec_adc_h_sample_data;
reg rec_adc_sample_en;
reg ADC_SCLK_i;
reg ADC_CS_i;
reg[3:0] adc_mode;
reg[31:0] sample_en_delay;
reg[31:0] adc_stop_delay;reg[15:0] rec_data_cnt;reg[7:0] s_axis_tdata;
reg s_axis_tvalid;
wire s_axis_tlast;
reg[15:0] s_axis_tvalid_cnt;reg[15:0] spi_clk_cnt;
reg[15:0] clk_cnt;reg sample_en_r1;
reg sample_en_r2;
wire sample_en_neg;
wire[13:0] axis_data_count;reg fifo_rst_n;
reg[15:0] fifo_rst_cnt;
reg fifo_rst_en;wire channel_a_en;
wire channel_b_en;
wire channel_c_en;
wire channel_d_en;
wire channel_e_en;
wire channel_f_en;
wire channel_g_en;
wire channel_h_en;assign channel_a_en = adc_sample_channel_en_reg[7];
assign channel_b_en = adc_sample_channel_en_reg[6];
assign channel_c_en = adc_sample_channel_en_reg[5];
assign channel_d_en = adc_sample_channel_en_reg[4];
assign channel_e_en = adc_sample_channel_en_reg[3];
assign channel_f_en = adc_sample_channel_en_reg[2];
assign channel_g_en = adc_sample_channel_en_reg[1];
assign channel_h_en = adc_sample_channel_en_reg[0];assign rx_data_length = adc_frame_length;
assign tx_reg_wr = adc_rw_set[0];
assign tx_reg_rd = adc_rw_set[1];
assign sample_en = adc_rw_set[2];
assign ADC_SAMPLE_RATE = {adc_sample_rate_h,adc_sample_rate_l};
assign ADC_BUSY_neg = (~ADC_BUSY_r4) && ADC_BUSY_r5;assign ADC_SCLK = (adc_mode == 'd3)?ADC_SCLK_i:ADC_SCLK_ii;
assign ADC_CS = (adc_mode == 'd3)?ADC_CS_i:ADC_CS_ii;
assign sample_en_neg = sample_en_r2 && (~sample_en_r1);assign s_axis_tlast = (s_axis_tvalid_cnt == adc_frame_length - 'd1)?1'b1:1'b0;always@(posedge sys_clk or negedge sys_rst_n)beginif(sys_rst_n == 'D0)begin adc_mode <= 'd0;endelse if(tx_reg_wr == 'd1)beginadc_mode <= 'd1;	endelse if(tx_reg_rd == 'd1)beginadc_mode <= 'd2;endelse if(sample_en == 'd1)beginadc_mode <= 'd3;end
endreg set
always@(posedge sys_clk)begintx_reg_wr_r1 <= tx_reg_wr;tx_reg_rd_r1 <= tx_reg_rd;
end	always@(posedge sys_clk or negedge sys_rst_n)beginif(sys_rst_n == 'D0)begin  spi_tdata <= 'd0;spi_tvalid <= 'd0;endelse if(tx_reg_wr == 'd1)beginspi_tdata <= {2'b00,adc_tdata_reg[13:8]};spi_tvalid <= 'd1;endelse if(tx_reg_rd == 'd1)beginspi_tdata <= {2'b01,adc_tdata_reg[13:8]};spi_tvalid <= 'd1;endelse if(tx_reg_wr_r1 == 'd1 || tx_reg_rd_r1 == 'd1)beginspi_tdata <= adc_tdata_reg[7:0];spi_tvalid <= 'd1;		endelse beginspi_tdata <= 'd0;spi_tvalid <= 'd0;		end
endsamplealways@(posedge sys_clk)beginADC_BUSY_r1 <= ADC_BUSY;ADC_BUSY_r2 <= ADC_BUSY_r1;ADC_BUSY_r3 <= ADC_BUSY_r2;ADC_BUSY_r4 <= ADC_BUSY_r3;ADC_BUSY_r5 <= ADC_BUSY_r4;sample_en_r1 <= sample_en;sample_en_r2 <= sample_en_r1;
endalways@(posedge sys_clk or negedge sys_rst_n)beginif(sys_rst_n == 'D0)begin  sample_cnt <= 'd0;endelse if(sample_cnt >= ADC_SAMPLE_RATE - 'd1)beginsample_cnt <= 'd0;endelse if(sample_en == 'd1)beginsample_cnt <= sample_cnt + 'd1;endelse beginsample_cnt <= 'd0;end
endalways@(posedge sys_clk or negedge sys_rst_n)beginif(sys_rst_n == 'D0)begin  ADC_CONVST <= 'd0;endelse if(sample_cnt < ADC_CONVST_num + 'd10 && sample_cnt >= 'd10 && sample_en == 'd1)beginADC_CONVST <= 'd1;endelse beginADC_CONVST <= 'd0;end
endalways@(posedge sys_clk or negedge sys_rst_n)beginif(sys_rst_n == 'D0)begin  spi_clk_cnt <= 'd0;clk_cnt <= 'd0;end	else if(ADC_BUSY_neg == 'd1) beginspi_clk_cnt <= 'd36;clk_cnt <= adc_sample_rate_reg;20M;endelse if(spi_clk_cnt > 'd0 && clk_cnt == 'd1)beginspi_clk_cnt <= spi_clk_cnt - 'd1;clk_cnt <= adc_sample_rate_reg;endelse if(spi_clk_cnt > 'd0)beginclk_cnt <= clk_cnt - 'd1;end
endalways@(posedge sys_clk or negedge sys_rst_n)beginif(sys_rst_n == 'D0)begin  ADC_CS_i <= 'd1;end	else if(spi_clk_cnt > 'd0) beginADC_CS_i <= 'd0;endelse beginADC_CS_i <= 'd1;end
endalways@(posedge sys_clk or negedge sys_rst_n)beginif(sys_rst_n == 'D0)begin  ADC_SCLK_i <= 'd1;end	else if(clk_cnt == 'd1 && spi_clk_cnt >='d3 && spi_clk_cnt <= 'd34) beginADC_SCLK_i <= ~ADC_SCLK_i;end
endalways@(posedge sys_clk or negedge sys_rst_n)beginif(sys_rst_n == 'D0)begin  rec_adc_a_sample_data <= 'd0;rec_adc_b_sample_data <= 'd0;	rec_adc_c_sample_data <= 'd0;	rec_adc_d_sample_data <= 'd0;	rec_adc_e_sample_data <= 'd0;	rec_adc_f_sample_data <= 'd0;	rec_adc_g_sample_data <= 'd0;	rec_adc_h_sample_data <= 'd0;		end	else if(clk_cnt == 'd1 && spi_clk_cnt >='d3 && spi_clk_cnt <= 'd34 && ADC_SCLK_i == 'd0) beginrec_adc_a_sample_data <= {rec_adc_a_sample_data[14:0],ADC_DATA[7]};rec_adc_b_sample_data <= {rec_adc_b_sample_data[14:0],ADC_DATA[6]};rec_adc_c_sample_data <= {rec_adc_c_sample_data[14:0],ADC_DATA[5]};rec_adc_d_sample_data <= {rec_adc_d_sample_data[14:0],ADC_DATA[4]};	rec_adc_e_sample_data <= {rec_adc_e_sample_data[14:0],ADC_DATA[3]};rec_adc_f_sample_data <= {rec_adc_f_sample_data[14:0],ADC_DATA[2]};rec_adc_g_sample_data <= {rec_adc_g_sample_data[14:0],ADC_DATA[1]};rec_adc_h_sample_data <= {rec_adc_h_sample_data[14:0],ADC_DATA[0]};end
endalways@(posedge sys_clk or negedge sys_rst_n)beginif(sys_rst_n == 'D0)begin  rec_adc_sample_en <= 'd0;end	else if(clk_cnt == 'd1 && spi_clk_cnt == 'd3 && ADC_SCLK_i == 'd0) beginrec_adc_sample_en <= 'd1;endelse beginrec_adc_sample_en <= 'd0;end
endalways@(posedge sys_clk or negedge sys_rst_n)beginif(sys_rst_n == 'D0)begin  sample_en_delay <= 'd0;adc_stop_delay <= 'd0;end	else beginsample_en_delay <= {sample_en_delay[30:0],rec_adc_sample_en};adc_stop_delay <= {adc_stop_delay[30:0],sample_en_neg};end
endalways@(posedge sys_clk or negedge sys_rst_n)beginif(sys_rst_n == 'D0)begin  s_axis_tdata <= 'd0;s_axis_tvalid <= 'd0;end	else if(sample_en_delay[0] == 'd1 && channel_a_en == 'd1)begins_axis_tdata <= rec_adc_a_sample_data[15:8];s_axis_tvalid <= 'd1;endelse if(sample_en_delay[1] == 'd1 && channel_a_en == 'd1)begins_axis_tdata <= rec_adc_a_sample_data[7:0];s_axis_tvalid <= 'd1;endelse if(sample_en_delay[2] == 'd1 && channel_b_en == 'd1)begins_axis_tdata <= rec_adc_b_sample_data[15:8];s_axis_tvalid <= 'd1;endelse if(sample_en_delay[3] == 'd1 && channel_b_en == 'd1)begins_axis_tdata <= rec_adc_b_sample_data[7:0];s_axis_tvalid <= 'd1;endelse if(sample_en_delay[4] == 'd1 && channel_c_en == 'd1)begins_axis_tdata <= rec_adc_c_sample_data[15:8];s_axis_tvalid <= 'd1;endelse if(sample_en_delay[5] == 'd1 && channel_c_en == 'd1)begins_axis_tdata <= rec_adc_c_sample_data[7:0];s_axis_tvalid <= 'd1;endelse if(sample_en_delay[6] == 'd1 && channel_d_en == 'd1)begins_axis_tdata <= rec_adc_d_sample_data[15:8];s_axis_tvalid <= 'd1;endelse if(sample_en_delay[7] == 'd1 && channel_d_en == 'd1)begins_axis_tdata <= rec_adc_d_sample_data[7:0];s_axis_tvalid <= 'd1;endelse if(sample_en_delay[8] == 'd1 && channel_e_en == 'd1)begins_axis_tdata <= rec_adc_e_sample_data[15:8];s_axis_tvalid <= 'd1;endelse if(sample_en_delay[9] == 'd1 && channel_e_en == 'd1)begins_axis_tdata <= rec_adc_e_sample_data[7:0];s_axis_tvalid <= 'd1;endelse if(sample_en_delay[10] == 'd1 && channel_f_en == 'd1)begins_axis_tdata <= rec_adc_f_sample_data[15:8];s_axis_tvalid <= 'd1;endelse if(sample_en_delay[11] == 'd1 && channel_f_en == 'd1)begins_axis_tdata <= rec_adc_f_sample_data[7:0];s_axis_tvalid <= 'd1;endelse if(sample_en_delay[12] == 'd1 && channel_g_en == 'd1)begins_axis_tdata <= rec_adc_g_sample_data[15:8];s_axis_tvalid <= 'd1;endelse if(sample_en_delay[13] == 'd1 && channel_g_en == 'd1)begins_axis_tdata <= rec_adc_g_sample_data[7:0];s_axis_tvalid <= 'd1;endelse if(sample_en_delay[14] == 'd1 && channel_h_en == 'd1)begins_axis_tdata <= rec_adc_h_sample_data[15:8];s_axis_tvalid <= 'd1;endelse if(sample_en_delay[15] == 'd1 && channel_h_en == 'd1)begins_axis_tdata <= rec_adc_h_sample_data[7:0];s_axis_tvalid <= 'd1;endelse begins_axis_tvalid <= 'd0;end
endalways@(posedge sys_clk or negedge sys_rst_n)beginif(sys_rst_n == 'D0)begin  s_axis_tvalid_cnt <= 'd0;end	else if(s_axis_tvalid == 'd1 && s_axis_tvalid_cnt == adc_frame_length - 'd1)begins_axis_tvalid_cnt <= 'd0;endelse if(s_axis_tvalid == 'd1)begins_axis_tvalid_cnt <= s_axis_tvalid_cnt + 'd1;end
endalways@(posedge sys_clk or negedge sys_rst_n)beginif(sys_rst_n == 'D0)begin  fifo_rst_en <= 'd0;end	else if(sample_en == 'd0 && axis_adc_tvalid == 'd0 && axis_data_count > 'd0 && axis_data_count <adc_frame_length)beginfifo_rst_en <= 'd1;endelse beginfifo_rst_en <= 'd0;end
endalways@(posedge sys_clk or negedge sys_rst_n)beginif(sys_rst_n == 'D0)begin  fifo_rst_n <= 'd1;fifo_rst_cnt <= 'd0;end		else if(fifo_rst_en == 'd1)beginfifo_rst_n <= 'd0;fifo_rst_cnt <= 'd200;endelse if(fifo_rst_cnt > 'd0)beginfifo_rst_n <= 'd0;fifo_rst_cnt <= fifo_rst_cnt - 'd1;endelse beginfifo_rst_n <= 'd1;fifo_rst_cnt <= 'd0;end
endSPI_DRV	SPI_DRV_inst(.sys_rstn(sys_rst_n),.sys_clk_100m(sys_clk),.spi_mode(2'b11),.spi_tvalid(spi_tvalid),.spi_tdata(spi_tdata),.spi_rate('d20),.spi_rd_num('d1),.DUT_SPI_WR_BIT_reg(8'h04),.spi_tready(),.dut_data_out(adc_rec_reg_data),.dut_data_out_en(adc_rec_reg_data_en),.spi_fifo_recv_en('d1),.spi_rd_busy(),.spi_sck(ADC_SCLK_ii),.spi_cs(ADC_CS_ii),.spi_mosi(ADC_SDI),.spi_miso(ADC_DATA[7])	
);fifo_adc_sample_data	fifo_adc_sample_data_inst(.s_aclk(sys_clk),.s_aresetn(sys_rst_n && fifo_rst_n),.s_axis_tvalid(s_axis_tvalid),.s_axis_tready(),.s_axis_tdata(s_axis_tdata),.s_axis_tlast(s_axis_tlast),.m_axis_tvalid(axis_adc_tvalid),.m_axis_tready('d1),.m_axis_tdata(axis_adc_data),.m_axis_tlast(axis_adc_tlast),.axis_data_count(axis_data_count));/* testreg[31:0] cnt_tx;
reg[31:0] delay;assign rx_data_length = adc_frame_length;always @(posedge sys_clk or negedge sys_rst_n) beginif(sys_rst_n == 'd0) begin	axis_adc_data <= 'd0;axis_adc_tvalid <= 'd0;axis_adc_tlast <= 'd0;cnt_tx <= 'd0;delay <= 'd0;endelse if(delay <= 'd2000)begindelay <= delay + 'd1;endelse if(cnt_tx == adc_frame_length - 'd1)beginaxis_adc_data <= axis_adc_data + 'd1;axis_adc_tvalid <= 'd1;axis_adc_tlast <= 'd1;cnt_tx <= cnt_tx + 'd1;		endelse if(cnt_tx < adc_frame_length - 'd1)beginaxis_adc_data <= axis_adc_data + 'd1;axis_adc_tvalid <= 'd1;axis_adc_tlast <= 'd0;cnt_tx <= cnt_tx + 'd1;		end///else if(cnt_tx <= 'd20000)beginaxis_adc_data <= 'd0;axis_adc_tvalid <= 'd0;axis_adc_tlast <= 'd0;cnt_tx <= cnt_tx + 'd1;		endelse beginaxis_adc_data <= 'd0;axis_adc_tvalid <= 'd0;axis_adc_tlast <= 'd0;cnt_tx <= 'd0;end
end*/	endmodule

代码接口说明:

信号名说明
adc_frame_length采样数据打包成帧输出,这里设置帧内容长度
adc_tdata_reg寄存器地址+数据信息,如果是读只有读地址有效
adc_sample_rate_hADC循环采样周期高16位
adc_sample_rate_l                ADC循环采样周期低16位
adc_rec_reg_dataADC返回的寄存器值
adc_rec_reg_data_enADC返回的寄存器值使能位
adc_rw_setADC读、写、循环采样控制寄存器
adc_sample_rate_regclk速率控制
adc_sample_channel_en_reg通道使能寄存器控制,8通道可以做任意通道使能。

仿真

代码仿真结果如下:

首先是SPI写操作,放大效果如下:

该操作标识对寄存0x01写0x23值;

ADC采样波形如下:

         CONGVST为高电平期间触发芯片同步采集,此时BUSY会至高表示正在转换中,当BUSY拉低代表转换完成,输出SCLK时钟信号并开始同步采样。

如需要完整的驱动代码或者技术支持可以私聊我,谢谢。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 打卡50天------图论
  • 【给女朋友讲C++】C++的调试之gdb
  • python socket 发生UDP 和 UDPServer接受UDP实例
  • 快速绘制思维导图:高效思考与信息整理的利器
  • LeetCode 热题 100 回顾
  • Qt详解QUrl
  • MS sqlserver备份软件 SQLBackupAndFTP
  • 开源模型应用落地-LlamaIndex学习之旅-LLMs-集成OpenAI(一)
  • Pictory AI——博客、文章等内容转换为视频,自动适配动态画面和字幕
  • 【STM32 Blue Pill编程】-UAR数据接收与发送(中断模式)
  • 力扣52-最大子序和(java详细题解)
  • sql查询之“列命名问题“
  • Qdrant官方快速入门和教程简化版
  • RocketMQ第5集
  • Flutter ListView滑动
  • “Material Design”设计规范在 ComponentOne For WinForm 的全新尝试!
  • 【React系列】如何构建React应用程序
  • C# 免费离线人脸识别 2.0 Demo
  • Docker入门(二) - Dockerfile
  • Fastjson的基本使用方法大全
  • JavaScript设计模式系列一:工厂模式
  • JAVA并发编程--1.基础概念
  • Java程序员幽默爆笑锦集
  • laravel with 查询列表限制条数
  • Node.js 新计划:使用 V8 snapshot 将启动速度提升 8 倍
  • node-sass 安装卡在 node scripts/install.js 解决办法
  • SegmentFault 社区上线小程序开发频道,助力小程序开发者生态
  • SwizzleMethod 黑魔法
  • Travix是如何部署应用程序到Kubernetes上的
  • tweak 支持第三方库
  • 测试如何在敏捷团队中工作?
  • 关于字符编码你应该知道的事情
  • 坑!为什么View.startAnimation不起作用?
  • 力扣(LeetCode)56
  • 前端_面试
  • 山寨一个 Promise
  • 我与Jetbrains的这些年
  • 一道面试题引发的“血案”
  • 一文看透浏览器架构
  • 京东物流联手山西图灵打造智能供应链,让阅读更有趣 ...
  • 扩展资源服务器解决oauth2 性能瓶颈
  • ​软考-高级-信息系统项目管理师教程 第四版【第23章-组织通用管理-思维导图】​
  • #QT(TCP网络编程-服务端)
  • #window11设置系统变量#
  • #绘制圆心_R语言——绘制一个诚意满满的圆 祝你2021圆圆满满
  • #我与Java虚拟机的故事#连载03:面试过的百度,滴滴,快手都问了这些问题
  • #我与Java虚拟机的故事#连载17:我的Java技术水平有了一个本质的提升
  • (+3)1.3敏捷宣言与敏捷过程的特点
  • (层次遍历)104. 二叉树的最大深度
  • (动态规划)5. 最长回文子串 java解决
  • (二)正点原子I.MX6ULL u-boot移植
  • (简单有案例)前端实现主题切换、动态换肤的两种简单方式
  • (每日一问)设计模式:设计模式的原则与分类——如何提升代码质量?
  • (免费分享)基于springboot,vue疗养中心管理系统
  • (南京观海微电子)——COF介绍