Skip to content

Commit 1948a8c

Browse files
committed
zephyrCommon: Implement analogWrite()
The 'pwms' node under the 'zephyr,user' defines available PWM channels. The 'pwm-pins' defines the mapping of PWM channels to pin numbers. API looks up the 'pwm-pins' when querying the PWM channel by digital pin number. So it should be in the same order as 'pwms' node. PWM channels should configure and tied to the output pins. The period property of the PWM channel is used as resolution as PWM. For original Arduino API compatibility, it should be 255. The period property and API argument determines the duty ratio. Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@fujitsu.com>
1 parent 5a76d45 commit 1948a8c

File tree

7 files changed

+298
-0
lines changed

7 files changed

+298
-0
lines changed

cores/arduino/Arduino.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "api/ArduinoAPI.h"
88

99
#include <zephyr/drivers/gpio.h>
10+
#include <zephyr/drivers/pwm.h>
1011
#include <zephyr/kernel.h>
1112

1213
#include <variants.h>

cores/arduino/zephyrCommon.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,33 @@
66

77
#include <Arduino.h>
88

9+
#define PWM_DT_SPEC(n,p,i) PWM_DT_SPEC_GET_BY_IDX(n, i),
10+
#define PWM_PINS(n,p,i) DT_PROP_BY_IDX(n, p, i),
11+
12+
namespace {
13+
14+
#ifdef CONFIG_PWM
15+
16+
const struct pwm_dt_spec arduino_pwm[] =
17+
{ DT_FOREACH_PROP_ELEM(DT_PATH(zephyr_user), pwms, PWM_DT_SPEC) };
18+
19+
/* pwm-pins node provides a mapping digital pin numbers to pwm channels */
20+
const pin_size_t arduino_pwm_pins[] =
21+
{ DT_FOREACH_PROP_ELEM(DT_PATH(zephyr_user), pwm_pins, PWM_PINS) };
22+
23+
size_t pwm_pin_index(pin_size_t pinNumber) {
24+
for(size_t i=0; i<ARRAY_SIZE(arduino_pwm_pins); i++) {
25+
if (arduino_pwm_pins[i] == pinNumber) {
26+
return i;
27+
}
28+
}
29+
return (size_t)-1;
30+
}
31+
32+
#endif //CONFIG_PWM
33+
34+
}
35+
936
void yield(void) {
1037
k_yield();
1138
}
@@ -49,3 +76,28 @@ unsigned long micros(void) {
4976

5077
unsigned long millis(void) { return k_uptime_get_32(); }
5178

79+
#ifdef CONFIG_PWM
80+
81+
void analogWrite(pin_size_t pinNumber, int value)
82+
{
83+
size_t idx = pwm_pin_index(pinNumber);
84+
85+
if (idx >= ARRAY_SIZE(arduino_pwm) ) {
86+
return;
87+
}
88+
89+
if (((uint32_t)value) > arduino_pwm[idx].period) {
90+
value = arduino_pwm[idx].period;
91+
} else if (value < 0) {
92+
value = 0;
93+
}
94+
95+
/*
96+
* A duty ratio determines by the period value defined in dts
97+
* and the value arguments. So usually the period value sets as 255.
98+
*/
99+
(void)pwm_set_cycles(arduino_pwm[idx].dev, arduino_pwm[idx].channel,
100+
arduino_pwm[idx].period, value, arduino_pwm[idx].flags);
101+
}
102+
103+
#endif

variants/arduino_mkrzero/arduino_mkrzero.overlay

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,27 @@
2727
d19_gpios = <&arduino_mkr_header 19 0>; /* D19 / A5 / I2C-SCL */
2828
d20_gpios = <&arduino_mkr_header 20 0>;
2929
d21_gpios = <&arduino_mkr_header 21 0>;
30+
pwms = <&tcc0 2 255>,
31+
<&tcc0 3 255>;
32+
pwm-pins = <2 3>;
3033
};
3134
};
35+
36+
&pinctrl {
37+
pwm_default: pwm_default {
38+
group1 {
39+
pinmux = <PA10F_TCC0_WO2>,
40+
<PA11F_TCC0_WO3>;
41+
};
42+
};
43+
};
44+
45+
&tcc0 {
46+
status = "okay";
47+
compatible = "atmel,sam0-tcc-pwm";
48+
prescaler = <2>;
49+
#pwm-cells = <2>;
50+
51+
pinctrl-0 = <&pwm_default>;
52+
pinctrl-names = "default";
53+
};

