Project

General

Profile

Statistics
| Revision:

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

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