Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 28 additions & 8 deletions cores/gecko/pwm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,13 @@ PwmClass::PwmClass() :
.polarity = PWM_ACTIVE_HIGH,
};

for (auto& pwm_pin : pwm_pins) {
pwm_pin.pin = PIN_NAME_MAX;
pwm_pin.inst.timer = TIMER0;
pwm_pin.inst.channel = 0;
pwm_pin.inst.port = gpioPortA;
pwm_pin.inst.pin = 0;
pwm_pin.inst.location = 0;
for (uint8_t i = 0; i < max_pwm_channels; i++) {
pwm_pins[i].pin = PIN_NAME_MAX;
pwm_pins[i].inst.timer = get_timer_for_channel(i);
pwm_pins[i].inst.channel = get_cc_channel_for_pwm_channel(i);
pwm_pins[i].inst.port = gpioPortA;
pwm_pins[i].inst.pin = 0;
pwm_pins[i].inst.location = 0;
}

this->pwm_mutex = xSemaphoreCreateMutexStatic(&this->pwm_mutex_buf);
Expand All @@ -71,7 +71,7 @@ bool PwmClass::init(PinName pin, int frequency)
this->pwm_pins[pwm_channel_idx].duty_cycle_percent = 101;
this->pwm_pins[pwm_channel_idx].inst.port = getSilabsPortFromArduinoPin(pin);
this->pwm_pins[pwm_channel_idx].inst.pin = getSilabsPinFromArduinoPin(pin);
this->pwm_pins[pwm_channel_idx].inst.channel = pwm_channel_idx;
this->pwm_pins[pwm_channel_idx].inst.channel = get_cc_channel_for_pwm_channel(pwm_channel_idx);

GPIO_PinModeSet(this->pwm_pins[pwm_channel_idx].inst.port, this->pwm_pins[pwm_channel_idx].inst.pin, gpioModePushPull, 0);
pwm_config.frequency = frequency;
Expand Down Expand Up @@ -240,4 +240,24 @@ void PwmClass::deinit_all_pwm_channels()
}
}

TIMER_TypeDef* PwmClass::get_timer_for_channel(uint8_t channel_idx)
{
// Channels 0-2 use TIMER0, channels 3-4 use TIMER1
if (channel_idx <= 2) {
return TIMER0;
} else {
return TIMER1;
}
}

uint8_t PwmClass::get_cc_channel_for_pwm_channel(uint8_t channel_idx)
{
// Map PWM channel to timer's CC channel
if (channel_idx <= 2) {
return channel_idx; // 0->CC0, 1->CC1, 2->CC2
} else {
return channel_idx - 3; // 3->CC0, 4->CC1
}
}

