7
7
namespace audio_tools {
8
8
9
9
/* *
10
- * @brief Information for a PIN
11
- * @author Phil Schatzmann
12
- * @copyright GPLv3
10
+ * @brief Mapping information for one complementary PWM audio channel.
11
+ *
12
+ * A single logical audio PWM channel is produced by one MCPWM timer within an
13
+ * MCPWM unit. Each timer provides two generator outputs (A and B) which we map
14
+ * to a high-side MOSFET gate (gpio_high / PWMxA) and a low-side MOSFET gate
15
+ * (gpio_low / PWMxB). When dead time is enabled the peripheral inserts blanking
16
+ * around switching edges to avoid shoot-through between the high and low
17
+ * transistors on a half bridge.
13
18
*/
14
19
struct PinInfoESP32Compl {
15
20
int gpio_high; // high-side pin (PWMxA)
@@ -26,6 +31,67 @@ struct PinInfoESP32Compl {
26
31
* @copyright GPLv3
27
32
*/
28
33
34
+ /* *
35
+ * @class PWMComplementaryDriverESP32
36
+ * @brief Complementary (half‑bridge) PWM audio driver for ESP32 using the legacy MCPWM driver API.
37
+ *
38
+ * @details This driver produces audio by modulating one or more complementary
39
+ * PWM pairs (high / low outputs) using the ESP32 MCPWM peripheral. Each audio
40
+ * channel occupies one MCPWM timer (up to 3 timers per MCPWM unit, and 2 units
41
+ * → maximum of 6 complementary channels). For every channel two GPIOs are
42
+ * driven 180° out of phase. Optional hardware dead time can be inserted to
43
+ * protect external half‑bridge power stages.
44
+ *
45
+ * The duty cycle is derived from the (optionally decimated) audio samples in
46
+ * the base class buffer. The effective output sample rate equals the rate at
47
+ * which new duty values are pushed to the MCPWM hardware (timer interrupt /
48
+ * alarm frequency) and may differ from the nominal input sample rate due to
49
+ * decimation (see DriverPWMBase).
50
+ *
51
+ * Resolution & PWM Frequency:
52
+ * The requested bit resolution (e.g. 8–11 bits) determines the PWM carrier
53
+ * frequency using empirically chosen values (see frequency()). If
54
+ * PWMConfig::pwm_frequency is left as 0 the driver derives it from the
55
+ * resolution. Otherwise the provided frequency is used.
56
+ *
57
+ * Dead Time:
58
+ * If PWMConfig::dead_time_us > 0 the driver configures hardware complementary
59
+ * mode with symmetric dead time (rising & falling) in ticks computed from the
60
+ * APB clock (assumed 80 MHz). For very large dead time requests relative to
61
+ * the PWM period the value is limited to maintain a usable duty range.
62
+ * Without dead time the driver emulates complementary operation by inverting
63
+ * the B duty in software (B = 100% - A).
64
+ *
65
+ * Pin Assignment:
66
+ * Provide either 2 * channels GPIO values (high0, low0, high1, low1, ...). If
67
+ * only one pin per channel is supplied the low pin is assumed to be high+1.
68
+ *
69
+ * Limitations:
70
+ * - Uses the legacy MCPWM API (driver/mcpwm.h). ESP-IDF v5+ introduces a new
71
+ * prelude API which is not covered here.
72
+ * - Maximum 6 complementary channels (2 units * 3 timers).
73
+ * - Dead time calculation assumes 80 MHz APB clock.
74
+ * - No dynamic reconfiguration of frequency / dead time while running; call
75
+ * end() and begin() again to change.
76
+ *
77
+ * Thread Safety:
78
+ * Access from a single task context; ISR only invokes playNextFrame().
79
+ *
80
+ * Typical Usage:
81
+ * @code
82
+ * PWMComplementaryDriverESP32 drv;
83
+ * PWMConfig cfg = drv.defaultConfig();
84
+ * cfg.channels = 2; // stereo
85
+ * cfg.setPins({25,26, 27,14}); // high0,low0, high1,low1
86
+ * cfg.dead_time_us = 1; // 1 microsecond dead time
87
+ * drv.begin(cfg);
88
+ * // write PCM frames (uint8_t / int16_t depending on bits_per_sample)
89
+ * drv.write(samples, len);
90
+ * drv.end();
91
+ * @endcode
92
+ *
93
+ * @ingroup platform
94
+ */
29
95
class PWMComplementaryDriverESP32 : public DriverPWMBase {
30
96
public:
31
97
// friend void pwm_callback(void*ptr);
0 commit comments