2
// � 2010 Shadow Robot Company Limited.
7
// Compiler: MPLAB� C18
9
// +-------------------------------------------------------------------------------+
10
// | This file is part of The Shadow Robot PIC18 firmware code base. |
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. |
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. |
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
// +-------------------------------------------------------------------------------+
28
// This file implements the bulk of the CAN bootloader.
2
32
#include <p18f2580.h>
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
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
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
37
69
WRITE_FLASH_ADDRESS_COMMAND = 0x05,
38
70
MAGIC_PACKET = 0x0A
39
71
}BOOTLOADER_COMMAND;
41
#define WAITING_FOR_ADDRESS 0x00
42
#define BUFFERING_DATA 0x01
44
// The motor_id, hardcoded, this will have to be put in EEPROM in the future.
45
int8u motor_id = 0xFF;
49
#pragma code VIntH=0x0008
51
//! This function remaps the High Interrupt Vector
53
//! @author Yann Sionneau
64
#pragma code VIntL=0x000e
66
//! This function remaps the Low Interrupt Vector
68
//! @author Yann Sionneau
82
typedef enum _ECAN_RX_MSG_FLAGS
84
75
ECAN_RX_OVERFLOW = 0b00001000,
85
76
ECAN_RX_INVALID_MSG = 0b00010000,
103
97
ECAN_RX_MSG_FLAGS flags;
104
} CanMsgR; // declares the reception CAN message
106
struct CANmsg CanMsgT; // declares the transmit CAN message
108
int8u position; // this is the position of the current FLASH_WRITTING operation ( 0 <= position <= 32)
99
struct CANmsg CanMsgT; //!< Structure to store CAN message to be transmitted
100
struct CANmsg CanMsgR; //!< Structure to store CAN message just received
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)
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.
112
//! @author Yann Sionneau
113
#pragma code VIntH=0x0008
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.
127
//! @author Yann Sionneau
128
#pragma code VIntL=0x000e
142
//! Read one byte of EEPROM.
144
//! @param address The EEPROM address of the byte to read
146
//! @return The value read from the EEPROM
148
//! @author Yann Sionneau
111
149
static int8u read_eeprom(int8u address)
194
233
CANTX_DRIVE_VDD = 0b00100000,
195
234
CANTX_DRIVE_TRI_STATE = 0b00000000
196
235
}CANTX_DRIVE_VALUES;
198
238
// The following #defines are used to configure the CAN bus,
199
239
// Specifically the speed and timing, among other things
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
213
240
#define BAUD_RATE_PRESCALER 1
214
241
#define SYNC_JUMP_WIDTH SYNC_JUMP_WIDTH_2X
215
242
#define SEG2PHTS SEG2PHTS_FREE
228
256
static void can_init(void)
231
while ((CANSTAT & 0b11100000) != CAN_CONFIG_MODE) // Entering CAN Config mode
259
while ((CANSTAT & 0b11100000) != CAN_CONFIG_MODE) // Enter CAN Config mode
233
260
CANCON = CAN_CONFIG_MODE;
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;
241
// Setup the Baud Rate
243
//BRGCON1 = 0x41; // These are the data copied from SimpleMotor
253
267
ECANCON = CAN_MODE;
254
268
RXB1CON = RECEIVE_BUFFER_MODE;
255
269
RXB0CON = RECEIVE_BUFFER_MODE;
256
270
CIOCON = CANTX_DRIVE;
258
RXF0SIDH = 0b11000000 | (motor_id << 2);
260
RXF1SIDH = 0b11000000 | (motor_id << 2);
262
RXM0SIDH = 0b11111100; // set mask to 0b11111100000
272
RXF0SIDH = 0b11000000 | (motor_id << 2); // This mask/filter is used to accept bootloader messages 0b11MMMMxxxxx
274
RXF1SIDH = 0b11000000 | (motor_id << 2); //
276
RXM0SIDH = 0b11111100; // set mask to 0b11111100000
271
RXM1SIDH = 0b11111111;
272
RXM1SIDL = 0b11100000;
277
while ((CANSTAT & 0b11100000) != CAN_NORMAL_MODE)
279
RXF2SIDH = 0; // This mask/filter is not used.
285
RXM1SIDH = 0b11111111; //
286
RXM1SIDL = 0b11100000; //
288
TRISB &= ~(1 << 2); // set CAN TX pin to output mode
290
while ((CANSTAT & 0b11100000) != CAN_NORMAL_MODE) // Enter Normal Mode
278
291
CANCON = CAN_NORMAL_MODE;
291
296
//! This is the "Send Can Message" function.
292
297
//! It sends the content of the CanMsgT struct over the CAN bus.
295
299
//! @author Yann Sionneau
296
300
static void sendCanMsg(void)
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];
310
TXB0CON |= (1 << TXREQ); // Now transmit that message
314
TXB0CON |= (1 << TXREQ); // Now transmit that message
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)
320
overlay int16u i = 0;
325
overlay int16u address = 0; // address we're erasing
322
i = 0x04c0; // user application start address
327
address = 0x04c0; // user application start address
323
328
// 0x7dc0 is the start of debugger code
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
328
333
TBLPTR &= 0xFFFFE0;
330
335
EECON1 |=128; // point to Flash program memory
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
380
385
//! @author Yann Sionneau
381
386
static void acknowledge_packet(void)
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;
389
CanMsgT.messageID |= 0x10; // Just add the ACK bit
390
sendCanMsg(); // And send the message back
401
398
//! @author Yann Sionneau
402
399
static void write_flash_address(void)
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];
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.
420
417
//! @author Yann Sionneau
421
418
static void write_flash_data(void)
433
430
position += 8; // We just buffered 8 more bytes
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
438
435
TBLRDPOSTDEC // We do a TBLRDPOSTDEC in order for the TBLPTR addressing register to stay in the range of the 32 bytes
474
473
EECON1 |= (1 << WR); // do the write
476
while (EECON1 & (1 << WR)); // wait for the write to finish
475
while (EECON1 & (1 << WR)) // wait for the write to finish
478
479
INTCON |= (1 << GIE ); // enable back interrupts
479
480
EECON1 &= ~(1 << WREN); // disable write to memory
533
534
acknowledge_packet();
535
goto 0x0000 // This jumps to the Reset vector
536
goto 0x0000 // This jumps to the Reset vector
537
538
// no break needed because of the goto above
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;
560
if ( (RXB1CON & (1 << RXFUL) ) )
562
if ( (RXB1CON & (1 << RXFUL) ) ) // DEBUGGING
571
//! Called in case a serious error is discovered.
572
//! Just sits and does nothing. Safer that way.
574
//! @author Yann Sionneau
566
575
void serious_error(void)
584
//! Sending a hello message tells the host the we have entered bootloader mode.
586
//! @author Yann Sionneau
587
void send_bootloader_hello_message(void)
589
CanMsgT.length = 8; // The following lines craft an ACK for a switch-to-bootloader message
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;
599
sendCanMsg(); // We ACK the magic packet at boot time
573
604
//! Main function
574
605
//! This is always executed at startup of the PIC18F regardless of whether there is
599
627
// From here we are in boot loader mode
600
628
// ------------------------------------
603
630
position = 0; // Resets the position for the "write to flash" process
604
631
can_init(); // Initializes ECAN module
606
CanMsgT.length = 8; // The following lines craft an ACK for a magic packet
609
//CanMsgT.messageID = 0x600 | (motor_id << 5) | 0x0010 | 0x00A; // Don't do it this way! (motor_id << 5) looses the top bit.
611
CanMsgT.messageID = motor_id; // Do it this way. CanMsgT.messageID is 16 bits.
612
CanMsgT.messageID <<= 5;
613
CanMsgT.messageID |= 0x600 | 0x0010 | 0x00A;
615
for (i = 0 ; i < 4 ; ++i)
616
CanMsgT.d.word[i] = 0xAA55; // swapped because of endianness
618
sendCanMsg(); // We ACK the magic packet at boot time
621
while ( 1 ) // Main loop
632
send_bootloader_hello_message(); // Tell the host we have entered bootloader mode, and are ready to program!
636
while (1) // Main loop
623
638
handle_can_msg(); // checks if we have received a CAN msg, and handles it