1 /*
2  * Copyright (c) 2020 Vestas Wind Systems A/S
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/device.h>
8 #include <zephyr/drivers/sensor.h>
9 #include <zephyr/drivers/sensor/mcux_acmp.h>
10 #include <zephyr/kernel.h>
11 
12 #include <stdio.h>
13 
14 #ifdef CONFIG_BOARD_TWR_KE18F
15 #define ACMP_NODE  DT_NODELABEL(cmp2)
16 #define ACMP_POSITIVE 5
17 #define ACMP_NEGATIVE 5
18 #define ACMP_DAC_VREF 0
19 #elif defined(CONFIG_BOARD_MIMXRT1170_EVK)
20 #define ACMP_NODE  DT_NODELABEL(acmp1)
21 #define ACMP_POSITIVE 2
22 #define ACMP_NEGATIVE 7
23 /* Select Vin2. Vin1 is not used and tied to ground on this chip. Vin2 is from VDDA_1P8_IN. */
24 #define ACMP_DAC_VREF 1
25 #elif (defined(CONFIG_BOARD_FRDM_KE17Z) || defined(CONFIG_BOARD_FRDM_KE17Z512))
26 #define ACMP_NODE  DT_NODELABEL(cmp0)
27 #define ACMP_POSITIVE 4
28 #define ACMP_NEGATIVE 4
29 #define ACMP_DAC_VREF 0
30 #else
31 #error Unsupported board
32 #endif
33 
34 #define ACMP_DAC_VALUE 128
35 
36 struct acmp_attr {
37 	int16_t attr;
38 	int32_t val;
39 };
40 
41 static const struct acmp_attr attrs[] = {
42 #if MCUX_ACMP_HAS_INPSEL
43 	/* Positive input port set to MUX */
44 	{ .attr = SENSOR_ATTR_MCUX_ACMP_POSITIVE_PORT_INPUT, .val = 1 },
45 #endif
46 	/* Positive input channel */
47 	{ .attr = SENSOR_ATTR_MCUX_ACMP_POSITIVE_MUX_INPUT,
48 	  .val = ACMP_POSITIVE },
49 #if MCUX_ACMP_HAS_INNSEL
50 	/* Negative input port set to DAC */
51 	{ .attr = SENSOR_ATTR_MCUX_ACMP_NEGATIVE_PORT_INPUT, .val = 0 },
52 #endif
53 	/* Negative input channel */
54 	{ .attr = SENSOR_ATTR_MCUX_ACMP_NEGATIVE_MUX_INPUT,
55 	  .val = ACMP_NEGATIVE },
56 	/* DAC voltage reference */
57 	{ .attr = SENSOR_ATTR_MCUX_ACMP_DAC_VOLTAGE_REFERENCE,
58 	  .val = ACMP_DAC_VREF },
59 	/* DAC value */
60 	{ .attr = SENSOR_ATTR_MCUX_ACMP_DAC_VALUE, .val = ACMP_DAC_VALUE },
61 	/* Hysteresis level */
62 	{ .attr = SENSOR_ATTR_MCUX_ACMP_HYSTERESIS_LEVEL, .val = 3 },
63 #if MCUX_ACMP_HAS_DISCRETE_MODE
64 	/* Discrete mode */
65 	{ .attr = SENSOR_ATTR_MCUX_ACMP_POSITIVE_DISCRETE_MODE, .val = 1 },
66 #endif
67 #if MCUX_ACMP_HAS_OFFSET
68 	/* Offset level */
69 	{ .attr = SENSOR_ATTR_MCUX_ACMP_OFFSET_LEVEL, .val = 0 },
70 #endif
71 };
72 
73 static const int16_t triggers[] = {
74 	SENSOR_TRIG_MCUX_ACMP_OUTPUT_RISING,
75 	SENSOR_TRIG_MCUX_ACMP_OUTPUT_FALLING,
76 };
77 
acmp_input_handler(bool above_threshold)78 static void acmp_input_handler(bool above_threshold)
79 {
80 	if (above_threshold) {
81 		printf("ACMP input above threshold\n");
82 	} else {
83 		printf("ACMP input below threshold\n");
84 	}
85 }
86 
acmp_trigger_handler(const struct device * dev,const struct sensor_trigger * trigger)87 static void acmp_trigger_handler(const struct device *dev,
88 				 const struct sensor_trigger *trigger)
89 {
90 	ARG_UNUSED(dev);
91 
92 	acmp_input_handler((int16_t)trigger->type ==
93 			   SENSOR_TRIG_MCUX_ACMP_OUTPUT_RISING);
94 }
95 
main(void)96 int main(void)
97 {
98 	struct sensor_trigger trigger;
99 	const struct device *const acmp = DEVICE_DT_GET(ACMP_NODE);
100 	struct sensor_value val;
101 	int err;
102 	int i;
103 
104 	if (!device_is_ready(acmp)) {
105 		printf("ACMP device not ready");
106 		return 0;
107 	}
108 
109 	/* Set ACMP attributes */
110 	val.val2 = 0;
111 	for (i = 0; i < ARRAY_SIZE(attrs); i++) {
112 		val.val1 = attrs[i].val;
113 		err = sensor_attr_set(acmp, SENSOR_CHAN_MCUX_ACMP_OUTPUT,
114 				      attrs[i].attr, &val);
115 		if (err) {
116 			printf("failed to set attribute %d (err %d)", i, err);
117 			return 0;
118 		}
119 	}
120 
121 	/* Delay for analog components (DAC, CMP, ...) to settle */
122 	k_sleep(K_MSEC(1));
123 
124 	/* Set ACMP triggers */
125 	trigger.chan = SENSOR_CHAN_MCUX_ACMP_OUTPUT;
126 	for (i = 0; i < ARRAY_SIZE(triggers); i++) {
127 		trigger.type = triggers[i];
128 		err = sensor_trigger_set(acmp, &trigger, acmp_trigger_handler);
129 		if (err) {
130 			printf("failed to set trigger %d (err %d)", i, err);
131 			return 0;
132 		}
133 	}
134 
135 	printf("Adjust ACMP input voltage by turning the potentiometer\n");
136 
137 	/* Read initial state */
138 	err = sensor_sample_fetch(acmp);
139 	if (err) {
140 		printf("failed to fetch sample (err %d)", err);
141 		return 0;
142 	}
143 
144 	err = sensor_channel_get(acmp, SENSOR_CHAN_MCUX_ACMP_OUTPUT, &val);
145 	if (err) {
146 		printf("failed to get channel (err %d)", err);
147 		return 0;
148 	}
149 
150 	acmp_input_handler(val.val1 == 1);
151 
152 	/* Await trigger */
153 	while (true) {
154 		k_sleep(K_MSEC(1));
155 	}
156 	return 0;
157 }
158