๐ŸŽ›๏ธ BasePwm API Reference

๐ŸŒŸ Overview

BasePwm is the abstract base class for all PWM (Pulse Width Modulation) implementations in the HardFOC system. It provides a unified interface for motor control, LED dimming, servo control, and other PWM applications with comprehensive multi-channel support.

โœจ Features

  • ๐Ÿ”ข Multi-Channel Support - Control multiple PWM channels simultaneously
  • โšก Variable Frequency - Configurable frequency per channel with wide range support
  • ๐ŸŽฏ Precise Duty Control - High-resolution duty cycle control with hardware precision
  • ๐Ÿ”„ Fade Operations - Smooth transitions between duty cycle values
  • ๐Ÿ›ก๏ธ Hardware Protection - Built-in fault detection and recovery mechanisms
  • ๐Ÿ“Š Performance Monitoring - Comprehensive statistics and diagnostics
  • ๐Ÿ”ง Lazy Initialization - Resources allocated only when needed
  • ๐ŸŽ๏ธ Real-Time Optimized - Designed for time-critical motor control applications

๐Ÿ“ Header File

1
#include "inc/base/BasePwm.h"

๐ŸŽฏ Type Definitions

๐Ÿšจ Error Codes

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
enum class hf_pwm_err_t : hf_u32_t {
    PWM_SUCCESS = 0,                    // โœ… Success
    PWM_ERR_FAILURE = 1,                // โŒ General failure
    PWM_ERR_NOT_INITIALIZED = 2,        // โš ๏ธ Not initialized
    PWM_ERR_ALREADY_INITIALIZED = 3,    // โš ๏ธ Already initialized
    PWM_ERR_INVALID_PARAMETER = 4,      // ๐Ÿšซ Invalid parameter
    PWM_ERR_NULL_POINTER = 5,           // ๐Ÿšซ Null pointer
    PWM_ERR_OUT_OF_MEMORY = 6,          // ๐Ÿ’พ Out of memory
    PWM_ERR_INVALID_CHANNEL = 7,        // ๐Ÿ” Invalid PWM channel
    PWM_ERR_CHANNEL_BUSY = 8,           // ๐Ÿ”„ Channel already in use
    PWM_ERR_CHANNEL_NOT_AVAILABLE = 9,  // ๐Ÿšซ Channel not available
    PWM_ERR_INSUFFICIENT_CHANNELS = 10, // ๐Ÿ“‰ Insufficient channels
    PWM_ERR_INVALID_FREQUENCY = 11,     // ๐Ÿ“ป Invalid frequency
    PWM_ERR_FREQUENCY_TOO_HIGH = 12,    // ๐Ÿ“ˆ Frequency too high
    PWM_ERR_FREQUENCY_TOO_LOW = 13,     // ๐Ÿ“‰ Frequency too low
    PWM_ERR_RESOLUTION_NOT_SUPPORTED = 14, // ๐ŸŽฏ Resolution not supported
    PWM_ERR_INVALID_DUTY_CYCLE = 15,    // ๐ŸŽ›๏ธ Invalid duty cycle
    PWM_ERR_DUTY_OUT_OF_RANGE = 16,     // ๐Ÿ“ Duty cycle out of range
    PWM_ERR_HARDWARE_FAULT = 17,        // ๐Ÿ’ฅ Hardware fault
    PWM_ERR_TIMER_CONFLICT = 18,        // โฑ๏ธ Timer resource conflict
    PWM_ERR_PIN_CONFLICT = 19,          // ๐Ÿ”Œ Pin already in use
    PWM_ERR_COMMUNICATION_TIMEOUT = 20, // โฐ Communication timeout
    PWM_ERR_COMMUNICATION_FAILURE = 21, // ๐Ÿ“ก Communication failure
    PWM_ERR_DEVICE_NOT_RESPONDING = 22, // ๐Ÿ”‡ Device not responding
    PWM_ERR_INVALID_DEVICE_ID = 23,     // ๐Ÿ†” Invalid device ID
    PWM_ERR_UNSUPPORTED_OPERATION = 24  // ๐Ÿšซ Unsupported operation
};

๐Ÿ“Š Statistics Structure

1
2
3
4
5
6
7
8
struct hf_pwm_statistics_t {
    hf_u32_t duty_updates_count;        // ๐Ÿ”„ Total duty cycle updates
    hf_u32_t frequency_changes_count;   // ๐Ÿ“ป Total frequency changes
    hf_u32_t fade_operations_count;     // ๐ŸŒŸ Total fade operations
    hf_u32_t error_count;               // โŒ Total error count
    hf_u32_t channel_enables_count;     // โœ… Total channel enable operations
    hf_u32_t channel_disables_count;    // โŒ Total channel disable operations
};

๐Ÿ—๏ธ Class Interface

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class BasePwm {
public:
    // ๐Ÿ”ง Lifecycle management
    virtual ~BasePwm() noexcept = default;
    virtual hf_pwm_err_t Initialize() noexcept = 0;
    virtual hf_pwm_err_t Deinitialize() noexcept = 0;
    bool IsInitialized() const noexcept;
    bool EnsureInitialized() noexcept;
    bool EnsureDeinitialized() noexcept;

    // ๐Ÿ“ก Channel management
    virtual hf_pwm_err_t EnableChannel(hf_channel_id_t channel_id) noexcept = 0;
    virtual hf_pwm_err_t DisableChannel(hf_channel_id_t channel_id) noexcept = 0;
    virtual bool IsChannelEnabled(hf_channel_id_t channel_id) const noexcept = 0;

    // ๐ŸŽ›๏ธ PWM control
    virtual hf_pwm_err_t SetDutyCycle(hf_channel_id_t channel_id, float duty_cycle) noexcept = 0;
virtual float GetDutyCycle(hf_channel_id_t channel_id) const noexcept = 0;
    virtual hf_pwm_err_t SetFrequency(hf_channel_id_t channel_id, hf_frequency_hz_t frequency) noexcept = 0;
    virtual hf_pwm_err_t GetFrequency(hf_channel_id_t channel_id, hf_frequency_hz_t& frequency) const noexcept = 0;

    // ๐ŸŒŸ Advanced features
    virtual hf_pwm_err_t StartFade(hf_channel_id_t channel_id, float target_duty_percent, 
                                  hf_time_t fade_time_ms) noexcept = 0;
    virtual hf_pwm_err_t StopFade(hf_channel_id_t channel_id) noexcept = 0;
    virtual bool IsFading(hf_channel_id_t channel_id) const noexcept = 0;

    // ๐Ÿ“Š Information and diagnostics
    virtual hf_u8_t GetMaxChannels() const noexcept = 0;
    virtual bool IsChannelAvailable(hf_channel_id_t channel_id) const noexcept = 0;
    virtual hf_pwm_err_t GetStatistics(hf_pwm_statistics_t& stats) const noexcept = 0;
    virtual hf_pwm_err_t ResetStatistics() noexcept = 0;
};

๐ŸŽฏ Core Methods

๐Ÿ”ง Initialization

1
bool EnsureInitialized() noexcept;

Purpose: ๐Ÿš€ Lazy initialization - automatically initializes PWM if not already done
Returns: true if successful, false on failure
Usage: Call before any PWM operations

๐Ÿ“ก Channel Control

1
2
3
hf_pwm_err_t EnableChannel(hf_channel_id_t channel_id) noexcept;
hf_pwm_err_t DisableChannel(hf_channel_id_t channel_id) noexcept;
bool IsChannelEnabled(hf_channel_id_t channel_id) const noexcept;

Purpose: ๐ŸŽ›๏ธ Enable/disable individual PWM channels
Parameters: Channel ID (0-based indexing)
Returns: Error code or boolean status

๐ŸŽ›๏ธ Duty Cycle Control

