#include <sfud.h>
#include <string.h>
#define DUMMY_DATA 0xFF
#ifndef SFUD_FLASH_DEVICE_TABLE
#error "Please configure the flash device information table in (in sfud_cfg.h)."
#endif
static sfud_flash flash_table[] = SFUD_FLASH_DEVICE_TABLE;
static const sfud_mf mf_table[] = SFUD_MF_TABLE;
#ifdef SFUD_USING_FLASH_INFO_TABLE
static const sfud_flash_chip flash_chip_table[] = SFUD_FLASH_CHIP_TABLE;
#endif
#ifdef SFUD_USING_QSPI
enum sfud_qspi_read_mode {
NORMAL_SPI_READ = 1 << 0,
DUAL_OUTPUT = 1 << 1,
DUAL_IO = 1 << 2,
QUAD_OUTPUT = 1 << 3,
QUAD_IO = 1 << 4,
};
static const sfud_qspi_flash_ext_info qspi_flash_ext_info_table[] = SFUD_FLASH_EXT_INFO_TABLE;
#endif
static sfud_err software_init(const sfud_flash *flash);
static sfud_err hardware_init(sfud_flash *flash);
static sfud_err page256_or_1_byte_write(const sfud_flash *flash, uint32_t addr, size_t size, uint16_t write_gran,
const uint8_t *data);
static sfud_err aai_write(const sfud_flash *flash, uint32_t addr, size_t size, const uint8_t *data);
static sfud_err wait_busy(const sfud_flash *flash);
static sfud_err reset(const sfud_flash *flash);
static sfud_err read_jedec_id(sfud_flash *flash);
static sfud_err set_write_enabled(const sfud_flash *flash, bool enabled);
static sfud_err set_4_byte_address_mode(sfud_flash *flash, bool enabled);
static void make_address_byte_array(const sfud_flash *flash, uint32_t addr, uint8_t *array);
extern void sfud_log_debug(const char *file, const long line, const char *format, ...);
extern void sfud_log_info(const char *format, ...);
sfud_err sfud_device_init(sfud_flash *flash) {
sfud_err result = SFUD_SUCCESS;
result = hardware_init(flash);
if (result == SFUD_SUCCESS) {
result = software_init(flash);
}
if (result == SFUD_SUCCESS) {
flash->init_ok = true;
SFUD_INFO("%s flash device initialized successfully.", flash->name);
} else {
flash->init_ok = false;
SFUD_INFO("Error: %s flash device initialization failed.", flash->name);
}
return result;
}
sfud_flash *sfud_get_device(size_t index) {
if (index < sfud_get_device_num()) {
return &flash_table[index];
} else {
return NULL;
}
}
size_t sfud_get_device_num(void) {
return sizeof(flash_table) / sizeof(sfud_flash);
}
const sfud_flash *sfud_get_device_table(void) {
return flash_table;
}
#ifdef SFUD_USING_QSPI
static void qspi_set_read_cmd_format(sfud_flash *flash, uint8_t ins, uint8_t ins_lines, uint8_t addr_lines,
uint8_t dummy_cycles, uint8_t data_lines) {
if (flash->chip.capacity <= 0x1000000) {
flash->read_cmd_format.instruction = ins;
flash->read_cmd_format.address_size = 24;
} else {
if(ins == SFUD_CMD_READ_DATA){
flash->read_cmd_format.instruction = ins + 0x10;
}
else{
flash->read_cmd_format.instruction = ins + 1;
}
flash->read_cmd_format.address_size = 32;
}
flash->read_cmd_format.instruction_lines = ins_lines;
flash->read_cmd_format.address_lines = addr_lines;
flash->read_cmd_format.alternate_bytes_lines = 0;
flash->read_cmd_format.dummy_cycles = dummy_cycles;
flash->read_cmd_format.data_lines = data_lines;
}
sfud_err sfud_qspi_fast_read_enable(sfud_flash *flash, uint8_t data_line_width) {
size_t i = 0;
uint8_t read_mode = NORMAL_SPI_READ;
sfud_err result = SFUD_SUCCESS;
SFUD_ASSERT(flash);
SFUD_ASSERT(data_line_width == 1 || data_line_width == 2 || data_line_width == 4);
for (i = 0; i < sizeof(qspi_flash_ext_info_table) / sizeof(sfud_qspi_flash_ext_info); i++) {
if ((qspi_flash_ext_info_table[i].mf_id == flash->chip.mf_id)
&& (qspi_flash_ext_info_table[i].type_id == flash->chip.type_id)
&& (qspi_flash_ext_info_table[i].capacity_id == flash->chip.capacity_id)) {
read_mode = qspi_flash_ext_info_table[i].read_mode;
}
}
switch (data_line_width) {
case 1:
qspi_set_read_cmd_format(flash, SFUD_CMD_READ_DATA, 1, 1, 0, 1);
break;
case 2:
if (read_mode & DUAL_IO) {
qspi_set_read_cmd_format(flash, SFUD_CMD_DUAL_IO_READ_DATA, 1, 2, 4, 2);
} else if (read_mode & DUAL_OUTPUT) {
qspi_set_read_cmd_format(flash, SFUD_CMD_DUAL_OUTPUT_READ_DATA, 1, 1, 8, 2);
} else {
qspi_set_read_cmd_format(flash, SFUD_CMD_READ_DATA, 1, 1, 0, 1);
}
break;
case 4:
if (read_mode & QUAD_IO) {
qspi_set_read_cmd_format(flash, SFUD_CMD_QUAD_IO_READ_DATA, 1, 4, 6, 4);
} else if (read_mode & QUAD_OUTPUT) {
qspi_set_read_cmd_format(flash, SFUD_CMD_QUAD_OUTPUT_READ_DATA, 1, 1, 8, 4);
} else {
qspi_set_read_cmd_format(flash, SFUD_CMD_READ_DATA, 1, 1, 0, 1);
}
break;
}
return result;
}
#endif
static sfud_err hardware_init(sfud_flash *flash) {
extern sfud_err sfud_spi_port_init(sfud_flash * flash);
sfud_err result = SFUD_SUCCESS;
size_t i;
SFUD_ASSERT(flash);
result = sfud_spi_port_init(flash);
if (result != SFUD_SUCCESS) {
return result;
}
#ifdef SFUD_USING_QSPI
flash->read_cmd_format.instruction = SFUD_CMD_READ_DATA;
#endif
SFUD_ASSERT(flash->spi.wr);
if (flash->chip.capacity == 0 || flash->chip.write_mode == 0 || flash->chip.erase_gran == 0
|| flash->chip.erase_gran_cmd == 0) {
result = read_jedec_id(flash);
if (result != SFUD_SUCCESS) {
return result;
}
#ifdef SFUD_USING_SFDP
extern bool sfud_read_sfdp(sfud_flash *flash);
if (sfud_read_sfdp(flash)) {
flash->chip.name = NULL;
flash->chip.capacity = flash->sfdp.capacity;
if (flash->sfdp.write_gran == 1) {
flash->chip.write_mode = SFUD_WM_BYTE;
} else {
flash->chip.write_mode = SFUD_WM_PAGE_256B;
}
flash->chip.erase_gran = flash->sfdp.eraser[0].size;
flash->chip.erase_gran_cmd = flash->sfdp.eraser[0].cmd;
for (i = 1; i < SFUD_SFDP_ERASE_TYPE_MAX_NUM; i++) {
if (flash->sfdp.eraser[i].size != 0 && flash->chip.erase_gran > flash->sfdp.eraser[i].size) {
flash->chip.erase_gran = flash->sfdp.eraser[i].size;
flash->chip.erase_gran_cmd = flash->sfdp.eraser[i].cmd;
}
}
} else {
#endif
#ifdef SFUD_USING_FLASH_INFO_TABLE
for (i = 0; i < sizeof(flash_chip_table) / sizeof(sfud_flash_chip); i++) {
if ((flash_chip_table[i].mf_id == flash->chip.mf_id)
&& (flash_chip_table[i].type_id == flash->chip.type_id)
&& (flash_chip_table[i].capacity_id == flash->chip.capacity_id)) {
flash->chip.name = flash_chip_table[i].name;
flash->chip.capacity = flash_chip_table[i].capacity;
flash->chip.write_mode = flash_chip_table[i].write_mode;
flash->chip.erase_gran = flash_chip_table[i].erase_gran;
flash->chip.erase_gran_cmd = flash_chip_table[i].erase_gran_cmd;
break;
}
}
#endif
#ifdef SFUD_USING_SFDP
}
#endif
}
if (flash->chip.capacity == 0 || flash->chip.write_mode == 0 || flash->chip.erase_gran == 0
|| flash->chip.erase_gran_cmd == 0) {
SFUD_INFO("Warning: This flash device is not found or not supported.");
return SFUD_ERR_NOT_FOUND;
} else {
const char *flash_mf_name = NULL;
for (i = 0; i < sizeof(mf_table) / sizeof(sfud_mf); i++) {
if (mf_table[i].id == flash->chip.mf_id) {
flash_mf_name = mf_table[i].name;
break;
}
}
if (flash_mf_name && flash->chip.name) {
SFUD_INFO("Found a %s %s flash chip. Size is %ld bytes.", flash_mf_name, flash->chip.name,
flash->chip.capacity);
} else if (flash_mf_name) {
SFUD_INFO("Found a %s flash chip. Size is %ld bytes.", flash_mf_name, flash->chip.capacity);
} else {
SFUD_INFO("Found a flash chip. Size is %ld bytes.", flash->chip.capacity);
}
}
result = reset(flash);
if (result != SFUD_SUCCESS) {
return result;
}
if (flash->chip.write_mode & SFUD_WM_AAI) {
result = sfud_write_status(flash, true, 0x00);
} else {
if ((0xC2 == flash->chip.mf_id) && (0x20 == flash->chip.type_id) && (0x16 == flash->chip.capacity_id)) {
result = sfud_write_status(flash, false, 0x00);
}
}
if (result != SFUD_SUCCESS) {
return result;
}
if (flash->chip.capacity > (1L << 24)) {
result = set_4_byte_address_mode(flash, true);
} else {
flash->addr_in_4_byte = false;
}
return result;
}
static sfud_err software_init(const sfud_flash *flash) {
(void)flash;
sfud_err result = SFUD_SUCCESS;
SFUD_ASSERT(flash);
return result;
}
sfud_err sfud_read(const sfud_flash *flash, uint32_t addr, size_t size, uint8_t *data) {
sfud_err result = SFUD_SUCCESS;
const sfud_spi *spi = &flash->spi;
uint8_t cmd_data[5], cmd_size;
SFUD_ASSERT(flash);
SFUD_ASSERT(data);
SFUD_ASSERT(flash->init_ok);
if (addr + size > flash->chip.capacity) {
SFUD_INFO("Error: Flash address is out of bound.");
return SFUD_ERR_ADDR_OUT_OF_BOUND;
}
if (spi->lock) {
spi->lock(spi);
}
result = wait_busy(flash);
if (result == SFUD_SUCCESS) {
#ifdef SFUD_USING_QSPI
if (flash->read_cmd_format.instruction != SFUD_CMD_READ_DATA) {
result = spi->qspi_read(spi, addr, (sfud_qspi_read_cmd_format *)&flash->read_cmd_format, data, size);
} else
#endif
{
cmd_data[0] = SFUD_CMD_READ_DATA;
make_address_byte_array(flash, addr, &cmd_data[1]);
cmd_size = flash->addr_in_4_byte ? 5 : 4;
result = spi->wr(spi, cmd_data, cmd_size, data, size);
}
}
if (spi->unlock) {
spi->unlock(spi);
}
return result;
}
sfud_err sfud_chip_erase(const sfud_flash *flash) {
sfud_err result = SFUD_SUCCESS;
const sfud_spi *spi = &flash->spi;
uint8_t cmd_data[4];
SFUD_ASSERT(flash);
SFUD_ASSERT(flash->init_ok);
if (spi->lock) {
spi->lock(spi);
}
result = set_write_enabled(flash, true);
if (result != SFUD_SUCCESS) {
goto __exit;
}
cmd_data[0] = SFUD_CMD_ERASE_CHIP;
if (flash->chip.write_mode & SFUD_WM_DUAL_BUFFER) {
cmd_data[1] = 0x94;
cmd_data[2] = 0x80;
cmd_data[3] = 0x9A;
result = spi->wr(spi, cmd_data, 4, NULL, 0);
} else {
result = spi->wr(spi, cmd_data, 1, NULL, 0);
}
if (result != SFUD_SUCCESS) {
SFUD_INFO("Error: Flash chip erase SPI communicate error.");
goto __exit;
}
result = wait_busy(flash);
__exit:
set_write_enabled(flash, false);
if (spi->unlock) {
spi->unlock(spi);
}
return result;
}
sfud_err sfud_erase(const sfud_flash *flash, uint32_t addr, size_t size) {
extern size_t sfud_sfdp_get_suitable_eraser(const sfud_flash *flash, uint32_t addr, size_t erase_size);
sfud_err result = SFUD_SUCCESS;
const sfud_spi *spi = &flash->spi;
uint8_t cmd_data[5], cmd_size, cur_erase_cmd;
size_t cur_erase_size;
SFUD_ASSERT(flash);
SFUD_ASSERT(flash->init_ok);
if (addr + size > flash->chip.capacity) {
SFUD_INFO("Error: Flash address is out of bound.");
return SFUD_ERR_ADDR_OUT_OF_BOUND;
}
if (addr == 0 && size == flash->chip.capacity) {
return sfud_chip_erase(flash);
}
if (spi->lock) {
spi->lock(spi);
}
while (size) {
#ifdef SFUD_USING_SFDP
size_t eraser_index;
if (flash->sfdp.available) {
eraser_index = sfud_sfdp_get_suitable_eraser(flash, addr, size);
cur_erase_cmd = flash->sfdp.eraser[eraser_index].cmd;
cur_erase_size = flash->sfdp.eraser[eraser_index].size;
} else {
#else
{
#endif
cur_erase_cmd = flash->chip.erase_gran_cmd;
cur_erase_size = flash->chip.erase_gran;
}
result = set_write_enabled(flash, true);
if (result != SFUD_SUCCESS) {
goto __exit;
}
cmd_data[0] = cur_erase_cmd;
make_address_byte_array(flash, addr, &cmd_data[1]);
cmd_size = flash->addr_in_4_byte ? 5 : 4;
result = spi->wr(spi, cmd_data, cmd_size, NULL, 0);
if (result != SFUD_SUCCESS) {
SFUD_INFO("Error: Flash erase SPI communicate error.");
goto __exit;
}
result = wait_busy(flash);
if (result != SFUD_SUCCESS) {
goto __exit;
}
if (addr % cur_erase_size != 0) {
if (size > cur_erase_size - (addr % cur_erase_size)) {
size -= cur_erase_size - (addr % cur_erase_size);
addr += cur_erase_size - (addr % cur_erase_size);
} else {
goto __exit;
}
} else {
if (size > cur_erase_size) {
size -= cur_erase_size;
addr += cur_erase_size;
} else {
goto __exit;
}
}
}
__exit:
set_write_enabled(flash, false);
if (spi->unlock) {
spi->unlock(spi);
}
return result;
}
static sfud_err page256_or_1_byte_write(const sfud_flash *flash, uint32_t addr, size_t size, uint16_t write_gran,
const uint8_t *data) {
sfud_err result = SFUD_SUCCESS;
const sfud_spi *spi = &flash->spi;
static uint8_t cmd_data[5 + SFUD_WRITE_MAX_PAGE_SIZE];
uint8_t cmd_size;
size_t data_size;
SFUD_ASSERT(flash);
SFUD_ASSERT(write_gran == 1 || write_gran == 256);
SFUD_ASSERT(flash->init_ok);
if (addr + size > flash->chip.capacity) {
SFUD_INFO("Error: Flash address is out of bound.");
return SFUD_ERR_ADDR_OUT_OF_BOUND;
}
if (spi->lock) {
spi->lock(spi);
}
while (size) {
result = set_write_enabled(flash, true);
if (result != SFUD_SUCCESS) {
goto __exit;
}
cmd_data[0] = SFUD_CMD_PAGE_PROGRAM;
make_address_byte_array(flash, addr, &cmd_data[1]);
cmd_size = flash->addr_in_4_byte ? 5 : 4;
if (addr % write_gran != 0) {
if (size > write_gran - (addr % write_gran)) {
data_size = write_gran - (addr % write_gran);
} else {
data_size = size;
}
} else {
if (size > write_gran) {
data_size = write_gran;
} else {
data_size = size;
}
}
size -= data_size;
addr += data_size;
memcpy(&cmd_data[cmd_size], data, data_size);
result = spi->wr(spi, cmd_data, cmd_size + data_size, NULL, 0);
if (result != SFUD_SUCCESS) {
SFUD_INFO("Error: Flash write SPI communicate error.");
goto __exit;
}
result = wait_busy(flash);
if (result != SFUD_SUCCESS) {
goto __exit;
}
data += data_size;
}
__exit:
set_write_enabled(flash, false);
if (spi->unlock) {
spi->unlock(spi);
}
return result;
}
static sfud_err aai_write(const sfud_flash *flash, uint32_t addr, size_t size, const uint8_t *data) {
sfud_err result = SFUD_SUCCESS;
const sfud_spi *spi = &flash->spi;
uint8_t cmd_data[8], cmd_size;
bool first_write = true;
SFUD_ASSERT(flash);
SFUD_ASSERT(flash->init_ok);
if (addr + size > flash->chip.capacity) {
SFUD_INFO("Error: Flash address is out of bound.");
return SFUD_ERR_ADDR_OUT_OF_BOUND;
}
if (spi->lock) {
spi->lock(spi);
}
if (addr % 2 != 0) {
result = page256_or_1_byte_write(flash, addr++, 1, 1, data++);
if (result != SFUD_SUCCESS) {
goto __exit;
}
size--;
}
result = set_write_enabled(flash, true);
if (result != SFUD_SUCCESS) {
goto __exit;
}
cmd_data[0] = SFUD_CMD_AAI_WORD_PROGRAM;
while (size >= 2) {
if (first_write) {
make_address_byte_array(flash, addr, &cmd_data[1]);
cmd_size = flash->addr_in_4_byte ? 5 : 4;
cmd_data[cmd_size] = *data;
cmd_data[cmd_size + 1] = *(data + 1);
first_write = false;
} else {
cmd_size = 1;
cmd_data[1] = *data;
cmd_data[2] = *(data + 1);
}
result = spi->wr(spi, cmd_data, cmd_size + 2, NULL, 0);
if (result != SFUD_SUCCESS) {
SFUD_INFO("Error: Flash write SPI communicate error.");
goto __exit;
}
result = wait_busy(flash);
if (result != SFUD_SUCCESS) {
goto __exit;
}
size -= 2;
addr += 2;
data += 2;
}
result = set_write_enabled(flash, false);
if (result == SFUD_SUCCESS && size == 1) {
result = page256_or_1_byte_write(flash, addr, 1, 1, data);
}
__exit:
if (result != SFUD_SUCCESS) {
set_write_enabled(flash, false);
}
if (spi->unlock) {
spi->unlock(spi);
}
return result;
}
sfud_err sfud_write(const sfud_flash *flash, uint32_t addr, size_t size, const uint8_t *data) {
sfud_err result = SFUD_SUCCESS;
if (flash->chip.write_mode & SFUD_WM_PAGE_256B) {
result = page256_or_1_byte_write(flash, addr, size, 256, data);
} else if (flash->chip.write_mode & SFUD_WM_AAI) {
result = aai_write(flash, addr, size, data);
} else if (flash->chip.write_mode & SFUD_WM_DUAL_BUFFER) {
}
return result;
}
sfud_err sfud_erase_write(const sfud_flash *flash, uint32_t addr, size_t size, const uint8_t *data) {
sfud_err result = SFUD_SUCCESS;
result = sfud_erase(flash, addr, size);
if (result == SFUD_SUCCESS) {
result = sfud_write(flash, addr, size, data);
}
return result;
}
static sfud_err reset(const sfud_flash *flash) {
sfud_err result = SFUD_SUCCESS;
const sfud_spi *spi = &flash->spi;
uint8_t cmd_data[2];
SFUD_ASSERT(flash);
cmd_data[0] = SFUD_CMD_ENABLE_RESET;
result = spi->wr(spi, cmd_data, 1, NULL, 0);
if (result == SFUD_SUCCESS) {
result = wait_busy(flash);
} else {
SFUD_INFO("Error: Flash device reset failed.");
return result;
}
cmd_data[1] = SFUD_CMD_RESET;
result = spi->wr(spi, &cmd_data[1], 1, NULL, 0);
if (result == SFUD_SUCCESS) {
result = wait_busy(flash);
}
if (result == SFUD_SUCCESS) {
SFUD_DEBUG("Flash device reset success.");
} else {
SFUD_INFO("Error: Flash device reset failed.");
}
return result;
}
static sfud_err read_jedec_id(sfud_flash *flash) {
sfud_err result = SFUD_SUCCESS;
const sfud_spi *spi = &flash->spi;
uint8_t cmd_data[1], recv_data[3];
SFUD_ASSERT(flash);
cmd_data[0] = SFUD_CMD_JEDEC_ID;
result = spi->wr(spi, cmd_data, sizeof(cmd_data), recv_data, sizeof(recv_data));
if (result == SFUD_SUCCESS) {
flash->chip.mf_id = recv_data[0];
flash->chip.type_id = recv_data[1];
flash->chip.capacity_id = recv_data[2];
SFUD_DEBUG("The flash device manufacturer ID is 0x%02X, memory type ID is 0x%02X, capacity ID is 0x%02X.",
flash->chip.mf_id, flash->chip.type_id, flash->chip.capacity_id);
} else {
SFUD_INFO("Error: Read flash device JEDEC ID error.");
}
return result;
}
static sfud_err set_write_enabled(const sfud_flash *flash, bool enabled) {
sfud_err result = SFUD_SUCCESS;
uint8_t cmd, register_status;
SFUD_ASSERT(flash);
if (enabled) {
cmd = SFUD_CMD_WRITE_ENABLE;
} else {
cmd = SFUD_CMD_WRITE_DISABLE;
}
result = flash->spi.wr(&flash->spi, &cmd, 1, NULL, 0);
if (result == SFUD_SUCCESS) {
result = sfud_read_status(flash, ®ister_status);
}
if (result == SFUD_SUCCESS) {
if (enabled && (register_status & SFUD_STATUS_REGISTER_WEL) == 0) {
SFUD_INFO("Error: Can't enable write status.");
return SFUD_ERR_WRITE;
} else if (!enabled && (register_status & SFUD_STATUS_REGISTER_WEL) != 0) {
SFUD_INFO("Error: Can't disable write status.");
return SFUD_ERR_WRITE;
}
}
return result;
}
static sfud_err set_4_byte_address_mode(sfud_flash *flash, bool enabled) {
sfud_err result = SFUD_SUCCESS;
uint8_t cmd;
SFUD_ASSERT(flash);
result = set_write_enabled(flash, true);
if (result != SFUD_SUCCESS) {
return result;
}
if (enabled) {
cmd = SFUD_CMD_ENTER_4B_ADDRESS_MODE;
} else {
cmd = SFUD_CMD_EXIT_4B_ADDRESS_MODE;
}
result = flash->spi.wr(&flash->spi, &cmd, 1, NULL, 0);
if (result == SFUD_SUCCESS) {
flash->addr_in_4_byte = enabled ? true : false;
SFUD_DEBUG("%s 4-Byte addressing mode success.", enabled ? "Enter" : "Exit");
} else {
SFUD_INFO("Error: %s 4-Byte addressing mode failed.", enabled ? "Enter" : "Exit");
}
return result;
}
sfud_err sfud_read_status(const sfud_flash *flash, uint8_t *status) {
uint8_t cmd = SFUD_CMD_READ_STATUS_REGISTER;
SFUD_ASSERT(flash);
SFUD_ASSERT(status);
return flash->spi.wr(&flash->spi, &cmd, 1, status, 1);
}
static sfud_err wait_busy(const sfud_flash *flash) {
sfud_err result = SFUD_SUCCESS;
uint8_t status;
size_t retry_times = flash->retry.times;
SFUD_ASSERT(flash);
while (true) {
result = sfud_read_status(flash, &status);
if (result == SFUD_SUCCESS && ((status & SFUD_STATUS_REGISTER_BUSY)) == 0) {
break;
}
SFUD_RETRY_PROCESS(flash->retry.delay, retry_times, result);
}
if (result != SFUD_SUCCESS || ((status & SFUD_STATUS_REGISTER_BUSY)) != 0) {
SFUD_INFO("Error: Flash wait busy has an error.");
}
return result;
}
static void make_address_byte_array(const sfud_flash *flash, uint32_t addr, uint8_t *array) {
uint8_t len, i;
SFUD_ASSERT(flash);
SFUD_ASSERT(array);
len = flash->addr_in_4_byte ? 4 : 3;
for (i = 0; i < len; i++) {
array[i] = (addr >> ((len - (i + 1)) * 8)) & 0xFF;
}
}
sfud_err sfud_write_status(const sfud_flash *flash, bool is_volatile, uint8_t status) {
sfud_err result = SFUD_SUCCESS;
const sfud_spi *spi = &flash->spi;
uint8_t cmd_data[2];
SFUD_ASSERT(flash);
if (is_volatile) {
cmd_data[0] = SFUD_VOLATILE_SR_WRITE_ENABLE;
result = spi->wr(spi, cmd_data, 1, NULL, 0);
} else {
result = set_write_enabled(flash, true);
}
if (result == SFUD_SUCCESS) {
cmd_data[0] = SFUD_CMD_WRITE_STATUS_REGISTER;
cmd_data[1] = status;
result = spi->wr(spi, cmd_data, 2, NULL, 0);
}
if (result != SFUD_SUCCESS) {
SFUD_INFO("Error: Write_status register failed.");
}
return result;
}