From f792dca2dac8162dc9303dffbf7b00b23df3f9aa Mon Sep 17 00:00:00 2001 From: kwagyeman <5694981+kwagyeman@users.noreply.github.com> Date: Sat, 19 Sep 2026 10:13:59 -0700 Subject: [PATCH 1/2] stm32/boards/OPENMVPT: Stop turning the white illuminator on at boot. MICROPY_HW_LED4 mapped the white LED to PG3, but that pin is not wired like the other three. Red, green and blue drive an HSMF-C116 whose common pin ties to 3V3 through 220R, so they are active low, which is what the board's MICROPY_HW_LED_ON()/OFF() macros assume. PG3 instead gates a PMZ390UN N-channel MOSFET with a 100K pulldown on its gate, so the white LED is active high. The result is that MICROPY_HW_LED_OFF() drives PG3 high and switches the MOSFET on, so led_init() lights the illuminator on every boot and leaves it on. It is not a status LED: it is a CLP6B-WKW rated 3 x 50mA, drawing 100mA through R120 off the 5V rail. The polarity macros are board-wide and correct for the RGB LED, and the stm32 port has no per-LED polarity hook, so the fix is to leave PG3 out of the LED table. Nothing then configures the pin, it stays high impedance out of reset, and R142 holds the gate low, which is off. This also removes an inverted API: pyb.LED(4).on() turned the illuminator off and .off() turned it on. No example uses LED(4) on this board. Driving it deliberately is machine.Pin("G3", machine.Pin.OUT). --- ports/stm32/boards/OPENMVPT/mpconfigboard.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ports/stm32/boards/OPENMVPT/mpconfigboard.h b/ports/stm32/boards/OPENMVPT/mpconfigboard.h index da4903f1ba1..84f6199791c 100644 --- a/ports/stm32/boards/OPENMVPT/mpconfigboard.h +++ b/ports/stm32/boards/OPENMVPT/mpconfigboard.h @@ -116,9 +116,10 @@ void board_low_power(int mode); #define MICROPY_HW_LED1 (pin_C0) // red #define MICROPY_HW_LED2 (pin_C1) // green #define MICROPY_HW_LED3 (pin_C2) // blue -#define MICROPY_HW_LED4 (pin_G3) // white #define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) -// NOTE: LEDs are active low. +// NOTE: LEDs are active low. The white illuminator on PG3 is NOT: it gates a +// PMZ390UN N-MOSFET (100K pulldown on the gate), so it is active high and is +// deliberately left out of the LED table - see the commit message. #define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRR = (pin->pin_mask << 16)) #define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRR = pin->pin_mask) From 631ffab4563bdb33ba0ea2e53bb598e84881f140 Mon Sep 17 00:00:00 2001 From: kwagyeman <5694981+kwagyeman@users.noreply.github.com> Date: Sat, 19 Sep 2026 10:49:26 -0700 Subject: [PATCH 2/2] stm32/boards/OPENMVPT: Actually reset the Lepton at boot. board_early_init() drove LEPTON_RSTN straight high and never pulsed it low, and released it before starting MCLK. Both are wrong for this part: it wants its master clock present when RESET_L is released, and it never receives a reset at all. On a cold power-up POR hides this. Once the Lepton is confused it is unrecoverable: it still ACKs its I2C address, so the probe detects it, but its status register never reads LEPTON_I2C_STATUS_BOOT, so lepton_config() times out and omv_csi_init() returns OMV_CSI_ERROR_CSI_INIT_FAILED. main() treats anything other than OMV_CSI_ERROR_ISC_UNDETECTED as fatal, and this happens before USB is brought up, so the board stops enumerating entirely - no CDC, no REPL, no way in short of SWD - and every subsequent MCU reset runs this same code and leaves the part exactly as it was. Observed on a bench board that stayed in this state across MCU resets, an nRST pin reset, toggling the shared CSI power/reset rail, and a physical power cycle. Pulsing RSTN low by hand brought it straight back. Hold RSTN low, release powerdown, start MCLK, spin past the 5000 clock periods the part requires, then release RSTN. SystemClock_Config() has not run this early, hence the spin rather than mp_hal_delay_ms(). Verified on hardware: Lepton enumerates at 160x120 and the full thermal overlay demo path runs at 17.9fps. --- ports/stm32/boards/OPENMVPT/board_init.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/ports/stm32/boards/OPENMVPT/board_init.c b/ports/stm32/boards/OPENMVPT/board_init.c index 937abbcc2c9..752e0d0dccb 100644 --- a/ports/stm32/boards/OPENMVPT/board_init.c +++ b/ports/stm32/boards/OPENMVPT/board_init.c @@ -6,10 +6,16 @@ #define OMV_BOOTLOADER_MAGIC_VALUE (0xB00710ADU) void board_early_init(void) { - // Bring FLIR Lepton out of reset. + // Hold the FLIR Lepton in reset until its master clock is running. The part + // wants MCLK present when RESET_L is released, and driving RSTN straight + // high (as this used to) means a Lepton that is already confused never sees + // a reset at all: it answers on I2C but never reports booted, omv_csi_init() + // fails, and main() takes that as fatal before USB is up. The board then + // looks bricked - no enumeration, no REPL - and no amount of resetting the + // MCU recovers it, because only removing the Lepton's power does. mp_hal_pin_config(pyb_pin_LEPTON_RSTN, MP_HAL_PIN_MODE_OUTPUT, MP_HAL_PIN_PULL_NONE, 0); mp_hal_pin_config_speed(pyb_pin_LEPTON_RSTN, MP_HAL_PIN_SPEED_LOW); - mp_hal_pin_write(pyb_pin_LEPTON_RSTN, 1); + mp_hal_pin_write(pyb_pin_LEPTON_RSTN, 0); // Release powerdown. mp_hal_pin_config(pyb_pin_LEPTON_PWDN, MP_HAL_PIN_MODE_OUTPUT, MP_HAL_PIN_PULL_NONE, 0); @@ -50,6 +56,14 @@ void board_early_init(void) { HAL_TIM_PWM_Init(&mclk_tim_handle); HAL_TIM_PWM_ConfigChannel(&mclk_tim_handle, &mclk_tim_oc_handle, TIM_CHANNEL_2); HAL_TIM_PWM_Start(&mclk_tim_handle, TIM_CHANNEL_2); + + // Release the Lepton now that MCLK is running, after holding reset for well + // over the 5000 clock periods the part requires. SystemClock_Config() has + // not run yet, so this is a spin rather than mp_hal_delay_ms(): at the 64MHz + // HSI boot clock this is comfortably past 210us even if it compiles tight. + for (volatile uint32_t i = 0; i < 50000; i++) { + } + mp_hal_pin_write(pyb_pin_LEPTON_RSTN, 1); } void board_low_power(int mode) {