unosquare / wiringpi-dotnet

Provides complete managed access to the popular wiringpi C library

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Enable setting GpioPin.PwmRegister prior to changing pin mode

alobakov opened this issue · comments

Hi guys!
Been playing with hardware PWM on RPi 3B and encountered this issue:
When switching GpioPin.PinMode to GpioPinDriveMode.PwmOutput, the underlying WiringPi library immediately starts the clock. That's probably the right thing to do, as long as one gets a chance to set the desired duty cycle first. That could be done by calling pwmWrite(pin, val) which doesn't care if a pin is not yet in PWM mode. However, the wrapping setter in GpioPin.PwmRegister throws InvalidOperationException because the pin hasn't been switched to PwmOutput. But if we switch the pin to PwmOutput, the clock is started and the default range and divisor kick in immediately, producing an "arbitrary" burst signal for at least the 100 microsecond delay that is hard-coded in WiringPi, before any code gets a chance to adjust those parameters and set register value to the desired duty cycle. The way it manifests itself with an LED is a short burst of light until the proper duty cycle gets set.
Having the mode check in the PwmRegister property setter commented out and setting a value prior to switching pin mode, I was finally able to start PWM with any desired duty cycle (e.g. a flat-line zero).
I believe this is important if one wants to get a predictable PWM output right off the bat when starting a motor at a low speed or slowly lighting up an LED without getting an uncontrolled initial "burst".
Let me know what you think. - Advance thanks!

@alobakov you are correct. I had experienced this in the past and was unable to figure out why these bursts appeared. It is now clear that the order matters. @k3z0 could you please check this out?

Hi @alobakov

This behavior was changed in the just-released nuget (0.4.0), could you please give it a try and let us know if it's working ok?

Thanks.

@alobakov

Can we close this issue?

Sorry guys, I've been totally swamped at my primary job for the last two weeks, - I will definitely have this tested out by end of the week, and will report the results. - Thanks for getting this addressed!

Thank you @alobakov, we will wait for your feedback.

@k3z0 Could you please double-check the nuget package content?
It seems the assembly in the package claims to be of version 0.4.0, but the latest commit doesn't appear to have been included. The assembly size is exactly the same as that in 0.3.1, - to the byte.
Not a reliable measure, but still pretty suspicious given that the exception messages have changed. The old exceptions are still there (note the Assembly.FullName in the output):
image

Hi @alobakov , I updated the nuget again, can you check version 0.4.1?

No exception now. - Thank you!
However, I just realized I had actually made 2 other changes locally when I originally got it to work as required before opening this ticket.

  1. PwmRegister need not be constrained by 1024, - in my working model I had a range of 24000, and the Register value could be much higher than 1024. In fact, there are posts suggesting that even 4096 is not the max value. It worked well for me when I removed the call to value.Clamp(0, 1024) in PwmRegister setter.
  2. As I'm testing this on RPI 3B, the hardware PWM capable pins are not just 13 and 18, but also 12 and 19 (with the caveat that each pair of 12+18 and 13+19 uses single clock/channel). It's understandable that the library is meant for models with different capabilities, - perhaps PWM-capable pins could be made configurable. But the underlying WiringPI lib does support those.

You can check the latest changes with the nuget v0.4.2.

Thanks, I will take a look on Saturday.

I have tested 0.4.2 and overall it appears to do what it's supposed to do, - the extra pins are working and the library allows setting PWM parameters before changing pin mode to PWM.
Trouble is, the underlying libwiringpi seems to have its own quirks.
Whatever parameter values are being set do not take until pin mode is switched to PWM. And that kinda sounds logical, - right? E.g. setting PwmMode, PwmRange, PwmClockDivisor or PwmRegister works, but reading the same properties returns zeros, as the pin is not yet in PWM mode. Then, once the pin mode is switched to PWM, the properties read the correct values. - Very cool!
BUT! Sadly, the signal does not honor those set values once started. I don't have an oscilloscope to see what's going on, but the servo motors I'm using do not respond at all. Which tells me that the output frequency is outside the expected range. Then I tried moving mode switchover call higher up, i.e. before setting certain properties, and it feels like whatever properties get set prior to that call are not honored when the PWM clock is started, despite returning set values when reading them.
The motors behave very odd (either move extremely slow or just produce weird noises without any motion), - depending on what parameters are being set after the clock starts.
Now, I'm 99.999% certain that this flaw is not in Unosquare.WiringPI because the code is all good, - it's most likely in libwiringpi.so. This might take reaching out to that team or opening a ticket there, but I think this ticket here should now be closed.
Thanks for all the effort!

By the way, I have no idea who "owns" the source code for the underlying .so library used by Unosquare.WiringPI, - all I've been able to find was a bunch of unofficial mirrors on github.
If you could refer me the github repo of the team I could reach out to, - that would be fantastic.

Hi @alobakov

You can find more information about WiringPi (the underlying library) here.

According to the underlying library code, when you change the mode to PWM it sets the parameters back to its default values:

    pwmSetMode(PWM_MODE_BAL);
    pwmSetRange(1024);
    pwmSetClock(32);

Therefore, a change to customize the underlying library must be done in order to get the desired behavior.