f9fa14c29cfa60e5abbb8bea4386dd3e426a861a
[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; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 #include "ao.h"
20
21 #ifndef BEEPER_CHANNEL
22 #define BEEPER_CHANNEL  1
23 #endif
24
25 void
26 ao_beep(uint8_t beep)
27 {
28         if (beep == 0) {
29                 stm_tim3.cr1 = 0;
30                 stm_rcc.apb1enr &= ~(1 << STM_RCC_APB1ENR_TIM3EN);
31         } else {
32                 stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_TIM3EN);
33
34                 stm_tim3.cr2 = ((0 << STM_TIM234_CR2_TI1S) |
35                                 (STM_TIM234_CR2_MMS_RESET << STM_TIM234_CR2_MMS) |
36                                 (0 << STM_TIM234_CR2_CCDS));
37
38                 /* Set prescaler to match cc1111 clocks
39                  */
40                 stm_tim3.psc = AO_TIM23467_CLK / 750000;
41
42                 /* 1. Select the counter clock (internal, external, prescaler).
43                  *
44                  * Setting SMCR to zero means use the internal clock
45                  */
46
47                 stm_tim3.smcr = 0;
48
49                 /* 2. Write the desired data in the TIMx_ARR and TIMx_CCRx registers. */
50                 stm_tim3.arr = beep;
51                 stm_tim3.ccr1 = beep;
52
53                 /* 3. Set the CCxIE and/or CCxDE bits if an interrupt and/or a
54                  * DMA request is to be generated.
55                  */
56                 /* don't want this */
57
58                 /* 4. Select the output mode. For example, you must write
59                  *  OCxM=011, OCxPE=0, CCxP=0 and CCxE=1 to toggle OCx output
60                  *  pin when CNT matches CCRx, CCRx preload is not used, OCx
61                  *  is enabled and active high.
62                  */
63
64 #if BEEPER_CHANNEL == 1
65                 stm_tim3.ccmr1 = ((0 << STM_TIM234_CCMR1_OC2CE) |
66                                   (STM_TIM234_CCMR1_OC2M_FROZEN << STM_TIM234_CCMR1_OC2M) |
67                                   (0 << STM_TIM234_CCMR1_OC2PE) |
68                                   (0 << STM_TIM234_CCMR1_OC2FE) |
69                                   (STM_TIM234_CCMR1_CC2S_OUTPUT << STM_TIM234_CCMR1_CC2S) |
70
71                                   (0 << STM_TIM234_CCMR1_OC1CE) |
72                                   (STM_TIM234_CCMR1_OC1M_TOGGLE << STM_TIM234_CCMR1_OC1M) |
73                                   (0 << STM_TIM234_CCMR1_OC1PE) |
74                                   (0 << STM_TIM234_CCMR1_OC1FE) |
75                                   (STM_TIM234_CCMR1_CC1S_OUTPUT << STM_TIM234_CCMR1_CC1S));
76
77                 stm_tim3.ccer = ((0 << STM_TIM234_CCER_CC4NP) |
78                                  (0 << STM_TIM234_CCER_CC4P) |
79                                  (0 << STM_TIM234_CCER_CC4E) |
80                                  (0 << STM_TIM234_CCER_CC3NP) |
81                                  (0 << STM_TIM234_CCER_CC3P) |
82                                  (0 << STM_TIM234_CCER_CC3E) |
83                                  (0 << STM_TIM234_CCER_CC2NP) |
84                                  (0 << STM_TIM234_CCER_CC2P) |
85                                  (0 << STM_TIM234_CCER_CC2E) |
86                                  (0 << STM_TIM234_CCER_CC1NP) |
87                                  (0 << STM_TIM234_CCER_CC1P) |
88                                  (1 << STM_TIM234_CCER_CC1E));
89 #endif
90 #if BEEPER_CHANNEL == 4
91                 stm_tim3.ccmr2 = ((0 << STM_TIM234_CCMR2_OC4CE) |
92                                   (STM_TIM234_CCMR2_OC4M_TOGGLE << STM_TIM234_CCMR2_OC4M) |
93                                   (0 << STM_TIM234_CCMR2_OC4PE) |
94                                   (0 << STM_TIM234_CCMR2_OC4FE) |
95                                   (STM_TIM234_CCMR2_CC4S_OUTPUT << STM_TIM234_CCMR2_CC4S) |
96
97                                   (0 << STM_TIM234_CCMR2_OC3CE) |
98                                   (STM_TIM234_CCMR2_OC3M_FROZEN << STM_TIM234_CCMR2_OC3M) |
99                                   (0 << STM_TIM234_CCMR2_OC3PE) |
100                                   (0 << STM_TIM234_CCMR2_OC3FE) |
101                                   (STM_TIM234_CCMR2_CC3S_OUTPUT << STM_TIM234_CCMR2_CC3S));
102
103                 stm_tim3.ccer = ((0 << STM_TIM234_CCER_CC4NP) |
104                                  (0 << STM_TIM234_CCER_CC4P) |
105                                  (1 << STM_TIM234_CCER_CC4E) |
106                                  (0 << STM_TIM234_CCER_CC3NP) |
107                                  (0 << STM_TIM234_CCER_CC3P) |
108                                  (0 << STM_TIM234_CCER_CC3E) |
109                                  (0 << STM_TIM234_CCER_CC2NP) |
110                                  (0 << STM_TIM234_CCER_CC2P) |
111                                  (0 << STM_TIM234_CCER_CC2E) |
112                                  (0 << STM_TIM234_CCER_CC1NP) |
113                                  (0 << STM_TIM234_CCER_CC1P) |
114                                  (0 << STM_TIM234_CCER_CC1E));
115 #endif
116
117
118                 /* 5. Enable the counter by setting the CEN bit in the TIMx_CR1 register. */
119
120                 stm_tim3.cr1 = ((STM_TIM234_CR1_CKD_1 << STM_TIM234_CR1_CKD) |
121                                 (0 << STM_TIM234_CR1_ARPE) |
122                                 (STM_TIM234_CR1_CMS_EDGE << STM_TIM234_CR1_CMS) |
123                                 (0 << STM_TIM234_CR1_DIR) |
124                                 (0 << STM_TIM234_CR1_OPM) |
125                                 (0 << STM_TIM234_CR1_URS) |
126                                 (0 << STM_TIM234_CR1_UDIS) |
127                                 (1 << STM_TIM234_CR1_CEN));
128
129                 /* Update the values */
130                 stm_tim3.egr = (1 << STM_TIM234_EGR_UG);
131         }
132 }
133
134 void
135 ao_beep_for(uint8_t beep, uint16_t ticks) 
136 {
137         ao_beep(beep);
138         ao_delay(ticks);
139         ao_beep(0);
140 }
141
142 void
143 ao_beep_init(void)
144 {
145 #if BEEPER_CHANNEL == 1
146
147         /* Our beeper is on PC6, which is hooked to TIM3_CH1.
148          */
149         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOCEN);
150
151         stm_afr_set(&stm_gpioc, 6, STM_AFR_AF2);
152 #endif
153 #if BEEPER_CHANNEL == 4
154
155         /* Our beeper is on PB1, which is hooked to TIM3_CH4.
156          */
157         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN);
158
159         stm_afr_set(&stm_gpiob, 1, STM_AFR_AF2);
160 #endif
161
162         /* Leave the timer off until requested */
163         
164         stm_rcc.apb1enr &= ~(1 << STM_RCC_APB1ENR_TIM3EN);
165 }