Skip to content

Commit 02181a7

Browse files
committed
zephyr analog
1 parent 6ab423e commit 02181a7

File tree

11 files changed

+541
-3
lines changed

11 files changed

+541
-3
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
*
4+
* Copyright (c) 2022 Nordic Semiconductor ASA
5+
*/
6+
7+
/ {
8+
zephyr,user {
9+
io-channels = <&adc 0>, <&adc 1>, <&adc 7>;
10+
};
11+
};
12+
13+
&adc {
14+
#address-cells = <1>;
15+
#size-cells = <0>;
16+
17+
channel@0 {
18+
reg = <0>;
19+
zephyr,gain = "ADC_GAIN_1_6";
20+
zephyr,reference = "ADC_REF_INTERNAL";
21+
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
22+
zephyr,input-positive = <NRF_SAADC_AIN1>; /* P0.03 */
23+
zephyr,resolution = <12>;
24+
};
25+
26+
channel@1 {
27+
reg = <1>;
28+
zephyr,gain = "ADC_GAIN_1_6";
29+
zephyr,reference = "ADC_REF_INTERNAL";
30+
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
31+
zephyr,input-positive = <NRF_SAADC_AIN6>; /* P0.30 */
32+
zephyr,resolution = <12>;
33+
zephyr,oversampling = <8>;
34+
};
35+
36+
channel@7 {
37+
reg = <7>;
38+
zephyr,gain = "ADC_GAIN_1_6";
39+
zephyr,reference = "ADC_REF_INTERNAL";
40+
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
41+
zephyr,input-positive = <NRF_SAADC_AIN7>; /* P0.31 */
42+
zephyr,resolution = <12>;
43+
zephyr,oversampling = <4>;
44+
};
45+
};

build/devices/zephyr/targets/nrf52840dk/manifest.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
"zephyrConfig": {
1212
"CONFIG_USERSPACE": "n"
1313
},
14+
"zephyrOverlay": [
15+
"./analog.overlay"
16+
],
1417
"config": {
1518
},
1619
"defines": {

build/devices/zephyr/targets/stm32u5a9j_dk/manifest.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
"preload": "setup/target",
1111
"config": {
1212
},
13+
"zephyrShields": [
14+
"st_lcd_dsi_mb1835"
15+
],
1316
"defines": {
1417
}
1518
}

