/** ****************************************************************************** * File 07_PWM_EdgeAligned/main.c * Author MCD Application Team * Version V1.2.0 * Date 05-February-2016 * Brief This code example shows how to configure the timer * to generate a PWM edge aligned signal. * ============================================================================== ##### RCC specific features ##### ============================================================================== [..] After reset the device is running from MSI (2 MHz) with Flash 0 WS, and voltage scaling range is 2 (1.5V) all peripherals are off except internal SRAM, Flash and SW-DP. (+) There is no prescaler on High speed (AHB) and Low speed (APB) busses; all peripherals mapped on these busses are running at MSI speed. (+) The clock for all peripherals is switched off, except the SRAM and FLASH. (+) All GPIOs are in analog state, except the SW-DP pins which are assigned to be used for debug purpose. [..] Once the device started from reset, the user application has to: (+) Configure the clock source to be used to drive the System clock (if the application needs higher frequency/performance) (+) Configure the System clock frequency and Flash settings (+) Configure the AHB and APB busses prescalers (+) Enable the clock for the peripheral(s) to be used (+) Configure the clock source(s) for peripherals whose clocks are not derived from the System clock (ADC, RTC/LCD, RNG and IWDG) =============================================================================== ##### MCU Resources ##### =============================================================================== - RCC - TIMx - GPIO PB13 for TIM21_CH1 - GPIO PA5 and PB4 for LEDs - SYSTICK for led management =============================================================================== ##### How to use this example ##### =============================================================================== - this file must be inserted in a project containing the following files : o system_stm32l0xx.c, startup_stm32l053xx.s o stm32l0xx.h to get the register definitions o CMSIS files =============================================================================== ##### How to test this example ##### =============================================================================== - This example configures the TIM21 in order to generate a PWM edge aligned on OC1 (channel 1)with a period of 9 microseconds and a 4/9 duty cycle. The GPIO PPB13, corresponding to TIM21_CH1, is configured as alternate function and the AFR6 is selected. - To test this example, the user must monitor the signal on PB13. - This example can be easily ported on any other timer by modifying TIMx definition. The corresponding GPIO must be also adapted according to the datasheet. - The green LED is switched on. * ****************************************************************************** * Attention * *

© COPYRIGHT 2015 STMicroelectronics

* * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); * You may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.st.com/software_license_agreement_liberty_v2 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "stm32l0xx.h" /** STM32L0_Snippets * */ /* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/ /* Time-out values */ #define HSI_TIMEOUT_VALUE ((uint32_t)100) /* 100 ms */ #define PLL_TIMEOUT_VALUE ((uint32_t)100) /* 100 ms */ #define CLOCKSWITCH_TIMEOUT_VALUE ((uint32_t)5000) /* 5 s */ /* Delay value : short one is used for the error coding, long one (~1s) in case of no error or between two bursts */ #define SHORT_DELAY 200 #define LONG_DELAY 1000 /* Error codes used to make the red led blinking */ #define ERROR_HSI_TIMEOUT 0x01 #define ERROR_PLL_TIMEOUT 0x02 #define ERROR_CLKSWITCH_TIMEOUT 0x03 /* Define the Timer to be configured */ #define TIMx_BASE TIM21_BASE #define TIMx ((TIM_TypeDef *) TIMx_BASE) /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ static __IO uint32_t Tick; volatile uint16_t error = 0xFF; //initialized at 0 and modified by the functions /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); void ConfigureGPIO(void); void ConfigureTIMxAsPWM_EdgeAligned(void); /* Private functions ---------------------------------------------------------*/ /** * Brief Main program. * Param None * Retval None */ int main(void) { /*!< At this stage the microcontroller clock setting is already configured, this is done through SystemInit() function which is called from startup file (startup_stm32l0xx.s) before to branch to application main. To reconfigure the default setting of SystemInit() function, refer to system_stm32l0xx.c file */ SysTick_Config(2000); /* 1ms config */ SystemClock_Config(); ConfigureGPIO(); if (error != 0xFF) { while(1) /* endless loop */ { } } error = 0; SysTick->CTRL = 0; /* Disable SysTick */ ConfigureTIMxAsPWM_EdgeAligned(); GPIOB->BSRR = 1<<4; /* switch on green led */ while (1) { __WFI(); } } /** * Brief This function configures the system clock @16MHz and voltage scale 1 * assuming the registers have their reset value before the call. * POWER SCALE = RANGE 1 * SYSTEM CLOCK = PLL MUL8 DIV2 * PLL SOURCE = HSI/4 * FLASH LATENCY = 0 * Param None * Retval None */ __INLINE void SystemClock_Config(void) { uint32_t tickstart; /* (1) Enable power interface clock */ /* (2) Select voltage scale 1 (1.65V - 1.95V) i.e. (01) for VOS bits in PWR_CR */ /* (3) Enable HSI divided by 4 in RCC-> CR */ /* (4) Wait for HSI ready flag and HSIDIV flag */ /* (5) Set PLL on HSI, multiply by 8 and divided by 2 */ /* (6) Enable the PLL in RCC_CR register */ /* (7) Wait for PLL ready flag */ /* (8) Select PLL as system clock */ /* (9) Wait for clock switched on PLL */ RCC->APB1ENR |= (RCC_APB1ENR_PWREN); /* (1) */ PWR->CR = (PWR->CR & ~(PWR_CR_VOS)) | PWR_CR_VOS_0; /* (2) */ RCC->CR |= RCC_CR_HSION | RCC_CR_HSIDIVEN; /* (3) */ tickstart = Tick; while ((RCC->CR & (RCC_CR_HSIRDY |RCC_CR_HSIDIVF)) != (RCC_CR_HSIRDY |RCC_CR_HSIDIVF)) /* (4) */ { if ((Tick - tickstart ) > HSI_TIMEOUT_VALUE) { error = ERROR_HSI_TIMEOUT; /* Report an error */ return; } } RCC->CFGR |= RCC_CFGR_PLLSRC_HSI | RCC_CFGR_PLLMUL8 | RCC_CFGR_PLLDIV2; /* (5) */ RCC->CR |= RCC_CR_PLLON; /* (6) */ tickstart = Tick; while ((RCC->CR & RCC_CR_PLLRDY) == 0) /* (7) */ { if ((Tick - tickstart ) > PLL_TIMEOUT_VALUE) { error = ERROR_PLL_TIMEOUT; /* Report an error */ return; } } RCC->CFGR |= RCC_CFGR_SW_PLL; /* (8) */ tickstart = Tick; while ((RCC->CFGR & RCC_CFGR_SWS_PLL) == 0) /* (9) */ { if ((Tick - tickstart ) > CLOCKSWITCH_TIMEOUT_VALUE) { error = ERROR_CLKSWITCH_TIMEOUT; /* Report an error */ return; } } } /** * Brief This function enables the peripheral clocks on GPIO port A and B, * configures GPIO PB4 in output mode for the Green LED pin, * configures GPIO PA5 in output mode for the Red LED pin, * Param None * Retval None */ __INLINE void ConfigureGPIO(void) { /* (1) Enable the peripheral clock of GPIOA and GPIOB */ /* (2) Select output mode (01) on GPIOA pin 5 */ /* (3) Select output mode (01) on GPIOB pin 4 */ RCC->IOPENR |= RCC_IOPENR_GPIOAEN | RCC_IOPENR_GPIOBEN; /* (1) */ GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODE5)) | (GPIO_MODER_MODE5_0); /* (2) */ GPIOB->MODER = (GPIOB->MODER & ~(GPIO_MODER_MODE4)) | (GPIO_MODER_MODE4_0); /* (3) */ } /** * Brief This function configures the TIMx as PWM mode 1 * and enables the peripheral clock on TIMx and on GPIOB. * It configures GPIO PB13 as Alternate function for TIM21_CH1 * To use another timer, channel or GPIO, the RCC and GPIO configuration * must be adapted according to the datasheet. * In case of other timer, the interrupt sub-routine must also be renamed * with the right handler and the NVIC configured correctly. * Param None * Retval None */ __INLINE void ConfigureTIMxAsPWM_EdgeAligned(void) { /* (1) Enable the peripheral clock of Timer x */ /* (2) Enable the peripheral clock of GPIOB */ /* (3) Select alternate function mode on GPIOB pin 13 */ /* (4) Select AF6 on PB13 in AFRH for TIM21_CH1 */ RCC->APB2ENR |= RCC_APB2ENR_TIM21EN; /* (1) */ RCC->IOPENR |= RCC_IOPENR_GPIOBEN; /* (2) */ GPIOB->MODER = (GPIOB->MODER & ~(GPIO_MODER_MODE13)) \ | (GPIO_MODER_MODE13_1); /* (3) */ GPIOB->AFR[1] |= 0x6 << ((13 - 8) * 4); /* (4) */ /* (1) Set prescaler to 15, so APBCLK/16 i.e 1MHz */ /* (2) Set ARR = 8, as timer clock is 1MHz the period is 9 us */ /* (3) Set CCRx = 4, , the signal will be high during 4 us */ /* (4) Select PWM mode 1 on OC1 (OC1M = 110), enable preload register on OC1 (OC1PE = 1) */ /* (5) Select active high polarity on OC1 (CC1P = 0, reset value), enable the output on OC1 (CC1E = 1)*/ /* (6) Enable output (MOE = 1)*/ /* (7) Enable counter (CEN = 1) select edge aligned mode (CMS = 00, reset value) select direction as upcounter (DIR = 0, reset value) */ /* (8) Force update generation (UG = 1) */ TIMx->PSC = 15; /* (1) */ TIMx->ARR = 8; /* (2) */ TIMx->CCR1 = 4; /* (3) */ TIMx->CCMR1 |= TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1PE; /* (4) */ TIMx->CCER |= TIM_CCER_CC1E; /* (5) */ TIMx->CR1 |= TIM_CR1_CEN; /* (7) */ TIMx->EGR |= TIM_EGR_UG; /* (8) */ } /******************************************************************************/ /* Cortex-M0 Plus Processor Exceptions Handlers */ /******************************************************************************/ /** * Brief This function handles NMI exception. * Param None * Retval None */ void NMI_Handler(void) { } /** * Brief This function handles Hard Fault exception. * Param None * Retval None */ void HardFault_Handler(void) { /* Go to infinite loop when Hard Fault exception occurs */ while (1) { } } /** * Brief This function handles SVCall exception. * Param None * Retval None */ void SVC_Handler(void) { } /** * Brief This function handles PendSVC exception. * Param None * Retval None */ void PendSV_Handler(void) { } /** * Brief This function handles SysTick Handler. * It only toggles the red led coding the error number * Param None * Retval None */ void SysTick_Handler(void) { static uint32_t long_counter = LONG_DELAY; static uint32_t short_counter = SHORT_DELAY; static uint16_t error_temp = 0; Tick++; if (long_counter-- == 0) { if ((error != 0) && (error != 0xFF)) { /* red led blinks according to the code error value */ error_temp = (error << 1) - 1; short_counter = SHORT_DELAY; long_counter = LONG_DELAY << 1; GPIOA->BSRR = (1<<5); /* Set red led on PA5 */ GPIOB->BRR = (1<<4); /* Switch off green led on PB4 */ } else { long_counter = LONG_DELAY; } } if (error_temp > 0) { if (short_counter-- == 0) { GPIOA->ODR ^= (1 << 5); /* Toggle red led */ short_counter = SHORT_DELAY; error_temp--; } } } /******************************************************************************/ /* STM32L0xx Peripherals Interrupt Handlers */ /* Add here the Interrupt Handler for the used peripheral(s) (PPP), for the */ /* available peripheral interrupt handler's name please refer to the startup */ /* file (startup_stm32l0xx.s). */ /******************************************************************************/ /** * Brief This function handles PPP interrupt request. * Param None * Retval None */ /* void PPP_IRQHandler(void) { } */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/