Experimental Manuals FPGA Tutor PRX100 Risc-V

digital-to-analog conversion: DAC, analog-to-digital conversion: ADC – Xilinx Risc-V Board Tutorial : AD, DA Experiment – FII-PRX100 FPGA Board Experiment 13

Experiment 13 AD, DA Experiment

1.Experiment Objective

Since in the real world, all naturally occurring signals are analog signals, and all that are read and processed in actual engineering are digital signals. There is a process of mutual conversion between natural and industrial signals (digital-to-analog conversion: DAC, analog-to-digital conversion: ADC). The purpose of this experiment is twofold:

  1. Learning the theory of AD conversion
  2. Read the value of AD acquisition from PCF8591, and convert the value obtained into actual value, display it with segment decoders

2.Experiment Requirement

Perform analog-to-digital conversion using the ADC port of the chip and display the collected voltage value through the segment decoders.

Board downloading verification for comparison

Introduction to PCF8591: The PCF8591 uses the IIC bus protocol to communicate with the controller (FPGA). Please refer to the previous experiment for the contents of the IIC bus protocol. The first four bits of the device address are 1001, and the last three bits are determined by the actual circuit connection (here the circuit is grounded, so the device address is 7’b1001000). The LSB is the read/write control signal. After sending the device address information and the read/write control word are done, the control word information is sent. The specific control word information is shown in Fig 13. 1.

Fig 13. 1 PCF8591 Control address

Here, the experiment uses the DIP switch (SW1, SW0) input channel as the AD acquisition input channel. Configure the control information as (8’h40). For more details, refer to the datasheet of PCF8591.

SW1,SW0 Channel Selection Collection Object
00 0 Photosensitive Resistor Voltage Value
01 1 Thermistor Voltage Value
10 2 Adjustable Voltage Value

3.Experiment Design

  1. Program design and review the top-down design method used before.
  2. The top-level entity is divided into three parts: the segment decoder driver part, the AD sampling part of the PCF and the IIC serial port driver part.

IIC serial driver part code is as follows:

module iic_com (

clk,rst_n,

data,

sw1,sw2,

scl,sda,

iic_done,

dis_data

);

input clk; // 50MHz

input rst_n;

input sw1,sw2;

inout scl;

inout sda;

output reg [7:0] dis_data=8’h00;

input [7:0] data ;

output reg iic_done =0 ;

reg [7:0] data_tep;

reg scl_link ;

 

reg [19:0] cnt_5ms ;

reg sw1_r,sw2_r;

reg[19:0] cnt_20ms;

always @ (posedge clk or negedge rst_n)

if(!rst_n) cnt_20ms <= 20’d0;

else cnt_20ms <= cnt_20ms+1’b1;

always @ (posedge clk or negedge rst_n)

if(!rst_n) begin

sw1_r <= 1’b1;

sw2_r <= 1’b1;

end

else if(cnt_20ms == 20’hfffff) begin

sw1_r <= sw1;

sw2_r <= sw2;

end

reg[2:0] cnt;

reg[8:0] cnt_delay;

reg scl_r;

reg [7:0] read_data_temp [15:0];

reg [11:0] dis_data_temp ;

always @ (posedge clk )

dis_data_temp<=read_data_temp[0]+read_data_temp[1]+read_data_temp[2]+read_data_temp[3]+read_data_temp[4]+read_data_temp[5]+read_data_temp[6]+read_data_temp[7]+read_data_temp[8]+read_data_temp[9]+read_data_temp[10]+read_data_temp[11]+read_data_temp[12]+read_data_temp[13]+read_data_temp[14]+read_data_temp[15];

 

always @ (posedge clk )

dis_data <= dis_data_temp>>4 ;

integer i;

always @ (posedge clk or negedge rst_n)

if(!rst_n) begin

for (i=0;i<16;i=i+1)

read_data_temp[i]<=8’h00;

end

else if (iic_done) begin

