mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2026-08-24 11:08:38 +08:00
* feat[ADC V2]: add ADC V2 driver support add ADC V2 core APIs, session state management, and sequence read support add STM32 ADC V2 HAL backend with internal-channel and VREF handling add per-series STM32 ADC V2 default configuration headers wire ADC V2 Kconfig and SConscript integration for components and STM32 BSP drivers keep ADC V2 mutually exclusive with the legacy ADC driver path * feat[ADC V2]: add ADC V2 MSH special channel read support add generic ADC V2 MSH commands for probing, configuring, raw reads, voltage reads, and sequence reads add STM32 ADC V2 backend special commands for VREFINT, temperature sensor, and VBAT reads add STM32 helper APIs for special logical channels, sampling time, resolution, and temperature calculation wire ADC V2 MSH sources through Kconfig and SConscript * feat[ADC V2]: add ADC V2 stream DMA support add ADC V2 stream APIs with latest-frame and FIFO buffering policies wire STM32 ADC V2 to circular DMA stream mode with per-instance Kconfig options extend STM32 ADC config headers and DMA helpers for stream DMA configuration add FinSH stream commands for start, read, cancel, and stop operations handle Cortex-M7 cache-safe DMA buffers for STM32 stream sampling * feat[ADC V2]: add timer trigger support for ADC V2 streams add ADC V2 trigger configuration, validation, and lifecycle coordination add timer update trigger support through clock timer TRGO controls map STM32 ADC V2 timer update triggers to HAL external trigger selector fields add Kconfig, SConscript, and MSH entries for ADC trigger setup and inspection * feat[ADCV2]: add timer and comparator trigger selectors add ADC V2 timer compare and analog comparator trigger configuration support extend clock timer trigger config with compare event and channel fields wire STM32 ADC external trigger selector mappings for TIM update, TIM compare, and COMP output add FinSH trigger_set commands and Kconfig switches for timer and comparator trigger backends * fix[ADC V2]: resolve ADC V1 compatibility Kconfig loop * ci[ADC V2][stm32]: add ADC v2 peripheral config for stm32f407-rt-spark BSP
301 lines
8.4 KiB
C
301 lines
8.4 KiB
C
/*
|
|
* Copyright (c) 2006-2023, RT-Thread Development Team
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Change Logs:
|
|
* Date Author Notes
|
|
* 2018-05-07 aozima the first version
|
|
* 2018-11-16 Ernest Chen add finsh command and update adc function
|
|
* 2022-05-11 Stanley Lwin add finsh voltage conversion command
|
|
*/
|
|
|
|
#include <rtthread.h>
|
|
#include <rtdevice.h>
|
|
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#define DBG_TAG "adc"
|
|
#define DBG_LVL DBG_INFO
|
|
#include <rtdbg.h>
|
|
|
|
static rt_ssize_t _adc_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
|
|
{
|
|
rt_err_t result;
|
|
rt_size_t i;
|
|
struct rt_adc_device *adc = (struct rt_adc_device *)dev;
|
|
rt_uint32_t *value = (rt_uint32_t *)buffer;
|
|
|
|
for (i = 0; i < size; i++)
|
|
{
|
|
result = adc->ops->convert(adc, pos, value);
|
|
if (result != RT_EOK)
|
|
{
|
|
return 0;
|
|
}
|
|
value++;
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
static rt_err_t _adc_control(rt_device_t dev, int cmd, void *args)
|
|
{
|
|
rt_adc_device_t adc = (struct rt_adc_device *)dev;
|
|
rt_err_t result = -RT_ERROR;
|
|
|
|
if (cmd == RT_ADC_CMD_ENABLE && adc->ops->enabled)
|
|
{
|
|
result = adc->ops->enabled(adc, (rt_int8_t)(rt_base_t)args, RT_TRUE);
|
|
}
|
|
else if (cmd == RT_ADC_CMD_DISABLE && adc->ops->enabled)
|
|
{
|
|
result = adc->ops->enabled(adc, (rt_int8_t)(rt_base_t)args, RT_FALSE);
|
|
}
|
|
else if (cmd == RT_ADC_CMD_GET_RESOLUTION && adc->ops->get_resolution && args)
|
|
{
|
|
rt_uint8_t resolution = adc->ops->get_resolution(adc);
|
|
if (resolution != 0)
|
|
{
|
|
*((rt_uint8_t *)args) = resolution;
|
|
LOG_D("resolution: %d bits", resolution);
|
|
result = RT_EOK;
|
|
}
|
|
}
|
|
else if (cmd == RT_ADC_CMD_GET_VREF && adc->ops->get_vref && args)
|
|
{
|
|
rt_int16_t value = adc->ops->get_vref(adc);
|
|
if (value != 0)
|
|
{
|
|
*((rt_int16_t *)args) = value;
|
|
result = RT_EOK;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
#ifdef RT_USING_DEVICE_OPS
|
|
const static struct rt_device_ops adc_ops =
|
|
{
|
|
RT_NULL,
|
|
RT_NULL,
|
|
RT_NULL,
|
|
_adc_read,
|
|
RT_NULL,
|
|
_adc_control,
|
|
};
|
|
#endif
|
|
|
|
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)
|
|
{
|
|
RT_ASSERT(ops != RT_NULL && ops->convert != RT_NULL);
|
|
rt_err_t result;
|
|
|
|
device->parent.type = RT_Device_Class_ADC;
|
|
device->parent.rx_indicate = RT_NULL;
|
|
device->parent.tx_complete = RT_NULL;
|
|
|
|
#ifdef RT_USING_DEVICE_OPS
|
|
device->parent.ops = &adc_ops;
|
|
#else
|
|
device->parent.init = RT_NULL;
|
|
device->parent.open = RT_NULL;
|
|
device->parent.close = RT_NULL;
|
|
device->parent.read = _adc_read;
|
|
device->parent.write = RT_NULL;
|
|
device->parent.control = _adc_control;
|
|
#endif
|
|
device->ops = ops;
|
|
device->parent.user_data = (void *)user_data;
|
|
|
|
result = rt_device_register(&device->parent, name, RT_DEVICE_FLAG_RDWR);
|
|
|
|
return result;
|
|
}
|
|
|
|
rt_uint32_t rt_adc_read(rt_adc_device_t dev, rt_int8_t channel)
|
|
{
|
|
RT_ASSERT(dev);
|
|
rt_uint32_t value;
|
|
rt_err_t result;
|
|
|
|
result = dev->ops->convert(dev, channel, &value);
|
|
if (result != RT_EOK)
|
|
return 0;
|
|
|
|
return value;
|
|
}
|
|
|
|
rt_err_t rt_adc_enable(rt_adc_device_t dev, rt_int8_t channel)
|
|
{
|
|
RT_ASSERT(dev);
|
|
rt_err_t result;
|
|
|
|
if (dev->ops->enabled != RT_NULL)
|
|
{
|
|
result = dev->ops->enabled(dev, channel, RT_TRUE);
|
|
}
|
|
else
|
|
{
|
|
result = -RT_ENOSYS;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
rt_err_t rt_adc_disable(rt_adc_device_t dev, rt_int8_t channel)
|
|
{
|
|
RT_ASSERT(dev);
|
|
rt_err_t result;
|
|
|
|
if (dev->ops->enabled != RT_NULL)
|
|
{
|
|
result = dev->ops->enabled(dev, channel, RT_FALSE);
|
|
}
|
|
else
|
|
{
|
|
result = -RT_ENOSYS;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
rt_int16_t rt_adc_voltage(rt_adc_device_t dev, rt_int8_t channel)
|
|
{
|
|
RT_ASSERT(dev);
|
|
|
|
rt_uint32_t value;
|
|
rt_int16_t vref, voltage = 0;
|
|
rt_uint8_t resolution;
|
|
rt_err_t result;
|
|
|
|
/*get the resolution in bits*/
|
|
resolution = dev->ops->get_resolution(dev);
|
|
/*get the reference voltage*/
|
|
vref = dev->ops->get_vref(dev);
|
|
if (vref == 0)
|
|
goto _voltage_exit;
|
|
|
|
/*read the value and convert to voltage*/
|
|
result = dev->ops->enabled(dev, channel, RT_TRUE);
|
|
if (result != RT_EOK)
|
|
goto _voltage_exit;
|
|
result = dev->ops->convert(dev, channel, &value);
|
|
if (result != RT_EOK)
|
|
goto _voltage_exit;
|
|
result = dev->ops->enabled(dev, channel, RT_FALSE);
|
|
if (result != RT_EOK)
|
|
goto _voltage_exit;
|
|
voltage = value * vref / ((1 << resolution) - 1);
|
|
|
|
_voltage_exit:
|
|
return voltage;
|
|
}
|
|
|
|
#ifdef RT_USING_FINSH
|
|
|
|
static int adc(int argc, char **argv)
|
|
{
|
|
int value = 0;
|
|
rt_int16_t voltage = 0;
|
|
rt_err_t result = -RT_ERROR;
|
|
static rt_adc_device_t adc_device = RT_NULL;
|
|
char *result_str;
|
|
|
|
if (argc > 1)
|
|
{
|
|
if (!strcmp(argv[1], "probe"))
|
|
{
|
|
if (argc == 3)
|
|
{
|
|
adc_device = (rt_adc_device_t)rt_device_find(argv[2]);
|
|
result_str = (adc_device == RT_NULL) ? "failure" : "success";
|
|
rt_kprintf("probe %s %s \n", argv[2], result_str);
|
|
}
|
|
else
|
|
{
|
|
rt_kprintf("adc probe <device name> - probe adc by name\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (adc_device == RT_NULL)
|
|
{
|
|
rt_kprintf("Please using 'adc probe <device name>' first\n");
|
|
return -RT_ERROR;
|
|
}
|
|
if (!strcmp(argv[1], "enable"))
|
|
{
|
|
if (argc == 3)
|
|
{
|
|
result = rt_adc_enable(adc_device, atoi(argv[2]));
|
|
result_str = (result == RT_EOK) ? "success" : "failure";
|
|
rt_kprintf("%s channel %d enables %s \n", adc_device->parent.parent.name, (rt_base_t)atoi(argv[2]), result_str);
|
|
}
|
|
else
|
|
{
|
|
rt_kprintf("adc enable <channel> - enable adc channel\n");
|
|
}
|
|
}
|
|
else if (!strcmp(argv[1], "read"))
|
|
{
|
|
if (argc == 3)
|
|
{
|
|
value = rt_adc_read(adc_device, atoi(argv[2]));
|
|
rt_kprintf("%s channel %d read value is 0x%08X \n", adc_device->parent.parent.name, (rt_base_t)atoi(argv[2]), value);
|
|
}
|
|
else
|
|
{
|
|
rt_kprintf("adc read <channel> - read adc value on the channel\n");
|
|
}
|
|
}
|
|
else if (!strcmp(argv[1], "disable"))
|
|
{
|
|
if (argc == 3)
|
|
{
|
|
result = rt_adc_disable(adc_device, atoi(argv[2]));
|
|
result_str = (result == RT_EOK) ? "success" : "failure";
|
|
rt_kprintf("%s channel %d disable %s \n", adc_device->parent.parent.name, (rt_base_t)atoi(argv[2]), result_str);
|
|
}
|
|
else
|
|
{
|
|
rt_kprintf("adc disable <channel> - disable adc channel\n");
|
|
}
|
|
}
|
|
else if (!strcmp(argv[1], "voltage"))
|
|
{
|
|
if (argc == 3)
|
|
{
|
|
voltage = rt_adc_voltage(adc_device, atoi(argv[2]));
|
|
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);
|
|
}
|
|
else
|
|
{
|
|
rt_kprintf("adc convert voltage <channel> \n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rt_kprintf("Unknown command. Please enter 'adc' for help\n");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rt_kprintf("Usage: \n");
|
|
rt_kprintf("adc probe <device name> - probe adc by name\n");
|
|
rt_kprintf("adc read <channel> - read adc value on the channel\n");
|
|
rt_kprintf("adc disable <channel> - disable adc channel\n");
|
|
rt_kprintf("adc enable <channel> - enable adc channel\n");
|
|
rt_kprintf("adc voltage <channel> - read voltage on the channel\n");
|
|
|
|
result = -RT_ERROR;
|
|
}
|
|
return RT_EOK;
|
|
}
|
|
MSH_CMD_EXPORT(adc, adc [option]);
|
|
|
|
#endif /* RT_USING_FINSH */
|