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 *
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
3836struct 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};
4743typedef struct PWMRecord PWMRecord ;
4844typedef 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
6348void 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
140115void 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)
163134void 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
178151void 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
185160void xs_pwm_get_resolution_ (xsMachine * the )
0 commit comments