static int spi_flash_send_write_sequence(spi_flash_dev *sfd) { u32_t addr = sfd->addr; u32_t len_rem_page = sfd->flash_conf.size_page_write_max - (addr & (sfd->flash_conf.size_page_write_max - 1)); u32_t len_to_write = MIN(len_rem_page, sfd->count); if (len_to_write == 0) { len_to_write = MIN(sfd->count, sfd->flash_conf.size_page_write_max); } spi_flash_set_first_seq_to_wren(sfd); sfd->tmp_buf[0] = sfd->flash_conf.cmd_defs[SPI_FLASH_CMD_WRITE]; spi_flash_fill_in_address(sfd, &sfd->tmp_buf[1], addr); sfd->sequence_buf[1].tx = &sfd->tmp_buf[0]; sfd->sequence_buf[1].tx_len = 1 + sfd->flash_conf.addressing_bytes + 1; sfd->sequence_buf[1].rx = 0; sfd->sequence_buf[1].rx_len = 0; sfd->sequence_buf[1].cs_release = 0; sfd->sequence_buf[2].tx = (u8_t*)sfd->ptr; sfd->sequence_buf[2].tx_len = len_to_write; sfd->sequence_buf[2].rx = 0; sfd->sequence_buf[2].rx_len = 0; sfd->sequence_buf[2].cs_release = 0; int res = spi_flash_exec(sfd, &sfd->sequence_buf[0], 3); if (res == SPI_OK) { sfd->addr += len_to_write; sfd->ptr += len_to_write; sfd->count -= len_to_write; } return res; }
int spi_flash_read_reg(struct spi_flash *flash, u8 inst, u8 *buf, size_t len) { struct spi_flash_command cmd; spi_flash_command_init(&cmd, inst, 0, SFLASH_TYPE_READ_REG); cmd.proto = flash->reg_proto; cmd.data_len = len; cmd.rx_data = buf; return spi_flash_exec(flash, &cmd); }
int SPI_FLASH_read_busy(spi_flash_dev *sfd, spi_flash_callback cb, u8_t *res) { spi_dev_sequence seq; sfd->state = SPI_FLASH_STATE_READ_BUSY; sfd->sr_dst = res; seq.tx = (u8_t*)&sfd->flash_conf.cmd_defs[SPI_FLASH_CMD_READ_SR]; seq.tx_len = 1; seq.rx = &sfd->sr_tmp; seq.rx_len = 1; seq.cs_release = 0; sfd->spi_flash_callback = cb; return spi_flash_exec(sfd, &seq, 1); }
static int spi_flash_closeprotectun(spi_flash_dev *sfd, char unprotect) { spi_flash_set_first_seq_to_wren(sfd); sfd->tmp_buf[0] = sfd->flash_conf.cmd_defs[SPI_FLASH_CMD_WRITE_SR]; sfd->tmp_buf[1] = sfd->flash_conf.cmd_defs[unprotect ? SPI_FLASH_CMD_SR_UNPROTECT : SPI_FLASH_CMD_SR_PROTECT]; sfd->sequence_buf[1].tx = &sfd->tmp_buf[0]; sfd->sequence_buf[1].tx_len = 2; sfd->sequence_buf[1].rx = 0; sfd->sequence_buf[1].rx_len = 0; sfd->sequence_buf[1].cs_release = 0; return spi_flash_exec(sfd, &sfd->sequence_buf[0], 2); }
int SPI_FLASH_open(spi_flash_dev *sfd, spi_flash_callback cb) { if (sfd->open) { return SPI_FLASH_ERR_OPENED; } if (sfd->busy) { return SPI_FLASH_ERR_BUSY; } sfd->busy = TRUE; sfd->state = SPI_FLASH_STATE_OPENING_READ_ID; sfd->sequence_buf[0].tx = (u8_t*)&sfd->flash_conf.cmd_defs[SPI_FLASH_CMD_READ_ID]; sfd->sequence_buf[0].tx_len = 1; sfd->sequence_buf[0].rx = sfd->tmp_buf; sfd->sequence_buf[0].rx_len = 3; sfd->sequence_buf[0].cs_release = 0; sfd->spi_flash_callback = cb; return spi_flash_exec(sfd, &sfd->sequence_buf[0], 1); }
int SPI_FLASH_mass_erase(spi_flash_dev *sfd, spi_flash_callback cb) { if (!sfd->open) { return SPI_FLASH_ERR_CLOSED; } if (sfd->busy) { return SPI_FLASH_ERR_BUSY; } sfd->busy = TRUE; sfd->state = SPI_FLASH_STATE_MASS_ERASE; sfd->spi_flash_callback = cb; spi_flash_set_first_seq_to_wren(sfd); sfd->sequence_buf[1].tx = (u8_t*)&sfd->flash_conf.cmd_defs[SPI_FLASH_CMD_MASS_ERASE]; sfd->sequence_buf[1].tx_len = 1; sfd->sequence_buf[1].rx = 0; sfd->sequence_buf[1].rx_len = 0; sfd->sequence_buf[1].cs_release = 0; return spi_flash_exec(sfd, &sfd->sequence_buf[0], 2); }
static int spi_flash_send_erase_sequence(spi_flash_dev *sfd) { u32_t addr = sfd->addr; u32_t len = sfd->flash_conf.size_sector_erase_min; spi_flash_set_first_seq_to_wren(sfd); sfd->tmp_buf[0] = sfd->flash_conf.cmd_defs[SPI_FLASH_CMD_SECTOR_ERASE]; spi_flash_fill_in_address(sfd, &sfd->tmp_buf[1], addr); sfd->sequence_buf[1].tx = &sfd->tmp_buf[0]; sfd->sequence_buf[1].tx_len = 1 + sfd->flash_conf.addressing_bytes + 1; sfd->sequence_buf[1].rx = 0; sfd->sequence_buf[1].rx_len = 0; sfd->sequence_buf[1].cs_release = 0; int res = spi_flash_exec(sfd, &sfd->sequence_buf[0], 2); if (res == SPI_OK) { sfd->addr += len; sfd->count -= len; } return res; }
int SPI_FLASH_read(spi_flash_dev *sfd, spi_flash_callback cb, u32_t addr, u16_t size, u8_t *dest) { if (!sfd->open) { return SPI_FLASH_ERR_CLOSED; } if (addr > sfd->flash_conf.size_total || (addr+size) > sfd->flash_conf.size_total) { return SPI_FLASH_ERR_ADDRESS; } if (sfd->busy) { return SPI_FLASH_ERR_BUSY; } sfd->busy = TRUE; sfd->state = SPI_FLASH_STATE_READ; sfd->tmp_buf[0] = sfd->flash_conf.cmd_defs[SPI_FLASH_CMD_READ]; spi_flash_fill_in_address(sfd, &sfd->tmp_buf[1], (u32_t)addr); sfd->sequence_buf[0].tx = &sfd->tmp_buf[0]; sfd->sequence_buf[0].tx_len = 1 + (1+sfd->flash_conf.addressing_bytes); sfd->sequence_buf[0].rx = dest; sfd->sequence_buf[0].rx_len = size; sfd->sequence_buf[0].cs_release = 0; sfd->spi_flash_callback = cb; return spi_flash_exec(sfd, &sfd->sequence_buf[0], 1); }
/* * spi flash task function, used for reporting finished operations to user and * to keep state of intermediate operations */ static void spi_flash_task_f(u32_t res_u, void *sfd_v) { int res = (int)res_u; spi_flash_dev *sfd = (spi_flash_dev *)sfd_v; ASSERT(sfd); if (sfd->busy_poll) { spi_dev_sequence seq; // busy poll, fire off an SR read sfd->poll_count++; DBG(D_SPI, D_DEBUG, "SPIF poll: SR busy %i/%i?\n", sfd->poll_count, sfd->flash_conf.busy_poll_divisor); seq.tx = (u8_t*)&sfd->flash_conf.cmd_defs[SPI_FLASH_CMD_READ_SR]; seq.tx_len = 1; seq.rx = sfd->tmp_buf; seq.rx_len = 1; seq.cs_release = 0; res = spi_flash_exec(sfd, &seq, 1); if (res == SPI_ERR_DEV_BUSY && sfd->poll_count < 16) { DBG(D_SPI, D_INFO, "SPIF poll: device busy\n"); } else if (res != SPI_OK) { DBG(D_SPI, D_WARN, "SPIF poll: ERROR %i\n", res); TASK_stop_timer(&sfd->timer); sfd->busy_poll = FALSE; sfd->state = SPI_FLASH_STATE_ERROR; spi_flash_finalize(sfd, res); } return; } // if res != SPI_OK, state is always SPI_FLASH_STATE_ERROR here switch (sfd->state) { case SPI_FLASH_STATE_WRITE_WAIT: { if (sfd->count > 0) { // more to write sfd->state = SPI_FLASH_STATE_WRITE_SEQ; res = spi_flash_send_write_sequence(sfd); if (res != SPI_OK) { // error in middle of write sfd->state = SPI_FLASH_STATE_ERROR; spi_flash_finalize(sfd, res); } } else { // finished sfd->state = SPI_FLASH_STATE_OPENED; spi_flash_finalize(sfd, res); } break; } case SPI_FLASH_STATE_ERASE_WAIT: { if (sfd->count > 0) { // more to erase sfd->state = SPI_FLASH_STATE_ERASE_SEQ; res = spi_flash_send_erase_sequence(sfd); if (res != SPI_OK) { // error in middle of erase sfd->state = SPI_FLASH_STATE_ERROR; spi_flash_finalize(sfd, res); } } else { // finished sfd->state = SPI_FLASH_STATE_OPENED; spi_flash_finalize(sfd, res); } break; } case SPI_FLASH_STATE_CLOSED: if (sfd->open) { SPI_DEV_close(&sfd->dev); spi_flash_finalize(sfd, res); TASK_stop_timer(&sfd->timer); TASK_free(sfd->task); sfd->open = FALSE; } break; case SPI_FLASH_STATE_WRSR_WAIT: case SPI_FLASH_STATE_OPENED: case SPI_FLASH_STATE_ERROR: spi_flash_finalize(sfd, res); break; default: sfd->state = SPI_FLASH_STATE_ERROR; if (sfd->open) { SPI_DEV_close(&sfd->dev); spi_flash_finalize(sfd, res); TASK_stop_timer(&sfd->timer); TASK_free(sfd->task); sfd->open = FALSE; } break; } }