Skip to content

Commit dc35d20

Browse files
committed
zephyr: pwm led functionality
1 parent ddaa55d commit dc35d20

File tree

4 files changed

+73
-67
lines changed

4 files changed

+73
-67
lines changed

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@
99
},
1010
"preload": "setup/target",
1111
"zephyrConfig": {
12-
"CONFIG_USERSPACE": "n"
12+
"CONFIG_PWM": "y"
1313
},
1414
"zephyrOverlay": [
15-
"./analog.overlay"
15+
"./analog.overlay",
16+
"./pwm.overlay"
1617
],
1718
"config": {
1819
},
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
2+
&pinctrl {
3+
pwm0_custom: pwm0_custom {
4+
group1 {
5+
psels = <NRF_PSEL(PWM_OUT0, 0, 13)>,
6+
<NRF_PSEL(PWM_OUT1, 0, 14)>,
7+
<NRF_PSEL(PWM_OUT2, 0, 15)>,
8+
<NRF_PSEL(PWM_OUT3, 0, 16)>;
9+
nordic,invert;
10+
};
11+
};
12+
pwm0_csleep: pwm0_csleep {
13+
group1 {
14+
psels = <NRF_PSEL(PWM_OUT0, 0, 13)>,
15+
<NRF_PSEL(PWM_OUT1, 0, 14)>,
16+
<NRF_PSEL(PWM_OUT2, 0, 15)>,
17+
<NRF_PSEL(PWM_OUT3, 0, 16)>;
18+
low-power-enable;
19+
};
20+
};
21+
};
22+
23+
&pwm0 {
24+
status = "okay";
25+
pinctrl-0 = <&pwm0_custom>;
26+
pinctrl-1 = <&pwm0_csleep>;
27+
pinctrl-names = "default", "sleep";
28+
};
29+

modules/io/manifests/zephyr/manifest.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
}
4242
},
4343
"zephyrConfig": {
44-
"CONFIG_ADC": "y"
44+
"CONFIG_ADC": "y",
45+
"CONFIG_PWM": "y"
4546
}
4647
}

modules/io/pwm/zephyr/_pwm.c

Lines changed: 39 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019-2022 Moddable Tech, Inc.
2+
* Copyright (c) 2019-2025 Moddable Tech, Inc.
33
*
44
* This file is part of the Moddable SDK Runtime.
55
*
@@ -28,65 +28,42 @@
2828

2929
#include "builtinCommon.h"
3030

31-
#if 0 // kModZephyrPWMBusCount
31+
#if kModZephyrPWMBusCount
3232

33-
#include "hardware/pwm.h"
34-
#include "hardware/clocks.h"
35-
36-
#define RES_BITS_MAX 16
33+
#include <zephyr/device.h>
34+
#include <zephyr/drivers/pwm.h>
3735

3836
struct PWMRecord {
39-
uint8_t pin;
4037
int hz;
4138
int resolution;
42-
int duty;
43-
uint8_t slice;
44-
uint8_t channel;
39+
uint8_t channel;
40+
const struct device *port;
4541
xsSlot obj;
4642
};
4743
typedef struct PWMRecord PWMRecord;
4844
typedef struct PWMRecord *PWM;
4945

50-
uint32_t pwm_set_freq_duty(PWM pwm, uint32_t f, int d)
51-
{
52-
uint32_t clock = clock_get_hz(clk_sys);
53-
uint32_t clock_div = clock / f / 4096 + (clock % (f * 4096) != 0);
54-
if (0 == clock_div / 16)
55-
clock_div = 16;
56-
uint32_t wrap = clock * 16 / clock_div / f - 1;
57-
pwm_set_clkdiv_int_frac(pwm->slice, clock_div/16, clock_div & 0xF);
58-
pwm_set_wrap(pwm->slice, wrap);
59-
pwm_set_chan_level(pwm->slice, pwm->channel, (wrap * d) / (1 << pwm->resolution));
60-
return wrap;
61-
}
46+
#define RES_BITS_MAX 16
6247

