How to use counters for controlling discrete RGB Led (common anode)
twm47099
Posts: 867
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
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
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
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?
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
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
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.