1 /*
2 * Copyright (c) 2006-2023, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2018-05-07 aozima the first version
9 * 2018-11-16 Ernest Chen add finsh command and update adc function
10 * 2022-05-11 Stanley Lwin add finsh voltage conversion command
11 */
12
13 #include <rtthread.h>
14 #include <rtdevice.h>
15
16 #include <string.h>
17 #include <stdlib.h>
18
19 #define DBG_TAG "adc"
20 #define DBG_LVL DBG_INFO
21 #include <rtdbg.h>
22
_adc_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)23 static rt_ssize_t _adc_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
24 {
25 rt_err_t result;
26 rt_size_t i;
27 struct rt_adc_device *adc = (struct rt_adc_device *)dev;
28 rt_uint32_t *value = (rt_uint32_t *)buffer;
29
30 for (i = 0; i < size; i++)
31 {
32 result = adc->ops->convert(adc, pos, value);
33 if (result != RT_EOK)
34 {
35 return 0;
36 }
37 value++;
38 }
39
40 return i;
41 }
42
_adc_control(rt_device_t dev,int cmd,void * args)43 static rt_err_t _adc_control(rt_device_t dev, int cmd, void *args)
44 {
45 rt_adc_device_t adc = (struct rt_adc_device *)dev;
46 rt_err_t result = RT_ERROR;
47
48 if (cmd == RT_ADC_CMD_ENABLE && adc->ops->enabled)
49 {
50 result = adc->ops->enabled(adc, (rt_int8_t)(rt_base_t)args, RT_TRUE);
51 }
52 else if (cmd == RT_ADC_CMD_DISABLE && adc->ops->enabled)
53 {
54 result = adc->ops->enabled(adc, (rt_int8_t)(rt_base_t)args, RT_FALSE);
55 }
56 else if (cmd == RT_ADC_CMD_GET_RESOLUTION && adc->ops->get_resolution && args)
57 {
58 rt_uint8_t resolution = adc->ops->get_resolution(adc);
59 if (resolution != 0)
60 {
61 *((rt_uint8_t *)args) = resolution;
62 LOG_D("resolution: %d bits", resolution);
63 result = RT_EOK;
64 }
65 }
66 else if (cmd == RT_ADC_CMD_GET_VREF && adc->ops->get_vref && args)
67 {
68 rt_int16_t value = adc->ops->get_vref(adc);
69 if (value != 0)
70 {
71 *((rt_int16_t *)args) = value;
72 result = RT_EOK;
73 }
74 }
75
76 return result;
77 }
78
79 #ifdef RT_USING_DEVICE_OPS
80 const static struct rt_device_ops adc_ops =
81 {
82 RT_NULL,
83 RT_NULL,
84 RT_NULL,
85 _adc_read,
86 RT_NULL,
87 _adc_control,
88 };
89 #endif
90
rt_hw_adc_register(rt_adc_device_t device,const char * name,const struct rt_adc_ops * ops,const void * user_data)91 rt_err_t rt_hw_adc_register(rt_adc_device_t device, const char *name, const struct rt_adc_ops *ops, const void *user_data)
92 {
93 RT_ASSERT(ops != RT_NULL && ops->convert != RT_NULL);
94 rt_err_t result;
95
96 device->parent.type = RT_Device_Class_ADC;
97 device->parent.rx_indicate = RT_NULL;
98 device->parent.tx_complete = RT_NULL;
99
100 #ifdef RT_USING_DEVICE_OPS
101 device->parent.ops = &adc_ops;
102 #else
103 device->parent.init = RT_NULL;
104 device->parent.open = RT_NULL;
105 device->parent.close = RT_NULL;
106 device->parent.read = _adc_read;
107 device->parent.write = RT_NULL;
108 device->parent.control = _adc_control;
109 #endif
110 device->ops = ops;
111 device->parent.user_data = (void *)user_data;
112
113 result = rt_device_register(&device->parent, name, RT_DEVICE_FLAG_RDWR);
114
115 return result;
116 }
117
rt_adc_read(rt_adc_device_t dev,rt_int8_t channel)118 rt_uint32_t rt_adc_read(rt_adc_device_t dev, rt_int8_t channel)
119 {
120 RT_ASSERT(dev);
121 rt_uint32_t value;
122 rt_err_t result;
123
124 result = dev->ops->convert(dev, channel, &value);
125 if (result != RT_EOK)
126 return 0;
127
128 return value;
129 }
130
rt_adc_enable(rt_adc_device_t dev,rt_int8_t channel)131 rt_err_t rt_adc_enable(rt_adc_device_t dev, rt_int8_t channel)
132 {
133 RT_ASSERT(dev);
134 rt_err_t result;
135
136 if (dev->ops->enabled != RT_NULL)
137 {
138 result = dev->ops->enabled(dev, channel, RT_TRUE);
139 }
140 else
141 {
142 result = -RT_ENOSYS;
143 }
144
145 return result;
146 }
147
rt_adc_disable(rt_adc_device_t dev,rt_int8_t channel)148 rt_err_t rt_adc_disable(rt_adc_device_t dev, rt_int8_t channel)
149 {
150 RT_ASSERT(dev);
151 rt_err_t result;
152
153 if (dev->ops->enabled != RT_NULL)
154 {
155 result = dev->ops->enabled(dev, channel, RT_FALSE);
156 }
157 else
158 {
159 result = -RT_ENOSYS;
160 }
161
162 return result;
163 }
164
rt_adc_voltage(rt_adc_device_t dev,rt_int8_t channel)165 rt_int16_t rt_adc_voltage(rt_adc_device_t dev, rt_int8_t channel)
166 {
167 RT_ASSERT(dev);
168
169 rt_uint32_t value;
170 rt_int16_t vref, voltage;
171 rt_uint8_t resolution;
172 rt_err_t result;
173
174 /*get the resolution in bits*/
175 resolution = dev->ops->get_resolution(dev);
176 /*get the reference voltage*/
177 vref = dev->ops->get_vref(dev);
178 if (vref == 0)
179 goto _voltage_exit;
180
181 /*read the value and convert to voltage*/
182 result = dev->ops->enabled(dev, channel, RT_TRUE);
183 if (result != RT_EOK)
184 goto _voltage_exit;
185 result = dev->ops->convert(dev, channel, &value);
186 if (result != RT_EOK)
187 goto _voltage_exit;
188 result = dev->ops->enabled(dev, channel, RT_FALSE);
189 if (result != RT_EOK)
190 goto _voltage_exit;
191 voltage = value * vref / ((1 << resolution) - 1);
192
193 _voltage_exit:
194 return voltage;
195 }
196
197 #ifdef RT_USING_FINSH
198
adc(int argc,char ** argv)199 static int adc(int argc, char **argv)
200 {
201 int value = 0;
202 rt_int16_t voltage = 0;
203 rt_err_t result = -RT_ERROR;
204 static rt_adc_device_t adc_device = RT_NULL;
205 char *result_str;
206
207 if (argc > 1)
208 {
209 if (!strcmp(argv[1], "probe"))
210 {
211 if (argc == 3)
212 {
213 adc_device = (rt_adc_device_t)rt_device_find(argv[2]);
214 result_str = (adc_device == RT_NULL) ? "failure" : "success";
215 rt_kprintf("probe %s %s \n", argv[2], result_str);
216 }
217 else
218 {
219 rt_kprintf("adc probe <device name> - probe adc by name\n");
220 }
221 }
222 else
223 {
224 if (adc_device == RT_NULL)
225 {
226 rt_kprintf("Please using 'adc probe <device name>' first\n");
227 return -RT_ERROR;
228 }
229 if (!strcmp(argv[1], "enable"))
230 {
231 if (argc == 3)
232 {
233 result = rt_adc_enable(adc_device, atoi(argv[2]));
234 result_str = (result == RT_EOK) ? "success" : "failure";
235 rt_kprintf("%s channel %d enables %s \n", adc_device->parent.parent.name, (rt_base_t)atoi(argv[2]), result_str);
236 }
237 else
238 {
239 rt_kprintf("adc enable <channel> - enable adc channel\n");
240 }
241 }
242 else if (!strcmp(argv[1], "read"))
243 {
244 if (argc == 3)
245 {
246 value = rt_adc_read(adc_device, atoi(argv[2]));
247 rt_kprintf("%s channel %d read value is 0x%08X \n", adc_device->parent.parent.name, (rt_base_t)atoi(argv[2]), value);
248 }
249 else
250 {
251 rt_kprintf("adc read <channel> - read adc value on the channel\n");
252 }
253 }
254 else if (!strcmp(argv[1], "disable"))
255 {
256 if (argc == 3)
257 {
258 result = rt_adc_disable(adc_device, atoi(argv[2]));
259 result_str = (result == RT_EOK) ? "success" : "failure";
260 rt_kprintf("%s channel %d disable %s \n", adc_device->parent.parent.name, (rt_base_t)atoi(argv[2]), result_str);
261 }
262 else
263 {
264 rt_kprintf("adc disable <channel> - disable adc channel\n");
265 }
266 }
267 else if (!strcmp(argv[1], "voltage"))
268 {
269 if (argc == 3)
270 {
271 voltage = rt_adc_voltage(adc_device, atoi(argv[2]));
272 rt_kprintf("%s channel %d voltage is %d.%03dV \n", adc_device->parent.parent.name, (rt_base_t)atoi(argv[2]), voltage / 1000, voltage % 1000);
273 }
274 else
275 {
276 rt_kprintf("adc convert voltage <channel> \n");
277 }
278 }
279 else
280 {
281 rt_kprintf("Unknown command. Please enter 'adc' for help\n");
282 }
283 }
284 }
285 else
286 {
287 rt_kprintf("Usage: \n");
288 rt_kprintf("adc probe <device name> - probe adc by name\n");
289 rt_kprintf("adc read <channel> - read adc value on the channel\n");
290 rt_kprintf("adc disable <channel> - disable adc channel\n");
291 rt_kprintf("adc enable <channel> - enable adc channel\n");
292 rt_kprintf("adc voltage <channel> - read voltage on the channel\n");
293
294 result = -RT_ERROR;
295 }
296 return RT_EOK;
297 }
298 MSH_CMD_EXPORT(adc, adc [option]);
299
300 #endif /* RT_USING_FINSH */
301