Subversion Repositories HomeAutomation

Rev

Details | Last modification | View Log | SVN | RSS feed

Rev Author Line No. Line
228 andfri 1
#include <avr/interrupt.h>
2
#include <avr/boot.h>
3
#include <avr/pgmspace.h>
283 andfri 4
#include <avr/wdt.h>
228 andfri 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
 
233 andfri 28
    flash_buffer_dirty = 0;
29
 
228 andfri 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
 
254 andfri 39
#ifdef FLASH_LOAD_BUFFER
40
void flash_load_buffer(uint16_t addr) BOOTLOADER;
228 andfri 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.)
283 andfri 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.
228 andfri 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
    }
254 andfri 59
}
60
#endif
228 andfri 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();
254 andfri 66
#ifdef FLASH_LOAD_BUFFER
228 andfri 67
        flash_load_buffer(addr);
254 andfri 68
#endif
228 andfri 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
}
254 andfri 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();
283 andfri 85
    cli(); // From this point we're on our own
254 andfri 86
    for (i = 0; i < len; i+=2) {
87
        flash_write_word(dst + i, pgm_read_word(src + i));
283 andfri 88
        wdt_reset();
254 andfri 89
    }
90
    flash_flush_buffer();
283 andfri 91
    while (1); // Nothing more we can do, hopefully there is a watchdog active
254 andfri 92
}
93
#endif