From f910c0348215fe80d986cdd576a809735d957316 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 | 41 +++ applications/sdp/mspi/prj.conf | 3 + applications/sdp/mspi/sample.yaml | 12 + applications/sdp/mspi/src/hrt/hrt.c | 180 ++++++++++++ applications/sdp/mspi/src/hrt/hrt.h | 73 +++++ applications/sdp/mspi/src/hrt/hrt.s | 273 ++++++++++++++++++ applications/sdp/mspi/src/main.c | 209 ++++++++++++++ applications/sdp/mspi/sysbuild.conf | 2 + 10 files changed, 858 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/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..338d1d7ad562 --- /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.s) + +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..4afa34f53f35 --- /dev/null +++ b/applications/sdp/mspi/boards/nrf54l15dk_nrf54l15_cpuflpr.overlay @@ -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"; +}; diff --git a/applications/sdp/mspi/prj.conf b/applications/sdp/mspi/prj.conf new file mode 100644 index 000000000000..33d849aaadd3 --- /dev/null +++ b/applications/sdp/mspi/prj.conf @@ -0,0 +1,3 @@ +CONFIG_MBOX=n +CONFIG_IPC_SERVICE=n +CONFIG_IPC_SERVICE_BACKEND_ICMSG=n diff --git a/applications/sdp/mspi/sample.yaml b/applications/sdp/mspi/sample.yaml new file mode 100644 index 000000000000..5baf87658636 --- /dev/null +++ b/applications/sdp/mspi/sample.yaml @@ -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 diff --git a/applications/sdp/mspi/src/hrt/hrt.c b/applications/sdp/mspi/src/hrt/hrt.c new file mode 100644 index 000000000000..48cdd310b01d --- /dev/null +++ b/applications/sdp/mspi/src/hrt/hrt.c @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ +#include "hrt.h" +#include +#include + +#define CLK_FIRST_CYCLE_MULTIPLICATOR (3) + +void write_single_by_word(volatile 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, CLK_FIRST_CYCLE_MULTIPLICATOR * 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(volatile 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 % 4 == 0); + 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(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..b7b9fb2b5042 --- /dev/null +++ b/applications/sdp/mspi/src/hrt/hrt.h @@ -0,0 +1,73 @@ +/* + * 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. + * @param[in] ce_enable_state Chip enable pin polarity in enabled state. + * @param[in] hold_ce If true CE pin will be left enabled after transfer. + */ +void write_single_by_word(volatile 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. + * @param[in] ce_enable_state Chip enable pin polarity in enabled state. + * @param[in] hold_ce If true CE pin will be left enabled after transfer. + */ +void write_quad_by_word(volatile 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..e4eece2a87bb --- /dev/null +++ b/applications/sdp/mspi/src/hrt/hrt.s @@ -0,0 +1,273 @@ + .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: + addi sp,sp,-4 + sw s0,0(sp) + mv t1,a4 + #APP + csrr a4, 3009 + #NO_APP + ori a4,a4,35 + slli a4,a4,16 + srli a4,a4,16 + #APP + csrw 3009, a4 + csrr a4, 3008 + #NO_APP + ori a4,a4,32 + slli a4,a4,16 + srli a4,a4,16 + #APP + csrw 3008, a4 + #NO_APP + li a4,65536 + addi a4,a4,4 + #APP + csrw 3043, a4 + csrw 3045, 0 + csrr a4, 1996 + #NO_APP + andi a4,a4,17 + #APP + csrw 1996, a4 + #NO_APP + li a4,31 + bleu a3,a4,.L8 +.L5: + #APP + csrw 2000, 2 + csrr t0, 2003 + #NO_APP + li a4,-65536 + and t0,t0,a4 + slli a4,a2,16 + srli a4,a4,16 + or a4,a4,t0 + #APP + csrw 2003, a4 + csrw 3022, a3 + #NO_APP + addi a3,a3,-1 + andi a3,a3,0xff + #APP + csrw 3023, a3 + csrr a4, 3008 + #NO_APP + andi a4,a4,-33 + slli a4,a4,16 + slli a3,t1,5 + srli a4,a4,16 + or a4,a4,a3 + #APP + csrw 3008, a4 + #NO_APP + li a4,3 + mul a4,a2,a4 + slli a4,a4,16 + srli a4,a4,16 + #APP + csrw 2005, a4 + #NO_APP + li a4,0 +.L3: + andi a3,a4,0xff + bltu a3,a1,.L6 + #APP + csrw 3012, 0 + #NO_APP + li a4,65536 + #APP + csrw 3043, a4 + csrw 3045, 0 + #NO_APP + bne a5,zero,.L7 + #APP + csrr a4, 3008 + #NO_APP + andi a4,a4,-34 + slli a4,a4,16 + xori t1,t1,1 + slli t1,t1,5 + srli a4,a4,16 + or a4,a4,t1 + slli a4,a4,16 + srli a4,a4,16 + #APP + csrw 3008, a4 + #NO_APP +.L7: + #APP + csrw 2000, 0 + #NO_APP + lw s0,0(sp) + addi sp,sp,4 + jr ra +.L4: + slli t0,a4,2 + add t0,a0,t0 + lw s0,0(t0) + addi a4,a4,1 + sll s0,s0,t2 + sw s0,0(t0) +.L2: + andi t0,a4,0xff + bgtu a1,t0,.L4 + j .L5 +.L8: + li t2,32 + li a4,0 + sub t2,t2,a3 + j .L2 +.L6: + slli a3,a4,2 + add a3,a0,a3 + lw a3,0(a3) + #APP + csrw 3016, a3 + #NO_APP + addi a4,a4,1 + j .L3 + .size write_single_by_word, .-write_single_by_word + .section .text.write_quad_by_word,"ax",@progbits + .align 1 + .globl write_quad_by_word + .type write_quad_by_word, @function +write_quad_by_word: + addi sp,sp,-4 + sw s0,0(sp) + mv t1,a4 + #APP + csrr a4, 3009 + #NO_APP + ori a4,a4,63 + slli a4,a4,16 + srli a4,a4,16 + #APP + csrw 3009, a4 + csrr a4, 3008 + #NO_APP + ori a4,a4,32 + slli a4,a4,16 + srli a4,a4,16 + #APP + csrw 3008, a4 + #NO_APP + li a4,262144 + addi a4,a4,4 + #APP + csrw 3043, a4 + csrw 3045, 0 + csrr a4, 1996 + #NO_APP + andi a4,a4,17 + #APP + csrw 1996, a4 + #NO_APP + li a4,31 + bleu a3,a4,.L17 +.L14: + #APP + csrw 2000, 2 + csrr t0, 2003 + #NO_APP + li a4,-65536 + and t0,t0,a4 + slli a4,a2,16 + srli a4,a4,16 + or a4,a4,t0 + #APP + csrw 2003, a4 + #NO_APP + srli a3,a3,2 + #APP + csrw 3022, a3 + #NO_APP + addi a3,a3,-1 + andi a3,a3,0xff + #APP + csrw 3023, a3 + csrr a4, 3008 + #NO_APP + andi a4,a4,-33 + slli a4,a4,16 + slli a3,t1,5 + srli a4,a4,16 + or a4,a4,a3 + #APP + csrw 3008, a4 + #NO_APP + li a4,3 + mul a4,a2,a4 + slli a4,a4,16 + srli a4,a4,16 + #APP + csrw 2005, a4 + #NO_APP + li a4,0 +.L12: + andi a3,a4,0xff + bltu a3,a1,.L15 + #APP + csrw 3012, 0 + #NO_APP + li a4,262144 + #APP + csrw 3043, a4 + csrw 3045, 0 + #NO_APP + bne a5,zero,.L16 + #APP + csrr a4, 3008 + #NO_APP + andi a4,a4,-34 + slli a4,a4,16 + xori t1,t1,1 + slli t1,t1,5 + srli a4,a4,16 + or a4,a4,t1 + slli a4,a4,16 + srli a4,a4,16 + #APP + csrw 3008, a4 + #NO_APP +.L16: + #APP + csrw 2000, 0 + #NO_APP + lw s0,0(sp) + addi sp,sp,4 + jr ra +.L13: + slli t0,a4,2 + add t0,a0,t0 + lw s0,0(t0) + addi a4,a4,1 + sll s0,s0,t2 + sw s0,0(t0) +.L11: + andi t0,a4,0xff + bgtu a1,t0,.L13 + j .L14 +.L17: + li t2,32 + li a4,0 + sub t2,t2,a3 + j .L11 +.L15: + slli a3,a4,2 + add a3,a0,a3 + lw a3,0(a3) + #APP + csrw 3016, a3 + #NO_APP + addi a4,a4,1 + j .L12 + .size write_quad_by_word, .-write_quad_by_word diff --git a/applications/sdp/mspi/src/main.c b/applications/sdp/mspi/src/main.c new file mode 100644 index 000000000000..10d9c2a67fed --- /dev/null +++ b/applications/sdp/mspi/src/main.c @@ -0,0 +1,209 @@ +/* + * 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 XFER_COMMAND_IDX (0) +#define XFER_ADDRESS_IDX (1) +#define XFER_DATA_IDX (2) + +#define HRT_IRQ_PRIORITY 2 +#define HRT_VEVIF_IDX_WRITE_SINGLE 17 +#define HRT_VEVIF_IDX_WRITE_QUAD 18 + +/* how many words are needed for given amount of bytes.*/ +#define WORDS_FOR_BYTES(bytes) ((bytes - 1) / 4 + 1) + +#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[XFER_COMMAND_IDX] = 0xe5b326c1; + data_buffer[XFER_ADDRESS_IDX] = 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 + XFER_ADDRESS_IDX; + + 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; + /* TODO: this system needs to be fixed as for now, + * there are problems when (data_length%4) != 0 + */ + data_len = WORDS_FOR_BYTES(data_length); + data_to_send = data_buffer + XFER_DATA_IDX; + + 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) +{ + bool ce_enable_state = (mspi_dev_configs.ce_polarity == MSPI_CE_ACTIVE_LOW); + + 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) +{ + bool ce_enable_state = (mspi_dev_configs.ce_polarity == MSPI_CE_ACTIVE_LOW); + + 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); + + /* this pin initialization is temporary until code is merged with app with gpio + * initialization + */ + 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; + + /* this is temporary sample data */ + 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