1
2
hf_pwm_err_t SetDutyCycle(hf_channel_id_t channel_id, float duty_percent) noexcept;
hf_pwm_err_t GetDutyCycle(hf_channel_id_t channel_id, float& duty_percent) const noexcept;

Purpose: ๐ŸŽฏ Set/get PWM duty cycle as percentage (0.0 - 100.0)
Parameters:

  • channel_id - Target PWM channel
  • duty_percent - Duty cycle percentage (0.0 = 0%, 100.0 = 100%)

๐Ÿ“ป Frequency Control

1
2
hf_pwm_err_t SetFrequency(hf_channel_id_t channel_id, hf_frequency_hz_t frequency) noexcept;
hf_pwm_err_t GetFrequency(hf_channel_id_t channel_id, hf_frequency_hz_t& frequency) const noexcept;

Purpose: โšก Set/get PWM frequency in Hz
Parameters:

  • channel_id - Target PWM channel
  • frequency - Frequency in Hz

๐ŸŒŸ Fade Operations

1
2
3
4
hf_pwm_err_t StartFade(hf_channel_id_t channel_id, float target_duty_percent, 
                      hf_time_t fade_time_ms) noexcept;
hf_pwm_err_t StopFade(hf_channel_id_t channel_id) noexcept;
bool IsFading(hf_channel_id_t channel_id) const noexcept;

Purpose: ๐ŸŒ… Smooth transitions between duty cycle values
Parameters:

  • target_duty_percent - Target duty cycle (0.0 - 100.0)
  • fade_time_ms - Fade duration in milliseconds

๐Ÿ’ก Usage Examples

๐ŸŽฏ Basic Motor Speed Control

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include "inc/mcu/esp32/EspPwm.h"

// ๐Ÿ—๏ธ Create PWM instance for motor control
EspPwm motor_pwm;

void setup_motor_control() {
    // ๐Ÿš€ Initialize PWM system
    if (!motor_pwm.EnsureInitialized()) {
        printf("โŒ Failed to initialize PWM\n");
        return;
    }
    
    // ๐Ÿ“ก Enable channel 0 for motor speed control
    hf_pwm_err_t result = motor_pwm.EnableChannel(0);
    if (result != hf_pwm_err_t::PWM_SUCCESS) {
        printf("โŒ Failed to enable PWM channel: %s\n", HfPwmErrToString(result));
        return;
    }
    
    // ๐Ÿ“ป Set PWM frequency to 20kHz (typical for motor control)
    result = motor_pwm.SetFrequency(0, 20000);
    if (result != hf_pwm_err_t::PWM_SUCCESS) {
        printf("โŒ Failed to set frequency: %s\n", HfPwmErrToString(result));
        return;
    }
    
    printf("โœ… Motor PWM initialized successfully\n");
}

void set_motor_speed(float speed_percent) {
    // ๐ŸŽ›๏ธ Set motor speed (0-100%)
    hf_pwm_err_t result = motor_pwm.SetDutyCycle(0, speed_percent);
    if (result == hf_pwm_err_t::PWM_SUCCESS) {
        printf("๐ŸŽ๏ธ Motor speed set to %.1f%%\n", speed_percent);
    } else {
        printf("โŒ Failed to set motor speed: %s\n", HfPwmErrToString(result));
    }
}

void motor_control_demo() {
    setup_motor_control();
    
    // ๐Ÿš€ Gradually increase motor speed
    for (float speed = 0.0f; speed <= 100.0f; speed += 10.0f) {
        set_motor_speed(speed);
        vTaskDelay(pdMS_TO_TICKS(500));  // Wait 500ms
    }
    
    // ๐Ÿ›‘ Stop motor
    set_motor_speed(0.0f);
}

๐Ÿ’ก LED Dimming with Fade Effects

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include "inc/mcu/esp32/EspPwm.h"

class SmartLED {
private:
    EspPwm led_pwm*;
    hf_channel_id_t channel*;
    
public:
    SmartLED(hf_channel_id_t channel) : channel*(channel) {}
    
