diff --git a/variants/STM32L4xx/L433C(B-C)(T-U)_L443CC(T-U)/PeripheralPins_CYGNET.c b/variants/STM32L4xx/L433C(B-C)(T-U)_L443CC(T-U)/PeripheralPins_CYGNET.c index f281bba8a5..fb4bd84726 100644 --- a/variants/STM32L4xx/L433C(B-C)(T-U)_L443CC(T-U)/PeripheralPins_CYGNET.c +++ b/variants/STM32L4xx/L433C(B-C)(T-U)_L443CC(T-U)/PeripheralPins_CYGNET.c @@ -36,7 +36,7 @@ WEAK const PinMap PinMap_ADC[] = { {PA_1, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 6, 0)}, // ADC1_IN6 - A1 {PA_2, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 7, 0)}, // ADC1_IN7 - A2 {PA_3, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 8, 0)}, // ADC1_IN8 - A3 - {PA_4, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 9, 0)}, // ADC1_IN9 - BAT_VOLTAGE + {PA_4, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 9, 0)}, // ADC1_IN9 - A6/BATTERY_VOLTAGE (STAT) {PA_5, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 10, 0)}, // ADC1_IN10 - CK {PA_6, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 11, 0)}, // ADC1_IN11 - MI {PA_7, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 12, 0)}, // ADC1_IN12 - A5 diff --git a/variants/STM32L4xx/L433C(B-C)(T-U)_L443CC(T-U)/variant_CYGNET.cpp b/variants/STM32L4xx/L433C(B-C)(T-U)_L443CC(T-U)/variant_CYGNET.cpp index ca404abbc5..fb63c60fb0 100644 --- a/variants/STM32L4xx/L433C(B-C)(T-U)_L443CC(T-U)/variant_CYGNET.cpp +++ b/variants/STM32L4xx/L433C(B-C)(T-U)_L443CC(T-U)/variant_CYGNET.cpp @@ -16,53 +16,53 @@ // Digital PinName array const PinName digitalPin[] = { - PA_0, // 0 - D0/A0 - PA_1, // 1 - D1/A1 - PA_2, // 2 - D2/A2 - PA_3, // 3 - D3/A3 - PB_1, // 4 - D4/A4 - PB_8, // 5 - D5 - PB_9, // 6 - D6 - PA_4, // 7 - BAT_VOLTAGE - PA_8, // 8 - LED_BUILTIN - PB_14, // 9 - D9 + PA_0, // 0 - A0/D0 + PA_1, // 1 - A1/D1 + PA_2, // 2 - A2/D2 + PA_3, // 3 - A3/D3 + PB_1, // 4 - A4/D4 + PB_8, // 5 - D5 + PB_9, // 6 - D6 + PA_8, // 7 - LED_BUILTIN + PC_13, // 8 - USER_BTN + PB_14, // 9 - D9 PB_13, // 10 - D10 PB_0, // 11 - D11 PB_15, // 12 - D12 PB_4, // 13 - D13 - PA_5, // 14 - CK - PA_6, // 15 - MI - PA_7, // 16 - A5 - PA_9, // 17 - TX + PA_7, // 14 - A5 + PA_5, // 15 - CK + PB_5, // 16 - MO + PA_6, // 17 - MI PA_10, // 18 - RX - PA_11, // 19 - USB_DM - PA_12, // 20 - USB_DP - PA_13, // 21 - SWDIO - PA_14, // 22 - SWCLK - PA_15, // 23 - CHARGE_DETECT - PB_3, // 24 - USB_DETECT - PB_5, // 25 - MO - PB_6, // 26 - SCL - PB_7, // 27 - SDA - PB_10, // 28 - LPUART1_VCP_RX - PB_11, // 29 - LPUART1_VCP_TX - PC_13, // 30 - USER_BTN - PC_14, // 31 - OSC32_IN - PC_15, // 32 - OSC32_OUT - PH_0, // 33 - ENABLE_3V3 - PH_1, // 34 - DISCHARGE_3V3 - PH_3 // 35 - B + PA_9, // 19 - TX + PH_3, // 20 - B + PB_6, // 21 - SCL + PB_7, // 22 - SDA + PA_13, // 23 - SWDIO + PA_14, // 24 - SWCLK + PB_10, // 25 - LPUART1_VCP_RX + PB_11, // 26 - LPUART1_VCP_TX + PH_0, // 27 - ENABLE_3V3 + PH_1, // 28 - DISCHARGE_3V3 + PA_15, // 29 - CHARGE_DETECT + PA_4, // 30 - A6/BATTERY_VOLTAGE (STAT) + PB_3, // 31 - USB_DETECT + PA_11, // 32 - USB_DM + PA_12, // 33 - USB_DP + PC_14, // 34 - OSC32_IN (LSE) + PC_15 // 35 - OSC32_OUT (LSE) }; // Analog (Ax) to digital pin number array const uint32_t analogInputPin[] = { - 0, // PA0, A0 - 1, // PA1, A1 - 2, // PA2, A2 - 3, // PA3, A3 - 4, // PB1, A4 - 16, // PA7, A5 - 7 // PA4, BAT_VOLTAGE + 0, // PA0, A0 + 1, // PA1, A1 + 2, // PA2, A2 + 3, // PA3, A3 + 4, // PB1, A4 + 14, // PA7, A5 + 30 // PA4, A6/BATTERY_VOLTAGE (STAT) }; // ---------------------------------------------------------------------------- @@ -75,92 +75,226 @@ WEAK void initVariant(void) { /* All pins set to high-Z (floating) initially */ /* DS11449 Rev 8, Section 3.9.5 - Reset Mode: */ - /* In order to improve the consumption under reset, the I/Os state under and after reset is - * “analog state” (the I/O schmitt trigger is disable). In addition, the internal reset pull-up is - * deactivated when the reset source is internal. + /* In order to improve the consumption under reset, the I/Os state under + * and after reset is "analog state" (the I/O schmitt trigger is disabled). + * In addition, the internal reset pull-up is deactivated when the reset + * source is internal. */ - /* Turn on the 3V3 regulator */ - __HAL_RCC_GPIOH_CLK_ENABLE(); - GPIO_InitTypeDef GPIO_InitStruct; - GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; - GPIO_InitStruct.Speed = GPIO_SPEED_LOW; - GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1; - HAL_GPIO_Init(GPIOH, &GPIO_InitStruct); /* PH0 is ENABLE_3V3, PH1 is DISCHARGE_3V3 */ - HAL_GPIO_WritePin(GPIOH, GPIO_InitStruct.Pin, GPIO_PIN_SET); /* Enable 3V3 regulator and disable discharging */ + /* Configure the USB charge detection; leaks ~80uA if not configured. */ + { + __HAL_RCC_GPIOA_CLK_ENABLE(); + GPIO_InitTypeDef GPIO_InitStruct = {}; + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_PULLDOWN; + GPIO_InitStruct.Speed = GPIO_SPEED_LOW; + /* PA15 is CHARGE_DETECT */ + GPIO_InitStruct.Pin = GPIO_PIN_15; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + } + + /* Configure D13 manually, to avoid stray current on D13 */ + { + __HAL_RCC_GPIOB_CLK_ENABLE(); + GPIO_InitTypeDef GPIO_InitStruct = {}; + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_LOW; + /* PB4 is D13 */ + GPIO_InitStruct.Pin = GPIO_PIN_4; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + } + + /* Configure the 3V3 regulator */ + { + __HAL_RCC_GPIOH_CLK_ENABLE(); + GPIO_InitTypeDef GPIO_InitStruct = {}; + GPIO_InitStruct.Speed = GPIO_SPEED_LOW; + + /* PH0 is ENABLE_3V3 */ + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pin = GPIO_PIN_0; + HAL_GPIO_Init(GPIOH, &GPIO_InitStruct); + + /* PH1 is DISCHARGE_3V3 */ + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; + GPIO_InitStruct.Pin = GPIO_PIN_1; + HAL_GPIO_Init(GPIOH, &GPIO_InitStruct); + + /* Enable 3V3 regulator and disable discharging */ + HAL_GPIO_WritePin(GPIOH, (GPIO_PIN_0 | GPIO_PIN_1), GPIO_PIN_SET); + } } /** - * @brief System Clock Configuration - * @param None - * @retval None - */ + * @brief System Clock Configuration - PLL-based STM32L433 with native USB FS + * + * Key features: + * - SYSCLK = 80 MHz from MSI (4 MHz, Range 6) via PLL (4MHz x 40/2) + * - USB FS (48 MHz) sourced from PLLSAI1 (4MHz x 24/2) + * - HSI disabled to reduce current consumption (~200-300 uA) + * - LSE enabled with medium-low drive for RTC and MSI auto-calibration (MSIPLLEN) + * - Voltage Scale 1 required for 80 MHz operation + * - FLASH_LATENCY_4 required for HCLK > 64 MHz at VOS1 (RM0394 s.3.3.3) + * - MSI PLL-mode (MSIPLLEN) enabled after SYSCLK moves to PLL to avoid MSIRDY stall + * - Wake-up clock after STOP: MSI (PLL must be re-locked manually after wake) + * + * References: + * - RM0394 Rev 6 (STM32L43x/L44x) - s.6.2 "MSI clock" + * - RM0394 s.6.2.9 "MSI PLL-mode" + * - RM0394 s.3.3.3 "Performance versus VDD and clock frequency" + * - AN2867 Rev 11 - "Oscillator design guide for STM8AF/AL/S, STM32 MCUs and MPUs" + */ WEAK void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {}; RCC_PeriphCLKInitTypeDef PeriphClkInit = {}; - /** Configure the main internal regulator output voltage + /** Enable PWR peripheral clock + * + * RM0394 s.5.1.2: PWR registers are on APB1. PWREN (RCC_APB1ENR1 bit 28) + * resets to 1, so this is defensive rather than strictly necessary, but + * required for correctness if PWREN has been cleared by prior code. + * CubeMX generates this unconditionally for all STM32L4 projects. */ + __HAL_RCC_PWR_CLK_ENABLE(); + + /* Voltage scaling - Scale 1 required for SYSCLK = 80 MHz + * RM0394 s.6.1: VOS2 supports up to 26 MHz only + */ if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK) { Error_Handler(); } /** Configure LSE Drive Capability + * + * Use MEDIUMLOW (not LOW): RCC_LSEDRIVE_LOW risks marginal LSE startup + * on units near the crystal ESR tolerance limit and degrades MSI PLL mode + * (MSIPLLEN) lock quality. ST recommends MEDIUMLOW as the minimum when + * MSIPLLEN is in use. + * + * Backup domain access must be enabled before configuring LSE or selecting + * the RTC clock source, as those registers (RCC->BDCR) are write-protected + * after reset and silently ignore writes until the lock is cleared. */ HAL_PWR_EnableBkUpAccess(); - __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW); + __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_MEDIUMLOW); /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. + * + * Oscillator configuration summary: + * - MSI: MSIRANGE_6 (4 MHz) -- used as PLL input + * - HSI: OFF -- Unused, disabling it saves ~200-300 uA + * - PLL: ON (MSI 4MHz x PLLN=40 / PLLR=2 = 80 MHz) + * - SYSCLK: PLLCLK (80 MHz) + * - USB clock: PLLSAI1 (48 MHz) + * - MSIRDY transient can not stall SysTick because SYSCLK = PLL, not MSI. + * - FLASH_LATENCY: 4 (required for 80 MHz / VOS1 per RM0394 s.3.3) */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE - | RCC_OSCILLATORTYPE_MSI - | RCC_OSCILLATORTYPE_HSI; + | RCC_OSCILLATORTYPE_MSI; RCC_OscInitStruct.LSEState = RCC_LSE_ON; + RCC_OscInitStruct.HSIState = RCC_HSI_OFF; RCC_OscInitStruct.MSIState = RCC_MSI_ON; RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT; - RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_11; - RCC_OscInitStruct.HSIState = RCC_HSI_ON; - RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; - RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; + RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6; + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; + RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI; + RCC_OscInitStruct.PLL.PLLM = 1; + RCC_OscInitStruct.PLL.PLLN = 40; + RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7; + RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2; + RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2; /* 4MHz x 40 / 2 = 80 MHz */ if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB buses clocks + * + * SYSCLK = PLLCLK (80 MHz). SysTick and HAL_GetTick() are now driven by + * the PLL output, completely decoupled from MSI. Any subsequent MSIRDY + * transient (from HAL_RCCEx_EnableMSIPLLMode below) cannot stall SysTick. */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; - // RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; - RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_MSI; + RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; - if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) { + /* FLASH_LATENCY_4: required for HCLK > 64 MHz at VOS1 (RM0394 s.3.3.3) */ + if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) { Error_Handler(); } /** Initializes the Peripheral clocks + * + * USB clock: PLLSAI1 (MSI 4 MHz x PLLSAI1N=24 / PLLSAI1Q=2 = 48 MHz). + * This mirrors the Nucleo L432KC exactly. RCCEx_PLLSAI1_Config() waits + * for PLLSAI1RDY using HAL_GetTick(). Because SYSCLK is now PLL-based, + * HAL_GetTick() is immune to MSI transients -- the wait is reliable. + * PLLSAI1 and the main PLL share the same source (MSI) and M divider (1), + * which the HAL enforces; both are configured consistently here. + * + * HAL_RCCEx_PeriphCLKConfig writes CLK48SEL first (pointing at PLLSAI1 + * before it is running), then enables PLLSAI1 and waits for its RDY flag. + * During that brief window the USB peripheral has no 48 MHz clock and + * stays quiescent -- avoiding the race where a live MSI clock is handed + * to USB before the peripheral is ready to handle the absence of VBUS. */ - PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USB | RCC_PERIPHCLK_SDMMC1 - | RCC_PERIPHCLK_ADC /* | RCC_PERIPHCLK_OSPI */; + PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC | RCC_PERIPHCLK_USB; PeriphClkInit.AdcClockSelection = RCC_ADCCLKSOURCE_SYSCLK; - // PeriphClkInit.OspiClockSelection = RCC_OSPICLKSOURCE_SYSCLK; - PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_MSI; - PeriphClkInit.Sdmmc1ClockSelection = RCC_SDMMC1CLKSOURCE_MSI; + PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_PLLSAI1; + PeriphClkInit.PLLSAI1.PLLSAI1Source = RCC_PLLSOURCE_MSI; + PeriphClkInit.PLLSAI1.PLLSAI1M = 1; + PeriphClkInit.PLLSAI1.PLLSAI1N = 24; + PeriphClkInit.PLLSAI1.PLLSAI1P = RCC_PLLP_DIV7; + PeriphClkInit.PLLSAI1.PLLSAI1Q = RCC_PLLQ_DIV2; /* 4 x 24 / 2 = 48 MHz */ + PeriphClkInit.PLLSAI1.PLLSAI1R = RCC_PLLR_DIV2; + PeriphClkInit.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_48M2CLK; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) { Error_Handler(); } - /** Enable MSI Auto calibration - */ + /** Enable MSI Auto calibration (MSIPLLEN, RCC_CR[2]) + * + * RM0394 s.6.2 (MSI clock): setting MSIPLLEN causes the MSI hardware + * to automatically trim itself against LSE as a phase reference, + * reducing MSI frequency error to < +/-0.25%. LSE must already be + * stable (LSERDY=1) before the bit is set -- guaranteed here because + * HAL_RCC_OscConfig() waited for LSERDY before returning. + * + * Setting MSIPLLEN causes MSIRDY to deassert transiently while MSI + * re-synchronises to LSE. HAL_RCCEx_EnableMSIPLLMode() returns + * immediately (it is a single SET_BIT); no MSIRDY wait is performed + * inside it. Two conclusions follow: + * + * (1) This call must come AFTER any HAL routine that polls MSIRDY + * under a HAL_GetTick() timeout -- if MSIRDY drops inside such + * a routine, the routine returns HAL_TIMEOUT and leaves the + * clock tree in an undefined state. + * + * (2) If SYSCLK were MSI, a deadlock would be possible: MSIRDY + * drops -> SysTick stalls -> HAL_GetTick() freezes -> any + * subsequent timeout loop never exits. RM0394 s.6.2.9 confirms + * SysTick is driven by HCLK (= SYSCLK / AHBdiv). Because + * SYSCLK is now PLLCLK (80 MHz), SysTick is completely + * decoupled from MSI and the transient is harmless. + * + * Placement here -- after PeriphCLKConfig -- satisfies both constraints + * and mirrors the ordering generated by CubeMX for the Nucleo L432KC. + */ HAL_RCCEx_EnableMSIPLLMode(); /** Ensure that MSI is wake-up system clock + * + * After STOP mode, the PLL is not automatically re-enabled. MSI is used + * as the initial wake-up clock; firmware must re-lock the PLL manually + * if 80 MHz is required after wake. This is the same behaviour as any + * PLL-based design on STM32L4. */ - __HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_MSI); + HAL_RCCEx_WakeUpStopCLKConfig(RCC_STOP_WAKEUPCLOCK_MSI); } #ifdef __cplusplus diff --git a/variants/STM32L4xx/L433C(B-C)(T-U)_L443CC(T-U)/variant_CYGNET.h b/variants/STM32L4xx/L433C(B-C)(T-U)_L443CC(T-U)/variant_CYGNET.h index 2b64142628..28270043d4 100644 --- a/variants/STM32L4xx/L433C(B-C)(T-U)_L443CC(T-U)/variant_CYGNET.h +++ b/variants/STM32L4xx/L433C(B-C)(T-U)_L443CC(T-U)/variant_CYGNET.h @@ -13,170 +13,211 @@ #pragma once /*---------------------------------------------------------------------------- - * Arduino digital pin numbers on the right (indexes into the digitalPin[] array) - * and the STM32 pins they correspond to on the left. The only apparent - * function I can see is to reference a pin in a sketch in something - * like digitalWrite() and have it index into digitalPin[] to find the - * actual pin. On the other hand, PIN_A* are numbers offset by PNUM_ANALOG_BASE, - * which serves to say that this IS an analog pin and which tells analogWrite - * to index into the digitalPin[] array to find the actual pin. + * STM32 pin numbers + *---------------------------------------------------------------------------- + * The pin number definitions below are used to provide a named index + * into the digitalPin array defined in variant_CYGNET.cpp. The analog + * pins (i.e. PIN_A*) are defined as offset from PNUM_ANALOG_BASE, which + * is defined in pin_arduino_analog.h. The index of the analog pin in the + * digitalPin array can be retrieved from the analogInputPin array by + * masking the pin number against PNUM_ANALOG_BASE (resulting in the + * bottom 6 bits) and using that value as an index into the analog array. *----------------------------------------------------------------------------*/ -#define PA0 PIN_A0 // A0/D0 -#define PA1 PIN_A1 // A1/D1 -#define PA2 PIN_A2 // A2/D2 -#define PA3 PIN_A3 // A3/D3 -#define PB1 PIN_A4 // A4/D4 -#define PB8 5 // D5 -#define PB9 6 // D6 -#define PA4 PIN_A6 // BAT_VOLTAGE -#define PA8 8 // LED_BUILTIN -#define PB14 9 // D9 -#define PB13 10 // D10 -#define PB0 11 // D11 -#define PB15 12 // D12 -#define PB4 13 // D13 -#define PA5 14 // CK -#define PA6 15 // MI -#define PA7 PIN_A5 // A5 -#define PA9 17 // TX -#define PA10 18 // RX -#define PA11 19 // USB_DM -#define PA12 20 // USB_DP -#define PA13 21 // SWDIO -#define PA14 22 // SWCLK -#define PA15 23 // CHARGE_DETECT -#define PB3 24 // USB_DETECT -#define PB5 25 // MO -#define PB6 26 // SCL -#define PB7 27 // SDA -#define PB10 28 // LPUART1_VCP_RX -#define PB11 29 // LPUART1_VCP_TX -#define PC13 30 // USER_BTN -#define PC14 31 // OSC32_IN -#define PC15 32 // OSC32_OUT -#define PH0 33 // ENABLE_3V3 -#define PH1 34 // DISCHARGE_3V3 -#define PH3 35 // B +#define PA0 PIN_A0 // A0/D0 +#define PA1 PIN_A1 // A1/D1 +#define PA2 PIN_A2 // A2/D2 +#define PA3 PIN_A3 // A3/D3 +#define PA4 PIN_A6 // A6/BATTERY_VOLTAGE (STAT) +#define PA5 15 // CK +#define PA6 17 // MI +#define PA7 PIN_A5 // A5 +#define PA8 7 // LED_BUILTIN +#define PA9 19 // TX +#define PA10 18 // RX +#define PA11 32 // USB_DM +#define PA12 33 // USB_DP +#define PA13 23 // SWDIO +#define PA14 24 // SWCLK +#define PA15 29 // CHARGE_DETECT +#define PB0 11 // D11 +#define PB1 PIN_A4 // A4/D4 +#define PB3 31 // USB_DETECT +#define PB4 13 // D13 +#define PB5 16 // MO +#define PB6 21 // SCL +#define PB7 22 // SDA +#define PB8 5 // D5 +#define PB9 6 // D6 +#define PB10 25 // LPUART1_VCP_RX +#define PB11 26 // LPUART1_VCP_TX +#define PB13 10 // D10 +#define PB14 9 // D9 +#define PB15 12 // D12 +#define PC13 8 // USER_BTN +#define PC14 34 // OSC32_IN (LSE) +#define PC15 35 // OSC32_OUT (LSE) +#define PH0 27 // ENABLE_3V3 +#define PH1 28 // DISCHARGE_3V3 +#define PH3 20 // B // Alternate pins number -#define PA1_ALT1 (PA1 | ALT1) -#define PA2_ALT1 (PA2 | ALT1) -#define PA3_ALT1 (PA3 | ALT1) -#define PA4_ALT1 (PA4 | ALT1) -#define PA6_ALT1 (PA6 | ALT1) -#define PA15_ALT1 (PA15 | ALT1) -#define PB1_ALT1 (PB1 | ALT1) -#define PB3_ALT1 (PB3 | ALT1) -#define PB4_ALT1 (PB4 | ALT1) -#define PB5_ALT1 (PB5 | ALT1) -#define PB13_ALT1 (PB13 | ALT1) -#define PB14_ALT1 (PB14 | ALT1) -#define PB15_ALT1 (PB15 | ALT1) - -#define NUM_DIGITAL_PINS 36 -#define NUM_ANALOG_INPUTS 7 +#define PA1_ALT1 (PA1 | ALT1) +#define PA2_ALT1 (PA2 | ALT1) +#define PA3_ALT1 (PA3 | ALT1) +#define PA4_ALT1 (PA4 | ALT1) +#define PA6_ALT1 (PA6 | ALT1) +#define PA15_ALT1 (PA15 | ALT1) +#define PB1_ALT1 (PB1 | ALT1) +#define PB3_ALT1 (PB3 | ALT1) +#define PB4_ALT1 (PB4 | ALT1) +#define PB5_ALT1 (PB5 | ALT1) +#define PB13_ALT1 (PB13 | ALT1) +#define PB14_ALT1 (PB14 | ALT1) +#define PB15_ALT1 (PB15 | ALT1) + +#define NUM_DIGITAL_PINS 36 +#define NUM_ANALOG_INPUTS 7 // On-board LED pin number #ifndef LED_BUILTIN - #define LED_BUILTIN PA8 + #define LED_BUILTIN PA8 #endif // On-board user button #ifndef USER_BTN - #define USER_BTN PC13 + #define USER_BTN PC13 #endif // Power switch ENABLE and DISCHARGE pins #ifndef ENABLE_3V3 - #define ENABLE_3V3 PH0 + #define ENABLE_3V3 PH0 #endif #ifndef DISCHARGE_3V3 - #define DISCHARGE_3V3 PH1 - #define DISABLE_DISCHARGING HIGH - #define ENABLE_DISCHARGING LOW + #define DISCHARGE_3V3 PH1 + #define DISABLE_DISCHARGING HIGH + #define ENABLE_DISCHARGING LOW +#endif + +// Macro functions for 3V3 regulator management +#ifndef ENABLE_3V3_REGULATOR +# define ENABLE_3V3_REGULATOR() do { \ + digitalWrite(DISCHARGE_3V3, DISABLE_DISCHARGING); \ + digitalWrite(ENABLE_3V3, HIGH); \ + } while (0) +#endif +#ifndef DISABLE_3V3_REGULATOR +# define DISABLE_3V3_REGULATOR() do { \ + digitalWrite(ENABLE_3V3, LOW); \ + } while (0) +#endif +#ifndef DRAIN_3V3_REGULATOR_MS +# define DRAIN_3V3_REGULATOR_MS(ms) do { \ + if (digitalRead(ENABLE_3V3)) { break; } \ + digitalWrite(DISCHARGE_3V3, ENABLE_DISCHARGING); \ + delay(ms); \ + digitalWrite(DISCHARGE_3V3, DISABLE_DISCHARGING); \ + } while (0) +#endif + +// Dedicated board pins +#ifndef VMAIN_ADC + #define VMAIN_ADC PA4 + #define VMAIN_ADC_DIV_BOT_R 4.3f + #define VMAIN_ADC_DIV_TOP_R 10.0f + #define VMAIN_DIV_K ((double)((VMAIN_ADC_DIV_TOP_R + VMAIN_ADC_DIV_BOT_R) / VMAIN_ADC_DIV_BOT_R)) +#endif +#ifndef VMAIN_MV +# define VMAIN_MV() ({ \ + __HAL_ADC_CALC_DATA_TO_VOLTAGE(__LL_ADC_CALC_VREFANALOG_VOLTAGE(analogRead(AVREF), LL_ADC_GetResolution(ADC1)), analogRead(VMAIN_ADC), LL_ADC_GetResolution(ADC1)) * VMAIN_DIV_K; \ + }) #endif #ifndef CHARGE_DETECT - #define CHARGE_DETECT PA15 + #define CHARGE_DETECT PA15 + #define CHARGING LOW + #define NOT_CHARGING HIGH +#endif +#ifndef USB_DETECT + #define USB_DETECT PB3 #endif // SPI definitions #ifndef PIN_SPI_SS - #define PIN_SPI_SS PB8 // Just default to D5, because we don't have a CS pin + #define PIN_SPI_SS PB0 // Shared with D11 (no dedicated CS pin) #endif #ifndef PIN_SPI_SS1 - #define PIN_SPI_SS1 PNUM_NOT_DEFINED + #define PIN_SPI_SS1 PNUM_NOT_DEFINED #endif #ifndef PIN_SPI_SS2 - #define PIN_SPI_SS2 PNUM_NOT_DEFINED + #define PIN_SPI_SS2 PNUM_NOT_DEFINED #endif #ifndef PIN_SPI_SS3 - #define PIN_SPI_SS3 PNUM_NOT_DEFINED + #define PIN_SPI_SS3 PNUM_NOT_DEFINED #endif #ifndef PIN_SPI_MOSI - #define PIN_SPI_MOSI PB5 + #define PIN_SPI_MOSI PB5 #endif #ifndef PIN_SPI_MISO - #define PIN_SPI_MISO PA6 + #define PIN_SPI_MISO PA6 #endif #ifndef PIN_SPI_SCK - #define PIN_SPI_SCK PA5 + #define PIN_SPI_SCK PA5 #endif // I2C definitions #ifndef PIN_WIRE_SDA - #define PIN_WIRE_SDA PB7 + #define PIN_WIRE_SDA PB7 #endif #ifndef PIN_WIRE_SCL - #define PIN_WIRE_SCL PB6 + #define PIN_WIRE_SCL PB6 #endif // Timer Definitions // Use TIM6/TIM7 when possible as servo and tone don't need GPIO output pin #ifndef TIMER_TONE - #define TIMER_TONE TIM6 + #define TIMER_TONE TIM6 #endif #ifndef TIMER_SERVO - #define TIMER_SERVO TIM7 + #define TIMER_SERVO TIM7 #endif // UART Definitions #ifndef SERIAL_UART_INSTANCE - #define SERIAL_UART_INSTANCE 1 + #define SERIAL_UART_INSTANCE 1 #endif // Default pin used for generic 'Serial' instance // Mandatory for Firmata #ifndef PIN_SERIAL_RX - #define PIN_SERIAL_RX PA10 + #define PIN_SERIAL_RX PA10 #endif #ifndef PIN_SERIAL_TX - #define PIN_SERIAL_TX PA9 + #define PIN_SERIAL_TX PA9 #endif // Default pin used for generic `Serial2` instance #ifndef PIN_SERIAL2_RX - #define PIN_SERIAL2_RX PA3_ALT1 + #define PIN_SERIAL2_RX PA3_ALT1 #endif #ifndef PIN_SERIAL2_TX - #define PIN_SERIAL2_TX PA2_ALT1 + #define PIN_SERIAL2_TX PA2_ALT1 #endif // LPUART1 #ifndef PIN_SERIAL_LP1_RX - #define PIN_SERIAL_LP1_RX PB10 + #define PIN_SERIAL_LP1_RX PB10 #endif #ifndef PIN_SERIAL_LP1_TX - #define PIN_SERIAL_LP1_TX PB11 + #define PIN_SERIAL_LP1_TX PB11 #endif // Virtual COM Port for Cygnet with a 14-pin STLink Connector mounted. -// To use the STLINK's Virtual COM port, this would be added to an Arduino project: +// To use the STLINK's Virtual COM port, add the following line to an Arduino project: // HardwareSerial SerialVCP(PIN_VCP_RX, PIN_VCP_TX); #ifndef PIN_VCP_RX - #define PIN_VCP_RX PIN_SERIAL_LP1_RX + #define PIN_VCP_RX PIN_SERIAL_LP1_RX #endif #ifndef PIN_VCP_TX - #define PIN_VCP_TX PIN_SERIAL_LP1_TX + #define PIN_VCP_TX PIN_SERIAL_LP1_TX #endif // Extra HAL modules