aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/timers.c
blob: 401b267df6609d30e0ef1359278fb7ee85f63a88 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
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
}