/** * Close file \a fd */ static int flash_avr_close(struct KFile *_fd) { Flash *fd = FLASH_CAST(_fd); flash_avr_flush(fd); LOG_INFO("Flash file closed\n"); return 0; }
/** * Return true if no error are occurred after flash memory * read or write operation, otherwise return error code. */ static bool flash_getStatus(struct KBlock *blk) { Flash *fls = FLASH_CAST(blk); /* * This bit is set to one if an invalid command and/or a bad keywords was/were * written in the Flash Command Register. */ if(MC_FSR & BV(MC_PROGE)) { fls->hw->status |= FLASH_WR_ERR; LOG_ERR("flash not erased..\n"); return false; } /* * This bit is set to one if we programming of at least one locked lock * region. */ if(MC_FSR & BV(MC_LOCKE)) { fls->hw->status |= FLASH_WR_PROTECT; LOG_ERR("wr protect..\n"); return false; } return true; }
/** * Reopen file \a fd */ static struct KFile *flash_avr_reopen(struct KFile *fd) { Flash *_fd = FLASH_CAST(fd); flash_avr_close(fd); flash_avr_open((struct Flash *)_fd); return fd; }
/** * Write program memory. * Write \a size bytes from buffer \a _buf to file \a fd * \note Write operations are buffered. */ static size_t flash_avr_write(struct KFile *_fd, const void *_buf, size_t size) { Flash *fd = FLASH_CAST(_fd); const uint8_t *buf =(const uint8_t *)_buf; page_t page; page_addr_t page_addr; size_t total_write = 0; ASSERT(fd->fd.seek_pos + (kfile_off_t)size <= (kfile_off_t)fd->fd.size); size = MIN((kfile_off_t)size, fd->fd.size - fd->fd.seek_pos); LOG_INFO("Writing at pos[%u]\n", fd->fd.seek_pos); while (size) { page = fd->fd.seek_pos / SPM_PAGESIZE; page_addr = fd->fd.seek_pos % SPM_PAGESIZE; flash_avr_loadPage(fd, page); size_t wr_len = MIN(size, SPM_PAGESIZE - page_addr); memcpy(fd->page_buf + page_addr, buf, wr_len); fd->page_dirty = true; buf += wr_len; fd->fd.seek_pos += wr_len; size -= wr_len; total_write += wr_len; } LOG_INFO("written %u bytes\n", total_write); return total_write; }
static bool flash_wait(struct KBlock *blk, uint32_t event) { Flash *fls = FLASH_CAST(blk); ticks_t start = timer_clock(); while (true) { if (!(FLASH_FMC_R & event)) break; if (FLASH_FCRIS_R & FLASH_FCRIS_ARIS) { fls->hw->status |= FLASH_WR_PROTECT; LOG_ERR("wr protect..\n"); return false; } if (timer_clock() - start > ms_to_ticks(CONFIG_FLASH_WR_TIMEOUT)) { fls->hw->status |= FLASH_WR_TIMEOUT; LOG_ERR("Timeout..\n"); return false; } cpu_relax(); } return true; }
static bool flash_wait(struct KBlock *blk) { Flash *fls = FLASH_CAST(blk); ticks_t start = timer_clock(); while (true) { if (!(EMB_FLASH->SR & FLASH_FLAG_BSY)) break; if (EMB_FLASH->SR & FLASH_FLAG_PGERR) { fls->hw->status |= FLASH_NOT_ERASED; LOG_ERR("flash not erased..\n"); return false; } if (EMB_FLASH->SR & FLASH_FLAG_WRPRTERR) { fls->hw->status |= FLASH_WR_PROTECT; LOG_ERR("wr protect..\n"); return false; } if (timer_clock() - start > ms_to_ticks(CONFIG_FLASH_WR_TIMEOUT)) { fls->hw->status |= FLASH_WR_TIMEOUT; LOG_ERR("Timeout..\n"); return false; } cpu_relax(); } return true; }
/** * Read from file \a fd \a size bytes and put it in buffer \a buf * \return the number of bytes read. */ static size_t flash_avr_read(struct KFile *_fd, void *buf, size_t size) { Flash *fd = FLASH_CAST(_fd); ASSERT(fd->fd.seek_pos + (kfile_off_t)size <= (kfile_off_t)fd->fd.size); size = MIN((kfile_off_t)size, fd->fd.size - fd->fd.seek_pos); LOG_INFO("Reading at pos[%u]\n", fd->fd.seek_pos); // Flush current buffered page (if modified). flash_avr_flush(fd); /* * AVR pointers are 16 bits wide, this hack is needed to avoid * compiler warning, cause fd->seek_pos is a 32bit offset. */ const uint8_t *pgm_addr = (const uint8_t *)0; pgm_addr += fd->fd.seek_pos; memcpy_P(buf, pgm_addr, size); fd->fd.seek_pos += size; LOG_INFO("Read %u bytes\n", size); return size; }
static void at91_flash_clearerror(struct KBlock *blk) { Flash *fls = FLASH_CAST(blk); fls->hw->status = 0; }
static int at91_flash_error(struct KBlock *blk) { Flash *fls = FLASH_CAST(blk); return fls->hw->status; }
/** * Flush avr flash function. * * Write current buffered page in flash memory (if modified). * This function erase flash memory page before writing. */ static int flash_avr_kfileFlush(struct KFile *_fd) { Flash *fd = FLASH_CAST(_fd); flash_avr_flush(fd); return 0; }
static size_t lpc2_flash_writeDirect(struct KBlock *blk, block_idx_t idx, const void *_buf, size_t offset, size_t size) { ASSERT(offset == 0); ASSERT(FLASH_PAGE_SIZE_BYTES == size); Flash *fls = FLASH_CAST(blk); if (!(fls->blk.priv.flags & KB_WRITE_ONCE)) ASSERT(sector_size(idx) <= FLASH_PAGE_SIZE_BYTES); const uint8_t *buf = (const uint8_t *)_buf; cpu_flags_t flags; //Compute page address of current page. uint32_t addr = idx * blk->blk_size; uint32_t sector = addr_to_sector(addr); // Compute the first page index in the sector to manage the status int idx_sector = sector_addr(sector) / blk->blk_size; LOG_INFO("Writing page[%ld]sector[%ld]idx[%d]\n", idx, sector, idx_sector); IRQ_SAVE_DISABLE(flags); IapCmd cmd; IapRes res; cmd.cmd = PREPARE_SECTOR_FOR_WRITE; cmd.param[0] = cmd.param[1] = sector; iap(&cmd, &res); if (res.status != CMD_SUCCESS) goto flash_error; if ((fls->blk.priv.flags & KB_WRITE_ONCE) && bitarray_isRangeFull(&lpc2_bitx, idx_sector, erase_group[sector])) { kputs("blocchi pieni\n"); ASSERT(0); goto flash_error; } bool erase = false; if ((fls->blk.priv.flags & KB_WRITE_ONCE) && bitarray_isRangeEmpty(&lpc2_bitx, idx_sector, erase_group[sector])) erase = true; if (!(fls->blk.priv.flags & KB_WRITE_ONCE)) erase = true; if (erase) { cmd.cmd = ERASE_SECTOR; cmd.param[0] = cmd.param[1] = sector; cmd.param[2] = CPU_FREQ / 1000; iap(&cmd, &res); if (res.status != CMD_SUCCESS) goto flash_error; } LOG_INFO("Writing page [%ld], addr [%ld] in sector[%ld]\n", idx, addr, sector); cmd.cmd = PREPARE_SECTOR_FOR_WRITE; cmd.param[0] = cmd.param[1] = sector; iap(&cmd, &res); if (res.status != CMD_SUCCESS) goto flash_error; if (fls->blk.priv.flags & KB_WRITE_ONCE) { if (bitarray_test(&lpc2_bitx, idx)) { ASSERT(0); goto flash_error; } else bitarray_set(&lpc2_bitx, idx); } cmd.cmd = COPY_RAM_TO_FLASH; cmd.param[0] = addr; cmd.param[1] = (uint32_t)buf; cmd.param[2] = FLASH_PAGE_SIZE_BYTES; cmd.param[3] = CPU_FREQ / 1000; iap(&cmd, &res); if (res.status != CMD_SUCCESS) goto flash_error; IRQ_RESTORE(flags); LOG_INFO("Done\n"); return blk->blk_size; flash_error: LOG_ERR("%ld\n", res.status); fls->hw->status |= FLASH_WR_ERR; return 0; }