Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NRF5x: QSPI SFDP read, min read/write implementation #9291

Merged
merged 2 commits into from
Jan 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ using namespace mbed;

/* Default QSPIF Parameters */
/****************************/
#define QSPIF_DEFAULT_READ_SIZE 1
#define QSPIF_DEFAULT_PROG_SIZE 1
#define QSPIF_DEFAULT_PAGE_SIZE 256
#define QSPIF_DEFAULT_SE_SIZE 4096
#define QSPI_MAX_STATUS_REGISTER_SIZE 3
Expand Down Expand Up @@ -462,14 +460,14 @@ int QSPIFBlockDevice::erase(bd_addr_t addr, bd_size_t in_size)

bd_size_t QSPIFBlockDevice::get_read_size() const
{
// Assuming all devices support 1byte read granularity
return QSPIF_DEFAULT_READ_SIZE;
// Return minimum read size in bytes for the device
return MBED_CONF_QSPIF_QSPI_MIN_READ_SIZE;
}

bd_size_t QSPIFBlockDevice::get_program_size() const
{
// Assuming all devices support 1byte program granularity
return QSPIF_DEFAULT_PROG_SIZE;
// Return minimum program/write size in bytes for the device
return MBED_CONF_QSPIF_QSPI_MIN_PROG_SIZE;
}

bd_size_t QSPIFBlockDevice::get_erase_size() const
Expand Down
10 changes: 7 additions & 3 deletions components/storage/blockdevice/COMPONENT_QSPIF/mbed_lib.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
"QSPI_SCK": "QSPI_FLASH1_SCK",
"QSPI_CSN": "QSPI_FLASH1_CSN",
"QSPI_POLARITY_MODE": 0,
"QSPI_FREQ": "40000000"
"QSPI_FREQ": "40000000",
"QSPI_MIN_READ_SIZE": "1",
"QSPI_MIN_PROG_SIZE": "1"
},
"target_overrides": {
"DISCO_F413ZH": {
Expand All @@ -32,8 +34,10 @@
"DISCO_F769NI": {
"QSPI_FREQ": "8000000"
},
"NRF52840_DK": {
"QSPI_FREQ": "32000000"
"MCU_NRF52840": {
"QSPI_FREQ": "32000000",
"QSPI_MIN_READ_SIZE": "4",
"QSPI_MIN_PROG_SIZE": "4"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,8 @@ typedef struct
bool io3_level; /**< I/O line level during transmission. */
bool wipwait; /**< Wait if a Wait in Progress bit is set in the memory status byte. */
bool wren; /**< Send write enable before instruction. */
bool lfen; /**< Enable long frame mode. */
bool lfstop; /**< Stop long frame mode. */
} nrf_qspi_cinstr_conf_t;

/**
Expand Down Expand Up @@ -751,7 +753,9 @@ __STATIC_INLINE void nrf_qspi_cinstr_transfer_start(NRF_QSPI_Type *
((uint32_t)p_config->io2_level << QSPI_CINSTRCONF_LIO2_Pos) |
((uint32_t)p_config->io3_level << QSPI_CINSTRCONF_LIO3_Pos) |
((uint32_t)p_config->wipwait << QSPI_CINSTRCONF_WIPWAIT_Pos) |
((uint32_t)p_config->wren << QSPI_CINSTRCONF_WREN_Pos));
((uint32_t)p_config->wren << QSPI_CINSTRCONF_WREN_Pos) |
((uint32_t)p_config->lfen << QSPI_CINSTRCONF_LFEN_Pos) |
((uint32_t)p_config->lfstop << QSPI_CINSTRCONF_LFSTOP_Pos) );
}

#endif // SUPPRESS_INLINE_IMPLEMENTATION
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,9 @@ typedef struct
.io2_level = false, \
.io3_level = false, \
.wipwait = false, \
.wren = false \
.wren = false, \
.lfen = false, \
.lfstop = false \
}

/**
Expand Down
136 changes: 129 additions & 7 deletions targets/TARGET_NORDIC/TARGET_NRF5x/qspi_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,12 @@ TODO
#define MBED_HAL_QSPI_MAX_FREQ 32000000UL

// NRF supported R/W opcodes
#define FAST_READ_opcode 0x0B
#define FASTREAD_opcode 0x0B
#define READ2O_opcode 0x3B
#define READ2IO_opcode 0xBB
#define READ4O_opcode 0x6B
#define READ4IO_opcode 0xEB
#define READSFDP_opcode 0x5A

#define PP_opcode 0x02
#define PP2O_opcode 0xA2
Expand All @@ -70,12 +71,21 @@ TODO
#define SCK_DELAY 0x05
#define WORD_MASK 0x03

// NRF SFDP defines
#define DWORD_LEN 4
#define SFDP_CMD_LEN DWORD_LEN
#define SFDP_DATA_LEN 128 // SFPD data buffer length in bytes, may need to be increased for other flash parts
#define SFDP_READ_LEN 8 // 8 SFDP bytes can be read at a time
#define SFDP_READ_MAX (SFDP_DATA_LEN / SFDP_READ_LEN)

static nrf_drv_qspi_config_t config;

// Private helper function to track initialization
static ret_code_t _qspi_drv_init(void);
// Private helper function to set NRF frequency divider
nrf_qspi_frequency_t nrf_frequency(int hz);
// Private helper function to read SFDP data
qspi_status_t sfdp_read(qspi_t *obj, const qspi_command_t *command, void *data, size_t *length);

qspi_status_t qspi_prepare_command(qspi_t *obj, const qspi_command_t *command, bool write)
{
Expand All @@ -93,7 +103,7 @@ qspi_status_t qspi_prepare_command(qspi_t *obj, const qspi_command_t *command, b
return QSPI_STATUS_INVALID_PARAMETER;
}
} else {
if (command->instruction.value == FAST_READ_opcode) {
if (command->instruction.value == FASTREAD_opcode) {
config.prot_if.readoc = NRF_QSPI_READOC_FASTREAD;
} else {
return QSPI_STATUS_INVALID_PARAMETER;
Expand Down Expand Up @@ -277,9 +287,15 @@ qspi_status_t qspi_read(qspi_t *obj, const qspi_command_t *command, void *data,
return QSPI_STATUS_INVALID_PARAMETER;
}

qspi_status_t status = qspi_prepare_command(obj, command, false);
if (status != QSPI_STATUS_OK) {
// check to see if this is an SFDP read
if (command->instruction.value == READSFDP_opcode) {
qspi_status_t status = sfdp_read(obj, command, data, length );
return status;
} else {
qspi_status_t status = qspi_prepare_command(obj, command, false);
if (status != QSPI_STATUS_OK) {
return status;
}
}

ret_code_t ret = nrf_drv_qspi_read(data, *length, command->address.value);
Expand All @@ -293,16 +309,16 @@ qspi_status_t qspi_read(qspi_t *obj, const qspi_command_t *command, void *data,
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)
{
ret_code_t ret_code;
uint8_t data[8];
uint8_t data[8] = { 0 };
uint32_t data_size = tx_size + rx_size;

nrf_qspi_cinstr_conf_t qspi_cinstr_config;
nrf_qspi_cinstr_conf_t qspi_cinstr_config = { 0 };
qspi_cinstr_config.opcode = command->instruction.value;
qspi_cinstr_config.io2_level = true;
qspi_cinstr_config.io3_level = true;
qspi_cinstr_config.wipwait = false;
qspi_cinstr_config.wren = false;

if(!command->address.disabled && data_size == 0) {
// erase command with address
if (command->address.size == QSPI_CFG_ADDR_SIZE_24) {
Expand Down Expand Up @@ -400,6 +416,112 @@ nrf_qspi_frequency_t nrf_frequency(int hz)
return freq;
}

// Private helper to read nRF5x SFDP data using QSPI
qspi_status_t sfdp_read(qspi_t *obj, const qspi_command_t *command, void *data, size_t *length)
{
ret_code_t ret_code;
static bool b_init = false;
static uint8_t sfdp_rx[SFDP_DATA_LEN] = { 0 };

if (b_init == false) {
// get the SFDP data usig nRF5x QSPI custom instuctions and long frame mode (lfen)
nrf_qspi_cinstr_conf_t qspi_cinstr_config = { 0 };
qspi_cinstr_config.opcode = command->instruction.value;
qspi_cinstr_config.io2_level = true;
qspi_cinstr_config.io3_level = true;
qspi_cinstr_config.wipwait = false;
qspi_cinstr_config.wren = false;
qspi_cinstr_config.lfen = true;
qspi_cinstr_config.lfstop = false;

// read the SFDP data, cmd + 8 bytes at a time
uint8_t sfdp_data[SFDP_READ_LEN];
qspi_cinstr_config.length = NRF_QSPI_CINSTR_LEN_9B;

for (uint32_t i = 0; i < SFDP_READ_MAX; ++i) {

static uint32_t rx_i = 0;
memset(sfdp_data, 0, SFDP_READ_LEN);

if (i == (SFDP_READ_MAX - 1) ){
qspi_cinstr_config.lfstop = true;
}

ret_code = nrf_drv_qspi_cinstr_xfer(&qspi_cinstr_config, sfdp_data, sfdp_data);
if (ret_code != NRF_SUCCESS) {
return QSPI_STATUS_ERROR;
}

// copy the second DWORD from the command data, the first DWORD is 0's
for (uint32_t c = DWORD_LEN; c < SFDP_READ_LEN; ++c) {
((uint8_t *)sfdp_rx)[rx_i] = sfdp_data[c];
++rx_i;
}
rx_i += DWORD_LEN;
}

// re-send just the SFDP CMD to offset the next read by DWORD
uint8_t sfdp_cmd[SFDP_CMD_LEN] = { 0 };
qspi_cinstr_config.lfstop = false;
qspi_cinstr_config.length = NRF_QSPI_CINSTR_LEN_5B;

ret_code = nrf_drv_qspi_cinstr_xfer(&qspi_cinstr_config, sfdp_cmd, sfdp_cmd);
if (ret_code != NRF_SUCCESS) {
return QSPI_STATUS_ERROR;
}

// read the offset SFDP data, cmd + 8 bytes at a time
qspi_cinstr_config.length = NRF_QSPI_CINSTR_LEN_9B;
for (uint32_t i = 0; i < SFDP_READ_MAX; ++i) {

static uint32_t rx_i = DWORD_LEN; // offset sfdp_rx data start
memset(sfdp_data, 0, SFDP_READ_LEN);

if (i == (SFDP_READ_MAX - 1) ){
qspi_cinstr_config.lfstop = true;
}

ret_code = nrf_drv_qspi_cinstr_xfer(&qspi_cinstr_config, sfdp_data, sfdp_data);
if (ret_code != NRF_SUCCESS) {
return QSPI_STATUS_ERROR;
}

// copy the second DWORD from the command data, the first DWORD is 0's
for (uint32_t c = DWORD_LEN; c < SFDP_READ_LEN; ++c) {
((uint8_t *)sfdp_rx)[rx_i] = sfdp_data[c];
++rx_i;
}
rx_i += DWORD_LEN;
}

b_init = true;
}

if ( b_init == true) {
// check for valid SFDP data, last basic header byte is always 0xFF
// NOTE: "nRF52840-Preview-DK" boards do not support SFDP read
if (sfdp_rx[7] != 0xFF) {
return QSPI_STATUS_ERROR;
}

// calculate the SFDP data length based on the parameter table offset
// provided at index 12, plus the table length in DWORDS at index 11
uint32_t sfdp_length = sfdp_rx[12] + (sfdp_rx[11] * DWORD_LEN);

// check if the data request is within the SFDP data array
// increase SFDP_DATA_LEN to match sfdp_length, if necessary
if ( sfdp_length <= SFDP_DATA_LEN &&
sfdp_length >= (command->address.value + *length) ) {
memcpy(data, (sfdp_rx + command->address.value), *length);
return QSPI_STATUS_OK;
} else {
return QSPI_STATUS_INVALID_PARAMETER;
}
} else {
return QSPI_STATUS_ERROR;
}
}


#endif

Expand Down
1 change: 1 addition & 0 deletions targets/targets.json
Original file line number Diff line number Diff line change
Expand Up @@ -6798,6 +6798,7 @@
},
"MCU_NRF52840": {
"inherits": ["Target"],
"components_add": ["QSPIF"],
"core": "Cortex-M4F",
"static_memory_defines": false,
"macros": [
Expand Down