Cyber Brows - The Software
If you're interested in learning about Charlieplexing I have an earlier project where I explain it in detail. In this project I used 4 I/O lines to control four banks of three LEDs for a total of 12 LEDs.
In the main loop of the program I turn on each bank of LEDs in turn. Each bank remains on for about 2.5mS. So after 10mS a full 12 LED pattern has been displayed.
Within each bank I can turn LEDs off early if they are supposed to have reduced brightness. The minimum duty cycle for LEDs is 1/128 of the bank duration. Because LEDs have such a non-linear perceived brightness, this is just barely short enough.
Once the four LED banks have been display there is a 2mS I2C communication burst during which I read the X,Y and Z acceleration values. This could be shortened as I use three separate I2C read commands. The MMA8453QT offers a streamlined command that can read all three axis with one read but I opted to keep things simple. Also, the I2C is running at only 100KHz and I suspect 400KHz might work as well, shortening the I2C burst even more.
After the acceleration values are read, the processor increments the display pattern and then the cycle repeats. This entire process runs at about 70 to 80 Hz depending on the type of display.
Running asynchronously is the Timer1 interrupt. This occurs at 61 Hz and is used to detect nods in various directions. Again, the MMA8453QT offers advanced tap and tip detection but I opted to do this in code since my initial attempts to do this 'in-chip' were frustrating.
The patterns are mostly generated by writing gaussian shaped peaks into the display buffer. The position, width and intensity of each peak are specified as parameters. At most I use two peak generators. I then use a signal generator to feed the peak generators. I have saw tooth, ramp, sine wave, and a pseudo random signal that I can apply to the various peek inputs.
To create a Cylon type display, I use a peak generator with its intensity and width fixed, but the position driven by a saw tooth signal that varies from 0 to 100% of the display width.
To create a Gort type display, I use a peak generator with its intensity and position fixed, but the intensity is driven by a sine wave signal that varies from 0 to 100% of the display intensity.
To create a Sparkle type display, I use a peak generator with a narrow, intense peak and feed its position with a pseudo random signal. Coupled with 'fade' (below), a lovely sparkling display results.
In addition I've also added various effects. Normally after each pass, the display buffer is simply emptied and a new pattern is written. To allow for more interesting displays the display buffer can be treated differently.
Setting 'Fade' makes the display fade to dark. If you combine this with a Cylon display, you get a fading ghost behind the sweep.
Setting 'Spread' makes the peaks fade and spread out, like a blur function. Coupled with a slow Sparkle display, this creates seemingly random glowing blobs. Hard to describe.
As I mentioned briefly, LEDs have a very non-linear brightness with regard to PWM. Even at low PWM duty cycles, the LEDs appear quite bright. Once the pattern to display has been calculated, I apply a gamma correction to produce a more linear intensity scale. In practice I use a gamma of three. This is accomplished using a few stored points plus linear interpolation.
I used the free Hi-Tech PIC10/12/16 compiler operating in LITE mode to write all the code. There are still a lot of possible uses for the Cyber Brows but I am constrained by the size of my code. In order to add more features I'd need to buy the Standard version which offers moderate optimizations. In its trial more, the Standard compiler can shrink the code to 75% of its original size. The Pro version does even better but its cost climbs to over a thousand. Such is life.
Nonetheless, the free LITE version works quite well and you can't complain about the price.
--- end ---