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 <michal.frankiewicz@nordicsemi.no>
  • Loading branch information
mif1-nordic committed Jan 15, 2025
1 parent df92bc2 commit da76bf6
Show file tree
Hide file tree
Showing 4 changed files with 469 additions and 329 deletions.
299 changes: 149 additions & 150 deletions applications/sdp/mspi/src/hrt/hrt.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,182 +7,181 @@
#include <hal/nrf_vpr_csr_vio.h>
#include <hal/nrf_vpr_csr_vtim.h>

#define CLK_FIRST_CYCLE_MULTIPLICATOR (3)
/** @brief Shift control configuration. */
typedef struct {
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);
}

void write_single_by_word(volatile struct hrt_ll_xfer xfer_ll_params)
NRF_STATIC_INLINE void nrf_vpr_csr_vio_out_or_set(uint16_t value)
{
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,
};
nrf_csr_set_bits(VPRCSR_NORDIC_OUT, value);
}

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)));
NRF_STATIC_INLINE void nrf_vpr_csr_vio_out_clear_set(uint16_t value)
{
nrf_csr_clear_bits(VPRCSR_NORDIC_OUT, value);
}

out = nrf_vpr_csr_vio_out_get();
nrf_vpr_csr_vio_out_set(out | PIN_OUT_LOW_MASK(VIO(NRFE_MSPI_DQ0_PIN_NUMBER)));
static const nrf_vpr_csr_vio_shift_ctrl_t write_final_shift_ctrl_cfg = {
.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_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->word_count == 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);

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

/* 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]);
}
nrf_vpr_csr_vio_shift_ctrl_t xfer_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,
};

/* Clear all bits, wait until the last word is sent */
nrf_vpr_csr_vio_out_buffered_set(0);
nrf_vpr_csr_vio_shift_ctrl_buffered_set(&xfer_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);

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

/* Stop counter */
nrf_vpr_csr_vtim_count_mode_set(0, NRF_VPR_CSR_VTIM_COUNT_STOP);
switch (xfer_data->word_count - i) {
case 1: /* Last transfer */
xfer_shift_ctrl.shift_count = xfer_data->last_word_clocks - 1;
nrf_vpr_csr_vio_shift_ctrl_buffered_set(&xfer_shift_ctrl);

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

if ((i == 0) && (!*counter_running)) {
/* Start counter */
nrf_vpr_csr_vtim_simple_counter_set(0, counter_value);
*counter_running = true;
}
}
}

void write_quad_by_word(volatile struct hrt_ll_xfer xfer_ll_params)
void hrt_write(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,
.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();
hrt_frame_element_t first_element = HRT_FE_DATA;
bool counter_running = false;

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)));
nrf_vpr_csr_vio_mode_out_t out_mode = {.mode = NRF_VPR_CSR_VIO_SHIFT_OUTB_TOGGLE};

out = nrf_vpr_csr_vio_out_get();
/* Configure clock and pins */
nrf_vpr_csr_vio_dir_set(hrt_xfer_params->tx_direction_mask);

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)));
for (uint8_t i = 0; i < HRT_FE_MAX; i++) {

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

/* Counter settings */
switch (first_element) {
case HRT_FE_COMMAND:
out_mode.frame_width = hrt_xfer_params->bus_widths.command;
break;
case HRT_FE_ADDRESS:
out_mode.frame_width = hrt_xfer_params->bus_widths.address;
break;
case HRT_FE_DATA:
out_mode.frame_width = hrt_xfer_params->bus_widths.data;
break;
default:
break;
}

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

nrf_vpr_csr_vio_mode_out_set(&out_mode);

switch (hrt_xfer_params->xfer_data[first_element].word_count) {
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);
}

/* Clear all bits, wait until the last word is sent */
nrf_vpr_csr_vio_out_buffered_set(0);
/* Enable CE */
if (hrt_xfer_params->ce_polarity == MSPI_CE_ACTIVE_LOW) {
nrf_vpr_csr_vio_out_clear_set(BIT(hrt_xfer_params->ce_vio));
} else {
nrf_vpr_csr_vio_out_or_set(BIT(hrt_xfer_params->ce_vio));
}

/* 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);
/* Transfer command */
hrt_tx(&hrt_xfer_params->xfer_data[HRT_FE_COMMAND], hrt_xfer_params->bus_widths.command,
&counter_running, hrt_xfer_params->counter_value);
/* Transfer address */
hrt_tx(&hrt_xfer_params->xfer_data[HRT_FE_ADDRESS], hrt_xfer_params->bus_widths.address,
&counter_running, hrt_xfer_params->counter_value);
/* Transfer data */
hrt_tx(&hrt_xfer_params->xfer_data[HRT_FE_DATA], hrt_xfer_params->bus_widths.data,
&counter_running, hrt_xfer_params->counter_value);

if (hrt_xfer_params->eliminate_last_pulse) {

/* Wait until the last word is sent */
while (nrf_vpr_csr_vio_shift_cnt_out_get() != 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 */
nrf_vpr_csr_vio_shift_ctrl_buffered_set(&write_final_shift_ctrl_cfg);
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 CE */
if (!hrt_xfer_params->ce_hold) {

if (hrt_xfer_params->ce_polarity == MSPI_CE_ACTIVE_LOW) {
nrf_vpr_csr_vio_out_or_set(BIT(hrt_xfer_params->ce_vio));
} else {
nrf_vpr_csr_vio_out_clear_set(BIT(hrt_xfer_params->ce_vio));
}
}
}
Loading

0 comments on commit da76bf6

Please sign in to comment.