1 | /* ########################################################################## */
|
2 | /* include */
|
3 |
|
4 | #include "ATmega164PA_BtLdr.h"
|
5 | #include "Bootloader.h"
|
6 |
|
7 |
|
8 | /* ########################################################################## */
|
9 | /* code constants */
|
10 |
|
11 |
|
12 | /* ########################################################################## */
|
13 | /* variables */
|
14 |
|
15 | u16_t ihex_line_dest_addr = 0;
|
16 | u8_t ihex_line_dat_len = 0;
|
17 | u8_t ihex_line_dat_type = 0;
|
18 | u8_t ihex_line_dat_buf[32];
|
19 |
|
20 | u16_t flash_page_num = 0;
|
21 | u16_t flash_page_addr = 0;
|
22 | u16_t flash_cnt = 0;
|
23 |
|
24 | u8_t SPM_timer = 0;
|
25 |
|
26 | /* ########################################################################## */
|
27 | /* local functions: */
|
28 |
|
29 |
|
30 | /* ########################################################################## */
|
31 | /* global functions */
|
32 |
|
33 | /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
|
34 | /* bootloader control */
|
35 | void bootload_ctl(void)
|
36 | {
|
37 | u8_t parser_ret;
|
38 | u8_t write_ret;
|
39 |
|
40 | /* check line from hex file */
|
41 | parser_ret = ihex_line_parser();
|
42 |
|
43 | if( parser_ret == IHEX_LINE_OKAY )
|
44 | {
|
45 | /* write to flash */
|
46 | write_ret = ihex2flash(IHEX_RECTYP_DATA);
|
47 |
|
48 | TX1_byte(write_ret);
|
49 | }
|
50 | else if( parser_ret == IHEX_LINE_EOF )
|
51 | {
|
52 | /* write last data, fill rest with 0xFF */
|
53 | write_ret = ihex2flash(IHEX_LINE_EOF);
|
54 | /* send message we're done */
|
55 | TX1_byte(write_ret);
|
56 | }
|
57 | else TX1_byte(parser_ret);
|
58 |
|
59 | /* reset RX1 stuff */
|
60 | mem_set(RX1_buffer, 0x00, (u16_t)sizeof(RX1_buffer));
|
61 | RX1_timer = UART1_TIMEOUT_MAX;
|
62 | RX1_ihex_avl = 0;
|
63 | }
|
64 |
|
65 |
|
66 | /* check received line, length, CRC, data type - no ASCII !!! */
|
67 | u8_t ihex_line_parser(void)
|
68 | {
|
69 | u8_t i;
|
70 | u16_t crc_sum = 0;
|
71 |
|
72 | /* check start code and length */
|
73 | if( RX1_buffer[0] != ':' || RX1_counter < IHEX_LINE_OVERHEAD_BIN ) return IHEX_ERROR_STRT_LEN;
|
74 |
|
75 | /* get data length in line */
|
76 | ihex_line_dat_len = RX1_buffer[1];
|
77 |
|
78 | /* get flash address */
|
79 | ihex_line_dest_addr = (u16_t)RX1_buffer[2] << 8;
|
80 | ihex_line_dest_addr += (u16_t)RX1_buffer[3];
|
81 |
|
82 | /* get data type */
|
83 | ihex_line_dat_type = RX1_buffer[4];
|
84 |
|
85 | /* CRC check, add all execept ':', incl CRC byte, lower byte sum must be 0 */
|
86 | for( i = 1; i < RX1_counter; i++ ) crc_sum += (u16_t)RX1_buffer[i];
|
87 | crc_sum &= 0x00FF;
|
88 | if( crc_sum != 0 ) return IHEX_ERROR_CRC;
|
89 |
|
90 | /* get data and copy to buffer */
|
91 | if( ihex_line_dat_type == IHEX_RECTYP_DATA && ihex_line_dat_len != 0 )
|
92 | {
|
93 | for( i = 0; i < ihex_line_dat_len; i++ )
|
94 | {
|
95 | ihex_line_dat_buf[i] = RX1_buffer[i + 5];
|
96 | }
|
97 | }
|
98 | /* extended address for > 64kB? */
|
99 | else if( ihex_line_dat_type == IHEX_RECTYP_XSADR )
|
100 | {
|
101 | /* for now just return error code */
|
102 | return IHEX_ERROR_EXTADDR;
|
103 | }
|
104 | /* EOF? */
|
105 | else if( ihex_line_dat_type == IHEX_RECTYP_EOF &&
|
106 | RX1_counter == IHEX_LINE_OVERHEAD_BIN )
|
107 | {
|
108 | return IHEX_LINE_EOF;
|
109 | }
|
110 | else return IHEX_FLASH_FT_ERROR;
|
111 |
|
112 | return IHEX_LINE_OKAY;
|
113 | }
|
114 |
|
115 |
|
116 | /* write line from hex file to flash page buffer */
|
117 | u8_t ihex2flash(u8_t dat_type)
|
118 | {
|
119 | u8_t ret_val;
|
120 | u8_t i;
|
121 | u16_t page_addr_b;
|
122 |
|
123 | /* - writing flash page by page
|
124 | * - a complete page must be written
|
125 | * - data must be collected until page is full
|
126 | *
|
127 | * 1) fill page buffer
|
128 | * 2) erase page
|
129 | * 3) write page
|
130 | *
|
131 | */
|
132 |
|
133 | /* end of hex file, write current page buffer to flash */
|
134 | if( dat_type == IHEX_LINE_EOF )
|
135 | {
|
136 | if( flash_cnt != 0 )
|
137 | {
|
138 | eeprom_busy_wait();
|
139 |
|
140 | /* erase page */
|
141 | // SPM_processing((void flash *)flash_page_num, SPM_CMND_ERASE_PAGE);
|
142 | // SPM_processing(flash_page_num, SPM_CMND_ERASE_PAGE);
|
143 | // boot_spm_busy_wait();
|
144 |
|
145 | /* write page */
|
146 | SPM_processing((void flash *)flash_page_num, SPM_CMND_WRITE_PAGE);
|
147 | if( boot_spm_busy_wait() ) ret_val = IHEX_FLASH_EOF_TO;
|
148 | SPM_R0_to_SPM(0, SPM_CMND_ENABLE_RWW);
|
149 |
|
150 | /* reset stuff */
|
151 | flash_page_num = 0;
|
152 | flash_cnt = 0;
|
153 | flash_page_addr = 0;
|
154 | }
|
155 | ret_val = IHEX_FLASH_WR_END;
|
156 | }
|
157 | /* copy data from new line to page buffer, erase & write page */
|
158 | else
|
159 | {
|
160 | for( i = 0; i < ihex_line_dat_len; i += 2 )
|
161 | {
|
162 | flash_page_addr = flash_page_num + flash_cnt;
|
163 | page_addr_b = flash_page_addr;// << 1;
|
164 |
|
165 | SPM_fill_page_buffer((void flash *)page_addr_b, ihex_line_dat_buf[i+1], ihex_line_dat_buf[i], SPM_CMND_FILL_PAGE_BUF);
|
166 | /* hängt hier nach erstem page write */
|
167 | LED2_GREEN;
|
168 | if( boot_spm_busy_wait() ) ret_val = IHEX_FLASH_FILL_TO;
|
169 | LED2_OFF;
|
170 |
|
171 | flash_cnt += 2;
|
172 |
|
173 | /* page buffer full => erase page => write page! */
|
174 | if( flash_cnt == SPM_PAGE_SIZE )
|
175 | {
|
176 | eeprom_busy_wait();
|
177 |
|
178 | /* erase page */
|
179 | // SPM_processing((void flash *)flash_page_num, SPM_CMND_ERASE_PAGE);
|
180 | // SPM_processing(flash_page_num, SPM_CMND_ERASE_PAGE);
|
181 | // boot_spm_busy_wait();
|
182 |
|
183 | /* write page */
|
184 | SPM_processing((void flash *)flash_page_num, SPM_CMND_WRITE_PAGE);
|
185 | LED2_RED;
|
186 | /* hier hängt's nach 1. page write! */
|
187 | if( boot_spm_busy_wait() ) ret_val = IHEX_FLASH_WR_TO;
|
188 | LED2_OFF;
|
189 | SPM_R0_to_SPM(0, SPM_CMND_ENABLE_RWW);
|
190 |
|
191 | /* new page */
|
192 | page_addr_b = flash_page_num;
|
193 | flash_page_num = ihex_line_dest_addr - (ihex_line_dest_addr % SPM_PAGE_SIZE);
|
194 | if( flash_page_num == page_addr_b ) flash_page_num += SPM_PAGE_SIZE;
|
195 | flash_cnt = 0;
|
196 | }
|
197 | }
|
198 | ret_val = IHEX_FLASH_LINE_WR;
|
199 | }
|
200 |
|
201 | LED2_OFF;
|
202 |
|
203 | return ret_val;
|
204 | }
|
205 |
|
206 |
|
207 | #pragma warn-
|
208 | /* call: SPM_fill_page_buffer((void flash *)addr, ... */
|
209 | /* fill buffer */
|
210 | void SPM_fill_page_buffer(void flash *addr, u8_t dat_hi, u8_t dat_lo, u8_t cmnd)
|
211 | {
|
212 | #asm
|
213 | cli
|
214 | ldd r30,y+3
|
215 | ldd r31,y+4
|
216 | ldd r0,y+1
|
217 | ldd r1,y+2
|
218 | ld r22,y
|
219 | WR_SPMCR_REG_R22
|
220 | spm
|
221 | sei
|
222 | #endasm
|
223 | }
|
224 |
|
225 |
|
226 | /* call: SPM_processing((void flash *)addr, ... */
|
227 | /* erase page (cmnd = 0x03) / write buffer to page (cmnd = 0x05) */
|
228 | void SPM_processing(void flash *addr, u8_t cmnd)
|
229 | {
|
230 | #asm
|
231 | cli
|
232 | ldd r30,y+1
|
233 | ldd r31,y+2
|
234 | ld r22,y
|
235 | WR_SPMCR_REG_R22
|
236 | spm
|
237 | sei
|
238 | #endasm
|
239 | }
|
240 |
|
241 |
|
242 | /* ??? */
|
243 | void SPM_R0_to_SPM(u8_t data, u8_t cmnd)
|
244 | {
|
245 | #asm
|
246 | cli
|
247 | ldd r0,y+1
|
248 | ld r22,y
|
249 | WR_SPMCR_REG_R22
|
250 | spm
|
251 | sei
|
252 | #endasm
|
253 | }
|
254 | #pragma warn+
|
255 |
|
256 |
|
257 | /* read flash */
|
258 | void SPM_read_flash(u16_t addr, u16_t len)
|
259 | {
|
260 | u8_t byte;
|
261 |
|
262 | do
|
263 | {
|
264 | #if(0)
|
265 | /* ASCII, takes too much prog space */
|
266 | if( (len % 16) == 0 ) TX1_byte('\n');
|
267 | TX1_byte('0');
|
268 | TX1_byte('x');
|
269 | byte = (u8_t)*((u8_t flash *)addr);
|
270 | TX1_byte(hex_char[(byte & 0xF0) >> 4]);
|
271 | TX1_byte(hex_char[ byte & 0x0F]);
|
272 | TX1_byte(' ');
|
273 | #endif
|
274 |
|
275 | byte = (u8_t)*((u8_t flash *)addr);
|
276 | TX1_byte(byte);
|
277 | addr++;
|
278 | len--;
|
279 | } while( len );
|
280 | }
|
281 |
|
282 |
|
283 | u8_t boot_spm_busy_wait(void)
|
284 | {
|
285 | LED1_RED;
|
286 | SPM_timer = 10; /* *100 ms */
|
287 | while( SPMCSR )//& (1<<SPMEN) )
|
288 | {
|
289 | if( SPM_timer == 0 ) return 1;
|
290 | };
|
291 | LED1_GREEN;
|
292 | return 0;
|
293 | }
|
294 |
|
295 |
|
296 | void eeprom_busy_wait(void)
|
297 | {
|
298 | while( EECR & (u8_t)(1<<EEPE) );
|
299 | }
|
300 |
|
301 |
|
302 | void mem_set(u8_t *buf, u8_t val, u16_t len)
|
303 | {
|
304 | u16_t i = 0;
|
305 |
|
306 | for( i = 0; i < len; i++ ) buf[i] = val;
|
307 | }
|