Go Down

Topic: bootloader callable from sketch? (Read 3 times) previous topic - next topic

tim7

Thanks for the link.  That specific statement from Atmel doesn't match my own measurements, so I've asked their tech support to clarify the issue for us.

Whether I'm right or wrong doesn't matter a great deal to me.  I wouldn't be very good at my job if I attached my ego to every test or measurement I make - especially one as trival as this is.

What has provoked me, and caused this thread to be as long as it is, is Grumpy Mike's attempt to trump an observation with his supposed seniority.  This is known as Proof by Assertion http://en.wikipedia.org/wiki/Proof_by_assertion, and it is very offensive to anybody that loves science or technology.

To anybody still reading this topic, I offer the following code.  It generates reset pulses of varying durations, and indicates which if any are successful.  After reset it checks the state of the registers and lists any which do not match the expected values.  Read the comments before running.

Code: [Select]
/*
Self-reset test sketch
Made for 16MHz ATmega328-based Arduino

To use:
- Compile, upload, and launch the serial monitor (57600 baud)
- Update the register values in checkreg() to those reported.
- Recompile, re-upload, and check there are no "Register" messages
- Cut the auto-reset connection if present (the track between the solder pads marked "RESET-EN on Uno boards)
- Connect Pin-2 to Reset
- Optionally, connect Pin-3 to an oscilloscope and a resistive load to show when the port is reset.

Disabling Auto-Reset is optional, but required for testing with very short pulses <1ms (do this *after* uploading and checking this sketch)
To re-enable Auto-Reset on an Uno, dab a spot of solder between the pads where the track was cut.

NB. Whilst Pin-2 is connected to Reset and the sketch is running, do not push the reset button (will short Pin-2 to ground)

*/
#define reg_is(x,y) if (x != y) {\
  Serial.print("Register ");\
  Serial.print(#x);\
  Serial.print(" = ");\
  Serial.println(x,HEX);\
  }


void setup() {
  Serial.begin(57600);
  Serial.println("-");
  Serial.println("Started (do not push the Reset button)");
  checkreg();
  PORTD = 0x04; // Pin-2 high, Pin-3 low
  DDRD = 0x0C;

  delay(1000);

  PORTD = 0x08; // Pin-2 low, Pin-3 high
  PORTD = 0x04; // Pin-2 high, Pin-3 low
  Serial.println("Failed to reset after a  60ns pulse (this is normal)");

  delay(1000);

  PORTD = 0x08; // Pin-2 low, Pin-3 high
  asm volatile("nop\n");
  PORTD = 0x04; // Pin-2 high, Pin-3 low
  Serial.println("Failed to reset after a 120ns pulse (this is normal)");

  delay(1000);

  PORTD = 0x08; // Pin-2 low, Pin-3 high
  asm volatile("nop\nnop\n");
  PORTD = 0x04; // Pin-2 high, Pin-3 low
  Serial.println("Failed to reset after a 180ns pulse (this is normal)");

  delay(1000);

  PORTD = 0x08; // Pin-2 low, Pin-3 high
  asm volatile("nop\nnop\nnop\n");
  PORTD = 0x04; // Pin-2 high, Pin-3 low
  Serial.println("Failed to reset after a 250ns pulse (this is normal)");

  delay(1000);

  PORTD = 0x08; // Pin-2 low, Pin-3 high
  asm volatile("nop\nnop\nnop\nnop\n");
  PORTD = 0x04; // Pin-2 high, Pin-3 low
  Serial.println("Failed to reset after a 300ns pulse (within spec, but differs from Tim's result)");

  delay(1000);

  PORTD = 0x08; // Pin-2 low, Pin-3 high
  asm volatile("nop\nnop\nnop\nnop\nnop\nnop\nnop\n");
  PORTD = 0x04; // Pin-2 high, Pin-3 low
  Serial.println("Failed to reset after a 500ns pulse (within spec, but differs from Tim's result)");

  delay(1000);

  PORTD = 0x08; // Pin-2 low, Pin-3 high
  asm volatile("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n");
  asm volatile("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n");
  asm volatile("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n");
  asm volatile("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n");
  PORTD = 0x04; // Pin-2 high, Pin-3 low
  Serial.println("Failed to reset after a 2.5us pulse (out of spec - is autoreset disconnected?)");

  delay(1000);

  PORTD = 0x08; // Pin-2 low, Pin-3 high
  delay(1);
  PORTD = 0x04; // Pin-2 high, Pin-3 low
  Serial.println("Failed to reset after a   1ms pulse (this shouldn't happen!)");

  delay(1000);

  DDRD = 0x00;
  Serial.println("Stopped (you may now push the reset button)");

}

void loop() {
}

void checkreg() {
// This routine compares the register contents to values after a "normal" reset
// Normal values vary from board to board -- update the code below as necessary

Serial.println("Looking for uninitialised registers...");
//  reg_is(PINB,    0) // floating inputs can be random
  reg_is(DDRB,    0)
  reg_is(PORTB,   0)
//  reg_is(PINC,    0) // floating inputs can be random
  reg_is(DDRC,    0)
  reg_is(PORTC,   0)
//  reg_is(PIND,    0) // floating inputs can be random
  reg_is(DDRD,    0)
  reg_is(PORTD,   0)
//  reg_is(TIFR0,   0) // timer
//  reg_is(TIFR1,   0) // timer
//  reg_is(TIFR2,   0) // timer
  reg_is(PCIFR,   0)
  reg_is(EIFR,    0)
  reg_is(EIMSK,   0)
  reg_is(GPIOR0,  0)
  reg_is(EECR,    0)
  reg_is(EEDR,    0)
  reg_is(EEAR,    0x03DF)
  reg_is(EEARL,   0x00DF)
  reg_is(EEARH,   0x0003)
  reg_is(GTCCR,   0)
  reg_is(TCCR0A,  0x0003)
  reg_is(TCCR0B,  0x0003)
//  reg_is(TCNT0,   0) // timer
  reg_is(OCR0A,   0)
  reg_is(OCR0B,   0)
  reg_is(GPIOR1,  0)
  reg_is(GPIOR2,  0)
  reg_is(SPCR,    0)
  reg_is(SPSR,    0)
  reg_is(SPDR,    0)
  reg_is(ACSR,    0x0030)
  reg_is(SMCR,    0)
  reg_is(MCUSR,   0x0005)
  reg_is(MCUCR,   0)
  reg_is(SPMCSR,  0)
  reg_is(WDTCSR,  0)
  reg_is(CLKPR,   0)
  reg_is(PRR,     0)
  reg_is(OSCCAL,  0x0084)
  reg_is(PCICR,   0)
  reg_is(EICRA,   0)
  reg_is(PCMSK0,  0)
  reg_is(PCMSK1,  0)
  reg_is(PCMSK2,  0)
  reg_is(TIMSK0,  0x0001)
  reg_is(TIMSK1,  0)
  reg_is(TIMSK2,  0)
  reg_is(ADC,     0)
  reg_is(ADCW,    0)
  reg_is(ADCL,    0)
  reg_is(ADCH,    0)
  reg_is(ADCSRA,  0x0087)
  reg_is(ADCSRB,  0)
  reg_is(ADMUX,   0)
  reg_is(DIDR0,   0)
  reg_is(DIDR1,   0)
  reg_is(TCCR1A,  0x0001)
  reg_is(TCCR1B,  0x0003)
  reg_is(TCCR1C,  0)
//  reg_is(TCNT1,   0) // timer
//  reg_is(TCNT1L,  0) // timer
//  reg_is(TCNT1H,  0) // timer
  reg_is(ICR1,    0)
  reg_is(ICR1L,   0)
  reg_is(ICR1H,   0)
  reg_is(OCR1A,   0)
  reg_is(OCR1AL,  0)
  reg_is(OCR1AH,  0)
  reg_is(OCR1B,   0)
  reg_is(OCR1BL,  0)
  reg_is(OCR1BH,  0)
  reg_is(TCCR2A,  0x0001)
  reg_is(TCCR2B,  0x0004)
//  reg_is(TCNT2,   0) // timer
  reg_is(OCR2A,   0)
  reg_is(OCR2B,   0)
  reg_is(ASSR,    0)
  reg_is(TWBR,    0)
  reg_is(TWSR,    0x00F8)
  reg_is(TWAR,    0x00FE)
  reg_is(TWDR,    0x00FF)
  reg_is(TWCR,    0)
  reg_is(TWAMR,   0)
  reg_is(UCSR0A,  0)
  reg_is(UCSR0B,  0x00B8)
  reg_is(UCSR0C,  0x0006)
  reg_is(UBRR0,   0x0010)
  reg_is(UBRR0L,  0x0010)
  reg_is(UBRR0H,  0)
  reg_is(UDR0,    0)
  Serial.println("...finished register check");
}



Oscilloscope traces from an Uno r2:
Yellow = pin-3 (connected via 10kOhm to ground)
Blue = pin-2 (connected to Reset, and two resistors (internal + 10kOhm) in parallel to Vcc)

A 250ns pulse is insufficient to cause reset and sketch execution continues.  Note the rapid trailing-edge of the pulses.


Pulses 300ns or longer trigger reset.  After 300ns the port outputs go high-impedance.  Note the slower voltage decay.

westfw

Quote
A 250ns pulse is insufficient to cause reset
   :
After 300ns the port outputs go high-impedance. 

Eh.  Violate the datasheet at your own risk.  It says reset should be 2.5us (Section 26.5: System and Reset Characteristics)

Your measurements are interesting in that they confirm that you do NOT get a 2.5us reset pulse if you set a connected output pin to LOW and allow the chip to (begin) resetting.

The datasheet has other information hinting at the complexity of the reset process.  See section 6.2.2 "Clock Startup Sequence" and Section 8 "System Control and Reset."

tim7

I too wondered why reset was starting earlier than 2.5us.  Reading the datasheet more closely, it says that there is some minimum reset pulse-width, tRST.  And the maximum value of tRST is 2.5us (table 29-12).  Typical and minimum values are not given.  So my value of tRST = 300ns does not contradict the datasheet.

I also checked the startup timing:

  • Following the release of the Reset button, there's a delay tOUT for Vcc to stabilise (figure 11-4).  With the normal Arduino fuse settings tOUT is ~65ms (table 9-2), but with an error of ~10% (the 128kHz clock is "not designed for high accuracy", section 9-7).

  • This is followed by 16000 clock cycles (~1ms) to allow the crystal/resonator to stabilise.

  • A few clock-cycles later the bootloader starts toggling pin-13 to show it is working.


I measured a total startup time of 62.8ms.  More importantly startup-time did not vary, implying that the proper startup sequence is being followed even after very short reset pulses.  See traces below.

PS. My datasheet seems to have different section numbers to yours.  The references above are for the latest version.

Oscilloscope trace legend

  • Yellow = reset-pin : connected to Reset-Button, or Pin-2 for the auto-reset examples
    Ports are tri-stated 300ns after falling edge
    Reset sequence starts on rising edge

  • Blue    = pin-3      : connected to gnd via 10k, initial state = high output
    Falling-edge shows end of sketch execution and tri-stating of ports

  • Purple = pin-13     : connected to Vcc via 10k and gnd via LED, initial state = input
    First falling-edge indicates start of bootloader operation, followed by LED flashes



Normal button-push reset (210ms)


Long button-push reset (470ms)


Short button-push reset (60ms)


Auto reset (300ns)


Normal button-push reset (5x zoom)


Auto reset (5x zoom)


Normal button-push reset (100,000x zoom)


Auto reset (100,000x zoom)


ScottishDave


It would probably be easier to create a custom bootloader with a longer timeout.  Up to 8s is an easy change.



Sorry to hijack the thread, but creating a bootloader with an altered timeout is something I really want. I've looked for advice on how to start going about this, posted some threads and got nowhere. Can anyone please suggest a starting point where I can read up on what I need to do ?

tim7

To make your modified bootloader, find the source code in .\arduino-1.0\hardware\arduino\bootloaders\optiboot.  Make a backup copy of this directory and keep it somewhere safe.  Then modify line 311 of optiboot.c from

Code: [Select]
  watchdogConfig(WATCHDOG_1S);

to

Code: [Select]
  watchdogConfig(WATCHDOG_8S);

This will give you an 8s time-out.  To compile, open a command window in the optiboot directory and type omake clean followed by omake atmega328 (I'm assuming that your Arduino has an ATmega328 processor clocked at 16Mz).

Unless you have a dedicated programmer, you'll need a second Arduino to upload the new bootloader.  Follow the instructions at http://arduino.cc/en/Tutorial/ArduinoISP.
Good luck,

ScottishDave


To make your modified bootloader, find the source code in .\arduino-1.0\hardware\arduino\bootloaders\optiboot.  Make a backup copy of this directory and keep it somewhere safe.  Then modify line 311 of optiboot.c from

Code: [Select]
  watchdogConfig(WATCHDOG_1S);

to

Code: [Select]
  watchdogConfig(WATCHDOG_8S);

This will give you an 8s time-out.  To compile, open a command window in the optiboot directory and type omake clean followed by omake atmega328 (I'm assuming that your Arduino has an ATmega328 processor clocked at 16Mz).

Unless you have a dedicated programmer, you'll need a second Arduino to upload the new bootloader.  Follow the instructions at http://arduino.cc/en/Tutorial/ArduinoISP.
Good luck,


Wow. Thank you so much - everything I need to get going. I'm sending much internet karma your way.

Coding Badly

And the maximum value of tRST is 2.5us (table 29-12).  Typical and minimum values are not given.  So my value of tRST = 300ns does not contradict the datasheet.


How is that value labeled?  Why would there be a maximum pulse width?  What happens to a processor when the maximum pulse width is exceeded (something I do every time I program an ATtiny processor)?  Is it possible the person who wrote the document placed the value in the wrong column?  That the value is the minimum pulse width rather than the maximum?

tim7

Between the Reset pin and the internal reset logic there is a glitch filter (see the diagram I posted earlier), and I'm guessing that tRST is the threshold for pulses passing through that filter.  In other words, the minimum reset-pulse-width is tRST ... and the specified value of tRST is not greater than 2.5us.

westfw

It's the maximum value of the minimum reset pulse width.  Ie, you will never need a pulse longer than 2.5us to cause the AVR to reset.  In the particular case of the Arduino with its particular fuse settings, at 5V and room temperature with a 16MHz ceramic resonator that is running at the time, it seems that a much shorter pulse also succeeds in resetting the AVR; that's OK - the datasheet does not list a minimum time for Trst

SirNickity

Cool stuff.  I suppose it's safe to say that component differences may affect these results greatly, but on your particular board, it took 300nS before the pins were tri-stated, and that amount of time was sufficient to trigger its own reset.  Nifty.  I might try this myself just to see if it works.  I don't think I would count on it for a design yet.  ;-)

smeezekitty

#40
Mar 28, 2012, 06:31 am Last Edit: Mar 28, 2012, 06:38 am by smeezekitty Reason: 1

It's the maximum value of the minimum reset pulse width.  Ie, you will never need a pulse longer than 2.5us to cause the AVR to reset.  In the particular case of the Arduino with its particular fuse settings, at 5V and room temperature with a 16MHz ceramic resonator that is running at the time, it seems that a much shorter pulse also succeeds in resetting the AVR; that's OK - the datasheet does not list a minimum time for Trst


Although you can no doubt go lower then 2.5us, 300ns seems much too short.
What works on one chip, clock, pin etc... may not work on another.
Now that I think about it, wouldn't using a single NPN transistor between reset and GND with the base triggered with a high state from a pin and a capacitor on the base to lengthen the pulse.
Avoid throwing electronics out as you or someone else might need them for parts or use.
Solid state rectifiers are the only REAL rectifiers.
Resistors for LEDS!

Nick Gammon

FWIW I did a few tests. With this sketch:

Code: [Select]
const byte RESET = 8;
const byte LED = 9;

void setup ()
{
  digitalWrite (LED, LOW);
  digitalWrite (RESET, HIGH);
 
  pinMode (LED, OUTPUT);
  pinMode (RESET, OUTPUT);

  for (byte i = 0; i < 5; i++)
    {
    delay (20);
    digitalWrite (LED, HIGH);
    digitalWrite (LED, LOW);
    }
   
  digitalWrite (RESET, LOW);
 
}  // end of setup

void loop () {}


I connected D8 to /RESET, and measured timings. The loop of 5 was to identify when we were about to pull reset low. I found that reset went low for 937.5 nS. This was on a "bare bones" board with no capacitor on the reset line.

The datasheet, page 422, appears to indicate that the minimum reset pulse varies per the supply voltage. At 5V it can be between 200 nS and 400 nS depending on temperature.

However the datasheet on page 318 says that the "maximum" minimum reset pulse (whatever a maximum minimum is) is 2.5 uS. This appears to contradict the chart on page 422.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

Nick Gammon

The other point though is that I got rather strange results when I also had D8 connected via an LED to ground. The processor never seemed to get into flashing the "indicator" pin at all.

And I think this is probably the heart of the problem. When the processor powers up, the pins are probably in an indeterminate state. Now if you have one of the pins connected direct to /RESET, before the processor has time to set the pins high impedance, the pin you choose might assert reset again, going into some strange loop of being reset before it can escape from reset.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

Nick Gammon


And the maximum value of tRST is 2.5us (table 29-12).  Typical and minimum values are not given.  So my value of tRST = 300ns does not contradict the datasheet.


Actually it's the maximum minimum. Because, tRST is "Minimum pulse width on /RESET Pin".

So in the absence of minimum and typical, I would read that as the figure which is the minimum reset pulse. Notwithstanding that it contradicts the chart on page 422.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

Nick Gammon

It could just be a documentation error. After all, what's a maximum minimum anyway? Maybe whoever drew up that chart thought that a minimum minimum would be confusing.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

Go Up