PolarFire® System on a Chip (SoC) Applications - Serial Peripheral Interface (SPI)
Introduction
The Serial Peripheral Interface (SPI) protocol is a widely used solution that facilitates high-speed, synchronous data transfer. This article focuses on the SPI capabilities of the PolarFire® System on a Chip (SoC) series and will guide you through the basics of using the SPI peripheral on PolarFire SoC boards from:
- Linux® userspace using the spidev_test utility and writing C application code
- Bare metal SPI application
Prerequisites
Hardware Setup
- This application applies to the following PolarFire SoC-based boards:
- Linux host PC for the Yocto Project® building environment or Windows Subsystem for Linux (WSL) on a Windows machine
- NAND flash memory Click board™ (MIKROE-Flash-5-Click) for experiments
- Digital Logic Analyzer (not required, but useful for observing and analyzing signals)
Software Setup
Additional Resources: SPI Protocol Background
Enabling Microprocessor Subsystem (MSS) SPI in the Libero® SoC Design Suite
To use the Microprocessor Subsystem (MSS) SPI at the application level, the SPI peripheral must be enabled in the Libero SoC design suite. In the reference design that we will use, MSS SPI_1 is enabled in the MSS configurator, and its signals are routed to the mikroBUS™ (MBUS) expansion connector.

The reference design is also prepared with future Yocto Project Linux support in mind. When using SPI under Linux, it is essential to know how the SPI interface is connected in the hardware design. The SPI connection mapping for the PolarFire SoC Discovery Kit and Icicle Kit is shown in the following table.
| Icicle Kit | Discovery Kit | ||
|---|---|---|---|
| SPI 1 | Physical Connection | SPI 0 | Physical Connection |
| MOSI | MBUS SPI MOSI | MOSI | MBUS SPI MOSI |
| MISO | MBUS SPI MISO | MISO | MBUS SPI MISO |
| SCLK | MBUS SPI SCLK | SCLK | MBUS SPI SCLK |
| CS | MBUS SPI CS | CS | MBUS SPI CS |
We will rely on the PolarFire Icicle Kit reference design created using the Libero® SoC design suite:
Start by downloading the PolarFire Icicle Kit reference design generation FlashPro images from the latest release in the PolarFire SoC GitHub repo:
Program the FPGA by the MPFS_ICICLE_KIT_BASE_DESIGN_{VERSION} design using the FlashPro Express tool (included with the Libero SoC design suite).
Open FlashPro Express to program the prebuilt reference programming FPGA fabric logic.
- Open FlashPro Express.
- Create new project.
- Choose the MPFS_ICICLE_KIT_ES_*\MPFS_ICICLE_KIT_ES_BASE_DESIGN_*\MPFS_ICICLE_KIT_ES_*.job file from reference design download folder
- Click on Run button.
Now you have programmed the FPGA fabric logic.
SPI in Linux® Environment
We need to set up and configure the MSS SPI peripheral in the Linux configurations. That's why we need a Linux build system to configure it. For this article, we will use the Yocto Project.
Hart Software Services (HSS) Configurations
HSS (Hart Software Services) is the bootloader for PolarFire SoC. It runs first, sets up hardware, launches Linux or other apps, and is essential for multi-core and secure boot.
Objectives:
- Download and import HSS to SoftConsole.
- Update references and build HSS
- Deploy HSS to PolarFire Icicle Kit
At first we need to download HSS from GitHub.
Import HSS project to SoftConsole by going to File > Import > Import Existing Project Into Workspace.

Browse the HSS folder and import project into workspace by clicking Finish.
Copy your MSS xml file into project.
Copy xml file to hart-software-services/boards/mpfs-icicle-kit/soc_fpga_design/xml/<your xml>.xml.
Copy and rename configurations for HSS.
- Copy hart-software-services/boards/mpfs-icicle-kit-es/def_config to hart-software-services/.
- Rename def_config to .config.
- Edit .config file and update path to your xml by changing next line.
Build HSS and deploy.
Right-click on the project name.
Click on the build project.
Select PolarFire SoC program non-secure boot mode 1 run option and deploy project to SoC.
Yocto Project Configurations
In this section, we will create a Linux image and program it into the PolarFire SoC Icicle Kit.
Objectives:
- Setting up the Yocto Project building environment.
- Enabling the SPI peripheral and including the necessary packages in the build.
- Building a Linux image and deploying it into the SoC.
Creating Environment
Open the command line on your Linux machine or the WSL.
Create an empty directory to hold the workspace:
mkdir yocto-dev && cd yocto-dev
Use the repo tool to fetch all the required repositories:
repo init -u https://github.com/linux4microchip/meta-mchp-manifest.git -b refs/tags/linux4microchip+fpga-2025.07 -m polarfire-soc/default.xml
repo sync
Set the TEMPLATECONF environment variable to point to the appropriate configuration template before initializing the build environment:
export TEMPLATECONF=${TEMPLATECONF:-../meta-mchp/meta-mchp-polarfire-soc/meta-mchp-polarfire-soc-bsp/conf/templates/default}
Then initialize the Yocto Project build environment:
source openembedded-core/oe-init-build-env
Build the Linux image with default configurations to make sure that all packages and tools are installed and working properly:
MACHINE=mpfs-icicle-kit bitbake mchp-base-image
Configuring SPI Peripheral
Prepare the Microchip Linux kernel (linux-mchp) source tree for local development:
Add all necessary libraries and apps to include to the build.
Open the conf/local.conf file and add the following variable at the of file:
CORE_IMAGE_EXTRA_INSTALL += "spidev-test packagegroup-core-buildessential vim libudev kernel-modules"
Save the file and exit.
Open the Linux kernel configuration menu to enable the SPI subsystem and SPI controller drivers:
MACHINE=mpfs-icicle-kit bitbake linux-mchp -c menuconfig
Navigate down to the Device Drivers:

Enable the SPI Support option:

Save the config by selecting Save > Exit.
Locate the PolarFire Icicle kit related Device Tree Source (DTS) files for modification:
yocto-dev/build/workspace/sources/linux-mchp/arch/riscv/boot/dts/microchip/mpfs-icicle-kit-common.dtsi
Enable the SPI1 and add spidev as a node at the end of the DTS (in .dts file):
2
3
4
5
6
7
8
9
10
11
status = "okay";
spidev@0 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "microchip,mpfs-spidev";
spi-max-frequency = <20000000>;
reg = <0>;
};
};
Compile a customized Yocto Project Linux kernel recipe in a developer-friendly way, producing kernel binaries for PolarFire SoC.
Adding spidev Driver Support
Locate the spidev.c source code for modification:
Add the compatible string to the spi_device_id and of_device_id structs:
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{ .name = "bh2228fv" },
..
{ .name = "si3210" },
{ .name = "mpfs-spidev" },
{},
};
..
static const struct of_device_id spidev_dt_ids[] = {
{ .compatible = "cisco,spi-petra", .data = &spidev_of_check },
..
{ .compatible = "silabs,si3210", .data = &spidev_of_check },
{ .compatible = "microchip,mpfs-spidev", .data = &spidev_of_check },
{},
};
Lines 5 and 13 are added.
Building Linux Image and Deploying
Execute the command shown below to build the Linux image:
MACHINE=mpfs-icicle-kit bitbake mchp-base-image
Here's the list of names of supporting machines.
| MACHINE | Board Name | Description |
|---|---|---|
| MACHINE=mpfs-icicle-kit | MPFS-ICICLE-KIT-ES, MPFS-ICICLE-KIT | PolarFire SoC Icicle Kit |
| MACHINE=mpfs-disco-kit | MPFS-DISCO-KIT | PolarFire SoC Discovery Kit |
| MACHINE=mpfs-video-kit | MPFS250-VIDEO-KIT | PolarFire SoC Video Kit |
As the build is done, you can locate your Linux image at:
yocto-dev/build/tmp-glibc/deploy/images/<board_name>/<image-name>.rootfs-***.wic
Follow the GitHub instructions to deploy the built Image to the eMMC/SD card memory.
After booting Linux on the PolarFire Icicle Board, login as root and check if the SPI device 1 is appeared under the devices:
spidev1.0
If nothing returns, that means the SPI device is not enabled and you have to double-check the configuration, DTS, and driver modifications needed to be done.
Software
Testing spidev_test Utility
spidev_test is a utility program used to test and verify the functionality of SPI devices on Linux systems. It is typically used to send and receive data over SPI to ensure that the SPI bus and connected devices are working correctly.
The spidev_test program interacts with the SPI device driver through the /dev/spidevX.Y device files, where X and Y represent the bus and chip select numbers, respectively. It allows users to perform basic read and write operations, configure SPI settings such as mode, speed, and word length, and observe the data exchanged between the host (master) (usually the microcontroller or processor) and the SPI target (slave) device.
spidev_test Commands
Here is a list of arguments that can be used with the spidev_test command:
Usage: spidev_test [-2348CDFHILMNORSZbdilopsv]
general device settings:
-D --device device to use (default /dev/spidev1.1)
-s --speed max speed (Hz)
-d --delay delay (usec)
-l --loop loopback
spi mode:
-H --cpha clock phase
-O --cpol clock polarity
-F --rx-cpha-flip flip CPHA on Rx only xfer
number of wires for transmission:
-2 --dual dual transfer
-4 --quad quad transfer
-8 --octal octal transfer
-3 --3wire SI/SO signals shared
-Z --3wire-hiz high impedance turnaround
data:
-i --input input data from a file (e.g. "test.bin")
-o --output output data to a file (e.g. "results.bin")
-p Send data (e.g. "1234\xde\xad")
-S --size transfer size
-I --iter iterations
additional parameters:
-b --bpw bits per word
-L --lsb least significant bit first
-C --cs-high chip select active high
-N --no-cs no chip select
-R --ready slave pulls low to pause
-M --mosi-idle-low leave mosi line low when idle
misc:
-v --verbose Verbose (show tx buffer)
Using spidev_test on PolarFire Icicle Kit

