差别
这里会显示出您选择的修订版和当前版本之间的差别。
后一修订版 | 前一修订版 | ||
dac数模转换模块 [2017/06/30 10:33] anran 创建 |
dac数模转换模块 [2020/01/18 21:41] (当前版本) gongyu |
||
---|---|---|---|
行 1: | 行 1: | ||
- | ======基于STEP FPGA的PCF8591的ADC(I2C)功能驱动====== | + | ### 基于STEP FPGA的PCF8591的DAC(I2C)功能驱动 |
- | 本节将和大家一起使用FPGA驱动底板上的PCF8591的ADC采样(I2C)功能。 | + | 本节将和大家一起使用FPGA驱动底板上的PCF8591的DAC转换(I2C)功能。 |
+ | --- | ||
+ | #### 硬件说明 | ||
- | ====硬件说明==== | ||
- | ------- | ||
PCF8591是集成了4路ADC和1路DAC的芯片,使用I2C总线通信。 | PCF8591是集成了4路ADC和1路DAC的芯片,使用I2C总线通信。 | ||
\\ | \\ | ||
行 17: | 行 17: | ||
{{ :pcf8591_i2c地址.jpg?800 |}} | {{ :pcf8591_i2c地址.jpg?800 |}} | ||
\\ | \\ | ||
- | PCF8591集成了很多功能,当需要不同的功能时要对PCF8591做相应的配置,配置数据存储在名为CONTROL BYTE的寄存器中,下图展示了寄存器中部分bit的功能,详细请参考PCF8591的datasheet,本设计中我们只使用通道1的ADC功能,配置数据为8'h01。 | + | PCF8591集成了很多功能,当需要不同的功能时要对PCF8591做相应的配置,配置数据存储在名为CONTROL BYTE的寄存器中,下图展示了寄存器中部分bit的功能,详细请参考PCF8591的datasheet,本设计中我们只使用DAC功能,配置数据为8'h40。 |
{{ :pcf8591_控制字.jpg?800 |}} | {{ :pcf8591_控制字.jpg?800 |}} | ||
\\ | \\ | ||
- | 本设计中我们需要两次通信, | + | 本设计中我们需要的通信过程具体为:开始--写寻址--读响应--写配置数据--读响应--[写DAC数据--读响应]循环--结束 |
- | * 第一次为配置数据,具体为:开始--写寻址--读响应--写配置数据--读响应--结束 | + | {{ :pcf8591_dac时序.jpg?1000 |}} |
- | * 第二次为读ADC数据,具体为:开始--读寻址--读响应--[读ADC数据--写响应--]循环读 | + | |
- | 第二次的时序如下图: | + | |
- | {{ :pcf8591_adc时序.jpg?1000 |}} | + | |
\\ | \\ | ||
- | 通过上面的介绍大家应该对如何驱动PCF8591进行ADC采样有了整体的概念,还有一些细节就是I2C通信的时序明细,如下图 | + | 通过上面的介绍大家应该对如何驱动PCF8591进行DAC采样有了整体的概念,还有一些细节就是I2C通信的时序明细,如下图 |
{{ :pcf8591_时序控制.jpg?800 |}} | {{ :pcf8591_时序控制.jpg?800 |}} | ||
{{ :pcf8591_时序控制2.jpg?800 |}} | {{ :pcf8591_时序控制2.jpg?800 |}} | ||
- | ====Verilog代码==== | + | --- |
- | ------ | + | #### Verilog代码 |
<code verilog> | <code verilog> | ||
// -------------------------------------------------------------------- | // -------------------------------------------------------------------- | ||
// >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<< | // >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<< | ||
// -------------------------------------------------------------------- | // -------------------------------------------------------------------- | ||
- | // Module: ADC_I2C | + | // Module: DAC_I2C |
// | // | ||
// Author: Step | // Author: Step | ||
// | // | ||
- | // Description: ADC_I2C | + | // Description: DAC_I2C |
// | // | ||
// Web: www.stepfpga.com | // Web: www.stepfpga.com | ||
行 50: | 行 47: | ||
// V1.1 |2016/10/30 |Initial ver | // V1.1 |2016/10/30 |Initial ver | ||
// -------------------------------------------------------------------- | // -------------------------------------------------------------------- | ||
- | module ADC_I2C | + | module DAC_I2C |
( | ( | ||
input clk_in, //系统时钟 | input clk_in, //系统时钟 | ||
input rst_n_in, //系统复位,低有效 | input rst_n_in, //系统复位,低有效 | ||
+ | |||
+ | output reg dac_done, //DAC采样完成标志 | ||
+ | input [7:0] dac_data, //DAC采样数据 | ||
+ | |||
output scl_out, //I2C总线SCL | output scl_out, //I2C总线SCL | ||
- | inout sda_out, //I2C总线SDA | + | inout sda_out //I2C总线SDA |
- | output reg adc_done, //ADC采样完成标志 | + | |
- | output reg [7:0] adc_data //ADC采样数据 | + | |
); | ); | ||
行 66: | 行 65: | ||
localparam START = 3'd2; | localparam START = 3'd2; | ||
localparam WRITE = 3'd3; | localparam WRITE = 3'd3; | ||
- | localparam READ = 3'd4; | + | localparam STOP = 3'd4; |
- | localparam STOP = 3'd5; | + | |
//根据PCF8591的datasheet,I2C的频率最高为100KHz, | //根据PCF8591的datasheet,I2C的频率最高为100KHz, | ||
行 90: | 行 88: | ||
reg sda_out_r; | reg sda_out_r; | ||
reg [2:0] cnt; | reg [2:0] cnt; | ||
- | reg [3:0] cnt_main; | + | reg [2:0] cnt_main; |
reg [7:0] data_wr; | reg [7:0] data_wr; | ||
reg [2:0] cnt_start; | reg [2:0] cnt_start; | ||
reg [2:0] cnt_write; | reg [2:0] cnt_write; | ||
- | reg [4:0] cnt_read; | ||
reg [2:0] cnt_stop; | reg [2:0] cnt_stop; | ||
reg [2:0] state; | reg [2:0] state; | ||
行 103: | 行 100: | ||
sda_out_r <= 1'd1; | sda_out_r <= 1'd1; | ||
cnt <= 1'b0; | cnt <= 1'b0; | ||
- | cnt_main <= 4'd0; | + | cnt_main <= 1'b0; |
- | cnt_start <= 3'd0; | + | cnt_start <= 1'b0; |
cnt_write <= 3'd0; | cnt_write <= 3'd0; | ||
- | cnt_read <= 5'd0; | ||
cnt_stop <= 1'd0; | cnt_stop <= 1'd0; | ||
- | adc_done <= 1'b0; | + | dac_done <= 1'b1; |
- | adc_data <= 1'b0; | + | |
state <= IDLE; | state <= IDLE; | ||
end else begin | end else begin | ||
行 117: | 行 112: | ||
sda_out_r <= 1'd1; | sda_out_r <= 1'd1; | ||
cnt <= 1'b0; | cnt <= 1'b0; | ||
- | cnt_main <= 4'd0; | + | cnt_main <= 1'b0; |
- | cnt_start <= 3'd0; | + | cnt_start <= 1'b0; |
cnt_write <= 3'd0; | cnt_write <= 3'd0; | ||
- | cnt_read <= 5'd0; | ||
cnt_stop <= 1'd0; | cnt_stop <= 1'd0; | ||
- | adc_done <= 1'b0; | + | dac_done <= 1'b1; |
state <= MAIN; | state <= MAIN; | ||
end | end | ||
MAIN:begin | MAIN:begin | ||
- | if(cnt_main >= 4'd6) cnt_main <= 4'd6; //对MAIN中的子状态执行控制cnt_main | + | if(cnt_main >= 3'd3) cnt_main <= 3'd3; //对MAIN中的子状态执行控制cnt_main |
else cnt_main <= cnt_main + 1'b1; | else cnt_main <= cnt_main + 1'b1; | ||
case(cnt_main) | case(cnt_main) | ||
- | 4'd0: begin state <= START; end //I2C通信时序中的START | + | 3'd0: begin state <= START; end //I2C通信时序中的START |
- | 4'd1: begin data_wr <= 8'h90; state <= WRITE; end //A0,A1,A2都接了GND,写地址为8'h90 | + | 3'd1: begin data_wr <= 8'h90; state <= WRITE; end //A0,A1,A2都接了GND,写地址为8'h90 |
- | 4'd2: begin data_wr <= 8'h00; state <= WRITE; end //control byte为8'h00,采用4通道ADC中的通道0 | + | 3'd2: begin data_wr <= 8'h40; state <= WRITE; end //control byte为8'h40,打开DAC功能 |
- | 4'd3: begin state <= STOP; end //I2C通信时序中的START | + | 3'd3: begin data_wr <= dac_data; state <= WRITE; dac_done <= 1'b0; end //需要进行DAC转换的数据 |
- | 4'd4: begin state <= START; end //I2C通信时序中的STOP | + | 3'd4: begin state <= STOP; end //I2C通信时序中的结束STOP |
- | 4'd5: begin data_wr <= 8'h91; state <= WRITE; end //A0 A1 A2都接了GND,读地址为8'h91 | + | |
- | 4'd6: begin state <= READ; adc_done <= 1'b0; end //读取ADC的采样数据 | + | |
- | 4'd7: begin state <= STOP; adc_done <= 1'b1; end //I2C通信时序中的STOP,读取完成标志 | + | |
- | 4'd8: begin state <= MAIN; end //预留状态,不执行 | + | |
default: state <= IDLE; //如果程序失控,进入IDLE自复位状态 | default: state <= IDLE; //如果程序失控,进入IDLE自复位状态 | ||
endcase | endcase | ||
行 169: | 行 159: | ||
3'd3: begin scl_out_r <= 1'b0; end //SCL拉低,准备发送下1bit的数据 | 3'd3: begin scl_out_r <= 1'b0; end //SCL拉低,准备发送下1bit的数据 | ||
//获取从设备的响应信号并判断 | //获取从设备的响应信号并判断 | ||
- | 3'd4: begin sda_out_r <= 1'bz; end //释放SDA线,准备接收从设备的响应信号 | + | 3'd4: begin sda_out_r <= 1'bz; dac_done <= 1'b1; end //释放SDA线,准备接收从设备的响应信号 |
3'd5: begin scl_out_r <= 1'b1; end //SCL拉高,保持4.0us以上 | 3'd5: begin scl_out_r <= 1'b1; end //SCL拉高,保持4.0us以上 | ||
3'd6: begin if(sda_out) state <= IDLE; else state <= state; end //获取从设备的响应信号并判断 | 3'd6: begin if(sda_out) state <= IDLE; else state <= state; end //获取从设备的响应信号并判断 | ||
- | 3'd7: begin scl_out_r <= 1'b0; state <= MAIN; end //SCL拉低,返回MAIN状态 | ||
- | default: state <= IDLE; //如果程序失控,进入IDLE自复位状态 | ||
- | endcase | ||
- | end | ||
- | READ:begin //I2C通信时序中的读操作READ和返回ACK的操作 | ||
- | if(cnt <= 3'd6) begin //共需要接收8bit的数据,这里控制循环的次数 | ||
- | if(cnt_read >= 3'd3) begin cnt_read <= 1'b0; cnt <= cnt + 1'b1; end | ||
- | else begin cnt_read <= cnt_read + 1'b1; cnt <= cnt; end | ||
- | end else begin | ||
- | if(cnt_read >= 3'd7) begin cnt_read <= 1'b0; cnt <= 1'b0; end //两个变量都恢复初值 | ||
- | else begin cnt_read <= cnt_read + 1'b1; cnt <= cnt; end | ||
- | end | ||
- | case(cnt_read) | ||
- | //按照I2C的时序接收数据 | ||
- | 3'd0: begin scl_out_r <= 1'b0; sda_out_r <= 1'bz; end //SCL拉低,释放SDA线,准备接收从设备数据 | ||
- | 3'd1: begin scl_out_r <= 1'b1; end //SCL拉高,保持4.0us以上 | ||
- | 3'd2: begin adc_data_r[7-cnt] <= sda_out; end //读取从设备返回的数据 | ||
- | 3'd3: begin scl_out_r <= 1'b0; end //SCL拉低,准备接收下1bit的数据 | ||
- | //向从设备发送响应信号 | ||
- | 3'd4: begin sda_out_r <= 1'b0; adc_done <= 1'b1; adc_data <= adc_data_r; end //发送响应信号,将前面接收的数据锁存 | ||
- | 3'd5: begin scl_out_r <= 1'b1; end //SCL拉高,保持4.0us以上 | ||
- | 3'd6: begin scl_out_r <= 1'b1; adc_done <= 1'b0; end //SCL拉高,保持4.0us以上 | ||
3'd7: begin scl_out_r <= 1'b0; state <= MAIN; end //SCL拉低,返回MAIN状态 | 3'd7: begin scl_out_r <= 1'b0; state <= MAIN; end //SCL拉低,返回MAIN状态 | ||
default: state <= IDLE; //如果程序失控,进入IDLE自复位状态 | default: state <= IDLE; //如果程序失控,进入IDLE自复位状态 | ||
行 222: | 行 190: | ||
</code> | </code> | ||
+ | --- | ||
+ | #### 小结 | ||
- | ====小结==== | + | 本节主要为大家讲解了使用I2C驱动PCF8591的DAC功能的原理及软件设计,需要大家掌握的同时自己创建工程,通过整个设计流程,生成FPGA配置文件加载测试。 |
- | ------ | + | |
- | 本节主要为大家讲解了使用I2C驱动PCF8591的ADC功能的原理及软件设计,需要大家掌握的同时自己创建工程,通过整个设计流程,生成FPGA配置文件加载测试。 | + | |
\\ | \\ | ||
如果你对Diamond软件的使用不了解,请参考这里:[[lattice_diamond的使用|Diamond的使用]]。 | 如果你对Diamond软件的使用不了解,请参考这里:[[lattice_diamond的使用|Diamond的使用]]。 | ||
- | ====相关资料==== | + | --- |
- | ------ | + | #### 相关资料 |
\\ | \\ | ||
- | 使用[[STEP-MXO2第二代]]的PCF8591的ADC驱动程序: 后续会有下载连接 待更新 | + | 使用[[STEP-MXO2第二代]]的PCF8591的DAC驱动程序: 后续会有下载连接 待更新 |
\\ | \\ | ||
- | 使用[[STEP-MAX10]]的PCF8591的ADC驱动程序: 后续会有下载连接 待更新 | + | 使用[[STEP-MAX10]]的PCF8591的DAC驱动程序: 后续会有下载连接 待更新 |
\\ | \\ |