PDA

View Full Version : 18F4550 Bootloader enter via eeprom setting



bradb
- 21st November 2008, 20:38
Hello all,

I've been stalking around this board for a couple months sucking knowledge from so many great minds. I wanted to do something I couldn't find, after I figured it out I thought I'd share my code. I wanted to use an EEPROM byte to control on boot if I should enter bootloader mode or jump up to Pic basic code.

I loaded the new MCHPFSUSB v2.3 (just release 6 weeks or so ago) and modified the HID Bootloader C code to do exactly what I want.

In my Pic I'm doing the following



If ProgramMe = 1 then 'Put the chip into programming mode via a ProgramMe variable i'm passing across the USB
Write 1, 255 'Set eeprom byte 1 back to FF
pause 250 'I small pause for no good reason, probably not needed
@ Reset 'reset/reboot the PIC
ENDIF



I then modified the main.c in the "C:\Microchip Solutions\USB Device - Bootloaders\HID - Bootloader\HID Bootloader - Firmware for PIC18 Non-J Devices" to the following


/************************************************** *******************
*
* Microchip USB HID Bootloader for PIC18 (Non-J Family) USB Microcontrollers
*
************************************************** *******************
* FileName: main.c
* Dependencies: See INCLUDES section below
* Processor: PIC18
* Compiler: C18 3.20+
* Company: Microchip Technology, Inc.
*



/** I N C L U D E S ************************************************** ********/
#include <p18cxxx.h>
#include "typedefs.h"
#include "usb.h"
#include "io_cfg.h"
#include "BootPIC18NonJ.h"


#if defined(PIC18F4550_PICDEM_FS_USB)
#pragma config PLLDIV = 5
#pragma config CPUDIV = OSC1_PLL2
#pragma config USBDIV = 2
#pragma config FOSC = HSPLL_HS
#pragma config FCMEN = OFF
#pragma config IESO = OFF
#pragma config PWRT = OFF
#pragma config BOR = ON
#pragma config BORV = 3
#pragma config VREGEN = ON
#pragma config WDT = OFF
#pragma config WDTPS = 32768
#pragma config MCLRE = ON
#pragma config LPT1OSC = OFF
#pragma config PBADEN = OFF


#pragma config STVREN = ON
#pragma config LVP = OFF

#pragma config XINST = OFF
#pragma config CP0 = OFF
#pragma config CP1 = OFF
#pragma config CPB = OFF

#pragma config WRT0 = OFF
#pragma config WRT1 = OFF
#pragma config WRTB = OFF // Boot Block Write Protection
#pragma config WRTC = OFF

#pragma config EBTR0 = OFF
#pragma config EBTR1 = OFF
#pragma config EBTRB = OFF

#elif defined(LOW_PIN_COUNT_USB_DEVELOPMENT_KIT)
//14K50
#pragma config CPU_DIV = NoClkDiv, USB_LSCLK = OFF
#pragma config FOSC = HS, PLL_EN=ON, FCMEN = OFF, IESO = OFF
#pragma config PWRT = OFF, BOREN = OFF, BORV = 30, VREGEN = ON
#pragma config WDTEN = OFF, WDTPS = 32768
#pragma config MCLRE = OFF, HFOFST = OFF
#pragma config STVREN = ON, LVP = OFF, XINST = OFF, BBSIZ=OFF
#pragma config CP0 = OFF, CP1 = OFF
#pragma config CPB = OFF
#pragma config WRT0 = OFF, WRT1 = OFF

#pragma config WRTB = OFF, WRTC = OFF
#pragma config EBTR0 = OFF, EBTR1 = OFF
#pragma config EBTRB = OFF


#ifdef __DEBUG
#pragma config BKBUG = ON
#endif
#ifndef __DEBUG
#pragma config BKBUG = OFF
#endif
#else
#error Not a supported board (yet), make sure the proper board is selected in usbcfg.h, and if so, set configuration bits in __FILE__, line __LINE__
#endif

/** V A R I A B L E S ************************************************** ******/
#pragma udata

/** P R I V A T E P R O T O T Y P E S ***************************************/
static void InitializeSystem(void);
void USBTasks(void);
#if !defined(__18F14K50) && !defined(__18F13K50) && !defined(__18LF14K50) && !defined(__18LF13K50)
void BlinkUSBStatus(void);
#else
#define BlinkUSBStatus()
#endif

