~shadowrobot/sr-ros-interface-ethercat/friction_comp_tests

« back to all changes in this revision

Viewing changes to sr_external_dependencies/released/external/simplemotor-bootloader/.svn/text-base/boot.c.svn-base

  • Committer: Toni Oliver Duran
  • Date: 2012-01-26 11:31:12 UTC
  • mfrom: (530.2.8 shadow_robot_ethercat)
  • Revision ID: toni@mallorca-20120126113112-74x2v7fh82fxrtpt
Merged with rewrite-bootloader.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
2
// � 2010 Shadow Robot Company Limited.
 
3
//
 
4
// FileName:        boot.c
 
5
// Dependencies:    
 
6
// Processor:       PIC18
 
7
// Compiler:        MPLAB� C18 
 
8
//
 
9
//  +-------------------------------------------------------------------------------+
 
10
//  | This file is part of The Shadow Robot PIC18 firmware code base.               |
 
11
//  |                                                                               |
 
12
//  | It is free software: you can redistribute it and/or modify                    |
 
13
//  | it under the terms of the GNU General Public License as published by          |
 
14
//  | the Free Software Foundation, either version 3 of the License, or             |
 
15
//  | (at your option) any later version.                                           |
 
16
//  |                                                                               |
 
17
//  | It is distributed in the hope that it will be useful,                         |
 
18
//  | but WITHOUT ANY WARRANTY; without even the implied warranty of                |
 
19
//  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                 |
 
20
//  | GNU General Public License for more details.                                  |
 
21
//  |                                                                               |
 
22
//  | You should have received a copy of the GNU General Public License (gpl.txt)   |
 
23
//  | along with this code repository. The text of the license can be found         |
 
24
//  | in Pic32/License/gpl.txt. If not, see <http://www.gnu.org/licenses/>.         |
 
25
//  +-------------------------------------------------------------------------------+
 
26
//
 
27
//
 
28
// This file implements the bulk of the CAN bootloader.
 
29
//
 
30
 
1
31
#include "basics.h"
2
32
#include <p18f2580.h>
3
33
 
4
 
 
5
 
#define CAN_SJW         0x01    // range 1..4       Synchronisation Jump Width
6
 
#define CAN_BRP         0x02    // range 1..64      Baud Rate Prescaler
7
 
#define CAN_PHSEG1      0x01    // range 1..8       Phase Segment 1
8
 
#define CAN_PHSEG2      0x02    // range 1..8       Phase Segment 2
9
 
#define CAN_PROPSEG     0x06    // range 1..8       Propagation Segment
10
 
#define CAN_SAM         0x00    // range 0 or 1     Sample type (0==once, 1==three times)
11
 
#define CAN_SEG2PHTS    0x00    // range 0 or 1     
12
 
 
13
 
#define CAN_CONFIG_MODE     0b10000000
 
34
                                            // These are values for setting up the CAN baud rate and timings
 
35
                                            // -------------------------------------------------------------
 
36
#define CAN_SJW         0x01                // range 1..4       Synchronisation Jump Width
 
37
#define CAN_BRP         0x02                // range 1..64      Baud Rate Prescaler
 
38
#define CAN_PHSEG1      0x01                // range 1..8       Phase Segment 1
 
39
#define CAN_PHSEG2      0x02                // range 1..8       Phase Segment 2
 
40
#define CAN_PROPSEG     0x06                // range 1..8       Propagation Segment
 
41
#define CAN_SAM         0x00                // range 0 or 1     Sample type (0==once, 1==three times)
 
42
#define CAN_SEG2PHTS    0x00                // range 0 or 1     
 
43
 
 
44
#define CAN_CONFIG_MODE     0b10000000      // 
14
45
#define CAN_LISTEN_MODE     0b01100000
15
46
#define CAN_LOOPBACK_MODE   0b01000000
16
47
#define CAN_DISABLE_MODE    0b00100000
25
56
#define CFGS        6
26
57
#define GIE         7
27
58
 
 
59
 
28
60
//! These are the different commands the bootloader accepts.
29
61
//! 
30
62
typedef enum
37
69
    WRITE_FLASH_ADDRESS_COMMAND   = 0x05,
38
70
    MAGIC_PACKET                  = 0x0A
39
71
}BOOTLOADER_COMMAND;
40
 
 
41
 
#define WAITING_FOR_ADDRESS             0x00
42
 
