From f5b93a752a4844b8ec834f9e5519034515248e28 Mon Sep 17 00:00:00 2001 From: Dylan Luo Date: Sun, 8 Feb 2026 12:00:57 +0800 Subject: [PATCH 1/2] support StamPLC IO set pwm. add set pwm and hot plug detect example. --- .../HotPlugDetection/HotPlugDetection.ino | 169 ++++++++++++++++++ .../StamPLC_IO/PWM_Control/PWM_Control.ino | 154 ++++++++++++++++ src/modules/M5StamPLC_IO.cpp | 120 ++++++++++++- src/modules/M5StamPLC_IO.h | 53 +++++- 4 files changed, 488 insertions(+), 8 deletions(-) create mode 100644 examples/Modules/StamPLC_IO/HotPlugDetection/HotPlugDetection.ino create mode 100644 examples/Modules/StamPLC_IO/PWM_Control/PWM_Control.ino diff --git a/examples/Modules/StamPLC_IO/HotPlugDetection/HotPlugDetection.ino b/examples/Modules/StamPLC_IO/HotPlugDetection/HotPlugDetection.ino new file mode 100644 index 0000000..bca12b9 --- /dev/null +++ b/examples/Modules/StamPLC_IO/HotPlugDetection/HotPlugDetection.ino @@ -0,0 +1,169 @@ +/* + * SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD + * + * SPDX-License-Identifier: MIT + * + * M5StamPLC IO Hot-Plug Detection Example + * + * This example demonstrates hot-plug detection for multiple M5StamPLC IO modules: + * - Automatically scan I2C bus and detect connected modules (0x20-0x2F) + * - Display online modules list + * - Real-time detection of module insertion and removal + */ +#include +#include + +#define MAX_MODULES 16 +#define SCAN_INTERVAL_MS 2000 + +struct ModuleInfo { + uint8_t address; + uint8_t firmware_version; + bool connected; +}; + +ModuleInfo modules[MAX_MODULES]; +uint8_t module_count = 0; +unsigned long last_scan_time = 0; + +void initModules() +{ + for (int i = 0; i < MAX_MODULES; i++) { + modules[i].address = 0; + modules[i].firmware_version = 0; + modules[i].connected = false; + } + module_count = 0; +} + +int findModuleSlot(uint8_t addr) +{ + for (int i = 0; i < MAX_MODULES; i++) { + if (modules[i].address == addr && modules[i].connected) { + return i; + } + } + return -1; +} + +int getEmptySlot() +{ + for (int i = 0; i < MAX_MODULES; i++) { + if (!modules[i].connected) { + return i; + } + } + return -1; +} + +void scanModules() +{ + uint8_t detected[16]; + uint8_t detected_count = 0; + + for (uint8_t addr = M5StamPLC_IO::I2C_ADDR_MIN; addr <= M5StamPLC_IO::I2C_ADDR_MAX; addr++) { + Wire.beginTransmission(addr); + if (Wire.endTransmission() == 0) { + detected[detected_count++] = addr; + + int slot = findModuleSlot(addr); + if (slot == -1) { + slot = getEmptySlot(); + if (slot != -1) { + M5StamPLC_IO temp_device; + if (temp_device.begin(addr, false)) { + modules[slot].address = addr; + modules[slot].firmware_version = temp_device.getFirmwareVersion(); + modules[slot].connected = true; + module_count++; + Serial.printf("[+] Module connected: 0x%02X (FW: 0x%02X)\n", addr, + modules[slot].firmware_version); + } + } + } + } + } + + for (int i = 0; i < MAX_MODULES; i++) { + if (modules[i].connected) { + bool still_present = false; + for (int j = 0; j < detected_count; j++) { + if (detected[j] == modules[i].address) { + still_present = true; + break; + } + } + + if (!still_present) { + Serial.printf("[-] Module disconnected: 0x%02X\n", modules[i].address); + modules[i].connected = false; + modules[i].address = 0; + module_count--; + } + } + } +} + +void displayModules() +{ + M5StamPLC.Display.fillScreen(TFT_BLACK); + M5StamPLC.Display.setCursor(0, 0); + + M5StamPLC.Display.setTextColor(TFT_GREENYELLOW); + M5StamPLC.Display.println("=== IO Hot-Plug ==="); + + M5StamPLC.Display.setTextColor(TFT_CYAN); + M5StamPLC.Display.printf("Online: %d\n\n", module_count); + + if (module_count == 0) { + M5StamPLC.Display.setTextColor(TFT_ORANGE); + M5StamPLC.Display.println("No modules found"); + } else { + int displayed = 0; + for (int i = 0; i < MAX_MODULES && displayed < 8; i++) { + if (modules[i].connected) { + M5StamPLC.Display.setTextColor(TFT_GREEN); + M5StamPLC.Display.printf("%d. Addr: 0x%02X\n", displayed + 1, modules[i].address); + M5StamPLC.Display.setTextColor(TFT_YELLOW); + M5StamPLC.Display.printf(" FW: 0x%02X\n", modules[i].firmware_version); + displayed++; + } + } + } +} + +void setup() +{ + M5StamPLC.begin(); + M5StamPLC.Display.setTextScroll(false); + M5StamPLC.Display.setTextSize(1); + M5StamPLC.Display.setFont(&fonts::efontCN_16); + + initModules(); + + M5StamPLC.Display.fillScreen(TFT_BLACK); + M5StamPLC.Display.setCursor(0, 0); + M5StamPLC.Display.setTextColor(TFT_GREENYELLOW); + M5StamPLC.Display.println("M5StamPLC IO"); + M5StamPLC.Display.println("Hot-Plug Detection"); + M5StamPLC.Display.setTextColor(TFT_CYAN); + M5StamPLC.Display.println("\nScanning..."); + + delay(1000); + scanModules(); + displayModules(); + last_scan_time = millis(); +} + +void loop() +{ + M5StamPLC.update(); + + if (millis() - last_scan_time > SCAN_INTERVAL_MS) { + scanModules(); + displayModules(); + last_scan_time = millis(); + } + + delay(100); +} diff --git a/examples/Modules/StamPLC_IO/PWM_Control/PWM_Control.ino b/examples/Modules/StamPLC_IO/PWM_Control/PWM_Control.ino new file mode 100644 index 0000000..0b121f9 --- /dev/null +++ b/examples/Modules/StamPLC_IO/PWM_Control/PWM_Control.ino @@ -0,0 +1,154 @@ +/* + * SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD + * + * SPDX-License-Identifier: MIT + * + * M5StamPLC IO PWM Control Example + * + * This example demonstrates how to use the PWM control function of the M5StamPLC IO module: + * - Switch between IO mode and PWM mode + * - Set PWM frequency (1-100 Hz) + * - Adjust CH1 and CH2 duty cycle (0-1000 thousandths) + * + * Button functions: + * - Button A: Toggle PWM mode on/off + * - Button B: Increase CH1 duty cycle (+10%) + * - Long press B: Decrease CH1 duty cycle (-10%) + * - Button C: Increase CH2 duty cycle (+10%) + * - Long press C: Decrease CH2 duty cycle (-10%) + */ +#include +#include + +M5StamPLC_IO stamplc_io; + +bool pwm_mode = false; +uint8_t pwm_freq = 50; +uint16_t ch1_duty = 0; +uint16_t ch2_duty = 0; +bool btnB_longPressed = false; +bool btnC_longPressed = false; + +unsigned long lastUpdateTime = 0; + +void updateDisplay() +{ + M5StamPLC.Display.fillScreen(TFT_BLACK); + M5StamPLC.Display.setCursor(0, 0); + + M5StamPLC.Display.setTextColor(TFT_GREENYELLOW); + M5StamPLC.Display.println("=== PWM Control ==="); + + M5StamPLC.Display.setTextColor(TFT_CYAN); + M5StamPLC.Display.printf("Mode: %s\n", pwm_mode ? "PWM" : "IO"); + M5StamPLC.Display.printf("Frequency: %d Hz\n", pwm_freq); + + M5StamPLC.Display.setTextColor(TFT_YELLOW); + M5StamPLC.Display.printf("CH1 Duty: %d.%d%% (%d/1000)\n", ch1_duty / 10, ch1_duty % 10, ch1_duty); + M5StamPLC.Display.printf("CH2 Duty: %d.%d%% (%d/1000)\n", ch2_duty / 10, ch2_duty % 10, ch2_duty); + + M5StamPLC.Display.setTextColor(TFT_DARKGREY); + M5StamPLC.Display.println("A: Toggle PWM mode"); + M5StamPLC.Display.println("B: CH1+ Long press: CH1-"); + M5StamPLC.Display.println("C: CH2+ Long press: CH2-"); +} + +void setup() +{ + /* Init M5StamPLC */ + M5StamPLC.begin(); + M5StamPLC.Display.setTextScroll(false); + M5StamPLC.Display.setTextSize(1); + M5StamPLC.Display.setFont(&fonts::efontCN_16); + M5StamPLC.Display.println("Try to find M5StamPLC IO module..."); + + /* Init M5StamPLC IO */ + while (!stamplc_io.begin()) { + M5StamPLC.Display.println("Not found, retry in 1s..."); + delay(1000); + } + + M5StamPLC.Display.printf("Found IO module: 0x%02X\n", stamplc_io.getCurrentAddress()); + M5StamPLC.Display.printf("Firmware Version: 0x%02X\n", stamplc_io.getFirmwareVersion()); + + delay(2000); + + // Read current PWM settings + pwm_mode = stamplc_io.getPWMMode(); + pwm_freq = stamplc_io.getPWMFrequency(); + ch1_duty = stamplc_io.getChannelDuty(1); + ch2_duty = stamplc_io.getChannelDuty(2); + + // If frequency is 0, set to default 50Hz + if (pwm_freq == 0) { + pwm_freq = 50; + stamplc_io.setPWMFrequency(pwm_freq); + } + + updateDisplay(); + lastUpdateTime = millis(); +} + +void loop() +{ + M5StamPLC.update(); + + bool needUpdate = false; + + // Button A: Toggle PWM mode + if (M5StamPLC.BtnA.wasClicked()) { + pwm_mode = !pwm_mode; + stamplc_io.setPWMMode(pwm_mode); + needUpdate = true; + } + + // Button B: Adjust CH1 duty cycle + if (M5StamPLC.BtnB.wasClicked()) { + // Increase 10% (100/1000) + ch1_duty += 100; + if (ch1_duty > 1000) ch1_duty = 1000; + stamplc_io.setChannelDuty(1, ch1_duty); + needUpdate = true; + } else if (M5StamPLC.BtnB.pressedFor(500) && !btnB_longPressed) { + // Decrease 10% + btnB_longPressed = true; + if (ch1_duty >= 100) { + ch1_duty -= 100; + } else { + ch1_duty = 0; + } + stamplc_io.setChannelDuty(1, ch1_duty); + needUpdate = true; + } else if (!M5StamPLC.BtnB.isPressed()) { + btnB_longPressed = false; + } + + // Button C: Adjust CH2 duty cycle + if (M5StamPLC.BtnC.wasClicked()) { + // Increase 10% (100/1000) + ch2_duty += 100; + if (ch2_duty > 1000) ch2_duty = 1000; + stamplc_io.setChannelDuty(2, ch2_duty); + needUpdate = true; + } else if (M5StamPLC.BtnC.pressedFor(500) && !btnC_longPressed) { + // Decrease 10% + btnC_longPressed = true; + if (ch2_duty >= 100) { + ch2_duty -= 100; + } else { + ch2_duty = 0; + } + stamplc_io.setChannelDuty(2, ch2_duty); + needUpdate = true; + } else if (!M5StamPLC.BtnC.isPressed()) { + btnC_longPressed = false; + } + + // Periodically update display + if (needUpdate || (millis() - lastUpdateTime > 1000)) { + updateDisplay(); + lastUpdateTime = millis(); + } + + delay(10); +} diff --git a/src/modules/M5StamPLC_IO.cpp b/src/modules/M5StamPLC_IO.cpp index 1c5522d..64671f1 100644 --- a/src/modules/M5StamPLC_IO.cpp +++ b/src/modules/M5StamPLC_IO.cpp @@ -8,8 +8,10 @@ static const char* _tag = "M5StamPLC_IO"; -bool M5StamPLC_IO::begin(uint8_t addr) +bool M5StamPLC_IO::begin(uint8_t addr, bool debug) { + esp_log_level_set(_tag, debug ? ESP_LOG_DEBUG : ESP_LOG_NONE); + if (addr == 0) { _current_addr = scanI2CDevices(); if (_current_addr == 0) { @@ -319,20 +321,26 @@ void M5StamPLC_IO::writeINA226Config(uint8_t channel, uint16_t config) return; } - uint8_t lsb = config & 0xFF; - uint8_t msb = (config >> 8) & 0xFF; + uint8_t data[2]; + data[0] = config & 0xFF; + data[1] = (config >> 8) & 0xFF; + uint8_t start_reg; if (channel == 1) { - writeRegister(REG_INA226_CONFIG_CH1_LSB, lsb); - writeRegister(REG_INA226_CONFIG_CH1_MSB, msb); + start_reg = REG_INA226_CONFIG_CH1_LSB; } else if (channel == 2) { - writeRegister(REG_INA226_CONFIG_CH2_LSB, lsb); - writeRegister(REG_INA226_CONFIG_CH2_MSB, msb); + start_reg = REG_INA226_CONFIG_CH2_LSB; } else { ESP_LOGW(_tag, "Invalid channel: %d", channel); return; } + bool success = m5::In_I2C.writeRegister(_current_addr, start_reg, data, 2, 400000); + if (!success) { + ESP_LOGW(_tag, "Failed to write CH%d INA226 config", channel); + return; + } + ESP_LOGI(_tag, "Write CH%d INA226 config: 0x%04X", channel, config); } @@ -393,3 +401,101 @@ esp_err_t M5StamPLC_IO::getINA226Averaging(uint8_t channel, uint8_t* avg) *avg = (config & INA226_AVG_MASK) >> 9; return ESP_OK; } + +void M5StamPLC_IO::setPWMMode(bool enable) +{ + uint8_t currentState = readRegister(REG_IO_CONTROL); + uint8_t newState; + + if (enable) { + newState = currentState | (1 << BIT_PWM_MODE); + ESP_LOGI(_tag, "Enable PWM mode"); + } else { + newState = currentState & ~(1 << BIT_PWM_MODE); + ESP_LOGI(_tag, "Disable PWM mode"); + } + + if (newState != currentState) { + writeRegister(REG_IO_CONTROL, newState); + } +} + +bool M5StamPLC_IO::getPWMMode() +{ + uint8_t state = readRegister(REG_IO_CONTROL); + return (state & (1 << BIT_PWM_MODE)) != 0; +} + +void M5StamPLC_IO::setPWMFrequency(uint8_t freq) +{ + if (freq < 1 || freq > 100) { + ESP_LOGW(_tag, "Invalid PWM frequency: %d, must be 1-100 Hz", freq); + return; + } + + writeRegister(REG_PWM_FREQ, freq); + ESP_LOGI(_tag, "Set PWM frequency: %d Hz", freq); +} + +uint8_t M5StamPLC_IO::getPWMFrequency() +{ + return readRegister(REG_PWM_FREQ); +} + +void M5StamPLC_IO::setChannelDuty(uint8_t channel, uint16_t duty) +{ + if (_current_addr == 0) { + ESP_LOGE(_tag, "Device not initialized"); + return; + } + + if (duty > 1000) { + ESP_LOGW(_tag, "Invalid duty cycle: %d, must be 0-1000", duty); + return; + } + + uint8_t data[2]; + data[0] = duty & 0xFF; + data[1] = (duty >> 8) & 0xFF; + + uint8_t start_reg; + if (channel == 1) { + start_reg = REG_CH1_DUTY_LSB; + } else if (channel == 2) { + start_reg = REG_CH2_DUTY_LSB; + } else { + ESP_LOGW(_tag, "Invalid channel: %d", channel); + return; + } + + bool success = m5::In_I2C.writeRegister(_current_addr, start_reg, data, 2, 400000); + if (!success) { + ESP_LOGW(_tag, "Failed to write CH%d duty cycle", channel); + return; + } + + ESP_LOGI(_tag, "Set CH%d duty cycle: %d/1000 (%d%%)", channel, duty, duty / 10); +} + +uint16_t M5StamPLC_IO::getChannelDuty(uint8_t channel) +{ + uint8_t data[2]; + uint8_t start_reg; + + if (channel == 1) { + start_reg = REG_CH1_DUTY_LSB; + } else if (channel == 2) { + start_reg = REG_CH2_DUTY_LSB; + } else { + ESP_LOGW(_tag, "Invalid channel: %d", channel); + return 0; + } + + if (m5::In_I2C.readRegister(_current_addr, start_reg, data, 2, 400000)) { + uint16_t duty = (data[1] << 8) | data[0]; + return duty; + } else { + ESP_LOGW(_tag, "Failed to read CH%d duty cycle", channel); + return 0; + } +} diff --git a/src/modules/M5StamPLC_IO.h b/src/modules/M5StamPLC_IO.h index da39a83..ddb34dd 100644 --- a/src/modules/M5StamPLC_IO.h +++ b/src/modules/M5StamPLC_IO.h @@ -28,6 +28,11 @@ class M5StamPLC_IO { static constexpr uint8_t REG_I_CH2_EXT1 = 0x0A; static constexpr uint8_t REG_I_CH2_EXT2 = 0x0B; static constexpr uint8_t REG_IO_CONTROL = 0x10; + static constexpr uint8_t REG_PWM_FREQ = 0x30; + static constexpr uint8_t REG_CH1_DUTY_LSB = 0x31; + static constexpr uint8_t REG_CH1_DUTY_MSB = 0x32; + static constexpr uint8_t REG_CH2_DUTY_LSB = 0x33; + static constexpr uint8_t REG_CH2_DUTY_MSB = 0x34; static constexpr uint8_t REG_SYSTEM_STATUS = 0xFB; static constexpr uint8_t REG_FIRMWARE_VER = 0xFE; static constexpr uint8_t REG_ADDR_CONFIG = 0xFF; @@ -49,6 +54,7 @@ class M5StamPLC_IO { static constexpr uint8_t BIT_CH1_PU_EN = 2; static constexpr uint8_t BIT_CH2_PU_EN = 3; static constexpr uint8_t BIT_RELAY_TRIG = 4; + static constexpr uint8_t BIT_PWM_MODE = 5; // SYSTEM STATUS BIT DEFINITION static constexpr uint8_t SYS_CH1_INA226_ERROR = 0; @@ -82,10 +88,11 @@ class M5StamPLC_IO { * @brief Initialize M5StamPLC-IO * * @param addr I2C address (0x20-0x2F), if 0 will auto-scan + * @param debug Enable debug logging (default: false) * @return true if initialization successful * @return false if initialization failed */ - bool begin(uint8_t addr = 0); + bool begin(uint8_t addr = 0, bool debug = false); /** * @brief Scan for I2C devices @@ -260,6 +267,50 @@ class M5StamPLC_IO { return _current_addr; } + /** + * @brief Set PWM mode + * + * @param enable true for PWM mode, false for IO mode + */ + void setPWMMode(bool enable); + + /** + * @brief Get PWM mode + * + * @return true if PWM mode enabled + */ + bool getPWMMode(); + + /** + * @brief Set PWM frequency + * + * @param freq frequency in Hz (1-100), default 50 + */ + void setPWMFrequency(uint8_t freq); + + /** + * @brief Get PWM frequency + * + * @return frequency in Hz + */ + uint8_t getPWMFrequency(); + + /** + * @brief Set channel duty cycle + * + * @param channel 1 or 2 + * @param duty duty cycle in permille (0-1000), default 0 + */ + void setChannelDuty(uint8_t channel, uint16_t duty); + + /** + * @brief Get channel duty cycle + * + * @param channel 1 or 2 + * @return duty cycle in permille (0-1000) + */ + uint16_t getChannelDuty(uint8_t channel); + protected: uint8_t _current_addr = 0; }; From f4391decd8c59de9914e415fcc494957699819e6 Mon Sep 17 00:00:00 2001 From: Dylan Luo Date: Sun, 8 Feb 2026 14:44:39 +0800 Subject: [PATCH 2/2] fix compilation failed --- .../HotPlugDetection/HotPlugDetection.ino | 79 +++++-------------- .../StamPLC_IO/PWM_Control/PWM_Control.ino | 3 - 2 files changed, 19 insertions(+), 63 deletions(-) diff --git a/examples/Modules/StamPLC_IO/HotPlugDetection/HotPlugDetection.ino b/examples/Modules/StamPLC_IO/HotPlugDetection/HotPlugDetection.ino index bca12b9..0008c77 100644 --- a/examples/Modules/StamPLC_IO/HotPlugDetection/HotPlugDetection.ino +++ b/examples/Modules/StamPLC_IO/HotPlugDetection/HotPlugDetection.ino @@ -29,77 +29,33 @@ unsigned long last_scan_time = 0; void initModules() { for (int i = 0; i < MAX_MODULES; i++) { - modules[i].address = 0; + modules[i].address = M5StamPLC_IO::I2C_ADDR_MIN + i; modules[i].firmware_version = 0; modules[i].connected = false; } module_count = 0; } -int findModuleSlot(uint8_t addr) -{ - for (int i = 0; i < MAX_MODULES; i++) { - if (modules[i].address == addr && modules[i].connected) { - return i; - } - } - return -1; -} - -int getEmptySlot() -{ - for (int i = 0; i < MAX_MODULES; i++) { - if (!modules[i].connected) { - return i; - } - } - return -1; -} - void scanModules() { - uint8_t detected[16]; - uint8_t detected_count = 0; - - for (uint8_t addr = M5StamPLC_IO::I2C_ADDR_MIN; addr <= M5StamPLC_IO::I2C_ADDR_MAX; addr++) { - Wire.beginTransmission(addr); - if (Wire.endTransmission() == 0) { - detected[detected_count++] = addr; - - int slot = findModuleSlot(addr); - if (slot == -1) { - slot = getEmptySlot(); - if (slot != -1) { - M5StamPLC_IO temp_device; - if (temp_device.begin(addr, false)) { - modules[slot].address = addr; - modules[slot].firmware_version = temp_device.getFirmwareVersion(); - modules[slot].connected = true; - module_count++; - Serial.printf("[+] Module connected: 0x%02X (FW: 0x%02X)\n", addr, - modules[slot].firmware_version); - } - } - } - } - } + bool found_map[0x80] = {false}; + m5::In_I2C.scanID(found_map); for (int i = 0; i < MAX_MODULES; i++) { - if (modules[i].connected) { - bool still_present = false; - for (int j = 0; j < detected_count; j++) { - if (detected[j] == modules[i].address) { - still_present = true; - break; - } - } - - if (!still_present) { - Serial.printf("[-] Module disconnected: 0x%02X\n", modules[i].address); - modules[i].connected = false; - modules[i].address = 0; - module_count--; + uint8_t addr = M5StamPLC_IO::I2C_ADDR_MIN + i; + if (found_map[addr] && !modules[i].connected) { + M5StamPLC_IO temp_device; + if (temp_device.begin(addr, false)) { + modules[i].address = addr; + modules[i].firmware_version = temp_device.getFirmwareVersion(); + modules[i].connected = true; + module_count++; + Serial.printf("[+] Module connected: 0x%02X (FW: 0x%02X)\n", addr, modules[i].firmware_version); } + } else if (!found_map[addr] && modules[i].connected) { + Serial.printf("[-] Module disconnected: 0x%02X\n", modules[i].address); + modules[i].connected = false; + module_count--; } } } @@ -139,6 +95,9 @@ void setup() M5StamPLC.Display.setTextSize(1); M5StamPLC.Display.setFont(&fonts::efontCN_16); + Serial.begin(115200); + Serial.println("\n=== M5StamPLC IO Hot-Plug Detection ==="); + initModules(); M5StamPLC.Display.fillScreen(TFT_BLACK); diff --git a/examples/Modules/StamPLC_IO/PWM_Control/PWM_Control.ino b/examples/Modules/StamPLC_IO/PWM_Control/PWM_Control.ino index 0b121f9..ef764bc 100644 --- a/examples/Modules/StamPLC_IO/PWM_Control/PWM_Control.ino +++ b/examples/Modules/StamPLC_IO/PWM_Control/PWM_Control.ino @@ -55,7 +55,6 @@ void updateDisplay() void setup() { - /* Init M5StamPLC */ M5StamPLC.begin(); M5StamPLC.Display.setTextScroll(false); M5StamPLC.Display.setTextSize(1); @@ -73,13 +72,11 @@ void setup() delay(2000); - // Read current PWM settings pwm_mode = stamplc_io.getPWMMode(); pwm_freq = stamplc_io.getPWMFrequency(); ch1_duty = stamplc_io.getChannelDuty(1); ch2_duty = stamplc_io.getChannelDuty(2); - // If frequency is 0, set to default 50Hz if (pwm_freq == 0) { pwm_freq = 50; stamplc_io.setPWMFrequency(pwm_freq);