Skip to content

Commit

Permalink
applications: sdp: mspi: Ipc Hrt Connection
Browse files Browse the repository at this point in the history
  • Loading branch information
jaz1-nordic authored and mif1-nordic committed Dec 16, 2024
1 parent fd6a31a commit c2b4727
Show file tree
Hide file tree
Showing 13 changed files with 719 additions and 625 deletions.
2 changes: 1 addition & 1 deletion applications/sdp/mspi/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ 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)
target_sources(app PRIVATE src/hrt/hrt.c)

add_dependencies(app asm_check)
2 changes: 2 additions & 0 deletions applications/sdp/mspi/boards/nrf54l15dk_nrf54l15_cpuflpr.conf
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,5 @@ CONFIG_SYS_CLOCK_EXISTS=n

CONFIG_OUTPUT_DISASSEMBLY=y
CONFIG_COMMON_LIBC_MALLOC=n

CONFIG_COMPILER_OPT="-fshort-enums"
2 changes: 2 additions & 0 deletions applications/sdp/mspi/sample.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ tests:
sysbuild: true
platform_allow: nrf54l15dk/nrf54l15/cpuflpr
tags: ci_build sysbuild mspi
required_snippets:
- sdp-mspi
213 changes: 66 additions & 147 deletions applications/sdp/mspi/src/hrt/hrt.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,183 +6,102 @@
#include "hrt.h"
#include <hal/nrf_vpr_csr_vio.h>
#include <hal/nrf_vpr_csr_vtim.h>
#include <drivers/mspi/nrfe_mspi.h>
#include <zephyr/drivers/mspi.h>

#define CLK_FIRST_CYCLE_MULTIPLICATOR (3)

void write_single_by_word(volatile struct hrt_ll_xfer xfer_ll_params)
void hrt_write(volatile struct hrt_ll_xfer xfer_ll_params)
{
uint16_t dir;
uint8_t shift_count;
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,
.mode = NRF_VPR_CSR_VIO_SHIFT_NONE,
.frame_width = 1,
};

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(VIO(NRFE_MSPI_DQ0_PIN_NUMBER)));
NRFX_ASSERT((xfer_ll_params.last_word_clocks != 1) || (xfer_ll_params.words == 1))

/* Enable CS */
out = nrf_vpr_csr_vio_out_get();
nrf_vpr_csr_vio_out_set(out | PIN_OUT_LOW_MASK(VIO(NRFE_MSPI_DQ0_PIN_NUMBER)));

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);
}
if (xfer_ll_params.ce_polarity == MSPI_CE_ACTIVE_LOW) {
out = BIT_SET_VALUE(out, xfer_ll_params.ce_vio, VPRCSR_NORDIC_OUT_LOW);
} else {
out = BIT_SET_VALUE(out, xfer_ll_params.ce_vio, VPRCSR_NORDIC_OUT_HIGH);
}

/* 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(VIO(NRFE_MSPI_CS0_PIN_NUMBER));
out |= xfer_ll_params.ce_enable_state ? PIN_OUT_HIGH_MASK(VIO(NRFE_MSPI_CS0_PIN_NUMBER))
: PIN_OUT_LOW_MASK(VIO(NRFE_MSPI_CS0_PIN_NUMBER));
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);
for (uint32_t i = 0; i < xfer_ll_params.words; i++) {
switch (xfer_ll_params.words - i) {
case 1: /* Last transfer */
nrf_vpr_csr_vio_shift_cnt_out_buffered_set(xfer_ll_params.last_word_clocks -
1);
switch (xfer_ll_params.bit_order) {
case HRT_BO_NORMAL:
nrf_vpr_csr_vio_out_buffered_set(xfer_ll_params.last_word);
break;
case HRT_BO_REVERSED_BYTE:
nrf_vpr_csr_vio_out_buffered_reversed_byte_set(
xfer_ll_params.last_word);
break;
case HRT_BO_REVERSED_WORD:
nrf_vpr_csr_vio_out_buffered_reversed_word_set(
xfer_ll_params.last_word);
break;
}
break;
case 2: /* Last but one transfer.*/
nrf_vpr_csr_vio_shift_cnt_out_buffered_set(
xfer_ll_params.penultimate_word_clocks - 1);

/* Intentional fallthrough. */
default:
switch (xfer_ll_params.bit_order) {
case HRT_BO_NORMAL:
nrf_vpr_csr_vio_out_buffered_set(
((uint32_t *)xfer_ll_params.data)[i]);
break;
case HRT_BO_REVERSED_BYTE:
nrf_vpr_csr_vio_out_buffered_reversed_byte_set(
((uint32_t *)xfer_ll_params.data)[i]);
break;
case HRT_BO_REVERSED_WORD:
nrf_vpr_csr_vio_out_buffered_reversed_word_set(
((uint32_t *)xfer_ll_params.data)[i]);
break;
}
}

/* 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]);
if (i == 0) {
/* Start counter */
nrf_vpr_csr_vtim_simple_counter_set(0,
xfer_ll_params.counter_initial_value);
/* Wait for first clock cycle */
shift_count = nrf_vpr_csr_vio_shift_cnt_out_get();
while (nrf_vpr_csr_vio_shift_cnt_out_get() == shift_count) {
}
}
}

