Remove CONFIG_WATCHDOG stuff: watchdog macros expand to nothing when wdt is active.
[bertos.git] / mware / prog_avr.c
1 /**
2  * \file
3  * <!--
4  * Copyright 2004 Develer S.r.l. (http://www.develer.com/)
5  * All Rights Reserved.
6  * -->
7  *
8  * \brief Self programming routines
9  *
10  * \version $Id$
11  * \author Francesco Sacchi <batt@develer.com>
12  */
13
14 #include "prog.h"
15 #include <drv/wdt.h>
16 #include <cfg/macros.h> // MIN()
17 #include <cfg/compiler.h>
18 #include <flash.h>
19 #include <defines.h>
20 #include <avr/io.h>
21 #include <algos/rotating_hash.h>
22
23 #define PAGEBUF 512
24
25 typedef uint16_t page_addr_t;
26 typedef uint16_t page_t;
27
28 /**
29  * Temporary buffer for cointain data block to
30  * write on flash.
31  */
32 static uint8_t page_buf[PAGEBUF];
33
34 /**
35  * Store current flash page memory in use.
36  */
37 static page_t curr_pag_num = 0;
38
39
40
41 /**
42  * Erase Flash.
43  */
44 static void prog_erase_flash(void)
45 {
46         uint32_t flash_addr;
47
48         /* Erase the flash ROM */
49         #ifdef LARGE_MEMORY
50                 /*
51                  * SPM uses Z pointer but the pointer is only 16 bit and
52                  * can only address up to 64Kbytes FLASH. Higher locations
53                  * require the use of RAMPZ
54                  */
55                 RAMPZ = 0x00;
56
57                 for (flash_addr = 0; (flash_addr < (uint16_t)(APP_END & 0xFFFF)) | (RAMPZ == 0x00));
58                 {
59                         wdt_reset();
60
61                         /* Page erase */
62                         write_page(flash_addr, BV(PGERS) + BV(SPMEN));
63
64                         /* Re-enable the RWW section */
65                         write_page(flash_addr, BV(REENABLE_RWW_BIT) + BV(SPMEN));
66
67                         /* Last section on lower 64k segment is erased */
68                         if(flashgg_addr >= (0xFFFF - PAGESIZE))
69
70                                 /* RAMPZ has to be incremented into upper 64k segment */
71                                 RAMPZ = BV(RAMPZ0);
72                 }
73                 RAMPZ = 0x00;
74         #else /* LARGE_MEMORY */
75                  /* Application section = 60 pages */
76                 for (flash_addr = 0; flash_addr < APP_END; flash_addr += PAGESIZE)
77                 {
78                         wdt_reset();
79
80                         /* Page erase */
81                         write_page(flash_addr, BV(PGERS) + BV(SPMEN));
82                         /* Re-enable RWW section */
83                         write_page(flash_addr, BV(REENABLE_RWW_BIT) + BV(SPMEN));
84                 }
85         #endif /* LARGE_MEMORY */
86 }
87
88
89 /**
90  * Write a page in program memory.
91  */
92 static void prog_pagewrite(uint16_t addr)
93 {
94         write_page(addr, BV(PGWRT) + BV(SPMEN));
95
96         /* Re-enable the RWW section */
97         write_page(addr, BV(REENABLE_RWW_BIT) + BV(SPMEN));
98 }
99
100
101 /**
102  * Delete a page in program memory.
103  */
104 static void prog_pagedelete(uint16_t addr)
105 {
106         /* Page erase */
107         write_page(addr, BV(PGERS) + BV(SPMEN));
108
109         /* Re-enable the RWW section */
110         write_page(addr, BV(REENABLE_RWW_BIT) + BV(SPMEN));
111 }
112
113 /**
114  * Flush temporary buffer into flash memory.
115  */
116 static void prog_flush(void)
117 {
118
119         /* Fill the temporary buffer of the AVR */
120         for (page_addr_t page_addr = 0; page_addr < PAGEBUF; page_addr += 2)
121                 fill_temp_buffer(page_buf[page_addr + 1] | (uint16_t)page_buf[page_addr] << 8, page_addr);
122
123
124         wdt_reset();
125
126         /* Page delete */
127         prog_pagedelete(curr_page_num * PAGEBUF);
128
129         /* Page write */
130         prog_pagewrite(curr_page_num * PAGEBUF);
131 }
132
133 /**
134  * Write program memory.
135  * This function to write on flash memory load a selected page from
136  * flash memory and save it in temporary buffer. Them update temporary buffer
137  * with \param buf data. We write in flash memory everery time we
138  * change current page memory.
139  * 
140  */
141 size_t  prog_write(struct _KFile *fd, const char *buf, size_t size)
142 {
143
144         page_t page;
145         page_addr_t page_addr;
146         size_t total_write = 0;
147         size_t wr_len;
148
149         while (size)
150         {
151                 /* Current page memory */
152                 page = fd->SeekPos / PAGEBUF;
153
154                 /* Address in page memory */
155                 page_addr = fd->SeekPos % PAGEBUF;
156
157                 prog_loadPage(page);
158
159                 wr_len = MIN(size, PAGEBUF - page_addr);
160                 memcpy(page_buf + page_addr, buf, wr_len);
161
162                 buf += wr_len;
163                 fd->SeekPos += wr_len;
164                 size -= wr_len;
165                 total_write += wr_len;
166         }
167         /* Return total byte write on flash memory */
168         return total_write;
169 }
170
171
172
173 /**
174  * Load select \param page memory buffer from AVR flash memory.
175  * If select page is not current page, we flush it, and then we load
176  * select page memory flash.
177  */
178 void prog_loadPage(page_t page)
179 {
180         if (page != curr_page_num)
181         {
182                 prog_flush();
183                 /* Load selet page in temporary buffer store into RAM */
184                 memcpy_P(page_buf, (const char *)(page * PAGEBUF), PAGEBUF);
185                 /* Update current page */
186                 curr_page_num = page;
187         }
188 }