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..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..7e56585d48da --- /dev/null +++ b/applications/sdp/mspi/src/hrt/hrt.c @@ -0,0 +1,195 @@ +/* + * 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(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, 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(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); + 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..10b8dcc81462 --- /dev/null +++ b/applications/sdp/mspi/src/hrt/hrt.h @@ -0,0 +1,81 @@ +/* + * 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..1ba7a9026c41 --- /dev/null +++ b/applications/sdp/mspi/src/hrt/hrt.s @@ -0,0 +1,328 @@ + .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,-16 + sw s0,12(sp) + #APP + csrr t1, 3009 + #NO_APP + slli t1,t1,16 + srli t1,t1,16 + ori t1,t1,35 + #APP + csrw 3009, t1 + csrr t1, 3008 + #NO_APP + slli t1,t1,16 + srli t1,t1,16 + ori t1,t1,32 + #APP + csrw 3008, t1 + #NO_APP + li t1,4 + sw t1,4(sp) + li t1,1 + sh t1,8(sp) + li t1,65536 + addi t1,t1,4 + #APP + csrw 3043, t1 + csrw 3045, 0 + csrr t1, 1996 + #NO_APP + andi t2,t1,1 + sb t2,0(sp) + srli t0,t1,4 + andi t0,t0,1 + sb t0,1(sp) + srli t1,t1,8 + andi t1,t1,1 + sb t1,2(sp) + sb zero,2(sp) + slli t0,t0,4 + or t2,t2,t0 + #APP + csrw 1996, t2 + #NO_APP + li t1,31 + bleu a3,t1,.L10 +.L3: + #APP + csrw 2000, 2 + #NO_APP + slli t1,a2,16 + srli t1,t1,16 + #APP + csrr t0, 2003 + #NO_APP + li t2,-65536 + and t0,t0,t2 + or a2,t1,t0 + #APP + csrw 2003, a2 + csrw 3022, a3 + #NO_APP + addi a3,a3,-1 + andi a3,a3,0xff + #APP + csrw 3023, a3 + csrr a3, 3008 + #NO_APP + slli a3,a3,16 + srli a3,a3,16 + andi a3,a3,-33 + slli a3,a3,16 + srli a3,a3,16 + beq a4,zero,.L11 + li a2,32 +.L5: + or a3,a2,a3 + #APP + csrw 3008, a3 + #NO_APP + slli a3,t1,1 + add t1,t1,a3 + slli t1,t1,16 + srli t1,t1,16 + #APP + csrw 2005, t1 + #NO_APP + li a3,0 + j .L6 +.L10: + li t1,0 +.L2: + bgeu t1,a1,.L3 + slli t0,t1,2 + add t0,a0,t0 + lw t2,0(t0) + li s0,32 + sub s0,s0,a3 + sll t2,t2,s0 + sw t2,0(t0) + addi t1,t1,1 + andi t1,t1,0xff + j .L2 +.L11: + li a2,0 + j .L5 +.L7: + slli a2,a3,2 + add a2,a0,a2 + lw a2,0(a2) + #APP + csrw 3016, a2 + #NO_APP + addi a3,a3,1 + andi a3,a3,0xff +.L6: + bltu a3,a1,.L7 + #APP + csrw 3012, 0 + #NO_APP + sw zero,4(sp) + lhu a3,8(sp) + slli a3,a3,16 + li a2,2031616 + and a3,a3,a2 + #APP + csrw 3043, a3 + csrw 3045, 0 + #NO_APP + bne a5,zero,.L8 + #APP + csrr a5, 3008 + #NO_APP + slli a5,a5,16 + srli a5,a5,16 + andi a5,a5,-34 + slli a5,a5,16 + srli a5,a5,16 + beq a4,zero,.L12 + li a4,0 +.L9: + or a5,a4,a5 + #APP + csrw 3008, a5 + #NO_APP +.L8: + #APP + csrw 2000, 0 + #NO_APP + lw s0,12(sp) + addi sp,sp,16 + jr ra +.L12: + li a4,32 + j .L9 + .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,-16 + sw s0,12(sp) + #APP + csrr t1, 3009 + #NO_APP + slli t1,t1,16 + srli t1,t1,16 + ori t1,t1,63 + #APP + csrw 3009, t1 + csrr t1, 3008 + #NO_APP + slli t1,t1,16 + srli t1,t1,16 + ori t1,t1,32 + #APP + csrw 3008, t1 + #NO_APP + li t1,4 + sw t1,4(sp) + sh t1,8(sp) + li t1,262144 + addi t1,t1,4 + #APP + csrw 3043, t1 + csrw 3045, 0 + csrr t1, 1996 + #NO_APP + andi t2,t1,1 + sb t2,0(sp) + srli t0,t1,4 + andi t0,t0,1 + sb t0,1(sp) + srli t1,t1,8 + andi t1,t1,1 + sb t1,2(sp) + sb zero,2(sp) + slli t0,t0,4 + or t2,t2,t0 + #APP + csrw 1996, t2 + #NO_APP + li t1,31 + bleu a3,t1,.L23 +.L16: + #APP + csrw 2000, 2 + #NO_APP + slli t1,a2,16 + srli t1,t1,16 + #APP + csrr t0, 2003 + #NO_APP + li t2,-65536 + and t0,t0,t2 + or a2,t1,t0 + #APP + csrw 2003, a2 + #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 a3, 3008 + #NO_APP + slli a3,a3,16 + srli a3,a3,16 + andi a3,a3,-33 + slli a3,a3,16 + srli a3,a3,16 + beq a4,zero,.L24 + li a2,32 +.L18: + or a3,a2,a3 + #APP + csrw 3008, a3 + #NO_APP + slli a3,t1,1 + add t1,t1,a3 + slli t1,t1,16 + srli t1,t1,16 + #APP + csrw 2005, t1 + #NO_APP + li a3,0 + j .L19 +.L23: + li t1,0 +.L15: + bgeu t1,a1,.L16 + slli t0,t1,2 + add t0,a0,t0 + lw t2,0(t0) + li s0,32 + sub s0,s0,a3 + sll t2,t2,s0 + sw t2,0(t0) + addi t1,t1,1 + andi t1,t1,0xff + j .L15 +.L24: + li a2,0 + j .L18 +.L20: + slli a2,a3,2 + add a2,a0,a2 + lw a2,0(a2) + #APP + csrw 3016, a2 + #NO_APP + addi a3,a3,1 + andi a3,a3,0xff +.L19: + bltu a3,a1,.L20 + #APP + csrw 3012, 0 + #NO_APP + sw zero,4(sp) + lhu a3,8(sp) + slli a3,a3,16 + li a2,2031616 + and a3,a3,a2 + #APP + csrw 3043, a3 + csrw 3045, 0 + #NO_APP + bne a5,zero,.L21 + #APP + csrr a5, 3008 + #NO_APP + slli a5,a5,16 + srli a5,a5,16 + andi a5,a5,-34 + slli a5,a5,16 + srli a5,a5,16 + beq a4,zero,.L25 + li a4,0 +.L22: + or a5,a4,a5 + #APP + csrw 3008, a5 + #NO_APP +.L21: + #APP + csrw 2000, 0 + #NO_APP + lw s0,12(sp) + addi sp,sp,16 + jr ra +.L25: + li a4,32 + j .L22 + .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..6436a11ba49d --- /dev/null +++ b/applications/sdp/mspi/src/main.c @@ -0,0 +1,216 @@ +/* + * 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