[DONE] Dynamic PWM channel configuration?

ChibiOS public support forum for topics related to the STMicroelectronics STM32 family of micro-controllers.

Moderator: RoccoMarco

User avatar
Tectu
Posts: 1225
Joined: Thu May 10, 2012 9:50 am

[DONE] Dynamic PWM channel configuration?

Post by Tectu »

Hello Folks,

Let's say I need four PWM outputs to drive four devices (RC servos). I can create the PWM config struct as follows:

Code: Select all

static PWMConfig pwmcfg = {
    1000000,
    20000,
    NULL,
    {
        {PWM_OUTPUT_ACTIVE_HIGH, NULL},
        {PWM_OUTPUT_ACTIVE_HIGH, NULL},
        {PWM_OUTPUT_ACTIVE_HIGH, NULL},
        {PWM_OUTPUT_ACTIVE_HIGH, NULL},
    },
    0
};


Now, that works well. But let's say I am writing a small driver/wrapper which does allow it to easily use servos with ChibiOS/RT. Therefore, I need to adjust the PWM channel configuration and add the new channel as soon as I create a new instance. How can this be done? The init function which does call the pwmStart() does know what channel needs to be enabled.
Maybe this is some very easy, basic C thing and I am just thinking to far. Also, maybe I don't explain the problem very well. I'd be thankful if anyone could try to help me.


Thanks in advance.

~ Tectu
User avatar
Giovanni
Site Admin
Posts: 14891
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: Dynamic PWM channel configuration?

Post by Giovanni »

Just keep your configuration structure in RAM, change it when needed and then call pwmStart() again to reconfigure.

Giovanni
User avatar
Tectu
Posts: 1225
Joined: Thu May 10, 2012 9:50 am

Re: Dynamic PWM channel configuration?

Post by Tectu »

Thank you very much for your help, Giovanni. This is how I solved it:

Code: Select all

static PWMConfig pwmcfg = {
    1000000,   // 1MHz PWM clock frequency
    20000,      // PWM period 20 milliseconds
    NULL,      // no callback
    NULL,      // channel configuration set dynamicall in servoInit()
    0
};

void servoInit(Servo *servo) {
   PWMChannelConfig chcfg = { PWM_OUTPUT_ACTIVE_HIGH, NULL };
   pwmcfg.channels[servo->pwm_channel] = chcfg;
   ...
}



~ Tectu
ruslanpopov
Posts: 35
Joined: Sun Aug 19, 2012 9:36 pm

Re: Dynamic PWM channel configuration?

Post by ruslanpopov »

I think you have to use dummy channel configuration, like this:

Code: Select all

static PWMConfig pwmcfg = {
    STM32_SYSCLK,                           /* PWM clock frequency, PSC register. */
    (uint16_t) (STM32_SYSCLK / PWM_FREQ) + 1,   /* Initial PWM period. ARR register*/
    NULL,                                   /* Periodic callback pointer. */
    {                                       /* Channel configuration set dynamically below, */
        {PWM_OUTPUT_DISABLED, NULL},
        {PWM_OUTPUT_DISABLED, NULL},
        {PWM_OUTPUT_DISABLED, NULL},
        {PWM_OUTPUT_DISABLED, NULL}
    },
    0                                       /* TIM CR2 register initialization data. */
#if STM32_PWM_USE_ADVANCED
    ,0                                      /* TIM BDTR register initialization data. */
#endif
};


I am not C language guru but I guess NULL takes lower count bytes than channel configuration structure and you may overwrite some bytes there.
goeck
Posts: 92
Joined: Mon Feb 11, 2013 12:00 pm

Re: Dynamic PWM channel configuration?

Post by goeck »

Hey guys,

sorry to dig up this thread again, but I think my matter does fit in here pretty well. The thing is, I have a PWM output on the STM32F0-DISCOVER which works just fine thanks to the examples under ChibiOS/testhal and this post. Now I want to change the frequency "on the fly", but before I want to check whether the channel is enabled or disabled; not if PWM is stopped or running.
Say my code looked like this:

Code: Select all

static PWMConfig pwmcfg = {
  10000,                                    /* 10kHz PWM clock frequency.   */
   1000,                                    /* Initial PWM period 0,1S.     */
  NULL,
  {
   {PWM_OUTPUT_ACTIVE_HIGH, NULL},
   {PWM_OUTPUT_DISABLED, NULL},
   {PWM_OUTPUT_DISABLED, NULL},
   {PWM_OUTPUT_DISABLED, NULL}
  },
  0,
};

