Files
pi-pm3/LED_PWM_IMPLEMENTATION.md
michael 4f35df1781 Initial commit - Phase 3/4
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-06 13:46:22 -08:00

6.1 KiB

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)

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)

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

# 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

// 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)

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

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

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 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