Bootloader

Go To Last Post
5 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hy guys!

I need a bit help in bootloader topic. I'm using a Mega328P. My code contains a char variable, e.g.:char letter='c'. I want to refresh this variable throug UART communication, and burn the new variable in the flash. I like to use the bootloader with a condition, for example if PC4 high do not exit bootloader, if low, exit, thus when I power-on the AVR while a jumper attached to PC4 and Vcc, I could program the AVR through UART, if the jumper is not attached while powering-on the AVR, it would jump to my application code. 

I read the datasheet of the AVR, AVR109, and almost everything I found on the internet (include avrfreaks too), but I'm still really confused how to do it. Could somebody help me with an example code how to solve this (in C language)?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

For something like a 'c' wouldn't it be much easier to store it into EEPROM not flash. With EEPROM it's real easy to write just one byte. With flash you have to mess around erasing/replacing complete 64/128/256 byte SPM pages. Also EEPROM can be erased/written 100,000 times while flash is limited to 10,000 times.

 

If you are serious about pursuing a bootloader (SPM) solution then you will need to say which C compiler. If, for example, it is avr-gcc then that already has:

 

http://www.nongnu.org/avr-libc/u...

 

which provides a lot of what you need to implement a bootloader.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You suggested a very practical solution. I've alredy used eeprom, but I never used self-programming. My aim is to learn using this function with this simple program.  I compile my code with avr-gcc. Can you help me in the code?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As I say <avr/boot.h> It almost has a prewritten bootloader for you:

#include <inttypes.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>

void boot_program_page (uint32_t page, uint8_t *buf)
{
    uint16_t i;
    uint8_t sreg;
    // Disable interrupts.
    sreg = SREG;
    cli();
    eeprom_busy_wait ();
    boot_page_erase (page);
    boot_spm_busy_wait (); // Wait until the memory is erased.
    for (i=0; i<SPM_PAGESIZE; i+=2)
    {
        // Set up little-endian word.
        uint16_t w = *buf++;
        w += (*buf++) << 8;
        boot_page_fill (page + i, w);
    }
    boot_page_write (page); // Store buffer in flash page.
    boot_spm_busy_wait(); // Wait until the memory is written.
    // Reenable RWW-section again. We need this if we want to jump back
    // to the application after bootloading.
    boot_rww_enable ();
    // Re-enable interrupts (if they were ever enabled).
    SREG = sreg;
}

You pass that routine a flash page address (like 0x0400 or something) and a pointer to a buffer that is SPM_PAGESIZE bytes long (64/128/256 bytes depending on AVR) and it will program the given data into the page you asked for. Note that "page" is an absolute address like 0x0400, 0x0480, 0x0500 and not just a 1,2,3,4... page number.

 

Also this routine MUST be located in high flash (the "bootloader section") to operate successfully.

 

To implement a complete bootloader you just wrap a for() loop around this that keeps receiving 64/128/256 bytes and when it has a complete page full this routine is called to program an entire page. That's pretty much all there is to it.

 

(I didn't write that code by the way - it's given as the example in boot.h as to how to use the other routines that header file provides).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I learnt a bit about bootloaders, but I still need some help. I wrote two code, one for the bootloader and one for the test application. I want to refresh a variable (named "appint")

 in the application, when I'm in the bootloader. I attached the two codes. The conclusion that this method is still not working, the variable is not refreshing, but am I on the right path? What's the mistake? With this kind of method the variable (what I refreshed once through UART) will still be refreshed after a power cycle? 
Application: 

#define F_CPU	12000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <inttypes.h>
#include <avr/interrupt.h>
#include <string.h>
#include <stdlib.h>

void USART_Init( unsigned int ubrr)
{
	UBRR0H = (unsigned char)(ubrr>>8);
	UBRR0L = (unsigned char)ubrr;
	UCSR0B = (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0);
	UCSR0C = (0<<USBS0)|(1<<UCSZ00)|(1<<UCSZ01);
}

void USART_Transmit( unsigned char data )
{
	while ( !( UCSR0A & (1<<UDRE0)) )
	;
	UDR0 = data;
}

unsigned char USART_Receive( void )
{
	while ( !(UCSR0A & (1<<RXC0)) )
	;
	return UDR0;
}

void USARTStringSend( char *p)
{
	while(*p)
	{
		USART_Transmit( *p++);
	}
}

ISR(USART_RX_vect)
{
	char datain=USART_Receive();
	USART_Transmit(datain);
}

const uint8_t appint __attribute__ ((section (".MySection")))=8;
//at the settings-->toolchain-->memory settings-->FLASH segment I added this: .MySection=0x3400
int main(void)
{
	USART_Init(77);
	
	char buff[10];
	
	MCUCR|=(1<<IVCE);//
	MCUCR=0;
	
	sei();
	
    while(1)
    {
		itoa(appint,buff,10);
		USARTStringSend(buff);
		_delay_ms(2000);
    }
}

 

Bootloader: 

 

#define F_CPU 12000000UL
#include <avr/io.h>
#include <inttypes.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/boot.h>
#include <util/delay.h>
#include <string.h>
#include <stdlib.h>

void USART_Init( unsigned int ubrr)
{
	UBRR0H = (unsigned char)(ubrr>>8);
	UBRR0L = (unsigned char)ubrr;
	UCSR0B = (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0);
	UCSR0C = (0<<USBS0)|(1<<UCSZ00)|(1<<UCSZ01);
}

void USART_Transmit( unsigned char data )
{
	while ( !( UCSR0A & (1<<UDRE0)) )
	;
	UDR0 = data;
}

unsigned char USART_Receive( void )
{
	while ( !(UCSR0A & (1<<RXC0)) )
	;
	return UDR0;
}

void USARTStringSend( char *p)
{
	while(*p)
	{
		USART_Transmit( *p++);
	}
}

void boot_program_page (uint32_t page, uint8_t *buf)
{
	uint16_t i;
	uint8_t sreg;
	// Disable interrupts.
	sreg = SREG;
	cli();
	eeprom_busy_wait ();
	boot_page_erase (page);
	boot_spm_busy_wait (); // Wait until the memory is erased.
	for (i=0; i<SPM_PAGESIZE; i+=2)
	{
		// Set up little-endian word.
		uint16_t w = *buf++;
		w += (*buf++) << 8;
		boot_page_fill (page + i, w);
	}
	boot_page_write (page); // Store buffer in flash page.
	boot_spm_busy_wait(); // Wait until the memory is written.
	// Reenable RWW-section again. We need this if we want to jump back
	// to the application after bootloading.
	boot_rww_enable ();
	
	// Re-enable interrupts (if they were ever enabled).
	SREG = sreg;
	sei();
	
}

void bootgreating()
{
		USARTStringSend("Booting... ");
}

uint8_t buffer[1];

ISR(USART_RX_vect)
{
	char receivedData=USART_Receive();
	buffer[0]=atoi(receivedData);
	USART_Transmit(receivedData);
	boot_program_page(0x3400,buffer);
}

int main(void)
{
	
	MCUCR|=(1<<IVCE); 
	MCUCR=0x02; 
	
	USART_Init(77);
	
	if(PIND&(1<<PD6))
	{
		bootgreating();		
	}
	
	sei();
	
	while(1)
	{
		
		if(!(PIND&(1<<PD6)))//if PD6 low, jump to the application
		{
					
					USARTStringSend("Starting program... ");
					_delay_ms(600);
					_delay_ms(600);
					_delay_ms(600);
					asm("jmp 0x0000");
		}
			
	}
}

 

Last Edited: Fri. Aug 14, 2015 - 01:49 PM