for (i=0;i<15;i=i+1)

read_data_temp[i+1]<=read_data_temp[i];

read_data_temp[0] <= read_data ;

end

else begin for (i=0;i<16;i=i+1)

read_data_temp[i]<=read_data_temp[i];

end

always @ (posedge clk or negedge rst_n)

if(!rst_n) cnt_delay <= 9’d0;

else if(cnt_delay == 9’d499) cnt_delay <= 9’d0;

else cnt_delay <= cnt_delay+1’b1;

always @ (posedge clk or negedge rst_n) begin

if(!rst_n) cnt <= 3’d5;

else begin

case (cnt_delay)

9’d124: cnt <= 3’d1; //cnt=1:scl

9’d249: cnt <= 3’d2; //cnt=2:scl

9’d374: cnt <= 3’d3; //cnt=3:scl

9’d499: cnt <= 3’d0; //cnt=0:scl

default: cnt<=3’d5;

endcase

end

end

`define SCL_POS (cnt==3’d0) //cnt=0:scl

`define SCL_HIG (cnt==3’d1) //cnt=1:scl

`define SCL_NEG (cnt==3’d2) //cnt=2:scl

`define SCL_LOW (cnt==3’d3) //cnt=3:scl

always @ (posedge clk or negedge rst_n)

if(!rst_n) data_tep <= 8’h00;

else data_tep<= data ; //

always @ (posedge clk or negedge rst_n)

if(!rst_n) scl_r <= 1’b0;

else if(cnt==3’d0) scl_r <= 1’b1; //scl

else if(cnt==3’d2) scl_r <= 1’b0; //scl

assign scl = scl_link?scl_r: 1’bz ;

`define DEVICE_READ {7’h48,1’b1}

`define DEVICE_WRITE {7’h48,1’b0}

`define WRITE_DATA 8’b1000_0001

`define BYTE_ADDR 8’b0000_0011

reg[7:0] db_r;

reg[7:0] read_data;

parameter IDLE = 4’d0;

parameter START1 = 4’d1;

parameter ADD1 = 4’d2;

parameter ACK1 = 4’d3;

parameter ADD2 = 4’d4;

parameter ACK2 = 4’d5;

parameter START2 = 4’d6;

parameter ADD3 = 4’d7;

parameter ACK3 = 4’d8;

parameter DATA = 4’d9;

parameter ACK4 = 4’d10;

parameter STOP1 = 4’d11;

parameter STOP2 = 4’d12;

reg[3:0] cstate;

reg sda_r;

reg sda_link;

reg[3:0] num;

always @ (posedge clk or negedge rst_n) begin

if(!rst_n) begin

cstate <= IDLE;

sda_r <= 1’b1;

scl_link <= 1’b1;

sda_link <= 1’b1;

num <= 4’d0;

read_data <= 8’b0000_0000;

cnt_5ms <=20’h00000 ;

iic_done<=1’b0 ;

end

else

case (cstate)

IDLE: begin

sda_link <= 1’b1;

scl_link <= 1’b1;

iic_done<=1’b0 ;

if(!sw1_r || !sw2_r) begin

db_r <= `DEVICE_WRITE;

cstate <= START1;

end

else cstate <= IDLE;

end

START1: begin

if(`SCL_HIG) begin

sda_link <= 1’b1;

sda_r <= 1’b0;

cstate <= ADD1;

num <= 4’d0;

end

else cstate <= START1;

end

ADD1: begin

if(`SCL_LOW) begin

if(num == 4’d8) begin

num <= 4’d0;

sda_r <= 1’b1;

sda_link <= 1’b0;

cstate <= ACK1;

end

else begin

cstate <= ADD1;

num <= num+1’b1;

case (num)

4’d0: sda_r <= db_r[7];

4’d1: sda_r <= db_r[6];

4’d2: sda_r <= db_r[5];

4’d3: sda_r <= db_r[4];

4’d4: sda_r <= db_r[3];

4’d5: sda_r <= db_r[2];

4’d6: sda_r <= db_r[1];

4’d7: sda_r <= db_r[0];

default: ;

endcase

// sda_r <= db_r[4’d7-num];

end

end

// else if(`SCL_POS) db_r <= {db_r[6:0],1’b0};

else cstate <= ADD1;

end

ACK1: begin

if(/*!sda*/`SCL_NEG) begin

cstate <= ADD2;

db_r <= {6’b0100_00,data_tep[1:0]};

end

else cstate <= ACK1;

end

ADD2: begin

if(`SCL_LOW) begin

if(num==4’d8) begin

num <= 4’d0;

sda_r <= 1’b1;

sda_link <= 1’b0;

cstate <= ACK2;

 

end

else begin

sda_link <= 1’b1;

num <= num+1’b1;

case (num)

4’d0: sda_r <= db_r[7];

4’d1: sda_r <= db_r[6];

4’d2: sda_r <= db_r[5];

4’d3: sda_r <= db_r[4];

4’d4: sda_r <= db_r[3];

4’d5: sda_r <= db_r[2];

4’d6: sda_r <= db_r[1];

4’d7: sda_r <= db_r[0];

default: ;

endcase

// sda_r <= db_r[4’d7-num];

cstate <= ADD2;

end

end

// else if(`SCL_POS) db_r <= {db_r[6:0],1’b0};

else cstate <= ADD2;

end

ACK2: begin

if(/*!sda*/`SCL_NEG) begin

if(!sw1_r) begin

cstate <= DATA;

db_r <= data_tep;

end

else if(!sw2_r) begin

db_r <= `DEVICE_READ;

cstate <= START2;

end

end

else cstate <= ACK2;

end

START2: begin

if(`SCL_LOW) begin

sda_link <= 1’b1;

sda_r <= 1’b1;

cstate <= START2;

end

else if(`SCL_HIG) begin

sda_r <= 1’b0;

cstate <= ADD3;

end

else cstate <= START2;

end

ADD3: begin

if(`SCL_LOW) begin

if(num==4’d8) begin

num <= 4’d0;

sda_r <= 1’b1;

sda_link <= 1’b0;

cstate <= ACK3;

end

else begin

num <= num+1’b1;

case (num)

4’d0: sda_r <= db_r[7];

4’d1: sda_r <= db_r[6];

4’d2: sda_r <= db_r[5];

4’d3: sda_r <= db_r[4];

4’d4: sda_r <= db_r[3];

4’d5: sda_r <= db_r[2];

4’d6: sda_r <= db_r[1];

4’d7: sda_r <= db_r[0];

default: ;

endcase

// sda_r <= db_r[4’d7-num];

cstate <= ADD3;

end

end

// else if(`SCL_POS) db_r <= {db_r[6:0],1’b0};

else cstate <= ADD3;

end

ACK3: begin

if(/*!sda*/`SCL_NEG) begin

cstate <= DATA;

sda_link <= 1’b0;

end

else cstate <= ACK3;

end

DATA: begin

if(!sw2_r) begin

if(num<=4’d7) begin

cstate <= DATA;

if(`SCL_HIG) begin

num <= num+1’b1;

case (num)

4’d0: read_data[7] <= sda;

4’d1: read_data[6] <= sda;

4’d2: read_data[5] <= sda;

4’d3: read_data[4] <= sda;

4’d4: read_data[3] <= sda;

4’d5: read_data[2] <= sda;

4’d6: read_data[1] <= sda;

4’d7: read_data[0] <= sda;

default: ;

endcase

// read_data[4’d7-num] <= sda;

end

// else if(`SCL_NEG) read_data <= {read_data[6:0],read_data[7]};

end

else if((`SCL_LOW) && (num==4’d8)) begin

num <= 4’d0;

cstate <= ACK4;

end

else cstate <= DATA;

end

else if(!sw1_r) begin

sda_link <= 1’b1;

if(num<=4’d7) begin

cstate <= DATA;

if(`SCL_LOW) begin

sda_link <= 1’b1;

num <= num+1’b1;

case (num)

4’d0: sda_r <= db_r[7];

4’d1: sda_r <= db_r[6];

4’d2: sda_r <= db_r[5];

4’d3: sda_r <= db_r[4];

4’d4: sda_r <= db_r[3];

4’d5: sda_r <= db_r[2];

4’d6: sda_r <= db_r[1];

4’d7: sda_r <= db_r[0];

default: ;

endcase

// sda_r <= db_r[4’d7-num];

end

// else if(`SCL_POS) db_r <= {db_r[6:0],1’b0};

end

else if((`SCL_LOW) && (num==4’d8)) begin

num <= 4’d0;

sda_r <= 1’b1;

sda_link <= 1’b0;

cstate <= ACK4;

end

else cstate <= DATA;

end

end

ACK4: begin

if(/*!sda*/`SCL_NEG) begin

// sda_r <= 1’b1;

cstate <= STOP1;

end

else cstate <= ACK4;

end

STOP1: begin

if(`SCL_LOW) begin

sda_link <= 1’b1;

sda_r <= 1’b0;

cstate <= STOP1;

end

else if(`SCL_HIG) begin

sda_r <= 1’b1;

cstate <= STOP2;

end

else cstate <= STOP1;

end

STOP2: begin

if(`SCL_NEG) begin sda_link <= 1’b0; scl_link <= 1’b0; end

else if(cnt_5ms==20’h3fffc) begin cstate <= IDLE; cnt_5ms<=20’h00000; iic_done<=1 ; end

else begin cstate <= STOP2 ; cnt_5ms<=cnt_5ms+1 ; end

end

default: cstate <= IDLE;

endcase

end

assign sda = sda_link ? sda_r:1’bz;

endmodule

Segment decoder driver part is as follow:

module led_seg7(

clk,rst_n,

dis_data,

point1 ,

sel,sm_db

);

input clk;

input rst_n;

input[7:0] dis_data;

output reg [5:0] sel;

output[6:0] sm_db;

output reg point1 ;

reg[11:0] cnt1;

reg[2:0] cnt;

reg [3:0] num;

wire en=(cnt1==12’hfff) ?1:0 ;

parameter V_REF = 12’d3300 ;

reg [19:0] num_t ;

reg [19:0] num1 ;

always @ (posedge clk)

num_t <= V_REF *dis_data ;

wire [3:0] data0 ;

wire [3:0] data1 ;

wire [3:0] data2 ;

wire [3:0] data3 ;

wire [3:0] data4 ;

wire [3:0] data5 ;

assign data5 = num1 / 17’d100000;

assign data4 = num1 / 14’d10000 % 4’d10;

assign data3 = num1 / 10’d1000 % 4’d10 ;

assign data2 = num1 / 7’d100 % 4’d10 ;

assign data1 = num1 / 4’d10 % 4’d10 ;

assign data0 = num1 % 4’d10;

always @(posedge clk or negedge rst_n) begin

if(rst_n == 1’b0) begin

num1 <= 20’d0;

end

else

num1 <= num_t >> 4’d8;

end

always @ (posedge clk or negedge rst_n)

if(!rst_n) cnt1 <= 4’d0;

else cnt1 <= cnt1+1’b1;

 

parameter seg0 = 7’h3f,

seg1 = 7’h06,

seg2 = 7’h5b,

seg3 = 7’h4f,

seg4 = 7’h66,

seg5 = 7’h6d,

seg6 = 7’h7d,

seg7 = 7’h07,

seg8 = 7’h7f,

seg9 = 7’h6f,

sega = 7’h77,

segb = 7’h7c,

segc = 7’h39,

segd = 7’h5e,

sege = 7’h79,

segf = 7’h71;

reg[6:0] sm_dbr;

 

always @ (*)

case (num)

4’h0: sm_dbr = seg0;

4’h1: sm_dbr = seg1;

4’h2: sm_dbr = seg2;

4’h3: sm_dbr = seg3;

4’h4: sm_dbr = seg4;

4’h5: sm_dbr = seg5;

4’h6: sm_dbr = seg6;

4’h7: sm_dbr = seg7;

4’h8: sm_dbr = seg8;

4’h9: sm_dbr = seg9;

4’ha: sm_dbr = sega;

4’hb: sm_dbr = segb;

4’hc: sm_dbr = segc;

4’hd: sm_dbr = segd;

4’he: sm_dbr = sege;

4’hf: sm_dbr = segf;

default: ;

endcase

assign sm_db = sm_dbr;

always @ (posedge clk or negedge rst_n) begin

if(!rst_n) begin

sel <= 6’b000000;

num <= 4’b0;

cnt<=3’b000;

end

else begin

 

case (cnt)

3’d0 :begin

sel <= 6’b111111;

num <= data5 ;

point1 <= 1’b1 ;

if(en)

cnt<=3’d1 ;

end

3’d1 :begin

sel <= 6’b111111;

num <= data4 ;

point1 <=1’b1 ;

if(en)

cnt<=3’d2 ;

 

end

3’d2 :begin

sel <= 6’b111011;

num <= data3;

point1 <= 1’b0 ;

if(en)

cnt<=3’d3 ;

 

end

3’d3 :begin

sel <= 6’b110111;

num <= data2;

point1 <= 1’b1 ;

if(en)

cnt<=3’d4 ;

 

end

3’d4 :begin

sel <= 6’b101111;

num <= data1;

point1 <=1’b1;

 

if(en)

cnt<=3’d5 ;

 

end

3’d5 :begin

sel <= 6’b011111;

num <= data0;

point1 <=1’b1;

if(en)

cnt<=3’d0 ;

 

end

default :begin

sel <= 6’b000000;

num <= 4’h0;

point1 <= 1’b1;

end

endcase

 

end

end

endmodule

4.Downloading to The Board

      1. Lock the pins
SignaL Name Port Description Network Label FPGA Pin
clk System clock, 50 MHz C10_50MCLK U22
rst_n Reset, high by default KEY1 M4
sm_db[0] Segment a SEG_PA K26
sm_db [1] Segment b SEG_PB M20
sm_db [2] Segment c SEG_PC L20
sm_db [3] Segment d SEG_PD N21
sm_db [4] Segment e SEG_PE N22
sm_db [5] Segment f SEG_PF P21
sm_db [6] Segment g SEG_PG P23
sm_db [7] Segment h SEG_DP P24
data[0] Switch input GPIO_DIP_SW0 N8
data[1] Switch input GPIO_DIP_SW1 M5
data[2] Switch input GPIO_DIP_SW2 P4
data[3] Switch input GPIO_DIP_SW3 N4
data[4] Switch input GPIO_DIP_SW4 U6
data[5] Switch input GPIO_DIP_SW5 U5
data[6] Switch input GPIO_DIP_SW6 R8
data[7] Switch input GPIO_DIP_SW7 P8
scl PCF8591 clock ADDA_I2C_SCl E20
sda PCF8591 data line ADDA_I2C_SDA C19
sel[0] Segment decoder position selection SEG_3V3_D0 R16
sel[1] Segment decoder position selection SEG_3V3_D1 R17
sel[2] Segment decoder position selection SEG_3V3_D2 N18
sel[3] Segment decoder position selection SEG_3V3_D3 K25
sel[4] Segment decoder position selection SEG_3V3_D4 R25
sel[5] Segment decoder position selection SEG_3V3_D5 T24
      1. Testing by selecting SW0 and SW1 to change the measurement objects.
AD, DA Experiment Results
AD, DA Experiment Results

Fig 13. 2 Test result

Related posts