A story of embedded development on two platforms with similar goals
In late 2013 I was blogging about creating a WS2811/WS2812 RGB LED controller using a PIC18F4520. My work life got fairly busy after Christmas and I dropped the ball on the controller project until recently.
Since picking up the ball, I've taken the PIC project to a point where I have a functional multi-pattern display controller. The controller allows the user to choose from among four light patterns. Each pattern has eight speeds and eight brightness levels. All user selections are accomplished with a standard Sony style infrared remote control.
When I had the PIC controller working to an acceptable level of performance, I turned my attention to the Cypress PSoC 4 Pioneer development kit. Voted by Element 14 members as product of the year for 2013, I figured it merited attention and at $25 CAD purchasing the kit was an inexpensive way to explore a new platform. My preferred way to learn a new technology is to immediately apply it to solve an interesting challenge. For example, when I needed to learn my way around a TI MSP-EXP430F5529 for a course I was teaching, I set about writing code for a persistence of vision demonstration using the 5 blue LEDs in the capacitive touch buttons. The result is shown in the photo below.
This is a time exposure of me swiping the MSP430 board in front of the camera. ELEMENT 14 is formed by flashing the 5 blue LEDs on the development board at a rate appropriate for persistence of human vision. The yellow streak is generated by the always on power LED.
Often when learning a new platform I try to reproduce a challenge I have tackled previously using other technology. Doing so allows me to enter the learning process with established experience that acts like a scaffold I can build upon.
Having recently achieved my goal of getting the PIC18F series to control strings of WS2812 RGB LEDs, I decided to attempt the same challenge with the PSoC4 Pioneer development kit and Cypress's PSoC Creator IDE. After a few evenings and one weekend of effort, I can say I found it very easy to make the PSoC4 generate basic WS2812 bit streams. I'd like to mention that when I bought the PSoC4 Pioneer development kit I also bought a Raspberry Pi and a Beaglebone Black with the intent to apply each platform to the same task - controlling WS2812 LED strings. After exploring the discussion threads about the Raspberry Pi and the Beaglebone (especially influential was my read of Shabz's blog on using the BBB PRU) on Element 14 and a look at available documentation on each, I decided the PSoC 4 was the most familiar and welcoming in terms of the available design tools, documentation, and overall ecosystem architecture. I will, at a later date, dive into the Raspberry Pi and Beaglebone, but probably with the intent to solve a different challenge.
What follows in this post is a description of what I did with the PIC18F to get it to work as a basic lighting controller and then, what I have done so far with the PSoC 4 Pioneer development kit to turn it into a lighting controller.
Getting the PIC controller up to a functional state
As a quick recap, the PIC lighting controller is built on a PIC18F platform I designed some years ago for teaching embedded control to post secondary technology students. I use a PICkit 3 to download firmware. The whole set up is shown in the photograph below.
On the top line of the LCD you see three hex digits that represent the last received IR code from the remote. On the second line you see the user selected delay value and brightness value. The single yellow wire running from the oscilloscope probe down to the bottom right carries the generated data stream from a GPIO pin on the PIC to the data in pin on the LED string.
Code development was accomplished using MELab's PIC Basic Pro 3.0 (PBPX 3.0.7.4 compiler) and Microchip's MPASMX assembler. The target processor is a PIC18F4520 running at 40 MHz (10 MHz external resonator with 4x HSPLL clock multiplier turned on through configuration bits).
A good portion of the coding effort was expended on getting the foundational serial bit timing engine to work. I decided to see if a bit engine could be coded in PIC Basic without use of interrupts or hardware timers, partially because interrupt support in PIC Basic is a little clunky and partly just to see if I could do it. Once the bit timing engine was debugged I worked on writing code for four lighting effects, as follows:
The Electric Rainbow
A pseudo random colour sequence that appears to move along the LED string.
Red-Green cross fade
Alternating red and green LEDs cross fading in intensity. Red decreasing while green is increasing, then the opposite, repeating forever.
White-Blue ribbon
A moving pattern of alternating 25 white LEDs followed by 25 Blue LEDs
Single LED chaser
A single white LED moving from one end of the LED string to the other.
The next stage of code development was to wrap all of this into a user interface where selection of pattern, brightness and speed would be made by pressing buttons on a consumer style TV remote control that generates Sony commands.
Two short video clips show operation of the PIC18F based lighting controller.
Future plans for the PIC18F controller
There are many other light patterns that could be coded; the ones I show here illustrate in general what can be accomplished. My plans for the PIC18F controller include moving the user interface to an Android tablet app using Bluetooth as the interface between the tablet and the PIC18F controller hardware. The hardware I plan to use includes a USB Bluetooth adapter and the FDTI V2DIP2-32 USB host controller, both available from Newark (please note: the links are to the Canadian Newark site). See the photo below showing the FTDI development board, the Bluetooth USB adapter, and the USB programming dongle. I took a one-week on-line class on Basic4Android app development and bought the compiler. I'll be using it to write the app.
What I've done so far with the Cypress PSoC 4 Pioneer
Because the PSoC 4 contains a nice programmable mixed signal hardware resource, I decided to see if I could use digital hardware to offload the bit timing task from the firmware. The approach I took was the first that occurred to me, so it may lack elegance, but it was dead easy to implement and it works. The idea was to design digital hardware that would accept a stream of binary bits and have the hardware convert the bits into correctly timed pulses acceptable to WS2812 RGB LEDs. I selected the 800 kHz timing parameters from the WS2812 spec sheet. The base clock source in my design is 8 MHz which means each WS2812 logic 0 and logic 1 pulse is composed of ten 125 ns segments, some at +5 VDC, others at 0 VDC. A logic 0 pulse starts with three 125 ns segments at +5 V followed by 7 125 ns segments at 0 V. A logic 1 pulse starts with six 125 ns segments at +5 V followed by 4 segments at 0 V.
To achieve the two timing structures for logic 0 and logic 1 I used the Basic_Counter component in PSoC Creator then adjusted its parameters to make it a 4-bit up counter. On the output of this 4-bit counter I attached three 4-bit digital comparators. One detects equality with a value of 9. The output of this comparator is used to reset the 4-bit counter, making it behave as a 0 to 9 decimal counter. This comparator also advances the pseudo random bit generator - more on this element later.
Two other 4-bit digital comparators watch the output of the decimal counter for the values 2 and 5. The 2 comparator is used to mark the end of a logic 0's high time. Counting form 0 to 2 will mark off three 125 ns segments. The 5 comparator is used to mark the end of a logic 1's high time. Counting from 0 to 5 will mark off six 125 ns segments.
A clocked SR latch at the output of the bit timing generator is the final element that forms the output wave shape to drive the WS2812 LED string. At the start of every new bit, the SR latch is set. At a later time, either 3 x 125 ns or 6 x 125 ns, the SR latch is reset by one of the edges emerging from the 2 or 5 comparators. The specific edge that resets the SR latch is determined by the bit value entering a 2:1 multiplexer connected to the two comparator outputs.
In order to avoid having to code a bit pattern generator in firmware, for my initial tests I decided to use the Pseudo Random Sequence (PRS) function in the Creator component library. This component is a fully configurable Linear Feedback Shift Register (LFSR) that can generate short or very long pseudo random bit sequences. Perfect for creating a random color sequence to test my bit timing engine design. Because the LED strings I'm using have 240 LEDs and each LED takes 24 bits to describe a color, I wanted an LFSR that could generate at least 5760 pseudo random bits before repeating. A 13-bit LFSR can generate an 8191 bit sequence, and a 14-bit can generate a 16,383 bit sequence before repeating. I played with both.
The schematic for the bit timing generator logic is shown below.
To allow firmware control of the bit timing generator I added the Data_Out_Enable control bit near the top centre of the schematic. The value of this firmware controlled bit determines if the SR output latch is set regularly by the 800 kHz up counter, or if it remains stuck at logic 0. If this control bit were not available, the color pattern on the LED string would never change. The 240 LEDs in the string would fill with pseudo random values then all following bits would fall off the end of the last LED into the proverbial "bit bucket" (Where does information that falls off the end of digital circuits go?). By inserting logic 0 intervals of at least 50 μs every once in a while I can be assured the string will reset and accept a new pattern of pseudo random values. Timing of the Data_Out_Enable control bit is managed with the following C code.
#include <project.h>
int main()
{
PRS_1_Start(); /*Cypress API function to seed and start the LFSR in the PRS component*/
for(;;)
{
Data_out_Enable_Write(1); /*Cypress API function to write a 1 into the Data_Out_Enable bit. Let the data stream start.*/
CyDelay(500); /*Delay 500 ms. This is way more time than necessary to fill the 240 LEDs with values.*/
Data_out_Enable_Write(0); /*Stop the data stream.*/
CyDelayUs(50); /*Delay 50 us. This is long enough to initiate a reset in the first device.*/
}
}
The video clip below illustrates the behavior generated by the hardware and firmware described above once the two are compiled and downloaded to the Cypress PSoC 4 Pioneer kit.
Finally, here is a screen capture of all the digital signals created by the logic shown above. Compare the Pseudo_rnd_bits trace with the Data_out trace. The logic levels arriving from the Pseudo Random Sequence component are converted into timed pulses by the logic to drive the LED strings. A photo of the Pioneer board with all the logic analyzer connections is also included below.
All the best,
Mark
Top Comments