Abb first skel of programmming AVR flash memory.
[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 /**
24  * Erase Flash.
25  */
26 static void prog_erase_flash(void)
27 {
28         uint32_t flash_addr;
29         /* Erase the flash ROM */
30         #ifdef LARGE_MEMORY
31                 /*
32                 * SPM uses Z pointer but the pointer is only 16 bit and
33                 * can only address up to 64Kbytes FLASH. Higher locations
34                 * require the use of RAMPZ
35                 */
36                 RAMPZ = 0x00;
37
38                 for (flash_addr = 0; (flash_addr < (uint16_t)(APP_END & 0xFFFF)) | (RAMPZ == 0x00); flash_addr += PAGESIZE)
39                 {
40                         wdt_reset();
41
42                         write_page(flash_addr, BV(PGERS) + BV(SPMEN));             /* Page erase */
43                         write_page(flash_addr, BV(REENABLE_RWW_BIT) + BV(SPMEN));  /* Re-enable the RWW section */
44
45                         if(flashgg_addr >= (0xFFFF - PAGESIZE))  /* Last section on lower 64k segment is erased */
46                                 RAMPZ = BV(RAMPZ0);          /* RAMPZ has to be incremented into upper 64k segment */
47                 }
48                 RAMPZ = 0x00;
49         #else /* LARGE_MEMORY */
50                 for (flash_addr = 0; flash_addr < APP_END; flash_addr += PAGESIZE)  /* Application section = 60 pages */
51                 {
52                         wdt_reset();
53
54                         /* Page erase */
55                         write_page(flash_addr, BV(PGERS) + BV(SPMEN));
56                         /* Re-enable RWW section */
57                         write_page(flash_addr, BV(REENABLE_RWW_BIT) + BV(SPMEN));
58                 }
59         #endif /* LARGE_MEMORY */
60 }
61
62
63 /**
64  * Write a page in program memory.
65  */
66 static void prog_pagewrite(uint16_t addr)
67 {
68         write_page(addr, BV(PGWRT) + BV(SPMEN));
69         /* Re-enable the RWW section */
70         write_page(addr, BV(REENABLE_RWW_BIT) + BV(SPMEN));
71 }
72
73
74 /**
75  * Write program memory.
76  */
77 rotating_t prog_write(struct _KFile *file, progress_func_t progress)
78 {
79         size_t size;
80         rotating_t rot = 0;
81         uint32_t flash_addr = 0;
82         uint16_t page_addr;
83         uint8_t buf[PAGESIZE];
84         
85         /* We erase fash memory before to write inside */
86         prog_erase_flash();
87
88         for (;;)
89         {
90                 wdt_reset();
91
92                 /* Read data from file */
93                 size = file->read(file, buf, PAGESIZE);
94
95                 /* If we reached end of file exit */
96                 if (!size)
97                         break;
98         
99                 /* Update checksum */
100                 rotating_update(buf, size, &rot);
101         
102                 /* Fill the temporary buffer of the AVR */
103                 for (page_addr = 0; page_addr < size; page_addr += 2)
104                         fill_temp_buffer(buf[page_addr + 1] | (uint16_t)buf[page_addr] << 8, page_addr);
105                 
106                 /* Page write */
107                 prog_pagewrite(flash_addr);
108         
109                 /* Update progess (if present) */
110                 if (progress)
111                         if (!progress(file->SeekPos, file->Size))
112                                 break;
113                 
114                 flash_addr += size;
115         }
116
117         return rot
118 }