Shop OBEX P1 Docs P2 Docs Learn Events
How to use counters for controlling discrete RGB Led (common anode) — Parallax Forums

How to use counters for controlling discrete RGB Led (common anode)

twm47099twm47099 Posts: 867
edited 2014-02-20 09:51 in Propeller 1
The last time I was at Radio Shack I bought an RGB Led. After I got home I went on the RS website and found the data sheet for it, and found out that it was a common anode Led. I connected it to my QS board with the intent of using counters in duty cycle mode to control the intensity of each primary color and get a wide range of colors depending on how I set frqa. I think I know how to do this if the Led was a common cathode device the way I control the intensity of the blue Leds on the QS board.

I thought that with a common anode Led, increasing the off time of the duty cycle would increase the intensity of the Led. But I don't get any response from the Led. I also tried NCO mode with phsa set to very low (and high values, and mid values). Same result.

I can turn each color on by setting dira(pin#)~~ and using outa(pin#)~ and off with outa(pin#)~~ . By setting delays after the on and off, I can adjust the colors, but I would rather use the counters (if possible).

I am going to try to get a common cathode Led (if for no other reason than I prefer 'high' = 'on'), but would like to know if anyone has a suggestion or experience with using common anode rgb Leds with counters to control them.

The code below is in pfth, but it is pretty well commented. The word 'gocounter' is the body of the code to turn on the red led. Everything above that are just the definitions that I've written for using counters, and I've used them with single color Leds, and servos. I've only included it because 'gocounter' calls them and it would be more confusing w/o them.

By the way, I'm not wedded to forth for this. Spin or C would be fine also. It's just that I'm at a lower point in the learning curve with those.

Thanks
Tom
[SIZE=2][FONT=arial]hex
( Registers )

: ctra@ 1f8 cog@ ;
: ctra! 1f8 cog! ;
: ctrb@ 1f9 cog@ ;
: ctrb! 1f9 cog! ;
: frqa@ 1fa cog@ ;
: frqa! 1fa cog! ;
: frqb@ 1fb cog@ ;
: frqb! 1fb cog! ;
: phsa@ 1fc cog@ ;
: phsa! 1fc cog! ;
: phsb@ 1fd cog@ ;
: phsb! 1fd cog! ;

1000000 constant scale256 ( for calc of freq duty cycle )
1000 constant pinmask12
0ff0000 constant pinmask16-23
0ffffffc0 constant 0apin
0ffff81ff constant 0bpin
0fc7fffff constant 0plldiv

\ --------------
decimal

2 constant ctrpllse        \ CTRx mode: PLL single ended (+1 = differential)
4 constant ctrncose        \ CTRx mode: NCO single ended (+1 = differential)
6 constant ctrdutyse       \ CTRx mode: Dutycycle single ended (+1 = differential)

variable ctrcmd   ( counter command )   


: clrctrcmd  0 ctrcmd ! ;           ( clear ctrcmd )

: setctrmode  ( mode# -- ) 
   26 lshift ctrcmd @ or ctrcmd ! ;

: setplldiv ( n -- )
   23 lshift ctrcmd @ or ctrcmd ! ;

: setctrapin ( apin# -- )
   ctrcmd @ or ctrcmd ! ;

: setctrbpin ( bpin# -- )
   9 lshift ctrcmd @ or ctrcmd ! ;

: ldctra ( --  )  ctrcmd @ ctra! ;    

: ldctrb ( --  )  ctrcmd @ ctrb! ;    


: duty>frq  ( duty -- )  scale256 * ;

: xctra  0 ctra! ;  ( stop ctra – does not clr ctrcmd )    

: xctrb  0 ctrb! ; ( stop ctrb – does not clr ctrcmd )   

: clrapin ctrcmd @ 0apin and ctrcmd ! ;  ( zero out the apin bits )

: clrbpin ctrcmd @ 0bpin and ctrcmd ! ;  ( zero out the bpin bits )

: clrpll ctrcmd @ 0plldiv and ctrcmd ! ;  ( zero out the plldiv bits )


\ Start counter turn on the RGB red Led (P12), 
\  For the QuickStart Board Leds with 220 ohm current limiting resistors
\  frqa has to be > x80F00000 ( d 2,163,212,288 )
\   'duty' needs to be > x88 to xFF i.e. decimal 136 to 255. 
\  For common anode RGB Led, using lower values should turn it on try d 50 

: gocounter  ( turn on pin 12 [red] using ctra  )
   clrctrcmd
   ctrdutyse setctrmode
   12 setctrapin
   ldctra
   50 duty>frq frqa!        \ duty cycle = 50/255 = .20
   pinmask12 dirasetbit 
;[/FONT][/SIZE]

Comments

  • Tracy AllenTracy Allen Posts: 6,664
    edited 2014-02-19 08:03
    It should work. Did you make the led pins outputs? In Spin, that would be the dira[] command, e.g.,
    [SIZE=1][FONT=courier new]PUB RgbTest  ' common anode rgb
     dira[REDPIN..BLUPIN] := %111    ' LED pins are outputs
     outa[BLUPIN] := 1  ' blue is off
     ctra := %0_00110 <<  26 | REDPIN  ' duty mode a
     ctrb := %0_00110 << 26 | GRNPIN  ' duty mode b  
     frqa := $8000_0000    ' 1/2 intensity red
     frqb := $C000_0000   '  1/4 intensity green[/FONT][/SIZE] 
    
    Two counters per cog, can modulate two of the LEDs, with the third either full on or full off. That is, without getting fancy.
  • twm47099twm47099 Posts: 867
    edited 2014-02-19 09:55
    It should work. Did you make the led pins outputs? In Spin, that would be the dira[] command, e.g.,
    [SIZE=1][FONT=courier new]PUB RgbTest  ' common anode rgb
     dira[REDPIN..BLUPIN] := %111    ' LED pins are outputs
     outa[BLUPIN] := 1  ' blue is off
     ctra := %0_00110 <<  26 | REDPIN  ' duty mode a
     ctrb := %0_00110 << 26 | GRNPIN  ' duty mode b  
     frqa := $8000_0000    ' 1/2 intensity red
     frqb := $C000_0000   '  1/4 intensity green[/FONT][/SIZE] 
    
    Two counters per cog, can modulate two of the LEDs, with the third either full on or full off. That is, without getting fancy.

    Thanks for the information. The last line of my code 'pinmask12 dirasetbit' is the equivalent of Spin dira[12]~~ (I was testing one lead at a time).

    I will try your spin code this evening, It looks straightforward.

    Thanks
    Tom
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2014-02-19 12:38
    Noticing your position lower on the Spin learning curve, here is a complete Spin program to replace the snippet:
    [SIZE=1][FONT=courier new]CON
      _clkmode = xtal1 + pll8x
      _xinfreq = 5_000_000
    
      REDPIN = 13                   ' cathodes on three sequential pins
      GRNPIN = 14
      BLUPIN = 15
    
    PUB RgbTest  ' common anode rgb
     dira[REDPIN..BLUPIN] := %111    ' LED pins are outputs
     outa[BLUPIN] := 1  ' blue is off
     ctra := %0_00110 <<  26 | REDPIN  ' duty mode a
     ctrb := %0_00110 << 26 | GRNPIN  ' duty mode b
     frqa := $8000_0000               ' 1/2 intensity red
     frqb := $c000_0000               '  1/4 intensity green
     repeat                           ' keep alive[/FONT][/SIZE]  
    

    Also attached is a more compete object that includes a demo. First steps through red, green, blue, "white", off, and then a random pattern of color mixing. This uses a trick to address the cog counters as spr[.], special purpose registers, a trick Kuroneko showed earlier this week in Blinking-led-with-counter?
  • twm47099twm47099 Posts: 867
    edited 2014-02-19 18:48
    Tracy,
    Thanks for your help. The spin programs worked as advertised, and I was able to rewrite the first one into pfth. I have to compare the code that works with my original, but I found out that the RGB Led is very sensitive to the values used in frqa and frqb. That may be because I am using 220 ohm current limiting resistors. I will try lower and higher values to see if it makes any difference.

    I appreciate the spin program you attached. It has some complexity so studying it will be useful.

    Thanks again
    Tom
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2014-02-19 22:55
    Tom,

    You're much higher on the Spin curve than I am on the Forth curve!

    Visual response to light is logarithmic, the eye response to color favors green, and RGB leds vary in efficiency. You have to balance all those factors to find your pleasing results. Maybe write balancing factors into the program. My board too has 220Ω resistors in series with each LED.
  • twm47099twm47099 Posts: 867
    edited 2014-02-20 06:32
    Tom,

    You're much higher on the Spin curve than I am on the Forth curve!

    Visual response to light is logarithmic, the eye response to color favors green, and RGB leds vary in efficiency. You have to balance all those factors to find your pleasing results. Maybe write balancing factors into the program. My board too has 220Ω resistors in series with each LED.

    I did a quick check last night to find the range of frqx values where each color was visible. (One thing nice about forth is once I got the counters running, I was able to define "fa" as :fa frqa! ; and then from the command line just enter a value <space> fa <ret> to check values quickly.)

    My results were (with the 220 ohm resistors):

    Red: Just visible = xff00_0000 to bright with no further change = x2000_0000
    Green: x7f00_0000 to x1000_0000
    Blue: x7e00_0000 to 1000_0000

    There are a couple of things I will try. First, I simply took the min and max for each color, subtracted them and calculated the value for 10% of the range. The intent was to have a 10 step brightness range where I could adjust brightness by entering a value from 1 to 10. However, since you enlightened me about the log nature of response to light, I'm not sure how a linear relation will work.

    The second thing I'm going to do is to use a lower value resistor for the green and blue leds to try to get a better balance between them and the red. The Radio Shack data sheet didn't have recommended resistor values, but other brand sheets recommended about 1 to 1.8 ratio for blue and green compared to red.

    One other issue I'm seeing, is that the Led I'm using does not blend red very well with blue and green (which blend very well). The red is significantly off to the side of the Led. I'm wondering if there is a better source for rgb Leds?

    Thanks
    Tom
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2014-02-20 09:51
    A clear or translucent diffuser over the LED can mix the colors well.

    As for the logarithmic dependence, in another program I used a function like the following to achieve 7 discrete levels from 0 (off) to 7 (on)

    frqx := |< level << 24 - 1

    The |< operator is essentially a power of two exponential. So for levels 7 and 1 respectively, |< level is equal to $100 and $2, and shift left 24... $0000_0000 and $0200_0000, and subtract 1... $FFFF_FFFF and $01FF_FFFF. The 7 levels are thus powers of two rather than linear. Level zero can be forced to zero rather than to $FF_FFFF.
Sign In or Register to comment.