From: batt Date: Tue, 18 Sep 2007 09:51:09 +0000 (+0000) Subject: Merge from triface. X-Git-Tag: 1.0.0~432 X-Git-Url: https://codewiz.org/gitweb?a=commitdiff_plain;h=732f02c7bf4bb42dec29af588556a76bde861508;p=bertos.git Merge from triface. git-svn-id: https://src.develer.com/svnoss/bertos/trunk@809 38d2e660-2303-0410-9eaa-f027e97ec537 --- diff --git a/mware/prog.c b/mware/prog.c new file mode 100755 index 00000000..bd76ac95 --- /dev/null +++ b/mware/prog.c @@ -0,0 +1,144 @@ +/** + * \file + * + * + * \brief Flash memory programmar interface. + * + * \version $Id$ + * \author Stefano Fedrigo + * \author Francesco Sacchi + * \author Daniele Basile + */ + +#include "prog.h" + +#include + +#include +#include +#include + +#include + +/* + * Include platform-specific binding code if we're hosted. + * Try the CPU specific one for bare-metal environments. + */ +#if OS_HOSTED + #include OS_CSOURCE(prog) +#else + #include CPU_CSOURCE(prog) +#endif + + +#define TEST_SIZE 683 +#define ONE_BYTE_TEST_ADDRESS 347 + +uint8_t test_buf[TEST_SIZE]; +uint8_t save_buf[TEST_SIZE]; + +/** + * Program memory read/write subtest. + * Try to write/read in the same file location \param _size bytes. + * \return true if all is ok, false otherwise + * \note Restore file position at exit (if no error) + * \note Test buffer \param buf must be filled with + * the following statement: + *
+ * buf[i] = i & 0xff
+ * 
+ */ +static bool prog_rwTest(KFile *f, uint8_t *buf, size_t _size) +{ + int32_t size = _size; + // Write test buffer + if (f->write(f, buf, size) != size) + return false; + f->seek(f, -size); + + // Reset test buffer + memset(buf, 0, size); + + // Read flash in test buffer + if (f->read(f, buf, size) != size) + return false; + f->seek(f, -size); + + // Check test result + for (size_t i = 0; i < size; i++) + if (buf[i] != (i & 0xff)) + return false; + + return true; +} + +/** + * Test for program memory read/write. + */ +bool prog_test(void) +{ + KFile fd; + + // Set up flash programming functions. + fd.open = prog_open; + fd.close = prog_close; + fd.read = prog_read; + fd.write = prog_write; + fd.seek = prog_seek; + + // Fill in test buffer + for (int i = 0; i < TEST_SIZE; i++) + test_buf[i] = (i & 0xff); + + // Open flash + fd.open(&fd, NULL, 0); + // Save flash content (for later restore). + fd.read(&fd, save_buf, sizeof(save_buf)); + fd.seek(&fd, -TEST_SIZE); + + // Test flash read/write to address 0..TEST_SIZE + if (!prog_rwTest(&fd, test_buf, TEST_SIZE)) + goto prog_test_end; + + // One byte read/write test + fd.seek(&fd, ONE_BYTE_TEST_ADDRESS); // Random address + if (!prog_rwTest(&fd, test_buf, 1)) + goto prog_test_end; + fd.seek(&fd, -(int32_t)ONE_BYTE_TEST_ADDRESS); + + // Restore old flash data + if (fd.write(&fd, save_buf, sizeof(test_buf)) != TEST_SIZE) + goto prog_test_end; + fd.seek(&fd, -TEST_SIZE); + + // Go to the Flash end + fd.seek(&fd, fd.size - TEST_SIZE); + // Save flash content (for later restore). + fd.read(&fd, save_buf, sizeof(save_buf)); + fd.seek(&fd, -TEST_SIZE); + + // Test flash read/write to address (FLASHEND - TEST_SIZE) ... FLASHEND + if (!prog_rwTest(&fd, test_buf, TEST_SIZE)) + goto prog_test_end; + + // Go to half test size. + fd.seek(&fd, (TEST_SIZE / 2)); + + // This test should FAIL, cause we try to write over file end. + if (prog_rwTest(&fd, test_buf, TEST_SIZE)) + goto prog_test_end; + + fd.seek(&fd, -TEST_SIZE); + // Restore old flash data + fd.write(&fd, save_buf, TEST_SIZE); + + fd.close(&fd); + return true; + +prog_test_end: + fd.close(&fd); + return false; +} diff --git a/mware/prog.h b/mware/prog.h index ee9c6cae..76685c87 100755 --- a/mware/prog.h +++ b/mware/prog.h @@ -1,17 +1,17 @@ /** * \file * * * \brief Generic program read/write routines interface - * + * * This module implements an interface function for programming * a CPU flash memory. To guarantee correct memory writing, we * use a rotating hash algorithm. - * - * + * + * * \version $Id$ * \author Francesco Sacchi * \author Daniele Basile @@ -22,23 +22,18 @@ #include #include -#include - -/** - * Generic interface of progress status function. - * \param value is current progress value - * \param max is max progress value - * \return True if programming should continue - * \return False to stop programming - */ -typedef bool (*progress_func_t) (int value, int max); /** - * Generic interface for programming a CPU flash memory. - * \param *file is the Kfile pointer to write - * \param progress is progress fuction pointer, can be NULL if not used - * \return rotating hash of file written + * Prototype of function for manage read/write on + * flash memory. + *\{ */ -rotating_t prog_write(struct _KFile *file, progress_func_t progress); +size_t prog_write(struct _KFile *fd, const void *buf, size_t size); +bool prog_open(struct _KFile *fd, UNUSED_ARG(const char *, name), UNUSED_ARG(int, mode)); +bool prog_close(struct _KFile *fd); +bool prog_seek(struct _KFile *fd, int32_t offset); +size_t prog_read(struct _KFile *fd, void *buf, size_t size); +bool prog_test(void); +/* \} */ #endif /* PROG_H */ diff --git a/mware/prog_avr.c b/mware/prog_avr.c index 70dd1741..39b6806a 100755 --- a/mware/prog_avr.c +++ b/mware/prog_avr.c @@ -1,7 +1,7 @@ /** * \file * * @@ -9,180 +9,211 @@ * * \version $Id$ * \author Francesco Sacchi + * \author Daniele Basile */ #include "prog.h" + +#include + #include #include // MIN() #include -#include -#include -#include -#include +#include -#define PAGEBUF 512 +#include +#include +#include -typedef uint16_t page_addr_t; -typedef uint16_t page_t; +typedef uint16_t avr_page_addr_t; +typedef uint16_t avr_page_t; /** - * Temporary buffer for cointain data block to + * Temporary buffer cointaing data block to * write on flash. */ -static uint8_t page_buf[PAGEBUF]; +static uint8_t page_buf[SPM_PAGESIZE]; + +bool page_modified; /// Flag for checking if current page is modified. /** - * Store current flash page memory in use. + * Current buffered page. */ -static page_t curr_pag_num = 0; - - +static avr_page_t curr_page = 0; /** - * Erase Flash. + * Write current buffered page in flash memory (if modified). + * This function erase flash memory page before writing. */ -static void prog_erase_flash(void) +static void prog_flush(void) { - uint32_t flash_addr; + if (page_modified) + { + kprintf("Flushing page %d\n", curr_page); - /* 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; + boot_spm_busy_wait(); // Wait while the SPM instruction is busy. - for (flash_addr = 0; (flash_addr < (uint16_t)(APP_END & 0xFFFF)) | (RAMPZ == 0x00)); + 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(); - - /* Page erase */ - write_page(flash_addr, BV(PGERS) + BV(SPMEN)); - - /* Re-enable the RWW section */ - write_page(flash_addr, BV(REENABLE_RWW_BIT) + BV(SPMEN)); + uint16_t word = ((uint16_t)page_buf[page_addr + 1] << 8) | page_buf[page_addr]; - /* Last section on lower 64k segment is erased */ - if(flashgg_addr >= (0xFFFF - PAGESIZE)) - - /* RAMPZ has to be incremented into upper 64k segment */ - RAMPZ = BV(RAMPZ0); + ATOMIC(boot_page_fill(page_addr, word)); } - RAMPZ = 0x00; - #else /* LARGE_MEMORY */ - /* Application section = 60 pages */ - for (flash_addr = 0; flash_addr < APP_END; flash_addr += PAGESIZE) - { - wdt_reset(); + kprintf("Done.\n"); - /* Page erase */ - write_page(flash_addr, BV(PGERS) + BV(SPMEN)); - /* Re-enable RWW section */ - write_page(flash_addr, BV(REENABLE_RWW_BIT) + BV(SPMEN)); - } - #endif /* LARGE_MEMORY */ -} + wdt_reset(); + kprintf("Erasing page, addr %d...", curr_page * SPM_PAGESIZE); -/** - * Write a page in program memory. - */ -static void prog_pagewrite(uint16_t addr) -{ - write_page(addr, BV(PGWRT) + BV(SPMEN)); + /* Page erase */ + ATOMIC(boot_page_erase(curr_page * SPM_PAGESIZE)); - /* Re-enable the RWW section */ - write_page(addr, BV(REENABLE_RWW_BIT) + BV(SPMEN)); -} + /* Wait until the memory is erased. */ + boot_spm_busy_wait(); + kprintf("Done.\n"); + kprintf("Writing page, addr %d...", curr_page * SPM_PAGESIZE); -/** - * Delete a page in program memory. - */ -static void prog_pagedelete(uint16_t addr) -{ - /* Page erase */ - write_page(addr, BV(PGERS) + BV(SPMEN)); + /* Store buffer in flash page. */ + ATOMIC(boot_page_write(curr_page * SPM_PAGESIZE)); + boot_spm_busy_wait(); // Wait while the SPM instruction is busy. - /* Re-enable the RWW section */ - write_page(addr, BV(REENABLE_RWW_BIT) + BV(SPMEN)); + /* + * 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"); + } } + /** - * Flush temporary buffer into flash memory. + * Check current page and if \param page is different, load it in + * temporary buffer. */ -static void prog_flush(void) +static void prog_loadPage(avr_page_t page) { - - /* Fill the temporary buffer of the AVR */ - for (page_addr_t page_addr = 0; page_addr < PAGEBUF; page_addr += 2) - fill_temp_buffer(page_buf[page_addr + 1] | (uint16_t)page_buf[page_addr] << 8, page_addr); - - - wdt_reset(); - - /* Page delete */ - prog_pagedelete(curr_page_num * PAGEBUF); - - /* Page write */ - prog_pagewrite(curr_page_num * PAGEBUF); + 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. - * This function to write on flash memory load a selected page from - * flash memory and save it in temporary buffer. Them update temporary buffer - * with \param buf data. We write in flash memory everery time we - * change current page memory. - * + * Write \param size bytes from buffer \param buf to file \param *fd + * \note Write operations are buffered. */ -size_t prog_write(struct _KFile *fd, const char *buf, size_t size) +size_t prog_write(struct _KFile *fd, const void *_buf, size_t size) { + const uint8_t *buf =(const uint8_t *)_buf; - page_t page; - page_addr_t page_addr; + avr_page_t page; + avr_page_addr_t page_addr; size_t total_write = 0; - size_t wr_len; + 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) { - /* Current page memory */ - page = fd->SeekPos / PAGEBUF; - - /* Address in page memory */ - page_addr = fd->SeekPos % PAGEBUF; + page = fd->seek_pos / SPM_PAGESIZE; + page_addr = fd->seek_pos % SPM_PAGESIZE; prog_loadPage(page); - wr_len = MIN(size, PAGEBUF - page_addr); + 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->SeekPos += wr_len; + fd->seek_pos += wr_len; size -= wr_len; total_write += wr_len; } - /* Return total byte write on flash memory */ + kprintf("written %d bytes\n", total_write); return total_write; } +/** + * 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; +} /** - * Load select \param page memory buffer from AVR flash memory. - * If select page is not current page, we flush it, and then we load - * select page memory flash. + * Close file \param *fd */ -void prog_loadPage(page_t page) +bool prog_close(UNUSED_ARG(struct _KFile *,fd)) { - if (page != curr_page_num) - { - prog_flush(); - /* Load selet page in temporary buffer store into RAM */ - memcpy_P(page_buf, (const char *)(page * PAGEBUF), PAGEBUF); - /* Update current page */ - curr_page_num = page; - } + 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; +} +