Project

General

Profile

Statistics
| Revision:

root / trunk / code / projects / wireless_bootloader / wireless_bootloader.c @ 1439

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
}