Author Topic: SPI interfacing with AD5791 DAC via Raspberry Pi?  (Read 1124 times)

0 Members and 1 Guest are viewing this topic.

Offline imisaac

  • Regular Contributor
  • *
  • Posts: 51
  • Country: de
SPI interfacing with AD5791 DAC via Raspberry Pi?
« on: April 17, 2019, 09:14:09 pm »
The SPI pins on the AD5791 evaluation board is connected to a Raspberry Pi 3 Model B. In order to set some DAC output voltages, I tried to follow the guide here: https://wiki.analog.com/resources/quick-start/ad5791

In that guide, the DAC is supposed to output a midrange voltage (0V? I used +/-10V voltage references) after issuing the following string of binary bits to the DAC (0001 1000 0000 0000 0000 0000).

However, nothing happened....

Does the ordering of the bit stream need to be reversed (i.e. MSB first) in order to set the DAC register or I am missing another step in setting the /LDAC or /Clr bits? Or Raspberry Pi is not suitable for SPI with AD5791 for more subtle reasons?

As a complementary info, I used a loop-back test (i.e. connecting MOSI to MOSO) to confirm that I am indeed outputing something already.

Any tips would be extremely useful and thanks in advance!
 

Offline LateLesley

  • Regular Contributor
  • *
  • Posts: 175
  • Country: scotland
Re: SPI interfacing with AD5791 DAC via Raspberry Pi?
« Reply #1 on: April 18, 2019, 02:27:07 am »
I think we need more information to be able to help you. You've told us that the reference voltages are +/-10V, but we don't know how the rest of it is connected.

First, supply voltages. What are you feeding in to :-
Vdd
Vss
Vcc
IOVcc

I think we can assume that VREFPS and VREFPF are at +10V, and that VREFNS and VREFNF are at -10V ??

when sending data, what are you setting the control pins to? (/LDAC, /CLR, /RESET)

These pins will need set for it to work, as these set the output from the register values.

You may be loading the value into the register, but you then need to set the control pins to set the output to the DAC register value.

EDIT : Just noticed, you can set the LDAC, CLR, RESET with data sent to the device, it's further down the datasheet, under "Writing to the Software Control Register". So try writing the DAC register, then sending to the software control register afterwards to latch the data in to the output.
« Last Edit: April 18, 2019, 02:30:21 am by LateLesley »
 

Offline Dave

  • Super Contributor
  • ***
  • Posts: 1199
  • Country: si
  • I like to measure things.
Re: SPI interfacing with AD5791 DAC via Raspberry Pi?
« Reply #2 on: April 18, 2019, 06:48:02 am »
You need to write to the control register first and disable the output tristate mode.
All of this is described in the guide you linked to in your post.
<fellbuendel> it's arduino, you're not supposed to know anything about what you're doing
<fellbuendel> if you knew, you wouldn't be using it
 

Offline imisaac

  • Regular Contributor
  • *
  • Posts: 51
  • Country: de
Re: SPI interfacing with AD5791 DAC via Raspberry Pi?
« Reply #3 on: April 19, 2019, 07:23:08 pm »
Thanks all. I have not got the Pi set up working with AD5791 yet, but here is what I have tried.

To make sure the AD5791 evaluation board was functional, I connected a SDP board (also from AD) to it. Then, I ran the evaluation software on a Windows PC. In this set up, the DAC output could be manipulated. This implied that the DAC hardware was fine.

The evaluation board was powered by a single power supply of 4 V. There was no need to have a separate voltage reference. Nevertheless, I checked the Vref pins directly on AD5791 and got +/-10 volts from them.

On the software side, I was using Matlab to talk to Pi. Here is the code I was testing.
Code: [Select]
clear rpi; clear spidevice;
rpi = raspi('192.168.178.49','xx','xxxx');
enableSPI(rpi);
spidevice = spidev(rpi,'CE0',2);
wdata = ['110011001100110011001100'];
writeAD5791(spidevice,wdata);

function [readdata] = writeAD5791(spidevice,wdata)
    wdata = flip(wdata);
    readdata = writeRead(spidevice,[bin2dec(wdata(1:8)) bin2dec(wdata(9:16)) bin2dec(wdata(17:end))],'uint8');
    pause(1);
end


To make sure that the code was spitting out the bits, I connected the SPI outputs on the Pi to a ADALM20000 based logic analyser. The result from the first SPI write is attached. The guide to use SCOPY software to debug SPI is given here:
https://ez.analog.com/university-program/b/blogs/posts/adalm2000-spi-debug

It looks like the output bit stream is different from the one I intended. In the SPI write function I created, the intended bit stream was flipped in the order such that the MSB is spit out first. Looking at the logic analyser plot, however, the second bit counting from the left turns out to be wrong!

Does anyone know why this is happening? I guess this could be one of the reasons that the AD5791 was not responding...

Thanks in advance.
« Last Edit: April 19, 2019, 07:38:45 pm by imisaac »
 

Offline imisaac

  • Regular Contributor
  • *
  • Posts: 51
  • Country: de
Re: SPI interfacing with AD5791 DAC via Raspberry Pi?
« Reply #4 on: April 19, 2019, 08:22:11 pm »
This is a short follow-up. It seems that the wrong bit stream was due to the logic analyser configuration in SCOPY. If the transition edges of each of the four SPI pins were meeting some "condition", the right bit stream could be observed.

I am not sure why it worked though....In particular, for each of the SPI pin, how do I know it is rising edge or falling edge detection?

The present edge detection characteristics are attached in case someone knows the reason.

Update:
In the Matlab program attached in the previous message, I used "mode 2" for the SPI communication. According to the wiki page of SPI,

https://en.wikipedia.org/wiki/Serial_Peripheral_Interface

mode 2 means that CPOL=1 and CPHA=0. That is, the SPI clock is 1 when idle. The data bits are spit out on the leading edge of the clock pulses. Therefore, in the logic analyser, I should set the MOSI an MISO pins for the rising edge detections as well.

Attached is the timing diagram for AD5791. The confusing part is that it is unclear the CPOL is 1 or 0 when idle for AD5791. Anyone knows the SPI mode for AD5791?
« Last Edit: April 19, 2019, 10:04:01 pm by imisaac »
 

Offline mikerj

  • Super Contributor
  • ***
  • Posts: 2095
  • Country: gb
Re: SPI interfacing with AD5791 DAC via Raspberry Pi?
« Reply #5 on: April 21, 2019, 09:54:55 am »
That looks like a Mode 1 device to me, though it's not the clearest timing diagram I've seen.  The clock pulses are numbered in the center, and the incoming data bit is being latched on the trailing edge of the clock pulse (CPHA=1) and the leading edge is positive going (CPOL=0).
 

Online MarkF

  • Super Contributor
  • ***
  • Posts: 1365
  • Country: us
Re: SPI interfacing with AD5791 DAC via Raspberry Pi?
« Reply #6 on: April 21, 2019, 05:57:01 pm »
I think you would be better off with the FULL datasheet.
   https://www.analog.com/media/en/technical-documentation/data-sheets/ad5791.pdf
 

Offline imisaac

  • Regular Contributor
  • *
  • Posts: 51
  • Country: de
Re: SPI interfacing with AD5791 DAC via Raspberry Pi?
« Reply #7 on: April 23, 2019, 03:46:15 pm »
Thanks mikerj!

I used the SPI mode 1, and the DAC output actually did something (went to -10 V) before it went back to zero instead of the voltage that I intended to. The following Matlab code was used.

