This is a bare-bones Vivado project for the Red-Pitaya/STEMlab boards. It is meant to be a starting point for custom designs with the Red Pitaya. HDL code is written in VHDL, and it includes modules for reading from the ADCs, writing to the DACs, writing to the PWM outputs, reading from the "slow" ADC inputs using the programmable logic, as well as a simplified interface for reading/writing to the device via the AXI interface.
This project has been written to interface with a personal computer (PC) running MATLAB via a TCP/IP socket server running on the Red Pitaya (RP). The necessary MATLAB class definitions for your PC and Python code for running on the RP can be found in this interface repository. See the "Set up" section below or the README in the interface repository.
Once the FPGA bitstream is uploaded and the Python server is running, the suite of MATLAB classes can be used to send and receive data. Create an instance of
dev = DeviceControl(ip_addr);
where ip_addr
is the IP address of the Red Pitaya; you can also use the hostname if you prefer. You can then fetch data using dev.fetch
and upload data using dev.upload
. Refer to the code to see how this works.
DAC outputs can be written using dev.dac(<index>).set(<value>).write
where <index>
is either 1 or 2 and <value>
is a value in volts between -1 V and 1 V.
Fast ADC inputs can be read using dev.adc(<index>).read
where <index>
is either 1 or 2. The value in volts is then stored in dev.adc(<index>).value
. Make sure that dev.jumpers
is set correctly.
PWM outputs can be written using dev.pwm(<index>).set(<value>).write
where <index>
is an integer between 1 and 4 and <value>
is a value in volts between 0 and 1.62 V. The PWM outputs are clocked at 250 MHz and the data for each output are 8 bits long leading to a PWM period of
Slow ADC inputs can be read using dev.slow_adcs(<index>).read
where <index>
is an integer between 1 and 4. The value in volts is then stored in dev.slow_adcs(<index>).value
.
You can query the device status as read through the XADC system, which includes temperature and supply voltages, using dev.get_xadc_status
.
For testing purposes, a block memory element with 256 address spaces and a write/read data with of 32 has been included to show how to write to and read from a memory element. The C program 'testMemory.c' can be used for this purpose. Copy it to the Red Pitaya, compile it using the command 'gcc -o testMemory testMemory.c', and then run it using './testMemory 10' to write to and then read from 10 addresses in sequence. You can replace '10' with any integer up to 255. You can also use the methods dev.memwrite(<data>)
and dev.memread(<num_samples>)
to test it with the MATLAB interface.
When creating the project, make sure to use the correct Vivado version. The Git version v2020.2 works for Vivado 2020.2, while the version v2023.1 works for Vivado 2023.1, and so on. The TCL script used to create the Vivado projects are unfortunately not interchangeable.
To create the project, clone the repository to a directory on your computer, open Vivado, navigate to the fpga/ directory (use pwd
in the TCL console to determine your current directory and cd
to navigate, just like in Bash), and then run source make-project.tcl
which will create the project files under the directory basic-project
. If you want a different file name, open the make-project.tcl
file and edit the line under the comment # Set the project name
. This should create the project with no errors. It may not correctly assign the AXI addresses, so you will need to open the address editor and assign the PS7/AXI_Parse_0/s_axi
interface the address range 0x4000_000
to 0x7fff_ffff
.
Connect the Red Pitaya (RP) to power via the USB connector labelled PWR (on the underside of the board, it's the connector closest to the edge of the board), and connect the device to the local network using an ethernet cable. Log into the device using SSH with the user name root
and password root
using the hostname rp-{MAC}.local
where {MAC}
is the last 6 characters in the device's MAC address - this will be printed on the ethernet connector of the device.
Clone the interface repository to your computer, and then copy over all files in that directory ending in '.py' and '.sh' using either scp
(from a terminal on your computer) or your favourite GUI (I recommend WinSCP for Windows). Make sure to add this directory to your MATLAB path.
You will also need to copy over the file 'fpga/system_wrapper.bit' which is the device configuration file. If using scp
from the command line, navigate to the main project directory on your computer and use
scp fpga/system_wrapper.bit software/*.c root@rp-{MAC}.local:/root/
and give your password as necessary. You can move these files to a different directory on the RP after they have been copied.
Next, change the execution privileges of get_ip.sh
using chmod a+x get_ip.sh
. Check that running ./get_ip.sh
produces a single IP address (you may need to install dos2unix using apt install dos2unix
and then run dos2unix get_ip.sh
to make it work). If it doesn't, run the command ip addr
and look for an IP address that isn't 127.0.0.1
(which is the local loopback address). There may be more than one IP address -- you're looking for one that has tags 'global' and 'dynamic'. Here is the output from one such device:
root@rp-f0919a:~# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:26:32:f0:91:9a brd ff:ff:ff:ff:ff:ff
inet 169.254.176.82/16 brd 169.254.255.255 scope link eth0
valid_lft forever preferred_lft forever
inet 192.168.1.109/24 brd 192.168.1.255 scope global dynamic eth0
valid_lft 77723sec preferred_lft 77723sec
3: sit0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1
link/sit 0.0.0.0 brd 0.0.0.0
In this case the one we want is the address 192.168.1.109
. In this case, get_ip.sh
will work because it looks for an IP address with the 'global' tag. If you have your RP connectly directly to your PC, then you will need to use the relevant IP address: in the above example, it is the address '169.254.176.82'.
Finally, compile the C program testMemory.c
using gcc -o testMemory testMemory.c
. This will automatically be executable.
You will need to re-configure the FPGA and start the Python socket server after a reboot. To re-configure the FPGA run the command
cat system_wrapper.bit > /dev/xdevcfg
To start the Python socket server run
python3 appserver.py &
This should print a line telling you the job number and process ID as, for example, [1] 5760
, and a line telling you that it is 'Listening on' and then an address and port number. The program will not block the command line and will run in the background as long as the SSH session is active (The ampersand & at the end tells the shell to run the program in the background). To stop the server, run the command fg 1
where 1
is the job number and then hit 'CTRL-C' to send a keyboard interrupt.
You will need to check that the socket server is running. Run the command
ps -ef | grep appserver.py
This will print out a list of processes that match the pattern appserver.py
. One of these might be the grep
process itself -- not especially useful -- but one might be the socket server. Here's an example output:
root 5768 5738 7 00:59 pts/0 00:00:00 python3 appserver.py
root 5775 5738 0 01:00 pts/0 00:00:00 grep --color=auto appserver.py
The first entry is the actual socket server process and the second one is the grep
process. If you need to stop the server, and it is not in the jobs list (run using jobs
), then you can kill the process using kill -15 5768
where 5768
is the process ID of the process (the first number in the entry above).
If you want the server to run you don't need to do anything. If the server is not running, start it using python3 appserver.py
.