// 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;
}