Коротко: Klipper використовує програмний PWM за замовчуванням, але може використовувати апаратний PWM на підтримуваних MCU, якщо ви явно увімкнете його в конфігурації.
Програмний PWM за замовчуванням
Коли ви налаштовуєте вентилятор, нагрівач або загальний вихідний пін у Klipper без спеціальних прапорців, Klipper використовує програмний PWM. Важливо розуміти, що бітове маніпулювання не виконується на стороні хоста/Linux — хост лише планує переходи та надсилає їх до MCU. Фактичне перемикання GPIO відбувається всередині прошивки MCU.
У klippy/mcu.py клас MCU_pwm вирішує, який шлях обрати. Якщо hardware_pwm має значення False (за замовчуванням), він налаштовує пін як звичайний цифровий вихід і надсилає config_digital_out та set_digital_out_pwm_cycle до MCU (рядки 509-530). Для кожного оновлення робочого циклу він надсилає queue_digital_out зі значенням on_ticks, яке повідомляє MCU, скільки тактів годинника пін повинен залишатися високим у межах PWM-циклу.
На стороні MCU src/gpiocmds.c реалізує кінцевий автомат soft-PWM:
digital_load_event()зчитує наступне оновлення з черги, встановлює початковий стан піна та обчислює, чи потрібно перемикнути пін.digital_toggle_event()перемикає пін і переплановує себе для тривалості увімкнення або вимкнення в межах циклу.
Отже, PWM-хвилі генеруються планувальником переривань таймера MCU, керованим списком майбутніх переходів хоста.
Апаратний PWM — опціональний
Апаратний PWM вмикається для кожного піна за допомогою hardware_pwm: True у конфігурації. Коли це встановлено, хост надсилає команди config_pwm_out та queue_pwm_out замість попередніх, а MCU використовує PWM-периферію платформи.
Диспетчер на стороні MCU знаходиться у src/pwmcmds.c. Специфічні для платформи реалізації існують для кількох MCU:
src/atsam/hard_pwm.csrc/atsamd/hard_pwm.csrc/avr/hard_pwm.csrc/hc32f460/hard_pwm.csrc/lpc176x/hard_pwm.csrc/rp2040/hard_pwm.csrc/stm32/hard_pwm.c
Наприклад, реалізація STM32 у gpio_pwm_setup() знаходить таймер/канал для запитаного піна, обчислює прескалер та період лічильника, що найкраще відповідають запитаному часу циклу, а потім записує значення робочого циклу в регістр захоплення/порівняння таймера.
Документація Klipper прямо попереджає, що “більшість вентиляторів не працюють добре з апаратним PWM, тому не рекомендується вмикати це, якщо немає електричної потреби перемикати на дуже високих швидкостях” (Config_Reference.md).
Що визначає частоту PWM?
Частота — це просто 1 / cycle_time, що задається в конфігурації:
[fan]:cycle_time: 0.010→ 100 Гц (за замовчуванням).[output_pin]:cycle_time: 0.100→ 10 Гц (за замовчуванням).[extruder]/[heater_bed]:pwm_cycle_time: 0.100→ 10 Гц (за замовчуванням).
Для програмного PWM це фактична частота, на якій перемикається MCU. Для апаратного PWM це запитана частота, але апаратний таймер MCU може округлити її до найближчого досяжного значення через обмеження прескалера/лічильника. Крім того, кілька апаратних PWM-пінів, що поділяють один таймер, повинні працювати на однаковій частоті; інакше Klipper видає помилку “PWM already programmed at different speed”.
Приклад конфігурації
Вентилятор з програмним PWM (за замовчуванням)
[fan]
pin: PA8
cycle_time: 0.010
hardware_pwm: FalseВихідний пін з апаратним PWM
[output_pin my_pwm]
pin: PB0
pwm: True
cycle_time: 0.001
hardware_pwm: TrueПеріод PWM нагрівача
[extruder]
heater_pin: PA2
pwm_cycle_time: 0.100