From 27f6f37591cd9457fecb866d3bc9f4b70437f12d Mon Sep 17 00:00:00 2001 From: Magdalena Pastula Date: Wed, 6 Nov 2024 15:41:06 +0100 Subject: [PATCH] applications: sdp: mspi: Initial implementation Added initial mspi implementation with hard real time task running on interrupts. Signed-off-by: Michal Frankiewicz Signed-off-by: Magdalena Pastula --- applications/sdp/mspi/CMakeLists.txt | 19 ++ .../boards/nrf54l15dk_nrf54l15_cpuflpr.conf | 46 ++++ .../nrf54l15dk_nrf54l15_cpuflpr.overlay | 52 +++++ .../nrf54l15dk_nrf54l15_cpuflpr_icmsg.overlay | 46 ++++ .../nrf54l15dk_nrf54l15_cpuflpr_mbox.overlay | 41 ++++ applications/sdp/mspi/prj.conf | 1 + applications/sdp/mspi/sample.yaml | 15 ++ applications/sdp/mspi/src/hrt/hrt.c | 190 ++++++++++++++++ applications/sdp/mspi/src/hrt/hrt.h | 63 ++++++ applications/sdp/mspi/src/hrt/hrt.s | 76 +++++++ applications/sdp/mspi/src/main.c | 210 ++++++++++++++++++ applications/sdp/mspi/sysbuild.conf | 2 + 12 files changed, 761 insertions(+) create mode 100644 applications/sdp/mspi/CMakeLists.txt create mode 100644 applications/sdp/mspi/boards/nrf54l15dk_nrf54l15_cpuflpr.conf create mode 100644 applications/sdp/mspi/boards/nrf54l15dk_nrf54l15_cpuflpr.overlay create mode 100644 applications/sdp/mspi/boards/nrf54l15dk_nrf54l15_cpuflpr_icmsg.overlay create mode 100644 applications/sdp/mspi/boards/nrf54l15dk_nrf54l15_cpuflpr_mbox.overlay create mode 100644 applications/sdp/mspi/prj.conf create mode 100644 applications/sdp/mspi/sample.yaml create mode 100644 applications/sdp/mspi/src/hrt/hrt.c create mode 100644 applications/sdp/mspi/src/hrt/hrt.h create mode 100644 applications/sdp/mspi/src/hrt/hrt.s create mode 100644 applications/sdp/mspi/src/main.c create mode 100644 applications/sdp/mspi/sysbuild.conf diff --git a/applications/sdp/mspi/CMakeLists.txt b/applications/sdp/mspi/CMakeLists.txt new file mode 100644 index 000000000000..3bf82cf56770 --- /dev/null +++ b/applications/sdp/mspi/CMakeLists.txt @@ -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.c) + +add_dependencies(app asm_check) diff --git a/applications/sdp/mspi/boards/nrf54l15dk_nrf54l15_cpuflpr.conf b/applications/sdp/mspi/boards/nrf54l15dk_nrf54l15_cpuflpr.conf new file mode 100644 index 000000000000..6c1b7543e212 --- /dev/null +++ b/applications/sdp/mspi/boards/nrf54l15dk_nrf54l15_cpuflpr.conf @@ -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 diff --git a/applications/sdp/mspi/boards/nrf54l15dk_nrf54l15_cpuflpr.overlay b/applications/sdp/mspi/boards/nrf54l15dk_nrf54l15_cpuflpr.overlay new file mode 100644 index 000000000000..132d62c10b33 --- /dev/null +++ b/applications/sdp/mspi/boards/nrf54l15dk_nrf54l15_cpuflpr.overlay @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +// &cpuflpr_vevif_rx { +// status = "okay"; +// interrupts = <16 NRF_DEFAULT_IRQ_PRIORITY>; +// nordic,tasks = <1>; +// nordic,tasks-mask = <0x00010000>; +// }; + +// &cpuflpr_vevif_tx { +// status = "okay"; +// }; + +&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"; +}; diff --git a/applications/sdp/mspi/boards/nrf54l15dk_nrf54l15_cpuflpr_icmsg.overlay b/applications/sdp/mspi/boards/nrf54l15dk_nrf54l15_cpuflpr_icmsg.overlay new file mode 100644 index 000000000000..9c10b2fb3aa9 --- /dev/null +++ b/applications/sdp/mspi/boards/nrf54l15dk_nrf54l15_cpuflpr_icmsg.overlay @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +/ { + soc { + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + + sram_tx: memory@2003c000 { + reg = <0x2003c000 0x0800>; + }; + + sram_rx: memory@2003c800 { + reg = <0x2003c800 0x0800>; + }; + }; + }; + + ipc { + ipc0: ipc0 { + compatible = "zephyr,ipc-icmsg"; + tx-region = <&sram_tx>; + rx-region = <&sram_rx>; + mboxes = <&cpuflpr_vevif_rx 16>, <&cpuflpr_vevif_tx 20>; + mbox-names = "rx", "tx"; + status = "okay"; + }; + }; +}; + +&cpuflpr_rram { + reg = <0x17a000 DT_SIZE_K(12)>; +}; + +&cpuflpr_code_partition { + reg = <0x0 DT_SIZE_K(12)>; +}; + +&cpuflpr_sram { + reg = <0x2003d000 DT_SIZE_K(12)>; + ranges = <0x0 0x2003d000 0x3000>; +}; diff --git a/applications/sdp/mspi/boards/nrf54l15dk_nrf54l15_cpuflpr_mbox.overlay b/applications/sdp/mspi/boards/nrf54l15dk_nrf54l15_cpuflpr_mbox.overlay new file mode 100644 index 000000000000..2eb0cf2b8282 --- /dev/null +++ b/applications/sdp/mspi/boards/nrf54l15dk_nrf54l15_cpuflpr_mbox.overlay @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +/ { + soc { + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + + sram_tx: memory@2003c000 { + reg = <0x2003c000 0x0800>; + }; + + sram_rx: memory@2003c800 { + reg = <0x2003c800 0x0800>; + }; + }; + }; + + mbox_consumer: mbox_consumer { + compatible = "vnd,mbox-consumer"; + mboxes = <&cpuflpr_vevif_rx 16>, <&cpuflpr_vevif_tx 20>; + mbox-names = "rx", "tx"; + }; +}; + +&cpuflpr_rram { + reg = <0x17a000 DT_SIZE_K(12)>; +}; + +&cpuflpr_code_partition { + reg = <0x0 DT_SIZE_K(12)>; +}; + +&cpuflpr_sram { + reg = <0x2003d000 DT_SIZE_K(12)>; + ranges = <0x0 0x2003d000 0x3000>; +}; diff --git a/applications/sdp/mspi/prj.conf b/applications/sdp/mspi/prj.conf new file mode 100644 index 000000000000..79f89305ca0d --- /dev/null +++ b/applications/sdp/mspi/prj.conf @@ -0,0 +1 @@ +CONFIG_MBOX=y diff --git a/applications/sdp/mspi/sample.yaml b/applications/sdp/mspi/sample.yaml new file mode 100644 index 000000000000..5e17c3454469 --- /dev/null +++ b/applications/sdp/mspi/sample.yaml @@ -0,0 +1,15 @@ +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 + extra_configs: + - CONFIG_IPC_SERVICE=y + - CONFIG_IPC_SERVICE_BACKEND_ICMSG=y diff --git a/applications/sdp/mspi/src/hrt/hrt.c b/applications/sdp/mspi/src/hrt/hrt.c new file mode 100644 index 000000000000..489c72a966a7 --- /dev/null +++ b/applications/sdp/mspi/src/hrt/hrt.c @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ +#include "hrt.h" +#include +#include + +#define TOP 4 + +void write_single_by_word(uint32_t *data, + uint8_t data_len, + uint32_t counter_top, + uint8_t word_size, + bool ce_enable_state, + bool hold_ce) +{ + NRFX_ASSERT(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(CS_PIN) | + PIN_DIR_OUT_MASK(SCLK_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_HIGH_MASK(CS_PIN) | + PIN_OUT_LOW_MASK(SCLK_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 (word_size < MAX_WORD_SIZE){ + for (uint8_t i = 0; i < data_len; i++){ + data[i] = data[i] << (MAX_WORD_SIZE - 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, 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(word_size); + nrf_vpr_csr_vio_shift_cnt_out_buffered_set(word_size - 1); + + /* Enable CS */ + out = nrf_vpr_csr_vio_out_get(); + out &= ~PIN_OUT_HIGH_MASK(CS_PIN); + out |= 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 * counter_top); + + /* Send data */ + for (uint8_t i = 0; i < data_len; i++){ + nrf_vpr_csr_vio_out_buffered_reversed_byte_set(data[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 (!hold_ce){ + out = nrf_vpr_csr_vio_out_get(); + out &= ~(PIN_OUT_HIGH_MASK(CS_PIN) | PIN_OUT_HIGH_MASK(SCLK_PIN)); + out |= ce_enable_state ? PIN_OUT_LOW_MASK(CS_PIN) : PIN_OUT_HIGH_MASK(CS_PIN); + out |= PIN_OUT_LOW_MASK(SCLK_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(uint32_t *data, + uint8_t data_len, + uint32_t counter_top, + uint8_t word_size, + bool ce_enable_state, + bool hold_ce) +{ + NRFX_ASSERT(word_size > MAX_WORD_SIZE); + NRFX_ASSERT(word_size % 4 == 0); + + /* 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) | + PIN_DIR_OUT_MASK(CS_PIN) | PIN_DIR_OUT_MASK(SCLK_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) | + PIN_OUT_HIGH_MASK(CS_PIN) | PIN_OUT_LOW_MASK(SCLK_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 (word_size < MAX_WORD_SIZE){ + for (uint8_t i = 0; i < data_len; i++){ + data[i] = data[i] << (MAX_WORD_SIZE - 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, 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(word_size / 4); + nrf_vpr_csr_vio_shift_cnt_out_buffered_set(word_size / 4 - 1); + + /* Enable CS */ + out = nrf_vpr_csr_vio_out_get(); + out &= ~PIN_OUT_HIGH_MASK(CS_PIN); + out |= 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 * counter_top); + + /* Send data */ + for (uint8_t i = 0; i < data_len; i++){ + nrf_vpr_csr_vio_out_buffered_reversed_byte_set(data[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 (!hold_ce){ + out = nrf_vpr_csr_vio_out_get(); + out &= ~(PIN_OUT_HIGH_MASK(CS_PIN) | PIN_OUT_HIGH_MASK(SCLK_PIN)); + out |= ce_enable_state ? PIN_OUT_LOW_MASK(CS_PIN) : PIN_OUT_HIGH_MASK(CS_PIN); + out |= PIN_OUT_LOW_MASK(SCLK_PIN); + nrf_vpr_csr_vio_out_set(out); + } + + /* Stop counter */ + nrf_vpr_csr_vtim_count_mode_set(0, NRF_VPR_CSR_VTIM_COUNT_STOP); +} diff --git a/applications/sdp/mspi/src/hrt/hrt.h b/applications/sdp/mspi/src/hrt/hrt.h new file mode 100644 index 000000000000..a86a9241a936 --- /dev/null +++ b/applications/sdp/mspi/src/hrt/hrt.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#ifndef _HRT_H__ +#define _HRT_H__ + +#include +#include + +#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 Write on single line. + * + * Function to be used to write data on single data line (SPI). + * + * @param[in] data Data to be sent. + * @param[in] data_len Length of data in words. + * @param[in] counter_top Top value of VTIM. This will determine clock frequency (SPI_CLOCK ~= CPU_CLOCK / (2 * TOP)). + * @param[in] word_size Size of a word in bits. + */ +void write_single_by_word(uint32_t* data, uint8_t data_len, uint32_t counter_top, uint8_t word_size, bool ce_enable_state, bool hold_ce); + +/** @brief Write on four lines. + * + * Function to be used to write data on quad data line (SPI). + * + * @param[in] data Data to be sent. + * @param[in] data_len Length of data in words. + * @param[in] counter_top Top value of VTIM. This will determine clock frequency (SPI_CLOCK ~= CPU_CLOCK / (2 * TOP)). + * @param[in] word_size Size of a word in bits. + */ +void write_quad_by_word(uint32_t* data, uint8_t data_len, uint32_t counter_top, uint8_t word_size, bool ce_enable_state, bool hold_ce); + +#endif /* _HRT_H__ */ diff --git a/applications/sdp/mspi/src/hrt/hrt.s b/applications/sdp/mspi/src/hrt/hrt.s new file mode 100644 index 000000000000..6e30da11f87b --- /dev/null +++ b/applications/sdp/mspi/src/hrt/hrt.s @@ -0,0 +1,76 @@ + .file "hrt.c" + .option nopic + .attribute arch, "rv32e1p9_m2p0_c2p0_zicsr2p0" + .attribute unaligned_access, 0 + .attribute stack_align, 4 + .text + .section .text.write_single_by_word,"ax",@progbits + .align 1 + .globl write_single_by_word + .type write_single_by_word, @function +write_single_by_word: + li a5,35 + #APP + csrw 3009, a5 + #NO_APP + li a5,32 + #APP + csrw 3008, a5 + #NO_APP + li a5,65536 + addi a5,a5,4 + #APP + csrw 3043, a5 + csrw 3045, 0 + csrr a5, 1996 + #NO_APP + andi a5,a5,17 + #APP + csrw 1996, a5 + csrw 2000, 2 + csrr a5, 2003 + #NO_APP + li a4,-65536 + and a5,a5,a4 + ori a5,a5,4 + #APP + csrw 2003, a5 + csrw 3023, 31 + csrw 3008, 0 + csrw 2002, 8 + #NO_APP + li a5,0 + addi a3,a1,-1 +.L2: + bgt a3,a5,.L3 + #APP + csrw 3023, 31 + #NO_APP + slli a1,a1,2 + add a0,a0,a1 + lw a5,-4(a0) + #APP + csrw 3017, a5 + #NO_APP + li a5,65536 + #APP + csrw 3043, a5 + csrw 3045, 0 + csrw 3012, 0 + #NO_APP + li a5,32 + #APP + csrw 3008, a5 + csrw 2000, 0 + #NO_APP + ret +.L3: + slli a4,a5,2 + add a4,a0,a4 + lw a4,0(a4) + #APP + csrw 3017, a4 + #NO_APP + addi a5,a5,1 + j .L2 + .size write_single_by_word, .-write_single_by_word diff --git a/applications/sdp/mspi/src/main.c b/applications/sdp/mspi/src/main.c new file mode 100644 index 000000000000..45a318e4f72a --- /dev/null +++ b/applications/sdp/mspi/src/main.c @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include "./hrt/hrt.h" + +#include +#include +#include +#include +#include + +#include + +#define MAX_DATA_LEN 256 + +#define HRT_IRQ_PRIORITY 2 +#define HRT_VEVIF_IDX_WRITE_SINGLE 17 +#define HRT_VEVIF_IDX_WRITE_QUAD 18 + +#define VEVIF_IRQN(vevif) VEVIF_IRQN_1(vevif) +#define VEVIF_IRQN_1(vevif) VPRCLIC_##vevif##_IRQn + +struct mspi_config { + uint8_t* data; + uint8_t data_len; + uint8_t word_size; +}; + +struct mspi_dev_config { + enum mspi_io_mode io_mode; + enum mspi_ce_polarity ce_polarity; + uint32_t read_cmd; + uint32_t write_cmd; + uint8_t cmd_length; /* Command length in bits. */ + uint8_t addr_length; /* Address length in bits. */ +}; + +static struct mspi_dev_config mspi_dev_configs; + +uint32_t data_buffer[MAX_DATA_LEN + 2]; + +volatile uint8_t counter_top = 4; +volatile uint8_t word_size; +volatile uint32_t* data_to_send; +volatile uint8_t data_len; +volatile uint8_t ce_hold; + +void configure_clock(enum mspi_cpp_mode cpp_mode) +{ + nrf_vpr_csr_vio_config_t vio_config = { + .input_sel = 0, + .stop_cnt = 0, + }; + + nrf_vpr_csr_vio_dir_set(PIN_DIR_OUT_MASK(SCLK_PIN)); + + switch (cpp_mode) + { + case MSPI_CPP_MODE_0: + { + vio_config.clk_polarity = 0; + nrf_vpr_csr_vio_out_set(PIN_OUT_LOW_MASK(SCLK_PIN)); + break; + } + case MSPI_CPP_MODE_1: + { + vio_config.clk_polarity = 1; + nrf_vpr_csr_vio_out_set(PIN_OUT_LOW_MASK(SCLK_PIN)); + break; + } + case MSPI_CPP_MODE_2: + { + vio_config.clk_polarity = 1; + nrf_vpr_csr_vio_out_set(PIN_OUT_HIGH_MASK(SCLK_PIN)); + break; + } + case MSPI_CPP_MODE_3: + { + vio_config.clk_polarity = 0; + nrf_vpr_csr_vio_out_set(PIN_OUT_HIGH_MASK(SCLK_PIN)); + break; + } + } + + nrf_vpr_csr_vio_config_set(&vio_config); +} + +void prepare_and_send_data(uint8_t* data, uint8_t data_length) +{ + /* this is here only temporarly to set command and address parameters */ + data_buffer[0] = 0xe5b326c1; + data_buffer[1] = 0xaabbccdd; + + memcpy(&(data_buffer[2]), data, data_length); + + /* Send command */ + ce_hold = true; + word_size = mspi_dev_configs.cmd_length; + data_len = 1; + data_to_send = data_buffer; + + if (mspi_dev_configs.io_mode == MSPI_IO_MODE_QUAD) + { + nrf_vpr_clic_int_pending_set(NRF_VPRCLIC, VEVIF_IRQN(HRT_VEVIF_IDX_WRITE_QUAD)); + } + else + { + nrf_vpr_clic_int_pending_set(NRF_VPRCLIC, VEVIF_IRQN(HRT_VEVIF_IDX_WRITE_SINGLE)); + } + + /* Send address */ + word_size = mspi_dev_configs.addr_length; + data_to_send = data_buffer + 1; + + if (mspi_dev_configs.io_mode == MSPI_IO_MODE_SINGLE || mspi_dev_configs.io_mode == MSPI_IO_MODE_QUAD_1_1_4) + { + nrf_vpr_clic_int_pending_set(NRF_VPRCLIC, VEVIF_IRQN(HRT_VEVIF_IDX_WRITE_SINGLE)); + } + else + { + nrf_vpr_clic_int_pending_set(NRF_VPRCLIC, VEVIF_IRQN(HRT_VEVIF_IDX_WRITE_QUAD)); + } + + /* Send data */ + ce_hold = false; + word_size = 32; + data_len = (data_length-1)/4+1; + data_to_send = data_buffer + 2; + + + + if (mspi_dev_configs.io_mode == MSPI_IO_MODE_SINGLE) + { + nrf_vpr_clic_int_pending_set(NRF_VPRCLIC, VEVIF_IRQN(HRT_VEVIF_IDX_WRITE_SINGLE)); + } + else + { + nrf_vpr_clic_int_pending_set(NRF_VPRCLIC, VEVIF_IRQN(HRT_VEVIF_IDX_WRITE_QUAD)); + } +} + +__attribute__ ((interrupt)) void hrt_handler_write_single(void) +{ + uint8_t ce_enable_state = (mspi_dev_configs.ce_polarity == MSPI_CE_ACTIVE_LOW) ? 0 : 1; + write_single_by_word(data_to_send, data_len, counter_top, word_size, ce_enable_state, ce_hold); +} + +__attribute__ ((interrupt)) void hrt_handler_write_quad(void) +{ + uint8_t ce_enable_state = (mspi_dev_configs.ce_polarity == MSPI_CE_ACTIVE_LOW) ? 0 : 1; + write_quad_by_word(data_to_send, data_len, counter_top, word_size, ce_enable_state, ce_hold); +} + +int main(void) +{ + IRQ_DIRECT_CONNECT(HRT_VEVIF_IDX_WRITE_SINGLE, HRT_IRQ_PRIORITY, hrt_handler_write_single, 0); + nrf_vpr_clic_int_enable_set(NRF_VPRCLIC, VEVIF_IRQN(HRT_VEVIF_IDX_WRITE_SINGLE), true); + + IRQ_DIRECT_CONNECT(HRT_VEVIF_IDX_WRITE_QUAD, HRT_IRQ_PRIORITY, hrt_handler_write_quad, 0); + nrf_vpr_clic_int_enable_set(NRF_VPRCLIC, VEVIF_IRQN(HRT_VEVIF_IDX_WRITE_QUAD), true); + + nrf_vpr_csr_rtperiph_enable_set(true); + + nrf_gpio_pin_dir_t dir = NRF_GPIO_PIN_DIR_OUTPUT; + nrf_gpio_pin_input_t input = NRF_GPIO_PIN_INPUT_DISCONNECT; + nrf_gpio_pin_pull_t pull = NRF_GPIO_PIN_NOPULL; + nrf_gpio_pin_drive_t drive = NRF_GPIO_PIN_E0E1; + + nrfy_gpio_reconfigure(NRF_GPIO_PIN_MAP(2, SCLK_PIN), &dir, &input, &pull, &drive, NULL); + nrfy_gpio_reconfigure(NRF_GPIO_PIN_MAP(2, D0_PIN), &dir, &input, &pull, &drive, NULL); + nrfy_gpio_reconfigure(NRF_GPIO_PIN_MAP(2, D1_PIN), &dir, &input, &pull, &drive, NULL); + nrfy_gpio_reconfigure(NRF_GPIO_PIN_MAP(2, D2_PIN), &dir, &input, &pull, &drive, NULL); + nrfy_gpio_reconfigure(NRF_GPIO_PIN_MAP(2, D3_PIN), &dir, &input, &pull, &drive, NULL); + nrfy_gpio_reconfigure(NRF_GPIO_PIN_MAP(2, CS_PIN), &dir, &input, &pull, &drive, NULL); + + nrfy_gpio_pin_control_select(NRF_GPIO_PIN_MAP(2, SCLK_PIN), NRF_GPIO_PIN_SEL_VPR); + nrfy_gpio_pin_control_select(NRF_GPIO_PIN_MAP(2, D0_PIN), NRF_GPIO_PIN_SEL_VPR); + nrfy_gpio_pin_control_select(NRF_GPIO_PIN_MAP(2, D1_PIN), NRF_GPIO_PIN_SEL_VPR); + nrfy_gpio_pin_control_select(NRF_GPIO_PIN_MAP(2, D2_PIN), NRF_GPIO_PIN_SEL_VPR); + nrfy_gpio_pin_control_select(NRF_GPIO_PIN_MAP(2, D3_PIN), NRF_GPIO_PIN_SEL_VPR); + nrfy_gpio_pin_control_select(NRF_GPIO_PIN_MAP(2, CS_PIN), NRF_GPIO_PIN_SEL_VPR); + + mspi_dev_configs.ce_polarity = MSPI_CE_ACTIVE_LOW; + mspi_dev_configs.io_mode = MSPI_IO_MODE_SINGLE; + mspi_dev_configs.cmd_length = 32; + mspi_dev_configs.addr_length = 32; + + uint8_t data[30] = {0xa3, 0x21, 0x54, 0x3a, + 0x55, 0xa5, 0x45, 0x35, + 0x34, 0x23, 0xa3, 0xad, + 0x97, 0xb2, 0x56, 0x54, + 0x38, 0x88, 0x0 , 0x5 , + 0x33, 0x6 , 0x34, 0x6 , + 0x57, 0x7 , 0xbb, 0xba, + 0xa3, 0xf6}; + prepare_and_send_data(data, 30); + + mspi_dev_configs.io_mode = MSPI_IO_MODE_QUAD; + + prepare_and_send_data(data, 30); + + while (true) { + k_cpu_idle(); + } + + return 0; +} diff --git a/applications/sdp/mspi/sysbuild.conf b/applications/sdp/mspi/sysbuild.conf new file mode 100644 index 000000000000..ffa5894f2abd --- /dev/null +++ b/applications/sdp/mspi/sysbuild.conf @@ -0,0 +1,2 @@ +# SB_CONFIG_VPR_LAUNCHER=n +SB_CONFIG_PARTITION_MANAGER=n