CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Bootloader via I2C?

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
DEsterline



Joined: 25 Aug 2009
Posts: 6

View user's profile Send private message

Bootloader via I2C?
PostPosted: Thu Nov 05, 2009 11:08 am     Reply with quote

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

View user's profile Send private message Visit poster's website

PostPosted: Thu Nov 05, 2009 11:40 am     Reply with quote

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: 1635
Location: Perth, Australia

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Thu Nov 05, 2009 8:37 pm     Reply with quote

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

View user's profile Send private message Visit poster's website

PostPosted: Fri Nov 06, 2009 8:19 am     Reply with quote

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

View user's profile Send private message Visit poster's website

PostPosted: Fri Nov 06, 2009 8:30 am     Reply with quote

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

View user's profile Send private message

PostPosted: Fri Nov 06, 2009 11:26 am     Reply with quote

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

View user's profile Send private message Visit poster's website

PostPosted: Fri Nov 06, 2009 1:40 pm     Reply with quote

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.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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