Prop C PWM of simple RGB LED
John Kauffman
Posts: 653
I’m having trouble controlling an RGB LED with C and I haven’t gotten a search hit in fora on “RGB Propeller C”
This is not the smart/programmable kind of LED. It is just 3 LEDs in one case with 4 pins (common cathode). I checked the device without Prop control and no problem.
In the library reference I don't understand the purpose of the channel argument: pwm_set(int pin, int channel, int tHigh)
I tried the following code and got result of: blue > bright blue > nothing.
- Thanks.
This is not the smart/programmable kind of LED. It is just 3 LEDs in one case with 4 pins (common cathode). I checked the device without Prop control and no problem.
In the library reference I don't understand the purpose of the channel argument: pwm_set(int pin, int channel, int tHigh)
I tried the following code and got result of: blue > bright blue > nothing.
- Thanks.
/*RGB LED: use PWM to turn on red, green, blue in order 0.5 sec at 50%. what is “channel”?*/ #include "simpletools.h" int pinRed = 0;int pinGreen = 1;int pinBlue = 2; int main(void){ pwm_start(1000); pwm_set(pinRed,1,500) ; pwm_set(pinGreen,1,000) ; pwm_set(pinBlue,1,000) ; pause(500); pwm_set(pinRed,1,000) ; pwm_set(pinGreen,1,500) ; pwm_set(pinBlue,1,100) ; pause(500); pwm_set(pinRed,1,000) ; pwm_set(pinGreen,1,000) ; pwm_set(pinBlue,1,500) ; pause(500); pwm_stop(); return 0; }
Comments
Now it makes sense. The channels are the two timers in the cog.
Changing pinGreen to channel 2 gave me another color.
Can I start two PWM modules to get greater than 2 pins controlled? Perhaps in different cogs?
That being said, IIRC there was something in the Learn forum re: multiple channels ... have to check. Remembered, would the servo library be fast enough/suitable? At least it supports multiple pins but is limited in frequency.
Result is red, off, green, off, blue stays on.
I expected it to be red then ADD green then ADD blue to make white. Any guesses? Thanks.
My next try will be 2 LEDs on D/A pins and third on PWM
I have used Forth (pfth) to control the 3 inputs of an RGB Led using one PWM counter. I turn each assign each Led (R, B, G) pin in turn to the counter with a 3 millisecond delay between each and repeat the loop without any other delays. The 3 ms delay between colors is enough to blend the colors w/o flickering. It works in forth, but you may have to play with that number to get what you want.
I do have to assign different values to the PWM value (the 3rd value in your PWM statement) for each color to balance them. I am using a common anode LED which turns a color on by setting its cathode to Low. That means I have to turn off each color before moving to the next by changing its pin from output to input. In forth I have to interact with each parameter of the counters, but the C library should take care of that for you. I've attached the looping section of my code (there's more code to set the counter to pwm mode, but that's not needed to illustrate how to blend the colors.) Even though it's in forth, you should be able to follow the comments. The 'load intensity' and 'set ctra' commands essentially do the pwm function. The dirasetbit and diraclrbit commands are used to change the respective pin to input (turn off) and output (turn on). You probably don't have to worry about that. rctra, bctra, and gctra are variables that contain everything the counter needs to set the PWM function to the pin. Again, this is taken care of by C's PWM library function.
In my code the routine below is started in a new cog and I adjust the color intensities (rval, bval, and gval on a scale of 0 to 10) in the original cog. That code and the code to start the new cog are not shown. The initial values for rval, bval, and gval are shown in hex (just because it was easier to debug and balance the colors). I don't expect those values (even in decimal) would work in the PWM library function.
Hope this helps
Tom
I tried it in C. The following code works. It just turns on all 3 leds using one PWM channel. It's just an endless loop with each color set to 500 which gives a white light. You should be able to add controls to vary each intensity and stop the loop.
Tom
In the meantime I had tried the low road DIY with 8 possible pulse widths:
I am confused. When I tried my code to cycle separate color (R,B,G) on by itself for a given time by changing the pause to a long time (e.g. 1/2sec), it didn't work. The colors blended (each color did not turn off when I set the pin direction to input). I tried a number of things, for example just switching pin numbers after the half second delay. Since the documentation for pwm says that pins numbers can switched on the fly I expected it to work. It didn't. The colors still blended.
That is an issue with using library functions, it's not always clear what the library function is doing at the lower level - I assume it is setting pin directions.
I finally used a brute force method, stopping pwm and restarting it for each color. That worked. The code below works to cycle R, B, and G at 50% for times given by ton and toff. I think the code I wrote above could be simplified to get rid of the direction statements in the loop.
Tom
It does not mix to make, e.g., purple, right? I don't see a way to do that with that code.
But if you set 'ton' = 6, 'toof' = 1, and play with the 3rd value in the pwm_set function you can blend colors. For example with my common anode Led (low = on, high = off), if I set the 3rd value to 1000 for green (i.e. off), and 0 for both red and blue, I get magenta. With a common cathode Led set green = 0, red and blue to a high value to get magenta.
You do have to play with the values. If I set 'ton' to 10ms or more, I see flickering, but 8ms makes the led brighter. Changing the values in the R,B,G calls to pwm_set will adjust the colors. Subtle changes in values don't have much effect. For example, with my LED if I turn Blue off and set both Green and Red to 0, I get a greenish yellow. To get a pure yellow, I need to increase the green value (make it dimmer) to about 500.
I'm not very happy using the method in that post, because the Led is not as bright as it could be and the range of color adjustments is touchy. By directly manipulating the counters (like in the forth program), I get a much greater range of brightness and color adjustments. However, even with that, it took a lot of fooling around changing the values that contributed to changed intensity to get the constants set so I can get 10 different intensities for each prime color.
Your brute force method may be a better start.
Tom
I wish I knew how to link PASM into C. If I did, I'd use this simple code for rgb handling.
Bad JonnyMac! The code I originally posted was out of my head and not tested -- the code posted now does in fact work (in Spin), and I'm doing as Steve suggests and trying to incorporate it into a C demo.
The RGB LED is a nice little way for students to see results of PWM (and reminds me of my college years spent in discos).
I don't have the skills to write it but am glad to test.
If you include the .spin file in a SimpleIDE project, your spin PASM code will automatically be linked (as binary_filename_dat_start).
This is demonstrated in the Documents/SimpleIDE/Propeller GCC Demos/toggle/pasm_toggle project.
All you need is an interface to the PASM similar to what you would write in SPIN. It's not really complicated. Many demo projects do this.
That limit exists only when using counters; with software PWM quite a lot more is possible.
10 % 4 SETPWM
and that will set P4 to 10% duty cycle, or:
20 % 4 8 SETPWMS
will set P4 through to P8 to 20 %
Jazzed,
1. Where can I find: Documents/SimpleIDE/Propeller GCC Demos/toggle/pasm_toggle project
2. Are you saying that if I write a C program using SimpleIDE (the IDE located at:
https://sites.google.com/site/propellergcc/documentation/simpleide ) that I can include a spin file and that it will automatically be linked? Like I would with #include simpletools.h
Thanks
Tom
I played a bit more with the code and found that for blending colors, the pause(toff) isn't needed, and without it there is more control over the individual colors.
Tom
1. If you have SimpleIDE installed the demo would be in the "Documents" area assuming you have one of those.
If you don't have that, look here: https://code.google.com/p/propsideworkspace/source/browse/#hg%2FPropeller GCC Demos%2Ftoggle%2Fpasm_toggle
2. SimpleIDE (the spinside branch) will link the PASM, that's all. It's been like that since the beginning.
Now that David added the ability to automatically generate and call SPIN from C/C++, the rest of the linking story can be added when I have time.
I've also go to look at Peter's PWM code.
Thanks, I've been using the tutorials on the C learning page and never realized this was in the SimpleIDE. Now I got some more studying to do.
Thanks again
Tom
can you help me understand that note? I'm thinking of PWM_set and PWM_start as the software solution. I'm thinking the D/A chip as the hardware solution. What do you mean by software in your note? Maybe working with ASM instead of a C library?
Thanks.
I've been working through jm_rgb.c and the spin program you posted. I can follow the process (writing one is another story), but I'm not sure about the 'start' function in the C program and have a question.
Is the format of 'binary_rgbled_dat_start[]' specified? (start a binary in the dat section of rgbled.spin ?) or is it your method of keeping things straight. If it's specified, where can I find the explanation? If it is not specified, please explain what is happening.
I appreciate your help.
Tom
I followed Steve's guidance and opened one of the SimpleIDE demos to get the basic structure. Using the PASM Toggle demo as guidance, I muddled through and got things working (in Spin in about 5 minutes, in C about an hour).
My understanding is (please jump in and save me, Steve), that adding rgbled.spin to the project causes the compiler to create an executable module from it; the module is called binary_FILENAME_dat_start. All I did was copy, paste, and modify the start function from the C demo. Note that the Spin file has a start method in it -- but I don't think this is used (by C that is; I did use it to test the code with Spin).
The only reason I jumped into this fracas was to point out that with very little effort (on the PASM side), one could have multiple PWM outputs without resorting to the counters and being limited to two.
Jon,
Thanks. I'm glad you jumped in because having an actual example helps a lot for those of us who are not very experienced with this.
The C Learning tutorials are very detailed in their explanations and how-tos. Extending concepts taught to different sensors and devices is relatively straightforward, but going beyond the specific subjects covered, such as combining C with Spin or PASM, there are not any details on the how tos.
I assume that as time goes on there will be tutorials on more advanced concepts. But for now, asking questions and getting help from you experts (even when you have to use trial and error) are very helpful, particularly when there are examples to study.
My issue is that the Propellor is such an interesting device, that I keep jumping out of sequence with the C and Spin tutorials (and then there's all the different Forths and PASM). For example in the Prop Education Manual there is a section on A-D conversion using a potentiometer. So now, before I've done that section, I thinking about interfacing 3 pots to control the intensity of the 3 Leds in the rgb LED (and maybe use a couple of Xbees to do it remotely). I probably should learn to crawl before entering a marathon.
Thanks again
Tom
Again, I think if you stick to one language until it's very comfortable, translating code from other places will be less daunting.