ADC前端控制与处理模块--AD7606_Module

总体框架

AD7606_Module主要由3个模块组成组成,AD7606_Data_Pkt和AD7606_Drive以及AD7606_ctrl。
1.AD7606_Data_Pkt主要作用是把AD芯片数据组好数据包,然后发送给上位机;
2.AD7606_Drive主要负责和芯片的交互部分
3.AD7606_ctrl控制模块的作用接受命令报文,然后把里面具体的控制信号解析出来,把控制信号给到数据组包模块。

系统框图

一、数据组包模块AD7606_Data_Pkt

数据格式如图所示,其中每一个通道的数据由3个字节组成,第一个字节代表该通道的通道数,后两个字节是AD采集到的16位数据,CRC暂时不设计

图1

组包设计思路是,
1.输入定义一个r_cnt寄存器,当查询指令进来或者计数到0到4时候自增,在计数到4时候等待有效信号进来才继续自增,等到读完所有通道数3+3*channel-1这时候才清零.

always @(posedge i_clk or posedge i_rst )
begin
    if(i_rst) 
        r_cnt <= 'd0 ;
    else if(r_cnt == 2 + (ri_cap_channel + ri_cap_channel + ri_cap_channel))//读完就是26,一个通道占用3个字节
        r_cnt <= 'd0 ;
    else if (r_cnt > 4)
        r_cnt <= r_cnt + 1 ;
    else if (r_cnt == 4 && ri_user_valid_1)
        r_cnt <= r_cnt + 1 ;//这里是确保第一个数据进来了
    else if(ri_cap_seek || (r_cnt > 0 && r_cnt < 4 ) )
        r_cnt <= r_cnt + 1 ; //查询指令来了之后才开始组包,算到4就真正开始进来数据了
    else 
        r_cnt <= r_cnt ;
end

2.使用一个case在计数器r_cnt自增时候就开始组包

always @(posedge i_clk or posedge i_rst )
begin
    if(i_rst)
        r_adc_per_data <= 'd0 ; 

    else case(r_cnt)
        0          :    r_adc_per_data <= 8 'h55 ; //前导码 
        1          :    r_adc_per_data <= 'd5    ;//指令,代表通道电压采集结果查询 
        2          :    r_adc_per_data <= ri_cap_channel + ri_cap_channel + ri_cap_channel; //长度信息,一个通道需要3个字节 , 3*通道数 ,3 *ri_cap_channel,乘法在fpga里面一个周期算不出来
        3          :    r_adc_per_data <= 1 ; //代表通道1
        4          :    r_adc_per_data <= ri_user_data_1[15 : 8] ; //数据高字节
        5          :    r_adc_per_data <= ri_user_data_1[7  : 0] ; //数据低字节
        6          :    r_adc_per_data <= 2 ; 
        7          :    r_adc_per_data <= ri_user_data_2[15 : 8] ;
        8          :    r_adc_per_data <= ri_user_data_2[7  : 0] ; 
        9          :    r_adc_per_data <= 3 ; 
        10         :    r_adc_per_data <= ri_user_data_3[15 : 8] ; 
        11         :    r_adc_per_data <= ri_user_data_3[7  : 0] ; 
        12         :    r_adc_per_data <= 4 ; 
        13         :    r_adc_per_data <= ri_user_data_4[15 : 8] ; 
        14         :    r_adc_per_data <= ri_user_data_4[7  : 0] ; 
        15         :    r_adc_per_data <= 5 ; 
        16         :    r_adc_per_data <= ri_user_data_5[15 : 8] ;
        17         :    r_adc_per_data <= ri_user_data_5[7  : 0] ; 
        18         :    r_adc_per_data <= 6 ; 
        19         :    r_adc_per_data <= ri_user_data_6[15 : 8] ; 
        20         :    r_adc_per_data <= ri_user_data_6[7  : 0] ; 
        21         :    r_adc_per_data <= 7 ; 
        22         :    r_adc_per_data <= ri_user_data_7[15 : 8] ; 
        23         :    r_adc_per_data <= ri_user_data_7[7  : 0] ; 
        24         :    r_adc_per_data <= 8 ; 
        25         :    r_adc_per_data <= ri_user_data_8[15 : 8] ;
        26         :    r_adc_per_data <= ri_user_data_8[7  : 0] ; 
    endcase 

end

3.然后把r_adc_per_data输入进去fifo里面,fifo输出就是组好的包,记住fifo的读使能要打一拍,才和输出数据同步,同时定义一个r_sent_cnt,发一个数据加1,可以作为o_adc_last信号拉高的条件

二、AD控制模块AD7606_ctrl

i_cmd_data信号进来,需要把解包,读取指令数据,数据包的格式依然是图1 所示,重点关注指令那一块,当r_cnt数到1的时候,读取指令type,type就是决定后面的数据包含什么信息,然后把信息输出给ad_drive和ad_pkt

解包设计思路:
1.定义一个计数器r_cnt,有效信号valid来的时候就加1
2.取出type

always @(posedge i_clk or posedge i_rst )
begin
    if(i_rst)
        r_type <= 'd0 ;
    else if(r_cnt == 1 && ri_cmd_valid)
        r_type <= ri_cmd_data ;       
    else
        r_type <= r_type ;