    bool initialize() {
        // ๐Ÿš€ Initialize PWM for LED control
        if (!led_pwm*.EnsureInitialized()) {
            printf("โŒ Failed to initialize LED PWM\n");
            return false;
        }
        
        // ๐Ÿ“ก Enable LED channel
        hf_pwm_err_t result = led_pwm*.EnableChannel(channel*);
        if (result != hf_pwm_err_t::PWM_SUCCESS) {
            printf("โŒ Failed to enable LED channel: %s\n", HfPwmErrToString(result));
            return false;
        }
        
        // ๐Ÿ“ป Set frequency to 1kHz (good for LED dimming)
        result = led_pwm*.SetFrequency(channel*, 1000);
        if (result != hf_pwm_err_t::PWM_SUCCESS) {
            printf("โŒ Failed to set LED frequency: %s\n", HfPwmErrToString(result));
            return false;
        }
        
        printf("โœ… Smart LED initialized on channel %u\n", channel*);
        return true;
    }
    
    void set_brightness(float brightness_percent) {
        // ๐Ÿ’ก Set LED brightness instantly
        hf_pwm_err_t result = led_pwm*.SetDutyCycle(channel*, brightness_percent);
        if (result == hf_pwm_err_t::PWM_SUCCESS) {
            printf("๐Ÿ’ก LED brightness set to %.1f%%\n", brightness_percent);
        } else {
            printf("โŒ Failed to set brightness: %s\n", HfPwmErrToString(result));
        }
    }
    
    void fade_to(float target_brightness, hf_time_t fade_time_ms) {
        // ๐ŸŒŸ Start smooth fade to target brightness
        hf_pwm_err_t result = led_pwm*.StartFade(channel*, target_brightness, fade_time_ms);
        if (result == hf_pwm_err_t::PWM_SUCCESS) {
            printf("๐ŸŒ… Starting fade to %.1f%% over %u ms\n", target_brightness, fade_time_ms);
        } else {
            printf("โŒ Failed to start fade: %s\n", HfPwmErrToString(result));
        }
    }
    
    void breathing_effect() {
        printf("๐Ÿซ Starting breathing effect...\n");
        
        // ๐ŸŒŸ Fade in over 2 seconds
        fade_to(100.0f, 2000);
        vTaskDelay(pdMS_TO_TICKS(2500));  // Wait for fade + extra
        
        // ๐ŸŒ™ Fade out over 2 seconds
        fade_to(0.0f, 2000);
        vTaskDelay(pdMS_TO_TICKS(2500));  // Wait for fade + extra
    }
    
    bool is_fading() {
        return led_pwm*.IsFading(channel*);
    }
};

๐ŸŽต Multi-Channel RGB LED Control

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
class RGBController {
private:
    EspPwm rgb_pwm*;
    static constexpr hf_channel_id_t RED_CHANNEL = 0;
    static constexpr hf_channel_id_t GREEN_CHANNEL = 1;
    static constexpr hf_channel_id_t BLUE_CHANNEL = 2;
    
public:
    bool initialize() {
        // ๐Ÿš€ Initialize RGB PWM controller
        if (!rgb_pwm*.EnsureInitialized()) {
            printf("โŒ Failed to initialize RGB PWM\n");
            return false;
        }
        
        // ๐Ÿ“ก Enable all RGB channels
        const hf_channel_id_t channels[] = {RED_CHANNEL, GREEN_CHANNEL, BLUE_CHANNEL};
        const char* colors[] = {"๐Ÿ”ด Red", "๐ŸŸข Green", "๐Ÿ”ต Blue"};
        
        for (int i = 0; i < 3; i++) {
            hf_pwm_err_t result = rgb_pwm*.EnableChannel(channels[i]);
            if (result != hf_pwm_err_t::PWM_SUCCESS) {
                printf("โŒ Failed to enable %s channel: %s\n", colors[i], HfPwmErrToString(result));
                return false;
            }
            
            // ๐Ÿ“ป Set frequency to 1kHz for all channels
            result = rgb_pwm*.SetFrequency(channels[i], 1000);
            if (result != hf_pwm_err_t::PWM_SUCCESS) {
                printf("โŒ Failed to set %s frequency: %s\n", colors[i], HfPwmErrToString(result));
                return false;
            }
        }
        
        printf("๐ŸŒˆ RGB Controller initialized successfully\n");
        return true;
    }
    
