Skip to content

Commit 0b94ab7

Browse files
Jeppe Odgaardjhedberg
authored andcommitted
drivers: sensors: add veaa_x_3 proportional pressure regulator sensor
Add driver for Festo VEAA-X-3 series proportional pressure regulator. The driver assumes that the maximum ADC value matches the maximum output from the device, and that the maximum DAC value matches the maximum input value for the device. External hardware is probably required between the ADC/DAC and the device. Signed-off-by: Jeppe Odgaard <jeppe.odgaard@prevas.dk>
1 parent 5e4d552 commit 0b94ab7

File tree

6 files changed

+269
-0
lines changed

6 files changed

+269
-0
lines changed

drivers/sensor/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ add_subdirectory_ifdef(CONFIG_SBS_GAUGE sbs_gauge)
6262
add_subdirectory_ifdef(CONFIG_SX9500 sx9500)
6363
add_subdirectory_ifdef(CONFIG_TH02 th02)
6464
add_subdirectory_ifdef(CONFIG_TSIC_XX6 tsic_xx6)
65+
add_subdirectory_ifdef(CONFIG_VEAA_X_3 veaa_x_3)
6566
add_subdirectory_ifdef(CONFIG_VOLTAGE_DIVIDER voltage_divider)
6667
add_subdirectory_ifdef(CONFIG_TACH_ENE_KB1200 ene_tach_kb1200)
6768

drivers/sensor/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ source "drivers/sensor/sbs_gauge/Kconfig"
143143
source "drivers/sensor/sx9500/Kconfig"
144144
source "drivers/sensor/th02/Kconfig"
145145
source "drivers/sensor/tsic_xx6/Kconfig"
146+
source "drivers/sensor/veaa_x_3/Kconfig"
146147
source "drivers/sensor/voltage_divider/Kconfig"
147148
source "drivers/sensor/ene_tach_kb1200/Kconfig"
148149

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
zephyr_library()
4+
5+
zephyr_library_sources(veaa_x_3.c)

drivers/sensor/veaa_x_3/Kconfig

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# VEAA-X-3 configuration options
2+
3+
# Copyright (c) 2024, Vitrolife A/S
4+
# SPDX-License-Identifier: Apache-2.0
5+
6+
config VEAA_X_3
7+
bool "VEAA-X-3 pressure driver"
8+
default y
9+
depends on DT_HAS_FESTO_VEAA_X_3_ENABLED
10+
depends on ADC
11+
depends on DAC
12+
help
13+
Enable driver for Festo VEAA-X-3.
14+
15+
The driver assumes that the maximum ADC value matches the maximum
16+
output from the device, and that the maximum DAC value matches the
17+
maximum input value for the device. External hardware is probably
18+
required between the ADC/DAC and the device.

