Project

General

Profile

Statistics
| Revision:

root / trunk / toolbox / bootloader / bootloader.c @ 169

History | View | Annotate | Download (6.67 KB)

1 154 bneuman
#include <avr/io.h>
2
#include <avr/boot.h>
3 165 kwoo
#include <avr/pgmspace.h>
4 154 bneuman
5 156 kwoo
#include "tooltron.h"
6 154 bneuman
#include "uart.h"
7
8
#define TRUE        0
9
#define FALSE        1
10
11 156 kwoo
#define ADDR    18
12
13
14 154 bneuman
#define MAX_WAIT_IN_CYCLES 800000
15 158 kwoo
#define MAX_TIMEOUT 60000        // Seconds to wait before exiting bootloader mode
16 165 kwoo
#define MAIN_ADDR 0x000
17 169 kwoo
#define BOOT_START 0x400
18 154 bneuman
19
//Status LED
20
#define LED_DDR  DDRB
21
#define LED_PORT PORTB
22
#define LED      PORTB1
23
24
//Function prototypes
25 165 kwoo
void __init(void) __attribute__((naked));
26 169 kwoo
  void (*main_start)(void) = BOOT_START/2 - 1;
27 154 bneuman
28 165 kwoo
29 156 kwoo
typedef enum {
30
    sd,
31
    src,
32
    dest,
33
    comd,
34
    read,
35
    cs,
36
    ack
37
} state_t;
38
39 168 kwoo
typedef union {
40
    uint8_t bytes[2];
41
    int16_t sword;
42
} rjump_t;
43
44 165 kwoo
// Redirect all unused interrupts to reti
45 169 kwoo
//EMPTY_INTERRUPT(__vector_default);
46
//extern void __ctors_end(void) __attribute__((__noreturn__));
47 165 kwoo
48
// macros for entering subprograms
49 169 kwoo
//#define __JMP_INIT__ __asm__ __volatile__ ("rjmp __ctors_end" )
50 165 kwoo
51 169 kwoo
/*BOOTLOADER_SECTION*/ void init_uart(uint16_t baud) {
52 164 kwoo
        // Set baud rate
53
        UBRRH = (uint8_t)(baud>>8);
54
        UBRRL = (uint8_t)baud;
55
56 167 kwoo
        // Enable RX/TX
57 166 kwoo
        UCSRB = _BV(RXEN) | _BV(TXEN);
58 164 kwoo
59
        // Enable the TXEN pin as output
60
        DDRD |= TX_EN;
61 166 kwoo
    uart_toggle_transmit(UART_TX_OFF);
62 164 kwoo
}
63 156 kwoo
64 169 kwoo
/*BOOTLOADER_SECTION*/ int8_t uart_get_byte(uint8_t *output_byte) {
65 164 kwoo
    if (UCSRA & _BV(RXC)) {
66
        *output_byte = UDR;
67
        return 0;
68
    } else {
69
        return -1;
70
    }
71 158 kwoo
}
72
73 169 kwoo
/*BOOTLOADER_SECTION*/ void uart_send_byte(uint8_t data) {
74 164 kwoo
        //Waits until current transmit is done
75
    while (!(UCSRA & _BV(UDRE)));
76 167 kwoo
    //PORTB |= _BV(PORTB2);
77 164 kwoo
78
    // Enable writes and send
79
        uart_toggle_transmit(UART_TX_ON);
80
    UDR = data;
81
82
    // Waits until the transmit is done
83 167 kwoo
    while(!(UCSRA & _BV(TXC)));
84 164 kwoo
    uart_toggle_transmit(UART_TX_OFF);
85 167 kwoo
    UCSRA |= _BV(TXC);
86 164 kwoo
87 167 kwoo
    //PORTB |= _BV(PORTB1);
88
89
90 164 kwoo
        return;
91 158 kwoo
}
92
93 169 kwoo
/*BOOTLOADER_SECTION*/ void uart_toggle_transmit(uint8_t state) {
94 164 kwoo
        if (state == UART_TX_ON) {
95
                PORTD |= TX_EN;
96
        } else {
97
                PORTD &= ~TX_EN;
98
        }
99 158 kwoo
}
100
101 169 kwoo
/*BOOTLOADER_SECTION*/ char parse_packet(uint8_t *mbuf) {
102 168 kwoo
  uint8_t r;        // Byte from the network
103
  uint8_t crc;      // Running checksum of the packet
104
  uint8_t cmd;      // The command received
105
  uint8_t pos;      // Position in the message buffer
106
  uint8_t lim;      // Max number of bytes to read into the message buf
107
  state_t state;    // State machine
108
  uint16_t count;
109
110
  r = 0;
111
  crc = 0;
112
  cmd = 0;
113
  pos = 0;
114
  lim = 0;
115
  state = sd;
116 158 kwoo
  count = 0;
117
118 156 kwoo
  while (1) {
119
    // Wait for the next byte
120 158 kwoo
    while ((uart_get_byte(&r)) < 0) {
121 161 kwoo
        if (count >= MAX_TIMEOUT) {
122
            return TT_BAD;
123
       }
124 158 kwoo
    }
125 156 kwoo
126
    switch (state) {
127
        case sd:
128
            if (r == DELIM) {
129
                state = src;
130
            }
131
            break;
132
133
        case src:
134
            if (r == DELIM) {
135
                state = src;
136
            } else {
137
                crc = r;
138
                state = dest;
139
            }
140
            break;
141
142
        case dest:
143
            if (r == DELIM) {
144
                state = src;
145
            } else if (r == ADDR) {
146
                crc ^= r;
147
                state = comd;
148
            } else {
149
                state = sd;
150
            }
151
            break;
152
153
        case comd:
154
            cmd = r;
155
            crc ^= r;
156
157
            if (r == DELIM) {
158
                state = src;
159
            } else if (r == TT_PROGM) {
160
                lim = PROGM_PACKET_SIZE;
161
                state = read;
162
            } else if (r == TT_PROGD) {
163
                lim = PROGD_PACKET_SIZE;
164
                state = read;
165
            } else {
166
                state = cs;
167
            }
168
            break;
169
170
        case read:
171
            mbuf[pos] = r;
172
            crc ^= r;
173
            pos++;
174
175
            if (pos == lim) {
176
                state = cs;
177
            }
178
179
            break;
180
181
        case cs:
182
            if (r == crc) {
183
                return cmd;
184
            } else {
185
                return TT_BAD;
186
            }
187
188
            break;
189
190
        default:
191
            return TT_BAD;
192
    }
193
  }
194
}
195
196 169 kwoo
/*BOOTLOADER_SECTION*/ void send_packet(uint8_t cmd) {
197 156 kwoo
    uart_send_byte(DELIM);
198
    uart_send_byte(ADDR);
199
    uart_send_byte(SERVER);
200 158 kwoo
    uart_send_byte(cmd);
201
    uart_send_byte(ACK_CRC ^ cmd);
202 156 kwoo
}
203
204 164 kwoo
//#define SPM_PAGESIZE 32
205 169 kwoo
/*BOOTLOADER_SECTION*/ void onboard_program_write(uint16_t page, uint8_t *buf) {
206 164 kwoo
  uint16_t i;
207
208
  boot_page_erase (page);
209
  boot_spm_busy_wait ();      // Wait until the memory is erased.
210
211
  for (i=0; i < SPM_PAGESIZE; i+=2){
212
    // Set up little-endian word.
213 168 kwoo
    boot_page_fill (page + i, buf[i] | (buf[i+1] <<8));
214 164 kwoo
  }
215
216
  boot_page_write (page);     // Store buffer in flash page.
217
  boot_spm_busy_wait();       // Wait until the memory is written.
218
}
219
220 169 kwoo
/*BOOTLOADER_SECTION*/ int main(void) {
221 164 kwoo
  uint8_t mbuf[PROGD_PACKET_SIZE];
222 168 kwoo
  rjump_t jbuf;
223 161 kwoo
  uint16_t caddr = MAIN_ADDR;
224 168 kwoo
  uint8_t iteration;
225 158 kwoo
  uint8_t resp;
226 168 kwoo
  uint16_t prog_len;
227 165 kwoo
  uint8_t i;
228 168 kwoo
229 169 kwoo
  //main_start = (void*)(BOOT_START - 2);
230 168 kwoo
  iteration = 0;
231 158 kwoo
232 155 bneuman
  init_uart(51); //MAGIC NUMBER??
233 154 bneuman
234
  //set LED pin as output
235 161 kwoo
  LED_DDR |= 0x07;
236 167 kwoo
  PORTB = 0x07;
237 154 bneuman
238
  //Start bootloading process
239 158 kwoo
  send_packet(TT_BOOT);
240 154 bneuman
241 158 kwoo
  resp = parse_packet(mbuf);
242
  if (resp == TT_PROGM) {
243
    prog_len = mbuf[0];
244
    prog_len |= mbuf[1] << 8;
245
  } else {
246 168 kwoo
      //PORTB = 0;
247 161 kwoo
      main_start();
248 154 bneuman
  }
249 158 kwoo
  send_packet(TT_ACK);
250 154 bneuman
251
  while(1) {
252 158 kwoo
      resp = parse_packet(mbuf);
253 154 bneuman
254 161 kwoo
      if (resp == TT_PROGD) {
255 164 kwoo
          if (iteration == 0) {
256 165 kwoo
              // Store the jump to user code
257 168 kwoo
              jbuf.bytes[0] = mbuf[0];
258
              jbuf.bytes[1] = mbuf[1];
259
260
              jbuf.sword &= 0x0FFF;
261 169 kwoo
              jbuf.sword -= (BOOT_START >> 1) - 1;
262 168 kwoo
              jbuf.sword &= 0x0FFF;
263
              jbuf.sword |= 0xC000;
264 165 kwoo
265 169 kwoo
              mbuf[0] = (BOOT_START/2 - 1) & 0xFF;
266
              mbuf[1] = 0xC0 | (((BOOT_START/2 - 1) >> 8) & 0x0F);
267
              //memcpy_P(mbuf, (PGM_VOID_P)MAIN_ADDR, 2);
268
              //mbuf[0] = pgm_read_byte(MAIN_ADDR);
269
              //mbuf[1] = pgm_read_byte(MAIN_ADDR + 1);
270 168 kwoo
              //PORTB &= ~_BV(PORTB0);
271
              //while(1);
272 165 kwoo
273 164 kwoo
              iteration = 1;
274 168 kwoo
          } /*else {
275
              PORTB &= ~_BV(PORTB1);
276
              while(1);
277
          }*/
278 167 kwoo
279 168 kwoo
280 167 kwoo
          onboard_program_write(caddr, mbuf);
281
          caddr += PROGD_PACKET_SIZE;
282 161 kwoo
      } else {
283 166 kwoo
          //main_start();
284 168 kwoo
          PORTB &= ~_BV(PORTB2);
285 166 kwoo
          while(1);
286 161 kwoo
      }
287
288 158 kwoo
      send_packet(TT_ACK);
289 161 kwoo
290
      if (prog_len <= PROGD_PACKET_SIZE) {
291 165 kwoo
          for (i = 0; i < PROGD_PACKET_SIZE; i++) {
292
              mbuf[i]= 0;
293
          }
294
295 168 kwoo
          mbuf[PROGD_PACKET_SIZE-2] = jbuf.bytes[0];
296
          mbuf[PROGD_PACKET_SIZE-1] = jbuf.bytes[1];
297 165 kwoo
298 168 kwoo
          onboard_program_write(BOOT_START - SPM_PAGESIZE, mbuf);
299 165 kwoo
300 164 kwoo
          PORTB = 0;
301 161 kwoo
          main_start();
302
      } else {
303
          prog_len -= PROGD_PACKET_SIZE;
304
      }
305 154 bneuman
  }
306 169 kwoo
307
  return -1;
308 154 bneuman
}
309
310 168 kwoo
/*
311 165 kwoo
int main (void) {
312
    while(1);
313 168 kwoo
}*/