int main(){
// init routine
palSetPadMode(GPIOA, 15, PAL_MODE_ALTERNATE(2));      // GPIOA15 is the PWM output (CH1).
pwmStart(&PWMD2, &pwmcfg);                           // Initializes the PWM driver 2

...

if(dataAvailable){
   // set speed of slider motion
   pwmChangePeriod(&PWMD2, 500 - data3d.x);

   // if PWM was shut of previously, restart it
   if(PWMD2.state == PWM_STOP)                  // <--- This is where the cash goes
      pwmEnableChannel(&PWMD2, 0, PWM_PERCENTAGE_TO_WIDTH(&PWMD2, 5000));         // Starts the PWM channel 0 using 50% duty cycle.
}
else{
   if(PWMD2.state == PWM_READY){               // <--- This is where the cash goes
      pwmDisableChannel(&PWMD2, 0);            // PWM channel disabled: no motion
      palClearPad(GPIOA, 15);
   }
}
}


Since I didn't use and don't wanna use pwmStart() and pwmStop() to start the whole PWM machinery it doesn't make sense to use PWMD2.state as an indicator whether to enable or disable the channel output. But my knowledge is done here. How can I substitute this with the asking for enabled or disabled channels? It's not right to check the pwmcfg variable like this, is it?

Code: Select all

if(pwmcfg.channels[0].mode == PWM_OUTPUT_DISABLED)
     pwmEnableChannel(&PWMD2, 0, PWM_PERCENTAGE_TO_WIDTH(&PWMD2, 5000));         // Starts the PWM channel 0 using 50% duty cycle.


--- EDIT: ------
Ok, I found a way, but this doesn't satisfy me since it is very application specific and related to STM32 ICs only

Code: Select all

if(PWMD2.tim->CCR[0])                        // PWM channel was disabled previously, timer entry = 0
   pwmDisableChannel(&PWMD2, 0);            // PWM channel disabled: no motion


I really appreciate any help here,
Keep it up.
Stefan
User avatar
Giovanni
Site Admin
Posts: 14891
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: Dynamic PWM channel configuration?

Post by Giovanni »

Hi,

A channel initialized as PWM_OUTPUT_DISABLED must not be used, it means "not used", probably I should have given it a better name. Note that all data in the configuration structure is meant to be static and not writable so it cannot change.

You can call pwmEnableChannel() and pwmDisableChannel() in any moment without having to know if it is actually enabled or not so you don't have to query the channel state before calling those functions. Do you have other reasons to query a channel state? that would require a new function and could be added eventually but I don't see a use case.

You can use pwmChangePeriod() in order to change the PWM period on the fly.

Giovanni
goeck
Posts: 92
Joined: Mon Feb 11, 2013 12:00 pm

Re: Dynamic PWM channel configuration?

Post by goeck »

Hey Giovanni, thanks for the reply.
I have a periodic data input and want to recalculate the pwm frequency after each input and put it on the line. This can be sucessfully done by the mentioned pwmChangePeriod() *thumbsUp*
Now, my data input stops, so my PWM output shall stopp also. Some time later my data input my be present again, for a certain time, and a PWM signal should be generated accordingly.
This is why I first want to gather information about the channel state.

What I've done so far is this:

Code: Select all

pwmChangePeriod(&PWMD2, dataInputValue);
if(!PWMD2.tim->CCR[0]){
   pwmEnableChannel(&PWMD2, 0, PWM_PERCENTAGE_TO_WIDTH(&PWMD2, 5000));         // Starts the PWM channel 0 using 50% duty cycle.
   chVTSet(&dataXTimeout, MS2ST(myDataRate*2), dataXTimoutCB, NULL);
}

I change the PWM frequency, enable the channel if disabled earlier and set a timeout timer which calls a function [dataXTimeoutCB()], that actually just disables the channel clears the related pad. So I have a clear view over my possible PWM channel states.
I get into trouble when leaving out the check for channel state, because of the timeout timer I guess. After a while I just get no PWM output anymore...
Well, it kinda works, but not just fine right now.

To me this is not the best style, because IC specific.
I think, having the option to check the channel state easily would be a great addition to the PWM driver.

Thanks for the hard work, Giovanni!
Cheers
User avatar
Giovanni
Site Admin
Posts: 14891
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: Dynamic PWM channel configuration?

Post by Giovanni »

I'll add a channel-query function in the to-do list.

Giovanni
goeck
Posts: 92
Joined: Mon Feb 11, 2013 12:00 pm

Re: Dynamic PWM channel configuration?

Post by goeck »

:) nice!
User avatar
Giovanni
Site Admin
Posts: 14891
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: [DONE] Dynamic PWM channel configuration?

Post by Giovanni »

Hi,

I added to the driver a new API, sorry if this took a while but it could not be helped.

Giovanni
Post Reply