=================================
Programming a three-button DIODER
=================================

This is a tutorial describing how to hack the IKEA DIODER and how to make it
more awesome by reprogramming the PIC and adding external interfaces.

**Warning**: It seems that IKEA has started selling a new version of the DIODER
that is not compatible with this tutorial; see the section about `device
variants`_ below.

.. figure:: dioderplus.small.png
   :target: ./video/dioder_introduction.ogv

   Click on the image for a `video introduction to the project`__.

.. __: ./video/dioder_introduction.ogv

.. contents::

Intro
=====

DIODER_ is a series of LED stripes and controllers from IKEA_, intended for
bookcase lighting or similar, and it can be modified easily. Its core component
is a PIC16F684, for programming which this article includes an introduction.

The particular variety this is all about is the RGB version of the DIODER that
has a controller with three buttons and a color wheel (the one with four fixed
stripes; this description should work for the version with flexible stripes or
four disks as well). I bought mine for 30€.

.. _DIODER: http://www.ikea.com/us/en/catalog/products/50192365/
.. _IKEA: http://www.ikea.com/

I am aware there are pre-existing "DIODER hacks" (`A "real" Ikea Dioder hack`_,
`Another IKEA DIODER HACK`_). Both of them replace the builtin PIC with another
device, and they refer to a different controller version (the one with a single
button).

.. _`A "real" Ikea Dioder hack`: http://cauldrondevelopment.com/blog/2009/12/29/a-real-ikea-dioder-hack/
.. _`Another IKEA DIODER HACK`: http://www.meirsman.eu/dioder/Another_IKEA_DIODER_HAck.html

In order to follow through the tutorial, you'll need:

* a DIODER
* a soldering station with some tin-solder
* 8 wires, preferably an 8-pin flat band cable
* a multimeter (recommended)
* a PICkit2 programmer
* a computer with

  * sdcc_ (packaged in major Linux distributions; for further introduction see `Micah Carrick's article`_)
  * pk2cmd_ (`Linux pk2cmd installation instructions`_)

.. _sdcc: http://sdcc.sourceforge.net/
.. _pk2cmd: http://www.microchip.com/pickit2/
.. _`Micah Carrick's article`: http://www.micahcarrick.com/pic-c-programming-linux.html
.. _`Linux pk2cmd installation instructions`: http://people.virginia.edu/~ll2bf/docs/nix/pk2cmd.html

Basic soldering and C knowledge are assumed.

Hardware description
====================

Apart from cables and mounting equipment, the DIODER consists of three groups
of devices:

* The hub: white plastic box to which the 12V 5W power adapter is hard-wired.
  Supplies the control device with power and routes its output to four sockets
  on the side.
* The control device: white plastic box with a color dial, a power button
  (central), a fade button (right), and a color change button (left). Connected
  to the hub with a 6-pin plug.
* Four led stripes: plastic cased circuit board stripes with 9 RGB LEDs each.
  Groups of 3 LEDs are in series, with current limiting resistors in place. The
  stripes can be connected to the hub with 4-pin plugs, or daisychanined from
  another powered stripe.

.. figure:: components.small.jpg
   :target: components.jpg

   The hub has its power cord at the back, a LED stripe connected at the right
   side, and the controller at the front. The gray cable is an addition from
   this tutorial.

The control device
------------------

The control device is closed by a snapping mechanism, so some force has to be
applied to open it. (Did I yet say this probably voids your warranty? No? Now
here it is: Once you open that device, your warranty is void, and you're on
your own; neither do I take any responsibility if it fails.)

.. figure:: controller_open_original.small.jpg
   :target: controller_open_original.jpg

   This is what the controller looks like when opened.

The internals are hardly surprising:

* a PIC16F684
* 3 push buttons S1/2/3 (with a pullup resistor R1/2/3 each)
* 3 FDD880 N channel MOSFETs Q1/2/3 (with a resistor R5/6/7 each between its
  gate and the PIC)
* a rotational voltage divider W1 (with another resistor R4 between its middle
  point and the PIC)