drivers/sensor/veaa_x_3/veaa_x_3.c

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
/*
2+
* Copyright (c) 2024, Vitrolife A/S
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*
6+
* Datasheet:
7+
* https://www.festo.com/media/pim/620/D15000100140620.PDF
8+
*
9+
*/
10+
11+
#define DT_DRV_COMPAT festo_veaa_x_3
12+
13+
#include <stdio.h>
14+
15+
#include <zephyr/device.h>
16+
#include <zephyr/drivers/adc.h>
17+
#include <zephyr/drivers/dac.h>
18+
#include <zephyr/drivers/sensor.h>
19+
#include <zephyr/drivers/sensor/veaa_x_3.h>
20+
#include <zephyr/logging/log.h>
21+
#include <zephyr/sys/math_extras.h>
22+
#include <zephyr/sys/util_macro.h>
23+
24+
LOG_MODULE_REGISTER(veaa_x_3_sensor, CONFIG_SENSOR_LOG_LEVEL);
25+
26+
struct veaa_x_3_data {
27+
uint16_t adc_buf;
28+
};
29+
30+
struct veaa_x_3_cfg {
31+
const struct adc_dt_spec adc;
32+
const struct device *dac;
33+
const uint8_t dac_channel;
34+
const uint8_t dac_resolution;
35+
const uint16_t kpa_max;
36+
const uint8_t kpa_min;
37+
};
38+
39+
static uint16_t veaa_x_3_kpa_range(const struct veaa_x_3_cfg *cfg)
40+
{
41+
return cfg->kpa_max - cfg->kpa_min;
42+
}
43+
44+
static int veaa_x_3_attr_set(const struct device *dev, enum sensor_channel chan,
45+
enum sensor_attribute attr, const struct sensor_value *val)
46+
{
47+
const struct veaa_x_3_cfg *cfg = dev->config;
48+
uint32_t tmp;
49+
50+
if (chan != SENSOR_CHAN_PRESS) {
51+
return -ENOTSUP;
52+
}
53+
54+
switch ((enum sensor_attribute_veaa_x_3)attr) {
55+
case SENSOR_ATTR_VEAA_X_3_SETPOINT:
56+
if (val->val1 > cfg->kpa_max || val->val1 < cfg->kpa_min) {
57+
LOG_ERR("%d kPa outside range", val->val1);
58+
return -EINVAL;
59+
}
60+
61+
/* Convert from kPa to DAC value */
62+
tmp = val->val1 - cfg->kpa_min;
63+
if (u32_mul_overflow(tmp, BIT(cfg->dac_resolution) - 1, &tmp)) {
64+
LOG_ERR("kPa to DAC overflow");
65+
return -ERANGE;
66+
}
67+
tmp /= veaa_x_3_kpa_range(cfg);
68+
69+
return dac_write_value(cfg->dac, cfg->dac_channel, tmp);
70+
default:
71+
return -ENOTSUP;
72+
}
73+
}
74+
75+
static int veaa_x_3_attr_get(const struct device *dev, enum sensor_channel chan,
76+
enum sensor_attribute attr, struct sensor_value *val)
77+
{
78+
const struct veaa_x_3_cfg *cfg = dev->config;
79+
80+
if (chan != SENSOR_CHAN_PRESS) {
81+
return -ENOTSUP;
82+
}
83+
84+
switch ((enum sensor_attribute_veaa_x_3)attr) {
85+
case SENSOR_ATTR_VEAA_X_3_RANGE:
86+
val->val1 = cfg->kpa_min;
87+
val->val2 = cfg->kpa_max;
88+
return 0;
89+
default:
90+
return -ENOTSUP;
91+
}
92+
}
93+
94+
static int veaa_x_3_sample_fetch(const struct device *dev, enum sensor_channel chan)
95+
{
96+
int rc;
97+
const struct veaa_x_3_cfg *cfg = dev->config;
98+
struct veaa_x_3_data *data = dev->data;
99+
struct adc_sequence sequence = {
100+
.buffer = &data->adc_buf,
101+
.buffer_size = sizeof(data->adc_buf),
102+
};
103+
104+
if (chan != SENSOR_CHAN_PRESS && chan != SENSOR_CHAN_ALL) {
105+
return -ENOTSUP;
106+
}
107+
108+
rc = adc_sequence_init_dt(&cfg->adc, &sequence);
109+
if (rc != 0) {
110+
return rc;
111+
}
112+
sequence.options = NULL;
113+
sequence.buffer = &data->adc_buf;
114+
sequence.buffer_size = sizeof(data->adc_buf);
115+
sequence.calibrate = false;
116+
117+
rc = adc_read_dt(&cfg->adc, &sequence);
118+
if (rc != 0) {
119+
return rc;
120+
}
121+
122+
return 0;
123+
}
124+
125+
static int veaa_x_3_channel_get(const struct device *dev, enum sensor_channel chan,
126+
struct sensor_value *val)
127+
{
128+
const struct veaa_x_3_cfg *cfg = dev->config;
129+
struct veaa_x_3_data *data = dev->data;
130+
const uint32_t max_adc_val = BIT(cfg->adc.resolution) - 1;
131+
132+
if (chan != SENSOR_CHAN_PRESS) {
133+
return -ENOTSUP;
134+
}
135+
136+
/* Convert from ADC value to kPa */
137+
if (u32_mul_overflow(data->adc_buf, veaa_x_3_kpa_range(cfg), &val->val1)) {
138+
LOG_ERR("ADC to kPa overflow");
139+
return -ERANGE;
140+
}
141+
val->val2 = (val->val1 % max_adc_val) * 1000000 / max_adc_val;
142+
val->val1 = (val->val1 / max_adc_val) + cfg->kpa_min;
143+
144+
return 0;
145+
}
146+
147+
static const struct sensor_driver_api veaa_x_3_api_funcs = {
148+
.attr_set = veaa_x_3_attr_set,
149+
.attr_get = veaa_x_3_attr_get,
150+
.sample_fetch = veaa_x_3_sample_fetch,
151+
.channel_get = veaa_x_3_channel_get,
152+
};
153+
154+
static int veaa_x_3_init(const struct device *dev)
155+
{
156+
int rc;
157+
const struct veaa_x_3_cfg *cfg = dev->config;
158+
const struct dac_channel_cfg dac_cfg = {
159+
.channel_id = cfg->dac_channel,
160+
.resolution = cfg->dac_resolution,
161+
.buffered = false,
162+
};
163+
164+
LOG_DBG("Initializing %s with range %u-%u kPa", dev->name, cfg->kpa_min, cfg->kpa_max);
165+
166+
if (!adc_is_ready_dt(&cfg->adc)) {
167+
LOG_ERR("ADC not ready");
168+
return -ENODEV;
169+
}
170+
171+
rc = adc_channel_setup_dt(&cfg->adc);
172+
if (rc != 0) {
173+
LOG_ERR("%s setup failed: %d", cfg->adc.dev->name, rc);
174+
return -ENODEV;
175+
}
176+
177+
if (!device_is_ready(cfg->dac)) {
178+
LOG_ERR("DAC not ready");
179+
return -ENODEV;
180+
}
181+
182+
rc = dac_channel_setup(cfg->dac, &dac_cfg);
183+
if (rc != 0) {
184+
LOG_ERR("%s setup failed: %d", cfg->dac->name, rc);
185+
return -ENODEV;
186+
}
187+
188+
return 0;
189+
}
190+
191+
#define VEAA_X_3_RANGE_KPA_INIT(n) \
192+
COND_CODE_1(DT_INST_ENUM_HAS_VALUE(n, pressure_range_type, d11), ({.max = 1000, min = 5}), \
193+
(COND_CODE_1(DT_INST_ENUM_HAS_VALUE(n, pressure_range_type, d9), \
194+
({.max = 600, min = 3}), ({.max = 200, .min = 1}))))
195+
196+
#define VEAA_X_3_TYPE_INIT(n) \
197+
COND_CODE_1(DT_INST_ENUM_HAS_VALUE(n, pressure_range_type, d11), \
198+
(.kpa_max = 1000, .kpa_min = 5), \
199+
(COND_CODE_1(DT_INST_ENUM_HAS_VALUE(n, pressure_range_type, d9), \
200+
(.kpa_max = 600, kpa_min = 3), (.kpa_max = 200, .kpa_min = 1))))
201+
202+
#define VEAA_X_3_INIT(n) \
203+
\
204+
static struct veaa_x_3_data veaa_x_3_data_##n; \
205+
\
206+
static const struct veaa_x_3_cfg veaa_x_3_cfg_##n = { \
207+
.adc = ADC_DT_SPEC_INST_GET(n), \
208+
.dac = DEVICE_DT_GET(DT_INST_PHANDLE(n, dac)), \
209+
.dac_channel = DT_INST_PROP(n, dac_channel_id), \
210+
.dac_resolution = DT_INST_PROP(n, dac_resolution), \
211+
VEAA_X_3_TYPE_INIT(n)}; \
212+
\
213+
SENSOR_DEVICE_DT_INST_DEFINE(n, veaa_x_3_init, NULL, &veaa_x_3_data_##n, \
214+
&veaa_x_3_cfg_##n, POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \
215+
&veaa_x_3_api_funcs);
216+
217+
DT_INST_FOREACH_STATUS_OKAY(VEAA_X_3_INIT)
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright (c) 2024, Vitrolife A/S
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifndef ZEPHYR_INCLUDE_DRIVERS_SENSOR_VEAA_X_3_H_
8+
#define ZEPHYR_INCLUDE_DRIVERS_SENSOR_VEAA_X_3_H_
9+
10+
#ifdef __cplusplus
11+
extern "C" {
12+
#endif
13+
14+
#include <zephyr/drivers/sensor.h>
15+
16+
enum sensor_attribute_veaa_x_3 {
17+
/* Set pressure setpoint value in kPa. */
18+
SENSOR_ATTR_VEAA_X_3_SETPOINT = SENSOR_ATTR_PRIV_START,
19+
/* Supported pressure range in kPa. val1 is minimum and val2 is maximum */
20+
SENSOR_ATTR_VEAA_X_3_RANGE,
21+
};
22+
23+
#ifdef __cplusplus
24+
}
25+
#endif
26+
27+
#endif /* ZEPHYR_INCLUDE_DRIVERS_SENSOR_VEAA_X_3_H_ */

0 commit comments

Comments
 (0)