Jump to content
  • 0

XADC on Zybo gives inaccurate voltages




I have recently instantiated XADC in my block design in Vivado and connected Vaux14 as single channel, unipolar. I read voltages through IIO driver in Xilinx Linux. When I read internal voltages and temperatures, everything seems to be fine. However, when I try to measure voltage of battery (0.8 V) by connecting it to N15 and N16 (PMODs wired up with Vaux14 input), I get rather unsatisfactory results. Reading raw value and dividing it with 4096 I'm supposed to get real voltage, but I get stable value around 1300, which makes only around 0.3 after division. When I connect battery with lower voltage, I get lower value, but still not correct. Signal generator gives incorrect value as well. Am I missing something, what prevents me from getting expected results?

Thanks for replies.

Link to comment
Share on other sites

13 answers to this question

Recommended Posts

Are you instantiating the XADC wizard in the PL? I'd recommend doing that even though the ARM has direct access to the XADC block in the FPGA, because the wizard will allow you to initialize the XADC with some settings that might help you improve the accuracy, such as averaging and calibration. You will also need to make sure that your device tree has a block describing the XADC wizard to linux.

Link to comment
Share on other sites

I do instantiate XADC wizard in the PL, constraints are set properly too. FPGA is programmed before booting Linux from SD card. I also have XADC in the devicetree (otherwise I would not be able to read anything). 


Link to comment
Share on other sites

Notarobot, can you export your block diagram as a .tcl script? That will help so that Jakub can see what your configuration settings are for the XADC wizard.

Jakub, I want to verify that you are connecting an appropriate ground to the JA1_N pin on the pmod (N16). The analog inputs are all differential. Another test would be to run the XADC project found in this repo:


If you can monitor the data_out bus in that demo, then you can see if that project results in closer to expected results. You can then use that project as a good platform to tweak the XADC wizard settings and try to improve accuracy. It should build faster than your typical block diagram project. 

It might be necessary to calibrate the XADC block in order to reach your desired accuracy. That will need to be done in software, and I don't know if the Xilinx linux driver supports it. 

Link to comment
Share on other sites

I've successfully loaded FPGA with bitstream synthetized out of Notarobot's project and adjusted the devicetree (because he uses Vaux6 instead of Vaux14). Then I plugged the positive cord into K14 and negative cord into J14. With this configuration I get the same results as with my configuration. When the battery is not connected, I get very low values (around 60, that's what I'd expect).

I had no luck with synthetizing XADC project from https://github.com/Digilent/ZYBO, I'm getting this error:

[Synth 8-439] module 'xadc_wiz_0' not found ["/XADCdemo.v":59]

I'm pretty sure it measures something, because values with connected (~1300) and disconnected battery (~60) significantly differ. The main problem is accuracy. How can I perform the calibration?

Link to comment
Share on other sites

Notarobot, I used correct pins, K14 and J14, you used them in your project (Vaux6), so I used them. With Vaux14 I would use N15 and N16. That's why I adjusted my devicetree: to comply with your project. I'm completely aware of this. That's what I'm trying to say. I'm sure I use right ports. There's no need to discuss that, I'd rather focus on the accuracy.

Link to comment
Share on other sites


Regarding to accuracy my thinking is:

1. Since according to your experince the accuracy of the ADC is fine when it's configured to read internal parameters, a valid conclusion is that the ADC hardware has no issues. To my knowledge calibration is not needed for the majority of ADC chips. The reference voltage is the only parameter which determines the scaling of raw count. In this case it is 1V.

2. If the above said is correct then it would be reasonable to conclude that the issue is in the configuration of XADC wizard or .xdc constraints files. Just in case I attached that file.

3. It useful to connect an oscilloscope to the Pmod JA PCB traces and verify the signal you are sending. 

Good luck!



Link to comment
Share on other sites

I think a good route would be to start by getting the accuracy issues resolved in standalone and then compare that to Linux.

First off make sure the XADC wizard is in Channel sequencer mode, Channel averaging is set to 16, and that the following channels are enabled: Calibration, Temperature, vccint, vccaux, vaux6, vaux7, vaux14, vaux15

Here is tcl snippet that will insert a properly configured XADC wizard into a Vivado 2016.4 block diagram is run from the TCL console in the Vivado GUI while the block diagram is open:

  set xadc_wiz_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:xadc_wiz:3.3 xadc_wiz_0 ]
  set_property -dict [ list \
CONFIG.XADC_STARUP_SELECTION {channel_sequencer} \
 ] $xadc_wiz_0

After you export to SDK, try running the attached code. Apologies, I'm not setup to test it myself right now, so it might have a couple of build errors. I can test it tomorrow. 

The attached code should print out the voltage across pins JA1/JA7 to the UART terminal at 115200 baud. 

EDIT: Sorry, the code definitely doesn't build... I'm fixing it now


Link to comment
Share on other sites

Sorry, it looks like the last code I provided didn't work. Please use the attached .c file, which has been fixed. It will print out the state of all 4 XADC pairs on JA every 2 seconds over UART.

I've also attached a tcl scipt for generating the block diagram I used. It will only work in 2016.4, and you will need to have already created a project that targets our Zybo board files. 

I am getting accurate readings on all the Pmod pairs +/- a couple millivolts. See if you can replicate this. From there we can work backwards to finding the issue with the XADC driver. 

If I had to guess, I would say that Xilinx's XADC Linux driver is probably just using the default values of the XADC, which are determined by the IP configuration in the block diagram. If that is the case, then a good strategy will be to play around with this demo code by removing the manual calls I make to xsysmon and replacing them with equivalent values in the XADC wizard. Hopefully, you will get to a point where you can read accurate values directly after the self test, without all the additional config.

Another possibility is that the 4096 divisor you are using is not correct. Where did you get that value? 



Link to comment
Share on other sites

A few suggestions to debug:

1) Can you access vp/vn? These pins are always connected, so as long as you enable them in the sequence (and enable sequence mode) they will be read. 

2) Are you using unipolar or bipolar mode for your inputs? A battery like signal should be configured as unipolar.

3) It is also good to connect vn to analog ground for unipolar signals. There must be a relationship between analog ground and the signal you are monitoring. This is due to the common mode input specs and all ADCS require this.

4) Transfer function: unipolar mode is 0 to 1v. Taking 12 bit data divide the code by 4096 gives the value. There is no other scaling required.

5) If internal sensors are good then calibration is good. There is no extra calibration for external channels required.

Link to comment
Share on other sites


This topic is now archived and is closed to further replies.

  • Create New...