Jump to: navigation, search

ledFlicker is a six-channel LED oscillator for visual experiments. It has 12-bits of color precision per channel and a refresh rate of about 2000 Hz. It is based on the Arduino Mega microcontroller board. The firmware should also work with any Arduino Mega clone, like the Seeeduino Mega.

ledFlicker uses pulse width modulation (PWM) to achieve nearly linear intensity modulation over its entire 12-bit range. It also has a user-configurable gamma correction table for each channel to allow fine-tuning of intensity linearity. The gamma calibration is stored on the board's EEPROM and is automatically loaded when the board boots up. The PWM frequency is about 2KHz and is phase and frequency correct.


[edit] Building the firmware

The firmware code is open-source, released under the GPL. You can browse the source at the github project page or check it out with:


To build the firmware, you need the Arduino environment (we used versions 18 and 19). If you move (or soft-link) the contents of the 'firmware' directory to your sketchbook directory (~/sketchbook on linux), then the Arduino app will automatically find it. You also need the Flash library. For convenience, that is also included in the firmware directory, so you don't need to find and install it. We also use a modified version of the Messenger library, which is also included. Just make sure that you have a folder called "libraries" in your sketchbook directory and that the Flash and Messenger directories are there. (See the Arduino guide for details.) ledFlicker.pde file should have a parent folder with the same name. Your sketchbook directory should have at least the following items:


[edit] Using ledFlicker

To use ledFlicker, simply plug it into a USB port. On modern Linux distros, the USB driver should already be installed, so the Arduino will appear as a serial device (e.g., /dev/ttyUSB0) as soon as you plug it in. On Windows and Mac, you might need to install a USB driver (see the Arduino Guide for more info). If you have followed the instructions above for installing the full Arduino environment, then you can skip this step as the driver will have been installed at that step.

