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