arduino::PwmClass PWM;
20 changes: 19 additions & 1 deletion cores/gecko/pwm.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ class PwmClass {
SemaphoreHandle_t pwm_mutex;
StaticSemaphore_t pwm_mutex_buf;

static const uint8_t max_pwm_channels = 3u;
static const uint8_t max_pwm_channels = 5u;
static const uint32_t pwm_stabilization_time_ms = 2u;

uint32_t duty_cycle_set_time;
Expand Down Expand Up @@ -165,6 +165,24 @@ class PwmClass {
*****************************************************************************/
uint8_t get_num_of_pwm_channels_in_use();

/**************************************************************************//**
* Returns the timer peripheral for the given PWM channel index
*
* @param[in] channel_idx PWM channel index (0-4)
*
* @return Pointer to timer peripheral (TIMER0 or TIMER1)
*****************************************************************************/
TIMER_TypeDef* get_timer_for_channel(uint8_t channel_idx);

/**************************************************************************//**
* Returns the compare/capture channel number for the given PWM channel index
*
* @param[in] channel_idx PWM channel index (0-4)
*
* @return CC channel number (0, 1, or 2)
*****************************************************************************/
uint8_t get_cc_channel_for_pwm_channel(uint8_t channel_idx);

/**************************************************************************//**
* Deinitializes all active PWM channels
*****************************************************************************/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
Multi-Channel PWM

This sketch demonstrates the use of up to 5 simultaneous PWM channels on Silicon Labs boards.
Each channel can have an independent duty cycle (0-100%), all running at the same frequency (1kHz default).

The sketch outputs PWM signals with different duty cycles on pins D3-D7:
- D3: 20% duty cycle
- D4: 40% duty cycle
- D5: 60% duty cycle
- D6: 80% duty cycle
- D7: 100% duty cycle (always HIGH)

You can connect LEDs (with appropriate current-limiting resistors) to these pins to see
different brightness levels, or measure the PWM signals with an oscilloscope.

Hardware Implementation:
- Channels 0-2 use TIMER0 (CC0, CC1, CC2)
- Channels 3-4 use TIMER1 (CC0, CC1)
- All channels share the same frequency (GSDK constraint)
- Each channel has independent duty cycle control

Compatible with all Silicon Labs Arduino boards.

Author: Greg Matthew Crossley (github.com/gregmatthewcrossley)
*/

// Define PWM output pins
#define PWM_PIN_1 D3
#define PWM_PIN_2 D4
#define PWM_PIN_3 D5
#define PWM_PIN_4 D6
#define PWM_PIN_5 D7

// Define duty cycles (0-255, where 255 = 100%)
#define DUTY_20_PERCENT 51 // 20% of 255
#define DUTY_40_PERCENT 102 // 40% of 255
#define DUTY_60_PERCENT 153 // 60% of 255
#define DUTY_80_PERCENT 204 // 80% of 255
#define DUTY_100_PERCENT 255 // 100% of 255

void setup()
{
Serial.begin(115200);
delay(2000); // Wait for Serial connection

Serial.println("Multi-Channel PWM Demo");
Serial.println();
Serial.println("This demo shows 5 simultaneous PWM channels");
Serial.println("with different duty cycles on pins D3-D7.");
Serial.println();

// Configure pins as outputs
pinMode(PWM_PIN_1, OUTPUT);
pinMode(PWM_PIN_2, OUTPUT);
pinMode(PWM_PIN_3, OUTPUT);
pinMode(PWM_PIN_4, OUTPUT);
pinMode(PWM_PIN_5, OUTPUT);

// Start PWM on all 5 channels with different duty cycles
Serial.println("Starting PWM channels...");

analogWrite(PWM_PIN_1, DUTY_20_PERCENT);
Serial.println(" D3: 20% duty cycle");

analogWrite(PWM_PIN_2, DUTY_40_PERCENT);
Serial.println(" D4: 40% duty cycle");

analogWrite(PWM_PIN_3, DUTY_60_PERCENT);
Serial.println(" D5: 60% duty cycle");

analogWrite(PWM_PIN_4, DUTY_80_PERCENT);
Serial.println(" D6: 80% duty cycle");

analogWrite(PWM_PIN_5, DUTY_100_PERCENT);
Serial.println(" D7: 100% duty cycle (always HIGH)");

Serial.println();
Serial.println("All PWM channels active at 1kHz frequency!");
Serial.println("Connect LEDs or an oscilloscope to see the outputs.");
}

void loop()
{
// PWM continues running automatically
// You can add code here to dynamically change duty cycles if desired

delay(1000);
}
1 change: 1 addition & 0 deletions test/build/test_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@
"../../libraries/SiliconLabs/examples/ble_xg27_devkit_sensors/ble_xg27_devkit_sensors.ino": xg27devkit_ble_silabs,
"../../libraries/SiliconLabs/examples/dac_sawtooth/dac_sawtooth.ino": boards_with_dac,
"../../libraries/SiliconLabs/examples/hwinfo/hwinfo.ino": all_variants,
"../../libraries/SiliconLabs/examples/pwm_multi_channel/pwm_multi_channel.ino": all_variants,
"../../libraries/SiliconLabs/examples/xg27devkit_sensors/xg27devkit_sensors.ino": xg27devkit_ble_silabs,
"../../libraries/SiliconLabs/examples/thingplusmatter_debug_unix/thingplusmatter_debug_unix.ino": all_ble_silabs,
"../../libraries/SiliconLabs/examples/thingplusmatter_debug_win/thingplusmatter_debug_win.ino": all_ble_silabs,
Expand Down
6 changes: 5 additions & 1 deletion test/build/test_sketch/test_sketch.ino
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,11 @@ void setup()
val = analogRead(PA1);
Serial.println(val, OCT);

analogWrite(PA0, 128);
analogWrite(PA0, 51);
analogWrite(PA1, 102);
analogWrite(PA2, 153);
analogWrite(PA3, 204);
analogWrite(PA4, 255);

tone(PA0, 440, 0);
noTone(PA0);
Expand Down