root / trunk / code / projects / wireless_bootloader / wireless_bootloader.c @ 1443
History | View | Annotate | Download (9.11 KB)
1 |
/*
|
---|---|
2 |
adapted from "Wireless bootloader for the ATmega168 and XBee Series 1 modules"
|
3 |
orginal code copyright 2009 Nathan Seidle, Spark Fun Electronics?
|
4 |
|
5 |
Modifications for Colony Project, Robotics Club, Carngie Mellon University
|
6 |
by Ryan Cahoon
|
7 |
*/
|
8 |
|
9 |
#include <avr/io.h> |
10 |
#include <util/delay.h> |
11 |
#include <avr/boot.h> |
12 |
|
13 |
#define TRUE 0 |
14 |
#define FALSE 1 |
15 |
|
16 |
//Status LEDs
|
17 |
#define LED_DDR DDRC
|
18 |
#define LED_PORT PORTC
|
19 |
#define LED_PIN PINC
|
20 |
#define LED (_BV(PINC1) | _BV(PINC5))
|
21 |
|
22 |
//Command Button
|
23 |
#define BLPORT PORTG
|
24 |
#define BLDDR DDRG
|
25 |
#define BLPIN PING
|
26 |
#define BLPNUM PING0
|
27 |
|
28 |
//Function prototypes
|
29 |
void setup_uart0(void); |
30 |
void setup_uart1(void); |
31 |
void putch0(char); |
32 |
void putch1(char); |
33 |
int getch0(void); |
34 |
int getch1(void); |
35 |
void flash_led(uint8_t);
|
36 |
void onboard_program_write(uint32_t page, uint8_t *buf);
|
37 |
int bootloader(int force); |
38 |
int xbee_setup(int robotNum); |
39 |
int xbee_reset(void); |
40 |
int code_transfer(int (*getch)(void), void (*putch)(char)); |
41 |
|
42 |
int usb_send(char* buf, int size); |
43 |
|
44 |
void (*main_start)(void) = 0x0000; |
45 |
|
46 |
//Variables
|
47 |
uint8_t incoming_page_data[256];
|
48 |
uint8_t retransmit_flag = FALSE; |
49 |
|
50 |
union page_address_union {
|
51 |
uint16_t word; |
52 |
uint8_t byte[2];
|
53 |
}; |
54 |
union page_address_union page_address;
|
55 |
union page_address_union page_length;
|
56 |
|
57 |
int main(void) |
58 |
{ |
59 |
return bootloader(0); |
60 |
} |
61 |
|
62 |
#define EEPROM_ROBOT_ID_ADDR 0x10 |
63 |
int eeprom_get_byte(unsigned int uiAddress, unsigned char *byte) { |
64 |
/* Wait for completion of previous write */
|
65 |
while(EECR & (1<<EEWE)); |
66 |
/* Set up address register */
|
67 |
EEAR = uiAddress; |
68 |
/* Start eeprom read by writing EERE */
|
69 |
EECR |= (1<<EERE);
|
70 |
/* get data from data register */
|
71 |
*byte=EEDR; |
72 |
|
73 |
return 0; |
74 |
} |
75 |
unsigned char get_robotid(void) { |
76 |
unsigned char c0, c1, c2; |
77 |
|
78 |
eeprom_get_byte(EEPROM_ROBOT_ID_ADDR, &c0); |
79 |
eeprom_get_byte(EEPROM_ROBOT_ID_ADDR+1, &c1);
|
80 |
eeprom_get_byte(EEPROM_ROBOT_ID_ADDR+2, &c2);
|
81 |
if(c0 == 'I' && c1 == 'D') |
82 |
return c2;
|
83 |
else
|
84 |
return 0xFF; |
85 |
} |
86 |
|
87 |
int bootloader(int force) |
88 |
{ |
89 |
int robotId;
|
90 |
|
91 |
// check if button pressed
|
92 |
int oldBLDDR = BLDDR;
|
93 |
int oldBLPORT = BLPORT;
|
94 |
BLDDR &= ~(1<<BLPNUM); // set as Input |
95 |
BLPORT |= (1<<BLPNUM); // Enable pullup |
96 |
|
97 |
if ((BLPIN & (1<<BLPNUM)) && !force) { |
98 |
// jump to main app if pin is not grounded
|
99 |
BLPORT = oldBLPORT; // set to default
|
100 |
BLDDR = oldBLDDR; |
101 |
main_start(); // Jump to application sector
|
102 |
} |
103 |
|
104 |
//set LED pin as output
|
105 |
LED_DDR |= 0x77;
|
106 |
|
107 |
flash_led(1);
|
108 |
|
109 |
robotId = get_robotid(); |
110 |
|
111 |
setup_uart1(); |
112 |
xbee_setup(robotId); |
113 |
setup_uart0(); |
114 |
|
115 |
//turn on LED to signal entering of bootloader
|
116 |
LED_PORT = ~LED; |
117 |
|
118 |
//Start bootloading process
|
119 |
|
120 |
//Wait for the computer
|
121 |
while(1) |
122 |
{ |
123 |
// transfering over USB
|
124 |
if (getch0()==6) |
125 |
code_transfer(getch0, putch0); |
126 |
// transfering over wireless
|
127 |
if (getch1()==6) |
128 |
code_transfer(getch1, putch1); |
129 |
|
130 |
// Communication testing code:
|
131 |
/*int ch0 = getch0();
|
132 |
if (ch0 >= 0)
|
133 |
{
|
134 |
putch1(ch0);
|
135 |
PORTC ^= 0x70;
|
136 |
}
|
137 |
int ch1 = getch1();
|
138 |
if (ch1 >= 0)
|
139 |
{
|
140 |
putch0(ch1);
|
141 |
PORTC ^= 0x07;
|
142 |
}*/
|
143 |
} |
144 |
|
145 |
return 0; |
146 |
} |
147 |
|
148 |
int code_transfer(int (*getch)(void), void (*putch)(char)) |
149 |
{ |
150 |
uint8_t check_sum = 0;
|
151 |
uint16_t i; |
152 |
|
153 |
retransmit_flag = FALSE; |
154 |
|
155 |
LED_PORT |= 0x77;
|
156 |
LED_PORT &= 0x9A;
|
157 |
|
158 |
while(1) |
159 |
{ |
160 |
// Flash the orbs to show progress
|
161 |
PORTC ^= 0x77;
|
162 |
|
163 |
//Determine if the last received data was good or bad
|
164 |
if (check_sum != 0) //If the check sum does not compute, tell computer to resend same line |
165 |
RESTART: |
166 |
putch(7); //Tell the computer to retransmit the last page |
167 |
else
|
168 |
putch('T'); //Tell the computer that we are ready for the next line |
169 |
|
170 |
while(1) //Wait for the computer to initiate transfer |
171 |
{ |
172 |
if (getch() == ':') break; //This is the "gimme the next chunk" command |
173 |
if (retransmit_flag == TRUE) goto RESTART; |
174 |
} |
175 |
|
176 |
//Get the length of this block
|
177 |
page_length.byte[0] = getch(); if (retransmit_flag == TRUE) goto RESTART; |
178 |
page_length.byte[1] = getch(); if (retransmit_flag == TRUE) goto RESTART; |
179 |
|
180 |
if (page_length.byte[0] == 'S') //Check to see if we are done - this is the "all done" command |
181 |
{ |
182 |
//Wait for any flash writes to complete
|
183 |
boot_rww_enable (); |
184 |
|
185 |
// signal programming done
|
186 |
LED_PORT |= 0x77;
|
187 |
flash_led(1);
|
188 |
|
189 |
// reset xbee
|
190 |
xbee_reset(); |
191 |
|
192 |
flash_led(2);
|
193 |
|
194 |
// reset robot
|
195 |
WDTCR &= 0xF8;
|
196 |
WDTCR |= 0x08;
|
197 |
while(1); |
198 |
} |
199 |
|
200 |
//Get the memory address at which to store this block of data
|
201 |
page_address.byte[0] = getch(); if (retransmit_flag == TRUE) goto RESTART; |
202 |
page_address.byte[1] = getch(); if (retransmit_flag == TRUE) goto RESTART; |
203 |
|
204 |
check_sum = getch(); //Pick up the check sum for error dectection
|
205 |
if (retransmit_flag == TRUE) goto RESTART; |
206 |
|
207 |
for(i = 0 ; i < page_length.word ; i++) //Read the program data |
208 |
{ |
209 |
incoming_page_data[i] = getch(); |
210 |
if (retransmit_flag == TRUE) goto RESTART; |
211 |
} |
212 |
|
213 |
//Calculate the checksum
|
214 |
for(i = 0 ; i < page_length.word ; i++) |
215 |
check_sum += incoming_page_data[i]; |
216 |
|
217 |
check_sum += page_length.byte[0];
|
218 |
check_sum += page_length.byte[1];
|
219 |
check_sum += page_address.byte[0];
|
220 |
check_sum += page_address.byte[1];
|
221 |
|
222 |
if(check_sum == 0) //If we have a good transmission, put it in ink |
223 |
onboard_program_write((uint32_t)page_address.word, incoming_page_data); |
224 |
} |
225 |
|
226 |
return 0; |
227 |
} |
228 |
|
229 |
void onboard_program_write(uint32_t page, uint8_t *buf)
|
230 |
{ |
231 |
uint16_t i; |
232 |
|
233 |
boot_page_erase (page); |
234 |
boot_spm_busy_wait (); // Wait until the memory is erased.
|
235 |
|
236 |
for (i=0; i<SPM_PAGESIZE; i+=2) |
237 |
{ |
238 |
// Set up little-endian word.
|
239 |
|
240 |
uint16_t w = *buf++; |
241 |
w += (*buf++) << 8;
|
242 |
|
243 |
boot_page_fill (page + i, w); |
244 |
} |
245 |
|
246 |
boot_page_write (page); // Store buffer in flash page.
|
247 |
boot_spm_busy_wait(); // Wait until the memory is written.
|
248 |
} |
249 |
|
250 |
void flash_led(uint8_t count)
|
251 |
{ |
252 |
uint8_t i; |
253 |
|
254 |
for (i = 0; i < count; ++i) { |
255 |
LED_PORT = ~LED; |
256 |
_delay_ms(100);
|
257 |
LED_PORT = 0xff;
|
258 |
_delay_ms(100);
|
259 |
} |
260 |
} |
261 |
|
262 |
/**************************************************************************************/
|
263 |
|
264 |
#define MYUBRR (((((F_CPU * 10) / (8L * baud)) + 5) / 10) - 1) |
265 |
|
266 |
#define MAX_CHARACTER_WAIT 15 |
267 |
#define MAX_WAIT_IN_CYCLES ( ((MAX_CHARACTER_WAIT * 8) * F_CPU) / baud ) |
268 |
|
269 |
long baud = 9600; |
270 |
|
271 |
void setup_uart0(void) |
272 |
{ |
273 |
//Setup USART baud rate
|
274 |
UBRR0H = MYUBRR >> 8;
|
275 |
UBRR0L = MYUBRR; |
276 |
UCSR0B = (1<<RXEN0)|(1<<TXEN0); |
277 |
UCSR0A |= _BV(U2X0); |
278 |
} |
279 |
void setup_uart1(void) |
280 |
{ |
281 |
//Setup USART baud rate
|
282 |
UBRR1H = MYUBRR >> 8;
|
283 |
UBRR1L = MYUBRR; |
284 |
UCSR1B = (1<<RXEN1)|(1<<TXEN1); |
285 |
UCSR1A |= _BV(U2X1); |
286 |
} |
287 |
|
288 |
void putch0(char ch) |
289 |
{ |
290 |
while (!(UCSR0A & _BV(UDRE0)));
|
291 |
UDR0 = ch; |
292 |
} |
293 |
void putch1(char ch) |
294 |
{ |
295 |
while (!(UCSR1A & _BV(UDRE1)));
|
296 |
UDR1 = ch; |
297 |
} |
298 |
|
299 |
int getch0(void) |
300 |
{ |
301 |
retransmit_flag = FALSE; |
302 |
|
303 |
uint32_t count = 0;
|
304 |
while(!(UCSR0A & _BV(RXC0)))
|
305 |
{ |
306 |
count++; |
307 |
if (count > MAX_WAIT_IN_CYCLES)
|
308 |
{ |
309 |
retransmit_flag = TRUE; |
310 |
return -1; |
311 |
} |
312 |
} |
313 |
|
314 |
return UDR0;
|
315 |
} |
316 |
|
317 |
int getch1(void) |
318 |
{ |
319 |
retransmit_flag = FALSE; |
320 |
|
321 |
uint32_t count = 0;
|
322 |
while(!(UCSR1A & _BV(RXC1)))
|
323 |
{ |
324 |
count++; |
325 |
if (count > MAX_WAIT_IN_CYCLES)
|
326 |
{ |
327 |
retransmit_flag = TRUE; |
328 |
return -1; |
329 |
} |
330 |
} |
331 |
|
332 |
return UDR1;
|
333 |
} |
334 |
|
335 |
|
336 |
|
337 |
int xbee_wait_for_ok(void) |
338 |
{ |
339 |
const char* s = "OK\r"; |
340 |
const char* curr = s; |
341 |
while (curr - s < 3) |
342 |
{ |
343 |
int c = getch1();
|
344 |
if (c>=0) |
345 |
{ |
346 |
if (c == *curr) {
|
347 |
curr++; |
348 |
} else {
|
349 |
curr = s; |
350 |
} |
351 |
} |
352 |
} |
353 |
|
354 |
return 0; |
355 |
} |
356 |
|
357 |
int xbee_send_command(const char* buf, int size) |
358 |
{ |
359 |
int i;
|
360 |
for (i = 0; i < size; i++) |
361 |
{ |
362 |
putch1(buf[i]); |
363 |
} |
364 |
|
365 |
xbee_wait_for_ok(); |
366 |
|
367 |
return 0; |
368 |
} |
369 |
|
370 |
int usb_send(char* buf, int size) |
371 |
{ |
372 |
int i;
|
373 |
for(i=0; i<size; i++) |
374 |
putch0(buf[i]); |
375 |
return 0; |
376 |
} |
377 |
|
378 |
int xbee_setup(int robotNum) |
379 |
{ |
380 |
char idstr[9] = "ATIDFF"; |
381 |
|
382 |
xbee_send_command("+++", 3); |
383 |
xbee_send_command("ATCH0C\r", 7); |
384 |
|
385 |
idstr[6] = (robotNum / 10) + 0x30; |
386 |
idstr[7] = robotNum % 10 + 0x30; |
387 |
idstr[8] = '\r'; |
388 |
xbee_send_command(idstr, 9);
|
389 |
|
390 |
xbee_send_command("ATDH0\r", 6); |
391 |
xbee_send_command("ATDLFFFF\r", 9); |
392 |
xbee_send_command("ATAP0\r", 6); |
393 |
xbee_send_command("ATBD6\r", 6); |
394 |
xbee_send_command("ATCN\r", 5); |
395 |
|
396 |
baud = 57600;
|
397 |
setup_uart1(); |
398 |
|
399 |
return 0; |
400 |
} |
401 |
|
402 |
int xbee_reset(void) |
403 |
{ |
404 |
// command sequence guard time
|
405 |
_delay_ms(1100);
|
406 |
xbee_send_command("+++", 3); |
407 |
xbee_send_command("ATBD3\r", 6); |
408 |
xbee_send_command("ATFR\r", 5); |
409 |
// delay 150 ms to wait for reset
|
410 |
_delay_ms(150);
|
411 |
|
412 |
return 0; |
413 |
} |