AXI Lite Memory Mapped Interface
AXI IP in Vivado
In order to work with an AXI Lite device, we created a new AXI IP in Vivado.
In our Vivado project, we selected Tools → Create and Package New IP → Next → Create a new AXI4 peripheral → Next.
In the Peripheral Details tab we can give the peripheral an appropriate name, description and location. After this, we click Next again.
On the next page, we can configure the AXI bus interface. In our project we will work with an AXI Lite with a Data Width of 32 bits in Slave mode. Hence, we will stick with the default values.
Lastly, we click Finish, after selecting Edit IP. We go to the Packaging Steps of our IP and select Package for IPI and Ignore Freq_Hz in the Compatibility-tab. After this, we Re-Package the IP and add it do our block design. Here we connect it's clock and reset to those of the Processor System Reset and connect the Slave to the AXI Interconnect. Now the bitstream can be generated and the XSA can be exported to use in our PetaLinux project.
Custom Kernel Driver for AXI Lite
Creating the User Module
To be able to acces the AXI Lite registers from user-space, we started developing a custom kernel driver for the AXI Lite interface. Due to a time shortage, the driver wasn't finished for our final project and we accessed the registers as root, but here you can find the steps we executed to try to achieve this goal.
We created the custom user module using the petalinux-create command within our PetaLinux project environment:
This command generates a new module located at:
/project-spec/meta-user/recipes-modules/axi-lite
This directory contains a template for a PetaLinux kernel module, including the following files:
axi-lite.bb– BitBake recipe for building the module.axi-lite.c– The C source file for the driver.Makefile– Build instructions for the kernel module.
Customizing the Driver
We made significant modifications to the axi-lite.c template to tailor it to our requirements:
-
Interrupts Removal: Interrupt handling was removed from the module as it was not required for our use case.
-
AXI Lite Probe and Remove Functions:
- The
axi_lite_probefunction was rewritten to handle device initialization specifically for our AXI Lite interface. - The
axi_lite_removefunction was updated to manage proper cleanup when the device is removed.
- The
-
AXI Lite Read and Write Functions: We added custom functions to handle reading from and writing to the AXI Lite interface. These functions enable direct interaction with the device memory space.
-
Updating the Device Compatibility: We modified the
.compatibleproperty in thestatic struct of_device_id axi_lite_of_match[]array. This ensures that our custom driver is correctly associated with the device during kernel initialization. Additionally, the corresponding compatible property needs to be updated in the device tree.
The updated version of the axi-lite.c template can be found on our Gitlab repository, together with the other driver files.
Updating the Device Tree
We added the custom compatible property to the device tree by modifying the system-user.dtsi file located at
/project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi.
This file allows us to overwrite the compatible property defined in the default device tree at /images/linux/system.dts. system.dtsis not directly available in /images/linux/, but can be created by executing dtc -I dtb -O dts -o system.dts system.dtbfrom terminal.
We will add the following snippet to system-user.dtsi:
Later on during the project we used audio_pipeline_IP@a0050000 instead of axi_lite@a004000.
Adding our module to the build
Before building the module, run the following command to access the menuconfig interface for the root filesystem:
In the menuconfig interface, navigate to theUser Packages submenu, ensure that the axi-lite module is enabled and save and exit the configuration menu. We will first build the kernel to ensure all dependencies are resolved and then build the AXI Lite module. We do this by executing the following commands:
To update the target filesystem and bootable images with the compiled module, rebuild the root filesystem and the bootable images:
To make sure we correctly compiled the module, installed it to the target filesystem host copy and updated the bootable images, we can run the following command again:
We can now create the boot files and the wic-image and flash it to our SD card so we are able to boot the system.Testing our custom kernel driver
After booting our system, we can test the functionality of our newly created driver.
The driver will be directly loaded into the kernel during the boot process. We can verify this by running lsmod:
blendinator:~$ lsmod
Module Size Used by
iptable_nat 16384 0
nf_nat 36864 1 iptable_nat
iptable_filter 16384 0
wilc_sdio 98304 0
cfg80211 360448 1 wilc_sdio
zocl 196608 0
axi_lite 16384 0
uio_pdrv_genirq 16384 0
nfsd 114688 1
When we run a grepon dmesg, we can also verify that we succesfully probed:
blendinator:~$ dmesg | grep "axi-lite"
[ 9.240845] axi-lite a0040000.axi_lite: Probing AXI-Lite
[ 9.240908] axi-lite a0040000.axi_lite: axi-lite at 0xa0040000 mapped to 0x09b60000
Furthermore, we can also take a look at iomem. If we run sudo cat /proc/iomem, we can see the AXI Lite with an adress space from 0xa0040000 to 0xa004ffff, just like we expected:
blendinator:~$ sudo cat /proc/iomem
Password:
00000000-3ecfffff : System RAM
...
a0030000-a003ffff : a0030000.dma dma@a0030000
a0040000-a004ffff : a0040000.axi_lite axi_lite@a0040000
fd0b0000-fd0bffff : fd0b0000.perf-monitor perf-monitor@fd0b0000
...
ffaf0000-ffaf0fff : ffaf0000.dma-controller dma-controller@ffaf0000
rmmod, the AXI Lite will be removed from iomem:
blendinator:~$ sudo rmmod /lib/modules/6.1.30-xilinx-v2023.2/extra/axi-lite.ko
Password:
blendinator:~$ sudo cat /proc/iomem
Password:
00000000-3ecfffff : System RAM
...
a0030000-a003ffff : a0030000.dma dma@a0030000
fd0b0000-fd0bffff : fd0b0000.perf-monitor perf-monitor@fd0b0000
...
ffaf0000-ffaf0fff : ffaf0000.dma-controller dma-controller@ffaf0000
insmod:
AXI Lite Memory Mapped registers
Our audio pipeline has 94 registers to control the various filters and audio effects. All these registers are 32 bit. Some of the filters and audio effect modules need a strobe to ensure that the data will be correctly stored in the filters and audio effects. When the strobe is active, all the data of the different registers that belong to the filter or audio effect will be loaded in the filter or audio effect at the same time. So, it is important to first load all the registers with valid data before enabling the strobe.
Some modules have a channel_address register. This has to be loaded with the address of the source you want to control. Evey source has two addresses, one for the left channel and one for the right channel. In our current configuration, channel address 0 and 1 belong to the left and right channel of the analog source and channel address 2 and 3 belong to the left and right channel of the DMA source.
volume
The channel_value register controls the volume of all the the input signals before they enter the audio pipeline. The value has to be between 0 and 1 V/V.
| Name | PS Addr | PS Numerical Format | PL Addr | PL Numerical Format |
|---|---|---|---|---|
| channel_value | 0xA0050000 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg0 | sfixed(0 downto -23) |
band_volume
- The
channel_valueregister controls the gain of the band shelf. The value has to be between 0.05 and 2 V/V. - The
channel_addressregister has to be loaded with the address for which thechannel_valuebelongs.
| Name | PS Addr | PS Numerical Format | PL Addr | PL Numerical Format |
|---|---|---|---|---|
| channel_value | 0xA0050004 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg1 | sfixed(1 downto -23) |
| channel_address | 0xA0050008 | Integer | slv_reg2 | std_logic_vector(1 downto 0) |
| strobe | 0xA005000C | Boolean | slv_reg3 | std_logic |
biquad_tdm
- The
b0,b1,b2,a1anda2registers are for the coëfficients of the biquad filter. The value has to be between 0 and 8. - The
channel_addressregister has to be loaded with the address for which theb0,b1,b2,a1anda2belongs.
Because we have an 8th order band shelf filter, 4th order low shelf filter, 4th order high shelf filter, 2nd order low pass filter and 4th order high pass filter, we need 4, 2, 2, 1 and 2 biquad filters respectively to make these filters.
Band Shelf Low 1
These are the registers for the first (of the 2) Low Shelf filters needed to make the Band Shelf. (If you have no idea how to make the band shelf filter or the filters/audio effects in general, please check the Filters/MATLAB and Filters/HDL documentation)
| Name | PS Addr | PS Numerical Format | PL Addr | PL Numerical Format |
|---|---|---|---|---|
| b0 | 0xA0050010 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg4 | sfixed(3 downto -23) |
| b1 | 0xA0050014 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg5 | sfixed(3 downto -23) |
| b2 | 0xA0050018 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg6 | sfixed(3 downto -23) |
| a1 | 0xA005001C | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg7 | sfixed(3 downto -23) |
| a2 | 0xA0050020 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg8 | sfixed(3 downto -23) |
| channel_address | 0xA0050024 | Integer | slv_reg9 | std_logic_vector(1 downto 0) |
| strobe | 0xA0050028 | Boolean | slv_reg10 | std_logic |
Band Shelf Low 2
These are the registers for the second (of the 2) Low Shelf filters needed to make the Band Shelf.
| Name | PS Addr | PS Numerical Format | PL Addr | PL Numerical Format |
|---|---|---|---|---|
| b0 | 0xA005002C | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg11 | sfixed(3 downto -23) |
| b1 | 0xA0050030 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg12 | sfixed(3 downto -23) |
| b2 | 0xA0050034 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg13 | sfixed(3 downto -23) |
| a1 | 0xA0050038 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg14 | sfixed(3 downto -23) |
| a2 | 0xA005003C | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg15 | sfixed(3 downto -23) |
| channel_address | 0xA0050040 | Integer | slv_reg16 | std_logic_vector(1 downto 0) |
| strobe | 0xA0050044 | Boolean | slv_reg17 | std_logic |
Band Shelf High 1
These are the registers for the first (of the 2) High Shelf filters needed to make the Band Shelf.
| Name | PS Addr | PS Numerical Format | PL Addr | PL Numerical Format |
|---|---|---|---|---|
| b0 | 0xA0050048 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg18 | sfixed(3 downto -23) |
| b1 | 0xA005004C | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg19 | sfixed(3 downto -23) |
| b2 | 0xA0050050 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg20 | sfixed(3 downto -23) |
| a1 | 0xA0050054 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg21 | sfixed(3 downto -23) |
| a2 | 0xA0050058 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg22 | sfixed(3 downto -23) |
| channel_address | 0xA005005C | Integer | slv_reg23 | std_logic_vector(1 downto 0) |
| strobe | 0xA0050060 | Boolean | slv_reg24 | std_logic |
Band Shelf High 2
These are the registers for the second (of the 2) High Shelf filters needed to make the Band Shelf.
| Name | PS Addr | PS Numerical Format | PL Addr | PL Numerical Format |
|---|---|---|---|---|
| b0 | 0xA0050064 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg25 | sfixed(3 downto -23) |
| b1 | 0xA0050068 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg26 | sfixed(3 downto -23) |
| b2 | 0xA005006C | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg27 | sfixed(3 downto -23) |
| a1 | 0xA0050070 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg28 | sfixed(3 downto -23) |
| a2 | 0xA0050074 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg29 | sfixed(3 downto -23) |
| channel_address | 0xA0050078 | Integer | slv_reg30 | std_logic_vector(1 downto 0) |
| strobe | 0xA005007C | Boolean | slv_reg31 | std_logic |
Low Shelf 1
These are the registers for the first (of the 2) Low Shelf filters.
| Name | PS Addr | PS Numerical Format | PL Addr | PL Numerical Format |
|---|---|---|---|---|
| b0 | 0xA0050080 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg32 | sfixed(3 downto -23) |
| b1 | 0xA0050084 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg33 | sfixed(3 downto -23) |
| b2 | 0xA0050088 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg34 | sfixed(3 downto -23) |
| a1 | 0xA005008C | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg35 | sfixed(3 downto -23) |
| a2 | 0xA0050090 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg36 | sfixed(3 downto -23) |
| channel_address | 0xA0050094 | Integer | slv_reg37 | std_logic_vector(1 downto 0) |
| strobe | 0xA0050098 | Boolean | slv_reg38 | std_logic |
Low Shelf 2
These are the registers for the second (of the 2) Low Shelf filters.
| Name | PS Addr | PS Numerical Format | PL Addr | PL Numerical Format |
|---|---|---|---|---|
| b0 | 0xA005009C | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg39 | sfixed(3 downto -23) |
| b1 | 0xA00500A0 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg40 | sfixed(3 downto -23) |
| b2 | 0xA00500A4 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg41 | sfixed(3 downto -23) |
| a1 | 0xA00500A8 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg42 | sfixed(3 downto -23) |
| a2 | 0xA00500AC | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg43 | sfixed(3 downto -23) |
| channel_address | 0xA00500B0 | Integer | slv_reg44 | std_logic_vector(1 downto 0) |
| strobe | 0xA00500B4 | Boolean | slv_reg45 | std_logic |
High Shelf 1
These are the registers for the first (of the 2) High Shelf filters.
| Name | PS Addr | PS Numerical Format | PL Addr | PL Numerical Format |
|---|---|---|---|---|
| b0 | 0xA00500B8 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg46 | sfixed(3 downto -23) |
| b1 | 0xA00500BC | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg47 | sfixed(3 downto -23) |
| b2 | 0xA00500C0 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg48 | sfixed(3 downto -23) |
| a1 | 0xA00500C4 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg49 | sfixed(3 downto -23) |
| a2 | 0xA00500C8 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg50 | sfixed(3 downto -23) |
| channel_address | 0xA00500CC | Integer | slv_reg51 | std_logic_vector(1 downto 0) |
| strobe | 0xA00500D0 | Boolean | slv_reg52 | std_logic |
High Shelf 2
These are the registers for the second (of the 2) High Shelf filters.
| Name | PS Addr | PS Numerical Format | PL Addr | PL Numerical Format |
|---|---|---|---|---|
| b0 | 0xA00500D4 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg53 | sfixed(3 downto -23) |
| b1 | 0xA00500D8 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg54 | sfixed(3 downto -23) |
| b2 | 0xA00500DC | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg55 | sfixed(3 downto -23) |
| a1 | 0xA00500E0 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg56 | sfixed(3 downto -23) |
| a2 | 0xA00500E4 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg57 | sfixed(3 downto -23) |
| channel_address | 0xA00500E8 | Integer | slv_reg58 | std_logic_vector(1 downto 0) |
| strobe | 0xA00500EC | Boolean | slv_reg59 | std_logic |
Low Pass
These are the registers for the Low Pass filter.
| Name | PS Addr | PS Numerical Format | PL Addr | PL Numerical Format |
|---|---|---|---|---|
| b0 | 0xA00500F0 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg60 | sfixed(3 downto -23) |
| b1 | 0xA00500F4 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg61 | sfixed(3 downto -23) |
| b2 | 0xA00500F8 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg62 | sfixed(3 downto -23) |
| a1 | 0xA00500FC | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg63 | sfixed(3 downto -23) |
| a2 | 0xA0050100 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg64 | sfixed(3 downto -23) |
| channel_address | 0xA0050104 | Integer | slv_reg65 | std_logic_vector(1 downto 0) |
| strobe | 0xA0050108 | Boolean | slv_reg66 | std_logic |
High Pass 1
These are the registers for the first (of the 2) High Pass filters.
| Name | PS Addr | PS Numerical Format | PL Addr | PL Numerical Format |
|---|---|---|---|---|
| b0 | 0xA005010C | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg67 | sfixed(3 downto -23) |
| b1 | 0xA0050110 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg68 | sfixed(3 downto -23) |
| b2 | 0xA0050114 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg69 | sfixed(3 downto -23) |
| a1 | 0xA0050118 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg70 | sfixed(3 downto -23) |
| a2 | 0xA005011C | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg71 | sfixed(3 downto -23) |
| channel_address | 0xA0050120 | Integer | slv_reg72 | std_logic_vector(1 downto 0) |
| strobe | 0xA0050124 | Boolean | slv_reg73 | std_logic |
High Pass 2
These are the registers for the second (of the 2) High Pass filters.
| Name | PS Addr | PS Numerical Format | PL Addr | PL Numerical Format |
|---|---|---|---|---|
| b0 | 0xA0050128 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg74 | sfixed(3 downto -23) |
| b1 | 0xA005012C | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg75 | sfixed(3 downto -23) |
| b2 | 0xA0050130 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg76 | sfixed(3 downto -23) |
| a1 | 0xA0050134 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg77 | sfixed(3 downto -23) |
| a2 | 0xA0050138 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg78 | sfixed(3 downto -23) |
| channel_address | 0xA005013C | Integer | slv_reg79 | std_logic_vector(1 downto 0) |
| strobe | 0xA0050140 | Boolean | slv_reg80 | std_logic |
echo_tdm
- The
channel_valueregister controls the amount of echo. The value has to be between 0 and 0.8. - The
channel_addressregister has to be loaded with the address for which thechannel_valuebelongs.
| Name | PS Addr | PS Numerical Format | PL Addr | PL Numerical Format |
|---|---|---|---|---|
| channel_value | 0xA0050144 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg81 | sfixed(0 downto -23) |
| channel_address | 0xA0050148 | Integer | slv_reg82 | std_logic_vector(1 downto 0) |
| strobe | 0xA005014C | Boolean | slv_reg83 | std_logic |
saturation_tdm
- The
channel_valueregister controls the amount of saturation. The value has to be between 1 and 8 V/V. - The
channel_addressregister has to be loaded with the address for which thechannel_valuebelongs.
| Name | PS Addr | PS Numerical Format | PL Addr | PL Numerical Format |
|---|---|---|---|---|
| channel_value | 0xA0050150 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg84 | sfixed(3 downto -23) |
| channel_address | 0xA0050154 | Integer | slv_reg85 | std_logic_vector(1 downto 0) |
| strobe | 0xA0050158 | Boolean | slv_reg86 | std_logic |
ring_modulator
- The
on_offregister turns the ring_modulator on or off. The value has to be 0 or 1. - The
phase_incregister controls the speed of the effect.
In our audio pipeline, there are two ring_modulator modules, one for the analog source and one for the DMA source.
Analog Source
| Name | PS Addr | PS Numerical Format | PL Addr | PL Numerical Format |
|---|---|---|---|---|
| on_off | 0xA005015C | Boolean | slv_reg87 | std_logic |
| phase_inc | 0xA0050160 | Integer | slv_reg88 | integer |
DMA Source
| Name | PS Addr | PS Numerical Format | PL Addr | PL Numerical Format |
|---|---|---|---|---|
| on_off | 0xA0050164 | Boolean | slv_reg89 | std_logic |
| phase_inc | 0xA0050168 | Integer | slv_reg90 | integer |
Master Volume
- The
master_volumeregister controls volume of the ouput. The value has to be between 0 and 4 V/V.
| Name | PS Addr | PS Numerical Format | PL Addr | PL Numerical Format |
|---|---|---|---|---|
| master_volume | 0xA005016C | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg91 | std_logic_vector(17 downto 0) |
Channel Volume
- The
channel_volume_selectregister has to be loaded with the address for which thechannel_volume_valuebelongs. - The
channel_volume_valueregister controls volume of a channel. The value has to be between 0 and 4 V/V.
| Name | PS Addr | PS Numerical Format | PL Addr | PL Numerical Format |
|---|---|---|---|---|
| channel_volume_select | 0xA0050170 | Integer | slv_reg92 | std_logic_vector(1 downto 0) |
| channel_volume_value | 0xA0050174 | Signed Fixed-Point (8 integer digits and 23 fractional digits) | slv_reg93 | std_logic_vector(17 downto 0) |
| channel_volume_strobe | 0xA0050178 | Boolean | slv_reg94 | std_logic |