#define BUFFERING_DATA                  0x01
43
 
 
44
 
// The motor_id, hardcoded, this will have to be put in EEPROM in the future.
45
 
int8u motor_id = 0xFF;
46
 
 
47
 
 
48
 
 
49
 
#pragma code VIntH=0x0008
50
 
 
51
 
//! This function remaps the High Interrupt Vector
52
 
//! 
53
 
//! @author Yann Sionneau
54
 
void VIntH(void)
55
 
{
56
 
    _asm
57
 
        goto 0x0270 
58
 
    _endasm
59
 
}
60
 
 
61
 
#pragma code
62
 
 
63
 
 
64
 
#pragma code VIntL=0x000e
65
 
 
66
 
//! This function remaps the Low Interrupt Vector
67
 
//! 
68
 
//! @author Yann Sionneau
69
 
void VIntL(void)
70
 
{
71
 
    _asm
72
 
        goto 0x0280
73
 
    _endasm
74
 
}
75
 
 
76
 
 
77
 
 
78
 
#pragma code
79
 
 
80
 
//#pragma code BOOT
81
 
 
82
 
typedef enum _ECAN_RX_MSG_FLAGS
 
72
 
 
73
typedef enum
83
74
{
84
75
    ECAN_RX_OVERFLOW     = 0b00001000,
85
76
    ECAN_RX_INVALID_MSG  = 0b00010000,
89
80
 
90
81
} ECAN_RX_MSG_FLAGS;
91
82
 
 
83
 
 
84
 
 
85
//! Structure to store an incoming or outgoing CAN messages.
92
86
struct CANmsg 
93
87
{
94
88
        int16u messageID;
101
95
        } d;
102
96
        int8u length;
103
97
        ECAN_RX_MSG_FLAGS flags;
104
 
} CanMsgR; // declares the reception CAN message
105
 
 
106
 
struct CANmsg CanMsgT; // declares the transmit CAN message
107
 
 
108
 
int8u position; // this is the position of the current FLASH_WRITTING operation ( 0 <= position <= 32)
109
 
 
110
 
 
 
98
};
 
99
struct CANmsg CanMsgT;                          //!< Structure to store CAN message to be transmitted
 
100
struct CANmsg CanMsgR;                          //!< Structure to store CAN message just received
 
101
 
 
102
 
 
103
int8u motor_id = 0xFF;                          //!< motor_id will be read from the EEPROM at boot time.
 
104
int8u position = 0x00;                          //!< this is the position of the current FLASH_WRITTING operation ( 0 <= position <= 32)
 
105
 
 
106
 
 
107
 
 
108
//! This function remaps the High Interrupt Vector
 
109
//! The user's High interrupt will be placed at address 0x0270, and this 
 
110
//! function will just straight to it.
 
111
//! 
 
112
//! @author Yann Sionneau
 
113
#pragma code VIntH=0x0008
 
114
void VIntH(void)
 
115
{
 
116
    _asm
 
117
        goto 0x0270 
 
118
    _endasm
 
119
}
 
120
#pragma code
 
121
 
 
122
 
 
123
//! This function remaps the Low Interrupt Vector
 
124
//! The user's Low interrupt will be placed at address 0x0270, and this 
 
125
//! function will just straight to it.
 
126
//! 
 
127
//! @author Yann Sionneau
 
128
#pragma code VIntL=0x000e
 
129
void VIntL(void)
 
130
{
 
131
    _asm
 
132
        goto 0x0280
 
133
    _endasm
 
134
}
 
135
#pragma code
 
136
 
 
137
 
 
138
 
 
139
 
 
140
 
 
141
 
 
142
//! Read one byte of EEPROM.
 
143
//!
 
144
//! @param  address     The EEPROM address of the byte to read
 
145
//!
 
146
//! @return             The value read from the EEPROM
 
147
//!
 
148
//! @author Yann Sionneau
111
149
static int8u read_eeprom(int8u address)
112
150
{
113
151
    EECON1 = 0;
117
155
    return EEDATA;
118
156
}
119
157
 
 
158
 
120
159
//! This checks if we should boot (start the user application), or stay in bootloader mode. 
121
160
//! We check the last byte of EEPROM if it is 0xFF it means no firmware has been
122
161
//! written in user application memory and we need to stay in bootloader mode,
194
233
    CANTX_DRIVE_VDD           = 0b00100000,
