# STM32L0 Series
> [name= Adcantech Barry.Chung]
###### tags: `STM32`
## [STM32L0 MCU Series 32bit Arm Cortex-M0+ -32MHZ with MPU](https://www.st.com/en/microcontrollers-microprocessors/stm32l0-series.html)

### [STM32CubeL0 firmware components](https://www.st.com/resource/en/user_manual/dm00114438-getting-started-with-stm32cubel0-for-stm32l0-series-stmicroelectronics.pdf)


## [Cortex®-M0+ programming manual for STM32L0, STM32G0,STM32WL and STM32WB Series ](https://www.st.com/resource/en/programming_manual/pm0223-cortexm0-programming-manual-for-stm32l0-stm32g0-stm32wl-and-stm32wb-series-stmicroelectronics.pdf)
### Cortex®-M0+ is a high performance 32-bit processor designed for integration in microcontrollers. It offers significant benefits to developers, including:
* Outstanding processing performance combined with fast interrupt handling
* Enhanced system debug with extensive breakpoint options
* Efficient processor core, system and memories
* Ultra-low power consumption with integrated sleep modes
* Platform security

### [Ultra-low-power STM32L0x1 advanced Arm®-based 32-bit MCUs](https://www.st.com/resource/en/reference_manual/rm0377-ultralowpower-stm32l0x1-advanced-armbased-32bit-mcus-stmicroelectronics.pdf)
* Related documents
* Cortex®-M0+ Technical Reference Manual, available from www.arm.com.
* STM32L0 Series Cortex®-M0+ programming manual (PM0223).
* STM32L0x1 datasheets.
* STM32L0x1 erratasheet.
### [Ultra-low-power STM32L0x3 advanced Arm®-based 32-bit MCUs](https://www.st.com/resource/en/reference_manual/dm00095744-ultra-low-power-stm32l0x3-advanced-arm-based-32-bit-mcus-stmicroelectronics.pdf)
* RM0367 Reference manual
* Related documents
* Cortex®-M0+ Technical Reference Manual, available from www.arm.com.
* STM32L0 Series Cortex®-M0+ programming manual (PM0223).
* STM32L0x3 datasheets.
* STM32L0x3 erratasheet.
## 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 */
```
### GPIO setting
```=
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIOA pins Output : PA0 PA2 PA3 PA4 PA11 PA12*/
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_11|GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIOB pins : PB1 PB4 */
GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_4;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
```
### GPIO HI and LOW
```=
HAL_GPIO_WritePin(GOIOA, GPIO_PIN_3,GPIO_PIN_SET);
HAL_Delay(100);
HAL_GPIO_WritePin(GOIOA, GPIO_PIN_3,GPIO_PIN_RESET);
```
## System clock
### [RCC Firmware driver API description](https://www.st.com/resource/en/user_manual/dm00113898-description-of-stm32l0-hal-and-low-layer-drivers-stmicroelectronics.pdf)
#### Initialization and de-initialization functions
* 54.2.2 or 379
1. MSI (Multispeed internal): 提供七個頻率範圍:65.536 kHz、131.072kHz、262.144 kHz、524.288 kHz、1.048 MHz、2.097 MHz(默認值)和 4.194 MHz。
2. HSI (High-speed internal): 16 MHz factory-trimmed RC 直接或通過 PLL 用System clock 。
3. LSI (low-speed internal): 37 KHz 低功耗 RC 用作 IWDG and RTC clock。
4. HSE (High-speed external): 1 到 24 MHz 晶振直接使用或通過PLL system Clock。 也可用作 RTC Clock。
5. LSE (low-speed external):32 KHz 振盪器用作 RTC Clock。
6. PLL (clocked by HSI or HSE), featuring different output clocks:
* 第一個輸出用於生成 high speed system clock(高達 32 MHz)
* 第二個輸出用於生成 USB OTG FS (48 MHz) 的時鐘
7. CSS (Clock security system): _HAL_RCC_CSS_ENABLE() 啟用,如果發生 HSE Clock故障(HSE 直接使用或通過 PLL 作為System Clock),系統時鐘會自動切換到 MSI,如果啟用則生成中斷。中斷鍊接到 Cortex-M0+ NMI(不可屏蔽中斷)異常向量。
8. MCO1/MCO2/MCO3 (microcontroller clock output): 用於在 PA8/PA9/PB13 引腳上輸出 SYSCLK、HSI、LSI、MSI、LSE、HSE、HSI48 或 PLL 時鐘(通過可配置的預分頻器)
### STM32 system clock 可透過內部震盪,外部震盪就可以省略
```=
/******************************************************************************
* @brief System Clock Configuration
* The system Clock is configured as follow :
* System Clock source = PLL (HSI)
* SYSCLK(Hz) = 32000000
* HCLK(Hz) = 32000000
* AHB Prescaler = 1
* APB1 Prescaler = 1
* APB2 Prescaler = 1
* HSI Frequency(Hz) = 16000000
* PLL_MUL = 4
* PLL_DIV = 2
* Flash Latency(WS) = 1
* Main regulator output voltage = Scale1 mode
* I2C1Clock = 1
* Usart1Clock = 2
* @param None
* @retval None
******************************************************************************/
```
### MSI
#### MSI 2.097
```=
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** 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_5;
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_0) != HAL_OK)
{
Error_Handler();
}
```
### HSI
#### HSI 16M
```=
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** 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();
}
```
### LSI
#### LSI + HSE
* stm32l0xx_hal_conf.h
```=
#if !defined (HSE_VALUE)
#define HSE_VALUE ((uint32_t)12000000U) /*!< Value of the External oscillator in Hz */
#endif /* HSE_VALUE */
```
```=
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI|RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.LSIState = RCC_LSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLLMUL_8;
RCC_OscInitStruct.PLL.PLLDIV = RCC_PLLDIV_3;
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;
```
### HSE
#### HSE 25
* 開啟外部震盪 25M
* stm32l0xx_hal_conf.h
```=
#if !defined (HSE_VALUE)
#define HSE_VALUE ((uint32_t)25000000U) /*!< Value of the External oscillator in Hz */
#endif /* HSE_VALUE */
```
```=
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** Configure the main internal regulator output voltage
*/
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** 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_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_HSE;
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_1) != HAL_OK)
{
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_I2C1;
PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
PeriphClkInit.I2c1ClockSelection = RCC_I2C1CLKSOURCE_PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
```
### PLLCLK
#### PLLCLK 24 Mhz
* 外部震盪 8MHZ
* stm32l0xx_hal_conf.h
```=
#if !defined (HSE_VALUE)
#define HSE_VALUE ((uint32_t)8000000U) /*!< Value of the External oscillator in Hz */
#endif /* HSE_VALUE */
```
```=
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** 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.PLLMUL = RCC_PLLMUL_3;
RCC_OscInitStruct.PLL.PLLDIV = RCC_PLLDIV_2;
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_1) != HAL_OK)
{
Error_Handler();
}
```
#### PLLCLK 32MHZ
```=
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.PLLMUL = RCC_PLLMUL_4;
RCC_OscInitStruct.PLL.PLLDIV = RCC_PLLDIV_2;
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;
```
## 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資料暫存器的值

* STM32L051C8TC: Vref = Vdda (每一顆IC都不一樣需要核對)
* 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 需帶入暫存器,數值。

### ADC 設定解說
```=
hadc.Instance = ADC1; 設定ADC暫存器初始值
hadc.Init.OversamplingMode = DISABLE; 建議DISABLE,如果沒有正常轉換數值才需要ENABLE
hadc.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV1;
hadc.Init.Resolution = ADC_RESOLUTION_12B; //使用12BIT 讀取
hadc.Init.SamplingTime = ADC_SAMPLETIME_7CYCLES_5; //如果是使用12BIT,ADC採樣時間 建議使用 7.5 CYCLES 以上
hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD; //channel 0 to channel 18
hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT; //轉換結果資料對齊模式,可選右對齊ADC_DataAlign_Right或者左對齊 ADC_DataAlign_Left。一般我們選擇右對齊模式。
hadc.Init.ContinuousConvMode = DISABLE; // 要連續讀取多通道,使用DISABLE
hadc.Init.DiscontinuousConvMode = DISABLE; //如上
hadc.Init.DMAContinuousRequests = DISABLE; //關閉,使DMA如下
```
### DMA 設定解說
* ADC DMA功能,DMA是記憶體到記憶體或記憶體到儲存的直接對映,資料不用經過微控制器處理器而直接由硬體進行資料的傳遞。方便直接將讀取的ADC值放到記憶體變數中。
```=
hdma_adc.Instance = DMA1_Channel1; //設定DMA暫存器初始值
hdma_adc.Init.Request = DMA_REQUEST_0; //指定為指定通道選擇的請求
hdma_adc.Init.Direction = DMA_PERIPH_TO_MEMORY; //指定數據是從內存傳輸到外設、從內存傳輸到內存還是從外設傳輸到內存
hdma_adc.Init.PeriphInc = DMA_PINC_DISABLE; //指定外設地址寄存器是否應該遞增
hdma_adc.Init.MemInc = DMA_MINC_ENABLE; //指定內存地址寄存器是否應該遞增
hdma_adc.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; //指定外設數據寬度
hdma_adc.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; //指定內存數據寬度
hdma_adc.Init.Mode = DMA_NORMAL; //如果在選定的 Channel 上配置了內存到內存的數據傳輸,則無法使用循環緩沖模式
hdma_adc.Init.Priority = DMA_PRIORITY_HIGH; //指定 DMAy Channelx 的軟件優先級
```
```
mode:模式
Normal:正常模式,當一次DMA資料傳輸完後,停止DMA傳送 ,也就是隻傳輸一次
Circular: 迴圈模式,傳輸完成後又重新開始繼續傳輸,不斷迴圈永不停止
data width:資料寬度
byte:位元組,通用8位,與u8相同
word:字長,與硬體的位數相同,STM32是32位,所以對應是u32
Half Word:半個字長,所以對應是u16
```
### Setting ADC
```=
/* ### - 1 - Initialize ADC peripheral #################################### */
/*
* Instance = ADC1.
* OversamplingMode = Disabled
* ClockPrescaler = PCLK clock with no division.
* LowPowerAutoPowerOff = Disabled (For this exemple continuous mode is enabled with software start)
* LowPowerFrequencyMode = Enabled (To be enabled only if ADC clock is lower than 2.8MHz)
* LowPowerAutoWait = Disabled (New conversion starts only when the previous conversion is completed)
* Resolution = 12 bit (increased to 16 bit with oversampler)
* SamplingTime = 7.5 cycles od ADC clock.
* ScanConvMode = Forward
* DataAlign = Right
* ContinuousConvMode = Enabled
* DiscontinuousConvMode = Enabled
* ExternalTrigConvEdge = None (Software start)
* EOCSelection = End Of Conversion event
* DMAContinuousRequests = ENABLE
*/
```
```=
void hal_adc_init(void){
uint16_t Calibration = 0;
__HAL_RCC_ADC1_CLK_ENABLE();
/* USER CODE END ADC_Init 1 */
/** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)*/
hadc.Instance = ADC1;
hadc.Init.OversamplingMode = DISABLE;
hadc.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV1;
hadc.Init.Resolution = ADC_RESOLUTION_12B;
hadc.Init.SamplingTime = ADC_SAMPLETIME_19CYCLES_5;
hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;
hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc.Init.ContinuousConvMode = DISABLE;
hadc.Init.DiscontinuousConvMode = DISABLE;
hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc.Init.DMAContinuousRequests = DISABLE;
hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED;
hadc.Init.LowPowerAutoWait = DISABLE;
hadc.Init.LowPowerFrequencyMode = ENABLE;
hadc.Init.LowPowerAutoPowerOff = DISABLE;
if (HAL_ADC_Init(&hadc) != HAL_OK){
Error_Handler();
}
HAL_ADCEx_Calibration_Start(&hadc,ADC_SINGLE_ENDED);
Calibration = HAL_ADC_GetValue(&hadc);
sConfig.Channel = ADC_CHANNEL_6|ADC_CHANNEL_7;
sConfig.Rank = ADC_RANK_NONE;
if(HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK){
Error_Handler();
}
}
```
### GET ADC
* 透過這函數進行讀取ADC數值
* HAL_ADC_GetValue(&hadc)
```=
uint32_t read_adc_value(uint32_t CH){
uint32_t adc_conv_var;
sConfig.Channel = CH;
sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
HAL_ADC_ConfigChannel(&hadc, &sConfig);
HAL_ADC_Start(&hadc);
HAL_ADC_Start_DMA(&hadc,&adc_conv_var, 2); //開啟DMA
HAL_ADC_PollForConversion(&hadc,1000);
adc_conv_var = HAL_ADC_GetValue(&hadc);
sConfig.Rank = ADC_RANK_NONE;
HAL_ADC_ConfigChannel(&hadc, &sConfig);
return adc_conv_var;
}
```
### GET Vref and VDD
```=
void Verf_vdd(void){
unsigned int u16rawCnt;
unsigned int u16VREFINT_CAL;
unsigned int u32VrefVolt;
unsigned int u32VddVolt;
u16VREFINT_CAL=*(uint16_t *)0x1FF80078;
printf("u16VREFINT_CAL =%d\r\n",u16VREFINT_CAL);
u32VrefVolt=(u16VREFINT_CAL*3000)/4096;
printf("Vref =%d mv\r\n",u32VrefVolt);
u16rawCnt=read_adc_value(ADC_CHANNEL_7);
printf("Vref Raw= %d \r\n",u16rawCnt);
u32VddVolt=(u32VrefVolt*4096)/(u16rawCnt);
printf("Vdd Volt= %.2f \r\n",u32VddVolt);
}
```
## DAC(Digital-To-Analog Conversion)
* DAC 是一種將數字轉換為模擬信號的設備,該模擬信號與提供的參考電壓 VREF 成正比(參見圖 1)。有許多類別的 DAC。其中一些包括脈衝寬度調製器 (PWM)、內插、sigma-delta DAC 和高速 DAC。我們在第 11 章中分析瞭如何使用 STM32 定時器來生成 PWM 信號,並且我們已經使用此功能在 RC 低通濾波器的幫助下生成輸出正弦波


* 列出了配備我們在本書中考慮的 16 個 Nucleo 板的所有 STM32 MCU 的 DAC 外設及其相關輸出通道的確切數量。

* DMA_Handle{1,2}:這是指向配置為在 DMA 模式下執行 D/A 轉換的 DMA 處理程序的指針。在具有兩個輸出通道的 DAC 中,存在兩個獨立的 DMA 處理程序,用於為每個通道執行轉換
### Setting DAC
```=
void hal_dac_Init(void) {
__HAL_RCC_DAC_CLK_ENABLE();
hdac.Instance = DAC;
if (HAL_DAC_Init(&hdac) != HAL_OK) {
Error_Handler();
}
/** DAC channel OUT1 config */
sConfig.DAC_Trigger = DAC_TRIGGER_T3_CH3;
sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
if (HAL_DAC_ConfigChannel(&hdac, &sConfig, DAC_CHANNEL_1) != HAL_OK) {
Error_Handler();
}
/** DAC channel OUT2 config */
sConfig.DAC_Trigger = DAC_TRIGGER_T6_TRGO;
if (HAL_DAC_ConfigChannel(&hdac, &sConfig, DAC_CHANNEL_2) != HAL_OK) {
Error_Handler();
}
}
```
### GET DAC
```=
uint32_t read_dac_value(uint32_t value) {
uint32_t value;
value = HAL_DAC_SetValue(&hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, value);
HAL_DAC_Start(&hdac, DAC_CHANNEL_1);
//HAL_DAC_Start_DMA(&hdac ,&sConfig , DAC_CHANNEL_1); /* open DMA conversion*/
return value;
// HAL_DAC_Stop(&hdac, DAC_CHANNEL_1);
}
```
## Timers(TIM)
* STM32L051C8T6有5個計數器
* 通用計數器(TIM2、TIM21、TIM22)。
* 基本計數器(TIM6),低功號計數器(LPTIM1)。
* STM32各系列timers如下圖分佈

* STM32 Timers 最大週期 65535
* 可透過以下公式進行換算
* Core: Arm® 32-bit Cortex®-M0+ with MPU
* From 32 kHz up to 32 MHz max. 0.95 DMIPS/MHz
* STM32L051C8T6 32MHZ 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) ÷ 頻率 单位:秒
* Timer setting
```=
#define SYS_CLK 32000000
#define DELAY_TIM_FREQUENCY 1000000 // = 1MHZ -> timer runs in microseconds
void MX_TIM2_Init(void){
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
htim2.Instance = TIM2;
htim2.Init.Period = 65535;
htim2.Init.Prescaler = (SYS_CLK / DELAY_TIM_FREQUENCY) - 1; ;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM2_Init 2 */
/* USER CODE END TIM2_Init 2 */
}
```
```=
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_11);
}
```
## UART
### uart_printf
* setting printf, use single write

#### uart clock
* board_sysinit.c
```=
#if 0
/* UART CLOCK*/
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1;
PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK){
Error_Handler();
}
#endif
```
#### function name
* uart_printf.c ---> hal_uart.c
```=
hal_uart_Init();
hal_uart2_Init();
```
* stm32l0xx_hal_msp.c ---> hal_uart.c
```=
void HAL_UART_MspInit(UART_HandleTypeDef* huart)
void HAL_UART_MspDeInit(UART_HandleTypeDef* huart)
```
* stm32l0xx_hal_conf.h
```=
#define HAL_UART_MODULE_ENABLED
```
#### setting uart function,code in main
```=
/********************************************
* Copyright (c)
* File name : uart_printf.c
* Author : Barry.Chung
* Version : 1.0
* Date : 2021.4.16
* Description : Configure STM32L051X peripherals.
* Function List:
********************************************/
#include "main.h"
UART_HandleTypeDef uart_deg;
static void hal_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 hal_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();
}
}
#### setting uart pin
```=
void HAL_UART_MspInit(UART_HandleTypeDef* huart)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(huart->Instance==USART1) {
/* Peripheral clock enable */
__HAL_RCC_USART1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/**USART1 GPIO Configuration
PA9 ------> USART1_TX
PA10 ------> USART1_RX
*/
GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF4_USART1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
}
/**
* @brief UART MSP De-Initialization
* This function freeze the hardware resources used in this example
* @param huart: UART handle pointer
* @retval None
*/
void HAL_UART_MspDeInit(UART_HandleTypeDef* huart)
{
if(huart->Instance==USART1) {
/* Peripheral clock disable */
__HAL_RCC_USART1_CLK_DISABLE();
/**USART1 GPIO Configuration
PA9 ------> USART1_TX
PA10 ------> USART1_RX
*/
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10);
}
}
```
## I2C
### STM32L051C8T6
* 2kHZ I2C Clocke speed
* 100khz ===> hi2c1.Init.Timing = 0x00000708;
* 400khz ===> hi2c1.Init.Timing = 0x00000000;
* 1000khz ===> hi2c2.Init.Timing = 0x00000000;
* 16MHZ I2C Clocke speed
* 100khz ===> hi2c1.Init.Timing = 0x00303D5B;
* 400khz ===> hi2c1.Init.Timing = 0x0010061A;
* 24MHZ I2c Clocke speed
* 100khz ===> hi2c1.Init.Timing = 0x00506682;
* 400khz ===> hi2c1.Init.Timing = 0x00200C28;
* 1000khz ===> hi2c2.Init.Timing = 0x0010030D;
* 32MHZ I2C Clocke speed
* 100khz ===> hi2c1.Init.Timing = 0x10A13E56;
* 400khz ===> hi2c1.Init.Timing = 0x00B1112E;
* 1000khz ===> hi2c2.Init.Timing = 0x00100413;

### I2C API
* I2C(I2C BUS、I2C Device address、Data Buffer、Data size、 Timout)
*
### Open I2C slave Callback
```
HAL_I2C_MasterTxCpltCallback() I2Cx_EV_IRQHandler() Signals that the transfer from master to slave is completed (peripheral working in master mode).
HAL_I2C_MasterRxCpltCallback() I2Cx_EV_IRQHandler() Signals that the transfer from slave to master is completed (peripheral working in master mode).
HAL_I2C_SlaveTxCpltCallback() I2Cx_EV_IRQHandler() Signals that the transfer from slave to master is completed (peripheral working in slave mode).
HAL_I2C_SlaveRxCpltCallback() I2Cx_EV_IRQHandler() Signals that the transfer from master to slave is completed (peripheral working in slave mode).
HAL_I2C_MemTxCpltCallback() I2Cx_EV_IRQHandler() Signals that the transfer from master to an external memory is completed (this is called only when HAL_I2C_Mem_xxx()
routines are used and the peripheral works in master mode).
```
* I2c slave need open Callback,Cause i2c slave can not be operated.
* Core\Inc\stm32l0xx_hal_conf.h
```
#define USE_HAL_I2C_REGISTER_CALLBACKS 1U
```
* API stm32l0xx_hal_i2c.h
- If it is opened, as shown below


## [DMA](https://adammunich.com/stm32-dma-cheat-sheet/)
* The Direct Memory Access (DMA) 控制器是一個專用的可編程硬件單元,它允許 MCU 外部訪問內部暫儲器,而無需 Cortex-M 內核的干預。CPU 完全擺脫了數據傳輸產生的效能(與 DMA 配置相關的效能分開),它可以並行執行其他活動。 DMA 被設計成以兩種方式工作(即它允許數據從存儲器傳輸到外設,反之亦然),所有 STM32 MCU都提供至少一個 DMA 控制器,M0以上是兩個獨立的DMA。


### DMA 原理
* Cortex-M 內核和 DMA1 控制器都與其他 MCU 外設交互通過一系列Bus。如果仍然不清楚,重要的是要注意flash和SRAM暫儲器是 MCU 內核之外的元件,因此它們需要相互交互其他通過總線互連。
* Cortex-M 內核和 DMA1 控制器都是主機。這意味著他們是唯一的可以在總線上啟動事務的單元。但是,必須規範對總線的訪問這樣他們就不能同時訪問同一個從外圍設備。
* BusMatrix 管理 Cortex-M 內核與 DMA1 之間的訪問仲裁控制器。仲裁使用循環算法來控制對總線的訪問。這BusMatrix 由兩個主機(CPU、DMA)和四個從機(flash、SRAM、AHB1 帶有 AHB 到高級外部總線 (APB) 橋接器和 AHB2)。 BusMatrix 也允許在它們之間自動互連多個外部設備。
* 系統總線將 Cortex-M 內核連接到 BusMatrix。
* DMA 總線將 DMA 的高級高性能總線 (AHB) 主接口連接到 BusMatrix。
* AHB 到 APB 橋接器提供了 AHB 和 APB 總線之間的完全同步連接,其中連接了大多數外部設備

* 在CPU跟SARM是分開設計
1. 周邊到記憶體 Peripheral To Memory
2. 記憶體到周邊 Memory To Peripheral
3. 記憶體到記憶體 Memory To Memory
4. 周邊到周邊 Peripheral To Peripheral

## Flash
### [切割flash and RAM](https://www.pcbway.com/blog/technology/STM32_Blue_Pill___Analyse_and_Optimise_Your_RAM_and_ROM.html)
* STM32L051C8TX_FLASH.ld
* L0 系列太小建議不要切割,除非選用64k以上Flash空間
```=
/* Memories definition */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 8K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 64K
}
```
## Reference
* [STM32L051使用HAL库操作实例(8)-(TIM)定时器中断实验](https://blog.csdn.net/cheng_nnan/article/details/105581022)
* [STM32L051使用HAL库操作实例(5)-外部中断实验](https://blog.csdn.net/cheng_nnan/article/details/105555972?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162071198316780357298483%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=162071198316780357298483&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_v2~rank_v29-8-105555972.pc_search_result_cache&utm_term=STM32L0+%E6%8C%89%E9%94%AE%E4%B8%AD%E6%96%AD)
### ADC
* [STM32L0系列之ADC采集](https://blog.csdn.net/meng5670/article/details/90409475?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162122774416780366586455%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=162122774416780366586455&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-90409475.first_rank_v2_pc_rank_v29&utm_term=stm32l0+adc)
#### ADC + DMA
* [STM32 ADC(单通道、多通道、基于DMA)](https://blog.csdn.net/weixin_42653531/article/details/81123770?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162149608416780262545330%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=162149608416780262545330&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_v2~rank_v29-4-81123770.first_rank_v2_pc_rank_v29&utm_term=stm32l0+adc+%E5%A4%9A%E9%80%9A%E9%81%93)
* [STM32 - Working with ADC and DMA](https://www.digikey.com/en/maker/projects/getting-started-with-stm32-working-with-adc-and-dma/f5009db3a3ed4370acaf545a3370c30c)
### DAC
* [STM32-DAC 使用方法](https://blog.csdn.net/u014470361/article/details/78801826?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165303129116780357256225%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=165303129116780357256225&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~baidu_landing_v2~default-2-78801826-null-null.142^v10^pc_search_result_control_group,157^v4^control&utm_term=STM32L051+DAC)
* [STM32 基础系列教程 31 – DAC](https://blog.csdn.net/zhanglifu3601881/article/details/89919992)
### Timers
* [STM32L051使用HAL库操作实例(8)-(TIM)定时器中断实验](https://blog.csdn.net/cheng_nnan/article/details/105581022?ops_request_misc=&request_id=&biz_id=102&utm_term=STM32L0%20%E8%A8%88%E6%95%B8%E5%99%A8&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-6-.pc_search_result_before_js)
* [STM32 TIME 函數介紹](https://blog.csdn.net/qq_17525633/article/details/115873322)
* [STM32 timers 公式計算](https://www.cnblogs.com/zhx831/p/3249682.html)
### I2C
* [Implementation of HAL library i2c slave of stm32](https://programming.vip/docs/implementation-of-hal-library-i2c-slave-of-stm32.html)
### DMA
* [STM32 DMA](https://adammunich.com/stm32-dma-cheat-sheet/)
### 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)
### EEPROM
* [STM32L0系列之【EEPROM读写】](https://blog.csdn.net/qq_23327993/article/details/103135400)