|
|
View previous topic :: View next topic |
Author |
Message |
DEsterline
Joined: 25 Aug 2009 Posts: 6
|
Bootloader via I2C? |
Posted: Thu Nov 05, 2009 11:08 am |
|
|
I'm about to do a couple things that are new to me and I was hoping someone here could shorten my learning curve. Any pointers would be greatly appreciated.
The hardware has a PIC16F877A with a couple 256k FRAM's (not on the hardware I2C pins) We have a separate tool that can plug in and access the I2C bus and access this memory to retrieve log data and set some configuration parameters. When this tool is connected the PIC recognizes it and goes into a special mode with it's I2C pins high-z. It's a little more involved, but think of it as a multi-master I2C bus.
Ideally, I'd like the PIC to check a specific FRAM memory location as a flag to indicate an update is available, run a checksum or other test to validate the block of data, then reprogram itself from the FRAM data. A bit of a variation on the "normal" bootloader.
Since this is my first attempt to create a bootloader, and it's different than the examples.... I'd appreciate some input. |
|
|
treitmey
Joined: 23 Jan 2004 Posts: 1094 Location: Appleton,WI USA
|
|
Posted: Thu Nov 05, 2009 11:40 am |
|
|
I've done something similar.
I have a RS485 connection to a PC.
If I want to update firmware I can send packets of data that are the HEX update to firmware. They are stored in FRAM.
Then I jump to a protected function (like a bootloader)
and then read the hex (that was stored in FRAM) and reprogram myself
(the 18F4525 PIC)
Code: | //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
//:::::::::::::::::::: NOTHING CHANGED FROM HERE DOWN ::::::::::::::::::::::://
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
// 0xBCD0 Software looks for Firmware version here
// 0xBD00 Reprogram up to here
// 0xBD10 Where PrgmPIC function sits
//===================== PrgmPIC =========================
#org 0xBD10, 0xBFFF default
#use I2C(MASTER,SDA=PIN_C4,SCL=PIN_C3,FORCE_HW,FAST=1000000,RESTART_WDT)
void PrgmPIC(void){
int8 indx;
int16 address;
disable_interrupts(INT_RDA);
output_low(PIN_C5);//turn off tx_enable
output_high(PIN_C6);
i2c_start();
i2c_write(0xA0);//Chip select
i2c_write(0);i2c_write(0);//Set address hi and lo
i2c_start();i2c_write(0xA1);//Read
setup_wdt(WDT_OFF);
for(address=0;address<0xBD00;address+=64){
output_toggle(PIN_D0);
for(indx=0;indx<64;indx++)
RX_BUF[indx]=i2c_read(1);
write_program_memory(address,RX_BUF,64);//write FRAM data in blocks of 64
//fprintf(DEBUG,"#");
}
i2c_read(0);//No ack on last read, we don't care what we read
i2c_stop();//stop the i2cbus
reset_cpu();
}
#org default
//:10BCE000FFFFFFFFF2CF0EF0F29EF76AFE0FF66E77
//:10BCF0007C0EF7220900F5500EBEF28E1200030032<--Firmware version 3.00
//:10BD000003020100000CFFFFFFFFFFFFFFFFFFFF6B<-----Hardware ver 3.02 Prod ID 01
//:10BD1000C69E9E96F1C3C9FF020EC6BE05D09EA6A2
//:10BD2000FED7000EC5BC010E016E000CC586C5B69F<--PrgmPIC is located here 0xBD10
//:10BD3000FED700B0C59A00A0C58AC588C5B8FED7D1
//:10BD4000C9CF01F0000CF250036EF29EA68EA684FD
// Programming is for locations 0x0 up to 0xBCFF, thus hardware version and
// product ID at 0xBD00 will NOT be reprogrammed, but firmware version is.
|
|
|
|
asmallri
Joined: 12 Aug 2004 Posts: 1634 Location: Perth, Australia
|
|
Posted: Thu Nov 05, 2009 8:37 pm |
|
|
treitmey wrote: |
Code: |
//:10BCE000FFFFFFFFF2CF0EF0F29EF76AFE0FF66E77
//:10BCF0007C0EF7220900F5500EBEF28E1200030032<--Firmware version 3.00
//:10BD000003020100000CFFFFFFFFFFFFFFFFFFFF6B<-----Hardware ver 3.02 Prod ID 01
//:10BD1000C69E9E96F1C3C9FF020EC6BE05D09EA6A2
//:10BD2000FED7000EC5BC010E016E000CC586C5B69F<--PrgmPIC is located here 0xBD10// product ID at 0xBD00 will NOT be reprogrammed, but firmware version is.
|
|
Now sticking the Firmware and Hardware serial numbers in the hex file like this is a really good idea. I embedded them in the normal image but this method makes image management much clearner. _________________ Regards, Andrew
http://www.brushelectronics.com/software
Home of Ethernet, SD card and Encrypted Serial Bootloaders for PICs!! |
|
|
treitmey
Joined: 23 Jan 2004 Posts: 1094 Location: Appleton,WI USA
|
|
Posted: Fri Nov 06, 2009 8:19 am |
|
|
Thanks
That means a lot from you.
I am a hardware engineer, working from home, and don't get much praise.
Thanks
: ) |
|
|
treitmey
Joined: 23 Jan 2004 Posts: 1094 Location: Appleton,WI USA
|
|
Posted: Fri Nov 06, 2009 8:30 am |
|
|
DEsterline:
To start with, try to get the hex data into FRAM.
Then call a function that will print the data as a check.
Compare the print to the program.hex file.
If you can do that then you just have to adjust a few addresses
and the size of the array for writing.
Always try to write with the same size as the erase.
If they don't match, I think you will have problems.
Also note that I duplicated the
#use I2C line. 1 is in the main program for normal FRAM access, and a 2nd one is in the protected function. This is because we want all the code needed to be programming separate from the rest that will be re-written. Make sense?? |
|
|
DEsterline
Joined: 25 Aug 2009 Posts: 6
|
|
Posted: Fri Nov 06, 2009 11:26 am |
|
|
treitmey:
Yes, just loading the hex file into the FRAM is going to be a bit of a task in itself. That'll be a task for a different piece of hardware (also based on a 16F877A with an FTDI usb/serial adaptor) But reading data in and writing to memory is something I _do_ have experience with. And I can bypass some of that process in the beginning with other development tools, specifically I have a SeeVal (microchip's I2C eeprom reader/programmer tool)
The parts I was more concerned about was the self write to flash and beating the compiler into submission regarding placing and protecting the code to do the update - and any functions that needs to call...
Thanks for the clarification about the second #use I2C declaration, I was (wrongly) assuming it was because you were using different parameters in the main program. The other thing that confused me momentarily was your manipulation of the WDT. But now I see that you're using the 18F parts and can do that :-)
Specifically, you disables the WDT before the flash write routine -why? Is there a reason you couldn't have just serviced it in that routine?
I understand that if something fails and we have a watchdog reset in the middle of a self update, the system will reset to non-functional. My concern is that with a 16F part, I can't turn the WDT off on the fly and I would strongly prefer the main application did have it. |
|
|
treitmey
Joined: 23 Jan 2004 Posts: 1094 Location: Appleton,WI USA
|
|
Posted: Fri Nov 06, 2009 1:40 pm |
|
|
as for the wdt. I think I would have used it in the loop,.. but the write
of the program memory was too slow,((from what I remember)).
The only solution for me was to tickle the watchdog during FRAM read and
right before and after the program memory write. Too much I thought.
remember the 16F877a is a different animal. (probably) smaller erase/write array,.. and thus faster loop. May have to test it.
You could test and see if the watchdog will work for you.
use the reset_cause() function right at the beginning of your program.
to see if the reset was because of the wdt.
once you have it working,.. maybe back the wdt slower 1 step for a safety margin, and there you go. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|