Subversion Repositories HomeAutomation

Rev

Rev 315 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | SVN | RSS feed

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