195
234
    CANTX_DRIVE_TRI_STATE     = 0b00000000
196
235
}CANTX_DRIVE_VALUES;
 
236
 
197
237
 
198
238
// The following #defines are used to configure the CAN bus,
199
239
// Specifically the speed and timing, among other things
200
 
/*
201
 
#define BAUD_RATE_PRESCALER                             2
202
 
#define SYNC_JUMP_WIDTH                SYNC_JUMP_WIDTH_1X
203
 
#define SEG2PHTS                            SEG2PHTS_FREE
204
 
#define SAMPLE_TIMES                        SAMPLE_THRICE
205
 
#define PHASE_SEGMENT_1                                 3
206
 
#define PHASE_SEGMENT_2                                 3
207
 
#define PROPAGATION_SEGMENT                             3
208
 
#define CAN_MODE                          CAN_MODE_LEGACY
209
 
#define RECEIVE_BUFFER_MODE     RECEIVE_STANDARD_MESSAGES
210
 
#define CANTX_DRIVE                       CANTX_DRIVE_VDD
211
 
*/
212
 
 
213
240
#define BAUD_RATE_PRESCALER                             1
214
241
#define SYNC_JUMP_WIDTH                SYNC_JUMP_WIDTH_2X
215
242
#define SEG2PHTS                            SEG2PHTS_FREE
221
248
#define RECEIVE_BUFFER_MODE     RECEIVE_STANDARD_MESSAGES
222
249
#define CANTX_DRIVE                       CANTX_DRIVE_VDD
223
250
 
 
251
 
224
252
//! This initializes the ECAN module of the PIC18F
225
253
//! It sets up the baud rate, filters, masks and CAN MODE.
226
254
//! 
228
256
static void can_init(void)
229
257
{
230
258
 
231
 
    while ((CANSTAT & 0b11100000) != CAN_CONFIG_MODE)       // Entering CAN Config mode
232
 
    {
 
259
    while ((CANSTAT & 0b11100000) != CAN_CONFIG_MODE)       // Enter CAN Config mode
233
260
        CANCON = CAN_CONFIG_MODE;
234
 
    }
235
261
 
236
262
    BRGCON1 = SYNC_JUMP_WIDTH | (BAUD_RATE_PRESCALER-1);                                        //0x41;
237
263
    BRGCON2 = SEG2PHTS | SAMPLE_TIMES | ((PHASE_SEGMENT_1-1)<<3) | (PROPAGATION_SEGMENT-1);     //0x0B;
238
264
    BRGCON3 = CAN_WAKE_DISABLE | (PHASE_SEGMENT_2-1);                                           //0x82;
239
265
 
240
 
 
241
 
                                                            // Setup the Baud Rate
242
 
/*
243
 
    //BRGCON1 = 0x41;                                         // These are the data copied from SimpleMotor
244
 
    //BRGCON2 = 0x0B;
245
 
    //BRGCON3 = 0x82;
246
 
 
247
 
    RXB0CON = 0;
248
 
 
249
 
    CIOCON = 0b00100000;
250
 
    PIE3 = 0;
251
 
*/
252
266
    
253
267
    ECANCON = CAN_MODE;                    
254
268
    RXB1CON = RECEIVE_BUFFER_MODE;
255
269
    RXB0CON = RECEIVE_BUFFER_MODE;
256
270
    CIOCON  = CANTX_DRIVE;
257
271
 
258
 
    RXF0SIDH = 0b11000000 | (motor_id << 2);
259
 
    RXF0SIDL = 0;
260
 
    RXF1SIDH = 0b11000000 | (motor_id << 2);
261
 
    RXF1SIDL = 0;
262
 
    RXM0SIDH = 0b11111100;  // set mask to 0b11111100000
263
 
    RXM0SIDL = 0;
 
272
    RXF0SIDH = 0b11000000 | (motor_id << 2);                // This mask/filter is used to accept bootloader messages 0b11MMMMxxxxx
 
273
    RXF0SIDL = 0;                                           // 
 
274
    RXF1SIDH = 0b11000000 | (motor_id << 2);                // 
 
275
    RXF1SIDL = 0;                                           // 
 
276
    RXM0SIDH = 0b11111100;                                  // set mask to                                            0b11111100000
 
277
    RXM0SIDL = 0;                                           // 
264
278
 
265
 
    RXF2SIDH = 0;
266
 
    RXF2SIDL = 0;
267
 
    RXF3SIDH = 0;
268
 
    RXF3SIDL = 0;
269
 
    RXF4SIDH = 0;
270
 
    RXF4SIDL = 0;
271
 
    RXM1SIDH = 0b11111111;
272
 
    RXM1SIDL = 0b11100000;
273
 
 
274
 
    TRISB &= ~(1 << 2); 
275
 
 
276
 
    // Enter Normal Mode
277
 
    while ((CANSTAT & 0b11100000) != CAN_NORMAL_MODE)
 
279
    RXF2SIDH = 0;                                           // This mask/filter is not used.
 
280
    RXF2SIDL = 0;                                           // 
 
281
    RXF3SIDH = 0;                                           // 
 
282
    RXF3SIDL = 0;                                           // 
 
283
    RXF4SIDH = 0;                                           // 
 
284
    RXF4SIDL = 0;                                           // 
 
285
    RXM1SIDH = 0b11111111;                                  // 
 
286
    RXM1SIDL = 0b11100000;                                  //  
 
287
 
 
288
    TRISB &= ~(1 << 2);                                     // set CAN TX pin to output mode
 
289
 
 
290
    while ((CANSTAT & 0b11100000) != CAN_NORMAL_MODE)       // Enter Normal Mode
278
291
        CANCON = CAN_NORMAL_MODE;
279
292
}
280
 
 
281
 
