altos: Add quadrature driver
[fw/altos] / src / drivers / ao_quadrature.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 #include <ao_quadrature.h>
20 #include <ao_exti.h>
21
22 __xdata int32_t ao_quadrature_count;
23
24 static uint8_t  wait_clear;
25
26 static void
27 ao_quadrature_isr(void)
28 {
29         if (wait_clear) {
30                 wait_clear = 0;
31                 ao_exti_set_mode(AO_QUADRATURE_PORT, AO_QUADRATURE_A, AO_EXTI_MODE_RISING);
32         } else {
33                 wait_clear = 1;
34                 ao_exti_set_mode(AO_QUADRATURE_PORT, AO_QUADRATURE_A, AO_EXTI_MODE_FALLING);
35                 if (ao_gpio_get(AO_QUADRATURE_PORT, AO_QUADRATURE_B, AO_QUADRATURE_B_PIN))
36                         ao_quadrature_count++;
37                 else
38                         ao_quadrature_count--;
39                 ao_wakeup(&ao_quadrature_count);
40         }
41 }
42
43 int32_t
44 ao_quadrature_poll(void)
45 {
46         int32_t ret;
47         ao_arch_critical(ret = ao_quadrature_count;);
48         return ret;
49 }
50
51 int32_t
52 ao_quadrature_wait(void)
53 {
54         ao_sleep(&ao_quadrature_count);
55         return ao_quadrature_poll();
56 }
57
58 static void
59 ao_quadrature_test(void)
60 {
61 #if 0
62         for (;;) {
63                 int32_t c;
64                 printf ("waiting...\n");
65                 flush();
66                 c = ao_quadrature_wait();
67                 printf ("new count %d\n", c);
68                 if (ao_stdin_ready)
69                         break;
70         }
71 #endif
72         uint8_t a, old_a, b, old_b;
73
74         old_a = 2; old_b = 2;
75         for (;;) {
76                 a = ao_gpio_get(AO_QUADRATURE_PORT, AO_QUADRATURE_A, AO_QUADRATURE_A_PIN);
77                 b = ao_gpio_get(AO_QUADRATURE_PORT, AO_QUADRATURE_B, AO_QUADRATURE_B_PIN);
78                 if (a != old_a || b != old_b) {
79                         printf ("A %d B %d\n", a, b);
80                         flush();
81                         ao_yield();
82                         old_a = a;
83                         old_b = b;
84                 }
85                 if (ao_stdin_ready)
86                         break;
87         }
88                 
89 }
90
91 static const struct ao_cmds ao_quadrature_cmds[] = {
92         { ao_quadrature_test,   "q\0Test quadrature" },
93         { 0, NULL }
94 };
95
96 void
97 ao_quadrature_init(void)
98 {
99         ao_quadrature_count = 0;
100
101         ao_enable_port(AO_QUADRATURE_PORT);
102         ao_exti_setup(AO_QUADRATURE_PORT, AO_QUADRATURE_A,
103                       AO_EXTI_MODE_PULL_UP|AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_MED,
104                       ao_quadrature_isr);
105         ao_exti_enable(AO_QUADRATURE_PORT, AO_QUADRATURE_A);
106         ao_enable_input(AO_QUADRATURE_PORT, AO_QUADRATURE_B, AO_EXTI_MODE_PULL_UP);
107         ao_cmd_register(&ao_quadrature_cmds[0]);
108 }