# Proxmark3 LED PWM Implementation - Complete **Status:** ✅ Implemented, Flashed, and Tested **Date:** 2025-12-02 **Hardware:** Proxmark3 Easy **Firmware:** Iceman/master/4fa8f27-dirty ## Summary Successfully implemented two-channel hardware PWM brightness control for LED A and LED B on Proxmark3 Easy, along with basic on/off/toggle control for all LEDs. ## Hardware Configuration ### Proxmark3 Easy LED Mappings | LED | Color | GPIO Pin | PWM Channel | Brightness Control | Position | |-----|--------|----------|-------------|--------------------|----------| | A | Green | PA0 | PWM0 | ✅ 0-100% | 1st (left) | | B | Blue | PA2 | PWM2 | ✅ 0-100% | 4th (right) | | C | Orange | PA9 | None | On/Off only | 2nd | | D | Red | PA8 | None | On/Off only | 3rd | **Physical LED order (left to right):** Green, Orange, Red, Blue ### PWM Channel Allocation - **PWM0** → LED A brightness control (PA0) - **PWM1** → System timing functions (moved from PWM0) - **PWM2** → LED B brightness control (PA2) - **PWM3** → Unused ## Command Interface ### Basic LED Control (All LEDs) ```bash hw led --led a --on # Turn on LED A hw led --led b --off # Turn off LED B hw led --led c,d --toggle # Toggle LEDs C and D hw led --led all --off # Turn off all LEDs ``` ### PWM Brightness Control (LED A and B only) ```bash hw led --led a --brightness 50 # LED A at 50% brightness hw led --led b --brightness 75 # LED B at 75% brightness hw led --led a,b --brightness 25 # Both LEDs at 25% brightness hw led --led a --brightness 0 # LED A off via PWM hw led --led b --brightness 100 # LED B at full brightness ``` ### Multi-Device Identification Examples ```bash # Device 1 - Dim green hw led --led a --brightness 20 # Device 2 - Medium blue hw led --led b --brightness 50 # Device 3 - Bright green hw led --led a --brightness 80 # Device 4 - Mixed (40% green + 60% blue) hw led --led a --brightness 40 hw led --led b --brightness 60 ``` ## Implementation Details ### Files Modified (7 files) **Firmware:** 1. `common_arm/ticks.c` - Moved SpinDelay timing from PWM0 → PWM1 2. `common_arm/usb_cdc.c` - Moved USB timing from PWM0 → PWM1 3. `armsrc/util.c` - Moved button timing PWM0 → PWM1, added PWM LED functions 4. `armsrc/util.h` - Added function declarations 5. `armsrc/appmain.c` - Added CMD_LED_CONTROL handler **Protocol:** 6. `include/pm3_cmd.h` - Added CMD_LED_CONTROL (0x011A) and payload structure **Client:** 7. `client/src/cmdhw.c` - Added `hw led` command with CLIParser ### Protocol Definition ```c // Command ID #define CMD_LED_CONTROL 0x011A // Payload structure typedef struct { uint8_t led; // LED bitmask: LED_A=1, LED_B=2, LED_C=4, LED_D=8 uint8_t action; // 0=off, 1=on, 2=toggle, 3=pwm uint8_t brightness; // 0-100 (for action=3 PWM mode only) } PACKED payload_led_control_t; ``` ### PWM Functions (armsrc/util.c) ```c void led_set_pwm_brightness(uint8_t led, uint8_t brightness); void led_pwm_disable(uint8_t led); ``` **PWM Configuration:** - Frequency: 48 kHz (MCK / 1000) - Resolution: 1000 steps (0.1% precision, exposed as 0-100%) - Duty cycle: Inverted for active-low LEDs - CPU overhead: Zero (hardware-controlled) ### Action Modes | Action | Value | Description | |--------|-------|-------------| | Off | 0 | Turn LED off (disables PWM if active) | | On | 1 | Turn LED on at full brightness (disables PWM) | | Toggle | 2 | Toggle LED state (disables PWM) | | PWM | 3 | Set PWM brightness (0-100%, LED A/B only) | ## Build Configuration ### Required Makefile.platform Settings ```makefile PLATFORM=PM3GENERIC LED_ORDER=PM3EASY ``` **IMPORTANT:** The `LED_ORDER=PM3EASY` flag is **required** for PM3 Easy hardware. Without it, LED B will be mapped to PA8 (no PWM) instead of PA2 (PWM2). ### Build Commands ```bash cd .pm3-test/proxmark3 # Ensure correct platform settings cat > Makefile.platform << EOF PLATFORM=PM3GENERIC LED_ORDER=PM3EASY EOF # Build SKIPQT=1 CFLAGS="-Wno-error=bad-function-cast" make all # Flash ./pm3-flash-all ``` ## Testing Results ✅ **All Tests Passed:** - Firmware compiled: 359,015 bytes (68% of 512KB) - Flashed successfully to Proxmark3 Easy - PWM LED commands working correctly - Timing functions verified (`hw status` passed) - No interference with RF operations - Button functionality intact ## Technical Notes ### PWM Channel Reallocation The original Proxmark3 firmware used PWM0 for timing functions. To enable LED A brightness control, all timing functions were moved from PWM0 to PWM1: - `SpinDelayUsPrecision()` - High precision delays - `SpinDelayUs()` - Standard delays - `BUTTON_CLICKED()` / `BUTTON_HELD()` - Button debouncing - USB timing functions This change has **zero performance impact** and frees PWM0 for LED control. ### Compatibility **Hardware Compatibility:** - ✅ PM3 Easy (PA0=PWM0, PA2=PWM2) - ⚠️ Other PM3 variants - PWM support depends on LED pin mapping - Without `LED_ORDER=PM3EASY`, LED B may not support PWM **Backward Compatibility:** - ✅ Fully backward compatible with existing firmware - ✅ New `hw led` command co-exists with other hw commands - ✅ No changes to existing command behavior ### Performance Impact **Expected impact: ZERO** - PWM channels operate independently in hardware - No CPU overhead once configured - No timer interrupts needed - No interference with RF operations - Timing functions work identically on PWM1 ## Future Enhancements Potential improvements if needed: 1. Software PWM for LED C/D (more complex, CPU overhead) 2. Fade in/out effects using gradual brightness changes 3. Brightness presets (low, medium, high) 4. Auto-dim after inactivity for power saving ## References - [LED_MAPPINGS.md](LED_MAPPINGS.md) - LED color and pin reference - PM3_EASY_PWM_FINAL.md - Original design document (archived) - PWM_ENHANCEMENT_COMPLETE.md - Development notes (archived) --- **Implementation by:** Claude Code **Hardware Tested:** Proxmark3 Easy **Firmware Version:** Iceman/master/4fa8f27-dirty