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