1616
1717// Digital PinName array
1818const PinName digitalPin[] = {
19- PA_0, // 0 - D0/A0
20- PA_1, // 1 - D1/A1
21- PA_2, // 2 - D2/A2
22- PA_3, // 3 - D3/A3
23- PB_1, // 4 - D4/A4
24- PB_8, // 5 - D5
25- PB_9, // 6 - D6
26- PA_4 , // 7 - BAT_VOLTAGE
27- PA_8 , // 8 - LED_BUILTIN
28- PB_14, // 9 - D9
19+ PA_0, // 0 - A0/D0
20+ PA_1, // 1 - A1/D1
21+ PA_2, // 2 - A2/D2
22+ PA_3, // 3 - A3/D3
23+ PB_1, // 4 - A4/D4
24+ PB_8, // 5 - D5
25+ PB_9, // 6 - D6
26+ PA_8 , // 7 - LED_BUILTIN
27+ PC_13 , // 8 - USER_BTN
28+ PB_14, // 9 - D9
2929 PB_13, // 10 - D10
3030 PB_0, // 11 - D11
3131 PB_15, // 12 - D12
3232 PB_4, // 13 - D13
33- PA_5 , // 14 - CK
34- PA_6 , // 15 - MI
35- PA_7 , // 16 - A5
36- PA_9 , // 17 - TX
33+ PA_7 , // 14 - A5
34+ PA_5 , // 15 - CK
35+ PB_5 , // 16 - MO
36+ PA_6 , // 17 - MI
3737 PA_10, // 18 - RX
38- PA_11 , // 19 - USB_DM
39- PA_12 , // 20 - USB_DP
40- PA_13 , // 21 - SWDIO
41- PA_14 , // 22 - SWCLK
42- PA_15 , // 23 - CHARGE_DETECT
43- PB_3 , // 24 - USB_DETECT
44- PB_5 , // 25 - MO
45- PB_6 , // 26 - SCL
46- PB_7 , // 27 - SDA
47- PB_10 , // 28 - LPUART1_VCP_RX
48- PB_11 , // 29 - LPUART1_VCP_TX
49- PC_13 , // 30 - USER_BTN
50- PC_14 , // 31 - OSC32_IN
51- PC_15 , // 32 - OSC32_OUT
52- PH_0 , // 33 - ENABLE_3V3
53- PH_1 , // 34 - DISCHARGE_3V3
54- PH_3 // 35 - B
38+ PA_9 , // 19 - TX
39+ PH_3 , // 20 - B
40+ PB_6 , // 21 - SCL
41+ PB_7 , // 22 - SDA
42+ PA_13 , // 23 - SWDIO
43+ PA_14 , // 24 - SWCLK
44+ PB_10 , // 25 - LPUART1_VCP_RX
45+ PB_11 , // 26 - LPUART1_VCP_TX
46+ PH_0 , // 27 - ENABLE_3V3
47+ PH_1 , // 28 - DISCHARGE_3V3
48+ PA_15 , // 29 - CHARGE_DETECT
49+ PA_4 , // 30 - A6/BATTERY_VOLTAGE (STAT)
50+ PB_3 , // 31 - USB_DETECT
51+ PA_11 , // 32 - USB_DM
52+ PA_12 , // 33 - USB_DP
53+ PC_14 , // 34 - OSC32_IN (LSE)
54+ PC_15 // 35 - OSC32_OUT (LSE)
5555};
5656
5757// Analog (Ax) to digital pin number array
5858const uint32_t analogInputPin[] = {
59- 0 , // PA0, A0
60- 1 , // PA1, A1
61- 2 , // PA2, A2
62- 3 , // PA3, A3
63- 4 , // PB1, A4
64- 16 , // PA7, A5
65- 7 // PA4, BAT_VOLTAGE
59+ 0 , // PA0, A0
60+ 1 , // PA1, A1
61+ 2 , // PA2, A2
62+ 3 , // PA3, A3
63+ 4 , // PB1, A4
64+ 14 , // PA7, A5
65+ 30 // PA4, A6/BATTERY_VOLTAGE (STAT)
6666};
6767
6868// ----------------------------------------------------------------------------
@@ -75,92 +75,226 @@ WEAK void initVariant(void)
7575{
7676 /* All pins set to high-Z (floating) initially */
7777 /* DS11449 Rev 8, Section 3.9.5 - Reset Mode: */
78- /* In order to improve the consumption under reset, the I/Os state under and after reset is
79- * “analog state” (the I/O schmitt trigger is disable). In addition, the internal reset pull-up is
80- * deactivated when the reset source is internal.
78+ /* In order to improve the consumption under reset, the I/Os state under
79+ * and after reset is "analog state" (the I/O schmitt trigger is disabled).
80+ * In addition, the internal reset pull-up is deactivated when the reset
81+ * source is internal.
8182 */
8283
83- /* Turn on the 3V3 regulator */
84- __HAL_RCC_GPIOH_CLK_ENABLE ();
85- GPIO_InitTypeDef GPIO_InitStruct;
86- GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
87- GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
88- GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1;
89- HAL_GPIO_Init (GPIOH, &GPIO_InitStruct); /* PH0 is ENABLE_3V3, PH1 is DISCHARGE_3V3 */
90- HAL_GPIO_WritePin (GPIOH, GPIO_InitStruct.Pin , GPIO_PIN_SET); /* Enable 3V3 regulator and disable discharging */
84+ /* Configure the USB charge detection; leaks ~80uA if not configured. */
85+ {
86+ __HAL_RCC_GPIOA_CLK_ENABLE ();
87+ GPIO_InitTypeDef GPIO_InitStruct = {};
88+ GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
89+ GPIO_InitStruct.Pull = GPIO_PULLDOWN;
90+ GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
91+ /* PA15 is CHARGE_DETECT */
92+ GPIO_InitStruct.Pin = GPIO_PIN_15;
93+ HAL_GPIO_Init (GPIOA, &GPIO_InitStruct);
94+ }
95+
96+ /* Configure D13 manually, to avoid stray current on D13 */
97+ {
98+ __HAL_RCC_GPIOB_CLK_ENABLE ();
99+ GPIO_InitTypeDef GPIO_InitStruct = {};
100+ GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
101+ GPIO_InitStruct.Pull = GPIO_NOPULL;
102+ GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
103+ /* PB4 is D13 */
104+ GPIO_InitStruct.Pin = GPIO_PIN_4;
105+ HAL_GPIO_Init (GPIOB, &GPIO_InitStruct);
106+ }
107+
108+ /* Configure the 3V3 regulator */
109+ {
110+ __HAL_RCC_GPIOH_CLK_ENABLE ();
111+ GPIO_InitTypeDef GPIO_InitStruct = {};
112+ GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
113+
114+ /* PH0 is ENABLE_3V3 */
115+ GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
116+ GPIO_InitStruct.Pin = GPIO_PIN_0;
117+ HAL_GPIO_Init (GPIOH, &GPIO_InitStruct);
118+
119+ /* PH1 is DISCHARGE_3V3 */
120+ GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
121+ GPIO_InitStruct.Pin = GPIO_PIN_1;
122+ HAL_GPIO_Init (GPIOH, &GPIO_InitStruct);
123+
124+ /* Enable 3V3 regulator and disable discharging */
125+ HAL_GPIO_WritePin (GPIOH, (GPIO_PIN_0 | GPIO_PIN_1), GPIO_PIN_SET);
126+ }
91127}
92128
93129/* *
94- * @brief System Clock Configuration
95- * @param None
96- * @retval None
97- */
130+ * @brief System Clock Configuration - PLL-based STM32L433 with native USB FS
131+ *
132+ * Key features:
133+ * - SYSCLK = 80 MHz from MSI (4 MHz, Range 6) via PLL (4MHz x 40/2)
134+ * - USB FS (48 MHz) sourced from PLLSAI1 (4MHz x 24/2)
135+ * - HSI disabled to reduce current consumption (~200-300 uA)
136+ * - LSE enabled with medium-low drive for RTC and MSI auto-calibration (MSIPLLEN)
137+ * - Voltage Scale 1 required for 80 MHz operation
138+ * - FLASH_LATENCY_4 required for HCLK > 64 MHz at VOS1 (RM0394 s.3.3.3)
139+ * - MSI PLL-mode (MSIPLLEN) enabled after SYSCLK moves to PLL to avoid MSIRDY stall
140+ * - Wake-up clock after STOP: MSI (PLL must be re-locked manually after wake)
141+ *
142+ * References:
143+ * - RM0394 Rev 6 (STM32L43x/L44x) - s.6.2 "MSI clock"
144+ * - RM0394 s.6.2.9 "MSI PLL-mode"
145+ * - RM0394 s.3.3.3 "Performance versus VDD and clock frequency"
146+ * - AN2867 Rev 11 - "Oscillator design guide for STM8AF/AL/S, STM32 MCUs and MPUs"
147+ */
98148WEAK void SystemClock_Config (void )
99149{
100150 RCC_OscInitTypeDef RCC_OscInitStruct = {};
101151 RCC_ClkInitTypeDef RCC_ClkInitStruct = {};
102152 RCC_PeriphCLKInitTypeDef PeriphClkInit = {};
103153
104- /* * Configure the main internal regulator output voltage
154+ /* * Enable PWR peripheral clock
155+ *
156+ * RM0394 s.5.1.2: PWR registers are on APB1. PWREN (RCC_APB1ENR1 bit 28)
157+ * resets to 1, so this is defensive rather than strictly necessary, but
158+ * required for correctness if PWREN has been cleared by prior code.
159+ * CubeMX generates this unconditionally for all STM32L4 projects.
105160 */
161+ __HAL_RCC_PWR_CLK_ENABLE ();
162+
163+ /* Voltage scaling - Scale 1 required for SYSCLK = 80 MHz
164+ * RM0394 s.6.1: VOS2 supports up to 26 MHz only
165+ */
106166 if (HAL_PWREx_ControlVoltageScaling (PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK) {
107167 Error_Handler ();
108168 }
109169
110170 /* * Configure LSE Drive Capability
171+ *
172+ * Use MEDIUMLOW (not LOW): RCC_LSEDRIVE_LOW risks marginal LSE startup
173+ * on units near the crystal ESR tolerance limit and degrades MSI PLL mode
174+ * (MSIPLLEN) lock quality. ST recommends MEDIUMLOW as the minimum when
175+ * MSIPLLEN is in use.
176+ *
177+ * Backup domain access must be enabled before configuring LSE or selecting
178+ * the RTC clock source, as those registers (RCC->BDCR) are write-protected
179+ * after reset and silently ignore writes until the lock is cleared.
111180 */
112181 HAL_PWR_EnableBkUpAccess ();
113- __HAL_RCC_LSEDRIVE_CONFIG (RCC_LSEDRIVE_LOW );
182+ __HAL_RCC_LSEDRIVE_CONFIG (RCC_LSEDRIVE_MEDIUMLOW );
114183
115184 /* * Initializes the RCC Oscillators according to the specified parameters
116185 * in the RCC_OscInitTypeDef structure.
186+ *
187+ * Oscillator configuration summary:
188+ * - MSI: MSIRANGE_6 (4 MHz) -- used as PLL input
189+ * - HSI: OFF -- Unused, disabling it saves ~200-300 uA
190+ * - PLL: ON (MSI 4MHz x PLLN=40 / PLLR=2 = 80 MHz)
191+ * - SYSCLK: PLLCLK (80 MHz)
192+ * - USB clock: PLLSAI1 (48 MHz)
193+ * - MSIRDY transient can not stall SysTick because SYSCLK = PLL, not MSI.
194+ * - FLASH_LATENCY: 4 (required for 80 MHz / VOS1 per RM0394 s.3.3)
117195 */
118196 RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE
119- | RCC_OSCILLATORTYPE_MSI
120- | RCC_OSCILLATORTYPE_HSI;
197+ | RCC_OSCILLATORTYPE_MSI;
121198 RCC_OscInitStruct.LSEState = RCC_LSE_ON;
199+ RCC_OscInitStruct.HSIState = RCC_HSI_OFF;
122200 RCC_OscInitStruct.MSIState = RCC_MSI_ON;
123201 RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT;
124- RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_11;
125- RCC_OscInitStruct.HSIState = RCC_HSI_ON;
126- RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
127- RCC_OscInitStruct.PLL .PLLState = RCC_PLL_NONE;
202+ RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
203+ RCC_OscInitStruct.PLL .PLLState = RCC_PLL_ON;
204+ RCC_OscInitStruct.PLL .PLLSource = RCC_PLLSOURCE_MSI;
205+ RCC_OscInitStruct.PLL .PLLM = 1 ;
206+ RCC_OscInitStruct.PLL .PLLN = 40 ;
207+ RCC_OscInitStruct.PLL .PLLP = RCC_PLLP_DIV7;
208+ RCC_OscInitStruct.PLL .PLLQ = RCC_PLLQ_DIV2;
209+ RCC_OscInitStruct.PLL .PLLR = RCC_PLLR_DIV2; /* 4MHz x 40 / 2 = 80 MHz */
128210 if (HAL_RCC_OscConfig (&RCC_OscInitStruct) != HAL_OK) {
129211 Error_Handler ();
130212 }
131213
132214 /* * Initializes the CPU, AHB and APB buses clocks
215+ *
216+ * SYSCLK = PLLCLK (80 MHz). SysTick and HAL_GetTick() are now driven by
217+ * the PLL output, completely decoupled from MSI. Any subsequent MSIRDY
218+ * transient (from HAL_RCCEx_EnableMSIPLLMode below) cannot stall SysTick.
133219 */
134220 RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
135221 | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
136- // RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
137- RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_MSI;
222+ RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
138223 RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
139224 RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
140225 RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
141- if (HAL_RCC_ClockConfig (&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) {
226+ /* FLASH_LATENCY_4: required for HCLK > 64 MHz at VOS1 (RM0394 s.3.3.3) */
227+ if (HAL_RCC_ClockConfig (&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) {
142228 Error_Handler ();
143229 }
144230
145231 /* * Initializes the Peripheral clocks
232+ *
233+ * USB clock: PLLSAI1 (MSI 4 MHz x PLLSAI1N=24 / PLLSAI1Q=2 = 48 MHz).
234+ * This mirrors the Nucleo L432KC exactly. RCCEx_PLLSAI1_Config() waits
235+ * for PLLSAI1RDY using HAL_GetTick(). Because SYSCLK is now PLL-based,
236+ * HAL_GetTick() is immune to MSI transients -- the wait is reliable.
237+ * PLLSAI1 and the main PLL share the same source (MSI) and M divider (1),
238+ * which the HAL enforces; both are configured consistently here.
239+ *
240+ * HAL_RCCEx_PeriphCLKConfig writes CLK48SEL first (pointing at PLLSAI1
241+ * before it is running), then enables PLLSAI1 and waits for its RDY flag.
242+ * During that brief window the USB peripheral has no 48 MHz clock and
243+ * stays quiescent -- avoiding the race where a live MSI clock is handed
244+ * to USB before the peripheral is ready to handle the absence of VBUS.
146245 */
147- PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USB | RCC_PERIPHCLK_SDMMC1
148- | RCC_PERIPHCLK_ADC /* | RCC_PERIPHCLK_OSPI */ ;
246+ PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC | RCC_PERIPHCLK_USB;
149247 PeriphClkInit.AdcClockSelection = RCC_ADCCLKSOURCE_SYSCLK;
150- // PeriphClkInit.OspiClockSelection = RCC_OSPICLKSOURCE_SYSCLK;
151- PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_MSI;
152- PeriphClkInit.Sdmmc1ClockSelection = RCC_SDMMC1CLKSOURCE_MSI;
248+ PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_PLLSAI1;
249+ PeriphClkInit.PLLSAI1 .PLLSAI1Source = RCC_PLLSOURCE_MSI;
250+ PeriphClkInit.PLLSAI1 .PLLSAI1M = 1 ;
251+ PeriphClkInit.PLLSAI1 .PLLSAI1N = 24 ;
252+ PeriphClkInit.PLLSAI1 .PLLSAI1P = RCC_PLLP_DIV7;
253+ PeriphClkInit.PLLSAI1 .PLLSAI1Q = RCC_PLLQ_DIV2; /* 4 x 24 / 2 = 48 MHz */
254+ PeriphClkInit.PLLSAI1 .PLLSAI1R = RCC_PLLR_DIV2;
255+ PeriphClkInit.PLLSAI1 .PLLSAI1ClockOut = RCC_PLLSAI1_48M2CLK;
153256 if (HAL_RCCEx_PeriphCLKConfig (&PeriphClkInit) != HAL_OK) {
154257 Error_Handler ();
155258 }
156259
157- /* * Enable MSI Auto calibration
158- */
260+ /* * Enable MSI Auto calibration (MSIPLLEN, RCC_CR[2])
261+ *
262+ * RM0394 s.6.2 (MSI clock): setting MSIPLLEN causes the MSI hardware
263+ * to automatically trim itself against LSE as a phase reference,
264+ * reducing MSI frequency error to < +/-0.25%. LSE must already be
265+ * stable (LSERDY=1) before the bit is set -- guaranteed here because
266+ * HAL_RCC_OscConfig() waited for LSERDY before returning.
267+ *
268+ * Setting MSIPLLEN causes MSIRDY to deassert transiently while MSI
269+ * re-synchronises to LSE. HAL_RCCEx_EnableMSIPLLMode() returns
270+ * immediately (it is a single SET_BIT); no MSIRDY wait is performed
271+ * inside it. Two conclusions follow:
272+ *
273+ * (1) This call must come AFTER any HAL routine that polls MSIRDY
274+ * under a HAL_GetTick() timeout -- if MSIRDY drops inside such
275+ * a routine, the routine returns HAL_TIMEOUT and leaves the
276+ * clock tree in an undefined state.
277+ *
278+ * (2) If SYSCLK were MSI, a deadlock would be possible: MSIRDY
279+ * drops -> SysTick stalls -> HAL_GetTick() freezes -> any
280+ * subsequent timeout loop never exits. RM0394 s.6.2.9 confirms
281+ * SysTick is driven by HCLK (= SYSCLK / AHBdiv). Because
282+ * SYSCLK is now PLLCLK (80 MHz), SysTick is completely
283+ * decoupled from MSI and the transient is harmless.
284+ *
285+ * Placement here -- after PeriphCLKConfig -- satisfies both constraints
286+ * and mirrors the ordering generated by CubeMX for the Nucleo L432KC.
287+ */
159288 HAL_RCCEx_EnableMSIPLLMode ();
160289
161290 /* * Ensure that MSI is wake-up system clock
291+ *
292+ * After STOP mode, the PLL is not automatically re-enabled. MSI is used
293+ * as the initial wake-up clock; firmware must re-lock the PLL manually
294+ * if 80 MHz is required after wake. This is the same behaviour as any
295+ * PLL-based design on STM32L4.
162296 */
163- __HAL_RCC_WAKEUPSTOP_CLK_CONFIG (RCC_STOP_WAKEUPCLOCK_MSI);
297+ HAL_RCCEx_WakeUpStopCLKConfig (RCC_STOP_WAKEUPCLOCK_MSI);
164298}
165299
166300#ifdef __cplusplus
0 commit comments