/* 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(VIO(NRFE_MSPI_CS0_PIN_NUMBER)) |
PIN_OUT_HIGH_MASK(VIO(NRFE_MSPI_SCK_PIN_NUMBER)));
out |= xfer_ll_params.ce_enable_state
? PIN_OUT_LOW_MASK(VIO(NRFE_MSPI_CS0_PIN_NUMBER))
: PIN_OUT_HIGH_MASK(VIO(NRFE_MSPI_CS0_PIN_NUMBER));
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(VIO(NRFE_MSPI_DQ0_PIN_NUMBER)) |
PIN_DIR_OUT_MASK(VIO(NRFE_MSPI_DQ1_PIN_NUMBER)) |
PIN_DIR_OUT_MASK(VIO(NRFE_MSPI_DQ2_PIN_NUMBER)) |
PIN_DIR_OUT_MASK(VIO(NRFE_MSPI_DQ3_PIN_NUMBER)));

out = nrf_vpr_csr_vio_out_get();

nrf_vpr_csr_vio_out_set(out | PIN_OUT_LOW_MASK(VIO(NRFE_MSPI_DQ0_PIN_NUMBER)) |
PIN_OUT_LOW_MASK(VIO(NRFE_MSPI_DQ1_PIN_NUMBER)) |
PIN_OUT_LOW_MASK(VIO(NRFE_MSPI_DQ2_PIN_NUMBER)) |
PIN_OUT_LOW_MASK(VIO(NRFE_MSPI_DQ3_PIN_NUMBER)));

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);
out = nrf_vpr_csr_vio_out_get();

/* 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);
if (xfer_ll_params.ce_polarity == MSPI_CE_ACTIVE_LOW) {
out = BIT_SET_VALUE(out, xfer_ll_params.ce_vio, VPRCSR_NORDIC_OUT_HIGH);
} else {
out = BIT_SET_VALUE(out, xfer_ll_params.ce_vio, VPRCSR_NORDIC_OUT_LOW);
}
}

/* 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(VIO(NRFE_MSPI_CS0_PIN_NUMBER));
out |= xfer_ll_params.ce_enable_state ? PIN_OUT_HIGH_MASK(VIO(NRFE_MSPI_CS0_PIN_NUMBER))
: PIN_OUT_LOW_MASK(VIO(NRFE_MSPI_CS0_PIN_NUMBER));
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(VIO(NRFE_MSPI_CS0_PIN_NUMBER)) |
PIN_OUT_HIGH_MASK(VIO(NRFE_MSPI_SCK_PIN_NUMBER)));
out |= xfer_ll_params.ce_enable_state
? PIN_OUT_LOW_MASK(VIO(NRFE_MSPI_CS0_PIN_NUMBER))
: PIN_OUT_HIGH_MASK(VIO(NRFE_MSPI_CS0_PIN_NUMBER));
nrf_vpr_csr_vio_out_set(out);
}

/* Stop counter */
nrf_vpr_csr_vtim_count_mode_set(0, NRF_VPR_CSR_VTIM_COUNT_STOP);
}
}
96 changes: 56 additions & 40 deletions applications/sdp/mspi/src/hrt/hrt.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,67 +10,83 @@
#include <stdint.h>
#include <stdbool.h>
#include <drivers/mspi/nrfe_mspi.h>
#include <zephyr/drivers/mspi.h>

/* Max word size. */
#define MAX_WORD_SIZE NRF_VPR_CSR_VIO_SHIFT_CNT_OUT_BUFFERED_MAX
#define BIT_SET_VALUE(var, pos, value) ((var & (~(1 << pos))) | (value << pos))

/* 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)
#define VPRCSR_NORDIC_OUT_HIGH 1
#define VPRCSR_NORDIC_OUT_LOW 0

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

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

/* 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)
enum hrt_bit_order {
HRT_BO_NORMAL,
HRT_BO_REVERSED_BYTE,
HRT_BO_REVERSED_WORD
};

/** @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)).

/** @brief Timer initial value,
* time which passes beetwen chip enable and first data clock
*/
uint16_t counter_initial_value;

/** @brief Buffer for RX/TX data */
uint8_t *data;

/** @brief CEIL(buffer_length_bits/32)
*/
uint32_t words;

/** @brief Amount of clock pulses for last word.
* Due to hardware limitation, in case when last word clock pulse count is 1,
* the penultimate word has to share its bits with last word,
* for example:
* buffer length = 36bits,
* io_mode = QUAD,
* last_word_clocks would be:(buffer_length%32)/QUAD = 1
* so:
* penultimate_word_clocks = 32-BITS_IN_BYTE
* last_word_clocks = (buffer_length%32)/QUAD + BITS_IN_BYTE
* last_word = penultimate_word>>24 | last_word<<8
*/
volatile uint8_t counter_top;
uint8_t last_word_clocks;

/** @brief Word size of passed data, bits. */
volatile uint8_t word_size;
/** @brief Amount of clock pulses for penultimate word.
* For more info see last_word_clocks.
*/
uint8_t penultimate_word_clocks;

/** @brief Value of last word.
* For more info see last_word_clocks.
*/
uint32_t last_word;

/** @brief Data to send, under each index there is data of length word_size. */
volatile uint32_t *data_to_send;
/** @brief Bit transfer order. */
enum hrt_bit_order bit_order;

/** @brief Data length. */
volatile uint8_t data_len;
/** @brief Number of CE VIO pin */
uint8_t ce_vio;

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

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

/** @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.
/** @brief Write.
*
* Function to be used to write data on quad data line (SPI).
* Function to be used to write data on SPI.
*
* @param[in] xfer_ll_params Low level transfer parameters.
*/
void write_quad_by_word(volatile struct hrt_ll_xfer xfer_ll_params);
void hrt_write(volatile struct hrt_ll_xfer xfer_ll_params);

#endif /* _HRT_H__ */
Loading

0 comments on commit c2b4727

Please sign in to comment.