Bootloader.c


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
}