2 * Copyright © 2013 Keith Packard <keithp@keithp.com>
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.
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.
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.
19 #include <ao_debounce.h>
21 static uint8_t ao_debounce_initialized;
22 static uint8_t ao_debounce_running;
23 static struct ao_debounce *ao_debounce;
28 stm_tim6.cr1 = ((0 << STM_TIM67_CR1_ARPE) |
29 (0 << STM_TIM67_CR1_OPM) |
30 (1 << STM_TIM67_CR1_URS) |
31 (0 << STM_TIM67_CR1_UDIS) |
32 (1 << STM_TIM67_CR1_CEN));
38 stm_tim6.cr1 = ((0 << STM_TIM67_CR1_ARPE) |
39 (0 << STM_TIM67_CR1_OPM) |
40 (1 << STM_TIM67_CR1_URS) |
41 (0 << STM_TIM67_CR1_UDIS) |
42 (0 << STM_TIM67_CR1_CEN));
46 _ao_debounce_set(struct ao_debounce *debounce, uint8_t value)
48 if (value != debounce->value) {
49 debounce->value = value;
50 debounce->_set(debounce, value);
52 _ao_debounce_stop(debounce);
56 * Get the current value, set the result when we've
57 * reached the debounce count limit
60 _ao_debounce_check(struct ao_debounce *debounce)
62 if (debounce->_get(debounce)) {
63 if (debounce->count < 0)
65 if (debounce->count < debounce->hold) {
66 if (++debounce->count == debounce->hold)
67 _ao_debounce_set(debounce, 1);
70 if (debounce->count > 0)
72 if (debounce->count > -debounce->hold) {
73 if (--debounce->count == -debounce->hold)
74 _ao_debounce_set(debounce, 0);
80 * Start monitoring one pin
83 _ao_debounce_start(struct ao_debounce *debounce)
85 if (debounce->running)
87 debounce->running = 1;
89 /* Reset the counter */
93 debounce->next = ao_debounce;
94 ao_debounce = debounce;
96 /* Make sure the timer is running */
97 if (!ao_debounce_running++)
100 /* And go check the current value */
101 _ao_debounce_check(debounce);
105 * Stop monitoring one pin
108 _ao_debounce_stop(struct ao_debounce *debounce)
110 struct ao_debounce **prev;
111 if (!debounce->running)
114 debounce->running = 0;
117 for (prev = &ao_debounce; (*prev); prev = &((*prev)->next)) {
118 if (*prev == debounce) {
119 *prev = debounce->next;
123 debounce->next = NULL;
125 /* Turn off the timer if possible */
126 if (!--ao_debounce_running)
130 void stm_tim6_isr(void)
132 struct ao_debounce *debounce, *next;
133 if (stm_tim6.sr & (1 << STM_TIM67_SR_UIF)) {
136 /* Walk the current list, allowing the current
137 * object to be removed from the list
139 for (debounce = ao_debounce; debounce; debounce = next) {
140 next = debounce->next;
141 _ao_debounce_check(debounce);
147 * According to the STM clock-configuration, timers run
148 * twice as fast as the APB1 clock *if* the APB1 prescaler
152 #if AO_APB1_PRESCALER > 1
153 #define TIMER_23467_SCALER 2
155 #define TIMER_23467_SCALER 1
158 #define TIMER_100kHz ((AO_PCLK1 * TIMER_23467_SCALER) / 100000)
161 ao_debounce_init(void)
163 if (ao_debounce_initialized)
165 ao_debounce_initialized = 1;
167 stm_nvic_set_enable(STM_ISR_TIM6_POS);
168 stm_nvic_set_priority(STM_ISR_TIM6_POS, AO_STM_NVIC_CLOCK_PRIORITY);
170 /* Turn on timer 6 */
171 stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_TIM6EN);
173 stm_tim6.psc = TIMER_100kHz;
177 /* Enable update interrupt */
178 stm_tim6.dier = (1 << STM_TIM67_DIER_UIE);
180 /* Poke timer to reload values */
181 stm_tim6.egr |= (1 << STM_TIM67_EGR_UG);
183 stm_tim6.cr2 = (STM_TIM67_CR2_MMS_RESET << STM_TIM67_CR2_MMS);
185 /* And turn it off (for now) */