Build_flags = -Wl,--section-start=.text=0x7000 Code not executing on ATMEGA328

Im currently using GitHub - MCUdude/MiniCore: Arduino hardware package for ATmega8, ATmega48, ATmega88, ATmega168, ATmega328 and ATmega328PB for the ATMEGA support.

I’ve stripped back alot of my code into a simple blinky application, but when placed in the bootloader section

build_flags =
-Wl,–section-start=.text=0x7000

it doesn’t run. When i change the section to
build_flags =
-Wl,–section-start=.text=0x0000

The basic blinky code runs, even if I leave the fuses set to run from bootloader code space first (I suspect its hitting asm(‘NOP’) until the program counter rolls over to 0).

Im unsure why setting -Wl,–section-start=.text=0x0000 to 0x7000 no longer allows this code to work.

Below is the full platform.ini file:

[env:ATmega328]
platform = atmelavr
board = ATmega328
framework = arduino
build_flags =
  -Wl,--section-start=.text=0x7000

And here is main.cpp

#include <Arduino.h>

const int ledPin1 = 4;  // PD4
const int ledPin2 = 7;  // PD7

void setup() 
{
  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);;
}

void loop() 
{
      while(1)
    {
  // Turn on both LEDs
  digitalWrite(ledPin1, HIGH);
  digitalWrite(ledPin2, HIGH);

  delay(100);
  
  // Turn off both LEDs
  digitalWrite(ledPin1, LOW);
  digitalWrite(ledPin2, LOW);
  
  delay(100);
    }
}

Fuse settings as follows

So more experimentation, something in ARDUINO.h expects code be executed from flash address 0. Or something along those lines. The following code does work when altering the .text value

#include <avr/io.h>
#include <util/delay.h>

int main(void) 
{
    DDRD |= (1 << PD4);  // Set PD4 as an output
    DDRD |= (1 << PD7);  // Set PD4 as an output

    while (1) 
    {
        PORTD |= (1 << PD4);  // Turn on LED
        PORTD |= (1 << PD7);  // Turn on LED
        _delay_ms(500);      // Delay for 500 ms
        PORTD &= ~(1 << PD4); // Turn off LED
        PORTD &= ~(1 << PD7); // Turn off LED
        _delay_ms(500);      // Delay for 500 ms
    }

    return 0;
}

Which is a shame as there are arduino libraries I’d like to use.

I’ve discovered its something to do with the Arduino delay function as this also works.

#include <avr/io.h>
#include <util/delay.h>
#include <Arduino.h>

const int ledPin1 = 4;  // PD4
const int ledPin2 = 7;  // PD7

int main(void) 
{
  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);;

    while (1) 
    {
  digitalWrite(ledPin1, HIGH);
  digitalWrite(ledPin2, HIGH);
        _delay_ms(500);      // Delay for 500 ms
  digitalWrite(ledPin1, LOW);
  digitalWrite(ledPin2, LOW);
        _delay_ms(500);      // Delay for 500 ms
    }

    return 0;
}

Issue found to be a combination of not setting registers to move interrupt table to boot location and Arduino trying to to init interrupts before they are moved in setup.

Solution to this is implementing you own main, calling arduino init(), setup() and loop() in it. See below.


int main() 
{
  // Call your custom initialization function
  MCUCR = _BV(IVCE);       
  MCUCR = _BV(IVSEL); //move interruptvectors to the Boot sector 

  // Initialize the Arduino framework
  init();

  // Run the Arduino setup and loop functions
  setup();
  for (;;) {
    loop();
  }
  return 0;
}

Can you report that to https://github.com/MCUdude/MiniCore/issues?

Why? The isn’t a MiniCore issue to my knowledge and is a fundamental feature of Arduino libraries (that I was un aware of).

Arduino implements its own main in which it does its own initialisation that enables a timer interrupt for functions such as delay()as such an interrupt will fire and jump to the wrong vector table long before you hit the setup() function.

You would encounter this exact problem trying to use interrupts in bootloader flash space (with appropriate fuses) on an Arduino uno, never using MiniCore.

1 Like