flash_avr.c
Go to the documentation of this file.00001
00045 #include "flash_avr.h"
00046
00047 #include "cfg/cfg_flash_avr.h"
00048 #include <cfg/macros.h>
00049 #include <cfg/compiler.h>
00050 #include <cfg/debug.h>
00051 #include <cpu/irq.h>
00052
00053
00054 #define LOG_LEVEL CONFIG_FLASH_AVR_LOG_LEVEL
00055 #define LOG_FORMAT CONFIG_FLASH_AVR_LOG_FORMAT
00056 #include <cfg/log.h>
00057
00058 #include <drv/wdt.h>
00059
00060 #include <kern/kfile.h>
00061
00062 #include <avr/io.h>
00063 #include <avr/boot.h>
00064 #include <avr/pgmspace.h>
00065
00066 #include <string.h>
00067
00068
00072 typedef uint16_t avr_page_addr_t;
00073
00074
00075
00076
00085 static void flash_avr_flush(FlashAvr *fd)
00086 {
00087 if (fd->page_dirty)
00088 {
00089
00090 LOG_INFO("Flushing page %d\n", fd->curr_page);
00091
00092
00093 boot_spm_busy_wait();
00094
00095 LOG_INFO("Filling temparary page buffer...");
00096
00097
00098 for (avr_page_addr_t page_addr = 0; page_addr < SPM_PAGESIZE; page_addr += 2)
00099 {
00100 uint16_t word = ((uint16_t)fd->page_buf[page_addr + 1] << 8) | fd->page_buf[page_addr];
00101
00102 ATOMIC(boot_page_fill(page_addr, word));
00103 }
00104 LOG_INFO("Done.\n");
00105
00106 wdt_reset();
00107
00108 LOG_INFO("Erasing page, addr %u...", fd->curr_page * SPM_PAGESIZE);
00109
00110
00111 ATOMIC(boot_page_erase(fd->curr_page * SPM_PAGESIZE));
00112
00113
00114 boot_spm_busy_wait();
00115
00116 LOG_INFO("Done.\n");
00117 LOG_INFO("Writing page, addr %u...", fd->curr_page * SPM_PAGESIZE);
00118
00119
00120 ATOMIC(boot_page_write(fd->curr_page * SPM_PAGESIZE));
00121 boot_spm_busy_wait();
00122
00123
00124
00125
00126
00127 ATOMIC(boot_rww_enable());
00128
00129 fd->page_dirty = false;
00130 LOG_INFO("Done.\n");
00131 }
00132 }
00133
00134
00141 static int flash_avr_kfileFlush(struct KFile *_fd)
00142 {
00143 FlashAvr *fd = FLASHAVR_CAST(_fd);
00144 flash_avr_flush(fd);
00145 return 0;
00146 }
00147
00148
00153 static void flash_avr_loadPage(FlashAvr *fd, avr_page_t page)
00154 {
00155 if (page != fd->curr_page)
00156 {
00157 flash_avr_flush(fd);
00158
00159 memcpy_P(fd->page_buf, (const char *)(page * SPM_PAGESIZE), SPM_PAGESIZE);
00160 fd->curr_page = page;
00161 LOG_INFO("Loaded page %d\n", fd->curr_page);
00162 }
00163 }
00164
00170 static size_t flash_avr_write(struct KFile *_fd, const void *_buf, size_t size)
00171 {
00172 FlashAvr *fd = FLASHAVR_CAST(_fd);
00173 const uint8_t *buf =(const uint8_t *)_buf;
00174
00175 avr_page_t page;
00176 avr_page_addr_t page_addr;
00177 size_t total_write = 0;
00178
00179
00180 ASSERT(fd->fd.seek_pos + (kfile_off_t)size <= (kfile_off_t)fd->fd.size);
00181 size = MIN((kfile_off_t)size, fd->fd.size - fd->fd.seek_pos);
00182
00183 LOG_INFO("Writing at pos[%u]\n", fd->fd.seek_pos);
00184 while (size)
00185 {
00186 page = fd->fd.seek_pos / SPM_PAGESIZE;
00187 page_addr = fd->fd.seek_pos % SPM_PAGESIZE;
00188
00189 flash_avr_loadPage(fd, page);
00190
00191 size_t wr_len = MIN(size, SPM_PAGESIZE - page_addr);
00192 memcpy(fd->page_buf + page_addr, buf, wr_len);
00193 fd->page_dirty = true;
00194
00195 buf += wr_len;
00196 fd->fd.seek_pos += wr_len;
00197 size -= wr_len;
00198 total_write += wr_len;
00199 }
00200 LOG_INFO("written %u bytes\n", total_write);
00201 return total_write;
00202 }
00203
00209 static void flash_avr_open(struct FlashAvr *fd)
00210 {
00211 fd->curr_page = 0;
00212 memcpy_P(fd->page_buf, (const char *)(fd->curr_page * SPM_PAGESIZE), SPM_PAGESIZE);
00213
00214 fd->fd.seek_pos = 0;
00215 fd->fd.size = (uint16_t)(FLASHEND - CONFIG_FLASH_AVR_BOOTSIZE + 1);
00216 fd->page_dirty = false;
00217
00218 LOG_INFO("Flash file opened\n");
00219 }
00220
00224 static int flash_avr_close(struct KFile *_fd)
00225 {
00226 FlashAvr *fd = FLASHAVR_CAST(_fd);
00227 flash_avr_flush(fd);
00228 LOG_INFO("Flash file closed\n");
00229 return 0;
00230 }
00231
00235 static struct KFile *flash_avr_reopen(struct KFile *fd)
00236 {
00237 FlashAvr *_fd = FLASHAVR_CAST(fd);
00238 flash_avr_close(fd);
00239 flash_avr_open(_fd);
00240 return fd;
00241 }
00242
00243
00248 static size_t flash_avr_read(struct KFile *_fd, void *buf, size_t size)
00249 {
00250 FlashAvr *fd = FLASHAVR_CAST(_fd);
00251 ASSERT(fd->fd.seek_pos + (kfile_off_t)size <= (kfile_off_t)fd->fd.size);
00252 size = MIN((kfile_off_t)size, fd->fd.size - fd->fd.seek_pos);
00253
00254 LOG_INFO("Reading at pos[%u]\n", fd->fd.seek_pos);
00255
00256 flash_avr_flush(fd);
00257
00258
00259
00260
00261
00262 const uint8_t *pgm_addr = (const uint8_t *)0;
00263 pgm_addr += fd->fd.seek_pos;
00264
00265 memcpy_P(buf, pgm_addr, size);
00266 fd->fd.seek_pos += size;
00267 LOG_INFO("Read %u bytes\n", size);
00268 return size;
00269 }
00270
00274 void flash_avr_init(struct FlashAvr *fd)
00275 {
00276 memset(fd, 0, sizeof(*fd));
00277 DB(fd->fd._type = KFT_FLASHAVR);
00278
00279
00280 fd->fd.reopen = flash_avr_reopen;
00281 fd->fd.close = flash_avr_close;
00282 fd->fd.read = flash_avr_read;
00283 fd->fd.write = flash_avr_write;
00284 fd->fd.seek = kfile_genericSeek;
00285 fd->fd.flush = flash_avr_kfileFlush;
00286 fd->curr_page = 0;
00287
00288 flash_avr_open(fd);
00289 }
00290
00291