When we last looked at the MicroZed we had just finished implementing the hardware and exporting it to the SDK. Once exported, you should be able to see the added XADC within the System.mss and System.xml files available under your board support package (BSP) and hardware definition respectively:
System.mss will show the XADC and the driver type, which appears as “generic” in this import. In fact, the SDK does come with drivers for the XADC, which are defined with xadcps.h and are available under the include files within the BSP. As we will be using other driver types unique to the Zynq, I also included xil_types.h to support the u32 type.
The xil_types.h header defines a number of macros you can use to configure, control, and read from the XADC. Amongst other things, this header file contains definitions for the XADC registers, sampling averaging options, channel sequence options, and power-down modes. It also contains a series of type definitions, macros, and other functions.
For my simple example, I am going to read the Zynq SoC’s internal temperature and voltage parameters and output them over an RS-232 link.
The first thing to do in the code is to look up the configuration of the XADC to be initialized; this requires a pointer of type "XAdcPs_Config." Using the function call "XAdcPs_LookupConfig()" coupled with the device ID this function will return 0 as there is only one XADC block within the Zynq. The configuration (device ID and base address of the XADC being initialized, see xparameters.h for this) will be stored in the pointer. If the configuration for the XADC with the device ID cannot be found, then "null" will be returned allowing the error to be handled.
The next step in the initialization process is to use the information previously obtained and stored within the configuration pointer, which requires a pointer of type "XAdcPs."
I named my configuration pointer "ConfigPtr" and my instantiation pointer "XADCInstPtr" (very original, as I'm sure you will agree).
Having initialized the XADC, the next few steps configure it for my example:
Use the "XAdcPs_SelfTest()" function to perform a self-test to check that there are no issues with the device.
Use "XAdcPs_SetSequencerMode()" to stop the sequencer from performing its current operation by setting it to a single channel.
Use "XAdcPs_SetAlarmEnables()" to disable any alarms that may be set.
Use "XAdcPs_SetSeqInputMode()" to restart the sequencer with the desired sequence.
Use "XAdcPs_SetSeqChEnables()" to configure the enables for the channels I wish to sample.
Reading a sample from the XADC can be as simple as calling the function "XAdcPs_GetAdcData()." For the internal temperature and voltage parameters, I then used two of the provided macros -- "XAdcPs_RawToTemperature()" and "XAdcPs_RawToVoltage()" -- to convert the raw XADC values into their real-world temperature or voltage equivalents.
Both these raw and real-world values are then output over an RS-232 link to be displayed in a terminal window. When I ran my code I was presented with the following results:
Below, you can download the attached C file I used to generate this output.
Note: Please see the previous entries in this MicroZed series by Adam Taylor: