High-Performance Framework MSPI

Caution

The High-Performance Framework (HPF) support in the nRF Connect SDK is experimental and is limited to the nRF54L15, nRF54LM20A/B, nRF54LC10A, and nRF54LV10A devices.

This application demonstrates how to write a High-Performance Framework (HPF) application and communicate with it. The application implements a subset of the Zephyr MSPI API.

Application overview

The MSPI HPF application is structured into the following main components:

  • The HPF application - Operates on the FLPR core and facilitates data transmission between the application core and the connected MSPI device.

  • The Hard Real Time (HRT) module - Runs on the FLPR core and facilitates data transmission between the FLPR core and the connected MSPI device. The module emulates the MSPI hardware peripheral on the FLPR core, managing real-time data transmission and ensuring precise timing and synchronization of data transfer operations.

  • The MSPI Zephyr driver - Operates on the application core and uses the Zephyr’s scalable real-time operating system (RTOS) MSPI API for data and configuration transmission between the application and FLPR cores.

Scope

The application must meet the following key requirements:

  • Compatibility with the MSPI configuration including clock polarity, phase, and the number of data lines or transmission modes (single, quad).

  • Low latency and high throughput.

Requirements

The application supports the following development kits:

Hardware platforms

PCA

Board name

Board target

nRF54LV10 DK

PCA10188

nrf54lv10dk

nrf54lv10dk/nrf54lv10a/cpuflpr

nRF54LM20 DK

PCA10184

nrf54lm20dk

nrf54lm20dk/nrf54lm20b/cpuflpr nrf54lm20dk/nrf54lm20a/cpuflpr

nRF54LC10 DK

PCA10226

nrf54lc10dk

nrf54lc10dk/nrf54lc10a/cpuflpr

nRF54L15 DK

PCA10156

nrf54l15dk

nrf54l15dk/nrf54l15/cpuflpr

Configuration and data transfer management

Data transfer between the MSPI driver and the HPF application is done through the ICMsg. Data can be configured to be passed either by copy or by reference. By default, data is passed by reference. To enable data passing by copy, you must disable the HPF_MSPI_IPC_NO_COPY and its MSPI driver-side equivalent MSPI_HPF_IPC_NO_COPY Kconfig options.

Initialization phase

The initialization of the MSPI HPF application is divided into two main phases: driver initialization and device initialization.

  1. Driver initialization:

    1. A user application calls the mspi_config() function to initialize the MSPI driver.

    2. The MSPI driver passes the DTS pin configuration to the HPF application.

    3. The HPF application calls the config_pins() function to initialize GPIO settings based on the received configuration.

    4. All pins are assigned to specific VIO lines using a mapping array.

  2. Device initialization

    1. A user application calls the mspi_dev_config() function to configure the MSPI device.

    2. The MSPI driver passes selected parts of the configuration to the HPF application.

    3. The HPF application adds the device configuration to the device list.

Data transmission phase

The data transmission process is structured into two parts: preparation and the transfer.

  1. Transfer preparation

    1. A user application calls the mspi_transceive() function to initiate a data transfer.

    2. The MSPI driver passes transfer parameters to HPF application (hrt_xfer_t).

    3. The HPF application calls the configure_clock() function to set the clock polarity and phase (SPI modes) based on the cpp_mode parameter. It ensures compatibility with modes 0 and 3.

    4. For each packet, MSPI driver passes packet data to HPF application, awaiting completion.

    5. For each packet, HPF application calls the xfer_execute() function to prepare the transfer and adjust the last word.

    Note

    Due to hardware constraints, the length of the last word cannot be 1. The adjust_tail() function modifies the last two words to meet this requirement.

  2. Packet element transfer

    1. Each packet transfer is initiated by the hrt_write() or hrt_read() functions on the FLPR core. Additionally, each packet is divided into four elements: command, address, dummy_cycles, and data.

    2. The hrt_write() and hrt_read() functions prepare the hardware for data transmission by setting GPIO direction masks and determining active packet elements.

    3. The chip select (CS) is enabled before the transfer and disabled afterward unless ce_hold is set to true.

    4. Each TX packet element is processed using the hrt_tx() function.

    5. hrt_read() function treats the data element as RX and passes all other elements to the hrt_write() function.

    6. For each packet element, the shift controller is configured for the appropriate number of data lines and word size.

Sequence flow

The following diagram illustrates the interactions between the user application and the FLPR HRT, mapping out each step from initialization to data transfer:

@startuml
skinparam sequence {
DividerBackgroundColor #8DBEFF
DividerBorderColor #8DBEFF
LifeLineBackgroundColor #13B6FF
LifeLineBorderColor #13B6FF
ParticipantBackgroundColor #13B6FF
ParticipantBorderColor #13B6FF
BoxBackgroundColor #C1E8FF
BoxBorderColor #C1E8FF
GroupBackgroundColor #8DBEFF
GropuBorderColor #8DBEFF
}

skinparam note {
BackgroundColor #ABCFFF
BorderColor #2149C2
}

box "Application"
participant "User\nApplication" as t
participant "Zephyr RTOS\nMSPI API" as a
participant "HPF eMSPI driver" as d
end box
box "FLPR"
participant "HPF FLPR APP" as f
participant "HRT" as h
end box

== Initialization ==

activate t
t -> a : mspi_config()
activate a
a -> d : api_config()
activate d
d -> d : send_config(HPF_MSPI_CONFIG_PINS)
note right d: Shared mem and/or IRQ num
d -> f : HPF_MSPI_CONFIG_PINS
activate f
f -> f : config_pins()
return
deactivate f
d --> a
deactivate d
a --> t
deactivate a

...

loop for each device
t -> a : mspi_dev_config()
activate a
a -> d : api_dev_config()
activate d
d -> d : send_config(HPF_MSPI_CONFIG_DEV)
note right d: Shared mem and/or IRQ num
d -> f : HPF_MSPI_CONFIG_DEV
activate f
note right f: Fill structures\nwith data from APP\nand configure CE pins
return
deactivate f
d --> a
deactivate d
a --> t
deactivate a
end

...

== TX-RX-TX requests ==

t -> a : mspi_transceive()
activate a
a -> d : api_transceive()
activate d
d -> d : send_config(HPF_MSPI_CONFIG_XFER)
note right d: Shared mem and/or IRQ num
d -> f : HPF_MSPI_CONFIG_XFER
activate f
f -> f : configure_clock()
return
deactivate f
loop for each packet
d -> d ++ : start_next_packet()
d -> d ++ : xfer_packet()
note right d: Shared mem and/or IRQ num
d -> f : HPF_MSPI_TX or HPF_MSPI_TXRX
activate f
f -> f ++ : xfer_execute()
f -> f ++ : adjust_tail(command)
deactivate f
f -> f ++ : adjust_tail(address)
deactivate f
f -> f ++ : adjust_tail(dummy_cycles)
deactivate f
f -> f ++ : adjust_tail(data)
deactivate f
deactivate f
note right f: IRQ num
f -> h : Dispatch
activate h

alt transfer type TX
h -> h ++ : hrt_write()
h -> h ++ : hrt_tx(command)
deactivate h
h -> h ++ : hrt_tx(address)
deactivate h
h -> h ++ : hrt_tx(dummy_cycles)
deactivate h
h -> h ++ : hrt_tx(data)
deactivate h
deactivate h

else trasnfer type TXRX
note right h: Temp. set data length to 0
h -> h ++ : hrt_write()
h -> h ++ : hrt_tx(command)
deactivate h
h -> h ++ : hrt_tx(address)
deactivate h
h -> h ++ : hrt_tx(dummy_cycles)
deactivate h
deactivate h
note right h: Temp. set data length to original value
note right h: Receive data
end
return
return
deactivate d
deactivate d
d --> a
deactivate d
a --> t
deactivate a
deactivate t
@enduml

Key functions

Key functions, such as hrt_write(), hrt_tx(), and hrt_read() are integral to managing the data transfer process, handling tasks from setting GPIO directions to executing low-level data transfers.

Function

Purpose

Key Steps

hrt_write()

The primary function for executing a TX transfer. It handles configuration, timing, and data transmission for all frame elements.

  1. Configures GPIO directions for TX using the transfer parameters.

  2. Determines the active frame element (command, address, dummy bits, or data).

  3. Transfers the frame elements sequentially via hrt_tx().

  4. Manages clock timing and CE pin behavior.

hrt_tx()

Handles the low-level data transfer for a specific frame element (for example, command, address, dummy_cycles, or data).

  1. Configures the shift controller (nrf_vpr_csr_vio_shift_ctrl_buffered_set()).

  2. Writes each word from the data buffer to the output register.

  3. Starts the hardware counter for generating clock signal.

