TLIGHT_PRODUCTS / WS281X
Revision:
0:dff187a80020
Child:
2:cc8e091fd975
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WS281X.cpp	Tue Jul 26 18:09:24 2016 +0000
@@ -0,0 +1,345 @@
+/* WS281X.cpp (for LPC82X/STM32F0x/STM32F746xx)
+ * mbed Microcontroller Library
+ * Copyright (c) 2016 muetch, t.kuroki, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "WS281X.h"
+#include "pinmap.h"
+
+// TARGET_DISCO_F746NG
+// TARGET_NUCLEO_F746ZG
+// TARGET_NUCLEO_F030R8
+// TARGET_NUCLEO_F070RB
+// TARGET_LPC824
+
+//----------------------------------------------------------------------------
+WS281X::WS281X(PinName wirePin, PinMode pinMode, int numPixels, RGBOrder rgbOrder)
+    : _wirePin(wirePin), _gpio(), _pixels(0)
+{
+    gpio_init_inout(&_gpio, wirePin, PIN_OUTPUT, pinMode, 0);
+#if defined(TARGET_STM)
+    pin_mode_ex(wirePin, pinMode);
+#endif
+
+    setRGBOrder(rgbOrder);
+
+    if (numPixels < 1)
+        numPixels = 1;
+    else if (numPixels > MAX_PIXELS)
+        numPixels = MAX_PIXELS;
+    _numPixels = (uint16_t)numPixels;
+    _pixels = new RGBColor[_numPixels];
+    _dummyPixel = 0;
+
+    clear();
+}
+
+WS281X::~WS281X()
+{
+    if (_pixels)
+        delete[] _pixels;
+}
+
+#if defined(TARGET_STM)
+void WS281X::pin_mode_ex(PinName pin, PinMode mode)
+{
+    if (mode == OpenDrain)
+    {
+        int port_index = STM_PORT(pin);
+        int pin_index = STM_PIN(pin);
+        int offset = pin_index << 1;
+
+        GPIO_TypeDef * port_reg = ((GPIO_TypeDef *) (GPIOA_BASE + (port_index << 10)));
+//        if (mode == OpenDrain)
+        {
+            port_reg->PUPDR &= ~(0x3 << offset);
+            port_reg->OTYPER |= 1 << pin_index;
+        }
+    #if 0
+        else
+        {
+            port_reg->OTYPER &= ~(1 << pin_index);
+            port_reg->PUPDR &= ~(0x3 << offset);
+            port_reg->PUPDR |= mode_ << offset;
+        }
+    #endif
+    }
+    else
+        pin_mode(pin, mode);
+}
+#endif
+
+void WS281X::setRGBOrder(RGBOrder rgbOrder)
+{
+    _rgbOrder = rgbOrder;
+    switch(_rgbOrder)
+    {
+        case RGB:
+            _1st = 0;
+            _2nd = 1;
+            _3rd = 2;
+            break;
+
+        case RBG:
+            _1st = 0;
+            _2nd = 2;
+            _3rd = 1;
+            break;
+
+        case GRB:
+            _1st = 1;
+            _2nd = 0;
+            _3rd = 2;
+            break;
+
+        case GBR:
+            _1st = 2;
+            _2nd = 0;
+            _3rd = 1;
+            break;
+
+        case BRG:
+            _1st = 1;
+            _2nd = 2;
+            _3rd = 0;
+            break;
+
+        case BGR:
+            _1st = 2;
+            _2nd = 1;
+            _3rd = 0;
+            break;
+
+        default:
+            _1st = 0;
+            _2nd = 1;
+            _3rd = 2;
+            break;
+    }
+}
+
+#define _nop1()     __nop()
+#define _nop2()     __nop(); __nop()
+#define _nop3()     _nop1(); _nop2()
+#define _nop4()     _nop2(); _nop2()
+#define _nop5()     _nop1(); _nop4()
+#define _nop6()     _nop2(); _nop4()
+#define _nop7()     _nop3(); _nop4()
+#define _nop8()     _nop4(); _nop4()
+#define _nop9()     _nop1(); _nop8()
+#define _nop10()    _nop2(); _nop8()
+#define _nop11()    _nop3(); _nop8()
+#define _nop12()    _nop4(); _nop8()
+#define _nop13()    _nop5(); _nop8()
+#define _nop14()    _nop6(); _nop8()
+#define _nop15()    _nop7(); _nop8()
+#define _nop16()    _nop8(); _nop8()
+
+#if defined(TARGET_NXP)
+// LPC824-30MHz
+#define DELAY_T0H()     do{ _nop2(); }while(0)
+#define DELAY_T1H()     do{ _nop6(); }while(0)
+#define DELAY_TLOW()    do{ _nop6(); }while(0)
+#define DELAY_TLOW2()   //do{ _nop2(); }while(0)
+#define DELAY_SPACE()   do{ _nop2(); }while(0)
+#define DELAY_NEXT()    do{ _nop1(); }while(0)
+#endif
+
+#if defined(TARGET_STM32F0)
+// STM32F030R8-48MHz
+#define DELAY_T0H()     do{ _nop8(); _nop4(); }while(0)
+#define DELAY_T1H()     do{ _nop8(); _nop8(); }while(0)
+#define DELAY_TLOW()    do{ _nop16(); }while(0)
+#define DELAY_TLOW2()   //do{ _nop8(); _nop4(); }while(0)
+#define DELAY_SPACE()   do{ _nop8(); _nop4(); }while(0)
+#define DELAY_NEXT()    do{ _nop4(); }while(0)
+#endif
+
+#if defined(TARGET_STM32F7)
+// DISCO-F746NG (216MHz), NUCLEO-F746ZG (216MHz)
+#define T0H             (35)
+#define T0L             (128-T0H)
+#define T1H             (100)
+#define T1L             (128-T1H)
+
+#define DELAY_T0H()     _delay(T0H)
+#define DELAY_T1H()     _delay(T1H-T0H)
+#define DELAY_TLOW()    _delay(T1L)
+#define DELAY_TLOW2()   //DELAY_TLOW()
+#define DELAY_SPACE()   DELAY_TLOW()
+#define DELAY_NEXT()    _delay(35)
+
+inline __attribute__((always_inline))
+void WS281X::_delay(int value)
+{
+    do { __nop(); } while (--value);
+}
+#endif
+
+inline __attribute__((always_inline))
+void WS281X::writeByte(__IO regsize_t *reg_set, __IO regsize_t *reg_clr, regsize_t *mask, uint8_t value)
+{
+    do
+    {
+    // bit7
+        *reg_set = mask[0];
+        DELAY_T0H();
+        *reg_clr = mask[(value >> 7) & 1];
+        DELAY_T1H();
+        *reg_clr = mask[0];
+        DELAY_TLOW();
+
+    // bit6
+        *reg_set = mask[0];
+        DELAY_T0H();
+        *reg_clr = mask[(value >> 6) & 1];
+        DELAY_T1H();
+        *reg_clr = mask[0];
+        DELAY_TLOW();
+
+    // bit5
+        *reg_set = mask[0];
+        DELAY_T0H();
+        *reg_clr = mask[(value >> 5) & 1];
+        DELAY_T1H();
+        *reg_clr = mask[0];
+        DELAY_TLOW();
+
+    // bit4
+        *reg_set = mask[0];
+        DELAY_T0H();
+        *reg_clr = mask[(value >> 4) & 1];
+        DELAY_T1H();
+        *reg_clr = mask[0];
+        DELAY_TLOW();
+
+    // bit3
+        *reg_set = mask[0];
+        DELAY_T0H();
+        *reg_clr = mask[(value >> 3) & 1];
+        DELAY_T1H();
+        *reg_clr = mask[0];
+        DELAY_TLOW();
+
+    // bit2
+        *reg_set = mask[0];
+        DELAY_T0H();
+        *reg_clr = mask[(value >> 2) & 1];
+        DELAY_T1H();
+        *reg_clr = mask[0];
+        DELAY_TLOW();
+
+    // bit1
+        *reg_set = mask[0];
+        DELAY_T0H();
+        *reg_clr = mask[(value >> 1) & 1];
+        DELAY_T1H();
+        *reg_clr = mask[0];
+        DELAY_TLOW();
+
+    // bit0
+        *reg_set = mask[0];
+        DELAY_T0H();
+        *reg_clr = mask[(value >> 0) & 1];
+        DELAY_T1H();
+        *reg_clr = mask[0];
+        DELAY_TLOW2();
+
+    } while (0);
+}
+
+void WS281X::show()
+{
+// CPU_FREQ = 30MHz -> 0.0333us/cycle
+// WS2811 0: 0.25us+1.0us, 1: 1.0us+0.25us
+// WS2812 0: 0.45us+0.8us, 1: 0.8us+0.45us
+
+#if defined(TARGET_NXP)
+    __IO uint32_t *reg_set = _gpio.reg_set;
+    __IO uint32_t *reg_clr = _gpio.reg_clr;
+    uint32_t mask[2] = { _gpio.mask, 0 };
+#elif defined(TARGET_STM32F0) || defined(TARGET_STM32F1)
+    __IO uint32_t *reg_set = _gpio.reg_set;
+    __IO uint32_t *reg_clr = _gpio.reg_clr;
+    uint32_t mask[2] = { _gpio.mask, 0 };
+#elif defined(TARGET_STM)
+    __IO uint16_t *reg_set = (__IO uint16_t *)_gpio.reg_set_clr;
+    __IO uint16_t *reg_clr = reg_set + 1;
+    uint16_t mask[2] = { _gpio.mask, 0 };
+#endif
+
+    uint8_t *pix = (uint8_t *)_pixels;
+    uint8_t *end = pix + (_numPixels * sizeof(_pixels[0]));
+
+    __disable_irq();   // Disable interrupts temporarily because we don't want our pulse timing to be messed up.
+
+    uint8_t value;
+    do
+    {
+        value = pix[_1st];
+        writeByte(reg_set, reg_clr, mask, value);
+        DELAY_SPACE();
+
+        value = pix[_2nd];
+        writeByte(reg_set, reg_clr, mask, value);
+        DELAY_SPACE();
+
+        value = pix[_3rd];
+        writeByte(reg_set, reg_clr, mask, value);
+        pix += sizeof(_pixels[0]);
+        DELAY_NEXT();
+    } while (pix < end);
+
+    __enable_irq();   // Re-enable interrupts now that we are done.
+
+    wait_us(50);
+}
+
+// 先頭から指定サイズ分のブロックをバッファの最後までコピーする
+void WS281X::repeatBlock(int block_size)
+{
+    if (block_size < 1 || block_size >= _numPixels)
+        return;
+
+    RGBColor *dest = _pixels + block_size;
+    int left = _numPixels - block_size;
+    while (left > block_size)
+    {
+        memcpy(dest, _pixels, block_size * sizeof(_pixels[0]));
+        dest += block_size;
+        left -= block_size;
+        block_size <<= 1;       // 次回は2倍のサイズの転送
+    }
+    memcpy(dest, _pixels, left * sizeof(_pixels[0]));
+}
+
+// 指定色でバッファを埋める
+void WS281X::clear(uint32_t color)
+{
+    _pixels[0] = color;
+    repeatBlock(1);
+}
+
+// 指定色でバッファを埋めた後表示
+void WS281X::show(uint32_t color)
+{
+    clear(color);
+    show();
+}
+
+//----------------------------------------------------------------------------