Shop OBEX P1 Docs P2 Docs Learn Events
OBEX update: PWM_32_v2 — Parallax Forums

OBEX update: PWM_32_v2

Beau SchwabeBeau Schwabe Posts: 6,568
edited 2009-08-07 12:17 in Propeller 1
A new object has been added to the OBEX that allows independent PWM control on up to 32 I/O Channels.


This object requires 1 COG and has a pulse resolution of 8.15us



Features include:
- Phase Sync between multiple PWM pins
- 0% to 100% Duty control
- Hobby Servo control
- PWM control



http://obex.parallax.com/objects/467/





DEMO code example




PUB DEMO_Example | DutyCycle
''-------- This Block Starts the PWM Object ----------
    PWM.Start                   '' Initialize PWM cog 


''-------- This Block sets a Standard servo on Pin 0 to it's center Position ----------
    PWM.Servo(0,1500)           '' Define Pin0 with a standard center position
                                '' servo signal

''-------- This Block creates a 3-Phase 60Hz square wave on Pins 1,2, and 3 -----------
    PWM.Duty(1,50,16665)        ''Create a 60Hz 50% duty cycle on Pin1
    PWM.Duty(2,50,16665)        ''Create a 60Hz 50% duty cycle on Pin2
    PWM.Duty(3,50,16665)        ''Create a 60Hz 50% duty cycle on Pin3
    PWM.PhaseSync(1,2,5555)     ''Phase Sync Pin2 to Pin1 with a Phase leading by 120 Deg    
    PWM.PhaseSync(2,3,5555)     ''Phase Sync Pin3 to Pin2 with a Phase leading by 120 Deg


''-------- This Block creates a PWM pulse on pin 4 with a duty ratio of 1:10 -----------
    PWM.PWM(4,1,10)             '' Creates a pulse with 1 On-Time unit and 10 Off-Time
                                '' units on Pin 4


''-------- This Block creates a speed up/down Motor test on Pin7 -----------
    repeat
      repeat DutyCycle from 0 to 100
        PWM.Duty(7,DutyCycle,5000)       '' Ramp Duty cycle up from 0 to 100               
        repeat 10000
      repeat 1000000                     '' Hold at 100% for a little bit
        
      repeat DutyCycle from 100 to 0
        PWM.Duty(7,DutyCycle,5000)       '' Ramp Duty cycle down from 100 to 0
        repeat 10000
      repeat 1000000                     '' Hold at 0% for a little bit


'-------- Extra Stuff -----------

'' PWM.StateMode(Pin,State)
' Used behind the scenes but available to the user, this function allows you to
' Enable/Dissable a pin...  If State = 0 pin is Disabled, if State = 1 pin is Enabled

 

'' DutyMode(Pin,Mode)
' Also used behind the scenes but available to the user, this function allows you to
' Force the output state of a pin to a HIGH or a LOW regardless of what Ton or Toff is
' telling the pin to do .  This is especially useful when creating a pulse that needs to
' cover the full duty range of 0% to 100%
'
' If Mode = 1 then the Pin will be forced HIGH ; If Mode = 2 then the Pin will be forced
' LOW ; Any other value for Mode, causes the pin to resume it's default state which will
' follow what Ton and Toff are telling it to do.


▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe

IC Layout Engineer
Parallax, Inc.

Post Edited (Beau Schwabe (Parallax)) : 8/7/2009 3:30:28 AM GMT

