buserror / simavr

simavr is a lean, mean and hackable AVR simulator for linux & OSX
GNU General Public License v3.0
1.56k stars 365 forks source link

WDIE is wronly cleared on interrupt in Interrupt Mode #456

Open WGH- opened 3 years ago

WGH- commented 3 years ago

WDIE should be only cleared in "Interrupt and System Reset Mode".

The fix is to add && avr_regbit_get(avr, p->wde) condition.

https://github.com/buserror/simavr/blob/a56b550872906a971ac128002772d90c9e30377d/simavr/sim/avr_watchdog.c#L172-L188

I think I'll submit a PR (unless someone does that first) once I get access to hardware to double-check the tests on.

lcgamboa commented 2 years ago

Hi @WGH-

I have applied your fix suggestion to my simavr fork and now I can use WDT and Arduino_freeRTOS without any problems. I recommend you do a PR. Thanks for the info.

WGH- commented 2 years ago

@lcgamboa just to clarify, Arduino_freeRTOS depends on the correct behaviour of WDIE auto-clearing, doesn't work correctly on simavr, and my suggested change fixes it?

lcgamboa commented 2 years ago

Yes, I tested some examples from the Arduino_freeRTOS library and they all worked after the fix you suggested.

itopaloglu83 commented 2 years ago

I was having issues with the watchdog timer interrupts and I'm glad to find this issue. Here's a simple example code for testing purposes. it uses the watchdog timer to blink an LED.

The watchdog timer interrupt only works once and then stops. I updated the interrupt clearing line with the following line of code as an interim solution.

Current: WDTCSR |= (1 << WDIF); Temporary Solution: WDTCSR |= (1 << WDIE) | (1 << WDIF);

#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/interrupt.h>

ISR(WDT_vect)
{
    // Clear interrupt flag by writing 1 to it.
    WDTCSR |= (1 << WDIF);
    // Toggle LED.
    PORTB ^= _BV(PB5);
}

int main()
{
    // Set LED as output.
    DDRB |= _BV(DDB5);

    // Enable watchdog timer.
    WDTCSR |= (1 << WDCE) | (1 << WDE);
    WDTCSR = (1 << WDIE);

    // Toggle LED.
    PORTB ^= _BV(PB5);

    // Enable global interrupts.
    sei();

    // Loop forever.
    while (1)
    {
        _NOP();
    }
}