Skip to content

Commit

Permalink
applications: sdp: mspi: Initial implementation
Browse files Browse the repository at this point in the history
Added initial mspi implementation with hard real time task running on
interrupts.

Signed-off-by: Michal Frankiewicz <[email protected]>
Signed-off-by: Magdalena Pastula <[email protected]>
  • Loading branch information
magp-nordic authored and mif1-nordic committed Dec 3, 2024
1 parent 9598724 commit 7a16741
Show file tree
Hide file tree
Showing 11 changed files with 893 additions and 1 deletion.
19 changes: 19 additions & 0 deletions applications/sdp/mspi/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#
# Copyright (c) 2024 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
#

cmake_minimum_required(VERSION 3.20.0)

find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(sdp_mspi)

sdp_assembly_generate("${CMAKE_SOURCE_DIR}/src/hrt/hrt.c")
sdp_assembly_check("${CMAKE_SOURCE_DIR}/src/hrt/hrt.c")
sdp_assembly_prepare_install("${CMAKE_SOURCE_DIR}/src/hrt/hrt.c")

target_sources(app PRIVATE src/main.c)
target_sources(app PRIVATE src/hrt/hrt.s)

add_dependencies(app asm_check)
46 changes: 46 additions & 0 deletions applications/sdp/mspi/boards/nrf54l15dk_nrf54l15_cpuflpr.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Single-threaded
CONFIG_MULTITHREADING=n
CONFIG_KERNEL_MEM_POOL=n
CONFIG_LOG=n

# Drivers and peripherals
CONFIG_I2C=n
CONFIG_WATCHDOG=n
CONFIG_GPIO=n
CONFIG_PINCTRL=n
CONFIG_SPI=n
CONFIG_SERIAL=n
CONFIG_FLASH=n

# Power management
CONFIG_PM=n

# Interrupts
CONFIG_DYNAMIC_INTERRUPTS=n
CONFIG_IRQ_OFFLOAD=n
CONFIG_GEN_SW_ISR_TABLE=n

# Memory protection
CONFIG_THREAD_STACK_INFO=n
CONFIG_THREAD_CUSTOM_DATA=n
CONFIG_FPU=n

# Boot
CONFIG_BOOT_BANNER=n
CONFIG_NCS_BOOT_BANNER=n

# Console
CONFIG_CONSOLE=n
CONFIG_UART_CONSOLE=n
CONFIG_STDOUT_CONSOLE=n
CONFIG_PRINTK=n
CONFIG_EARLY_CONSOLE=n

# Build
CONFIG_SIZE_OPTIMIZATIONS=y

# No timer support in the kernel
CONFIG_SYS_CLOCK_EXISTS=n

CONFIG_OUTPUT_DISASSEMBLY=y
CONFIG_COMMON_LIBC_MALLOC=n
41 changes: 41 additions & 0 deletions applications/sdp/mspi/boards/nrf54l15dk_nrf54l15_cpuflpr.overlay
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/

&gpio0 {
status = "disabled";
};

&gpio1 {
status = "disabled";
};

&gpio2 {
status = "disabled";
};

&gpiote20 {
status = "disabled";
};

&gpiote30 {
status = "disabled";
};

&grtc {
status = "disabled";
};

&uart20 {
status = "disabled";
};

&uart30 {
status = "disabled";
};

&pwm20 {
status = "disabled";
};
3 changes: 3 additions & 0 deletions applications/sdp/mspi/prj.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
CONFIG_MBOX=n
CONFIG_IPC_SERVICE=n
CONFIG_IPC_SERVICE_BACKEND_ICMSG=n
12 changes: 12 additions & 0 deletions applications/sdp/mspi/sample.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
sample:
name: SDP mSPI application
description: SDP mSPI application
common:
integration_platforms:
- nrf54l15dk/nrf54l15/cpuflpr
tests:
applications.sdp.mspi.icmsg:
build_only: true
sysbuild: true
platform_allow: nrf54l15dk/nrf54l15/cpuflpr
tags: ci_build sysbuild mspi
181 changes: 181 additions & 0 deletions applications/sdp/mspi/src/hrt/hrt.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/
#include "hrt.h"
#include <hal/nrf_vpr_csr_vio.h>
#include <hal/nrf_vpr_csr_vtim.h>

