14c030143e42662676f509c430f73827ff80cd12
[fw/altos] / src / drivers / ao_ads131a0x.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_ads131a0x.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_ads131a0x_sample      ao_ads131a0x_current;
31 uint8_t         nextchan = 0;
32 uint8_t         ao_ads131a0x_drdy;
33
34 static void
35 ao_ads131a0x_start(void) {
36         ao_spi_get_bit(AO_ADS131A0X_SPI_CS_PORT,
37                        AO_ADS131A0X_SPI_CS_PIN,
38                        AO_ADS131A0X_SPI_BUS,
39                        AO_ADS131A0X_SPI_SPEED);
40 }
41
42 static void
43 ao_ads131a0x_stop(void) {
44         ao_spi_put_bit(AO_ADS131A0X_SPI_CS_PORT,
45                        AO_ADS131A0X_SPI_CS_PIN,
46                        AO_ADS131A0X_SPI_BUS);
47 }
48
49 static uint8_t
50 ao_ads131a0x_reg_read(uint8_t addr)
51 {
52         uint8_t d[15];
53
54         d[0] = addr | (AO_ADS131A0X_RREG >> 8);
55         d[1] = 0;                       
56         d[2] = 0;                       
57         d[3] = 0;                       
58         d[4] = 0;                       
59         d[5] = 0;                       
60         d[6] = 0;                       
61         d[7] = 0;                       
62         d[8] = 0;                       
63         d[9] = 0;                       
64         d[10] = 0;                      
65         d[11] = 0;                      
66         d[12] = 0;                      
67         d[13] = 0;                      
68         d[14] = 0;                      
69         ao_ads131a0x_start();
70         ao_spi_send(d, 15, AO_ADS131A0X_SPI_BUS);
71         ao_ads131a0x_stop();
72
73         /* data isn't actually returned until the next frame */
74         d[0] = AO_ADS131A0X_NULL >> 8;
75         d[1] = AO_ADS131A0X_NULL & 0xff;
76         ao_ads131a0x_start();
77         ao_spi_duplex(d, d, 15, AO_ADS131A0X_SPI_BUS);
78         ao_ads131a0x_stop();
79
80         /* first byte is register number, second byte is the data */
81         PRINTD(DEBUG_LOW, "read %x = %x\n", addr, d[1]);
82
83         return d[1];
84 }
85
86 /*
87 static void
88 ao_ads131a0x_reg_write(uint8_t addr, uint8_t value)
89 {
90         uint8_t d[15];
91
92         PRINTD(DEBUG_LOW, "write %x %x\n", addr, value);
93         d[0] = addr | (AO_ADS131A0X_WREG >> 8);
94         d[1] = value;
95         d[2] = 0;                       
96         d[3] = 0;                       
97         d[4] = 0;                       
98         d[5] = 0;                       
99         d[6] = 0;                       
100         d[7] = 0;                       
101         d[8] = 0;                       
102         d[9] = 0;                       
103         d[10] = 0;                      
104         d[11] = 0;                      
105         d[12] = 0;                      
106         d[13] = 0;                      
107         d[14] = 0;                      
108         ao_ads131a0x_start();
109         ao_spi_send(d, 15, AO_ADS131A0X_SPI_BUS);
110         ao_ads131a0x_stop();
111 }
112 */
113
114 static void 
115 ao_ads131a0x_isr(void)
116 {
117         ao_ads131a0x_drdy = 1;
118         ao_wakeup(&ao_ads131a0x_drdy);
119 }
120
121 static void
122 ao_ads131a0x_setup(void)
123 {
124         uint8_t d[20];
125
126         ao_delay(1);
127
128         ao_gpio_set(AO_ADS131A0X_RESET_PORT, AO_ADS131A0X_RESET_PIN, 1);
129
130         ao_delay(1);
131
132         /* send unlock command?  why, if we've not locked it? */
133
134         uint8_t devid = ao_ads131a0x_reg_read(AO_ADS131A0X_ID_MSB);
135         if (devid != AO_ADS131A0X_ID_ADS131A04)
136                 ao_panic(AO_PANIC_SELF_TEST_ADS);
137
138         ao_exti_setup(AO_ADS131A0X_DRDY_PORT, AO_ADS131A0X_DRDY_PIN,
139                 AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH,
140                 ao_ads131a0x_isr);
141
142         /* register writes use top 16 bits of each 24-bit word */
143
144         d[0] = AO_ADS131A0X_A_SYS_CFG | (AO_ADS131A0X_WREGS >> 8);
145         d[1] = 8;       /* write (n-1) registers starting with A_SYS_CFG */
146         d[2] = 0;
147
148         d[3] = 0x78;    /* A_SYS_CFG - charge pump off, high res, 4.0V ref,
149                            internal ref on, 5/95% fault thresholds */
150         d[4] = 0x00;    /* D_SYS_CFG - watchdog off, crc on device words, 
151                            shortest done and hi-z delays, non-fixed size, 
152                            crc disabled */
153         d[5] = 0;
154
155         d[6] = 0x02;    /* CLK1 - crystal osc on, ICLK = CLKIN / 2 */
156         d[7] = 0x20;    /* CLK2 - MOD = ICLK / 2, DATA = MOD / 4096 */
157         d[8] = 0;
158
159         d[9] = 0x0f;    /* ADC_ENA - all channels powered up */
160         d[10] = 0;      /* reserved */
161         d[11] = 0;
162
163         d[12] = 0x00;   /* ADC1 - gain = 1 */
164         d[13] = 0x00;   /* ADC2 - gain = 1 */
165         d[14] = 0;
166
167         d[15] = 0x00;   /* ADC3 - gain = 1 */
168         d[16] = 0x00;   /* ADC4 - gain = 1 */
169         d[17] = 0;
170
171         ao_ads131a0x_start();
172         ao_spi_send(d, 18, AO_ADS131A0X_SPI_BUS);
173         ao_ads131a0x_stop();
174
175         /* start conversions */
176         
177         d[0] = AO_ADS131A0X_WAKEUP >> 8;
178         d[1] = AO_ADS131A0X_WAKEUP & 0xff;
179         d[2] = 0;
180         ao_ads131a0x_start();
181         ao_spi_send(d, 3, AO_ADS131A0X_SPI_BUS);
182         ao_ads131a0x_stop();
183
184         /* documented initialization sends the LOCK command here, but I can 
185            see no value in doing that! */
186 }
187
188 static void
189 ao_ads131a0x(void)
190 {
191         uint8_t d[15];
192
193         ao_ads131a0x_setup();
194
195         ao_exti_enable(AO_ADS131A0X_DRDY_PORT, AO_ADS131A0X_DRDY_PIN);
196
197         for (;;) {
198                 ao_arch_block_interrupts();
199                 ao_ads131a0x_drdy = 0;
200                 while (ao_ads131a0x_drdy == 0)
201                         ao_sleep(&ao_ads131a0x_drdy);
202                 ao_arch_release_interrupts();
203
204                 d[0] = AO_ADS131A0X_NULL >> 8;
205                 d[1] = AO_ADS131A0X_NULL & 0xff;
206                 d[2] = 0;                       
207                 d[3] = 0;                       
208                 d[4] = 0;                       
209                 d[5] = 0;                       
210                 d[6] = 0;                       
211                 d[7] = 0;                       
212                 d[8] = 0;                       
213                 d[9] = 0;                       
214                 d[10] = 0;                      
215                 d[11] = 0;                      
216                 d[12] = 0;                      
217                 d[13] = 0;                      
218                 d[14] = 0;                      
219
220                 ao_ads131a0x_start();
221                 ao_spi_duplex(d, d, 15, AO_ADS131A0X_SPI_BUS);
222                 ao_ads131a0x_stop();
223
224                 ao_ads131a0x_current.ain[0] = 
225                         d[3] << 16 | d[4] << 8 | d[5];
226                 ao_ads131a0x_current.ain[1] = 
227                         d[6] << 16 | d[7] << 8 | d[8];
228                 ao_ads131a0x_current.ain[2] = 
229                         d[9] << 16 | d[10] << 8 | d[11];
230                 ao_ads131a0x_current.ain[3] = 
231                         d[12] << 16 | d[13] << 8 | d[14];
232
233                 // FIXME
234                 //       we need to log this data somewhere
235
236                 ao_ads131a0x_drdy = 0;
237         }
238 }
239
240 static struct ao_task ao_ads131a0x_task;
241
242 static void
243 ao_ads131a0x_dump(void) 
244 {
245         static int done;
246
247         if (!done) {
248                 done = 1;
249                 ao_add_task(&ao_ads131a0x_task, ao_ads131a0x, "ads131a0x");
250         }
251                 
252         printf ("ADS131A0X value %d %d %d %d\n",
253                 ao_ads131a0x_current.ain[0],
254                 ao_ads131a0x_current.ain[1],
255                 ao_ads131a0x_current.ain[2],
256                 ao_ads131a0x_current.ain[3]);
257 }
258
259 const struct ao_cmds ao_ads131a0x_cmds[] = {
260         { ao_ads131a0x_dump,    "I\0Display ADS131A0X data" },
261         { 0, NULL },
262 };
263
264 void
265 ao_ads131a0x_init(void)
266 {
267         ao_cmd_register(ao_ads131a0x_cmds);
268
269         ao_enable_output(AO_ADS131A0X_RESET_PORT, AO_ADS131A0X_RESET_PIN, 0);
270
271         ao_spi_init_cs(AO_ADS131A0X_SPI_CS_PORT, 
272                 (1 << AO_ADS131A0X_SPI_CS_PIN));
273
274 //      ao_add_task(&ao_ads131a0x_task, ao_ads131a0x, "ads131a0x");
275 }