[Libmaple] pinMode() disables timer even if no PWM mode involved

LibMaple (The core that Roger's repo uses)
rmdMoba
Posts: 16
Joined: Thu May 11, 2017 10:44 am

[Libmaple] pinMode() disables timer even if no PWM mode involved

Post by rmdMoba » Thu May 11, 2017 11:09 am

Hello,
I'm using the STM32duino now for a while and enhanced my model-railroaders library to run on STM32.
This library extensivly uses timer 4 and compare interrupts. It does NOT use the related PWM output pins.
Sometimes my library stopped to work, and I found out, that this is always the case, when a pinMode() command ist running on one of the pins that can be used with PWM and timer 4.

The cause is this code snippet in wirish_digital_f1.cpp:

Code: Select all

    gpio_set_mode(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit, outputMode);

    if (PIN_MAP[pin].timer_device != NULL) {
        /* Enable/disable timer channels if we're switching into or
         * out of PWM. */
        timer_set_mode(PIN_MAP[pin].timer_device,
                       PIN_MAP[pin].timer_channel,
                       pwm ? TIMER_PWM : TIMER_DISABLED);
    }
The timer is disabled in any mode that is not PWM - even if it has never been set to a PWM mode. This makes use of the timer nearly impossible. You can never be sure, that someone using the library sets this pin to e.g. OUTPUT.
The timer should only be touched if the last mode was a pwm mode, or if the mode to be set is a PWM mode. In all other cases the timer should be left untouched.

I tried with this code, and it worked fine in my tests:

Code: Select all

    // remember old mode to see whether we have to change timer mode
    gpio_pin_mode oldMode = gpio_get_mode(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit); 
    
    gpio_set_mode(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit, outputMode);
    
    if (PIN_MAP[pin].timer_device != NULL) {
        /* Enable/disable timer channels if we're switching into or
         * out of PWM. */
        if ( pwm || oldMode == GPIO_AF_OUTPUT_OD || oldMode == GPIO_AF_OUTPUT_PP ) {
            timer_set_mode(PIN_MAP[pin].timer_device,
                           PIN_MAP[pin].timer_channel,
                           pwm ? TIMER_PWM : TIMER_DISABLED);
        }
    }
It would be fine if this could be fixed in a new release

Regards,
Franz

User avatar
RogerClark
Posts: 7134
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: pinMode() disables timer even if no PWM mode involved

Post by RogerClark » Thu May 11, 2017 10:59 pm

Thanks for reporting this.

If you have a github account, ( or could create one), the best way to submit your fix is via a Pull Request on github.

I will create an issue on github to track this asap.

edogaldo
Posts: 279
Joined: Fri Jun 03, 2016 8:19 am

Re: pinMode() disables timer even if no PWM mode involved

Post by edogaldo » Fri May 12, 2017 7:13 am

rmdMoba wrote:The timer should only be touched if the last mode was a pwm mode, or if the mode to be set is a PWM mode. In all other cases the timer should be left untouched.

I tried with this code, and it worked fine in my tests:

Code: Select all

    // remember old mode to see whether we have to change timer mode
    gpio_pin_mode oldMode = gpio_get_mode(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit); 
    
    gpio_set_mode(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit, outputMode);
    
    if (PIN_MAP[pin].timer_device != NULL) {
        /* Enable/disable timer channels if we're switching into or
         * out of PWM. */
        if ( pwm || oldMode == GPIO_AF_OUTPUT_OD || oldMode == GPIO_AF_OUTPUT_PP ) {
            timer_set_mode(PIN_MAP[pin].timer_device,
                           PIN_MAP[pin].timer_channel,
                           pwm ? TIMER_PWM : TIMER_DISABLED);
        }
    }
It would be fine if this could be fixed in a new release

Regards,
Franz
Hello all, I'd suggest to avoid disabling the timer via pinMode at all because the same problem could happen if you disable a pwm pin while using the timer for both pwm and something else or you use different pwm pins belonging to the same timer..

rmdMoba
Posts: 16
Joined: Thu May 11, 2017 10:44 am

Re: pinMode() disables timer even if no PWM mode involved

Post by rmdMoba » Fri May 12, 2017 12:37 pm

Well, maybe a solution too. The gpio_set_mode() function disconnects the pin from the timer output if any standard outputmode is set ( no alternate function ). May be this is sufficient and the timer can be left untouched generally when setting any nonpwm mode.

victor_pv
Posts: 1679
Joined: Mon Apr 27, 2015 12:12 pm

Re: pinMode() disables timer even if no PWM mode involved

Post by victor_pv » Fri May 12, 2017 3:17 pm

edogaldo wrote:
rmdMoba wrote:The timer should only be touched if the last mode was a pwm mode, or if the mode to be set is a PWM mode. In all other cases the timer should be left untouched.

I tried with this code, and it worked fine in my tests:

Code: Select all

    // remember old mode to see whether we have to change timer mode
    gpio_pin_mode oldMode = gpio_get_mode(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit); 
    
    gpio_set_mode(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit, outputMode);
    
    if (PIN_MAP[pin].timer_device != NULL) {
        /* Enable/disable timer channels if we're switching into or
         * out of PWM. */
        if ( pwm || oldMode == GPIO_AF_OUTPUT_OD || oldMode == GPIO_AF_OUTPUT_PP ) {
            timer_set_mode(PIN_MAP[pin].timer_device,
                           PIN_MAP[pin].timer_channel,
                           pwm ? TIMER_PWM : TIMER_DISABLED);
        }
    }
It would be fine if this could be fixed in a new release

Regards,
Franz
Hello all, I'd suggest to avoid disabling the timer via pinMode at all because the same problem could happen if you disable a pwm pin while using the timer for both pwm and something else or you use different pwm pins belonging to the same timer..
A vote for that, don't see the point disabling the whole timer when the pinMode change will stop the PWM output anyway.
I think the logic was probably to disable the timer if it's not needed anymore, but that would affect other pins or anything else using that timer. No point disabling it.

User avatar
RogerClark
Posts: 7134
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: pinMode() disables timer even if no PWM mode involved

Post by RogerClark » Fri May 12, 2017 9:34 pm

I agree.

It doesnt seem ncessary to disable the timer(s) at all.

The only downside I can think of, is increased power consumption, but would only effect anyone running from batteries, in whuch case they would probably write their own additional code to make sure any unused hardware is shut down.

rmdMoba
Posts: 16
Joined: Thu May 11, 2017 10:44 am

Re: pinMode() disables timer even if no PWM mode involved

Post by rmdMoba » Sat May 13, 2017 8:49 pm

Hi all,
if we decide to never disable the timer in the pinMode function, the fix is even more simple:

Code: Select all

    gpio_set_mode(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit, outputMode);
    
    if (pwm && PIN_MAP[pin].timer_device != NULL) {
        /* Enable timer channels if we're switching into  PWM. */
        timer_set_mode(PIN_MAP[pin].timer_device,
                       PIN_MAP[pin].timer_channel,
                       TIMER_PWM);
    }
I'll do some tests the next days and then create a pull request on github.
Because I have got only a maple mini and a generic F103 board, I can do the tests only for the F1 series.
When looking at the corresponding files for the F3 and F4 series , I detected, that in the F3 file the timer is already never disabled, whereas with F4 it is the same as with F1 .

User avatar
RogerClark
Posts: 7134
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: pinMode() disables timer even if no PWM mode involved

Post by RogerClark » Sat May 13, 2017 9:15 pm

Thanks

rmdMoba
Posts: 16
Joined: Thu May 11, 2017 10:44 am

Re: pinMode() disables timer even if no PWM mode involved

Post by rmdMoba » Thu May 18, 2017 3:39 pm

Hello all,
I did several tests and my fix worked so far. But I found some strange behaviour with pins that provide two alternate functions, e.g. PWM and Serial or PWM and SPI. If once SPI or Serial was activated ( and then deactivated with the end method ) PWM did not work anymore. The other way round is OK: when starting PWM and later starting SPI or Serial this works, but switching back to PWM is not possible. This is the case with both variants - original and with my fix.
I could not find a reason for that so far. In the STM32F1-reference I didn't find a way to exactly connect the pin to one or the other alternate function. In the GPIO Regs you only can generally connect the pin to alternate functions. And you can enable or disable these functions ( even both at the same time ). SPI or Serial seem to have priority over PWM, and if they once have been connected to the pin, there is no going back till reset. Does somene know more about that?

Maybe in practice this is not really a problem. I think it will be seldom that someone enables SPI on a pin and later will output a PWM Signal at the same pin.

victor_pv
Posts: 1679
Joined: Mon Apr 27, 2015 12:12 pm

Re: pinMode() disables timer even if no PWM mode involved

Post by victor_pv » Thu May 18, 2017 3:54 pm

rmdMoba wrote:Hello all,
I did several tests and my fix worked so far. But I found some strange behaviour with pins that provide two alternate functions, e.g. PWM and Serial or PWM and SPI. If once SPI or Serial was activated ( and then deactivated with the end method ) PWM did not work anymore. The other way round is OK: when starting PWM and later starting SPI or Serial this works, but switching back to PWM is not possible. This is the case with both variants - original and with my fix.
I could not find a reason for that so far. In the STM32F1-reference I didn't find a way to exactly connect the pin to one or the other alternate function. In the GPIO Regs you only can generally connect the pin to alternate functions. And you can enable or disable these functions ( even both at the same time ). SPI or Serial seem to have priority over PWM, and if they once have been connected to the pin, there is no going back till reset. Does somene know more about that?

Maybe in practice this is not really a problem. I think it will be seldom that someone enables SPI on a pin and later will output a PWM Signal at the same pin.
I don't remember that when I read about the GPIO a while back in the reference manual. I suspect the case may be that when SPI or Serial end, the pins are not configured completely back to default and something extra may need to be done.

Post Reply