Go Down

Topic: Self burn by i2c EEPROM (bootloader) (Read 1 time) previous topic - next topic

reinaldoaf

Jun 03, 2013, 06:15 pm Last Edit: Jun 03, 2013, 06:25 pm by reinaldoaf Reason: 1
hi guys,

first sorry my english.

I'm trying make bootloader self write sketch by one eeprom memory on i2c bus,
the concep is:
1. the first time:
   I burn new bootloader then burn fist version of sketch.
 
2. I send hex content to i2c memory using any comunication interface, using one routine on fist sketch to do it, check the information twice ,write flag on device eprom memory and reboot device.

3. bootloader find new version of software(flag) and selfburn new sketch using i2c eeprom and start app.

4. the new version of sketch is runing.

I can use this routine by serial, ethernet, wifi or any comunication device, only need have apropriate function on fist sketch (and updates of this) to receive new firmware and write on i2c memory.

my problems, I'm a newbie on atmegas, I have expertise with firmwares but no with atmegas and still having problens with my "hack bootloader"

I start with(maybe) the original bootloader on /hardware/arduino/avr/bootloaders/atmega
and make this changes.

on includes of ATmegaBOOT_168.c

Code: [Select]
/* some includes */
#include <util/twi.h> //TWI Library to use i2c serial eeprom


and this 2 funcions to use EEPROM
after the functions prototypes on bootloader

Code: [Select]
void EEOpen()
{
//Set up TWI Module
TWBR = 5;
TWSR &= (~((1<<TWPS1)|(1<<TWPS0)));

}

uint8_t EEReadByte(uint16_t address)
{
uint8_t data;

//Initiate a Dummy Write Sequence to start Random Read
do
{
//Put Start Condition on TWI Bus
TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN);

//Poll Till Done
while(!(TWCR & (1<<TWINT)));

//Check status
if((TWSR & 0xF8) != 0x08)
return FALSE;

//Now write SLA+W
//EEPROM @ 00h
TWDR=0b10100000;

//Initiate Transfer
TWCR=(1<<TWINT)|(1<<TWEN);

//Poll Till Done
while(!(TWCR & (1<<TWINT)));

}while((TWSR & 0xF8) != 0x18);


//Now write ADDRH
TWDR=(address>>8);

//Initiate Transfer
TWCR=(1<<TWINT)|(1<<TWEN);

//Poll Till Done
while(!(TWCR & (1<<TWINT)));

//Check status
if((TWSR & 0xF8) != 0x28)
return FALSE;

//Now write ADDRL
TWDR=(address);

//Initiate Transfer
TWCR=(1<<TWINT)|(1<<TWEN);

//Poll Till Done
while(!(TWCR & (1<<TWINT)));

//Check status
if((TWSR & 0xF8) != 0x28)
return FALSE;

//*************************DUMMY WRITE SEQUENCE END **********************



//Put Start Condition on TWI Bus
TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN);

//Poll Till Done
while(!(TWCR & (1<<TWINT)));

//Check status
if((TWSR & 0xF8) != 0x10)
return FALSE;

//Now write SLA+R
//EEPROM @ 00h
TWDR=0b10100001;

//Initiate Transfer
TWCR=(1<<TWINT)|(1<<TWEN);

//Poll Till Done
while(!(TWCR & (1<<TWINT)));

//Check status
if((TWSR & 0xF8) != 0x40)
return FALSE;

//Now enable Reception of data by clearing TWINT
TWCR=(1<<TWINT)|(1<<TWEN);

//Wait till done
while(!(TWCR & (1<<TWINT)));

//Check status
if((TWSR & 0xF8) != 0x58)
return FALSE;

//Read the data
data=TWDR;

//Put Stop Condition on bus
TWCR=(1<<TWINT)|(1<<TWEN)|(1<<TWSTO);

//Wait for STOP to finish
while(TWCR & (1<<TWSTO));

//Return TRUE
return data;
}

then I make a changes on main code

add at_ep variable and start at_ep and ch variables;

Code: [Select]

uint8_t ch,ch2,at_ep;
at_ep=0;
ch = 0x00;



before forever loop I will test the device address to see if have version on i2c eeprom
in this case I just use the 328 to test

Code: [Select]
#if defined(__AVR_ATmega168__)  || defined(__AVR_ATmega328P__)
address.byte[0] = 0x03; //address of the last byte on device eeprom
address.byte[1] = 0xfe;
address.word = address.word << 1;
while(EECR & (1<<EEPE));
EEAR = (uint16_t)(void *)address.word;
EECR |= (1<<EERE);
if(EEDR == 0xFE){
flash_led(10); //just for I know if read the 0xFE on last byte.
at_ep = 1;
EEOpen();  //start i2c
}
length.byte[1] = 0x00;
length.byte[0] = 0x40; //fixe the length of page
#endif


next step is the first char identification by avrdude '0'
I only will wait this if not have a i2c flags

Code: [Select]

/* get character from UART */
#if defined(__AVR_ATmega168__)  || defined(__AVR_ATmega328P__)
if(at_ep != 1)
ch = getch();
#else
ch = getch();
#endif


on the write memory funcion 'd' I need make tests
first if is one i2c update I read memory by i2c and put informations on buff like by serial but...

Code: [Select]

/* Write memory, length is big endian and is in bytes  */
else if((ch=='d')) || (at_ep==1)) {
#if defined(__AVR_ATmega168__)  || defined(__AVR_ATmega328P__)
if(at_ep!=1){
length.byte[1] = getch();
length.byte[0] = getch();
flags.eeprom = 0;
if (getch() == 'E') flags.eeprom = 1;
for (w=0;w<length.word;w++) {
buff[w] = getch();                        // Store data in buffer, can't keep up with serial data stream whilst programming pages
}
ch = getch();
}else{
for (w=0;w<length.word;w++) {
buff[w]=EEReadByte(((uint16_t)(void *)address.word)+w);
}
ch = ' ';
}
#else
length.byte[1] = getch();
length.byte[0] = getch();
flags.eeprom = 0;
if (getch() == 'E') flags.eeprom = 1;
for (w=0;w<length.word;w++) {
buff[w] = getch();                        // Store data in buffer, can't keep up with serial data stream whilst programming pages
}
ch = getch();
#endif
... //after this the processes is same, get buff bytes and burn on program memory by  the asm codes.
//in the end I update to nexts adress
putch(0x14);
putch(0x10);
#if defined(__AVR_ATmega168__)  || defined(__AVR_ATmega328P__)
if(at_ep ==1){
//check if is my last memory block (remember I only test on 328)
//I clear flag of update on device eeprom for don't come on loop on next reboot

if((address.byte[1]==0x75)&&(address.byte[0]=0xc0))
{
address.byte[1]=0x03;
address.byte[0]=0xff;
while(EECR & (1<<EEPE));
EEAR = (uint16_t)(void *)address.word;
EEDR = 0xFF;
EECR |= (1<<EEMPE);
EECR |= (1<<EEPE);
app_start();
}

if(address.byte[0] == 0xC0) //check if is the last block of first byte
{
address.byte[1]++; // plus second byte
                                       address.byte[0] += 0x00;
}else{
address.byte[0] += 0x40; //plus the first byte address.
}
}
#endif


I assume this changes is I need to work with and without memory i2c eeprom, in this case 24lc256 (32Kb)

why I don´t use the 24lc256 to store the flag information of new firmware, because I need on write memory code to clear that, if have implementation of versions maybe no use write code.

I compile it, and burn on arduino uno using another uno, the bootloader stop to work, it need work with or without eeprom and work normal on arduino IDE but no :/

I make this change on makefile

Code: [Select]

atmega328: TARGET = atmega328
atmega328: MCU_TARGET = atmega328p
atmega328: CFLAGS += '-DMAX_TIME_COUNT=F_CPU>>4' '-DNUM_LED_FLASHES=1' -DBAUD_RATE=9600
atmega328: AVR_FREQ = 16000000L
atmega328: LDSECTION  = --section-start=.text=0x7400
atmega328: $(PROGRAM)_atmega328.hex

--section-start=.text=0x7400

because the bootloader is bigger, but I don´t know if it is all I need to make this work well

I need help to make it work, and think is a good way to remote update fimwares with low cost, only need one memory i2c and 2 resistors to work.

thank you the help
and sorry my english.

CrossRoads

You are limited to rather small sketches, just 1 Kbyte of EEPROM exists.
Bootloader code to read from EEPROM and write to Flash memory needs to be written.
Bootloader now to read from serial port and write to memory is 512 bytes.

Maybe you could have a compromise - standard bootloader, and a sketch that reads data from PC and makes some updates to EEPROM. Next reset, sketch runs with variables/settings updated from EEPROM, and if no serial data comes in to change those settings, they keep getting used.
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

reinaldoaf

CrossRoads,

No, I don´t want use the device(atmega) eeprom to store new sketch, the device eeprom is just to store flag of have new firmware the sketch I want store on i2c eeprom serial memory like 24lc256 (256Kb/8BitsperByte = 32Kb same size of flash of atmega328).

the bootloader need read the i2c serial memory with new sketch and write this on device program memory.

in this case the sketch can have the full memory disponible, arround 30k if bootloader have 2k.

sorry if i don´t make me understand on first time, or if I don´t understand your reply.

klim

Hi reinaldoaf,

did you have any progress in your i2c hex flash method?
I had the same idea and was searching if someone was already working on it.

Go Up