Hi. Hope everyone’s keeping healthy…at least we have more time to work with Arduino at the moment…
Quick breakdown of the problem - Using the internal watchdog timer to check for timeout between rising edges on an input pin.
I’ve previously used ISR vectors defined in the sketch .ino file to use the WDT to light up an LED. Now I’m trying to get some friends into Arduino so trying to convert the .ino file into a library .h with .cpp source.
It all compiles fine until the ISR is added into the library - declaring the variables to be called from the ISR as extern in the .h file, then defining them in the .cpp file also works OK with int and bool datatypes, but not a union struct typedef…
Have attached code in the following order:
-
.ino sketch file with WDT ISR
-
What i want the .ino file to look like to my friends
-
.cpp source to implement the clean .ino file
-
.h header for wdtTest class
const uint32_t TimeoutTimer = 1500UL;
uint32_t timeoutCounter;
typedef union
{
struct {
uint32_t msg[8];
uint8_t len;
} d32;
struct {
uint8_t dat[32];
uint8_t len;
} d8;
} MessageDataTypeDef;
volatile MessageDataTypeDef testmsg;
volatile bool testflag;
ISR(WDT_vect){
//wdt.inthandle();
pinMode(13,OUTPUT);
digitalWrite(13,OUTPUT);
testmsg.d8.len=45;
testmsg.d8.dat[0]=SPCR;
testflag=1;
//reset WDRF
MCUSR &= ~(1<<WDRF);
//end WDT
WDTCSR = (1<<WDCE);
}
void setup() {
while(millis()<500UL);
Serial.begin(115200);
delay(250);
pinMode(13,OUTPUT);
digitalWrite(13,HIGH);
delay(1000);
Serial.println("Starting...");
digitalWrite(13,LOW);
delay(1250);
//setup wdt
noInterrupts();
//reset WDRF
MCUSR &= ~(1<<WDRF);
WDTCSR = (1<<WDCE)|(1<<WDE);
//set prescaler ~ 2000ms - interrupt enabled - clear WDE for int
WDTCSR = (1<<WDP2)|(1<<WDP1)|(1<<WDP0)|(1<<WDIE);//|(1<<WDCE);//2000ms
//WDTCSR = (1<<WDP3)|(1<<WDP0)|(1<<WDIE);//|(1<<WDCE);//8000ms
asm ("wdr \n");
interrupts();
asm ("wdr \n");
//test 1
timeoutCounter=millis();
asm ("wdr \n");
while((millis()-timeoutCounter)<TimeoutTimer) asm ("wdr \n");
Serial.println("WDT reset stopped...");
delay(250);
while(!testflag);
Serial.println("WDT interrupt...");
delay(250);
Serial.println(testmsg.d8.len);
delay(250);
Serial.println("Done!");
}
void loop() {}
#include "wdtTest.h"
const uint32_t TimeoutTimer = 1500UL;
uint32_t timeoutCounter;
MessageDataTypeDef testmsg;
wdtTest wdt = wdtTest();
void setup() {
wdt.begin();
Serial.begin(115200);
delay(250);
Serial.println("Starting...");
//setup wdt
wdt.wdT_init();
//test 1
timeoutCounter=millis();
while((millis()-timeoutCounter)<TimeoutTimer) wdt.wdT_reset();
Serial.println("WDT reset stopped...");
delay(250);
while(!wdt.retFlag());
Serial.println("WDT interrupt...");
delay(250);
testmsg.d8.len=wdt.retLen();
Serial.println(testmsg.d8.len);
delay(250);
Serial.println("Done!");
}
void loop() {}
#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include "wdtTest.h"
static volatile MessageDataTypeDef wdtTest::spimsg={
.d32.msg[0]=0,
.d32.msg[1]=0,
.d32.msg[2]=0,
.d32.msg[3]=0,
.d32.msg[4]=0,
.d32.msg[5]=0,
.d32.msg[6]=0,
.d32.msg[7]=0,
.d32.len=0
};
static volatile bool wdtTest::spiflag=0;
wdtTest::wdtTest(){}
ISR(WDT_vect){
pinMode(13,OUTPUT);
digitalWrite(13,OUTPUT);
wdtTest::spimsg.d8.len=45;//test var
wdtTest::spimsg.d8.dat[0]=105;//test var
wdtTest::spiflag=1;
wdtTest::wdT_end();
//wdtTest::inthandle();
}
bool wdtTest::begin(){
wdtTest::spimsg.d8.len=0;
for(byte i=0; i<32; i++) wdtTest::spimsg.d8.dat[i]=0;
wdtTest::spiflag=0;
return 1;
}
bool wdtTest::wdT_init(){
//timed sequence
noInterrupts();
//reset WDRF
//MCUSR &= ~(1<<WDRF);
MCUSR = 0;
WDTCSR = (1<<WDCE)|(1<<WDE);
//set prescaler ~ 2000ms - interrupt enabled - clear WDE for int only
WDTCSR = (1<<WDP2)|(1<<WDP1)|(1<<WDP0)|(1<<WDIE);
interrupts();
return 1;
}
static volatile bool wdtTest::wdT_end(){
//reset WDRF
//MCUSR &= ~(1<<WDRF);
MCUSR = 0;
//end WDT
WDTCSR = (1<<WDCE);
return 1;
}
bool wdtTest::wdT_reset(){
asm ("wdr \n");
return 1;
}
uint8_t wdtTest::retLen(){
uint8_t ret;
ret = wdtTest::spimsg.d8.len;
return ret;
}
bool wdtTest::retFlag(){
bool ret;
ret = wdtTest::spiflag;
wdtTest::spiflag=0;
return ret;
}
static volatile void wdtTest::inthandle(){
pinMode(13,OUTPUT);
digitalWrite(13,OUTPUT);
wdtTest::spimsg.d8.len=45;
wdtTest::spimsg.d8.dat[0]=SPCR;
wdtTest::spiflag=1;
wdtTest::wdT_end();
}
#ifndef _WDTTESTH_
#define _WDTTESTH_
#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
//extern bool spiflag;
//extern MessageDataTypeDef spimsg;
typedef union
{
struct {
uint32_t msg[8];
uint8_t len;
} d32;
struct {
uint8_t dat[32];
uint8_t len;
} d8;
} MessageDataTypeDef;
class wdtTest{
public:
extern MessageDataTypeDef spimsg;
extern bool spiflag;
//class constructor
wdtTest(void);
bool begin(void);
bool wdT_init(void);
bool wdT_reset(void);
uint8_t retLen(void);
bool retFlag(void);
static volatile void inthandle(void);
//friend void WDT_vect(void);
private:
//extern MessageDataTypeDef spimsg;
//extern bool spiflag;
static volatile bool wdT_end(void);
};
#endif
The problems seems to come from my declaration/definition of the the typedef union struct which needs to be accessed from within the ISR.
Have tried a bunch of different things, with the following error messages showing up:
Variable | Declaration | Location | Definition | Location | ID | Error |
---|---|---|---|---|---|---|
spimsg | static volatile BmcMessageDataTypeDef _spimsg=NULL; | .h class A{ public: | 1 | conversion from ‘int’ to non-scalar type ‘volatile BmcMessageDataTypeDef’ requested | ||
spiflag | static volatile bool _spiflag=0; | .h class A{ public: | 1 | ISO C++ forbids in-class initialization of non-const static member ‘A::_spiflag’ | ||
spimsg | static volatile BmcMessageDataTypeDef _spimsg; | .h class A{ public: | A::_spimsg.d8.len=0; for(uint8_t i=0; i<32; i++) A::_spimsg.d8.dat*=0;[/td] .cpp bool A::begin(){ 3 In function begin': undefined reference to A::_spimsg’[/tr] spiflag static volatile bool _spiflag; .h class A{ public: A::_spiflag=0; .cpp bool A::begin(){ 3 In function begin': undefined reference to A::_spiflag’spimsg extern BmcMessageDataTypeDef _spimsg; .h [global] static volatile BmcMessageDataTypeDef A::_spimsg={.d32.msg[0]=0; …;.d32.len=0;}; .cpp [global] 4 ’_spimsg’ is not a member of ‘A’ spiflag extern bool _spiflag; .h [global] static volatile bool A::_spiflag=0; .cpp [global] 4 ’_spiflag’ is not a member of 'A’ spimsg extern BmcMessageDataTypeDef _spimsg; .h class A{ public: static volatile BmcMessageDataTypeDef A::_spimsg={.d32.msg[0]=0; …;.d32.len=0;}; .cpp [global] 5 storage class specified for '_spimsg’ spiflag extern bool _spiflag; .h class A{ public: static volatile bool A::_spiflag=0; .cpp [global] 5 storage class specified for ‘_spiflag’ [/table]* Sorry about the shoddy formatting and inconsistency between variable names (above table was run as a test script) but in essence the bits that changed are: ID 1 - static volatile variables declared and defined as public in .h class ID 2 - identical to ID 5 ID 3 - static volatile variable declared public in . class; defined in A::begin() method ID 4 - extern variables declared in .h at global scope; defined as static volatile in .cpp at global scope ID 5 - extern variables declared public in .h class; defined as static volatile in .cpp at global scope Feels like I’m just going round in circles and like there’s something fundamental I’m missing. If anyone could help out with this it would actually be amazing! |