flash_avr.c
Go to the documentation of this file.00001
00045 #include "flash_avr.h"
00046
00047 #include <avr/io.h>
00048 #include <avr/boot.h>
00049 #include <avr/pgmspace.h>
00050
00051 #include <cfg/macros.h>
00052 #include <cfg/compiler.h>
00053 #include <cfg/debug.h>
00054 #include <cpu/irq.h>
00055
00056 #include <drv/wdt.h>
00057
00058 #include <kern/kfile.h>
00059
00060 #include <string.h>
00061
00065 typedef uint16_t avr_page_addr_t;
00066 typedef uint16_t avr_page_t;
00067
00072 static uint8_t page_buf[SPM_PAGESIZE];
00073
00077 bool page_modified;
00078
00082 static avr_page_t curr_page = 0;
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092 static void flash_avr_flush(void)
00093 {
00094 if (page_modified)
00095 {
00096 kprintf("Flushing page %d\n", curr_page);
00097
00098
00099 boot_spm_busy_wait();
00100
00101 kprintf("Filling temparary page buffer...");
00102
00103
00104 for (avr_page_addr_t page_addr = 0; page_addr < SPM_PAGESIZE; page_addr += 2)
00105 {
00106 uint16_t word = ((uint16_t)page_buf[page_addr + 1] << 8) | page_buf[page_addr];
00107
00108 ATOMIC(boot_page_fill(page_addr, word));
00109 }
00110 kprintf("Done.\n");
00111
00112 wdt_reset();
00113
00114 kprintf("Erasing page, addr %u...", curr_page * SPM_PAGESIZE);
00115
00116
00117 ATOMIC(boot_page_erase(curr_page * SPM_PAGESIZE));
00118
00119
00120 boot_spm_busy_wait();
00121
00122 kprintf("Done.\n");
00123 kprintf("Writing page, addr %u...", curr_page * SPM_PAGESIZE);
00124
00125
00126 ATOMIC(boot_page_write(curr_page * SPM_PAGESIZE));
00127 boot_spm_busy_wait();
00128
00129
00130
00131
00132
00133 ATOMIC(boot_rww_enable());
00134
00135 page_modified = false;
00136 kprintf("Done.\n");
00137 }
00138 }
00139
00140
00147 static int flash_avr_kfileFlush(struct KFile * fd)
00148 {
00149 KFILE_ASSERT_GENERIC(fd);
00150 (void)fd;
00151 flash_avr_flush();
00152 return 0;
00153 }
00154
00155
00160 static void flash_avr_loadPage(avr_page_t page)
00161 {
00162 if (page != curr_page)
00163 {
00164 flash_avr_flush();
00165
00166 memcpy_P(page_buf, (const char *)(page * SPM_PAGESIZE), SPM_PAGESIZE);
00167 curr_page = page;
00168 kprintf("Loaded page %d\n", curr_page);
00169 }
00170 }
00171
00177 static size_t flash_avr_write(struct KFile *fd, const void *_buf, size_t size)
00178 {
00179 KFILE_ASSERT_GENERIC(fd);
00180 const uint8_t *buf =(const uint8_t *)_buf;
00181
00182 avr_page_t page;
00183 avr_page_addr_t page_addr;
00184 size_t total_write = 0;
00185
00186 ASSERT(fd->seek_pos + size <= fd->size);
00187 size = MIN((uint32_t)size, fd->size - fd->seek_pos);
00188
00189 kprintf("Writing at pos[%u]\n", fd->seek_pos);
00190 while (size)
00191 {
00192 page = fd->seek_pos / SPM_PAGESIZE;
00193 page_addr = fd->seek_pos % SPM_PAGESIZE;
00194
00195 flash_avr_loadPage(page);
00196
00197 size_t wr_len = MIN(size, SPM_PAGESIZE - page_addr);
00198 memcpy(page_buf + page_addr, buf, wr_len);
00199 page_modified = true;
00200
00201 buf += wr_len;
00202 fd->seek_pos += wr_len;
00203 size -= wr_len;
00204 total_write += wr_len;
00205 }
00206 kprintf("written %u bytes\n", total_write);
00207 return total_write;
00208 }
00209
00215 static void flash_avr_open(struct KFile *fd)
00216 {
00217 KFILE_ASSERT_GENERIC(fd);
00218 curr_page = 0;
00219 memcpy_P(page_buf, (const char *)(curr_page * SPM_PAGESIZE), SPM_PAGESIZE);
00220
00221 fd->seek_pos = 0;
00222 fd->size = (uint16_t)(FLASHEND - CONFIG_BOOT_SIZE + 1);
00223 page_modified = false;
00224
00225 kprintf("Flash file opened\n");
00226 }
00227
00231 static int flash_avr_close(UNUSED_ARG(struct KFile *,fd))
00232 {
00233 KFILE_ASSERT_GENERIC(fd);
00234 flash_avr_flush();
00235 kprintf("Flash file closed\n");
00236 return 0;
00237 }
00238
00242 static struct KFile *flash_avr_reopen(struct KFile *fd)
00243 {
00244 KFILE_ASSERT_GENERIC(fd);
00245 flash_avr_close(fd);
00246 flash_avr_open(fd);
00247 return fd;
00248 }
00249
00250
00255 static size_t flash_avr_read(struct KFile *fd, void *buf, size_t size)
00256 {
00257 KFILE_ASSERT_GENERIC(fd);
00258 ASSERT(fd->seek_pos + size <= fd->size);
00259 size = MIN((uint32_t)size, fd->size - fd->seek_pos);
00260
00261 kprintf("Reading at pos[%u]\n", fd->seek_pos);
00262
00263 flash_avr_flush();
00264
00265
00266
00267
00268
00269 const uint8_t *pgm_addr = (const uint8_t *)0;
00270 pgm_addr += fd->seek_pos;
00271
00272 memcpy_P(buf, pgm_addr, size);
00273 fd->seek_pos += size;
00274 kprintf("Read %u bytes\n", size);
00275 return size;
00276 }
00277
00281 void flash_avr_init(struct KFile *fd)
00282 {
00283 memset(fd, 0, sizeof(*fd));
00284 DB(fd->_type = KFT_GENERIC);
00285
00286
00287 fd->reopen = flash_avr_reopen;
00288 fd->close = flash_avr_close;
00289 fd->read = flash_avr_read;
00290 fd->write = flash_avr_write;
00291 fd->seek = kfile_genericSeek;
00292 fd->flush = flash_avr_kfileFlush;
00293
00294 flash_avr_open(fd);
00295 }
00296