/*
282
 
    11 0100 0 0001
283
 
F0: 11 0100 0 0000
284
 
F1: 11 0100 0 0000
285
 
F2: 01 0000 0 1000
286
 
 
287
 
M0: 11 1111 0 0000
288
 
M1: 00 0011 0 1001
289
 
*/
 
293
 
 
294
 
290
295
 
291
296
//! This is the "Send Can Message" function.
292
297
//! It sends the content of the CanMsgT struct over the CAN bus.
293
298
//!
294
 
//!
295
299
//! @author Yann Sionneau
296
300
static void sendCanMsg(void)
297
301
{
298
 
    TXB0SIDL = ((CanMsgT.messageID << 5) & 0xff);
 
302
    TXB0SIDL = ((CanMsgT.messageID << 5) & 0xff);           // Load the message into the registers
299
303
    TXB0SIDH = ((CanMsgT.messageID >> 3) & 0xff);
300
304
    TXB0DLC  = CanMsgT.length;
301
305
    TXB0D0   = CanMsgT.d.byte[0];
307
311
    TXB0D6   = CanMsgT.d.byte[6];
308
312
    TXB0D7   = CanMsgT.d.byte[7];
309
313
 
310
 
    TXB0CON |= (1 << TXREQ);        // Now transmit that message
 
314
    TXB0CON |= (1 << TXREQ);                                // Now transmit that message
311
315
}
312
316
 
 
317
 
313
318
//! This function erases the program memory (which is flash)
314
319
//! It only erases the user application
315
320
//! So it starts erasing after the bootloader and stops before the debugger code
317
322
//! @author Yann Sionneau
318
323
static void erase_flash(void)
319
324
{
320
 
    overlay int16u i = 0;
 
325
    overlay int16u address = 0;         // address we're erasing
321
326
 
322
 
    i = 0x04c0;                         // user application start address
 
327
    address = 0x04c0;                   // user application start address
323
328
                                        // 0x7dc0 is the start of debugger code
324
329
 
325
 
    while (i < 0x7dc0)                  // and we don't want to erase debugger code
 
330
    while (address < 0x7dc0)            // and we don't want to erase debugger code
326
331
    {
327
 
        TBLPTR  = i;           
 
332
        TBLPTR  = address;
328
333
        TBLPTR &= 0xFFFFE0;
329
334
        
330
335
        EECON1 |=128;                   // point to Flash program memory
340
345
        {
341
346
        }
342
347
 
343
 
        INTCON |= 128;
344
 
        i += 64;
 
348
        INTCON |= 128;                  // enable interrupts
 
349
        address += 64;
345
350
    }   
346
351
}
347
352
 
375
380
 
376
381
 
377
382
//! This function acknowledges ( most of ) the commands.
378
 
//! Which means sending back the same content, same length, same SID but with the "ACK" bit (0x10).
 
383
//! Which means sending back the same content, same length, same SID but with the "ACK" bit (0x10) set
379
384
//!
380
385
//! @author Yann Sionneau
381
386
static void acknowledge_packet(void)
382
387
{
383
 
    CanMsgT.messageID = CanMsgR.messageID | 0x10;       // ACK bit
384
 
    CanMsgT.d.byte[0] = CanMsgR.d.byte[0];
385
 
    CanMsgT.d.byte[1] = CanMsgR.d.byte[1];
386
 
    CanMsgT.d.byte[2] = CanMsgR.d.byte[2];
387
 
    CanMsgT.d.byte[3] = CanMsgR.d.byte[3];
388
 
    CanMsgT.d.byte[4] = CanMsgR.d.byte[4];
389
 
    CanMsgT.d.byte[5] = CanMsgR.d.byte[5];
390
 
    CanMsgT.d.byte[6] = CanMsgR.d.byte[6];
391
 
    CanMsgT.d.byte[7] = CanMsgR.d.byte[7];
392
 
    CanMsgT.length    = CanMsgR.length;
393
 
    sendCanMsg();
 
388
    CanMsgT = CanMsgR;
 
389
    CanMsgT.messageID |= 0x10;          // Just add the ACK bit
 
390
    sendCanMsg();                       // And send the message back
394
391
}
395
392
 
396
393
 
401
398
//! @author Yann Sionneau
402
399
static void write_flash_address(void)
403
400
{
404
 
    position = 0; // resets the position to 0, we are starting to write a 32 bytes block
 
401
    position = 0;                       // resets the position to 0, we are starting to write a 32 bytes block
405
402
    TBLPTRU = CanMsgR.d.byte[2];
406
403
    TBLPTRH = CanMsgR.d.byte[1];
407
404
    TBLPTRL = CanMsgR.d.byte[0];
410
407
 
411
408
 
412
409
//! This function does the actual writting in program memory (which is FLASH).
413
 
//! Writting the flash has to be done by 32 bytes blocks. But we can only transport
 
410
//! Writting the flash has to be done in blocks of 32 bytes. But we can only transport
414
411
//! 8 bytes of data in a CAN message, so we do the block writting in 4 CAN commands.
415
412
//! So this command writes 8 bytes, and is called several times (4 times in theory)
416
413
//! Each time it is called the "position" variable gets added 8.
417
414
//! When position gets equal to 32, it means we have buffered a block and we can start
418
 
//! the writting procedure.
 
415
//! the writing procedure.
419
416
//!
420
417
//! @author Yann Sionneau
421
418
static void write_flash_data(void)
432
429
 
433
430
    position += 8;                                      // We just buffered 8 more bytes
434
431
 
435
 
    if (position == 32)                                 // We have buffured a 32 bytes block, we can start the writting procedure
 
432
    if (position == 32)                                 // If we have buffured a 32 bytes block, we can start the wrtting procedure
436
433
    {
437
434
        _asm
438
435
            TBLRDPOSTDEC                                // We do a TBLRDPOSTDEC in order for the TBLPTR addressing register to stay in the range of the 32 bytes
450
447
        EECON1 &= ~(1 << WREN);                         // disable write to memory
451
448
        position = 0;                                   // reset the position to 0, we just finished a 32 bytes block
452
449
    }
453
 
 
450
}
 
451
 
 
452
 
454
453
 
455
454
//! This function writes to the EEPROM memory
456
455
//! The only goal of this function is to write something different than 0xFF
473
472
    EECON2  = 0xaa;
474
473
    EECON1 |= (1 << WR);                                // do the write
475
474
 
476
 
    while (EECON1 & (1 << WR));                         // wait for the write to finish
 
475
    while (EECON1 & (1 << WR))                          // wait for the write to finish
 
476
    {
 
477
    }
477
478
 
478
479
    INTCON |=  (1 << GIE );                             // enable back interrupts
479
480
    EECON1 &= ~(1 << WREN);                             // disable write to memory
532
533
                write_eeprom();
533
534
                acknowledge_packet();
534
535
                _asm
535
 
                    goto 0x0000                     // This jumps to the Reset vector
 
536
                    goto 0x0000                         // This jumps to the Reset vector
536
537
                _endasm
537
538
                // no break needed because of the goto above
538
539
 
539
 
            case READ_VERSION_COMMAND: // should return the boot loader version number
 
540
            case READ_VERSION_COMMAND:                  // should return the boot loader version number
540
541
                CanMsgT.messageID = CanMsgR.messageID | 0x10;
