差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

后一修订版
前一修订版
dac数模转换模块 [2017/06/30 10:33]
anran 创建
dac数模转换模块 [2022/07/20 10:24] (当前版本)
zhijun [====小结====]
行 1: 行 1:
-======基于STEP FPGA的PCF8591的ADC(I2C)功能驱动======+======基于STEP FPGA的PCF8591的DAC(I2C)功能驱动======
  
-本节将和大家一起使用FPGA驱动底板上的PCF8591的ADC采样(I2C)功能。+本节将和大家一起使用FPGA驱动底板上的PCF8591的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 |}}
行 36: 行 33:
 // >>>>>>>>>>>>>>>>>>>>>>>>>​ 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自复位状态
行 225: 行 193:
 ====小结==== ====小结====
 ------ ------
-本节主要为大家讲解了使用I2C驱动PCF8591的ADC功能的原理及软件设计,需要大家掌握的同时自己创建工程,通过整个设计流程,生成FPGA配置文件加载测试。+本节主要为大家讲解了使用I2C驱动PCF8591的DAC功能的原理及软件设计,需要大家掌握的同时自己创建工程,通过整个设计流程,生成FPGA配置文件加载测试。
 \\ \\
-如果你对Diamond软件的使用不了解,请参考这里:[[lattice_diamond的使用|Diamond的使用]]。+如果你对Diamond软件的使用不了解,请参考这里:[[lattice_fpga|Diamond的使用]]。
  
 ====相关资料==== ====相关资料====
 ------ ------
 \\ \\
-使用[[STEP-MXO2第二代]]的PCF8591的ADC驱动程序: ​ 后续会有下载连接 ​ 待更新+使用[[STEP-MXO2第二代]]的PCF8591的DAC驱动程序: ​ 后续会有下载连接 ​ 待更新
 \\ \\
-使用[[STEP-MAX10]]的PCF8591的ADC驱动程序: ​ 后续会有下载连接 ​ 待更新+使用[[STEP-MAX10]]的PCF8591的DAC驱动程序: ​ 后续会有下载连接 ​ 待更新
 \\ \\