Mega2560 bootloader source

At massimo's request I have posted the updated source code for the standard bootloader that works on the 2560. Also included is a new make file. There are several additional cpus supported.

http://www.cbxdragbike.com/arduino/bootloaderdocs/index.html

Mark

Thanks for posting this!

I can verify it works with a prototype board with a 2560. :slight_smile:

I just got a board with a 2560 and did get one program to load correctly.

Another produced some errors, I think in your new cores. I am going to bed, can look at this myself in a day or two.

Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../../avr/include/avr/eeprom.h: In function 'void eeprom_read_block(void*, const void*, size_t)':

/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../../avr/include/avr/eeprom.h:290: error: ISO C++ forbids incrementing a pointer of type 'void*'

/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../../avr/include/avr/eeprom.h:290: error: ISO C++ forbids incrementing a pointer of type 'const void*'

/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../../avr/include/avr/eeprom.h:290: error: invalid conversion from 'const void*' to 'const uint8_t*'

/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../../avr/include/avr/eeprom.h:290: error:   initializing argument 1 of 'uint8_t eeprom_read_byte(const uint8_t*)'

/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../../avr/include/avr/eeprom.h: In function 'void eeprom_write_block(const void*, void*, size_t)':

/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../../avr/include/avr/eeprom.h:398: error: ISO C++ forbids incrementing a pointer of type 'void*'

/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../../avr/include/avr/eeprom.h:398: error: ISO C++ forbids incrementing a pointer of type 'const void*'

/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../../avr/include/avr/eeprom.h:398: error: invalid conversion from 'void*' to 'uint8_t*'

/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../../avr/include/avr/eeprom.h:398: error:   initializing argument 1 of 'void eeprom_write_byte(uint8_t*, uint8_t)'

Its not in cores, the issue is in
/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/avr/include/avr/eeprom.h
and there are several sections of the form
#if (! (defined(AVR_ATmega2560) || defined(AVR_ATmega2561)) ) in there. So the code is not yours
but was not being compiled for other Arduinos.

static __inline__ void
eeprom_read_block (void *__dst, const void *__src, size_t __n)
{
#if (! (defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__)) )
    __eerd_block (__dst, __src, __n, eeprom_read_byte);
#else
    /* If ATmega256x device, do not call function. */
    while (__n--)
    {
        *(char *)__dst++ = eeprom_read_byte(__src++);      //line 290 
    }
#endif
}
static __inline__ void
eeprom_write_block (const void *__src, void *__dst, size_t __n)
{
#if (! (defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__)) )
    __eewr_block (__dst, __src, __n, eeprom_write_byte);
#else
    /* If ATmega256x device, do not call function. */
    while (__n--)
        eeprom_write_byte (__dst++, *(uint8_t *)__src++);         //line 398
#endif

I wonder if this code, which seems to have come from Atmel, works on a different compiler but not on gcc?

Seems like one of C++s < > casts might be the ticket.

...source code for the standard bootloader that works on the 2560.

I just had a look at the source to see how support for 256k flash was handled (the current bootloader limit is 128k max). As far as I can see however no attempt has been made to solve this - or did I miss out on something?

I think I read elsewhere that the bootloader only handles 128K. that is a small problem when gcc only works up to 80K, as you have probably followed on the developer mailing list.

So why would anyone want to get a 2560 based board is only 80k is actually usable? Is this something anticipated to be fixed someday?

Lefty

This does get through the compiler without errors. I would hope the optimizer reduces what seems like a lot of unnecessary nonsense

/** \ingroup avr_eeprom
    Read a block of \a __n bytes from EEPROM address \a __src to SRAM
    \a __dst.
 */
static __inline__ void
eeprom_read_block (void *__dst, const void *__src, size_t __n)
{
#if (! (defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__)) )
    __eerd_block (__dst, __src, __n, eeprom_read_byte);
#else
    /* If ATmega256x device, do not call function. */
      uint8_t* dest = reinterpret_cast<uint8_t*> (__dst);
      const uint8_t* source = reinterpret_cast< const uint8_t*> (__src);
    while (__n--)
    {
        *dest++ = eeprom_read_byte(source++);      // once was line 290 
    }
#endif
}

seems like there must be a better way.

Coding Badly helped me out with this which is MUCH better. It looks like it will produce the same code as the original and fixes both problems.

static __inline__ void
eeprom_write_block (const void *__src, void *__dst, size_t __n)
{
#if (! (defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__)) )
  __eewr_block (__dst, __src, __n, eeprom_write_byte);
#else
  /* If ATmega256x device, do not call function. */
  while (__n--)
  {
    eeprom_write_byte( (uint8_t*)__dst, *(uint8_t *)__src );
    __src = (uint8_t*)__src + 1;
    __dst = (uint8_t*)__dst + 1;
  }
#endif
}

As I look at a datasheet what I see is this

9.4 ATmega2560 rev. E
No known errata.

...
9.8 ATmega2560 rev. A
...

  1. EEPROM read from application code does not work in Lock Bit Mode 3
    When the Memory Lock Bits LB2 and LB1 are programmed to mode 3, EEPROM read does
    not work from the application code.
    Problem Fix/Workaround
    Do not set Lock Bit Protection Mode 3 when the application code needs to read from
    EEPROM.

So I am wondering if everyone using a 2560 on an arduino, given that this is a recent development, will end up with a revE and not actually need the code that is conditionally compiled??

I have had this fixed for some time, refer to

http://www.cbxdragbike.com/arduino/new/

I was puzzled as to why eeprom.h actually had code conditionally compiled for the 2560 and 2561 chips. Reading the datasheet for the ATmega 640_1280_1281_2560_2561, there is example code for how to write and read EEPROM that makes no distinction between the processors. The size of EEPROM is the same. There was an error on rev A of the 2560 (see section 36.8 of the datasheet, page 428 of the version I have), involving LB mode 3, which is described in table 29-2 (on page 335 of the version of the datasheet that I have). That error is not present in more recent versions of the 2560 and Mark Sproul thinks that flaws in that chip would prevent his bootloader from working with it. The error described didn't really fit with the code in eeprom.h, as far as I could tell.

I think more than half of the source lines in eeprom.h were in the conditionally compiled stuff. I decided to try to see if the conditionally compiled code was needed at all, by first writing a little test program to write all of EEPROM, then read it then write it again, reversing every 1 bit to a 0 bit and reading it again. Once I had that working, I eliminated all of the lines in eeprom.h relating to specifically to the 2560. The test runs without any complaint on my example of a 2560. The test sketch looks like this:

#include <EEPROM.h>
#include <Streaming.h>

#define LEDPIN 13 

/*This is a program to test EEPROM in the arduino Mega, etc. it assumes that there are 4096 bytes of EEPROM
  I hope the EEPROM is laid out in a 64 row x 64 column square. if that is so, then the program writes a pattern to 
  EEPROM that puts a 1 on all 4 side of each 0 and a zero on all 4 sides of each one. then it reads that, checking
  to see that the pattern is as expected. then it reverses the pattern so that each 1 becomes a zero and vice versa.
  
  After the program loads, it waits until you open a Serial window and send it something before it starts.
  
  if it succeeds, the output should look like:
    starting writing
    starting reading
    Done with pattern1 = AA
    starting writing
    starting reading
    Done with pattern1 = 55
    All done.
*/



void setup(void) {
 Serial.begin(38400);
 uint16_t i,j,column;
 uint8_t valRead,k;
 pinMode(LEDPIN,OUTPUT);
 while ( !Serial.available( ) ) {};  //wait for serial window to be valid so we don't lose output.
 uint8_t pattern1=0xAA;
 uint8_t pattern2=0x55;
 for (k=0;k<=1;k++) { 

  Serial.println("starting writing");
  for (i=0;i<=62;i+=2) {
    digitalWrite(LEDPIN,HIGH);
    column = i<<6;
    for (j=0; j<=62; j+=2) {
      //Serial<<column+j<<" i="; Serial<<i;
      //Serial<<"  j="; Serial<<j; Serial<<endl;
      EEPROM.write(column+j,pattern1);             // i*256+j
      EEPROM.write( column+j+1,pattern2);         // column j+1
    }
    digitalWrite(LEDPIN,LOW);
    column +=64;
    for (j=0;j<=62;j+=2) {
      //Serial<<column+j<<" I="<<i<<"  J="<<j<<endl;
      EEPROM.write( column+j,pattern2);               // row i+1
      EEPROM.write( column+j+1,pattern1);
    }
  }
   Serial.println("starting reading");
   for (i=0;i<=62;i+=2) {
    column = i<<6;
    digitalWrite(LEDPIN,HIGH);
    for (j=0;j<=62;j+=2) {
      valRead = EEPROM.read(column+j);
      if (pattern1 != valRead) {
         Serial<<"read "<<_HEX(valRead)<<" at "<<(int)(column+j)<<" should be "<< _HEX(pattern1)<<endl; 
      }
      valRead = EEPROM.read(column+j+1);
      if (pattern2 != valRead) {
         Serial<<"read "<<_HEX(valRead)<<" at "<<(int)(column+j+1)<<" should be "<< _HEX(pattern2)<<endl; 
      }
    }
    column += 64;
    digitalWrite(LEDPIN,LOW);
    for (j=0;j<=62;j+=2) {
      valRead = EEPROM.read(column+j);
      if (pattern2 != valRead) {
         Serial<<"read "<<_HEX(valRead)<<" at "<<(int)(column+j)<<" should be "<<  _HEX (pattern2)<<endl;
         uint8_t pattern2=0x55;pattern2<<endl; 
      }
      valRead = EEPROM.read(column+j+1);
      if (pattern1 != valRead) {
         Serial<<"read "<<_HEX(valRead)<<" at "<<(int)(column+j+1)<<" should be "<< _HEX (pattern1)<<endl; 
      }
    }

  }
   Serial<<"Done with pattern1 = "<<_HEX(pattern1)<<endl;
   pattern1=0x55;
   pattern2=0xAA; 

 }
 Serial.println("All done.");
}
void loop(void){
  
  delay(500);
}

The eeprom.h source won't fit in a post, it is at http://www.healthriskappraisal.org/eeprom.zip