* a 78L05 linear voltage regulator N1 for powering the PIC with 5V, with a
  protection diode D1 and stabilising capacitors C1/2/3
* a 6-pin output connector

What's interesting here is the choice of FETs – they are rated about 10A
current according to their `FET data sheet`_ (Figure 5). Given an appropriate
power supply, they could probably drive much more than the four stripes of a
set. The limiting part seems to be the power supply, which would have to be
replaced by a larger one.

.. _`FET data sheet`: http://www.fairchildsemi.com/ds/FD/FDD8880.pdf

Pimping it
==========

Soldering
---------

The PIC16F684 can be programmed in-system -- no component involved breaks when
putting the 12V programming voltage to it. (Programming voltage is connected to
the power button, so don't push any buttons while programming!)

.. figure:: controller_open_original_top.small.png
   :target: controller_open_original_top.svg

   _`Top view of the controller`, with the important solder pads marked.

All the pins required for programming (numbered counter-clockwise, starting at
the corner with the notch:

* pin 1: operating voltage Vdd,
* pin 4: programming voltage Vpp, 
* pin 12: programming clock ISPCLK,
* pin 13: programming data ISPDATA, and
* pin 14: ground Vss
  
) have large pads attached to them, where wires can be soldered on
easily: Put the tip of the soldering iron on the pad and feed the tin to the
pad for a brief moment -- some of it should melt and form a drop covering the
whole or at least some area of the pad. Do the same with the wires (especially
important if they are braid wire), then re-heat the drop on the pad while
putting the wire on top of it; it should sink in and form a good connection.

Pins 8–10 (as well as pins 2 and 6, which I chose to leave unconnected as they
are not that easily accessible) can be used for communication with the outside
world, and are a bit harder to hit as they are not connected anywhere. Solder
wires directly to the pins by covering the wires with tin and bringing them in
contact with the ends of the pins while heating them. Be sure not to heat for
too long, or you might fry the PIC.

.. figure:: controller_open_withcable.small.jpg
   :target: controller_open_withcable.jpg

   With all the wires soldered to the board, it could look like this.

.. admonition:: CHECKPOINT

  Configure your multimeter to connection tester mode ("beeping"), verify its
  operation by connecting the two probe ends (it should beep while they are
  connected), and check that each wire is connected to the respective PIC pin
  and that no two wires are connected.

Testing the programmer
----------------------

For programming, I used a Microchip `PICkit 2`_ programmer and the Linux
version of their `pk2cmd software`_ (unfortunately, there seems not to be a free
alternative, but at least it's gratis and they provide source code). Any other
PIC programmer will do as well, but this is the one I had at hand. Other
programmers will require different software.

Disconnect the DIODER from its power source and connect wires from the DIODER
to your PICkit. The names on the "`Top view of the controller`_" image above
match the ones on the `PICkit connector pinout`_.

.. figure:: controller_open_programming.small.jpg
   :target: controller_open_programming.jpg

   The blue wires connect the PICkit with the plug at the end of the cable to
   the PIC.

As a first step on the computer side, read the configuration register [1]_::

    $ pk2cmd -PPIC16f684 -GC
    Read successfully.
    
    Configuration Memory
    
    000C  
    
    Operation Succeeded

.. [1] The syntax used here is common for UNIX style systems -- lines starting
  with ``$`` are what the user entered, successive lines are program output. On
  a Windows prompt, this would look like ``C:\> pk2cmd /PPIC16f684 /GC``.

This shows that the PIC really talks to us, and the `PIC data sheet`_ (register
12-1, p.100) tells us that the response means that fail-safe clock monitor,
internal external switchover and brownout detection are disabled (the first
``00``); data memory and code protection are enabled, power-up timer and
watchdog are enabled, and the oscillator selection is set to use the internal
clock and keep the clock pins as GPIO pins (``0C``).

.. _`PICkit 2`: http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1406&dDocName=en023805
.. _`pk2cmd software`: http://ww1.microchip.com/downloads/en/DeviceDoc/pk2cmdv1.20LinuxMacSource.tar.gz
.. _`PIC data sheet`: http://ww1.microchip.com/downloads/en/DeviceDoc/41202F-print.pdf

.. admonition:: CHECKPOINT

  The ``000C Operation Succeeded`` indicates that the PICkit2 can talk to the
  PIC. If it fails with ``No PICkit 2 found``, make sure the PICkit2 i
  connected to the computer and that you have sufficient privileges to access
  it (try ``sudo pk2cmd ...``).

  For all other errors, check the wiring; make sure the `PICkit connector
  pinout`_ (from the `Linux pk2cmd installation instructions`_) and the
  connectors on the board (see the `Top view of the controller`_ image) match.

.. _`PICkit connector pinout`: http://people.virginia.edu/~ll2bf/docs/nix/img/pickit2_pinout.png

New software
------------

It is now time to write a new firmware for the DIODER. A `minimal example`__
program consists of:

.. __: ./minimaldemo.c

* A platform specific header file inclusion: This is where expressions like
  ``PORTA`` come from that we'll use later.

  .. include:: minimaldemo.c
     :literal:
     :end-before: typedef unsigned int config

* Configuration bits: These settings determine how the chip will behave and
  take effect before the rest of the program starts running, e.g. that we'll
  use an internal oscillator as a clock source. They correspond to the ``000C``
  we've read above, just in a form that is readable more easily.

  .. include:: minimaldemo.c
     :literal:
     :start-after: pic/pic16f684.h"
     :end-before: #define RED

* Some definitions that make the rest of the program easier to read (in
  particular, these describe which pin is connected to which LED channel):

  .. include:: minimaldemo.c
     :literal:
     :start-after: _INTRC_OSC_NOCLKOUT;
     :end-before: void main

* A main function that handles initialization (configures the LED pins as
  output pins) and stays in an endless loop that configures colors according to
  whether the central button is just pressed or not:

  .. include:: minimaldemo.c
     :literal:
     :start-after: #define BLUE (1<<1)

In order to burn a first new program on the PIC, download `the complete file`__
and compile it using ::

    $ sdcc -mpic14 -p16f684 minimaldemo.c

.. __: ./minimaldemo.c

You will find that, among other files, a ``minimaldemo.hex`` has been created.
This file contains the compiled code and the configuration flags in hexadecimal
notation. You can upload it to your DIODER now -- but be aware that this will
irrevocably remove the original firmware, as it can't be backed up due to
protection settings. If you want to go for it, run::

    $ pk2cmd -PPIC16F684 -Fminimaldemo.hex -M

Unplug your programmer and power the DIODER -- it should be yellow unless the
middle button is pressed, when it will be blue. Congratulations -- now you are
in full control of your device.

.. admonition:: CHECKPOINT

  If it doesn't, you probably already got errors from pk2cmd. In that case, try
  the configuration register reading above again to make sure the connection is
  still good.

  If you get errors like ::

    Program Memory Errors
    
    Address   Good     Bad
    000000    000000   000084

  this does not necessarily mean that your PIC is broken. Just try
  disconnecting the device for a minute and try again. Hints on why this
  happens are welcome.

A more complete example program is the `hardware demo`__, which exposes all
three buttons and the color dial. It requires a bit more setup calls for the
analog/digital converter, and in order to get all buttons to work properly. It
also implements PWM (pulse width modulation) dimming of the LEDs.

Based on this tutorial, there is a more advanced `firmware hosted on
GitLab`_, which tries to implement some of the suggestions below.

.. __: ./hardwaredemo.c
.. _`firmware hosted on GitLab`: https://gitlab.com/chrysn/dioder-firmware/

---------------

Happy hacking!

    --chrysn_

.. figure:: controller_with_cable.small.jpg
   :target: controller_with_cable.jpg

   With two little cuts in the case, you can close the case again and still use
   the cable.

---------------

Appendices
==========

Possibilities for further expansion
-----------------------------------

* The three additional I/O pins are currently left unused. Possible uses are
  additional buttons (internal pullups are available, so the pins can just be
  pulled to ground), sensors (e.g. reed sensor for turning on a drawer's
  lighting when opened) or a remote control (using software SPI).

* If you don't even want tiny cuts in the case, use short cable and a five-pin
  header to the pins required for programming; you can then leave the
  programming header inside the case and just upload new firmware.

* For better strength of the soldering points, drilling through the board at
  the pads and soldering the wires through-hole should be possible. Ground and
  Vpp already have vias that can be used for that. I am not sure how bad the
  problems with exposed copper from the back side will be.

* Some applications might want to use the 12V provided as well; there are both
  pads and vias available for soldering.

* Begin able to individually address the LED stripes would be a nice add-on,
  but this would require abandoning most of the hardware provided.

* There are pin-compatible ATTiny devices (e.g. the ATTiny44_) that can be used
  as a drop-in replacement for the PIC if no PIC programmer is at hand and you
  are already familiar with the AVR series. It should be possible to de-solder
  the whole PIC and replace it with an AVR device. Programming can then be done
  from any other AVR device (e.g. an Arduino_). The ATTiny could even directly
  connect to USB using the `V-USB`_ library.

  The power button is connected to the reset pin, so you can either use it as a
  pure "power off" button or sacrifice in-system-programmability.

* The FETs can power much longer LED stripes -- it would be necessary to
  replace the power supply, though.

.. _ATTiny44: http://www.atmel.com/dyn/products/product_card.asp?category_id=163&family_id=607&subfamily_id=791&part_id=3828
.. _Arduino: http://www.arduino.cc/
.. _`V-USB`: http://www.obdev.at/products/vusb/

Further resources
-----------------

These websites could be helpful in this field, although they were not used in
writing this (as they were discovered later):

* `Burningsmell's PIC16F628 page`_: example programs for PICs with SDCC
* `IKEA DIODER USB Mod`_: another DIODER hack, using the same 3-button version
* `OSAA Skilt 2.0`_: a page on the same topic, but with superior firmware and
  some hardware additions
* Ambioder_: an extension of this project by Gabriel-LG, which implements a
  UART based on the hardware described here

.. _`Burningsmell's PIC16F628 page`: http://burningsmell.org/pic16f628/
.. _`IKEA DIODER USB Mod`: http://slashhome.se/p/projects/id/ikea_dioder_usb/
.. _`OSAA Skilt 2.0`: http://www.vagrearg.org/?p=skilt20
.. _Ambioder: http://gabriel-lg.github.com/Ambioder/

Device variants
---------------

As of December 2014, it seems that some devices sold are not compatible with
this tutorial any more. Images of opened cases indicate that the design was
reduced to a single-layer design, with less over-sized FETs and -- most
importantly -- another microcontroller. The new chip is labelled SC91F729BM,
which I think is produced by a company named SINCOM and exclusively documented
in chinese, if at all. (The `SC-series website`_ shows similarly named chips
with data sheets that indicate an 8051 architecture).

As the new board resembles the original one in its outline, the change is
likely not to be visible from outside; hints on how to tell the revisions apart
would be very much appreciated.

.. _`SC-series website`: http://www.szcdxkmcu.com/product.asp?ClassID=002

About this tutorial
-------------------

© chrysn_ <chrysn@fsfe.org> 2011, published under the terms of `CC-BY-SA`_.

Thanks to the people at Metalab_ for providing tools and tips.

The original URI for this document is
http://christian.amsuess.com/tutorials/threebutton_dioder/. It is available as
HTML_ or as reStructuredText_.

.. _chrysn: http://christian.amsuess.com/#CMA
.. _`CC-BY-SA`: http://creativecommons.org/licenses/by-sa/3.0/
.. _Metalab: https://metalab.at/wiki/English
.. _HTML: http://christian.amsuess.com/tutorials/threebutton_dioder/index.html
.. _reStructuredText: http://christian.amsuess.com/tutorials/threebutton_dioder/index.rst
