Bootloader trouble with boot.h, it doesn't flash...

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

Hi,

Let's get straight to the point, one of my students is writing bootloader code based on the AVR - Butterfly AVR-GCC ports that are circling the web.
Everything seems to be correct when the code is simulated but when it's executed in the target board it simply doesn't flash the application section.

page = address;

for (cnt = 0; cnt < SPM_PAGESIZE; cnt += 2)
{
	w = (*pbuf ++);
	w += (*pbuf ++) << 8;
					
	boot_page_fill (address, w);
					
	address += 2;  	// Select next word in memory					
} 									// Loop until all bytes written
				
boot_page_write (page);  	// Store buffer in flash page.
boot_spm_busy_wait();       	// Wait until the memory is written.
boot_rww_enable ();

As you can see the code is almost completely copied from the AVR-Libc user's manual. It translates in the asm code below;

176: page = address;
+00000F27:   01B7        MOVW    R22,R14          Copy register pair
---- No Source ------------------------------------------------------------------------------------
+00000F28:   E031        LDI     R19,0x01         Load immediate
+00000F29:   E74E        LDI     R20,0x7E         Load immediate
+00000F2A:   E050        LDI     R21,0x00         Load immediate
180: w = (*pbuf ++);
+00000F2B:   01F5        MOVW    R30,R10          Copy register pair
---- No Source ------------------------------------------------------------------------------------
+00000F2C:   9121        LD      R18,Z+           Load indirect and postincrement
181: w += (*pbuf ++) << 8;
+00000F2D:   9181        LD      R24,Z+           Load indirect and postincrement
---- No Source ------------------------------------------------------------------------------------
+00000F2E:   015F        MOVW    R10,R30          Copy register pair
+00000F2F:   2799        CLR     R25              Clear Register
+00000F30:   2F98        MOV     R25,R24          Copy register
+00000F31:   2788        CLR     R24              Clear Register
+00000F32:   0F82        ADD     R24,R18          Add without carry
+00000F33:   1D91        ADC     R25,R1           Add with carry
183:  boot_page_fill (address, w);
+00000F34:   010C        MOVW    R0,R24           Copy register pair
---- No Source ------------------------------------------------------------------------------------
+00000F35:   01F7        MOVW    R30,R14          Copy register pair
+00000F36:   93300057    STS     0x0057,R19       Store direct to data space
+00000F38:   95E8        SPM                      Store program memory
+00000F39:   2411        CLR     R1               Clear Register
185:  address += 2;  	// Select next word in memory	
+00000F3A:   E082        LDI     R24,0x02         Load immediate
---- No Source ------------------------------------------------------------------------------------
+00000F3B:   E090        LDI     R25,0x00         Load immediate
+00000F3C:   0EE8        ADD     R14,R24          Add without carry
+00000F3D:   1EF9        ADC     R15,R25          Add with carry
178: for (cnt = 0; cnt < SPM_PAGESIZE; cnt += 2)
+00000F3E:   5042        SUBI    R20,0x02         Subtract immediate
---- No Source ------------------------------------------------------------------------------------
+00000F3F:   4050        SBCI    R21,0x00         Subtract immediate with carry
+00000F40:   FF57        SBRS    R21,7            Skip if bit in register set
+00000F41:   CFE9        RJMP    PC-0x0016        Relative jump
188: boot_page_write (page);  	// Store buffer in flash page.
+00000F42:   E085        LDI     R24,0x05         Load immediate
---- No Source ------------------------------------------------------------------------------------
+00000F43:   01FB        MOVW    R30,R22          Copy register pair
+00000F44:   93800057    STS     0x0057,R24       Store direct to data space
+00000F46:   95E8        SPM                      Store program memory
190: boot_spm_busy_wait();       	// Wait until the memory is written.
+00000F47:   B607        IN      R0,0x37          In from I/O location
---- No Source ------------------------------------------------------------------------------------
+00000F48:   FC00        SBRC    R0,0             Skip if bit in register cleared
+00000F49:   CFFD        RJMP    PC-0x0002        Relative jump
191: boot_rww_enable ();
+00000F4A:   E181        LDI     R24,0x11         Load immediate
---- No Source ------------------------------------------------------------------------------------
+00000F4B:   93800057    STS     0x0057,R24       Store direct to data space
+00000F4D:   95E8        SPM                      Store program memory
+00000F4E:   CF22        RJMP    PC-0x00DD        Relative jump

At first i tought the pagebuffer wasn't correctly written since i had trouble finding the LDI setting up r19, but then i found it.
Bootsize is 1024 bytes and the fuse bits are programmed accordingly.
Device is a ATMega16L.
I've been debugging this codesnippet for about two days now... Does anybody see what is wrong or does anybody know how to fix this from past experiences???
Any input is appriciated

Thanks in advance,
KK.

Assumptio mater errorum est

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

kkempeneers wrote:

page = address;

for (cnt = 0; cnt < SPM_PAGESIZE; cnt += 2)
{
	w = (*pbuf ++);
	w += (*pbuf ++) << 8;
					
	boot_page_fill (address, w);
					
	address += 2;  	// Select next word in memory					
} 									// Loop until all bytes written
				
