Skip to content
This repository was archived by the owner on Sep 6, 2023. It is now read-only.

Commit f3913bf

Browse files
tyggerjaidpgeorge
authored andcommitted
esp32: Add support for WS2812 and APA106 RGB LEDs.
1 parent 7cf3312 commit f3913bf

File tree

6 files changed

+109
-0
lines changed

6 files changed

+109
-0
lines changed

esp32/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ SRC_C = \
127127
modnetwork.c \
128128
modsocket.c \
129129
modesp.c \
130+
espneopixel.c \
130131
$(SRC_MOD)
131132

132133
STM_SRC_C = $(addprefix stmhal/,\

esp32/espneopixel.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Original version from https://github.com/adafruit/Adafruit_NeoPixel
2+
// Modifications by dpgeorge to support auto-CPU-frequency detection
3+
4+
// This is a mash-up of the Due show() code + insights from Michael Miller's
5+
// ESP8266 work for the NeoPixelBus library: github.com/Makuna/NeoPixelBus
6+
// Needs to be a separate .c file to enforce ICACHE_RAM_ATTR execution.
7+
8+
#include "py/mpconfig.h"
9+
#include "py/mphal.h"
10+
#include "modesp.h"
11+
12+
void IRAM_ATTR esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32_t numBytes, uint8_t timing) {
13+
uint8_t *p, *end, pix, mask;
14+
uint32_t t, time0, time1, period, c, startTime, pinMask;
15+
16+
pinMask = 1 << pin;
17+
p = pixels;
18+
end = p + numBytes;
19+
pix = *p++;
20+
mask = 0x80;
21+
startTime = 0;
22+
23+
uint32_t fcpu = ets_get_cpu_frequency() * 1000000;
24+
25+
if (timing == 1) {
26+
// 800 KHz
27+
time0 = (fcpu * 0.35) / 1000000; // 0.35us
28+
time1 = (fcpu * 0.8) / 1000000; // 0.8us
29+
period = (fcpu * 1.25) / 1000000; // 1.25us per bit
30+
} else {
31+
// 400 KHz
32+
time0 = (fcpu * 0.5) / 1000000; // 0.35us
33+
time1 = (fcpu * 1.2) / 1000000; // 0.8us
34+
period = (fcpu * 2.5) / 1000000; // 1.25us per bit
35+
}
36+
37+
uint32_t irq_state = mp_hal_quiet_timing_enter();
38+
for (t = time0;; t = time0) {
39+
if (pix & mask) t = time1; // Bit high duration
40+
while (((c = mp_hal_ticks_cpu()) - startTime) < period); // Wait for bit start
41+
GPIO_REG_WRITE(GPIO_OUT_W1TS_REG, pinMask); // Set high
42+
startTime = c; // Save start time
43+
while (((c = mp_hal_ticks_cpu()) - startTime) < t); // Wait high duration
44+
GPIO_REG_WRITE(GPIO_OUT_W1TC_REG, pinMask); // Set low
45+
if (!(mask >>= 1)) { // Next bit/byte
46+
if(p >= end) break;
47+
pix = *p++;
48+
mask = 0x80;
49+
}
50+
}
51+
while ((mp_hal_ticks_cpu() - startTime) < period); // Wait for last bit
52+
mp_hal_quiet_timing_exit(irq_state);
53+
}

esp32/modesp.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@
3333

3434
#include "py/runtime.h"
3535
#include "py/mperrno.h"
36+
#include "py/mphal.h"
3637
#include "drivers/dht/dht.h"
38+
#include "modesp.h"
3739

3840
STATIC mp_obj_t esp_flash_read(mp_obj_t offset_in, mp_obj_t buf_in) {
3941
mp_int_t offset = mp_obj_get_int(offset_in);
@@ -79,6 +81,15 @@ STATIC mp_obj_t esp_flash_user_start(void) {
7981
}
8082
STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_flash_user_start_obj, esp_flash_user_start);
8183

84+
STATIC mp_obj_t esp_neopixel_write_(mp_obj_t pin, mp_obj_t buf, mp_obj_t timing) {
85+
mp_buffer_info_t bufinfo;
86+
mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ);
87+
esp_neopixel_write(mp_hal_get_pin_obj(pin),
88+
(uint8_t*)bufinfo.buf, bufinfo.len, mp_obj_get_int(timing));
89+
return mp_const_none;
90+
}
91+
STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp_neopixel_write_obj, esp_neopixel_write_);
92+
8293
STATIC const mp_rom_map_elem_t esp_module_globals_table[] = {
8394
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_esp) },
8495

@@ -88,6 +99,7 @@ STATIC const mp_rom_map_elem_t esp_module_globals_table[] = {
8899
{ MP_ROM_QSTR(MP_QSTR_flash_size), MP_ROM_PTR(&esp_flash_size_obj) },
89100
{ MP_ROM_QSTR(MP_QSTR_flash_user_start), MP_ROM_PTR(&esp_flash_user_start_obj) },
90101

102+
{ MP_ROM_QSTR(MP_QSTR_neopixel_write), MP_ROM_PTR(&esp_neopixel_write_obj) },
91103
{ MP_ROM_QSTR(MP_QSTR_dht_readinto), MP_ROM_PTR(&dht_readinto_obj) },
92104
};
93105

@@ -97,3 +109,4 @@ const mp_obj_module_t esp_module = {
97109
.base = { &mp_type_module },
98110
.globals = (mp_obj_dict_t*)&esp_module_globals,
99111
};
112+

esp32/modesp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
void esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32_t numBytes, uint8_t timing);

esp32/modules/apa106.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# APA106driver for MicroPython on ESP32
2+
# MIT license; Copyright (c) 2016 Damien P. George
3+
4+
from neopixel import NeoPixel
5+
6+
7+
class APA106(NeoPixel):
8+
ORDER = (0, 1, 2, 3)

esp32/modules/neopixel.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# NeoPixel driver for MicroPython on ESP32
2+
# MIT license; Copyright (c) 2016 Damien P. George
3+
4+
from esp import neopixel_write
5+
6+
7+
class NeoPixel:
8+
ORDER = (1, 0, 2, 3)
9+
10+
def __init__(self, pin, n, bpp=3, timing=0):
11+
self.pin = pin
12+
self.n = n
13+
self.bpp = bpp
14+
self.buf = bytearray(n * bpp)
15+
self.pin.init(pin.OUT)
16+
self.timing = timing
17+
18+
def __setitem__(self, index, val):
19+
offset = index * self.bpp
20+
for i in range(self.bpp):
21+
self.buf[offset + self.ORDER[i]] = val[i]
22+
23+
def __getitem__(self, index):
24+
offset = index * self.bpp
25+
return tuple(self.buf[offset + self.ORDER[i]]
26+
for i in range(self.bpp))
27+
28+
def fill(self, color):
29+
for i in range(self.n):
30+
self[i] = color
31+
32+
def write(self):
33+
neopixel_write(self.pin, self.buf, self.timing)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy