diff --git a/Makefile.dep b/Makefile.dep index 3abf863f13..6ebede633f 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -635,11 +635,16 @@ endif ifneq (,$(filter arduino,$(USEMODULE))) FEATURES_REQUIRED += arduino + FEATURES_OPTIONAL += arduino_pwm FEATURES_OPTIONAL += periph_adc FEATURES_REQUIRED += periph_gpio USEMODULE += xtimer endif +ifneq (,$(filter arduino_pwm,$(FEATURES_USED))) + FEATURES_REQUIRED += periph_pwm +endif + ifneq (,$(filter xtimer,$(USEMODULE))) FEATURES_REQUIRED += periph_timer USEMODULE += div diff --git a/sys/arduino/base.cpp b/sys/arduino/base.cpp index 5faa6463df..b1d58e7d41 100644 --- a/sys/arduino/base.cpp +++ b/sys/arduino/base.cpp @@ -22,6 +22,7 @@ extern "C" { #include "xtimer.h" #include "periph/gpio.h" #include "periph/adc.h" +#include "periph/pwm.h" } #include "arduino.hpp" @@ -106,3 +107,55 @@ int analogRead(int arduino_pin) return adc_value; } #endif + +#if MODULE_PERIPH_PWM +static int _get_pwm_pin_idx(int pin) +{ + for (uint8_t i = 0; i < ARRAY_SIZE(arduino_pwm_list); ++i) { + if (arduino_pwm_list[i].pin == pin) { + return i; + } + } + + return -1; +} + +void analogWrite(int pin, int value) +{ + /* + * Bitfield for the state of the PWM devices. + * 0: Not initialized + * 1: Successfully initialized + */ + static uint8_t pwm_dev_state; + + /* Clamp given value within bounds */ + if (value < 0) { + value = 0; + } + if ((unsigned)value >= ARDUINO_PWM_STEPS) { + value = ARDUINO_PWM_STEPS - 1; + } + + /* Check if the PWM pin is valid */ + int pin_idx = _get_pwm_pin_idx(pin); + if (pin_idx == -1) { + /* Set to digital write if not a PWM pin */ + pinMode(pin, OUTPUT); + return; + } + + /* Initialization of given PWM pin */ + if (!(pwm_dev_state & (1 << arduino_pwm_list[pin_idx].dev))) { + if (pwm_init(arduino_pwm_list[pin_idx].dev, + ARDUINO_PWM_MODE, ARDUINO_PWM_FREQU, ARDUINO_PWM_STEPS) == 0) { + return; + } + /* The PWM channel is initialized */ + pwm_dev_state |= (1 << arduino_pwm_list[pin_idx].dev); + } + + /* Write analog value */ + pwm_set(arduino_pwm_list[pin_idx].dev, arduino_pwm_list[pin_idx].chan, value); +} +#endif /* MODULE_PERIPH_PWM */ diff --git a/sys/arduino/include/arduino.hpp b/sys/arduino/include/arduino.hpp index 6953a694f1..13cf7ebc42 100644 --- a/sys/arduino/include/arduino.hpp +++ b/sys/arduino/include/arduino.hpp @@ -122,5 +122,37 @@ unsigned long millis(); int analogRead(int pin); #endif +#if MODULE_PERIPH_PWM || DOXYGEN +/** + * @brief PWM default frequency + * + * Can be overridden at board level in arduino_board.h. + * + * See table from https://www.arduino.cc/reference/en/language/functions/analog-io/analogwrite/ + * for reference values. + */ +#ifndef ARDUINO_PWM_FREQU +#define ARDUINO_PWM_FREQU (1000U) +#endif + +/** + * @brief PWM mode + */ +#define ARDUINO_PWM_MODE PWM_LEFT + +/** + * @brief PWM steps + */ +#define ARDUINO_PWM_STEPS (256U) + +/** + * @brief Write an analog value to a pin + * + * @param[in] pin pin to write + * @param[in] value duty cycle value, between 0 and 255 + */ +void analogWrite(int pin, int value); +#endif + #endif /* ARDUINO_HPP */ /** @} */