Several weeks ago I created a hackster project detailing the creation of a breakout board for the Ultra96V2 which provided Pmod and SYZYGY interfaces.
Of course designing the board is only one step in the process, we need to have the design manufactured and test the board to make sure the design functions as intended.
In this project we are going to look at how we commissioned the received boards with the Ultra96V2 prior to being able to use them in our projects.
InspectionThe first thing to do when receiving the boards back from manufacture is to examine the boards. This examination should examine the physical assembly of the board. This visual inspection should include examining the correct connectors have been fitted, and they are in the correct orientation. We will also want to observe the components and ensure all fitted components have been fitted and to the correct pads. While looking at the components ensure surface mount components are not tombstoned or there are not solder shorts between pins on IC's. The assembly house should have of course done these inspections however, at times things slip through.
The next step is to make sure the board mechanically mates with the Ultra96 there is little point in testing the power rails and signal integrity etc if we got the connector positioning wrong.
Of course on this breakout board we have both the high and low speed connectors populated if one of them is not positioned correctly then the board will not be able to connect to the Ultra96.
Luckily when I rested the breakout board on top of the Ultra96 and aligned the connectors, it was obvious the boards would mate.
However, before the boards where mated and powered on, I first wanted to ensure there was no shorts between the power rails and ground.
Happy that there are no show circuits on the board, they can be connected and powered on for the first time.
Powering on the board requires the power on button on the breakout board to be pushed, which is a good test of the push buttons functionality!
With power applied to the board the next element is to measure the voltages rails we have four voltage rails to measure on the breakout board
- 5v0 +/- 5% - provided by the Ultra96
- 3v3 +/- 5% - generated by the breakout board
- 1v2 +/- 5% - generated by the breakout board
- 1v8 +/- 5% - provided by the Ultra96
Now we are happy the boards connect and power up safely we can get started developing the applications to test out the SYZYGY and Pmod Interfaces.
Vivado Project CreationTo get started we need to create a Ultra96 project which uses the High Speed and Low Speed connectors.
The first thing to do is to create a new project
Select the Ultra96 as the target board.
Before we get started developing the Vivado design we need to include the Digilent Pmod IP libraries. These can be downloaded from the website
If you download the Zip file, extract the zip file to the location on your computer that you wish to use the library from.
To add in the library to Vivado, select the settings icon and and IP Repository from the Project Settings. Navigate to the location of the unzipped libraries and you should see Vivado find a number of IP and Interfaces.
With the IP added we are able to start creation of the of the designs, create a new block design and add in the Zynq MPSoC processing system.
Run the block automation to configure the processing system specifically for the Ultra96 configuration.
Once the block design automation is completed, we can create the rest of our design. For this project I want to output data from a DAC Pmod and receive data on a ADC Pmod. This will test out the Pmod interfaces, of course if we have any issues we will see the failures in data transmission or reception.
To communicate with the AD2 Pmod we can use the AD2 Pmod driver from the digilent IP library. This will provide a IP core for the PL and drivers for the SW too.
The DA4 does not have a driver as such we are going to use the PS SPI driver, to do this we are going to route both PS SPI interfaces to the EMIO.
We will use SPI0 to communicate with the DA4 Pmod and SPI1 to communicate with the ADC on SYZYGY board - More on this interface later.
The completed design looks like below
With the design completed we need to create several constraints to place the IO in the correct locations.
set_property PACKAGE_PIN D7 [get_ports {pmod2_ss[0]}]
set_property PACKAGE_PIN F8 [get_ports pmod2_MOSI]
#set_property PACKAGE_PIN F7 [get_ports Pmod2_io1_io]
set_property PACKAGE_PIN G7 [get_ports pmod2_sclk]
#set_property PACKAGE_PIN F6 [get_ports Pmod2_pin7_io]
#set_property PACKAGE_PIN G5 [get_ports Pmod2_pin8_io]
#set_property PACKAGE_PIN A6 [get_ports Pmod2_pin9_io]
#set_property PACKAGE_PIN A7 [get_ports Pmod2_pin10_io]
set_property PACKAGE_PIN G6 [get_ports Pmod1_pin1_io]
set_property PACKAGE_PIN E6 [get_ports Pmod1_pin2_io]
set_property PACKAGE_PIN E5 [get_ports Pmod1_pin3_io]
set_property PACKAGE_PIN D6 [get_ports Pmod1_pin4_io]
set_property PACKAGE_PIN D5 [get_ports Pmod1_pin7_io]
set_property PACKAGE_PIN C7 [get_ports Pmod1_pin8_io]
set_property PACKAGE_PIN B6 [get_ports Pmod1_pin9_io]
set_property PACKAGE_PIN C5 [get_ports Pmod1_pin10_io]
set_property IOSTANDARD LVCMOS18 [get_ports -of_objects [get_iobanks 26]]
# Set the bank voltage for IO Bank 65 to 1.2V
set_property IOSTANDARD LVCMOS12 [get_ports -of_objects [get_iobanks 65]];
# Set the bank voltage for IO Bank 66 to 1.2V
set_property IOSTANDARD LVCMOS12 [get_ports -of_objects [get_iobanks 66]];
set_property PULLUP true [get_ports Pmod1_pin1_io]
set_property PULLUP true [get_ports Pmod1_pin2_io]
set_property PULLUP true [get_ports Pmod1_pin3_io]
set_property PULLUP true [get_ports Pmod1_pin4_io]
set_property PULLUP true [get_ports Pmod1_pin7_io]
set_property PULLUP true [get_ports Pmod1_pin8_io]
set_property PULLUP true [get_ports Pmod1_pin9_io]
set_property PULLUP true [get_ports Pmod1_pin10_io]
Once the constraints are included, we are able to build the design and export the hardware design to Vitis
Exporting the hardware platform is simple, select fixed platform
Include the bit stream we have just created
Select the location and name for the exported XSA
Finally click on finish
Once the project has been exported we are able to open Vitis and select the workspace we wish to work within.
Once this is created we are able to create a application project
Select create new platform from hardware specification and point to the XSA just exported from Vivado.
Select the A53 Cortex 0 and create a application and system project name.
Create a standalone domain for the A53_0
Select the hello world application project
Once the project is open we can create the application, this application will use the code below.
At the simplest level the code will
- Configure and initialise the AD2 driver and SPI0 Driver
- Output a incrementing count over the DA4 Pmod
- Receive the signal over the AD2
- Output the received channels over the serial terminal
#include <stdio.h>
#include "xparameters.h"
#include "xil_cache.h"
#include "PmodAD2.h"
#include "xspips.h"
#include "xgpiops.h"
#define SPI_MIO XPAR_XSPIPS_0_DEVICE_ID
#define max_count 4095
static XSpiPs SpiInstance_MIO;
u8 op_buff[4] = {0x00,0x01,0x02,0xaa};
#define pmod1_pin 37
#define pmod2_pin 40
#ifdef XPAR_MICROBLAZE_ID
#include "microblaze_sleep.h"
#else
#include "sleep.h"
#endif
void DemoInitialize();
void DemoRun();
//static void SendHandler(PmodAD2 *InstancePtr);
//static void ReceiveHandler(PmodAD2 *InstancePtr);
PmodAD2 myDevice;
//void print(char *str);
int main()
{
Xil_ICacheEnable();
Xil_DCacheEnable();
DemoInitialize();
DemoRun();
return 0;
}
void DemoInitialize()
{
XSpiPs_Config *SpiConfig_MIO;
XGpioPs Gpio;
int Status;
XGpioPs_Config *GPIOConfigPtr;
xil_printf("UART Established\n\r");
GPIOConfigPtr = XGpioPs_LookupConfig(XPAR_XGPIOPS_0_DEVICE_ID);
XGpioPs_CfgInitialize(&Gpio, GPIOConfigPtr, GPIOConfigPtr ->BaseAddr);
XGpioPs_SetDirectionPin(&Gpio, pmod1_pin, 1);
XGpioPs_SetOutputEnablePin(&Gpio, pmod1_pin, 1);
XGpioPs_SetDirectionPin(&Gpio, pmod2_pin, 1);
XGpioPs_SetOutputEnablePin(&Gpio, pmod2_pin, 1);
XGpioPs_WritePin(&Gpio, pmod1_pin, 0x1);
XGpioPs_WritePin(&Gpio, pmod2_pin, 0x1);
SpiConfig_MIO = XSpiPs_LookupConfig((u16)SPI_MIO);
Status = XSpiPs_CfgInitialize(&SpiInstance_MIO, SpiConfig_MIO,SpiConfig_MIO->BaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
XSpiPs_SetOptions(&SpiInstance_MIO, XSPIPS_MASTER_OPTION | XSPIPS_CLK_PHASE_1_OPTION);
XSpiPs_SetClkPrescaler(&SpiInstance_MIO, XSPIPS_CLK_PRESCALE_128);
//XSpiPs_SetClkPrescaler(&SpiInstance_MIO, XSPIPS_CLK_PRESCALE_128);
//internal reference
op_buff[0] = 0x10;
op_buff[1] = 0x00;
op_buff[2] = 0x00;
op_buff[3] = 0x01;
//XSpi_SetSlaveSelect(&SpiInstance,0x01);
XSpiPs_PolledTransfer(&SpiInstance_MIO, op_buff, NULL,4);
//power up
op_buff[0] = 0x08;
op_buff[1] = 0x00;
op_buff[2] = 0x00;
op_buff[3] = 0xff;
//XSpi_SetSlaveSelect(&SpiInstance,0x01);
XSpiPs_PolledTransfer(&SpiInstance_MIO, op_buff, NULL,4);
AD2_begin(&myDevice, XPAR_PMODAD2_0_AXI_LITE_IIC_BASEADDR, AD2_IIC_ADDR);
//AD2_SetupInterruptSystem(&myDevice, XPAR_PS7_SCUGIC_0_DEVICE_ID, XPAR_FABRIC_AXI_IIC_0_IIC2INTC_IRPT_INTR, SendHandler, ReceiveHandler);
//XIic_Start(&myDevice.AD2Iic);
}
void DemoRun()
{
//u16 an[4],
u16 conv;
u8 channel;
//u8 buf[2] = {0,0};
double voltage;
u16 count;
//int nan = 4, i = 0;
printf("Demo Started\n\r");
AD2_WriteConfig(&myDevice, AD2_DEFAULT_CONFIG);
//Default config is 0xF0, all channels on
printf("AD2 Configured\n\r");
op_buff[0] = 0x03;
op_buff[3] = 0x00;
while(1) {
AD2_ReadConv(&myDevice, &conv);
channel = (conv & AD2_CHANNEL_MASK) >> AD2_CHANNEL_BIT;
voltage = (double) (conv & AD2_DATA_MASK) * 3.3 / (AD2_DATA_MASK + 1);
//conv = (buf[0] << 8) | buf[1];
//val = (double) (conv);
//val = (val * 3.3)/4096.0;
printf("CHANNEL %d = %.02f V\n\r", channel+1, voltage);
//an[AD2_CONV_CHANNEL(conv)] = AD2_CONV_VALUE(conv);
if (count == 2048) {
count = 0;
}
else {
count ++;
}
op_buff[1] = 0xff & count >>8;
op_buff[1] = 0xf0 | op_buff[1];
op_buff[2] = (u8) count;
//XSpi_SetSlaveSelect(&SpiInstance,0x01);
XSpiPs_PolledTransfer(&SpiInstance_MIO, op_buff, NULL,4);
usleep(100000);
}
}
To run the application on the baord we need to create a system debug project, this will allow us to download the Ultra96 configuration and the application just created
Once the board was running the test application, the first thing to do was to examine the signals being sent to and from the Pmod with a scope.
Here we are looking at the signal amplitudes, monotonic edges, reflections etc and noise anything which might lower the performance.
As can be seen below the signals to and from the Pmod look pretty good.
I2C signals SDA and SCL
SPI Signals -SCLK
SPI Signal - MOSI
Of course the SPI signals could benefit from the slew rate being set to fast in the constraints.
The final step was to test the DAC output with the scope, we should see a incrementing count implementing a saw tooth wave. This exactly what we see when observing the data with the scope.
Looking at the input of the ADC channel we also see this ramping value being correctly reported by the SW
This means we can be pretty happy that the Pmod interfaces work correctly as we are able to start developing Pmod applications for the Ultra96.
ConclusionWe have designed and commissioned a board which connects onto the Ultra96 and enables us to bring together a range of new sensors and breakout boards.
I cannot wait to get started using it!
Comments
Please log in or sign up to comment.