X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=mware%2Fprog_avr.c;h=dc9ac9e7702bbc89bf131f34fe7f3b9e2f6d20ef;hb=656aba7a717ec0c145a25be75ff11c6eaf0f12cf;hp=05c1ab19cbcabcdef474bf953869bd1ed202fac0;hpb=594bfc507f2901777e93ca03fa34f4245a752b35;p=bertos.git diff --git a/mware/prog_avr.c b/mware/prog_avr.c index 05c1ab19..dc9ac9e7 100755 --- a/mware/prog_avr.c +++ b/mware/prog_avr.c @@ -1,7 +1,7 @@ /** * \file * * @@ -9,110 +9,211 @@ * * \version $Id$ * \author Francesco Sacchi + * \author Daniele Basile */ #include "prog.h" + +#include + #include #include // MIN() #include -#include -#include +#include + #include -#include +#include +#include + +typedef uint16_t avr_page_addr_t; +typedef uint16_t avr_page_t; /** - * Erase Flash. + * Temporary buffer cointaing data block to + * write on flash. */ -static void prog_erase_flash(void) -{ - uint32_t flash_addr; - /* Erase the flash ROM */ - #ifdef LARGE_MEMORY - /* - * SPM uses Z pointer but the pointer is only 16 bit and - * can only address up to 64Kbytes FLASH. Higher locations - * require the use of RAMPZ - */ - RAMPZ = 0x00; +static uint8_t page_buf[SPM_PAGESIZE]; - for (flash_addr = 0; (flash_addr < (uint16_t)(APP_END & 0xFFFF)) | (RAMPZ == 0x00); flash_addr += PAGESIZE) - { - wdt_reset(); +bool page_modified; /// Flag for checking if current page is modified. - write_page(flash_addr, BV(PGERS) + BV(SPMEN)); /* Page erase */ - write_page(flash_addr, BV(REENABLE_RWW_BIT) + BV(SPMEN)); /* Re-enable the RWW section */ +/** + * Current buffered page. + */ +static avr_page_t curr_page = 0; - if(flashgg_addr >= (0xFFFF - PAGESIZE)) /* Last section on lower 64k segment is erased */ - RAMPZ = BV(RAMPZ0); /* RAMPZ has to be incremented into upper 64k segment */ - } - RAMPZ = 0x00; - #else /* LARGE_MEMORY */ - for (flash_addr = 0; flash_addr < APP_END; flash_addr += PAGESIZE) /* Application section = 60 pages */ +/** + * Write current buffered page in flash memory (if modified). + * This function erase flash memory page before writing. + */ +static void prog_flush(void) +{ + if (page_modified) + { + kprintf("Flushing page %d\n", curr_page); + + boot_spm_busy_wait(); // Wait while the SPM instruction is busy. + + kprintf("Filling temparary page buffer..."); + /* Fill the temporary buffer of the AVR */ + for (avr_page_addr_t page_addr = 0; page_addr < SPM_PAGESIZE; page_addr += 2) { - wdt_reset(); + uint16_t word = ((uint16_t)page_buf[page_addr + 1] << 8) | page_buf[page_addr]; - /* Page erase */ - write_page(flash_addr, BV(PGERS) + BV(SPMEN)); - /* Re-enable RWW section */ - write_page(flash_addr, BV(REENABLE_RWW_BIT) + BV(SPMEN)); + ATOMIC(boot_page_fill(page_addr, word)); } - #endif /* LARGE_MEMORY */ + kprintf("Done.\n"); + + wdt_reset(); + + kprintf("Erasing page, addr %d...", curr_page * SPM_PAGESIZE); + + /* Page erase */ + ATOMIC(boot_page_erase(curr_page * SPM_PAGESIZE)); + + /* Wait until the memory is erased. */ + boot_spm_busy_wait(); + + kprintf("Done.\n"); + kprintf("Writing page, addr %d...", curr_page * SPM_PAGESIZE); + + /* Store buffer in flash page. */ + ATOMIC(boot_page_write(curr_page * SPM_PAGESIZE)); + boot_spm_busy_wait(); // Wait while the SPM instruction is busy. + + /* + * Reenable RWW-section again. We need this if we want to jump back + * to the application after bootloading. + */ + ATOMIC(boot_rww_enable()); + + page_modified = false; + kprintf("Done.\n"); + } } /** - * Write a page in program memory. + * Check current page and if \param page is different, load it in + * temporary buffer. */ -static void prog_pagewrite(uint16_t addr) +static void prog_loadPage(avr_page_t page) { - write_page(addr, BV(PGWRT) + BV(SPMEN)); - /* Re-enable the RWW section */ - write_page(addr, BV(REENABLE_RWW_BIT) + BV(SPMEN)); + if (page != curr_page) + { + prog_flush(); + // Load page + memcpy_P(page_buf, (const char *)(page * SPM_PAGESIZE), SPM_PAGESIZE); + curr_page = page; + kprintf("Loaded page %d\n", curr_page); + } } - /** * Write program memory. + * Write \param size bytes from buffer \param _buf to file \param *fd + * \note Write operations are buffered. */ -rotating_t prog_write(struct _KFile *file, progress_func_t progress) +size_t prog_write(struct _KFile *fd, const void *_buf, size_t size) { - size_t size; - rotating_t rot = 0; - uint32_t flash_addr = 0; - uint16_t page_addr; - uint8_t buf[PAGESIZE]; - - /* We erase fash memory before to write inside */ - prog_erase_flash(); - - for (;;) + const uint8_t *buf =(const uint8_t *)_buf; + + avr_page_t page; + avr_page_addr_t page_addr; + size_t total_write = 0; + + ASSERT(fd->seek_pos + size <= fd->size); + size = MIN((uint32_t)size, fd->size - fd->seek_pos); + + kprintf("Writing at pos[%d]\n", fd->seek_pos); + while (size) { - wdt_reset(); + page = fd->seek_pos / SPM_PAGESIZE; + page_addr = fd->seek_pos % SPM_PAGESIZE; - /* Read data from file */ - size = file->read(file, buf, PAGESIZE); + prog_loadPage(page); - /* If we reached end of file exit */ - if (!size) - break; - - /* Update checksum */ - rotating_update(buf, size, &rot); - - /* Fill the temporary buffer of the AVR */ - for (page_addr = 0; page_addr < size; page_addr += 2) - fill_temp_buffer(buf[page_addr + 1] | (uint16_t)buf[page_addr] << 8, page_addr); - - /* Page write */ - prog_pagewrite(flash_addr); - - /* Update progess (if present) */ - if (progress) - if (!progress(file->SeekPos, file->Size)) - break; - - flash_addr += size; + size_t wr_len = MIN(size, SPM_PAGESIZE - page_addr); + memcpy(page_buf + page_addr, buf, wr_len); + page_modified = true; + + buf += wr_len; + fd->seek_pos += wr_len; + size -= wr_len; + total_write += wr_len; } + kprintf("written %d bytes\n", total_write); + return total_write; +} - return rot +/** + * Open flash file \param *fd + * \param name and \param mode are unused, cause flash memory is + * threated like one file. + */ +bool prog_open(struct _KFile *fd, UNUSED_ARG(const char *, name), UNUSED_ARG(int, mode)) +{ + curr_page = 0; + memcpy_P(page_buf, (const char *)(curr_page * SPM_PAGESIZE), SPM_PAGESIZE); + + fd->seek_pos = 0; + fd->size = (uint16_t)(FLASHEND - CONFIG_BOOT_SIZE + 1); + page_modified = false; + + kprintf("Flash file opened\n"); + return true; +} + +/** + * Close file \param *fd + */ +bool prog_close(UNUSED_ARG(struct _KFile *,fd)) +{ + prog_flush(); + kprintf("Flash file closed\n"); + return true; } + +/** + * Move \param *fd file seek position of \param offset bytes + * from current position. + */ +bool prog_seek(struct _KFile *fd, int32_t offset) +{ + ASSERT(fd->seek_pos + offset <= fd->size); + + /* Bound check */ + if (fd->seek_pos + offset > fd->size) + return false; + + fd->seek_pos += offset; + kprintf("Flash seek to [%d]\n", fd->seek_pos); + + return true; +} + +/** + * Read from file \param *fd \param size bytes and put it in buffer \param *buf + * \return the number of bytes read. + */ +size_t prog_read(struct _KFile *fd, void *buf, size_t size) +{ + ASSERT(fd->seek_pos + size <= fd->size); + size = MIN((uint32_t)size, fd->size - fd->seek_pos); + + kprintf("Reading at pos[%d]\n", fd->seek_pos); + // Flush current buffered page (if modified). + prog_flush(); + + /* + * 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->seek_pos; + + memcpy_P(buf, pgm_addr, size); + fd->seek_pos += size; + kprintf("Read %d bytes\n", size); + return size; +} +