This project is going to use the real digital blackboard to implement a simple signal processing chain using the XDAC and DMA to transfer the signals into the memory.
If you are not familiar the Real Digital Black board is a Zynq 7007S single core device which is ideal for learning Zynq development.
To get started with the real digital black board the first thing we need to do is download the assets from real digital GitHub.
https://github.com/RealDigitalOrg/Blackboard/releases/tag/1.0.0-beta
This will provide us with the configuration scripts for the processing system and its clocking and DDR configuration.
In this example we will be connecting to the XADC channels made available over the XADC Auxiliary channels on the Pmod interface.
We are doing this because on the Blackboard the dedicated Vp/Vn interface is connected to a Potentiometer. This is of course great to teaching but in this project we want to capture a real signal
Creating the Vivado ProjectUnlike with many previous projects we are not going to start the project targeting a board but a component. Create a new project using the xc7007sclg400-1
Once the project has been created, the next step is to create a IP Integrator block diagram. Add in a Zynq processing system.
To configure the Zynq PS as for the Blackboard we need to apply the script we downloaded earlier. Double click on the Zynq block to re-customise and select apply configuration.
in the dialog which appears select the Blackboard presets tcl file and click OK
This will configure the Zynq PS correctly for the Blackboard configuration
Once we close the re-customization window we are able to then re run the block automation
At the completion of the block automation the Zynq processing system shall be configured for use in our application.
To get started being able to receive a signal we need to add in the XADC to the IP Integrator block diagram
Once the XADC is added the next stage is to configure the XADC for use.
As we want to stream the data out of the XADC and use DMA we need to enable the AXIS Stream interface.
I also disabled all of the alarms
Finally I enabled the Auxiliary input channels which are connected to the Pmod
Once the XADC is connected, run the connection automation to connect the XADC to the Zynq PS using the AXI Lite network.
The completed block diagram should look like below.
Right clock on the Vaux0 Channel and select make external
The next step is to connect the AXIS output from the XADC to the S_AXI input on the Zynq PS Block.
This connection will enable Vivado to create a DMA system between the XADC and the Processing System.
The completed diagram will be as shown below
Run the connection automation and the AXI Lite connection on the DAM will be added into the AXI Lite network.
The completed diagram will be as below.
However, the XADC AXI Stream output does not have all of the signals necessary to support the DMA. The TLast signal is not provided on the AXIS Stream output
This will prevent the DMA from working correctly as such we need to select the AXIS output between the XADC and the DMA input
Delete the signal
Add in a AXI Subset convertor
Connect this between the XADC AXI Stream output and the DMA Input
Re customize the AXI Subset convertor to provide the Tlast and generate it every 256 transfers.
Once this is completed, we are able to validate the block design, there should be no errors or critical warnings.
The next stage is to create the HDL wrapper for the project and generate the bitstream. This might take a few minutes.
Once the design is completed, export the XSA including the bitstream.
From Vivado open Vitis and select a workspace for the software development.
Create a new application project and select the XSA just exported from Vivado to define the platform.
Create a new application project targeting the single A9 processor
Create the domain using standalone operating system
Select the hello world application template.
Once the project is created we need tp update the BSP to use PS UART1 for serial communications.
We will also be using the The software system,
The software application will capture samples from the XDAC and store them on the SD Card. This means the SD Card can be used for storing data and make the data available for post analysis if desired.
The software application in its entirety is
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "stdlib.h"
#include "xsysmon.h"
#include "xaxidma.h"
#include "ff.h"
#define SYSMON_DEVICE_ID XPAR_SYSMON_0_DEVICE_ID
#define DMA_DEV_ID XPAR_AXIDMA_0_DEVICE_ID
#define DDR_BASE_ADDR XPAR_AXIDMA_0_BASEADDR
#define RX_BUFFER_BASE (0x00100000)
#define MAX_PKT_LEN 512 //bytes
XSysMon SysMonInst;
int main()
{
int Status;
u8 xfer_size;
u16 TempData;
int Temp;
int reset_done;
u16 *RxBufferPtr;
u32 value;
u32 addr;
XSysMon_Config *SYSConfigPtr ;
XSysMon* SysMonInstPtr = &SysMonInst;
XAxiDma_Config *CfgPtr;
XAxiDma AxiDma;
UINT NumBytesWritten;
int i,len,position,n;
static FIL fil; /* File object */
static FATFS fatfs; // Pointer to the filesystem object
static char FileName[50] = "XADC.CSV";
static char *SD_File;
char buffer[100] ;
UINT *ByteRead;
FRESULT Res;
TCHAR *Path = "0:/";
u32 BuffCnt;
Res = f_mount(&fatfs, Path, 0); //0 is the mounting option
SD_File = (char *)FileName;
init_platform();
print("Hello World\n\r");
SYSConfigPtr = XSysMon_LookupConfig(SYSMON_DEVICE_ID);
if (SYSConfigPtr == NULL) {
return XST_FAILURE;
}
CfgPtr = XAxiDma_LookupConfig(DMA_DEV_ID);
if (!CfgPtr) {
printf("No config found for %d\r\n", DMA_DEV_ID);
return XST_FAILURE;
}
Status = XAxiDma_CfgInitialize(&AxiDma, CfgPtr);
if (Status != XST_SUCCESS) {
printf("Initialization DMA failed %d\r\n", Status);
return XST_FAILURE;
}
XSysMon_CfgInitialize(SysMonInstPtr, SYSConfigPtr, SYSConfigPtr->BaseAddress);
XSysMon_SetSequencerMode(SysMonInstPtr, XSM_SEQ_MODE_SAFE);
XSysMon_SetAlarmEnables(SysMonInstPtr, 0x0);
XSysMon_SetSeqChEnables(SysMonInstPtr, XSM_SEQ_CH_AUX00);
XSysMon_SetAdcClkDivisor(SysMonInstPtr, 32);
XSysMon_SetSequencerMode(SysMonInstPtr, XSM_SEQ_MODE_CONTINPASS);
//TempData = XSysMon_GetAdcData(SysMonInstPtr, XSM_CH_TEMP);
//Temp = XSysMon_RawToTemperature(TempData);
RxBufferPtr = (u16 *)RX_BUFFER_BASE;
addr = (u32)RX_BUFFER_BASE;
XAxiDma_Reset(&AxiDma);
reset_done = XAxiDma_ResetIsDone(&AxiDma);
while(reset_done != 1){
}
XAxiDma_IntrDisable(&AxiDma, XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DEVICE_TO_DMA);
XAxiDma_IntrDisable(&AxiDma, XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DMA_TO_DEVICE);
while(1){
Status = XAxiDma_SimpleTransfer(&AxiDma,(u32) RX_BUFFER_BASE,MAX_PKT_LEN, XAXIDMA_DEVICE_TO_DMA);
if (Status != XST_SUCCESS) {
printf("XFER failed %d\r\n", Status);
return XST_FAILURE;
}
while ((XAxiDma_Busy(&AxiDma,XAXIDMA_DEVICE_TO_DMA))){
/* Wait */
}
position = 0;
Xil_DCacheFlushRange((UINTPTR)RxBufferPtr, MAX_PKT_LEN);
Res = f_open(&fil, SD_File, FA_CREATE_ALWAYS | FA_WRITE | FA_READ);
Res = f_lseek(&fil, 0);
for(i=0;i<MAX_PKT_LEN/2;i++){
n=sprintf(buffer, "%d,%04x\r\n",i,RxBufferPtr[i]);
Res = f_lseek(&fil, position); //find ext write position
Res = f_write(&fil, (const void*)buffer, MAX_PKT_LEN,&NumBytesWritten);
len = strlen(buffer);
position=position+len;
}
Res = f_close(&fil);
return 0;
//usleep(1000000);
}
cleanup_platform();
}
This will provide us a with a CSV on the SD card of the samples from the XADC.
Wrap UpThis project is a nice and simple introduction to the Real Digital Blackboard and shows how we can easily get up and running and working with simple signal processing examples.
We can of course add to this using Vitis HLS if we wanted to do signal processing.
Comments