#define CLK_FIRST_CYCLE_MULTIPLICATOR (3)

void write_single_by_word(volatile struct hrt_ll_xfer xfer_ll_params)
{

NRFX_ASSERT(xfer_ll_params.word_size <= MAX_WORD_SIZE);
/* Configuration step */
uint16_t dir = nrf_vpr_csr_vio_dir_get();

nrf_vpr_csr_vio_dir_set(dir | PIN_DIR_OUT_MASK(D0_PIN));

uint16_t out = nrf_vpr_csr_vio_out_get();

nrf_vpr_csr_vio_out_set(out | PIN_OUT_LOW_MASK(D0_PIN));

nrf_vpr_csr_vio_mode_out_t out_mode = {
.mode = NRF_VPR_CSR_VIO_SHIFT_OUTB_TOGGLE,
.frame_width = 1,
};

nrf_vpr_csr_vio_mode_out_set(&out_mode);
nrf_vpr_csr_vio_mode_in_buffered_set(NRF_VPR_CSR_VIO_MODE_IN_CONTINUOUS);

nrf_vpr_csr_vio_config_t config;

nrf_vpr_csr_vio_config_get(&config);
config.input_sel = false;
nrf_vpr_csr_vio_config_set(&config);

/* Fix position of data if word size < MAX_WORD_SIZE,
* so that leading zeros would not be printed instead of data bits.
*/
if (xfer_ll_params.word_size < MAX_WORD_SIZE) {
for (uint8_t i = 0; i < xfer_ll_params.data_len; i++) {
xfer_ll_params.data_to_send[i] =
xfer_ll_params.data_to_send[i]
<< (MAX_WORD_SIZE - xfer_ll_params.word_size);
}
}

/* Counter settings */
nrf_vpr_csr_vtim_count_mode_set(0, NRF_VPR_CSR_VTIM_COUNT_RELOAD);
nrf_vpr_csr_vtim_simple_counter_top_set(0, xfer_ll_params.counter_top);

/* Set number of shifts before OUTB needs to be updated.
* First shift needs to be increased by 1.
*/
nrf_vpr_csr_vio_shift_cnt_out_set(xfer_ll_params.word_size);
nrf_vpr_csr_vio_shift_cnt_out_buffered_set(xfer_ll_params.word_size - 1);

/* Enable CS */
out = nrf_vpr_csr_vio_out_get();
out &= ~PIN_OUT_HIGH_MASK(CS_PIN);
out |= xfer_ll_params.ce_enable_state ? PIN_OUT_HIGH_MASK(CS_PIN)
: PIN_OUT_LOW_MASK(CS_PIN);
nrf_vpr_csr_vio_out_set(out);

/* Start counter */
nrf_vpr_csr_vtim_simple_counter_set(0, CLK_FIRST_CYCLE_MULTIPLICATOR *
xfer_ll_params.counter_top);

/* Send data */
for (uint8_t i = 0; i < xfer_ll_params.data_len; i++) {
nrf_vpr_csr_vio_out_buffered_reversed_byte_set(xfer_ll_params.data_to_send[i]);
}

/* Clear all bits, wait until the last word is sent */
nrf_vpr_csr_vio_out_buffered_set(0);

/* Final configuration */
out_mode.mode = NRF_VPR_CSR_VIO_SHIFT_NONE;
nrf_vpr_csr_vio_mode_out_buffered_set(&out_mode);
nrf_vpr_csr_vio_mode_in_buffered_set(NRF_VPR_CSR_VIO_MODE_IN_CONTINUOUS);

/* Deselect slave */
if (!xfer_ll_params.ce_hold) {
out = nrf_vpr_csr_vio_out_get();
out &= ~(PIN_OUT_HIGH_MASK(CS_PIN) | PIN_OUT_HIGH_MASK(SCLK_PIN));
out |= xfer_ll_params.ce_enable_state ? PIN_OUT_LOW_MASK(CS_PIN)
: PIN_OUT_HIGH_MASK(CS_PIN);
nrf_vpr_csr_vio_out_set(out);
}

/* Stop counter */
nrf_vpr_csr_vtim_count_mode_set(0, NRF_VPR_CSR_VTIM_COUNT_STOP);
}

void write_quad_by_word(volatile struct hrt_ll_xfer xfer_ll_params)
{
NRFX_ASSERT(xfer_ll_params.word_size % 4 == 0);
NRFX_ASSERT(xfer_ll_params.word_size <= MAX_WORD_SIZE);
/* Configuration step */
uint16_t dir = nrf_vpr_csr_vio_dir_get();

nrf_vpr_csr_vio_dir_set(dir | PIN_DIR_OUT_MASK(D0_PIN) | PIN_DIR_OUT_MASK(D1_PIN) |
PIN_DIR_OUT_MASK(D2_PIN) | PIN_DIR_OUT_MASK(D3_PIN));

uint16_t out = nrf_vpr_csr_vio_out_get();

nrf_vpr_csr_vio_out_set(out | PIN_OUT_LOW_MASK(D0_PIN) | PIN_OUT_LOW_MASK(D1_PIN) |
PIN_OUT_LOW_MASK(D2_PIN) | PIN_OUT_LOW_MASK(D3_PIN));

nrf_vpr_csr_vio_mode_out_t out_mode = {
.mode = NRF_VPR_CSR_VIO_SHIFT_OUTB_TOGGLE,
.frame_width = 4,
};

nrf_vpr_csr_vio_mode_out_set(&out_mode);
nrf_vpr_csr_vio_mode_in_buffered_set(NRF_VPR_CSR_VIO_MODE_IN_CONTINUOUS);

nrf_vpr_csr_vio_config_t config;

nrf_vpr_csr_vio_config_get(&config);
config.input_sel = false;
nrf_vpr_csr_vio_config_set(&config);

/* Fix position of data if word size < MAX_WORD_SIZE,
* so that leading zeros would not be printed instead of data.
*/
if (xfer_ll_params.word_size < MAX_WORD_SIZE) {
for (uint8_t i = 0; i < xfer_ll_params.data_len; i++) {
xfer_ll_params.data_to_send[i] =
xfer_ll_params.data_to_send[i]
<< (MAX_WORD_SIZE - xfer_ll_params.word_size);
}
}

/* Counter settings */
nrf_vpr_csr_vtim_count_mode_set(0, NRF_VPR_CSR_VTIM_COUNT_RELOAD);
nrf_vpr_csr_vtim_simple_counter_top_set(0, xfer_ll_params.counter_top);

/* Set number of shifts before OUTB needs to be updated.
* First shift needs to be increased by 1.
*/
nrf_vpr_csr_vio_shift_cnt_out_set(xfer_ll_params.word_size / 4);
nrf_vpr_csr_vio_shift_cnt_out_buffered_set(xfer_ll_params.word_size / 4 - 1);

/* Enable CS */
out = nrf_vpr_csr_vio_out_get();
out &= ~PIN_OUT_HIGH_MASK(CS_PIN);
out |= xfer_ll_params.ce_enable_state ? PIN_OUT_HIGH_MASK(CS_PIN)
: PIN_OUT_LOW_MASK(CS_PIN);
nrf_vpr_csr_vio_out_set(out);

/* Start counter */
nrf_vpr_csr_vtim_simple_counter_set(0, 3 * xfer_ll_params.counter_top);

/* Send data */
for (uint8_t i = 0; i < xfer_ll_params.data_len; i++) {
nrf_vpr_csr_vio_out_buffered_reversed_byte_set(xfer_ll_params.data_to_send[i]);
}

/* Clear all bits, wait until the last word is sent */
nrf_vpr_csr_vio_out_buffered_set(0);

/* Final configuration */
out_mode.mode = NRF_VPR_CSR_VIO_SHIFT_NONE;
nrf_vpr_csr_vio_mode_out_buffered_set(&out_mode);
nrf_vpr_csr_vio_mode_in_buffered_set(NRF_VPR_CSR_VIO_MODE_IN_CONTINUOUS);

/* Deselect slave */
if (!xfer_ll_params.ce_hold) {
out = nrf_vpr_csr_vio_out_get();
out &= ~(PIN_OUT_HIGH_MASK(CS_PIN) | PIN_OUT_HIGH_MASK(SCLK_PIN));
out |= xfer_ll_params.ce_enable_state ? PIN_OUT_LOW_MASK(CS_PIN)
: PIN_OUT_HIGH_MASK(CS_PIN);
nrf_vpr_csr_vio_out_set(out);
}

/* Stop counter */
nrf_vpr_csr_vtim_count_mode_set(0, NRF_VPR_CSR_VTIM_COUNT_STOP);
}
83 changes: 83 additions & 0 deletions applications/sdp/mspi/src/hrt/hrt.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/

