1 | #include <string.h>
|
2 | #include <avr/io.h>
|
3 | #include <avr/interrupt.h>
|
4 | #include <avr/boot.h>
|
5 | #include <util/delay.h>
|
6 | #include "uart/uart.h"
|
7 |
|
8 | #define BOOT_UART_BAUD_RATE 9600 /* Baudrate */
|
9 | #define XON 17 /* XON Zeichen */
|
10 | #define XOFF 19 /* XOFF Zeichen */
|
11 | #define START_SIGN ':' /* Hex-Datei Zeilenstartzeichen */
|
12 |
|
13 | /* Zustände des Bootloader-Programms */
|
14 | #define BOOT_STATE_EXIT 0
|
15 | #define BOOT_STATE_PARSER 1
|
16 |
|
17 | /* Zustände des Hex-File-Parsers */
|
18 | #define PARSER_STATE_START 0
|
19 | #define PARSER_STATE_SIZE 1
|
20 | #define PARSER_STATE_ADDRESS 2
|
21 | #define PARSER_STATE_TYPE 3
|
22 | #define PARSER_STATE_DATA 4
|
23 | #define PARSER_STATE_CHECKSUM 5
|
24 | #define PARSER_STATE_ERROR 6
|
25 |
|
26 | ISR(BADISR_vect) {
|
27 |
|
28 | }
|
29 |
|
30 | void program_page (uint32_t page, uint8_t *buf)
|
31 | {
|
32 | uint16_t i;
|
33 | uint8_t sreg;
|
34 |
|
35 | /* Disable interrupts */
|
36 | sreg = SREG;
|
37 | cli();
|
38 |
|
39 | eeprom_busy_wait ();
|
40 |
|
41 | boot_page_erase (page);
|
42 | boot_spm_busy_wait (); /* Wait until the memory is erased. */
|
43 |
|
44 | for (i=0; i<SPM_PAGESIZE; i+=2)
|
45 | {
|
46 | /* Set up little-endian word. */
|
47 | uint16_t w = *buf++;
|
48 | w += (*buf++) << 8;
|
49 |
|
50 | boot_page_fill (page + i, w);
|
51 | }
|
52 |
|
53 | boot_page_write (page); /* Store buffer in flash page. */
|
54 | boot_spm_busy_wait(); /* Wait until the memory is written.*/
|
55 |
|
56 | /* Reenable RWW-section again. We need this if we want to jump back */
|
57 | /* to the application after bootloading. */
|
58 | boot_rww_enable ();
|
59 |
|
60 | /* Re-enable interrupts (if they were ever enabled). */
|
61 | SREG = sreg;
|
62 | }
|
63 |
|
64 | static uint16_t hex2num (const uint8_t * ascii, uint8_t num)
|
65 | {
|
66 | uint8_t i;
|
67 | uint16_t val = 0;
|
68 |
|
69 | for (i=0; i<num; i++)
|
70 | {
|
71 | uint8_t c = ascii[i];
|
72 |
|
73 | /* Hex-Ziffer auf ihren Wert abbilden */
|
74 | if (c >= '0' && c <= '9') c -= '0';
|
75 | else if (c >= 'A' && c <= 'F') c -= 'A' - 10;
|
76 | else if (c >= 'a' && c <= 'f') c -= 'a' - 10;
|
77 |
|
78 | val = 16 * val + c;
|
79 | }
|
80 |
|
81 | return val;
|
82 | }
|
83 |
|
84 | int main()
|
85 | {
|
86 | /* Empfangenes Zeichen + Statuscode */
|
87 | uint16_t c = 0,
|
88 | /* Intel-HEX Zieladresse */
|
89 | hex_addr = 0,
|
90 | /* Zu schreibende Flash-Page */
|
91 | flash_page = 0,
|
92 | /* Intel-HEX Checksumme zum Überprüfen des Daten */
|
93 | hex_check = 0,
|
94 | /* Positions zum Schreiben in der Datenpuffer */
|
95 | flash_cnt = 0;
|
96 | /* temporäre Variable */
|
97 | uint8_t temp,
|
98 | /* Flag zum steuern des Programmiermodus */
|
99 | boot_state = BOOT_STATE_EXIT,
|
100 | /* Empfangszustandssteuerung */
|
101 | parser_state = PARSER_STATE_START,
|
102 | /* Flag zum ermitteln einer neuen Flash-Page */
|
103 | flash_page_flag = 1,
|
104 | /* Datenpuffer für die Hexdaten*/
|
105 | flash_data[SPM_PAGESIZE],
|
106 | /* Position zum Schreiben in den HEX-Puffer */
|
107 | hex_cnt = 0,
|
108 | /* Puffer für die Umwandlung der ASCII in Binärdaten */
|
109 | hex_buffer[5],
|
110 | /* Intel-HEX Datenlänge */
|
111 | hex_size = 0,
|
112 | /* Zähler für die empfangenen HEX-Daten einer Zeile */
|
113 | hex_data_cnt = 0,
|
114 | /* Intel-HEX Recordtype */
|
115 | hex_type = 0,
|
116 | /* empfangene HEX-Checksumme */
|
117 | hex_checksum=0;
|
118 | /* Funktionspointer auf 0x0000 */
|
119 | void (*start)( void ) = 0x0000;
|
120 |
|
121 | /* Füllen der Puffer mit definierten Werten */
|
122 | memset(hex_buffer, 0x00, sizeof(hex_buffer));
|
123 | memset(flash_data, 0xFF, sizeof(flash_data));
|
124 |
|
125 | /* Interrupt Vektoren verbiegen */
|
126 | temp = MCUCR;
|
127 | MCUCR = temp | (1<<IVCE);
|
128 | MCUCR = temp | (1<<IVSEL);
|
129 |
|
130 | /* Einstellen der Baudrate und aktivieren der Interrupts */
|
131 | uart_init( UART_BAUD_SELECT(BOOT_UART_BAUD_RATE,F_CPU) );
|
132 | sei();
|
133 |
|
134 | uart_puts("Hallo hier ist der echte Bootloader\r\n");
|
135 | _delay_ms(2000);
|
136 |
|
137 | DDRC |= (1 << PC0);
|
138 |
|
139 | do
|
140 | {
|
141 | c = uart_getc();
|
142 | if( !(c & UART_NO_DATA) )
|
143 | {
|
144 | /* Programmzustand: Parser */
|
145 | if(boot_state == BOOT_STATE_PARSER)
|
146 | {
|
147 | switch(parser_state)
|
148 | {
|
149 | /* Warte auf Zeilen-Startzeichen */
|
150 | case PARSER_STATE_START:
|
151 | if((uint8_t)c == START_SIGN)
|
152 | {
|
153 | uart_putc(XOFF);
|
154 | parser_state = PARSER_STATE_SIZE;
|
155 | hex_cnt = 0;
|
156 | hex_check = 0;
|
157 | uart_putc(XON);
|
158 | }
|
159 | break;
|
160 | /* Parse Datengröße */
|
161 | case PARSER_STATE_SIZE:
|
162 | hex_buffer[hex_cnt++] = (uint8_t)c;
|
163 | if(hex_cnt == 2)
|
164 | {
|
165 | uart_putc(XOFF);
|
166 | parser_state = PARSER_STATE_ADDRESS;
|
167 | hex_cnt = 0;
|
168 | hex_size = (uint8_t)hex2num(hex_buffer, 2);
|
169 | hex_check += hex_size;
|
170 | uart_putc(XON);
|
171 | }
|
172 | break;
|
173 | /* Parse Zieladresse */
|
174 | case PARSER_STATE_ADDRESS:
|
175 | hex_buffer[hex_cnt++] = (uint8_t)c;
|
176 | if(hex_cnt == 4)
|
177 | {
|
178 | uart_putc(XOFF);
|
179 | parser_state = PARSER_STATE_TYPE;
|
180 | hex_cnt = 0;
|
181 | hex_addr = hex2num(hex_buffer, 4);
|
182 | hex_check += (uint8_t) hex_addr;
|
183 | hex_check += (uint8_t) (hex_addr >> 8);
|
184 | if(flash_page_flag)
|
185 | {
|
186 | flash_page = hex_addr - hex_addr % SPM_PAGESIZE;
|
187 | flash_page_flag = 0;
|
188 | }
|
189 | uart_putc(XON);
|
190 | }
|
191 | break;
|
192 | /* Parse Zeilentyp */
|
193 | case PARSER_STATE_TYPE:
|
194 | hex_buffer[hex_cnt++] = (uint8_t)c;
|
195 | if(hex_cnt == 2)
|
196 | {
|
197 | uart_putc(XOFF);
|
198 | hex_cnt = 0;
|
199 | hex_data_cnt = 0;
|
200 | hex_type = (uint8_t)hex2num(hex_buffer, 2);
|
201 | hex_check += hex_type;
|
202 | switch(hex_type)
|
203 | {
|
204 | case 0: parser_state = PARSER_STATE_DATA; break;
|
205 | case 1: parser_state = PARSER_STATE_CHECKSUM; break;
|
206 | default: parser_state = PARSER_STATE_DATA; break;
|
207 | }
|
208 | uart_putc(XON);
|
209 | }
|
210 | break;
|
211 | /* Parse Flash-Daten */
|
212 | case PARSER_STATE_DATA:
|
213 | hex_buffer[hex_cnt++] = (uint8_t)c;
|
214 | if(hex_cnt == 2)
|
215 | {
|
216 | uart_putc(XOFF);
|
217 | uart_putc('.');
|
218 | hex_cnt = 0;
|
219 | flash_data[flash_cnt] = (uint8_t)hex2num(hex_buffer, 2);
|
220 | hex_check += flash_data[flash_cnt];
|
221 | flash_cnt++;
|
222 | hex_data_cnt++;
|
223 | if(hex_data_cnt == hex_size)
|
224 | {
|
225 | parser_state = PARSER_STATE_CHECKSUM;
|
226 | hex_data_cnt=0;
|
227 | hex_cnt = 0;
|
228 | }
|
229 | /* Puffer voll -> schreibe Page */
|
230 | if(flash_cnt == SPM_PAGESIZE)
|
231 | {
|
232 | uart_puts("P\r\n");
|
233 | _delay_ms(100);
|
234 | program_page((uint16_t)flash_page, flash_data);
|
235 | memset(flash_data, 0xFF, sizeof(flash_data));
|
236 | flash_cnt = 0;
|
237 | flash_page_flag = 1;
|
238 | }
|
239 | uart_putc(XON);
|
240 | }
|
241 | break;
|
242 | /* Parse Checksumme */
|
243 | case PARSER_STATE_CHECKSUM:
|
244 | hex_buffer[hex_cnt++] = (uint8_t)c;
|
245 | if(hex_cnt == 2)
|
246 | {
|
247 | uart_putc(XOFF);
|
248 | hex_checksum = (uint8_t)hex2num(hex_buffer, 2);
|
249 | hex_check += hex_checksum;
|
250 | hex_check &= 0x00FF;
|
251 | /* Dateiende -> schreibe Restdaten */
|
252 | if(hex_type == 1)
|
253 | {
|
254 | uart_puts("P\r\n");
|
255 | _delay_ms(100);
|
256 | program_page((uint16_t)flash_page, flash_data);
|
257 | boot_state = BOOT_STATE_EXIT;
|
258 | }
|
259 | /* Überprüfe Checksumme -> muss '0' sein */
|
260 | if(hex_check == 0) parser_state = PARSER_STATE_START;
|
261 | else parser_state = PARSER_STATE_ERROR;
|
262 | uart_putc(XON);
|
263 | }
|
264 | break;
|
265 | /* Parserfehler (falsche Checksumme) */
|
266 | case PARSER_STATE_ERROR:
|
267 | uart_putc('#');
|
268 | break;
|
269 | default:
|
270 | break;
|
271 | }
|
272 | }
|
273 | /* Programmzustand: UART Kommunikation */
|
274 | else if(boot_state != BOOT_STATE_PARSER)
|
275 | {
|
276 | switch((uint8_t)c)
|
277 | {
|
278 | case 'p':
|
279 | boot_state = BOOT_STATE_PARSER;
|
280 | uart_puts("Programmiere den Flash!\r\n");
|
281 | uart_puts("Kopiere die Hex-Datei und füge sie"
|
282 | " hier ein (rechte Maustaste)\r\n");
|
283 | break;
|
284 | case 'q':
|
285 | boot_state = BOOT_STATE_EXIT;
|
286 | uart_puts("Verlasse den Bootloader!\r\n");
|
287 | break;
|
288 | case 'x':
|
289 | do
|
290 | {
|
291 | c = uart_getc();
|
292 | if( !(c & UART_NO_DATA) )
|
293 | {
|
294 | if (c == 'o') {
|
295 | uart_puts("XOFF kommt in 1 Sekunde...\r\n");
|
296 | _delay_ms(1000);
|
297 | uart_putc(XOFF);
|
298 | uart_puts("XON kommt in 1 Sekunde...\r\n");
|
299 | _delay_ms(1000);
|
300 | uart_putc(XON);
|
301 | }
|
302 | else
|
303 | {
|
304 | uart_puts("Du hast folgendes Zeichen gesendet: ");
|
305 | uart_putc((unsigned char)c);
|
306 | uart_puts("\r\n");
|
307 | }
|
308 | }
|
309 | } while (c != 'q');
|
310 | break;
|
311 | default:
|
312 | uart_puts("Du hast folgendes Zeichen gesendet: ");
|
313 | uart_putc((unsigned char)c);
|
314 | uart_puts("\r\n");
|
315 | break;
|
316 | }
|
317 | }
|
318 | }
|
319 | }
|
320 | while(boot_state!=BOOT_STATE_EXIT);
|
321 |
|
322 | uart_puts("Reset AVR!\r\n");
|
323 | _delay_ms(1000);
|
324 |
|
325 | /* Interrupt Vektoren wieder gerade biegen */
|
326 | temp = MCUCR;
|
327 | MCUCR = temp | (1<<IVCE);
|
328 | MCUCR = temp & ~(1<<IVSEL);
|
329 |
|
330 | /* Reset */
|
331 | start();
|
332 |
|
333 | return 0;
|
334 | }
|