examples/io/analog/README.md

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,30 @@
1+
# Analog
2+
Updated: December 10, 2025
3+
4+
## Table of Contents
5+
6+
* [Zephyr Analog constructor](#zephyr-analog)
7+
* [ESP32 Analog Additions](#esp32-analog)
8+
* [Attenuation](#esp32-atten)
9+
* [Calibrated](#esp32-calib)
10+
* [Example](#esp32-example)
11+
12+
<a id="zephyr-analog"></a>
13+
# Zephyr Analog
14+
15+
## Constructor
16+
17+
For Zephyr, use `port` and `channel` to choose which analog channel to sample from.
18+
19+
```
20+
const analogInput = new device.io.Analog({
21+
port: "adc",
22+
channel: 0
23+
});
24+
```
25+
26+
<a id="esp32-analog"></a>
127
# ESP32 Analog Additions
2-
Updated: November 13, 2024
328

429
## Constructor
530

@@ -16,12 +41,14 @@ const analogInput = new device.io.Analog({
1641
```
1742

1843

44+
<a id="esp32-calib"></a>
1945
### `calibrated`
2046

2147
If the `calibrated` option is included in the analog constructor, the return value of `sample()` will be a calibrated value returned from the ADC driver, with values between 0 and `((1 << analog.resolution) - 1)`. For the ESP32, the device has a resolution of 12 bits, so the range is 0 to 4095.
2248

2349
The [ADC Calibration Driver](https://docs.espressif.com/projects/esp-idf/en/v5.3.1/esp32/api-reference/peripherals/adc_calibration.html) is used to provide a closer approximation to actual voltage. The voltage range measured can be adjusted with the `attenuation` option.
2450

51+
<a id="esp32-atten"></a>
2552
### `attenuation`
2653

2754
Using the `attenuation` function adjusts the measurement range of the ADC driver.
@@ -39,6 +66,7 @@ There are [four attenuation](https://docs.espressif.com/projects/esp-idf/en/rele
3966

4067
With an attenuation of 6 dB, 1750 mV presented at the pin will return 4095.
4168

69+
<a id="esp32-example"></a>
4270
### Example:
4371

4472
By default, an `analog` object will provide a calibrated output with an attenuation of 12 dB. So, at 2450 mV to the pin, the `sample()` value will be 4095.

modules/io/analog/zephyr/_analog.c

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
/*
2+
* Copyright (c) 2019-2025 Moddable Tech, Inc.
3+
*
4+
* This file is part of the Moddable SDK Runtime.
5+
*
6+
* The Moddable SDK Runtime is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU Lesser General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* The Moddable SDK Runtime is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU Lesser General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Lesser General Public License
17+
* along with the Moddable SDK Runtime. If not, see <http://www.gnu.org/licenses/>.
18+
*
19+
*/
20+
21+
/*
22+
Analog -
23+
*/
24+
25+
#include "xsmc.h" // xs bindings for microcontroller
26+
#include "xsHost.h" // esp platform support
27+
#include "mc.xs.h" // for xsID_* values
28+
#include "mc.devicetree.h"
29+
30+
#include <zephyr/device.h>
31+
#include <zephyr/devicetree.h>
32+
33+
#include "builtinCommon.h"
34+
35+
#if kModZephyrAnalogBusCount
36+
37+
struct AnalogRecord {
38+
xsSlot obj;
39+
uint32_t pin;
40+
uint8_t channel;
41+
uint8_t channel_idx;
42+
// struct adc_sequence sequence;
43+
// const struct device *port;
44+
};
45+
typedef struct AnalogRecord AnalogRecord;
46+
typedef struct AnalogRecord *Analog;
47+
48+
#if !DT_NODE_EXISTS(DT_PATH(zephyr_user)) || \
49+
!DT_NODE_HAS_PROP(DT_PATH(zephyr_user), io_channels)
50+
#error "No suitable devicetree overlay specified"
51+
#endif
52+
53+
#define DT_SPEC_AND_COMMA(node_id, prop, idx) \
54+
ADC_DT_SPEC_GET_BY_IDX(node_id, idx),
55+
56+
static const struct adc_dt_spec adc_channels[] = {
57+
DT_FOREACH_PROP_ELEM(DT_PATH(zephyr_user), io_channels, DT_SPEC_AND_COMMA)
58+
};
59+
60+
static int adc_channel_idx(int channel) {
61+
int i;
62+
for (i = 0; i < (sizeof(adc_channels)/sizeof(struct adc_dt_spec)); i++) {
63+
if (adc_channels[i].channel_id == channel)
64+
return i;
65+
}
66+
return -1;
67+
}
68+
69+
void xs_analog_constructor_(xsMachine *the)
70+
{
71+
Analog analog;
72+
uint32_t channel;
73+
xsSlot tmp;
74+
int err;
75+
int idx;
76+
77+
xsmcVars(2);
78+
79+
if (!xsmcHas(xsArg(0), xsID_port))
80+
xsRangeError("port required");
81+
if (!xsmcHas(xsArg(0), xsID_channel))
82+
xsRangeError("channel required");
83+
84+
xsmcGet(tmp, xsArg(0), xsID_port);
85+
const struct modZephyrAnalog *port = modZephyrGetAnalog(xsmcToString(tmp));
86+
if (NULL == port)
87+
xsRangeError("bad_port");
88+
89+
xsmcGet(xsVar(0), xsArg(0), xsID_channel);
90+
channel = builtinGetPin(the, &xsVar(0)); //
91+
92+
idx = adc_channel_idx(channel);
93+
if (-1 == idx)
94+
xsRangeError("bad_channel");
95+
if (!adc_is_ready_dt(&adc_channels[idx]))
96+
xsRangeError("adc controller not ready");
97+
98+
err = adc_channel_setup_dt(&adc_channels[idx]);
99+
if (err < 0)
100+
xsRangeError("could not set up adc channel");
101+
102+
builtinInitializeTarget(the);
103+
if (kIOFormatNumber != builtinInitializeFormat(the, kIOFormatNumber))
104+
xsRangeError("invalid format");
105+
106+
analog = c_malloc(sizeof(AnalogRecord));
107+
if (!analog)
108+
xsRangeError("no memory");
109+
110+
analog->obj = xsThis;
111+
xsRemember(analog->obj);
112+
xsmcSetHostData(xsThis, analog);
113+
analog->channel = channel;
114+
analog->channel_idx = idx;
115+
}
116+
117+
void xs_analog_destructor_(void *data)
118+
{
119+
Analog analog = data;
120+
if (!analog)
121+
return;
122+
123+
c_free(analog);
124+
}
125+
126+
void xs_analog_close_(xsMachine *the)
127+
{
128+
Analog analog = xsmcGetHostData(xsThis);;
129+
if (analog && xsmcGetHostDataValidate(xsThis, xs_analog_destructor_)) {
130+
xsForget(analog->obj);
131+
xs_analog_destructor_(analog);
132+
xsmcSetHostData(xsThis, NULL);
133+
xsmcSetHostDestructor(xsThis, NULL);
134+
}
135+
}
136+
137+
void xs_analog_read_(xsMachine *the)
138+
{
139+
Analog analog = xsmcGetHostDataValidate(xsThis, xs_analog_destructor_);
140+
int err;
141+
uint16_t value;
142+
struct adc_sequence sequence = {
143+
.buffer = &value,
144+
.buffer_size = sizeof(value),
145+
};
146+
147+
(void)adc_sequence_init_dt(&adc_channels[analog->channel_idx], &sequence);
148+
err = adc_read_dt(&adc_channels[analog->channel_idx], &sequence);
149+
if (err < 0)
150+
xsUnknownError("Analog read error");
151+
152+
xsmcSetInteger(xsResult, value);
153+
}
154+
155+
void xs_analog_get_resolution_(xsMachine *the)
156+
{
157+
Analog analog = xsmcGetHostDataValidate(xsThis, xs_analog_destructor_);
158+
159+
xsmcSetInteger(xsResult, adc_channels[analog->channel_idx].resolution);
160+
}
161+
162+
#else // !kModZephyrAnalogBusCount
163+
164+
void xs_analog_constructor_(xsMachine *the)
165+
{
166+
xsUnknownError("no Analog");
167+
}
168+
169+
void xs_analog_destructor_(void *) {}
170+
void xs_analog_close_(xsMachine *the) {}
171+
void xs_analog_read_(xsMachine *the) {}
172+
void xs_analog_get_resolution_(xsMachine *the) {}
173+
174+
#endif
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright (c) 2019-2025 Moddable Tech, Inc.
3+
*
4+
* This file is part of the Moddable SDK Runtime.
5+
*
6+
* The Moddable SDK Runtime is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU Lesser General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* The Moddable SDK Runtime is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU Lesser General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Lesser General Public License
17+
* along with the Moddable SDK Runtime. If not, see <http://www.gnu.org/licenses/>.
18+
*
19+
*/
20+
21+
class Analog extends Native("xs_analog_destructor_") {
22+
constructor(options) { super(); native("xs_analog_constructor_").call(this, options); }
23+
close() { return native("xs_analog_close_").call(this); }
24+
read() { return native("xs_analog_read_").call(this); }
25+
26+
get resolution() { return native("xs_analog_get_resolution_").call(this); }
27+
28+
get format() {
29+
return "number";
30+
}
31+
set format(value) {
32+
if ("number" !== value)
33+
throw new RangeError;
34+
}
35+
}
36+
37+
export default Analog;

modules/io/manifests/zephyr/manifest.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@
1212
],
1313
"commodetto/Bitmap": "$(COMMODETTO)/commodettoBitmap",
1414

15+
"embedded:io/analog": "$(IO)/analog/$(PLATFORM)/_analog",
1516
"embedded:io/digital": "$(IO)/digital/digital",
1617
"embedded:io/digitalbank": "$(IO)/digital/digitalbank",
1718
"embedded:io/i2c": "$(IO)/i2c/_i2c",
19+
"embedded:io/pwm": "$(IO)/pwm/$(PLATFORM)/*",
1820
"embedded:io/serial": "$(IO)/serial/$(PLATFORM)/*",
1921

2022
"system": "$(IO)/system/*"
@@ -37,5 +39,8 @@
3739
"...": {
3840
"error": "zephyr manifest"
3941
}
42+
},
43+
"zephyrConfig": {
44+
"CONFIG_ADC": "y"
4045
}
4146
}

0 commit comments

Comments
 (0)