Subversion Repositories HomeAutomation

Rev

Rev 378 | Blame | Compare with Previous | 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. static uint8_t* flash_pagebuf;
  10.  
  11. void flash_flush_buffer() {
  12.     uint8_t sreg;
  13.     uint16_t word;
  14.     uint8_t i;
  15.     uint16_t* buf = (uint16_t*)flash_pagebuf; // Access buffer on a word basis.
  16.    
  17.     if (!flash_buffer_dirty) return; // Nothing to flush.
  18.    
  19.     // Copy the sram buffer to the temporary page buffer.
  20.     for (i = 0; i < SPM_PAGESIZE/2; i++) {
  21.         word = buf[i];
  22.         boot_page_fill(i*2, word); // Absolute addressing is not neccessary.
  23.     }
  24.    
  25.     // Disable interrupts.
  26.     sreg = SREG;
  27.     cli();
  28.    
  29.     eeprom_busy_wait(); // Make sure any eeprom access has finished.
  30.    
  31.     boot_page_erase(flash_prev_addr);
  32.     boot_spm_busy_wait();  // Wait until the memory is erased.
  33.    
  34.     boot_page_write(flash_prev_addr); // Store buffer in flash page.
  35.     boot_spm_busy_wait();  // Wait until the memory is written.
  36.  
  37.     flash_buffer_dirty = 0;
  38.  
  39.     // Reenable RWW-section again so we can return to BIOS after flashing.
  40.     boot_rww_enable ();
  41.    
  42.     // Re-enable interrupts (if they were ever enabled).
  43.     SREG = sreg;
  44. }
  45.  
  46. void flash_load_buffer(uint16_t addr) {
  47.     uint8_t i;
  48.     uint8_t byte;
  49.     uint16_t page = (addr / SPM_PAGESIZE) * SPM_PAGESIZE;
  50.    
  51.     // Load current flash page contents into sram page buffer to implement
  52.     // flash read-modify-writes with word granularity.
  53.     for (i = 0; i < SPM_PAGESIZE; i++) {
  54.         byte = pgm_read_byte(page + i);
  55.         flash_pagebuf[i] = byte;
  56.     }
  57. }
  58.  
  59. void flash_write_word(uint16_t addr, uint16_t word) {
  60.     uint16_t* buf = (uint16_t*)flash_pagebuf; // Access buffer on a word basis.
  61.    
  62.     // Check if page address has changed since last write
  63.     if ((addr / SPM_PAGESIZE) != (flash_prev_addr / SPM_PAGESIZE)) {
  64.         flash_flush_buffer(); // Flash buffer contents to previous page
  65.         flash_load_buffer(addr); // Read new page contents into buffer
  66.     }
  67.    
  68.     buf[(addr % SPM_PAGESIZE)/2] = word;
  69.     flash_prev_addr = addr;
  70.     flash_buffer_dirty = 1;
  71. }    
  72.  
  73. void flash_init(uint8_t* buf) {
  74.     // 0xffff is never in any page that can be written on devices with <= 64K flash,
  75.     // so the first flash_write_word will always trigger a buffer load.
  76.     flash_prev_addr = 0xffff;
  77.     flash_pagebuf = buf;
  78.     flash_buffer_dirty = 0;
  79. }
  80.  
  81. extern void __flash_code_start; // Start of .flash_code from ld-script
  82.  
  83. void flash_copy_data(uint16_t src, uint16_t dst, uint16_t len) {
  84.     uint16_t data;
  85.  
  86.     cli(); // From this point we're on our own
  87.    
  88.     len = (len | (SPM_PAGESIZE - 1)) + 3; // Round len up to a whole page + 2
  89.    
  90.     while (len -= 2) {
  91.         if (dst >= (uint16_t)&__flash_code_start) break;
  92.  
  93.         wdt_reset();
  94.  
  95.         data = pgm_read_word(src); // Read source word
  96.         boot_page_fill(dst, data); // Write word to destination
  97.        
  98.         if ((dst + 2) % SPM_PAGESIZE == 0) { // If we just wrote the last word of a page
  99.             boot_page_erase(dst);
  100.             boot_spm_busy_wait(); // Wait until the memory is erased.
  101.             boot_page_write(dst); // Store buffer in flash page.
  102.             boot_spm_busy_wait(); // Wait until the memory is written.
  103.             boot_rww_enable();
  104.         }
  105.          
  106.         src += 2;
  107.         dst += 2;      
  108.     }
  109.  
  110.     while (1); // Nothing more we can do, hopefully there is a watchdog active
  111. }
  112.