Files

219 lines
9.1 KiB
Zig

const sys = @import("sys");
const errors = @import("error");
// ---------------------------------------------------------------------------
// Type aliases & enums
// ---------------------------------------------------------------------------
pub const ChannelConfig = sys.ledc_channel_config_t;
pub const TimerConfig = sys.ledc_timer_config_t;
pub const IsrHandle = sys.ledc_isr_handle_t;
pub const CbParam = sys.ledc_cb_param_t;
pub const Cbs = sys.ledc_cbs_t;
/// Speed mode. Most modern ESP32 variants only support LOW_SPEED_MODE.
pub const SpeedMode = enum(sys.ledc_mode_t) {
low = sys.LEDC_LOW_SPEED_MODE,
};
pub const IntrType = enum(sys.ledc_intr_type_t) {
disable = sys.LEDC_INTR_DISABLE,
fade_end = sys.LEDC_INTR_FADE_END,
};
pub const DutyDir = enum(sys.ledc_duty_direction_t) {
decrease = sys.LEDC_DUTY_DIR_DECREASE,
increase = sys.LEDC_DUTY_DIR_INCREASE,
};
pub const Timer = enum(sys.ledc_timer_t) {
@"0" = sys.LEDC_TIMER_0,
@"1" = sys.LEDC_TIMER_1,
@"2" = sys.LEDC_TIMER_2,
@"3" = sys.LEDC_TIMER_3,
};
pub const Channel = enum(sys.ledc_channel_t) {
@"0" = sys.LEDC_CHANNEL_0,
@"1" = sys.LEDC_CHANNEL_1,
@"2" = sys.LEDC_CHANNEL_2,
@"3" = sys.LEDC_CHANNEL_3,
@"4" = sys.LEDC_CHANNEL_4,
@"5" = sys.LEDC_CHANNEL_5,
};
pub const TimerBit = enum(sys.ledc_timer_bit_t) {
@"1" = sys.LEDC_TIMER_1_BIT,
@"2" = sys.LEDC_TIMER_2_BIT,
@"3" = sys.LEDC_TIMER_3_BIT,
@"4" = sys.LEDC_TIMER_4_BIT,
@"5" = sys.LEDC_TIMER_5_BIT,
@"6" = sys.LEDC_TIMER_6_BIT,
@"7" = sys.LEDC_TIMER_7_BIT,
@"8" = sys.LEDC_TIMER_8_BIT,
@"9" = sys.LEDC_TIMER_9_BIT,
@"10" = sys.LEDC_TIMER_10_BIT,
@"11" = sys.LEDC_TIMER_11_BIT,
@"12" = sys.LEDC_TIMER_12_BIT,
@"13" = sys.LEDC_TIMER_13_BIT,
@"14" = sys.LEDC_TIMER_14_BIT,
};
pub const FadeMode = enum(sys.ledc_fade_mode_t) {
no_wait = sys.LEDC_FADE_NO_WAIT,
wait_done = sys.LEDC_FADE_WAIT_DONE,
};
// ---------------------------------------------------------------------------
// Timer configuration and control
// ---------------------------------------------------------------------------
pub const TimerCtrl = struct {
/// Configure a LEDC timer (frequency + duty resolution).
pub fn config(cfg: *const TimerConfig) !void {
try errors.espCheckError(sys.ledc_timer_config(cfg));
}
/// Reset a LEDC timer.
pub fn reset(mode: SpeedMode, timer: Timer) !void {
try errors.espCheckError(sys.ledc_timer_rst(@intFromEnum(mode), @intFromEnum(timer)));
}
/// Pause a LEDC timer.
pub fn pause(mode: SpeedMode, timer: Timer) !void {
try errors.espCheckError(sys.ledc_timer_pause(@intFromEnum(mode), @intFromEnum(timer)));
}
/// Resume a paused LEDC timer.
pub fn @"resume"(mode: SpeedMode, timer: Timer) !void {
try errors.espCheckError(sys.ledc_timer_resume(@intFromEnum(mode), @intFromEnum(timer)));
}
/// Set the frequency (Hz) of a running timer.
pub fn setFreq(mode: SpeedMode, timer: Timer, freq_hz: u32) !void {
try errors.espCheckError(sys.ledc_set_freq(@intFromEnum(mode), @intFromEnum(timer), freq_hz));
}
/// Get the current frequency (Hz) of a timer.
pub fn getFreq(mode: SpeedMode, timer: Timer) u32 {
return sys.ledc_get_freq(@intFromEnum(mode), @intFromEnum(timer));
}
/// Return the best duty resolution for a given source clock and target frequency.
pub fn findSuitableDutyResolution(src_clk_freq: u32, timer_freq: u32) u32 {
return sys.ledc_find_suitable_duty_resolution(src_clk_freq, timer_freq);
}
};
// ---------------------------------------------------------------------------
// Channel configuration and control
// ---------------------------------------------------------------------------
pub const ChannelCtrl = struct {
/// Configure a LEDC output channel.
pub fn config(cfg: *const ChannelConfig) !void {
try errors.espCheckError(sys.ledc_channel_config(cfg));
}
/// Re-assign a GPIO to an existing channel (without full reconfiguration).
pub fn setPin(gpio_num: c_int, mode: SpeedMode, ch: Channel) !void {
try errors.espCheckError(sys.ledc_set_pin(gpio_num, @intFromEnum(mode), @intFromEnum(ch)));
}
/// Stop the channel output and set the GPIO to `idle_level` (0 or 1).
pub fn stop(mode: SpeedMode, ch: Channel, idle_level: u32) !void {
try errors.espCheckError(sys.ledc_stop(@intFromEnum(mode), @intFromEnum(ch), idle_level));
}
/// Bind a channel to a different timer.
pub fn bindTimer(mode: SpeedMode, ch: Channel, timer: Timer) !void {
try errors.espCheckError(sys.ledc_bind_channel_timer(@intFromEnum(mode), @intFromEnum(ch), @intFromEnum(timer)));
}
// ── Duty ──────────────────────────────────────────────────────────────
/// Set the duty cycle (without updating the hardware — call `updateDuty` after).
pub fn setDuty(mode: SpeedMode, ch: Channel, duty: u32) !void {
try errors.espCheckError(sys.ledc_set_duty(@intFromEnum(mode), @intFromEnum(ch), duty));
}
/// Set duty + hpoint (without updating hardware).
pub fn setDutyWithHpoint(mode: SpeedMode, ch: Channel, duty: u32, hpoint: u32) !void {
try errors.espCheckError(sys.ledc_set_duty_with_hpoint(@intFromEnum(mode), @intFromEnum(ch), duty, hpoint));
}
/// Latch the duty value set by `setDuty`/`setDutyWithHpoint` into hardware.
pub fn updateDuty(mode: SpeedMode, ch: Channel) !void {
try errors.espCheckError(sys.ledc_update_duty(@intFromEnum(mode), @intFromEnum(ch)));
}
/// Set duty and immediately apply it to hardware (combines set + update).
pub fn setDutyAndUpdate(mode: SpeedMode, ch: Channel, duty: u32, hpoint: u32) !void {
try errors.espCheckError(sys.ledc_set_duty_and_update(@intFromEnum(mode), @intFromEnum(ch), duty, hpoint));
}
/// Get the current duty cycle value.
pub fn getDuty(mode: SpeedMode, ch: Channel) u32 {
return sys.ledc_get_duty(@intFromEnum(mode), @intFromEnum(ch));
}
/// Get the current hpoint value.
pub fn getHpoint(mode: SpeedMode, ch: Channel) c_int {
return sys.ledc_get_hpoint(@intFromEnum(mode), @intFromEnum(ch));
}
// ── Callback ──────────────────────────────────────────────────────────
/// Register a callback for fade-end events on a channel.
pub fn registerCallback(mode: SpeedMode, ch: Channel, cbs: *Cbs, user_arg: ?*anyopaque) !void {
try errors.espCheckError(sys.ledc_cb_register(@intFromEnum(mode), @intFromEnum(ch), cbs, user_arg));
}
};
// ---------------------------------------------------------------------------
// Fade functions
// ---------------------------------------------------------------------------
pub const Fade = struct {
/// Install the fade ISR service. Call once before using any fade functions.
/// `intr_alloc_flags`: interrupt allocation flags (e.g. ESP_INTR_FLAG_IRAM).
pub fn install(intr_alloc_flags: c_int) !void {
try errors.espCheckError(sys.ledc_fade_func_install(intr_alloc_flags));
}
/// Uninstall the fade ISR service.
pub fn uninstall() void {
sys.ledc_fade_func_uninstall();
}
/// Start a fade previously configured with `setFadeStep` or `setFadeTime`.
pub fn start(mode: SpeedMode, ch: Channel, fade_mode: FadeMode) !void {
try errors.espCheckError(sys.ledc_fade_start(@intFromEnum(mode), @intFromEnum(ch), @intFromEnum(fade_mode)));
}
/// Stop an in-progress fade.
pub fn stop(mode: SpeedMode, ch: Channel) !void {
try errors.espCheckError(sys.ledc_fade_stop(@intFromEnum(mode), @intFromEnum(ch)));
}
/// Configure a fade by time: ramp from current duty to `target_duty` in `fade_time_ms`.
pub fn setFadeTime(mode: SpeedMode, ch: Channel, target_duty: u32, fade_time_ms: c_int) !void {
try errors.espCheckError(sys.ledc_set_fade_with_time(@intFromEnum(mode), @intFromEnum(ch), target_duty, fade_time_ms));
}
/// Configure a fade by step: ramp with a fixed `scale` increment every `cycle_num` PWM cycles.
pub fn setFadeStep(mode: SpeedMode, ch: Channel, target_duty: u32, scale: u32, cycle_num: u32) !void {
try errors.espCheckError(sys.ledc_set_fade_with_step(@intFromEnum(mode), @intFromEnum(ch), target_duty, scale, cycle_num));
}
/// Set fade time and immediately start it.
pub fn setFadeTimeAndStart(mode: SpeedMode, ch: Channel, target_duty: u32, fade_time_ms: u32, fade_mode: FadeMode) !void {
try errors.espCheckError(sys.ledc_set_fade_time_and_start(@intFromEnum(mode), @intFromEnum(ch), target_duty, fade_time_ms, @intFromEnum(fade_mode)));
}
/// Set fade step and immediately start it.
pub fn setFadeStepAndStart(mode: SpeedMode, ch: Channel, target_duty: u32, scale: u32, cycle_num: u32, fade_mode: FadeMode) !void {
try errors.espCheckError(sys.ledc_set_fade_step_and_start(@intFromEnum(mode), @intFromEnum(ch), target_duty, scale, cycle_num, @intFromEnum(fade_mode)));
}
};