altos: ADS1256 seems to be running fast enough with 8 MHz crystal and 2 MHz SPI
[fw/altos] / src / drivers / ao_ads1256.c
1 /*
2  * Copyright © 2019 Bdale Garbee <bdale@gag.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
15 #include <ao.h>
16 #include <ao_exti.h>
17 #include "ao_ads1256.h"
18
19 #define DEBUG_LOW       1
20 #define DEBUG_HIGH      2
21
22 #define DEBUG           0
23
24 #if DEBUG
25 #define PRINTD(l, ...) do { if (DEBUG & (l)) { printf ("\r%5u %s: ", ao_tick_count, __func__); printf(__VA_ARGS__); flush(); } } while(0)
26 #else
27 #define PRINTD(l,...)
28 #endif
29
30 struct ao_ads1256_sample        ao_ads1256_current;
31 uint8_t         nextchan = 0;
32 uint8_t         ao_ads1256_drdy;
33
34 static void
35 ao_ads1256_start(void) {
36         ao_spi_get_bit(AO_ADS1256_SPI_CS_PORT,
37                        AO_ADS1256_SPI_CS_PIN,
38                        AO_ADS1256_SPI_BUS,
39                        AO_ADS1256_SPI_SPEED);
40 }
41
42 static void
43 ao_ads1256_stop(void) {
44         ao_spi_put_bit(AO_ADS1256_SPI_CS_PORT,
45                        AO_ADS1256_SPI_CS_PIN,
46                        AO_ADS1256_SPI_BUS);
47 }
48
49
50 static uint8_t
51 ao_ads1256_reg_read(uint8_t addr)
52 {
53         uint8_t d[2];
54
55         d[0] = addr | AO_ADS1256_RREG;
56         d[1] = 0;                       
57         ao_ads1256_start();
58         ao_spi_send(d, 2, AO_ADS1256_SPI_BUS);
59         d[0] = 0;
60         ao_spi_recv(d, 1, AO_ADS1256_SPI_BUS);
61         ao_ads1256_stop();
62
63         PRINTD(DEBUG_LOW, "read %x = %x\n", addr, d[0]);
64
65         return d[0];
66 }
67
68 /*
69 static void
70 ao_ads1256_reg_write(uint8_t addr, uint8_t value)
71 {
72         uint8_t d[3];
73
74         PRINTD(DEBUG_LOW, "write %x %x\n", addr, value);
75         d[0] = addr | AO_ADS1256_WREG;
76         d[1] = 0;                       
77         d[2] = value;
78         ao_ads1256_start();
79         ao_spi_send(d, 3, AO_ADS1256_SPI_BUS);
80         ao_ads1256_stop();
81
82 }
83 */
84
85 static void 
86 ao_ads1256_isr(void)
87 {
88         ao_ads1256_drdy = 1;
89         ao_wakeup(&ao_ads1256_drdy);
90 }
91
92 static void
93 ao_ads1256_setup(void)
94 {
95         uint8_t d[20];
96
97         ao_delay(1);
98
99         /* set up interrupt on DRDY going low */
100
101         ao_exti_setup(AO_ADS1256_DRDY_PORT, AO_ADS1256_DRDY_PIN,
102                 AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH,
103                 ao_ads1256_isr);
104
105         /* read status register and confirm device id matches */
106
107         uint8_t devid = ao_ads1256_reg_read(AO_ADS1256_STATUS) >> 4;
108         if (devid != AO_ADS1256_ID_ADS1256)
109                 ao_panic(AO_PANIC_SELF_TEST_ADS);
110
111         /* write configuration registers, tell converter to start working */
112
113         d[0] = AO_ADS1256_STATUS | AO_ADS1256_WREG;
114         d[1] = 4;       /* write 5 registers starting with STATUS */
115         d[2] = 0x00;    /* msb first, auto-cal off, analog buffer disabled */
116         d[3] = 0x08;    /* mux AIN0 relative to AINCOM */
117         d[4] = 0x20;    /* clock out = fclkin, sensor detect off, pga gain 1 */
118         d[5] = 0xf0;    /* data rate 7500 SPS */
119         d[6] = 0xf0;    /* all gpio pins are inputs */
120         d[7] = AO_ADS1256_SYNC;
121         d[8] = AO_ADS1256_WAKEUP;
122         ao_ads1256_start();
123         ao_spi_send(d, 9, AO_ADS1256_SPI_BUS);
124         ao_ads1256_stop();
125 }
126
127 static void
128 ao_ads1256(void)
129 {
130         uint8_t d[6], curchan;
131
132         ao_ads1256_setup();
133
134         ao_exti_enable(AO_ADS1256_DRDY_PORT, AO_ADS1256_DRDY_PIN);
135
136         for (;;) {
137                 ao_arch_block_interrupts();
138                 ao_ads1256_drdy = 0;
139                 while (ao_ads1256_drdy == 0)
140                         ao_sleep(&ao_ads1256_drdy);
141                 ao_arch_release_interrupts();
142
143                 curchan = nextchan;
144                 nextchan = (nextchan + 1) % AO_ADS1256_CHANNELS;
145
146                 d[0] = AO_ADS1256_MUX | AO_ADS1256_WREG;
147                 d[1] = 0;                       /* write one register */
148                 d[2] = nextchan << 4 | 0x08; ;  /* relative to AINCOM */
149                 d[3] = AO_ADS1256_SYNC;
150                 d[4] = AO_ADS1256_WAKEUP;
151                 d[5] = AO_ADS1256_RDATA;
152                 ao_ads1256_start();
153                 ao_spi_send(d, 6, AO_ADS1256_SPI_BUS);
154                 ao_spi_recv(d, 3, AO_ADS1256_SPI_BUS);
155                 ao_ads1256_stop();
156
157                 ao_ads1256_current.ain[curchan] = 
158                         d[0] << 16 | d[1] << 8 | d[2];
159
160                 // FIXME
161                 //      If nextchan == 0, we have a complete set of inputs
162                 //      and we need to log them somewhere
163
164                 ao_ads1256_drdy = 0;
165         }
166 }
167
168 static struct ao_task ao_ads1256_task;
169
170 static void
171 ao_ads1256_dump(void)   
172 {
173         static int done;
174
175         if (!done) {
176                 done = 1;
177                 ao_add_task(&ao_ads1256_task, ao_ads1256, "ads1256");
178         }
179                 
180         printf ("ADS1256 value 0x%x 0x%x 0x%x 0x%x\n",
181                 ao_ads1256_current.ain[0],
182                 ao_ads1256_current.ain[1],
183                 ao_ads1256_current.ain[2],
184                 ao_ads1256_current.ain[3]);
185 }
186
187 const struct ao_cmds ao_ads1256_cmds[] = {
188         { ao_ads1256_dump,      "D\0Display ADS1256 data" },
189         { 0, NULL },
190 };
191
192 void
193 ao_ads1256_init(void)
194 {
195         ao_cmd_register(ao_ads1256_cmds);
196
197 //      ao_enable_output(AO_ADS1256_RESET_PORT, AO_ADS1256_RESET_PIN, 0);
198
199         ao_spi_init_cs(AO_ADS1256_SPI_CS_PORT, 
200                 (1 << AO_ADS1256_SPI_CS_PIN));
201
202 //      ao_add_task(&ao_ads1256_task, ao_ads1256, "ads1256");
203 }