Copyright (c) 2021-2022 Antmicro.
This README describes new FPGA-related subsystems which allow users to control FPGA chips using the Zephyr real-time operating system.
The main part is the FPGA controller itself. It is a completely new Zephyr subsystem developed to enable communication between Zephyr and FPGAs. The subsystem is described in more detail in the following sections.
In addition to that, a serial loader command has been added to Zephyr. It allows users to load arbitrary data to the memory of a board running Zephyr over the serial interface. It ties well with the FPGA subsystem - as described below, it can be used to easily transfer bitstream files into the memory, and later load them onto the FPGA using the new controller subsystem.
The FPGA controller has been created to:
- have control over the FPGA from Zephyr
- enable bitstream loading into the FPGA
The work on the controller consisted of several parts:
- a completely new API, which enables the users to check the status of the FPGA chip, power it on or off, and change the contents of the reprogrammable logic
- FPGA drivers, the controller currently supports the EOS S3 chip with its embedded FPGA, and Xilinx US+ FPGAs (using Antmicro's Mercury XU port)
- a new Zephyr shell command which allows users to check the status, control and reprogram the FPGA using the Zephyr shell subsystem
The serial loader is a new Zephyr shell command that allows users to easily load arbitrary data into the device memory.
In this case it is used to load bitstream files, which can then be used in combination with the new fpga
command to reprogram the FPGA chip.
The FPGA subsystem for QuickLogic QuickFeather board is already mainlined. In case of subsystem for Xilinx US+ FPGA (using Antmicro's Mercury XU port), it is still in the process of mainlining, for now use our fork of Zephyr. You can find the fork containing all the relevant changes here.
This example demonstrates how to use the FPGA driver API. The described sample works with the QuickLogic QuickFeather board.
Please refer to Zephyr's official getting started guide for detailed setup instructions.
Then, build the sample for the quick_feather
board:
cd zephyr
west build -b quick_feather samples/drivers/fpga/fpga_loader/quickfeather/
See QuickFeather programming and debugging for instructions on how to load an image to the board.
Once the board is programmed, the LED should alternately flash red and green. Note that the blinking is not controlled by software. There are two bistreams: one lights up the red LED, the other one lights up the green LED. One bitstream replaces the other in a continuous loop to demonstrate dynamic FPGA reprogramming from Zephyr.
This example demonstrates how to use the FPGA driver API. The described sample works with the Antmicro's Mercury XU port
Please refer to Zephyr's official getting started guide for detailed setup instructions.
The first step is to initialize the workspace folder (workspace
) where
the app and all Zephyr modules will be cloned. You can do
that by running:
west init -m https://github.com/antmicro/zephyr-fpga-controller-examples --mr master workspace
cd workspace
west update
Then, build the sample for the mercury_xu
board:
cd zephyr-fpga-controller-examples
west build -b mercury_xu app/
See Zephyr RTOS and Cortex-R5 on Zynq UltraScale+ for instructions on how to load an image to the board.
Once the board is programmed, the LED should blink. Note that the blinking is not controlled by software. There are two bitstreams: one blinks slower than the other one. One bitstream replaces the other in a continuous loop to demonstrate dynamic FPGA reprogramming from Zephyr.
This sample demonstrates how to use the FPGA driver API along with the Serial loader subsystem in Zephyr Shell. Currently, the sample works with the QuickLogic QuickFeather board.
Follow the instructions from the previous chapter to download the sources.
Then, build the sample for the QuickLogic QuickFeather board with the following command:
west build -b quick_feather samples/drivers/fpga/fpga_loader_shell
See QuickFeather programming and debugging for instructions on how to load an image to the board.
After connecting to the UART console you should see the following output:
Address of bitstream (red): 0xADDR
Address of bitstream (green): 0xADDR
Size of bitstream (red): 75960
Size of bitstream (green): 75960
uart:~$
This sample is already prepared with two bitstreams. After executing the sample, you can see at what address it is stored and its size in bytes.
The FPGA loader command can now be used (fpga load <device> <size in bytes> <address>
):
uart:~$ fpga load FPGA 75960 0xADDR
FPGA: loading bitstream
The LED should start blinking (color depending on the selected bitstream). To upload the bitstream again, you need to reset the FPGA:
uart:~$ fpga reset FPGA
FPGA: resseting FPGA
You can also use your own bitstream.
To load a bitstream into the device memory, use the serial loader
subsystem.
It is important to use the -e option when sending the bitstream via xxd
:
uart:~$ serial load -e 0x10000
Loading...
Press ctrl+d to stop
Now, the serial loader is waiting for data.
You can either type it directly from the console or send it from the host PC (replace ttyX
with the appropriate one for your UART console):
xxd -p data > /dev/ttyX
(It is important to use a plain-style hex dump)
Once the data is transferred, use ctrl+d
to quit the loader.
It will print the sum of the read bytes and return to the shell:
sum of bytes read: 75960
uart:~$
Now the bitstream can be uploaded again.
uart:~$ fpga load FPGA 75960 0x10000
FPGA: loading bitstream