From 1a0b4193b7539899a41952769e7b566be7580d6a Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 16 Apr 2021 16:18:01 -0700 Subject: [PATCH 1/6] Simplify the status LED to save power This also removes the need to pin share because we don't use the status LED while user code is running. The status flashes fallback to the HW_STATUS LED if no RGB LED is present. Each status has a unique blink pattern as well. One caveat is the REPL state. In order to not pin share, we set the RGB color once. PWM and single color will be shutoff immediately but DotStars and NeoPixels will hold the color until the user overrides it. Fixes #4133 --- main.c | 180 +++++-- .../boards/picoplanet/mpconfigboard.h | 9 +- ports/atmel-samd/common-hal/busio/SPI.c | 20 +- .../common-hal/microcontroller/Pin.c | 69 --- .../common-hal/microcontroller/Pin.h | 8 - ports/atmel-samd/supervisor/internal_flash.c | 19 - ports/esp32s2/common-hal/busio/SPI.c | 1 - .../esp32s2/common-hal/microcontroller/Pin.c | 31 -- .../esp32s2/common-hal/microcontroller/Pin.h | 7 - .../common-hal/microcontroller/Pin.c | 64 --- .../common-hal/microcontroller/Pin.h | 8 - .../feather_nrf52840_express/mpconfigboard.h | 2 +- .../makerdiary_m60_keyboard/mpconfigboard.h | 6 +- .../mpconfigboard.h | 8 +- .../nrf/boards/particle_xenon/mpconfigboard.h | 6 +- ports/nrf/common-hal/microcontroller/Pin.c | 63 --- ports/nrf/common-hal/microcontroller/Pin.h | 8 - ports/raspberrypi/common-hal/busio/SPI.c | 1 - .../common-hal/microcontroller/Pin.c | 78 +-- .../common-hal/microcontroller/Pin.h | 8 - ports/stm/common-hal/microcontroller/Pin.c | 63 --- ports/stm/common-hal/microcontroller/Pin.h | 8 - shared-bindings/supervisor/__init__.c | 4 +- shared-module/displayio/EPaperDisplay.c | 17 +- shared-module/displayio/EPaperDisplay.h | 2 +- .../shared/external_flash/external_flash.c | 3 - supervisor/shared/rgb_led_colors.h | 27 +- supervisor/shared/rgb_led_status.c | 486 ------------------ supervisor/shared/rgb_led_status.h | 81 --- supervisor/shared/safe_mode.c | 32 +- supervisor/shared/status_leds.c | 263 +++++++++- supervisor/shared/status_leds.h | 29 +- supervisor/supervisor.mk | 1 - 33 files changed, 464 insertions(+), 1148 deletions(-) delete mode 100644 supervisor/shared/rgb_led_status.c delete mode 100644 supervisor/shared/rgb_led_status.h diff --git a/main.c b/main.c index 3730124863..78303e1235 100755 --- a/main.c +++ b/main.c @@ -53,7 +53,6 @@ #include "supervisor/port.h" #include "supervisor/serial.h" #include "supervisor/shared/autoreload.h" -#include "supervisor/shared/rgb_led_status.h" #include "supervisor/shared/safe_mode.h" #include "supervisor/shared/stack.h" #include "supervisor/shared/status_leds.h" @@ -114,7 +113,6 @@ static void reset_devices(void) { } STATIC void start_mp(supervisor_allocation* heap) { - reset_status_led(); autoreload_stop(); supervisor_workflow_reset(); @@ -251,7 +249,6 @@ STATIC void cleanup_after_vm(supervisor_allocation* heap) { #endif reset_port(); reset_board(); - reset_status_led(); } STATIC void print_code_py_status_message(safe_mode_t safe_mode) { @@ -284,8 +281,6 @@ STATIC bool run_code_py(safe_mode_t safe_mode) { bool found_main = false; if (safe_mode == NO_SAFE_MODE) { - new_status_color(MAIN_RUNNING); - static const char * const supported_filenames[] = STRING_LIST( "code.txt", "code.py", "main.py", "main.txt"); #if CIRCUITPY_FULL_BUILD @@ -315,6 +310,8 @@ STATIC bool run_code_py(safe_mode_t safe_mode) { serial_write_compressed(translate("WARNING: Your code filename has two extensions\n")); } } + #else + (void) found_main; #endif // Finished executing python code. Cleanup includes a board reset. @@ -332,42 +329,64 @@ STATIC bool run_code_py(safe_mode_t safe_mode) { } // Program has finished running. - bool printed_press_any_key = false; #if CIRCUITPY_DISPLAYIO - bool refreshed_epaper_display = false; + size_t time_to_epaper_refresh = 1; #endif - rgb_status_animation_t animation; - prep_rgb_status_animation(&result, found_main, safe_mode, &animation); + // Setup LED blinks. + #if CIRCUITPY_STATUS_LED + uint32_t color; + uint8_t blink_count; + #if CIRCUITPY_ALARM + if (result.return_code & PYEXEC_DEEP_SLEEP) { + color = BLACK; + blink_count = 0; + } else + #endif + if (result.return_code != PYEXEC_EXCEPTION) { + if (safe_mode == NO_SAFE_MODE) { + color = ALL_DONE; + blink_count = ALL_DONE_BLINKS; + } else { + color = SAFE_MODE; + blink_count = SAFE_MODE_BLINKS; + } + } else { + color = EXCEPTION; + blink_count = EXCEPTION_BLINKS; + } + size_t pattern_start = supervisor_ticks_ms32(); + size_t single_blink_time = (OFF_ON_RATIO + 1) * BLINK_TIME_MS; + size_t blink_time = single_blink_time * blink_count; + size_t total_time = blink_time + LED_SLEEP_TIME_MS; + if (blink_count > 0) { + status_led_init(); + } + #endif + + #if CIRCUITPY_ALARM bool fake_sleeping = false; + #endif + bool skip_repl = false; while (true) { RUN_BACKGROUND_TASKS; // If a reload was requested by the supervisor or autoreload, return if (reload_requested) { - #if CIRCUITPY_ALARM - if (fake_sleeping) { - board_init(); - } - #endif reload_requested = false; - return true; + skip_repl = true; + break; } // If interrupted by keyboard, return if (serial_connected() && serial_bytes_available()) { - #if CIRCUITPY_ALARM - if (fake_sleeping) { - board_init(); - } - #endif // Skip REPL if reload was requested. - bool ctrl_d = serial_read() == CHAR_CTRL_D; - if (ctrl_d) { + skip_repl = serial_read() == CHAR_CTRL_D; + if (skip_repl) { supervisor_set_run_reason(RUN_REASON_REPL_RELOAD); } - return ctrl_d; + break; } // Check for a deep sleep alarm and restart the VM. This can happen if @@ -376,9 +395,9 @@ STATIC bool run_code_py(safe_mode_t safe_mode) { #if CIRCUITPY_ALARM if (fake_sleeping && common_hal_alarm_woken_from_sleep()) { serial_write_compressed(translate("Woken up by alarm.\n")); - board_init(); supervisor_set_run_reason(RUN_REASON_STARTUP); - return true; + skip_repl = true; + break; } #endif @@ -398,25 +417,21 @@ STATIC bool run_code_py(safe_mode_t safe_mode) { printed_press_any_key = false; } - // Refresh the ePaper display if we have one. That way it'll show an error message. - #if CIRCUITPY_DISPLAYIO - // Don't refresh the display if we're about to deep sleep. - #if CIRCUITPY_ALARM - refreshed_epaper_display = refreshed_epaper_display || result.return_code & PYEXEC_DEEP_SLEEP; - #endif - if (!refreshed_epaper_display) { - refreshed_epaper_display = maybe_refresh_epaperdisplay(); - } - #endif - // Sleep until our next interrupt. #if CIRCUITPY_ALARM if (result.return_code & PYEXEC_DEEP_SLEEP) { // Make sure we have been awake long enough for USB to connect (enumeration delay). int64_t connecting_delay_ticks = CIRCUITPY_USB_CONNECTED_SLEEP_DELAY * 1024 - port_get_raw_ticks(NULL); - // Until it's safe to decide whether we're real/fake sleeping, just run the RGB - if (connecting_delay_ticks < 0 && !fake_sleeping) { - fake_sleeping = true; + // Until it's safe to decide whether we're real/fake sleeping + if (fake_sleeping) { + // This waits until a pretend deep sleep alarm occurs. They are set + // during common_hal_alarm_set_deep_sleep_alarms. On some platforms + // it may also return due to another interrupt, that's why we check + // for deep sleep alarms above. If it wasn't a deep sleep alarm, + // then we'll idle here again. + common_hal_alarm_pretending_deep_sleep(); + } else if (connecting_delay_ticks < 0) { + // Entering deep sleep (may be fake or real.) new_status_color(BLACK); board_deinit(); if (!supervisor_workflow_active()) { @@ -426,27 +441,71 @@ STATIC bool run_code_py(safe_mode_t safe_mode) { // Does not return. } else { serial_write_compressed(translate("Pretending to deep sleep until alarm, CTRL-C or file write.\n")); + fake_sleeping = true; } + } else { + // Loop while checking the time. We can't idle because we don't want to override a + // time alarm set for the deep sleep. } - } + } else #endif + { + // Refresh the ePaper display if we have one. That way it'll show an error message. + #if CIRCUITPY_DISPLAYIO + if (time_to_epaper_refresh > 0) { + time_to_epaper_refresh = maybe_refresh_epaperdisplay(); + } - if (!fake_sleeping) { - tick_rgb_status_animation(&animation); - } else { - // This waits until a pretend deep sleep alarm occurs. They are set - // during common_hal_alarm_set_deep_sleep_alarms. On some platforms - // it may also return due to another interrupt, that's why we check - // for deep sleep alarms above. If it wasn't a deep sleep alarm, - // then we'll idle here again. - - #if CIRCUITPY_ALARM - common_hal_alarm_pretending_deep_sleep(); - #else - port_idle_until_interrupt(); + #if !CIRCUITPY_STATUS_LED + port_interrupt_after_ticks(time_to_epaper_refresh); #endif + #endif + + #if CIRCUITPY_STATUS_LED + uint32_t tick_diff = supervisor_ticks_ms32() - pattern_start; + + // By default, don't sleep. + size_t time_to_next_change = 0; + if (tick_diff < blink_time) { + uint32_t blink_diff = tick_diff % (single_blink_time); + if (blink_diff >= BLINK_TIME_MS) { + new_status_color(BLACK); + time_to_next_change = single_blink_time - blink_diff; + } else { + new_status_color(color); + time_to_next_change = BLINK_TIME_MS - blink_diff; + } + } else if (tick_diff > total_time) { + pattern_start = supervisor_ticks_ms32(); + } else { + time_to_next_change = total_time - tick_diff; + } + #if CIRCUITPY_DISPLAYIO + if (time_to_epaper_refresh > 0 && time_to_next_change > 0) { + time_to_next_change = MIN(time_to_next_change, time_to_epaper_refresh); + } + #endif + if (time_to_next_change > 0) { + // time_to_next_change is in ms and ticks are slightly shorter so + // we'll undersleep just a little. It shouldn't matter. + port_interrupt_after_ticks(time_to_next_change); + } + #endif + port_idle_until_interrupt(); } } + // Done waiting, start the board back up. + #if CIRCUITPY_STATUS_LED + new_status_color(BLACK); + status_led_deinit(); + #endif + + #if CIRCUITPY_ALARM + if (fake_sleeping) { + board_init(); + } + #endif + return skip_repl; } FIL* boot_output_file; @@ -463,7 +522,6 @@ STATIC void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) { bool skip_boot_output = false; if (ok_to_run) { - new_status_color(BOOT_RUNNING); #ifdef CIRCUITPY_BOOT_OUTPUT_FILE FIL file_pointer; @@ -574,7 +632,16 @@ STATIC int run_repl(void) { #endif autoreload_suspend(); + + // Set the status LED to the REPL color before running the REPL. For + // NeoPixels and DotStars this will be sticky but for PWM or single LED it + // won't. This simplifies pin sharing because they won't be in use when + // actually in the REPL. + #if CIRCUITPY_STATUS_LED + status_led_init(); new_status_color(REPL_RUNNING); + status_led_deinit(); + #endif if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { exit_code = pyexec_raw_repl(); } else { @@ -589,9 +656,8 @@ int __attribute__((used)) main(void) { // initialise the cpu and peripherals safe_mode_t safe_mode = port_init(); - // Turn on LEDs - init_status_leds(); - rgb_led_status_init(); + // Turn on RX and TX LEDs if we have them. + init_rxtx_leds(); // Wait briefly to give a reset window where we'll enter safe mode after the reset. if (safe_mode == NO_SAFE_MODE) { diff --git a/ports/atmel-samd/boards/picoplanet/mpconfigboard.h b/ports/atmel-samd/boards/picoplanet/mpconfigboard.h index 30a9169e04..153150d1e1 100644 --- a/ports/atmel-samd/boards/picoplanet/mpconfigboard.h +++ b/ports/atmel-samd/boards/picoplanet/mpconfigboard.h @@ -33,10 +33,9 @@ #define DEFAULT_SPI_BUS_SCK (&pin_PA17) #define DEFAULT_SPI_BUS_MOSI (&pin_PA16) -// #define CP_RGB_STATUS_R (&pin_PA06) -// #define CP_RGB_STATUS_G (&pin_PA05) -// #define CP_RGB_STATUS_B (&pin_PA07) -// #define CP_RGB_STATUS_INVERTED_PWM -// #define CP_RGB_STATUS_LED +// #define CIRCUITPY_RGB_STATUS_R (&pin_PA06) +// #define CIRCUITPY_RGB_STATUS_G (&pin_PA05) +// #define CIRCUITPY_RGB_STATUS_B (&pin_PA07) +// #define CIRCUITPY_RGB_STATUS_INVERTED_PWM #define MICROPY_HW_LED_STATUS (&pin_PA06) diff --git a/ports/atmel-samd/common-hal/busio/SPI.c b/ports/atmel-samd/common-hal/busio/SPI.c index 7b4034d156..48ca8f843d 100644 --- a/ports/atmel-samd/common-hal/busio/SPI.c +++ b/ports/atmel-samd/common-hal/busio/SPI.c @@ -36,7 +36,6 @@ #include "hal/include/hal_gpio.h" #include "hal/include/hal_spi_m_sync.h" #include "hal/include/hpl_spi_m_sync.h" -#include "supervisor/shared/rgb_led_status.h" #include "samd/dma.h" #include "samd/sercom.h" @@ -72,11 +71,6 @@ void reset_sercoms(void) { if (never_reset_sercoms[i]) { continue; } - #ifdef MICROPY_HW_APA102_SERCOM - if (sercom_instances[i] == MICROPY_HW_APA102_SERCOM) { - continue; - } - #endif // SWRST is same for all modes of SERCOMs. sercom_instances[i]->SPI.CTRLA.bit.SWRST = 1; } @@ -122,15 +116,7 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, continue; } Sercom *potential_sercom = sercom_insts[sercom_index]; - if ( - #if defined(MICROPY_HW_APA102_SCK) && defined(MICROPY_HW_APA102_MOSI) && !CIRCUITPY_BITBANG_APA102 - (potential_sercom->SPI.CTRLA.bit.ENABLE != 0 && - potential_sercom != status_apa102.spi_desc.dev.prvt && - !apa102_sck_in_use) - #else - potential_sercom->SPI.CTRLA.bit.ENABLE != 0 - #endif - ) { + if (potential_sercom->SPI.CTRLA.bit.ENABLE != 0) { continue; } clock_pinmux = PINMUX(clock->number, (i == 0) ? MUX_C : MUX_D); @@ -181,10 +167,6 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, // Set up SPI clocks on SERCOM. samd_peripherals_sercom_clock_init(sercom, sercom_index); - #if defined(MICROPY_HW_APA102_SCK) && defined(MICROPY_HW_APA102_MOSI) && !CIRCUITPY_BITBANG_APA102 - // if we're re-using the dotstar sercom, make sure it is disabled or the init will fail out - hri_sercomspi_clear_CTRLA_ENABLE_bit(sercom); - #endif if (spi_m_sync_init(&self->spi_desc, sercom) != ERR_NONE) { mp_raise_OSError(MP_EIO); } diff --git a/ports/atmel-samd/common-hal/microcontroller/Pin.c b/ports/atmel-samd/common-hal/microcontroller/Pin.c index 564d037e03..8032673d03 100644 --- a/ports/atmel-samd/common-hal/microcontroller/Pin.c +++ b/ports/atmel-samd/common-hal/microcontroller/Pin.c @@ -32,15 +32,7 @@ #include "hal/include/hal_gpio.h" #include "samd/pins.h" -#include "supervisor/shared/rgb_led_status.h" -#ifdef MICROPY_HW_NEOPIXEL -bool neopixel_in_use; -#endif -#ifdef MICROPY_HW_APA102_MOSI -bool apa102_sck_in_use; -bool apa102_mosi_in_use; -#endif #ifdef SPEAKER_ENABLE_PIN bool speaker_enable_in_use; #endif @@ -90,14 +82,6 @@ void reset_all_pins(void) { gpio_set_pin_function(PIN_PA31, GPIO_PIN_FUNCTION_G); #endif - #ifdef MICROPY_HW_NEOPIXEL - neopixel_in_use = false; - #endif - #ifdef MICROPY_HW_APA102_MOSI - apa102_sck_in_use = false; - apa102_mosi_in_use = false; - #endif - // After configuring SWD because it may be shared. #ifdef SPEAKER_ENABLE_PIN speaker_enable_in_use = false; @@ -122,25 +106,6 @@ void reset_pin_number(uint8_t pin_number) { never_reset_pins[GPIO_PORT(pin_number)] &= ~(1 << GPIO_PIN(pin_number)); - #ifdef MICROPY_HW_NEOPIXEL - if (pin_number == MICROPY_HW_NEOPIXEL->number) { - neopixel_in_use = false; - rgb_led_status_init(); - return; - } - #endif - #ifdef MICROPY_HW_APA102_MOSI - if (pin_number == MICROPY_HW_APA102_MOSI->number || - pin_number == MICROPY_HW_APA102_SCK->number) { - apa102_mosi_in_use = apa102_mosi_in_use && pin_number != MICROPY_HW_APA102_MOSI->number; - apa102_sck_in_use = apa102_sck_in_use && pin_number != MICROPY_HW_APA102_SCK->number; - if (!apa102_sck_in_use && !apa102_mosi_in_use) { - rgb_led_status_init(); - } - return; - } - #endif - if (pin_number == PIN_PA30 #ifdef SAM_D5X_E5X ) { @@ -176,20 +141,6 @@ void common_hal_reset_pin(const mcu_pin_obj_t* pin) { } void claim_pin(const mcu_pin_obj_t* pin) { - #ifdef MICROPY_HW_NEOPIXEL - if (pin == MICROPY_HW_NEOPIXEL) { - neopixel_in_use = true; - } - #endif - #ifdef MICROPY_HW_APA102_MOSI - if (pin == MICROPY_HW_APA102_MOSI) { - apa102_mosi_in_use = true; - } - if (pin == MICROPY_HW_APA102_SCK) { - apa102_sck_in_use = true; - } - #endif - #ifdef SPEAKER_ENABLE_PIN if (pin == SPEAKER_ENABLE_PIN) { speaker_enable_in_use = true; @@ -223,26 +174,6 @@ bool pin_number_is_free(uint8_t pin_number) { } bool common_hal_mcu_pin_is_free(const mcu_pin_obj_t* pin) { - #ifdef MICROPY_HW_NEOPIXEL - if (pin == MICROPY_HW_NEOPIXEL) { - // Special case for Metro M0 where the NeoPixel is also SWCLK -#ifndef IGNORE_PIN_PA30 - if (MICROPY_HW_NEOPIXEL == &pin_PA30 && DSU->STATUSB.bit.DBGPRES == 1) { - return false; - } -#endif - return !neopixel_in_use; - } - #endif - #ifdef MICROPY_HW_APA102_MOSI - if (pin == MICROPY_HW_APA102_MOSI) { - return !apa102_mosi_in_use; - } - if (pin == MICROPY_HW_APA102_SCK) { - return !apa102_sck_in_use; - } - #endif - #ifdef SPEAKER_ENABLE_PIN if (pin == SPEAKER_ENABLE_PIN) { return !speaker_enable_in_use; diff --git a/ports/atmel-samd/common-hal/microcontroller/Pin.h b/ports/atmel-samd/common-hal/microcontroller/Pin.h index 6e313acfd3..76da10852f 100644 --- a/ports/atmel-samd/common-hal/microcontroller/Pin.h +++ b/ports/atmel-samd/common-hal/microcontroller/Pin.h @@ -31,14 +31,6 @@ #include "peripherals/samd/pins.h" -#ifdef MICROPY_HW_NEOPIXEL -extern bool neopixel_in_use; -#endif -#ifdef MICROPY_HW_APA102_MOSI -extern bool apa102_sck_in_use; -extern bool apa102_mosi_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. diff --git a/ports/atmel-samd/supervisor/internal_flash.c b/ports/atmel-samd/supervisor/internal_flash.c index 98d7892c9f..afac001232 100644 --- a/ports/atmel-samd/supervisor/internal_flash.c +++ b/ports/atmel-samd/supervisor/internal_flash.c @@ -51,21 +51,10 @@ #include "hal/include/hal_flash.h" #include "supervisor/flash.h" -#include "supervisor/shared/rgb_led_status.h" static struct flash_descriptor supervisor_flash_desc; void supervisor_flash_init(void) { - // Activity LED for flash writes. - #ifdef MICROPY_HW_LED_MSC - struct port_config pin_conf; - port_get_config_defaults(&pin_conf); - - pin_conf.direction = PORT_PIN_DIR_OUTPUT; - port_pin_set_config(MICROPY_HW_LED_MSC, &pin_conf); - port_pin_set_output_level(MICROPY_HW_LED_MSC, false); - #endif - #ifdef SAM_D5X_E5X hri_mclk_set_AHBMASK_NVMCTRL_bit(MCLK); #endif @@ -114,10 +103,6 @@ bool supervisor_flash_read_block(uint8_t *dest, uint32_t block) { } bool supervisor_flash_write_block(const uint8_t *src, uint32_t block) { - #ifdef MICROPY_HW_LED_MSC - port_pin_set_output_level(MICROPY_HW_LED_MSC, true); - #endif - temp_status_color(ACTIVE_WRITE); // non-MBR block, copy to cache int32_t dest = convert_block_to_flash_addr(block); if (dest == -1) { @@ -136,10 +121,6 @@ bool supervisor_flash_write_block(const uint8_t *src, uint32_t block) { if (error_code != ERR_NONE) { return false; } - clear_temp_status(); - #ifdef MICROPY_HW_LED_MSC - port_pin_set_output_level(MICROPY_HW_LED_MSC, false); - #endif return true; } diff --git a/ports/esp32s2/common-hal/busio/SPI.c b/ports/esp32s2/common-hal/busio/SPI.c index 917b391112..0e69d9f520 100644 --- a/ports/esp32s2/common-hal/busio/SPI.c +++ b/ports/esp32s2/common-hal/busio/SPI.c @@ -29,7 +29,6 @@ #include "py/runtime.h" #include "shared-bindings/microcontroller/Pin.h" -#include "supervisor/shared/rgb_led_status.h" static bool spi_never_reset[SOC_SPI_PERIPH_NUM]; diff --git a/ports/esp32s2/common-hal/microcontroller/Pin.c b/ports/esp32s2/common-hal/microcontroller/Pin.c index 5c00ca49e1..402de227d2 100644 --- a/ports/esp32s2/common-hal/microcontroller/Pin.c +++ b/ports/esp32s2/common-hal/microcontroller/Pin.c @@ -27,23 +27,15 @@ #include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/digitalio/DigitalInOut.h" -#include "supervisor/shared/rgb_led_status.h" #include "py/mphal.h" #include "components/driver/include/driver/gpio.h" #include "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]; -bool apa102_mosi_in_use; -bool apa102_sck_in_use; - STATIC void floating_gpio_reset(gpio_num_t pin_number) { // This is the same as gpio_reset_pin(), but without the pullup. // Note that gpio_config resets the iomatrix to GPIO_FUNC as well. @@ -78,14 +70,6 @@ void reset_pin_number(gpio_num_t pin_number) { in_use[pin_number / 32] &= ~(1 << pin_number % 32); floating_gpio_reset(pin_number); - - #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) { @@ -106,19 +90,10 @@ 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 } void common_hal_mcu_pin_claim(const mcu_pin_obj_t *pin) { @@ -126,12 +101,6 @@ void common_hal_mcu_pin_claim(const mcu_pin_obj_t *pin) { } 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; uint32_t mask = 1 << (pin_number % 32); return (in_use[offset] & mask) == 0; diff --git a/ports/esp32s2/common-hal/microcontroller/Pin.h b/ports/esp32s2/common-hal/microcontroller/Pin.h index e7b488f048..e82b28f282 100644 --- a/ports/esp32s2/common-hal/microcontroller/Pin.h +++ b/ports/esp32s2/common-hal/microcontroller/Pin.h @@ -31,13 +31,6 @@ #include "peripherals/pins.h" -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. diff --git a/ports/mimxrt10xx/common-hal/microcontroller/Pin.c b/ports/mimxrt10xx/common-hal/microcontroller/Pin.c index b55ab6e862..53e92d4105 100644 --- a/ports/mimxrt10xx/common-hal/microcontroller/Pin.c +++ b/ports/mimxrt10xx/common-hal/microcontroller/Pin.c @@ -27,15 +27,6 @@ */ #include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/microcontroller/Pin.h" -#include "supervisor/shared/rgb_led_status.h" - -#ifdef MICROPY_HW_NEOPIXEL -bool neopixel_in_use; -#endif -#ifdef MICROPY_HW_APA102_MOSI -bool apa102_sck_in_use; -bool apa102_mosi_in_use; -#endif STATIC bool claimed_pins[IOMUXC_SW_PAD_CTL_PAD_COUNT]; STATIC bool never_reset_pins[IOMUXC_SW_PAD_CTL_PAD_COUNT]; @@ -54,14 +45,6 @@ void reset_all_pins(void) { IOMUXC->SW_PAD_CTL_PAD[i] = ((mcu_pin_obj_t *)(mcu_pin_globals.map.table[i].value))->pad_reset; } } - - #ifdef MICROPY_HW_NEOPIXEL - neopixel_in_use = false; - #endif - #ifdef MICROPY_HW_APA102_MOSI - apa102_sck_in_use = false; - apa102_mosi_in_use = false; - #endif } // Since i.MX pins need extra register and reset information to reset properly, @@ -74,25 +57,6 @@ void common_hal_reset_pin(const mcu_pin_obj_t *pin) { claimed_pins[pin->mux_idx] = false; *(uint32_t *)pin->mux_reg = pin->mux_reset; *(uint32_t *)pin->cfg_reg = pin->pad_reset; - - #ifdef MICROPY_HW_NEOPIXEL - if (pin == MICROPY_HW_NEOPIXEL) { - neopixel_in_use = false; - rgb_led_status_init(); - return; - } - #endif - #ifdef MICROPY_HW_APA102_MOSI - if (pin->mux_idx == MICROPY_HW_APA102_MOSI->mux_idx || - pin->mux_idx == MICROPY_HW_APA102_SCK->mux_idx) { - apa102_mosi_in_use = apa102_mosi_in_use && pin->mux_idx != MICROPY_HW_APA102_MOSI->mux_idx; - apa102_sck_in_use = apa102_sck_in_use && pin->mux_idx != MICROPY_HW_APA102_SCK->mux_idx; - if (!apa102_sck_in_use && !apa102_mosi_in_use) { - rgb_led_status_init(); - } - return; - } - #endif } void common_hal_never_reset_pin(const mcu_pin_obj_t *pin) { @@ -100,20 +64,6 @@ void common_hal_never_reset_pin(const mcu_pin_obj_t *pin) { } bool common_hal_mcu_pin_is_free(const mcu_pin_obj_t *pin) { - #ifdef MICROPY_HW_NEOPIXEL - if (pin == MICROPY_HW_NEOPIXEL) { - return !neopixel_in_use; - } - #endif - #ifdef MICROPY_HW_APA102_MOSI - if (pin == MICROPY_HW_APA102_MOSI) { - return !apa102_mosi_in_use; - } - if (pin == MICROPY_HW_APA102_SCK) { - return !apa102_sck_in_use; - } - #endif - return !claimed_pins[pin->mux_idx]; } @@ -123,20 +73,6 @@ uint8_t common_hal_mcu_pin_number(const mcu_pin_obj_t *pin) { void common_hal_mcu_pin_claim(const mcu_pin_obj_t *pin) { claimed_pins[pin->mux_idx] = true; - - #ifdef MICROPY_HW_NEOPIXEL - if (pin == MICROPY_HW_NEOPIXEL) { - neopixel_in_use = true; - } - #endif - #ifdef MICROPY_HW_APA102_MOSI - if (pin == MICROPY_HW_APA102_MOSI) { - apa102_mosi_in_use = true; - } - if (pin == MICROPY_HW_APA102_SCK) { - apa102_sck_in_use = true; - } - #endif } void claim_pin(const mcu_pin_obj_t *pin) { diff --git a/ports/mimxrt10xx/common-hal/microcontroller/Pin.h b/ports/mimxrt10xx/common-hal/microcontroller/Pin.h index fde7fc8b8f..2638eb89b8 100644 --- a/ports/mimxrt10xx/common-hal/microcontroller/Pin.h +++ b/ports/mimxrt10xx/common-hal/microcontroller/Pin.h @@ -32,14 +32,6 @@ #include "pins.h" -#ifdef MICROPY_HW_NEOPIXEL -extern bool neopixel_in_use; -#endif -#ifdef MICROPY_HW_APA102_MOSI -extern bool apa102_sck_in_use; -extern bool apa102_mosi_in_use; -#endif - void reset_all_pins(void); void claim_pin(const mcu_pin_obj_t *pin); diff --git a/ports/nrf/boards/feather_nrf52840_express/mpconfigboard.h b/ports/nrf/boards/feather_nrf52840_express/mpconfigboard.h index 64988e1a28..8e4cd2287a 100644 --- a/ports/nrf/boards/feather_nrf52840_express/mpconfigboard.h +++ b/ports/nrf/boards/feather_nrf52840_express/mpconfigboard.h @@ -30,7 +30,7 @@ #define MICROPY_HW_BOARD_NAME "Adafruit Feather nRF52840 Express" #define MICROPY_HW_MCU_NAME "nRF52840" -#define MICROPY_HW_NEOPIXEL (&pin_P0_16) +// #define MICROPY_HW_NEOPIXEL (&pin_P0_16) #define MICROPY_HW_LED_STATUS (&pin_P1_15) diff --git a/ports/nrf/boards/makerdiary_m60_keyboard/mpconfigboard.h b/ports/nrf/boards/makerdiary_m60_keyboard/mpconfigboard.h index 4fb6049c5f..23a98c948b 100644 --- a/ports/nrf/boards/makerdiary_m60_keyboard/mpconfigboard.h +++ b/ports/nrf/boards/makerdiary_m60_keyboard/mpconfigboard.h @@ -31,9 +31,9 @@ #define MICROPY_HW_MCU_NAME "nRF52840" // RGB LEDs use PWM peripheral, avoid using them to save energy -// #define CP_RGB_STATUS_R (&pin_P0_30) -// #define CP_RGB_STATUS_G (&pin_P0_29) -// #define CP_RGB_STATUS_B (&pin_P0_31) +#define CIRCUITPY_RGB_STATUS_R (&pin_P0_30) +#define CIRCUITPY_RGB_STATUS_G (&pin_P0_29) +#define CIRCUITPY_RGB_STATUS_B (&pin_P0_31) #define MICROPY_QSPI_DATA0 NRF_GPIO_PIN_MAP(1, 10) #define MICROPY_QSPI_DATA1 NRF_GPIO_PIN_MAP(1, 14) diff --git a/ports/nrf/boards/makerdiary_nrf52840_m2_devkit/mpconfigboard.h b/ports/nrf/boards/makerdiary_nrf52840_m2_devkit/mpconfigboard.h index dab2ff042b..c398ce83dc 100644 --- a/ports/nrf/boards/makerdiary_nrf52840_m2_devkit/mpconfigboard.h +++ b/ports/nrf/boards/makerdiary_nrf52840_m2_devkit/mpconfigboard.h @@ -32,10 +32,10 @@ #define MICROPY_HW_LED_STATUS (&pin_P1_07) -#define CP_RGB_STATUS_INVERTED_PWM -#define CP_RGB_STATUS_R (&pin_P0_30) -#define CP_RGB_STATUS_G (&pin_P0_29) -#define CP_RGB_STATUS_B (&pin_P0_31) +#define CIRCUITPY_RGB_STATUS_INVERTED_PWM +#define CIRCUITPY_RGB_STATUS_R (&pin_P0_30) +#define CIRCUITPY_RGB_STATUS_G (&pin_P0_29) +#define CIRCUITPY_RGB_STATUS_B (&pin_P0_31) #define MICROPY_QSPI_DATA0 NRF_GPIO_PIN_MAP(1, 10) #define MICROPY_QSPI_DATA1 NRF_GPIO_PIN_MAP(1, 14) diff --git a/ports/nrf/boards/particle_xenon/mpconfigboard.h b/ports/nrf/boards/particle_xenon/mpconfigboard.h index f0d12bb0b9..b2221e163a 100644 --- a/ports/nrf/boards/particle_xenon/mpconfigboard.h +++ b/ports/nrf/boards/particle_xenon/mpconfigboard.h @@ -32,9 +32,9 @@ #define MICROPY_HW_LED_STATUS (&pin_P1_12) -#define CP_RGB_STATUS_R (&pin_P0_13) -#define CP_RGB_STATUS_G (&pin_P0_14) -#define CP_RGB_STATUS_B (&pin_P0_15) +#define CIRCUITPY_RGB_STATUS_R (&pin_P0_13) +#define CIRCUITPY_RGB_STATUS_G (&pin_P0_14) +#define CIRCUITPY_RGB_STATUS_B (&pin_P0_15) #if QSPI_FLASH_FILESYSTEM #define MICROPY_QSPI_DATA0 NRF_GPIO_PIN_MAP(0, 20) diff --git a/ports/nrf/common-hal/microcontroller/Pin.c b/ports/nrf/common-hal/microcontroller/Pin.c index aea4f63eae..39ee601428 100644 --- a/ports/nrf/common-hal/microcontroller/Pin.c +++ b/ports/nrf/common-hal/microcontroller/Pin.c @@ -31,15 +31,7 @@ #include "py/mphal.h" #include "nrf/pins.h" -#include "supervisor/shared/rgb_led_status.h" -#ifdef MICROPY_HW_NEOPIXEL -bool neopixel_in_use; -#endif -#ifdef MICROPY_HW_APA102_MOSI -bool apa102_sck_in_use; -bool apa102_mosi_in_use; -#endif #ifdef SPEAKER_ENABLE_PIN bool speaker_enable_in_use; #endif @@ -73,14 +65,6 @@ void reset_all_pins(void) { nrf_gpio_cfg_default(pin); } - #ifdef MICROPY_HW_NEOPIXEL - neopixel_in_use = false; - #endif - #ifdef MICROPY_HW_APA102_MOSI - apa102_sck_in_use = false; - apa102_mosi_in_use = false; - #endif - // After configuring SWD because it may be shared. reset_speaker_enable_pin(); } @@ -95,25 +79,6 @@ void reset_pin_number(uint8_t pin_number) { claimed_pins[nrf_pin_port(pin_number)] &= ~(1 << nrf_relative_pin_number(pin_number)); never_reset_pins[nrf_pin_port(pin_number)] &= ~(1 << nrf_relative_pin_number(pin_number)); - #ifdef MICROPY_HW_NEOPIXEL - if (pin_number == MICROPY_HW_NEOPIXEL->number) { - neopixel_in_use = false; - rgb_led_status_init(); - return; - } - #endif - #ifdef MICROPY_HW_APA102_MOSI - if (pin_number == MICROPY_HW_APA102_MOSI->number || - pin_number == MICROPY_HW_APA102_SCK->number) { - apa102_mosi_in_use = apa102_mosi_in_use && pin_number != MICROPY_HW_APA102_MOSI->number; - apa102_sck_in_use = apa102_sck_in_use && pin_number != MICROPY_HW_APA102_SCK->number; - if (!apa102_sck_in_use && !apa102_mosi_in_use) { - rgb_led_status_init(); - } - return; - } - #endif - #ifdef SPEAKER_ENABLE_PIN if (pin_number == SPEAKER_ENABLE_PIN->number) { reset_speaker_enable_pin(); @@ -144,20 +109,6 @@ void claim_pin(const mcu_pin_obj_t *pin) { // Set bit in claimed_pins bitmask. claimed_pins[nrf_pin_port(pin->number)] |= 1 << nrf_relative_pin_number(pin->number); - #ifdef MICROPY_HW_NEOPIXEL - if (pin == MICROPY_HW_NEOPIXEL) { - neopixel_in_use = true; - } - #endif - #ifdef MICROPY_HW_APA102_MOSI - if (pin == MICROPY_HW_APA102_MOSI) { - apa102_mosi_in_use = true; - } - if (pin == MICROPY_HW_APA102_SCK) { - apa102_sck_in_use = true; - } - #endif - #ifdef SPEAKER_ENABLE_PIN if (pin == SPEAKER_ENABLE_PIN) { speaker_enable_in_use = true; @@ -171,20 +122,6 @@ bool pin_number_is_free(uint8_t pin_number) { } bool common_hal_mcu_pin_is_free(const mcu_pin_obj_t *pin) { - #ifdef MICROPY_HW_NEOPIXEL - if (pin == MICROPY_HW_NEOPIXEL) { - return !neopixel_in_use; - } - #endif - #ifdef MICROPY_HW_APA102_MOSI - if (pin == MICROPY_HW_APA102_MOSI) { - return !apa102_mosi_in_use; - } - if (pin == MICROPY_HW_APA102_SCK) { - return !apa102_sck_in_use; - } - #endif - #ifdef SPEAKER_ENABLE_PIN if (pin == SPEAKER_ENABLE_PIN) { return !speaker_enable_in_use; diff --git a/ports/nrf/common-hal/microcontroller/Pin.h b/ports/nrf/common-hal/microcontroller/Pin.h index 888ab6a8c4..f4623aa2dc 100644 --- a/ports/nrf/common-hal/microcontroller/Pin.h +++ b/ports/nrf/common-hal/microcontroller/Pin.h @@ -31,14 +31,6 @@ #include "peripherals/nrf/pins.h" -#ifdef MICROPY_HW_NEOPIXEL -extern bool neopixel_in_use; -#endif -#ifdef MICROPY_HW_APA102_MOSI -extern bool apa102_sck_in_use; -extern bool apa102_mosi_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. diff --git a/ports/raspberrypi/common-hal/busio/SPI.c b/ports/raspberrypi/common-hal/busio/SPI.c index 0fc71136e6..23030cbd0d 100644 --- a/ports/raspberrypi/common-hal/busio/SPI.c +++ b/ports/raspberrypi/common-hal/busio/SPI.c @@ -32,7 +32,6 @@ #include "supervisor/board.h" #include "common-hal/microcontroller/Pin.h" -#include "supervisor/shared/rgb_led_status.h" #include "shared-bindings/microcontroller/Pin.h" #include "src/rp2_common/hardware_dma/include/hardware/dma.h" diff --git a/ports/raspberrypi/common-hal/microcontroller/Pin.c b/ports/raspberrypi/common-hal/microcontroller/Pin.c index 271966c2fe..d40c1f43b5 100644 --- a/ports/raspberrypi/common-hal/microcontroller/Pin.c +++ b/ports/raspberrypi/common-hal/microcontroller/Pin.c @@ -29,21 +29,8 @@ #include "common-hal/microcontroller/__init__.h" #include "shared-bindings/microcontroller/Pin.h" -#include "supervisor/shared/rgb_led_status.h" - #include "src/rp2_common/hardware_gpio/include/hardware/gpio.h" -#ifdef MICROPY_HW_NEOPIXEL -bool neopixel_in_use; -#endif -#ifdef MICROPY_HW_APA102_MOSI -bool apa102_sck_in_use; -bool apa102_mosi_in_use; -#endif -#ifdef SPEAKER_ENABLE_PIN -bool speaker_enable_in_use; -#endif - STATIC uint32_t never_reset_pins; void reset_all_pins(void) { @@ -77,31 +64,6 @@ void reset_pin_number(uint8_t pin_number) { PADS_BANK0_GPIO0_PUE_BITS | PADS_BANK0_GPIO0_PDE_BITS); hw_set_bits(&padsbank0_hw->io[pin_number], PADS_BANK0_GPIO0_OD_BITS); - - #ifdef MICROPY_HW_NEOPIXEL - if (pin_number == MICROPY_HW_NEOPIXEL->number) { - neopixel_in_use = false; - rgb_led_status_init(); - return; - } - #endif - #ifdef MICROPY_HW_APA102_MOSI - if (pin_number == MICROPY_HW_APA102_MOSI->number || - pin_number == MICROPY_HW_APA102_SCK->number) { - apa102_mosi_in_use = apa102_mosi_in_use && pin_number != MICROPY_HW_APA102_MOSI->number; - apa102_sck_in_use = apa102_sck_in_use && pin_number != MICROPY_HW_APA102_SCK->number; - if (!apa102_sck_in_use && !apa102_mosi_in_use) { - rgb_led_status_init(); - } - return; - } - #endif - - #ifdef SPEAKER_ENABLE_PIN - if (pin_number == SPEAKER_ENABLE_PIN->number) { - speaker_enable_in_use = false; - } - #endif } void common_hal_never_reset_pin(const mcu_pin_obj_t *pin) { @@ -113,25 +75,7 @@ void common_hal_reset_pin(const mcu_pin_obj_t *pin) { } void claim_pin(const mcu_pin_obj_t *pin) { - #ifdef MICROPY_HW_NEOPIXEL - if (pin == MICROPY_HW_NEOPIXEL) { - neopixel_in_use = true; - } - #endif - #ifdef MICROPY_HW_APA102_MOSI - if (pin == MICROPY_HW_APA102_MOSI) { - apa102_mosi_in_use = true; - } - if (pin == MICROPY_HW_APA102_SCK) { - apa102_sck_in_use = true; - } - #endif - - #ifdef SPEAKER_ENABLE_PIN - if (pin == SPEAKER_ENABLE_PIN) { - speaker_enable_in_use = true; - } - #endif + // Nothing to do because all changes will set the GPIO settings. } bool pin_number_is_free(uint8_t pin_number) { @@ -145,26 +89,6 @@ bool pin_number_is_free(uint8_t pin_number) { } bool common_hal_mcu_pin_is_free(const mcu_pin_obj_t *pin) { - #ifdef MICROPY_HW_NEOPIXEL - if (pin == MICROPY_HW_NEOPIXEL) { - return !neopixel_in_use; - } - #endif - #ifdef MICROPY_HW_APA102_MOSI - if (pin == MICROPY_HW_APA102_MOSI) { - return !apa102_mosi_in_use; - } - if (pin == MICROPY_HW_APA102_SCK) { - return !apa102_sck_in_use; - } - #endif - - #ifdef SPEAKER_ENABLE_PIN - if (pin == SPEAKER_ENABLE_PIN) { - return !speaker_enable_in_use; - } - #endif - return pin_number_is_free(pin->number); } diff --git a/ports/raspberrypi/common-hal/microcontroller/Pin.h b/ports/raspberrypi/common-hal/microcontroller/Pin.h index 7da3a2b88b..3e2287dc5d 100644 --- a/ports/raspberrypi/common-hal/microcontroller/Pin.h +++ b/ports/raspberrypi/common-hal/microcontroller/Pin.h @@ -34,14 +34,6 @@ #include "peripherals/pins.h" -#ifdef MICROPY_HW_NEOPIXEL -extern bool neopixel_in_use; -#endif -#ifdef MICROPY_HW_APA102_MOSI -extern bool apa102_sck_in_use; -extern bool apa102_mosi_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. diff --git a/ports/stm/common-hal/microcontroller/Pin.c b/ports/stm/common-hal/microcontroller/Pin.c index 80cb9defc8..fa03a7a210 100644 --- a/ports/stm/common-hal/microcontroller/Pin.c +++ b/ports/stm/common-hal/microcontroller/Pin.c @@ -27,19 +27,10 @@ #include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/digitalio/DigitalInOut.h" -#include "supervisor/shared/rgb_led_status.h" #include "py/mphal.h" #include "pins.h" -#ifdef MICROPY_HW_NEOPIXEL -bool neopixel_in_use; -#endif -#if defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK) -bool apa102_sck_in_use; -bool apa102_mosi_in_use; -#endif - #if defined(TFBGA216) GPIO_TypeDef *ports[] = {GPIOA, GPIOB, GPIOC, GPIOD, GPIOE, GPIOF, GPIOG, GPIOH, GPIOI, GPIOJ, GPIOK}; #elif defined(LQFP144) @@ -66,14 +57,6 @@ void reset_all_pins(void) { for (uint8_t i = 0; i < GPIO_PORT_COUNT; i++) { HAL_GPIO_DeInit(ports[i], ~never_reset_pins[i]); } - - #ifdef MICROPY_HW_NEOPIXEL - neopixel_in_use = false; - #endif - #if defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK) - apa102_sck_in_use = false; - apa102_mosi_in_use = false; - #endif } // Mark pin as free and return it to a quiescent state. @@ -89,25 +72,6 @@ void reset_pin_number(uint8_t pin_port, uint8_t pin_number) { claimed_pins[pin_port] &= ~(1 << pin_number); never_reset_pins[pin_port] &= ~(1 << pin_number); HAL_GPIO_DeInit(ports[pin_port], 1 << pin_number); - - #ifdef MICROPY_HW_NEOPIXEL - if (pin_port == MICROPY_HW_NEOPIXEL->port && pin_number == MICROPY_HW_NEOPIXEL->number) { - neopixel_in_use = false; - rgb_led_status_init(); - return; - } - #endif - #if defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK) - if ( - (pin_port == MICROPY_HW_APA102_MOSI->port && pin_number == MICROPY_HW_APA102_MOSI->number) - || (pin_port == MICROPY_HW_APA102_SCK->port && pin_number == MICROPY_HW_APA102_MOSI->number) - ) { - apa102_mosi_in_use = false; - apa102_sck_in_use = false; - rgb_led_status_init(); - return; - } - #endif } void never_reset_pin_number(uint8_t pin_port, uint8_t pin_number) { @@ -140,20 +104,6 @@ bool pin_number_is_free(uint8_t pin_port, uint8_t pin_number) { } bool common_hal_mcu_pin_is_free(const mcu_pin_obj_t *pin) { - #ifdef MICROPY_HW_NEOPIXEL - if (pin == MICROPY_HW_NEOPIXEL) { - return !neopixel_in_use; - } - #endif - #if defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK) - if (pin == MICROPY_HW_APA102_MOSI) { - return !apa102_mosi_in_use; - } - if (pin == MICROPY_HW_APA102_SCK) { - return !apa102_sck_in_use; - } - #endif - return pin_number_is_free(pin->port, pin->number); } @@ -171,19 +121,6 @@ uint8_t common_hal_mcu_pin_number(const mcu_pin_obj_t *pin) { void common_hal_mcu_pin_claim(const mcu_pin_obj_t *pin) { claim_pin(pin->port, pin->number); - #ifdef MICROPY_HW_NEOPIXEL - if (pin == MICROPY_HW_NEOPIXEL) { - neopixel_in_use = true; - } - #endif - #if defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK) - if (pin == MICROPY_HW_APA102_MOSI) { - apa102_mosi_in_use = true; - } - if (pin == MICROPY_HW_APA102_SCK) { - apa102_sck_in_use = true; - } - #endif } void common_hal_mcu_pin_reset_number(uint8_t pin_no) { diff --git a/ports/stm/common-hal/microcontroller/Pin.h b/ports/stm/common-hal/microcontroller/Pin.h index 4a33979421..52c6efd712 100644 --- a/ports/stm/common-hal/microcontroller/Pin.h +++ b/ports/stm/common-hal/microcontroller/Pin.h @@ -31,14 +31,6 @@ #include "peripherals/pins.h" -#ifdef MICROPY_HW_NEOPIXEL -extern bool neopixel_in_use; -#endif -#ifdef MICROPY_HW_APA102_MOSI -extern bool apa102_sck_in_use; -extern bool apa102_mosi_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. diff --git a/shared-bindings/supervisor/__init__.c b/shared-bindings/supervisor/__init__.c index 28ac68d629..b3b00f68d5 100644 --- a/shared-bindings/supervisor/__init__.c +++ b/shared-bindings/supervisor/__init__.c @@ -29,7 +29,7 @@ #include "lib/utils/interrupt_char.h" #include "supervisor/shared/autoreload.h" -#include "supervisor/shared/rgb_led_status.h" +#include "supervisor/shared/status_leds.h" #include "supervisor/shared/stack.h" #include "supervisor/shared/translate.h" #include "supervisor/shared/workflow.h" @@ -79,7 +79,7 @@ STATIC mp_obj_t supervisor_set_rgb_status_brightness(mp_obj_t lvl) { if (brightness_int < 0 || brightness_int > 255) { mp_raise_ValueError(translate("Brightness must be between 0 and 255")); } - set_rgb_status_brightness((uint8_t)brightness_int); + set_status_brightness((uint8_t)brightness_int); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(supervisor_set_rgb_status_brightness_obj, supervisor_set_rgb_status_brightness); diff --git a/shared-module/displayio/EPaperDisplay.c b/shared-module/displayio/EPaperDisplay.c index 7eff587757..826fe9b8ea 100644 --- a/shared-module/displayio/EPaperDisplay.c +++ b/shared-module/displayio/EPaperDisplay.c @@ -409,7 +409,7 @@ void displayio_epaperdisplay_collect_ptrs(displayio_epaperdisplay_obj_t *self) { gc_collect_ptr((void *)self->stop_sequence); } -bool maybe_refresh_epaperdisplay(void) { +size_t maybe_refresh_epaperdisplay(void) { for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { if (displays[i].epaper_display.base.type != &displayio_epaperdisplay_type || displays[i].epaper_display.core.current_group != &circuitpython_splash) { @@ -417,11 +417,16 @@ bool maybe_refresh_epaperdisplay(void) { continue; } displayio_epaperdisplay_obj_t *display = &displays[i].epaper_display; - if (common_hal_displayio_epaperdisplay_get_time_to_refresh(display) != 0) { - return false; + size_t time_to_refresh = common_hal_displayio_epaperdisplay_get_time_to_refresh(display); + if (time_to_refresh > 0) { + return time_to_refresh; } - return common_hal_displayio_epaperdisplay_refresh(display); + if (common_hal_displayio_epaperdisplay_refresh(display)) { + return 0; + } + // If we could refresh but it failed, then we want to retry. + return 1; } - // Return true if no ePaper displays are available to pretend it was updated. - return true; + // Return 0 if no ePaper displays are available to pretend it was updated. + return 0; } diff --git a/shared-module/displayio/EPaperDisplay.h b/shared-module/displayio/EPaperDisplay.h index 988cc57fa3..f200813626 100644 --- a/shared-module/displayio/EPaperDisplay.h +++ b/shared-module/displayio/EPaperDisplay.h @@ -61,7 +61,7 @@ typedef struct { void displayio_epaperdisplay_background(displayio_epaperdisplay_obj_t *self); void release_epaperdisplay(displayio_epaperdisplay_obj_t *self); -bool maybe_refresh_epaperdisplay(void); +size_t maybe_refresh_epaperdisplay(void); void displayio_epaperdisplay_collect_ptrs(displayio_epaperdisplay_obj_t *self); diff --git a/supervisor/shared/external_flash/external_flash.c b/supervisor/shared/external_flash/external_flash.c index 722393ce65..56a7f25b30 100644 --- a/supervisor/shared/external_flash/external_flash.c +++ b/supervisor/shared/external_flash/external_flash.c @@ -39,7 +39,6 @@ #include "lib/oofatfs/ff.h" #include "shared-bindings/microcontroller/__init__.h" #include "supervisor/memory.h" -#include "supervisor/shared/rgb_led_status.h" #define NO_SECTOR_LOADED 0xFFFFFFFF @@ -467,7 +466,6 @@ static void spi_flash_flush_keep_cache(bool keep_cache) { #ifdef MICROPY_HW_LED_MSC port_pin_set_output_level(MICROPY_HW_LED_MSC, true); #endif - temp_status_color(ACTIVE_WRITE); // If we've cached to the flash itself flush from there. if (MP_STATE_VM(flash_ram_cache) == NULL) { flush_scratch_flash(); @@ -475,7 +473,6 @@ static void spi_flash_flush_keep_cache(bool keep_cache) { flush_ram_cache(keep_cache); } current_sector = NO_SECTOR_LOADED; - clear_temp_status(); #ifdef MICROPY_HW_LED_MSC port_pin_set_output_level(MICROPY_HW_LED_MSC, false); #endif diff --git a/supervisor/shared/rgb_led_colors.h b/supervisor/shared/rgb_led_colors.h index 581c177442..56dc0f48d1 100644 --- a/supervisor/shared/rgb_led_colors.h +++ b/supervisor/shared/rgb_led_colors.h @@ -14,28 +14,17 @@ #define PURPLE COLOR(INTENSITY, 0, INTENSITY) #define WHITE COLOR(INTENSITY, INTENSITY, INTENSITY) -#define BOOT_RUNNING BLUE -#define MAIN_RUNNING GREEN -#define SAFE_MODE YELLOW #define ALL_DONE GREEN +#define EXCEPTION RED +#define SAFE_MODE YELLOW #define REPL_RUNNING WHITE -#define ACTIVE_WRITE 0x200000 +#define ALL_DONE_BLINKS 1 +#define EXCEPTION_BLINKS 2 +#define SAFE_MODE_BLINKS 3 -#define ALL_GOOD_CYCLE_MS 2000u +#define OFF_ON_RATIO 3 -#define LINE_NUMBER_TOGGLE_LENGTH 300u -#define EXCEPTION_TYPE_LENGTH_MS 1000u +#define LED_SLEEP_TIME_MS 5000u -#define THOUSANDS WHITE -#define HUNDREDS BLUE -#define TENS YELLOW -#define ONES CYAN - -#define INDENTATION_ERROR GREEN -#define SYNTAX_ERROR CYAN -#define NAME_ERROR WHITE -#define OS_ERROR ORANGE -#define VALUE_ERROR PURPLE -#define MPY_ERROR BLUE -#define OTHER_ERROR YELLOW +#define BLINK_TIME_MS 100u diff --git a/supervisor/shared/rgb_led_status.c b/supervisor/shared/rgb_led_status.c deleted file mode 100644 index d6e11c2aef..0000000000 --- a/supervisor/shared/rgb_led_status.c +++ /dev/null @@ -1,486 +0,0 @@ -/* - * This file is part of the Micro Python project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2017 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 "mphalport.h" -#include "shared-bindings/microcontroller/Pin.h" -#include "rgb_led_status.h" -#include "supervisor/shared/tick.h" -#include "py/obj.h" - -#ifdef MICROPY_HW_NEOPIXEL -uint8_t rgb_status_brightness = 63; -#include "shared-bindings/digitalio/DigitalInOut.h" -#include "shared-bindings/neopixel_write/__init__.h" -static uint8_t status_neopixel_color[3]; -static digitalio_digitalinout_obj_t status_neopixel; -#endif - - -#if defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK) -uint8_t rgb_status_brightness = 50; - -#define APA102_BUFFER_LENGTH 12 -static uint8_t status_apa102_color[APA102_BUFFER_LENGTH] = {0, 0, 0, 0, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff}; - -#if CIRCUITPY_BITBANG_APA102 -#include "shared-bindings/bitbangio/SPI.h" -static bitbangio_spi_obj_t status_apa102 = { - .base = { - .type = &bitbangio_spi_type, - }, -}; -#else -#include "shared-bindings/busio/SPI.h" -busio_spi_obj_t status_apa102 = { - .base = { - .type = &busio_spi_type, - }, -}; -#endif -#endif - -#if defined(CP_RGB_STATUS_R) || defined(CP_RGB_STATUS_G) || defined(CP_RGB_STATUS_B) -#define CP_RGB_STATUS_LED - -#include "shared-bindings/pwmio/PWMOut.h" -#include "shared-bindings/microcontroller/Pin.h" - -pwmio_pwmout_obj_t rgb_status_r = { - .base = { - .type = &pwmio_pwmout_type, - }, -}; -pwmio_pwmout_obj_t rgb_status_g = { - .base = { - .type = &pwmio_pwmout_type, - }, -}; -pwmio_pwmout_obj_t rgb_status_b = { - .base = { - .type = &pwmio_pwmout_type, - }, -}; - -uint8_t rgb_status_brightness = 0xFF; - -uint16_t status_rgb_color[3] = { - 0 /* red */, 0 /* green */, 0 /* blue */ -}; -#endif - -#if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)) || (defined(CP_RGB_STATUS_LED)) -static uint32_t current_status_color = 0; -#endif - -static bool rgb_led_status_init_in_progress = false; -void rgb_led_status_init() { - if (rgb_led_status_init_in_progress) { - // Avoid recursion. - return; - } - rgb_led_status_init_in_progress = true; - - #ifdef MICROPY_HW_NEOPIXEL - common_hal_digitalio_digitalinout_construct(&status_neopixel, MICROPY_HW_NEOPIXEL); - // Pretend we aren't using the pins. digitalio.DigitalInOut - // will mark them as used. - neopixel_in_use = false; - common_hal_digitalio_digitalinout_switch_to_output(&status_neopixel, false, DRIVE_MODE_PUSH_PULL); - #endif - #if defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK) - #if CIRCUITPY_BITBANG_APA102 - shared_module_bitbangio_spi_construct(&status_apa102, - MICROPY_HW_APA102_SCK, - MICROPY_HW_APA102_MOSI, - NULL); - #else - if (!common_hal_busio_spi_deinited(&status_apa102)) { - // This may call us recursively if common_hal_reset_pin() is called, - // The rgb_led_status_init_in_progress guard will prevent further recursion. - common_hal_busio_spi_deinit(&status_apa102); - } - common_hal_busio_spi_construct(&status_apa102, - MICROPY_HW_APA102_SCK, - MICROPY_HW_APA102_MOSI, - NULL); - common_hal_busio_spi_never_reset(&status_apa102); - #endif - // Pretend we aren't using the pins. bitbangio.SPI will - // mark them as used. - apa102_mosi_in_use = false; - apa102_sck_in_use = false; - #if CIRCUITPY_BITBANG_APA102 - shared_module_bitbangio_spi_try_lock(&status_apa102); - // Use 1MHz for clock rate. Some APA102's are spec'd 800kHz-1200kHz, - // though many can run much faster. bitbang will probably run slower. - shared_module_bitbangio_spi_configure(&status_apa102, 1000000, 0, 0, 8); - #else - common_hal_busio_spi_try_lock(&status_apa102); - common_hal_busio_spi_configure(&status_apa102, 1000000, 0, 0, 8); - #endif - #endif - - - #if defined(CP_RGB_STATUS_LED) - if (common_hal_mcu_pin_is_free(CP_RGB_STATUS_R)) { - pwmout_result_t red_result = common_hal_pwmio_pwmout_construct(&rgb_status_r, CP_RGB_STATUS_R, 0, 50000, false); - - if (PWMOUT_OK == red_result) { - common_hal_pwmio_pwmout_never_reset(&rgb_status_r); - } - } - - if (common_hal_mcu_pin_is_free(CP_RGB_STATUS_G)) { - pwmout_result_t green_result = common_hal_pwmio_pwmout_construct(&rgb_status_g, CP_RGB_STATUS_G, 0, 50000, false); - - if (PWMOUT_OK == green_result) { - common_hal_pwmio_pwmout_never_reset(&rgb_status_g); - } - } - - if (common_hal_mcu_pin_is_free(CP_RGB_STATUS_B)) { - pwmout_result_t blue_result = common_hal_pwmio_pwmout_construct(&rgb_status_b, CP_RGB_STATUS_B, 0, 50000, false); - - if (PWMOUT_OK == blue_result) { - common_hal_pwmio_pwmout_never_reset(&rgb_status_b); - } - } - #endif - - #if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)) || (defined(CP_RGB_STATUS_LED)) - // Force a write of the current status color. - uint32_t rgb = current_status_color; - current_status_color = 0x1000000; // Not a valid color - new_status_color(rgb); - #endif - - rgb_led_status_init_in_progress = false; -} - -void reset_status_led() { - #ifdef MICROPY_HW_NEOPIXEL - common_hal_reset_pin(MICROPY_HW_NEOPIXEL); - #endif - #if defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK) - common_hal_reset_pin(MICROPY_HW_APA102_MOSI); - common_hal_reset_pin(MICROPY_HW_APA102_SCK); - #endif - #if defined(CP_RGB_STATUS_LED) - // TODO: Support sharing status LED with user. - #endif -} - -void new_status_color(uint32_t rgb) { - #if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)) || (defined(CP_RGB_STATUS_LED)) - if (current_status_color == rgb) { - return; - } - uint32_t rgb_adjusted = color_brightness(rgb, rgb_status_brightness); - current_status_color = rgb; - #endif - - #ifdef MICROPY_HW_NEOPIXEL - if (neopixel_in_use) { - return; - } - status_neopixel_color[0] = (rgb_adjusted >> 8) & 0xff; - status_neopixel_color[1] = (rgb_adjusted >> 16) & 0xff; - status_neopixel_color[2] = rgb_adjusted & 0xff; - common_hal_neopixel_write(&status_neopixel, status_neopixel_color, 3); - #endif - #if defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK) - if (apa102_mosi_in_use || apa102_sck_in_use) { - return; - } - status_apa102_color[5] = rgb_adjusted & 0xff; - status_apa102_color[6] = (rgb_adjusted >> 8) & 0xff; - status_apa102_color[7] = (rgb_adjusted >> 16) & 0xff; - - #if CIRCUITPY_BITBANG_APA102 - shared_module_bitbangio_spi_write(&status_apa102, status_apa102_color, APA102_BUFFER_LENGTH); - #else - common_hal_busio_spi_write(&status_apa102, status_apa102_color, APA102_BUFFER_LENGTH); - #endif - #endif - - #if defined(CP_RGB_STATUS_LED) - uint8_t red_u8 = (rgb_adjusted >> 16) & 0xFF; - uint8_t green_u8 = (rgb_adjusted >> 8) & 0xFF; - uint8_t blue_u8 = rgb_adjusted & 0xFF; - - #if defined(CP_RGB_STATUS_INVERTED_PWM) - status_rgb_color[0] = (1 << 16) - 1 - ((uint16_t)(red_u8 << 8) + red_u8); - status_rgb_color[1] = (1 << 16) - 1 - ((uint16_t)(green_u8 << 8) + green_u8); - status_rgb_color[2] = (1 << 16) - 1 - ((uint16_t)(blue_u8 << 8) + blue_u8); - #else - status_rgb_color[0] = (uint16_t)(red_u8 << 8) + red_u8; - status_rgb_color[1] = (uint16_t)(green_u8 << 8) + green_u8; - status_rgb_color[2] = (uint16_t)(blue_u8 << 8) + blue_u8; - #endif - - common_hal_pwmio_pwmout_set_duty_cycle(&rgb_status_r, status_rgb_color[0]); - common_hal_pwmio_pwmout_set_duty_cycle(&rgb_status_g, status_rgb_color[1]); - common_hal_pwmio_pwmout_set_duty_cycle(&rgb_status_b, status_rgb_color[2]); - #endif -} - -void temp_status_color(uint32_t rgb) { - #if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)) || (defined(CP_RGB_STATUS_LED)) - uint32_t rgb_adjusted = rgb; - rgb_adjusted = color_brightness(rgb, rgb_status_brightness); - #endif - #ifdef MICROPY_HW_NEOPIXEL - if (neopixel_in_use) { - return; - } - uint8_t colors[3] = {(rgb_adjusted >> 8) & 0xff, (rgb_adjusted >> 16) & 0xff, rgb_adjusted & 0xff}; - common_hal_neopixel_write(&status_neopixel, colors, 3); - #endif - #if defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK) - if (apa102_mosi_in_use || apa102_sck_in_use) { - return; - } - uint8_t colors[APA102_BUFFER_LENGTH] = {0, 0, 0, 0, 0xff, rgb_adjusted & 0xff, (rgb_adjusted >> 8) & 0xff, (rgb_adjusted >> 16) & 0xff, 0xff, 0xff, 0xff, 0xff}; - #if CIRCUITPY_BITBANG_APA102 - shared_module_bitbangio_spi_write(&status_apa102, colors, APA102_BUFFER_LENGTH); - #else - common_hal_busio_spi_write(&status_apa102, colors, APA102_BUFFER_LENGTH); - #endif - #endif - #if defined(CP_RGB_STATUS_LED) - uint8_t red_u8 = (rgb_adjusted >> 16) & 0xFF; - uint8_t green_u8 = (rgb_adjusted >> 8) & 0xFF; - uint8_t blue_u8 = rgb_adjusted & 0xFF; - - uint16_t temp_status_color_rgb[3] = {0}; - - #if defined(CP_RGB_STATUS_INVERTED_PWM) - temp_status_color_rgb[0] = (1 << 16) - 1 - ((uint16_t)(red_u8 << 8) + red_u8); - temp_status_color_rgb[1] = (1 << 16) - 1 - ((uint16_t)(green_u8 << 8) + green_u8); - temp_status_color_rgb[2] = (1 << 16) - 1 - ((uint16_t)(blue_u8 << 8) + blue_u8); - #else - temp_status_color_rgb[0] = (uint16_t)(red_u8 << 8) + red_u8; - temp_status_color_rgb[1] = (uint16_t)(green_u8 << 8) + green_u8; - temp_status_color_rgb[2] = (uint16_t)(blue_u8 << 8) + blue_u8; - #endif - - common_hal_pwmio_pwmout_set_duty_cycle(&rgb_status_r, temp_status_color_rgb[0]); - common_hal_pwmio_pwmout_set_duty_cycle(&rgb_status_g, temp_status_color_rgb[1]); - common_hal_pwmio_pwmout_set_duty_cycle(&rgb_status_b, temp_status_color_rgb[2]); - #endif -} - -void clear_temp_status() { - #ifdef MICROPY_HW_NEOPIXEL - if (neopixel_in_use) { - return; - } - common_hal_neopixel_write(&status_neopixel, status_neopixel_color, 3); - #endif - #if defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK) - if (apa102_mosi_in_use || apa102_sck_in_use) { - return; - } - #if CIRCUITPY_BITBANG_APA102 - shared_module_bitbangio_spi_write(&status_apa102, status_apa102_color, APA102_BUFFER_LENGTH); - #else - common_hal_busio_spi_write(&status_apa102, status_apa102_color, APA102_BUFFER_LENGTH); - #endif - #endif - #if defined(CP_RGB_STATUS_LED) - - uint16_t red = 0; - uint16_t green = 0; - uint16_t blue = 0; - - #if defined(CP_RGB_STATUS_INVERTED_PWM) - red = (1 << 16) - 1 - status_rgb_color[0]; - green = (1 << 16) - 1 - status_rgb_color[1]; - blue = (1 << 16) - 1 - status_rgb_color[2]; - #else - red = status_rgb_color[0]; - green = status_rgb_color[1]; - blue = status_rgb_color[2]; - #endif - - common_hal_pwmio_pwmout_set_duty_cycle(&rgb_status_r, red); - common_hal_pwmio_pwmout_set_duty_cycle(&rgb_status_g, green); - common_hal_pwmio_pwmout_set_duty_cycle(&rgb_status_b, blue); - #endif -} - -uint32_t color_brightness(uint32_t color, uint8_t brightness) { - #if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)) || (defined(CP_RGB_STATUS_LED)) - uint32_t result = ((color & 0xff0000) * brightness / 255) & 0xff0000; - result += ((color & 0xff00) * brightness / 255) & 0xff00; - result += ((color & 0xff) * brightness / 255) & 0xff; - return result; - #else - return color; - #endif -} - -void set_rgb_status_brightness(uint8_t level) { - #if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)) || (defined(CP_RGB_STATUS_LED)) - rgb_status_brightness = level; - uint32_t current_color = current_status_color; - // Temporarily change the current color global to force the new_status_color call to update the - // LED. Usually duplicate calls of the same color are ignored without regard to brightness - // changes. - current_status_color = 0; - new_status_color(current_color); - #endif -} - -void prep_rgb_status_animation(const pyexec_result_t *result, - bool found_main, - safe_mode_t safe_mode, - rgb_status_animation_t *status) { - #if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)) || (defined(CP_RGB_STATUS_LED)) - new_status_color(ALL_DONE); - status->pattern_start = supervisor_ticks_ms32(); - status->safe_mode = safe_mode; - status->found_main = found_main; - status->total_exception_cycle = 0; - status->ok = result->return_code != PYEXEC_EXCEPTION; - if (status->ok) { - // If this isn't an exception, skip exception sorting and handling - return; - } - status->ones = result->exception_line % 10; - status->ones += status->ones > 0 ? 1 : 0; - status->tens = (result->exception_line / 10) % 10; - status->tens += status->tens > 0 ? 1 : 0; - status->hundreds = (result->exception_line / 100) % 10; - status->hundreds += status->hundreds > 0 ? 1 : 0; - status->thousands = (result->exception_line / 1000) % 10; - status->thousands += status->thousands > 0 ? 1 : 0; - status->digit_sum = status->ones + status->tens + status->hundreds + status->thousands; - uint8_t num_places = 0; - uint16_t line = result->exception_line; - for (int i = 0; i < 4; i++) { - if ((line % 10) > 0) { - num_places++; - } - line /= 10; - } - if (!status->ok) { - status->total_exception_cycle = EXCEPTION_TYPE_LENGTH_MS * 3 + LINE_NUMBER_TOGGLE_LENGTH * status->digit_sum + LINE_NUMBER_TOGGLE_LENGTH * num_places; - } - if (!result->exception_type) { - status->exception_color = OTHER_ERROR; - } else if (mp_obj_is_subclass_fast(result->exception_type, &mp_type_IndentationError)) { - status->exception_color = INDENTATION_ERROR; - } else if (mp_obj_is_subclass_fast(result->exception_type, &mp_type_SyntaxError)) { - status->exception_color = SYNTAX_ERROR; - } else if (mp_obj_is_subclass_fast(result->exception_type, &mp_type_NameError)) { - status->exception_color = NAME_ERROR; - } else if (mp_obj_is_subclass_fast(result->exception_type, &mp_type_OSError)) { - status->exception_color = OS_ERROR; - } else if (mp_obj_is_subclass_fast(result->exception_type, &mp_type_ValueError)) { - status->exception_color = VALUE_ERROR; - } else if (mp_obj_is_subclass_fast(result->exception_type, &mp_type_MpyError)) { - status->exception_color = MPY_ERROR; - } else { - status->exception_color = OTHER_ERROR; - } - #endif -} - -bool tick_rgb_status_animation(rgb_status_animation_t *status) { - #if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)) || (defined(CP_RGB_STATUS_LED)) - uint32_t tick_diff = supervisor_ticks_ms32() - status->pattern_start; - if (status->ok) { - // All is good. Ramp ALL_DONE up and down. - if (tick_diff > ALL_GOOD_CYCLE_MS) { - status->pattern_start = supervisor_ticks_ms32(); - new_status_color(BLACK); - return true; - } - - uint16_t brightness = tick_diff * 255 / (ALL_GOOD_CYCLE_MS / 2); - if (brightness > 255) { - brightness = 511 - brightness; - } - if (status->safe_mode == NO_SAFE_MODE) { - new_status_color(color_brightness(ALL_DONE, brightness)); - } else { - new_status_color(color_brightness(SAFE_MODE, brightness)); - } - } else { - if (tick_diff > status->total_exception_cycle) { - status->pattern_start = supervisor_ticks_ms32(); - return true; - } - // First flash the file color. - if (tick_diff < EXCEPTION_TYPE_LENGTH_MS) { - if (status->found_main) { - new_status_color(MAIN_RUNNING); - } else { - new_status_color(BOOT_RUNNING); - } - // Next flash the exception color. - } else if (tick_diff < EXCEPTION_TYPE_LENGTH_MS * 2) { - new_status_color(status->exception_color); - // Finally flash the line number digits from highest to lowest. - // Zeroes will not produce a flash but can be read by the absence of - // a color from the sequence. - } else if (tick_diff < (EXCEPTION_TYPE_LENGTH_MS * 2 + LINE_NUMBER_TOGGLE_LENGTH * status->digit_sum)) { - uint32_t digit_diff = tick_diff - EXCEPTION_TYPE_LENGTH_MS * 2; - if ((digit_diff % LINE_NUMBER_TOGGLE_LENGTH) < (LINE_NUMBER_TOGGLE_LENGTH / 2)) { - new_status_color(BLACK); - } else if (digit_diff < LINE_NUMBER_TOGGLE_LENGTH * status->thousands) { - if (digit_diff < LINE_NUMBER_TOGGLE_LENGTH) { - new_status_color(BLACK); - } else { - new_status_color(THOUSANDS); - } - } else if (digit_diff < LINE_NUMBER_TOGGLE_LENGTH * (status->thousands + status->hundreds)) { - if (digit_diff < LINE_NUMBER_TOGGLE_LENGTH * (status->thousands + 1)) { - new_status_color(BLACK); - } else { - new_status_color(HUNDREDS); - } - } else if (digit_diff < LINE_NUMBER_TOGGLE_LENGTH * (status->thousands + status->hundreds + status->tens)) { - if (digit_diff < LINE_NUMBER_TOGGLE_LENGTH * (status->thousands + status->hundreds + 1)) { - new_status_color(BLACK); - } else { - new_status_color(TENS); - } - } else { - if (digit_diff < LINE_NUMBER_TOGGLE_LENGTH * (status->thousands + status->hundreds + status->tens + 1)) { - new_status_color(BLACK); - } else { - new_status_color(ONES); - } - } - } else { - new_status_color(BLACK); - } - } - #endif - return false; // Animation is not finished. -} diff --git a/supervisor/shared/rgb_led_status.h b/supervisor/shared/rgb_led_status.h deleted file mode 100644 index 753a1167cb..0000000000 --- a/supervisor/shared/rgb_led_status.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2017 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. - */ - -#ifndef MICROPY_INCLUDED_SUPERVISOR_RGB_LED_STATUS_H -#define MICROPY_INCLUDED_SUPERVISOR_RGB_LED_STATUS_H - -#include -#include - -#include "lib/utils/pyexec.h" -#include "supervisor/port.h" - -#include "py/mpconfig.h" -#include "rgb_led_colors.h" - -#include "supervisor/shared/safe_mode.h" - -// Overall, the time module must be implemented. -// To work with a DotStar, one must have MICROPY_HW_APA102_SCK and -// MICROPY_HW_APA102_MOSI defined and bitbangio.SPI or busio.SPI implemented. -// To work with a NeoPixel, one must have MICROPY_HW_NEOPIXEL defined and -// neopixel_write implemented. - -#if defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK) && !CIRCUITPY_BITBANG_APA102 -#include "common-hal/busio/SPI.h" -extern busio_spi_obj_t status_apa102; -#endif - -void rgb_led_status_init(void); -void reset_status_led(void); -void new_status_color(uint32_t rgb); -void temp_status_color(uint32_t rgb); -void clear_temp_status(void); - -uint32_t color_brightness(uint32_t color, uint8_t brightness); -void set_rgb_status_brightness(uint8_t level); - -typedef struct { - bool ok; - uint32_t pattern_start; - uint32_t total_exception_cycle; - safe_mode_t safe_mode; - uint8_t digit_sum; - uint8_t ones; - uint8_t tens; - uint8_t hundreds; - uint8_t thousands; - uint32_t exception_color; - bool found_main; -} rgb_status_animation_t; - -void prep_rgb_status_animation(const pyexec_result_t *result, - bool found_main, - safe_mode_t safe_mode, - rgb_status_animation_t *status); -bool tick_rgb_status_animation(rgb_status_animation_t *status); - -#endif // MICROPY_INCLUDED_SUPERVISOR_RGB_LED_STATUS_H diff --git a/supervisor/shared/safe_mode.c b/supervisor/shared/safe_mode.c index 661fd79af8..ba31eac4cb 100644 --- a/supervisor/shared/safe_mode.c +++ b/supervisor/shared/safe_mode.c @@ -36,7 +36,7 @@ #include "supervisor/serial.h" #include "supervisor/shared/rgb_led_colors.h" -#include "supervisor/shared/rgb_led_status.h" +#include "supervisor/shared/status_leds.h" #include "supervisor/shared/translate.h" #include "supervisor/shared/tick.h" @@ -65,11 +65,9 @@ safe_mode_t wait_for_safe_mode_reset(void) { } port_set_saved_word(SAFE_MODE_DATA_GUARD | (MANUAL_SAFE_MODE << 8)); // Wait for a while to allow for reset. - temp_status_color(SAFE_MODE); - #ifdef MICROPY_HW_LED_STATUS - digitalio_digitalinout_obj_t status_led; - common_hal_digitalio_digitalinout_construct(&status_led, MICROPY_HW_LED_STATUS); - common_hal_digitalio_digitalinout_switch_to_output(&status_led, true, DRIVE_MODE_PUSH_PULL); + + #if CIRCUITPY_STATUS_LED + status_led_init(); #endif #ifdef CIRCUITPY_BOOT_BUTTON digitalio_digitalinout_obj_t boot_button; @@ -78,22 +76,32 @@ safe_mode_t wait_for_safe_mode_reset(void) { #endif uint64_t start_ticks = supervisor_ticks_ms64(); uint64_t diff = 0; + bool boot_in_safe_mode = false; while (diff < 700) { - #ifdef MICROPY_HW_LED_STATUS + #ifdef CIRCUITPY_STATUS_LED // Blink on for 100, off for 100, on for 100, off for 100 and on for 200 - common_hal_digitalio_digitalinout_set_value(&status_led, diff > 100 && diff / 100 != 2 && diff / 100 != 4); + bool led_on = diff > 100 && diff / 100 != 2 && diff / 100 != 4; + if (led_on) { + new_status_color(SAFE_MODE); + } else { + new_status_color(BLACK); + } #endif #ifdef CIRCUITPY_BOOT_BUTTON if (!common_hal_digitalio_digitalinout_get_value(&boot_button)) { - return USER_SAFE_MODE; + boot_in_safe_mode = true; + break; } #endif diff = supervisor_ticks_ms64() - start_ticks; } - #ifdef MICROPY_HW_LED_STATUS - common_hal_digitalio_digitalinout_deinit(&status_led); + #if CIRCUITPY_STATUS_LED + new_status_color(BLACK); + status_led_deinit(); #endif - clear_temp_status(); + if (boot_in_safe_mode) { + return USER_SAFE_MODE; + } port_set_saved_word(SAFE_MODE_DATA_GUARD); return NO_SAFE_MODE; } diff --git a/supervisor/shared/status_leds.c b/supervisor/shared/status_leds.c index 672242a963..a367aa3086 100644 --- a/supervisor/shared/status_leds.c +++ b/supervisor/shared/status_leds.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries + * Copyright (c) 2017-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 @@ -26,11 +26,75 @@ #include "supervisor/shared/status_leds.h" -#if CIRCUITPY_DIGITALIO -#include "common-hal/digitalio/DigitalInOut.h" +#include "mphalport.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "supervisor/shared/tick.h" +#include "py/obj.h" + +#ifdef MICROPY_HW_NEOPIXEL +uint8_t rgb_status_brightness = 63; + #include "shared-bindings/digitalio/DigitalInOut.h" + #include "shared-bindings/neopixel_write/__init__.h" +static uint8_t status_neopixel_color[3]; +static digitalio_digitalinout_obj_t status_neopixel; + +#elif defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK) +uint8_t rgb_status_brightness = 50; + + #define APA102_BUFFER_LENGTH 12 +static uint8_t status_apa102_color[APA102_BUFFER_LENGTH] = {0, 0, 0, 0, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff}; + + #if CIRCUITPY_BITBANG_APA102 + #include "shared-bindings/bitbangio/SPI.h" +static bitbangio_spi_obj_t status_apa102 = { + .base = { + .type = &bitbangio_spi_type, + }, +}; + #else + #include "shared-bindings/busio/SPI.h" +busio_spi_obj_t status_apa102 = { + .base = { + .type = &busio_spi_type, + }, +}; + #endif + +#elif CIRCUITPY_PWM_RGB_LED + #include "shared-bindings/pwmio/PWMOut.h" + #include "shared-bindings/microcontroller/Pin.h" + +pwmio_pwmout_obj_t rgb_status_r = { + .base = { + .type = &pwmio_pwmout_type, + }, +}; +pwmio_pwmout_obj_t rgb_status_g = { + .base = { + .type = &pwmio_pwmout_type, + }, +}; +pwmio_pwmout_obj_t rgb_status_b = { + .base = { + .type = &pwmio_pwmout_type, + }, +}; + +uint8_t rgb_status_brightness = 0xFF; + +uint16_t status_rgb_color[3] = { + 0 /* red */, 0 /* green */, 0 /* blue */ +}; +#elif CIRCUITPY_DIGITALIO && defined(MICROPY_HW_LED_STATUS) #include "shared-bindings/digitalio/DigitalInOut.h" +digitalio_digitalinout_obj_t single_color_led; + +uint8_t rgb_status_brightness = 0xff; #endif +#if CIRCUITPY_DIGITALIO && (defined(MICROPY_HW_LED_RX) || defined(MICROPY_HW_LED_TX)) +#include "shared-bindings/digitalio/DigitalInOut.h" + #ifdef MICROPY_HW_LED_RX digitalio_digitalinout_obj_t rx_led; #endif @@ -38,27 +102,210 @@ digitalio_digitalinout_obj_t rx_led; #ifdef MICROPY_HW_LED_TX digitalio_digitalinout_obj_t tx_led; #endif +#endif -void init_status_leds(void) { - #ifdef MICROPY_HW_LED_RX +#if CIRCUITPY_STATUS_LED +static uint32_t current_status_color = 0; +#endif + +static bool status_led_init_in_progress = false; +void status_led_init() { + if (status_led_init_in_progress) { + // Avoid recursion. + return; + } + status_led_init_in_progress = true; + + #ifdef MICROPY_HW_NEOPIXEL + common_hal_digitalio_digitalinout_construct(&status_neopixel, MICROPY_HW_NEOPIXEL); + common_hal_digitalio_digitalinout_switch_to_output(&status_neopixel, false, DRIVE_MODE_PUSH_PULL); + #elif defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK) + #if CIRCUITPY_BITBANG_APA102 + shared_module_bitbangio_spi_construct(&status_apa102, + MICROPY_HW_APA102_SCK, + MICROPY_HW_APA102_MOSI, + NULL); + #else + if (!common_hal_busio_spi_deinited(&status_apa102)) { + common_hal_busio_spi_deinit(&status_apa102); + } + common_hal_busio_spi_construct(&status_apa102, + MICROPY_HW_APA102_SCK, + MICROPY_HW_APA102_MOSI, + NULL); + #endif + #if CIRCUITPY_BITBANG_APA102 + shared_module_bitbangio_spi_try_lock(&status_apa102); + // Use 1MHz for clock rate. Some APA102's are spec'd 800kHz-1200kHz, + // though many can run much faster. bitbang will probably run slower. + shared_module_bitbangio_spi_configure(&status_apa102, 1000000, 0, 0, 8); + #else + common_hal_busio_spi_try_lock(&status_apa102); + common_hal_busio_spi_configure(&status_apa102, 1000000, 0, 0, 8); + #endif + + + #elif CIRCUITPY_PWM_RGB_LED + if (common_hal_mcu_pin_is_free(CIRCUITPY_RGB_STATUS_R)) { + pwmout_result_t red_result = common_hal_pwmio_pwmout_construct(&rgb_status_r, CIRCUITPY_RGB_STATUS_R, 0, 50000, false); + + if (PWMOUT_OK == red_result) { + common_hal_pwmio_pwmout_never_reset(&rgb_status_r); + } + } + + if (common_hal_mcu_pin_is_free(CIRCUITPY_RGB_STATUS_G)) { + pwmout_result_t green_result = common_hal_pwmio_pwmout_construct(&rgb_status_g, CIRCUITPY_RGB_STATUS_G, 0, 50000, false); + + if (PWMOUT_OK == green_result) { + common_hal_pwmio_pwmout_never_reset(&rgb_status_g); + } + } + + if (common_hal_mcu_pin_is_free(CIRCUITPY_RGB_STATUS_B)) { + pwmout_result_t blue_result = common_hal_pwmio_pwmout_construct(&rgb_status_b, CIRCUITPY_RGB_STATUS_B, 0, 50000, false); + + if (PWMOUT_OK == blue_result) { + common_hal_pwmio_pwmout_never_reset(&rgb_status_b); + } + } + + #elif defined(MICROPY_HW_LED_STATUS) + common_hal_digitalio_digitalinout_construct(&single_color_led, MICROPY_HW_LED_STATUS); + common_hal_digitalio_digitalinout_switch_to_output(&single_color_led, true, DRIVE_MODE_PUSH_PULL); + #endif + + #if CIRCUITPY_DIGITALIO && CIRCUITPY_STATUS_LED + // Force a write of the current status color. + uint32_t rgb = current_status_color; + current_status_color = 0x1000000; // Not a valid color + new_status_color(rgb); + #endif + + status_led_init_in_progress = false; +} + +void status_led_deinit() { + #ifdef MICROPY_HW_NEOPIXEL + common_hal_reset_pin(MICROPY_HW_NEOPIXEL); + + #elif defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK) + #if CIRCUITPY_BITBANG_APA102 + shared_module_bitbangio_spi_deinit(&status_apa102); + #else + common_hal_busio_spi_deinit(&status_apa102); + #endif + + #elif CIRCUITPY_PWM_RGB_LED + if (!common_hal_mcu_pin_is_free(CIRCUITPY_RGB_STATUS_R)) { + common_hal_pwmio_pwmout_deinit(&rgb_status_r); + } + + if (!common_hal_mcu_pin_is_free(CIRCUITPY_RGB_STATUS_G)) { + common_hal_pwmio_pwmout_deinit(&rgb_status_g); + } + + if (!common_hal_mcu_pin_is_free(CIRCUITPY_RGB_STATUS_B)) { + common_hal_pwmio_pwmout_deinit(&rgb_status_b); + } + + #elif defined(MICROPY_HW_LED_STATUS) + common_hal_digitalio_digitalinout_deinit(&single_color_led); + #endif +} + +void new_status_color(uint32_t rgb) { + #if CIRCUITPY_STATUS_LED + if (current_status_color == rgb) { + return; + } + uint32_t rgb_adjusted = color_brightness(rgb, rgb_status_brightness); + current_status_color = rgb; + #endif + + #ifdef MICROPY_HW_NEOPIXEL + status_neopixel_color[0] = (rgb_adjusted >> 8) & 0xff; + status_neopixel_color[1] = (rgb_adjusted >> 16) & 0xff; + status_neopixel_color[2] = rgb_adjusted & 0xff; + common_hal_neopixel_write(&status_neopixel, status_neopixel_color, 3); + + #elif defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK) + status_apa102_color[5] = rgb_adjusted & 0xff; + status_apa102_color[6] = (rgb_adjusted >> 8) & 0xff; + status_apa102_color[7] = (rgb_adjusted >> 16) & 0xff; + + #if CIRCUITPY_BITBANG_APA102 + shared_module_bitbangio_spi_write(&status_apa102, status_apa102_color, APA102_BUFFER_LENGTH); + #else + common_hal_busio_spi_write(&status_apa102, status_apa102_color, APA102_BUFFER_LENGTH); + #endif + + #elif CIRCUITPY_PWM_RGB_LED + uint8_t red_u8 = (rgb_adjusted >> 16) & 0xFF; + uint8_t green_u8 = (rgb_adjusted >> 8) & 0xFF; + uint8_t blue_u8 = rgb_adjusted & 0xFF; + + #ifdef CIRCUITPY_RGB_STATUS_INVERTED_PWM + status_rgb_color[0] = (1 << 16) - 1 - ((uint16_t)(red_u8 << 8) + red_u8); + status_rgb_color[1] = (1 << 16) - 1 - ((uint16_t)(green_u8 << 8) + green_u8); + status_rgb_color[2] = (1 << 16) - 1 - ((uint16_t)(blue_u8 << 8) + blue_u8); + #else + status_rgb_color[0] = (uint16_t)(red_u8 << 8) + red_u8; + status_rgb_color[1] = (uint16_t)(green_u8 << 8) + green_u8; + status_rgb_color[2] = (uint16_t)(blue_u8 << 8) + blue_u8; + #endif + + common_hal_pwmio_pwmout_set_duty_cycle(&rgb_status_r, status_rgb_color[0]); + common_hal_pwmio_pwmout_set_duty_cycle(&rgb_status_g, status_rgb_color[1]); + common_hal_pwmio_pwmout_set_duty_cycle(&rgb_status_b, status_rgb_color[2]); + #elif CIRCUITPY_DIGITALIO && defined(MICROPY_HW_LED_STATUS) + common_hal_digitalio_digitalinout_set_value(&single_color_led, rgb_adjusted > 0); + #endif +} + +uint32_t color_brightness(uint32_t color, uint8_t brightness) { + #if CIRCUITPY_STATUS_LED + uint32_t result = ((color & 0xff0000) * brightness / 255) & 0xff0000; + result += ((color & 0xff00) * brightness / 255) & 0xff00; + result += ((color & 0xff) * brightness / 255) & 0xff; + return result; + #else + return color; + #endif +} + +void set_status_brightness(uint8_t level) { + #if CIRCUITPY_STATUS_LED + rgb_status_brightness = level; + uint32_t current_color = current_status_color; + // Temporarily change the current color global to force the new_status_color call to update the + // LED. Usually duplicate calls of the same color are ignored without regard to brightness + // changes. + current_status_color = 0; + new_status_color(current_color); + #endif +} + +void init_rxtx_leds(void) { + #if CIRCUITPY_DIGITALIO && defined(MICROPY_HW_LED_RX) common_hal_digitalio_digitalinout_construct(&rx_led, MICROPY_HW_LED_RX); common_hal_digitalio_digitalinout_switch_to_output(&rx_led, true, DRIVE_MODE_PUSH_PULL); #endif - #ifdef MICROPY_HW_LED_TX + #if CIRCUITPY_DIGITALIO && defined(MICROPY_HW_LED_TX) common_hal_digitalio_digitalinout_construct(&tx_led, MICROPY_HW_LED_TX); common_hal_digitalio_digitalinout_switch_to_output(&tx_led, true, DRIVE_MODE_PUSH_PULL); #endif } void toggle_rx_led(void) { - #ifdef MICROPY_HW_LED_RX + #if CIRCUITPY_DIGITALIO && defined(MICROPY_HW_LED_RX) common_hal_digitalio_digitalinout_set_value(&rx_led, !common_hal_digitalio_digitalinout_get_value(&rx_led)); #endif } void toggle_tx_led(void) { - #ifdef MICROPY_HW_LED_TX + #if CIRCUITPY_DIGITALIO && defined(MICROPY_HW_LED_TX) common_hal_digitalio_digitalinout_set_value(&tx_led, !common_hal_digitalio_digitalinout_get_value(&tx_led)); #endif } diff --git a/supervisor/shared/status_leds.h b/supervisor/shared/status_leds.h index 30132753f3..4a55922845 100644 --- a/supervisor/shared/status_leds.h +++ b/supervisor/shared/status_leds.h @@ -27,10 +27,35 @@ #ifndef MICROPY_INCLUDED_SUPERVISOR_STATUS_LEDS_H #define MICROPY_INCLUDED_SUPERVISOR_STATUS_LEDS_H -void init_status_leds(void); +#include +#include +#include "lib/utils/pyexec.h" +#include "supervisor/port.h" + +#include "py/mpconfig.h" +#include "rgb_led_colors.h" + +#include "supervisor/shared/safe_mode.h" + +// Overall, the time module must be implemented. +// To work with a DotStar, one must have MICROPY_HW_APA102_SCK and +// MICROPY_HW_APA102_MOSI defined and bitbangio.SPI or busio.SPI implemented. +// To work with a NeoPixel, one must have MICROPY_HW_NEOPIXEL defined and +// neopixel_write implemented. + +#define CIRCUITPY_PWM_RGB_LED defined(CIRCUITPY_RGB_STATUS_R) || defined(CIRCUITPY_RGB_STATUS_G) || defined(CIRCUITPY_RGB_STATUS_B) +#define CIRCUITPY_STATUS_LED (CIRCUITPY_DIGITALIO && defined(MICROPY_HW_LED_STATUS)) || defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)) || CIRCUITPY_PWM_RGB_LED + +void status_led_init(void); +void status_led_deinit(void); +void new_status_color(uint32_t rgb); + +uint32_t color_brightness(uint32_t color, uint8_t brightness); +void set_status_brightness(uint8_t level); + +void init_rxtx_leds(void); void toggle_rx_led(void); - void toggle_tx_led(void); #endif // MICROPY_INCLUDED_SUPERVISOR_STATUS_LEDS_H diff --git a/supervisor/supervisor.mk b/supervisor/supervisor.mk index 1ca937cdab..0815a9ffc4 100644 --- a/supervisor/supervisor.mk +++ b/supervisor/supervisor.mk @@ -9,7 +9,6 @@ SRC_SUPERVISOR = \ supervisor/shared/flash.c \ supervisor/shared/memory.c \ supervisor/shared/micropython.c \ - supervisor/shared/rgb_led_status.c \ supervisor/shared/safe_mode.c \ supervisor/shared/stack.c \ supervisor/shared/status_leds.c \ From 5c33c9d597c364bd2a3f4bfc418c2cf3b561e76e Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 13 May 2021 11:04:07 -0700 Subject: [PATCH 2/6] Fix SAMD RTC needed to wait for sync. NeoPixel on SAMD doesn't need disabled caches. It just needed timing adjustment for 120mhz clock speed. --- main.c | 9 ++--- .../boards/feather_m4_express/mpconfigboard.h | 2 +- .../common-hal/neopixel_write/__init__.c | 39 +++---------------- ports/atmel-samd/supervisor/port.c | 20 ++++++++-- .../feather_nrf52840_express/mpconfigboard.h | 2 +- 5 files changed, 28 insertions(+), 44 deletions(-) diff --git a/main.c b/main.c index 78303e1235..1caeb12e2f 100755 --- a/main.c +++ b/main.c @@ -485,11 +485,10 @@ STATIC bool run_code_py(safe_mode_t safe_mode) { time_to_next_change = MIN(time_to_next_change, time_to_epaper_refresh); } #endif - if (time_to_next_change > 0) { - // time_to_next_change is in ms and ticks are slightly shorter so - // we'll undersleep just a little. It shouldn't matter. - port_interrupt_after_ticks(time_to_next_change); - } + + // time_to_next_change is in ms and ticks are slightly shorter so + // we'll undersleep just a little. It shouldn't matter. + port_interrupt_after_ticks(time_to_next_change); #endif port_idle_until_interrupt(); } diff --git a/ports/atmel-samd/boards/feather_m4_express/mpconfigboard.h b/ports/atmel-samd/boards/feather_m4_express/mpconfigboard.h index a57b18e24a..ef4a556227 100644 --- a/ports/atmel-samd/boards/feather_m4_express/mpconfigboard.h +++ b/ports/atmel-samd/boards/feather_m4_express/mpconfigboard.h @@ -12,7 +12,7 @@ // QSPI Data pins #define MICROPY_PORT_A (PORT_PA08 | PORT_PA09 | PORT_PA10 | PORT_PA11) // QSPI CS, QSPI SCK and NeoPixel pin -#define MICROPY_PORT_B (PORT_PB03 | PORT_PB10 | PORT_PB11) +#define MICROPY_PORT_B (PORT_PB10 | PORT_PB11) #define MICROPY_PORT_C (0) #define MICROPY_PORT_D (0) diff --git a/ports/atmel-samd/common-hal/neopixel_write/__init__.c b/ports/atmel-samd/common-hal/neopixel_write/__init__.c index 4677437f90..754bc97fdf 100644 --- a/ports/atmel-samd/common-hal/neopixel_write/__init__.c +++ b/ports/atmel-samd/common-hal/neopixel_write/__init__.c @@ -60,7 +60,7 @@ static void neopixel_send_buffer_core(volatile uint32_t *clraddr, uint32_t pinMa " movs r6, #3; d2: sub r6, #1; bne d2;" // delay 3 #endif #ifdef SAM_D5X_E5X - " movs r6, #3; d2: subs r6, #1; bne d2;" // delay 3 + " movs r6, #16; d2: subs r6, #1; bne d2;" // delay 3 #endif " tst r4, r5;" // mask&r5 " bne skipclr;" @@ -70,7 +70,7 @@ static void neopixel_send_buffer_core(volatile uint32_t *clraddr, uint32_t pinMa " movs r6, #6; d0: sub r6, #1; bne d0;" // delay 6 #endif #ifdef SAM_D5X_E5X - " movs r6, #6; d0: subs r6, #1; bne d0;" // delay 6 + " movs r6, #16; d0: subs r6, #1; bne d0;" // delay 6 #endif " str r1, [r0, #0];" // clr (possibly again, doesn't matter) #ifdef SAMD21 @@ -85,10 +85,13 @@ static void neopixel_send_buffer_core(volatile uint32_t *clraddr, uint32_t pinMa " movs r6, #2; d1: sub r6, #1; bne d1;" // delay 2 #endif #ifdef SAM_D5X_E5X - " movs r6, #2; d1: subs r6, #1; bne d1;" // delay 2 + " movs r6, #15; d1: subs r6, #1; bne d1;" // delay 2 #endif " b loopBit;" "nextbyte:" + #ifdef SAM_D5X_E5X + " movs r6, #12; d3: subs r6, #1; bne d3;" // delay 2 + #endif " cmp r2, r3;" " bcs neopixel_stop;" " b loopLoad;" @@ -114,42 +117,12 @@ void common_hal_neopixel_write(const digitalio_digitalinout_obj_t *digitalinout, // Turn off interrupts of any kind during timing-sensitive code. mp_hal_disable_all_interrupts(); - - #ifdef SAM_D5X_E5X - // When this routine is positioned at certain addresses, the timing logic - // below can be too fast by about 2.5x. This is some kind of (un)fortunate code - // positioning with respect to a cache line. - // Theoretically we should turn on off the CMCC caches and the - // NVM caches to ensure consistent timing. Testing shows the the NVMCTRL - // cache disabling seems to make the difference. But turn both off to make sure. - // It's difficult to test because additions to the code before the timing loop - // below change instruction placement. (though this should be less true now that - // the main code is in the cache-aligned function neopixel_send_buffer_core) - // Testing was done by adding cache changes below the loop (so only the - // first time through is wrong). - // - // Turn off instruction, data, and NVM caches to force consistent timing. - // Invalidate existing cache entries. - hri_cmcc_set_CFG_reg(CMCC, CMCC_CFG_DCDIS | CMCC_CFG_ICDIS); - hri_cmcc_write_MAINT0_reg(CMCC, CMCC_MAINT0_INVALL); - hri_nvmctrl_set_CTRLA_CACHEDIS0_bit(NVMCTRL); - hri_nvmctrl_set_CTRLA_CACHEDIS1_bit(NVMCTRL); - #endif - uint32_t pin = digitalinout->pin->number; port = &PORT->Group[GPIO_PORT(pin)]; // Convert GPIO # to port register pinMask = (1UL << (pin % 32)); // From port_pin_set_output_level ASF code. volatile uint32_t *clr = &(port->OUTCLR.reg); neopixel_send_buffer_core(clr, pinMask, pixels, numBytes); - #ifdef SAM_D5X_E5X - // Turn instruction, data, and NVM caches back on. - hri_cmcc_clear_CFG_reg(CMCC, CMCC_CFG_DCDIS | CMCC_CFG_ICDIS); - hri_nvmctrl_clear_CTRLA_CACHEDIS0_bit(NVMCTRL); - hri_nvmctrl_clear_CTRLA_CACHEDIS1_bit(NVMCTRL); - - #endif - // Update the next start. next_start_raw_ticks = port_get_raw_ticks(NULL) + 4; diff --git a/ports/atmel-samd/supervisor/port.c b/ports/atmel-samd/supervisor/port.c index 15112f5ba7..0ba6019e07 100644 --- a/ports/atmel-samd/supervisor/port.c +++ b/ports/atmel-samd/supervisor/port.c @@ -462,6 +462,8 @@ static uint32_t _get_count(uint64_t *overflow_count) { return count; } +volatile bool _woken_up; + static void _port_interrupt_after_ticks(uint32_t ticks) { uint32_t current_ticks = _get_count(NULL); if (ticks > 1 << 28) { @@ -473,9 +475,16 @@ static void _port_interrupt_after_ticks(uint32_t ticks) { return; } #endif - RTC->MODE0.COMP[0].reg = current_ticks + (ticks << 4); + uint32_t target = current_ticks + (ticks << 4); + RTC->MODE0.COMP[0].reg = target; + #ifdef SAM_D5X_E5X + while ((RTC->MODE0.SYNCBUSY.reg & (RTC_MODE0_SYNCBUSY_COMP0)) != 0) { + } + #endif RTC->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_CMP0; RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_CMP0; + current_ticks = _get_count(NULL); + _woken_up = current_ticks >= target; } void RTC_Handler(void) { @@ -485,15 +494,18 @@ void RTC_Handler(void) { // Our RTC is 32 bits and we're clocking it at 16.384khz which is 16 (2 ** 4) subticks per // tick. overflowed_ticks += (1L << (32 - 4)); + } #ifdef SAM_D5X_E5X - } else if (intflag & RTC_MODE0_INTFLAG_PER2) { + if (intflag & RTC_MODE0_INTFLAG_PER2) { RTC->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_PER2; // Do things common to all ports when the tick occurs supervisor_tick(); + } #endif - } else if (intflag & RTC_MODE0_INTFLAG_CMP0) { + if (intflag & RTC_MODE0_INTFLAG_CMP0) { // Clear the interrupt because we may have hit a sleep and _ticks_enabled RTC->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_CMP0; + _woken_up = true; #ifdef SAMD21 if (_ticks_enabled) { // Do things common to all ports when the tick occurs. @@ -565,7 +577,7 @@ void port_idle_until_interrupt(void) { } #endif common_hal_mcu_disable_interrupts(); - if (!tud_task_event_ready() && !hold_interrupt) { + if (!tud_task_event_ready() && !hold_interrupt && !_woken_up) { __DSB(); __WFI(); } diff --git a/ports/nrf/boards/feather_nrf52840_express/mpconfigboard.h b/ports/nrf/boards/feather_nrf52840_express/mpconfigboard.h index 8e4cd2287a..64988e1a28 100644 --- a/ports/nrf/boards/feather_nrf52840_express/mpconfigboard.h +++ b/ports/nrf/boards/feather_nrf52840_express/mpconfigboard.h @@ -30,7 +30,7 @@ #define MICROPY_HW_BOARD_NAME "Adafruit Feather nRF52840 Express" #define MICROPY_HW_MCU_NAME "nRF52840" -// #define MICROPY_HW_NEOPIXEL (&pin_P0_16) +#define MICROPY_HW_NEOPIXEL (&pin_P0_16) #define MICROPY_HW_LED_STATUS (&pin_P1_15) From 6164d44e6d0a9b30320dca48811fd29614cd6b44 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 18 May 2021 11:32:45 -0700 Subject: [PATCH 3/6] Turn off LED after REPL --- main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/main.c b/main.c index 1caeb12e2f..979070ebe3 100755 --- a/main.c +++ b/main.c @@ -647,6 +647,11 @@ STATIC int run_repl(void) { exit_code = pyexec_friendly_repl(); } cleanup_after_vm(heap); + #if CIRCUITPY_STATUS_LED + status_led_init(); + new_status_color(BLACK); + status_led_deinit(); + #endif autoreload_resume(); return exit_code; } From 642fbcf87ad85bbc3be52890e6267f821d9eb752 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 18 May 2021 15:56:37 -0700 Subject: [PATCH 4/6] Handle status led power This no longer turns on status LED power before running user code. Therefore, use of the status LED on some boards will also have to enable the power. --- main.c | 28 +++++++++++++------ .../boards/feather_m4_can/mpconfigboard.h | 5 ++-- ports/atmel-samd/boards/qtpy_m0/board.c | 7 ----- .../atmel-samd/boards/qtpy_m0/mpconfigboard.h | 1 + .../boards/qtpy_m0_haxpress/board.c | 7 ----- .../boards/qtpy_m0_haxpress/mpconfigboard.h | 1 + .../mpconfigboard.h | 1 + .../mpconfigboard.h | 1 + .../mpconfigboard.h | 1 + .../unexpectedmaker_tinys2/mpconfigboard.h | 1 + .../boards/adafruit_itsybitsy_rp2040/board.c | 7 ----- .../adafruit_itsybitsy_rp2040/mpconfigboard.h | 1 + .../boards/adafruit_qtpy_rp2040/board.c | 7 ----- .../adafruit_qtpy_rp2040/mpconfigboard.h | 1 + supervisor/shared/status_leds.c | 15 ++++++++++ 15 files changed, 46 insertions(+), 38 deletions(-) diff --git a/main.c b/main.c index 979070ebe3..6cf524edbb 100755 --- a/main.c +++ b/main.c @@ -338,6 +338,7 @@ STATIC bool run_code_py(safe_mode_t safe_mode) { #if CIRCUITPY_STATUS_LED uint32_t color; uint8_t blink_count; + bool led_active = false; #if CIRCUITPY_ALARM if (result.return_code & PYEXEC_DEEP_SLEEP) { color = BLACK; @@ -360,9 +361,6 @@ STATIC bool run_code_py(safe_mode_t safe_mode) { size_t single_blink_time = (OFF_ON_RATIO + 1) * BLINK_TIME_MS; size_t blink_time = single_blink_time * blink_count; size_t total_time = blink_time + LED_SLEEP_TIME_MS; - if (blink_count > 0) { - status_led_init(); - } #endif #if CIRCUITPY_ALARM @@ -432,7 +430,6 @@ STATIC bool run_code_py(safe_mode_t safe_mode) { common_hal_alarm_pretending_deep_sleep(); } else if (connecting_delay_ticks < 0) { // Entering deep sleep (may be fake or real.) - new_status_color(BLACK); board_deinit(); if (!supervisor_workflow_active()) { // Enter true deep sleep. When we wake up we'll be back at the @@ -469,15 +466,28 @@ STATIC bool run_code_py(safe_mode_t safe_mode) { if (tick_diff < blink_time) { uint32_t blink_diff = tick_diff % (single_blink_time); if (blink_diff >= BLINK_TIME_MS) { - new_status_color(BLACK); + if (led_active) { + new_status_color(BLACK); + status_led_deinit(); + led_active = false; + } time_to_next_change = single_blink_time - blink_diff; } else { - new_status_color(color); + if (!led_active) { + status_led_init(); + new_status_color(color); + led_active = true; + } time_to_next_change = BLINK_TIME_MS - blink_diff; } } else if (tick_diff > total_time) { pattern_start = supervisor_ticks_ms32(); } else { + if (led_active) { + new_status_color(BLACK); + status_led_deinit(); + led_active = false; + } time_to_next_change = total_time - tick_diff; } #if CIRCUITPY_DISPLAYIO @@ -495,8 +505,10 @@ STATIC bool run_code_py(safe_mode_t safe_mode) { } // Done waiting, start the board back up. #if CIRCUITPY_STATUS_LED - new_status_color(BLACK); - status_led_deinit(); + if (led_active) { + new_status_color(BLACK); + status_led_deinit(); + } #endif #if CIRCUITPY_ALARM diff --git a/ports/atmel-samd/boards/feather_m4_can/mpconfigboard.h b/ports/atmel-samd/boards/feather_m4_can/mpconfigboard.h index 20c4670e25..4cf4c57859 100644 --- a/ports/atmel-samd/boards/feather_m4_can/mpconfigboard.h +++ b/ports/atmel-samd/boards/feather_m4_can/mpconfigboard.h @@ -6,13 +6,14 @@ // Rev E #define MICROPY_HW_LED_STATUS (&pin_PA23) -#define MICROPY_HW_NEOPIXEL (&pin_PB03) +#define MICROPY_HW_NEOPIXEL (&pin_PB02) +#define CIRCUITPY_STATUS_LED_POWER (&pin_PB03) // These are pins not to reset. // QSPI Data pins #define MICROPY_PORT_A (PORT_PA08 | PORT_PA09 | PORT_PA10 | PORT_PA11) // QSPI CS, QSPI SCK and NeoPixel pin -#define MICROPY_PORT_B (PORT_PB03 | PORT_PB10 | PORT_PB11) +#define MICROPY_PORT_B (PORT_PB10 | PORT_PB11) #define MICROPY_PORT_C (0) #define MICROPY_PORT_D (0) diff --git a/ports/atmel-samd/boards/qtpy_m0/board.c b/ports/atmel-samd/boards/qtpy_m0/board.c index 6b948a9a7a..84960e73cf 100644 --- a/ports/atmel-samd/boards/qtpy_m0/board.c +++ b/ports/atmel-samd/boards/qtpy_m0/board.c @@ -25,15 +25,8 @@ */ #include "supervisor/board.h" -#include "common-hal/microcontroller/Pin.h" -#include "supervisor/shared/board.h" -#include "hal/include/hal_gpio.h" void board_init(void) { - gpio_set_pin_function(PIN_PA15, GPIO_PIN_FUNCTION_OFF); - gpio_set_pin_direction(PIN_PA15, GPIO_DIRECTION_OUT); - gpio_set_pin_level(PIN_PA15, true); // Turn on neopixel by default - never_reset_pin_number(PIN_PA15); } bool board_requests_safe_mode(void) { diff --git a/ports/atmel-samd/boards/qtpy_m0/mpconfigboard.h b/ports/atmel-samd/boards/qtpy_m0/mpconfigboard.h index 713d2c03eb..305a9b55f6 100644 --- a/ports/atmel-samd/boards/qtpy_m0/mpconfigboard.h +++ b/ports/atmel-samd/boards/qtpy_m0/mpconfigboard.h @@ -2,6 +2,7 @@ #define MICROPY_HW_MCU_NAME "samd21e18" #define MICROPY_HW_NEOPIXEL (&pin_PA18) +#define CIRCUITPY_STATUS_LED_POWER (&pin_PA15) #define MICROPY_PORT_A (0) #define MICROPY_PORT_B (0) diff --git a/ports/atmel-samd/boards/qtpy_m0_haxpress/board.c b/ports/atmel-samd/boards/qtpy_m0_haxpress/board.c index 6b948a9a7a..84960e73cf 100644 --- a/ports/atmel-samd/boards/qtpy_m0_haxpress/board.c +++ b/ports/atmel-samd/boards/qtpy_m0_haxpress/board.c @@ -25,15 +25,8 @@ */ #include "supervisor/board.h" -#include "common-hal/microcontroller/Pin.h" -#include "supervisor/shared/board.h" -#include "hal/include/hal_gpio.h" void board_init(void) { - gpio_set_pin_function(PIN_PA15, GPIO_PIN_FUNCTION_OFF); - gpio_set_pin_direction(PIN_PA15, GPIO_DIRECTION_OUT); - gpio_set_pin_level(PIN_PA15, true); // Turn on neopixel by default - never_reset_pin_number(PIN_PA15); } bool board_requests_safe_mode(void) { diff --git a/ports/atmel-samd/boards/qtpy_m0_haxpress/mpconfigboard.h b/ports/atmel-samd/boards/qtpy_m0_haxpress/mpconfigboard.h index 4e557751fc..c3434e22f0 100644 --- a/ports/atmel-samd/boards/qtpy_m0_haxpress/mpconfigboard.h +++ b/ports/atmel-samd/boards/qtpy_m0_haxpress/mpconfigboard.h @@ -2,6 +2,7 @@ #define MICROPY_HW_MCU_NAME "samd21e18" #define MICROPY_HW_NEOPIXEL (&pin_PA18) +#define CIRCUITPY_STATUS_LED_POWER (&pin_PA15) #define MICROPY_PORT_A (0) #define MICROPY_PORT_B (0) diff --git a/ports/esp32s2/boards/adafruit_feather_esp32s2_nopsram/mpconfigboard.h b/ports/esp32s2/boards/adafruit_feather_esp32s2_nopsram/mpconfigboard.h index a04065d25b..d2cd01a681 100644 --- a/ports/esp32s2/boards/adafruit_feather_esp32s2_nopsram/mpconfigboard.h +++ b/ports/esp32s2/boards/adafruit_feather_esp32s2_nopsram/mpconfigboard.h @@ -30,6 +30,7 @@ #define MICROPY_HW_MCU_NAME "ESP32S2" #define MICROPY_HW_NEOPIXEL (&pin_GPIO33) +#define CIRCUITPY_STATUS_LED_POWER (&pin_GPIO21) #define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0) diff --git a/ports/esp32s2/boards/adafruit_feather_esp32s2_tftback_nopsram/mpconfigboard.h b/ports/esp32s2/boards/adafruit_feather_esp32s2_tftback_nopsram/mpconfigboard.h index a04065d25b..d2cd01a681 100644 --- a/ports/esp32s2/boards/adafruit_feather_esp32s2_tftback_nopsram/mpconfigboard.h +++ b/ports/esp32s2/boards/adafruit_feather_esp32s2_tftback_nopsram/mpconfigboard.h @@ -30,6 +30,7 @@ #define MICROPY_HW_MCU_NAME "ESP32S2" #define MICROPY_HW_NEOPIXEL (&pin_GPIO33) +#define CIRCUITPY_STATUS_LED_POWER (&pin_GPIO21) #define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0) diff --git a/ports/esp32s2/boards/adafruit_magtag_2.9_grayscale/mpconfigboard.h b/ports/esp32s2/boards/adafruit_magtag_2.9_grayscale/mpconfigboard.h index 4d3e8c0972..b227fb01b3 100644 --- a/ports/esp32s2/boards/adafruit_magtag_2.9_grayscale/mpconfigboard.h +++ b/ports/esp32s2/boards/adafruit_magtag_2.9_grayscale/mpconfigboard.h @@ -30,6 +30,7 @@ #define MICROPY_HW_MCU_NAME "ESP32S2" #define MICROPY_HW_NEOPIXEL (&pin_GPIO1) +#define CIRCUITPY_STATUS_LED_POWER (&pin_GPIO21) #define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0) diff --git a/ports/esp32s2/boards/unexpectedmaker_tinys2/mpconfigboard.h b/ports/esp32s2/boards/unexpectedmaker_tinys2/mpconfigboard.h index e7d50f0894..64ef084ccd 100644 --- a/ports/esp32s2/boards/unexpectedmaker_tinys2/mpconfigboard.h +++ b/ports/esp32s2/boards/unexpectedmaker_tinys2/mpconfigboard.h @@ -30,6 +30,7 @@ #define MICROPY_HW_MCU_NAME "ESP32S2" #define MICROPY_HW_NEOPIXEL (&pin_GPIO1) +#define CIRCUITPY_STATUS_LED_POWER (&pin_GPIO2) #define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0) #define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n") diff --git a/ports/raspberrypi/boards/adafruit_itsybitsy_rp2040/board.c b/ports/raspberrypi/boards/adafruit_itsybitsy_rp2040/board.c index e05589883d..67486d4c23 100644 --- a/ports/raspberrypi/boards/adafruit_itsybitsy_rp2040/board.c +++ b/ports/raspberrypi/boards/adafruit_itsybitsy_rp2040/board.c @@ -26,14 +26,7 @@ #include "supervisor/board.h" -#include "shared-bindings/microcontroller/Pin.h" -#include "src/rp2_common/hardware_gpio/include/hardware/gpio.h" - void board_init(void) { - common_hal_never_reset_pin(&pin_GPIO16); - gpio_init(16); - gpio_set_dir(16, GPIO_OUT); - gpio_put(16, true); } bool board_requests_safe_mode(void) { diff --git a/ports/raspberrypi/boards/adafruit_itsybitsy_rp2040/mpconfigboard.h b/ports/raspberrypi/boards/adafruit_itsybitsy_rp2040/mpconfigboard.h index dad4e2eae8..131ddc8cee 100644 --- a/ports/raspberrypi/boards/adafruit_itsybitsy_rp2040/mpconfigboard.h +++ b/ports/raspberrypi/boards/adafruit_itsybitsy_rp2040/mpconfigboard.h @@ -2,6 +2,7 @@ #define MICROPY_HW_MCU_NAME "rp2040" #define MICROPY_HW_NEOPIXEL (&pin_GPIO17) +#define CIRCUITPY_STATUS_LED_POWER (&pin_GPIO16) #define DEFAULT_I2C_BUS_SCL (&pin_GPIO3) #define DEFAULT_I2C_BUS_SDA (&pin_GPIO2) diff --git a/ports/raspberrypi/boards/adafruit_qtpy_rp2040/board.c b/ports/raspberrypi/boards/adafruit_qtpy_rp2040/board.c index 332145ab84..67486d4c23 100644 --- a/ports/raspberrypi/boards/adafruit_qtpy_rp2040/board.c +++ b/ports/raspberrypi/boards/adafruit_qtpy_rp2040/board.c @@ -26,14 +26,7 @@ #include "supervisor/board.h" -#include "shared-bindings/microcontroller/Pin.h" -#include "src/rp2_common/hardware_gpio/include/hardware/gpio.h" - void board_init(void) { - common_hal_never_reset_pin(&pin_GPIO11); - gpio_init(11); - gpio_set_dir(11, GPIO_OUT); - gpio_put(11, true); } bool board_requests_safe_mode(void) { diff --git a/ports/raspberrypi/boards/adafruit_qtpy_rp2040/mpconfigboard.h b/ports/raspberrypi/boards/adafruit_qtpy_rp2040/mpconfigboard.h index a1947deaeb..5d3795dd5d 100644 --- a/ports/raspberrypi/boards/adafruit_qtpy_rp2040/mpconfigboard.h +++ b/ports/raspberrypi/boards/adafruit_qtpy_rp2040/mpconfigboard.h @@ -2,6 +2,7 @@ #define MICROPY_HW_MCU_NAME "rp2040" #define MICROPY_HW_NEOPIXEL (&pin_GPIO12) +#define CIRCUITPY_STATUS_LED_POWER (&pin_GPIO11) #define DEFAULT_I2C_BUS_SCL (&pin_GPIO25) #define DEFAULT_I2C_BUS_SDA (&pin_GPIO24) diff --git a/supervisor/shared/status_leds.c b/supervisor/shared/status_leds.c index a367aa3086..386dba5387 100644 --- a/supervisor/shared/status_leds.c +++ b/supervisor/shared/status_leds.c @@ -31,6 +31,12 @@ #include "supervisor/shared/tick.h" #include "py/obj.h" + +#ifdef CIRCUITPY_STATUS_LED_POWER +#include "shared-bindings/digitalio/DigitalInOut.h" +static digitalio_digitalinout_obj_t _status_power; +#endif + #ifdef MICROPY_HW_NEOPIXEL uint8_t rgb_status_brightness = 63; #include "shared-bindings/digitalio/DigitalInOut.h" @@ -116,6 +122,11 @@ void status_led_init() { } status_led_init_in_progress = true; + #ifdef CIRCUITPY_STATUS_LED_POWER + common_hal_digitalio_digitalinout_construct(&_status_power, CIRCUITPY_STATUS_LED_POWER); + common_hal_digitalio_digitalinout_switch_to_output(&_status_power, true, DRIVE_MODE_PUSH_PULL); + #endif + #ifdef MICROPY_HW_NEOPIXEL common_hal_digitalio_digitalinout_construct(&status_neopixel, MICROPY_HW_NEOPIXEL); common_hal_digitalio_digitalinout_switch_to_output(&status_neopixel, false, DRIVE_MODE_PUSH_PULL); @@ -212,6 +223,10 @@ void status_led_deinit() { #elif defined(MICROPY_HW_LED_STATUS) common_hal_digitalio_digitalinout_deinit(&single_color_led); #endif + + #ifdef CIRCUITPY_STATUS_LED_POWER + common_hal_digitalio_digitalinout_deinit(&_status_power); + #endif } void new_status_color(uint32_t rgb) { From b78e9fcd19e1ea7d99f6e2527cb8732b02f6abce Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 19 May 2021 11:48:02 -0700 Subject: [PATCH 5/6] Improve STM reset reason This causes safe mode to skip the wait for reset when waking up from an alarm. (It also means we don't flash the LED for it.) --- ports/stm/common-hal/alarm/__init__.c | 11 +++++++---- ports/stm/common-hal/alarm/__init__.h | 1 + ports/stm/common-hal/microcontroller/Processor.c | 8 ++++++++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/ports/stm/common-hal/alarm/__init__.c b/ports/stm/common-hal/alarm/__init__.c index e0b900bbfc..3307d8775c 100644 --- a/ports/stm/common-hal/alarm/__init__.c +++ b/ports/stm/common-hal/alarm/__init__.c @@ -64,7 +64,7 @@ void alarm_set_wakeup_reason(stm_sleep_source_t reason) { true_deep_wake_reason = reason; } -STATIC stm_sleep_source_t _get_wakeup_cause(void) { +stm_sleep_source_t alarm_get_wakeup_cause(void) { // If in light/fake sleep, check modules if (alarm_pin_pinalarm_woke_us_up()) { return STM_WAKEUP_GPIO; @@ -73,18 +73,18 @@ STATIC stm_sleep_source_t _get_wakeup_cause(void) { return STM_WAKEUP_RTC; } // Check to see if we woke from deep sleep (reason set in port_init) - if (true_deep_wake_reason) { + if (true_deep_wake_reason != STM_WAKEUP_UNDEF) { return true_deep_wake_reason; } return STM_WAKEUP_UNDEF; } bool common_hal_alarm_woken_from_sleep(void) { - return _get_wakeup_cause() != STM_WAKEUP_UNDEF; + return alarm_get_wakeup_cause() != STM_WAKEUP_UNDEF; } STATIC mp_obj_t _get_wake_alarm(size_t n_alarms, const mp_obj_t *alarms) { - stm_sleep_source_t cause = _get_wakeup_cause(); + stm_sleep_source_t cause = alarm_get_wakeup_cause(); switch (cause) { case STM_WAKEUP_RTC: { return alarm_time_timealarm_get_wakeup_alarm(n_alarms, alarms); @@ -156,6 +156,7 @@ void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *ala } void NORETURN common_hal_alarm_enter_deep_sleep(void) { + alarm_set_wakeup_reason(STM_WAKEUP_UNDEF); alarm_pin_pinalarm_prepare_for_deep_sleep(); alarm_time_timealarm_prepare_for_deep_sleep(); port_disable_tick(); @@ -182,6 +183,8 @@ void common_hal_alarm_pretending_deep_sleep(void) { GPIO_InitStruct.Pull = GPIO_PULLDOWN; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + alarm_set_wakeup_reason(STM_WAKEUP_UNDEF); + port_idle_until_interrupt(); } diff --git a/ports/stm/common-hal/alarm/__init__.h b/ports/stm/common-hal/alarm/__init__.h index 4ec7222d2e..6c72364fc3 100644 --- a/ports/stm/common-hal/alarm/__init__.h +++ b/ports/stm/common-hal/alarm/__init__.h @@ -40,6 +40,7 @@ typedef enum { #define STM_ALARM_FLAG (RTC->BKP0R) extern void alarm_set_wakeup_reason(stm_sleep_source_t reason); +stm_sleep_source_t alarm_get_wakeup_cause(void); extern void alarm_reset(void); #endif // MICROPY_INCLUDED_STM32_COMMON_HAL_ALARM__INIT__H diff --git a/ports/stm/common-hal/microcontroller/Processor.c b/ports/stm/common-hal/microcontroller/Processor.c index b33d96e736..13c661a60a 100644 --- a/ports/stm/common-hal/microcontroller/Processor.c +++ b/ports/stm/common-hal/microcontroller/Processor.c @@ -27,6 +27,9 @@ #include #include "py/runtime.h" +#if CIRCUITPY_ALARM +#include "common-hal/alarm/__init__.h" +#endif #include "common-hal/microcontroller/Processor.h" #include "shared-bindings/microcontroller/ResetReason.h" #include "supervisor/shared/translate.h" @@ -143,5 +146,10 @@ void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { } mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { + #if CIRCUITPY_ALARM + if (alarm_get_wakeup_cause() != STM_WAKEUP_UNDEF) { + return RESET_REASON_DEEP_SLEEP_ALARM; + } + #endif return RESET_REASON_UNKNOWN; } From 499a4388cf4fe8097107c89cddbede103c18491c Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 19 May 2021 17:29:02 -0700 Subject: [PATCH 6/6] Handle inverted neopixel power --- .../boards/adafruit_magtag_2.9_grayscale/mpconfigboard.h | 1 + ports/esp32s2/boards/adafruit_magtag_2.9_grayscale/pins.c | 1 + py/circuitpy_mpconfig.h | 4 ++++ supervisor/shared/status_leds.c | 3 ++- 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/ports/esp32s2/boards/adafruit_magtag_2.9_grayscale/mpconfigboard.h b/ports/esp32s2/boards/adafruit_magtag_2.9_grayscale/mpconfigboard.h index b227fb01b3..d0d1864993 100644 --- a/ports/esp32s2/boards/adafruit_magtag_2.9_grayscale/mpconfigboard.h +++ b/ports/esp32s2/boards/adafruit_magtag_2.9_grayscale/mpconfigboard.h @@ -31,6 +31,7 @@ #define MICROPY_HW_NEOPIXEL (&pin_GPIO1) #define CIRCUITPY_STATUS_LED_POWER (&pin_GPIO21) +#define CIRCUITPY_STATUS_LED_POWER_INVERTED (1) #define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0) diff --git a/ports/esp32s2/boards/adafruit_magtag_2.9_grayscale/pins.c b/ports/esp32s2/boards/adafruit_magtag_2.9_grayscale/pins.c index 1fb1f11945..990cfd9957 100644 --- a/ports/esp32s2/boards/adafruit_magtag_2.9_grayscale/pins.c +++ b/ports/esp32s2/boards/adafruit_magtag_2.9_grayscale/pins.c @@ -44,6 +44,7 @@ STATIC const mp_rom_map_elem_t board_global_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO33) }, { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO34) }, + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL_POWER_INVERTED), MP_ROM_PTR(&pin_GPIO21) }, { MP_ROM_QSTR(MP_QSTR_NEOPIXEL_POWER), MP_ROM_PTR(&pin_GPIO21) }, { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO1) }, diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 18a1480a10..c71cad6aeb 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -991,6 +991,10 @@ void supervisor_run_background_tasks_if_tick(void); #define CIRCUITPY_PROCESSOR_COUNT (1) #endif +#ifndef CIRCUITPY_STATUS_LED_POWER_INVERTED +#define CIRCUITPY_STATUS_LED_POWER_INVERTED (0) +#endif + #define CIRCUITPY_BOOT_OUTPUT_FILE "/boot_out.txt" #define CIRCUITPY_VERBOSE_BLE 0 diff --git a/supervisor/shared/status_leds.c b/supervisor/shared/status_leds.c index 386dba5387..e8b0983d9b 100644 --- a/supervisor/shared/status_leds.c +++ b/supervisor/shared/status_leds.c @@ -124,7 +124,8 @@ void status_led_init() { #ifdef CIRCUITPY_STATUS_LED_POWER common_hal_digitalio_digitalinout_construct(&_status_power, CIRCUITPY_STATUS_LED_POWER); - common_hal_digitalio_digitalinout_switch_to_output(&_status_power, true, DRIVE_MODE_PUSH_PULL); + common_hal_digitalio_digitalinout_switch_to_output(&_status_power, + CIRCUITPY_STATUS_LED_POWER_INVERTED == 0, DRIVE_MODE_PUSH_PULL); #endif #ifdef MICROPY_HW_NEOPIXEL