adc.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. /*
  2. * Copyright (c) 2006-2021, 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. #include <rtthread.h>
  13. #include <rtdevice.h>
  14. #include <string.h>
  15. #include <stdlib.h>
  16. #define DBG_TAG "adc"
  17. #define REFER_VOLTAGE 330 /*reference voltage, multiplied by 100 and reserve 2 decimal places for data accuracy*/
  18. #define DBG_LVL DBG_INFO
  19. #include <rtdbg.h>
  20. static rt_size_t _adc_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
  21. {
  22. rt_err_t result = RT_EOK;
  23. rt_size_t i;
  24. struct rt_adc_device *adc = (struct rt_adc_device *)dev;
  25. rt_uint32_t *value = (rt_uint32_t *)buffer;
  26. for (i = 0; i < size; i += sizeof(int))
  27. {
  28. result = adc->ops->convert(adc, pos + i, value);
  29. if (result != RT_EOK)
  30. {
  31. return 0;
  32. }
  33. value++;
  34. }
  35. return i;
  36. }
  37. static rt_err_t _adc_control(rt_device_t dev, int cmd, void *args)
  38. {
  39. rt_err_t result = -RT_EINVAL;
  40. rt_adc_device_t adc = (struct rt_adc_device *)dev;
  41. if (cmd == RT_ADC_CMD_ENABLE && adc->ops->enabled)
  42. {
  43. result = adc->ops->enabled(adc, (rt_uint32_t)args, RT_TRUE);
  44. }
  45. else if (cmd == RT_ADC_CMD_DISABLE && adc->ops->enabled)
  46. {
  47. result = adc->ops->enabled(adc, (rt_uint32_t)args, RT_FALSE);
  48. }
  49. else if (cmd == RT_ADC_CMD_GET_RESOLUTION && adc->ops->get_resolution)
  50. {
  51. rt_uint8_t resolution = adc->ops->get_resolution(adc);
  52. if(resolution != 0)
  53. {
  54. *((rt_uint8_t*)args) = resolution;
  55. LOG_D("resolution: %d bits", resolution);
  56. result = RT_EOK;
  57. }
  58. }
  59. return result;
  60. }
  61. #ifdef RT_USING_DEVICE_OPS
  62. const static struct rt_device_ops adc_ops =
  63. {
  64. RT_NULL,
  65. RT_NULL,
  66. RT_NULL,
  67. _adc_read,
  68. RT_NULL,
  69. _adc_control,
  70. };
  71. #endif
  72. 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)
  73. {
  74. rt_err_t result = RT_EOK;
  75. RT_ASSERT(ops != RT_NULL && ops->convert != RT_NULL);
  76. device->parent.type = RT_Device_Class_ADC;
  77. device->parent.rx_indicate = RT_NULL;
  78. device->parent.tx_complete = RT_NULL;
  79. #ifdef RT_USING_DEVICE_OPS
  80. device->parent.ops = &adc_ops;
  81. #else
  82. device->parent.init = RT_NULL;
  83. device->parent.open = RT_NULL;
  84. device->parent.close = RT_NULL;
  85. device->parent.read = _adc_read;
  86. device->parent.write = RT_NULL;
  87. device->parent.control = _adc_control;
  88. #endif
  89. device->ops = ops;
  90. device->parent.user_data = (void *)user_data;
  91. result = rt_device_register(&device->parent, name, RT_DEVICE_FLAG_RDWR);
  92. return result;
  93. }
  94. rt_uint32_t rt_adc_read(rt_adc_device_t dev, rt_uint32_t channel)
  95. {
  96. rt_uint32_t value;
  97. RT_ASSERT(dev);
  98. dev->ops->convert(dev, channel, &value);
  99. return value;
  100. }
  101. rt_err_t rt_adc_enable(rt_adc_device_t dev, rt_uint32_t channel)
  102. {
  103. rt_err_t result = RT_EOK;
  104. RT_ASSERT(dev);
  105. if (dev->ops->enabled != RT_NULL)
  106. {
  107. result = dev->ops->enabled(dev, channel, RT_TRUE);
  108. }
  109. else
  110. {
  111. result = -RT_ENOSYS;
  112. }
  113. return result;
  114. }
  115. rt_err_t rt_adc_disable(rt_adc_device_t dev, rt_uint32_t channel)
  116. {
  117. rt_err_t result = RT_EOK;
  118. RT_ASSERT(dev);
  119. if (dev->ops->enabled != RT_NULL)
  120. {
  121. result = dev->ops->enabled(dev, channel, RT_FALSE);
  122. }
  123. else
  124. {
  125. result = -RT_ENOSYS;
  126. }
  127. return result;
  128. }
  129. rt_uint32_t rt_adc_voltage(rt_adc_device_t dev, rt_uint32_t channel)
  130. {
  131. rt_uint32_t value = 0, voltage = 0;
  132. RT_ASSERT(dev);
  133. /*read the value and convert to voltage*/
  134. if (dev->ops->get_resolution != RT_NULL && dev->ops->convert != RT_NULL)
  135. {
  136. /*get the convert bits*/
  137. rt_uint8_t resolution = dev->ops->get_resolution(dev);
  138. dev->ops->convert(dev, channel, &value);
  139. voltage = value * REFER_VOLTAGE / (1 << resolution);
  140. }
  141. return voltage;
  142. }
  143. #ifdef RT_USING_FINSH
  144. static int adc(int argc, char **argv)
  145. {
  146. int value = 0, voltage = 0;
  147. rt_err_t result = -RT_ERROR;
  148. static rt_adc_device_t adc_device = RT_NULL;
  149. char *result_str;
  150. if (argc > 1)
  151. {
  152. if (!strcmp(argv[1], "probe"))
  153. {
  154. if (argc == 3)
  155. {
  156. adc_device = (rt_adc_device_t)rt_device_find(argv[2]);
  157. result_str = (adc_device == RT_NULL) ? "failure" : "success";
  158. rt_kprintf("probe %s %s \n", argv[2], result_str);
  159. }
  160. else
  161. {
  162. rt_kprintf("adc probe <device name> - probe adc by name\n");
  163. }
  164. }
  165. else
  166. {
  167. if (adc_device == RT_NULL)
  168. {
  169. rt_kprintf("Please using 'adc probe <device name>' first\n");
  170. return -RT_ERROR;
  171. }
  172. if (!strcmp(argv[1], "enable"))
  173. {
  174. if (argc == 3)
  175. {
  176. result = rt_adc_enable(adc_device, atoi(argv[2]));
  177. result_str = (result == RT_EOK) ? "success" : "failure";
  178. rt_kprintf("%s channel %d enables %s \n", adc_device->parent.parent.name, atoi(argv[2]), result_str);
  179. }
  180. else
  181. {
  182. rt_kprintf("adc enable <channel> - enable adc channel\n");
  183. }
  184. }
  185. else if (!strcmp(argv[1], "read"))
  186. {
  187. if (argc == 3)
  188. {
  189. value = rt_adc_read(adc_device, atoi(argv[2]));
  190. rt_kprintf("%s channel %d read value is 0x%08X \n", adc_device->parent.parent.name, atoi(argv[2]), value);
  191. }
  192. else
  193. {
  194. rt_kprintf("adc read <channel> - read adc value on the channel\n");
  195. }
  196. }
  197. else if (!strcmp(argv[1], "disable"))
  198. {
  199. if (argc == 3)
  200. {
  201. result = rt_adc_disable(adc_device, atoi(argv[2]));
  202. result_str = (result == RT_EOK) ? "success" : "failure";
  203. rt_kprintf("%s channel %d disable %s \n", adc_device->parent.parent.name, atoi(argv[2]), result_str);
  204. }
  205. else
  206. {
  207. rt_kprintf("adc disable <channel> - disable adc channel\n");
  208. }
  209. }
  210. else if (!strcmp(argv[1], "voltage"))
  211. {
  212. if(argc == 3)
  213. {
  214. voltage = rt_adc_voltage(adc_device, atoi(argv[2]));
  215. result_str = (result == RT_EOK) ? "success" : "failure";
  216. rt_kprintf("%s channel %d voltage is %d.%02d \n", adc_device->parent.parent.name, atoi(argv[2]), voltage / 100, voltage % 100);
  217. }
  218. else
  219. {
  220. rt_kprintf("adc convert voltage <channel> \n");
  221. }
  222. }
  223. else
  224. {
  225. rt_kprintf("Unknown command. Please enter 'adc' for help\n");
  226. }
  227. }
  228. }
  229. else
  230. {
  231. rt_kprintf("Usage: \n");
  232. rt_kprintf("adc probe <device name> - probe adc by name\n");
  233. rt_kprintf("adc read <channel> - read adc value on the channel\n");
  234. rt_kprintf("adc disable <channel> - disable adc channel\n");
  235. rt_kprintf("adc enable <channel> - enable adc channel\n");
  236. result = -RT_ERROR;
  237. }
  238. return RT_EOK;
  239. }
  240. MSH_CMD_EXPORT(adc, adc <device name> <option> <channel>);
  241. #endif /* RT_USING_FINSH */