Code: [Select]
clear rpi; clear spidevice;
rpi = raspi('192.168.178.49','xx,'xxx');
enableSPI(rpi);
spidevice = spidev(rpi,'CE0',1,500000);

%% Write to the "software control register" to reset the DAC to power-on state
wdata = ['010000000000000000000100'];
writeAD5791(spidevice,wdata);

%% Write to the "control register" to initialize the DAC to normal state
wdata = ['001000000000000000010010'];
writeAD5791(spidevice,wdata);

%% Write to the "DAC register" to place some non-zero voltage value at the register
wdata = ['000111000000000000000000'];
writeAD5791(spidevice,wdata);

%% Write to the "software control register" to enable the DAC output
wdata = ['010000000000000000000001'];
writeAD5791(spidevice,wdata);

function [readdata] = writeAD5791(spidevice,wdata)
    wdata = flip(wdata);
    readdata = writeRead(spidevice,[bin2dec(wdata(1:8)) bin2dec(wdata(9:16)) bin2dec(wdata(17:end))],'uint8');
    pause(2);
end

I again verified the bit patterns with a logic analyser (picture attached), and the bit patterns seemed to be as expected.

I am running out of debugging ideas to have this AD5791 output some voltages using a Matlab/Raspberry Pi combo setup. Can someone advice?

Thanks in advance.

Meanwhile, I am planning to switch to the Arduino system to try out next......

« Last Edit: April 23, 2019, 03:48:18 pm by imisaac »
 

Offline mikerj

  • Super Contributor
  • ***
  • Posts: 2095
  • Country: gb
Re: SPI interfacing with AD5791 DAC via Raspberry Pi?
« Reply #8 on: April 23, 2019, 07:56:59 pm »
What is the order of the above sequence?  Looking at the data you are sending, I think you may have the first two swapped?

reset.jpg:  Bits23:20 = 0010 = Write to the config register to disable output ground clamp and take DAC out of tri-state
initialize.jpg: Bits23:20 = 0100 = Write to the software control register to reset the device, returning all registers to power-on defaults
setdacout.jpg: Bits23:20 = 0000 Write to No-Operation register.  This will do nothing.
enabledact.jpg: Bits23:20 = 1000 Read to No=Operation register.  This will do nothing.

Performing a software reset is fine to ensure the chip is in it's default state, but obviously must be the first thing you do other wise you lose all the operations performed before it.

The last two are clearly wrong, the top four bits should be 0001 to write to the DAC register, and 1001 to read the DAC register.  Additionally if the LDAC pin is not held low during the write then you will either need to toggle LDAC after the SYNC (chip select) pin has gone high, or write to the software control register to perform an LDAC operation.  Easiest to just tie LDAC low, so the DAC gets updated when SYNC is de-asserted.
 

Offline imisaac

  • Regular Contributor
  • *
  • Posts: 51
  • Country: de
Re: SPI interfacing with AD5791 DAC via Raspberry Pi?
« Reply #9 on: April 23, 2019, 09:41:39 pm »
Thanks, mikerj. The bit pattern observed by the logic analyzer was reversed by purpose in order to follow the passage given in the datasheet:

Quote
...Data is loaded into the device MSB first as a 24-bit word under the control of a serial clock input, SCLK, which can operate at up to 50 MHz....

In the subroutine where the bits were spit out (e.g. see the code below), I reversed the binary bit pattern such that the MSB is sent to the SPI slave (AD5791 in this case) first.
Code: [Select]
function [readdata] = writeAD5791(spidevice,wdata)
    wdata = flip(wdata);
    readdata = writeRead(spidevice,[bin2dec(wdata(1:8)) bin2dec(wdata(9:16)) bin2dec(wdata(17:end))],'uint8');
    pause(2);
end


Therefore, in the reset.jpg, the MSB is the right most digit. That is, I was attempting to write ('0') to the '100' register address with '100' values for the RESET, CLR, and LDAC bits.

In the initialize.jpg, similarly, I was attempting to write ('0') to the '010' register address with '000001001' values for the LIN COMP, SDODIS, BIN/2sC, DACTRI, OPGND, RBUF bits.

However, your observation is very interesting because it suggests that I actually did not have to reverse the bit pattern at all before writing it to the SPI slave device. I will give non-reversal pattern a try to see what happens.

Last but not least, you mentioned to tie the LDAC low all the time. Does it mean I short the physical LDAC pin to the DGND pin on the evaluation board? Thanks.



« Last Edit: April 23, 2019, 09:51:50 pm by imisaac »
 

Offline imisaac

  • Regular Contributor
  • *
  • Posts: 51
  • Country: de
Re: SPI interfacing with AD5791 DAC via Raspberry Pi?
« Reply #10 on: April 24, 2019, 08:27:39 am »
This is a follow-up test. The working solution is given below:

1. The bit pattern to be sent to the SPI slave device (i.e. AD5791) does not need to be reversed in order.

2. The SPI mode of AD5791 can be either mode 1 (thanks to mikerj) and mode 3 (thanks to rrosario from this thread https://ez.analog.com/data_converters/precision_dacs/f/q-a/110156/spi-mode-of-ad5791/326300#326300). Both work equally well in my test program.

3. The LDAC bit should be set to 1 right after writing a value to the DAC register to “trigger” the output. This creates a square pulse on the LDAC pin. This is software triggering using the SPI bus.

4. An alternative way to trigger the output without writing to the LDAC bit is to physically short the LDAC pin and the DGND pin on the AD5791 evaluation board. The DAC output is updated automatically right after writing a value to the DAC register.

5. The interconnection between the AD5791 evaluation board and the Raspberry Pi are 5 wires. They include SCLK, SYNC, SDO, SDIN, and DGND on the evaluation board connecting to SPI0_CLK, SPI0_CE0, SPI0_MISO, SPI0_MOSI, and Ground respectively on the Pi.

6. The jumper settings on the AD5791 evaluation board are as follows: LK1=A, LK2=inserted, LK3=removed, LK4=removed, LK5=inserted, LK6=removed, LK7=removed, LK8=B, LK9=B, LK10=B, LK11=removed.

7. An working test program written in Matlab to drive the AD5791 is shared below (the physical pin of LDAC does not need to be grounded in this case):
Code: [Select]
clear rpi; clear spidevice;
rpi = raspi('192.168.2.2','xx,'xxx');
enableSPI(rpi);
spidevice = spidev(rpi,'CE0',1,500000);

%% Write to the "software control register" to reset the DAC to power-on state
wdata = ['010000000000000000000100'];
writeAD5791(spidevice,wdata);

%% Write to the "control register" to initialize the DAC to normal state
wdata = ['001000000000000000010010'];
writeAD5791(spidevice,wdata);

%% Write to the "DAC register" to place some non-zero voltage value at the register
wdata = ['000111000000000000000000'];
writeAD5791(spidevice,wdata);

%% Write to the "software control register" to enable the DAC output
wdata = ['010000000000000000000001'];
writeAD5791(spidevice,wdata);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [readdata] = writeAD5791(spidevice,wdata)
    readdata = writeRead(spidevice,[bin2dec(wdata(1:8)) bin2dec(wdata(9:16)) bin2dec(wdata(17:end))],'uint8');
    pause(0.5);
end

Thanks all!
« Last Edit: April 24, 2019, 09:14:00 am by imisaac »
 
The following users thanked this post: mikerj

Offline mikerj

  • Super Contributor
  • ***
  • Posts: 2095
  • Country: gb
Re: SPI interfacing with AD5791 DAC via Raspberry Pi?
« Reply #11 on: April 24, 2019, 11:03:47 am »
Glad you got it working, and thanks for letting us know.
 
The following users thanked this post: imisaac

Offline imisaac

  • Regular Contributor
  • *
  • Posts: 51
  • Country: de
Re: SPI interfacing with AD5791 DAC via Raspberry Pi?
« Reply #12 on: April 29, 2019, 02:13:22 pm »
Just a short update.

I added a ground isolator for the SPI bus (LTM2887 evaluation board) such that the ground of the USB is not connected to the digital ground of the AD5791 DAC.

Attached is a picture of the current setup.
 

Offline imisaac

  • Regular Contributor
  • *
  • Posts: 51
  • Country: de
Re: SPI interfacing with AD5791 DAC via Raspberry Pi?
« Reply #13 on: April 30, 2019, 03:27:58 pm »
Just another short update.

In the datasheet of AD5791, the voltage output noise floor is specified at ~8 nV/√Hz (see the attached figure).

Using the setup presented here (unboxed, not carefully shielded yet), I measured the noise floor to be ~20 nV/√Hz (see the measurement plot).

Has anyone managed to reproduce the noise floor of AD5791 in the datasheet?

Thanks in advance.
 

Offline RandallMcRee

  • Frequent Contributor
  • **
  • Posts: 364
  • Country: us
Re: SPI interfacing with AD5791 DAC via Raspberry Pi?
« Reply #14 on: April 30, 2019, 04:36:15 pm »
Just another short update.

In the datasheet of AD5791, the voltage output noise floor is specified at ~8 nV/√Hz (see the attached figure).

Using the setup presented here (unboxed, not carefully shielded yet), I measured the noise floor to be ~20 nV/√Hz (see the measurement plot).

Has anyone managed to reproduce the noise floor of AD5791 in the datasheet?

Thanks in advance.

I have not tried, yet, but there would be no way without proper shielding at those low levels. The spuriae in your plot look like unshielded interference problems, as well. In addition, air drafts become important (although not at 1khz!).

What frequency range are you really interested in? You ought to first verify that you can get reliable noise measurements with a grounded output. Especially when using ground isolation, you could be measuring some artifacts unrelated to the 5791. Your measurement noise floor should be measured, first.
« Last Edit: April 30, 2019, 04:40:47 pm by RandallMcRee »
 

Offline imisaac

  • Regular Contributor
  • *
  • Posts: 51
  • Country: de
Re: SPI interfacing with AD5791 DAC via Raspberry Pi?
« Reply #15 on: April 30, 2019, 09:49:18 pm »
Thanks RandallMcRee for the grounding suggestion.

I am interested in the white noise floor (the flat part of the noise spectrum) of the AD5791.

By "grounding" the DAC output, you meant to short the DAC output to the earth ground when it's on OR you meant to set the DAC output to zero volt?

 

Offline imisaac

  • Regular Contributor
  • *
  • Posts: 51
  • Country: de
Re: SPI interfacing with AD5791 DAC via Raspberry Pi?
« Reply #16 on: May 09, 2019, 04:58:34 pm »
Ok, I wrapped the enclosure all over with aluminum foil (see picture). The noise of the AD5791 evaluation board gets improved significantly (see plot).

However, it is still somewhat worse than the AD5791 datasheet spec. Maybe i am now limited by my noise measuring device.

Anyways, there are strange interference peaks on top of the white noise floor.

Does anyone know how to remove these peaks?

Thanks in advance.

 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf