bootloader callable from sketch?

• External Reset. The MCU is reset when a low level is present on the RESET pin for longer than the minimum pulse length.

The port pins are tri-stated when reset condition becomes active, even if no clocks are running.

The section 13.2
13.2.1 Ports as General Digital I/O
Shows a diagram. You will see the reset connected to the ~clear input of a flip flop. This means that as soon as (accounting for propagation delays) the reset is brought low the pin is tristated and thus can not hold the pin low for the minimum reset pulse length of 2.5uS.

Found some one who actually tried it:-

At first glance, it seems it may be possible to simply connect up a digital pin to the reset pin. In theory simply setting the digital pin to low would cause the reset. However, Atmel discourage this approach because as the chip starts it's reset, it sets digital pins tri-state, which stops the reset condition possibly leaving the chip in a half-reset state. Indeed, in all the tests we've done, this approach doesn't seem to work.

From:-
http://electronicsfordogs.com/articles/self-resetting-atmel-atmega-328

Grumpy_Mike:
This means that as soon as (accounting for propagation delays) the reset is brought low the pin is tristated and thus can not hold the pin low for the minimum reset pulse length of 2.5uS.

That "reset" signal is unlikely to be the external reset pin, because then other reset sources would not clear the ports. More likely it's the internal reset, in which case there's no problem.

Grumpy_Mike:
Found some one who actually tried it:-

Oookay. That person doesn't say they actually tried it, at least not without extra circuitry. I have (on an Uno R2 with the auto-reset track cut so that the capacitor doesn't interfere with the signals), and it worked perfectly every time.

I can imagine CPUs without proper reset circuitry can get in a pickle after a too-short reset, but in the case of the ATmega328 I don't think there's a problem.

That person doesn't say they actually tried it,

Read the words again !!!

Indeed, in all the tests we've done, this approach doesn't seem to work.

I have (on an Uno R2 with the auto-reset track cut so that the capacitor doesn't interfere with the signals), and it worked perfectly every time.

Because the reset is still pulled up with a 10K resistor and it is not connected to a GPIO pin.

but in the case of the ATmega328 I don't think there's a problem.

Well I suppose you are entitled to your opinion but in this case you are wrong.
My God, do you believe anything you are told or read. Just don't try peddling your clap trap round here.
Bye.

Grumpy_Mike:
Read the words again !!!

Indeed, in all the tests we've done, this approach doesn't seem to work.

My apologies, I missed that sentence. However that is not consistent with my experience, or my best interpretation of the AVR data-sheets. I'd be glad if someone could point me to an AVR reference on the matter. My test sketch is attached below. I don't believe the 10k pull-up resistor affected the reset pulse duration.

#define PIN_R 2 // pin-2 connected to Reset; auto-reset disconnected

void setup() {
  digitalWrite(PIN_R,HIGH);
  pinMode(PIN_R,OUTPUT);
  Serial.begin(19200);
  Serial.println("Start");
  delay(2000);
  digitalWrite(PIN_R,LOW);  
}

void loop() {
}

My God, do you believe anything you are told or read.

Certainly not. In fact it appears to be my enquiring nature which is causing you pain. I'm sorry if I offended you, and I hope you do not feel the need to be rude to me again.

I'd be glad if someone could point me to an AVR reference on the matter.

I've read it enough times to know it's something that AVR specifically cautions against doing. Do you own research and decide if you should throw caution to the wind or follow the recommendations. I have no need to convince you, as I have little interest if your design is successful or not.

Lefty

Grumpy_Mike:
My God, do you believe anything you are told or read. Just don't try peddling your clap trap round here.

LOL @ clap trap. But realistically, if everyone believed everything they read or were told, we would not be where we are now.
I suspect you would need to activate some sort of capacitive latch but the brain is not working right now on how to do it exactly.

retrolefty:
I have no need to convince you, as I have little interest if your design is successful or not.

There's not much one can say to that, is there? Searching through nearly 4000 pages of Atmel documentation I'm unable to find the reference you're so coy about giving. I did find a post on AVRfreaks by somebody called Retrolefty, but he didn't seem to know the answer either.

I find this very interesting. I'm also insatiably curious, and tend toward the "trust, but verify" side of taking common knowledge at face value. After all, that's how cargo-cult habits get to where they are.

If I had to guess, I would've figured the reset pin was latched, so that by the time the pins were tri-stated, the dominoes would be falling and there's no going back. I don't know if I ever would've had an occasion to use such a trick, but I love that I happened to stumble upon the topic.

I hope you guys are patient enough to both accept wisdom and challenge the status quo. There's much to be gained by seeing for yourself if, how, or why something works. Maybe not in this case, but often enough. 8)

http://support.atmel.com/bin/customer.exe?=&action=viewKbEntry&id=21

Lefty

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 Proof by assertion - Wikipedia, 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.

/*
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.

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."

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)

westfw:
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 ?

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

  watchdogConfig(WATCHDOG_1S);

to

  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,

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

  watchdogConfig(WATCHDOG_1S);

to

  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.

tim7:
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?

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.

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

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. :wink: