Page 1 of 1

HardwareTimer inside a Class

Posted: Sat Oct 24, 2020 5:38 pm
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(){}

Re: HardwareTimer inside a Class

Posted: Sat Oct 24, 2020 9:49 pm
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.

Re: HardwareTimer inside a Class

Posted: Sun Oct 25, 2020 12:27 am
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();
}

Re: HardwareTimer inside a Class

Posted: Sun Oct 25, 2020 3:36 am
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.

Re: HardwareTimer inside a Class

Posted: Sun Oct 25, 2020 7:28 am
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).

Re: HardwareTimer inside a Class

Posted: Sun Oct 25, 2020 8:01 am
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!

Re: HardwareTimer inside a Class

Posted: Sun Oct 25, 2020 6:22 pm
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...

Re: HardwareTimer inside a Class

Posted: Sun Oct 25, 2020 10:43 pm
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.

Re: HardwareTimer inside a Class

Posted: Mon Oct 26, 2020 1:38 am
by sigi
Thanks GonzoG! now It works properly...