diff --git a/hal/qspi_api.h b/hal/qspi_api.h index 12667e0fdb..8982aea502 100644 --- a/hal/qspi_api.h +++ b/hal/qspi_api.h @@ -141,16 +141,6 @@ qspi_status_t qspi_free(qspi_t *obj); */ qspi_status_t qspi_frequency(qspi_t *obj, int hz); -/** Send only QSPI command - * - * @param obj QSPI object - * @param command QSPI command - * @return QSPI_STATUS_OK if command was sent without any error - QSPI_STATUS_INVALID_PARAMETER if invalid parameter found - QSPI_STATUS_ERROR otherwise - */ -qspi_status_t qspi_write_command(qspi_t *obj, const qspi_command_t *command); - /** Send a command and block of data * * @param obj QSPI object @@ -163,6 +153,22 @@ qspi_status_t qspi_write_command(qspi_t *obj, const qspi_command_t *command); */ qspi_status_t qspi_write(qspi_t *obj, const qspi_command_t *command, const void *data, size_t *length); +/** Send a command (and optionally data) and get the response. Can be used to send/receive device specific commands. + * + * @param obj QSPI object + * @param command QSPI command + * @param tx_data TX buffer + * @param tx_length pointer to variable holding TX buffer length + * @param rx_data TX buffer + * @param rx_length pointer to variable holding TX buffer length + * @return QSPI_STATUS_OK if the data has been succesfully sent + QSPI_STATUS_INVALID_PARAMETER if invalid parameter found + QSPI_STATUS_ERROR otherwise + */ + +qspi_status_t qspi_command_transfer(qspi_t *obj, const qspi_command_t *command, const void *tx_data, size_t tx_size, void *rx_data, size_t rx_size); + + /** Receive a command and block of data * * @param obj QSPI object diff --git a/targets/TARGET_NORDIC/TARGET_NRF5/qspi_api.c b/targets/TARGET_NORDIC/TARGET_NRF5/qspi_api.c index b3f547e074..10c8e6b1fc 100644 --- a/targets/TARGET_NORDIC/TARGET_NRF5/qspi_api.c +++ b/targets/TARGET_NORDIC/TARGET_NRF5/qspi_api.c @@ -53,56 +53,79 @@ TODO - dummy cycles */ -#define MBED_HAL_QSPI_HZ_TO_CONFIG(hz) ((32000000/(hz))-1) -#define MBED_HAL_QSPI_MAX_FREQ 32000000UL +#define MBED_HAL_QSPI_HZ_TO_CONFIG(hz) ((32000000/(hz))-1) +#define MBED_HAL_QSPI_MAX_FREQ 32000000UL static nrf_drv_qspi_config_t config; qspi_status_t qspi_prepare_command(qspi_t *obj, const qspi_command_t *command, bool write) { - // we need to remap to command-address-data - x_x_x - // most commmon are 1-1-1, 1-1-4, 1-4-4 - // 1-1-1 - if (command->instruction.bus_width == QSPI_CFG_BUS_SINGLE && - command->address.bus_width == QSPI_CFG_BUS_SINGLE && - command->data.bus_width == QSPI_CFG_BUS_SINGLE) { + //Use custom command if provided by the caller + if(command->instruction.value != 0) { + //Use custom command if provided if (write) { - config.prot_if.writeoc = NRF_QSPI_WRITEOC_PP; + config.prot_if.writeoc = (nrf_qspi_writeoc_t)command->instruction.value; } else { - config.prot_if.readoc = NRF_QSPI_READOC_FASTREAD; + config.prot_if.readoc = (nrf_qspi_readoc_t)command->instruction.value; } - // 1-1-4 - } else if (command->instruction.bus_width == QSPI_CFG_BUS_SINGLE && - command->address.bus_width == QSPI_CFG_BUS_SINGLE && - command->data.bus_width == QSPI_CFG_BUS_QUAD) { - // 1_1_4 - if (write) { - config.prot_if.writeoc = QSPI_IFCONFIG0_WRITEOC_PP4O; - } else { - config.prot_if.readoc = NRF_QSPI_READOC_READ4O; + } else { + // we need to remap to command-address-data - x_x_x + // most commmon are 1-1-1, 1-1-4, 1-4-4 + // 1-1-1 + if (command->instruction.bus_width == QSPI_CFG_BUS_SINGLE && + command->address.bus_width == QSPI_CFG_BUS_SINGLE && + command->data.bus_width == QSPI_CFG_BUS_SINGLE) { + if (write) { + config.prot_if.writeoc = NRF_QSPI_WRITEOC_PP; + } else { + config.prot_if.readoc = NRF_QSPI_READOC_FASTREAD; + } + // 1-1-4 + } else if (command->instruction.bus_width == QSPI_CFG_BUS_SINGLE && + command->address.bus_width == QSPI_CFG_BUS_SINGLE && + command->data.bus_width == QSPI_CFG_BUS_QUAD) { + // 1_1_4 + if (write) { + config.prot_if.writeoc = NRF_QSPI_WRITEOC_PP4O; + } else { + config.prot_if.readoc = NRF_QSPI_READOC_READ4O; + } + // 1-4-4 + } else if (command->instruction.bus_width == QSPI_CFG_BUS_SINGLE && + command->address.bus_width == QSPI_CFG_BUS_QUAD && + command->data.bus_width == QSPI_CFG_BUS_QUAD) { + // 1_4_4 + if (write) { + config.prot_if.writeoc = NRF_QSPI_WRITEOC_PP4IO; + } else { + config.prot_if.readoc = NRF_QSPI_READOC_READ4IO; + } } - // 1-4-4 - } else if (command->instruction.bus_width == QSPI_CFG_BUS_SINGLE && - command->address.bus_width == QSPI_CFG_BUS_QUAD && - command->data.bus_width == QSPI_CFG_BUS_QUAD) { - // 1_4_4 - if (write) { - config.prot_if.writeoc = QSPI_IFCONFIG0_WRITEOC_PP4IO; - } else { - config.prot_if.readoc = NRF_QSPI_READOC_READ4IO; - } - } - + } + qspi_status_t ret = QSPI_STATUS_OK; // supporting only 24 or 32 bit address if (command->address.size == QSPI_CFG_ADDR_SIZE_24) { config.prot_if.addrmode = NRF_QSPI_ADDRMODE_24BIT; } else if (command->address.size == QSPI_CFG_ADDR_SIZE_32) { - config.prot_if.addrmode = QSPI_CFG_ADDR_SIZE_32; + config.prot_if.addrmode = NRF_QSPI_ADDRMODE_32BIT; } else { ret = QSPI_STATUS_INVALID_PARAMETER; } + + //Configure QSPI with new command format + if(ret == QSPI_STATUS_OK) { + ret_code_t ret_status = nrf_drv_qspi_init(&config, NULL , NULL); + if (ret_status != NRF_SUCCESS ) { + if (ret_status == NRF_ERROR_INVALID_PARAM) { + return QSPI_STATUS_INVALID_PARAMETER; + } else { + return QSPI_STATUS_ERROR; + } + } + } + return ret; } @@ -123,14 +146,19 @@ qspi_status_t qspi_init(qspi_t *obj, PinName io0, PinName io1, PinName io2, PinN config.pins.io3_pin = (uint32_t)io3; config.irq_priority = SPI_DEFAULT_CONFIG_IRQ_PRIORITY; - config.phy_if.sck_freq = MBED_HAL_QSPI_HZ_TO_CONFIG(hz), + config.phy_if.sck_freq = (nrf_qspi_frequency_t)MBED_HAL_QSPI_HZ_TO_CONFIG(hz), config.phy_if.sck_delay = 0x05, config.phy_if.dpmen = false; config.phy_if.spi_mode = mode == 0 ? NRF_QSPI_MODE_0 : NRF_QSPI_MODE_1; - nrf_drv_qspi_init(&config, NULL , NULL); - - return 0; + ret_code_t ret = nrf_drv_qspi_init(&config, NULL , NULL); + if (ret == NRF_SUCCESS ) { + return QSPI_STATUS_OK; + } else if (ret == NRF_ERROR_INVALID_PARAM) { + return QSPI_STATUS_INVALID_PARAMETER; + } else { + return QSPI_STATUS_ERROR; + } } qspi_status_t qspi_free(qspi_t *obj) @@ -142,7 +170,7 @@ qspi_status_t qspi_free(qspi_t *obj) qspi_status_t qspi_frequency(qspi_t *obj, int hz) { - config.phy_if.sck_freq = MBED_HAL_QSPI_HZ_TO_CONFIG(hz); + config.phy_if.sck_freq = (nrf_qspi_frequency_t)MBED_HAL_QSPI_HZ_TO_CONFIG(hz); // use sync version, no handler ret_code_t ret = nrf_drv_qspi_init(&config, NULL , NULL); if (ret == NRF_SUCCESS ) { @@ -185,30 +213,52 @@ qspi_status_t qspi_read(qspi_t *obj, const qspi_command_t *command, void *data, } } -// they provide 2 functions write or nrf_drv_qspi_cinstr_xfer -// nrf_drv_qspi_cinstr_xfer seems like it accepts simplified config that is very simplified -// and might not be useful for us. -// write on other hand, needs to write some data (errors if buffer is NULL!) -qspi_status_t qspi_write_command(qspi_t *obj, const qspi_command_t *command) +qspi_status_t qspi_command_transfer(qspi_t *obj, const qspi_command_t *command, const void *tx_data, size_t tx_size, void *rx_data, size_t rx_size) { - // use simplified API, as we are sending only instruction here - nrf_qspi_cinstr_conf_t config; - config.length = NRF_QSPI_CINSTR_LEN_1B; // no data - config.opcode = command->instruction.value; - config.io2_level = false; - config.io3_level = false; - config.wipwait = false; - config.wren = false; - - // no data phase, send only config - ret_code_t ret = nrf_drv_qspi_cinstr_xfer(&config, NULL, NULL); - if (ret == NRF_SUCCESS ) { - return QSPI_STATUS_OK; - } else { + ret_code_t ret_code; + uint32_t i; + uint8_t data[8]; + uint32_t data_size = tx_size + rx_size; + + nrf_qspi_cinstr_conf_t qspi_cinstr_config; + qspi_cinstr_config.opcode = command->instruction.value; + qspi_cinstr_config.io2_level = false; + qspi_cinstr_config.io3_level = false; + qspi_cinstr_config.wipwait = false; + qspi_cinstr_config.wren = false; + + if (data_size < 9) + { + qspi_cinstr_config.length = (nrf_qspi_cinstr_len_t)(NRF_QSPI_CINSTR_LEN_1B + data_size); + } + else + { return QSPI_STATUS_ERROR; } + + // preparing data to send + for (i = 0; i < tx_size; ++i) + { + data[i] = ((uint8_t *)tx_data)[i]; + } + + ret_code = nrf_drv_qspi_cinstr_xfer(&qspi_cinstr_config, data, data); + if (ret_code != NRF_SUCCESS) + { + return QSPI_STATUS_ERROR; + } + + // preparing received data + for (i = 0; i < rx_size; ++i) + { + // Data is sending as a normal SPI transmission so there is one buffer to send and receive data. + ((uint8_t *)rx_data)[i] = data[i]; + } + + return QSPI_STATUS_OK; } + #endif /** @}*/