end

3.然后取出指令,以取采样率为例,由于是二十四位,采用串转并操作,w_system_pos是上电启动,这部分还没开发,i_adc_speed 最后悬空的。

always @(posedge i_clk or posedge i_rst )
begin
    if(i_rst)
        ro_cap_speed <= 'd0 ;
    else if (w_system_pos)
        ro_cap_speed <= i_adc_speed ;   
    else if(ri_cmd_valid && r_cnt >= 3  && r_cnt <= 2 + r_payload && r_type == 2) 
        ro_cap_speed <= {ro_cap_speed [15 : 0] ,ri_cmd_data} ; //串并转换      
    else
        ro_cap_speed <= ro_cap_speed ;
end

二、AD驱动模块AD7606_drive

特点 :
					1.同步采样
					2.模拟通道数  :8
					3.分辨率 : 16 bit , 5V / 2的16次方 = 0.00007V 理论值 1 2
					4.有效位数 ENOB : 真正的分辨率 ,16 bit - 3~4  = 13bit 左右
					5.数字量输出形式 : 二进制补码
FPGA控制引脚:
				1.PAR / SER / BYTE SEL : 并行 、串行 、字节选择 ,本项目使用并行 ,设置为0
				2.STBY :睡眠控制 , 0电平睡眠
				3.CONVST A/B :驱动ADC模拟信号控制引脚,A控制第一半,B控制高一半
				4.RESET : 复位,高有效,持续50ns以上
				5.RD:读数据控制信号
				6.BUSY :繁忙指示信号
				6.CS: 片选信号
				7.FRSTDATA :第一通道指示信号
				8.DB0~DB15:读数据通道
时序图:

1

  1. t reset 需要50ns,状态机设置r_st_cnt == 10 ,一共200ns
    2
  2. CONSVT同时拉低,手册上说CONSVT A 和CONVST B之间上升沿相差最大为 0.5ms
    在这里2图片描述
  3. CONSVT 后大于40ns才能拉高 busy,状态机设置r_st_cnt >= 10 ,然后读busy状态再调到读状态。
    在这里插入图片描述

4.busy拉低了之后可以立刻拉低CS,就是读状态了。

1

读状态的时候就可以产生RD信号了,CS拉低后RD不需要延时,另外,由于RD需要接受8bit,需要计数器计数16,翻转状态下降沿的时候输入输出数据,上升沿读数据。
在这里插入图片描述
5.读完数据等待触发,等待时间用T cycle - T cony - 16*20ns = 5us - 3.45 us - 0.32 us =1.23us 等于 1230ns 也就是至少计数62个周期。

使用状态机,构建上面所示的信号图。

always@(*)
begin
   case(r_st_current)
        P_ST_RESET  : r_st_next = r_st_cnt == 10                ? P_ST_CONSVT   :  P_ST_RESET   ;//手册上持续50ns就行,这里一个时钟20ns,算够了200ns
        P_ST_CONSVT : r_st_next = ri_user_ctrl & ((!ri_trig_mode) ||(ri_trig_mode && ri_extrig[2]  &&  ri_extrig[1]))      
                      ? P_ST_BUSY     : P_ST_CONSVT   ;//(!ri_trig_mode)自触发就直接执行,外部触发就看ri_extrig是不是高
        P_ST_BUSY   : r_st_next = r_st_cnt >= 10 & !ri_ad_busy  ? P_ST_READ     : P_ST_BUSY     ;//要求是consvt后大于40ns才能拉高,等待200ns后才读busy状态
        P_ST_READ   : r_st_next = r_st_cnt == 16 - 1            ? P_ST_WAIT     : P_ST_READ     ;
        P_ST_WAIT   : r_st_next = r_st_cnt == ri_cap_speed      ? P_ST_CONSVT   : P_ST_WAIT     ;//手册上是5us,时钟是50Mhz,一个周期就是20ns,5除以0.02等于250,减去上面用25,留余量设置成230,,
        default     : r_st_next = P_ST_RESET                    ;
   endcase 
end
//触发模式寄存器ri_trig_mode
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ri_trig_mode <= 'd0;
    else
        ri_trig_mode <= i_trig_mode;//阈值限制,最小就是230


end

数据读入代码设计

//通道标识
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_user_channel <= 'd0;
    else if(r_st_current == P_ST_CONSVT)
        ro_user_channel <= 'd0;
    else if(ro_ad_rd && !ro_ad_rd_1d)
        ro_user_channel <= ro_user_channel + 1;
    else 
        ro_user_channel <= ro_user_channel;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_user_data_1 <= 'd0;
    else if(ro_ad_rd && !ro_ad_rd_1d && ro_user_channel == 0)
        ro_user_data_1 <= i_ad_data;
    else    
        ro_user_data_1 <= 'd0;
end
设计小技巧

1.外部触发信号输入进来需要打拍处理

//外部触发打拍ri_extig
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ri_extrig <= 'd0;
    else
        ri_extrig <= {ri_extrig[2:0],i_extrig};//阈值限制,最小就是230
end

2.ad7606有过采样功能,所谓过采样就是在单位时间内多采样几个点,然后他会取平均值,通过osc引脚控制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值