To verify SPI communication with the Flash 5 Click board, we can use the spidev_test utility to send a test pattern and observe the response. For example, to read the JEDEC ID register (address 0x9F) at a frequency of 1 MHz, execute the following command:
spi mode: 0x0
bits per word: 8
max speed: 1000000 Hz (1000 kHz)
TX | 9F 00 00 00 00 __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ |...|
RX | FF FF EF AA 21 __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ |...|

Application Programming in C Language Using spidev With ioct
We can write a C program that runs from userspace and interacts with SPI devices using the ioctl functions. The example below is a C code that performs the same loopback test we did earlier.
Boot Linux on your PolarFire Icicle kit. Navigate to /media and create spi_example.c using the vim editor:
Copy and paste the following C code to the spi_example.c:
#include <linux/spi/spidev.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
int main() {
int fd = open("/dev/spidev1.0", O_RDWR);
uint8_t tx[] = {0x9F, 0x00, 0x00, 0x00};
uint8_t rx[4] = {0};
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)tx,
.rx_buf = (unsigned long)rx,
.len = sizeof(tx),
.speed_hz = 1000000,
.bits_per_word = 8,
};
ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
printf("JEDEC ID: %02X %02X %02X\n", rx[1], rx[2], rx[3]);
close(fd);
return 0;
}
After saving the modification, compile the C code on target:
Run the spi_example executable:
SPI in Bare Metal Applications
To use the MSS SPI in the bare metal side, we have to use the softconsole to develop the application to build, compile, and deploy.
For this application, let us take one of the GitHub bare metal reference examples and change it so it uses the MSS SPI and communicates with the Flash 5 Click board.
Download the mpfs-blank-baremetal baremetal application project from the official GitHub repository and import it into the SoftConsole.
Replace the MSS Configuration XML file in the bare metal project with the XML file used in your Libero SoC design suite project. The path to the file that SoftConsole will use to generate header files, which are then used by the MPFS HAL, is:
Now we can begin modifying u54_1.c with our custom code to perform two actions:
Read the ID of the Flash board from register 0x9F referring to the W25N01GVZEIG data sheet.
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <string.h>
#include "mpfs_hal/mss_hal.h"
#include "drivers/mss/mss_mmuart/mss_uart.h"
#include "drivers/mss/mss_spi/mss_spi.h"
uint8_t tx_buffer[10];
uint8_t rx_buffer[10];
static void mss_spi_overflow_handler(uint8_t mss_spi_core)
{
(void)mss_config_clk_rst(MSS_PERIPH_SPI1, (uint8_t) MPFS_HAL_FIRST_HART, PERIPHERAL_OFF);
(void)mss_config_clk_rst(MSS_PERIPH_SPI1, (uint8_t) MPFS_HAL_FIRST_HART, PERIPHERAL_ON);
}
void u54_1(void)
{
PLIC_init();
PLIC_SetPriority(SPI1_PLIC, 2u);
PLIC_EnableIRQ(SPI1_PLIC);
__enable_irq();
(void) mss_config_clk_rst(MSS_PERIPH_MMUART1, (uint8_t) MPFS_HAL_FIRST_HART, PERIPHERAL_ON);
(void) mss_config_clk_rst(MSS_PERIPH_SPI1, (uint8_t) MPFS_HAL_FIRST_HART, PERIPHERAL_ON);
// Initialization
MSS_UART_init(&g_mss_uart1_lo, MSS_UART_115200_BAUD,
MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT);
MSS_SPI_init(&g_mss_spi1_lo);
MSS_SPI_configure_master_mode(&g_mss_spi1_lo,
MSS_SPI_SLAVE_0,
MSS_SPI_MODE0,
256u,
MSS_SPI_BLOCK_TRANSFER_FRAME_SIZE,
mss_spi_overflow_handler);
MSS_UART_polled_tx_string(&g_mss_uart1_lo, "Checking connection to Flash\r\n");
tx_buffer[0] = 0x9FU; // JEDEC_ID register
MSS_SPI_set_slave_select(&g_mss_spi1_lo, MSS_SPI_SLAVE_0);
MSS_SPI_transfer_block(&g_mss_spi1_lo, tx_buffer, 1, rx_buffer, 5);
MSS_SPI_clear_slave_select(&g_mss_spi1_lo, MSS_SPI_SLAVE_0);
if(rx_buffer[1] == 0xEF){
MSS_UART_polled_tx_string(&g_mss_uart1_lo, "Connected Successfully\r\n");
} else {
MSS_UART_polled_tx_string(&g_mss_uart1_lo, "Connection Failed");
}
}
Line 1-5: We start by including the necessary header files for standard input/output, string handling, and the PolarFire SoC HAL, UART, and SPI drivers.
Line 8-9: Defining unsigned 8 bit data array for TX and RX data storage.
Line 11-15: Implementing function that reboot SPI peripheral on SPI overflow.
Line 18: The u54_1() function is the main entry point for the application. It waits for a software interrupt to synchronize startup and enables the required peripherals.
Line 27-28: We initialize the interrupt controller and set priorities for SPI-related interrupts. Bringing out of reset UART and SPI peripherals.
Line 32-43: Setting up the SPI and the UART peripherals.
Line 46: Loading JEDEC_ID to the TX buffer.
Line 47-49: Making request to Flash board and getting 5B of response.
Line 51-56: Checking if device manufacturer ID is same as reference manual then prints connection success message else prints connection fail message.
Build the project and deploy it either in LIM for Debug mode or eNVM for Release mode.
Summary
This article explains how to enable and test SPI communication on PolarFire SoC-based boards using Yocto Project. The process begins with configuring the device tree to enable the SPI peripheral, then ensuring the SPI driver is enabled in the Linux kernel. User-space testing is then performed using the spidev utility to interact with SPI devices from the Linux Userspace. Additionally, a custom C program is written and executed to check the SPI Flash board connection. By following this guide, you establish a solid foundation for further development with SPI peripherals on the PolarFire SoC-based boards.