Skip to content

Commit

Permalink
application: sdp: mspi: Hrt data transfer
Browse files Browse the repository at this point in the history
Added MSPI_TX reaction to NRFE_MSPI_TXRX and NRFE_MSPI_TX.
Added HRT mspi TX functionality.

Signed-off-by: Michal Frankiewicz <[email protected]>
  • Loading branch information
mif1-nordic committed Jan 9, 2025
1 parent abddb2e commit 98e462b
Show file tree
Hide file tree
Showing 4 changed files with 486 additions and 355 deletions.
268 changes: 129 additions & 139 deletions applications/sdp/mspi/src/hrt/hrt.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,183 +6,173 @@
#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)
/** @brief Shift control configuration. */
typedef struct
{
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,
};

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

out = nrf_vpr_csr_vio_out_get();
nrf_vpr_csr_vio_out_set(out | PIN_OUT_LOW_MASK(VIO(NRFE_MSPI_DQ0_PIN_NUMBER)));
uint8_t shift_count;
nrf_vpr_csr_vio_shift_t out_mode;
uint8_t frame_width;
nrf_vpr_csr_vio_mode_in_t in_mode;
} nrf_vpr_csr_vio_shift_ctrl_t;

NRF_STATIC_INLINE void nrf_vpr_csr_vio_shift_ctrl_buffered_set(nrf_vpr_csr_vio_shift_ctrl_t const * p_shift_ctrl)
{
uint32_t reg = ((p_shift_ctrl->shift_count<<VPRCSR_NORDIC_SHIFTCTRLB_SHIFTCNTB_VALUE_Pos)&VPRCSR_NORDIC_SHIFTCTRLB_SHIFTCNTB_VALUE_Msk) |
((p_shift_ctrl->out_mode<<VPRCSR_NORDIC_SHIFTCTRLB_OUTMODEB_MODE_Pos)&VPRCSR_NORDIC_SHIFTCTRLB_OUTMODEB_MODE_Msk) |
((p_shift_ctrl->frame_width<<VPRCSR_NORDIC_SHIFTCTRLB_OUTMODEB_FRAMEWIDTH_Pos)&VPRCSR_NORDIC_SHIFTCTRLB_OUTMODEB_FRAMEWIDTH_Msk) |
((p_shift_ctrl->in_mode<<VPRCSR_NORDIC_SHIFTCTRLB_INMODEB_MODE_Pos)&VPRCSR_NORDIC_SHIFTCTRLB_INMODEB_MODE_Msk);

nrf_csr_write(VPRCSR_NORDIC_SHIFTCTRLB, reg);
}

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);
}
static void hrt_tx(volatile hrt_xfer_data_t *xfer_data, uint8_t frame_width, bool *counter_running, uint16_t counter_value)
{
if(xfer_data->words == 0)
{
return;
}

/* 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);
nrf_vpr_csr_vio_shift_ctrl_t shift_ctrl = {
.shift_count = BITS_IN_WORD / frame_width - 1,
.out_mode = NRF_VPR_CSR_VIO_SHIFT_OUTB_TOGGLE,
.frame_width = frame_width,
.in_mode = NRF_VPR_CSR_VIO_MODE_IN_CONTINUOUS,
};

/* 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);
nrf_vpr_csr_vio_shift_ctrl_buffered_set(&shift_ctrl);

/* 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]);
}
for (uint32_t i = 0; i < xfer_data->words; i++) {

/* Clear all bits, wait until the last word is sent */
nrf_vpr_csr_vio_out_buffered_set(0);
switch (xfer_data->words - i) {
case 1: /* Last transfer */
shift_ctrl.shift_count = xfer_data->last_word_clocks - 1;
nrf_vpr_csr_vio_shift_ctrl_buffered_set(&shift_ctrl);

/* 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);
xfer_data->vio_out_set(xfer_data->last_word);
break;
case 2: /* Last but one transfer.*/
shift_ctrl.shift_count = xfer_data->penultimate_word_clocks - 1;
nrf_vpr_csr_vio_shift_ctrl_buffered_set(&shift_ctrl);
default: /* Intentional fallthrough */
xfer_data->vio_out_set(((uint32_t *)xfer_data->data)[i]);
}

/* 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);
if ((i == 0) && (!*counter_running)) {
/* Start counter */
nrf_vpr_csr_vtim_simple_counter_set(0, counter_value);
*counter_running = true;
}
}

