FPGA are great they come in a range of sizes from multi million logic cells to a few thousands. It is surprising what we can do with the smaller FPGA such as the Artix XC7A35T which offers 33280 system logic cells.
Many FPGA in this size are often used for IO expansion or companion chips however, you can create quite a high performance solution within devices of this class as you will see.
In this project we are going to create a embedded softcore processor which is running embedded Linux (PetaLinux in this case) and use it to communicate with a SPI DAC. Now of course we could write the RTL to do this very simply however, this project is about demonstrating how to create the embedded processor capable of working with Linux and how to work effectively with it. The DAC like many times in the project is there to provide a simple interface we can demonstrate is working under our control using a Digilent Analogue Discovery 3.
Vivado DesignTo get started with this we are first going to create a new project which targets the Arty A7-35T board. Once this project is open we are going to create a new block diagram and add onto it the DDR3 SDRAM and System Clock from the boards Tab.
Delete the external pins connected on the MIG for the system and reference clocks. Re-customise the clocking wizard to provide 100, 200 and 25 MHz clocks, turn off the reset also.
Connect the reference clock on the MIG to the 200 MHz output and the 100MHz to the system clock. Make the 25MHz external this will be used for the Ethernet reference clock.
Once this is added we can add to the block diagram the MicroBlaze and configure it using the block automation to be an application processor.
Re-Customise the MicroBlaze to enable the AXI Instruction Interface.
Running the connection automation will create the AXI network
The final design will look similar to below
Onto the diagram add in the following
- AXI UART - From the boards tab
- AXI Quad SPI
- AXI Timer - Dual Timer Enabled
- AXI Ethernet Lite - From the boards tab
Run the connection wizard to connect in the AXI network. Ensure for each of the modules added we connect to the interrupts to the AXI Interrupt Controller, via the concatenation block.
The final diagram, will look like the below - Script attached to project to recreate.
We can run the Synthesis and when it completes in the synthesis view use the IO planner view to assign the ports.
Once this is created we are good to start the generation and implementation of the bit stream.
Linux DevelopmentWe are going to create a embedded Linux OS for the MicroBlaze, as such we need a Linux development machine.
For this project I created a VMWare Virtual Machine, which was running Ubuntu 2018.4.06 LTS.
Onto this machine I installed Petalinux 2023.1 and Vivado Lab Edition 2023.1
With these created we can take the XSA file from the Vivado and create a new project. To transfer from Host to VM you can simply copy and paste, I created a new projects directory on the VM and copied the XSA into there.
Inside a terminal in the VM we need to set up the PetaLinux and Vivado Lab tools run the following commands in the same terminal. The path might change depending on your installation paths.
source /tools/Xilinx/Vivado_Lab/2023.1/settings64.sh
source /petalinux/settings.sh
Now we can create the project
petalinux-create --type project --template microblaze --name linux_mb
CD into the project directory and run the command to configure the project depending upon the hardware in the XSA
petalinux-config --get-hw-description ../
This will open the system configuration, we want to change nothing so exit and save.
We do need to enable the SPI User Space Drivers to do this we issue the command
petalinux-config -c kernel
In the dialog which is opened we need to enable the SPI User Space drivers, enable these then save and exit the configuration.
The final thing we need to do is set the device tree to use pick up the SPI Dev. To get the SPI Dev to bind to our SPI device we need to tell it, the name of the device supported in the SPI Dev software. Hence I picked the Rohm device.
The device tree to change is found under the
<project location>linux_mb/project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi
Make the following edits
/include/ "system-conf.dtsi"
/ {
};
&axi_quad_spi_0 {
status = "okay";
spidev@0 {
compatible = "rohm,dh2228fv";
spi-max-frequency = <50000000>;
reg = <0>;
};
};
Close and save the device tree file
To build the project issue the command
petalinux-build
This might take a little while.
Once the build is completed, connect and power up the Arty A7, ensure the USB JTAG / Serial Port is forwarded to the VM and issue the following commands
petalinux-boot -jtag fpga
After this you should see the done LED on the FPGA illuminate, then issue the command
petalinux-boot -jtag kernel
With a serial terminal GtkTerm is recommended, you should be able to see the board boot Linux. Once it has completed, we are ready to start development of the software.
To debug and develop software on a embedded Linux application we need to the Linux debugging agent on the MicroBlaze.
This will allow us to download and test a application running in User Space, This means we need a Ethernet connection between the development machine and the Arty A7.
I used a USB Ethernet dongle to enable a direct connection to my development machine. This means on the MicroBlaze we need to set the IP address and subnet once Linux has booted.
Using a serial terminal we can log in, username petalinux and change the password to one desired.
Enter the command below - make sure you adjust the IP address for YOUR system.
sudo ifconfig eth0 192.100.1.2 netmask 255.255.255.0
Once this is completed we can open VITIS and create a new platform project based of the XSA and a new Application project with a Linux OS. In the application project I created the simple hello world example.
Into this example we have added the SPI Dev and configured it for operation as we need in the
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <fcntl.h>
#include <time.h>
#include <sys/ioctl.h>
#include <linux/ioctl.h>
#include <sys/stat.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#include <stdio.h>
#define ARRAY_SIZE(array) sizeof(array)/sizeof(array[0])
static const char *spi_device = "/dev/spidev0.0";
int main()
{
static uint8_t bits = 32;
static uint32_t speed = 20000000;
static uint32_t mode = SPI_MODE_0 ;
static uint16_t delay = 1;
int spi;
int ret = 0;
uint32_t spi_tx_buf[1];
uint32_t spi_rx_buf[1];
struct spi_ioc_transfer tr = {
.tx_buf = (uint32_t) spi_tx_buf,
.rx_buf = (uint32_t) spi_rx_buf,
.len = 4, //ARRAY_SIZE(spi_tx_buf),
.delay_usecs = delay,
.speed_hz = 0,
.bits_per_word = 0,
};
//Open SPI
spi = open(spi_device, O_RDWR);
if (spi < 0)
printf("can't open SPI device\n\r");
ret = ioctl(spi, SPI_IOC_WR_MODE32, &mode);
if (ret == -1)
printf("can't set spi wr mode\n\r");
ret = ioctl(spi, SPI_IOC_RD_MODE32, &mode);
if (ret == -1)
printf("can't get spi rd mode\n\r");
ret = ioctl(spi, SPI_IOC_WR_BITS_PER_WORD, &bits);
if (ret == -1)
printf("can't set bits per word\n\r");
ret = ioctl(spi, SPI_IOC_RD_BITS_PER_WORD, &bits);
if (ret == -1)
printf("can't get bits per word\n\r");
ret = ioctl(spi, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if (ret == -1)
printf("can't set max speed hz\n\r");
ret = ioctl(spi, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
if (ret == -1)
printf("can't get max speed hz\n\r");
spi_tx_buf[0] = (uint32_t) 0x08000001; //enable sampling
ret = ioctl(spi, SPI_IOC_MESSAGE(1), &tr);
if (ret == -1)
perror("write error set up:");
spi_tx_buf[0] = (uint32_t) 0x04000003; //enable sampling
ret = ioctl(spi, SPI_IOC_MESSAGE(1), &tr);
if (ret == -1)
perror("write error set up:");
spi_tx_buf[0] = (uint32_t) 0x03fff000; //enable sampling
ret = ioctl(spi, SPI_IOC_MESSAGE(1), &tr);
if (ret == -1)
perror("write error:");
uint16_t output=0;
uint32_t data_out = 0x03f00000;
while(1){
if (output == 0xfff){
output = 0x0;
} else {
output ++;
}
spi_tx_buf[0] = (uint32_t) data_out | (output <<8); //enable sampling
ret = ioctl(spi, SPI_IOC_MESSAGE(1), &tr);
if (ret == -1)
perror("write error:");
}
return 0;
}
TestingWith the Analogue Discovery 3 we are able to instrument the Pmod DA4, we can use the oscilloscope to look at the analogue outputs and the logic analyser to observe the SPI data
Setting up the DAC, we need to turn on the internal reference and power up the DACs we want to use.
We can see the output waveform here, using the Analogue Discovery 3 oscilloscope feature
This project has demonstrated that we can create a simple softcore processor in the cost optimised device which is capable of running embedded Linux. This enables us to leverage the Linux features when we are implementing the sequential processing.
Comments