aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/timers.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/timers.c')
-rw-r--r--src/lib/timers.c114
1 files changed, 114 insertions, 0 deletions
diff --git a/src/lib/timers.c b/src/lib/timers.c
new file mode 100644
index 0000000..401b267
--- /dev/null
+++ b/src/lib/timers.c
@@ -0,0 +1,114 @@
+#include "stm32f10x_rcc.h"
+#include "wiring.h"
+#include "timers.h"
+#include "util.h"
+
+typedef struct {
+ volatile uint16_t CR1;
+ uint16_t RESERVED0;
+ volatile uint16_t CR2;
+ uint16_t RESERVED1;
+ volatile uint16_t SMCR;
+ uint16_t RESERVED2;
+ volatile uint16_t DIER;
+ uint16_t RESERVED3;
+ volatile uint16_t SR;
+ uint16_t RESERVED4;
+ volatile uint16_t EGR;
+ uint16_t RESERVED5;
+ volatile uint16_t CCMR1;
+ uint16_t RESERVED6;
+ volatile uint16_t CCMR2;
+ uint16_t RESERVED7;
+ volatile uint16_t CCER;
+ uint16_t RESERVED8;
+ volatile uint16_t CNT;
+ uint16_t RESERVED9;
+ volatile uint16_t PSC;
+ uint16_t RESERVED10;
+ volatile uint16_t ARR;
+ uint16_t RESERVED11;
+ volatile uint16_t RCR;
+ uint16_t RESERVED12;
+ volatile uint16_t CCR1;
+ uint16_t RESERVED13;
+ volatile uint16_t CCR2;
+ uint16_t RESERVED14;
+ volatile uint16_t CCR3;
+ uint16_t RESERVED15;
+ volatile uint16_t CCR4;
+ uint16_t RESERVED16;
+ volatile uint16_t BDTR; // Not used in general purpose timers
+ uint16_t RESERVED17; // Not used in general purpose timers
+ volatile uint16_t DCR;
+ uint16_t RESERVED18;
+ volatile uint16_t DMAR;
+ uint16_t RESERVED19;
+} Timer;
+
+void timer_init(uint8_t timer_num, uint16_t prescale) {
+ Timer *timer;
+ uint32_t is_advanced = 0;
+
+ ASSERT(timer_num > 0 && timer_num <= 4);
+
+ switch(timer_num) {
+ case 1:
+ timer = (Timer*)TIMER1_BASE;
+ RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
+ is_advanced = 1;
+ break;
+ case 2:
+ timer = (Timer*)TIMER2_BASE;
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
+ break;
+ case 3:
+ timer = (Timer*)TIMER3_BASE;
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
+ break;
+ case 4:
+ timer = (Timer*)TIMER4_BASE;
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
+ break;
+ }
+
+ timer->CR1 = ARPE; // No clock division
+ // Do not buffer auto-reload preload
+ // Edge aligned
+ // Upcounter
+ // Do not stop counter at update event
+ // Update events enabled (etc, see bits [1:2])
+ // Counter disabled for now
+
+ timer->PSC = prescale; // Prescaling by prescale (duh)
+ timer->ARR = 0xFFFF; // Max reload cont
+
+ /* initialize all the channels to 50% duty cycle,
+ * TODO: none of them actually get output unless the gpio pin
+ * is set, this will probably consume a bit more power but
+ * we'll worry about that later. */
+ timer->CCR1 = 0x8FFF; // PWM start value
+ timer->CCMR1 |= 0x68; // PWM mode 1, enable preload register.
+ timer->CCER |= 0x001; // enable ch
+
+ timer->CCR2 = 0x8FFF; // PWM start value
+ timer->CCMR1 |= (0x68 << 8);// PWM mode 1, enable preload register.
+ timer->CCER |= 0x010; // enable ch
+
+ timer->CCR3 = 0x8FFF; // PWM start value
+ timer->CCMR2 |= 0x68; // PWM mode 1, enable preload register.
+ timer->CCER |= 0x100; // enable ch
+
+ timer->CCR4 = 0x8FFF; // PWM start value
+ timer->CCMR2 |= (0x68 << 8);// PWM mode 1, enable preload register.
+ timer->CCER |= 0x1000; // enable ch
+
+ /* Advanced timer? */
+ if (is_advanced) {
+ timer->BDTR = 0x8000; // moe enable
+ }
+
+ timer->DIER = 0; // disable update interrupt
+ timer->EGR = 1; // Initialize update event and shadow registers
+ timer->CR1 |= 1; // Enable timer
+}