altos: Add beeper driver to STM arch
[fw/altos] / src / stm / ao_beep_stm.c
1 /*
2  * Copyright © 2012 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 #include "ao.h"
19
20 void
21 ao_beep(uint8_t beep)
22 {
23         if (beep == 0) {
24                 stm_tim3.cr1 = 0;
25                 stm_rcc.apb1enr &= ~(1 << STM_RCC_APB1ENR_TIM3EN);
26         } else {
27                 stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_TIM3EN);
28
29                 stm_tim3.cr1 = ((STM_TIM234_CR1_CKD_1 << STM_TIM234_CR1_CKD) |
30                                 (0 << STM_TIM234_CR1_ARPE) |
31                                 (STM_TIM234_CR1_CMS_EDGE << STM_TIM234_CR1_CMS) |
32                                 (0 << STM_TIM234_CR1_DIR) |
33                                 (0 << STM_TIM234_CR1_OPM) |
34                                 (0 << STM_TIM234_CR1_URS) |
35                                 (0 << STM_TIM234_CR1_UDIS) |
36                                 (0 << STM_TIM234_CR1_CEN));
37
38                 stm_tim3.cr2 = ((0 << STM_TIM234_CR2_TI1S) |
39                                 (STM_TIM234_CR2_MMS_RESET << STM_TIM234_CR2_MMS) |
40                                 (0 << STM_TIM234_CR2_CCDS));
41
42                 /* Set prescaler to match cc1111 clocks
43                  */
44                 stm_tim3.psc = STM_APB1 / 750000;
45
46                 /* 1. Select the counter clock (internal, external, prescaler).
47                  *
48                  * Setting SMCR to zero means use the internal clock
49                  */
50
51                 stm_tim3.smcr = 0;
52
53                 /* 2. Write the desired data in the TIMx_ARR and TIMx_CCRx registers. */
54                 stm_tim3.arr = beep;
55                 stm_tim3.ccr1 = beep;
56
57                 /* 3. Set the CCxIE and/or CCxDE bits if an interrupt and/or a
58                  * DMA request is to be generated.
59                  */
60                 /* don't want this */
61
62                 /* 4. Select the output mode. For example, you must write
63                  *  OCxM=011, OCxPE=0, CCxP=0 and CCxE=1 to toggle OCx output
64                  *  pin when CNT matches CCRx, CCRx preload is not used, OCx
65                  *  is enabled and active high.
66                  */
67
68                 stm_tim3.ccmr1 = ((0 << STM_TIM234_CCMR1_OC2CE) |
69                                   (STM_TIM234_CCMR1_OC2M_FROZEN << STM_TIM234_CCMR1_OC2M) |
70                                   (0 << STM_TIM234_CCMR1_OC2PE) |
71                                   (0 << STM_TIM234_CCMR1_OC2FE) |
72                                   (STM_TIM234_CCMR1_CC2S_OUTPUT << STM_TIM234_CCMR1_CC2S) |
73
74                                   (0 << STM_TIM234_CCMR1_OC1CE) |
75                                   (STM_TIM234_CCMR1_OC1M_TOGGLE << STM_TIM234_CCMR1_OC1M) |
76                                   (0 << STM_TIM234_CCMR1_OC1PE) |
77                                   (0 << STM_TIM234_CCMR1_OC1FE) |
78                                   (STM_TIM234_CCMR1_CC1S_OUTPUT << STM_TIM234_CCMR1_CC1S));
79
80
81                 stm_tim3.ccer = ((0 << STM_TIM234_CCER_CC4NP) |
82                                  (0 << STM_TIM234_CCER_CC4P) |
83                                  (0 << STM_TIM234_CCER_CC4E) |
84                                  (0 << STM_TIM234_CCER_CC3NP) |
85                                  (0 << STM_TIM234_CCER_CC3P) |
86                                  (0 << STM_TIM234_CCER_CC3E) |
87                                  (0 << STM_TIM234_CCER_CC2NP) |
88                                  (0 << STM_TIM234_CCER_CC2P) |
89                                  (0 << STM_TIM234_CCER_CC2E) |
90                                  (0 << STM_TIM234_CCER_CC1NP) |
91                                  (0 << STM_TIM234_CCER_CC1P) |
92                                  (1 << STM_TIM234_CCER_CC1E));
93
94
95                 /* 5. Enable the counter by setting the CEN bit in the TIMx_CR1 register. */
96
97                 stm_tim3.cr1 = ((STM_TIM234_CR1_CKD_1 << STM_TIM234_CR1_CKD) |
98                                 (0 << STM_TIM234_CR1_ARPE) |
99                                 (STM_TIM234_CR1_CMS_EDGE << STM_TIM234_CR1_CMS) |
100                                 (0 << STM_TIM234_CR1_DIR) |
101                                 (0 << STM_TIM234_CR1_OPM) |
102                                 (0 << STM_TIM234_CR1_URS) |
103                                 (0 << STM_TIM234_CR1_UDIS) |
104                                 (1 << STM_TIM234_CR1_CEN));
105         }
106 }
107
108 void
109 ao_beep_for(uint8_t beep, uint16_t ticks) __reentrant
110 {
111         ao_beep(beep);
112         ao_delay(ticks);
113         ao_beep(0);
114 }
115
116 void
117 ao_beep_init(void)
118 {
119         /* Our beeper is on PC6, which is hooked to TIM3_CH1,
120          * which is on PC6
121          */
122
123         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOCEN);
124
125         stm_afr_set(&stm_gpioc, 6, STM_AFR_AF2);
126
127         /* Leave the timer off until requested */
128         
129         stm_rcc.apb1enr &= ~(1 << STM_RCC_APB1ENR_TIM3EN);
130 }