Skip to content

Commit 7434813

Browse files
authored
Merge pull request #2950 from zfields/zak-cygnet-init
Blues Cygnet Initialization
2 parents 4884119 + d41a60b commit 7434813

File tree

3 files changed

+335
-160
lines changed

3 files changed

+335
-160
lines changed

variants/STM32L4xx/L433C(B-C)(T-U)_L443CC(T-U)/PeripheralPins_CYGNET.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ WEAK const PinMap PinMap_ADC[] = {
3636
{PA_1, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 6, 0)}, // ADC1_IN6 - A1
3737
{PA_2, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 7, 0)}, // ADC1_IN7 - A2
3838
{PA_3, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 8, 0)}, // ADC1_IN8 - A3
39-
{PA_4, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 9, 0)}, // ADC1_IN9 - BAT_VOLTAGE
39+
{PA_4, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 9, 0)}, // ADC1_IN9 - A6/BATTERY_VOLTAGE (STAT)
4040
{PA_5, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 10, 0)}, // ADC1_IN10 - CK
4141
{PA_6, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 11, 0)}, // ADC1_IN11 - MI
4242
{PA_7, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 12, 0)}, // ADC1_IN12 - A5

variants/STM32L4xx/L433C(B-C)(T-U)_L443CC(T-U)/variant_CYGNET.cpp

Lines changed: 206 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -16,53 +16,53 @@
1616

1717
// Digital PinName array
1818
const 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
5858
const 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+
*/
98148
WEAK 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

Comments
 (0)