mirror of https://github.com/ARMmbed/mbed-os.git
				
				
				
			Modify QSPI HAL API to include an API for command-transfer operations
							parent
							
								
									d1b51b6328
								
							
						
					
					
						commit
						2df58e2d25
					
				| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -53,43 +53,53 @@ 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;
 | 
			
		||||
        }
 | 
			
		||||
    // 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;
 | 
			
		||||
    } 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;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }    
 | 
			
		||||
    
 | 
			
		||||
| 
						 | 
				
			
			@ -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) {
 | 
			
		||||
        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;
 | 
			
		||||
    ret_code_t ret_code;
 | 
			
		||||
    uint32_t i;
 | 
			
		||||
    uint8_t data[8];
 | 
			
		||||
    uint32_t data_size = tx_size + rx_size;
 | 
			
		||||
 
 | 
			
		||||
    // 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 {
 | 
			
		||||
    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
 | 
			
		||||
 | 
			
		||||
/** @}*/
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue