/* * Copyright (C) 2019 Max Regan * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "LptimPwm.h" #include "macros.h" namespace BSP { using Common::ReturnCode; LptimPwm::LptimPwm(LPTIM_TypeDef *lptim) : m_lptim(lptim) {} void LptimPwm::init_lptim() { /* Enable LPTIM in APB1 */ SET(RCC->APB1ENR, RCC_APB1ENR_LPTIM1EN); // Enable low-speed internal RCC->CSR |= RCC_CSR_LSION; while (!(RCC->CSR & RCC_CSR_LSIRDY)) {}; /*!< Set the LSE clock to be the source of the LPTIM */ SET_TO(RCC->CCIPR, RCC_CCIPR_LPTIM1SEL, RCC_CCIPR_LPTIM1SEL_0); /** Write CR CFGR and IER while LPTIM is disabled (LPTIM_CR_ENABLE not yet set) */ /*!< Disable Interrupts (not needed, this is the default */ LPTIM1->IER = 0; /*!< Reset * ENC (Disable encoder mode) * TIMOUT (disable timeout mode) * TRIGEN (Trigger count start with software only) * PRELOAD (Update ARR and CMP registers immediately after write) * CKSEL (LPTIM is not using an input clock) * COUNTMODE (LPTIM counter updated on every clock pulse) * TRGFLT (Do not debounce triggers) */ CLR(LPTIM1->CFGR, LPTIM_CFGR_ENC | LPTIM_CFGR_TIMOUT | LPTIM_CFGR_TRIGEN | LPTIM_CFGR_TRIGSEL | LPTIM_CFGR_PRELOAD | LPTIM_CFGR_CKSEL | LPTIM_CFGR_COUNTMODE); /*!< Set * PRESC (Set prescaler to 128. Using 32kHz LSE as input, this should * correspond to 250Hz counting. */ CLR(LPTIM1->CFGR, LPTIM_CFGR_PRESC); SET(LPTIM1->CR, LPTIM_CR_ENABLE); /*!< Do not modify ARR and CMP until after ENABLE bit is set */ /*!< Produce a 60Hz, signal with minimal "high" time. The display only needs 2us of "high" time on EXTCOMM, and it draws a fair amount of power. */ LPTIM1->ARR = 0x4FF; LPTIM1->CMP = 0x4FE; while(!(LPTIM1->ISR & LPTIM_ISR_ARROK)) {} while(!(LPTIM1->ISR & LPTIM_ISR_CMPOK)) {} /*!< Enable and start the timer */ SET(LPTIM1->CR, LPTIM_CR_CNTSTRT); } ReturnCode LptimPwm::init() { init_lptim(); /* Enable GPIO port A */ SET(RCC->IOPENR, RCC_IOPENR_IOPAEN); /* Assign LPTIM1_OUT to PA7 */ SET_TO(GPIOA->AFR[0], GPIO_AFRL_AFRL7, 1u << GPIO_AFRL_AFRL7_Pos); SET_TO(GPIOA->MODER, GPIO_MODER_MODE7, 2u << GPIO_MODER_MODE7_Pos); CLR(GPIOA->OTYPER, GPIO_OTYPER_OT_7); CLR(GPIOA->PUPDR, GPIO_PUPDR_PUPD7); return ReturnCode::OK; } }