    void set_rgb_color(float red_percent, float green_percent, float blue_percent) {
        // ๐ŸŽจ Set RGB color components
        struct {
            hf_channel_id_t channel;
            float value;
            const char* name;
            const char* emoji;
        } components[] = {
            {RED_CHANNEL, red_percent, "Red", "๐Ÿ”ด"},
            {GREEN_CHANNEL, green_percent, "Green", "๐ŸŸข"},
            {BLUE_CHANNEL, blue_percent, "Blue", "๐Ÿ”ต"}
        };
        
        printf("๐ŸŽจ Setting RGB color: R=%.1f%%, G=%.1f%%, B=%.1f%%\n", 
               red_percent, green_percent, blue_percent);
        
        for (const auto& comp : components) {
            hf_pwm_err_t result = rgb_pwm*.SetDutyCycle(comp.channel, comp.value);
            if (result != hf_pwm_err_t::PWM_SUCCESS) {
                printf("โŒ Failed to set %s %s: %s\n", comp.emoji, comp.name, HfPwmErrToString(result));
            }
        }
    }
    
    void color_demo() {
        printf("๐ŸŒˆ Starting RGB color demo...\n");
        
        // ๐Ÿ”ด Pure red
        set_rgb_color(100.0f, 0.0f, 0.0f);
        vTaskDelay(pdMS_TO_TICKS(1000));
        
        // ๐ŸŸข Pure green  
        set_rgb_color(0.0f, 100.0f, 0.0f);
        vTaskDelay(pdMS_TO_TICKS(1000));
        
        // ๐Ÿ”ต Pure blue
        set_rgb_color(0.0f, 0.0f, 100.0f);
        vTaskDelay(pdMS_TO_TICKS(1000));
        
        // ๐ŸŸก Yellow (red + green)
        set_rgb_color(100.0f, 100.0f, 0.0f);
        vTaskDelay(pdMS_TO_TICKS(1000));
        
        // ๐ŸŸฃ Magenta (red + blue)
        set_rgb_color(100.0f, 0.0f, 100.0f);
        vTaskDelay(pdMS_TO_TICKS(1000));
        
        // ๐ŸŸฆ Cyan (green + blue)
        set_rgb_color(0.0f, 100.0f, 100.0f);
        vTaskDelay(pdMS_TO_TICKS(1000));
        
        // โšช White (all colors)
        set_rgb_color(100.0f, 100.0f, 100.0f);
        vTaskDelay(pdMS_TO_TICKS(1000));
        
        // โšซ Off
        set_rgb_color(0.0f, 0.0f, 0.0f);
    }
    
    void rainbow_fade() {
        printf("๐ŸŒˆ Starting rainbow fade effect...\n");
        
        // Start fade operations for smooth color transitions
        rgb_pwm*.StartFade(RED_CHANNEL, 100.0f, 2000);
        vTaskDelay(pdMS_TO_TICKS(500));
        rgb_pwm*.StartFade(GREEN_CHANNEL, 100.0f, 2000);
        vTaskDelay(pdMS_TO_TICKS(500));
        rgb_pwm*.StartFade(BLUE_CHANNEL, 100.0f, 2000);
    }
};

๐Ÿค– Servo Motor Control

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
class ServoController {
private:
    EspPwm servo_pwm*;
    hf_channel_id_t channel*;
    static constexpr float SERVO_MIN_DUTY = 2.5f;   // 2.5% duty cycle (0 degrees)
    static constexpr float SERVO_MAX_DUTY = 12.5f;  // 12.5% duty cycle (180 degrees)
    static constexpr hf_frequency_hz_t SERVO_FREQ = 50; // 50Hz for standard servos
    
public:
    ServoController(hf_channel_id_t channel) : channel*(channel) {}
    