6348
void xs_pwm_constructor_(xsMachine *the)
6449
{
50+
xsSlot tmp;
6551
PWM pwm = NULL;
66-
int pin;
67-
int hz = 1024 * 10;
52+
int hz = 1024 * 3;
6853
int resolution = 10;
69-
int duty = 0;
54+
int channel = 0;
7055

7156
xsmcVars(2);
7257

73-
if (xsmcHas(xsArg(0), xsID_from)) {
74-
xsmcGet(xsVar(1), xsArg(0), xsID_from);
75-
pwm = xsmcGetHostDataValidate(xsVar(1), xs_pwm_destructor_);
76-
pin = pwm->pin;
77-
duty = pwm->duty;
78-
hz = pwm->hz;
79-
resolution = pwm->resolution;
80-
}
81-
else {
82-
int i = 0;
83-
84-
xsmcGet(xsVar(0), xsArg(0), xsID_pin);
85-
pin = builtinGetPin(the, &xsVar(0));
58+
if (!xsmcHas(xsArg(0), xsID_port))
59+
xsRangeError("port required");
60+
xsmcGet(tmp, xsArg(0), xsID_port);
61+
const struct modZephyrPWM *port = modZephyrGetPWM(xsmcToString(tmp));
62+
if (NULL == port)
63+
xsRangeError("bad pwm port");
8664

87-
if (!builtinIsPinFree(pin))
88-
xsUnknownError("in use");
89-
}
65+
if (!device_is_ready(port->device))
66+
xsRangeError("pwm port not ready");
9067

9168
if (xsmcHas(xsArg(0), xsID_hz)) {
9269
xsmcGet(xsVar(0), xsArg(0), xsID_hz);
@@ -95,6 +72,13 @@ void xs_pwm_constructor_(xsMachine *the)
9572
xsRangeError("invalid hz");
9673
}
9774

75+
if (xsmcHas(xsArg(0), xsID_channel)) {
76+
xsmcGet(xsVar(0), xsArg(0), xsID_channel);
77+
channel = xsmcToInteger(xsVar(0));
78+
if (channel < 0)
79+
xsRangeError("invalid channel");
80+
}
81+
9882
if (xsmcHas(xsArg(0), xsID_resolution)) {
9983
xsmcGet(xsVar(0), xsArg(0), xsID_resolution);
10084
resolution = xsmcToInteger(xsVar(0));
@@ -106,7 +90,7 @@ void xs_pwm_constructor_(xsMachine *the)
10690
xsRangeError("invalid format");
10791

10892
if (NULL == pwm) {
109-
pwm = c_malloc(sizeof(PWMRecord));
93+
pwm = c_calloc(1, sizeof(PWMRecord));
11094
if (!pwm)
11195
xsRangeError("no memory");
11296
}
@@ -118,34 +102,21 @@ void xs_pwm_constructor_(xsMachine *the)
118102

119103
builtinInitializeTarget(the);
120104

121-
pwm->pin = pin;
122-
pwm->duty = duty;
123105
pwm->hz = hz;
124106
pwm->resolution = resolution;
107+
pwm->channel = channel;
108+
pwm->port = port->device;
125109
pwm->obj = xsThis;
126110

127-
pwm->slice = pwm_gpio_to_slice_num(pin);
128-
pwm->channel = pwm_gpio_to_channel(pin);
129-
130111
xsRemember(pwm->obj);
131112
xsmcSetHostData(xsThis, pwm);
132-
133-
builtinUsePin(pin);
134-
135-
gpio_set_function(pin, GPIO_FUNC_PWM);
136-
pwm_set_freq_duty(pwm, hz, duty);
137-
pwm_set_enabled(pwm->slice, true);
138113
}
139114

140115
void xs_pwm_destructor_(void *data)
141116
{
142117
PWM pwm = data;
143118
if (!pwm) return;
144119

145-
pwm_set_enabled(pwm->slice, false);
146-
gpio_deinit(pwm->pin);
147-
builtinFreePin(pwm->pin);
148-
149120
c_free(pwm);
150121
}
151122

@@ -163,23 +134,27 @@ void xs_pwm_close_(xsMachine *the)
163134
void xs_pwm_write_(xsMachine *the)
164135
{
165136
PWM pwm = xsmcGetHostDataValidate(xsThis, xs_pwm_destructor_);
166-
int max = (1 << pwm->resolution) - 1;
137+
int err;
138+
139+
int period = PWM_SEC(1) / pwm->hz;
167140
int value = xsmcToInteger(xsArg(0));
168141

169-
if ((value < 0) || (value > max))
142+
if ((value < 0) || (value > period))
170143
xsRangeError("invalid value");
171-
if (value == max)
172-
value += 1;
173-
pwm->duty = value;
174144

175-
pwm_set_freq_duty(pwm, pwm->hz, pwm->duty);
145+
double cycle = period / (1 << pwm->resolution);
146+
int pulse = (double)value * cycle;
147+
148+
err = pwm_set(pwm->port, pwm->channel, period, pulse, 0);
176149
}
177150

178151
void xs_pwm_get_hz_(xsMachine *the)
179152
{
180153
PWM pwm = xsmcGetHostDataValidate(xsThis, xs_pwm_destructor_);
154+
uint64_t cycles;
181155

182-
xsmcSetInteger(xsResult, pwm->hz);
156+
pwm_get_cycles_per_sec(pwm->port, pwm->channel, &cycles);
157+
xsmcSetInteger(xsResult, cycles);
183158
}
184159

185160
void xs_pwm_get_resolution_(xsMachine *the)

0 commit comments

Comments
 (0)