HardwareTimer inside a Class

Post here first, or if you can't find a relevant section!
Post Reply
sigi
Posts: 57
Joined: Mon Sep 28, 2020 3:17 pm

HardwareTimer inside a Class

Post by sigi »

Hi
did somebody knows why this compiles but freezes the blackpill MCU? (PC13 LED flashes always and does not run anything more)

class Motor {
public:
uint8_t pinPulse;
uint8_t pinDirec;
uint8_t pinEnable;
uint8_t TimerNum;

Motor(uint8_t pinPulse, uint8_t pinDirec, uint8_t pinEnable, uint8_t TimerNum) {
this->pinPulse = pinPulse;
this->pinDirec = pinDirec;
this->pinEnable = pinEnable;
this->TimerNum = TimerNum;
pinMode(pinPulse, PWM );
pinMode(pinEnable, OUTPUT);
pinMode(pinDirec, OUTPUT);
}

HardwareTimer *MyTim = new HardwareTimer(TimerNum);

void Start() {
MyTim->pause();
MyTim->setPrescaleFactor(1);
MyTim->setOverflow(1000);
MyTim->refresh();
MyTim->resume();
}

};

Motor Mot1 = Motor(PA8,PA9,PB1,1);

void setup() {
Mot1.Start();
}

void loop(){}
GonzoG
Posts: 403
Joined: Wed Jan 15, 2020 11:30 am
Answers: 27
Location: Prudnik, Poland

Re: HardwareTimer inside a Class

Post by GonzoG »

How do you know that it freezes MCU ??
There's nothing in this code that would allow you to see if it's working.
sigi
Posts: 57
Joined: Mon Sep 28, 2020 3:17 pm

Re: HardwareTimer inside a Class

Post by sigi »

because the PC13 is not in normal conditions as when the timer is not inside the class.

Another more complete example of the code, that does not work for some reason...

class Motor {
public:
uint8_t pinPulse;
uint8_t pinDirec;
uint8_t pinEnable;
uint8_t TimerNum;

Motor(uint8_t pinPulse, uint8_t pinDirec, uint8_t pinEnable, uint8_t TimerNum) {
this->pinPulse = pinPulse;
this->pinDirec = pinDirec;
this->pinEnable = pinEnable;
this->TimerNum = TimerNum;
pinMode(pinPulse, PWM );
pinMode(pinEnable, OUTPUT);
pinMode(pinDirec, OUTPUT);
}

HardwareTimer *MyTim = new HardwareTimer(TimerNum);
void Close(){
MyTim->pause();
pwmWrite(pinPulse,0);
MyTim->refresh();
MyTim->resume();
}

void Start() {
int stepPulse = 100;
int tSpace = 100;

uint32 DutyCyc;
uint32 PeriodCyc;
uint16 Prescaler;
uint16 Overflow;

MyTim->pause();
PeriodCyc = (stepPulse + tSpace) * (F_CPU/1000000.0);// ciclos por us del STM32
#define MAX_RELOAD ((1 << 16) - 1)//timer 16 bits resolution
Prescaler = (PeriodCyc / MAX_RELOAD) + 1.0;
MyTim->setPrescaleFactor(Prescaler);
Overflow = (PeriodCyc + (Prescaler / 2.0)) / Prescaler;
MyTim->setOverflow(Overflow);
DutyCyc = Overflow*stepPulse/(stepPulse+tSpace);
pwmWrite(pinPulse,DutyCyc);
MyTim->refresh();
MyTim->resume();
}
};

Motor Mot1 = Motor(PA8,PA9,PB1,1);

void setup() {
Mot1.Close();
}

void loop(){
delay(3000);
Mot1.Start();
}
mrburnette
Posts: 633
Joined: Thu Dec 19, 2019 1:23 am
Answers: 7

Re: HardwareTimer inside a Class

Post by mrburnette »

Some working examples w/ caveats:

https://forum.arduino.cc/index.php?topi ... msg3453059

They compile error free on Roger's core, I do not guarantee them to work as
I am not in the lab to test on hardware.
GonzoG
Posts: 403
Joined: Wed Jan 15, 2020 11:30 am
Answers: 27
Location: Prudnik, Poland

Re: HardwareTimer inside a Class

Post by GonzoG »

Your timer declaration might be wrong.
It should be like this:

Code: Select all

HardwareTimer *MyTim;

Motor(...)
{
  ....
  this->TimerNum = TimerNum;
  MyTim = new HardwareTimer(this->TimerNum);
  ...
  }
All variables in class are created before you run constructor so you timer is created before you assign value to TimerNum.
(At least this is how I was taught).
stevestrong
Posts: 502
Joined: Fri Dec 27, 2019 4:53 pm
Answers: 8
Location: Munich, Germany
Contact:

Re: HardwareTimer inside a Class

Post by stevestrong »

I really don't see any point of using the "new" constructor.
This will use malloc and then you do not have any overwiev how you memory is increasing / decreasing.
Especially, contructing temporary objetcs in the main loop is the most common cause of memory corruption/overflow problems.

Usually, you should use the timer objects contructed per default in the core (at least in Roger's), or contruct your object (and not the pointer!) in the sketch outside any function.
This way you can access the timer class function with "." instead of "->" and you call "directly" the functions instead of using function pointers.

Another thing is the Motor class declaration. Usually it will be contructed at the first call of any function of the class. Therefore a begin() or init() function should be defined for that and called in setup, which should then setup the class internals with the input parameters used in your case by declaration.

So you better define and use such function of the class:

Code: Select all

begin(uint8_t pinPulse, uint8_t pinDirec, uint8_t pinEnable, uint8_t TimerNum) {
this->pinPulse = pinPulse;
this->pinDirec = pinDirec;
this->pinEnable = pinEnable;
this->TimerNum = TimerNum;
pinMode(pinPulse, PWM );
pinMode(pinEnable, OUTPUT);
pinMode(pinDirec, OUTPUT);
}
P.S. Use the code tag when posting code!
sigi
Posts: 57
Joined: Mon Sep 28, 2020 3:17 pm

Re: HardwareTimer inside a Class

Post by sigi »

GonzoG wrote: Sun Oct 25, 2020 7:28 am Your timer declaration might be wrong.
It should be like this:

Code: Select all

HardwareTimer *MyTim;

Motor(...)
{
  ....
  this->TimerNum = TimerNum;
  MyTim = new HardwareTimer(this->TimerNum);
  ...
  }
All variables in class are created before you run constructor so you timer is created before you assign value to TimerNum.
(At least this is how I was taught).
Yes It is about that Im sure BUT it still freezes the unit... using this compiles AND work...

Code: Select all

class Motor {
private:
uint32 DutyCyc;
uint32 PeriodCyc;
uint16 Prescaler;
uint16 Overflow;
HardwareTimer *TIMER;

public:
uint8_t pinPulse; 
uint8_t pinDirec; 
uint8_t pinEnable; 
float Pulse;
float Space;
uint8_t TimNum;

Motor(uint8_t pinPulse, uint8_t pinDirec, uint8_t pinEnable,uint8_t TimNum){
this->pinPulse = pinPulse;
this->pinDirec = pinDirec;
this->pinEnable = pinEnable;
this->TimNum=TimNum;
//HardwareTimer *TIMER = new HardwareTimer(TimNum);//HTline1 <----------
pinMode(pinPulse, PWM );
pinMode(pinEnable, OUTPUT);
pinMode(pinDirec, OUTPUT);
}

void move(float Pulse,float Space){
this->Pulse=Pulse;
this->Space=Space;
HardwareTimer *TIMER = new HardwareTimer(TimNum);//HTline2  <----------
TIMER->pause();	
PeriodCyc = (Pulse + Space) * (F_CPU/1000000.0);
#define MAX_RELOAD ((1 << 16) - 1)
Prescaler = (PeriodCyc / MAX_RELOAD) + 1.0;
TIMER->setPrescaleFactor(Prescaler);
Overflow  = (PeriodCyc + (Prescaler / 2.0)) / Prescaler;
TIMER->setOverflow(Overflow);
DutyCyc   = Overflow*Pulse/(Pulse+Space);
pwmWrite(pinPulse,DutyCyc);
digitalWrite(pinEnable,true);
TIMER->refresh();
TIMER->resume();
}

};

Motor Mot1 = Motor(PA8,PA9,PB1,1);
void setup(){}

void loop(){
Mot1.move(0,10);//0%
delay(1500);
Mot1.move(10,0);//100%
delay(1500);
}
switching the HTline1 with HTLine2 comments will make it not work... I do not know why or if there is a problem with memory using the way it works...
GonzoG
Posts: 403
Joined: Wed Jan 15, 2020 11:30 am
Answers: 27
Location: Prudnik, Poland

Re: HardwareTimer inside a Class

Post by GonzoG »

Both ways are wrong.
HT1: your TIMER in constructor is local variable.
In constructor function use:
TIMER = new HardwareTimer(TimNum);
not
HardwareTimer *TIMER = new HardwareTimer(TimNum);
pointer to TIMER is declared in your class, you don't need to create new one.

HT2: you create TIMER each time you run Move() function. You will run out of memory.
sigi
Posts: 57
Joined: Mon Sep 28, 2020 3:17 pm

Re: HardwareTimer inside a Class

Post by sigi »

Thanks GonzoG! now It works properly...
Post Reply

Return to “General discussion”