// vim: shiftwidth=4 tabstop=4 noexpandtab /* ledcontrol firmware Copyright (C) 2021 xengineering This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Contact: me@xengineering.eu */ #include #include #include #include static void clock_init(void); static void gpio_init(void); static void nvic_init(void); static void timer_init(void); void tim2_isr(void); int main(void) { clock_init(); gpio_init(); nvic_init(); timer_init(); while(1); // wait forever } static void clock_init(void) { // set sysclk to 72 MHz via external 8 MHz crystal rcc_clock_setup_pll(&rcc_hse_configs[RCC_CLOCK_HSE8_72MHZ]); // enable clocks for GPIO ports B and C rcc_periph_clock_enable(RCC_GPIOB); rcc_periph_clock_enable(RCC_GPIOC); // enable clock for timer 2 (blinking) rcc_periph_clock_enable(RCC_TIM2); // enable clock for timer 3 (PWM) rcc_periph_clock_enable(RCC_TIM3); // enable clock for alternate functions rcc_periph_clock_enable(RCC_AFIO); // TODO is this necessary? } static void gpio_init(void) { // init PC13 onboard LED for blinking gpio_set_mode( GPIOC, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO13 ); gpio_clear(GPIOC, GPIO13); // set initial value to 'on' // setup PB0 (connected to TIM3_CH3) for PWM gpio_set_mode( GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_TIM3_CH3 ); } static void nvic_init(void) { // enable timer 2 interrupt and set priority nvic_enable_irq(NVIC_TIM2_IRQ); nvic_set_priority(NVIC_TIM2_IRQ, 1); } static void timer_init(void) { // setup timer 2 for blinking timer_set_counter(TIM2, 1); timer_set_prescaler(TIM2, 1440); timer_set_period(TIM2, 50); // enable timer / counter 2 and the corresponding interrupt for blinking timer_enable_irq(TIM2, TIM_DIER_UIE); timer_enable_counter(TIM2); /* enable timer / counter 3 */ /* Clock division and mode */ TIM3_CR1 = TIM_CR1_CKD_CK_INT | TIM_CR1_CMS_EDGE; /* Period */ TIM3_ARR = 65535; /* Prescaler */ TIM3_PSC = 0; TIM3_EGR = TIM_EGR_UG; /* ---- */ /* Output compare 3 mode and preload */ TIM3_CCMR2 |= TIM_CCMR2_OC3M_PWM1 | TIM_CCMR2_OC3PE; /* Polarity and state */ TIM3_CCER |= TIM_CCER_CC3P | TIM_CCER_CC3E; //TIM3_CCER |= TIM_CCER_CC3E; /* Capture compare value */ TIM3_CCR3 = 30000; /* ---- */ /* ARR reload enable */ TIM3_CR1 |= TIM_CR1_ARPE; /* Counter enable */ TIM3_CR1 |= TIM_CR1_CEN; } void tim2_isr(void) { // PWM handling static uint32_t pwm_value; if (pwm_value == 0) { pwm_value = 65535; } else { pwm_value -= 20; } TIM3_CCR3 = pwm_value; // toggle blink LED static uint32_t counter; counter += 1; if (counter > 500) { gpio_toggle(GPIOC, GPIO13); counter = 0; } // clear interrrupt flag TIM_SR(TIM2) &= ~TIM_SR_UIF; }