[edit] Installing the driver


  • When you connect the Arduino, Windows should initiate the driver installation process (if you haven't used the computer with an Arduino board before).
    • On Windows Vista (and maybe 7?), the driver should be automatically downloaded and installed. (Really, it works!)
    • On Windows XP, the Add New Hardware wizard will open:
      • When asked Can Windows connect to Windows Update to search for software? select No, not this time. Click next.
      • Select Install from a list or specified location (Advanced) and click next.
      • Make sure that Search for the best driver in these locations is checked; uncheck Search removable media; check Include this location in the search and browse to the drivers/FTDI USB Drivers directory of the Arduino distribution. (The latest version of the drivers can be found on the FTDI website.) Click next.
      • The wizard will search for the driver and then tell you that a "USB Serial Converter" was found. Click finish.
      • The new hardware wizard will appear again. Go through the same steps and select the same options and location to search. This time, a "USB Serial Port" will be found.
  • You can check that the drivers have been installed by opening the Windows Device Mananger (in the Hardware tab of System control panel). Look for a "USB Serial Port" in the Ports section; that's the Arduino board.

Mac OS-X:

  • If this is your first time using an Arduino with your computer, you will need to install the drivers for the FTDI chip on the board. Double-click the FTDIUSBSerialDriver_10_4_10_5_10_6.mpkg icon and follow the instructions in the installer. You'll need to restart your computer after installing the drivers. (The latest version of the drivers can be found on the FTDI website.)

[edit] Communicating with ledFlicker

Once you have the Arduino appearing as a serial device, you control ledFlicker by sending serial commands at 57600 kbs (baud). Each command must be enclosed in square brackets ([]) and follows a simple structure, explained below. You can send multiple commands in one stream of serial data, but don't send too much at once, since the ledFlicker serial port buffer is somewhat small (128 characters).

[edit] ledFlicker Commands

Here is the help text from the firmware:

All ledFlicker commands must be enclosed in square brackets ([]); all characters
outside of the brackets are ignored. Each command begins with a single letter
(defined below), followed by some parameters. Parameters are separated by a comma.
Commands (optional params are enclosed in parens with default value):

   Help (displays this text).
   Set the mean outputs (0 - 4095) for all channels.
   Set the envelope duration and rise/fall times (in seconds, max = 33.54 secs).
   Set duration=0 for no envelope and infinite duration.
   Set six flags (one for each channel) that determine if the waveforms are played in full
   (0, the default), only the positive lobe is played (1), or only the negative lobe is played (-1).
   As with the envelope, this setting is preserved until the firmware is rebooted.
   Set waveform parameters for the specified waveform number (up to 2).
   Phase is 0-1, with 0.5 = pi radians. Amplitudes are -1 to 1.
   Play the waveforms. If the duration is infinite, then you only need to run
   this command once, even if waveform parmeters are changed.
   Halt waveform playout. This is especially useful with an infinite duration.
   Status information. If the previous command failed with an ERR, you can use this
   to see the error message. Also shows the time remaining for current playout.
   Set verbosity mode. 0 for very quiet (just OK or ERR), 1 to show errors, 2 or higher for everything.
   Check the currently specified waveform. Prints some internal variables and waveform stats.
   Dump the specified wavform. (Dumps a lot of data to your serial port!
   Set the inverse gamma LUT values and store them in EEPROM. The gamma tables will 
   be loaded automatically each time the board boots up. The computed (internal) modulation
   values (s) are in the range [0,65536]. The PWM value produced for internal modulation value s is:
      pwm = ((s%16)*lut[s>>4] + (16-s%16)*lut[s>>4+1]) / 16 
   There are 6 gamma tables (one for each output channel). Each gamma maps 257 internal modulation
   values ([0:256:65536]) to the 0-4095 PWM values according to the formula above, which includes
   linear interpolation for values between the 257 entries in the gamma LUTs. When setting the gamma
   tables, pass the 6 pwm values for one of the 257 slices through the 6 tables.
   Call this with no args to see the all the LUT values currently stored in EEPROM.
   Call this with just lutSlice to see the the LUT values for the specified slice of the gamma tables.

For example:

[edit] Hardware

LedFlicker is built around the Arduino Mega microcontroller board and the BuckPuck to provide an adjustable constant-current source for the LEDs. Six of the Arduino Mega's 16-bit PWM outputs are connected to the external dimming pin via a PNP transistor. (See Figure 1, which is copied from Figure 12 of the BuckPuck datasheet.)

Figure 1. Schematic for each of the six channels. The Arduino PWM output is connected to the base of the PNP transistor via a 5K resistor. The 5K trim pot is used to set the output current level.

[edit] Parts List

  • 1 - Arduino Mega microcontroller board
  • 6 - high-power LEDs. We used Luxeon Rebels pre-mounted to a 20mm star board from Luxeon Star. The colors we chose (and associated peak wavelength) are Royal Blue (447.5nm), Blue (470nm), Cyan (505nm), Green (530nm), Amber (590nm), and Red (627nm). These can be driven at up to 700mA each. The typical forward voltage drop (Vf) for Red and Amber is 2.9V and for the other colors it is 3.15V.
  • 6 - 700mA BuckPucks with external dimming.
  • 6 - 2N3906 PNP transistors
  • 6 - 25-turn 5 KOhm trim pots (connected between the CTRL and REF BuckPuck pins for current adjustment)
  • A few resistors & capacitors
  • Perfboard for mounting things
  • Fiber optics and a coupling lens from Carclo Optics (e.g., this one)
  • You'll also need a heatsink to keep the LEDs cool. We used the Thermaltake TR2-R1, a socket AM2/939/754 CPU heatsink ($15 at Fry's). This one is nice because it's all aluminum, has a large flat area for mounting the LEDs, has a relatively quiet fan, and there is a flat bracket on the fan that allows you to position it upside-down without interfering with the fan. To mount the LEDs, we drilled 3/32 inch holes and cut threads with a 4-40 plug tap. The LEDs were then secured with 1/4 inch 4-40 pan-head stainless steel screws, with nylon washers for electrical insulation.


[edit] Power Requirements

We use six LEDs, each drawing up to 700mA, for a total current of 6*.7 = 4.2A. The buckPuck drivers are very efficient (>80%). If we assume 80% efficiency and know the forward voltage drop for our LEDs (Vf), then we can compute the maximum power draw with:

Vf = [2.9, 2.9, 3.15, 3.15, 3.15, 3.15]
watts = sum((Vf.*0.7))/0.8

Thus, for our set-up, we expect the LEDs to draw a maximum of about 16 Watts. This obviously exceeds the 2.5 Watt (500mA * 5volt) USB power draw limit, so we need to power the LEDs with an external power supply. We used a standard 12v switching supply, like those that power external hard drives. At 12 volts, we need a supply that can provide at least 1.4 Amps. Note, however, that the actual Vf for your LEDs might be higher than the "typical" Vf provided in the spec sheet, so plan accordingly. Also, note that a switching supply might introduce RF noise in an MR environment. If you plan to place the power supply within the shielded MR scanner room, you should probably choose a linear power supply.

[edit] Calibration Information

[edit] LED Stability

[edit] Gamma Linearity

[edit] Differences between Red and Blue/Green LEDs

[edit] To Do

  • Add calibration info to this page. Especially note what we've learned about LED stability, gamma linearity, and the differences between red/amber LEDs and the blue/green LEDs.
  • Firmware edits:
    • keep count of LED hours of service
    • store calibration data on-board in EPROM
    • auto-sleep LEDs when no commands have been sent in ?? minutes
Personal tools