variants/arduino_nano_33_ble/arduino_nano_33_ble.overlay

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,69 @@
2222
d19_gpios = <&arduino_nano_header 19 0>; /* D19 / A5 / I2C-SCL */
2323
d20_gpios = <&arduino_nano_header 20 0>;
2424
d21_gpios = <&arduino_nano_header 21 0>;
25+
pwms = <&pwm1 1 255 PWM_POLARITY_NORMAL>,
26+
<&pwm1 2 255 PWM_POLARITY_NORMAL>,
27+
<&pwm1 3 255 PWM_POLARITY_NORMAL>,
28+
<&pwm2 0 255 PWM_POLARITY_NORMAL>,
29+
<&pwm2 1 255 PWM_POLARITY_NORMAL>,
30+
<&pwm2 2 255 PWM_POLARITY_NORMAL>,
31+
<&pwm2 3 255 PWM_POLARITY_NORMAL>;
32+
pwm-pins = <3 5 6 13 9 10 11>;
2533
};
2634
};
35+
36+
&pinctrl {
37+
pwm1_default: pwm1_default {
38+
group1 {
39+
psels = <NRF_PSEL(PWM_OUT0, 1, 9)>, /* keep original config */
40+
<NRF_PSEL(PWM_OUT1, 1, 12)>,
41+
<NRF_PSEL(PWM_OUT2, 1, 13)>,
42+
<NRF_PSEL(PWM_OUT3, 1, 14)>;
43+
nordic,invert;
44+
};
45+
};
46+
47+
pwm1_sleep: pwm1_sleep {
48+
group1 {
49+
psels = <NRF_PSEL(PWM_OUT0, 1, 9)>, /* keep original config */
50+
<NRF_PSEL(PWM_OUT1, 1, 12)>,
51+
<NRF_PSEL(PWM_OUT2, 1, 13)>,
52+
<NRF_PSEL(PWM_OUT3, 1, 14)>;
53+
low-power-enable;
54+
};
55+
};
56+
57+
pwm2_default: pwm2_default {
58+
group1 {
59+
psels = <NRF_PSEL(PWM_OUT0, 0, 13)>, /* keep original config */
60+
<NRF_PSEL(PWM_OUT1, 0, 27)>,
61+
<NRF_PSEL(PWM_OUT2, 1, 2)>,
62+
<NRF_PSEL(PWM_OUT3, 1, 1)>;
63+
nordic,invert;
64+
};
65+
};
66+
67+
pwm2_sleep: pwm2_sleep {
68+
group1 {
69+
psels = <NRF_PSEL(PWM_OUT0, 0, 13)>, /* keep original config */
70+
<NRF_PSEL(PWM_OUT1, 0, 27)>,
71+
<NRF_PSEL(PWM_OUT2, 1, 2)>,
72+
<NRF_PSEL(PWM_OUT3, 1, 1)>;
73+
low-power-enable;
74+
};
75+
};
76+
};
77+
78+
&pwm1 {
79+
status = "okay";
80+
pinctrl-0 = <&pwm1_default>;
81+
pinctrl-1 = <&pwm1_sleep>;
82+
pinctrl-names = "default", "sleep";
83+
};
84+
85+
&pwm2 {
86+
status = "okay";
87+
pinctrl-0 = <&pwm2_default>;
88+
pinctrl-1 = <&pwm2_sleep>;
89+
pinctrl-names = "default", "sleep";
90+
};

variants/arduino_nano_33_ble_sense/arduino_nano_33_ble_sense.overlay

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,69 @@
2222
d19_gpios = <&arduino_nano_header 19 0>; /* D19 / A5 / I2C-SCL */
2323
d20_gpios = <&arduino_nano_header 20 0>;
2424
d21_gpios = <&arduino_nano_header 21 0>;
25+
pwms = <&pwm1 1 255 PWM_POLARITY_NORMAL>,
26+
<&pwm1 2 255 PWM_POLARITY_NORMAL>,
27+
<&pwm1 3 255 PWM_POLARITY_NORMAL>,
28+
<&pwm2 0 255 PWM_POLARITY_NORMAL>,
29+
<&pwm2 1 255 PWM_POLARITY_NORMAL>,
30+
<&pwm2 2 255 PWM_POLARITY_NORMAL>,
31+
<&pwm2 3 255 PWM_POLARITY_NORMAL>;
32+
pwm-pins = <3 5 6 13 9 10 11>;
2533
};
2634
};
35+
36+
&pinctrl {
37+
pwm1_default: pwm1_default {
38+
group1 {
39+
psels = <NRF_PSEL(PWM_OUT0, 1, 9)>, /* keep original config */
40+
<NRF_PSEL(PWM_OUT1, 1, 12)>,
41+
<NRF_PSEL(PWM_OUT2, 1, 13)>,
42+
<NRF_PSEL(PWM_OUT3, 1, 14)>;
43+
nordic,invert;
44+
};
45+
};
46+
47+
pwm1_sleep: pwm1_sleep {
48+
group1 {
49+
psels = <NRF_PSEL(PWM_OUT0, 1, 9)>, /* keep original config */
50+
<NRF_PSEL(PWM_OUT1, 1, 12)>,
51+
<NRF_PSEL(PWM_OUT2, 1, 13)>,
52+
<NRF_PSEL(PWM_OUT3, 1, 14)>;
53+
low-power-enable;
54+
};
55+
};
56+
57+
pwm2_default: pwm2_default {
58+
group1 {
59+
psels = <NRF_PSEL(PWM_OUT0, 0, 13)>, /* keep original config */
60+
<NRF_PSEL(PWM_OUT1, 0, 27)>,
61+
<NRF_PSEL(PWM_OUT2, 1, 2)>,
62+
<NRF_PSEL(PWM_OUT3, 1, 1)>;
63+
nordic,invert;
64+
};
65+
};
66+
67+
pwm2_sleep: pwm2_sleep {
68+
group1 {
69+
psels = <NRF_PSEL(PWM_OUT0, 0, 13)>, /* keep original config */
70+
<NRF_PSEL(PWM_OUT1, 0, 27)>,
71+
<NRF_PSEL(PWM_OUT2, 1, 2)>,
72+
<NRF_PSEL(PWM_OUT3, 1, 1)>;
73+
low-power-enable;
74+
};
75+
};
76+
};
77+
78+
&pwm1 {
79+
status = "okay";
80+
pinctrl-0 = <&pwm1_default>;
81+
pinctrl-1 = <&pwm1_sleep>;
82+
pinctrl-names = "default", "sleep";
83+
};
84+
85+
&pwm2 {
86+
status = "okay";
87+
pinctrl-0 = <&pwm2_default>;
88+
pinctrl-1 = <&pwm2_sleep>;
89+
pinctrl-names = "default", "sleep";
90+
};

