Sleep behaving differently on different AtMega328p

Hey guys, I'm working on a project which should run on low power, therefore I use the power down sleep mode on the AtMega328p. The strange thing is , that it runs really smooth and without problems on some uC for days but on some other the same software resets the microcontroller after some seconds, sometimes longer, sometimes shorter.
The software works something like this:

setup()

  • reset wdt
  • read reset reasons
  • init io
  • init wdt to 8s and Interrupt + System Reset

loop()

  • wdt_reset()
  • long code which might get stuck // therefore the wdt on 8s and System reset
  • sleep500ms()

sleep500ms()

  • set wdt to 500ms and interrupt
  • power down
  • set wdt to 8s and Interrupt + System Reset

I need this kind of concept with reconfiguring the WDT because the long code part might get stuck in an infinite loop and if that happens it should reset the microcontroller. Like I said on some AtMegas it works fine, on some it doesnt work at all.
The whole simplified code looks like this.

#include <Arduino.h>
#include <avr/sleep.h>
#include <avr/wdt.h>

inline void sleep()
{
    cli();
    wdt_reset();
    WDTCSR |= (1 << WDCE) | (1 << WDE);
    WDTCSR = (1 << WDIE) | (1 << WDP2) | (1 << WDP0) | (0 << WDE); // Interrupt and 0.5s
    wdt_reset();


    SMCR &= ~0x0e;
    SMCR |= 0x01 | 0x04; // SE + SM1 (power-down)
    sei();
    // __asm__ __volatile__("sleep" "\n\t" ::);
    sleep_cpu();


    cli();
    wdt_reset();
    WDTCSR |= (1 << WDCE) | (1 << WDIE) | (1 << WDE); // Watchdog  Mode = Interrupt Mode && System Reset Mode // do not put this in ISR
    WDTCSR = (1 << WDP3) | (1 << WDP0);               // Interrupt and 8s
    sei();
}

// EMPTY_INTERRUPT(WDT_vect);
ISR(WDT_vect)
{
}

void setup()
{
    bool _WDRF = ((1 << WDRF) & MCUSR); // Watchdog Reset
    if (_WDRF)
    {
        cli();
        MCUSR &= ~(1 << WDRF);
        WDTCSR |= (1 << WDCE) | (1 << WDE);
        WDTCSR = 0;
        sei();
    }
    bool _BORF = ((1 << BORF) & MCUSR);   // BrownOut Reset
    bool _EXTRF = ((1 << EXTRF) & MCUSR); // External Reset
    bool _PORF = ((1 << PORF) & MCUSR);   // Power-Off Reset
    MCUSR = 0;

    pinMode(6, OUTPUT);

    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    sleep_enable();

    Serial.begin(4800);
    if (_WDRF)
        Serial.println("WDT Triggered");
    Serial.println(F("Start Setup"));
    Serial.print("Reset Reason: WDRF(");
    Serial.print(_WDRF);
    Serial.print(") BORF(");
    Serial.print(_BORF);
    Serial.print(") EXTRF(");
    Serial.print(_EXTRF);
    Serial.print(") PORF(");
    Serial.print(_PORF);
    Serial.println(")");

    delay(3000);

    cli();
    WDTCSR |= (1 << WDIE) | (1 << WDE); // Watchdog  Mode = Interrupt Mode && System Reset Mode
    wdt_enable(WDTO_8S);
    wdt_reset();
    sei();
}
void loop()
{
    static int x = 0;
    wdt_reset();
    digitalWrite(6, x++ % 2 == 0);
    sleep();
}

The interesting part is, when it resets (crashes?) it doesn't even trigger the WDT. After the "Start Setup" message, the reset reason will get printed out, and they are all zero. I (think) narrowed the reset down to the sleep_cpu() function. It is also pretty weird that microcontroller resets almost immediately without waiting the 8s for the WDT reset.

This would be my fuses

    "efuse": "0xFF",
    "file": "atmega/ATmegaBOOT_168_atmega328_pro_8MHz.hex",
    "hfuse": "0xD9",
    "lock_bits": "0xFF",
    "lfuse": "0x62",
    "unlock_bits": "0xFF"

f_cpu = 1MHz

Maybe someone would be able to tell me my error or we can get closer to a good solution.
I already read that it could be some kind of race condition before going to sleep but I just can't figure out how to fix it.

No idea actually, f_cpu is 1MHz? should'nt it be higher? Or am i missing something

yes f_cpu is defined a 1MHz

Should'nt the 328ps clock be at 8MHz or 16MHz. I never used an internal crystal but i used a 16MHz on a 2560 based custom board

No it doesnt have to be 8 or 16 MHz, you could go even lower than 1MHz. But this has nothing to do with my question unfortunately.

You said, on some it works and on some not. I just dont understand how thats possible. They are technically all the same except for the 328 and the 328p

Yes thats true, but they aren't exactly the same in detail. Every electronic part has slight differences even if they are from the same production batch. I also read that the WDT could be very inaccurate, and that inaccuracy could be part of the problem.

What if you just try to use an interrupt to reset your chip instead of the wdt itself

If you're using the bootloader, it will wipe the MCUSR so you will not have that information. If you have the option, upload your sketch via ICSP (which will remove the bootloader) and next check the reset reason. I don't have insight in your board but note that opening Serial Monitor will also reset the board so you need a terminal program that will not cause that behaviour (or hack te board to disconnect the DTR of the TTL-to-USB chip from reset pin of the processor.

If i block the loop with a delay and let the 8s wdt trigger I will get a valid WDRF bit, so that shouldnt be the problem i think

get in contact with that guy:

https://www.mikrocontroller.net/topic/542199

he has a very similar problem like you have.
Combine your efforts - work together.

1 Like

thats actually me lol

This is a long shot, but I have run across some counterfeit 328Ps on Pro Minis. Kevin Darrah came up with a sketch that might be used to distinguish between real and fake processors. The fake ones have a lot more FFs than the real ones. Ok, I said it was a long shot, but it's hard to come up with any other explanation if you're sure there are no power supply issues. The same bootloader, fuses and sketch should produce the same behavior. Anyway, here's the code:

#include <avr/boot.h>
#define SIGRD 5
void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  Serial.println("");
  Serial.println("boot sig dump");
  int newLineIndex = 0;
  for (uint8_t i = 0; i <= 0x1F; i += 1) {
    Serial.print(boot_signature_byte_get(i), HEX);
    Serial.print("\t");
    newLineIndex++;
    if (newLineIndex == 8) {
      Serial.println("");
      newLineIndex = 0;
    }
  }
  Serial.println();
}

void loop() {
}

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