X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;ds=sidebyside;f=bertos%2Fcpu%2Favr%2Fdrv%2Fflash_avr.c;h=2c0baa1b52924bdab9bc0c51f6cff08285a93d20;hb=540b160dbedfdb12ce29f9b107be860ba22cd6cb;hp=76023a29af1dd655760c85d6ea3b933d64506df7;hpb=e863779405806aeea209a213eeb82caa8f029acc;p=bertos.git diff --git a/bertos/cpu/avr/drv/flash_avr.c b/bertos/cpu/avr/drv/flash_avr.c index 76023a29..2c0baa1b 100644 --- a/bertos/cpu/avr/drv/flash_avr.c +++ b/bertos/cpu/avr/drv/flash_avr.c @@ -32,27 +32,34 @@ * * \brief Self programming routines. * - * \version $Id$ * \author Francesco Sacchi * \author Daniele Basile * - * This module implements a kfile-like access for Atmel avr - * internal flash. + * This module implements a kfile-like access for Atmel avr internal flash. * Internal flash writing access is controlled by BOOTSZ fuses, check * datasheet for details. */ #include "flash_avr.h" -#include "cfg/cfg_flash_avr.h" +#include "cfg/cfg_emb_flash.h" + #include // MIN() #include #include #include +// Define log settings for cfg/log.h +#define LOG_LEVEL CONFIG_FLASH_EMB_LOG_LEVEL +#define LOG_FORMAT CONFIG_FLASH_EMB_LOG_FORMAT +#include + #include +#include -#include +#include +#include +#include #include #include @@ -60,227 +67,112 @@ #include +struct FlashHardware; - -/** - * Definition of type for avr flash module. - */ -typedef uint16_t avr_page_addr_t; - - - - -/* - * Private avr flush funtion. - * - * Write current buffered page in flash memory (if modified). - * This function erase flash memory page before writing. - * - * This function is only use internaly in this module. - */ -static void flash_avr_flush(KFileFlashAvr *fd) +static size_t avr_flash_readDirect(struct KBlock *blk, block_idx_t idx, void *buf, size_t offset, size_t size) { - if (fd->page_dirty) - { - kprintf("Flushing page %d\n", fd->curr_page); + memcpy_P(buf, (const void *)(uint16_t)(idx * blk->blk_size + offset), size); + return blk->blk_size; +} - // Wait while the SPM instruction is busy. - boot_spm_busy_wait(); +static size_t avr_flash_writeDirect(struct KBlock *blk, block_idx_t idx, const void *_buf, size_t offset, size_t size) +{ + ASSERT(offset == 0); + ASSERT(size == blk->blk_size); - kprintf("Filling temparary page buffer..."); + uint32_t page_addr = idx * blk->blk_size; + uint32_t addr = idx * blk->blk_size; + const uint8_t *buf = (const uint8_t *)_buf; - // Fill the temporary buffer of the AVR - for (avr_page_addr_t page_addr = 0; page_addr < SPM_PAGESIZE; page_addr += 2) - { - uint16_t word = ((uint16_t)fd->page_buf[page_addr + 1] << 8) | fd->page_buf[page_addr]; + /* Wait while the SPM instruction is busy. */ + boot_spm_busy_wait(); - ATOMIC(boot_page_fill(page_addr, word)); - } - kprintf("Done.\n"); + /* Fill the temporary buffer of the AVR */ + while (size) + { + uint16_t data = ((*buf + 1) << 8) | *buf; + ATOMIC(boot_page_fill(addr, data)); - wdt_reset(); + buf += 2; + size -= 2; + addr += 2; + } - kprintf("Erasing page, addr %u...", fd->curr_page * SPM_PAGESIZE); + wdt_reset(); - /* Page erase */ - ATOMIC(boot_page_erase(fd->curr_page * SPM_PAGESIZE)); + /* Page erase */ + ATOMIC(boot_page_erase(page_addr)); - /* Wait until the memory is erased. */ - boot_spm_busy_wait(); + /* Wait until the memory is erased. */ + boot_spm_busy_wait(); - kprintf("Done.\n"); - kprintf("Writing page, addr %u...", fd->curr_page * SPM_PAGESIZE); + /* Store buffer in flash page. */ + ATOMIC(boot_page_write(page_addr)); - /* Store buffer in flash page. */ - ATOMIC(boot_page_write(fd->curr_page * SPM_PAGESIZE)); - boot_spm_busy_wait(); // Wait while the SPM instruction is busy. + /* Wait while the SPM instruction is busy. */ + boot_spm_busy_wait(); - /* - * Reenable RWW-section again. We need this if we want to jump back - * to the application after bootloading. - */ - ATOMIC(boot_rww_enable()); + /* + * Reenable RWW-section again. We need this if we want to jump back + * to the application after bootloading. + */ + ATOMIC(boot_rww_enable()); - fd->page_dirty = false; - kprintf("Done.\n"); - } + return blk->blk_size; } - -/** - * 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) +static int avr_flash_dummy(UNUSED_ARG(struct KBlock, *blk)) { - KFileFlashAvr *fd = KFILEFLASHAVR(_fd); - flash_avr_flush(fd); return 0; } - -/** - * Check current page and if \a page is different, load it in - * temporary buffer. - */ -static void flash_avr_loadPage(KFileFlashAvr *fd, avr_page_t page) -{ - if (page != fd->curr_page) - { - flash_avr_flush(fd); - // Load page - memcpy_P(fd->page_buf, (const char *)(page * SPM_PAGESIZE), SPM_PAGESIZE); - fd->curr_page = page; - kprintf("Loaded page %d\n", fd->curr_page); - } -} - -/** - * 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) +static const KBlockVTable flash_avr_buffered_vt = { - KFileFlashAvr *fd = KFILEFLASHAVR(_fd); - const uint8_t *buf =(const uint8_t *)_buf; + .readDirect = avr_flash_readDirect, + .writeDirect = avr_flash_writeDirect, - avr_page_t page; - avr_page_addr_t page_addr; - size_t total_write = 0; + .readBuf = kblock_swReadBuf, + .writeBuf = kblock_swWriteBuf, + .load = kblock_swLoad, + .store = kblock_swStore, + .error = avr_flash_dummy, + .clearerr = (kblock_clearerr_t)avr_flash_dummy, +}; - ASSERT(fd->fd.seek_pos + (kfile_off_t)size <= (kfile_off_t)fd->fd.size); - size = MIN((uint32_t)size, fd->fd.size - fd->fd.seek_pos); - - kprintf("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; - } - kprintf("written %u bytes\n", total_write); - return total_write; -} - -/** - * Open flash file \a fd - * \a name and \a mode are unused, cause flash memory is - * threated like one file. - */ -static void flash_avr_open(struct KFileFlashAvr *fd) +static const KBlockVTable flash_avr_unbuffered_vt = { - fd->curr_page = 0; - memcpy_P(fd->page_buf, (const char *)(fd->curr_page * SPM_PAGESIZE), SPM_PAGESIZE); + .readDirect = avr_flash_readDirect, + .writeDirect = avr_flash_writeDirect, - fd->fd.seek_pos = 0; - fd->fd.size = (uint16_t)(FLASHEND - CONFIG_FLASH_AVR_BOOTSIZE + 1); - fd->page_dirty = false; + .error = avr_flash_dummy, + .clearerr = (kblock_clearerr_t)avr_flash_dummy, +}; - kprintf("Flash file opened\n"); -} +static uint8_t flash_buf[SPM_PAGESIZE]; -/** - * Close file \a fd - */ -static int flash_avr_close(struct KFile *_fd) +static void common_init(Flash *fls) { - KFileFlashAvr *fd = KFILEFLASHAVR(_fd); - flash_avr_flush(fd); - kprintf("Flash file closed\n"); - return 0; -} + memset(fls, 0, sizeof(*fls)); + DB(fls->blk.priv.type = KBT_FLASH); -/** - * Reopen file \a fd - */ -static struct KFile *flash_avr_reopen(struct KFile *fd) -{ - KFileFlashAvr *_fd = KFILEFLASHAVR(fd); - flash_avr_close(fd); - flash_avr_open(_fd); - return fd; + fls->blk.blk_size = SPM_PAGESIZE; + fls->blk.blk_cnt = (FLASHEND + 1) / SPM_PAGESIZE; } -/** - * 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) +void flash_hw_init(Flash *fls, UNUSED_ARG(int, flags)) { - KFileFlashAvr *fd = KFILEFLASHAVR(_fd); - ASSERT(fd->fd.seek_pos + (kfile_off_t)size <= (kfile_off_t)fd->fd.size); - size = MIN((uint32_t)size, fd->fd.size - fd->fd.seek_pos); - - kprintf("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; - kprintf("Read %u bytes\n", size); - return size; + common_init(fls); + fls->blk.priv.vt = &flash_avr_buffered_vt; + fls->blk.priv.flags |= KB_BUFFERED | KB_PARTIAL_WRITE; + fls->blk.priv.buf = flash_buf; } -/** - * Init AVR flash read/write file. - */ -void flash_avr_init(struct KFileFlashAvr *fd) +void flash_hw_initUnbuffered(Flash *fls, UNUSED_ARG(int, flags)) { - memset(fd, 0, sizeof(*fd)); - DB(fd->fd._type = KFT_FLASHAVR); - - // Set up flash programming functions. - fd->fd.reopen = flash_avr_reopen; - fd->fd.close = flash_avr_close; - fd->fd.read = flash_avr_read; - fd->fd.write = flash_avr_write; - fd->fd.seek = kfile_genericSeek; - fd->fd.flush = flash_avr_kfileFlush; - fd->curr_page = 0; - - flash_avr_open(fd); + common_init(fls); + fls->blk.priv.vt = &flash_avr_unbuffered_vt; }