Watch dog timer and serial communication

Hello,

I am working on a project for a regulator with the ATmega328p. It has some parameters that I set with the serial communication and then save them into the eeprom for later use.

The customer for the project requested a watch dog timer for safety reasons which was easy enough to implement.

I do encouter a problem when sending the serial parameters now though. It seems that my do while loop to process the whole string of data recieved to the buffer takes more than 15ms set on the wdt. I could set the wdt for a longer period but Id like to make my code more rigid to this, since if I ever increase the data processed over the serial com I know Ill need something to reset the wdt on the side.

My question is what would be the best way to implement an interrupt to reset the wdt lets say every 10ms. Is it even possible? Does it then still safely “crash” when the code gets stuck, or should I stay in the loop scope. I could disable the wdt for the serial com event but I dont think thats a good enough solution too.

Thanks for any and all feedback ahead!

If you reset the watchdog periodically from an interrupt, you undermine its point, e.g. it will no longer be able to detect that your code is stuck. You could as well turn it off.

The better solution is to reset the watchdog once or twice from the long running operation. E.g. you could reset it whenver you have transmitted another 20 bytes (or whatever the appropriate size for your serial speed is).

1 Like

This has originally been my idea of solving it, and Id say it is right.

I was confused because for some reason the first time after a powerup of the MCU it always resets. after this reset everything works as intended.

To be exact my serialEvent() function gets the mcu to hold up, so I placed a wdt_reset in a helping function that cuts up the incoming string of commands and executes them, so basically every word recieved in the string resets the wdt. This seems to be enough for the wdt, just apart from the first run after powerup.

I will try to look onto the issue further, but it might not matter that much.

1 Like

@Morgulan Can I pick your brain for a minute… since you have been doing exactly the same think I was working on a little while ago, and seemed to be having issues with…

It has some parameters that I set with the serial communication and then save them into the eeprom for later use.

I have a program that I run to test and calibrate some ATmega328p modules before they get deployed into their main board.

There are two functions… simply


void loadCalibrationData()
{
  EEPROM.get(0, calData);
}

void saveCalibrationData()
{
  EEPROM.put(0, calData);
}

where calData is a struct

struct calStruct
{
  float calib_1v1; //1v1 as measured
  float vccOffset;
} calData;

I basically measure the 1.1 reference voltage for the ATmega328 with a meter, enter the measured value, check the calculated 5v bandgap voltage against the actual voltage and then enter any offset needed there (thus populating calData calib_1v1 and calData.vccOffset)… and then save it to EEPROM with the saveCalibrationData() function… but it didn’t seem to be saving. Have you had any problems with those functions, particularly put and get? I’ll probably be working on the code again next week, so it will be interesting to see if I stuffed up on something or not :wink:

Heyo,

I have made the following class:

#include <EEPROM.h>

class eepromManager {
private:
  struct address {
    uint16_t start = 0, current = 0,  end = 0;
  } _address;
public:
  eepromManager() {};
  
  template <typename T>
  void put(T &_data) {
    EEPROM.put(_address.current, _data);
    _address.current += sizeof(_data);
  }

  template <typename T>
  void get(T &_data) {
    _data = EEPROM.get(_address.current, _data);
    _address.current += sizeof(_data);
  }

  void chainEnd() {
    _address.end = _address.current;
    _address.current = _address.start;
  }

  void setStartAddress(uint16_t _startAddress) {
    _address.start = _startAddress;
    _address.current = _address.start;
  }
};

This manages the data stored at eeprom on this kind of format:

I have an object and I set its start address, if I dont set it its 0 by default. I can then after reading the data use the ending adrress as a new start address for a new object, bare in mind every object has a eepromhelp class subobject.

Okay here is an example:

MyClass.h -----------
class MyClass {
private:
  eepromManager mem;
public:
  valueRegulator(uint16_t _memStart) {
    mem.setStartAddress(_memStart);
    readData();
  };

  void saveData();
  void readData();
};

MyClass.cpp -----------
void MyClass::saveData() {
  mem.put(data.firsthalf);
  mem.put(data.secondhalf);
  mem.put(differentData.All);
  mem.put(bitmap, 1);
  mem.chainEnd();
}

void MyClass::readData() {
  mem.get(data.firsthalf);
  mem.get(data.secondhalf);
  mem.get(differentData.All);
  mem.get(bitmap);
  mem.chainEnd();
}

Note that the one is a chainEnd function at the end of a mem.get or mem.put chain, It sets the ending address and resets the current address back to its startingAddress. It just tells the class this is the end of my data. If you werent using more objects for the eeprom then you wouldnt need the ending address and you wouldnt have to do this. Also make sure the chains of mem.get or mem.put are in the same order for saving and loading, otherwise it wont read the same stuff you saved there!

Hopefully this will work for you, I have tested it and it does what its supposed to do, be sure to let me know how it turns out! :smile:

So the exact problem was using EEPROM to save the data, since I saved quite a bit of it it took more than time than the wdt timeout.

I solved this by setting the serial timeout to 100ms and the wdt to 120ms, so the 3ms eeprom save multiplied times the bytes, approx. 10 (30ms) is covered now.