    bool initialize() {
        // ๐Ÿš€ Initialize servo PWM
        if (!servo_pwm*.EnsureInitialized()) {
            printf("โŒ Failed to initialize servo PWM\n");
            return false;
        }
        
        // ๐Ÿ“ก Enable servo channel
        hf_pwm_err_t result = servo_pwm*.EnableChannel(channel*);
        if (result != hf_pwm_err_t::PWM_SUCCESS) {
            printf("โŒ Failed to enable servo channel: %s\n", HfPwmErrToString(result));
            return false;
        }
        
        // ๐Ÿ“ป Set servo frequency to 50Hz
        result = servo_pwm*.SetFrequency(channel*, SERVO_FREQ);
        if (result != hf_pwm_err_t::PWM_SUCCESS) {
            printf("โŒ Failed to set servo frequency: %s\n", HfPwmErrToString(result));
            return false;
        }
        
        // ๐ŸŽฏ Set to center position (90 degrees)
        set_angle(90.0f);
        
        printf("๐Ÿค– Servo controller initialized on channel %u\n", channel*);
        return true;
    }
    
    void set_angle(float angle_degrees) {
        // ๐ŸŽฏ Convert angle to PWM duty cycle
        // Servo range: 0-180 degrees maps to 2.5%-12.5% duty cycle
        if (angle_degrees < 0.0f) angle_degrees = 0.0f;
        if (angle_degrees > 180.0f) angle_degrees = 180.0f;
        
        float duty_percent = SERVO_MIN_DUTY + (angle_degrees / 180.0f) * (SERVO_MAX_DUTY - SERVO_MIN_DUTY);
        
        hf_pwm_err_t result = servo_pwm*.SetDutyCycle(channel*, duty_percent);
        if (result == hf_pwm_err_t::PWM_SUCCESS) {
            printf("๐Ÿค– Servo angle set to %.1fยฐ (%.2f%% duty)\n", angle_degrees, duty_percent);
        } else {
            printf("โŒ Failed to set servo angle: %s\n", HfPwmErrToString(result));
        }
    }
    
    void smooth_move_to(float target_angle, hf_time_t move_time_ms) {
        // ๐ŸŒŸ Smooth movement to target angle
        float current_duty, target_duty;
        servo_pwm*.GetDutyCycle(channel*, current_duty);
        
        // Calculate target duty cycle
        if (target_angle < 0.0f) target_angle = 0.0f;
        if (target_angle > 180.0f) target_angle = 180.0f;
        target_duty = SERVO_MIN_DUTY + (target_angle / 180.0f) * (SERVO_MAX_DUTY - SERVO_MIN_DUTY);
        
        hf_pwm_err_t result = servo_pwm*.StartFade(channel*, target_duty, move_time_ms);
        if (result == hf_pwm_err_t::PWM_SUCCESS) {
            printf("๐ŸŒŸ Servo smoothly moving to %.1fยฐ over %u ms\n", target_angle, move_time_ms);
        } else {
            printf("โŒ Failed to start smooth movement: %s\n", HfPwmErrToString(result));
        }
    }
    
    void sweep_demo() {
        printf("๐Ÿ”„ Starting servo sweep demo...\n");
        
        // ๐Ÿ”„ Sweep from 0 to 180 degrees
        for (float angle = 0.0f; angle <= 180.0f; angle += 30.0f) {
            set_angle(angle);
            vTaskDelay(pdMS_TO_TICKS(1000));
        }
        
        // ๐Ÿ”„ Sweep back from 180 to 0 degrees
        for (float angle = 180.0f; angle >= 0.0f; angle -= 30.0f) {
            set_angle(angle);
            vTaskDelay(pdMS_TO_TICKS(1000));
        }
        
        // ๐ŸŽฏ Return to center
        set_angle(90.0f);
    }
};

