This library lets you control the addressable RGB LED strips from Pololu Robotics & Electronics.

Dependents:   WoYaoChengGOng V2-WoYaoChengGOng STM32_MagneticLight tape_Led_Sample ... more

Summary

This is a library for the mbed that allows you to control these addressable RGB LED products from Pololu:

This library is optimized for the SK6812 and WS2812B, so it transmits colors in green-red-blue order.

If you have a WS2811 LED or a high-speed TM1804 LED strip, please note that its red and green channels are swapped relative to the WS2812B, so you will need to swap those channels in your code. You might prefer to use the version of the library from October 2013, which does not require you to swap red and green in your code.

If you need to control the older, low-speed LED strips (items #2540, #2541, and #2542), you will need to use the version of this library from March 2013.

This library allows complete control over the color of an arbitrary number of LED strips with an arbitrary number of LEDs. Each LED can be individually controlled, and LED strips can be chained together.

This library should also work with any other LED strip based on the SK6812, WS281x, or TM1804.

Supported Platforms

This library has been tested on the mbed NXP LPC1768 (Cortex-M3 at 96 MHz), the mbed NXP LPC11U24 (Cortex-M0 at 48 MHz), and the NUCLEO-F303K8 (Cortex-M4 at 72 MHz). It will probably work on many other boards without modification.

This library does not work on chips families such as the STM32F4 where there is a single register for setting and clearing the value of an output pin. The library checks for the GPIO_IP_WITHOUT_BRR preprocessor macro and triggers a compile-time error if that macro is set.

Getting Started

Software

Here are two example programs that show how to use the library:

Import programLedStripRainbow

This is an example program for the PololuLedStrip library. It generates a simple moving rainbow pattern.

Import programLedStripGradient

This is an example program for the PololuLedStrip library. It generates a simple moving gradient pattern.

As a first step, you should compile and upload one of these to the mbed. When the program runs, the mbed should output color data on pin p8 dozens of times per second. The expected signal is documented on the Pololu website. The example programs only send colors for 60 LEDs, but they can easily be changed to send more for a longer strip.

Hardware

The addressable RGB LED strips can be purchased on Pololu's website using the links above.

The LED strip’s data input connector has two pins that should be connected to the Arduino. The LED strip’s ground will need to be connected to one of the mbed’s GND pins, and the LED strip’s signal input line will be need to be connected to one of the Arduino’s I/O lines. Our example programs assume the signal line is connected to p8. These connections can be made using two Male-Female Premium Jumper Wires, with the female ends plugging into the LED strip and the male ends plugged into a breadboard that houses the mbed.

You will also need to connect a suitable power supply to the LED strip using one of the power connectors. The power supply must be at the right voltage and provide enough current to meet the LED strip's requirements.

If everything works properly, you will see a moving pattern of colors on the LED strip.

Timing Details

This library takes about 1.3 ms to update 30 LEDs (1 meter). The LED strips use a high speed one-wire protocol with relatively strict timing requirements, so this library disables interrupts to ensure reliable color transmission. Unfortunately, disabling the interrupts could cause problems in other libraries that uses interrupts.

This library provides an interruptFriendly option that can let it coexist with interrupt-based libraries. When this option is enabled, the library will temporarily enable interrupts after each color is sent, about every 45 microseconds. If you can keep all of your interrupts short enough, then this option should allow this library to work in conjunction with your interrupt-based libraries. However, if you have an interrupt enabled that takes too long, then this interrupt will sometimes cause an extra long low pulse to emitted, which will be interpreted by the LED strip as a reset command. This can cause visible flickering in the LED strip. To turn on the interruptFriendly option, add this line to the beginning of your main() function:

PololuLedStrip::interruptFriendly = true;

Chaining LED Strips together

No special code is required to chain LED strips together. An X-meter LED strip chained to a Y-meter LED strip can be controlled in exactly the same way as a single (X+Y)-meter LED strip.

Committer:
DavidEGrayson
Date:
Wed Nov 01 23:11:49 2017 +0000
Revision:
26:c3193bc73cff
Parent:
25:d72818ba17cc
Make it be a compile-time error if GPIO_IP_WITHOUT_BRR is set.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
DavidEGrayson 1:102307d9b701 1 #include "PololuLedStrip.h"
DavidEGrayson 1:102307d9b701 2
DavidEGrayson 26:c3193bc73cff 3 // Our assembly code currently does not work with chip families like the STM32F4
DavidEGrayson 26:c3193bc73cff 4 // that use the same register and a different mask for setting and clearing
DavidEGrayson 26:c3193bc73cff 5 // outputs.
DavidEGrayson 26:c3193bc73cff 6 #ifdef GPIO_IP_WITHOUT_BRR
DavidEGrayson 26:c3193bc73cff 7 #error This chip is not supported: does not have separate registers for setting and clearing GPIO outputs.
DavidEGrayson 26:c3193bc73cff 8 #endif
DavidEGrayson 26:c3193bc73cff 9
DavidEGrayson 1:102307d9b701 10 bool PololuLedStrip::interruptFriendly = false;
DavidEGrayson 1:102307d9b701 11
DavidEGrayson 19:46d7ab0ba3e7 12 // The two timed delays, in units of half-cycles.
DavidEGrayson 19:46d7ab0ba3e7 13 uint8_t led_strip_write_delays[2];
DavidEGrayson 4:d3b60bd43811 14
DavidEGrayson 7:9a088f042ee0 15 void PololuLedStrip::calculateDelays()
DavidEGrayson 7:9a088f042ee0 16 {
DavidEGrayson 15:d69eebdee025 17 int f_mhz = SystemCoreClock / 1000000; // Clock frequency in MHz.
DavidEGrayson 14:672baf3cf941 18
DavidEGrayson 14:672baf3cf941 19 if (f_mhz <= 48)
DavidEGrayson 14:672baf3cf941 20 {
DavidEGrayson 19:46d7ab0ba3e7 21 // The delays below result in 360/1120 ns pulses and a 1880 ns period on the mbed NXP LPC11U24.
DavidEGrayson 14:672baf3cf941 22 led_strip_write_delays[0] = 0;
DavidEGrayson 14:672baf3cf941 23 led_strip_write_delays[1] = 0;
DavidEGrayson 14:672baf3cf941 24 }
DavidEGrayson 14:672baf3cf941 25 else
DavidEGrayson 14:672baf3cf941 26 {
DavidEGrayson 22:5368af3ff07d 27 // Try to generally compute what the delays should be for a wide range of clock frequencies.
DavidEGrayson 14:672baf3cf941 28
DavidEGrayson 14:672baf3cf941 29 // The fudge factors below were experimentally chosen so that we would have
DavidEGrayson 23:881d93b8749a 30 // ~100 ns and ~840 ns pulses and a ~1430 ns period on the mbed NXP LPC1768 (96 MHz Cortex-M3).
DavidEGrayson 17:91fb934a2166 31 // There seem to be some ~100 ns inconsistencies in the timing depending on which example program is
DavidEGrayson 17:91fb934a2166 32 // running; the most likely explanation is some kind of flash caching that affects the timing.
DavidEGrayson 14:672baf3cf941 33 // If you ever change these numbers, it is important to check the the subtractions below
DavidEGrayson 19:46d7ab0ba3e7 34 // will not overflow in the worst case (smallest possible f_mhz).
DavidEGrayson 23:881d93b8749a 35 //
DavidEGrayson 23:881d93b8749a 36 // On an STM32F303K8 (72 MHz Cortex-M4), these delays give us ~170 ns and ~840 ns pulses
DavidEGrayson 23:881d93b8749a 37 // and a ~1595 ns period, and there were no timing differences between the two
DavidEGrayson 23:881d93b8749a 38 // example programs.
DavidEGrayson 19:46d7ab0ba3e7 39 led_strip_write_delays[0] = 750*f_mhz/1000 - 33;
DavidEGrayson 19:46d7ab0ba3e7 40 led_strip_write_delays[1] = 550*f_mhz/1000 - 20;
DavidEGrayson 15:d69eebdee025 41 }
DavidEGrayson 15:d69eebdee025 42
DavidEGrayson 15:d69eebdee025 43 // Convert from units of cycles to units of half-cycles; it makes the assembly faster.
DavidEGrayson 22:5368af3ff07d 44 led_strip_write_delays[0] <<= 1;
DavidEGrayson 22:5368af3ff07d 45 led_strip_write_delays[1] <<= 1;
DavidEGrayson 7:9a088f042ee0 46 }
DavidEGrayson 6:9d0530b7dae2 47
DavidEGrayson 1:102307d9b701 48 PololuLedStrip::PololuLedStrip(PinName pinName)
DavidEGrayson 1:102307d9b701 49 {
DavidEGrayson 22:5368af3ff07d 50 gpio_init_out(&gpio, pinName);
DavidEGrayson 1:102307d9b701 51 }
DavidEGrayson 1:102307d9b701 52
DavidEGrayson 1:102307d9b701 53 void PololuLedStrip::write(rgb_color * colors, unsigned int count)
DavidEGrayson 1:102307d9b701 54 {
DavidEGrayson 8:1578776ceac5 55 calculateDelays();
DavidEGrayson 8:1578776ceac5 56
DavidEGrayson 1:102307d9b701 57 __disable_irq(); // Disable interrupts temporarily because we don't want our pulse timing to be messed up.
DavidEGrayson 7:9a088f042ee0 58
DavidEGrayson 1:102307d9b701 59 while(count--)
DavidEGrayson 1:102307d9b701 60 {
DavidEGrayson 9:6ffb85d69eaf 61 led_strip_write_color(colors, gpio.reg_set, gpio.reg_clr, gpio.mask);
DavidEGrayson 9:6ffb85d69eaf 62 colors++;
DavidEGrayson 9:6ffb85d69eaf 63
DavidEGrayson 1:102307d9b701 64 if (interruptFriendly)
DavidEGrayson 1:102307d9b701 65 {
DavidEGrayson 1:102307d9b701 66 __enable_irq();
DavidEGrayson 1:102307d9b701 67 __nop();
DavidEGrayson 1:102307d9b701 68 __nop();
DavidEGrayson 1:102307d9b701 69 __nop();
DavidEGrayson 1:102307d9b701 70 __disable_irq();
DavidEGrayson 1:102307d9b701 71 }
DavidEGrayson 1:102307d9b701 72 }
DavidEGrayson 1:102307d9b701 73
DavidEGrayson 1:102307d9b701 74 __enable_irq(); // Re-enable interrupts now that we are done.
DavidEGrayson 25:d72818ba17cc 75 wait_us(80); // Send the reset signal.
DavidEGrayson 1:102307d9b701 76 }