+#include <libopencm3/cm3/nvic.h>
+#include <libopencm3/stm32/rcc.h>
+#include <libopencm3/stm32/gpio.h>
+#include <libopencm3/stm32/timer.h>
+
+int up = 1;
+int pwm;
+
+void tim4_isr(void)
+{
+ if (TIM_SR(TIM4) & TIM_SR_UIF) {
+ TIM_SR(TIM4) &= ~TIM_SR_UIF;
+ if (up) {
+ pwm += 5;
+ if (pwm == 1000) {
+ pwm = 995;
+ up = 0;
+ }
+ } else {
+ pwm -= 5;
+ if (pwm < 0) {
+ pwm = 5;
+ up = 1;
+ }
+ }
+ timer_set_oc_value(TIM3, TIM_OC3, pwm);
+ }
+}
+
+int main(void)
+{
+ rcc_clock_setup_in_hse_8mhz_out_72mhz();
+ rcc_periph_clock_enable(RCC_GPIOB);
+ rcc_periph_clock_enable(RCC_GPIOC);
+ rcc_periph_clock_enable(RCC_TIM3);
+ rcc_periph_clock_enable(RCC_TIM4);
+ rcc_periph_reset_pulse(RST_TIM3); // XXX
+ rcc_periph_reset_pulse(RST_TIM4); // XXX
+
+ // PC13 = BluePill LED
+ gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO13);
+ gpio_set(GPIOC, GPIO13);
+
+ // PB0 = TIM3_CH3
+ gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO0);
+
+ timer_set_prescaler(TIM3, 1); // 72 MHz / 2 = 36 MHz
+ timer_set_mode(TIM3, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
+ timer_set_period(TIM3, 999); // 36 MHz / 1000 = 36 kHz
+ timer_update_on_overflow(TIM3);
+
+ timer_set_oc_mode(TIM3, TIM_OC3, TIM_OCM_PWM1);
+ timer_set_oc_value(TIM3, TIM_OC3, 50);
+ timer_set_oc_polarity_high(TIM3, TIM_OC3);
+ timer_enable_oc_output(TIM3, TIM_OC3);
+
+ timer_enable_counter(TIM3);
+
+ timer_set_prescaler(TIM4, 35999); // 72 MHz / 36000 = 2 kHz
+ timer_set_mode(TIM4, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
+ timer_set_period(TIM4, 2); // 2 kHz / 2 = 1 kHz
+ timer_update_on_overflow(TIM4);
+ timer_enable_irq(TIM4, TIM_DIER_UIE);
+ nvic_enable_irq(NVIC_TIM4_IRQ);
+ timer_enable_counter(TIM4);
+
+ for (;;) {
+ asm volatile ("wfi");
+ }
+
+ return 0;
+}