]> oss.titaniummirror.com Git - oss-web.git/commitdiff
Add pages describing the rgblamp project
authorR. Steve McKown <rsmckown@gmail.com>
Sat, 24 Mar 2012 23:10:36 +0000 (17:10 -0600)
committerR. Steve McKown <rsmckown@gmail.com>
Sun, 25 Mar 2012 03:59:08 +0000 (21:59 -0600)
in/rgblamp.md [new file with mode: 0644]
in/rgblamp/code.md [new file with mode: 0644]
in/rgblamp/features.md [new file with mode: 0644]
in/rgblamp/leds.md [new file with mode: 0644]
in/rgblamp/mechanical.md [new file with mode: 0644]
in/rgblamp/random.md [new file with mode: 0644]
in/rgblamp/task.md [new file with mode: 0644]
in/rgblamp/timer.md [new file with mode: 0644]

diff --git a/in/rgblamp.md b/in/rgblamp.md
new file mode 100644 (file)
index 0000000..4b6ac06
--- /dev/null
@@ -0,0 +1,20 @@
+title: RGB Lamp
+linktitle: rgblamp
+parent: Home
+ctime: 2012-03-24
+
+The RGB Lamp was a little filler project.  A 4.2W CREE RGBW LED module is driven
+by a PIC16LF1933.  Learn more:
+
+* [[Code Notes|rgb-code]]
+* [[Features|rgb-features]]
+* [[Mechanical|rgb-mechanical]]
+* [Source Code](/gitweb/?p=rgblamp.git;a=summary)
+
+A future implementation might accept audio input from a stereo jack or onboard
+microphone, use a DFT to examine the frequency components present in the audio
+stream, represent each of several bands of frequencies with a color whose
+brightness is proportional to the signal strength, then 'mix' the per-frequency
+color results into an RGBW output that can drive the LED module.  Because of the
+higher performance needed, we will probably use a STMicro STM32 or EnergyMicro
+EFM32 low power ARM Cortex-M3 processor.
diff --git a/in/rgblamp/code.md b/in/rgblamp/code.md
new file mode 100644 (file)
index 0000000..b6086f0
--- /dev/null
@@ -0,0 +1,29 @@
+title: RGB Lamp Code
+linktitle: rgb-code
+parent: rgblamp
+ctime: 2012-03-24
+
+PIC code for the [[rgblamp]] is written in C and compiled using the MPLAB X
+cross-platform IDE and the HI-TECH C compiler.
+
+The lamp code uses a simple event driven strategy.  Events are generally
+initiated through hardware events.  Application logic is structured as a set of
+tasks, each of which is executed in response to a given event.  Because much of
+the behavior of the lamp application is dependent upon timing, a timer
+abstraction is also useful.
+
+So, this code uses both of these useful abstractions: tasks and timers.  This
+project hacks together some basic support for tasks and timers for the PIC16.
+Thankfully the atypical architecture of the PIC16 is mostly abstracted by the C
+compiler.  And because this is such a simple project, the simplistic interrupt
+handling of the PIC16 is not an issue either.  And although not very flexible in
+its use, driving Timer 1 via a 32 kHz crystal offers reasonable support for
+auto-on from soft off.
+
+* [[rgb-task]]
+* [[rgb-timer]]
+
+The project yielded some other other novel tidbits.
+
+* [[rgb-leds]]
+* [[rgb-random]]
diff --git a/in/rgblamp/features.md b/in/rgblamp/features.md
new file mode 100644 (file)
index 0000000..81a9a80
--- /dev/null
@@ -0,0 +1,36 @@
+title: RGB Lamp Features
+linktitle: rgb-features
+parent: rgblamp
+ctime: 2012-03-24
+
+# [[rgblamp]] features
+
+* Auto power cycling, 5 hours on, 19 hours off.
+* Brightness level adjustment
+* Twelve colors, which include white and a simulated candle color
+* Several modes: random color change, slow color change, and fixed color
+* Simulated candle flicker for all colors except for white
+* Persistent state configuration
+
+# The power switch
+
+The power switch has three positions: off, on, and auto.  When the switch
+position changes to auto, a timer is started that turns off the lamp in five
+hours, then back on again nineteen hours later.
+
+# The push button
+
+When the pushbutton is depressed briefly, then released, the lamp color mode is
+changed.  Modes cycle through all twelve color modes, the first of which is the
+candle simulation and the last of which is white.  The mode immediately
+following white is the slow color change mode, which itself cycles through the
+colors every sixteen minutes.  The next and final mode is a rapid and random
+color change mode (party mode).  A mode change when in party mode returns to the
+first mode.
+
+When the pushbutton is depressed and held, brightness varies until the
+pushbutton is released.  Brightness is dimmed until a minimum brightness is
+reached.  After a short delay at the minimum brightness, brightness is
+then increased over time until a maximum brightness is reached.  After a short
+delay at the maximum brightness, the process repeats.  Once the pushbutton is
+released, the brightness setting at that point is retained persistently.
diff --git a/in/rgblamp/leds.md b/in/rgblamp/leds.md
new file mode 100644 (file)
index 0000000..385b4f3
--- /dev/null
@@ -0,0 +1,58 @@
+title: RGB Lamp Led Driver
+linktitle: rgb-leds
+parent: rgb-code
+ctime: 2012-03-24
+
+# PWM drive
+
+The LEDs in the module receive varying current to adjust their brightness via
+the hardware PWM features of the PIC16LF1933 in conjunction with Timer 2.  The
+module has 4 capture/compare peripherals, which is perfect for the 4 LEDs in the
+module.
+
+Each PWM output controls a simple current limited 2-transister drive circuit.
+This circuit is superior to a simple single transistor switch, as the CE
+junction of one transistor is used as a fixed voltage drop controlling current
+through a resistor of known size.  This is particularly nice given that
+different LED modules have differnt voltage drops, and voltage drop is also a
+function of current and temperature.  A fixed current driver removes these
+variables.
+
+# Mixing color and brightness
+
+An interesting challenge is to manipulate the output of the discrete color LEDs
+both for the purpose of emitting a specific color and for controlling the
+brightness.  The solution is to treat the pre-computed PWM output value as a
+fraction of the maximum value (255).  In the same fashion, the color range and
+the brightness are also treated as a fraction of their respective maximums.
+Therefore, the rgb drive output is essentially the product of the color and
+brightness values.  Simple, and it seems to work out pretty well.
+
+    rgb = 255 * (color/color_max * bright/bright_max)
+
+Of course, for this processor the preference is to do this computation in
+integer math.  The actual implementation looks more like this:
+
+    color: 0..63
+    bright: 0..BRIGHT_MAX
+    rgb = (color << 4) * bright / 4 / BRIGHT_MAX
+
+# LEDs
+
+An interesting effect was uncovered during testing.  A certain delta change in
+drive string of a LED at a relatively low average power level is readily
+perceptible vsually, while the same delta is hard to detect at higher power
+levels.  Some research shows this to be a nature of the human eye -- it
+perceives changes at lower intensities more readily than at higher percentages
+[(1)](http://neuroelec.com/2011/04/led-brightness-to-your-eye-gamma-correction-no/).
+To get a perceived linear output, the PWM value must be adjusted according to
+CIE Lightness.
+
+    L* = 116(Y/Yn)^1/3 - 16 , Y/Yn > 0.008856
+    L* = 903.3(Y/Yn), Y/Yn <= 0.008856
+
+Using these formulas, a look-up table can be created to provide the
+compensation.  It works pretty well.  The rgb.c and rgb.h files in the
+[repository](http://oss/gitweb?p=rgblamp.git;a=summary) implement this feature.
+Note that there are two different look-up tables available, depending upon the
+resolution desired.
diff --git a/in/rgblamp/mechanical.md b/in/rgblamp/mechanical.md
new file mode 100644 (file)
index 0000000..88653ed
--- /dev/null
@@ -0,0 +1,53 @@
+title: RGB Lamp Features
+linktitle: rgb-mechanical
+parent: rgblamp
+ctime: 2012-03-24
+
+The [[rgblamp]] mechanicals are based on a little rectangular lamp purchased at
+IKEA.  The CREE LED module is placed on a 1/2 inch think heat sink designed for
+the module, and that module is mounted inside the lamp in place of the standard
+screw bulb mount.
+
+There are several challenges with this design.  First, the LED module must not
+exceed its thermal specs during operation.  Second, the lamp must not expose
+human eyes to the direct output of the LED module.  Finally, we need to find a
+way to mount both the module and the electronics.
+
+# Thermal issues
+
+The
+[datasheet](http://media.digikey.com/PDF/Data%20Sheets/Wakefield%20Thermal%20PDFs/882_Series.pdf)
+for the 0.5 inch thick [heat
+sink](http://search.digikey.com/us/en/products/882-50AB/345-1104-ND/2640527)
+specifies a 60 degree C rise in temperature when dissipating 9W with natural
+convection.  That is 60/9 or 6.67 C/W.  Since the [CREE LED
+module](http://search.digikey.com/us/en/products/MCE4CT-A2-RGBCW-STAR-IND/955-1043-ND/2357817)
+will be limited to 350 mA at about 3.2 V by the control circuitry, maximum power
+dissipation is 1.12 W per LED, or 4.48 W for the entire module.  In ambient air,
+the 0.5 inch heatsink will see a rise over ambient of about 30 degrees Celcius.
+So if room temperature is 30 C (86 F), the temperature and the juntion beween
+the module and the heatsink should be about 60 C.  I failed to locate a maximum
+junction temperature for this module, but 60 C is not too high for most other
+LEDs out there.  To ensure good thermal contact, the module was secured to the
+heat sink with machine screws and a bit of thermal paste.
+
+In operation, the lamp when tested in operation suggests the heat sink is
+actually performing a bit better than the data sheet numbers suggest.
+
+# Eye protection
+
+The problem with the IKEA lamp used is that it is open through the top.  This is
+an advantage thermally because the lamp acts like a chimney, allowing cool air
+to enter through the opening in the bottom -- which was left open for
+ventilation purposes -- and warmer air to rise out of the top.  The downside is that a
+person could easily look into the lamp from above.  These high power modules can
+cause retinal damage, so this is a problem.  The solution was to mount a few
+inches above the LED module a diffuser.  The diffuesr spreads the light nicely
+while also blocking direct visual exposure of the module LEDs.
+
+# Mechanical mounting notes
+
+This was a quick project, so the mechanicals are of the basic prototype variety.
+The electronics are mounted on perfboard in a small project box, and a short
+section of 28 AWG cat 5e cable delivers current to the LED module. A DC wall
+wart is used for power, and the heat sink is mounted in the lamp with hot glue.
diff --git a/in/rgblamp/random.md b/in/rgblamp/random.md
new file mode 100644 (file)
index 0000000..3a26df2
--- /dev/null
@@ -0,0 +1,21 @@
+title: A Source of Randomness
+linktitle: rgb-random
+parent: rgb-code
+ctime: 2012-03-24
+
+# Randomness
+
+The lamp implements a 'party' mode, which randomizes the next color and the time
+for which that color will be displayed before the next color change.  The code
+uses an efficient parallel bit implementation of a Galois linear shift register.
+However, unless a random seed value can be acquired, the sequence will be the
+same each and every time.
+
+# Truly random
+
+The PIC16 has no PRNG (pseudo-random number generator).  An approach to
+simulating a PRNG is to use the ADC to capture from an unused pin.  The
+assumption is that noise present in the last least significant bit or so of the
+result can be summed to generate a pseudo-random number.  No testing was done to
+attempt to quantify the quality of this methodology, but it certainly provides
+some amount of randomness and is adequate for the simple needs of this project.
diff --git a/in/rgblamp/task.md b/in/rgblamp/task.md
new file mode 100644 (file)
index 0000000..30759f2
--- /dev/null
@@ -0,0 +1,64 @@
+title: RGB Lamp Tasks
+linktitle: rgb-task
+parent: rgb-code
+ctime: 2012-03-24
+
+# Tasks
+
+A task implements an application behavior in response to an event.  Tasks are
+executed to completion without pre-emption.  Task start requests are queued if
+another task is already executing.  A task start request when that task is
+already queued to start is effectively a null operation.  However, a task start
+request for a task that is not queued but currently running will queue the task
+for a subsequent execution.  This very simple task design is more than
+sufficient for the needs of the lamp application.
+
+One key decision under such a task architecture is which task to run next if
+multiple tasks are queued.  This code selects the task with the highest priority
+in such a case.  Application code must be cognizant of this fact, as a
+perpetually queueing high priority task will prevent execution of a queued lower
+priority task.  This behavior is similar to hardware interrupt dispatch in many
+processor architectures, so most developers should already be familiar with its
+pitfalls.
+
+# Task implementation
+
+Tasks are implemented in the task.c, task.h and task_defs.h files,
+as found in the [repository](http://oss/gitweb?p=rgblamp.git;a=summary).
+
+Task identifiers are defind in the task_defs.h file.  Each task id is an
+enumeration, with the highest priority task given the value of zero, and
+successively lower priority tasks having incrementally larger numbers.  Since
+the task queue is implemented as bits in a variable, the width of the task_id_t
+structure defines the maximum number of supported tasks.
+
+Before using, initialize the task subsystem:
+
+    task_init();
+
+To queue a task for execution, post it.  Tasks can be posted from within an ISR
+or from without.  A task can post itself as well.
+
+    task_post(TASK_ID);
+
+Task dispatch is constructed from the task_get() function, which atomically gets
+and clears the next task (bit).  The user application code then constructs a
+switch statement or similar structure to call a function associated with each
+task id.    The lamp code implements this behavior in the user_tasks() function
+in main.c.  Check it out in the
+[repository](http://oss/gitweb?p=rgblamp.git;a=summary).  A short version:
+
+    void user_tasks(unsigned char block)
+    {
+      task_id_t tid;
+
+      while ((tid = task_get(block)) >= 0) {
+        switch (tid) {
+          case TASK_BTN_PB:
+            pb_task();
+            break;
+          ...
+        }
+      }
+    }
+
diff --git a/in/rgblamp/timer.md b/in/rgblamp/timer.md
new file mode 100644 (file)
index 0000000..b851a20
--- /dev/null
@@ -0,0 +1,50 @@
+title: RGB Lamp Timers
+linktitle: rgb-timer
+parent: rgb-code
+ctime: 2012-03-24
+
+# Timers
+
+Most microcontroller applications must respond to temporal events.  The timers
+subsystem allows an application to have multiple timers running concurrently,
+each with a different duration before expiration.  This implementation is very
+simple, in that timers can be started, stoped, and polled for expiration
+(fired).  By integrating with tasks, a timer expiration can post an event.
+
+Timers are identified by a timer id.  A timer started will fire at the end of
+the time period specified in the timer start call.  A timer may also be started
+via startPeriodic(), which will fire the timer periodically according to the
+timer period specified in the call.
+
+# Implementation
+
+The timer subsystem is implemented through the use of the PIC16 TMR0.  It is
+configured to trigger a hardware interrupt every 32.768 milliseconds.  Within
+each interrupt, the status of the currently active timers is updated.  This is a
+very simplistic approach.  A better solution would be to use a timer compare
+feature, which would dramatically reduce the number of ISR events and therefore
+servicing overhead for the timer subsystem.
+
+Periodically the application can poll for timer fired by the tmr_fired() call.
+A good time to do this is in the ISR, and timers that fire can post tasks.  The
+comments in tmr.h gives a complete example.  Check the
+[repository](http://oss/gitweb?p=rgblamp.git;a=summary).
+
+# Timer and low power modes
+
+Unfortunately, the PIC16 has limitations when it comes to using timers in sleep.
+While it is true that Timer 1 can run when the PIC16 is in sleep using an
+external 32 kHz crystal, no timer compare feature is possible in sleep.
+Therefore, the only timer inerrupt that can wake the micro is the overflow.
+This overflow happens every 2 seconds.  In fact, the lamp code uses this
+behavior to handle the long term timer events via the tmr32 module.
+Specifically, this is used for the auto-off and auto-on events.
+
+It is possible to get different overflow periods by programmatically setting the
+Timer 1 register.  Since this is a 16 bit value implemented in 2 8-bit
+registers, there are race conditions that challenge this use.  But the ability
+to support variable timer periods in sleep is possible.
+
+When it comes to managing temporal events and deep sleep, the MSP430, the EFM32,
+and the STM32L are superior processors.
+