1. ads8688芯片简介
芯片详细介绍可仔细查看数据手册,链接:
由于数据手册内容太多,在次不做过多介绍,此处将只对实现8通道的扫描采集所涉及到的知识点做解释说明,大概需掌握如下3点。
1.1 程序寄存器配置
程序寄存器映射图如下所示。16位的程序寄存器可设置0~7通道的电压范围及其他内容,可直接将16位的数据(已含地址)写入芯片。
采集通道电压范围定义如下。
1.2 命令寄存器
命令寄存器可配置为自动扫描模数、手动扫描模数等其他模数。
1.3 时序图
详细时序图满足如下要求即可。
1.4 程序设计思路
1. 配置程序寄存器,将0~7通道的电压范围写入程序寄存器
2. 配置命令寄存器,选择自动扫描模数,先写入16'hA000,选择自动从0通道开始采集,后续写入16'h0000表示继续自动扫描至1通道一次类推。
值得注意的一点是:32个时钟为一次读写完整周期,在配置自动选择模式时,当第一次32个时钟周期写入16'hA000选择自动模式后,应在第二次32个时钟周期的后16个时钟周期读取出采集的数据。
2. 工程在线调试结果
3.程序列表
4.PLL调用设置
5.详细代码
5.1顶层模块代码
module TopModule(
input ExtClk,
input ExtRstN,
input SDO,
output SDI,
output CS_N,
output SCLK);
//
Ads8688 UUTAds8688(
.CLK100M(CLK100M),//100M
.RST_N(RST_N),
.SCLK(SCLK),//10M
.CS_N(CS_N),
.SDI(SDI),
.SDO(SDO));
//
PllClk UUTPllClk
(
// Clock out ports
.clk_out1(CLK100M), // output clk_out1
// Status and control signals
.reset(~ExtRstN), // input reset
.locked(RST_N), // output locked
// Clock in ports
.clk_in1(ExtClk)); // input clk_in1
endmodule
5.2.Ads8688模块代码
//SPI通信协议
//[2:0]RangeChn 101 Vref = 4.096V
// 000表示±2.5Vref;001表示±1.25Vref;010表示0.625Vref;101表示0~2.5Vref;110表示0~1.25Vref
//101表示选中0~10.24V;0001h~ffffh 156.25uV
//0000:0 0001:156.25
//顺序:先配置程序寄存器,再配置命令寄存器
//程序寄存器:各个通道的电压范围配置
//命令寄存器:模式选择、通道选择
module Ads8688(
input CLK100M,//100M
input RST_N,
output reg SCLK,//10M
output reg CS_N,
output reg SDI,
input SDO);
//命令寄存器命令字
parameter AutoRst = 16'hA000;//自动扫描通道
//程序寄存器
parameter RangeChn = 3'b101;//0~10.24V
parameter WriteEn = 1'b1;
parameter ReadEn = 1'b0;
parameter Ch0InRange = {7'h05,WriteEn,5'd0,RangeChn};
parameter Ch1InRange = {7'h06,WriteEn,5'd0,RangeChn};
parameter Ch2InRange = {7'h07,WriteEn,5'd0,RangeChn};
parameter Ch3InRange = {7'h08,WriteEn,5'd0,RangeChn};
parameter Ch4InRange = {7'h09,WriteEn,5'd0,RangeChn};
parameter Ch5InRange = {7'h0A,WriteEn,5'd0,RangeChn};
parameter Ch6InRange = {7'h0B,WriteEn,5'd0,RangeChn};
parameter Ch7InRange = {7'h0C,WriteEn,5'd0,RangeChn};
//[17:0]Cnt2ms
reg [17:0]Cnt2ms;
always@(posedge CLK100M or negedge RST_N)
if(RST_N == 1'b0) Cnt2ms <= 'd0;
else if(Cnt2ms == 'd200) Cnt2ms <= 'd200;
else Cnt2ms <= Cnt2ms + 1'b1;
//ConfigureStage 配置阶段(程序寄存器)
reg ConfigureStage;
always@(posedge CLK100M or negedge RST_N)
if(RST_N == 1'b0) ConfigureStage <= 1'b0;
else if(Cnt2ms == 'd199) ConfigureStage <= 1'b1;//2ms启动配置
else if(CntCsNegedge == 'd8 && CntSclkPosedge == 'd33) ConfigureStage <= 1'b0;//配置结束
else;
//ConfigureStageOver
reg ConfigureStageOver;
always@(posedge CLK100M or negedge RST_N)
if(RST_N == 1'b0) ConfigureStageOver <= 1'b0;
else if(CntCsNegedge == 'd8 && CntSclkPosedge == 'd33) ConfigureStageOver <= 1'b1;
else if(Cnt5ms == 'd500) ConfigureStageOver <= 1'b0;
else;
//[18:0]Cnt5ms
reg [18:0]Cnt5ms;
always@(posedge CLK100M or negedge RST_N)
if(RST_N == 1'b0) Cnt5ms <= 'd0;
else if(Cnt5ms == 'd500) Cnt5ms <= 'd500;
else if(ConfigureStageOver == 1'b1) Cnt5ms <= Cnt5ms + 1'b1;
else;
//OperationStage 操作阶段(命令寄存器)
reg OperationStage;
always@(posedge CLK100M or negedge RST_N)
if(RST_N == 1'b0) OperationStage <= 1'b0;
else if(Cnt5ms == 'd499) OperationStage <= 1'b1;
else;
//CS_N
always@(posedge CLK100M or negedge RST_N)
if(RST_N == 1'b0) CS_N <= 1'b1;
else if(CntSclkPosedge == 'd33) CS_N <= 1'b1;
else if(ConfigureStage || OperationStage) CS_N <= 1'b0;
else;
//[5:0]Cnt50 SCLK 1M 50翻转
reg [5:0]Cnt50;
always@(posedge CLK100M or negedge RST_N)
if(RST_N == 1'b0) Cnt50 <= 'd0;
else if(Cnt50 == 'd49 || CS_N == 1'b1) Cnt50 <= 'd0;
else if(ConfigureStage || OperationStage) Cnt50 <= Cnt50 + 1'b1;
else;
//SCLK
always@(posedge CLK100M or negedge RST_N)
if(RST_N == 1'b0) SCLK <= 1'b0;
else if(CS_N == 1'b1) SCLK <= 1'b0;
else if(Cnt50 == 'd49) SCLK <= ~SCLK;
else;
//
reg SclkReg;
always@(posedge CLK100M)
SclkReg <= SCLK;
//SclkPosedgeFlag SclkNegedgeFlag
wire SclkPosedgeFlag;
wire SclkNegedgeFlag;
assign SclkPosedgeFlag = (SCLK == 1'b1 && SclkReg == 1'b0) ? 1'b1:1'b0;
assign SclkNegedgeFlag = (SCLK == 1'b0 && SclkReg == 1'b1) ? 1'b1:1'b0;
//[12:0]Cnt30us 配置阶段CS拉高时间
reg [12:0]Cnt30us;
always@(posedge CLK100M or negedge RST_N)
if(RST_N == 1'b0) Cnt30us <= 'd0;
else if(CntSclkPosedge == 'd33) Cnt30us <= Cnt30us + 1'b1;
else Cnt30us <= 'd0;
//CsReg
reg CsReg;
always@(posedge CLK100M)
CsReg <= CS_N;
//CsNegedgeFlag
wire CsNegedgeFlag;
assign CsNegedgeFlag = (CsReg == 1'b1 && CS_N == 1'b0) ? 1'b1:1'b0;
//[3:0]CntCsNegedge 配置阶段
reg [3:0]CntCsNegedge;
always@(posedge CLK100M or negedge RST_N)
if(RST_N == 1'b0) CntCsNegedge <= 'd0;
else if(ConfigureStage && CntCsNegedge == 'd8 && CntSclkPosedge == 'd33) CntCsNegedge <= 'd0;
else if(OperationStage && CntCsNegedge == 'd9 && CntSclkPosedge == 'd33) CntCsNegedge <= 'd1;
else if(CsNegedgeFlag && (ConfigureStage || OperationStage)) CntCsNegedge <= CntCsNegedge + 1'b1;
else;
//[5:0]CntSclkPosedge
reg [5:0]CntSclkPosedge;
always@(posedge CLK100M or negedge RST_N)
if(RST_N == 1'b0) CntSclkPosedge <= 'd0;
else if(CntSclkPosedge == 'd33 && Cnt30us == 'd3000) CntSclkPosedge <= 'd0;
else if(SclkPosedgeFlag == 1'b1) CntSclkPosedge <= CntSclkPosedge + 1'b1;
else;
//[5:0]CntSclkNegedge
reg [5:0]CntSclkNegedge;
always@(posedge CLK100M or negedge RST_N)
if(RST_N == 1'b0) CntSclkNegedge <= 'd0;
else if(CS_N == 1'b1) CntSclkNegedge <= 'd0;
else if(SclkNegedgeFlag == 1'b1) CntSclkNegedge <= CntSclkNegedge + 1'b1;
else;
//SDI
always@(posedge CLK100M or negedge RST_N)
if(RST_N == 1'b0) SDI <= 1'bz;
else if(ConfigureStage == 1'b1 && (CntSclkPosedge > 'd0 && CntSclkPosedge < 'd17) &&
(CntCsNegedge >= 'd1 && CntCsNegedge <= 'd8)) SDI <= ProgramRegister['d16 - CntSclkPosedge];
else if(OperationStage == 1'b1 && (CntSclkPosedge > 'd0 && CntSclkPosedge < 'd17) &&
(CntCsNegedge >= 'd1 && CntCsNegedge <= 'd9)) SDI <= CommandRegister['d16 - CntSclkPosedge];
else SDI <= 1'bz;
//[15:0]ProgramRegister
//[15:0]CommandRegister
reg [15:0]ProgramRegister;
reg [15:0]CommandRegister;
always@(posedge CLK100M or negedge RST_N)
if(RST_N == 1'b0)begin
ProgramRegister <= 16'h0000;
CommandRegister <= 16'h0000;
end
else if(ConfigureStage == 1'b1)begin
case(CntCsNegedge)
'd1:ProgramRegister <= Ch0InRange;
'd2:ProgramRegister <= Ch1InRange;
'd3:ProgramRegister <= Ch2InRange;
'd4:ProgramRegister <= Ch3InRange;
'd5:ProgramRegister <= Ch4InRange;
'd6:ProgramRegister <= Ch5InRange;
'd7:ProgramRegister <= Ch6InRange;
'd8:ProgramRegister <= Ch7InRange;
default;
endcase
end
else if(OperationStage == 1'b1 && CntCsNegedge == 'd1) CommandRegister <= AutoRst;
else if(OperationStage == 1'b1 && CntCsNegedge > 'd1) CommandRegister <= 16'h0000;
else;
//[15:0]TempMem1[7:0] 瞬态采集脉冲幅值 每25us变化一次
reg [15:0]TempMem1[7:0];
always@(posedge CLK100M or negedge RST_N)
if(RST_N == 1'b0)begin
TempMem1[0] <= 16'h0000; TempMem1[1] <= 16'h0000;
TempMem1[2] <= 16'h0000; TempMem1[3] <= 16'h0000;
TempMem1[4] <= 16'h0000; TempMem1[5] <= 16'h0000;
TempMem1[6] <= 16'h0000; TempMem1[7] <= 16'h0000;
end
else if(OperationStage == 1'b1 && CntCsNegedge == 'd2 && Cnt50 == 'd25 && SCLK == 1'b1)begin//Ch0
case(CntSclkPosedge)
'd17:TempMem1[0][15] <= SDO;
'd18:TempMem1[0][14] <= SDO;
'd19:TempMem1[0][13] <= SDO;
'd20:TempMem1[0][12] <= SDO;
'd21:TempMem1[0][11] <= SDO;
'd22:TempMem1[0][10] <= SDO;
'd23:TempMem1[0][9] <= SDO;
'd24:TempMem1[0][8] <= SDO;
'd25:TempMem1[0][7] <= SDO;
'd26:TempMem1[0][6] <= SDO;
'd27:TempMem1[0][5] <= SDO;
'd28:TempMem1[0][4] <= SDO;
'd29:TempMem1[0][3] <= SDO;
'd30:TempMem1[0][2] <= SDO;
'd31:TempMem1[0][1] <= SDO;
'd32:TempMem1[0][0] <= SDO;
default;
endcase
end
else if(OperationStage == 1'b1 && CntCsNegedge == 'd3 && Cnt50 == 'd25 && SCLK == 1'b1)begin//Ch1
case(CntSclkPosedge)
'd17:TempMem1[1][15] <= SDO;
'd18:TempMem1[1][14] <= SDO;
'd19:TempMem1[1][13] <= SDO;
'd20:TempMem1[1][12] <= SDO;
'd21:TempMem1[1][11] <= SDO;
'd22:TempMem1[1][10] <= SDO;
'd23:TempMem1[1][9] <= SDO;
'd24:TempMem1[1][8] <= SDO;
'd25:TempMem1[1][7] <= SDO;
'd26:TempMem1[1][6] <= SDO;
'd27:TempMem1[1][5] <= SDO;
'd28:TempMem1[1][4] <= SDO;
'd29:TempMem1[1][3] <= SDO;
'd30:TempMem1[1][2] <= SDO;
'd31:TempMem1[1][1] <= SDO;
'd32:TempMem1[1][0] <= SDO;
default;
endcase
end
else if(OperationStage == 1'b1 && CntCsNegedge == 'd4 && Cnt50 == 'd25 && SCLK == 1'b1)begin//Ch2
case(CntSclkPosedge)
'd17:TempMem1[2][15] <= SDO;
'd18:TempMem1[2][14] <= SDO;
'd19:TempMem1[2][13] <= SDO;
'd20:TempMem1[2][12] <= SDO;
'd21:TempMem1[2][11] <= SDO;
'd22:TempMem1[2][10] <= SDO;
'd23:TempMem1[2][9] <= SDO;
'd24:TempMem1[2][8] <= SDO;
'd25:TempMem1[2][7] <= SDO;
'd26:TempMem1[2][6] <= SDO;
'd27:TempMem1[2][5] <= SDO;
'd28:TempMem1[2][4] <= SDO;
'd29:TempMem1[2][3] <= SDO;
'd30:TempMem1[2][2] <= SDO;
'd31:TempMem1[2][1] <= SDO;
'd32:TempMem1[2][0] <= SDO;
default;
endcase
end
else if(OperationStage == 1'b1 && CntCsNegedge == 'd5 && Cnt50 == 'd25 && SCLK == 1'b1)begin//Ch3
case(CntSclkPosedge)
'd17:TempMem1[3][15] <= SDO;
'd18:TempMem1[3][14] <= SDO;
'd19:TempMem1[3][13] <= SDO;
'd20:TempMem1[3][12] <= SDO;
'd21:TempMem1[3][11] <= SDO;
'd22:TempMem1[3][10] <= SDO;
'd23:TempMem1[3][9] <= SDO;
'd24:TempMem1[3][8] <= SDO;
'd25:TempMem1[3][7] <= SDO;
'd26:TempMem1[3][6] <= SDO;
'd27:TempMem1[3][5] <= SDO;
'd28:TempMem1[3][4] <= SDO;
'd29:TempMem1[3][3] <= SDO;
'd30:TempMem1[3][2] <= SDO;
'd31:TempMem1[3][1] <= SDO;
'd32:TempMem1[3][0] <= SDO;
default;
endcase
end
else if(OperationStage == 1'b1 && CntCsNegedge == 'd6 && Cnt50 == 'd25 && SCLK == 1'b1)begin//Ch4
case(CntSclkPosedge)
'd17:TempMem1[4][15] <= SDO;
'd18:TempMem1[4][14] <= SDO;
'd19:TempMem1[4][13] <= SDO;
'd20:TempMem1[4][12] <= SDO;
'd21:TempMem1[4][11] <= SDO;
'd22:TempMem1[4][10] <= SDO;
'd23:TempMem1[4][9] <= SDO;
'd24:TempMem1[4][8] <= SDO;
'd25:TempMem1[4][7] <= SDO;
'd26:TempMem1[4][6] <= SDO;
'd27:TempMem1[4][5] <= SDO;
'd28:TempMem1[4][4] <= SDO;
'd29:TempMem1[4][3] <= SDO;
'd30:TempMem1[4][2] <= SDO;
'd31:TempMem1[4][1] <= SDO;
'd32:TempMem1[4][0] <= SDO;
default;
endcase
end
else if(OperationStage == 1'b1 && CntCsNegedge == 'd7 && Cnt50 == 'd25 && SCLK == 1'b1)begin//Ch5
case(CntSclkPosedge)
'd17:TempMem1[5][15] <= SDO;
'd18:TempMem1[5][14] <= SDO;
'd19:TempMem1[5][13] <= SDO;
'd20:TempMem1[5][12] <= SDO;
'd21:TempMem1[5][11] <= SDO;
'd22:TempMem1[5][10] <= SDO;
'd23:TempMem1[5][9] <= SDO;
'd24:TempMem1[5][8] <= SDO;
'd25:TempMem1[5][7] <= SDO;
'd26:TempMem1[5][6] <= SDO;
'd27:TempMem1[5][5] <= SDO;
'd28:TempMem1[5][4] <= SDO;
'd29:TempMem1[5][3] <= SDO;
'd30:TempMem1[5][2] <= SDO;
'd31:TempMem1[5][1] <= SDO;
'd32:TempMem1[5][0] <= SDO;
default;
endcase
end
else if(OperationStage == 1'b1 && CntCsNegedge == 'd8 && Cnt50 == 'd25 && SCLK == 1'b1)begin//Ch6
case(CntSclkPosedge)
'd17:TempMem1[6][15] <= SDO;
'd18:TempMem1[6][14] <= SDO;
'd19:TempMem1[6][13] <= SDO;
'd20:TempMem1[6][12] <= SDO;
'd21:TempMem1[6][11] <= SDO;
'd22:TempMem1[6][10] <= SDO;
'd23:TempMem1[6][9] <= SDO;
'd24:TempMem1[6][8] <= SDO;
'd25:TempMem1[6][7] <= SDO;
'd26:TempMem1[6][6] <= SDO;
'd27:TempMem1[6][5] <= SDO;
'd28:TempMem1[6][4] <= SDO;
'd29:TempMem1[6][3] <= SDO;
'd30:TempMem1[6][2] <= SDO;
'd31:TempMem1[6][1] <= SDO;
'd32:TempMem1[6][0] <= SDO;
default;
endcase
end
else if(OperationStage == 1'b1 && CntCsNegedge == 'd9 && Cnt50 == 'd25 && SCLK == 1'b1)begin//Ch7
case(CntSclkPosedge)
'd17:TempMem1[7][15] <= SDO;
'd18:TempMem1[7][14] <= SDO;
'd19:TempMem1[7][13] <= SDO;
'd20:TempMem1[7][12] <= SDO;
'd21:TempMem1[7][11] <= SDO;
'd22:TempMem1[7][10] <= SDO;
'd23:TempMem1[7][9] <= SDO;
'd24:TempMem1[7][8] <= SDO;
'd25:TempMem1[7][7] <= SDO;
'd26:TempMem1[7][6] <= SDO;
'd27:TempMem1[7][5] <= SDO;
'd28:TempMem1[7][4] <= SDO;
'd29:TempMem1[7][3] <= SDO;
'd30:TempMem1[7][2] <= SDO;
'd31:TempMem1[7][1] <= SDO;
'd32:TempMem1[7][0] <= SDO;
default;
endcase
end
else;
//[15:0]Mem1[7:0]单次存储脉冲幅值
reg [15:0]Mem1[7:0];
always@(posedge CLK100M or negedge RST_N)
if(RST_N == 1'b0)begin
Mem1[0] <= 16'h0000; Mem1[1] <= 16'h0000;
Mem1[2] <= 16'h0000; Mem1[3] <= 16'h0000;
Mem1[4] <= 16'h0000; Mem1[5] <= 16'h0000;
Mem1[6] <= 16'h0000; Mem1[7] <= 16'h0000;
end
else if(TempMem1[0] > 'd640 && CntCsNegedge == 'd2 && CntSclkPosedge == 'd33) Mem1[0] <= TempMem1[0];
else if(TempMem1[1] > 'd640 && CntCsNegedge == 'd3 && CntSclkPosedge == 'd33) Mem1[1] <= TempMem1[1];
else if(TempMem1[2] > 'd640 && CntCsNegedge == 'd4 && CntSclkPosedge == 'd33) Mem1[2] <= TempMem1[2];
else if(TempMem1[3] > 'd640 && CntCsNegedge == 'd5 && CntSclkPosedge == 'd33) Mem1[3] <= TempMem1[3];
else if(TempMem1[4] > 'd640 && CntCsNegedge == 'd6 && CntSclkPosedge == 'd33) Mem1[4] <= TempMem1[4];
else if(TempMem1[5] > 'd640 && CntCsNegedge == 'd7 && CntSclkPosedge == 'd33) Mem1[5] <= TempMem1[5];
else if(TempMem1[6] > 'd640 && CntCsNegedge == 'd8 && CntSclkPosedge == 'd33) Mem1[6] <= TempMem1[6];
else if(TempMem1[7] > 'd640 && CntCsNegedge == 'd9 && CntSclkPosedge == 'd33) Mem1[7] <= TempMem1[7];
else;
endmodule