bc4441afa7
At the WS2812 driver level, a 400ns value was used for T0H (time high to send a 0 bit) but LED specification says it should be 350ns +- 150ns. Due to loop overhead the 400ns value could lead to T0H close to 500ns which is too close from the limit value and gave glitches (bad data to pixels) in some cases. This patch makes the calculated T0H value 350ns.
66 lines
2.1 KiB
C
66 lines
2.1 KiB
C
// Original version from https://github.com/adafruit/Adafruit_NeoPixel
|
|
// Modifications by dpgeorge to support auto-CPU-frequency detection
|
|
|
|
// This is a mash-up of the Due show() code + insights from Michael Miller's
|
|
// ESP8266 work for the NeoPixelBus library: github.com/Makuna/NeoPixelBus
|
|
// Needs to be a separate .c file to enforce ICACHE_RAM_ATTR execution.
|
|
|
|
#include "py/mpconfig.h"
|
|
#if MICROPY_ESP8266_NEOPIXEL
|
|
|
|
#include "c_types.h"
|
|
#include "eagle_soc.h"
|
|
#include "user_interface.h"
|
|
#include "espneopixel.h"
|
|
#include "esp_mphal.h"
|
|
|
|
#define NEO_KHZ400 (1)
|
|
|
|
void /*ICACHE_RAM_ATTR*/ esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32_t numBytes, bool is800KHz) {
|
|
|
|
uint8_t *p, *end, pix, mask;
|
|
uint32_t t, time0, time1, period, c, startTime, pinMask;
|
|
|
|
pinMask = 1 << pin;
|
|
p = pixels;
|
|
end = p + numBytes;
|
|
pix = *p++;
|
|
mask = 0x80;
|
|
startTime = 0;
|
|
|
|
uint32_t fcpu = system_get_cpu_freq() * 1000000;
|
|
|
|
#ifdef NEO_KHZ400
|
|
if(is800KHz) {
|
|
#endif
|
|
time0 = fcpu / 2857143; // 0.35us
|
|
time1 = fcpu / 1250000; // 0.8us
|
|
period = fcpu / 800000; // 1.25us per bit
|
|
#ifdef NEO_KHZ400
|
|
} else { // 400 KHz bitstream
|
|
time0 = fcpu / 2000000; // 0.5uS
|
|
time1 = fcpu / 833333; // 1.2us
|
|
period = fcpu / 400000; // 2.5us per bit
|
|
}
|
|
#endif
|
|
|
|
uint32_t irq_state = mp_hal_quiet_timing_enter();
|
|
for(t = time0;; t = time0) {
|
|
if(pix & mask) t = time1; // Bit high duration
|
|
while(((c = mp_hal_ticks_cpu()) - startTime) < period); // Wait for bit start
|
|
GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pinMask); // Set high
|
|
startTime = c; // Save start time
|
|
while(((c = mp_hal_ticks_cpu()) - startTime) < t); // Wait high duration
|
|
GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pinMask); // Set low
|
|
if(!(mask >>= 1)) { // Next bit/byte
|
|
if(p >= end) break;
|
|
pix = *p++;
|
|
mask = 0x80;
|
|
}
|
|
}
|
|
while((mp_hal_ticks_cpu() - startTime) < period); // Wait for last bit
|
|
mp_hal_quiet_timing_exit(irq_state);
|
|
}
|
|
|
|
#endif // MICROPY_ESP8266_NEOPIXEL
|