diff --git a/src/utility/M5IOE1_Class.cpp b/src/utility/M5IOE1_Class.cpp index 7b0f08c..1d2515c 100644 --- a/src/utility/M5IOE1_Class.cpp +++ b/src/utility/M5IOE1_Class.cpp @@ -117,15 +117,24 @@ namespace m5 writeRegister(M5IOE1_REG_PWM_FREQ_L, data, sizeof(data)); } - void M5IOE1_Class::setPwmDuty(std::uint8_t channel, std::uint16_t duty12, bool enable, bool polarity) + bool M5IOE1_Class::setPwmDutyPercent(pwm_channel_t channel, std::uint32_t duty, + pwm_polarity_t polarity, bool enable) { - if (channel > pwm_ch4) { return; } - duty12 &= 0x0FFF; + if (duty > 100) { return false; } + auto duty12 = duty * 0x0FFF / 100; + return setPwmDuty12bit(channel, duty12, polarity, enable); + } + + bool M5IOE1_Class::setPwmDuty12bit(pwm_channel_t channel, std::uint32_t duty12, + pwm_polarity_t polarity, bool enable) + { + if (channel > pwm_ch4 || duty12 > 0x0FFF) { return false; } std::uint8_t high = static_cast(duty12 >> 8); if (enable) { high |= M5IOE1_PWM_ENABLE; } - if (polarity) { high |= M5IOE1_PWM_POLARITY; } + if (polarity == pwm_polarity_t::inverted) { high |= M5IOE1_PWM_POLARITY; } std::uint8_t data[2] = { static_cast(duty12 & 0xFF), high }; - writeRegister(static_cast(M5IOE1_REG_PWM1_DUTY_L + channel * 2), data, sizeof(data)); + auto reg = static_cast(M5IOE1_REG_PWM1_DUTY_L + static_cast(channel) * 2); + return writeRegister(reg, data, sizeof(data)); } void M5IOE1_Class::resetIrq() diff --git a/src/utility/M5IOE1_Class.hpp b/src/utility/M5IOE1_Class.hpp index c6c7fc0..0901e4e 100644 --- a/src/utility/M5IOE1_Class.hpp +++ b/src/utility/M5IOE1_Class.hpp @@ -5,6 +5,7 @@ #define __M5_M5IOE1_CLASS_H__ #include "IOExpander_Base.hpp" +#include "pwm_types.hpp" namespace m5 { @@ -61,7 +62,21 @@ namespace m5 void setPwmFrequency(std::uint16_t frequency); - void setPwmDuty(std::uint8_t channel, std::uint16_t duty12, bool enable = true, bool polarity = false); + /// set PWM duty in percent. + /// @param channel PWM channel (pwm_ch1 - pwm_ch4). + /// @param duty duty cycle in percent (0-100). + /// @param polarity PWM output polarity. + /// @param enable true=enable / false=disable. + bool setPwmDutyPercent(pwm_channel_t channel, std::uint32_t duty, + pwm_polarity_t polarity = pwm_polarity_t::normal, bool enable = true); + + /// set PWM duty with 12-bit precision. + /// @param channel PWM channel (pwm_ch1 - pwm_ch4). + /// @param duty12 duty cycle (0-4095). + /// @param polarity PWM output polarity. + /// @param enable true=enable / false=disable. + bool setPwmDuty12bit(pwm_channel_t channel, std::uint32_t duty12, + pwm_polarity_t polarity = pwm_polarity_t::normal, bool enable = true); void resetIrq() override; diff --git a/src/utility/Power_Class.cpp b/src/utility/Power_Class.cpp index f1a1812..b1f6fe9 100644 --- a/src/utility/Power_Class.cpp +++ b/src/utility/Power_Class.cpp @@ -287,7 +287,7 @@ namespace m5 /// cannot be confirmed, the pin is left as a plain output driving low, /// which is silent whatever the retained PWM state is. bool pwm_off = false; - for (int retry = 3; !(pwm_off = M5pm1.setPwmDuty12bit(M5PM1_Class::pwm_ch1, 0, false, false)) && --retry; ) + for (int retry = 3; !(pwm_off = M5pm1.setPwmDuty12bit(M5PM1_Class::pwm_ch1, 0, pwm_polarity_t::normal, false)) && --retry; ) { m5gfx::delay(10); } @@ -402,7 +402,7 @@ namespace m5 // IO9 (G9 motor / PWM1): push-pull output, duty off until setVibration ioe1.setHighImpedance(M5IOE1_Class::gpio9, false); ioe1.setDirection(M5IOE1_Class::gpio9, true); - ioe1.setPwmDuty(M5IOE1_Class::pwm_ch1, 0, false); // PWM off at boot + ioe1.setPwmDuty12bit(M5IOE1_Class::pwm_ch1, 0, pwm_polarity_t::normal, false); // PWM off at boot } break; @@ -2780,13 +2780,13 @@ namespace m5 // M5IOE1 PWM1 (0x1B/0x1C) -> pin IO9 / G9 motor; duty 12-bit in [11:0], EN=bit7 of high byte. auto& ioe1 = static_cast(M5.getIOExpander(0)); if (level == 0) { - ioe1.setPwmDuty(M5IOE1_Class::pwm_ch1, 0, false); + ioe1.setPwmDuty12bit(M5IOE1_Class::pwm_ch1, 0, pwm_polarity_t::normal, false); } else { // PWM needs IO9 in output mode (M5IOE1 pin index 8 -> GPIO_MODE_H bit0). ioe1.setHighImpedance(M5IOE1_Class::gpio9, false); ioe1.setDirection(M5IOE1_Class::gpio9, true); uint16_t duty12 = static_cast((static_cast(level) * 0x0FFFu) / 255u); - ioe1.setPwmDuty(M5IOE1_Class::pwm_ch1, duty12); + ioe1.setPwmDuty12bit(M5IOE1_Class::pwm_ch1, duty12); } return; } diff --git a/src/utility/led/LED_PaperMono_Class.cpp b/src/utility/led/LED_PaperMono_Class.cpp index 8650fdd..bb3ab26 100644 --- a/src/utility/led/LED_PaperMono_Class.cpp +++ b/src/utility/led/LED_PaperMono_Class.cpp @@ -76,7 +76,7 @@ namespace m5 ioe1.digitalWrite(ioe1_led_b_pin, b >= 2048); if (g > 4095) { g = 4095; } - ioe1.setPwmDuty(M5IOE1_Class::pwm_ch2, g, g > 0); + ioe1.setPwmDuty12bit(M5IOE1_Class::pwm_ch2, g, pwm_polarity_t::normal, g > 0); } } diff --git a/src/utility/power/M5PM1_Class.cpp b/src/utility/power/M5PM1_Class.cpp index 130303b..23c3bbd 100644 --- a/src/utility/power/M5PM1_Class.cpp +++ b/src/utility/power/M5PM1_Class.cpp @@ -193,19 +193,21 @@ namespace m5 return writeRegister(M5PM1_REG_PWM_FREQ_L, data, sizeof(data)); } - bool M5PM1_Class::setPwmDuty(pwm_channel_t channel, std::uint8_t duty, bool polarity, bool enable) + bool M5PM1_Class::setPwmDutyPercent(pwm_channel_t channel, std::uint32_t duty, + pwm_polarity_t polarity, bool enable) { if (duty > 100) { return false; } - auto duty12 = static_cast(static_cast(duty) * 0x0FFF / 100); + auto duty12 = duty * 0x0FFF / 100; return setPwmDuty12bit(channel, duty12, polarity, enable); } - bool M5PM1_Class::setPwmDuty12bit(pwm_channel_t channel, std::uint16_t duty12, bool polarity, bool enable) + bool M5PM1_Class::setPwmDuty12bit(pwm_channel_t channel, std::uint32_t duty12, + pwm_polarity_t polarity, bool enable) { if (!is_valid_pwm_channel(channel) || duty12 > 0x0FFF) { return false; } std::uint8_t high = static_cast(duty12 >> 8); if (enable) { high |= M5PM1_PWM_ENABLE; } - if (polarity) { high |= M5PM1_PWM_POLARITY; } + if (polarity == pwm_polarity_t::inverted) { high |= M5PM1_PWM_POLARITY; } std::uint8_t data[2] = { static_cast(duty12 & 0xFF), high }; auto reg = static_cast(M5PM1_REG_PWM0_L + static_cast(channel) * 2); return writeRegister(reg, data, sizeof(data)); diff --git a/src/utility/power/M5PM1_Class.hpp b/src/utility/power/M5PM1_Class.hpp index eefe7ab..a73f5c5 100644 --- a/src/utility/power/M5PM1_Class.hpp +++ b/src/utility/power/M5PM1_Class.hpp @@ -5,6 +5,7 @@ #define __M5_M5PM1_CLASS_H__ #include "../I2C_Class.hpp" +#include "../pwm_types.hpp" namespace m5 { @@ -129,16 +130,18 @@ namespace m5 /// set PWM duty in percent. /// @param channel PWM channel (pwm_ch0 / pwm_ch1). /// @param duty duty cycle in percent (0-100). - /// @param polarity false=normal / true=inverted. + /// @param polarity PWM output polarity. /// @param enable true=enable / false=disable. - bool setPwmDuty(pwm_channel_t channel, std::uint8_t duty, bool polarity = false, bool enable = true); + bool setPwmDutyPercent(pwm_channel_t channel, std::uint32_t duty, + pwm_polarity_t polarity = pwm_polarity_t::normal, bool enable = true); /// set PWM duty with 12-bit precision. /// @param channel PWM channel (pwm_ch0 / pwm_ch1). /// @param duty12 duty cycle (0-4095). - /// @param polarity false=normal / true=inverted. + /// @param polarity PWM output polarity. /// @param enable true=enable / false=disable. - bool setPwmDuty12bit(pwm_channel_t channel, std::uint16_t duty12, bool polarity = false, bool enable = true); + bool setPwmDuty12bit(pwm_channel_t channel, std::uint32_t duty12, + pwm_polarity_t polarity = pwm_polarity_t::normal, bool enable = true); /// clear PM1 wake source bits selected by mask. bool clearWakeSource(std::uint8_t mask = 0x7F); diff --git a/src/utility/pwm_types.hpp b/src/utility/pwm_types.hpp new file mode 100644 index 0000000..0dc6fe0 --- /dev/null +++ b/src/utility/pwm_types.hpp @@ -0,0 +1,21 @@ +// Copyright (c) M5Stack. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#ifndef __M5_PWM_TYPES_H__ +#define __M5_PWM_TYPES_H__ + +#include + +namespace m5 +{ + /// PWM output polarity. + /// normal : the duty is the high time. The output idles low (POL = 0). + /// inverted : the duty is the low time. The output idles high (POL = 1), + /// which the datasheet calls active low. + enum class pwm_polarity_t : std::uint8_t + { normal = 0 + , inverted = 1 + }; +} + +#endif