Allow for arbitrary QSPI alt sizes

The QSPI spec allows alt to be any size that is a multiple of the
number of data lines. For example, Micron's N25Q128A uses only a
single alt cycle for all read modes (1, 2, or 4 bits depending on
how many data lines are in use).
pull/11696/head
Matthew Macovsky 2019-09-06 18:09:21 +01:00 committed by adbridge
parent 03affe94d8
commit 08a2709993
11 changed files with 266 additions and 106 deletions

View File

@ -102,10 +102,10 @@ struct Qspi {
#define ADDR_SIZE_24 QSPI_CFG_ADDR_SIZE_24 #define ADDR_SIZE_24 QSPI_CFG_ADDR_SIZE_24
#define ADDR_SIZE_32 QSPI_CFG_ADDR_SIZE_32 #define ADDR_SIZE_32 QSPI_CFG_ADDR_SIZE_32
#define ALT_SIZE_8 QSPI_CFG_ALT_SIZE_8 #define ALT_SIZE_8 8u
#define ALT_SIZE_16 QSPI_CFG_ALT_SIZE_16 #define ALT_SIZE_16 16u
#define ALT_SIZE_24 QSPI_CFG_ALT_SIZE_24 #define ALT_SIZE_24 24u
#define ALT_SIZE_32 QSPI_CFG_ALT_SIZE_32 #define ALT_SIZE_32 32u
#define STATUS_REG QSPI_CMD_RDSR #define STATUS_REG QSPI_CMD_RDSR
#define CONFIG_REG0 QSPI_CMD_RDCR0 #define CONFIG_REG0 QSPI_CMD_RDCR0

View File

@ -247,7 +247,7 @@ int QSPIFBlockDevice::init()
// Configure BUS Mode to 1_1_1 for all commands other than Read // Configure BUS Mode to 1_1_1 for all commands other than Read
_qspi_configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE, _qspi_configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE,
QSPI_CFG_ALT_SIZE_8, QSPI_CFG_BUS_SINGLE, 0); 0, QSPI_CFG_BUS_SINGLE, 0);
_is_initialized = true; _is_initialized = true;
@ -303,7 +303,7 @@ int QSPIFBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size)
// Configure Bus for Reading // Configure Bus for Reading
_qspi_configure_format(_inst_width, _address_width, _address_size, QSPI_CFG_BUS_SINGLE, _qspi_configure_format(_inst_width, _address_width, _address_size, QSPI_CFG_BUS_SINGLE,
QSPI_CFG_ALT_SIZE_8, _data_width, _dummy_and_mode_cycles); 0, _data_width, _dummy_and_mode_cycles);
if (QSPI_STATUS_OK != _qspi_send_read_command(_read_instruction, buffer, addr, size)) { if (QSPI_STATUS_OK != _qspi_send_read_command(_read_instruction, buffer, addr, size)) {
status = QSPIF_BD_ERROR_DEVICE_ERROR; status = QSPIF_BD_ERROR_DEVICE_ERROR;
@ -312,7 +312,7 @@ int QSPIFBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size)
// All commands other than Read use default 1-1-1 Bus mode (Program/Erase are constrained by flash memory performance less than that of the bus) // All commands other than Read use default 1-1-1 Bus mode (Program/Erase are constrained by flash memory performance less than that of the bus)
_qspi_configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE, _qspi_configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE,
QSPI_CFG_ALT_SIZE_8, QSPI_CFG_BUS_SINGLE, 0); 0, QSPI_CFG_BUS_SINGLE, 0);
_mutex.unlock(); _mutex.unlock();
return status; return status;
@ -718,7 +718,7 @@ int QSPIFBlockDevice::_sfdp_parse_sfdp_headers(uint32_t &basic_table_addr, size_
// Set 1-1-1 bus mode for SFDP header parsing // Set 1-1-1 bus mode for SFDP header parsing
_qspi_configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE, _qspi_configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE,
QSPI_CFG_ALT_SIZE_8, QSPI_CFG_BUS_SINGLE, 8); 0, QSPI_CFG_BUS_SINGLE, 8);
qspi_status_t status = _qspi_send_read_command(QSPIF_SFDP, (char *)sfdp_header, addr /*address*/, data_length); qspi_status_t status = _qspi_send_read_command(QSPIF_SFDP, (char *)sfdp_header, addr /*address*/, data_length);
if (status != QSPI_STATUS_OK) { if (status != QSPI_STATUS_OK) {
@ -885,7 +885,7 @@ int QSPIFBlockDevice::_sfdp_set_quad_enabled(uint8_t *basic_param_table_ptr)
// Configure BUS Mode to 1_1_1 for all commands other than Read // Configure BUS Mode to 1_1_1 for all commands other than Read
_qspi_configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE, _qspi_configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE,
QSPI_CFG_ALT_SIZE_8, QSPI_CFG_BUS_SINGLE, 0); 0, QSPI_CFG_BUS_SINGLE, 0);
// Read Status Register // Read Status Register
if (QSPI_STATUS_OK == _qspi_send_general_command(_read_register_inst, QSPI_NO_ADDRESS_COMMAND, NULL, 0, if (QSPI_STATUS_OK == _qspi_send_general_command(_read_register_inst, QSPI_NO_ADDRESS_COMMAND, NULL, 0,
@ -1206,7 +1206,7 @@ int QSPIFBlockDevice::_enable_fast_mdoe()
// Configure BUS Mode to 1_1_1 for all commands other than Read // Configure BUS Mode to 1_1_1 for all commands other than Read
_qspi_configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE, _qspi_configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE,
QSPI_CFG_ALT_SIZE_8, QSPI_CFG_BUS_SINGLE, 0); 0, QSPI_CFG_BUS_SINGLE, 0);
// Read Status Register // Read Status Register
if (QSPI_STATUS_OK == _qspi_send_general_command(read_conf_register_inst, QSPI_NO_ADDRESS_COMMAND, NULL, 0, if (QSPI_STATUS_OK == _qspi_send_general_command(read_conf_register_inst, QSPI_NO_ADDRESS_COMMAND, NULL, 0,
@ -1306,7 +1306,6 @@ int QSPIFBlockDevice::_utils_iterate_next_largest_erase_type(uint8_t &bitfield,
tr_error("No erase type was found for current region addr"); tr_error("No erase type was found for current region addr");
} }
return largest_erase_type; return largest_erase_type;
} }
/***************************************************/ /***************************************************/

View File

@ -106,7 +106,7 @@ public:
* @param address_width Bus width used by address phase(Valid values are QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_DUAL, QSPI_CFG_BUS_QUAD) * @param address_width Bus width used by address phase(Valid values are QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_DUAL, QSPI_CFG_BUS_QUAD)
* @param address_size Size in bits used by address phase(Valid values are QSPI_CFG_ADDR_SIZE_8, QSPI_CFG_ADDR_SIZE_16, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_ADDR_SIZE_32) * @param address_size Size in bits used by address phase(Valid values are QSPI_CFG_ADDR_SIZE_8, QSPI_CFG_ADDR_SIZE_16, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_ADDR_SIZE_32)
* @param alt_width Bus width used by alt phase(Valid values are QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_DUAL, QSPI_CFG_BUS_QUAD) * @param alt_width Bus width used by alt phase(Valid values are QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_DUAL, QSPI_CFG_BUS_QUAD)
* @param alt_size Size in bits used by alt phase(Valid values are QSPI_CFG_ALT_SIZE_8, QSPI_CFG_ALT_SIZE_16, QSPI_CFG_ALT_SIZE_24, QSPI_CFG_ALT_SIZE_32) * @param alt_size Size in bits used by alt phase (must be a multiple of the number of bus lines indicated in alt_width)
* @param data_width Bus width used by data phase(Valid values are QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_DUAL, QSPI_CFG_BUS_QUAD) * @param data_width Bus width used by data phase(Valid values are QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_DUAL, QSPI_CFG_BUS_QUAD)
* @param dummy_cycles Number of dummy clock cycles to be used after alt phase * @param dummy_cycles Number of dummy clock cycles to be used after alt phase
* *

View File

@ -26,6 +26,21 @@ namespace mbed {
QSPI *QSPI::_owner = NULL; QSPI *QSPI::_owner = NULL;
SingletonPtr<PlatformMutex> QSPI::_mutex; SingletonPtr<PlatformMutex> QSPI::_mutex;
uint8_t convert_bus_width_to_line_count(qspi_bus_width_t width)
{
switch (width) {
case QSPI_CFG_BUS_SINGLE:
return 1;
case QSPI_CFG_BUS_DUAL:
return 2;
case QSPI_CFG_BUS_QUAD:
return 4;
default:
// Unrecognized bus width
return 0;
}
}
QSPI::QSPI(PinName io0, PinName io1, PinName io2, PinName io3, PinName sclk, PinName ssel, int mode) : _qspi() QSPI::QSPI(PinName io0, PinName io1, PinName io2, PinName io3, PinName sclk, PinName ssel, int mode) : _qspi()
{ {
_qspi_io0 = io0; _qspi_io0 = io0;
@ -38,7 +53,7 @@ QSPI::QSPI(PinName io0, PinName io1, PinName io2, PinName io3, PinName sclk, Pin
_address_width = QSPI_CFG_BUS_SINGLE; _address_width = QSPI_CFG_BUS_SINGLE;
_address_size = QSPI_CFG_ADDR_SIZE_24; _address_size = QSPI_CFG_ADDR_SIZE_24;
_alt_width = QSPI_CFG_BUS_SINGLE; _alt_width = QSPI_CFG_BUS_SINGLE;
_alt_size = QSPI_CFG_ALT_SIZE_8; _alt_size = 0;
_data_width = QSPI_CFG_BUS_SINGLE; _data_width = QSPI_CFG_BUS_SINGLE;
_num_dummy_cycles = 0; _num_dummy_cycles = 0;
_mode = mode; _mode = mode;
@ -52,7 +67,14 @@ QSPI::QSPI(PinName io0, PinName io1, PinName io2, PinName io3, PinName sclk, Pin
qspi_status_t QSPI::configure_format(qspi_bus_width_t inst_width, qspi_bus_width_t address_width, qspi_address_size_t address_size, qspi_bus_width_t alt_width, qspi_alt_size_t alt_size, qspi_bus_width_t data_width, int dummy_cycles) qspi_status_t QSPI::configure_format(qspi_bus_width_t inst_width, qspi_bus_width_t address_width, qspi_address_size_t address_size, qspi_bus_width_t alt_width, qspi_alt_size_t alt_size, qspi_bus_width_t data_width, int dummy_cycles)
{ {
qspi_status_t ret_status = QSPI_STATUS_OK; // Check that alt_size/alt_width are a valid combination
uint8_t alt_lines = convert_bus_width_to_line_count(alt_width);
if (alt_lines == 0) {
return QSPI_STATUS_ERROR;
} else if (alt_size % alt_lines != 0) {
// Invalid alt size/width combination (alt size is not a multiple of the number of bus lines used to transmit it)
return QSPI_STATUS_ERROR;
}
lock(); lock();
_inst_width = inst_width; _inst_width = inst_width;
@ -62,10 +84,9 @@ qspi_status_t QSPI::configure_format(qspi_bus_width_t inst_width, qspi_bus_width
_alt_size = alt_size; _alt_size = alt_size;
_data_width = data_width; _data_width = data_width;
_num_dummy_cycles = dummy_cycles; _num_dummy_cycles = dummy_cycles;
unlock(); unlock();
return ret_status; return QSPI_STATUS_OK;
} }
qspi_status_t QSPI::set_frequency(int hz) qspi_status_t QSPI::set_frequency(int hz)

View File

@ -255,7 +255,7 @@ void test_direct_access_to_device_inject_root()
ret = devkey.device_inject_root_of_trust(key, DEVICE_KEY_16BYTE); ret = devkey.device_inject_root_of_trust(key, DEVICE_KEY_16BYTE);
TEST_ASSERT_EQUAL_INT(DEVICEKEY_SUCCESS, ret); TEST_ASSERT_EQUAL_INT(DEVICEKEY_SUCCESS, ret);
// Now use Direct Access To DeviceKey to retrieve it */ // Now use Direct Access To DeviceKey to retrieve it
uint32_t internal_start_address; uint32_t internal_start_address;
uint32_t internal_rbp_size; uint32_t internal_rbp_size;
bool is_conf_tdb_internal = false; bool is_conf_tdb_internal = false;

View File

@ -60,12 +60,7 @@ typedef enum qspi_address_size {
/** Alternative size in bits /** Alternative size in bits
*/ */
typedef enum qspi_alt_size { typedef uint8_t qspi_alt_size_t;
QSPI_CFG_ALT_SIZE_8,
QSPI_CFG_ALT_SIZE_16,
QSPI_CFG_ALT_SIZE_24,
QSPI_CFG_ALT_SIZE_32,
} qspi_alt_size_t;
/** QSPI command /** QSPI command
* *

View File

@ -69,21 +69,6 @@ static inline cyhal_qspi_size_t cyhal_qspi_convert_addr_size(qspi_address_size_t
} }
} }
static inline cyhal_qspi_size_t cyhal_qspi_convert_alt_size(qspi_alt_size_t size)
{
switch (size) {
case QSPI_CFG_ALT_SIZE_8:
return CYHAL_QSPI_CFG_SIZE_8;
case QSPI_CFG_ALT_SIZE_16:
return CYHAL_QSPI_CFG_SIZE_16;
case QSPI_CFG_ALT_SIZE_24:
return CYHAL_QSPI_CFG_SIZE_24;
default: // fallthrough
case QSPI_CFG_ALT_SIZE_32:
return CYHAL_QSPI_CFG_SIZE_32;
}
}
static void cyhal_qspi_convert_command(const qspi_command_t *from, cyhal_qspi_command_t *to) static void cyhal_qspi_convert_command(const qspi_command_t *from, cyhal_qspi_command_t *to)
{ {
to->instruction.bus_width = cyhal_qspi_convert_width(from->instruction.bus_width); to->instruction.bus_width = cyhal_qspi_convert_width(from->instruction.bus_width);
@ -94,7 +79,7 @@ static void cyhal_qspi_convert_command(const qspi_command_t *from, cyhal_qspi_co
to->address.value = from->address.value; to->address.value = from->address.value;
to->address.disabled = from->address.disabled; to->address.disabled = from->address.disabled;
to->mode_bits.bus_width = cyhal_qspi_convert_width(from->alt.bus_width); to->mode_bits.bus_width = cyhal_qspi_convert_width(from->alt.bus_width);
to->mode_bits.size = cyhal_qspi_convert_alt_size(from->alt.size); to->mode_bits.size = from->alt.size;
to->mode_bits.value = from->alt.value; to->mode_bits.value = from->alt.value;
to->mode_bits.disabled = from->alt.disabled; to->mode_bits.disabled = from->alt.disabled;
to->dummy_count = from->dummy_count; to->dummy_count = from->dummy_count;

View File

@ -71,9 +71,12 @@ typedef enum {
} cyhal_qspi_event_t; } cyhal_qspi_event_t;
#define CYHAL_QSPI_RSLT_ERR_BUS_WIDTH (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_QSPI, 0)) /**< Bus width Error. >*/ #define CYHAL_QSPI_RSLT_ERR_BUS_WIDTH (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_QSPI, 0)) /**< Bus width Error. >*/
#define CYHAL_QSPI_RSLT_ERR_PIN (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_QSPI, 1)) /**< Pin related Error. >*/ #define CYHAL_QSPI_RSLT_ERR_SIZE (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_QSPI, 1)) /**< Size Error. >*/
#define CYHAL_QSPI_RSLT_ERR_DATA_SEL (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_QSPI, 2)) /**< Data select Error. >*/ #define CYHAL_QSPI_RSLT_ERR_PIN (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_QSPI, 2)) /**< Pin related Error. >*/
#define CYHAL_QSPI_RSLT_ERR_INSTANCE (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_QSPI, 3)) /**< QSPI instance related Error. >*/ #define CYHAL_QSPI_RSLT_ERR_DATA_SEL (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_QSPI, 3)) /**< Data select Error. >*/
#define CYHAL_QSPI_RSLT_ERR_INSTANCE (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_QSPI, 4)) /**< QSPI instance related Error. >*/
#define CYHAL_QSPI_RSLT_ERR_ALT_SIZE_WIDTH_MISMATCH (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_QSPI, 5)) /**< Provided alt size is incompatible with provided alt width. >*/
#define CYHAL_QSPI_RSLT_ERR_ALT_SIZE_DUMMY_CYCLES_MISMATCH (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CYHAL_RSLT_MODULE_QSPI, 6)) /**< Provided alt size is incompatible with provided number of dummy cycles (due to device-specific restrictions). >*/
/** @brief QSPI command settings */ /** @brief QSPI command settings */
typedef struct cyhal_qspi_command { typedef struct cyhal_qspi_command {
@ -90,7 +93,7 @@ typedef struct cyhal_qspi_command {
} address; } address;
struct { struct {
cyhal_qspi_bus_width_t bus_width; /**< Bus width for mode bits >*/ cyhal_qspi_bus_width_t bus_width; /**< Bus width for mode bits >*/
cyhal_qspi_size_t size; /**< Mode bits size >*/ uint8_t size; /**< Mode bits size >*/
uint32_t value; /**< Mode bits value >*/ uint32_t value; /**< Mode bits value >*/
bool disabled; /**< Mode bits phase skipped if disabled is set to true >*/ bool disabled; /**< Mode bits phase skipped if disabled is set to true >*/
} mode_bits; } mode_bits;

View File

@ -292,16 +292,45 @@ static inline uint32_t get_size(cyhal_qspi_size_t hal_size)
return ((uint32_t)hal_size >> 3); /* convert bits to bytes */ return ((uint32_t)hal_size >> 3); /* convert bits to bytes */
} }
/* cyhal_qspi_bus_width_t to number of bus lines used */
static uint8_t get_lines(cyhal_qspi_bus_width_t hal_width)
{
uint8_t lines;
switch (hal_width)
{
case CYHAL_QSPI_CFG_BUS_SINGLE:
lines = 1;
break;
case CYHAL_QSPI_CFG_BUS_DUAL:
lines = 2;
break;
case CYHAL_QSPI_CFG_BUS_QUAD:
lines = 4;
break;
case CYHAL_QSPI_CFG_BUS_OCTAL:
lines = 8;
break;
default:
lines = 0;
}
return lines;
}
/* Sends QSPI command with certain set of data */ /* Sends QSPI command with certain set of data */
/* Address passed through 'command' is not used, instead the value in 'addr' is used. */ /* Address passed through 'command' is not used, instead the value in 'addr' is used. */
static cy_rslt_t qspi_command_transfer(cyhal_qspi_t *obj, const cyhal_qspi_command_t *command, static cy_rslt_t qspi_command_transfer(cyhal_qspi_t *obj, const cyhal_qspi_command_t *command,
uint32_t addr, bool endOfTransfer) uint32_t addr, bool endOfTransfer, uint8_t *dummy_cycles)
{ {
/* max address size is 4 bytes and max mode bits size is 4 bytes */ /* max address size is 4 bytes and max mode bits size is 4 bytes */
uint8_t cmd_param[8] = {0}; uint8_t cmd_param[8] = {0};
uint32_t start_pos = 0; uint32_t start_pos = 0;
uint32_t addr_size = 0; uint32_t addr_size = 0;
uint32_t mode_bits_size = 0; uint32_t mode_size = 0;
uint8_t leftover_bits = 0;
uint8_t lines = 0;
uint8_t integrated_dummy_cycles = 0;
cy_en_smif_txfr_width_t bus_width = CY_SMIF_WIDTH_SINGLE; cy_en_smif_txfr_width_t bus_width = CY_SMIF_WIDTH_SINGLE;
cy_stc_smif_mem_cmd_t cyhal_cmd_config; cy_stc_smif_mem_cmd_t cyhal_cmd_config;
cy_rslt_t result = CY_RSLT_SUCCESS; cy_rslt_t result = CY_RSLT_SUCCESS;
@ -332,22 +361,67 @@ static cy_rslt_t qspi_command_transfer(cyhal_qspi_t *obj, const cyhal_qspi_comma
if (!command->address.disabled) if (!command->address.disabled)
{ {
addr_size = get_size(command->address.size); addr_size = get_size(command->address.size);
uint32_to_byte_array(addr, cmd_param, start_pos, addr_size); if (addr_size == 0)
start_pos += addr_size; {
bus_width = cyhal_cmd_config.addrWidth; result = CYHAL_QSPI_RSLT_ERR_SIZE;
}
else
{
uint32_to_byte_array(addr, cmd_param, start_pos, addr_size);
start_pos += addr_size;
bus_width = cyhal_cmd_config.addrWidth;
}
} }
if (!command->mode_bits.disabled) if (!command->mode_bits.disabled)
{ {
mode_bits_size = get_size(command->mode_bits.size); // Mode size must be a multiple of the number of bus lines used (i.e. a whole number of cycles)
uint32_to_byte_array(cyhal_cmd_config.mode, cmd_param, start_pos, mode_bits_size); lines = get_lines(command->mode_bits.bus_width);
bus_width = cyhal_cmd_config.modeWidth; if (lines == 0)
{
result = CYHAL_QSPI_RSLT_ERR_BUS_WIDTH;
}
else if (command->mode_bits.size % lines != 0)
{
result = CYHAL_QSPI_RSLT_ERR_ALT_SIZE_WIDTH_MISMATCH;
}
else
{
// Round mode size up to nearest byte - unused parts of byte act as dummy cycles
mode_size = get_size(command->mode_bits.size - 1) + 1;
// Unused bits in most significant byte of mode
leftover_bits = (mode_size << 3) - command->mode_bits.size;
if (leftover_bits != 0)
{
// Account for dummy cycles that will be spent in the mode portion of the command
integrated_dummy_cycles = (8 - (command->mode_bits.size % 8)) / lines;
if (*dummy_cycles < integrated_dummy_cycles)
{
// Not enough dummy cycles to account for a short mode
result = CYHAL_QSPI_RSLT_ERR_ALT_SIZE_DUMMY_CYCLES_MISMATCH;
}
else
{
*dummy_cycles -= integrated_dummy_cycles;
}
// Align mode value to the end of the most significant byte
cyhal_cmd_config.mode <<= leftover_bits;
}
uint32_to_byte_array(cyhal_cmd_config.mode, cmd_param, start_pos, mode_size);
bus_width = cyhal_cmd_config.modeWidth;
}
} }
uint32_t cmpltTxfr = ((endOfTransfer) ? 1UL : 0UL); if (CY_RSLT_SUCCESS == result)
result = (cy_rslt_t)Cy_SMIF_TransmitCommand(obj->base, cyhal_cmd_config.command, {
cyhal_cmd_config.cmdWidth, cmd_param, (addr_size + mode_bits_size), uint32_t cmpltTxfr = ((endOfTransfer) ? 1UL : 0UL);
bus_width, obj->slave_select, cmpltTxfr, &obj->context); result = (cy_rslt_t)Cy_SMIF_TransmitCommand(obj->base, cyhal_cmd_config.command,
cyhal_cmd_config.cmdWidth, cmd_param, (addr_size + mode_size),
bus_width, obj->slave_select, cmpltTxfr, &obj->context);
}
} }
return result; return result;
} }
@ -810,6 +884,7 @@ cy_rslt_t cyhal_qspi_read(cyhal_qspi_t *obj, const cyhal_qspi_command_t *command
uint32_t chunk = 0; uint32_t chunk = 0;
size_t read_bytes = *length; size_t read_bytes = *length;
uint32_t addr = command->address.value; uint32_t addr = command->address.value;
uint8_t dummy_cycles = command->dummy_count;
/* SMIF can read only up to 65536 bytes in one go. Split the larger read into multiple chunks */ /* SMIF can read only up to 65536 bytes in one go. Split the larger read into multiple chunks */
while (read_bytes > 0) while (read_bytes > 0)
@ -823,11 +898,11 @@ cy_rslt_t cyhal_qspi_read(cyhal_qspi_t *obj, const cyhal_qspi_command_t *command
* to create a copy of the command object. Instead of copying the object, the address is * to create a copy of the command object. Instead of copying the object, the address is
* passed separately. * passed separately.
*/ */
status = qspi_command_transfer(obj, command, addr, false); status = qspi_command_transfer(obj, command, addr, false, &dummy_cycles);
if (CY_RSLT_SUCCESS == status) if (CY_RSLT_SUCCESS == status)
{ {
if (command->dummy_count > 0u) if (dummy_cycles > 0u)
{ {
status = (cy_rslt_t)Cy_SMIF_SendDummyCycles(obj->base, command->dummy_count); status = (cy_rslt_t)Cy_SMIF_SendDummyCycles(obj->base, command->dummy_count);
} }
@ -852,13 +927,15 @@ cy_rslt_t cyhal_qspi_read(cyhal_qspi_t *obj, const cyhal_qspi_command_t *command
cy_rslt_t cyhal_qspi_read_async(cyhal_qspi_t *obj, const cyhal_qspi_command_t *command, void *data, size_t *length) cy_rslt_t cyhal_qspi_read_async(cyhal_qspi_t *obj, const cyhal_qspi_command_t *command, void *data, size_t *length)
{ {
cy_rslt_t status = qspi_command_transfer(obj, command, command->address.value, false); cy_rslt_t status = CY_RSLT_SUCCESS;
uint32_t addr = command->address.value;
uint8_t dummy_cycles = command->dummy_count;
status = qspi_command_transfer(obj, command, addr, false, &dummy_cycles);
if (CY_RSLT_SUCCESS == status) if (CY_RSLT_SUCCESS == status)
{ {
if (command->dummy_count > 0u) if (command->dummy_count > 0u)
{ {
status = (cy_rslt_t)Cy_SMIF_SendDummyCycles(obj->base, command->dummy_count); status = (cy_rslt_t)Cy_SMIF_SendDummyCycles(obj->base, dummy_cycles);
} }
if (CY_RSLT_SUCCESS == status) if (CY_RSLT_SUCCESS == status)
@ -873,13 +950,14 @@ cy_rslt_t cyhal_qspi_read_async(cyhal_qspi_t *obj, const cyhal_qspi_command_t *c
/* length can be up to 65536. */ /* length can be up to 65536. */
cy_rslt_t cyhal_qspi_write(cyhal_qspi_t *obj, const cyhal_qspi_command_t *command, const void *data, size_t *length) cy_rslt_t cyhal_qspi_write(cyhal_qspi_t *obj, const cyhal_qspi_command_t *command, const void *data, size_t *length)
{ {
cy_rslt_t status = qspi_command_transfer(obj, command, command->address.value, false); uint8_t dummy_cycles = command->dummy_count;
cy_rslt_t status = qspi_command_transfer(obj, command, command->address.value, false, &dummy_cycles);
if (CY_RSLT_SUCCESS == status) if (CY_RSLT_SUCCESS == status)
{ {
if (command->dummy_count > 0u) if (command->dummy_count > 0u)
{ {
status = (cy_rslt_t)Cy_SMIF_SendDummyCycles(obj->base, command->dummy_count); status = (cy_rslt_t)Cy_SMIF_SendDummyCycles(obj->base, dummy_cycles);
} }
if ((CY_SMIF_SUCCESS == status) && (*length > 0)) if ((CY_SMIF_SUCCESS == status) && (*length > 0))
@ -895,13 +973,14 @@ cy_rslt_t cyhal_qspi_write(cyhal_qspi_t *obj, const cyhal_qspi_command_t *comman
/* length can be up to 65536. */ /* length can be up to 65536. */
cy_rslt_t cyhal_qspi_write_async(cyhal_qspi_t *obj, const cyhal_qspi_command_t *command, const void *data, size_t *length) cy_rslt_t cyhal_qspi_write_async(cyhal_qspi_t *obj, const cyhal_qspi_command_t *command, const void *data, size_t *length)
{ {
cy_rslt_t status = qspi_command_transfer(obj, command, command->address.value, false); uint8_t dummy_cycles = command->dummy_count;
cy_rslt_t status = qspi_command_transfer(obj, command, command->address.value, false, &dummy_cycles);
if (CY_RSLT_SUCCESS == status) if (CY_RSLT_SUCCESS == status)
{ {
if (command->dummy_count > 0u) if (command->dummy_count > 0u)
{ {
status = (cy_rslt_t)Cy_SMIF_SendDummyCycles(obj->base, command->dummy_count); status = (cy_rslt_t)Cy_SMIF_SendDummyCycles(obj->base, dummy_cycles);
} }
if ((CY_SMIF_SUCCESS == status) && (*length > 0)) if ((CY_SMIF_SUCCESS == status) && (*length > 0))
@ -922,7 +1001,7 @@ cy_rslt_t cyhal_qspi_transfer(
if ((tx_data == NULL || tx_size == 0) && (rx_data == NULL || rx_size == 0)) if ((tx_data == NULL || tx_size == 0) && (rx_data == NULL || rx_size == 0))
{ {
/* only command, no rx or tx */ /* only command, no rx or tx */
status = qspi_command_transfer(obj, command, command->address.value, true); status = qspi_command_transfer(obj, command, command->address.value, true, NULL);
} }
else else
{ {

View File

@ -43,7 +43,7 @@
#define QSPI_FLASH_SIZE_DEFAULT 0x80000000 #define QSPI_FLASH_SIZE_DEFAULT 0x80000000
#if defined(OCTOSPI1) #if defined(OCTOSPI1)
void qspi_prepare_command(const qspi_command_t *command, OSPI_RegularCmdTypeDef *st_command) qspi_status_t qspi_prepare_command(const qspi_command_t *command, OSPI_RegularCmdTypeDef *st_command)
{ {
debug_if(qspi_api_c_debug, "qspi_prepare_command In: instruction.value %x dummy_count %x address.bus_width %x address.disabled %x address.value %x address.size %x\n", debug_if(qspi_api_c_debug, "qspi_prepare_command In: instruction.value %x dummy_count %x address.bus_width %x address.disabled %x address.value %x address.size %x\n",
command->instruction.value, command->dummy_count, command->address.bus_width, command->address.disabled, command->address.value, command->address.size); command->instruction.value, command->dummy_count, command->address.bus_width, command->address.disabled, command->address.value, command->address.size);
@ -66,8 +66,8 @@ void qspi_prepare_command(const qspi_command_t *command, OSPI_RegularCmdTypeDef
st_command->InstructionMode = HAL_OSPI_INSTRUCTION_4_LINES; st_command->InstructionMode = HAL_OSPI_INSTRUCTION_4_LINES;
break; break;
default: default:
error("Command param error: wrong istruction format\n"); error("Command param error: wrong instruction format\n");
break; return QSPI_STATUS_ERROR;
} }
} }
@ -99,7 +99,7 @@ void qspi_prepare_command(const qspi_command_t *command, OSPI_RegularCmdTypeDef
break; break;
default: default:
error("Command param error: wrong address size\n"); error("Command param error: wrong address size\n");
break; return QSPI_STATUS_ERROR;
} }
switch(command->address.size) { switch(command->address.size) {
case QSPI_CFG_ADDR_SIZE_8: case QSPI_CFG_ADDR_SIZE_8:
@ -116,7 +116,7 @@ void qspi_prepare_command(const qspi_command_t *command, OSPI_RegularCmdTypeDef
break; break;
default: default:
error("Command param error: wrong address size\n"); error("Command param error: wrong address size\n");
break; return QSPI_STATUS_ERROR;
} }
} }
@ -124,39 +124,62 @@ void qspi_prepare_command(const qspi_command_t *command, OSPI_RegularCmdTypeDef
st_command->AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE; st_command->AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
st_command->AlternateBytesSize = 0; st_command->AlternateBytesSize = 0;
} else { } else {
st_command->AlternateBytes = command->alt.value; uint8_t alt_lines = 0;
switch (command->alt.bus_width) { switch (command->alt.bus_width) {
case QSPI_CFG_BUS_SINGLE: case QSPI_CFG_BUS_SINGLE:
st_command->AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_1_LINE; st_command->AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_1_LINE;
alt_lines = 1;
break; break;
case QSPI_CFG_BUS_DUAL: case QSPI_CFG_BUS_DUAL:
st_command->AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_2_LINES; st_command->AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_2_LINES;
alt_lines = 2;
break; break;
case QSPI_CFG_BUS_QUAD: case QSPI_CFG_BUS_QUAD:
st_command->AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_4_LINES; st_command->AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_4_LINES;
alt_lines = 4;
break; break;
default: default:
st_command->AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE; st_command->AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
break; error("Command param error: invalid alt bytes mode\n");
return QSPI_STATUS_ERROR;
} }
switch(command->alt.size) {
case QSPI_CFG_ALT_SIZE_8: // Alt size must be a multiple of the number of bus lines used (i.e. a whole number of cycles)
st_command->AlternateBytesSize = HAL_OSPI_ALTERNATE_BYTES_8_BITS; if (command->alt.size % alt_lines != 0) {
break; error("Command param error: incompatible alt size and alt bus width\n");
case QSPI_CFG_ALT_SIZE_16: return QSPI_STATUS_ERROR;
st_command->AlternateBytesSize = HAL_OSPI_ALTERNATE_BYTES_16_BITS;
break;
case QSPI_CFG_ALT_SIZE_24:
st_command->AlternateBytesSize = HAL_OSPI_ALTERNATE_BYTES_24_BITS;
break;
case QSPI_CFG_ALT_SIZE_32:
st_command->AlternateBytesSize = HAL_OSPI_ALTERNATE_BYTES_32_BITS;
break;
default:
st_command->AlternateBytesSize = 0;
printf("Command param error: wrong address size\n");
break;
} }
// Round up to nearest byte - unused parts of byte act as dummy cycles
uint32_t rounded_size = ((command->alt.size - 1) >> 3) + 1;
// Maximum of 4 alt bytes
if (rounded_size > 4) {
error("Command param error: alt size exceeds maximum of 32 bits\n");
return QSPI_STATUS_ERROR;
}
// Unused bits in most significant byte of alt
uint8_t leftover_bits = (rounded_size << 3) - command->alt.size;
if (leftover_bits != 0) {
// Account for dummy cycles that will be spent in the alt portion of the command
uint8_t integrated_dummy_cycles = leftover_bits / alt_lines;
if (st_command->DummyCycles < integrated_dummy_cycles)
{
// Not enough dummy cycles to account for a short alt
error("Command param error: not enough dummy cycles to make up for given alt size\n");
return QSPI_STATUS_ERROR;
}
st_command->DummyCycles -= integrated_dummy_cycles;
// Align alt value to the end of the most significant byte
st_command->AlternateBytes = command->alt.value << leftover_bits;
} else {
st_command->AlternateBytes = command->alt.value;
}
/* command->AlternateBytesSize needs to be shifted by OCTOSPI_CCR_ABSIZE_Pos */
// 0b00 = 1 byte, 0b01 = 2 bytes, 0b10 = 3 bytes, 0b11 = 4 bytes
st_command->AlternateBytesSize = ((rounded_size - 1) << OCTOSPI_CCR_ABSIZE_Pos) & OCTOSPI_CCR_ABSIZE_Msk;
} }
switch (command->data.bus_width) { switch (command->data.bus_width) {
@ -176,9 +199,11 @@ void qspi_prepare_command(const qspi_command_t *command, OSPI_RegularCmdTypeDef
debug_if(qspi_api_c_debug, "qspi_prepare_command Out: InstructionMode %x Instruction %x AddressMode %x AddressSize %x Address %x DataMode %x\n", debug_if(qspi_api_c_debug, "qspi_prepare_command Out: InstructionMode %x Instruction %x AddressMode %x AddressSize %x Address %x DataMode %x\n",
st_command->InstructionMode, st_command->Instruction, st_command->AddressMode, st_command->AddressSize, st_command->Address, st_command->DataMode); st_command->InstructionMode, st_command->Instruction, st_command->AddressMode, st_command->AddressSize, st_command->Address, st_command->DataMode);
return QSPI_STATUS_OK;
} }
#else /* OCTOSPI */ #else /* OCTOSPI */
void qspi_prepare_command(const qspi_command_t *command, QSPI_CommandTypeDef *st_command) qspi_status_t qspi_prepare_command(const qspi_command_t *command, QSPI_CommandTypeDef *st_command)
{ {
debug_if(qspi_api_c_debug, "qspi_prepare_command In: instruction.value %x dummy_count %x address.bus_width %x address.disabled %x address.value %x address.size %x\n", debug_if(qspi_api_c_debug, "qspi_prepare_command In: instruction.value %x dummy_count %x address.bus_width %x address.disabled %x address.value %x address.size %x\n",
command->instruction.value, command->dummy_count, command->address.bus_width, command->address.disabled, command->address.value, command->address.size); command->instruction.value, command->dummy_count, command->address.bus_width, command->address.disabled, command->address.value, command->address.size);
@ -230,15 +255,19 @@ void qspi_prepare_command(const qspi_command_t *command, QSPI_CommandTypeDef *st
st_command->AddressSize = (command->address.size << QUADSPI_CCR_ADSIZE_Pos) & QUADSPI_CCR_ADSIZE_Msk; st_command->AddressSize = (command->address.size << QUADSPI_CCR_ADSIZE_Pos) & QUADSPI_CCR_ADSIZE_Msk;
} }
uint8_t alt_lines = 0;
switch (command->alt.bus_width) { switch (command->alt.bus_width) {
case QSPI_CFG_BUS_SINGLE: case QSPI_CFG_BUS_SINGLE:
st_command->AlternateByteMode = QSPI_ALTERNATE_BYTES_1_LINE; st_command->AlternateByteMode = QSPI_ALTERNATE_BYTES_1_LINE;
alt_lines = 1;
break; break;
case QSPI_CFG_BUS_DUAL: case QSPI_CFG_BUS_DUAL:
st_command->AlternateByteMode = QSPI_ALTERNATE_BYTES_2_LINES; st_command->AlternateByteMode = QSPI_ALTERNATE_BYTES_2_LINES;
alt_lines = 2;
break; break;
case QSPI_CFG_BUS_QUAD: case QSPI_CFG_BUS_QUAD:
st_command->AlternateByteMode = QSPI_ALTERNATE_BYTES_4_LINES; st_command->AlternateByteMode = QSPI_ALTERNATE_BYTES_4_LINES;
alt_lines = 4;
break; break;
default: default:
st_command->AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; st_command->AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
@ -249,10 +278,40 @@ void qspi_prepare_command(const qspi_command_t *command, QSPI_CommandTypeDef *st
st_command->AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; st_command->AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
st_command->AlternateBytesSize = 0; st_command->AlternateBytesSize = 0;
} else { } else {
st_command->AlternateBytes = command->alt.value; // Alt size must be a multiple of the number of bus lines used (i.e. a whole number of cycles)
if ((alt_lines == 0) || (command->alt.size % alt_lines != 0)) {
return QSPI_STATUS_ERROR;
}
// Round up to nearest byte - unused parts of byte act as dummy cycles
uint32_t rounded_size = ((command->alt.size - 1) >> 3) + 1;
// Maximum of 4 alt bytes
if (rounded_size > 4) {
return QSPI_STATUS_ERROR;
}
// Unused bits in most significant byte of alt
uint8_t leftover_bits = (rounded_size << 3) - command->alt.size;
if (leftover_bits != 0) {
// Account for dummy cycles that will be spent in the alt portion of the command
uint8_t integrated_dummy_cycles = leftover_bits / alt_lines;
if (st_command->DummyCycles < integrated_dummy_cycles)
{
// Not enough dummy cycles to account for a short alt
return QSPI_STATUS_ERROR;
}
st_command->DummyCycles -= integrated_dummy_cycles;
// Align alt value to the end of the most significant byte
st_command->AlternateBytes = command->alt.value << leftover_bits;
} else {
rounded_size -= 1;
st_command->AlternateBytes = command->alt.value;
}
/* command->AlternateBytesSize needs to be shifted by QUADSPI_CCR_ABSIZE_Pos */ /* command->AlternateBytesSize needs to be shifted by QUADSPI_CCR_ABSIZE_Pos */
st_command->AlternateBytesSize = (command->alt.size << QUADSPI_CCR_ABSIZE_Pos) & QUADSPI_CCR_ABSIZE_Msk; // 0b00 = 1 byte, 0b01 = 2 bytes, 0b10 = 3 bytes, 0b11 = 4 bytes
st_command->AlternateBytesSize = command->alt.size; st_command->AlternateBytesSize = ((rounded_size - 1) << QUADSPI_CCR_ABSIZE_Pos) & QUADSPI_CCR_ABSIZE_Msk;
} }
switch (command->data.bus_width) { switch (command->data.bus_width) {
@ -271,8 +330,11 @@ void qspi_prepare_command(const qspi_command_t *command, QSPI_CommandTypeDef *st
} }
st_command->NbData = 0; st_command->NbData = 0;
debug_if(qspi_api_c_debug, "qspi_prepare_command Out: InstructionMode %x Instruction %x AddressMode %x AddressSize %x Address %x DataMode %x\n", debug_if(qspi_api_c_debug, "qspi_prepare_command Out: InstructionMode %x Instruction %x AddressMode %x AddressSize %x Address %x DataMode %x\n",
st_command->InstructionMode, st_command->Instruction, st_command->AddressMode, st_command->AddressSize, st_command->Address, st_command->DataMode); st_command->InstructionMode, st_command->Instruction, st_command->AddressMode, st_command->AddressSize, st_command->Address, st_command->DataMode);
return QSPI_STATUS_OK;
} }
#endif /* OCTOSPI */ #endif /* OCTOSPI */
@ -586,10 +648,12 @@ qspi_status_t qspi_write(qspi_t *obj, const qspi_command_t *command, const void
debug_if(qspi_api_c_debug, "qspi_write size %u\n", *length); debug_if(qspi_api_c_debug, "qspi_write size %u\n", *length);
OSPI_RegularCmdTypeDef st_command; OSPI_RegularCmdTypeDef st_command;
qspi_prepare_command(command, &st_command); qspi_status_t status = qspi_prepare_command(command, &st_command);
if (status != QSPI_STATUS_OK) {
return status;
}
st_command.NbData = *length; st_command.NbData = *length;
qspi_status_t status = QSPI_STATUS_OK;
if (HAL_OSPI_Command(&obj->handle, &st_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { if (HAL_OSPI_Command(&obj->handle, &st_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
debug_if(qspi_api_c_debug, "HAL_OSPI_Command error\n"); debug_if(qspi_api_c_debug, "HAL_OSPI_Command error\n");
@ -607,10 +671,12 @@ qspi_status_t qspi_write(qspi_t *obj, const qspi_command_t *command, const void
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)
{ {
QSPI_CommandTypeDef st_command; QSPI_CommandTypeDef st_command;
qspi_prepare_command(command, &st_command); qspi_status_t status = qspi_prepare_command(command, &st_command);
if (status != QSPI_STATUS_OK) {
return status;
}
st_command.NbData = *length; st_command.NbData = *length;
qspi_status_t status = QSPI_STATUS_OK;
if (HAL_QSPI_Command(&obj->handle, &st_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { if (HAL_QSPI_Command(&obj->handle, &st_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
status = QSPI_STATUS_ERROR; status = QSPI_STATUS_ERROR;
@ -631,10 +697,12 @@ qspi_status_t qspi_write(qspi_t *obj, const qspi_command_t *command, const void
qspi_status_t qspi_read(qspi_t *obj, const qspi_command_t *command, void *data, size_t *length) qspi_status_t qspi_read(qspi_t *obj, const qspi_command_t *command, void *data, size_t *length)
{ {
OSPI_RegularCmdTypeDef st_command; OSPI_RegularCmdTypeDef st_command;
qspi_prepare_command(command, &st_command); qspi_status_t status = qspi_prepare_command(command, &st_command);
if (status != QSPI_STATUS_OK) {
return status;
}
st_command.NbData = *length; st_command.NbData = *length;
qspi_status_t status = QSPI_STATUS_OK;
if (HAL_OSPI_Command(&obj->handle, &st_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { if (HAL_OSPI_Command(&obj->handle, &st_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
debug_if(qspi_api_c_debug, "HAL_OSPI_Command error\n"); debug_if(qspi_api_c_debug, "HAL_OSPI_Command error\n");
@ -654,10 +722,12 @@ qspi_status_t qspi_read(qspi_t *obj, const qspi_command_t *command, void *data,
qspi_status_t qspi_read(qspi_t *obj, const qspi_command_t *command, void *data, size_t *length) qspi_status_t qspi_read(qspi_t *obj, const qspi_command_t *command, void *data, size_t *length)
{ {
QSPI_CommandTypeDef st_command; QSPI_CommandTypeDef st_command;
qspi_prepare_command(command, &st_command); qspi_status_t status = qspi_prepare_command(command, &st_command);
if (status != QSPI_STATUS_OK) {
return status;
}
st_command.NbData = *length; st_command.NbData = *length;
qspi_status_t status = QSPI_STATUS_OK;
if (HAL_QSPI_Command(&obj->handle, &st_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { if (HAL_QSPI_Command(&obj->handle, &st_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
status = QSPI_STATUS_ERROR; status = QSPI_STATUS_ERROR;
@ -683,7 +753,10 @@ qspi_status_t qspi_command_transfer(qspi_t *obj, const qspi_command_t *command,
if ((tx_data == NULL || tx_size == 0) && (rx_data == NULL || rx_size == 0)) { if ((tx_data == NULL || tx_size == 0) && (rx_data == NULL || rx_size == 0)) {
// only command, no rx or tx // only command, no rx or tx
OSPI_RegularCmdTypeDef st_command; OSPI_RegularCmdTypeDef st_command;
qspi_prepare_command(command, &st_command); status = qspi_prepare_command(command, &st_command);
if (status != QSPI_STATUS_OK) {
return status;
}
st_command.NbData = 1; st_command.NbData = 1;
st_command.DataMode = HAL_OSPI_DATA_NONE; /* Instruction only */ st_command.DataMode = HAL_OSPI_DATA_NONE; /* Instruction only */
@ -720,7 +793,10 @@ qspi_status_t qspi_command_transfer(qspi_t *obj, const qspi_command_t *command,
if ((tx_data == NULL || tx_size == 0) && (rx_data == NULL || rx_size == 0)) { if ((tx_data == NULL || tx_size == 0) && (rx_data == NULL || rx_size == 0)) {
// only command, no rx or tx // only command, no rx or tx
QSPI_CommandTypeDef st_command; QSPI_CommandTypeDef st_command;
qspi_prepare_command(command, &st_command); status = qspi_prepare_command(command, &st_command);
if (status != QSPI_STATUS_OK) {
return status;
}
st_command.NbData = 1; st_command.NbData = 1;
st_command.DataMode = QSPI_DATA_NONE; /* Instruction only */ st_command.DataMode = QSPI_DATA_NONE; /* Instruction only */

View File

@ -33,6 +33,8 @@
#include "PeripheralPins.h" #include "PeripheralPins.h"
#include "pinmap_function.h" #include "pinmap_function.h"
#define SUPPORTED_ALT_SIZE 8u
qspi_status_t qspi_init(qspi_t *obj, PinName io0, PinName io1, PinName io2, PinName io3, PinName sclk, PinName ssel, uint32_t hz, uint8_t mode) qspi_status_t qspi_init(qspi_t *obj, PinName io0, PinName io1, PinName io2, PinName io3, PinName sclk, PinName ssel, uint32_t hz, uint8_t mode)
{ {
@ -268,7 +270,7 @@ qspi_status_t qspi_command_transfer(qspi_t *obj, const qspi_command_t *command,
cfg.modeBitEnable = true; cfg.modeBitEnable = true;
obj->instance->MODEBITCONFIG = command->alt.value & _QSPI_MODEBITCONFIG_MODE_MASK; obj->instance->MODEBITCONFIG = command->alt.value & _QSPI_MODEBITCONFIG_MODE_MASK;
if(command->alt.size != QSPI_CFG_ALT_SIZE_8) { if(command->alt.size != SUPPORTED_ALT_SIZE) {
//do not support 'alt' bigger than 8 bit //do not support 'alt' bigger than 8 bit
return QSPI_STATUS_INVALID_PARAMETER; return QSPI_STATUS_INVALID_PARAMETER;
} }
@ -338,7 +340,7 @@ qspi_status_t qspi_read(qspi_t *obj, const qspi_command_t *command, void *data,
obj->instance->DEVINSTRRDCONFIG |= QSPI_DEVINSTRRDCONFIG_MODEBITENABLE; obj->instance->DEVINSTRRDCONFIG |= QSPI_DEVINSTRRDCONFIG_MODEBITENABLE;
obj->instance->MODEBITCONFIG = command->alt.value & _QSPI_MODEBITCONFIG_MODE_MASK; obj->instance->MODEBITCONFIG = command->alt.value & _QSPI_MODEBITCONFIG_MODE_MASK;
if(command->alt.size != QSPI_CFG_ALT_SIZE_8) { if(command->alt.size != SUPPORTED_ALT_SIZE) {
// Do not support 'alt' bigger than 8 bit // Do not support 'alt' bigger than 8 bit
return QSPI_STATUS_INVALID_PARAMETER; return QSPI_STATUS_INVALID_PARAMETER;
} }