STM32 Ecosystem workshop
T.O.M.A.S Team
STM32 Ecosystem workshop T.O.M.A.S Team 2 We will continue a bit - - PowerPoint PPT Presentation
STM32 Ecosystem workshop T.O.M.A.S Team 2 We will continue a bit more with software activities. Lets try to rewrite our L4_DAC_ADC application using Low Layer libraries. In this step we will create an empty STM32CubeMX template and
T.O.M.A.S Team
try to write complete application (except clock configuration) using only Low Layer library. Then we will compare the code size
manual configuration steps)
2
added manually in software)
4
5
80 PLLCLK HSI
6
7
STM32 snippets
Init functions Unitary functions LL Drivers
Standard peripheral library HAL Drivers
8
stm32l4xx_ll_adc.c stm32l4xx_ll_dac.c stm32l4xx_ll_dma.c stm32l4xx_ll_gpio.c stm32l4xx_ll_rcc.c stm32l4xx_ll_tim.c
stm32l4xx_ll_adc.h stm32l4xx_ll_bus.h stm32l4xx_ll_dac.h stm32l4xx_ll_dma.h stm32l4xx_ll_gpio.h stm32l4xx_ll_rcc.h stm32l4xx_ll_tim.h
$PROJ_DIR\Drivers\STM32L4xx_HAL_Driver\Src\ $PROJ_DIR\Drivers\STM32L4xx_HAL_Driver\Inc\
1. Select project 2. Menu>Project>Properties>C/C++ Build>Settings 3. MCU GCC Compiler>Symbols 4. Add … 5. Define USE_FULL_LL_DRIVER to allow use of LL library It will allow us to use the Init…() functions like in Standard Peripherals Library (SPL) 9
1 2 3 4 5
Within main.c file perform the following actions
1. Include necessary low layer header files. 2. Declare initialization structures for used peripherals and buffers for DAC and ADC. 3. Initialize peripherals one by one (mind to connect the clock to the peripheral first). 4. Start the peripheral using low layer functions.
As a reference please use already copied header and source files for low layer part of the library.
10
/* USER CODE BEGIN Includes */ #include "stm32l4xx_ll_???.h" … … … … … … /* USER CODE END Includes */ 11
/* USER CODE BEGIN Includes */ #include "stm32l4xx_ll_adc.h" #include "stm32l4xx_ll_dac.h" #include "stm32l4xx_ll_dma.h" #include "stm32l4xx_ll_gpio.h" #include "stm32l4xx_ll_rcc.h" #include "stm32l4xx_ll_tim.h" #include "stm32l4xx_ll_bus.h" /* USER CODE END Includes */ 12
/* USER CODE BEGIN PV */ /* Private variables ---------------------------------------------------------*/ LL_GPIO_InitTypeDef GPIO_InitStruct; //GPIO init structure LL_TIM_InitTypeDef TIM2_InitStruct; //TIM2 init structure LL_TIM_OC_InitTypeDef TIM2_OCInitStruct; //TIM2 OC init structure LL_DAC_InitTypeDef DAC_InitStruct; //DAC init structure LL_ADC_InitTypeDef ADC_InitStruct; //ADC init structure LL_ADC_CommonInitTypeDef ADC_ComInitStruct; //ADC common init structure LL_ADC_REG_InitTypeDef ADC_RegInitStruct; //ADC regular conversion init structure LL_DMA_InitTypeDef DMA_DAC_InitStruct; //DMA init structure LL_DMA_InitTypeDef DMA_ADC_InitStruct; //DMA init structure /* USER CODE END PV */ 13
should be configured in (i.e. Output Capture, Input Capture for timers etc.).
/* USER CODE BEGIN PV */ /* Private variables ---------------------------------------------------------*/ LL_GPIO_InitTypeDef GPIO_InitStruct; //GPIO init structure LL_TIM_InitTypeDef TIM2_InitStruct; //TIM2 init structure LL_TIM_OC_InitTypeDef TIM2_OCInitStruct; //TIM2 OC init structure LL_DAC_InitTypeDef DAC_InitStruct; //DAC init structure LL_ADC_InitTypeDef ADC_InitStruct; //ADC init structure LL_ADC_CommonInitTypeDef ADC_ComInitStruct; //ADC common init structure LL_ADC_REG_InitTypeDef ADC_RegInitStruct; //ADC regular conversion init structure LL_DMA_InitTypeDef DMA_DAC_InitStruct; //DMA init structure LL_DMA_InitTypeDef DMA_ADC_InitStruct; //DMA init structure /* USER CODE END PV */ 14
should be configured in (i.e. Output Capture, Input Capture for timers etc.).
/* USER CODE BEGIN PV */ /* Private variables ---------------------------------------------------------*/ #define ADCBUFSIZE 32 #define DACBUFSIZE 32 const uint16_t dacbuf[DACBUFSIZE] = { 2047, 2447, 2831, 3185, 3498, 3750, 3939, 4056, 4095, 4056, 3939, 3750, 3495, 3185, 2831, 2447, 2047, 1647, 1263, 909, 599, 344, 155, 38, 0, 38, 155, 344, 599, 909, 1263, 1647}; uint32_t adcbuf[ADCBUFSIZE]; /* USER CODE END PV */ 15
the measured data (adcbuf[]). Size for both can be 32.
/* USER CODE BEGIN PV */ /* Private variables ---------------------------------------------------------*/ #define ADCBUFSIZE 32 #define DACBUFSIZE 32 const uint16_t dacbuf[DACBUFSIZE] = { 2047, 2447, 2831, 3185, 3498, 3750, 3939, 4056, 4095, 4056, 3939, 3750, 3495, 3185, 2831, 2447, 2047, 1647, 1263, 909, 599, 344, 155, 38, 0, 38, 155, 344, 599, 909, 1263, 1647}; uint16_t adcbuf[ADCBUFSIZE]; /* USER CODE END PV */ 16
the measured data (adcbuf[]). Size for both can be 32.
/* USER CODE BEGIN 2 */ /* GPIO LL configuration */ __HAL_RCC_GPIOA_CLK_ENABLE(); //enable clock to the GPIOA peripheral LL_GPIO_StructInit(&GPIO_InitStruct); //structure initialization to default values GPIO_InitStruct.Pin= GPIO_PIN_1 | GPIO_PIN_4; //set pin 1 (ADC_IN6), 4 (DAC_OUT1) GPIO_InitStruct.Mode= LL_GPIO_MODE_ANALOG; //set GPIO as analog mode GPIO_InitStruct.Pull= LL_GPIO_PULL_NO; //no pull up or pull down LL_GPIO_Init(GPIOA,&GPIO_InitStruct); //initialize GPIOA, pins 1 and 4 17 The task is to configure 2 analog pins (PA1 – ADC1 Channel6 and PA4 – DAC output1) 1. Before PPP configuration it is necessary to connect the clock to the PPP peripheral. To do this we can use there dedicated macro: __HAL_RCC_PPP_CLK_ENABLE() 2. Initialize PPP init structure with default values using LL_PPP_StructInit() 3. Fill PPP init structure with required configuration parameters 4. Copy structure fields into PPP (GPIO in this case) registers using LL_PPP_Init() function (like in Standard Peripherals Library or in HAL library) 5. Connect GPIO analog switch to ADC input using LL_GPIO_EnablePinAnalogControl() function
/* USER CODE BEGIN 2 */ /* GPIO LL configuration */ __HAL_RCC_GPIOA_CLK_ENABLE(); //enable clock to the GPIOA peripheral LL_GPIO_StructInit(&GPIO_InitStruct); //structure initialization to default values GPIO_InitStruct.Pin= GPIO_PIN_1 | GPIO_PIN_4; //set pin 1 (ADC_IN6), 4 (DAC_OUT1) GPIO_InitStruct.Mode= LL_GPIO_MODE_ANALOG; //set GPIO as analog mode GPIO_InitStruct.Pull= LL_GPIO_PULL_NO; //no pull up or pull down LL_GPIO_Init(GPIOA,&GPIO_InitStruct); //initialize GPIOA, pins 1 and 4 LL_GPIO_EnablePinAnalogControl(GPIOA, LL_GPIO_PIN_1); 18 The task is to configure 2 analog pins (PA1 – ADC1 Channel6 and PA4 – DAC output1) 1. Before PPP configuration it is necessary to connect the clock to the PPP peripheral. To do this we can use there dedicated macro: __HAL_RCC_PPP_CLK_ENABLE() 2. Initialize PPP init structure with default values using LL_PPP_StructInit() 3. Fill PPP init structure with required configuration parameters 4. Copy structure fields into PPP (GPIO in this case) registers using LL_PPP_Init() function (like in Standard Peripherals Library or in HAL library) 5. Connect GPIO analog switch to ADC input using LL_GPIO_EnablePinAnalogControl() function
1 2 3 4 5
/* USER CODE BEGIN 2 */ /* DAC LL configuration */ __HAL_RCC_DAC1_CLK_ENABLE(); //enable clock LL_DAC_StructInit(&DAC_InitStruct); DAC_InitStruct.TriggerSource = LL_DAC_TRIG_EXT_TIM2_TRGO; DAC_InitStruct.WaveAutoGeneration = LL_DAC_WAVE_AUTO_GENERATION_NONE; DAC_InitStruct.OutputBuffer = LL_DAC_OUTPUT_BUFFER_ENABLE; LL_DAC_Init(DAC1, LL_DAC_CHANNEL_1, &DAC_InitStruct); 19 The task is to configure DAC1, Channel1 to work without output buffer, triggered by Timer2 TRGO signal, without triangle nor noise wave generation 1. Before PPP configuration it is necessary to connect the clock to the PPP peripheral. To do this we can use there dedicated macro: __HAL_RCC_PPP_CLK_ENABLE() 2. Initialize PPP init structure with default values using LL_PPP_StructInit() 3. Fill PPP init structure with required configuration parameters 4. Copy structure fields into PPP (DAC in this case) registers using LL_PPP_Init() function (like in Standard Peripherals Library or in HAL library)
/* USER CODE BEGIN 2 */ /* DAC LL configuration */ __HAL_RCC_DAC1_CLK_ENABLE(); //enable clock LL_DAC_StructInit(&DAC_InitStruct); DAC_InitStruct.TriggerSource = LL_DAC_TRIG_EXT_TIM2_TRGO; DAC_InitStruct.OutputBuffer = LL_DAC_OUTPUT_BUFFER_ENABLE; LL_DAC_Init(DAC1, LL_DAC_CHANNEL_1, &DAC_InitStruct); 20 The task is to configure DAC1, Channel1 to work without output buffer, triggered by Timer2 TRGO signal, without triangle nor noise wave generation 1. Before PPP configuration it is necessary to connect the clock to the PPP peripheral. To do this we can use there dedicated macro: __HAL_RCC_PPP_CLK_ENABLE() 2. Initialize PPP init structure with default values using LL_PPP_StructInit() 3. Fill PPP init structure with required configuration parameters 4. Copy structure fields into PPP (DAC in this case) registers using LL_PPP_Init() function (like in Standard Peripherals Library or in HAL library)
1 2 3 4
21 The task is to configure ADC1, Channel 6 to work in regular continue mode with DMA support, triggered by Timer2 Output Compare event on channel2, with sampling time 12.5 ADC clk cycles. ADC should be clocked by PCLK/2 synchronous clock (40MHz in our case). 1. Before PPP configuration it is necessary to connect the clock to the PPP peripheral. To do this we can use there dedicated macro: __HAL_RCC_PPP_CLK_ENABLE() 2. Initialize proper PPP init structure(s) with default values using LL_PPP_StructInit(). In case of ADC we have 4 different structures:
a. LL_ADC_CommonInitTypeDef – configuration of common parameters for all ADCs (like input clock source) and multimode configuration b. LL_ADC_InitTypeDef – configuration of the particular ADC basic parameters c. LL_ADC_REG_InitTypeDef – configuration of the regular conversions d. LL_ADC_INJ_InitTypeDef – configuration of the injected conversions – NOT USED in the exercise
3. Fill proper PPP init structure(s) with desired configuration parameters 4. Copy structure fields into PPP (ADC in this case) registers using LL_PPP_Init() function (like in Standard Peripherals Library
22
The task is to configure ADC1, Channel 6 to work in regular continue mode with DMA support, triggered by Timer2 Output Compare event
1. At the beginning we should select system clock as clock source for ADC using LL_RCC_SetADCClockSource() function 2. Before PPP configuration it is necessary to connect the clock to the ADC1 peripheral. To do this we can use there dedicated macro: __HAL_RCC_ADC_CLK_ENABLE() 3. Initialize LL_ADC_CommonInitTypeDef structure (defining common settings for all ADCs and multimode configuration) with default values using LL_ADC_CommonStructInit(). 4. Fill LL_ADC_CommonInitTypeDef structure with desired configuration parameters (clock source for ADC) 5. Copy structure fields into ADC registers using LL_ADC_CommonInit() function
/* ADC LL configuration */ __HAL_RCC_ADC1_CLK_ENABLE();//enable clock LL_ADC_CommonStructInit(&ADC_ComInitStruct); ADC_ComInitStruct.CommonClock = LL_ADC_CLOCK_SYNC_PCLK_DIV2; LL_ADC_CommonInit(ADC1,&ADC_ComInitStruct);
23
The task is to configure ADC1, Channel 6 to work in regular continue mode with DMA support, triggered by Timer2 Output Compare event
1. At the beginning we should select system clock as clock source for ADC using LL_RCC_SetADCClockSource() function 2. Before PPP configuration it is necessary to connect the clock to the ADC1 peripheral. To do this we can use there dedicated macro: __HAL_RCC_ADC_CLK_ENABLE() 3. Initialize LL_ADC_CommonInitTypeDef structure (defining common settings for all ADCs and multimode configuration) with default values using LL_ADC_CommonStructInit(). 4. Fill LL_ADC_CommonInitTypeDef structure with desired configuration parameters (clock source for ADC) 5. Copy structure fields into ADC registers using LL_ADC_CommonInit() function
/* ADC LL configuration */ LL_RCC_SetADCClockSource(LL_RCC_ADC_CLKSOURCE_SYSCLK); __HAL_RCC_ADC_CLK_ENABLE();//enable clock LL_ADC_CommonStructInit(&ADC_ComInitStruct); ADC_ComInitStruct.CommonClock = LL_ADC_CLOCK_SYNC_PCLK_DIV2; LL_ADC_CommonInit(ADC1,&ADC_ComInitStruct);
1 2 3 4 5
24
The task is to configure ADC1, Channel 6 to work in regular continue mode with DMA support, triggered by Timer2 Output Compare event on channel2, with sampling time 12.5 ADC clk cycles. ADC should be clocked by PCLK/2 synchronous clock (40MHz in our case). 1. Initialize LL_ADC_InitTypeDef structure (defining general settings for particular ADC) with default values using LL_ADC_StructInit(). 2. Fill LL_ADC_InitTypeDef structure with desired configuration parameters (clock source for ADC) 3. Copy structure fields into ADC registers using LL_ADC_Init() function
LL_ADC_StructInit(&ADC_InitStruct); ADC_InitStruct.Resolution = LL_ADC_RESOLUTION_12B ; ADC_InitStruct.DataAlignment = LL_ADC_DATA_ALIGN_RIGHT; ADC_InitStruct.LowPowerMode = LL_ADC_LP_MODE_NONE; LL_ADC_Init(ADC1,&ADC_InitStruct);
25
The task is to configure ADC1, Channel 6 to work in regular continue mode with DMA support, triggered by Timer2 Output Compare event on channel2, with sampling time 12.5 ADC clk cycles. ADC should be clocked by PCLK/2 synchronous clock (40MHz in our case). 1. Initialize LL_ADC_InitTypeDef structure (defining general settings for particular ADC) with default values using LL_ADC_StructInit(). 2. Fill LL_ADC_InitTypeDef structure with desired configuration parameters (clock source for ADC) 3. Copy structure fields into ADC registers using LL_ADC_Init() function
LL_ADC_StructInit(&ADC_InitStruct); ADC_InitStruct.Resolution = LL_ADC_RESOLUTION_12B ; ADC_InitStruct.DataAlignment = LL_ADC_DATA_ALIGN_RIGHT; ADC_InitStruct.LowPowerMode = LL_ADC_LP_MODE_NONE; LL_ADC_Init(ADC1,&ADC_InitStruct);
1 2 3
26
The task is to configure ADC1, Channel 6 to work in regular continue mode with DMA support, triggered by Timer2 Output Compare event on channel2, with sampling time 12.5 ADC clk cycles. ADC should be clocked by PCLK/2 synchronous clock (40MHz in our case). 1. Initialize LL_ADC_REG_InitTypeDef structure (defining regular conversion parameters) with default values using LL_ADC_REG_StructInit(). 2. Fill LL_ADC_REG_InitTypeDef structure with desired configuration parameters (clock source for ADC) 3. Copy structure fields into ADC registers using LL_ADC_REG_Init() function
LL_ADC_REG_StructInit(&ADC_RegInitStruct); ADC_RegInitStruct.TriggerSource = LL_ADC_REG_TRIG_EXT_TIM2_CH2; ADC_RegInitStruct.SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_DISABLE; ADC_RegInitStruct.ContinuousMode = LL_ADC_REG_CONV_SINGLE; ADC_RegInitStruct.DMATransfer = LL_ADC_REG_DMA_TRANSFER_UNLIMITED; ADC_RegInitStruct.Overrun = LL_ADC_REG_OVR_DATA_PRESERVED; LL_ADC_REG_Init(ADC1,&ADC_RegInitStruct);
27
The task is to configure ADC1, Channel 6 to work in regular continue mode with DMA support, triggered by Timer2 Output Compare event on channel2, with sampling time 12.5 ADC clk cycles. ADC should be clocked by PCLK/2 synchronous clock (40MHz in our case). 1. Initialize LL_ADC_REG_InitTypeDef structure (defining regular conversion parameters) with default values using LL_ADC_REG_StructInit(). 2. Fill LL_ADC_REG_InitTypeDef structure with desired configuration parameters (clock source for ADC) 3. Copy structure fields into ADC registers using LL_ADC_REG_Init() function
LL_ADC_REG_StructInit(&ADC_RegInitStruct); ADC_RegInitStruct.TriggerSource = LL_ADC_REG_TRIG_EXT_TIM2_CH2; ADC_RegInitStruct.SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_DISABLE; ADC_RegInitStruct.SequencerLength = LL_ADC_REG_SEQ_SCAN_DISABLE; ADC_RegInitStruct.ContinuousMode = LL_ADC_REG_CONV_SINGLE; ADC_RegInitStruct.DMATransfer = LL_ADC_REG_DMA_TRANSFER_UNLIMITED; ADC_RegInitStruct.Overrun = LL_ADC_REG_OVR_DATA_PRESERVED; LL_ADC_REG_Init(ADC1,&ADC_RegInitStruct);
1 2 3
LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_6 , LL_ADC_SAMPLINGTIME_12CYCLES_5); LL_ADC_SetChannelSingleDiff(ADC1, LL_ADC_CHANNEL_6, LL_ADC_SINGLE_ENDED ); 28
The task is to configure ADC1, Channel 6 to work in regular continue mode with DMA support, triggered by Timer2 Output Compare event on channel2, with sampling time 12.5 ADC clk cycles. ADC should be clocked by PCLK/2 synchronous clock (40MHz in our case). 1. Configure trigger edge to rising using LL_ADC_REG_SetTriggerEdge() function 2. Configure the sequencer to: a. setting the order of the channels to be converted (in our case single channel 6) b. select sampling time for each channel There is a single function to set both parameters: LL_ADC_SetChannelSamplingTime() 3. After the reset ADC is in deep power down mode. It is necessary to disable this mode using LL_ADC_DisableDeepPowerDown() function 4. Further we need to enable ADC internal voltage regulator using LL_ADC_EnableInternalRegulator() function and wait for it stabilization (implement your own delay() function)
LL_ADC_REG_SetTriggerEdge(ADC1,LL_ADC_REG_TRIG_EXT_RISING); LL_ADC_REG_SetSequencerRanks(ADC1,LL_ADC_REG_RANK_1,LL_ADC_CHANNEL_6); LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_6 , LL_ADC_SAMPLINGTIME_12CYCLES_5); LL_ADC_DisableDeepPowerDown(ADC1); LL_ADC_EnableInternalRegulator(ADC1); //wait 20us for internal regulator stabilization 29
b a 1 2
The task is to configure ADC1, Channel 6 to work in regular continue mode with DMA support, triggered by Timer2 Output Compare event on channel2, with sampling time 12.5 ADC clk cycles. ADC should be clocked by PCLK/2 synchronous clock (40MHz in our case). 1. Configure trigger edge to rising using LL_ADC_REG_SetTriggerEdge() function 2. Configure the sequencer to: a. setting the order of the channels to be converted (in our case single channel 6) b. select sampling time for each channel There is a single function to set both parameters: LL_ADC_SetChannelSamplingTime() 3. After the reset ADC is in deep power down mode. It is necessary to disable this mode using LL_ADC_DisableDeepPowerDown() function 4. Further we need to enable ADC internal voltage regulator using LL_ADC_EnableInternalRegulator() function and wait for it stabilization (implement your own delay() function)
3 4
30 The task is to configure Channel 3 in DMA1 to work with DAC using LL_DMA_InitTypeDef structure and LL_DMA_Init() function in the following way:
alignment)*.
*) Hint: To get the proper address we can use function LL_DAC_DMA_GetRegAddr()
31
The task is to configure Channel 3 in DMA1 to work with DAC using LL_DMA_InitTypeDef structure and LL_DMA_Init() function in the following way:
/* DAC DMA LL configuration */ __HAL_RCC_DMA1_CLK_ENABLE(); //enable clock LL_DMA_StructInit(&DMA_DAC_InitStruct); DMA_DAC_InitStruct.PeriphOrM2MSrcAddress = LL_DAC_DMA_GetRegAddr(DAC1,LL_DAC_CHANNEL_1,LL_DAC_DMA_REG_DATA_12BITS_RIGHT_ALIGNED); DMA_DAC_InitStruct.MemoryOrM2MDstAddress = (uint32_t)dacbuf; DMA_DAC_InitStruct.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; DMA_DAC_InitStruct.Mode = LL_DMA_MODE_CIRCULAR; DMA_DAC_InitStruct.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; DMA_DAC_InitStruct.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; DMA_DAC_InitStruct.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_HALFWORD; DMA_DAC_InitStruct.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_HALFWORD; DMA_DAC_InitStruct.NbData = DACBUFSIZE; DMA_DAC_InitStruct.PeriphRequest = LL_DMA_REQUEST_6; DMA_DAC_InitStruct.Priority = LL_DMA_PRIORITY_LOW; LL_DMA_Init(DMA1, LL_DMA_CHANNEL_3, &DMA_DAC_InitStruct); LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_3);
32 The task is to configure Channel 1 in DMA1 to work with ADC using LL_DMA_InitTypeDef structure and LL_DMA_Init() function in the following way:
*) Hint: To get the proper address we can use function LL_ADC_DMA_GetRegAddr()
/* ADC DMA LL configuration */ LL_DMA_StructInit(&DMA_ADC_InitStruct); DMA_ADC_InitStruct.PeriphOrM2MSrcAddress = LL_ADC_DMA_GetRegAddr(ADC1,LL_ADC_DMA_REG_REGULAR_DATA); DMA_ADC_InitStruct.MemoryOrM2MDstAddress = (uint32_t)adcbuf; DMA_ADC_InitStruct.Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY; DMA_ADC_InitStruct.Mode = LL_DMA_MODE_CIRCULAR; DMA_ADC_InitStruct.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; DMA_ADC_InitStruct.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; DMA_ADC_InitStruct.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_HALFWORD; DMA_ADC_InitStruct.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_HALFWORD; DMA_ADC_InitStruct.NbData = ADCBUFSIZE; DMA_ADC_InitStruct.PeriphRequest = LL_DMA_REQUEST_0; DMA_ADC_InitStruct.Priority = LL_DMA_PRIORITY_LOW; LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &DMA_ADC_InitStruct); LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1);
33 The task is to configure Channel 1 in DMA1 to work with ADC using LL_DMA_InitTypeDef structure and LL_DMA_Init() function in the following way:
34
The task is to configure Timer2 (TIM2) to work in up-counting mode with the following parameters/options:
LL_TIM_InitTypeDef value ClockDivision ? Prescaler ? CounterMode ? Autoreload ?
16-Bit Prescaler
ITR 1..4
Trigger/Clock Controller
Trigger Output (TRGO) Update
APB1 clk
Auto Reload REG
+/- 32-Bit Counter
CH1 CH2 CH3 CH4 Capture Compare Capture Compare Capture Compare Capture Compare CH1 CH2 CH3 CH4
Autoreload (Period) CompareValue Prescaler CounterMode ClockDivision
LL_TIM_Init()
LL_TIM_InitTypeDef LL_TIM_OC_InitTypeDef
LL_TIM_OC_Init()
80MHz 80MHz 5Hz 5Hz/50% 2kHz
TRGO (update) – trigger for DAC CC2 – trigger for ADC
OCMode
LL_TIM_OC_InitTypeDef value CompareValue ? OCMode ?
/* TIM2 LL configuration */ __HAL_RCC_TIM2_CLK_ENABLE(); //enable clock TIM2_InitStruct.Prescaler = 7999; TIM2_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP; TIM2_InitStruct.Autoreload = 999; TIM2_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1; LL_TIM_Init(TIM2,&TIM2_InitStruct); 35
Configuration of the clock and counter block of the timer (LL_TIM_InitTypeDef structure) 1. Connect clock to Timer2 (TIM2) using macro __HAL_RCC_TIM2_CLK_ENABLE() 2. Initialize LL_TIM_InitTypeDef structure with default values using LL_TIM_StructInit() function. 3. Fill LL_TIM_InitTypeDef structure with desired configuration parameters (calculated clock prescalers, mode and autoreload value for TIM2 to reach target 5Hz, 50% dc on OC channel4) 4. Copy structure fields into TIM2 registers using LL_TIM_Init() function
/* TIM2 LL configuration */ __HAL_RCC_TIM2_CLK_ENABLE(); //enable clock LL_TIM_StructInit(&TIM2_InitStruct); TIM2_InitStruct.Prescaler = 39999; TIM2_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP; TIM2_InitStruct.Autoreload = 399; TIM2_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1; LL_TIM_Init(TIM2,&TIM2_InitStruct); 36
Configuration of the clock and counter block of the timer (LL_TIM_InitTypeDef structure) 1. Connect clock to Timer2 (TIM2) using macro __HAL_RCC_TIM2_CLK_ENABLE() 2. Initialize LL_TIM_InitTypeDef structure with default values using LL_TIM_StructInit() function. 3. Fill LL_TIM_InitTypeDef structure with desired configuration parameters (calculated clock prescalers, mode and autoreload value for TIM2 to reach target 5Hz, 50% dc on OC channel4) 4. Copy structure fields into TIM2 registers using LL_TIM_Init() function
1 3 4 2
/* TIM2 output compare mode for channel 2 - LL configuration */ TIM2_OCInitStruct.OCMode = LL_TIM_OCMODE_TOGGLE; TIM2_OCInitStruct.OCState = LL_TIM_OCSTATE_ENABLE; TIM2_OCInitStruct.CompareValue = 500; TIM2_OCInitStruct.OCPolarity = LL_TIM_OCPOLARITY_HIGH; LL_TIM_OC_Init(TIM2,LL_TIM_CHANNEL_CH2,&TIM2_OCInitStruct); LL_TIM_SetTriggerOutput(TIM2, LL_TIM_TRGO_UPDATE); LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH2); 37
Configuration of the output compare block for channel2 of the timer2 (LL_TIM_OCInitTypeDef structure) 1. Initialize LL_TIM_OCInitTypeDef structure with default values using LL_TIM_OCStructInit() function. 2. Fill LL_TIM_OCInitTypeDef structure with desired configuration parameters (calculated pulse, mode and autoreload value for TIM2 to reach target 5Hz, 50% dc on OC channel4) 3. Copy structure fields into TIM2 registers using LL_TIM_OC_Init() function 4. Configure trigger output (TRGO) to update using LL_TIM_SetTriggerOutput() function. 5. Enable TIM2 channel2 using LL_TIM_CC_EnableChannel() function.
/* TIM2 output compare mode for channel 2 - LL configuration */ LL_TIM_OC_StructInit(&TIM2_OCInitStruct); TIM2_OCInitStruct.OCMode = LL_TIM_OCMODE_TOGGLE; TIM2_OCInitStruct.OCState = LL_TIM_OCSTATE_ENABLE; TIM2_OCInitStruct.CompareValue = 200; TIM2_OCInitStruct.OCPolarity = LL_TIM_OCPOLARITY_HIGH; LL_TIM_OC_Init(TIM2,LL_TIM_CHANNEL_CH2,&TIM2_OCInitStruct); LL_TIM_SetTriggerOutput(TIM2, LL_TIM_TRGO_UPDATE); LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH2); 38
Configuration of the output compare block for channel2 of the timer2 (LL_TIM_OCInitTypeDef structure) 1. Initialize LL_TIM_OCInitTypeDef structure with default values using LL_TIM_OCStructInit() function. 2. Fill LL_TIM_OCInitTypeDef structure with desired configuration parameters (calculated pulse, mode and autoreload value for TIM2 to reach target 5Hz, 50% dc on OC channel4) 3. Copy structure fields into TIM2 registers using LL_TIM_OC_Init() function 4. Configure trigger output (TRGO) to update using LL_TIM_SetTriggerOutput() function. 5. Enable TIM2 channel2 using LL_TIM_CC_EnableChannel() function.
39 /* DAC activation */ LL_DAC_EnableDMAReq(DAC1, LL_DAC_CHANNEL_1); LL_DAC_EnableTrigger(DAC1, LL_DAC_CHANNEL_1); LL_DAC_Enable(DAC1, LL_DAC_CHANNEL_1); /* ADC activation */ LL_ADC_StartCalibration(ADC1, LL_ADC_SINGLE_ENDED); LL_ADC_Enable(ADC1); LL_ADC_REG_StartConversion(ADC1); /* TIM2 activation */ LL_TIM_EnableCounter(TIM2);
Start already configured peripherals:
1. Enable DMA for Channel1 of DAC1 using LL_DAC_EnableDMAReq() function 2. Enable trigger for Channel1 of DAC1 using LL_DAC_EnableTrigger() function 3. Enable Channel1 of DAC1 using LL_DAC_Enable() function 4. Start calibration of ADC1 (for single ended conversions) using function LL_ADC_StartCalibration(). 5. Add necessary 116 ADC clk delay after calibration start 6. Enable ADC1 using LL_ADC_Enable() function 7. Start regular conversion (ADC1 will start conversion after next HW trigger) using LL_ADC_REG_StartConversion() function 8. Activate timer2 using LL_TIM_EnableCounter() function
40 /* DAC activation */ LL_DAC_EnableDMAReq(DAC1, LL_DAC_CHANNEL_1); LL_DAC_EnableTrigger(DAC1, LL_DAC_CHANNEL_1); LL_DAC_Enable(DAC1, LL_DAC_CHANNEL_1); /* ADC activation */ LL_ADC_StartCalibration(ADC1, LL_ADC_SINGLE_ENDED); //necessary 116 ADC clk delay LL_ADC_Enable(ADC1); LL_ADC_REG_StartConversion(ADC1); /* TIM2 activation */ LL_TIM_EnableCounter(TIM2);
Start already configured peripherals:
1. Enable DMA for Channel1 of DAC1 using LL_DAC_EnableDMAReq() function 2. Enable trigger for Channel1 of DAC1 using LL_DAC_EnableTrigger() function 3. Enable Channel1 of DAC1 using LL_DAC_Enable() function 4. Start calibration of ADC1 (for single ended conversions) using function LL_ADC_StartCalibration(). 5. Add necessary 116 ADC clk delay after calibration start 6. Enable ADC1 using LL_ADC_Enable() function 7. Start regular conversion (ADC1 will start conversion after next HW trigger) using LL_ADC_REG_StartConversion() function 8. Activate timer2 using LL_TIM_EnableCounter() function
1 2 3 4 5 6 7 8
41
function name size [B] function name size [B] Reduction vs HAL function name size [B] Reduction vs LL structures Reduction vs HAL Startup & Initialization HAL_Init 1432 HAL_Init 1256 12% HAL_Init 1256 0%
12%
Clock configuration SystemClock_Config 5512 LL_SystemClock_Config 1552 72% LL_SystemClock_Config 1552 0%
72%
GPIO configuration MX_GPIO_Init 5552 GPIO_LL_configuration 1984 64% LL_GPIO_configuration 1680 15%
70%
ADC configuration MX_ADC1_Init 8400 ADC_LL_configuration 2480 70% LL_ADC_configuration 1896 24%
77%
DAC configuration MX_DAC1_Init 8896 DAC_LL_configuration 2672 70% LL_DAC_configuration 1960 27%
78%
ADC DMA configuration DMA_ADC_LL_configuration 2928 na LL_DMA_ADC_configuration 2080 29%
na
DAC DMA configuration DMA_DAC_LL_configuration 3120 65% LL_DMA_DAC_configuration 2288 27%
75%
TIM2 configuration MX_TIM2_Init 10776 TIM2_LL_configuration 4272 60% LL_TIM2_configuration 2400 44%
78%
ADC activation HAL_ADC_Start_DMA 11424 ADC_LL_activation 4344 62% ADC_LL_activation 2472 43%
78%
DAC activation HAL_DAC_Start_DMA 11816 DAC_LL_activation 4384 63% DAC_LL_activation 2512 43%
79%
TIM2 activation HAL_TIM_OC_Start 11936 TIM2_LL_activation 4400 63% TIM2_LL_activation 2528 43%
79%
ADC without calibration Unitary Low Layer Library (based on simple functions) HAL Init Low Layer Library (based on structures) Role MX_DMA_Init 8984
Complete application code size
42
More information can be found in the following documents:
http://www.st.com/resource/en/user_manual/dm00157440.pdf
http://www.st.com/resource/en/user_manual/dm00173145.pdf
Cube library in the path:
\STM32Cube_FW_L4_V1.5.0\Drivers\STM32L4xx_HAL_Driver\
/STM32 @ST_World st.com/e2e