I've been struggling with the analog outputs recently.
I have used the given example IP (AXI4-Stream Red Pitaya DAC) and my custom DAC interface.
Both gave me the same results.
I want to get a constant DC voltage between 0 and +1 volt from the analog outputs.
First, whenever I set a DAC code from the GPIO, it resets back to zero immediately at the next clock pulse.
I expected it to keep the voltage level since the GPIO still holds the same DAC code, and it's still applied to the DAC data input.
Second, I couldn't understand the relationship between the DAC code and the output voltage.
For instance, since the DAC is 14 bits, the analog range must be divided between -1V and +1V.
So, the DAC code must be related to this analog range and between 0x0000 and 0x3FFF.
Am I wrong?
Since I only wanted positive voltages, I tried to adjust the DAC code accordingly, but whatever I did, I always got bipolar outputs with positive and negative components.
Is there something in the "Amplifier & filter" block given on the 4th page of the schematics preventing only unipolar output? (https://downloads.redpitaya.com/doc//Re ... v1.0.1.pdf)
All the best,
Here is the alternative DAC module that I wrote but still getting the same results:
Code: Select all
`timescale 1ns / 1ps
module DAC_AD9767 (
input wire clk, // System clock
input wire reset_n, // Active low reset
input wire [31:0] data_in, // 32-bit input data
input wire data_valid, // Input data valid signal
output reg [13:0] dac_data, // DAC data output
output reg dac_clock, // DAC clock (CLK2/IQCLK)
output reg iqwrt, // WRT1/IQWRT signal
output reg iqsel // WRT2/IQSEL signal
);
// Internal registers
reg [13:0] ch1_data, ch2_data;
reg [1:0] state;
reg data_loaded;
// State machine parameters
localparam IDLE = 2'b00;
localparam SEND_CH1 = 2'b01;
localparam SEND_CH2 = 2'b10;
// Clock divider for DAC clock
reg clk_div;
always @(posedge clk or negedge reset_n) begin
if (!reset_n)
clk_div <= 1'b0;
else
clk_div <= ~clk_div;
end
// Main state machine
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
state <= IDLE;
ch1_data <= 14'b0;
ch2_data <= 14'b0;
dac_data <= 14'b0;
iqwrt <= 1'b0;
iqsel <= 1'b0;
data_loaded <= 1'b0;
end else begin
case (state)
IDLE: begin
if (data_valid) begin
ch1_data <= data_in[15:0];
ch2_data <= data_in[31:16];
state <= SEND_CH1;
data_loaded <= 1'b1;
end
end
SEND_CH1: begin
if (clk_div) begin
dac_data <= ch1_data;
iqwrt <= 1'b1;
iqsel <= 1'b0;
state <= SEND_CH2;
end
end
SEND_CH2: begin
if (clk_div) begin
dac_data <= ch2_data;
iqwrt <= 1'b1;
iqsel <= 1'b1;
state <= IDLE;
data_loaded <= 1'b0;
end
end
default: state <= IDLE;
endcase
// Reset iqwrt after one clock cycle
if (iqwrt)
iqwrt <= 1'b0;
end
end
// Generate DAC clock
always @(posedge clk or negedge reset_n) begin
if (!reset_n)
dac_clock <= 1'b0;
else if (data_loaded)
dac_clock <= clk_div;
else
dac_clock <= 1'b0;
end
endmodule
Code: Select all
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <stdlib.h>
#include <time.h>
int main(int argc, char **argv)
{
int fd;
void *dacmap;
char *name = "/dev/mem";
uint32_t dac_addr = 0x41210000;
if((fd = open(name, O_RDWR)) < 0){
perror("open");
return 1;
}
dacmap = mmap(NULL, sysconf(_SC_PAGESIZE), PROT_WRITE, MAP_SHARED, fd, dac_addr );
uint32_t dacVal;
uint16_t iTemp;
while (1)
{
for (uint16_t i = 0; i < 0x4000; i += 0xFFF)
{
iTemp = (~i & 0x3FFF); // 14 bit
dacVal = (iTemp << 16) | iTemp;
*((uint32_t *)(dacmap)) = dacVal;
printf("DAC\t:\t%d\t0x%0x\n", i, dacVal);
//usleep(10000);
}
}
munmap(dacmap, sysconf(_SC_PAGESIZE));
return 0;
}
https://imgur.com/a/m1Xfq5u
And here is the output signal when I set the for loop up to 0x2000. I expected to see the positive part of the output. But here it is:
https://imgur.com/a/GBKkyvx