TLIGHT_PRODUCTS / WS281X
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers WS281X.cpp Source File

WS281X.cpp

00001 /* WS281X.cpp (for LPC82X/STM32F0x/STM32F746xx)
00002  * mbed Microcontroller Library
00003  * Copyright (c) 2016 muetch, t.kuroki
00004  * Allrights reserved.
00005  *
00006  * Rev 0.97 2016-09-07
00007  * Rev 0.98 2016-09-08
00008  */
00009 
00010 #include "WS281X.h"
00011 #if defined(TARGET_STM)
00012 #include "pinmap.h"
00013 #endif
00014 
00015 // TARGET_STM32F7
00016 // TARGET_DISCO_F746NG
00017 // TARGET_NUCLEO_F746ZG
00018 // TARGET_NUCLEO_F446RE
00019 // TARGET_STM32F0
00020 // TARGET_NUCLEO_F030R8
00021 // TARGET_NUCLEO_F070RB
00022 // TARGET_NUCLEO_F072RB
00023 // TARGET_NUCLEO_F091RC
00024 // TARGET_LPC82X
00025 // TARGET_LPC824
00026 
00027 //----------------------------------------------------------------------------
00028 WS281X::WS281X(PinName txPin, PinMode pinMode, int maxPixels, RGBOrder order)
00029     : RGBPixels(maxPixels), _gpio()
00030 {
00031     pin_init(txPin, pinMode);
00032     rgbOrder(order);
00033     show(CL_BLACK);
00034 }
00035 
00036 WS281X::WS281X(PinName txPin, PinMode pinMode,
00037         RGBColor *buffer, int maxPixels, RGBOrder order)
00038     : RGBPixels(buffer, maxPixels), _gpio()
00039 {
00040     pin_init(txPin, pinMode);
00041     rgbOrder(order);
00042     show(CL_BLACK);
00043 }
00044 
00045 void WS281X::pin_init(PinName txPin, PinMode pinMode)
00046 {
00047     _txPin = txPin;
00048     gpio_init_inout(&_gpio, txPin, PIN_OUTPUT, pinMode, 0);
00049 #if defined(TARGET_STM)
00050     pin_mode_ex(txPin, pinMode);
00051 #endif
00052 }
00053 
00054 #if defined(TARGET_STM)
00055 /**
00056  * Configure pin pull-up/pull-down/OpenDrain
00057  * typedef enum {
00058  *     PullNone  = 0,
00059  *     PullUp    = 1,
00060  *     PullDown  = 2,
00061  *     OpenDrain = 3,
00062  *     PullDefault = PullNone
00063  * } PinMode;
00064  */
00065 void WS281X::pin_mode_ex(PinName pin, PinMode mode)
00066 {
00067     int port_index = STM_PORT(pin);
00068     int pin_index = STM_PIN(pin);
00069     int offset = pin_index << 1;
00070     GPIO_TypeDef * port_reg = ((GPIO_TypeDef *) (GPIOA_BASE + (port_index << 10)));
00071 
00072     // Configure pull-up/pull-down resistors
00073     uint32_t pupd = (uint32_t)mode & 3;
00074     if (pupd > 2)
00075         pupd = 0; // Open-drain = No pull-up/No pull-down
00076 
00077     if (mode == OpenDrain)
00078     {
00079         port_reg->PUPDR &= ~(0x3 << offset);    // Open-drain = No pull-up/No pull-down
00080         port_reg->OTYPER |= 1 << pin_index;
00081     }
00082     else
00083     {
00084         port_reg->OTYPER &= ~(1 << pin_index);
00085 //      pin_mode(pin, mode);
00086         port_reg->PUPDR &= ~(0x3 << offset);
00087         port_reg->PUPDR |= (mode & 0x03) << offset;
00088     }
00089 }
00090 #endif
00091 
00092 WS281X::RGBOrder WS281X::rgbOrder(RGBOrder order)
00093 {
00094     switch(_rgb_order = order)
00095     {
00096         case RGB: _1st = 0; _2nd = 1; _3rd = 2; break;  // WS2811
00097         case RBG: _1st = 0; _2nd = 2; _3rd = 1; break;
00098         case GRB: _1st = 1; _2nd = 0; _3rd = 2; break;  // WS2812
00099         case GBR: _1st = 2; _2nd = 0; _3rd = 1; break;
00100         case BRG: _1st = 1; _2nd = 2; _3rd = 0; break;
00101         case BGR: _1st = 2; _2nd = 1; _3rd = 0; break;
00102         default:
00103             _1st = 0; _2nd = 1; _3rd = 2;
00104             _rgb_order = GRB;    // WS2812
00105             break;
00106     }
00107     return _rgb_order;
00108 }
00109 
00110 //#define _nop1()     __nop()
00111 #define _nop1()     do {asm volatile ("nop"); } while(0)
00112 #define _nop2()     _nop1(); _nop1()
00113 #define _nop3()     _nop1(); _nop2()
00114 #define _nop4()     _nop2(); _nop2()
00115 #define _nop5()     _nop1(); _nop4()
00116 #define _nop6()     _nop2(); _nop4()
00117 #define _nop7()     _nop3(); _nop4()
00118 #define _nop8()     _nop4(); _nop4()
00119 #define _nop9()     _nop1(); _nop8()
00120 #define _nop10()    _nop2(); _nop8()
00121 #define _nop11()    _nop3(); _nop8()
00122 #define _nop12()    _nop4(); _nop8()
00123 #define _nop13()    _nop5(); _nop8()
00124 #define _nop14()    _nop6(); _nop8()
00125 #define _nop15()    _nop7(); _nop8()
00126 #define _nop16()    _nop8(); _nop8()
00127 
00128 #if defined(TARGET_LPC82X)
00129 // LPCXpresso824-MAX (30MHz)
00130 #define DELAY_T0H()     do{ _nop2(); }while(0)
00131 #define DELAY_T1H()     do{ _nop6(); }while(0)
00132 #define DELAY_TLOW()    do{ _nop6(); }while(0)
00133 #define DELAY_TLOW2()   //do{ _nop2(); }while(0)
00134 #define DELAY_SPACE()   do{ _nop4(); }while(0)
00135 #define DELAY_NEXT()    //do{ _nop1(); }while(0)
00136 #endif
00137 
00138 #if defined(TARGET_STM32F0)
00139 // NUCLEO-F030R8 (48MHz)
00140 // NUCLEO-F070RB (48MHz)
00141 // NUCLEO-F072RB (48MHz)
00142 #define DELAY_T0H()     do{ _nop8(); _nop4(); }while(0)
00143 #define DELAY_T1H()     do{ _nop8(); _nop8(); }while(0)
00144 #define DELAY_TLOW()    do{ _nop16(); }while(0)
00145 #define DELAY_TLOW2()   //do{ _nop8(); _nop4(); }while(0)
00146 #define DELAY_SPACE()   do{ _nop8(); _nop6(); }while(0)
00147 #define DELAY_NEXT()    do{ _nop8(); }while(0)
00148 #endif
00149 
00150 #if defined(TARGET_NUCLEO_F411RE)
00151 // NUCLEO-F411RE (96MHz)
00152 #define USE_DELAYFUNC   1
00153 #define T0H             (10)
00154 #define T0L             (31-T0H)
00155 #define T1H             (21)
00156 #define T1L             (31-T1H)
00157 
00158 #define DELAY_T0H()     _delay(T0H)
00159 #define DELAY_T1H()     _delay(T1H-T0H)
00160 #define DELAY_TLOW()    _delay(T1L)
00161 #define DELAY_TLOW2()   //DELAY_TLOW()
00162 #define DELAY_SPACE()   _delay(T1L-2)
00163 #define DELAY_NEXT()    _delay(16)
00164 #endif
00165 
00166 #if defined(TARGET_NUCLEO_F446RE)
00167 // NUCLEO-F446RE (180MHz)
00168 #define USE_DELAYFUNC   1
00169 #define T0H             (18)
00170 #define T0L             (58-T0H)
00171 #define T1H             (40)
00172 #define T1L             (58-T1H)
00173 
00174 #define DELAY_T0H()     _delay(T0H)
00175 #define DELAY_T1H()     _delay(T1H-T0H)
00176 #define DELAY_TLOW()    _delay(T1L)
00177 #define DELAY_TLOW2()   //DELAY_TLOW()
00178 #define DELAY_SPACE()   _delay(T1L-2)
00179 #define DELAY_NEXT()    _delay(16)
00180 #endif
00181 
00182 #if defined(TARGET_NUCLEO_F746ZG)
00183 // NUCLEO-F746ZG (216MHz)
00184 #define USE_DELAYFUNC   1
00185 #define T0H             (35)
00186 #define T0L             (130-T0H)
00187 #define T1H             (75)
00188 #define T1L             (130-T1H)
00189 
00190 #define DELAY_T0H()     _delay(T0H)
00191 #define DELAY_T1H()     _delay(T1H-T0H)
00192 #define DELAY_TLOW()    _delay(T1L)
00193 #define DELAY_TLOW2()   //DELAY_TLOW()
00194 #define DELAY_SPACE()   _delay(T1L+20)
00195 #define DELAY_NEXT()    _delay(50)
00196 #endif
00197 
00198 #if defined(TARGET_DISCO_F746NG)
00199 // TARGET_DISCO_F746NG (216MHz)
00200 #define USE_DELAYFUNC   1
00201 #define T0H             (35)
00202 #define T0L             (125-T0H)
00203 #define T1H             (90)
00204 #define T1L             (125-T1H)
00205 
00206 #define DELAY_T0H()     _delay(T0H)
00207 #define DELAY_T1H()     _delay(T1H-T0H)
00208 #define DELAY_TLOW()    _delay(T1L)
00209 #define DELAY_TLOW2()   //DELAY_TLOW()
00210 #define DELAY_SPACE()   _delay(T1L-5)
00211 #define DELAY_NEXT()    _delay(40)
00212 #endif
00213 
00214 #if defined(USE_DELAYFUNC) && (USE_DELAYFUNC != 0)
00215 static inline __attribute__((always_inline))
00216 void _delay(int value)
00217 {
00218     do { _nop1(); } while (--value);
00219 }
00220 #endif
00221 
00222 inline __attribute__((always_inline))
00223 void WS281X::writeByte(__IO regsize_t *reg_set, __IO regsize_t *reg_clr, regsize_t *mask, uint8_t value)
00224 {
00225     do
00226     {
00227 #if 1
00228     // bit7
00229         *reg_set = mask[0];
00230         DELAY_T0H();
00231         *reg_clr = mask[(value >> 7) & 1];
00232         DELAY_T1H();
00233         *reg_clr = mask[0];
00234         DELAY_TLOW();
00235 
00236     // bit6
00237         *reg_set = mask[0];
00238         DELAY_T0H();
00239         *reg_clr = mask[(value >> 6) & 1];
00240         DELAY_T1H();
00241         *reg_clr = mask[0];
00242         DELAY_TLOW();
00243 
00244     // bit5
00245         *reg_set = mask[0];
00246         DELAY_T0H();
00247         *reg_clr = mask[(value >> 5) & 1];
00248         DELAY_T1H();
00249         *reg_clr = mask[0];
00250         DELAY_TLOW();
00251 
00252     // bit4
00253         *reg_set = mask[0];
00254         DELAY_T0H();
00255         *reg_clr = mask[(value >> 4) & 1];
00256         DELAY_T1H();
00257         *reg_clr = mask[0];
00258         DELAY_TLOW();
00259 #endif
00260 
00261     // bit3
00262         *reg_set = mask[0];
00263         DELAY_T0H();
00264         *reg_clr = mask[(value >> 3) & 1];
00265         DELAY_T1H();
00266         *reg_clr = mask[0];
00267         DELAY_TLOW();
00268 
00269     // bit2
00270         *reg_set = mask[0];
00271         DELAY_T0H();
00272         *reg_clr = mask[(value >> 2) & 1];
00273         DELAY_T1H();
00274         *reg_clr = mask[0];
00275         DELAY_TLOW();
00276 
00277     // bit1
00278         *reg_set = mask[0];
00279         DELAY_T0H();
00280         *reg_clr = mask[(value >> 1) & 1];
00281         DELAY_T1H();
00282         *reg_clr = mask[0];
00283         DELAY_TLOW();
00284 
00285     // bit0
00286         *reg_set = mask[0];
00287         DELAY_T0H();
00288         *reg_clr = mask[(value >> 0) & 1];
00289         DELAY_T1H();
00290         *reg_clr = mask[0];
00291         DELAY_TLOW2();
00292 
00293     } while (0);
00294 }
00295 
00296 void WS281X::show()
00297 {
00298 // CPU_FREQ = 30MHz -> 0.0333us/cycle
00299 // WS2811 0: 0.25us+1.0us, 1: 1.0us+0.25us
00300 // WS2812 0: 0.45us+0.8us, 1: 0.8us+0.45us
00301 
00302     if (!_pixels)
00303         return;
00304 
00305 #if defined(TARGET_NXP)
00306     __IO uint32_t *reg_set = _gpio.reg_set;
00307     __IO uint32_t *reg_clr = _gpio.reg_clr;
00308     uint32_t mask[2] = { _gpio.mask, 0 };
00309 #elif defined(TARGET_STM32F0) || defined(TARGET_STM32F1)
00310     __IO uint32_t *reg_set = _gpio.reg_set;
00311     __IO uint32_t *reg_clr = _gpio.reg_clr;
00312     uint32_t mask[2] = { _gpio.mask, 0 };
00313 #elif defined(TARGET_STM)
00314     __IO uint16_t *reg_set = (__IO uint16_t *)_gpio.reg_set_clr;
00315     __IO uint16_t *reg_clr = reg_set + 1;
00316     uint16_t mask[2] = { _gpio.mask, 0 };
00317 #endif
00318 
00319     uint8_t *pix = (uint8_t *)_pixels;
00320     uint8_t *end = pix + (_num_pixels * sizeof(_pixels[0]));
00321 
00322     __disable_irq();   // Disable interrupts temporarily because we don't want our pulse timing to be messed up.
00323 
00324     uint8_t value;
00325     do
00326     {
00327         value = pix[_1st];
00328         writeByte(reg_set, reg_clr, mask, value);
00329         DELAY_SPACE();
00330 
00331         value = pix[_2nd];
00332         writeByte(reg_set, reg_clr, mask, value);
00333         DELAY_SPACE();
00334 
00335         value = pix[_3rd];
00336         writeByte(reg_set, reg_clr, mask, value);
00337         pix += sizeof(_pixels[0]);
00338         DELAY_NEXT();
00339     } while (pix < end);
00340 
00341     __enable_irq();   // Re-enable interrupts now that we are done.
00342 
00343 //@-    wait_us(50);
00344 }
00345 
00346 // 指定色でバッファを埋めた後表示
00347 void WS281X::show(const RGBColor color)
00348 {
00349     fill(color);
00350     show();
00351 }
00352 
00353 //----------------------------------------------------------------------------
00354