PWM (Pulse Width Modulation) support for libDaisy Nim wrapper
This module provides hardware PWM support using the STM32 timer peripherals. PWM is useful for LED control, motor control, servo control, and generating analog-like signals.
Example - Simple LED dimming:
import nimphea, per/pwm var hw = initDaisy() # Initialize PWM on TIM3, channel 2 (internal LED on Daisy Seed) var pwm = initPwm(TIM_3, frequency = 1000.0) # 1kHz pwm.channel2.init() # Fade LED in and out while true: for brightness in 0..100: pwm.channel2.set(brightness / 100.0) hw.delay(10) for brightness in countdown(100, 0): pwm.channel2.set(brightness / 100.0) hw.delay(10)
Example - Multiple channels:
# TIM4 with 4 channels (RGB LED + servo) var pwm = initPwm(TIM_4, frequency = 50.0) # 50Hz for servo # Configure channels with specific pins pwm.channel1.init(D13()) # Red LED pwm.channel2.init(D14()) # Green LED pwm.channel3.init(D11()) # Blue LED pwm.channel4.init(D12()) # Servo control # Set RGB color and servo position pwm.channel1.set(1.0) # Red full pwm.channel2.set(0.5) # Green half pwm.channel3.set(0.0) # Blue off pwm.channel4.set(0.075) # Servo center (1.5ms @ 50Hz)
Types
PwmChannel {.importcpp: "daisy::PWMHandle::Channel".} = object
- Source Edit
PwmChannelConfig {.importcpp: "daisy::PWMHandle::Channel::Config", bycopy.} = object pin* {.importc: "pin".}: Pin polarity* {.importc: "polarity".}: PwmPolarity
- Source Edit
PwmConfig {.importcpp: "daisy::PWMHandle::Config", bycopy.} = object periph* {.importc: "periph".}: PwmPeripheral prescaler* {.importc: "prescaler".}: uint32 period* {.importc: "period".}: uint32
- Source Edit
PwmHandleImpl {.importcpp: "daisy::PWMHandle::Impl".} = object
- Source Edit
PwmPeripheral {.importcpp: "daisy::PWMHandle::Config::Peripheral", size: 4.} = enum TIM_3 = 0, ## TIM3 - 16-bit counter TIM_4 = 1, ## TIM4 - 16-bit counter TIM_5 = 2 ## TIM5 - 32-bit counter
- Source Edit
PwmPolarity {.importcpp: "daisy::PWMHandle::Channel::Config::Polarity", size: 4.} = enum POLARITY_HIGH = 0, ## Output high when active POLARITY_LOW ## Output low when active
- Source Edit
Consts
TIM3_CH1_DEFAULT = "D19"
- PA6 Source Edit
TIM3_CH2_DEFAULT = "LED"
- PC7 (internal LED) Source Edit
TIM3_CH3_DEFAULT = "D4"
- PC8 Source Edit
TIM3_CH4_DEFAULT = "D17"
- PB1 Source Edit
TIM4_CH1_PIN = "D13"
- PB6 Source Edit
TIM4_CH2_PIN = "D14"
- PB7 Source Edit
TIM4_CH3_PIN = "D11"
- PB8 Source Edit
TIM4_CH4_PIN = "D12"
- PB9 Source Edit
TIM5_CH1_PIN = "D25"
- PA0 Source Edit
TIM5_CH2_PIN = "D24"
- PA1 Source Edit
TIM5_CH3_PIN = "D28"
- PA2 Source Edit
TIM5_CH4_PIN = "D16"
- PA3 Source Edit
Procs
proc channel1(pwm: var PwmHandle): var PwmChannel {.inline, ...raises: [], tags: [], forbids: [].}
- Source Edit
proc channel2(pwm: var PwmHandle): var PwmChannel {.inline, ...raises: [], tags: [], forbids: [].}
- Source Edit
proc channel3(pwm: var PwmHandle): var PwmChannel {.inline, ...raises: [], tags: [], forbids: [].}
- Source Edit
proc channel4(pwm: var PwmHandle): var PwmChannel {.inline, ...raises: [], tags: [], forbids: [].}
- Source Edit
proc cppInit(pwm: var PwmHandle; peripheral: PwmPeripheral; frequency: float = 1000.0) {....raises: [], tags: [], forbids: [].}
-
Initialize PWM peripheral in-place with a target frequency
This function initializes an existing PwmHandle variable. Use this to avoid copy constructor issues.
Parameters: pwm: The PwmHandle variable to initialize peripheral: TIM_3, TIM_4, or TIM_5 frequency: Target frequency in Hz (default 1000Hz / 1kHz)
Example:
var pwm {.noinit.}: PwmHandle pwm.cppInit(TIM_3, 1000.0) # 1kHz pwm.channel1.init()
Source Edit proc deinit(channel: var PwmChannel): PwmResult {....raises: [], tags: [], forbids: [].}
- Deinitialize a PWM channel Source Edit
proc init(channel: var PwmChannel; pin: Pin = Pin(); polarity: PwmPolarity = POLARITY_HIGH): PwmResult {....raises: [], tags: [], forbids: [].}
-
Initialize a PWM channel
Parameters: pin: GPIO pin for output (use Pin() for default) polarity: POLARITY_HIGH (normal) or POLARITY_LOW (inverted)
Example:
pwm.channel1.init(D13()) pwm.channel2.init() # Use default pin
Source Edit proc initPwm(peripheral: PwmPeripheral; frequency: float = 1000.0): PwmHandle {. ...raises: [], tags: [], forbids: [].}
-
Initialize PWM peripheral with a target frequency
Note: Due to C++ copy constructor restrictions, you may need to use cppInit() instead if you get compiler errors.
Parameters: peripheral: TIM_3, TIM_4, or TIM_5 frequency: Target frequency in Hz (default 1000Hz / 1kHz)
Returns: Initialized PWM handle (channels must be initialized separately)
Example:
var pwm {.noinit.}: PwmHandle pwm.cppInit(TIM_3, 1000.0) # Recommended
Source Edit proc initPwmCustom(peripheral: PwmPeripheral; prescaler: uint32; period: uint32): PwmHandle {. ...raises: [], tags: [], forbids: [].}
-
Initialize PWM with explicit prescaler and period values
For advanced users who want exact control over timing. Frequency = SYSCLK / (2 * (period + 1) * (prescaler + 1))
Parameters: peripheral: TIM_3, TIM_4, or TIM_5 prescaler: Clock prescaler (0 = no division) period: Counter period before reset
Example:
# 100Hz PWM with maximum resolution var pwm = initPwmCustom(TIM_5, 0, 2_400_000)
Source Edit proc set(channel: var PwmChannel; dutyCycle: float) {....raises: [], tags: [], forbids: [].}
-
Set PWM duty cycle as a float (0.0 to 1.0)
Parameters: dutyCycle: Duty cycle from 0.0 (0%) to 1.0 (100%)
Example:
channel.set(0.5) # 50% duty cycle channel.set(0.25) # 25% duty cycle channel.set(1.0) # 100% duty cycle (fully on)
Source Edit proc setPrescaler(pwm: var PwmHandle; prescaler: uint32) {....raises: [], tags: [], forbids: [].}
- Change the prescaler after initialization Source Edit
proc setRaw(channel: var PwmChannel; value: uint32) {....raises: [], tags: [], forbids: [].}
-
Set PWM duty cycle as raw counter value
Value must be <= timer's period
Parameters: value: Raw counter value
Example:
# If period is 1000, this sets 75% duty cycle channel.setRaw(750)
Source Edit