541
542
                CanMsgT.d.byte[0] = 0x40;
542
543
                CanMsgT.d.byte[1] = 0x41;
546
547
                sendCanMsg();
547
548
                break;
548
549
 
549
 
            case MAGIC_PACKET: // Means "reboot", it will be ACK'ed at boot time (in the main())
 
550
            case MAGIC_PACKET:                          // Means "reboot", it will be ACK'ed at boot time (in the main())
550
551
                _asm
551
552
                    goto 0x0000
552
553
                _endasm
557
558
        }
558
559
    }
559
560
 
560
 
    if ( (RXB1CON & (1 << RXFUL) ) )
 
561
/*
 
562
    if ( (RXB1CON & (1 << RXFUL) ) )                    // DEBUGGING
561
563
    {
562
564
        Nop();
563
 
    }
 
565
    }
 
566
*/
564
567
}
565
568
 
 
569
 
 
570
 
 
571
//! Called in case a serious error is discovered.
 
572
//! Just sits and does nothing. Safer that way.
 
573
//! 
 
574
//! @author Yann Sionneau
566
575
void serious_error(void)
567
576
{
568
577
    while(1)
569
578
    {
570
579
    }
571
580
}
 
581
 
 
582
 
 
583
 
 
584
//! Sending a hello message tells the host the we have entered bootloader mode.
 
585
//! 
 
586
//! @author Yann Sionneau
 
587
void send_bootloader_hello_message(void)
 
588
{
 
589
    CanMsgT.length = 8;                     // The following lines craft an ACK for a switch-to-bootloader message
 
590
 
 
591
    CanMsgT.d.word[0] = 0xAA55;             // swapped because of endianness
 
592
    CanMsgT.d.word[1] = 0xAA55;
 
593
    CanMsgT.d.word[2] = 0xAA55;
 
594
    CanMsgT.d.word[3] = 0xAA55;
 
595
    CanMsgT.messageID = motor_id;
 
596
    CanMsgT.messageID <<= 5;
 
597
    CanMsgT.messageID  |= 0x600 | 0x0010 | 0x00A;
 
598
 
 
599
    sendCanMsg();                           // We ACK the magic packet at boot time
 
600
}
 
601
 
 
602
 
572
603
 
573
604
//! Main function
574
605
//! This is always executed at startup of the PIC18F regardless of whether there is
577
608
//! @author Yann Sionneau
578
609
void main(void)
579
610
{
580
 
    overlay int8u i = 0;
581
 
    
582
611
    WDTCON = 0;                             // disables the watchdog
583
612
                                            // has no effect if the configuration bit WDTEN is enabled
584
613
 
585
 
 
586
614
    motor_id = read_eeprom(0x00);
587
615
 
588
616
    if (motor_id == 0xFF)
598
626
 
599
627
                                            // From here we are in boot loader mode
600
628
                                            // ------------------------------------
601
 
 
602
629
 
603
630
    position = 0;                           // Resets the position for the "write to flash" process
604
631
    can_init();                             // Initializes ECAN module
605
 
 
606
 
    CanMsgT.length = 8;                     // The following lines craft an ACK for a magic packet
607
 
 
608
 
 
609
 
    //CanMsgT.messageID = 0x600 | (motor_id << 5) | 0x0010 | 0x00A;     // Don't do it this way! (motor_id << 5) looses the top bit.
610
 
 
611
 
    CanMsgT.messageID = motor_id;                                       // Do it this way. CanMsgT.messageID is 16 bits.
612
 
    CanMsgT.messageID <<= 5;
613
 
    CanMsgT.messageID  |= 0x600 | 0x0010 | 0x00A;
614
 
 
615
 
    for (i = 0 ; i < 4 ; ++i)
616
 
        CanMsgT.d.word[i] = 0xAA55;         // swapped because of endianness
617
 
 
618
 
    sendCanMsg();                           // We ACK the magic packet at boot time
619
 
 
620
 
 
621
 
    while ( 1 )                             // Main loop
622
 
    {
 
632
    send_bootloader_hello_message();        // Tell the host we have entered bootloader mode, and are ready to program!
 
633
 
 
634
 
 
635
 
 
636
    while (1)                               // Main loop
 
637
    {                                       // ---------
623
638
        handle_can_msg();                   // checks if we have received a CAN msg, and handles it
624
639
    }
625
 
 
626
640
}