boot_page_write (page);  	// Store buffer in flash page.
boot_spm_busy_wait();       	// Wait until the memory is written.
boot_rww_enable ();

As you can see the code is almost completely copied from the AVR-Libc user's manual.

Hi Koen,

- I'm assuming you're using avr-libc 1.2.3, correct?

- Can you show a little bit more of the context of the code above? Specifically, definition of page, address, pbuf, what gets assigned to pbuf. Is it just like the code example in the avr-libc manual, with the disabling of the interrupts, waiting for any eeprom writes to finish, etc.

Thanks
Eric

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

Eric,

Thanks for taking a look, i'm really losing it with this... Yes i'm using the 1.2.3 AVR-Libc. The address is set by AVRProg to 0x0000 (Big Endian);

if (command == 'A')						// Set Address
{
	address = UART_getchar ();
	address <<= 8;
	address |= UART_getchar ();
			
	/* Convert Word to Byte addresses */
	address = address << 1;
	UART_putchar ('\r');
}

The fusebits set the bootsize to 1024 words starting address 0x1C00. That is where the bootreset vector lies (BOOTRST = 0) Since interrupts are never enabled there was no disabling of interrupts before. I tried with the cli () macro just after reset the problem stays the same.
Below you'll find the entire context of the flashing sequence;

else if (command == 'B')						// Start Block Write
{
	unsigned int cnt;
	unsigned int w;
	
	unsigned char * pbuf = buf;
	
	// Get the buffersize
	size = UART_getchar ();
	size <<= 8;
	size |= UART_getchar ();
	
	mem = UART_getchar ();						// 'F' for Flash, 'E' for EEPROM
	
	for (cnt = 0 ; cnt < UART_RX_BUFFER_SIZE; cnt ++) 
	{
		if (cnt < size) buf [cnt] = UART_getchar ();
		else buf [cnt] = 0xFF;
	}
	
	eeprom_busy_wait ();	
	
	if (mem == 'E')								// Start EEPROM
	{
		address >>= 1;
		
		do {
			eeprom_busy_wait ();				// Wait for EEPROM write to finish
			eeprom_write_byte ((char *) address, (*pbuf ++));				
		 
			address ++;							// Select next byte
			size --;							// Decrease number of bytes to write
		} while(size);							// Loop until all bytes written
		
	} else {
		page = address;
		
		for (cnt = 0; cnt < SPM_PAGESIZE; cnt += 2)
		{
			w = (*pbuf ++);
			w += (*pbuf ++) << 8;
			
			boot_page_fill (address, w);
			
			address += 2;  						// Select next word in memory					
		} 										// Loop until all bytes written
		
		boot_page_write (page);  				// Store buffer in flash page.
		
		boot_spm_busy_wait();       			// Wait until the memory is written.
		boot_rww_enable ();
	}											// End FLASH			
	
	UART_putchar ('\r');			
}

Koen.

Assumptio mater errorum est

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

Have you tried using the boot_page_fill_safe() and boot_page_write_safe() macros in place of the normal ones? (See avr-libc docs).

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

No i haven't, what is the data argument supposed to be??? There's nothing mentioned in the documents...

I there a typo in the header file???

#define boot_page_write_safe(address, data) \
    __boot_eeprom_spm_safe (boot_page_wrte, address, data)

KK

Assumptio mater errorum est

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

Yeah, I think it's a typo. Looks that way to me. (You could always fill out a bug report on it.)

AFAIK, the data arguments are the same for the *_safe macros.

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

@ KK

If you need a code sample to compare, then check my bootloader project here:
https://www.avrfreaks.net/index.php?module=FreaksAcademy&func=viewItem&item_id=320&item_type=project
The code use the functions from avr-libc and it works.

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

That doesn't seem to bring salvation, the *_safe macro's generate;

Compiling: main.c
avr-gcc -c -mmcu=atmega16 -I. -gdwarf-2   -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=main.lst  -std=gnu99 -Wp,-M,-MP,-MT,main.o,-MF,.dep/main.o.d main.c -o main.o 
main.c:207:34: macro "boot_page_write" passed 2 arguments, but takes just 1
main.c: In function `main':
main.c:207: error: `boot_page_write' undeclared (first use in this function)
main.c:207: error: (Each undeclared identifier is reported only once
main.c:207: error: for each function it appears in.)
make.exe: *** [main.o] Error 1

That's with the suspected typo corrected.

KK

Assumptio mater errorum est

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

Thanks Mr. Mic, i'll do the comparing... Let you know what i find.

Assumptio mater errorum est

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

Ok, The problem is allways where you don't look, the byte - word address issue... Again. The bootsection start in the makefile was filled in with a word address (0x1C00 for M16). While the linker expects byte addresses.
So darn confusing.

KK.

Assumptio mater errorum est

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

Yes, it's terribly confusing. It's my biggest gripe with the otherwise excellent datasheets by Atmel.

I'm glad you got it working!

Eric