ATmega644PA bootloader start address

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

I have written a simple bootloader for the ATmega644PA but I cannot get it to run at the proper boot start address. I can run it when built using standard options but once I modify the section start address it refuses to start.

 

I am using max bootloader size of 4k words i.e. 8 kB. I modify the start address with the following option under Misc:

-Wl,-Ttext=0xE000

 

I also set fuses so that boot flash size = 4096 words and set BOOTRST to 0 in order to enable boot reset. 

 

I tried to change around a couple of times but it just never starts. Any ideas?

/Jakob Selbing

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

Everything you have done sounds right. 4K words is 8K bytes. 64K minus 8K is 56K which is 0xE000. How are you determining whether it does/doesn't start? Do you use a JTAG ICE (best way to debug)?

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

I am stuck with ISP unfortunately since it is a Crumb644 PCB:

https://www.chip45.com/products/crumb644-1.1_avr_atmega_module_board_atmega644p_usb_rs485.php

 

At start-up I blink the LED and print a message to the UART. With standard settings this works fine but with boot loader settings there is no activity on neither LED nor UART.

/Jakob Selbing

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

Name             Origin             Length             Attributes
text             0x00000000         0x00020000         xr
data             0x00800060         0x0000ffa0         rw !x
eeprom           0x00810000         0x00010000         rw !x
fuse             0x00820000         0x00000003         rw !x
lock             0x00830000         0x00000400         rw !x
signature        0x00840000         0x00000400         rw !x
user_signatures  0x00850000         0x00000400         rw !x
*default*        0x00000000         0xffffffff

Just saw this in the MAP file. Strange that text section has length 0x2000. It should be 0x1000 since it is has 64 kB flash?!

/Jakob Selbing

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

I discovered that the boot loader does in fact start properly but seems to crash if I enable interrupts. If I keep interrupts disabled then it at least flashes the LED.

 

Could this have something to do with the IVSEL bit in MCUCR? I tried setting it but boot loader still fails when interrupts are enabled.

/Jakob Selbing

Last Edited: Sat. Dec 28, 2019 - 08:34 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

A bootloader shouldn't need or use interrupts but if you are ill advised enough to use them then, yes, the first thing you should do before you sei() is to move IVSEL so the IVT is just above E000 rather than just above 0000 as usual.

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

Quote:
A bootloader shouldn't need or use interrupts but if you are ill advised enough to use them...
Why would that be ill-advised? I use a timer overflow interrupt for generating a system tick. I also use interrupt-driven UART. Sure I could avoid interrupts but I share a lot of code between boot loader and main application so it makes things simpler.

 

EDIT: just noticed that there is a special procedure to set the IVSEL bit so that is probably why bootloader still crashes. Will fix it and get back...

 

EDIT 2: yep, now it works!

/Jakob Selbing

Last Edited: Sat. Dec 28, 2019 - 11:20 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well now the transition from boot loader to main application works but with one exception - the main application's UART output is all garbage:

Starting BOOTNPB v0.1

Valid application: YES
Time-out; starting main application...
A“yq`r;rXkevœƒMù

Notice the last line is all garbage - it should say "AM29F010 programmer v1.0".

 

If I run main application without boot loader by changing the fuses (BOOTRST = 1 i.e. reset vector at 0x0000) then UART output is fine:

AM29F010 programmer v1.0

 

I suspect there is some problem with initialization/uninitialization of the UART. This is how it's done by the boot loader:

/* Initialize UART */
void InitUART(  )
{
	// Configure UART
	UBRR_REGISTER = UBRR_VALUE;

	#if USE_2X
		UCSRA_REGISTER |= (1 << U2X_BIT);
	#else
		UCSRA_REGISTER &= ~(1 << U2X_BIT);
	#endif

	/* Enable UART receiver and transmitter, and receive interrupt */
	UCSRB_REGISTER |= (1<<RXCIE_BIT) | (1 << RXEN_BIT) | (1 << TXEN_BIT);

	/* Use 8-bit character sizes - URSEL bit set to select the UCRSC register (NOTE: only on old ATmega8/16 etc) */
	UCSRC_REGISTER |= URSEL_BIT_VALUE | (1 << UCSZ0_BIT) | (1 << UCSZ1_BIT);

	InitFifo(&f_UART_Rx, &tmp_UART_RxBuf[0], UART_RX_BUFFER_MASK);
	InitFifo(&f_UART_Tx, &tmp_UART_TxBuf[0], UART_TX_BUFFER_MASK);
}

void UnititUART(void)
{
	UCSRA_REGISTER = 0;
	UCSRB_REGISTER = 0;
	UCSRC_REGISTER = 0;
	UBRR_REGISTER = 0;
}

Note that I do use a 1 second delay before jumping to main application in order to flush the UART completely and ensure the idle state is present.

 

Maybe there is something else that has to be done in order to fully restore the UART to its reset state? 

 

EDIT: I found the problem. I had defined the UCSZ1_BIT as UCSZ10 instead of UCSZ01. Now everything is hunky-dory.

/Jakob Selbing

Last Edited: Sun. Dec 29, 2019 - 08:27 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As to why no interrupts. In a system that uses a bootloader the entire application can be replaced at will so it doesn't matter how bug ridden and truly dreadful the code is on the day you ship as you can easily deliver a fixed update. But the one bit of the system you can never replace is the bootloader itself so it must be perfect code with no bugs on day one. To achieve that means keeping it as plain and simple as you can. Unneeded functionality is just a potential for more bugs. Worse of all is code with multiple, interleaving paths of execution that can make 100% testing almost impossible. As soon as you add an interrupt path to a program the potential complexity increase ten-fold. As a bootloader is a piece of code that runs for 10 seconds just once every 6-12 months and all it does is sit in a loop receiving code bytes and SPMing them into flash there's no reason for anything as complex as interrupts.
.
As for the UART: one thing a well designed bootloader is likely to do is perform a watchdog reset just before it enters the app code. If you do that things like UART will be reset to default.

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

Good point. I think the primary goal is simplicity rather than absence of interrupts.

 

Good point about using watchdog too. I used that method in another boot loader. I will probably use that method in this one too.

/Jakob Selbing