Add neopixel support
This commit is contained in:
parent
7be9837f73
commit
1c1df053d5
|
@ -171,6 +171,7 @@ SRC_C += \
|
|||
lib/utils/stdout_helpers.c \
|
||||
lib/utils/sys_stdio_mphal.c \
|
||||
peripherals/pins.c \
|
||||
peripherals/rmt.c \
|
||||
supervisor/shared/memory.c
|
||||
|
||||
ifneq ($(USB),FALSE)
|
||||
|
|
|
@ -29,4 +29,6 @@
|
|||
#define MICROPY_HW_BOARD_NAME "Saola 1 w/Wrover"
|
||||
#define MICROPY_HW_MCU_NAME "ESP32S2"
|
||||
|
||||
#define MICROPY_HW_NEOPIXEL (&pin_GPIO18)
|
||||
|
||||
#define AUTORESET_DELAY_MS 500
|
||||
|
|
|
@ -42,5 +42,7 @@ STATIC const mp_rom_map_elem_t board_global_dict_table[] = {
|
|||
{ MP_ROM_QSTR(MP_QSTR_IO44), MP_ROM_PTR(&pin_GPIO44) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_IO45), MP_ROM_PTR(&pin_GPIO45) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_IO46), MP_ROM_PTR(&pin_GPIO46) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO18) },
|
||||
};
|
||||
MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table);
|
||||
|
|
|
@ -26,12 +26,18 @@
|
|||
*/
|
||||
|
||||
#include "shared-bindings/microcontroller/Pin.h"
|
||||
#include "shared-bindings/digitalio/DigitalInOut.h"
|
||||
#include "supervisor/shared/rgb_led_status.h"
|
||||
|
||||
#include "py/mphal.h"
|
||||
|
||||
#include "esp-idf/components/driver/include/driver/gpio.h"
|
||||
#include "esp-idf/components/soc/include/hal/gpio_hal.h"
|
||||
|
||||
#ifdef MICROPY_HW_NEOPIXEL
|
||||
bool neopixel_in_use;
|
||||
#endif
|
||||
|
||||
STATIC uint32_t never_reset_pins[2];
|
||||
STATIC uint32_t in_use[2];
|
||||
|
||||
|
@ -50,6 +56,14 @@ void common_hal_never_reset_pin(const mcu_pin_obj_t* pin) {
|
|||
void reset_pin_number(gpio_num_t pin_number) {
|
||||
never_reset_pins[pin_number / 32] &= ~(1 << pin_number % 32);
|
||||
in_use[pin_number / 32] &= ~(1 << pin_number % 32);
|
||||
|
||||
#ifdef MICROPY_HW_NEOPIXEL
|
||||
if (pin_number == MICROPY_HW_NEOPIXEL->number) {
|
||||
neopixel_in_use = false;
|
||||
rgb_led_status_init();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void common_hal_reset_pin(const mcu_pin_obj_t* pin) {
|
||||
|
@ -69,13 +83,28 @@ void reset_all_pins(void) {
|
|||
}
|
||||
in_use[0] = 0;
|
||||
in_use[1] = 0;
|
||||
|
||||
#ifdef MICROPY_HW_NEOPIXEL
|
||||
neopixel_in_use = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void claim_pin(const mcu_pin_obj_t* pin) {
|
||||
in_use[pin->number / 32] |= (1 << pin->number % 32);
|
||||
#ifdef MICROPY_HW_NEOPIXEL
|
||||
if (pin == MICROPY_HW_NEOPIXEL) {
|
||||
neopixel_in_use = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool pin_number_is_free(gpio_num_t pin_number) {
|
||||
#ifdef MICROPY_HW_NEOPIXEL
|
||||
if (pin_number == MICROPY_HW_NEOPIXEL->number) {
|
||||
return !neopixel_in_use;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint8_t offset = pin_number / 32;
|
||||
uint8_t mask = 1 << pin_number % 32;
|
||||
return (never_reset_pins[offset] & mask) == 0 && (in_use[offset] & mask) == 0;
|
||||
|
|
|
@ -34,6 +34,10 @@
|
|||
extern bool apa102_mosi_in_use;
|
||||
extern bool apa102_sck_in_use;
|
||||
|
||||
#ifdef MICROPY_HW_NEOPIXEL
|
||||
extern bool neopixel_in_use;
|
||||
#endif
|
||||
|
||||
void reset_all_pins(void);
|
||||
// reset_pin_number takes the pin number instead of the pointer so that objects don't
|
||||
// need to store a full pointer.
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2018 hathach for Adafruit Industries
|
||||
* Copyright (c) 2020 Lucian Copeland 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
|
||||
|
@ -24,10 +24,101 @@
|
|||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Uses code from Espressif RGB LED Strip demo and drivers
|
||||
* Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "py/mphal.h"
|
||||
#include "shared-bindings/neopixel_write/__init__.h"
|
||||
#include "driver/rmt.h"
|
||||
#include "rmt.h"
|
||||
|
||||
#define WS2812_T0H_NS (350)
|
||||
#define WS2812_T0L_NS (1000)
|
||||
#define WS2812_T1H_NS (1000)
|
||||
#define WS2812_T1L_NS (350)
|
||||
#define WS2812_RESET_US (280)
|
||||
|
||||
static uint32_t ws2812_t0h_ticks = 0;
|
||||
static uint32_t ws2812_t1h_ticks = 0;
|
||||
static uint32_t ws2812_t0l_ticks = 0;
|
||||
static uint32_t ws2812_t1l_ticks = 0;
|
||||
|
||||
static void IRAM_ATTR ws2812_rmt_adapter(const void *src, rmt_item32_t *dest, size_t src_size,
|
||||
size_t wanted_num, size_t *translated_size, size_t *item_num)
|
||||
{
|
||||
if (src == NULL || dest == NULL) {
|
||||
*translated_size = 0;
|
||||
*item_num = 0;
|
||||
return;
|
||||
}
|
||||
const rmt_item32_t bit0 = {{{ ws2812_t0h_ticks, 1, ws2812_t0l_ticks, 0 }}}; //Logical 0
|
||||
const rmt_item32_t bit1 = {{{ ws2812_t1h_ticks, 1, ws2812_t1l_ticks, 0 }}}; //Logical 1
|
||||
size_t size = 0;
|
||||
size_t num = 0;
|
||||
uint8_t *psrc = (uint8_t *)src;
|
||||
rmt_item32_t *pdest = dest;
|
||||
while (size < src_size && num < wanted_num) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
// MSB first
|
||||
if (*psrc & (1 << (7 - i))) {
|
||||
pdest->val = bit1.val;
|
||||
} else {
|
||||
pdest->val = bit0.val;
|
||||
}
|
||||
num++;
|
||||
pdest++;
|
||||
}
|
||||
size++;
|
||||
psrc++;
|
||||
}
|
||||
*translated_size = size;
|
||||
*item_num = num;
|
||||
}
|
||||
|
||||
void common_hal_neopixel_write (const digitalio_digitalinout_obj_t* digitalinout, uint8_t *pixels, uint32_t numBytes) {
|
||||
(void)digitalinout;
|
||||
(void)numBytes;
|
||||
// Reserve channel
|
||||
uint8_t number = digitalinout->pin->number;
|
||||
rmt_channel_t channel = esp32s2_peripherals_find_and_reserve_rmt();
|
||||
|
||||
// Configure Channel
|
||||
rmt_config_t config = RMT_DEFAULT_CONFIG_TX(number, channel);
|
||||
config.clk_div = 2; // set counter clock to 40MHz
|
||||
rmt_config(&config);
|
||||
rmt_driver_install(config.channel, 0, 0);
|
||||
|
||||
// Convert NS timings to ticks
|
||||
uint32_t counter_clk_hz = 0;
|
||||
if (rmt_get_counter_clock(config.channel, &counter_clk_hz) != ESP_OK) {
|
||||
mp_raise_ValueError(translate("Could not retrieve clock"));
|
||||
}
|
||||
float ratio = (float)counter_clk_hz / 1e9;
|
||||
ws2812_t0h_ticks = (uint32_t)(ratio * WS2812_T0H_NS);
|
||||
ws2812_t0l_ticks = (uint32_t)(ratio * WS2812_T0L_NS);
|
||||
ws2812_t1h_ticks = (uint32_t)(ratio * WS2812_T1H_NS);
|
||||
ws2812_t1l_ticks = (uint32_t)(ratio * WS2812_T1L_NS);
|
||||
|
||||
// Initialize automatic timing translator
|
||||
rmt_translator_init(config.channel, ws2812_rmt_adapter);
|
||||
|
||||
// Write and wait to finish
|
||||
if(rmt_write_sample(config.channel, pixels, (size_t)numBytes, true) != ESP_OK) {
|
||||
mp_raise_ValueError(translate("Input/output error"));
|
||||
}
|
||||
rmt_wait_tx_done(config.channel, pdMS_TO_TICKS(100));
|
||||
|
||||
// Free channel again
|
||||
esp32s2_peripherals_free_rmt(config.channel);
|
||||
}
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Lucian Copeland for Adafruit Industries
|
||||
* Uses code from Micropython, Copyright (c) 2013-2016 Damien P. George
|
||||
* Copyright (c) 2020 Lucian Copeland 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
|
||||
|
|
|
@ -12,6 +12,8 @@ USB_SERIAL_NUMBER_LENGTH = 12
|
|||
# Longints can be implemented as mpz, as longlong, or not
|
||||
LONGINT_IMPL = MPZ
|
||||
|
||||
CIRCUITPY_NEOPIXEL_WRITE = 1
|
||||
|
||||
CIRCUITPY_FULL_BUILD = 0
|
||||
CIRCUITPY_ANALOGIO = 0
|
||||
CIRCUITPY_AUDIOBUSIO = 0
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Lucian Copeland 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 "rmt.h"
|
||||
#include "py/runtime.h"
|
||||
|
||||
bool rmt_reserved_channels[RMT_CHANNEL_MAX];
|
||||
|
||||
rmt_channel_t esp32s2_peripherals_find_and_reserve_rmt(void) {
|
||||
for (size_t i = 0; i < RMT_CHANNEL_MAX; i++) {
|
||||
if (!rmt_reserved_channels[i]) {
|
||||
rmt_reserved_channels[i] = true;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
mp_raise_RuntimeError(translate("All timers in use"));
|
||||
return false;
|
||||
}
|
||||
|
||||
void esp32s2_peripherals_free_rmt(rmt_channel_t chan) {
|
||||
rmt_reserved_channels[chan] = false;
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Lucian Copeland 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.
|
||||
*/
|
||||
|
||||
#ifndef MICROPY_INCLUDED_ESP32S2_PERIPHERALS_RMT_H
|
||||
#define MICROPY_INCLUDED_ESP32S2_PERIPHERALS_RMT_H
|
||||
|
||||
#include "py/mphal.h"
|
||||
#include "driver/rmt.h"
|
||||
#include <stdint.h>
|
||||
|
||||
rmt_channel_t esp32s2_peripherals_find_and_reserve_rmt(void);
|
||||
void esp32s2_peripherals_free_rmt(rmt_channel_t chan);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue