Merge pull request #5727 from tannewt/rpi_neopixel
Add neopixel support on PWM capable pins
This commit is contained in:
commit
3f50453dd0
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v2.3.0
|
rev: v4.0.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: check-yaml
|
- id: check-yaml
|
||||||
- id: end-of-file-fixer
|
- id: end-of-file-fixer
|
||||||
|
@ -82,7 +82,7 @@ SRC_SHARED_MODULE_EXPANDED = $(addprefix shared-bindings/, $(SRC_SHARED_MODULE))
|
|||||||
# because a few modules have files both in common-hal/ and shared-modules/.
|
# because a few modules have files both in common-hal/ and shared-modules/.
|
||||||
# Doing a $(sort ...) removes duplicates as part of sorting.
|
# Doing a $(sort ...) removes duplicates as part of sorting.
|
||||||
SRC_COMMON_HAL_SHARED_MODULE_EXPANDED = $(sort $(SRC_COMMON_HAL_EXPANDED) $(SRC_SHARED_MODULE_EXPANDED))
|
SRC_COMMON_HAL_SHARED_MODULE_EXPANDED = $(sort $(SRC_COMMON_HAL_EXPANDED) $(SRC_SHARED_MODULE_EXPANDED))
|
||||||
SRC_S = peripherals/broadcom/boot.s
|
SRC_S = peripherals/broadcom/boot8.s
|
||||||
|
|
||||||
OBJ = $(PY_O) $(SUPERVISOR_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
|
OBJ = $(PY_O) $(SUPERVISOR_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
|
||||||
OBJ += $(addprefix $(BUILD)/, $(SRC_COMMON_HAL_SHARED_MODULE_EXPANDED:.c=.o))
|
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) $
|
|||||||
|
|
||||||
SRC_QSTR += $(SRC_C) $(SRC_SUPERVISOR) $(SRC_COMMON_HAL_EXPANDED) $(SRC_SHARED_MODULE_EXPANDED)
|
SRC_QSTR += $(SRC_C) $(SRC_SUPERVISOR) $(SRC_COMMON_HAL_EXPANDED) $(SRC_SHARED_MODULE_EXPANDED)
|
||||||
|
|
||||||
LDFLAGS += $(CFLAGS) -T peripherals/broadcom/link.ld -Wl,--gc-sections -Wl,-Map=$@.map # -Wl,--cref
|
LDFLAGS += $(CFLAGS) -T peripherals/broadcom/link8.ld -Wl,--gc-sections -Wl,-Map=$@.map # -Wl,--cref
|
||||||
|
|
||||||
# Use toolchain libm if we're not using our own.
|
# Use toolchain libm if we're not using our own.
|
||||||
ifndef INTERNAL_LIBM
|
ifndef INTERNAL_LIBM
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#include "shared-bindings/microcontroller/Pin.h"
|
#include "shared-bindings/microcontroller/Pin.h"
|
||||||
#include "shared-bindings/microcontroller/Processor.h"
|
#include "shared-bindings/microcontroller/Processor.h"
|
||||||
#include "common-hal/microcontroller/__init__.h"
|
#include "common-hal/microcontroller/__init__.h"
|
||||||
|
#include "peripherals/broadcom/defines.h"
|
||||||
#include "peripherals/broadcom/interrupts.h"
|
#include "peripherals/broadcom/interrupts.h"
|
||||||
|
|
||||||
#include "mphalport.h"
|
#include "mphalport.h"
|
||||||
|
160
ports/broadcom/common-hal/neopixel_write/__init__.c
Normal file
160
ports/broadcom/common-hal/neopixel_write/__init__.c
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the MicroPython project, http://micropython.org/
|
||||||
|
*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021 Scott Shawcroft for Adafruit Industries
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "shared-bindings/neopixel_write/__init__.h"
|
||||||
|
|
||||||
|
#include "py/runtime.h"
|
||||||
|
|
||||||
|
#include "shared-bindings/microcontroller/__init__.h"
|
||||||
|
#include "shared-bindings/digitalio/DigitalInOut.h"
|
||||||
|
#include "shared-bindings/time/__init__.h"
|
||||||
|
|
||||||
|
#include "peripherals/broadcom/cpu.h"
|
||||||
|
|
||||||
|
#include "supervisor/port.h"
|
||||||
|
|
||||||
|
uint64_t next_start_raw_ticks = 0;
|
||||||
|
|
||||||
|
// NeoPixels are 800khz bit streams. Zeroes are 1/3 duty cycle (~416ns) and ones
|
||||||
|
// are 2/3 duty cycle (~833ns).
|
||||||
|
|
||||||
|
void common_hal_neopixel_write(const digitalio_digitalinout_obj_t *digitalinout,
|
||||||
|
uint8_t *pixels, uint32_t num_bytes) {
|
||||||
|
// Wait to make sure we don't append onto the last transmission. This should only be a tick or
|
||||||
|
// two.
|
||||||
|
while (port_get_raw_ticks(NULL) < next_start_raw_ticks) {
|
||||||
|
}
|
||||||
|
|
||||||
|
BP_Function_Enum alt_function;
|
||||||
|
uint8_t index;
|
||||||
|
uint8_t channel;
|
||||||
|
bool found = false;
|
||||||
|
for (size_t i = 0; i < NUM_ALT_FUNC; i++) {
|
||||||
|
const pin_function_t *f = &digitalinout->pin->functions[i];
|
||||||
|
if (f->type == PIN_FUNCTION_PWM) {
|
||||||
|
index = f->index;
|
||||||
|
channel = f->function;
|
||||||
|
alt_function = FSEL_VALUES[i];
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
mp_raise_ValueError(translate("NeoPixel not supported on pin"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Turn on the PWM clock. The speed is NeoPixel specific.
|
||||||
|
if (CM_PWM->CS_b.BUSY == 0) {
|
||||||
|
uint32_t source_clock;
|
||||||
|
#if BCM_VERSION == 2711
|
||||||
|
source_clock = 54000000;
|
||||||
|
#else
|
||||||
|
source_clock = 19200000;
|
||||||
|
#endif
|
||||||
|
// Three clocks per 800khz bit to get the 1/3 or 2/3 timing.
|
||||||
|
uint32_t target_clock = 3 * 800000;
|
||||||
|
uint32_t int_div = source_clock / target_clock;
|
||||||
|
|
||||||
|
CM_PWM->DIV = CM_PCM_DIV_PASSWD_PASSWD << CM_PCM_DIV_PASSWD_Pos |
|
||||||
|
(int_div) << CM_PCM_DIV_DIVI_Pos;
|
||||||
|
|
||||||
|
CM_PWM->CS = CM_PCM_CS_PASSWD_PASSWD << CM_PCM_CS_PASSWD_Pos |
|
||||||
|
CM_PCM_CS_SRC_XOSC << CM_PCM_CS_SRC_Pos;
|
||||||
|
|
||||||
|
// Set enable after setting the source to ensure it is stable.
|
||||||
|
CM_PWM->CS = CM_PCM_CS_PASSWD_PASSWD << CM_PCM_CS_PASSWD_Pos |
|
||||||
|
CM_PCM_CS_SRC_XOSC << CM_PCM_CS_SRC_Pos |
|
||||||
|
CM_PCM_CS_ENAB_Msk;
|
||||||
|
|
||||||
|
// Wait for the clock to start up.
|
||||||
|
COMPLETE_MEMORY_READS;
|
||||||
|
while (CM_PWM->CS_b.BUSY == 0) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PWM0_Type *pwm = PWM0;
|
||||||
|
#if BCM_VERSION == 2711
|
||||||
|
if (index == 1) {
|
||||||
|
pwm = PWM1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
(void)index;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
pwm->RNG1 = 24;
|
||||||
|
pwm->RNG2 = 24;
|
||||||
|
COMPLETE_MEMORY_READS;
|
||||||
|
pwm->CTL = PWM0_CTL_CLRF1_Msk;
|
||||||
|
COMPLETE_MEMORY_READS;
|
||||||
|
|
||||||
|
// Even though we're only transmitting one channel, we enable both. Without
|
||||||
|
// the second channel enabled, the output is repeated forever.
|
||||||
|
pwm->CTL =
|
||||||
|
PWM0_CTL_USEF2_Msk |
|
||||||
|
PWM0_CTL_MODE2_Msk |
|
||||||
|
PWM0_CTL_USEF1_Msk |
|
||||||
|
PWM0_CTL_MODE1_Msk;
|
||||||
|
|
||||||
|
COMPLETE_MEMORY_READS;
|
||||||
|
pwm->CTL |= PWM0_CTL_PWEN1_Msk | PWM0_CTL_PWEN2_Msk;
|
||||||
|
|
||||||
|
gpio_set_function(digitalinout->pin->number, alt_function);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < num_bytes; i++) {
|
||||||
|
uint32_t expanded = 0;
|
||||||
|
for (size_t j = 0; j < 8; j++) {
|
||||||
|
expanded = expanded >> 3;
|
||||||
|
if ((pixels[i] & (1 << j)) != 0) {
|
||||||
|
expanded |= 0xc0000000;
|
||||||
|
} else {
|
||||||
|
expanded |= 0x80000000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (pwm->STA_b.FULL1 == 1) {
|
||||||
|
RUN_BACKGROUND_TASKS;
|
||||||
|
}
|
||||||
|
if (channel == 1) {
|
||||||
|
// Dummy value for the first channel.
|
||||||
|
pwm->FIF1 = 0x000000;
|
||||||
|
}
|
||||||
|
pwm->FIF1 = expanded;
|
||||||
|
if (channel == 0) {
|
||||||
|
// Dummy value for the second channel.
|
||||||
|
pwm->FIF1 = 0x000000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Wait just a little bit so that transmission can start.
|
||||||
|
common_hal_mcu_delay_us(2);
|
||||||
|
while (pwm->STA_b.STA1 == 1) {
|
||||||
|
RUN_BACKGROUND_TASKS;
|
||||||
|
}
|
||||||
|
|
||||||
|
gpio_set_function(digitalinout->pin->number, GPIO_FUNCTION_OUTPUT);
|
||||||
|
|
||||||
|
// Update the next start.
|
||||||
|
next_start_raw_ticks = port_get_raw_ticks(NULL) + 1;
|
||||||
|
}
|
@ -8,7 +8,7 @@ CIRCUITPY_BUSIO = 1
|
|||||||
CIRCUITPY_ONEWIREIO = 0
|
CIRCUITPY_ONEWIREIO = 0
|
||||||
CIRCUITPY_PWMIO = 0
|
CIRCUITPY_PWMIO = 0
|
||||||
CIRCUITPY_COUNTIO = 0
|
CIRCUITPY_COUNTIO = 0
|
||||||
CIRCUITPY_NEOPIXEL_WRITE = 0
|
CIRCUITPY_NEOPIXEL_WRITE = 1
|
||||||
CIRCUITPY_PULSEIO = 0
|
CIRCUITPY_PULSEIO = 0
|
||||||
CIRCUITPY_OS = 1
|
CIRCUITPY_OS = 1
|
||||||
CIRCUITPY_NVM = 0
|
CIRCUITPY_NVM = 0
|
||||||
@ -31,7 +31,7 @@ CIRCUITPY_BITBANGIO = 1
|
|||||||
# Requires DigitalIO
|
# Requires DigitalIO
|
||||||
CIRCUITPY_GAMEPAD = 0
|
CIRCUITPY_GAMEPAD = 0
|
||||||
# Requires neopixel_write or SPI (dotstar)
|
# Requires neopixel_write or SPI (dotstar)
|
||||||
CIRCUITPY_PIXELBUF = 0
|
CIRCUITPY_PIXELBUF = 1
|
||||||
# Requires OS
|
# Requires OS
|
||||||
CIRCUITPY_RANDOM = 1
|
CIRCUITPY_RANDOM = 1
|
||||||
# Requires OS, filesystem
|
# Requires OS, filesystem
|
||||||
|
@ -6,7 +6,15 @@
|
|||||||
#include "shared-bindings/microcontroller/__init__.h"
|
#include "shared-bindings/microcontroller/__init__.h"
|
||||||
#include "mphalport.h"
|
#include "mphalport.h"
|
||||||
|
|
||||||
|
#include "peripherals/broadcom/defines.h"
|
||||||
|
|
||||||
void mp_hal_delay_us(mp_uint_t delay) {
|
void mp_hal_delay_us(mp_uint_t delay) {
|
||||||
|
uint32_t end = SYSTMR->CLO + delay;
|
||||||
|
// Wait if end is before current time because it must have wrapped.
|
||||||
|
while (end < SYSTMR->CLO) {
|
||||||
|
}
|
||||||
|
while (SYSTMR->CLO < end) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void mp_hal_disable_all_interrupts(void) {
|
void mp_hal_disable_all_interrupts(void) {
|
||||||
@ -19,6 +27,7 @@ void mp_hal_enable_all_interrupts(void) {
|
|||||||
|
|
||||||
mp_uint_t cpu_get_regs_and_sp(mp_uint_t *regs) {
|
mp_uint_t cpu_get_regs_and_sp(mp_uint_t *regs) {
|
||||||
size_t sp = 0;
|
size_t sp = 0;
|
||||||
|
#if defined(__ARM_ARCH) && (__ARM_ARCH >= 8)
|
||||||
__asm__ ("mov %[out], sp" : [out] "=r" (sp));
|
__asm__ ("mov %[out], sp" : [out] "=r" (sp));
|
||||||
__asm__ ("mov %[out], x19" : [out] "=r" (regs[0]));
|
__asm__ ("mov %[out], x19" : [out] "=r" (regs[0]));
|
||||||
__asm__ ("mov %[out], x20" : [out] "=r" (regs[1]));
|
__asm__ ("mov %[out], x20" : [out] "=r" (regs[1]));
|
||||||
@ -30,5 +39,19 @@ mp_uint_t cpu_get_regs_and_sp(mp_uint_t *regs) {
|
|||||||
__asm__ ("mov %[out], x26" : [out] "=r" (regs[7]));
|
__asm__ ("mov %[out], x26" : [out] "=r" (regs[7]));
|
||||||
__asm__ ("mov %[out], x27" : [out] "=r" (regs[8]));
|
__asm__ ("mov %[out], x27" : [out] "=r" (regs[8]));
|
||||||
__asm__ ("mov %[out], x28" : [out] "=r" (regs[9]));
|
__asm__ ("mov %[out], x28" : [out] "=r" (regs[9]));
|
||||||
|
#else
|
||||||
|
__asm__ ("mov %[out], sp" : [out] "=r" (sp));
|
||||||
|
__asm__ ("mov %[out], x19" : [out] "=r" (regs[0]));
|
||||||
|
__asm__ ("mov %[out], x20" : [out] "=r" (regs[1]));
|
||||||
|
__asm__ ("mov %[out], x21" : [out] "=r" (regs[2]));
|
||||||
|
__asm__ ("mov %[out], x22" : [out] "=r" (regs[3]));
|
||||||
|
__asm__ ("mov %[out], x23" : [out] "=r" (regs[4]));
|
||||||
|
__asm__ ("mov %[out], x24" : [out] "=r" (regs[5]));
|
||||||
|
__asm__ ("mov %[out], x25" : [out] "=r" (regs[6]));
|
||||||
|
__asm__ ("mov %[out], x26" : [out] "=r" (regs[7]));
|
||||||
|
__asm__ ("mov %[out], x27" : [out] "=r" (regs[8]));
|
||||||
|
__asm__ ("mov %[out], x28" : [out] "=r" (regs[9]));
|
||||||
|
#endif
|
||||||
|
|
||||||
return sp;
|
return sp;
|
||||||
}
|
}
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit e136e387177446c3c9979bbf274a4856bf13797d
|
Subproject commit 2c10889a4b2d78987bc4e0783db2e7584aa4d572
|
@ -22,7 +22,7 @@ port_deps = {
|
|||||||
"lib/tinyusb/",
|
"lib/tinyusb/",
|
||||||
"data/nvm.toml/",
|
"data/nvm.toml/",
|
||||||
],
|
],
|
||||||
"broadcom": ["lib/tinyusb/"],
|
"broadcom": ["extmod/ulab/", "lib/tinyusb/"],
|
||||||
"cxd56": ["extmod/ulab/", "lib/tinyusb/"],
|
"cxd56": ["extmod/ulab/", "lib/tinyusb/"],
|
||||||
"espressif": ["extmod/ulab/", "lib/tinyusb/", "lib/protomatter/", "lib/quirc/"],
|
"espressif": ["extmod/ulab/", "lib/tinyusb/", "lib/protomatter/", "lib/quirc/"],
|
||||||
"litex": ["extmod/ulab/", "lib/tinyusb/"],
|
"litex": ["extmod/ulab/", "lib/tinyusb/"],
|
||||||
|
Loading…
Reference in New Issue
Block a user