avrnet bootloader on mega1284p

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

I have been working on porting an atmega32 project to atmega1284p, and only have the bootloader left now.

I have changed, or rather defined the names for registers that have changed, and changed the bootloader address in project settings (avr studio 4) and fuses.

When the board boots, it enter bootloader correct, and I can start a upload, however several times during the load, it seems to reboot, without the MCUSR giving an idea of why.

The boot loading completes "successfully", but the program never stats, and a hex dump confirms the flash was not actually updated.

Anybody see anything wrong with this (just main file included)

//********************************************************************************************
//
// AVRnetLoader firmware Version 1.0
//
// MCU : ATMEGA32 @ 16MHz
// Ethernet controller : ENC28J60
// IDE & Compiler : AVR Studio version 4.13.528 & WINAVR version 20070525
// Author : Jirawat Kongkaen
// Website : http://www.avrportal.com/
//
// *** important ***
// Please set .text section to 0x3800 before build all source code 
// by select menu
// Project -> Configuration Options
// then select Memory settings and click add button
// Memory type is Flash
// Name is .text
// Address is 0x3800
//
//********************************************************************************************
//
// File : main.c main program for AVRnet development board.
//
//********************************************************************************************
//
// Copyright (C) 2007
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
// This program is distributed in the hope that it will be useful, but
//
// WITHOUT ANY WARRANTY;
//
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the Free Software Foundation, Inc., 51
// Franklin St, Fifth Floor, Boston, MA 02110, USA
//
// http://www.gnu.de/gpl-ger.html
//
//********************************************************************************************
#include "define.h"
#include 
#include 
#include 
#include 

// Global variables
MAC_ADDR avr_mac;
IP_ADDR avr_ip;
MAC_ADDR host_mac;
IP_ADDR host_ip;
BYTE rxtx_buffer[MAX_RXTX_BUFFER];
WORD dlength;
WORD boot_delay=0;
WORD_BYTES address, temp;
BYTE i, led_delay=0;

//BYTE ee_avr_ip[4] EEMEM = { 10, 1, 1, 1 };

void block_read(BYTE *rxtx_buffer, WORD size, BYTE mem, WORD *address);
BYTE block_load(BYTE *rxtx_buffer, WORD size, BYTE mem, WORD *address);

// software reset 
void software_reset(void) __attribute__ ((naked));
void software_reset(void)
{
	wdt_enable(WDTO_15MS);
	for(;;);
}

// application vector
void (*jump_to_application)(void) = (void *)0x0000;

#define LED_DDR		DDRC
#define LED_PORT	PORTC
#define LED_PIN		PINC
#define LED_STATUS	PC7


#define UCSRA UCSR0A
#define UBRRL UBRR0L
#define UCSRB UCSR0B
#define UDR UDR0
#define UDRE UDRE0
#define TXEN TXEN0
#define RXEN RXEN0
#define EEMWE EEMPE 
#define EEWE EEPE 

int uart_putchar0(char c, FILE *stream)
{
  while ((UCSRA & (1 << UDRE)) == 0) {}; // Do nothing until UDR is ready for more data to be written to it
    UDR = c;

  return 0;
}

//Fylder mindre end printf
void putString(char* str)
{
	char* ptr = str;

	while (*ptr != '\0')
	{
		putchar(*ptr);
		ptr++;
	}
}

FILE uart0_str = FDEV_SETUP_STREAM(uart_putchar0, NULL, _FDEV_SETUP_WRITE);

ISR(WDT_vect) {
    printf("Watchdog timeout, saving eeprom\r\n");
    while(true); //Next WDT timeout will reset chip
}

int main(void) __attribute__ ((naked));
int main(void) 
{
    uint8_t resetSource = MCUSR;
	wdt_reset();
	wdt_disable();
	wdt_reset();
//	wdt_enable(WDTO_4S);
//	WDTCSR |= (1 << WDIE);  //enable watchdog interrupt


	UBRRL = 0; //1,000,000@16mhz
    UCSRB = _BV(TXEN) | _BV(RXEN); /* tx/rx enable */

	stdout = &uart0_str;

    if(resetSource & (1<<WDRF))
    {
        printf("Mega was reset by watchdog...\r\n");
    }

    if(resetSource & (1<<BORF))
    {
        printf("Mega was reset by brownout...\r\n");
    }

    if(resetSource & (1<<EXTRF))
    {
        printf("Mega was reset by external...\r\n");
    }

    if(resetSource & (1<<PORF))
    {
        printf("Mega was reset by power on...\r\n");
    }

	printf("Bootloader ready\r\n");

	//BYTE i;
	//BYTE rxtx_buffer[MAX_RXTX_BUFFER];
	//WORD dlength;
	//WORD boot_delay=0;
	//WORD_BYTES address, temp;
	//BYTE i, led_delay=0;

	// Change MAC Address here
	eeprom_read_block ( &avr_mac, (void*)23, 6 );
	if (avr_mac.byte[0]==0xff || avr_mac.byte[1]==0xff || avr_mac.byte[2]==0xff || avr_mac.byte[3]==0xff || avr_mac.byte[4]==0xff || avr_mac.byte[5]==0xff)
	{
		avr_mac.byte[0] = 0;
		avr_mac.byte[1] = 32;
		avr_mac.byte[2] = 24;
		avr_mac.byte[3] = 177;
		avr_mac.byte[4] = 21;
		avr_mac.byte[5] = 111;
	}

	// read AVR IP from eeprom, if IP=0xff,0xff,0xff,0xff change it to default IP
	eeprom_read_block ( &avr_ip, (void*)11, 4 );
	if(avr_ip.byte[0]==0xff || avr_ip.byte[1]==0xff || avr_ip.byte[2]==0xff || avr_ip.byte[3]==0xff)
	{
		// default IP
		avr_ip.byte[0]=192;
		avr_ip.byte[1]=168;
		avr_ip.byte[2]=1;
		avr_ip.byte[3]=47;
	}

	// initial ENC28J60
	enc28j60_init((BYTE*)&avr_mac);
	// set LED_STATUS as output
	LED_DDR |= _BV(LED_STATUS);

	for(;;)
	{
		// wait 5'S for enter to bootloader command
		if(flag1.bits.prog_mode==0)
		{
			if(++boot_delay==10000)
			{						
				flag1.bits.prog_mode = 1;

				temp.word = 0;
			
				// check blank (first block only)
				block_read((BYTE*)&rxtx_buffer, BLOCKSIZE, 'F', &temp.word); // Block read
			
				for(i=0; i>8) & 0xFF); // MSB first.
			rxtx_buffer[UDP_DATA_P+2] = (BLOCKSIZE&0xFF); // Report BLOCKSIZE (bytes).
			udp_send_packet((BYTE*)&rxtx_buffer, 3); // send 3-bytes
			continue;
		}

		// Start block load.
		else if(rxtx_buffer[UDP_DATA_P]=='B')
		{
			temp.byte.high = rxtx_buffer[UDP_DATA_P+1];// Get block size.
			temp.byte.low = rxtx_buffer[UDP_DATA_P+2];

			rxtx_buffer[UDP_DATA_P] = block_load((BYTE*)&rxtx_buffer, temp.word, rxtx_buffer[UDP_DATA_P+3], &address.word); // Block load.
			udp_send_packet((BYTE*)&rxtx_buffer, 1); // send ok to host
			continue;
		}
		    
		// Start block read.
		else if(rxtx_buffer[UDP_DATA_P]=='g')
		{
			temp.byte.high = rxtx_buffer[UDP_DATA_P+1];// Get block size.
			temp.byte.low = rxtx_buffer[UDP_DATA_P+2];
			block_read((BYTE*)&rxtx_buffer[UDP_DATA_P], temp.word, rxtx_buffer[UDP_DATA_P+3], &address.word); // Block read
			udp_send_packet((BYTE*)&rxtx_buffer, temp.word); // send flash data to host
			continue;
		}		

	} // end for(;;)
	return 0;
}// end main


unsigned char block_load(BYTE *rxtx_buffer, WORD size, BYTE mem, WORD *address)
{
	//unsigned char buffer[BLOCKSIZE];
	WORD_BYTES data;
	WORD tempaddress;
	WORD temp;

	// EEPROM memory type.
	if(mem=='E')
	{
        /* Fill buffer first, as EEPROM is too slow to copy with UART speed */
        //for(tempaddress=0;tempaddress> 8);
            EEDR = rxtx_buffer[UDP_DATA_P+4+tempaddress]; // Get byte.
            EECR |= (1<<EEMWE); // Write byte.
            EECR |= (1<<EEWE);
            while (EECR & (1<<EEWE)); // Wait for write operation to finish.

  			(*address)++; // Select next EEPROM byte
        }

        return '\r'; // Report programming OK
    } 
    
    // Flash memory type.
	else if(mem=='F')
    { // NOTE: For flash programming, 'address' is given in words.
        (*address) <<= 1; // Convert address to bytes temporarily.
        tempaddress = (*address);  // Store address in page.
		putchar('#');
        for(temp=0; temp>= 1; // Convert address back to Flash words again.
        return '\r'; // Report programming OK
    }
    
    // Invalid memory type?
    else
    {
        return '?';
    }
}