Comments

  • RaymanRayman Posts: 14,845
    edited 2009-06-15 17:56
    This is different than your servo32 one right? Is there any reason to use this instead of your servo32 driver (if one is only doing servos)?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    My Prop Info&Apps: ·http://www.rayslogic.com/propeller/propeller.htm
  • Beau SchwabeBeau Schwabe Posts: 6,568
    edited 2009-06-15 18:06
    Rayman,

    Completely different... The Servo32 object provides better resolution, so if you are mainly using Servo's I would use that. The PWM offers more features that would be applicable to motor speed control, Power switching applications, etc.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Beau Schwabe

    IC Layout Engineer
    Parallax, Inc.
  • Beau SchwabeBeau Schwabe Posts: 6,568
    edited 2009-06-15 18:24
    Here is an example using the PWM_32_v1 object to simulate "Fire Flies" ... I will post some pictures and a video after tonight of this code in action, since I am using the code in a VBS(Vacation Bible School) stage prop that starts tonight at the Church.

    {{
    ''*******************************************
    ''*  Fire Fly Object                   V1.0 *
    ''*  Author: Beau Schwabe                   *
    ''*  Copyright (c) 2009 Parallax, Inc.      *               
    ''*  See end of file for terms of use.      *               
    ''*******************************************
    Schematic for Each LED (aka FireFly):
         330
    I/O ──── GND 
             LED
    LED = Yellow or Green         
    
    }}  
    
    CON
      _clkmode      = xtal1 + pll16x
      _xinfreq      = 5_000_000
    Number_of_Flies = 32
    OBJ
    PWM     :       "PWM_32_v1.spin"
    
    VAR
    byte    fly,i[noparse][[/noparse]Number_of_Flies],s[noparse][[/noparse]Number_of_Flies]
    long    random,w[noparse][[/noparse]Number_of_Flies]
    PUB MainLoop|t1
        LightTest
        random := $1234_5678
    ''-------- This Block Starts the PWM Object ----------
        PWM.Start                   '' Initialize PWM cog
        repeat fly from 0 to Number_of_Flies-1
          s[noparse][[/noparse]fly]++ 
          i[noparse][[/noparse]fly] := fly * 3
        repeat
          repeat fly from 0 to Number_of_Flies-1
            if w[noparse][[/noparse]fly] <> 0
               w[noparse][[/noparse]fly] -= 1
            else    
               i[noparse][[/noparse]fly] += s[noparse][[/noparse]fly]
               if i[noparse][[/noparse]fly] == 100
                  s[noparse][[/noparse]fly] := -1
               if i[noparse][[/noparse]fly] == 0
                  s[noparse][[/noparse]fly] := +1
           
               if i[noparse][[/noparse]fly] == 0
                  w[noparse][[/noparse]fly] := 200+((?random & $FF)*3000)/$FF
              
               PWM.Duty(fly,i[noparse][[/noparse]fly],10000)              
          waitcnt(clkfreq/600+cnt)
    PUB LightTest|_i
    '' Light test ALL blink
        repeat 3
          repeat _i from 0 to Number_of_Flies-1
            dira[noparse][[/noparse]_i]~~
            outa[noparse][[/noparse]_i]~~
            waitcnt(clkfreq/15+cnt)
          repeat _i from 0 to Number_of_Flies-1
            dira[noparse][[/noparse]_i]~
            outa[noparse][[/noparse]_i]~
            waitcnt(clkfreq/15+cnt)
        
    CON
    {{
    &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
    &#9474;                                                   TERMS OF USE: MIT License                                                  &#9474;
    &#9500;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9508;
    &#9474;Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation    &#9474;
    &#9474;files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,    &#9474;
    &#9474;modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software&#9474;
    &#9474;is furnished to do so, subject to the following conditions:                                                                   &#9474;
    &#9474;                                                                                                                              &#9474;
    &#9474;The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.&#9474;
    &#9474;                                                                                                                              &#9474;
    &#9474;THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE          &#9474;
    &#9474;WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR         &#9474;
    &#9474;COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,   &#9474;
    &#9474;ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                         &#9474;
    &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
    }}
    
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Beau Schwabe

    IC Layout Engineer
    Parallax, Inc.

    Post Edited (Beau Schwabe (Parallax)) : 6/15/2009 7:12:17 PM GMT
    2592 x 3456 - 1M
  • Timothy D. SwieterTimothy D. Swieter Posts: 1,613
    edited 2009-08-02 07:10
    Beau -

    First - thank you for the object.

    I am using the object, specifically the PWM function. During my testing I wonder if I found a bug. Can you check me here?

    My code is a simple call to the PWM method. This is just test code at the moment, so nothing else fancy happening. A byte variable will replace the temporary t0. The thought is 0 is off and 255 is full intensity of the LED.
      t0 := 200
    
      'Update the LED intensity
      PWM.PWM(_LED_0, t0, (255 - t0))  
    
    



    I think this will work based on the following of the PWM object:
    PUB PWM(Pin,OnTime,OffTime)                    '' Pin = 0 to 31
        If OnTime == 0                             '' An OnTime value of 0 forces a 0% Duty Cycle
           DutyMode(Pin,1)                         '' An OffTime value of 0 forces a 100% Duty Cycle
        If OffTime == 0                            '' If OnTime & OffTime are both 0 then the pin is
           DutyMode(Pin,2)                         '' disabled.
        If OnTime ==0 and OffTime == 0
           StateMode(Pin,0)  
    
    



    The bug, I think, is that when t0 is 0 in my code, the LED is on/100% duty cycle and I think it should be off. Similarly, when t0 is 255 the LED is off, 0% duty cycle and it should be on.

    Based on the comments in the below function, I think the "1" and "2" are swapped in the PUB PWM above for the zero testing of the on/off time.
    PUB DutyMode(Pin,Mode)                         '' Pin = 0 to 31
        ARG0    := Pin                             '' If Duty = 0 then the pin is in it's default state
        ARG1    := Mode                            '' If Duty = 1 then the pin is forced HIGH ; 100%
        command := DutyOverRide                    '' If Duty = 2 then the pin is forced LOW  ; 0%
        repeat until command == 0
    
    



    Bug, miswritten comments, problem with my understanding?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Timothy D. Swieter, E.I.
    www.brilldea.com - Prop Blade, LED Painter, RGB LEDs, 3.0" LCD Composite video display, eProto for SunSPOT
    www.tdswieter.com

    Post Edited (Timothy D. Swieter) : 8/2/2009 7:18:04 AM GMT
  • Timothy D. SwieterTimothy D. Swieter Posts: 1,613
    edited 2009-08-02 07:34
    Did some more testing. Perhaps I have another bug or misunderstanding.

    First, after my previous post I noticed that the Duty method "1" and "2" of the Duty method set as I suspect they should be, which is opposite the PWM method which makes me think the PWM method is wrong int he PWM_32_v1 object.

    Ok - the other potential bug. I created a simple program to use the object, the code is as follows:
    con
      _clkmode = xtal1 + pll16x     'Use the PLL to multiple the external clock by 16
      _xinfreq = 5_000_000          'An external clock of 5MHz. is used (80MHz. operation)
    
    obj
      PWM           : "PWM_32_v1.spin"
    pub main | t0
    
      PWM.Start
      
      repeat
        repeat t0 from 0 to 255
          PWM.PWM(20, t0, (255 - t0))
          PauseMSec(10)
    
        repeat t0 from 255 to 0
          PWM.PWM(20, t0, (255 - t0))
          PauseMSec(10)     
    
    PRI PauseMSec(Duration)
      
      waitcnt(((clkfreq / 1_000 * Duration - 3932) #> 381) + cnt)
        
      return
    
    



    When the above code executes, the LEDs is stuck on or off (depending on what way the PWM method is setup). I expected this routine to be cycling the LED to full brightness and then back down to off, repeating indefinitely. It appears that perhaps the duty on/off times are set by the first pass of the repeat loop, when t0 = 0, but then no duty on/off times are set after that. Maybe the PWM is a set it and forget it function, but keeps that same on/off times?

    I can get the Duty method working with the ramp up/down:
      repeat    
        repeat t0 from 0 to 100
          PWM.Duty(20, t0, 5000)
          PauseMSec(20)
    
        repeat t0 from 100 to 0
          PWM.Duty(20, t0, 5000)
          PauseMSec(10)
    
    



    With the Duty method as it currently written it is 0 to 100%. I am working with bytes, not percentages, so I would like to be able to set the range of values or perhaps use the PWM as I described in the other post, but my ideas are not working yet. What do you think regarding the two potential bugs/pitfalls? Should I use duty and covert bytes to a percentage?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Timothy D. Swieter, E.I.
    www.brilldea.com - Prop Blade, LED Painter, RGB LEDs, 3.0" LCD Composite video display, eProto for SunSPOT
    www.tdswieter.com
  • Timothy D. SwieterTimothy D. Swieter Posts: 1,613
    edited 2009-08-02 07:35
    Oh - would love to see the firefly video if you got one to post from your VBS.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Timothy D. Swieter, E.I.
    www.brilldea.com - Prop Blade, LED Painter, RGB LEDs, 3.0" LCD Composite video display, eProto for SunSPOT
    www.tdswieter.com
  • Timothy D. SwieterTimothy D. Swieter Posts: 1,613
    edited 2009-08-06 13:33
    A little bump and a little update. Beau and I had a conversation offline. He is out on holiday and will double check my findings and investigate further when he returns.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Timothy D. Swieter, E.I.
    www.brilldea.com - Prop Blade, LED Painter, RGB LEDs, 3.0" LCD Composite video display, eProto for SunSPOT
    www.tdswieter.com
  • Beau SchwabeBeau Schwabe Posts: 6,568
    edited 2009-08-07 03:17
    Timothy,

    Good Job for finding the errors! I have updated the OBEX and the errors you were observing should be fixed now.

    Revision History:
    Version 1.0 - (05/01/2009) initial release
    Version 2.0 - (08/06/2009) bug/error fix:
    1)Time on/off mode swapped in PWM function
    2)locked I/O states when returning from 0% or 100% Duty Cycle modes
    to 'normal' 1% to 99% Duty Cycle modes.


    BTW) I would have video of the fireflies, but my camera doesn't do it justice in the dark ... you can run the FireFly Program on the Propeller Demo Board and get an idea (after a small initialization routine) of what it does.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Beau Schwabe

    IC Layout Engineer
    Parallax, Inc.
  • Timothy D. SwieterTimothy D. Swieter Posts: 1,613
    edited 2009-08-07 12:17
    Thanks Beau! I just tested the Version 2 of the object and the PWM function is now behaving as expected.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Timothy D. Swieter, E.I.
    www.brilldea.com - Prop Blade, LED Painter, RGB LEDs, 3.0" LCD Composite video display, eProto for SunSPOT
    www.tdswieter.com
Sign In or Register to comment.