/** V E C T O R R E M A P P I N G *******************************************/
#pragma code high_vector=0x08
void interrupt_at_high_vector(void)
{
_asm goto 0x1008 _endasm
}
#pragma code low_vector=0x18
void interrupt_at_low_vector(void)
{
_asm goto 0x1018 _endasm
}
#pragma code


/** D E C L A R A T I O N S **************************************************/
#pragma code
/************************************************** ****************************
* Function: void main(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: Main program entry point.
*
* Note: None
************************************************** ***************************/
void main(void)
{

//read the first byte store in var eepTemp
signed char eepTemp; //setup a var to read the eep
EEADR = 0x0001; //location to read, I'm useing eeprom address 1
EECON1bits.EEPGD = 0;
EECON1bits.CFGS = 0;
EECON1bits.RD = 1;
eepTemp = EEDATA;

//write Byte "1" back to a 1, so no matter once bootloader code only enters once
EEADR =0x0001;
EEDATA =0x01;
Nop();
Nop();
EECON1bits.EEPGD = 0;
EECON1bits.CFGS = 0;
EECON1bits.WREN = 1;
INTCONbits.GIE = 0;
EECON2 = 0x55;
EECON2 = 0xAA;
EECON1bits.WR = 1;
while(EECON1bits.WR);
INTCONbits.GIE = 1;
EECON1bits.WREN = 0;


//Check Bootload Mode Entry Condition
if(eepTemp == 0x01) //Check the eepTemp and see if it's 0x01, if so boot to the PIC Basic code at 0x1000
{
_asm
goto 0x1000 //If the user is not trying to enter the bootloader, go straight to the main application remapped "reset" vector.
_endasm
}
InitializeSystem();
while(1)
{
ClrWdt();
USBTasks(); // Need to call USBTasks() periodically
// it handles SETUP packets needed for enumeration

//BlinkUSBStatus();

if((usb_device_state == CONFIGURED_STATE) && (UCONbits.SUSPND != 1))
{
ProcessIO(); // This is where all the actual bootloader related data transfer/self programming takes place
} // see ProcessIO() function in the Boot87J50Family.c file.
}//end while
}//end main

/************************************************** ****************************
* Function: static void InitializeSystem(void)
*
**/
static void InitializeSystem(void)
{

#if defined(__18F87J50)||defined(__18F86J55)|| \
defined(__18F86J50)||defined(__18F85J50)|| \
defined(__18F67J50)||defined(__18F66J55)|| \
defined(__18F66J50)||defined(__18F65J50)

unsigned int pll_startup_counter = 600;
OSCTUNEbits.PLLEN = 1; //Enable the PLL and wait 2+ms until the PLL locks before enabling USB module
while(pll_startup_counter--);


#else

#endif

#if defined(USE_USB_BUS_SENSE_IO)
tris_usb_bus_sense = INPUT_PIN; // See io_cfg.h
#endif
#if defined(USE_SELF_POWER_SENSE_IO)
tris_self_power = INPUT_PIN;
#endif

mInitializeUSBDriver(); // See usbdrv.h

UserInit(); // See user.c & .h

}//end InitializeSystem

/************************************************** ****************************
* Function: void USBTasks(void)
*/

void USBTasks(void)
{
/*
* Servicing Hardware
*/
USBCheckBusStatus(); // Must use polling method
USBDriverService(); // Interrupt or polling method

}// end USBTasks