hrt_read()

The primary function for executing a RX transfer. It handles configuration, timing, and data transmission for all frame elements.

  1. Call hrt_write() for command, address and dummy_cycles elements.

  2. Configures GPIO directions for RX using the transfer parameters.

  3. Receives data element.

  4. Manages clock timing and CE pin behavior.

adjust_tail()

Manages the formatting of the last and penultimate words in the transfer buffer to comply with hardware limitations.

  • Adjusts word boundaries when the last word requires only 1 clock cycle to be sent.

  • Handles cases where data needs to be split across multiple words.

Key data structures

The following section provides an overview of the primary data structures used in managing MSPI transfers. These structures are crucial for configuring and executing data transfers efficiently.

  • Transfer elements

  • Transfer configuration

    • hrt_xfer_t - Encapsulates the core configuration for an MSPI transfer.

    • xfer_data - An array of the hrt_xfer_data_t structures for the frame elements (command, address, dummy_cycles, data).

    • bus_widths - Defines the bit-width configuration for the command, address, dummy_cycles, and data sections of the transfer.

    • counter_value: Sets the clock divider to achieve frequency specified by a user.

    • ce_vio - Index of the VIO pin used as CE.

    • ce_hold - Whether CE remains asserted after the transfer.

    • ce_polarity - Active polarity of the CE pin.

    • tx_direction_mask and rx_direction_mask - Configure GPIO directions for data transmission.

    • cpp_mode - SPI mode 0 or 3

  • Transfer data

    • hrt_xfer_data_t - Represents transfer-specific properties for each frame element.

    • data - Points to the data being transmitted or received.

    • word_count - Number of 32-bit words in the data buffer.

    • last_word_clocks - Number of clock pulses for the final word.

    • penultimate_word_clocks - Clock pulses for the second-to-last word.

    • last_word - Holds the last word data (for transition or from reception).

    • fun_out - Selects which function in TX to use to access buffered output register.

Building and running

This application can be found under applications/hpf/mspi in the nRF Connect SDK folder structure.

To build the application, follow the instructions in Building an application for your preferred building environment. See also Programming an application for programming steps and Testing and optimization for general information about testing and debugging in the nRF Connect SDK.

Note

When building repository applications in the SDK repositories, building with sysbuild is enabled by default. If you work with out-of-tree freestanding applications, you need to manually pass the --sysbuild parameter to every build command or configure west to always use it.

To build and run the application, you must include code for both the application core and FLPR core. The process involves building a test or user application that is using MSPI driver with the appropriate sysbuild configuration.

You can use the tests listed in the Testing section. To build them, execute the following command in their respective directories:

west build -p -b <build_target>

Testing

The following tests utilize the MSPI driver along with this application:

  • nrf/tests/drivers/mspi/app_fault_timer

  • nrf/tests/drivers/mspi/error_cases

  • nrf/tests/drivers/mspi/trap_handler

  • nrf/tests/zephyr/drivers/mspi/api

  • nrf/tests/zephyr/drivers/mspi/flash

  • nrf/tests/zephyr/drivers/flash/common

These tests report results over the serial port, using the USB debug port on the nRF54L15, nRF54LM20, nrf54LC10 or nRF54LV10 DK.

Dependencies

  • zephyr/doc/services/ipc/ipc_service - Used for transferring data between application core and the FLPR core.

  • nrf HAL - Enables access to the VPR CSR registers for direct hardware control.

  • Assembly management - Used to optimize performance-critical sections.

API documentation

Application uses the following API elements:

Zephyr driver

  • Header file: include/drivers/mspi/hpf_mspi.h

  • Source file: drivers/mspi/mspi_hpf.c

FLPR application

  • Source file: applications/hpf/mspi/src/main.c

FLPR application HRT

  • Header file: applications/hpf/mspi/src/hrt/hrt.h

  • Source file applications/hpf/mspi/src/hrt/hrt.c

  • Assembly:

    • applications/hpf/mspi/src/hrt/hrt-nrf54l15.s

    • applications/hpf/mspi/src/hrt/hrt-nrf54lm20a.s

    • applications/hpf/mspi/src/hrt/hrt-nrf54lm20b.s

    • applications/hpf/mspi/src/hrt/hrt-nrf54lc10a.s

    • applications/hpf/mspi/src/hrt/hrt-nrf54lv10a.s