David Knight / PololuLedStrip

Fork of PololuLedStrip by David Grayson

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers PololuLedStrip.cpp Source File

PololuLedStrip.cpp

00001 #include "PololuLedStrip.h"
00002 
00003 // Our assembly code currently does not work with chip families like the STM32F4
00004 // that use the same register and a different mask for setting and clearing
00005 // outputs.
00006 #ifdef GPIO_IP_WITHOUT_BRR
00007 #error This chip is not supported: does not have separate registers for setting and clearing GPIO outputs.
00008 #endif
00009 
00010 bool PololuLedStrip::interruptFriendly = false;
00011 
00012 // The two timed delays, in units of half-cycles.
00013 uint8_t led_strip_write_delays[2];
00014 
00015 void PololuLedStrip::calculateDelays()
00016 {
00017     int f_mhz = SystemCoreClock / 1000000;   // Clock frequency in MHz.
00018 
00019     if (f_mhz <= 48)
00020     {
00021         // The delays below result in 360/1120 ns pulses and a 1880 ns period on the mbed NXP LPC11U24.        
00022         led_strip_write_delays[0] = 0;
00023         led_strip_write_delays[1] = 0;
00024     }
00025     else
00026     {
00027         // Try to generally compute what the delays should be for a wide range of clock frequencies.
00028         
00029         // The fudge factors below were experimentally chosen so that we would have
00030         // ~100 ns and ~840 ns pulses and a ~1430 ns period on the mbed NXP LPC1768 (96 MHz Cortex-M3).
00031         // There seem to be some ~100 ns inconsistencies in the timing depending on which example program is
00032         // running; the most likely explanation is some kind of flash caching that affects the timing.
00033         // If you ever change these numbers, it is important to check the the subtractions below
00034         // will not overflow in the worst case (smallest possible f_mhz).
00035         //
00036         // On an STM32F303K8 (72 MHz Cortex-M4), these delays give us ~170 ns and ~840 ns pulses
00037         // and a ~1595 ns period, and there were no timing differences between the two
00038         // example programs.
00039         led_strip_write_delays[0] = 750*f_mhz/1000 - 33;
00040         led_strip_write_delays[1] = 550*f_mhz/1000 - 20;    
00041     }
00042  
00043     // Convert from units of cycles to units of half-cycles; it makes the assembly faster.   
00044     led_strip_write_delays[0] <<= 1;
00045     led_strip_write_delays[1] <<= 1;
00046 }
00047 
00048 PololuLedStrip::PololuLedStrip(PinName pinName)
00049 {
00050     gpio_init_out(&gpio, pinName);
00051 }
00052 
00053 void PololuLedStrip::write(rgb_color * colors, unsigned int count)
00054 {
00055     uint8_t t;
00056     calculateDelays();
00057     
00058     __disable_irq();   // Disable interrupts temporarily because we don't want our pulse timing to be messed up.
00059 
00060     while(count--)
00061     {
00062 
00063 #ifdef _POLOLU_ORDER_GRB
00064         //swap red and green for WS2812b strips
00065         t = colors->red;
00066         colors->red = colors->green;
00067         colors->green = t;
00068 #endif
00069 
00070         led_strip_write_color(colors, gpio.reg_set, gpio.reg_clr, gpio.mask);
00071         colors++;
00072          
00073         if (interruptFriendly)
00074         {
00075             __enable_irq();
00076             __nop();
00077             __nop();
00078             __nop();
00079             __disable_irq();
00080         }
00081     }
00082         
00083     __enable_irq();   // Re-enable interrupts now that we are done.
00084     wait_us(80);      // Send the reset signal.
00085 }