/************************************************** ****************************
* Function: void BlinkUSBStatus(void)
*
* THIS FUNCTION WAS REMOVED TO MAKE ROOM FOR THE EEPROM READ AND WRITE CODE
*



Basically every time the pic boots I check EEPROM Byte 1. If the PICBasic code has set byte 1 back to 0xFF then the c code sets it back to 0x01 and runs the bootloader code for that boot. I then run the microchip HID bootloader and update the Pic Basic code.

Upon reseting after upgrading Byte 1 has already been switched back to 0x01 so it bypasses the bootloader.

No Switches to press... very simple upgrades. I send a command down to the pic, it reboots, I run the HID Bootloader, reboot after loading my new code. The PicBasic code Executes.

bcd
- 21st November 2008, 22:12
bradb,

Nice solution - reminds me of the old serial bootloaders where they would look for a single character on the com port at startup and use that to enter bootloader mode.

Giving the pic the ability to put itself into bootload mode rather than requiring a crazy key combination on reset, which some poor end user will manage to do while trying to mount a device in the wall is a great idea.

I notice you removed the blinky led code in the HID Bootloader to code - how much bigger does the read and write eeprom code make the bootloader code ? - from memory the HID one is about 1100 bytes.

Hmm, wonder if I could make it work with an I2C eeprom... I knew there was a reason the 18F2550 would be better than the 18f2450...

Quick thought though - what happens if you PBP program gets trashed ? - how can you get the unit into bootloader mode to get new code into it? I am thinking bootload session that crashes out half way through or cable falls out etc. - would it be better to write the eeprom once the bootloader has completed sucessfully, say after the ProcessIO() call in the HID bootlader code ?

Good work,
bill

bradb
- 22nd November 2008, 00:31
bradb,

Nice solution - reminds me of the old serial bootloaders where they would look for a single character on the com port at startup and use that to enter bootloader mode.

Giving the pic the ability to put itself into bootload mode rather than requiring a crazy key combination on reset, which some poor end user will manage to do while trying to mount a device in the wall is a great idea.

I notice you removed the blinky led code in the HID Bootloader to code - how much bigger does the read and write eeprom code make the bootloader code ? - from memory the HID one is about 1100 bytes.

Hmm, wonder if I could make it work with an I2C eeprom... I knew there was a reason the 18F2550 would be better than the 18f2450...

Quick thought though - what happens if you PBP program gets trashed ? - how can you get the unit into bootloader mode to get new code into it? I am thinking bootload session that crashes out half way through or cable falls out etc. - would it be better to write the eeprom once the bootloader has completed sucessfully, say after the ProcessIO() call in the HID bootlader code ?

Good work,
bill

I thought about adding the write byte1 = 1 code only after completing the firmware upgrade, but for my purpose I wanted the PIC to fall back to the Pic Basic code in the event of an aborted firmware upgrade attempt. I did not want to get stuck in pic upgrade loop. A quick power cycle aborts the upgrade procedure without even having to start the HID boot loader program. This was personal choice.

I would like to add a counter to eprom byte 2.
Every time the C code boots it would increment byte 2 by 1.
If byte 2 > 5 then the C program would go into boot loader mode regardless of the status of eprom byte1.

At the end of my Basic loop I would set eeprom byte2 back to 0, clearing the Eprom Byte 2 counter. 5 Failed boot attempts in a row would automatically send the PIC into boot loader mode, like hosed code from a failed upgrade. This gets around the failed upgrade issue with a handful of reboots.

However, I'm going to have to find some place to get more code space from, I'm not at my work PC but from memory I think I only have about 8 bytes left under the first 1000h which is why I had to remove the USB Led Blink status to begin with. Either that or figure out if it’s possible to change the start vector of the pic basic to 1200h.

Or, I can add an upgrade switch but because of the nature of the device I'm making I do not want the board or a switch field accessible. I really need to be able to upgrade these via a remote control solution, IE I remote desktop to a PC with the device attached via USB and then I can personally do the upgrade. I have the procedure in my VB program password protected so users can't send the pic into upgrade mode.

This was a quick project today but it is working.

The other mistake I can already see I made was writing byte 1 back to a every time even it’s already a 1, my code should be more like this:



void main(void)
{

//read the first byte store in var eepTemp
signed char eepTemp; //setup a var to read the eep
EEADR = 0x0001; //location to read, I'm using eeprom address 1
EECON1bits.EEPGD = 0;
EECON1bits.CFGS = 0;
EECON1bits.RD = 1;
eepTemp = EEDATA;

//Check Bootload Mode Entry Condition
if(eepTemp == 0x01) //Check the eepTemp and see if it's 0x01, if so boot to the PIC Basic code at 0x1000
{
_asm
goto 0x1000 //If the user is not trying to enter the bootloader, go straight to the main application remapped "reset" vector.
_endasm
}

//write Byte "1" back to a 1
EEADR =0x0001;
EEDATA =0x01;
Nop();
Nop();
EECON1bits.EEPGD = 0;
EECON1bits.CFGS = 0;
EECON1bits.WREN = 1;
INTCONbits.GIE = 0;
EECON2 = 0x55;
EECON2 = 0xAA;
EECON1bits.WR = 1;
while(EECON1bits.WR);
INTCONbits.GIE = 1;
EECON1bits.WREN = 0;


InitializeSystem();
etc ....

I've only been programming PICs for a couple months... the possibilities are so endless. The 18F4550 with USB connection is the coolest thing since sliced bread..

bcd
- 22nd November 2008, 23:51
...the possibilities are so endless. The 18F4550 with USB connection is the coolest thing since sliced bread..

I have to agree that the USB pics and the ease of using them with PBP has really got my excited again about dreaming up cool projects and making them a reality!

bill.