mirror of https://github.com/ARMmbed/mbed-os.git
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
parent
03affe94d8
commit
08a2709993
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************/
|
/***************************************************/
|
||||||
|
|
|
@ -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
|
||||||
*
|
*
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
*
|
*
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue