Subversion Repositories HomeAutomation

Rev

Rev 311 | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | SVN | RSS feed

Rev 311 Rev 315
Line 4... Line 4...
4
#include <avr/wdt.h>
4
#include <avr/wdt.h>
5
#include "flash.h"
5
#include "flash.h"
6
 
6
 
7
static uint16_t flash_prev_addr;
7
static uint16_t flash_prev_addr;
8
static uint8_t flash_buffer_dirty = 0;
8
static uint8_t flash_buffer_dirty = 0;
-
 
9
static uint8_t* flash_pagebuf;
9
 
10
 
10
void flash_flush_buffer() {
11
void flash_flush_buffer() {
11
    uint8_t sreg;
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.
12
   
16
   
13
    if (!flash_buffer_dirty) return; // Nothing to flush
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
    }
14
   
24
   
15
    // Disable interrupts.
25
    // Disable interrupts.
16
   
-
 
17
    sreg = SREG;
26
    sreg = SREG;
18
    cli();
27
    cli();
19
   
28
   
20
    eeprom_busy_wait();
29
    eeprom_busy_wait(); // Make sure any eeprom access has finished.
21
   
30
   
22
    boot_page_erase(flash_prev_addr);
31
    boot_page_erase(flash_prev_addr);
23
    boot_spm_busy_wait();      // Wait until the memory is erased.
32
    boot_spm_busy_wait();  // Wait until the memory is erased.
24
   
33
   
25
    boot_page_write(flash_prev_addr);     // Store buffer in flash page.
34
    boot_page_write(flash_prev_addr); // Store buffer in flash page.
26
    boot_spm_busy_wait();       // Wait until the memory is written.
35
    boot_spm_busy_wait();  // Wait until the memory is written.
27
 
36
 
28
    flash_buffer_dirty = 0;
37
    flash_buffer_dirty = 0;
29
 
38
 
30
    // Reenable RWW-section again. We need this if we want to jump back
39
    // Reenable RWW-section again so we can return to BIOS after flashing.
31
    // to the application after bootloading.
-
 
32
 
-
 
33
    boot_rww_enable ();
40
    boot_rww_enable ();
-
 
41
   
34
    // Re-enable interrupts (if they were ever enabled).
42
    // Re-enable interrupts (if they were ever enabled).
35
 
-
 
36
    SREG = sreg;
43
    SREG = sreg;
37
}
44
}
38
 
45
 
39
#ifdef FLASH_LOAD_BUFFER
-
 
40
void flash_load_buffer(uint16_t addr) BOOTLOADER;
-
 
41
void flash_load_buffer(uint16_t addr) {
46
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;
47
    uint8_t i;
52
    uint16_t data;
48
    uint8_t byte;
53
    uint16_t page = (addr / SPM_PAGESIZE) * SPM_PAGESIZE;
49
    uint16_t page = (addr / SPM_PAGESIZE) * SPM_PAGESIZE;
54
   
50
   
-
 
51
    // Load current flash page contents into sram page buffer to implement
-
 
52
    // flash read-modify-writes with word granularity.
55
    for (i = 0; i < SPM_PAGESIZE; i += 2) {
53
    for (i = 0; i < SPM_PAGESIZE; i++) {
56
        data = pgm_read_word(page + i);
54
        byte = pgm_read_byte(page + i);
57
        boot_page_fill(page + i, data);
55
        flash_pagebuf[i] = byte;
58
    }
56
    }
59
}
57
}
60
#endif
-
 
61
 
58
 
62
void flash_write_word(uint16_t addr, uint16_t word) {
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.
63
   
61
   
-
 
62
    // Check if page address has changed since last write
64
    if ((addr / SPM_PAGESIZE) != (flash_prev_addr / SPM_PAGESIZE)) {
63
    if ((addr / SPM_PAGESIZE) != (flash_prev_addr / SPM_PAGESIZE)) {
65
        flash_flush_buffer();
64
        flash_flush_buffer(); // Flash buffer contents to previous page
66
#ifdef FLASH_LOAD_BUFFER
-
 
67
        flash_load_buffer(addr);
65
        flash_load_buffer(addr); // Read new page contents into buffer
68
#endif
-
 
69
    }
66
    }
70
   
67
   
71
    boot_page_fill(addr, word);
68
    buf[addr % SPM_PAGESIZE] = word;
72
    flash_prev_addr = addr;
69
    flash_prev_addr = addr;
73
    flash_buffer_dirty = 1;
70
    flash_buffer_dirty = 1;
74
}    
71
}    
75
 
72
 
76
void flash_init() {
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.
77
    flash_prev_addr = 0xffff;
76
    flash_prev_addr = 0xffff;
-
 
77
    flash_pagebuf = buf;
78
    flash_buffer_dirty = 0;
78
    flash_buffer_dirty = 0;
79
}
79
}
80
 
80
 
81
#ifdef FLASH_COPY_DATA
-
 
82
void flash_copy_data(uint16_t src, uint16_t dst, uint16_t len) {
81
extern void __flash_code_start; // Start of .flash_code from ld-script
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
 
82
 
98
void flash_copy_data(uint16_t src, uint16_t dst, uint16_t len) {
83
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;
84
    uint16_t data;
103
 
85
 
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
86
    cli(); // From this point we're on our own
108
   
87
   
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
            boot_rww_enable();
-
 
121
        }
-
 
122
           
-
 
123
        wdt_reset();
-
 
124
    }
-
 
125
#else
-
 
126
    len = (len | (SPM_PAGESIZE - 1)) + 3; // Round len up to a whole page + 2
88
    len = (len | (SPM_PAGESIZE - 1)) + 3; // Round len up to a whole page + 2
127
   
89
   
128
    while (len -= 2) {
90
    while (len -= 2) {
-
 
91
        if (dst >= (uint16_t)&__flash_code_start) break;
-
 
92
 
129
        wdt_reset();
93
        wdt_reset();
130
 
94
 
131
        data = pgm_read_word(src); // Read source word
95
        data = pgm_read_word(src); // Read source word
132
        boot_page_fill_safe(dst, data); // Write word to destination
96
        boot_page_fill(dst, data); // Write word to destination
133
       
97
       
134
        if (((uint8_t)dst + 2) % SPM_PAGESIZE == 0) { // If we just wrote the last word of a page
98
        if ((dst + 2) % SPM_PAGESIZE == 0) { // If we just wrote the last word of a page
135
            boot_page_erase(dst);
99
            boot_page_erase(dst);
136
            boot_spm_busy_wait(); // Wait until the memory is erased.
100
            boot_spm_busy_wait(); // Wait until the memory is erased.
137
            boot_page_write(dst); // Store buffer in flash page.
101
            boot_page_write(dst); // Store buffer in flash page.
138
            boot_spm_busy_wait(); // Wait until the memory is written.
102
            boot_spm_busy_wait(); // Wait until the memory is written.
139
            boot_rww_enable();
103
            boot_rww_enable();
140
        }
104
        }
141
         
105
         
142
        src += 2;
106
        src += 2;
143
        dst += 2;
107
        dst += 2;      
144
       
-
 
145
        if (dst >= (uint16_t)&__flash_code_start) break;
-
 
146
    }
108
    }
147
         
109
 
148
#endif
-
 
149
    while (1); // Nothing more we can do, hopefully there is a watchdog active
110
    while (1); // Nothing more we can do, hopefully there is a watchdog active
150
}
111
}
151
#endif
-