๐Ÿ“Š Performance and Diagnostics

๐Ÿ“ˆ Statistics Monitoring

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void monitor_pwm_performance(BasePwm& pwm) {
    hf_pwm_statistics_t stats;
    hf_pwm_err_t result = pwm.GetStatistics(stats);
    
    if (result == hf_pwm_err_t::PWM_SUCCESS) {
        printf("๐Ÿ“Š PWM Performance Statistics:\n");
        printf("   ๐Ÿ”„ Duty Updates: %u\n", stats.duty_updates_count);
        printf("   ๐Ÿ“ป Frequency Changes: %u\n", stats.frequency_changes_count);
        printf("   ๐ŸŒŸ Fade Operations: %u\n", stats.fade_operations_count);
        printf("   โœ… Channel Enables: %u\n", stats.channel_enables_count);
        printf("   โŒ Channel Disables: %u\n", stats.channel_disables_count);
        printf("   โš ๏ธ Total Errors: %u\n", stats.error_count);
    }
}

๐Ÿ›ก๏ธ Error Handling Best Practices

๐ŸŽฏ Comprehensive Error Checking

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
hf_pwm_err_t safe_set_duty_cycle(BasePwm& pwm, hf_channel_id_t channel, float duty) {
    // โœ… Validate duty cycle range
    if (duty < 0.0f || duty > 100.0f) {
        printf("โŒ Invalid duty cycle: %.2f%% (must be 0-100%%)\n", duty);
        return hf_pwm_err_t::PWM_ERR_DUTY_OUT_OF_RANGE;
    }
    
    // โœ… Check if channel is available
    if (!pwm.IsChannelAvailable(channel)) {
        printf("โŒ Channel %u not available\n", channel);
        return hf_pwm_err_t::PWM_ERR_INVALID_CHANNEL;
    }
    
    // โœ… Ensure PWM is initialized
    if (!pwm.EnsureInitialized()) {
        printf("โŒ Failed to initialize PWM\n");
        return hf_pwm_err_t::PWM_ERR_NOT_INITIALIZED;
    }
    
    // โœ… Enable channel if not already enabled
    if (!pwm.IsChannelEnabled(channel)) {
        hf_pwm_err_t result = pwm.EnableChannel(channel);
        if (result != hf_pwm_err_t::PWM_SUCCESS) {
            printf("โŒ Failed to enable channel %u: %s\n", channel, HfPwmErrToString(result));
            return result;
        }
    }
    
    // ๐ŸŽ›๏ธ Set duty cycle
    return pwm.SetDutyCycle(channel, duty);
}

๐ŸŽ๏ธ Performance Considerations

โšก Optimization Tips

  • ๐Ÿ”ข Channel Limits - Check GetMaxChannels() before allocating channels
  • ๐Ÿ“ป Frequency Ranges - Respect hardware frequency limitations
  • ๐ŸŽฏ Resolution Trade-offs - Higher frequencies may reduce duty cycle resolution
  • ๐ŸŒŸ Fade Performance - Hardware-based fading is faster than software loops
  • ๐Ÿ’พ Memory Usage - Use lazy initialization to save memory

๐Ÿ“Š Typical Performance Ranges

Hardware Channels Frequency Range Resolution

|โ€”โ€”โ€”โ€”โ€“|โ€”โ€”โ€”โ€”โ€“|โ€”โ€”โ€”โ€”โ€”โ€”โ€”|โ€”โ€”โ€”โ€”โ€”-|

ESP32-C6 LEDC 8 1Hz - 40MHz 1-20 bits
External PWM ICs 4-16 1Hz - 1.5MHz 8-16 bits
Motor Controllers 2-6 1kHz - 100kHz 10-16 bits

๐Ÿงต Thread Safety

The BasePwm class is not thread-safe. For concurrent access, use appropriate synchronization or consider thread-safe wrapper implementations.