# STM32L4 Series
###### tags: `STM32`
## [STM32L4 Series 32-bit Arm M4(DSP+FPU)-80MHZ](https://www.st.com/content/st_com/en/products/microcontrollers-microprocessors/stm32-32-bit-arm-cortex-mcus/stm32-ultra-low-power-mcus/stm32l4-series.html)

## [STM32CubeL4 firmware components](https://www.st.com/en/embedded-software/stm32cubel4.html#documentation)
* UM1860 Getting started with STM32CubeL4 MCU Package for STM32L4 Series and STM32L4+ Series 14.0 09 Feb 2021


## [Description of STM32L4/L4+ HAL and low-layer drivers](https://www.st.com/resource/en/user_manual/dm00173145-description-of-stm32l4l4-hal-and-lowlayer-drivers-stmicroelectronics.pdf)
* UM1884 Description of STM32L4/L4+ HAL and low-layer drivers 9.0 03 Sep 2021
### Introduction
* STM32Cube is an STMicroelectronics original initiative to significantly improve developer productivity by reducing development effort, time and cost. STM32Cube covers the STM32 portfolio.
* STM32Cube includes:
* STM32CubeMX, a graphical software configuration tool that allows the generation of C initialization code using graphical
wizards.
* A comprehensive embedded software platform, delivered per Series (such as STM32CubeL4 for STM32L4 and STM32L4+
Series)
* The STM32Cube HAL, STM32 abstraction layer embedded software ensuring maximized portability across the
STM32 portfolio. HAL APIs are available for all peripherals.
* Low-layer APIs (LL) offering a fast light-weight expert-oriented layer which is closer to the hardware than the HAL. LL
APIs are available only for a set of peripherals.
* A consistent set of middleware components such as RTOS, USB and Graphics.
* All embedded software utilities, delivered with a full set of examples.
## [STM32 Cortex®-M4 MCUs and MPUs programming manual](https://www.st.com/resource/en/programming_manual/pm0214-stm32-cortexm4-mcus-and-mpus-programming-manual-stmicroelectronics.pdf)
* Outstanding processing performance combined with fast interrupt handling
* Enhanced system debug with extensive breakpoint and trace capabilities
* Efficient processor core, system and memories
* Ultra-low power consumption with integrated sleep modes
* Platform security

### [STM32L47xxx, STM32L48xxx, STM32L49xxx and STM32L4Axxx advanced Arm®-based 32-bit MCUs](https://www.st.com/resource/en/reference_manual/rm0351-stm32l47xxx-stm32l48xxx-stm32l49xxx-and-stm32l4axxx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf)
* Related documents
* Cortex®-M4 Technical Reference Manual, available from: http://infocenter.arm.com
* STM32L471xx, STM32L475xx, STM32L476xx, STM32L486xx, STM32L496xx and STM32L4A6xx datasheets
* STM32 Cortex®-M4 MCUs and MPUs programming manual (PM0214)
* STM32L471xx, STM32L475xx, STM32L476xx, STM32L486xx, STM32L496xx and STM32L4A6xx erratasheets In this document, the following short names, or combinations of them, may be used to refer to subsets of the above-listed part numbers:
* STM32L47x, STM32L48x, STM32L49x, STM32L4Ax
* STM32L471, STM32L4x5, STM32L4x6
## GPIO define
### mode
```=
#define GPIO_MODE_INPUT (0x00000000U) /*!< Input Floating Mode */
#define GPIO_MODE_OUTPUT_PP (0x00000001U) /*!< Output Push Pull Mode */
#define GPIO_MODE_OUTPUT_OD (0x00000011U) /*!< Output Open Drain Mode */
#define GPIO_MODE_AF_PP (0x00000002U) /*!< Alternate Function Push Pull Mode */
#define GPIO_MODE_AF_OD (0x00000012U) /*!< Alternate Function Open Drain Mode */
#define GPIO_MODE_ANALOG (0x00000003U) /*!< Analog Mode */
#define GPIO_MODE_IT_RISING (0x10110000U) /*!< External Interrupt Mode with Rising edge trigger detection */
#define GPIO_MODE_IT_FALLING (0x10210000U) /*!< External Interrupt Mode with Falling edge trigger detection */
#define GPIO_MODE_IT_RISING_FALLING (0x10310000U) /*!< External Interrupt Mode with Rising/Falling edge trigger detection */
#define GPIO_MODE_EVT_RISING (0x10120000U) /*!< External Event Mode with Rising edge trigger detection */
#define GPIO_MODE_EVT_FALLING (0x10220000U) /*!< External Event Mode with Falling edge trigger detection */
#define GPIO_MODE_EVT_RISING_FALLING (0x10320000U) /*!< External Event Mode with Rising/Falling edge trigger detection */
```
### pull
```=
#define GPIO_NOPULL (0x00000000U) /*!< No Pull-up or Pull-down activation */
#define GPIO_PULLUP (0x00000001U) /*!< Pull-up activation */
#define GPIO_PULLDOWN (0x00000002U) /*!< Pull-down activation */
```
### speed
* 大部分 Speed 採用GPIO_SPEED_FREQ_LOW,建議不要採用太高的speed,因為EMC驗證頻率太高會不過
* However, keep in mind that driving a pin “too hard” impacts on the overall EMI emissions of your board.
* Professional design is nowadays all about EMI minimizing. Unless differently required, it is strongly suggested you leave the default GPIO speed parameter to the minimum level.
* What about the effective switching frequency? ST claims in its datasheets that the fastest toggle speed of an output pin is every two clock cycles. The AHB1 bus, where the GPIO peripheral is connected, runs at 42MHz for an STM32F446 MCU. So a pin should toggle in about 20MHz. However, we have to add an additional overhead related to the memory transfer between the GPIO->ODR register and the value we are going to store inside it (0x110), which costs another CPU cycle.
```=
#define GPIO_SPEED_FREQ_LOW (0x00000000U) /*!< range up to 0.4 MHz, please refer to the product datasheet */
#define GPIO_SPEED_FREQ_MEDIUM (0x00000001U) /*!< range 0.4 MHz to 2 MHz, please refer to the product datasheet */
#define GPIO_SPEED_FREQ_HIGH (0x00000002U) /*!< range 2 MHz to 10 MHz, please refer to the product datasheet */
#define GPIO_SPEED_FREQ_VERY_HIGH (0x00000003U) /*!< range 10 MHz to 35 MHz, please refer to the product datasheet */
```
## [System clock](https://www.st.com/resource/en/user_manual/dm00173145-description-of-stm32l4l4-hal-and-lowlayer-drivers-stmicroelectronics.pdf)

* [P.20](https://www.st.com/content/ccc/resource/training/technical/product_training/7c/c6/36/09/9f/21/44/9c/STM32L4_System_RCC.pdf/files/STM32L4_System_RCC.pdf/jcr:content/translations/en.STM32L4_System_RCC.pdf)
### [RCC Firmware driver API description](https://www.st.com/resource/en/user_manual/dm00173145-description-of-stm32l4l4-hal-and-lowlayer-drivers-stmicroelectronics.pdf)
* 54.2
1. LSI (low-speed internal): 是低速內部Clock, RC 振盪器,頻率為 32kHz 左右。供獨立watchdog、 RTC 和 LCD。
2. HSE (high-speed external): 是高速外部Clock,4 到 48 MHz 晶振直接使用或通過 PLL 作為系統時鐘源。也可以選擇用作 RTC clock。
3. LSE (low-speed external): 是低速外部Clock,32 KHz 低功耗 RC 用作 IWDG 和/或 RTC。
4. HSI (high-speed internal): 直接或通過 PLL 用做系統clock 16 MHz RC 振盪器。
5. MSI (Mutiple Speed Internal):它的頻率是從 100KHZ 到 48MHZ 的軟件可調的。它可用於為 USB OTG FS (48 MHz) 生成時鐘。當使用 HAL_RCC_OscConfig() 更新 MSI 範圍並且將 MSI 用作系統時鐘源時,會自動調整閃存等待狀態的數量。
6. PLL (clocked by HSI, HSE or MSI)providing up to three independent output clocks:
* (1) PLL
* 第一個輸出用於產生high speed system clock (高達 80MHz)。
* 第二個輸出用於為 USB OTG FS (48 MHz)、隨機模擬發生器 (<=48 MHz) 和 SDMMC1 (<= 48 MHz) 生成時鐘。
* 第三個輸出用於生成準確的時鐘,以在 SAI 接口上實現高質量的音頻性能。
* (2) PLLSAI1
* 第一個輸出用於產生 SAR ADC1 Clock
* 第二個輸出用於為 USB OTG FS (48 MHz)、隨機模擬發生器 (<=48 MHz) 和 SDMMC1 (<= 48 MHz) 生成時鐘。
* 第三個輸出用於生成準確的時鐘,以在 SAI 接口上實現高質量的音頻性能。
* (3) PLLSAI2
* 第一個輸出用於生成準確的時鐘,以在 SAI 接口上實現高質量的音頻性能。
* 第二個輸出用於生成 SAR ADC2 時鐘(如果 ADC2 存在)或 LCD 時鐘(如果 LTDC 存在)
* 如果存在 DSI,則第三個輸出用於生成 DSI 時鐘
```=
/**
* @brief System Clock Configuration
* The system Clock is configured as follows :
* System Clock source = PLL (MSI)
* SYSCLK(Hz) = 80000000
* HCLK(Hz) = 80000000
* AHB Prescaler = 1
* APB1 Prescaler = 1
* APB2 Prescaler = 1
* MSI Frequency(Hz) = 4000000
* PLL_M = 1
* PLL_N = 40
* PLL_R = 2
* PLL_P = 7
* PLL_Q = 4
* Flash Latency(WS) = 4
* @param None
* @retval None
*/
```
### Internal and External
#### MSI
##### MSI 48MHZ
```=
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_MSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.MSIState = RCC_MSI_ON;
RCC_OscInitStruct.MSICalibrationValue = 0;
RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_11;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_MSI;
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)
{
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_I2C1
|RCC_PERIPHCLK_ADC;
PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
PeriphClkInit.I2c1ClockSelection = RCC_I2C1CLKSOURCE_PCLK1;
PeriphClkInit.AdcClockSelection = RCC_ADCCLKSOURCE_PLLSAI1;
PeriphClkInit.PLLSAI1.PLLSAI1Source = RCC_PLLSOURCE_HSI;
PeriphClkInit.PLLSAI1.PLLSAI1M = 1;
PeriphClkInit.PLLSAI1.PLLSAI1N = 12;
PeriphClkInit.PLLSAI1.PLLSAI1P = RCC_PLLP_DIV7;
PeriphClkInit.PLLSAI1.PLLSAI1Q = RCC_PLLQ_DIV2;
PeriphClkInit.PLLSAI1.PLLSAI1R = RCC_PLLR_DIV4;
PeriphClkInit.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_ADC1CLK;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
/** Configure the main internal regulator output voltage
*/
if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
{
Error_Handler();
}
```
#### HSI
##### HSI 16MHZ
```=
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
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_0) != HAL_OK)
{
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_I2C1
|RCC_PERIPHCLK_ADC;
PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
PeriphClkInit.I2c1ClockSelection = RCC_I2C1CLKSOURCE_PCLK1;
PeriphClkInit.AdcClockSelection = RCC_ADCCLKSOURCE_PLLSAI1;
PeriphClkInit.PLLSAI1.PLLSAI1Source = RCC_PLLSOURCE_HSI;
PeriphClkInit.PLLSAI1.PLLSAI1M = 1;
PeriphClkInit.PLLSAI1.PLLSAI1N = 8;
PeriphClkInit.PLLSAI1.PLLSAI1P = RCC_PLLP_DIV7;
PeriphClkInit.PLLSAI1.PLLSAI1Q = RCC_PLLQ_DIV2;
PeriphClkInit.PLLSAI1.PLLSAI1R = RCC_PLLR_DIV8;
PeriphClkInit.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_ADC1CLK;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
/** Configure the main internal regulator output voltage
*/
if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
{
Error_Handler();
}
```
#### HSE
##### HSE 48 + PLL 80M
* 開啟外部震盪 48M
* 開啟外部振盪器
* stm32l0xx_hal_conf.h
```=
#if !defined (HSE_VALUE)
#define HSE_VALUE ((uint32_t)48000000U) /*!< Value of the External oscillator in Hz */
#endif /* HSE_VALUE */
```
```=
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 3;
RCC_OscInitStruct.PLL.PLLN = 10;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
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_4) != HAL_OK)
{
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_I2C1
|RCC_PERIPHCLK_ADC;
PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
PeriphClkInit.I2c1ClockSelection = RCC_I2C1CLKSOURCE_PCLK1;
PeriphClkInit.AdcClockSelection = RCC_ADCCLKSOURCE_PLLSAI1;
PeriphClkInit.PLLSAI1.PLLSAI1Source = RCC_PLLSOURCE_HSE;
PeriphClkInit.PLLSAI1.PLLSAI1M = 3;
PeriphClkInit.PLLSAI1.PLLSAI1N = 10;
PeriphClkInit.PLLSAI1.PLLSAI1P = RCC_PLLP_DIV7;
PeriphClkInit.PLLSAI1.PLLSAI1Q = RCC_PLLQ_DIV2;
PeriphClkInit.PLLSAI1.PLLSAI1R = RCC_PLLR_DIV2;
PeriphClkInit.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_ADC1CLK;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
/** Configure the main internal regulator output voltage
*/
if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
{
Error_Handler();
}
```
#### PLLCLK
##### HSI + PLLCLK 80M
```=
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = 1;
RCC_OscInitStruct.PLL.PLLN = 10;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
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_4) != HAL_OK)
{
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_I2C1
|RCC_PERIPHCLK_ADC;
PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
PeriphClkInit.I2c1ClockSelection = RCC_I2C1CLKSOURCE_PCLK1;
PeriphClkInit.AdcClockSelection = RCC_ADCCLKSOURCE_PLLSAI1;
PeriphClkInit.PLLSAI1.PLLSAI1Source = RCC_PLLSOURCE_HSI;
PeriphClkInit.PLLSAI1.PLLSAI1M = 1;
PeriphClkInit.PLLSAI1.PLLSAI1N = 10;
PeriphClkInit.PLLSAI1.PLLSAI1P = RCC_PLLP_DIV7;
PeriphClkInit.PLLSAI1.PLLSAI1Q = RCC_PLLQ_DIV2;
PeriphClkInit.PLLSAI1.PLLSAI1R = RCC_PLLR_DIV2;
PeriphClkInit.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_ADC1CLK;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
/** Configure the main internal regulator output voltage
*/
if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
{
Error_Handler();
}
```
##### MSI + PLLCLK 80M
```=
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
RCC_OscInitStruct.MSIState = RCC_MSI_ON;
RCC_OscInitStruct.MSICalibrationValue = 0;
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;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
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_4) != HAL_OK)
{
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_I2C1
|RCC_PERIPHCLK_ADC;
PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
PeriphClkInit.I2c1ClockSelection = RCC_I2C1CLKSOURCE_PCLK1;
PeriphClkInit.AdcClockSelection = RCC_ADCCLKSOURCE_PLLSAI1;
PeriphClkInit.PLLSAI1.PLLSAI1Source = RCC_PLLSOURCE_MSI;
PeriphClkInit.PLLSAI1.PLLSAI1M = 1;
PeriphClkInit.PLLSAI1.PLLSAI1N = 40;
PeriphClkInit.PLLSAI1.PLLSAI1P = RCC_PLLP_DIV7;
PeriphClkInit.PLLSAI1.PLLSAI1Q = RCC_PLLQ_DIV2;
PeriphClkInit.PLLSAI1.PLLSAI1R = RCC_PLLR_DIV2;
PeriphClkInit.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_ADC1CLK;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
/** Configure the main internal regulator output voltage
*/
if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
{
Error_Handler();
}
```
## Interrupts Management
## UART
### UART Debuger
```=
/********************************************
* Copyright (h)
* File name : uart_printf.h
* Author : Barry.Chung
* Version : 1.0
* Date : 2021.12.2
* Description : Configure STM32L4X peripherals.
* Function List:
********************************************/
#include "main.h"
UART_HandleTypeDef uart_deg;
static void MX_USART1_UART_Init(void);
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
PUTCHAR_PROTOTYPE
{
HAL_UART_Transmit(&uart_deg, (uint8_t*)&ch, 1, HAL_MAX_DELAY);
return ch;
}
#endif
static void MX_USART1_UART_Init(void){
uart_deg.Instance = USART1;
uart_deg.Init.BaudRate = 115200;
uart_deg.Init.WordLength = UART_WORDLENGTH_8B;
uart_deg.Init.StopBits = UART_STOPBITS_1;
uart_deg.Init.Parity = UART_PARITY_NONE;
uart_deg.Init.Mode = UART_MODE_TX_RX;
uart_deg.Init.HwFlowCtl = UART_HWCONTROL_NONE;
uart_deg.Init.OverSampling = UART_OVERSAMPLING_16;
uart_deg.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
uart_deg.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&uart_deg) != HAL_OK)
{
Error_Handler();
}
}
```
## DMA Management
* The DMA controller performs direct memory transfer by sharing the AHB system bus with other system masters. The bus matrix implements round-robin scheduling.
* DMA requests may stop the CPU access to the system bus for a number of bus cycles, when CPU andDMA target the same destination (memory or peripheral).
* According to its configuration through the AHB slave interface, the DMA controller arbitrates between the DMA channels and their associated received requests.
* The DMA controller also schedules the DMA data transfers over the single AHB port master.
* The DMA controller generates an interrupt per channel to the interrupt controller.
### 11.3 DMA implementation
* 11.3.1 DMA1 and DMA2


### 11.4 DMA functional description
* 11.4.1 DMA block diagram



## Timers(TIM)

* STM32 Timers 最大週期 65535
* 可透過以下公式進行換算
* Core: Arm® 32-bit Cortex®-M4+ with MPU
* From 80 kHz up to 80 MHz max. 0.95 DMIPS/MHz
* STM32L476RZ 80MHZ MAX

* Prescaler: it divides the timer clock by a factor ranging from 1 up to 65535 (this means that theprescaler register has a 16-bit resolution). For example, if the bus where the timer is connectedruns at 48MHz, then a prescaler value equal to 48 lowers the counting frequency to 1MHz.
* TIME 1秒 ÷ (頻率 ÷ (Prescaler + 1)) ,定時計數器數滿一個周期的時間為 計數一次時間 × (Period + 1) 秒 。所以定時時間計算公式如下:
* 定時時間 = (Prescaler + 1) × (Period + 1) ÷ 頻率 单位:秒
## ADC
### 數據值如何轉化計算?
* The majority of STM32 MCUs provide a 12-bit ADC. Some of them from the STM32F3 portfolio even a 16-bit ADC.
* STM32 MCU提供一個12-bit ADC 只有少部分是16-bit 的,如:stm32f3、f4。
12 bit解析意味著我們電壓的精度可以達到:Vref / 4095(12bit 0-4095)。
採集電壓= Vref * ADC_DR / 4095;
VREF:參考電壓
ADC_DR:讀取到ADC資料暫存器的值

* Power supply schemes
* VDD = 1.65 to 3.6 V: external power supply for I/Os and the internal regulator. Provided externally through VDD pins.
* VDD = 1.65至3.6 V:用於I / O的外部電源和內部穩壓器。通過VDD引腳從外部提供。
* VSSA, VDDA = 1.65 to 3.6 V: external analog power supplies for ADC reset blocks, RCs and PLL. VDDA and VSSA must be connected to VDD and VSS, respectively.
* VSSA,VDDA = 1.65至3.6 V:用於ADC復位模塊,RC和PLL的外部模擬電源。 VDDA和VSSA必須分別連接到VDD和VSS。
* 算Vref = Vdda 需帶入暫存器,數值。

```=
AdcHandle.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1; /* Asynchronous clock mode, input ADC clock not divided */
AdcHandle.Init.Resolution = ADC_RESOLUTION_12B; /* 12-bit resolution for converted data */
AdcHandle.Init.DataAlign = ADC_DATAALIGN_RIGHT; /* Right-alignment for converted data */
AdcHandle.Init.ScanConvMode = DISABLE; /* Sequencer disabled (ADC conversion on only 1 channel: channel set on rank 1) */
AdcHandle.Init.EOCSelection = ADC_EOC_SINGLE_CONV; /* EOC flag picked-up to indicate conversion end */
AdcHandle.Init.LowPowerAutoWait = DISABLE; /* Auto-delayed conversion feature disabled */
AdcHandle.Init.ContinuousConvMode = DISABLE; /* Continuous mode disabled to have only 1 conversion at each conversion trig */
AdcHandle.Init.NbrOfConversion = 1; /* Parameter discarded because sequencer is disabled */
AdcHandle.Init.DiscontinuousConvMode = DISABLE; /* Parameter discarded because sequencer is disabled */
AdcHandle.Init.NbrOfDiscConversion = 1; /* Parameter discarded because sequencer is disabled */
AdcHandle.Init.ExternalTrigConv = ADC_SOFTWARE_START; /* Software start to trig the 1st conversion manually, without external event */
AdcHandle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; /* Parameter discarded because software trigger chosen */
AdcHandle.Init.DMAContinuousRequests = DISABLE; /* DMA one-shot mode selected (not applied to this example) */
AdcHandle.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN; /* DR register is overwritten with the last conversion result in case of overrun */
AdcHandle.Init.OversamplingMode = DISABLE; /* No oversampling */
```
```=
/*##-2- Configure ADC regular channel ######################################*/
sConfig.Channel = ADCx_CHANNEL; /* Sampled channel number */
sConfig.Rank = ADC_REGULAR_RANK_1; /* Rank of sampled channel number ADCx_CHANNEL */
sConfig.SamplingTime = ADC_SAMPLETIME_6CYCLES_5; /* Sampling time (number of clock cycles unit) */
sConfig.SingleDiff = ADC_SINGLE_ENDED; /* Single-ended input channel */
sConfig.OffsetNumber = ADC_OFFSET_NONE; /* No offset subtraction */
sConfig.Offset = 0; /* Parameter discarded because offset correction is disabled */
```
```=
/* USER CODE BEGIN ADC1_Init 0 */
/* USER CODE END ADC1_Init 0 */
ADC_MultiModeTypeDef multimode = {0};
ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC1_Init 1 */
/* USER CODE END ADC1_Init 1 */
/** Common config
*/
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc1.Init.LowPowerAutoWait = DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
hadc1.Init.OversamplingMode = DISABLE;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/** Configure the ADC multi-mode
*/
multimode.Mode = ADC_MODE_INDEPENDENT;
if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_6|ADC_CHANNEL_7;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_24CYCLES_5;
sConfig.SingleDiff = ADC_DIFFERENTIAL_ENDED;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC1_Init 2 */
/* USER CODE END ADC1_Init 2 */
```
## DAC
## I2C
## SPI
## IWDG and WWDG Timers
## Real-Time Clock(RTC)
## Flash
### 切割flash and RAM
* STM32L476RGTx_FLASH.ld
```=
_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */
_Min_Heap_Size = 0x200 ; /* required amount of heap */
_Min_Stack_Size = 0x400 ; /* required amount of stack */
/* Memories definition */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 96K
RAM2 (xrw) : ORIGIN = 0x10000000, LENGTH = 32K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K
}
```
* STM32L471VETx_FLASH.ld
```=
/* Highest address of the user mode stack */
_estack = 0x20018000; /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x400; /* required amount of heap */
_Min_Stack_Size = 0x800; /* required amount of stack */
/* Specify the memory areas */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 96K
RAM2 (xrw) : ORIGIN = 0x10000000, LENGTH = 32K
FLASH (rx) : ORIGIN = 0x8008200, LENGTH = (512K - 32K - 512)
}
```
## USB
### [USB (Virtual Com Port)](https://shawnhymel.com/1795/getting-started-with-stm32-nucleo-usb-virtual-com-port/)
* Pinout & Congfiguration
* System Core -> RCC -> High Speed Clock (HSE) -> Crystal/Ceramic Resonator
* Connectivity -> USB_OTG_FS -> Mode -> Device_Only
* Middleware -> USB_DEVICE -> Communication Device
### USB driver

### Code
* main.c
```
#include "usbd_cdc_if.h"
```
```
uint8_t buffer[] = "Hello, World!\r\n";
CDC_Transmit_FS(buffer, sizeof(buffer));
HAL_Delay(1000);
```
## Reference
### Flash
* [STM32 Blue Pill — Analyse and Optimise Your RAM and ROM](https://www.pcbway.com/blog/technology/STM32_Blue_Pill___Analyse_and_Optimise_Your_RAM_and_ROM.html)
### USB
* [STM32CubeMX系列教程25:USB Device](https://www.waveshare.net/study/article-664-1.html)