-
Notifications
You must be signed in to change notification settings - Fork 0
GPIO
This document describes the GPIO (General Purpose Input/Output) implementation in Gopper, which provides full compatibility with Klipper's digital output protocol.
The GPIO implementation allows Klipper to control digital output pins on the microcontroller with precise timing. This is used for various purposes including:
- Heater control (on/off or PWM)
- Fan control (on/off or PWM)
- LED indicators
- Enable/disable signals for stepper drivers
- Any other digital control signals
The GPIO implementation follows the same pattern as other Gopper subsystems:
┌─────────────────────────────────────────┐
│ Klipper Host (Python) │
│ - Sends GPIO commands via protocol │
└───────────────┬─────────────────────────┘
│ USB/UART
┌───────────────▼─────────────────────────┐
│ Protocol Layer (protocol/) │
│ - VLQ encoding/decoding │
└───────────────┬─────────────────────────┘
│
┌───────────────▼─────────────────────────┐
│ Core GPIO Logic (core/gpio.go) │
│ - Command handlers │
│ - DigitalOut management │
│ - Timer-based scheduling │
│ - PWM generation │
└───────────────┬─────────────────────────┘
│
┌───────────────▼─────────────────────────┐
│ GPIO HAL (core/gpio_hal.go) │
│ - Abstract interface │
└───────────────┬─────────────────────────┘
│
┌───────────────▼─────────────────────────┐
│ Platform Driver (targets/rp2040/) │
│ - Hardware-specific pin control │
└─────────────────────────────────────────┘
-
core/gpio_hal.go: HAL interface definition-
GPIODriverinterface for platform abstraction -
ConfigureOutput(),SetPin(),GetPin()methods
-
-
core/gpio.go: Main GPIO implementation-
DigitalOutstruct for managing GPIO state - Command handlers:
config_digital_out,queue_digital_out,update_digital_out,set_digital_out_pwm_cycle - Timer handlers for scheduled updates and PWM toggling
- Safety features: max_duration enforcement, shutdown behavior
-
-
core/gpio_test.go: Unit tests- Mock GPIO driver for testing
- Basic functionality tests
-
targets/rp2040/gpio.go: RP2040/RP2350 GPIO driver- Uses TinyGo's
machine.PinAPI - Direct mapping of GPIO numbers to hardware pins
- Uses TinyGo's
Configures a GPIO pin as a digital output.
Format: config_digital_out oid=%c pin=%u value=%c default_value=%c max_duration=%u
Parameters:
-
oid: Object ID (0-255) for this digital output -
pin: Hardware pin number (platform-specific) -
value: Initial value (0=low, 1=high) -
default_value: Default value for shutdown/emergency stop (0=low, 1=high) -
max_duration: Maximum time (in clock ticks) pin can remain in non-default state (0=unlimited)
Example: Configure GPIO25 (LED on Pico) as output, initially high, default low, no timeout
config_digital_out oid=1 pin=25 value=1 default_value=0 max_duration=0
Schedules a pin state change at a specific time.
Format: queue_digital_out oid=%c clock=%u on_ticks=%u
Parameters:
-
oid: Object ID of the digital output -
clock: System clock time to execute the change -
on_ticks: For simple on/off: 0=off, non-zero=on. For PWM: duration to keep pin high per cycle
Example: Turn on pin at clock time 1000000
queue_digital_out oid=1 clock=1000000 on_ticks=1
Immediately updates a pin value (not scheduled).
Format: update_digital_out oid=%c value=%c
Parameters:
-
oid: Object ID of the digital output -
value: New value (0=low, 1=high)
Example: Immediately turn off the pin
update_digital_out oid=1 value=0
Configures software PWM cycle time.
Format: set_digital_out_pwm_cycle oid=%c cycle_ticks=%u
Parameters:
-
oid: Object ID of the digital output -
cycle_ticks: Total PWM cycle duration in clock ticks (recommended ≥10ms)
Example: Set 10ms PWM cycle (at 12MHz: 120,000 ticks)
set_digital_out_pwm_cycle oid=1 cycle_ticks=120000
After setting a PWM cycle, queue_digital_out interprets on_ticks as the duration to keep the pin high per cycle, enabling PWM control.
All GPIO operations can be precisely scheduled using the system timer:
-
queue_digital_outschedules changes at specific clock times - Sub-millisecond precision (12MHz timer = 83.3ns resolution)
- Non-blocking operation
The implementation supports software PWM for analog-like control:
- Set PWM cycle time with
set_digital_out_pwm_cycle - Use
queue_digital_outto set duty cycle (on_ticks / cycle_ticks) - The timer system automatically toggles the pin at the correct intervals
Example: 50% duty cycle PWM at 100Hz
# Set 10ms cycle (100Hz)
set_digital_out_pwm_cycle oid=1 cycle_ticks=120000
# Set 50% duty cycle (5ms on, 5ms off)
queue_digital_out oid=1 clock=1000000 on_ticks=60000
The max_duration parameter prevents pins from staying in non-default states indefinitely:
- If non-zero, limits how long a pin can differ from its default value
- Automatically returns to default state when time expires
- Provides safety for heaters, fans, and other critical outputs
- Must be explicitly renewed by scheduling new updates
On emergency stop or firmware shutdown:
- All GPIO pins return to their default states
- PWM toggling is stopped
- Timer scheduling is halted
- Called from
handleEmergencyStop()andTryShutdown()
Each configured GPIO output has a DigitalOut instance tracking:
type DigitalOut struct {
OID uint8 // Object ID
Pin GPIOPin // Hardware pin number
Flags uint8 // State flags (DF_*)
Timer Timer // Scheduled event timer
OnDuration uint32 // PWM on time
OffDuration uint32 // PWM off time
CycleTime uint32 // PWM cycle time
EndTime uint32 // Max duration expiry time
MaxDuration uint32 // Max time in non-default state
}-
DF_ON(0x01): Current pin state (1=high, 0=low) -
DF_TOGGLING(0x02): PWM mode active -
DF_CHECK_END(0x04): Monitor max_duration -
DF_DEFAULT_ON(0x08): Default state for shutdown
Three timer handlers manage GPIO operations:
-
digitalOutLoadEvent: Executes scheduled updates- Sets pin to new state
- Starts PWM toggling if configured
- Schedules max_duration enforcement
-
digitalOutToggleEvent: Handles PWM toggling- Alternates pin between high and low
- Calculates next toggle time
- Continues until toggling disabled or max_duration reached
-
digitalOutEndEvent: Enforces max_duration- Returns pin to default state
- Stops PWM toggling
- Clears DF_CHECK_END flag
The RP2040 implementation uses TinyGo's hardware abstraction:
type RPGPIODriver struct {
configuredPins map[core.GPIOPin]machine.Pin
}Pin Mapping: GPIO numbers map directly to RP2040 pins (GPIO0 = Pin 0, GPIO25 = Pin 25, etc.)
Configuration: Pins are configured as outputs using machine.PinOutput
Control: Uses Pin.Set(bool) and Pin.Get() for state manipulation
Complete example of configuring and using a GPIO pin:
# In Klipper config (handled by host)
[output_pin my_led]
pin: gpio25
pwm: True
cycle_time: 0.010
value: 0
shutdown_value: 0This generates the following MCU commands:
# 1. Configure pin
config_digital_out oid=1 pin=25 value=0 default_value=0 max_duration=0
# 2. Set PWM cycle to 10ms (120,000 ticks @ 12MHz)
set_digital_out_pwm_cycle oid=1 cycle_ticks=120000
# 3. Set to 25% brightness (3,000 ticks on, 117,000 ticks off)
queue_digital_out oid=1 clock=1000000 on_ticks=30000
# 4. Later, turn off
update_digital_out oid=1 value=0
Run GPIO tests:
go test -v ./core/gpio_test.go ./core/gpio.go ./core/gpio_hal.go- Flash firmware with GPIO support
- Use Klipper console to send commands
- Observe pin behavior with LED or oscilloscope
Example Klipper console test:
# Connect to MCU
~/klippy-env/bin/python ~/klipper/klippy/console.py -v /dev/ttyACM0
# Send commands (after configuration)
# Blink LED on GPIO25
update_digital_out oid=1 value=1
# Wait...
update_digital_out oid=1 value=0Each GPIO requires timer resources:
- Simple on/off: 1 timer event per scheduled update
- PWM: 2 timer events per cycle (on→off, off→on)
- Max duration: 1 additional timer event
Per configured GPIO:
-
DigitalOutstruct: ~48 bytes - Map entry overhead: ~16 bytes
- Total: ~64 bytes per pin
- Timer resolution: 83.3ns @ 12MHz
- Software overhead: ~5-10µs per toggle
- PWM frequency limits: Practical max ~10kHz, recommended max ~1kHz
Possible improvements:
- Hardware PWM support for higher frequencies
- GPIO input support (digital_in)
- Interrupt-based edge detection
- Pin conflict detection
- GPIO grouping for simultaneous updates