Subversion Repositories HomeAutomation

Rev

Rev 309 | Blame | Last modification | View Log | SVN | RSS feed

  1. #include <avr/interrupt.h>
  2. #include <avr/boot.h>
  3. #include <avr/pgmspace.h>
  4. #include <avr/wdt.h>
  5. #include "flash.h"
  6.  
  7. static uint16_t flash_prev_addr;
  8. static uint8_t flash_buffer_dirty = 0;
  9.  
  10. void flash_flush_buffer() {
  11.     uint8_t sreg;
  12.    
  13.     if (!flash_buffer_dirty) return; // Nothing to flush
  14.    
  15.     // Disable interrupts.
  16.    
  17.     sreg = SREG;
  18.     cli();
  19.    
  20.     eeprom_busy_wait();
  21.    
  22.     boot_page_erase(flash_prev_addr);
  23.     boot_spm_busy_wait();      // Wait until the memory is erased.
  24.    
  25.     boot_page_write(flash_prev_addr);     // Store buffer in flash page.
  26.     boot_spm_busy_wait();       // Wait until the memory is written.
  27.  
  28.     flash_buffer_dirty = 0;
  29.  
  30.     // Reenable RWW-section again. We need this if we want to jump back
  31.     // to the application after bootloading.
  32.  
  33.     boot_rww_enable ();
  34.     // Re-enable interrupts (if they were ever enabled).
  35.  
  36.     SREG = sreg;
  37. }
  38.  
  39. #ifdef FLASH_LOAD_BUFFER
  40. void flash_load_buffer(uint16_t addr) BOOTLOADER;
  41. void flash_load_buffer(uint16_t addr) {
  42.     //TODO: Load current flash page contents into temporary buffer to implement
  43.     // flash read-modify-writes with word granularity. (If possible, the data
  44.     // sheet is a little fuzzy about this.)
  45.     // Update: It seems it isn't possible to write any location in the temporary
  46.     // buffer more than once without destroying the buffer. To implement this
  47.     // functionality, a sram based buffer is probably neccessary. Problem is,
  48.     // how should it be allocated? A global buffer uses valuable .bss space.
  49.     // All functions should probably take a pointer to a buffer allocated by
  50.     // main code.
  51.     uint8_t i;
  52.     uint16_t data;
  53.     uint16_t page = (addr / SPM_PAGESIZE) * SPM_PAGESIZE;
  54.    
  55.     for (i = 0; i < SPM_PAGESIZE; i += 2) {
  56.         data = pgm_read_word(page + i);
  57.         boot_page_fill(page + i, data);
  58.     }
  59. }
  60. #endif
  61.  
  62. void flash_write_word(uint16_t addr, uint16_t word) {
  63.    
  64.     if ((addr / SPM_PAGESIZE) != (flash_prev_addr / SPM_PAGESIZE)) {
  65.         flash_flush_buffer();
  66. #ifdef FLASH_LOAD_BUFFER
  67.         flash_load_buffer(addr);
  68. #endif
  69.     }
  70.    
  71.     boot_page_fill(addr, word);
  72.     flash_prev_addr = addr;
  73.     flash_buffer_dirty = 1;
  74. }    
  75.  
  76. void flash_init() {
  77.     flash_prev_addr = 0xffff;
  78.     flash_buffer_dirty = 0;
  79. }
  80.  
  81. #ifdef FLASH_COPY_DATA
  82. void flash_copy_data(uint16_t src, uint16_t dst, uint16_t len) {
  83.     uint16_t i;
  84.     flash_init();
  85.     cli(); // From this point we're on our own
  86.     for (i = 0; i < len; i+=2) {
  87.         flash_write_word(dst + i, pgm_read_word(src + i));
  88.         wdt_reset();
  89.     }
  90.     flash_flush_buffer();
  91.     while (1); // Nothing more we can do, hopefully there is a watchdog active
  92. }
  93. #endif
  94.  
  95. #ifdef FLASH_COPY_DATA_NEW
  96. extern uint16_t __flash_code_start;
  97.  
  98. void flash_copy_data(uint16_t src, uint16_t dst, uint16_t len) {
  99. #if 0
  100.     uint16_t offset;
  101. #endif
  102.     uint16_t data;
  103.  
  104.     eeprom_busy_wait();     // Make sure any current writes to eeprom
  105.     boot_spm_busy_wait();   // or flash has completed before updating.
  106.  
  107.     cli(); // From this point we're on our own
  108.    
  109. #if 0
  110.     for (offset = 0; offset < ((len | (SPM_PAGESIZE - 1)) + 1); offset += 2) {
  111.         if (dst + offset >= (uint16_t)&__flash_code_start) break;
  112.         data = pgm_read_word(src + offset);
  113.         boot_page_fill(dst + offset, data);
  114.         if ((dst + offset + 2) % SPM_PAGESIZE == 0) {
  115.             boot_page_erase(dst + offset);
  116.             boot_spm_busy_wait();      // Wait until the memory is erased.
  117.            
  118.             boot_page_write(dst + offset);     // Store buffer in flash page.
  119.             boot_spm_busy_wait();       // Wait until the memory is written.
  120.         }
  121.            
  122.         wdt_reset();
  123.     }
  124. #else
  125.     len = (len | (SPM_PAGESIZE - 1)) + 3; // Round len up to a whole page + 2
  126.    
  127.     while (len -= 2) {
  128.         wdt_reset();
  129.  
  130.         data = pgm_read_word(src); // Read source word
  131.         boot_page_fill_safe(dst, data); // Write word to destination
  132.         boot_spm_busy_wait();      // Make sure spm is ready.
  133.        
  134.         if (((uint8_t)dst + 2) % SPM_PAGESIZE == 0) { // If we just wrote the last word of a page
  135.             boot_page_erase(dst);
  136.             boot_spm_busy_wait(); // Wait until the memory is erased.
  137.             boot_page_write(dst); // Store buffer in flash page.
  138.             boot_spm_busy_wait(); // Wait until the memory is written.
  139.             boot_rww_enable();
  140.         }
  141.          
  142.         src += 2;
  143.         dst += 2;
  144.     }
  145.          
  146. #endif
  147.     while (1); // Nothing more we can do, hopefully there is a watchdog active
  148. }
  149. #endif
  150.