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