altos/stmf0: Remove ao_usb_free
[fw/altos] / src / stmf0 / ao_pwm.c
1 /*
2  * Copyright © 2016 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 #include "ao_pwm.h"
20
21 static uint8_t  pwm_running;
22
23 static uint16_t pwm_value[NUM_PWM];
24
25 static void
26 ao_pwm_up(void)
27 {
28         if (pwm_running++ == 0) {
29                 struct stm_tim23        *tim = AO_PWM_TIMER;
30
31                 tim->ccr1 = 0;
32                 tim->ccr2 = 0;
33                 tim->ccr3 = 0;
34                 tim->ccr4 = 0;
35                 tim->arr = PWM_MAX - 1; /* turn on the timer */
36                 tim->cr1 = ((STM_TIM23_CR1_CKD_1 << STM_TIM23_CR1_CKD) |
37                             (0 << STM_TIM23_CR1_ARPE) |
38                             (STM_TIM23_CR1_CMS_EDGE << STM_TIM23_CR1_CMS) |
39                             (STM_TIM23_CR1_DIR_UP << STM_TIM23_CR1_DIR) |
40                             (0 << STM_TIM23_CR1_OPM) |
41                             (0 << STM_TIM23_CR1_URS) |
42                             (0 << STM_TIM23_CR1_UDIS) |
43                             (1 << STM_TIM23_CR1_CEN));
44
45                 /* Set the timer running */
46                 tim->egr = (1 << STM_TIM23_EGR_UG);
47         }
48 }
49
50 static void
51 ao_pwm_down(void)
52 {
53         if (--pwm_running == 0) {
54                 struct stm_tim23        *tim = AO_PWM_TIMER;
55
56                 tim->arr = 0;
57                 tim->cr1 = ((STM_TIM23_CR1_CKD_1 << STM_TIM23_CR1_CKD) |
58                             (0 << STM_TIM23_CR1_ARPE) |
59                             (STM_TIM23_CR1_CMS_EDGE << STM_TIM23_CR1_CMS) |
60                             (STM_TIM23_CR1_DIR_UP << STM_TIM23_CR1_DIR) |
61                             (0 << STM_TIM23_CR1_OPM) |
62                             (0 << STM_TIM23_CR1_URS) |
63                             (0 << STM_TIM23_CR1_UDIS) |
64                             (0 << STM_TIM23_CR1_CEN));
65
66                 /* Stop the timer */
67                 tim->egr = (1 << STM_TIM23_EGR_UG);
68         }
69 }
70
71 void
72 ao_pwm_set(uint8_t pwm, uint16_t value)
73 {
74         struct stm_tim23        *tim = AO_PWM_TIMER;
75         uint8_t                 ch = AO_PWM_0_CH;
76
77         if (value > PWM_MAX)
78                 value = PWM_MAX;
79         if (value != 0) {
80                 if (pwm_value[pwm] == 0)
81                         ao_pwm_up();
82         }
83 #if NUM_PWM > 1
84         switch (pwm) {
85         case 0:
86                 ch = AO_PWM_0_CH;
87                 break;
88         case 1:
89                 ch = AO_PWM_0_CH;
90                 break;
91 #if NUM_PWM > 2
92         case 2:
93                 ch = AO_PWM_0_CH;
94                 break;
95 #endif
96 #if NUM_PWM > 3
97         case 3:
98                 ch = AO_PWM_0_CH;
99                 break;
100 #endif
101         }
102 #endif
103
104         switch (ch) {
105         case 1:
106                 tim->ccr1 = value;
107                 break;
108         case 2:
109                 tim->ccr2 = value;
110                 break;
111         case 3:
112                 tim->ccr3 = value;
113                 break;
114         case 4:
115                 tim->ccr4 = value;
116                 break;
117         }
118         if (value == 0) {
119                 if (pwm_value[pwm] != 0)
120                         ao_pwm_down();
121         }
122         pwm_value[pwm] = value;
123 }
124
125 static void
126 ao_pwm_cmd(void)
127 {
128         uint8_t ch;
129         uint16_t val;
130
131         ao_cmd_decimal();
132         ch = ao_cmd_lex_u32;
133         ao_cmd_decimal();
134         val = ao_cmd_lex_u32;
135         if (ao_cmd_status != ao_cmd_success)
136                 return;
137
138         printf("Set channel %d to %d\n", ch, val);
139         ao_pwm_set(ch, val);
140 }
141
142 static const struct ao_cmds ao_pwm_cmds[] = {
143         { ao_pwm_cmd,   "P <ch> <val>\0Set PWM ch to val" },
144         { 0, NULL },
145 };
146
147 void
148 ao_pwm_init(void)
149 {
150         struct stm_tim23        *tim = AO_PWM_TIMER;
151
152         stm_rcc.apb1enr |= (1 << AO_PWM_TIMER_ENABLE);
153
154         tim->cr1 = 0;
155         tim->psc = AO_PWM_TIMER_SCALE - 1;
156         tim->cnt = 0;
157         tim->ccer = ((1 << STM_TIM23_CCER_CC1E) |
158                      (0 << STM_TIM23_CCER_CC1P) |
159                      (1 << STM_TIM23_CCER_CC2E) |
160                      (0 << STM_TIM23_CCER_CC2P) |
161                      (1 << STM_TIM23_CCER_CC3E) |
162                      (0 << STM_TIM23_CCER_CC3P) |
163                      (1 << STM_TIM23_CCER_CC4E) |
164                      (0 << STM_TIM23_CCER_CC4P));
165
166         tim->ccmr1 = ((0 << STM_TIM23_CCMR1_OC2CE) |
167                       (STM_TIM23_CCMR1_OC2M_PWM_MODE_1 << STM_TIM23_CCMR1_OC2M) |
168                       (0 << STM_TIM23_CCMR1_OC2PE) |
169                       (0 << STM_TIM23_CCMR1_OC2FE) |
170                       (STM_TIM23_CCMR1_CC2S_OUTPUT << STM_TIM23_CCMR1_CC2S) |
171
172                       (0 << STM_TIM23_CCMR1_OC1CE) |
173                       (STM_TIM23_CCMR1_OC1M_PWM_MODE_1 << STM_TIM23_CCMR1_OC1M) |
174                       (0 << STM_TIM23_CCMR1_OC1PE) |
175                       (0 << STM_TIM23_CCMR1_OC1FE) |
176                       (STM_TIM23_CCMR1_CC1S_OUTPUT << STM_TIM23_CCMR1_CC1S));
177
178
179         tim->ccmr2 = ((0 << STM_TIM23_CCMR2_OC4CE) |
180                       (STM_TIM23_CCMR2_OC4M_PWM_MODE_1 << STM_TIM23_CCMR2_OC4M) |
181                       (0 << STM_TIM23_CCMR2_OC4PE) |
182                       (0 << STM_TIM23_CCMR2_OC4FE) |
183                       (STM_TIM23_CCMR2_CC4S_OUTPUT << STM_TIM23_CCMR2_CC4S) |
184
185                       (0 << STM_TIM23_CCMR2_OC3CE) |
186                       (STM_TIM23_CCMR2_OC3M_PWM_MODE_1 << STM_TIM23_CCMR2_OC3M) |
187                       (0 << STM_TIM23_CCMR2_OC3PE) |
188                       (0 << STM_TIM23_CCMR2_OC3FE) |
189                       (STM_TIM23_CCMR2_CC3S_OUTPUT << STM_TIM23_CCMR2_CC3S));
190         tim->egr = 0;
191
192         tim->sr = 0;
193         tim->dier = 0;
194         tim->smcr = 0;
195         tim->cr2 = ((0 << STM_TIM23_CR2_TI1S) |
196                     (STM_TIM23_CR2_MMS_RESET<< STM_TIM23_CR2_MMS) |
197                     (0 << STM_TIM23_CR2_CCDS));
198
199         stm_afr_set(AO_PWM_0_GPIO, AO_PWM_0_PIN, STM_AFR_AF1);
200         stm_ospeedr_set(AO_PWM_0_GPIO, AO_PWM_0_PIN, STM_OSPEEDR_MEDIUM);
201 #if NUM_PWM > 1
202         stm_afr_set(AO_PWM_1_GPIO, AO_PWM_1_PIN, STM_AFR_AF1);
203         stm_ospeedr_set(AO_PWM_1_GPIO, AO_PWM_1_PIN, STM_OSPEEDR_MEDIUM);
204 #endif
205 #if NUM_PWM > 2
206         stm_afr_set(AO_PWM_2_GPIO, AO_PWM_2_PIN, STM_AFR_AF1);
207         stm_ospeedr_set(AO_PWM_2_GPIO, AO_PWM_2_PIN, STM_OSPEEDR_MEDIUM);
208 #endif
209 #if NUM_PWM > 3
210         stm_afr_set(AO_PWM_3_GPIO, AO_PWM_3_PIN, STM_AFR_AF1);
211         stm_ospeedr_set(AO_PWM_3_GPIO, AO_PWM_3_PIN, STM_OSPEEDR_MEDIUM);
212 #endif
213         ao_cmd_register(&ao_pwm_cmds[0]);
214 }