Pages: [1]   Go Down
Author Topic: Leonardo bootloader won't program  (Read 1651 times)
0 Members and 1 Guest are viewing this topic.
USA
Offline Offline
Full Member
***
Karma: 0
Posts: 238
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

This may or may not be considered a bug.  I have been struggling with Leonardo boards not being able to be reprogrammed after I program them with the following Test Sketch.  I believe I now understand why.  The Leonardo bootloader uses a 16-bit value stored at base address 0x800 as a variable to tell it why the watchdog timer reset the chip.  If the value is set to 0x7777, then it assumes that the Arduino IDE has reset the chip for reprogramming; otherwise, it assumes that the sketch was uses the watchdog for its own reason.  If the IDE had reset the chip, then the bootloader will go into a mode where it waits for 8 seconds for instructions to be reprogrammed otherwise the bootloader jumps to the sketch.  The problem I was having is that the GCC linker was putting the variable timer0_millis on the base address of 0x800.  It's not the linker's fault because it has no way to know that this address is 'reserved.'  This problem can be prevented if it knows not to use that 'reserved' address block.  Can the linker script be modified so that the start or end address of SRAM is moved inwards one byte so the linker will never assign that address to any variable?  If you run the Test Sketch below, then you will have to manually start the bootloader in ‘reprogram’ mode by pushing the reset button on the board.  I consider this a bug because this is unexpected behavior.  This is not the hardware stack overrunning some global state.

I'm using the Arduino IDE v1.5 on Windows XP SP3.

Test sketch
Code:
#include <util/delay.h> // using _delay_ms

byte buf[1736];
extern unsigned long timer0_millis;

void setup(void)
{
  Serial.begin(9600);
  pinMode(13, OUTPUT);
  //TIMSK0 = 0;
}

void loop(void)
{
  static uint16_t last_value = *(uint16_t *)0x0800;
 
  // print the base address of the internal variable 'timer0_millis'
  // that is used by the function 'millis()'
  if (Serial) {
    Serial.println((unsigned int)&timer0_millis, HEX);
    _delay_ms(1000);
  }

  // pulse LED if bootKey is changing
  if (*(uint16_t *)0x0800 != last_value) {
    last_value = *(uint16_t *)0x0800;
    digitalWrite(13, !digitalRead(13));   
    _delay_ms(100);
  }
 
  // prevent the optimizer from removing the array
  buf[0] = buf[buf[0]];
}

From the file Caterina.c in the bootloader
Code:
uint16_t bootKey = 0x7777;
volatile uint16_t *const bootKeyPtr = (volatile uint16_t *)0x0800;
// ...
int main(void)
{
/* Save the value of the boot key memory before it is overwritten */
uint16_t bootKeyPtrVal = *bootKeyPtr;
*bootKeyPtr = 0;

/* Check the reason for the reset so we can act accordingly */
uint8_t  mcusr_state = MCUSR; // store the initial state of the Status register
MCUSR = 0; // clear all reset flags

/* Watchdog may be configured with a 15 ms period so must disable it before going any further */
wdt_disable();

if (mcusr_state & (1<<EXTRF)) {
// External reset -  we should continue to self-programming mode.
} else if (mcusr_state == (1<<PORF) && pgm_read_word(0) != 0xFFFF) {
// After a power-on reset skip the bootloader and jump straight to sketch
// if one exists.
StartSketch();
} else if ((mcusr_state == (1<<WDRF)) && (bootKeyPtrVal != bootKey) && (pgm_read_word(0) != 0xFFFF)) {
// If it looks like an "accidental" watchdog reset then start the sketch.
StartSketch();
}

From the file CDC.cpp
Code:
//...
*(uint16_t *)0x0800 = 0x7777;
wdt_enable(WDTO_120MS);
//...
Logged

Offline Offline
Full Member
***
Karma: 4
Posts: 187
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hard to understand what you want to say.

Is there any bug? How will we help you.

Or you want to tell us about some problem which may be we face during using Leonardo in any project.
« Last Edit: January 12, 2013, 05:26:44 am by Cybernetician » Logged

From Idea To Invention

USA
Offline Offline
Full Member
***
Karma: 0
Posts: 238
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I know my description is difficult to understand but the problem is difficult to explain.  Short answer: sketches can affect how the bootloader behaves and in a bad way.  I think I found a solution to the problem, but I haven't tried it yet.
Logged

USA
Offline Offline
Full Member
***
Karma: 0
Posts: 238
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The following modification to the platform.txt file will move the .data section in one byte leaving the first byte of SRAM available to the bootloader for its bootKey variable.  This will prevent the linker from assigning that address to any other variable.  The only problem is that this change will effect all boards not just the Leonardo board. 

Code:
## BEFORE
compiler.c.elf.flags=-Os -Wl,--gc-sections
## AFTER
compiler.c.elf.flags=-Os -Wl,--gc-sections -Wl,--section-start,.data=0x800101

For more information on memory sections:
http://www.nongnu.org/avr-libc/user-manual/mem_sections.html#sec_dot_data
Logged

USA
Offline Offline
Full Member
***
Karma: 0
Posts: 238
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I found a solution to the problem where my recommendation would affects all of the boards.  The answer is don't change the platform.txt file instead change the boards.txt file.  Add the following line to the boards.txt file.  The bootloader (Caterina.c) still needs to be updated as well as the "core library" (CDC.cpp).

Code:
leonardo.compiler.c.elf.flags=-Os -Wl,--gc-sections -Wl,--section-start,.data=0x800101
Logged

Pages: [1]   Go Up
Jump to: