Questions about the bootloader burning

Hello, I have a few questions about the arduino bootloader. For my project, the arduino has to start running code immediately after it receives power, but (as far as I have read) the arduino bootloader delays the code execution, so, the solution I found online is to burn the bootloader. Questions:
a) will burning the bootloader solve my problem (delayed code execution)?
b) is burning the bootloader a one time thing (like burning a CD) or can I reburn another program onto the arduino?
c) can I use an arduino nano to burn another arduino's (pro mini 3.3v) bootloader? (most examples I read were using an UNO as programmer)
d) Do you know any good YouTube tutorials on the subject?

Thanks for your help!

The solution is the exact opposite, ie don't have a bootloader and hence no delay while the bootloader figures out whether to run the currently loaded program or upload a new one from Serial. You can effectively remove the bootloader by uploading a program using a programmer.

No. See above

You can burn the bootloader (or a program) using a programmer as many times as you like within reason

1 Like

Thanks for the reply. I think I am confused as to what a bootloader is. So what I want is to upload a program to my arduino pro mini (using another arduino), using the "burn bootloader" option, or the "Upload using programmer" option (as seen in this video) ?

If you use "upload using programmer" to upload your sketch code, you wipe the boot loader and your code will run immediately.

1 Like

The bootloader is an optional small piece of code that runs on startup/reset that can start/run a separate piece of code/application (your sketch code) that also stored in the flash.
The bootloader starts up looks for activity on the serial port to update the application code. After a period of time it gives up and jumps to the application code to start it.
When you upload sketch code to the board using a bootloader, the serial port is used and the bootloader on the board processes the serial port data to get the code to store in the application area.

That said, with the optiboot bootloader, the timeout is 500ms and is only done if the external reset is used.
i.e. on powerup or watchdog reset there is no delay.
The 500ms delay only happens when the reset signal is grounded.
So if you want immediate startup on powerup, then you pretty much already have that even when using a bootloader.
i.e. there are only a few instructions that get executed by the bootloader before it determines the reset was not an external reset and jumps to the application code.

In the 1.x IDE tree you can look at bootloader source code.
It is in {installdir}/arduino/avr/bootloaders/optiboot
The main file is optiboot.c

Also, keep in mind that on powerup, the AVR can be up and running before the voltage is all the way up to 5v so other device may not be yet ready to communicate. I see this on devices like hd44780 LCDs where the AVR can be up and running attempting to talk to the LCD before the voltage is high enough for the LCD to work.

If you burn your code directly without using a bootloader, you will use the ISP pins (not the serial port) and you overwrite the entire flash with your sketch code which will erase a bootloader, if present.
This means that the sketch code will start immediately on powerup and reset.

IMO, it is odd that a bootloader is still being used on avr based boards since there now is a second AVR chip doing the USB to serial emulation and that second AVR could just as well also emulate an ISP programmer to program the main AVR processor using ISP instead of using serial talking to the bootloader in the main AVR.
It would save flash in the main AVR and allow the sketch code in the main AVR to start quicker.

--- bill

1 Like

Hello again. I uploaded my program using another arduino and it worked flawlessly. Unfortunately, my code still requires 30s and a reset press to start running. Any other ideas?

I think it's time to

  1. show your code :slight_smile:
  2. show a schematic of all what is connected and how; includes all power and GND. Photo of pencil/paper is fine.

Here is the code.

#include <TinyGPS++.h>
#include <SoftwareSerial.h>
#include<SPI.h>
#include<Adafruit_GFX.h>
#include <Adafruit_ST7789.h>
#define batteryPin A2
#define blueLedPin 7
#include <math.h>

#define R1 0.1006//measured res in Mohms
#define R2 0.0997//in Mohms
const float fact=((R2+((46.14*R1)/(46.14+R1)))/((46.14*R1)/(46.14+R1)));

char Buffer[15];

static const int RXPin = 4, TXPin = 3;
static const uint32_t GPSBaud = 9600;
const double FOURTHPI = PI / 4;
const double deg2rad = PI / 180;
const double rad2deg = 180.0 / PI;
const double equrad = 6377563;
const double squecc = 0.00667054;
#define TFT_DC 8
#define TFT_CS 6

Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, -1);

unsigned long long ms;
float acc;
float bat;
bool first=true, hasUpdate=false;
long easting=0, northing=0;
String GZ; //Grid Zone Designation
String SqID; //Square ID
String estText="";
String norText="";
String mgrsText="";
String statusText="";
String satText;
uint8_t GPSchar;

// The TinyGPS++ object
TinyGPSPlus gps;

// The serial connection to the GPS device
SoftwareSerial ss(RXPin, TXPin);


void setup()
{
  ss.begin(GPSBaud);
  pinMode(batteryPin, INPUT);
  pinMode(blueLedPin, INPUT);

  tft.init(240, 320); 
  tft.setTextSize(4);
  tft.setRotation(3);
  tft.invertDisplay(false);
  tft.fillScreen(tft.color565(0,0,0));
  tft.setTextColor(ST77XX_WHITE);
  tft.setCursor(0,0);
  tft.println("GNSS Finder");
  tft.setTextSize(2);
  tft.println("");
  tft.setTextSize(3);
  tft.print("v1.0\n");
  tft.setTextSize(4);
  tft.print("\n\n\n\n");
  tft.setTextSize(5);
  tft.print("MCH170");
  delay(1000);
  tft.setTextColor(ST77XX_BLACK);
  tft.setCursor(0,0);
  tft.setTextSize(4);
  tft.println("GNSS Finder");
  tft.setTextSize(2);
  tft.println("");
  tft.setTextSize(3);
  tft.print("v1.0\n");
  tft.setTextSize(4);
  tft.print("\n\n\n\n");
  tft.setTextSize(5);
  tft.print("MCH170");
}

void loop()
{
  // This sketch displays information every time a new sentence is correctly encoded.
  hasUpdate=false;
  while (ss.available() > 0)
    if (gps.encode(ss.read())){
  ms=millis();
  LLtoUTM(gps.location.lat(), gps.location.lng());
  acc=30;
  acc=gps.hdop.value()/100;

  sprintf(Buffer, "EST: %.5ld", easting);
  estText=Buffer;
  sprintf(Buffer, "NOR: %.5ld", northing);
  norText=Buffer;
  mgrsText=GZ+" "+SqID+"\n";
  if(digitalRead(blueLedPin)){
      statusText="BAT: CRG ";
  }else{
      if(first){
      //bat=analogRead(batteryPin)*3.3/1023*fact;
      bat=0;
      for(int k=0; k<20; k++){
        bat+=analogRead(batteryPin);
        delay(1);
      }
      bat=bat/20*3.13/1023*fact;
      //bat=(b1+b2+b3+b4+b5)/5/1000/1023*fact;
      if(bat>=4.18) statusText="BAT: 100% ";
      else if(bat>=4.15) statusText="BAT: 95% ";
      else if(bat>=4.11) statusText="BAT: 90% ";
      else if(bat>=4.08) statusText="BAT: 85% ";
      else if(bat>=4.03) statusText="BAT: 80% ";
      else if(bat>=3.99) statusText="BAT: 75% ";
      else if(bat>=3.95) statusText="BAT: 70% ";
      else if(bat>=3.91) statusText="BAT: 65% ";
      else if(bat>=3.87) statusText="BAT: 60% ";
      else if(bat>=3.84) statusText="BAT: 55% ";
      else if(bat>=3.82) statusText="BAT: 50% ";
      else if(bat>=3.80) statusText="BAT: 45% ";
      else if(bat>=3.78) statusText="BAT: 40% ";
      else if(bat>=3.75) statusText="BAT: 35% ";
      else if(bat>=3.72) statusText="BAT: 30% ";
      else if(bat>=3.68) statusText="BAT: 25% ";
      else if(bat>=3.64) statusText="BAT: 20% ";
      else if(bat>=3.60) statusText="BAT: 15% ";
      else if(bat>=3.55) statusText="BAT: 10% ";
      else if(bat>=3.50) statusText="BAT: 5% ";
      else statusText="BAT: LOW ";
  }else{
      statusText="BAT: --- ";
  }
  }
  if(!first)tft.fillScreen(tft.color565(0,0,0));
  first=false; 
  tft.setCursor(0,0);
  tft.setTextColor(tft.color565(255,255,255));
  tft.setTextSize(5);
  tft.println(estText);
  tft.setTextSize(3);
  tft.println(" ");
  tft.setTextSize(5);
  tft.println(norText);
  tft.setTextSize(4);
  tft.println(" ");
  tft.setTextSize(4);
  tft.println(mgrsText);
  tft.print(statusText);
  if(acc<=2.5 && gps.location.isValid()){
    tft.setTextColor(tft.color565(0,170,0));
  }else{
    if(acc<=8 && gps.location.isValid()){
      tft.setTextColor(tft.color565(255,189,23));  
    }else{
      tft.setTextColor(tft.color565(227,14,14));
    }
  }
  tft.print("ACC");

  while(millis()-ms<=300000 && !hasUpdate){
    GPSchar = ss.read();
    gps.encode(GPSchar);
    if(gps.location.isUpdated() && millis()-ms>=120000){
      hasUpdate=true;  
    }
  };
}}

String LLtoUTM(const double Lat, const double Long)
{
    double a = 6378137;
    double eccSquared = 0.00669438;   //WGS-84, 6378137, 0.00669438
    double k0 = 0.9996;
    double LongOrigin;
    double eccPrimeSquared;
    double N, T, C, A, M;
    double UTMEasting;
    double UTMNorthing;
    
  //Make sure the longitude is between -180.00 .. 179.9
    double LongTemp = (Long+180)-int((Long+180)/360)*360-180; // -180.00 .. 179.9;
    double LatRad = Lat*deg2rad;
    double LongRad = LongTemp*deg2rad;
    double LongOriginRad;
    int    ZoneNumber;
    
  ZoneNumber = int((LongTemp + 180)/6) + 1;
  if( Lat >= 56.0 && Lat < 64.0 && LongTemp >= 3.0 && LongTemp < 12.0 )
    ZoneNumber = 32;
  // Special zones for Svalbard
  if( Lat >= 72.0 && Lat < 84.0 ) 
  {
    if(      LongTemp >= 0.0  && LongTemp <  9.0 ) ZoneNumber = 31;
    else if( LongTemp >= 9.0  && LongTemp < 21.0 ) ZoneNumber = 33;
    else if( LongTemp >= 21.0 && LongTemp < 33.0 ) ZoneNumber = 35;
    else if( LongTemp >= 33.0 && LongTemp < 42.0 ) ZoneNumber = 37;
   }
  LongOrigin = (ZoneNumber - 1)*6 - 180 + 3;  //+3 puts origin in middle of zone
  LongOriginRad = LongOrigin * deg2rad;
  //compute the UTM Zone from the latitude and longitude
  eccPrimeSquared = (eccSquared)/(1-eccSquared);
  N = a/sqrt(1-eccSquared*sin(LatRad)*sin(LatRad));
  T = tan(LatRad)*tan(LatRad);
  C = eccPrimeSquared*cos(LatRad)*cos(LatRad);
  A = cos(LatRad)*(LongRad-LongOriginRad);
  M = a*((1 - eccSquared/4    - 3*eccSquared*eccSquared/64  - 5*eccSquared*eccSquared*eccSquared/256)*LatRad 
        - (3*eccSquared/8 + 3*eccSquared*eccSquared/32  + 45*eccSquared*eccSquared*eccSquared/1024)*sin(2*LatRad)
                  + (15*eccSquared*eccSquared/256 + 45*eccSquared*eccSquared*eccSquared/1024)*sin(4*LatRad) 
                  - (35*eccSquared*eccSquared*eccSquared/3072)*sin(6*LatRad));
  
  UTMEasting = (double)(k0*N*(A+(1-T+C)*A*A*A/6
          + (5-18*T+T*T+72*C-58*eccPrimeSquared)*A*A*A*A*A/120)
          + 500000.0);
  UTMNorthing = (double)(k0*(M+N*tan(LatRad)*(A*A/2+(5-T+9*C+4*C*C)*A*A*A*A/24
         + (61-58*T+T*T+600*C-330*eccPrimeSquared)*A*A*A*A*A*A/720)));
         
  if(Lat < 0)
    UTMNorthing += 10000000.0; //10000000 meter offset for southern hemisphere

  //Preparation of MGRS 100km chars  
  String UTMTwo = MGRSZoneDesignator(UTMEasting, UTMNorthing);
  int corrE = UTMEasting / 100000; //Correction from UTM to MGRS -> cutting first number
  UTMEasting = UTMEasting - (corrE * 100000); 
  int corrN = UTMNorthing / 100000; //Correction from UTM to MGRS -> cutting first two numbers
  UTMNorthing = UTMNorthing - (corrN * 100000);
   
  //Preparation to output
  String toUTM = String(ZoneNumber);
  toUTM += UTMLetterDesignator(Lat);
  GZ=toUTM;
  toUTM += " ";
  toUTM += UTMTwo;
  SqID=UTMTwo;
  toUTM += " E:";
  toUTM += UTMEasting;
  easting=UTMEasting;
  toUTM += " N:";
  toUTM += UTMNorthing;
  northing=UTMNorthing;
  return toUTM;
}

String MGRSZoneDesignator(double UTMEasting, double UTMNorthing)
{
  String e100kLetters[] = {"S","T","U","V","W","X","Y","Z"};
  String n100kLetters[] = {"F","G","H","J","K","L","M","N","P","Q","R","S","T","U","V","A","B","C","D","E"};
  const int col = floor(UTMEasting /100000); //Cutting first number. Upside is more info
  const int row = int(floor(UTMNorthing /100000))%20; //Cutting first two numbers. Upside is more info
  String ZoneDesignator = e100kLetters[col-1];
  ZoneDesignator += n100kLetters[row];
  return ZoneDesignator;
}

char UTMLetterDesignator(double Lat)
{
  //Written by Chuck Gantz- chuck.gantz@globalstar.com
  char LetterDesignator;
  if((84 >= Lat) && (Lat >= 72)) LetterDesignator = 'X';
  else if((72 > Lat) && (Lat >= 64)) LetterDesignator = 'W';
  else if((64 > Lat) && (Lat >= 56)) LetterDesignator = 'V';
  else if((56 > Lat) && (Lat >= 48)) LetterDesignator = 'U';
  else if((48 > Lat) && (Lat >= 40)) LetterDesignator = 'T';
  else if((40 > Lat) && (Lat >= 32)) LetterDesignator = 'S';
  else if((32 > Lat) && (Lat >= 24)) LetterDesignator = 'R';
  else if((24 > Lat) && (Lat >= 16)) LetterDesignator = 'Q';
  else if((16 > Lat) && (Lat >= 8)) LetterDesignator = 'P';
  else if(( 8 > Lat) && (Lat >= 0)) LetterDesignator = 'N';
  else if(( 0 > Lat) && (Lat >= -8)) LetterDesignator = 'M';
  else if((-8> Lat) && (Lat >= -16)) LetterDesignator = 'L';
  else if((-16 > Lat) && (Lat >= -24)) LetterDesignator = 'K';
  else if((-24 > Lat) && (Lat >= -32)) LetterDesignator = 'J';
  else if((-32 > Lat) && (Lat >= -40)) LetterDesignator = 'H';
  else if((-40 > Lat) && (Lat >= -48)) LetterDesignator = 'G';
  else if((-48 > Lat) && (Lat >= -56)) LetterDesignator = 'F';
  else if((-56 > Lat) && (Lat >= -64)) LetterDesignator = 'E';
  else if((-64 > Lat) && (Lat >= -72)) LetterDesignator = 'D';
  else if((-72 > Lat) && (Lat >= -80)) LetterDesignator = 'C';
  else LetterDesignator = 'Z'; //This is here as an error flag to show that the Latitude is outside the UTM limits
  return LetterDesignator;
}

unsigned int readVcc(void) {
  unsigned int result;
  // set the reference to Vcc and the measurement to the internal 1.1V reference
  ADMUX = (1 << REFS0) | (1 << MUX3) | (1 << MUX2) | (1 << MUX1);
  delay(2); // Wait for Vref to settle

  ADCSRA |= (1 << ADSC); // Start conversion
  while (bit_is_set(ADCSRA, ADSC)); // wait until done
  result = ADC;

  // two readings are better than one

  ADCSRA |= (1 << ADSC); // Start conversion
  while (bit_is_set(ADCSRA, ADSC)); // wait until done
  result = ADC;

  // calibrated for Miniduino board
  result = 1098700UL / (unsigned long)result; //1126400 = 1.1*1024*1000
  return result; // Vcc in millivolts
}

And here is the schematic (never drew one for other people so any feedback is welcome😉)

If you check your brace pairs closely, you'll find that the line
if (gps.encode(ss.read())) {
has the matching brace way down at the end of the loop function. As a result of this, the function skips over everything until gps.encode() returns true. That won't happen until the GPS has acquired a satellite lock. To be honest, I'm surprised it happens in only 30 seconds. Getting a GPS lock can take as long as 10-15 minutes at times.

Thanks for the reply, that part works. My problem is that nothing (not even setup()) runs until some time (a minute in this case) has passed and reset is pressed. This is a test setup identical to the final but powered by a powerbank: video

My goal is to reduce the white-screen time to 0 and not require a reset press.

That sort of delay is very odd. I doubt it's actually a bootloader issue because the bootloader delay is less than a second. I just don't see what else could be causing it.

Can you try an experiment? Upload the blink sketch from file->examples->basics. You should see the built-in LED in the Arduino blink three times very quickly, as soon as you let go of the reset button, then settle into a slow blink. The time between letting go of the reset and the first of the slow blinks should be under a second. If that works, then the bootloader is handling things correctly, and something else is going on.

How long did you have to wait in the past before you started uploading using the programmer?

To eliminate code as the possible cause, write a simple code. I'm not sure if the Pro Mini has a builtin LED, else hook one (plus resistor) up to pin 13.

void setup()
{
  pinMode (LED_BUILTIN, OUTPUT);
  digitalWrite (LED_BUILTIN, HIGH);
}

void loop()
{
}

Load it using the programmer.

When it's running, the LED should be on. Put the Pro Mini in reset (the LED should dim), release the reset and time how long it takes for the LED to switch on. How long does it take?

If that is immediate, your problem is in your code; if it also takes a long time, the problem is in the hardware (possibly the processor).

Do you have another Pro Mini for verification?

Another test can be to load the blink sketch using the programmer.
Observe the blink pattern; is it one second on, one second off? Or maybe two seconds on, two seconds off? Or even different (please provide the times in a reply).

What might be happening:

  1. The processor is running at 1 MHz.
  2. You have programmed it as a 16 MHz Pro Mini.

If my calculations are right, that could explain why your delay(1000) did become 30 (32) seconds.

Thanks for the help, I really appreciate it.

The arduino shown in the video has never been uploaded on using a programmer. Its for testing and I use a CP2102 to connect it straight to the computer. I have another pro mini which got uploaded with a programmer and it exhibits the same behavior.

Yes I have. I will try both programs you and @kellygray suggested. (Edit: I have exams at the moment, it could take me a week at most)

Why would the processor be running at 1MHz?
I am 100% (minus human error) sure that I set it to 8MHz but its worth a try.

I uploaded the blink sketch and it run without any delay. I made sure I uploaded using the 3.3v 8MHz setting and rerun my program, the delay is still there. That means the problem is in my code, right?

Sounds like it.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.