Atmega328P watchdog timer gives infinite reset loop - Page 1
Forum section: electronics / general

author: hydrogen18
author_rank: Contributor
timestamp: June 14, 2019, 12:29:36 am
content: I have put together a simple example code trying to use the watchdog timer. The goal is just to have the simplest example that uses the WDT, which will always fire while blinking an LED.Code:#define F_CPU 16000000#include <stdint.h>#include <avr/wdt.h>#include <util/delay.h>#include <avr/interrupt.h>void get_mcusr(void) \__attribute__((naked)) \__attribute__((section(".init3")));void get_mcusr(void){cli();/* Clear WDRF in MCUSR */MCUSR &= ~(1<<WDRF);wdt_disable();sei();}int main(void){wdt_reset();wdt_enable(WDTO_8S);DDRB = 1 << DDB5;uint8_t i = 0;for(; i != 5; i++){PORTB ^= 1 << PB5;_delay_ms(150);}for(;;){PORTB ^= 1 << PB5;_delay_ms(500);}}There is no wdt_reset() after the first one in main, so it should always fire at 8 seconds.Here is what compiles that code and writes it to my Arduino DuemilanoveCode:#!/bin/bashset -xeMCU='atmega328p'PROGRAM=wdtrm -f "${PROGRAM}.hex"rm -f "${PROGRAM}.elf"avr-gcc -O2 "-mmcu=${MCU}" -c -o "${PROGRAM}.o" "${PROGRAM}.c"avr-gcc "-mmcu=${MCU}" "${PROGRAM}.o" -o "${PROGRAM}.elf"avr-objcopy -j .data -j .text -O ihex -R .eeprom "${PROGRAM}.elf" "${PROGRAM}.hex"avrdude -p "${MCU?}" -c arduino -F -P ${1?} -b 57600 -D -U "flash:w:${PROGRAM}.hex"PB5 is the onboard LED on this board.What happens1. I get 3 quick flashes2. I get some slow flashes with a 1 second period3. The LED bilnks rapidly foreverWhat I expect1. I get 3 quick flashes2. I get some slow flashes with a 1 second period3. Go back to step 1Why is this happening? I have used avr-objdump but can't spot the problem. I must be missing something simple.Code:00000074 <get_mcusr>:74: f8 94 cli76: 84 b7 in r24, 0x34 ; 5278: 87 7f andi r24, 0xF7 ; 2477a: 84 bf out 0x34, r24 ; 527c: 88 e1 ldi r24, 0x18 ; 247e: 0f b6 in r0, 0x3f ; 6380: f8 94 cli82: 80 93 60 00 sts 0x0060, r2486: 10 92 60 00 sts 0x0060, r18a: 0f be out 0x3f, r0 ; 638c: 78 94 sei8e: 0e 94 4d 00 call 0x9a ; 0x9a <main>92: 0c 94 79 00 jmp 0xf2 ; 0xf2 <_exit>00000096 <__bad_interrupt>:96: 0c 94 00 00 jmp 0 ; 0x0 <__vectors>0000009a <main>:9a: a8 95 wdr9c: 29 e2 ldi r18, 0x29 ; 419e: 88 e1 ldi r24, 0x18 ; 24a0: 90 e0 ldi r25, 0x00 ; 0a2: 0f b6 in r0, 0x3f ; 63a4: f8 94 clia6: a8 95 wdr

author: sleemanj
author_rank: Super Contributor
timestamp: June 14, 2019, 12:51:14 am
content: From memory, you must clear WDRF immediately. I don't think wdt_reset does that, on WDT reset the wdt will be still enabled (regardless of WDE because WDRF overrides it) and it will probably be set to the minimum WDT interval, so you need to be quick to clear WDRF pretty much as the first thing you do.Code:MCUSR &= ~(1 << WDRF);

author: hydrogen18
author_rank: Contributor
timestamp: June 14, 2019, 01:10:20 am
content: Isn't that what I'm doing in the get_mcusr function I have declared in the .init3 section?

author: sleemanj
author_rank: Super Contributor
timestamp: June 14, 2019, 01:30:42 am
content: Sorry yes I didn't notice.What I also didn't notice is-c arduinothis indicates to me you are uploading using a bootloader yes? The bootloader isn't clearing WDRF and is waiting around long enough for it to reset again, and again, and again before your code even gets to run.

author: hydrogen18
author_rank: Contributor
timestamp: June 14, 2019, 01:37:04 am
content: You probably know more about avr-dude than I do. I know how to make it program something, that is about it.Are you suggesting I can try using the ICSP header on my arduino and bypass this problem? I have the programmer for that, I just rarely use the thing.

author: sleemanj
author_rank: Super Contributor
timestamp: June 14, 2019, 01:42:30 am
content: Yes that will likely solve your problem.You are using the bootloader, the bootloader always runs first after a reset so if it's not clearing WDRF then that will be the infinite reset cause.Upload using a programmer will nuke the bootloader so the first and only thing that runs is your code.

author: hydrogen18
author_rank: Contributor
timestamp: June 14, 2019, 02:08:41 am
content: I changed my programming line toCode:avrdude -p "${MCU?}" -c usbtiny -F -U "flash:w:${PROGRAM}.hex"And hooked up the usbtiny ICSP. It works as intended now, thanks for explaining this.So I guess there is some way I could modify the arduino bootloader to do this? Then I'd be OK to program via USB and not have this problem.

author: sleemanj
author_rank: Super Contributor
timestamp: June 14, 2019, 02:27:04 am
content: You could try just reburning the bootloader for a start, you may have had an old version on the board (now you have none), in the Arduino IDE select the appropriate board and then "Burn Bootloader" (uses the programmer to burn of course).If it still doesn't work with whatever bootloader was burnt by your version of the Arduino IDE, then you'd want to get a newer version of the bootloaderhttps://github.com/optiboot/optibootwhich I *think* will behave better with WD resets.

author: westfw
author_rank: Super Contributor
timestamp: June 14, 2019, 08:40:14 am
content: The easiest thing would be to install a newer bootloader on your duemilanove. The behavior you describe was a bootloader bug that was fixed a long time ago.The optiboot bootloader never had it.

author: hydrogen18
author_rank: Contributor
timestamp: June 14, 2019, 11:29:21 pm
content: So the order I'd need to do this in is1. Use ICSP programmer to put Optiboot 8.0 on the Atmega328P via avrdude2. Use USB programming to put my example code on the Atmega328P via avrdude3. My code should now run & work?

author: westfw
author_rank: Super Contributor
timestamp: June 15, 2019, 02:34:54 am
content: Sounds right. Use the arduino ide, set the board to “uno”, and use the “burn bootloader” command, and it will set the fuses for you too. Thereafter your board will be an “uno”...You don’t need v8 optiboot. The arduino stock v4.4 will work fine.See also “optiloader”, an arduino sketch that was designed to do this to older arduino boards “in bulk”

author: hydrogen18
author_rank: Contributor
timestamp: June 15, 2019, 02:47:38 am
content: Why would I set the board to Uno?Edit: I figured it outSteps1. Write optiboot 8 -avrdude -c usbtiny -p m328p -v -e -U flash:w:./optiboot_atmega328.hex -U lock:w:0x0F:m2. Write my example - avrdude -p atmega328p -c arduino -F -P /dev/ttyUSB0 -b 115200 -D -U "flash:w:wdt.hex"I had to change my programming to -b 115200 since apparently Optiboot 8 uses a higher speed for programming.Last question: Does Optiboot 8 work on the Atmega328PB?