Modify QSPI HAL API to include an API for command-transfer operations

pull/6106/head
Senthil Ramakrishnan 2017-11-22 19:02:56 -06:00 committed by Martin Kojtal
parent e8c059cca7
commit 9c0634fe43
2 changed files with 122 additions and 66 deletions

View File

@ -141,16 +141,6 @@ qspi_status_t qspi_free(qspi_t *obj);
*/ */
qspi_status_t qspi_frequency(qspi_t *obj, int hz); 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 /** Send a command and block of data
* *
* @param obj QSPI object * @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); 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 /** Receive a command and block of data
* *
* @param obj QSPI object * @param obj QSPI object

View File

@ -53,43 +53,53 @@ TODO
- dummy cycles - dummy cycles
*/ */
#define MBED_HAL_QSPI_HZ_TO_CONFIG(hz) ((32000000/(hz))-1) #define MBED_HAL_QSPI_HZ_TO_CONFIG(hz) ((32000000/(hz))-1)
#define MBED_HAL_QSPI_MAX_FREQ 32000000UL #define MBED_HAL_QSPI_MAX_FREQ 32000000UL
static nrf_drv_qspi_config_t config; static nrf_drv_qspi_config_t config;
qspi_status_t qspi_prepare_command(qspi_t *obj, const qspi_command_t *command, bool write) 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 //Use custom command if provided by the caller
// most commmon are 1-1-1, 1-1-4, 1-4-4 if(command->instruction.value != 0) {
// 1-1-1 //Use custom command if provided
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) { if (write) {
config.prot_if.writeoc = NRF_QSPI_WRITEOC_PP; config.prot_if.writeoc = (nrf_qspi_writeoc_t)command->instruction.value;
} else { } else {
config.prot_if.readoc = NRF_QSPI_READOC_FASTREAD; config.prot_if.readoc = (nrf_qspi_readoc_t)command->instruction.value;
} }
// 1-1-4 } else {
} else if (command->instruction.bus_width == QSPI_CFG_BUS_SINGLE && // we need to remap to command-address-data - x_x_x
command->address.bus_width == QSPI_CFG_BUS_SINGLE && // most commmon are 1-1-1, 1-1-4, 1-4-4
command->data.bus_width == QSPI_CFG_BUS_QUAD) { // 1-1-1
// 1_1_4 if (command->instruction.bus_width == QSPI_CFG_BUS_SINGLE &&
if (write) { command->address.bus_width == QSPI_CFG_BUS_SINGLE &&
config.prot_if.writeoc = QSPI_IFCONFIG0_WRITEOC_PP4O; command->data.bus_width == QSPI_CFG_BUS_SINGLE) {
} else { if (write) {
config.prot_if.readoc = NRF_QSPI_READOC_READ4O; config.prot_if.writeoc = NRF_QSPI_WRITEOC_PP;
} } else {
// 1-4-4 config.prot_if.readoc = NRF_QSPI_READOC_FASTREAD;
} else if (command->instruction.bus_width == QSPI_CFG_BUS_SINGLE && }
command->address.bus_width == QSPI_CFG_BUS_QUAD && // 1-1-4
command->data.bus_width == QSPI_CFG_BUS_QUAD) { } else if (command->instruction.bus_width == QSPI_CFG_BUS_SINGLE &&
// 1_4_4 command->address.bus_width == QSPI_CFG_BUS_SINGLE &&
if (write) { command->data.bus_width == QSPI_CFG_BUS_QUAD) {
config.prot_if.writeoc = QSPI_IFCONFIG0_WRITEOC_PP4IO; // 1_1_4
} else { if (write) {
config.prot_if.readoc = NRF_QSPI_READOC_READ4IO; 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;
}
} }
} }
@ -99,10 +109,23 @@ qspi_status_t qspi_prepare_command(qspi_t *obj, const qspi_command_t *command, b
if (command->address.size == QSPI_CFG_ADDR_SIZE_24) { if (command->address.size == QSPI_CFG_ADDR_SIZE_24) {
config.prot_if.addrmode = NRF_QSPI_ADDRMODE_24BIT; config.prot_if.addrmode = NRF_QSPI_ADDRMODE_24BIT;
} else if (command->address.size == QSPI_CFG_ADDR_SIZE_32) { } 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 { } else {
ret = QSPI_STATUS_INVALID_PARAMETER; 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; 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.pins.io3_pin = (uint32_t)io3;
config.irq_priority = SPI_DEFAULT_CONFIG_IRQ_PRIORITY; 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.sck_delay = 0x05,
config.phy_if.dpmen = false; config.phy_if.dpmen = false;
config.phy_if.spi_mode = mode == 0 ? NRF_QSPI_MODE_0 : NRF_QSPI_MODE_1; config.phy_if.spi_mode = mode == 0 ? NRF_QSPI_MODE_0 : NRF_QSPI_MODE_1;
nrf_drv_qspi_init(&config, NULL , NULL); ret_code_t ret = nrf_drv_qspi_init(&config, NULL , NULL);
if (ret == NRF_SUCCESS ) {
return 0; 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) 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) 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 // use sync version, no handler
ret_code_t ret = nrf_drv_qspi_init(&config, NULL , NULL); ret_code_t ret = nrf_drv_qspi_init(&config, NULL , NULL);
if (ret == NRF_SUCCESS ) { 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 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)
// 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)
{ {
// use simplified API, as we are sending only instruction here ret_code_t ret_code;
nrf_qspi_cinstr_conf_t config; uint32_t i;
config.length = NRF_QSPI_CINSTR_LEN_1B; // no data uint8_t data[8];
config.opcode = command->instruction.value; uint32_t data_size = tx_size + rx_size;
config.io2_level = false;
config.io3_level = false;
config.wipwait = false;
config.wren = false;
// no data phase, send only config nrf_qspi_cinstr_conf_t qspi_cinstr_config;
ret_code_t ret = nrf_drv_qspi_cinstr_xfer(&config, NULL, NULL); qspi_cinstr_config.opcode = command->instruction.value;
if (ret == NRF_SUCCESS ) { qspi_cinstr_config.io2_level = false;
return QSPI_STATUS_OK; qspi_cinstr_config.io3_level = false;
} else { 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; 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 #endif
/** @}*/ /** @}*/