Skip to content

Commit 3f50453

Browse files
authored
Merge pull request #5727 from tannewt/rpi_neopixel
Add neopixel support on PWM capable pins
2 parents 190aee5 + 5e4cb4f commit 3f50453

File tree

8 files changed

+191
-7
lines changed

8 files changed

+191
-7
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
repos:
66
- repo: https://github.com/pre-commit/pre-commit-hooks
7-
rev: v2.3.0
7+
rev: v4.0.1
88
hooks:
99
- id: check-yaml
1010
- id: end-of-file-fixer

ports/broadcom/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ SRC_SHARED_MODULE_EXPANDED = $(addprefix shared-bindings/, $(SRC_SHARED_MODULE))
8282
# because a few modules have files both in common-hal/ and shared-modules/.
8383
# Doing a $(sort ...) removes duplicates as part of sorting.
8484
SRC_COMMON_HAL_SHARED_MODULE_EXPANDED = $(sort $(SRC_COMMON_HAL_EXPANDED) $(SRC_SHARED_MODULE_EXPANDED))
85-
SRC_S = peripherals/broadcom/boot.s
85+
SRC_S = peripherals/broadcom/boot8.s
8686

8787
OBJ = $(PY_O) $(SUPERVISOR_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
8888
OBJ += $(addprefix $(BUILD)/, $(SRC_COMMON_HAL_SHARED_MODULE_EXPANDED:.c=.o))
@@ -134,7 +134,7 @@ CFLAGS += $(INC) -Wall -Werror -std=gnu11 $(BASE_CFLAGS) $(CFLAGS_MOD) $(COPT) $
134134

135135
SRC_QSTR += $(SRC_C) $(SRC_SUPERVISOR) $(SRC_COMMON_HAL_EXPANDED) $(SRC_SHARED_MODULE_EXPANDED)
136136

137-
LDFLAGS += $(CFLAGS) -T peripherals/broadcom/link.ld -Wl,--gc-sections -Wl,-Map=$@.map # -Wl,--cref
137+
LDFLAGS += $(CFLAGS) -T peripherals/broadcom/link8.ld -Wl,--gc-sections -Wl,-Map=$@.map # -Wl,--cref
138138

139139
# Use toolchain libm if we're not using our own.
140140
ifndef INTERNAL_LIBM

ports/broadcom/common-hal/microcontroller/__init__.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "shared-bindings/microcontroller/Pin.h"
3030
#include "shared-bindings/microcontroller/Processor.h"
3131
#include "common-hal/microcontroller/__init__.h"
32+
#include "peripherals/broadcom/defines.h"
3233
#include "peripherals/broadcom/interrupts.h"
3334

3435
#include "mphalport.h"
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2021 Scott Shawcroft for Adafruit Industries
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
#include "shared-bindings/neopixel_write/__init__.h"
28+
29+
#include "py/runtime.h"
30+
31+
#include "shared-bindings/microcontroller/__init__.h"
32+
#include "shared-bindings/digitalio/DigitalInOut.h"
33+
#include "shared-bindings/time/__init__.h"
34+
35+
#include "peripherals/broadcom/cpu.h"
36+
37+
#include "supervisor/port.h"
38+
39+
uint64_t next_start_raw_ticks = 0;
40+
41+
// NeoPixels are 800khz bit streams. Zeroes are 1/3 duty cycle (~416ns) and ones
42+
// are 2/3 duty cycle (~833ns).
43+
44+
void common_hal_neopixel_write(const digitalio_digitalinout_obj_t *digitalinout,
45+
uint8_t *pixels, uint32_t num_bytes) {
46+
// Wait to make sure we don't append onto the last transmission. This should only be a tick or
47+
// two.
48+
while (port_get_raw_ticks(NULL) < next_start_raw_ticks) {
49+
}
50+
51+
BP_Function_Enum alt_function;
52+
uint8_t index;
53+
uint8_t channel;
54+
bool found = false;
55+
for (size_t i = 0; i < NUM_ALT_FUNC; i++) {
56+
const pin_function_t *f = &digitalinout->pin->functions[i];
57+
if (f->type == PIN_FUNCTION_PWM) {
58+
index = f->index;
59+
channel = f->function;
60+
alt_function = FSEL_VALUES[i];
61+
found = true;
62+
break;
63+
}
64+
}
65+
if (!found) {
66+
mp_raise_ValueError(translate("NeoPixel not supported on pin"));
67+
return;
68+
}
69+
70+
// Turn on the PWM clock. The speed is NeoPixel specific.
71+
if (CM_PWM->CS_b.BUSY == 0) {
72+
uint32_t source_clock;
73+
#if BCM_VERSION == 2711
74+
source_clock = 54000000;
75+
#else
76+
source_clock = 19200000;
77+
#endif
78+
// Three clocks per 800khz bit to get the 1/3 or 2/3 timing.
79+
uint32_t target_clock = 3 * 800000;
80+
uint32_t int_div = source_clock / target_clock;
81+
82+
CM_PWM->DIV = CM_PCM_DIV_PASSWD_PASSWD << CM_PCM_DIV_PASSWD_Pos |
83+
(int_div) << CM_PCM_DIV_DIVI_Pos;
84+
85+
CM_PWM->CS = CM_PCM_CS_PASSWD_PASSWD << CM_PCM_CS_PASSWD_Pos |
86+
CM_PCM_CS_SRC_XOSC << CM_PCM_CS_SRC_Pos;
87+
88+
// Set enable after setting the source to ensure it is stable.
89+
CM_PWM->CS = CM_PCM_CS_PASSWD_PASSWD << CM_PCM_CS_PASSWD_Pos |
90+
CM_PCM_CS_SRC_XOSC << CM_PCM_CS_SRC_Pos |
91+
CM_PCM_CS_ENAB_Msk;
92+
93+
// Wait for the clock to start up.
94+
COMPLETE_MEMORY_READS;
95+
while (CM_PWM->CS_b.BUSY == 0) {
96+
}
97+
}
98+
99+
PWM0_Type *pwm = PWM0;
100+
#if BCM_VERSION == 2711
101+
if (index == 1) {
102+
pwm = PWM1;
103+
}
104+
#else
105+
(void)index;
106+
#endif
107+
108+
pwm->RNG1 = 24;
109+
pwm->RNG2 = 24;
110+
COMPLETE_MEMORY_READS;
111+
pwm->CTL = PWM0_CTL_CLRF1_Msk;
112+
COMPLETE_MEMORY_READS;
113+
114+
// Even though we're only transmitting one channel, we enable both. Without
115+
// the second channel enabled, the output is repeated forever.
116+
pwm->CTL =
117+
PWM0_CTL_USEF2_Msk |
118+
PWM0_CTL_MODE2_Msk |
119+
PWM0_CTL_USEF1_Msk |
120+
PWM0_CTL_MODE1_Msk;
121+
122+
COMPLETE_MEMORY_READS;
123+
pwm->CTL |= PWM0_CTL_PWEN1_Msk | PWM0_CTL_PWEN2_Msk;
124+
125+
gpio_set_function(digitalinout->pin->number, alt_function);
126+
127+
for (size_t i = 0; i < num_bytes; i++) {
128+
uint32_t expanded = 0;
129+
for (size_t j = 0; j < 8; j++) {
130+
expanded = expanded >> 3;
131+
if ((pixels[i] & (1 << j)) != 0) {
132+
expanded |= 0xc0000000;
133+
} else {
134+
expanded |= 0x80000000;
135+
}
136+
}
137+
while (pwm->STA_b.FULL1 == 1) {
138+
RUN_BACKGROUND_TASKS;
139+
}
140+
if (channel == 1) {
141+
// Dummy value for the first channel.
142+
pwm->FIF1 = 0x000000;
143+
}
144+
pwm->FIF1 = expanded;
145+
if (channel == 0) {
146+
// Dummy value for the second channel.
147+
pwm->FIF1 = 0x000000;
148+
}
149+
}
150+
// Wait just a little bit so that transmission can start.
151+
common_hal_mcu_delay_us(2);
152+
while (pwm->STA_b.STA1 == 1) {
153+
RUN_BACKGROUND_TASKS;
154+
}
155+
156+
gpio_set_function(digitalinout->pin->number, GPIO_FUNCTION_OUTPUT);
157+
158+
// Update the next start.
159+
next_start_raw_ticks = port_get_raw_ticks(NULL) + 1;
160+
}

ports/broadcom/mpconfigport.mk

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ CIRCUITPY_BUSIO = 1
88
CIRCUITPY_ONEWIREIO = 0
99
CIRCUITPY_PWMIO = 0
1010
CIRCUITPY_COUNTIO = 0
11-
CIRCUITPY_NEOPIXEL_WRITE = 0
11+
CIRCUITPY_NEOPIXEL_WRITE = 1
1212
CIRCUITPY_PULSEIO = 0
1313
CIRCUITPY_OS = 1
1414
CIRCUITPY_NVM = 0
@@ -31,7 +31,7 @@ CIRCUITPY_BITBANGIO = 1
3131
# Requires DigitalIO
3232
CIRCUITPY_GAMEPAD = 0
3333
# Requires neopixel_write or SPI (dotstar)
34-
CIRCUITPY_PIXELBUF = 0
34+
CIRCUITPY_PIXELBUF = 1
3535
# Requires OS
3636
CIRCUITPY_RANDOM = 1
3737
# Requires OS, filesystem

ports/broadcom/mphalport.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,15 @@
66
#include "shared-bindings/microcontroller/__init__.h"
77
#include "mphalport.h"
88

9+
#include "peripherals/broadcom/defines.h"
10+
911
void mp_hal_delay_us(mp_uint_t delay) {
12+
uint32_t end = SYSTMR->CLO + delay;
13+
// Wait if end is before current time because it must have wrapped.
14+
while (end < SYSTMR->CLO) {
15+
}
16+
while (SYSTMR->CLO < end) {
17+
}
1018
}
1119

1220
void mp_hal_disable_all_interrupts(void) {
@@ -19,6 +27,7 @@ void mp_hal_enable_all_interrupts(void) {
1927

2028
mp_uint_t cpu_get_regs_and_sp(mp_uint_t *regs) {
2129
size_t sp = 0;
30+
#if defined(__ARM_ARCH) && (__ARM_ARCH >= 8)
2231
__asm__ ("mov %[out], sp" : [out] "=r" (sp));
2332
__asm__ ("mov %[out], x19" : [out] "=r" (regs[0]));
2433
__asm__ ("mov %[out], x20" : [out] "=r" (regs[1]));
@@ -30,5 +39,19 @@ mp_uint_t cpu_get_regs_and_sp(mp_uint_t *regs) {
3039
__asm__ ("mov %[out], x26" : [out] "=r" (regs[7]));
3140
__asm__ ("mov %[out], x27" : [out] "=r" (regs[8]));
3241
__asm__ ("mov %[out], x28" : [out] "=r" (regs[9]));
42+
#else
43+
__asm__ ("mov %[out], sp" : [out] "=r" (sp));
44+
__asm__ ("mov %[out], x19" : [out] "=r" (regs[0]));
45+
__asm__ ("mov %[out], x20" : [out] "=r" (regs[1]));
46+
__asm__ ("mov %[out], x21" : [out] "=r" (regs[2]));
47+
__asm__ ("mov %[out], x22" : [out] "=r" (regs[3]));
48+
__asm__ ("mov %[out], x23" : [out] "=r" (regs[4]));
49+
__asm__ ("mov %[out], x24" : [out] "=r" (regs[5]));
50+
__asm__ ("mov %[out], x25" : [out] "=r" (regs[6]));
51+
__asm__ ("mov %[out], x26" : [out] "=r" (regs[7]));
52+
__asm__ ("mov %[out], x27" : [out] "=r" (regs[8]));
53+
__asm__ ("mov %[out], x28" : [out] "=r" (regs[9]));
54+
#endif
55+
3356
return sp;
3457
}

tools/ci_fetch_deps.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"lib/tinyusb/",
2323
"data/nvm.toml/",
2424
],
25-
"broadcom": ["lib/tinyusb/"],
25+
"broadcom": ["extmod/ulab/", "lib/tinyusb/"],
2626
"cxd56": ["extmod/ulab/", "lib/tinyusb/"],
2727
"espressif": ["extmod/ulab/", "lib/tinyusb/", "lib/protomatter/", "lib/quirc/"],
2828
"litex": ["extmod/ulab/", "lib/tinyusb/"],

0 commit comments

Comments
 (0)