diff --git a/applications/sdp/mspi/src/hrt/hrt.c b/applications/sdp/mspi/src/hrt/hrt.c index b4588856e1e9..80ace71d152a 100644 --- a/applications/sdp/mspi/src/hrt/hrt.c +++ b/applications/sdp/mspi/src/hrt/hrt.c @@ -6,183 +6,174 @@ #include "hrt.h" #include #include +#include +#include -#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<out_mode<frame_width<in_mode<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(hrt_xfer_t *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, + 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(); + NRFX_ASSERT((xfer_ll_data.last_word_clocks != 1) || (xfer_ll_data.words == 1)) - 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(xfer_ll_params->tx_direction_mask); - out = nrf_vpr_csr_vio_out_get(); + for(uint8_t i=0; ixfer_data[i].words != 0) + { + first_element = 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); - } + switch(first_element) { + case HRT_FE_COMMAND: + out_mode.frame_width = xfer_ll_params->io_mode.command; + break; + case HRT_FE_ADDRESS: + out_mode.frame_width = xfer_ll_params->io_mode.address; + break; + case HRT_FE_DATA: + out_mode.frame_width = xfer_ll_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, xfer_ll_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(xfer_ll_params->xfer_data[first_element].words) { + case 1: + nrf_vpr_csr_vio_shift_cnt_out_set(xfer_ll_params->xfer_data[first_element].last_word_clocks); + break; + case 2: + nrf_vpr_csr_vio_shift_cnt_out_set(xfer_ll_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 (xfer_ll_params->ce_polarity == MSPI_CE_ACTIVE_LOW) { + WRITE_BIT(out, xfer_ll_params->ce_vio, VPRCSR_NORDIC_OUT_LOW); + } else { + WRITE_BIT(out, xfer_ll_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(&xfer_ll_params->xfer_data[HRT_FE_COMMAND], xfer_ll_params->io_mode.command, &counter_running, xfer_ll_params->counter_value); + /* Transfer address */ + hrt_tx(&xfer_ll_params->xfer_data[HRT_FE_ADDRESS], xfer_ll_params->io_mode.address, &counter_running, xfer_ll_params->counter_value); + /* Transfer data */ + hrt_tx(&xfer_ll_params->xfer_data[HRT_FE_DATA], xfer_ll_params->io_mode.data, &counter_running, xfer_ll_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 (xfer_ll_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 (!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)); + + if (xfer_ll_params->ce_polarity == MSPI_CE_ACTIVE_LOW) { + WRITE_BIT(out, xfer_ll_params->ce_vio, VPRCSR_NORDIC_OUT_HIGH); + } else { + WRITE_BIT(out, xfer_ll_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); } diff --git a/applications/sdp/mspi/src/hrt/hrt.h b/applications/sdp/mspi/src/hrt/hrt.h index 6f3fa0d0935b..430d999bb8b5 100644 --- a/applications/sdp/mspi/src/hrt/hrt.h +++ b/applications/sdp/mspi/src/hrt/hrt.h @@ -12,8 +12,6 @@ #include #include -#define BIT_SET_VALUE(var, pos, value) ((var & (~(1 << pos))) | (value << pos)) - #define VPRCSR_NORDIC_OUT_HIGH 1 #define VPRCSR_NORDIC_OUT_LOW 0 @@ -23,8 +21,79 @@ #define BITS_IN_WORD 32 #define BITS_IN_BYTE 8 -/** @brief Low level transfer parameters. */ -struct hrt_xfer { +typedef enum { + HRT_FE_COMMAND, + HRT_FE_ADDRESS, + HRT_FE_DATA, + HRT_FE_MAX +}hrt_frame_element_t; + +/** @brief Structure for holding bus width of individual xfer parts */ +typedef struct { + uint8_t command; + uint8_t address; + uint8_t data; +}hrt_xfer_io_mode_cfg_t; + +typedef struct { + /** @brief Buffer for RX/TX data */ + uint8_t *data; + + /** @brief Data length in 4 byte words, + * calculated as 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 + */ + uint8_t last_word_clocks; + + /** @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 Function for writing to buffered out register. */ + void (*vio_out_set)(uint32_t value); +} hrt_xfer_data_t; + + +/** @brief Hrt transfer parameters. */ +typedef struct { + + /** @brief Data for all transfer parts */ + hrt_xfer_data_t xfer_data[HRT_FE_MAX]; + + /** @brief This xfer parts bus widths */ + hrt_xfer_io_mode_cfg_t io_mode; + + /** @brief Timer value, used for setting clock frequency + */ + uint16_t counter_value; + + /** @brief Index of CE VIO pin */ + uint8_t ce_vio; + + /** @brief If true chip enable pin will be left active after transfer */ + uint8_t ce_hold; + + /** @brief Chip enable pin polarity in enabled state. */ + enum mspi_ce_polarity ce_polarity; /** @brief When true clock signal makes 1 transition less. * It is required for spi modes 1 and 3 due to hardware issue. @@ -37,14 +106,14 @@ struct hrt_xfer { /** @brief Rx mode mask for csr dir register */ uint16_t rx_direction_mask; -}; +} hrt_xfer_t; /** @brief Write. * - * Function to be used to write data on SPI. + * Function to be used to write data on MSPI. * - * @param[in] xfer_ll_params Low level transfer parameters. + * @param[in] xfer_ll_params Hrt transfer parameters. */ -void hrt_write(struct hrt_xfer *xfer_ll_params); +void hrt_write(hrt_xfer_t *xfer_ll_params); #endif /* _HRT_H__ */ diff --git a/applications/sdp/mspi/src/hrt/hrt.s b/applications/sdp/mspi/src/hrt/hrt.s index c6358998304f..77e9475e2c04 100644 --- a/applications/sdp/mspi/src/hrt/hrt.s +++ b/applications/sdp/mspi/src/hrt/hrt.s @@ -18,16 +18,14 @@ hrt_tx: beq a5,zero,.L1 li a5,32 div a5,a5,a1 - andi a1,a1,31 - slli a1,a1,12 + slli a3,a1,12 mv s0,a0 addi a5,a5,-1 - andi a5,a5,63 + andi a5,a5,0xff + or a5,a5,a3 ori a5,a5,1024 - or a1,a5,a1 - sw a1,8(sp) #APP - csrw 3019, a1 + csrw 3019, a5 #NO_APP li s1,0 .L3: @@ -41,33 +39,34 @@ hrt_tx: jr ra .L9: sub a5,a5,s1 - li a2,1 - beq a5,a2,.L4 - li a2,2 - beq a5,a2,.L5 + li a1,1 + beq a5,a1,.L4 + li a1,2 + beq a5,a1,.L5 .L6: lw a5,0(s0) - slli a2,s1,2 - add a5,a5,a2 + slli a1,s1,2 + sw a3,8(sp) + add a5,a5,a1 lw a0,0(a5) - lw a2,16(s0) - jalr a2 - j .L7 + lw a1,16(s0) + jalr a1 + j .L12 .L4: - lbu a2,8(s0) - lw a5,8(sp) - addi a2,a2,-1 - andi a2,a2,63 - andi a5,a5,-64 - or a5,a5,a2 - sw a5,8(sp) + lbu a5,8(s0) + sw a3,8(sp) + addi a5,a5,-1 + andi a5,a5,0xff + or a5,a5,a3 + ori a5,a5,1024 #APP csrw 3019, a5 #NO_APP lw a5,16(s0) lw a0,12(s0) jalr a5 -.L7: +.L12: + lw a3,8(sp) bne s1,zero,.L8 lw a5,0(sp) lbu a5,0(a5) @@ -83,13 +82,11 @@ hrt_tx: addi s1,s1,1 j .L3 .L5: - lbu a2,9(s0) - lw a5,8(sp) - addi a2,a2,-1 - andi a2,a2,63 - andi a5,a5,-64 - or a5,a5,a2 - sw a5,8(sp) + lbu a5,9(s0) + addi a5,a5,-1 + andi a5,a5,0xff + or a5,a5,a3 + ori a5,a5,1024 #APP csrw 3019, a5 #NO_APP @@ -100,70 +97,84 @@ hrt_tx: .globl hrt_write .type hrt_write, @function hrt_write: - addi sp,sp,-20 - li a5,16384 - sw s0,12(sp) - sw ra,16(sp) - addi a5,a5,1 - sw a5,4(sp) - mv s0,a0 + addi sp,sp,-16 + sw s0,8(sp) + sw ra,12(sp) lhu a5,70(a0) + mv s0,a0 sb zero,3(sp) #APP csrw 3009, a5 #NO_APP - lw a5,4(a0) - beq a5,zero,.L15 + lw a4,4(a0) + lw a5,24(a0) + bne a4,zero,.L14 + bne a5,zero,.L15 +.L16: + lbu a3,62(s0) + li a5,2 + j .L17 +.L14: + bne a5,zero,.L15 + lw a5,44(a0) + bne a5,zero,.L16 lbu a3,60(a0) +.L17: #APP csrw 2000, 2 #NO_APP - lhu a5,64(a0) + lhu a4,64(s0) #APP - csrr a4, 2003 + csrr a2, 2003 #NO_APP - li a2,-65536 - and a4,a4,a2 - or a5,a5,a4 + li a1,-65536 + and a2,a2,a1 + or a4,a4,a2 #APP - csrw 2003, a5 + csrw 2003, a4 csrw 3011, 0 #NO_APP - li a4,2031616 - slli a5,a3,16 - and a5,a5,a4 - ori a5,a5,4 + li a2,2031616 + slli a4,a3,16 + and a4,a4,a2 + ori a4,a4,4 #APP - csrw 3043, a5 + csrw 3043, a4 #NO_APP - lw a5,4(a0) - li a4,1 - beq a5,a4,.L16 - li a4,2 - beq a5,a4,.L17 + li a4,20 + mul a5,a5,a4 + li a2,1 + add a5,s0,a5 + lw a4,4(a5) + beq a4,a2,.L18 + li a2,2 + beq a4,a2,.L19 li a5,32 div a5,a5,a3 j .L35 -.L16: - lbu a5,8(a0) +.L15: + lw a5,44(s0) + bne a5,zero,.L16 + lbu a3,61(s0) + li a5,1 + j .L17 +.L18: + lbu a5,8(a5) .L35: #APP csrw 3022, a5 + csrr a5, 3008 #NO_APP -.L15: - #APP - csrr a4, 3008 - #NO_APP - lbu a5,68(s0) - lbu a3,66(s0) - bne a5,zero,.L19 - li a5,1 - sll a5,a5,a3 - not a5,a5 - and a5,a5,a4 -.L36: + lbu a4,68(s0) slli a5,a5,16 + lbu a3,66(s0) srli a5,a5,16 + bne a4,zero,.L22 + li a4,1 + sll a4,a4,a3 + not a4,a4 + and a5,a5,a4 +.L23: #APP csrw 3008, a5 #NO_APP @@ -183,57 +194,62 @@ hrt_write: addi a0,s0,40 call hrt_tx lbu a5,69(s0) - beq a5,zero,.L21 -.L22: + beq a5,zero,.L24 +.L25: #APP csrr a5, 3022 #NO_APP andi a5,a5,0xff - bne a5,zero,.L22 + bne a5,zero,.L25 #APP csrw 2010, 0 #NO_APP -.L21: - lw a5,4(sp) +.L24: + li a5,16384 + addi a5,a5,1 #APP csrw 3019, a5 csrw 3017, 0 csrw 2000, 0 #NO_APP lbu a5,67(s0) - bne a5,zero,.L14 + bne a5,zero,.L13 #APP - csrr a4, 3008 + csrr a5, 3008 #NO_APP - lbu a5,68(s0) + lbu a4,68(s0) + slli a5,a5,16 lbu a3,66(s0) - bne a5,zero,.L24 - li a5,1 - sll a5,a5,a3 + srli a5,a5,16 + bne a4,zero,.L27 + li a4,1 + sll a4,a4,a3 or a5,a5,a4 -.L37: slli a5,a5,16 srli a5,a5,16 +.L28: #APP csrw 3008, a5 #NO_APP -.L14: - lw ra,16(sp) - lw s0,12(sp) - addi sp,sp,20 +.L13: + lw ra,12(sp) + lw s0,8(sp) + addi sp,sp,16 jr ra -.L17: - lbu a5,9(a0) - j .L35 .L19: - li a5,1 - sll a5,a5,a3 + lbu a5,9(a5) + j .L35 +.L22: + li a4,1 + sll a4,a4,a3 or a5,a5,a4 - j .L36 -.L24: - li a5,1 - sll a5,a5,a3 - not a5,a5 + slli a5,a5,16 + srli a5,a5,16 + j .L23 +.L27: + li a4,1 + sll a4,a4,a3 + not a4,a4 and a5,a5,a4 - j .L37 + j .L28 .size hrt_write, .-hrt_write diff --git a/applications/sdp/mspi/src/main.c b/applications/sdp/mspi/src/main.c index d5cd085c999f..95854dcfa6f5 100644 --- a/applications/sdp/mspi/src/main.c +++ b/applications/sdp/mspi/src/main.c @@ -21,6 +21,7 @@ #define CE_PINS_MAX 9 #define DATA_PINS_MAX 8 +#define VIO_COUNT 11 #define HRT_IRQ_PRIORITY 2 #define HRT_VEVIF_IDX_WRITE 18 @@ -28,7 +29,10 @@ #define VEVIF_IRQN(vevif) VEVIF_IRQN_1(vevif) #define VEVIF_IRQN_1(vevif) VPRCLIC_##vevif##_IRQn -static const uint8_t pin_to_vio_map[] = { +/* In OCTAL mode 4 bytes for address + 32 bytes for up to 32 dummy cycles*/ +#define ADDR_AND_CYCLES_MAX_SIZE 36 + +static const uint8_t pin_to_vio_map[VIO_COUNT] = { 4, /* Physical pin 0 */ 0, /* Physical pin 1 */ 1, /* Physical pin 2 */ @@ -42,6 +46,19 @@ static const uint8_t pin_to_vio_map[] = { 10, /* Physical pin 10 */ }; +static const hrt_xfer_io_mode_cfg_t io_modes[] = { + {1, 1, 1}, /* MSPI_IO_MODE_SINGLE */ + {2, 2, 2}, /* MSPI_IO_MODE_DUAL */ + {1, 1, 2}, /* MSPI_IO_MODE_DUAL_1_1_2 */ + {1, 2, 2}, /* MSPI_IO_MODE_DUAL_1_2_2 */ + {4, 4, 4}, /* MSPI_IO_MODE_QUAD */ + {1, 1, 4}, /* MSPI_IO_MODE_QUAD_1_1_4 */ + {1, 4, 4}, /* MSPI_IO_MODE_QUAD_1_4_4 */ + {8, 8, 8}, /* MSPI_IO_MODE_OCTAL */ + {1, 1, 8}, /* MSPI_IO_MODE_OCTAL_1_1_8 */ + {1, 8, 8}, /* MSPI_IO_MODE_OCTAL_1_8_8 */ +}; + static volatile uint8_t ce_vios_count; static volatile uint8_t ce_vios[CE_PINS_MAX]; static volatile uint8_t data_vios_count; @@ -49,11 +66,69 @@ static volatile uint8_t data_vios[DATA_PINS_MAX]; static volatile struct mspi_cfg nrfe_mspi_cfg; static volatile struct mspi_dev_cfg nrfe_mspi_dev_cfg; static volatile struct mspi_xfer nrfe_mspi_xfer; -static struct hrt_xfer xfer_params; +static hrt_xfer_t xfer_params; +static volatile uint8_t address_and_dummy_cycles[ADDR_AND_CYCLES_MAX_SIZE]; static struct ipc_ept ep; static atomic_t ipc_atomic_sem = ATOMIC_INIT(0); +static hrt_xfer_data_t prepare_transfer_data(uint16_t frame_width, uint32_t data_length, + void (*vio_out_set)(uint32_t value), + uint8_t *data) +{ + hrt_xfer_data_t xfer_data; + + if (data_length == 0) { + xfer_data.data = data; + xfer_data.words = 0; + xfer_data.last_word_clocks = 0; + xfer_data.penultimate_word_clocks = 0; + xfer_data.last_word = 0; + xfer_data.vio_out_set = vio_out_set; + + return xfer_data; + } + + /* Due to hardware limitation, it is not possible to send only 1 clock pulse. */ + NRFX_ASSERT(data_length / frame_width >= 1); + NRFX_ASSERT(data_vios_count >= frame_width); + NRFX_ASSERT(data_length % frame_width == 0); + + xfer_data.data = data; + xfer_data.vio_out_set = vio_out_set; + + uint8_t last_word_length = data_length % BITS_IN_WORD; + uint8_t penultimate_word_length = BITS_IN_WORD; + + xfer_data.words = NRFX_CEIL_DIV(data_length, BITS_IN_WORD); + xfer_data.last_word = ((uint32_t *)xfer_data.data)[xfer_data.words - 1]; + + /* Due to hardware limitations it is nt possible to send only 1 clock cycle. + * Therefore when data_length%32==1 last word is sent shorter (24bits) + * and the remaining byte and 1 bit is sent together. + */ + if (last_word_length == 0) { + + last_word_length = BITS_IN_WORD; + xfer_data.last_word = ((uint32_t *)xfer_data.data)[xfer_data.words - 1]; + + } else if ((last_word_length / frame_width == 1) && (xfer_data.words > 1)) { + + penultimate_word_length -= BITS_IN_BYTE; + last_word_length += BITS_IN_BYTE; + + xfer_data.last_word = ((uint32_t *)xfer_data.data)[xfer_data.words - 2] >> + (BITS_IN_WORD - BITS_IN_BYTE) | + ((uint32_t *)xfer_data.data)[xfer_data.words - 1] + << BITS_IN_BYTE; + } + + xfer_data.last_word_clocks = last_word_length / frame_width; + xfer_data.penultimate_word_clocks = penultimate_word_length / frame_width; + + return xfer_data; +} + static void configure_clock(enum mspi_cpp_mode cpp_mode) { nrf_vpr_csr_vio_config_t vio_config = { @@ -65,29 +140,25 @@ static void configure_clock(enum mspi_cpp_mode cpp_mode) switch (cpp_mode) { case MSPI_CPP_MODE_0: { vio_config.clk_polarity = 0; - out = BIT_SET_VALUE(out, pin_to_vio_map[NRFE_MSPI_SCK_PIN_NUMBER], - VPRCSR_NORDIC_OUT_LOW); + WRITE_BIT(out, pin_to_vio_map[NRFE_MSPI_SCK_PIN_NUMBER], VPRCSR_NORDIC_OUT_LOW); xfer_params.eliminate_last_pulse = false; break; } case MSPI_CPP_MODE_1: { vio_config.clk_polarity = 1; - out = BIT_SET_VALUE(out, pin_to_vio_map[NRFE_MSPI_SCK_PIN_NUMBER], - VPRCSR_NORDIC_OUT_LOW); + WRITE_BIT(out, pin_to_vio_map[NRFE_MSPI_SCK_PIN_NUMBER], VPRCSR_NORDIC_OUT_LOW); xfer_params.eliminate_last_pulse = true; break; } case MSPI_CPP_MODE_2: { vio_config.clk_polarity = 1; - out = BIT_SET_VALUE(out, pin_to_vio_map[NRFE_MSPI_SCK_PIN_NUMBER], - VPRCSR_NORDIC_OUT_HIGH); + WRITE_BIT(out, pin_to_vio_map[NRFE_MSPI_SCK_PIN_NUMBER], VPRCSR_NORDIC_OUT_HIGH); xfer_params.eliminate_last_pulse = false; break; } case MSPI_CPP_MODE_3: { vio_config.clk_polarity = 0; - out = BIT_SET_VALUE(out, pin_to_vio_map[NRFE_MSPI_SCK_PIN_NUMBER], - VPRCSR_NORDIC_OUT_HIGH); + WRITE_BIT(out, pin_to_vio_map[NRFE_MSPI_SCK_PIN_NUMBER], VPRCSR_NORDIC_OUT_HIGH); xfer_params.eliminate_last_pulse = true; break; } @@ -96,7 +167,49 @@ static void configure_clock(enum mspi_cpp_mode cpp_mode) nrf_vpr_csr_vio_config_set(&vio_config); } -static void config_pins() +static void prepare_and_send_data(struct mspi_xfer_packet xfer_packet) +{ + NRFX_ASSERT(nrfe_mspi_dev_cfg.ce_num < ce_vios_count); + NRFX_ASSERT(nrfe_mspi_dev_cfg.io_mode < sizeof(io_modes) / sizeof(io_modes[0])); + + xfer_params.counter_value = 4; + xfer_params.ce_vio = ce_vios[nrfe_mspi_dev_cfg.ce_num]; + xfer_params.ce_hold = nrfe_mspi_xfer.hold_ce; + xfer_params.ce_polarity = nrfe_mspi_dev_cfg.ce_polarity; + xfer_params.io_mode = io_modes[nrfe_mspi_dev_cfg.io_mode]; + + xfer_packet.address = xfer_packet.address + << (BITS_IN_WORD - nrfe_mspi_xfer.addr_length * BITS_IN_BYTE); + xfer_packet.cmd = xfer_packet.cmd + << (BITS_IN_WORD - nrfe_mspi_xfer.cmd_length * BITS_IN_BYTE); + + xfer_params.xfer_data[HRT_FE_COMMAND] = prepare_transfer_data( + io_modes[nrfe_mspi_dev_cfg.io_mode].command, + nrfe_mspi_xfer.cmd_length * BITS_IN_BYTE, + &nrf_vpr_csr_vio_out_buffered_reversed_word_set, (uint8_t *)&xfer_packet.cmd); + + for (uint8_t i = 0; i < sizeof(uint32_t); i++) { + address_and_dummy_cycles[i] = *(uint8_t *)&xfer_packet.address; + } + + for (uint8_t i = sizeof(uint32_t); i < ADDR_AND_CYCLES_MAX_SIZE; i++) { + address_and_dummy_cycles[i] = 0; + } + + xfer_params.xfer_data[HRT_FE_ADDRESS] = prepare_transfer_data( + io_modes[nrfe_mspi_dev_cfg.io_mode].address, + nrfe_mspi_xfer.addr_length * BITS_IN_BYTE + + nrfe_mspi_xfer.tx_dummy * io_modes[nrfe_mspi_dev_cfg.io_mode].address, + &nrf_vpr_csr_vio_out_buffered_reversed_word_set, (uint8_t *)&xfer_packet.address); + + xfer_params.xfer_data[HRT_FE_DATA] = prepare_transfer_data( + io_modes[nrfe_mspi_dev_cfg.io_mode].data, xfer_packet.num_bytes * BITS_IN_BYTE, + &nrf_vpr_csr_vio_out_buffered_reversed_byte_set, xfer_packet.data_buf); + + nrf_vpr_clic_int_pending_set(NRF_VPRCLIC, VEVIF_IRQN(HRT_VEVIF_IDX_WRITE)); +} + +static void config_pins(nrfe_mspi_pinctrl_soc_pin_t *pins_cfg) { ce_vios_count = 0; data_vios_count = 0; @@ -109,51 +222,36 @@ static void config_pins() uint8_t pin_number = NRF_PIN_NUMBER_TO_PIN(psel); - if (pin_number >= sizeof(pin_to_vio_map)) { - /* TODO: Jira ticket: NRFX-6875 error*/ - return; - } + NRFX_ASSERT(pin_number < VIO_COUNT) if ((fun >= NRF_FUN_SDP_MSPI_CS0) && (fun <= NRF_FUN_SDP_MSPI_CS4)) { - NRFX_ASSERT(pin_number < sizeof(pin_to_vio_map)) ce_vios[ce_vios_count] = pin_to_vio_map[pin_number]; - xfer_params.tx_direction_mask = BIT_SET_VALUE( - xfer_params.tx_direction_mask, ce_vios[ce_vios_count], - VPRCSR_NORDIC_DIR_OUTPUT); - xfer_params.rx_direction_mask = BIT_SET_VALUE( - xfer_params.rx_direction_mask, ce_vios[ce_vios_count], - VPRCSR_NORDIC_DIR_OUTPUT); + WRITE_BIT(xfer_params.tx_direction_mask, ce_vios[ce_vios_count], + VPRCSR_NORDIC_DIR_OUTPUT); + WRITE_BIT(xfer_params.rx_direction_mask, ce_vios[ce_vios_count], + VPRCSR_NORDIC_DIR_OUTPUT); ce_vios_count++; - /* TODO: Jira ticket: NRFX-6876 Get CE disabled states and set them, - * they need to be passed from app - */ } else if ((fun >= NRF_FUN_SDP_MSPI_DQ0) && (fun <= NRF_FUN_SDP_MSPI_DQ7)) { - NRFX_ASSERT(pin_number < sizeof(pin_to_vio_map)) data_vios[data_vios_count] = pin_to_vio_map[pin_number]; - xfer_params.tx_direction_mask = BIT_SET_VALUE( - xfer_params.tx_direction_mask, - data_vios[data_vios_count], VPRCSR_NORDIC_DIR_OUTPUT); - xfer_params.rx_direction_mask = BIT_SET_VALUE( - xfer_params.rx_direction_mask, - data_vios[data_vios_count], VPRCSR_NORDIC_DIR_INPUT); + WRITE_BIT(xfer_params.tx_direction_mask, data_vios[data_vios_count], + VPRCSR_NORDIC_DIR_OUTPUT); + WRITE_BIT(xfer_params.rx_direction_mask, data_vios[data_vios_count], + VPRCSR_NORDIC_DIR_INPUT); data_vios_count++; } else if (fun == NRF_FUN_SDP_MSPI_SCK) { - xfer_params.tx_direction_mask = - BIT_SET_VALUE(xfer_params.tx_direction_mask, - pin_to_vio_map[NRFE_MSPI_SCK_PIN_NUMBER], - VPRCSR_NORDIC_DIR_OUTPUT); - xfer_params.rx_direction_mask = - BIT_SET_VALUE(xfer_params.rx_direction_mask, - pin_to_vio_map[NRFE_MSPI_SCK_PIN_NUMBER], - VPRCSR_NORDIC_DIR_OUTPUT); + WRITE_BIT(xfer_params.tx_direction_mask, + pin_to_vio_map[NRFE_MSPI_SCK_PIN_NUMBER], + VPRCSR_NORDIC_DIR_OUTPUT); + WRITE_BIT(xfer_params.rx_direction_mask, + pin_to_vio_map[NRFE_MSPI_SCK_PIN_NUMBER], + VPRCSR_NORDIC_DIR_OUTPUT); } } nrf_vpr_csr_vio_dir_set(xfer_params.tx_direction_mask); - nrf_vpr_csr_vio_out_set(BIT_SET_VALUE(0, pin_to_vio_map[NRFE_MSPI_CS0_PIN_NUMBER], - VPRCSR_NORDIC_OUT_HIGH)); + nrf_vpr_csr_vio_out_set(VPRCSR_NORDIC_OUT_HIGH << pin_to_vio_map[NRFE_MSPI_CS0_PIN_NUMBER]); } static void ep_bound(void *priv) @@ -174,7 +272,7 @@ static void ep_recv(const void *data, size_t len, void *priv) response.opcode = pins_cfg->opcode; - config_pins(); + config_pins(pins_cfg); break; } case NRFE_MSPI_CONFIG_CTRL: { @@ -206,9 +304,8 @@ static void ep_recv(const void *data, size_t len, void *priv) response.opcode = packet->opcode; if (packet->packet.dir == MSPI_RX) { - /* TODO: Jira ticket: NRFX-6877 Process received data */ } else if (packet->packet.dir == MSPI_TX) { - //TODO prepare_and_send_data(packet->packet); + prepare_and_send_data(packet->packet); } break; } @@ -282,4 +379,4 @@ int main(void) } return 0; -} \ No newline at end of file +}