void block_read(BYTE *rxtx_buffer, WORD size, BYTE mem, WORD *address)
{
	//BYTE temp;

	//temp = size;
    // EEPROM memory type.
    if (mem=='E') // Read EEPROM
    {
        do
        {
            EEARL = *address; // Setup EEPROM address
            EEARH = ((*address) >> 8);
            (*address)++; // Select next EEPROM byte
            EECR |= (1<<EERE); // Read EEPROM
            *rxtx_buffer++ = EEDR; // Transmit EEPROM dat ato PC

            size--; // Decrease number of bytes to read
        } while (size); // Repeat until all block has been read
		
    }
    
    // Flash memory type.
	else if(mem=='F')
	{
        (*address) <<= 1; // Convert address to bytes temporarily.
	
        do
        {

            *rxtx_buffer++ = _LOAD_PROGRAM_MEMORY(*address);
            *rxtx_buffer++ = _LOAD_PROGRAM_MEMORY((*address)+1);

            (*address) += 2; // Select next word in memory.
            size -= 2; // Subtract two bytes from number of bytes to read
        } while (size); // Repeat until all block has been read
		
        (*address) >>= 1; // Convert address back to Flash words again.
    }
}

USART debug

Mega was reset by watchdog...
Mega was reset by brownout...
Mega was reset by external...
Mega was reset by power on...
Bootloader ready
Programming mode enabled
Chip erase mode
##################################Mega was reset by watchdog...
Mega was reset by brownout...
Mega was reset by external...
Mega was reset by power on...
Bootloader ready
########################################################################Mega was reset by watchdog...
Mega was reset by brownout...
Mega was reset by external...
Mega was reset by power on...
Bootloader ready
########################################################################Mega was reset by watchdog...
Mega was reset by brownout...
Mega was reset by external...
Mega was reset by power on...
Bootloader ready
##########################################EMega was reset by watchdog...

The program I am trying to load is less than 32kbyte, but the bootloader is located in the >64kbyte flash space, does this need special care ?

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

A couple of suggestions:
1) Clear the MCUSR after getting the reset source
2) Are you disabling interrupts before doing the flash page write? Here is suggested code

*---------------------------------------------------------------------------*/
/*
 * The following code was taken from the avr-libc manual:
 */
void
flash_write_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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have changed the flash code to use that function instead.
Also corrected the page size in the pc program to use 256byte/128word size (and avr program uses the SPM_PAGESIZE).

Looks better now, it flashes and tries to jump to app.
But a flash read shows it didnt go quite right.
Have included a diff between the read flash and the hex that was programmed (after a hex2bin conversion)

left is what avr studio read from the chip, right is the source.

Programming mode enabled
Chip erase mode
##############################################################################################################EMega was reset by watchdog...
Bootloader ready
Jumping to appBootloader ready

Attachment(s): 

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

I would guess you are writing page 0 over and over. There are ascii strings in there, is that the last page written?

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

When MCUCSR holds 0 after a "reset" it's likely because of a "JMP 0". That occurs in avr-gcc when an interrupt is enabled for which there's no defined handler. Do you enable interrupts? Do you have an ISR() for every ??IE bit that is set?

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

Thanks for the help.
Good to know that a missing ISR can cause a reset also.

I have got the bootloader working again, for anyone that may stumble on this topic in the future, the relevant parts are in boot.h and the client pc program, besides the defindes for renamed registers.

The pc program sends 2 bytes to represent the pagesize, since this is 256, that would be 0x01 0x00.

#define PROGMEM_SIZE	131072	// in bytes
#define BLOADER_SIZE	8192	// in bytes
#define	PAGESIZE		256		// in bytes
#define PAGE			((PROGMEM_SIZE-BLOADER_SIZE)/PAGESIZE)
#define	APP_END			0xEFFF
#define BLOCKSIZE		PAGESIZE

It can ofcause fit in 2kbyte, but I selected the largest bootloader size to allow for bigger bootloader in the future, without having to change fuses.