Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

applications: sdp: mspi: Initial implementation #19077

Merged
merged 1 commit into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
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
182 changes: 182 additions & 0 deletions applications/sdp/mspi/src/hrt/hrt.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
/*
* 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)
{
uint16_t dir;
uint16_t out;
nrf_vpr_csr_vio_config_t config;
nrf_vpr_csr_vio_mode_out_t out_mode = {
.mode = NRF_VPR_CSR_VIO_SHIFT_OUTB_TOGGLE,
.frame_width = 1,
};

mif1-nordic marked this conversation as resolved.
Show resolved Hide resolved
NRFX_ASSERT(xfer_ll_params.word_size <= MAX_WORD_SIZE);
/* Configuration step */
dir = nrf_vpr_csr_vio_dir_get();

nrf_vpr_csr_vio_dir_set(dir | PIN_DIR_OUT_MASK(D0_PIN));

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_set(&out_mode);
nrf_vpr_csr_vio_mode_in_buffered_set(NRF_VPR_CSR_VIO_MODE_IN_CONTINUOUS);

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);

/* Disable CS */
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)
{
uint16_t dir;
uint16_t out;
nrf_vpr_csr_vio_config_t config;
nrf_vpr_csr_vio_mode_out_t out_mode = {
.mode = NRF_VPR_CSR_VIO_SHIFT_OUTB_TOGGLE,
.frame_width = 4,
};

NRFX_ASSERT(xfer_ll_params.word_size % 4 == 0);
NRFX_ASSERT(xfer_ll_params.word_size <= MAX_WORD_SIZE);
/* Configuration step */
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));

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_set(&out_mode);
nrf_vpr_csr_vio_mode_in_buffered_set(NRF_VPR_CSR_VIO_MODE_IN_CONTINUOUS);

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);

/* Disable CS */
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);
}
82 changes: 82 additions & 0 deletions applications/sdp/mspi/src/hrt/hrt.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* 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
mif1-nordic marked this conversation as resolved.
Show resolved Hide resolved

/* 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
Loading