├── LICENSE ├── README.md ├── examples ├── a-rainbow │ └── a-rainbow.cpp ├── extra-examples │ └── extra-examples.cpp └── rgbw-strandtest │ └── rgbw-strandtest.cpp ├── library.properties └── src ├── neopixel.cpp ├── neopixel.h └── neopixel └── neopixel.h /LICENSE: -------------------------------------------------------------------------------- 1 | This package is free software; you can redistribute it and/or modify it 2 | under the terms of the GNU Lesser General Public License as published by 3 | the Free Software Foundation; either version 3 of the License, or (at 4 | your option) any later version. 5 | 6 | This package is distributed in the hope that it will be useful, but 7 | WITHOUT ANY WARRANTY; without even the implied warranty of 8 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 9 | General Public License for more details. 10 | 11 | The complete text of the GNU Lesser General 12 | Public License can be found at . 13 | 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Particle-NeoPixel 2 | 3 | A library for manipulating NeoPixel RGB LEDs for the: 4 | 5 | Particle Core, Photon, P1, Electron, Argon, Boron, Xenon and RedBear Duo 6 | 7 | Implementation based on Adafruit's NeoPixel Library. 8 | 9 | ## Supported Pixel Types 10 | - 800 KHz WS2812, WS2812B, WS2813 and 400kHz bitstream and WS2811 11 | - 800 KHz bitstream SK6812RGBW (NeoPixel RGBW pixel strips) 12 | (use 'SK6812RGBW' as PIXEL_TYPE) 13 | 14 | The most common kinds are WS2812/WS2813 (6-pin part), WS2812B (4-pin part) and SK6812RGBW (3 colors + white). 15 | 16 | #### Also supports these less common pixels 17 | 18 | - Radio Shack Tri-Color LED Strip with TM1803 controller 400kHz bitstream. 19 | - TM1829 pixels, many [details here.](https://community.particle.io/t/neopixel-library-for-tm1829-controller-resolved/5363) 20 | - Some functions from the [MessageTorch library](https://github.com/plan44/messagetorch/blob/master/messagetorch.cpp#L58-L134) have been added. 21 | - SK6812MINI "NeoPixel Mini" (use 'WS2812B' as `PIXEL_TYPE`) 22 | 23 | ## Usage 24 | 25 | Set up the hardware: 26 | 27 | - A NeoPixel digital RGB LED (get at [adafruit.com](https://www.adafruit.com)) 28 | - or a Radio Shack Tri-Color LED Strip (get at [radioshack.com](https://www.radioshack.com)) 29 | - A power supply or breakout board to supply NeoPixel's with 5V 30 | 31 | Flash the [rainbow example](examples/a-rainbow/a-rainbow.cpp). With the 32 | [Particle CLI](https://docs.particle.io/guide/tools-and-features/cli/) 33 | do `particle flash examples/a-rainbow` 34 | 35 | Adapt it to your needs while keeping this general structure: 36 | 37 | ```cpp 38 | Adafruit_NeoPixel strip(PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE); 39 | void setup() { 40 | strip.begin(); 41 | strip.show(); 42 | } 43 | void loop() { 44 | // change your pixel colors and call strip.show() again 45 | } 46 | ``` 47 | 48 | ## Documentation 49 | 50 | ### `Adafruit_NeoPixel` 51 | 52 | ``` 53 | // IMPORTANT: Set pixel COUNT, PIN and TYPE 54 | #define PIXEL_COUNT 10 55 | #define PIXEL_PIN D2 56 | #define PIXEL_TYPE WS2812B 57 | Adafruit_NeoPixel strip(PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE); 58 | ``` 59 | 60 | Creates an object to interact wth a NeoPixel strip. 61 | 62 | `PIXEL_COUNT` is the number of pixels in strip. 63 | 64 | _Note: for some stripes like those with the TM1829, you need to count the number of segments, i.e. the number of controllers in your stripe, not the number of individual LEDs!_ 65 | 66 | `PIXEL_PIN` is the pin number where your NeoPixel are connected (A0-A7, D0-D7, etc). If omitted, D2 is used. 67 | 68 | On Photon, Electron, P1, Core and Duo, any pin can be used for Neopixel. 69 | 70 | On the Argon, Boron and Xenon, only these pins can be used for Neopixel: 71 | - D2, D3, A4, A5 72 | - D4, D6, D7, D8 73 | - A0, A1, A2, A3 74 | 75 | In addition on the Argon/Boron/Xenon, only one pin per group can be used at a time. So it's OK to have one Adafruit_NeoPixel 76 | instance on pin D2 and another one on pin A2, but it's not possible to have one on pin A0 and another 77 | one on pin A1. 78 | 79 | `PIXEL_TYPE` is the type of LED, one of WS2811, WS2812, WS2812B, WS2812B2, WS2813, TM1803, TM1829, SK6812RGBW. If omitted, WS2812B is used. 80 | 81 | _Note: For legacy 50us reset pulse timing on WS2812/WS2812B or WS2812B2, select WS2812B_FAST or WS2812B2_FAST respectively. Otherwise, 300us timing will be used._ 82 | 83 | _Note: RGB order is automatically applied to WS2811, WS2812/WS2812B/WS2812B2/WS2813/TM1803 is GRB order._ 84 | 85 | ### `begin` 86 | 87 | `strip.begin();` 88 | 89 | Sets up the pin used for the NeoPixel strip. 90 | 91 | ### `setPixelColor` 92 | ### `setColor` 93 | 94 | ``` 95 | strip.setPixelColor(num, red, green, blue); 96 | strip.setPixelColor(num, red, green, blue, white); 97 | strip.setPixelColor(num, color); 98 | strip.setColor(num, red, green, blue); 99 | strip.setColor(num, red, green, blue, white); 100 | ``` 101 | 102 | Set the color of LED number `num` (0 to `PIXEL_COUNT-1`). `red`, 103 | `green`, `blue`, `white` are between 0 and 255. White is only used for 104 | RGBW type pixels. `color` is a color returned from [`Color`](#color). 105 | 106 | The brightness set with `setBrightness` will modify the color before it 107 | is applied to the LED. 108 | 109 | ### `show` 110 | 111 | `strip.show();` 112 | 113 | Displays the colors on the NeoPixel strip that were set with `setPixelColor` and other calls that change the color of LEDs. 114 | 115 | This function takes some time to run (more time the more LEDs you have) and disables interrupts while running. 116 | 117 | ### `clear` 118 | 119 | `strip.clear();` 120 | 121 | Set all LED color to off. Will take effect on next `show()`. 122 | 123 | ### `setBrightness` 124 | 125 | `strip.setBrightness(brightness);` 126 | 127 | Make the LED less bright. `brightness` is from 0 (off) to 255 (max brightness) and defaults to 255. 128 | 129 | This factor is not linear: 128 is not visibly half as bright as 255 but almost as bright. 130 | 131 | ### `getBrightness` 132 | 133 | `uint8_t brightness = strip.getBrightness();` 134 | 135 | Get the current brightness. 136 | 137 | ### `setColorScaled` 138 | 139 | ``` 140 | strip.setColorScaled(num, red, green, blue, scaling); 141 | strip.setColorScaled(num, red, green, blue, white, scaling); 142 | ``` 143 | 144 | Set the color of LED number `num` and scale that color non-linearly according to the `scaling` parameter (0 to 255). 145 | 146 | ### `setColorDimmed` 147 | 148 | ``` 149 | strip.setColorDimmed(num, red, green, blue, brightness); 150 | strip.setColorDimmed(num, red, green, blue, white, brightness); 151 | ``` 152 | 153 | Set the color of LED number `num` and dim that color linearly according to the `brightness` parameter (0 to 255). In this case 128 should look half as bright as 255. 154 | 155 | ### `Color` 156 | 157 | ``` 158 | uint32_t color = strip.Color(red, green, blue); 159 | uint32_t color = strip.Color(red, green, blue, white); 160 | ``` 161 | 162 | Make a color from component colors. Useful if you want to store colors in a variable or pass them as function arguments. 163 | 164 | ### `getPixelColor` 165 | 166 | `uint32_t color = strip.getPixelColor();` 167 | 168 | Get the current color of an LED in the same format as [`Color`](#color). 169 | 170 | ### `setPin` 171 | 172 | `strip.setPin(pinNumber);` 173 | 174 | Change the pin used for the NeoPixel strip. 175 | 176 | ### `updateLength` 177 | 178 | `strip.updateLength(n);` 179 | 180 | Change the number of LEDs in the NeoPixel strip. 181 | 182 | ### `getPixels` 183 | 184 | `uint8_t *pixels = strip.getPixels();` 185 | 186 | Get the raw color data for the LEDs. 187 | 188 | ### `getNumLeds` 189 | ### `numPixels` 190 | 191 | ``` 192 | uint16_t n = strip.getNumLeds(); 193 | uint16_t n = strip.numPixels(); 194 | ``` 195 | 196 | Get the number of LEDs in the NeoPixel strip. `numPixels` is an alias for `getNumLeds`. 197 | 198 | ## Nuances 199 | 200 | - Make sure get the # of pixels, pin number, type of pixels correct 201 | - NeoPixels require 5V logic level inputs and the Spark Core and Photon only have 3.3V logic level digital outputs. Level shifting from 3.3V to 5V is necessary, the Particle Shield Shield has the [TXB0108PWR](http://www.digikey.com/product-search/en?pv7=2&k=TXB0108PWR) 3.3V to 5V level shifter built in (but has been known to oscillate at 50MHz with wire length longer than 6"), alternatively you can wire up your own with a [SN74HCT245N](http://www.digikey.com/product-detail/en/SN74HCT245N/296-1612-5-ND/277258), or [SN74HCT125N](http://www.digikey.com/product-detail/en/SN74HCT125N/296-8386-5-ND/376860). These are rock solid. 202 | - To reduce NeoPixel burnout risk, add 1000 uF capacitor across pixel power leads, add 300 - 500 Ohm resistor on first pixel's data input and minimize distance between device and first pixel. Avoid connecting on a live circuit. If you must, connect GND first. 203 | - Don't use `getPixelColor()` to move pixel data around when you are also using `setBrightness()`. When the brightness is set, all `setPixelColor()` calls will end up scaling colors to dim them before they are stored in memory. When using `getPixelColor()` the stored dimmed color is rescaled back up to the original color. However, due to some loss of precision with the math, it is not possible to recreate this color data perfectly. This is especially true with low brightness values. If you `get` and `set` color data repeatedly with a dimmed pixel, it will eventually continue to decrease in value until it is equal to zero. 204 | - When changing the brightness, always call `setPixelColor()` first with fresh un-dimmed color data, then call `setBrightness()`, and finally `show()`. 205 | 206 | ## References 207 | 208 | - NeoPixel Guide: https://learn.adafruit.com/adafruit-neopixel-uberguide 209 | - Quad Level Shifter IC: [SN74ACHT125N](https://www.adafruit.com/product/1787) (Adafruit) 210 | - Quad Level Shifter IC: [SN74HCT125N](http://www.digikey.com/product-detail/en/SN74HCT125N/296-8386-5-ND/376860) (Digikey) 211 | - Quad Level Shifter IC: [SN74AHCT125N](http://www.digikey.com/product-detail/en/SN74AHCT125N/296-4655-5-ND/375798) (Digikey) 212 | 213 | ## License 214 | Copyright 2014-2018 Technobly, Julien Vanier, Cullen Shane, Phil Burgess 215 | 216 | Released under the LGPL license 217 | -------------------------------------------------------------------------------- /examples/a-rainbow/a-rainbow.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This is a minimal example, see extra-examples.cpp for a version 3 | * with more explantory documentation, example routines, how to 4 | * hook up your pixels and all of the pixel types that are supported. 5 | * 6 | * On Photon, Electron, P1, Core and Duo, any pin can be used for Neopixel. 7 | * 8 | * On the Argon, Boron and Xenon, only these pins can be used for Neopixel: 9 | * - D2, D3, A4, A5 10 | * - D4, D6, D7, D8 11 | * - A0, A1, A2, A3 12 | * 13 | * On Photon 2 / P2, only SPI(MOSI) or SPI1(D2) can be used for Neopixel, 14 | * and only PIXEL_TYPE's WS2812, WS2812B, WS2813 are supported. 15 | * - MISO (D12), SCK (D13) and SS (D8) can be used as GPIO when using SPI 16 | * - MISO1 (D3), SCK1 (D4) and SS1 (D5) can be used and GPIO when using SPI1 17 | * note: You may want to call System.disableFeature(FEATURE_ETHERNET_DETECTION); 18 | * to disable automatic Ethernet driver detection, which will cause some 19 | * glitches to SPI1 pins D2,D3,D4. 20 | * 21 | * In addition on the Argon/Boron/Xenon, only one pin per group can be used at a time. 22 | * So it's OK to have one Adafruit_NeoPixel instance on pin D2 and another one on pin 23 | * A2, but it's not possible to have one on pin A0 and another one on pin A1. 24 | */ 25 | 26 | #include "Particle.h" 27 | #include "neopixel.h" 28 | 29 | SYSTEM_MODE(AUTOMATIC); 30 | 31 | // IMPORTANT: Set pixel COUNT, PIN and TYPE 32 | #if (PLATFORM_ID == 32) 33 | // MOSI pin MO 34 | #define PIXEL_PIN SPI 35 | // MOSI pin D2 36 | // #define PIXEL_PIN SPI1 37 | #else // #if (PLATFORM_ID == 32) 38 | #define PIXEL_PIN D3 39 | #endif 40 | #define PIXEL_COUNT 11 41 | #define PIXEL_TYPE WS2812B 42 | 43 | Adafruit_NeoPixel strip(PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE); 44 | 45 | // Prototypes for local build, ok to leave in for Build IDE 46 | void rainbow(uint8_t wait); 47 | uint32_t Wheel(byte WheelPos); 48 | 49 | void setup() 50 | { 51 | strip.begin(); 52 | strip.show(); // Initialize all pixels to 'off' 53 | } 54 | 55 | void loop() 56 | { 57 | rainbow(20); 58 | } 59 | 60 | void rainbow(uint8_t wait) { 61 | uint16_t i, j; 62 | 63 | for(j=0; j<256; j++) { 64 | for(i=0; i> 8); 110 | } 111 | uint8_t green(uint32_t c) { 112 | return (c >> 16); 113 | } 114 | uint8_t blue(uint32_t c) { 115 | return (c); 116 | } 117 | 118 | // Fill the dots one after the other with a color 119 | void colorWipe(uint32_t c, uint8_t wait) { 120 | for(uint16_t i=0; i= 0 ; j--){ 137 | for(uint16_t i=0; i 255 - fadeMax ) { 170 | fadeVal--; 171 | } 172 | 173 | strip.show(); 174 | delay(wait); 175 | } 176 | } 177 | 178 | delay(500); 179 | 180 | for(int k = 0 ; k < whiteLoops ; k ++) { 181 | for(int j = 0; j < 256 ; j++) { 182 | for(uint16_t i=0; i < strip.numPixels(); i++) { 183 | strip.setPixelColor(i, strip.Color(0,0,0, gamma[j] ) ); 184 | } 185 | strip.show(); 186 | } 187 | 188 | delay(2000); 189 | for(int j = 255; j >= 0 ; j--) { 190 | for(uint16_t i=0; i < strip.numPixels(); i++) { 191 | strip.setPixelColor(i, strip.Color(0,0,0, gamma[j] ) ); 192 | } 193 | strip.show(); 194 | } 195 | } 196 | 197 | delay(500); 198 | } 199 | 200 | void whiteOverRainbow(uint8_t wait, uint8_t whiteSpeed, uint8_t whiteLength ) { 201 | 202 | if(whiteLength >= strip.numPixels()) whiteLength = strip.numPixels() - 1; 203 | 204 | int head = whiteLength - 1; 205 | int tail = 0; 206 | int loops = 3; 207 | int loopNum = 0; 208 | static unsigned long lastTime = 0; 209 | 210 | while(true) { 211 | for(int j=0; j<256; j++) { 212 | for(uint16_t i=0; i= tail && i <= head) 214 | || (tail > head && i >= tail) 215 | || (tail > head && i <= head) ) { 216 | strip.setPixelColor(i, strip.Color(0,0,0, 255 ) ); 217 | } else { 218 | strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255)); 219 | } 220 | } 221 | 222 | if(millis() - lastTime > whiteSpeed) { 223 | head++; 224 | tail++; 225 | if(head == strip.numPixels()) { 226 | loopNum++; 227 | } 228 | lastTime = millis(); 229 | } 230 | 231 | if(loopNum == loops) return; 232 | 233 | head %= strip.numPixels(); 234 | tail %= strip.numPixels(); 235 | strip.show(); 236 | delay(wait); 237 | } 238 | } 239 | 240 | } 241 | 242 | void fullWhite() { 243 | for(uint16_t i=0; i. 52 | -------------------------------------------------------------------------*/ 53 | 54 | #include "neopixel.h" 55 | 56 | #if PLATFORM_ID == 0 // Core (0) 57 | #define pinLO(_pin) (PIN_MAP[_pin].gpio_peripheral->BRR = PIN_MAP[_pin].gpio_pin) 58 | #define pinHI(_pin) (PIN_MAP[_pin].gpio_peripheral->BSRR = PIN_MAP[_pin].gpio_pin) 59 | #elif (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88) 60 | #if SYSTEM_VERSION < SYSTEM_VERSION_ALPHA(5,0,0,2) 61 | STM32_Pin_Info* PIN_MAP2 = HAL_Pin_Map(); // Pointer required for highest access speed 62 | #else 63 | STM32_Pin_Info* PIN_MAP2 = hal_pin_map(); // Pointer required for highest access speed 64 | #endif // SYSTEM_VERSION < SYSTEM_VERSION_ALPHA(5,0,0,2) 65 | #define pinLO(_pin) (PIN_MAP2[_pin].gpio_peripheral->BSRRH = PIN_MAP2[_pin].gpio_pin) 66 | #define pinHI(_pin) (PIN_MAP2[_pin].gpio_peripheral->BSRRL = PIN_MAP2[_pin].gpio_pin) 67 | #elif HAL_PLATFORM_NRF52840 // Argon, Boron, Xenon, B SoM, B5 SoM, E SoM X, Tracker 68 | #include "nrf.h" 69 | #include "nrf_gpio.h" 70 | #include "pinmap_impl.h" 71 | #if SYSTEM_VERSION < SYSTEM_VERSION_ALPHA(5,0,0,2) 72 | NRF5x_Pin_Info* PIN_MAP2 = HAL_Pin_Map(); 73 | #else 74 | NRF5x_Pin_Info* PIN_MAP2 = hal_pin_map(); 75 | #endif // SYSTEM_VERSION < SYSTEM_VERSION_ALPHA(5,0,0,2) 76 | #define pinLO(_pin) (nrf_gpio_pin_clear(NRF_GPIO_PIN_MAP(PIN_MAP2[_pin].gpio_port, PIN_MAP2[_pin].gpio_pin))) 77 | #define pinHI(_pin) (nrf_gpio_pin_set(NRF_GPIO_PIN_MAP(PIN_MAP2[_pin].gpio_port, PIN_MAP2[_pin].gpio_pin))) 78 | #elif (PLATFORM_ID == 32) // HAL_PLATFORM_RTL872X 79 | // nothing extra needed for P2 80 | #else 81 | #error "*** PLATFORM_ID not supported by this library. PLATFORM should be Particle Core, Photon, Electron, Argon, Boron, Xenon, RedBear Duo, B SoM, B5 SoM, E SoM X, Tracker or P2 ***" 82 | #endif 83 | // fast pin access 84 | #define pinSet(_pin, _hilo) (_hilo ? pinHI(_pin) : pinLO(_pin)) 85 | 86 | #if (PLATFORM_ID == 32) 87 | Adafruit_NeoPixel::Adafruit_NeoPixel(uint16_t n, SPIClass& spi, uint8_t t) : 88 | begun(false), type(t), brightness(0), pixels(NULL), endTime(0) 89 | { 90 | updateLength(n); 91 | spi_ = &spi; 92 | } 93 | #else 94 | Adafruit_NeoPixel::Adafruit_NeoPixel(uint16_t n, uint8_t p, uint8_t t) : 95 | begun(false), type(t), brightness(0), pixels(NULL), endTime(0) 96 | { 97 | updateLength(n); 98 | setPin(p); 99 | } 100 | 101 | #endif // #if (PLATFORM_ID == 32) 102 | 103 | Adafruit_NeoPixel::~Adafruit_NeoPixel() { 104 | if (pixels) free(pixels); 105 | #if (PLATFORM_ID == 32) 106 | spi_->end(); 107 | #else 108 | if (begun) pinMode(pin, INPUT); 109 | #endif 110 | } 111 | 112 | uint8_t Adafruit_NeoPixel::getPin() const { 113 | return pin; 114 | } 115 | 116 | uint8_t Adafruit_NeoPixel::getType() const { 117 | return type; 118 | } 119 | 120 | void Adafruit_NeoPixel::updateLength(uint16_t n) { 121 | if (pixels) free(pixels); // Free existing data (if any) 122 | 123 | // Allocate new data -- note: ALL PIXELS ARE CLEARED 124 | numBytes = n * ((type == SK6812RGBW) ? 4 : 3); 125 | if ((pixels = (uint8_t *)malloc(numBytes))) { 126 | memset(pixels, 0, numBytes); 127 | numLEDs = n; 128 | } else { 129 | numLEDs = numBytes = 0; 130 | } 131 | } 132 | 133 | void Adafruit_NeoPixel::begin(void) { 134 | #if (PLATFORM_ID == 32) 135 | if (getType() == WS2812B) { 136 | if (spi_->interface() >= HAL_PLATFORM_SPI_NUM) { 137 | Log.error("SPI/SPI1 interface not defined!"); 138 | return; 139 | } 140 | 141 | pin_t sckPin = SCK; 142 | pin_t misoPin = MISO; 143 | if (spi_->interface() == HAL_SPI_INTERFACE1) { 144 | sckPin = SCK; 145 | misoPin = MISO; 146 | } else if (spi_->interface() == HAL_SPI_INTERFACE2) { 147 | sckPin = SCK1; 148 | misoPin = MISO1; 149 | } 150 | PinMode sckPinMode = getPinMode(sckPin); 151 | PinMode misoPinMode = getPinMode(misoPin); 152 | int sckValue = (sckPinMode == OUTPUT) ? digitalRead(sckPin) : 0; 153 | int misoValue = (misoPinMode == OUTPUT) ? digitalRead(misoPin) : 0; 154 | // spi_->begin(PIN_INVALID); // PIN_INVALID will keep begin from taking over the default SS/SS1 pin as OUTPUT 155 | // Note: no Wiring API yet to configure SPI for MOSI ONLY 156 | hal_spi_config_t spi_config = {}; 157 | spi_config.size = sizeof(spi_config); 158 | spi_config.version = HAL_SPI_CONFIG_VERSION; 159 | spi_config.flags = (uint32_t)HAL_SPI_CONFIG_FLAG_MOSI_ONLY; 160 | hal_spi_begin_ext(spi_->interface(), SPI_MODE_MASTER, PIN_INVALID, &spi_config); 161 | spi_->setClockSpeed(3125000); // DVOS 5.7.0 requires setClockSpeed() to be set after begin() 162 | // allow SCLK and MISO pin to be used as GPIO 163 | pinMode(sckPin, sckPinMode); 164 | pinMode(misoPin, misoPinMode); 165 | if (sckPinMode == OUTPUT) { 166 | digitalWrite(sckPin, sckValue); 167 | } 168 | if (misoPinMode == OUTPUT) { 169 | digitalWrite(misoPin, misoValue); 170 | } 171 | } 172 | #else 173 | pinMode(pin, OUTPUT); 174 | digitalWrite(pin, LOW); 175 | #endif // #if (PLATFORM_ID == 32) 176 | begun = true; 177 | } 178 | 179 | // Set the output pin number 180 | void Adafruit_NeoPixel::setPin(uint8_t p) { 181 | if (begun) { 182 | pinMode(pin, INPUT); 183 | } 184 | pin = p; 185 | if (begun) { 186 | pinMode(p, OUTPUT); 187 | digitalWrite(p, LOW); 188 | } 189 | } 190 | 191 | void Adafruit_NeoPixel::show(void) { 192 | if(!pixels) return; 193 | 194 | #if (PLATFORM_ID != 32) 195 | // Data latch = 24 or 50 microsecond pause in the output stream. Rather than 196 | // put a delay at the end of the function, the ending time is noted and 197 | // the function will simply hold off (if needed) on issuing the 198 | // subsequent round of data until the latch time has elapsed. This 199 | // allows the mainline code to start generating the next frame of data 200 | // rather than stalling for the latch. 201 | uint32_t wait_time; // wait time in microseconds. 202 | switch(type) { 203 | case TM1803: { // TM1803 = 24us reset pulse 204 | wait_time = 24L; 205 | } break; 206 | case SK6812RGBW: { // SK6812RGBW = 80us reset pulse 207 | wait_time = 80L; 208 | } break; 209 | case TM1829: { // TM1829 = 500us reset pulse 210 | wait_time = 500L; 211 | } break; 212 | case WS2812B: // WS2812, WS2812B & WS2813 = 300us reset pulse 213 | case WS2812B2: { 214 | wait_time = 300L; 215 | } break; 216 | case WS2811: // WS2811, WS2812B_FAST & WS2812B2_FAST = 50us reset pulse 217 | case WS2812B_FAST: 218 | case WS2812B2_FAST: 219 | default: { // default = 50us reset pulse 220 | wait_time = 50L; 221 | } break; 222 | } 223 | while((micros() - endTime) < wait_time); 224 | // endTime is a private member (rather than global var) so that multiple 225 | // instances on different pins can be quickly issued in succession (each 226 | // instance doesn't delay the next). 227 | #endif // (PLATFORM_ID != 32) 228 | 229 | #if (PLATFORM_ID == 0) || (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Core (0), Photon (6), P1 (8), Electron (10) or Redbear Duo (88) 230 | __disable_irq(); // Need 100% focus on instruction timing 231 | 232 | volatile uint32_t 233 | c, // 24-bit/32-bit pixel color 234 | mask; // 1-bit mask 235 | volatile uint16_t i = numBytes; // Output loop counter 236 | volatile uint8_t 237 | j, // 8-bit inner loop counter 238 | *ptr = pixels, // Pointer to next byte 239 | g, // Current green byte value 240 | r, // Current red byte value 241 | b, // Current blue byte value 242 | w; // Current white byte value 243 | 244 | if(type == WS2812B || type == WS2812B_FAST) { // Same as WS2812 & WS2813, 800 KHz bitstream 245 | while(i) { // While bytes left... (3 bytes = 1 pixel) 246 | mask = 0x800000; // reset the mask 247 | i = i-3; // decrement bytes remaining 248 | g = *ptr++; // Next green byte value 249 | r = *ptr++; // Next red byte value 250 | b = *ptr++; // Next blue byte value 251 | c = ((uint32_t)g << 16) | ((uint32_t)r << 8) | b; // Pack the next 3 bytes to keep timing tight 252 | j = 0; // reset the 24-bit counter 253 | do { 254 | pinSet(pin, HIGH); // HIGH 255 | if (c & mask) { // if masked bit is high 256 | // WS2812 spec 700ns HIGH 257 | // Adafruit on Arduino (meas. 812ns) 258 | // This lib on Spark Core (meas. 804ns) 259 | // This lib on Photon (meas. 792ns) 260 | asm volatile( 261 | "mov r0, r0" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 262 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 263 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 264 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 265 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 266 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 267 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 268 | "nop" "\n\t" "nop" "\n\t" 269 | #if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88) 270 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 271 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 272 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 273 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 274 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 275 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 276 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 277 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 278 | #endif 279 | ::: "r0", "cc", "memory"); 280 | // WS2812 spec 600ns LOW 281 | // Adafruit on Arduino (meas. 436ns) 282 | // This lib on Spark Core (meas. 446ns) 283 | // This lib on Photon (meas. 434ns) 284 | pinSet(pin, LOW); // LOW 285 | asm volatile( 286 | "mov r0, r0" "\n\t" 287 | #if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88) 288 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 289 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 290 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 291 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 292 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 293 | "nop" "\n\t" 294 | #endif 295 | ::: "r0", "cc", "memory"); 296 | } 297 | else { // else masked bit is low 298 | // WS2812 spec 350ns HIGH 299 | // Adafruit on Arduino (meas. 312ns) 300 | // This lib on Spark Core (meas. 318ns) 301 | // This lib on Photon (meas. 308ns) 302 | asm volatile( 303 | "mov r0, r0" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 304 | #if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88) 305 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 306 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 307 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 308 | "nop" "\n\t" 309 | #endif 310 | ::: "r0", "cc", "memory"); 311 | // WS2812 spec 800ns LOW 312 | // Adafruit on Arduino (meas. 938ns) 313 | // This lib on Spark Core (meas. 944ns) 314 | // This lib on Photon (meas. 936ns) 315 | pinSet(pin, LOW); // LOW 316 | asm volatile( 317 | "mov r0, r0" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 318 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 319 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 320 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 321 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 322 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 323 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 324 | #if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88) 325 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 326 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 327 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 328 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 329 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 330 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 331 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 332 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 333 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 334 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 335 | "nop" "\n\t" "nop" "\n\t" 336 | #endif 337 | ::: "r0", "cc", "memory"); 338 | } 339 | mask >>= 1; 340 | } while ( ++j < 24 ); // ... pixel done 341 | } // end while(i) ... no more pixels 342 | } 343 | else if(type == SK6812RGBW) { // similar to WS2812, 800 KHz bitstream but with RGB+W components 344 | while(i) { // While bytes left... (4 bytes = 1 pixel) 345 | mask = 0x80000000; // reset the mask 346 | i = i-4; // decrement bytes remaining 347 | r = *ptr++; // Next red byte value 348 | g = *ptr++; // Next green byte value 349 | b = *ptr++; // Next blue byte value 350 | w = *ptr++; // Next white byte value 351 | c = ((uint32_t)r << 24) | ((uint32_t)g << 16) | ((uint32_t)b << 8) | w; // Pack the next 4 bytes to keep timing tight 352 | j = 0; // reset the 32-bit counter 353 | do { 354 | pinSet(pin, HIGH); // HIGH 355 | if (c & mask) { // if masked bit is high 356 | // SK6812RGBW spec 600ns HIGH 357 | // WS2812 spec 700ns HIGH 358 | // Adafruit on Arduino (meas. 812ns) 359 | // This lib on Spark Core (meas. 610ns) 360 | // This lib on Photon (meas. 608ns) 361 | asm volatile( 362 | "mov r0, r0" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 363 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 364 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 365 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 366 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 367 | #if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88) 368 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 369 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 370 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 371 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 372 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 373 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 374 | "nop" "\n\t" "nop" "\n\t" 375 | #endif 376 | ::: "r0", "cc", "memory"); 377 | // SK6812RGBW spec 600ns LOW 378 | // WS2812 spec 600ns LOW 379 | // Adafruit on Arduino (meas. 436ns) 380 | // This lib on Spark Core (meas. 598ns) 381 | // This lib on Photon (meas. 600ns) 382 | pinSet(pin, LOW); // LOW 383 | asm volatile( 384 | "mov r0, r0" "\n\t" 385 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 386 | "nop" "\n\t" 387 | #if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88) 388 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 389 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 390 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 391 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 392 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 393 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 394 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 395 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 396 | #endif 397 | ::: "r0", "cc", "memory"); 398 | } 399 | else { // else masked bit is low 400 | // SK6812RGBW spec 300ns HIGH 401 | // WS2812 spec 350ns HIGH 402 | // Adafruit on Arduino (meas. 312ns) 403 | // This lib on Spark Core (meas. 305ns) 404 | // This lib on Photon (meas. 308ns) 405 | asm volatile( 406 | "mov r0, r0" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 407 | #if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88) 408 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 409 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 410 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 411 | "nop" "\n\t" 412 | #endif 413 | ::: "r0", "cc", "memory"); 414 | // SK6812RGBW spec 900ns LOW 415 | // WS2812 spec 800ns LOW 416 | // Adafruit on Arduino (meas. 938ns) 417 | // This lib on Spark Core (meas. 904ns) 418 | // This lib on Photon (meas. 900ns) 419 | pinSet(pin, LOW); // LOW 420 | asm volatile( 421 | "mov r0, r0" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 422 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 423 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 424 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 425 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 426 | #if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88) 427 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 428 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 429 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 430 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 431 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 432 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 433 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 434 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 435 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 436 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 437 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 438 | "nop" "\n\t" 439 | #endif 440 | ::: "r0", "cc", "memory"); 441 | } 442 | mask >>= 1; 443 | } while ( ++j < 32 ); // ... pixel done 444 | } // end while(i) ... no more pixels 445 | } 446 | else if(type == WS2812B2 || type == WS2812B2_FAST) { // WS2812B with DWT timer 447 | #if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88) 448 | #define CYCLES_800_T0H 25 // 312ns (meas. 300ns) 449 | #define CYCLES_800_T0L 70 // 938ns (meas. 940ns) 450 | #define CYCLES_800_T1H 80 // 812ns (meas. 792ns) 451 | #define CYCLES_800_T1L 8 // 436ns (meas. 425ns) 452 | 453 | volatile uint32_t cyc; 454 | 455 | while(i) { // While bytes left... (3 bytes = 1 pixel) 456 | mask = 0x800000; // reset the mask 457 | i = i-3; // decrement bytes remaining 458 | g = *ptr++; // Next green byte value 459 | r = *ptr++; // Next red byte value 460 | b = *ptr++; // Next blue byte value 461 | c = ((uint32_t)g << 16) | ((uint32_t)r << 8) | b; // Pack the next 3 bytes to keep timing tight 462 | j = 0; // reset the 24-bit counter 463 | do { 464 | cyc = DWT->CYCCNT; 465 | pinSet(pin, HIGH); // HIGH 466 | if (c & mask) { // if masked bit is high 467 | while(DWT->CYCCNT - cyc < CYCLES_800_T1H); 468 | pinSet(pin, LOW); 469 | cyc = DWT->CYCCNT; 470 | while(DWT->CYCCNT - cyc < CYCLES_800_T1L); 471 | } 472 | else { // else masked bit is low 473 | while(DWT->CYCCNT - cyc < CYCLES_800_T0H); 474 | pinSet(pin, LOW); 475 | cyc = DWT->CYCCNT; 476 | while(DWT->CYCCNT - cyc < CYCLES_800_T0L); 477 | } 478 | mask >>= 1; 479 | } while ( ++j < 24 ); // ... pixel done 480 | } // end while(i) ... no more pixels 481 | #endif 482 | } 483 | else if(type == WS2811) { // WS2811, 400 KHz bitstream 484 | while(i) { // While bytes left... (3 bytes = 1 pixel) 485 | mask = 0x800000; // reset the mask 486 | i = i-3; // decrement bytes remaining 487 | r = *ptr++; // Next red byte value 488 | g = *ptr++; // Next green byte value 489 | b = *ptr++; // Next blue byte value 490 | c = ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; // Pack the next 3 bytes to keep timing tight 491 | j = 0; // reset the 24-bit counter 492 | do { 493 | pinSet(pin, HIGH); // HIGH 494 | if (c & mask) { // if masked bit is high 495 | // WS2811 spec 1.20us HIGH 496 | // Adafruit on Arduino (meas. 1.25us) 497 | // This lib on Spark Core (meas. 1.25us) 498 | // This lib on Photon (meas. 1.25us) 499 | asm volatile( 500 | "mov r0, r0" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 501 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 502 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 503 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 504 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 505 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 506 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 507 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 508 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 509 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 510 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 511 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 512 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 513 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 514 | #if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88) 515 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 516 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 517 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 518 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 519 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 520 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 521 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 522 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 523 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 524 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 525 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 526 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 527 | "nop" "\n\t" "nop" "\n\t" 528 | #endif 529 | ::: "r0", "cc", "memory"); 530 | // WS2811 spec 1.30us LOW 531 | // Adafruit on Arduino (meas. 1.25us) 532 | // This lib on Spark Core (meas. 1.24us) 533 | // This lib on Photon (meas. 1.24us) 534 | pinSet(pin, LOW); // LOW 535 | asm volatile( 536 | "mov r0, r0" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 537 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 538 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 539 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 540 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 541 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 542 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 543 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 544 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 545 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 546 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 547 | "nop" "\n\t" "nop" "\n\t" 548 | #if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88) 549 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 550 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 551 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 552 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 553 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 554 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 555 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 556 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 557 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 558 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 559 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 560 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 561 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 562 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 563 | #endif 564 | ::: "r0", "cc", "memory"); 565 | } 566 | else { // else masked bit is low 567 | // WS2811 spec 500ns HIGH 568 | // Adafruit on Arduino (meas. 500ns) 569 | // This lib on Spark Core (meas. 500ns) 570 | // This lib on Photon (meas. 500ns) 571 | asm volatile( 572 | "mov r0, r0" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 573 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 574 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 575 | #if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88) 576 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 577 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 578 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 579 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 580 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 581 | #endif 582 | "nop" "\n\t" "nop" "\n\t" 583 | ::: "r0", "cc", "memory"); 584 | // WS2811 spec 2.000us LOW 585 | // Adafruit on Arduino (meas. 2.000us) 586 | // This lib on Spark Core (meas. 2.000us) 587 | // This lib on Photon (meas. 2.000us) 588 | pinSet(pin, LOW); // LOW 589 | asm volatile( 590 | "mov r0, r0" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 591 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 592 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 593 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 594 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 595 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 596 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 597 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 598 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 599 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 600 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 601 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 602 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 603 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 604 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 605 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 606 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 607 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 608 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 609 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 610 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 611 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 612 | #if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88) 613 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 614 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 615 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 616 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 617 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 618 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 619 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 620 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 621 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 622 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 623 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 624 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 625 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 626 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 627 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 628 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 629 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 630 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 631 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 632 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 633 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 634 | #endif 635 | ::: "r0", "cc", "memory"); 636 | } 637 | mask >>= 1; 638 | } while ( ++j < 24 ); // ... pixel done 639 | } // end while(i) ... no more pixels 640 | } 641 | else if(type == TM1803) { // TM1803 (Radio Shack Tri-Color Strip), 400 KHz bitstream 642 | while(i) { // While bytes left... (3 bytes = 1 pixel) 643 | mask = 0x800000; // reset the mask 644 | i = i-3; // decrement bytes remaining 645 | r = *ptr++; // Next red byte value 646 | g = *ptr++; // Next blue byte value 647 | b = *ptr++; // Next green byte value 648 | c = ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; // Pack the next 3 bytes to keep timing tight 649 | j = 0; // reset the 24-bit counter 650 | do { 651 | pinSet(pin, HIGH); // HIGH 652 | if (c & mask) { // if masked bit is high 653 | // TM1803 spec 1.36us HIGH 654 | // Pololu on Arduino (meas. 1.31us) 655 | // This lib on Spark Core (meas. 1.36us) 656 | // This lib on Photon (meas. 1.36us) 657 | asm volatile( 658 | "mov r0, r0" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 659 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 660 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 661 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 662 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 663 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 664 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 665 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 666 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 667 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 668 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 669 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 670 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 671 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 672 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 673 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 674 | #if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88) 675 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 676 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 677 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 678 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 679 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 680 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 681 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 682 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 683 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 684 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 685 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 686 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 687 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 688 | "nop" "\n\t" 689 | #endif 690 | ::: "r0", "cc", "memory"); 691 | // TM1803 spec 680ns LOW 692 | // Pololu on Arduino (meas. 1.024us) 693 | // This lib on Spark Core (meas. 680ns) 694 | // This lib on Photon (meas. 684ns) 695 | pinSet(pin, LOW); // LOW 696 | asm volatile( 697 | "mov r0, r0" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 698 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 699 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 700 | #if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88) 701 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 702 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 703 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 704 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 705 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 706 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 707 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 708 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 709 | "nop" "\n\t" 710 | #endif 711 | ::: "r0", "cc", "memory"); 712 | } 713 | else { // else masked bit is low 714 | // TM1803 spec 680ns HIGH 715 | // Pololu on Arduino (meas. 374ns) 716 | // This lib on Spark Core (meas. 680ns) 717 | // This lib on Photon (meas. 684ns) 718 | asm volatile( 719 | "mov r0, r0" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 720 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 721 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 722 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 723 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 724 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 725 | #if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88) 726 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 727 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 728 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 729 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 730 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 731 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 732 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 733 | "nop" "\n\t" 734 | #endif 735 | ::: "r0", "cc", "memory"); 736 | // TM1803 spec 1.36us LOW 737 | // Pololu on Arduino (meas. 2.00us) 738 | // This lib on Spark Core (meas. 1.36us) 739 | // This lib on Photon (meas. 1.36us) 740 | pinSet(pin, LOW); // LOW 741 | asm volatile( 742 | "mov r0, r0" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 743 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 744 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 745 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 746 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 747 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 748 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 749 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 750 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 751 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 752 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 753 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 754 | #if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88) 755 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 756 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 757 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 758 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 759 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 760 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 761 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 762 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 763 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 764 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 765 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 766 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 767 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 768 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 769 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 770 | "nop" "\n\t" 771 | #endif 772 | ::: "r0", "cc", "memory"); 773 | } 774 | mask >>= 1; 775 | } while ( ++j < 24 ); // ... pixel done 776 | } // end while(i) ... no more pixels 777 | } 778 | else { // must be only other option TM1829, 800 KHz bitstream 779 | while(i) { // While bytes left... (3 bytes = 1 pixel) 780 | mask = 0x800000; // reset the mask 781 | i = i-3; // decrement bytes remaining 782 | r = *ptr++; // Next red byte value 783 | b = *ptr++; // Next blue byte value 784 | g = *ptr++; // Next green byte value 785 | c = ((uint32_t)r << 16) | ((uint32_t)b << 8) | g; // Pack the next 3 bytes to keep timing tight 786 | j = 0; // reset the 24-bit counter 787 | pinSet(pin, LOW); // LOW 788 | for( ;; ) { // ... pixel done 789 | if (c & mask) { // if masked bit is high 790 | // TM1829 spec 800ns LOW 791 | // This lib on Spark Core (meas. 806ns) 792 | // This lib on Photon (meas. 792ns) 793 | mask >>= 1; // Do this task during the long delay of this bit 794 | asm volatile( 795 | "mov r0, r0" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 796 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 797 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 798 | #if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88) 799 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 800 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 801 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 802 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 803 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 804 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 805 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 806 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 807 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 808 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 809 | "nop" "\n\t" "nop" "\n\t" 810 | #endif 811 | ::: "r0", "cc", "memory"); 812 | j++; 813 | // TM1829 spec 300ns HIGH 814 | // This lib on Spark Core (meas. 305ns) 815 | // This lib on Photon (meas. 300ns) 816 | pinSet(pin, HIGH); // HIGH 817 | asm volatile( 818 | "mov r0, r0" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 819 | #if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88) 820 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 821 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 822 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 823 | "nop" "\n\t" 824 | #endif 825 | ::: "r0", "cc", "memory"); 826 | if(j==24) break; 827 | pinSet(pin, LOW); // LOW 828 | } 829 | else { // else masked bit is low 830 | // TM1829 spec 300ns LOW 831 | // This lib on Spark Core (meas. 390ns) 832 | // This lib on Photon (meas. 300ns) 833 | #if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88) 834 | asm volatile( 835 | "mov r0, r0" "\n\t" 836 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 837 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 838 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 839 | "nop" "\n\t" 840 | ::: "r0", "cc", "memory"); 841 | #endif 842 | // TM1829 spec 800ns HIGH 843 | // This lib on Spark Core (meas. 792ns) 844 | // This lib on Photon (meas. 800ns) 845 | pinSet(pin, HIGH); // HIGH 846 | j++; 847 | mask >>= 1; // Do this task during the long delay of this bit 848 | asm volatile( 849 | "mov r0, r0" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 850 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 851 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 852 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 853 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 854 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 855 | #if (PLATFORM_ID == 6) || (PLATFORM_ID == 8) || (PLATFORM_ID == 10) || (PLATFORM_ID == 88) // Photon (6), P1 (8), Electron (10) or Redbear Duo (88) 856 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 857 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 858 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 859 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 860 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 861 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 862 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 863 | "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" 864 | #endif 865 | ::: "r0", "cc", "memory"); 866 | if(j==24) break; 867 | pinSet(pin, LOW); // LOW 868 | } 869 | } 870 | } // end while(i) ... no more pixels 871 | } 872 | 873 | __enable_irq(); 874 | 875 | #elif (PLATFORM_ID == 32) 876 | if (getType() != WS2812B) { // WS2812 WS2812B and WS2813 supported for P2 877 | Log.error("Pixel type not supported!"); 878 | return; 879 | } 880 | 881 | constexpr uint8_t PIX_HI = 0b110; 882 | constexpr uint8_t PIX_LO = 0b100; 883 | 884 | uint16_t resetOff = 120; // 300us / (1/3125000Mhz) / 8bits_per_byte 885 | switch (type) { 886 | case WS2812B: { // WS2812, WS2812B & WS2813 = 300us reset pulse 887 | resetOff = 120; 888 | } break; 889 | case WS2812B_FAST: // WS2812B_FAST = 50us reset pulse 890 | default: { // default = 50us reset pulse 891 | resetOff = 20; 892 | } break; 893 | } 894 | 895 | constexpr uint8_t numBitsPerBit = 3; // How many SPI bits represent one neopixel bit 896 | uint32_t spiArraySize = (numBytes * numBitsPerBit) + resetOff + resetOff; 897 | uint8_t* spiArray = NULL; 898 | spiArray = (uint8_t*) malloc(spiArraySize); 899 | 900 | if (spiArray == NULL) { 901 | Log.error("Not enough memory available!"); 902 | return; 903 | } 904 | 905 | memset(spiArray, 0, spiArraySize); 906 | // expand pixel data and pack into spi buffer 907 | for (int x = 0; x < numPixels(); x++) { 908 | for (int s = 0; s < 3; s++) { 909 | spiArray[(x*9)+(s*3)+0+resetOff] = ((0x80 & pixels[(x*3)+s])?(PIX_HI << 5):(PIX_LO << 5)) + ((0x40 & pixels[(x*3)+s])?(PIX_HI << 2):(PIX_LO << 2)) + ((0x20 & pixels[(x*3)+s])?(0b11):(0b10)); 910 | spiArray[(x*9)+(s*3)+1+resetOff] = 0 /* bit 7 always 0 */ + ((0x10 & pixels[(x*3)+s])?(PIX_HI << 4):(PIX_LO << 4)) + ((0x08 & pixels[(x*3)+s])?(PIX_HI << 1):(PIX_LO << 1)) + 1 /* bit 0 always 1 */; 911 | spiArray[(x*9)+(s*3)+2+resetOff] = ((0x04 & pixels[(x*3)+s])?(0b10 << 6):(0b00 << 6)) + ((0x02 & pixels[(x*3)+s])?(PIX_HI << 3):(PIX_LO << 3)) + ((0x01 & pixels[(x*3)+s])?(PIX_HI):(PIX_LO)); 912 | } 913 | } 914 | 915 | spi_->beginTransaction(); 916 | spi_->transfer(spiArray, nullptr, spiArraySize, nullptr); 917 | spi_->endTransaction(); 918 | 919 | free(spiArray); 920 | 921 | #elif HAL_PLATFORM_NRF52840 // Argon, Boron, Xenon, B SoM, B5 SoM, E SoM X, Tracker 922 | // [[[Begin of the Neopixel NRF52 EasyDMA implementation 923 | // by the Hackerspace San Salvador]]] 924 | // This technique uses the PWM peripheral on the NRF52. The PWM uses the 925 | // EasyDMA feature included on the chip. This technique loads the duty 926 | // cycle configuration for each cycle when the PWM is enabled. For this 927 | // to work we need to store a 16 bit configuration for each bit of the 928 | // RGB(W) values in the pixel buffer. 929 | // Comparator values for the PWM were hand picked and are guaranteed to 930 | // be 100% organic to preserve freshness and high accuracy. Current 931 | // parameters are: 932 | // * PWM Clock: 16Mhz 933 | // * Minimum step time: 62.5ns 934 | // * Time for zero in high (T0H): 0.31ms 935 | // * Time for one in high (T1H): 0.75ms 936 | // * Cycle time: 1.25us 937 | // * Frequency: 800Khz 938 | // For 400Khz we just double the calculated times. 939 | // ---------- BEGIN Constants for the EasyDMA implementation ----------- 940 | // The PWM starts the duty cycle in LOW. To start with HIGH we 941 | // need to set the 15th bit on each register. 942 | 943 | // WS2812 (rev A) timing is 0.35 and 0.7us 944 | //#define MAGIC_T0H 5UL | (0x8000) // 0.3125us 945 | //#define MAGIC_T1H 12UL | (0x8000) // 0.75us 946 | 947 | // WS2812B (rev B) timing is 0.4 and 0.8 us 948 | #define MAGIC_T0H 6UL | (0x8000) // 0.375us 949 | #define MAGIC_T1H 13UL | (0x8000) // 0.8125us 950 | 951 | // WS2811 (400 khz) timing is 0.5 and 1.2 952 | #define MAGIC_T0H_400KHz 8UL | (0x8000) // 0.5us 953 | #define MAGIC_T1H_400KHz 19UL | (0x8000) // 1.1875us 954 | 955 | // For 400Khz, we double value of CTOPVAL 956 | #define CTOPVAL 20UL // 1.25us 957 | #define CTOPVAL_400KHz 40UL // 2.5us 958 | 959 | // ---------- END Constants for the EasyDMA implementation ------------- 960 | // 961 | // If there is no device available an alternative cycle-counter 962 | // implementation is tried. 963 | // The nRF52832 runs with a fixed clock of 64Mhz. The alternative 964 | // implementation is the same as the one used for the Teensy 3.0/1/2 but 965 | // with the Nordic SDK HAL & registers syntax. 966 | // The number of cycles was hand picked and is guaranteed to be 100% 967 | // organic to preserve freshness and high accuracy. 968 | // ---------- BEGIN Constants for cycle counter implementation --------- 969 | #define CYCLES_800_T0H 18 // ~0.36 uS 970 | #define CYCLES_800_T1H 41 // ~0.76 uS 971 | #define CYCLES_800 71 // ~1.25 uS 972 | 973 | #define CYCLES_400_T0H 26 // ~0.50 uS 974 | #define CYCLES_400_T1H 70 // ~1.26 uS 975 | #define CYCLES_400 156 // ~2.50 uS 976 | // ---------- END of Constants for cycle counter implementation -------- 977 | 978 | // To support both the SoftDevice + Neopixels we use the EasyDMA 979 | // feature from the NRF25. However this technique implies to 980 | // generate a pattern and store it on the memory. The actual 981 | // memory used in bytes corresponds to the following formula: 982 | // totalMem = numBytes*8*2+(2*2) 983 | // The two additional bytes at the end are needed to reset the 984 | // sequence. 985 | // 986 | // If there is not enough memory, we will fall back to cycle counter 987 | // using DWT 988 | uint32_t pattern_size = numBytes*8*sizeof(uint16_t)+2*sizeof(uint16_t); 989 | uint16_t* pixels_pattern = NULL; 990 | 991 | NRF_PWM_Type* pwm = NULL; 992 | 993 | // Try to find a free PWM device, which is not enabled 994 | // and has no connected pins 995 | NRF_PWM_Type* PWM[3] = {NRF_PWM0, NRF_PWM1, NRF_PWM2}; 996 | for(int device = 0; device<3; device++) { 997 | if( (PWM[device]->ENABLE == 0) && 998 | (PWM[device]->PSEL.OUT[0] & PWM_PSEL_OUT_CONNECT_Msk) && 999 | (PWM[device]->PSEL.OUT[1] & PWM_PSEL_OUT_CONNECT_Msk) && 1000 | (PWM[device]->PSEL.OUT[2] & PWM_PSEL_OUT_CONNECT_Msk) && 1001 | (PWM[device]->PSEL.OUT[3] & PWM_PSEL_OUT_CONNECT_Msk) 1002 | ) { 1003 | pwm = PWM[device]; 1004 | break; 1005 | } 1006 | } 1007 | 1008 | // only malloc if there is PWM device available 1009 | if ( pwm != NULL ) { 1010 | #ifdef ARDUINO_FEATHER52 // use thread-safe malloc 1011 | pixels_pattern = (uint16_t *) rtos_malloc(pattern_size); 1012 | #else 1013 | pixels_pattern = (uint16_t *) malloc(pattern_size); 1014 | #endif 1015 | } 1016 | 1017 | // Use the identified device to choose the implementation 1018 | // If a PWM device is available use DMA 1019 | if( (pixels_pattern != NULL) && (pwm != NULL) ) { 1020 | uint16_t pos = 0; // bit position 1021 | 1022 | for(uint16_t n=0; n0; mask >>= 1, i++) { 1026 | #ifdef NEO_KHZ400 1027 | if( !is800KHz ) { 1028 | pixels_pattern[pos] = (pix & mask) ? MAGIC_T1H_400KHz : MAGIC_T0H_400KHz; 1029 | }else 1030 | #endif 1031 | { 1032 | pixels_pattern[pos] = (pix & mask) ? MAGIC_T1H : MAGIC_T0H; 1033 | } 1034 | 1035 | pos++; 1036 | } 1037 | } 1038 | 1039 | // Zero padding to indicate the end of que sequence 1040 | pixels_pattern[++pos] = 0 | (0x8000); // Seq end 1041 | pixels_pattern[++pos] = 0 | (0x8000); // Seq end 1042 | 1043 | // Set the wave mode to count UP 1044 | pwm->MODE = (PWM_MODE_UPDOWN_Up << PWM_MODE_UPDOWN_Pos); 1045 | 1046 | // Set the PWM to use the 16MHz clock 1047 | pwm->PRESCALER = (PWM_PRESCALER_PRESCALER_DIV_1 << PWM_PRESCALER_PRESCALER_Pos); 1048 | 1049 | // Setting of the maximum count 1050 | // but keeping it on 16Mhz allows for more granularity just 1051 | // in case someone wants to do more fine-tuning of the timing. 1052 | #ifdef NEO_KHZ400 1053 | if( !is800KHz ) { 1054 | pwm->COUNTERTOP = (CTOPVAL_400KHz << PWM_COUNTERTOP_COUNTERTOP_Pos); 1055 | }else 1056 | #endif 1057 | { 1058 | pwm->COUNTERTOP = (CTOPVAL << PWM_COUNTERTOP_COUNTERTOP_Pos); 1059 | } 1060 | 1061 | // Disable loops, we want the sequence to repeat only once 1062 | pwm->LOOP = (PWM_LOOP_CNT_Disabled << PWM_LOOP_CNT_Pos); 1063 | 1064 | // On the "Common" setting the PWM uses the same pattern for the 1065 | // for supported sequences. The pattern is stored on half-word 1066 | // of 16bits 1067 | pwm->DECODER = (PWM_DECODER_LOAD_Common << PWM_DECODER_LOAD_Pos) | 1068 | (PWM_DECODER_MODE_RefreshCount << PWM_DECODER_MODE_Pos); 1069 | 1070 | // Pointer to the memory storing the patter 1071 | pwm->SEQ[0].PTR = (uint32_t)(pixels_pattern) << PWM_SEQ_PTR_PTR_Pos; 1072 | 1073 | // Calculation of the number of steps loaded from memory. 1074 | pwm->SEQ[0].CNT = (pattern_size/sizeof(uint16_t)) << PWM_SEQ_CNT_CNT_Pos; 1075 | 1076 | // The following settings are ignored with the current config. 1077 | pwm->SEQ[0].REFRESH = 0; 1078 | pwm->SEQ[0].ENDDELAY = 0; 1079 | 1080 | // The Neopixel implementation is a blocking algorithm. DMA 1081 | // allows for non-blocking operation. To "simulate" a blocking 1082 | // operation we enable the interruption for the end of sequence 1083 | // and block the execution thread until the event flag is set by 1084 | // the peripheral. 1085 | // pwm->INTEN |= (PWM_INTEN_SEQEND0_Enabled<PSEL.OUT[0] = NRF_GPIO_PIN_MAP(PIN_MAP2[pin].gpio_port, PIN_MAP2[pin].gpio_pin); 1089 | 1090 | // Enable the PWM 1091 | pwm->ENABLE = 1; 1092 | 1093 | // After all of this and many hours of reading the documentation 1094 | // we are ready to start the sequence... 1095 | pwm->EVENTS_SEQEND[0] = 0; 1096 | pwm->TASKS_SEQSTART[0] = 1; 1097 | 1098 | // But we have to wait for the flag to be set. 1099 | while(!pwm->EVENTS_SEQEND[0]) 1100 | { 1101 | #ifdef ARDUINO_FEATHER52 1102 | yield(); 1103 | #endif 1104 | } 1105 | 1106 | // Before leave we clear the flag for the event. 1107 | pwm->EVENTS_SEQEND[0] = 0; 1108 | 1109 | // We need to disable the device and disconnect 1110 | // all the outputs before leave or the device will not 1111 | // be selected on the next call. 1112 | // TODO: Check if disabling the device causes performance issues. 1113 | pwm->ENABLE = 0; 1114 | 1115 | pwm->PSEL.OUT[0] = 0xFFFFFFFFUL; 1116 | 1117 | #ifdef ARDUINO_FEATHER52 // use thread-safe free 1118 | rtos_free(pixels_pattern); 1119 | #else 1120 | free(pixels_pattern); 1121 | #endif 1122 | }// End of DMA implementation 1123 | // --------------------------------------------------------------------- 1124 | else{ 1125 | // Fall back to DWT 1126 | #ifdef ARDUINO_FEATHER52 1127 | // Bluefruit Feather 52 uses freeRTOS 1128 | // Critical Section is used since it does not block SoftDevice execution 1129 | taskENTER_CRITICAL(); 1130 | #elif defined(NRF52_DISABLE_INT) 1131 | // If you are using the Bluetooth SoftDevice we advise you to not disable 1132 | // the interrupts. Disabling the interrupts even for short periods of time 1133 | // causes the SoftDevice to stop working. 1134 | // Disable the interrupts only in cases where you need high performance for 1135 | // the LEDs and if you are not using the EasyDMA feature. 1136 | __disable_irq(); 1137 | #endif 1138 | 1139 | uint32_t pinMask = 1UL << NRF_GPIO_PIN_MAP(PIN_MAP2[pin].gpio_port, PIN_MAP2[pin].gpio_pin); 1140 | 1141 | 1142 | uint32_t CYCLES_X00 = CYCLES_800; 1143 | uint32_t CYCLES_X00_T1H = CYCLES_800_T1H; 1144 | uint32_t CYCLES_X00_T0H = CYCLES_800_T0H; 1145 | 1146 | #ifdef NEO_KHZ400 1147 | if( !is800KHz ) 1148 | { 1149 | CYCLES_X00 = CYCLES_400; 1150 | CYCLES_X00_T1H = CYCLES_400_T1H; 1151 | CYCLES_X00_T0H = CYCLES_400_T0H; 1152 | } 1153 | #endif 1154 | 1155 | // Enable DWT in debug core 1156 | CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; 1157 | DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; 1158 | 1159 | // Tries to re-send the frame if is interrupted by the SoftDevice. 1160 | while(1) { 1161 | uint8_t *p = pixels; 1162 | 1163 | uint32_t cycStart = DWT->CYCCNT; 1164 | uint32_t cyc = 0; 1165 | 1166 | for(uint16_t n=0; n>= 1) { 1170 | while(DWT->CYCCNT - cyc < CYCLES_X00); 1171 | cyc = DWT->CYCCNT; 1172 | 1173 | NRF_GPIO->OUTSET |= pinMask; 1174 | 1175 | if(pix & mask) { 1176 | while(DWT->CYCCNT - cyc < CYCLES_X00_T1H); 1177 | } else { 1178 | while(DWT->CYCCNT - cyc < CYCLES_X00_T0H); 1179 | } 1180 | 1181 | NRF_GPIO->OUTCLR |= pinMask; 1182 | } 1183 | } 1184 | while(DWT->CYCCNT - cyc < CYCLES_X00); 1185 | 1186 | 1187 | // If total time longer than 25%, resend the whole data. 1188 | // Since we are likely to be interrupted by SoftDevice 1189 | if ( (DWT->CYCCNT - cycStart) < ( 8*numBytes*((CYCLES_X00*5)/4) ) ) { 1190 | break; 1191 | } 1192 | 1193 | // re-send need 300us delay 1194 | delayMicroseconds(300); 1195 | } 1196 | 1197 | // Enable interrupts again 1198 | #ifdef ARDUINO_FEATHER52 1199 | taskEXIT_CRITICAL(); 1200 | #elif defined(NRF52_DISABLE_INT) 1201 | __enable_irq(); 1202 | #endif 1203 | } 1204 | // END of NRF52 implementation 1205 | 1206 | 1207 | #endif 1208 | endTime = micros(); // Save EOD time for latch on next call 1209 | } 1210 | 1211 | // Set pixel color from separate R,G,B components: 1212 | void Adafruit_NeoPixel::setPixelColor( 1213 | uint16_t n, uint8_t r, uint8_t g, uint8_t b) { 1214 | if(n < numLEDs) { 1215 | if(brightness) { // See notes in setBrightness() 1216 | r = (r * brightness) >> 8; 1217 | g = (g * brightness) >> 8; 1218 | b = (b * brightness) >> 8; 1219 | } 1220 | uint8_t *p = &pixels[n * 3]; 1221 | switch(type) { 1222 | case WS2812B: // WS2812, WS2812B & WS2813 is GRB order. 1223 | case WS2812B_FAST: 1224 | case WS2812B2: 1225 | case WS2812B2_FAST: { 1226 | *p++ = g; 1227 | *p++ = r; 1228 | *p = b; 1229 | } break; 1230 | case TM1829: { // TM1829 is special RBG order 1231 | if(r == 255) r = 254; // 255 on RED channel causes display to be in a special mode. 1232 | *p++ = r; 1233 | *p++ = b; 1234 | *p = g; 1235 | } break; 1236 | case WS2811: // WS2811 is RGB order 1237 | case TM1803: // TM1803 is RGB order 1238 | default: { // default is RGB order 1239 | *p++ = r; 1240 | *p++ = g; 1241 | *p = b; 1242 | } break; 1243 | } 1244 | } 1245 | } 1246 | 1247 | // Set pixel color from separate R,G,B,W components: 1248 | void Adafruit_NeoPixel::setPixelColor( 1249 | uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w) { 1250 | if(n < numLEDs) { 1251 | if(brightness) { // See notes in setBrightness() 1252 | r = (r * brightness) >> 8; 1253 | g = (g * brightness) >> 8; 1254 | b = (b * brightness) >> 8; 1255 | w = (w * brightness) >> 8; 1256 | } 1257 | uint8_t *p = &pixels[n * (type==SK6812RGBW?4:3)]; 1258 | switch(type) { 1259 | case WS2812B: // WS2812, WS2812B & WS2813 is GRB order. 1260 | case WS2812B_FAST: 1261 | case WS2812B2: 1262 | case WS2812B2_FAST: { 1263 | *p++ = g; 1264 | *p++ = r; 1265 | *p = b; 1266 | } break; 1267 | case TM1829: { // TM1829 is special RBG order 1268 | if(r == 255) r = 254; // 255 on RED channel causes display to be in a special mode. 1269 | *p++ = r; 1270 | *p++ = b; 1271 | *p = g; 1272 | } break; 1273 | case SK6812RGBW: { // SK6812RGBW is RGBW order 1274 | *p++ = r; 1275 | *p++ = g; 1276 | *p++ = b; 1277 | *p = w; 1278 | } break; 1279 | case WS2811: // WS2811 is RGB order 1280 | case TM1803: // TM1803 is RGB order 1281 | default: { // default is RGB order 1282 | *p++ = r; 1283 | *p++ = g; 1284 | *p = b; 1285 | } break; 1286 | } 1287 | } 1288 | } 1289 | 1290 | // Set pixel color from 'packed' 32-bit RGB color: 1291 | // If RGB+W color, order of bytes is WRGB in packed 32-bit form 1292 | void Adafruit_NeoPixel::setPixelColor(uint16_t n, uint32_t c) { 1293 | if(n < numLEDs) { 1294 | uint8_t 1295 | r = (uint8_t)(c >> 16), 1296 | g = (uint8_t)(c >> 8), 1297 | b = (uint8_t)c; 1298 | if(brightness) { // See notes in setBrightness() 1299 | r = (r * brightness) >> 8; 1300 | g = (g * brightness) >> 8; 1301 | b = (b * brightness) >> 8; 1302 | } 1303 | uint8_t *p = &pixels[n * (type==SK6812RGBW?4:3)]; 1304 | switch(type) { 1305 | case WS2812B: // WS2812, WS2812B & WS2813 is GRB order. 1306 | case WS2812B_FAST: 1307 | case WS2812B2: 1308 | case WS2812B2_FAST: { 1309 | *p++ = g; 1310 | *p++ = r; 1311 | *p = b; 1312 | } break; 1313 | case TM1829: { // TM1829 is special RBG order 1314 | if(r == 255) r = 254; // 255 on RED channel causes display to be in a special mode. 1315 | *p++ = r; 1316 | *p++ = b; 1317 | *p = g; 1318 | } break; 1319 | case SK6812RGBW: { // SK6812RGBW is RGBW order 1320 | uint8_t w = (uint8_t)(c >> 24); 1321 | *p++ = r; 1322 | *p++ = g; 1323 | *p++ = b; 1324 | *p = brightness ? ((w * brightness) >> 8) : w; 1325 | } break; 1326 | case WS2811: // WS2811 is RGB order 1327 | case TM1803: // TM1803 is RGB order 1328 | default: { // default is RGB order 1329 | *p++ = r; 1330 | *p++ = g; 1331 | *p = b; 1332 | } break; 1333 | } 1334 | } 1335 | } 1336 | 1337 | void Adafruit_NeoPixel::setColor(uint16_t aLedNumber, byte aRed, byte aGreen, byte aBlue) { 1338 | return setPixelColor(aLedNumber, (uint8_t) aRed, (uint8_t) aGreen, (uint8_t) aBlue); 1339 | } 1340 | 1341 | void Adafruit_NeoPixel::setColor(uint16_t aLedNumber, byte aRed, byte aGreen, byte aBlue, byte aWhite) { 1342 | return setPixelColor(aLedNumber, (uint8_t) aRed, (uint8_t) aGreen, (uint8_t) aBlue, (uint8_t) aWhite); 1343 | } 1344 | 1345 | void Adafruit_NeoPixel::setColorScaled(uint16_t aLedNumber, byte aRed, byte aGreen, byte aBlue, byte aScaling) { 1346 | // scale RGB with a common brightness parameter 1347 | setColor(aLedNumber, (aRed*aScaling)>>8, (aGreen*aScaling)>>8, (aBlue*aScaling)>>8); 1348 | } 1349 | 1350 | void Adafruit_NeoPixel::setColorScaled(uint16_t aLedNumber, byte aRed, byte aGreen, byte aBlue, byte aWhite, byte aScaling) { 1351 | // scale RGB with a common brightness parameter 1352 | setColor(aLedNumber, (aRed*aScaling)>>8, (aGreen*aScaling)>>8, (aBlue*aScaling)>>8, (aWhite*aScaling)>>8); 1353 | } 1354 | 1355 | void Adafruit_NeoPixel::setColorDimmed(uint16_t aLedNumber, byte aRed, byte aGreen, byte aBlue, byte aBrightness) { 1356 | setColorScaled(aLedNumber, aRed, aGreen, aBlue, brightnessToPWM(aBrightness)); 1357 | } 1358 | 1359 | void Adafruit_NeoPixel::setColorDimmed(uint16_t aLedNumber, byte aRed, byte aGreen, byte aBlue, byte aWhite, byte aBrightness) { 1360 | setColorScaled(aLedNumber, aRed, aGreen, aBlue, aWhite, brightnessToPWM(aBrightness)); 1361 | } 1362 | 1363 | byte Adafruit_NeoPixel::brightnessToPWM(byte aBrightness) { 1364 | static const byte pwmLevels[16] = { 0, 1, 2, 3, 4, 6, 8, 12, 23, 36, 48, 70, 95, 135, 190, 255 }; 1365 | return pwmLevels[aBrightness>>4]; 1366 | } 1367 | 1368 | // Convert separate R,G,B into packed 32-bit RGB color. 1369 | // Packed format is always RGB, regardless of LED strand color order. 1370 | uint32_t Adafruit_NeoPixel::Color(uint8_t r, uint8_t g, uint8_t b) { 1371 | return ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; 1372 | } 1373 | 1374 | // Convert separate R,G,B,W into packed 32-bit WRGB color. 1375 | // Packed format is always WRGB, regardless of LED strand color order. 1376 | uint32_t Adafruit_NeoPixel::Color(uint8_t r, uint8_t g, uint8_t b, uint8_t w) { 1377 | return ((uint32_t)w << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; 1378 | } 1379 | 1380 | // Query color from previously-set pixel (returns packed 32-bit RGB value) 1381 | uint32_t Adafruit_NeoPixel::getPixelColor(uint16_t n) const { 1382 | if(n >= numLEDs) { 1383 | // Out of bounds, return no color. 1384 | return 0; 1385 | } 1386 | 1387 | uint8_t *p = &pixels[n * (type==SK6812RGBW?4:3)]; 1388 | uint32_t c; 1389 | 1390 | switch(type) { 1391 | case WS2812B: // WS2812, WS2812B & WS2813 is GRB order. 1392 | case WS2812B_FAST: 1393 | case WS2812B2: 1394 | case WS2812B2_FAST: { 1395 | c = ((uint32_t)p[1] << 16) | ((uint32_t)p[0] << 8) | (uint32_t)p[2]; 1396 | } break; 1397 | case TM1829: { // TM1829 is special RBG order 1398 | c = ((uint32_t)p[0] << 16) | ((uint32_t)p[2] << 8) | (uint32_t)p[1]; 1399 | } break; 1400 | case SK6812RGBW: { // SK6812RGBW is RGBW order, but returns packed WRGB color 1401 | c = ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | (uint32_t)p[3]; 1402 | } break; 1403 | case WS2811: // WS2811 is RGB order 1404 | case TM1803: // TM1803 is RGB order 1405 | default: { // default is RGB order 1406 | c = ((uint32_t)p[0] << 16) | ((uint32_t)p[1] << 8) | (uint32_t)p[2]; 1407 | } break; 1408 | } 1409 | 1410 | // Adjust this back up to the true color, as setting a pixel color will 1411 | // scale it back down again. 1412 | if(brightness) { // See notes in setBrightness() 1413 | //Cast the color to a byte array 1414 | uint8_t * c_ptr =reinterpret_cast(&c); 1415 | if (type == SK6812RGBW) { 1416 | c_ptr[3] = (c_ptr[3] << 8)/brightness; 1417 | } 1418 | c_ptr[0] = (c_ptr[0] << 8)/brightness; 1419 | c_ptr[1] = (c_ptr[1] << 8)/brightness; 1420 | c_ptr[2] = (c_ptr[2] << 8)/brightness; 1421 | } 1422 | return c; // Pixel # is out of bounds 1423 | } 1424 | 1425 | uint8_t *Adafruit_NeoPixel::getPixels(void) const { 1426 | return pixels; 1427 | } 1428 | 1429 | uint16_t Adafruit_NeoPixel::numPixels(void) const { 1430 | return numLEDs; 1431 | } 1432 | 1433 | uint16_t Adafruit_NeoPixel::getNumLeds(void) const { 1434 | return numPixels(); 1435 | } 1436 | 1437 | // Adjust output brightness; 0=darkest (off), 255=brightest. This does 1438 | // NOT immediately affect what's currently displayed on the LEDs. The 1439 | // next call to show() will refresh the LEDs at this level. However, 1440 | // this process is potentially "lossy," especially when increasing 1441 | // brightness. The tight timing in the WS2811/WS2812 code means there 1442 | // aren't enough free cycles to perform this scaling on the fly as data 1443 | // is issued. So we make a pass through the existing color data in RAM 1444 | // and scale it (subsequent graphics commands also work at this 1445 | // brightness level). If there's a significant step up in brightness, 1446 | // the limited number of steps (quantization) in the old data will be 1447 | // quite visible in the re-scaled version. For a non-destructive 1448 | // change, you'll need to re-render the full strip data. C'est la vie. 1449 | void Adafruit_NeoPixel::setBrightness(uint8_t b) { 1450 | // Stored brightness value is different than what's passed. 1451 | // This simplifies the actual scaling math later, allowing a fast 1452 | // 8x8-bit multiply and taking the MSB. 'brightness' is a uint8_t, 1453 | // adding 1 here may (intentionally) roll over...so 0 = max brightness 1454 | // (color values are interpreted literally; no scaling), 1 = min 1455 | // brightness (off), 255 = just below max brightness. 1456 | uint8_t newBrightness = b + 1; 1457 | if(newBrightness != brightness) { // Compare against prior value 1458 | // Brightness has changed -- re-scale existing data in RAM 1459 | uint8_t c, 1460 | *ptr = pixels, 1461 | oldBrightness = brightness - 1; // De-wrap old brightness value 1462 | uint16_t scale; 1463 | if(oldBrightness == 0) scale = 0; // Avoid /0 1464 | else if(b == 255) scale = 65535 / oldBrightness; 1465 | else scale = (((uint16_t)newBrightness << 8) - 1) / oldBrightness; 1466 | for(uint16_t i=0; i> 8; 1469 | } 1470 | brightness = newBrightness; 1471 | } 1472 | } 1473 | 1474 | //Return the brightness value 1475 | uint8_t Adafruit_NeoPixel::getBrightness(void) const { 1476 | return brightness - 1; 1477 | } 1478 | 1479 | void Adafruit_NeoPixel::clear(void) { 1480 | memset(pixels, 0, numBytes); 1481 | } 1482 | -------------------------------------------------------------------------------- /src/neopixel.h: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | Particle Core, Particle Photon, P1, Electron, Argon, Boron, Xenon, B SoM, B5 SoM, E SoM X, P2, Photon 2, Tracker and 3 | RedBear Duo library to control WS2811/WS2812/WS2813 based RGB LED 4 | devices such as Adafruit NeoPixel strips. 5 | 6 | Supports: 7 | - 800 KHz WS2812, WS2812B, WS2813 and 400kHz bitstream and WS2811 8 | - 800 KHz bitstream SK6812RGBW (NeoPixel RGBW pixel strips) 9 | (use 'SK6812RGBW' as PIXEL_TYPE) 10 | 11 | Also supports: 12 | - Radio Shack Tri-Color Strip with TM1803 controller 400kHz bitstream. 13 | - TM1829 pixels 14 | 15 | PLEASE NOTE that the NeoPixels require 5V level inputs 16 | and the supported microcontrollers only have 3.3V level outputs. Level 17 | shifting is necessary, but will require a fast device such as one of 18 | the following: 19 | 20 | [SN74HCT125N] 21 | http://www.digikey.com/product-detail/en/SN74HCT125N/296-8386-5-ND/376860 22 | 23 | [SN74HCT245N] 24 | http://www.digikey.com/product-detail/en/SN74HCT245N/296-1612-5-ND/277258 25 | 26 | Written by Phil Burgess / Paint Your Dragon for Adafruit Industries. 27 | Modified to work with Particle devices by Technobly. 28 | Contributions by PJRC and other members of the open source community. 29 | 30 | Adafruit invests time and resources providing this open source code, 31 | please support Adafruit and open-source hardware by purchasing products 32 | from Adafruit! 33 | --------------------------------------------------------------------*/ 34 | 35 | /* ======================= neopixel.h ======================= */ 36 | /*-------------------------------------------------------------------- 37 | This file is part of the Adafruit NeoPixel library. 38 | 39 | NeoPixel is free software: you can redistribute it and/or modify 40 | it under the terms of the GNU Lesser General Public License as 41 | published by the Free Software Foundation, either version 3 of 42 | the License, or (at your option) any later version. 43 | 44 | NeoPixel is distributed in the hope that it will be useful, 45 | but WITHOUT ANY WARRANTY; without even the implied warranty of 46 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 47 | GNU Lesser General Public License for more details. 48 | 49 | You should have received a copy of the GNU Lesser General Public 50 | License along with NeoPixel. If not, see 51 | . 52 | --------------------------------------------------------------------*/ 53 | 54 | #ifndef PARTICLE_NEOPIXEL_H 55 | #define PARTICLE_NEOPIXEL_H 56 | 57 | #include "Particle.h" 58 | 59 | // 'type' flags for LED pixels (third parameter to constructor): 60 | #define WS2811 0x00 // 400 KHz datastream (NeoPixel) 61 | #define WS2812 0x02 // 800 KHz datastream (NeoPixel) 62 | #define WS2812B 0x02 // 800 KHz datastream (NeoPixel) 63 | #define WS2813 0x02 // 800 KHz datastream (NeoPixel) 64 | #define TM1803 0x03 // 400 KHz datastream (Radio Shack Tri-Color Strip) 65 | #define TM1829 0x04 // 800 KHz datastream () 66 | #define WS2812B2 0x05 // 800 KHz datastream (NeoPixel) 67 | #define SK6812RGBW 0x06 // 800 KHz datastream (NeoPixel RGBW) 68 | #define WS2812B_FAST 0x07 // 800 KHz datastream (NeoPixel) 69 | #define WS2812B2_FAST 0x08 // 800 KHz datastream (NeoPixel) 70 | 71 | class Adafruit_NeoPixel { 72 | 73 | public: 74 | 75 | // Constructor: number of LEDs, pin number, LED type 76 | #if (PLATFORM_ID == 32) 77 | Adafruit_NeoPixel(uint16_t n, SPIClass& spi, uint8_t t=WS2812B); 78 | #else 79 | Adafruit_NeoPixel(uint16_t n, uint8_t p=2, uint8_t t=WS2812B); 80 | #endif // #if (PLATFORM_ID == 32) 81 | ~Adafruit_NeoPixel(); 82 | 83 | void 84 | begin(void), 85 | show(void) __attribute__((optimize("Ofast"))), 86 | setPin(uint8_t p), 87 | setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b), 88 | setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w), 89 | setPixelColor(uint16_t n, uint32_t c), 90 | setBrightness(uint8_t), 91 | setColor(uint16_t aLedNumber, byte aRed, byte aGreen, byte aBlue), 92 | setColor(uint16_t aLedNumber, byte aRed, byte aGreen, byte aBlue, byte aWhite), 93 | setColorScaled(uint16_t aLedNumber, byte aRed, byte aGreen, byte aBlue, byte aScaling), 94 | setColorScaled(uint16_t aLedNumber, byte aRed, byte aGreen, byte aBlue, byte aWhite, byte aScaling), 95 | setColorDimmed(uint16_t aLedNumber, byte aRed, byte aGreen, byte aBlue, byte aBrightness), 96 | setColorDimmed(uint16_t aLedNumber, byte aRed, byte aGreen, byte aBlue, byte aWhite, byte aBrightness), 97 | updateLength(uint16_t n), 98 | clear(void); 99 | uint8_t 100 | *getPixels() const, 101 | getBrightness(void) const, 102 | getPin() const, 103 | getType() const; 104 | uint16_t 105 | numPixels(void) const, 106 | getNumLeds(void) const; 107 | static uint32_t 108 | Color(uint8_t r, uint8_t g, uint8_t b), 109 | Color(uint8_t r, uint8_t g, uint8_t b, uint8_t w); 110 | uint32_t 111 | getPixelColor(uint16_t n) const; 112 | byte 113 | brightnessToPWM(byte aBrightness); 114 | 115 | private: 116 | 117 | bool 118 | begun; // true if begin() previously called 119 | uint16_t 120 | numLEDs, // Number of RGB LEDs in strip 121 | numBytes; // Size of 'pixels' buffer below 122 | const uint8_t 123 | type; // Pixel type flag (400 vs 800 KHz) 124 | uint8_t 125 | pin, // Output pin number 126 | brightness, 127 | *pixels; // Holds LED color values (3 bytes each) 128 | uint32_t 129 | endTime; // Latch timing reference 130 | #if (PLATFORM_ID == 32) 131 | SPIClass* 132 | spi_; 133 | #endif 134 | }; 135 | 136 | #endif // PARTICLE_NEOPIXEL_H 137 | -------------------------------------------------------------------------------- /src/neopixel/neopixel.h: -------------------------------------------------------------------------------- 1 | #include "../neopixel.h" --------------------------------------------------------------------------------