I have a situation where I have a class on a microcontroller which deals with pulse width modulation. Extremely simplified example:
class MotorDriver
{
int pin_;
public:
MotorDriver(int pin);
void init();
void start();
void stop();
void changeDutyCycle(int dc);
};
It has functions to initialize, start, stop and change pwm. If I connect 4 motors to the microcontroller, I will create 4 instances of that class and put them in an array, then call functions like
motors[0].changeDutyCycle(50);
motors[1].changeDutyCycle(40);
....
Problem arises because there is no generic way to configure timers on said microcontroller. For example, one motor will have to use Timer3 while another motor will have to use Timer4. Different timers have different bit sizes, registers, channels, pins, ... I want to be able to write custom functions for each timer, but still be able to put all objects into same array and call functions on them, ie
class MotorDriver
{
void changeDutyCycle(int dc) = 0;
};
class MotorDriver1 : public MotorDriver
{
void changeDutyCycle(int dc)
{
TIM3->CCR2 = dc;
}
};
class MotorDriver2 : public MotorDriver
{
void changeDutyCycle(int dc)
{
TIM4->CCR1 = dc;
}
};
MotorDriver1 md1();
MotorDriver2 md2();
MotorDriver* mds[] = { &md1, &md2 };
int main()
{
mds[0]->changeDutyCycle(10);
mds[1]->changeDutyCycle(20);
}
I know I can achieve what I want with virtual functions. This function is short and will be called often, so price of virtual functions is high. Is there a way to avoid them in this case or different design pattern? The goal was to have reusable code which is easy to use on the outside. Having everything that I need in an array makes many things much easier.
Edit: I know about this post Avoiding virtual functions but answer that relates to what I need states:
If you're in a situation where every cycle per call counts, that is you're doing very little work in the function call and you're calling it from your inner loop in a performance critical application you probably need a different approach altogether.
The differences between timers are usually pretty minor, especially when it comes to configuring the actual output width - the initialization may be different, but there you can have virtual functions. Just store the reference to underlying TIM registers and the channel index in your class and that seems all you have to do. If you use things like "complementary" channels, then you can store them as negative indexes.
Check this code - it's for a very similar purpose (driving stepper motors) on STM32F4, but should give you an idea.
Don't worry too much about the performance - in reality microcontrollers are extremely fast and just using proper architecture (like RTOS or event driven) will cause them to be bored for 80-90% of the time!
If you implement the simple code and it will in fact cause your application to be too slow, then - assuming that you cannot improve the algorithm or overall architecture - just precompute most of the values from
start()in your constructor and maybe drop error checking (or move it somewhere else, out from the loop).Or just use virtual functions, the impact of the indirect call is usually negligible.