variants/arduino_nano_33_iot/arduino_nano_33_iot.overlay

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,39 @@
2222
d19_gpios = <&arduino_nano_header 19 0>; /* D19 / A5 / I2C-SCL */
2323
d20_gpios = <&arduino_nano_header 20 0>;
2424
d21_gpios = <&arduino_nano_header 21 0>;
25+
pwms = <&tcc0 0 255>,
26+
<&tcc0 1 255>,
27+
<&tcc0 2 255>,
28+
<&tcc0 3 255>,
29+
<&tcc0 4 255>,
30+
<&tcc0 5 255>,
31+
<&tcc0 6 255>,
32+
<&tcc0 7 255>;
33+
pwm-pins = <6 5 17 12 2 3 9 10>;
2534
};
2635
};
36+
37+
&pinctrl {
38+
pwm_default: pwm_default {
39+
group1 {
40+
pinmux = <PA4E_TCC0_WO0>,
41+
<PA5E_TCC0_WO1>,
42+
<PA10F_TCC0_WO2>,
43+
<PA19F_TCC0_WO3>,
44+
<PB10F_TCC0_WO4>,
45+
<PB11F_TCC0_WO5>,
46+
<PA20F_TCC0_WO6>,
47+
<PA21F_TCC0_WO7>;
48+
};
49+
};
50+
};
51+
52+
&tcc0 {
53+
status = "okay";
54+
compatible = "atmel,sam0-tcc-pwm";
55+
prescaler = <2>;
56+
#pwm-cells = <2>;
57+
58+
pinctrl-0 = <&pwm_default>;
59+
pinctrl-names = "default";
60+
};

variants/nrf52840dk_nrf52840/nrf52840dk_nrf52840.overlay

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,66 @@
2323
d20_gpios = <&arduino_header 4 0>;
2424
d21_gpios = <&arduino_header 5 0>;
2525
d22_gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
26+
pwms = <&pwm0 1 255 PWM_POLARITY_NORMAL>,
27+
<&pwm0 2 255 PWM_POLARITY_NORMAL>,
28+
<&pwm0 3 255 PWM_POLARITY_NORMAL>,
29+
<&pwm1 0 255 PWM_POLARITY_NORMAL>,
30+
<&pwm1 1 255 PWM_POLARITY_NORMAL>,
31+
<&pwm1 2 255 PWM_POLARITY_NORMAL>;
32+
pwm-pins = <22 3 5 6 9 10 11>;
2633
};
2734
};
35+
36+
&pinctrl {
37+
pwm0_default: pwm0_default {
38+
group1 {
39+
psels = <NRF_PSEL(PWM_OUT0, 0, 13)>, /* keep original config */
40+
<NRF_PSEL(PWM_OUT1, 1, 4)>,
41+
<NRF_PSEL(PWM_OUT2, 1, 6)>,
42+
<NRF_PSEL(PWM_OUT3, 1, 7)>;
43+
nordic,invert;
44+
};
45+
};
46+
47+
pwm0_sleep: pwm0_sleep {
48+
group1 {
49+
psels = <NRF_PSEL(PWM_OUT0, 0, 13)>, /* keep original config */
50+
<NRF_PSEL(PWM_OUT1, 1, 4)>,
51+
<NRF_PSEL(PWM_OUT2, 1, 6)>,
52+
<NRF_PSEL(PWM_OUT3, 1, 7)>;
53+
low-power-enable;
54+
};
55+
};
56+
57+
pwm1_default: pwm1_default {
58+
group1 {
59+
psels = <NRF_PSEL(PWM_OUT0, 1, 11)>,
60+
<NRF_PSEL(PWM_OUT1, 1, 12)>,
61+
<NRF_PSEL(PWM_OUT2, 1, 13)>;
62+
nordic,invert;
63+
};
64+
};
65+
66+
pwm1_sleep: pwm1_sleep {
67+
group1 {
68+
psels = <NRF_PSEL(PWM_OUT0, 1, 11)>,
69+
<NRF_PSEL(PWM_OUT1, 1, 12)>,
70+
<NRF_PSEL(PWM_OUT2, 1, 13)>;
71+
low-power-enable;
72+
};
73+
};
74+
};
75+
76+
&pwm0 {
77+
status = "okay";
78+
pinctrl-0 = <&pwm0_default>;
79+
pinctrl-1 = <&pwm0_sleep>;
80+
pinctrl-names = "default", "sleep";
81+
};
82+
83+
&pwm1 {
84+
status = "okay";
85+
pinctrl-0 = <&pwm1_default>;
86+
pinctrl-1 = <&pwm1_sleep>;
87+
pinctrl-names = "default", "sleep";
88+
};

0 commit comments

Comments
 (0)