#ifndef _HRT_H__
#define _HRT_H__

#include <stdint.h>
#include <stdbool.h>

#define SCLK_PIN 0
#define D0_PIN 1
#define D1_PIN 2
#define D2_PIN 3
#define D3_PIN 4
#define CS_PIN 5

/* Max word size. */
#define MAX_WORD_SIZE NRF_VPR_CSR_VIO_SHIFT_CNT_OUT_BUFFERED_MAX

/* Macro for getting direction mask for specified pin and direction. */
#define PIN_DIR_MASK(PIN_NUM, DIR) \
(VPRCSR_NORDIC_DIR_PIN##PIN_NUM##_##DIR << VPRCSR_NORDIC_DIR_PIN##PIN_NUM##_Pos)

/* Macro for getting output mask for specified pin. */
#define PIN_DIR_OUT_MASK(PIN_NUM) PIN_DIR_MASK(PIN_NUM, OUTPUT)

/* Macro for getting input mask for specified pin. */
#define PIN_DIR_IN_MASK(PIN_NUM) PIN_DIR_MASK(PIN_NUM, INPUT)

/* Macro for getting state mask for specified pin and state. */
#define PIN_OUT_MASK(PIN_NUM, STATE) \
(VPRCSR_NORDIC_OUT_PIN##PIN_NUM##_##STATE << VPRCSR_NORDIC_OUT_PIN##PIN_NUM##_Pos)

/* Macro for getting high state mask for specified pin. */
#define PIN_OUT_HIGH_MASK(PIN_NUM) PIN_OUT_MASK(PIN_NUM, HIGH)

/* Macro for getting low state mask for specified pin. */
#define PIN_OUT_LOW_MASK(PIN_NUM) PIN_OUT_MASK(PIN_NUM, LOW)

/** @brief Low level transfer parameters. */
struct hrt_ll_xfer {

/** @brief Top value of VTIM. This will determine clock frequency
* (SPI_CLOCK ~= CPU_CLOCK / (2 * TOP)).
*/
volatile uint8_t counter_top;

/** @brief Word size of passed data, bits. */
volatile uint8_t word_size;

/** @brief Data to send, under each index there is data of length word_size. */
volatile uint32_t *data_to_send;

/** @brief Data length. */
volatile uint8_t data_len;

/** @brief If true chip enable pin will be left active after transfer */
volatile uint8_t ce_hold;

/** @brief Chip enable pin polarity in enabled state. */
volatile bool ce_enable_state;
};

/** @brief Write on single line.
*
* Function to be used to write data on single data line (SPI).
*
* @param[in] xfer_ll_params Low level transfer parameters.
*/
void write_single_by_word(volatile struct hrt_ll_xfer xfer_ll_params);

/** @brief Write on four lines.
*
* Function to be used to write data on quad data line (SPI).
*
* @param[in] xfer_ll_params Low level transfer parameters.
*/
void write_quad_by_word(volatile struct hrt_ll_xfer xfer_ll_params);

#endif /* _HRT_H__ */
Loading

0 comments on commit 7a16741

Please sign in to comment.