/* 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)
void hrt_write(volatile hrt_xfer_t *hrt_xfer_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,
hrt_frame_element_t first_element = HRT_FE_DATA;
bool counter_running = false;
nrf_vpr_csr_vio_shift_ctrl_t shift_ctrl = {
.shift_count = 1,
.out_mode = NRF_VPR_CSR_VIO_SHIFT_NONE,
.frame_width = 4,
.in_mode = NRF_VPR_CSR_VIO_MODE_IN_CONTINUOUS,
};

nrf_vpr_csr_vio_mode_out_t out_mode = {
.mode = NRF_VPR_CSR_VIO_SHIFT_OUTB_TOGGLE
};

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)));
/* Configure clock and pins */
nrf_vpr_csr_vio_dir_set(hrt_xfer_params->tx_direction_mask);

out = nrf_vpr_csr_vio_out_get();
for(uint8_t i=0; i<HRT_FE_MAX; i++) {

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)));
if(hrt_xfer_params->xfer_data[i].words != 0)
{
first_element = i;
break;
}
}

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);
}
switch(first_element) {
case HRT_FE_COMMAND:
out_mode.frame_width = hrt_xfer_params->io_mode.command;
break;
case HRT_FE_ADDRESS:
out_mode.frame_width = hrt_xfer_params->io_mode.address;
break;
case HRT_FE_DATA:
out_mode.frame_width = hrt_xfer_params->io_mode.data;
break;
default:
break;
}

/* 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);
nrf_vpr_csr_vtim_simple_counter_top_set(0, hrt_xfer_params->counter_value);
nrf_vpr_csr_vio_mode_in_set(NRF_VPR_CSR_VIO_MODE_IN_CONTINUOUS);

/* 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);
nrf_vpr_csr_vio_mode_out_set(&out_mode);

switch(hrt_xfer_params->xfer_data[first_element].words) {
case 1:
nrf_vpr_csr_vio_shift_cnt_out_set(hrt_xfer_params->xfer_data[first_element].last_word_clocks);
break;
case 2:
nrf_vpr_csr_vio_shift_cnt_out_set(hrt_xfer_params->xfer_data[first_element].penultimate_word_clocks);
break;
default:
nrf_vpr_csr_vio_shift_cnt_out_set(BITS_IN_WORD / out_mode.frame_width);
}

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

if (hrt_xfer_params->ce_polarity == MSPI_CE_ACTIVE_LOW) {
WRITE_BIT(out, hrt_xfer_params->ce_vio, VPRCSR_NORDIC_OUT_LOW);
} else {
WRITE_BIT(out, hrt_xfer_params->ce_vio, VPRCSR_NORDIC_OUT_HIGH);
}
nrf_vpr_csr_vio_out_set(out);

/* Start counter */
nrf_vpr_csr_vtim_simple_counter_set(0, 3 * xfer_ll_params.counter_top);
/* Transfer command */
hrt_tx(&hrt_xfer_params->xfer_data[HRT_FE_COMMAND], hrt_xfer_params->io_mode.command, &counter_running, hrt_xfer_params->counter_value);
/* Transfer address */
hrt_tx(&hrt_xfer_params->xfer_data[HRT_FE_ADDRESS], hrt_xfer_params->io_mode.address, &counter_running, hrt_xfer_params->counter_value);
/* Transfer data */
hrt_tx(&hrt_xfer_params->xfer_data[HRT_FE_DATA], hrt_xfer_params->io_mode.data, &counter_running, hrt_xfer_params->counter_value);

/* 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 (hrt_xfer_params->eliminate_last_pulse) {

/* Wait until the last word is sent */
while(nrf_vpr_csr_vio_shift_cnt_out_get() != 0){}

/* Clear all bits, wait until the last word is sent */
nrf_vpr_csr_vio_out_buffered_set(0);
/* This is a partial solution to surplus clock edge problem in modes 1 and 3.
* This solution works only for counter values above 20.
*/
nrf_vpr_csr_vtim_simple_wait_set(0, false, 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);
nrf_vpr_csr_vio_shift_ctrl_buffered_set(&shift_ctrl);
nrf_vpr_csr_vio_out_buffered_reversed_word_set(0x00);

/* Stop counter */
nrf_vpr_csr_vtim_count_mode_set(0, NRF_VPR_CSR_VTIM_COUNT_STOP);

/* Disable CS */
if (!xfer_ll_params.ce_hold) {
if (!hrt_xfer_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));

if (hrt_xfer_params->ce_polarity == MSPI_CE_ACTIVE_LOW) {
WRITE_BIT(out, hrt_xfer_params->ce_vio, VPRCSR_NORDIC_OUT_HIGH);
} else {
WRITE_BIT(out, hrt_xfer_params->ce_vio, VPRCSR_NORDIC_OUT_LOW);
}
nrf_vpr_csr_vio_out_set(out);
}

/* Stop counter */
nrf_vpr_csr_vtim_count_mode_set(0, NRF_VPR_CSR_VTIM_COUNT_STOP);
}
Loading

0 comments on commit 98e462b

Please sign in to comment.