# Is it possible to drive two PWM pins with opposite phase?

One well-known trick to make a piezo buzzer sound louder is to actively drive both sides of it with an opposite phase: when pin 1 is at 0V, pin 2 is at 3.3V and vice versa. This creates a voltage swing of 3.3*2 = 6.6V, making the buzz loud enough without any amplification.

How could I generate PWM signals of opposite phase using any of GPIO libraries? As a specific example, let's say I want to use GPIO pins 12 and 13 (PWM0/PWM1) at 50% duty cycle and a frequency of 1kHz.

• The pigpio and lg libraries both support this. If you provide a couple of GPIO and a frequency I can give concrete examples.
– joan
Commented Dec 7, 2020 at 9:34
• Why would you WANT to drive a piezo buzzer with PWM? They SHOULD be driven with a symmetrical signal to avoid DC. I have implemented differential drive on an Arduino, but you would get better results on the Pi using 5V - even better if you used a 5V differential drive. Commented Dec 7, 2020 at 10:43
• @Milliways PWM is not a requirement of course, just something which can produce sound without keeping the software busy switching the pins. And I don't think DC is a problem: piezo buzzers are essentially ceramic capacitors optimized for noise level. Commented Dec 7, 2020 at 13:29
• Would a hardware solution interest you? Commented Dec 8, 2020 at 6:54
• @Seamus No, thanks, I know I can use a hardware inverter to get the signal of an opposite phase. Commented Dec 8, 2020 at 8:09

What sort of frequencies are you talking about?

pigpio can do this with waves (hardware timing).

My new lg library can do this using software timed PWM.

E.g. Python http://abyz.me.uk/lg/py_lgpio.html#tx_pwm

pigpio example using pigs (command line)

``````G1=12
G2=13
OFFSET=500
B1=\$((1<<\$G1))
B2=\$((1<<\$G2))
pigs m \$G1 w
pigs m \$G2 w
pigs wvag \$B1 \$B2 \$OFFSET \$B2 \$B1 \$OFFSET
pigs wvcre
pigs wvtxr 0
``````

lgpio C example (local GPIO)

``````#include <stdio.h>
#include <stdlib.h>

#include <lgpio.h>

/*
gcc -o lt1 lt1.c -llgpio
./lt1
*/

#define G1 12
#define G2 13

#define FREQ 1000
#define DUTY 50

#define ON_MICS (int)(1e6 / FREQ * DUTY / 100.0)

#define LFLAGS 0

int main(int argc, char *argv[])
{
int h;

h = lgGpiochipOpen(0);

if (h < 0)
{
printf("gpiochip open failed\n");
exit(-1);
}

if (lgGpioClaimOutput(h, LFLAGS, G1, 0) != LG_OKAY)
{
printf("gpio claim output failed\n");
exit(-1);
}

if (lgGpioClaimOutput(h, LFLAGS, G2, 0) != LG_OKAY)
{
printf("gpio claim output failed\n");
exit(-1);
}

lgTxPwm(h, G1, FREQ, DUTY, 0, 0);
lgTxPwm(h, G2, FREQ, DUTY, ON_MICS, 0);

lguSleep(30);

lgGpiochipClose(h);
}
``````

rgpio C example (local and remote GPIO)

``````#include <stdio.h>
#include <stdlib.h>

#include <lgpio.h>
#include <rgpio.h>

/*
gcc -o rt1 rt1.c -lrgpio
./rt1
*/

#define G1 12
#define G2 13

#define FREQ 1000
#define DUTY 50

#define ON_MICS (int)(1e6 / FREQ * DUTY / 100.0)

#define LFLAGS 0

int main(int argc, char *argv[])
{
int sbc;
int h;

sbc = rgpiod_start(NULL, NULL);

if (sbc < 0)
{
printf("connection failed\n");
exit(-1);
}

h = gpiochip_open(sbc, 0);

if (h < 0)
{
printf("gpiochip open failed\n");
exit(-1);
}

if (gpio_claim_output(sbc, h, LFLAGS, G1, 0) != LG_OKAY)
{
printf("gpio claim output failed\n");
exit(-1);
}

if (gpio_claim_output(sbc, h, LFLAGS, G2, 0) != LG_OKAY)
{
printf("gpio claim output failed\n");
exit(-1);
}

tx_pwm(sbc, h, G1, FREQ, DUTY, 0, 0);
tx_pwm(sbc, h, G2, FREQ, DUTY, ON_MICS, 0);

lgu_sleep(30);

gpiochip_close(sbc, h);

rgpiod_stop(sbc);
}
``````

lgpio Python module (local GPIO)

``````import time
import lgpio as sbc

G1=12
G2=13

FREQ=1000
DUTY=50

ON_MICS = int(1e6 / FREQ * DUTY / 100.0)

h = sbc.gpiochip_open(0) # Pi's main gpiochip

sbc.gpio_claim_output(h, G1) # claim G1 of gpiochip
sbc.gpio_claim_output(h, G2) # claim G2 of gpiochip

sbc.tx_pwm(h, G1, FREQ, DUTY)
sbc.tx_pwm(h, G2, FREQ, DUTY, pulse_offset=ON_MICS)

time.sleep(30)
``````

rgpio Python module (local and remote GPIO)

``````import time
import rgpio

G1=12
G2=13

FREQ=1000
DUTY=50

ON_MICS = int(1e6 / FREQ * DUTY / 100.0)

sbc = rgpio.sbc()
if not sbc.connected:
exit()

h = sbc.gpiochip_open(0) # Pi's main gpiochip

sbc.gpio_claim_output(h, G1) # claim G1 of gpiochip
sbc.gpio_claim_output(h, G2) # claim G2 of gpiochip

sbc.tx_pwm(h, G1, FREQ, DUTY)
sbc.tx_pwm(h, G2, FREQ, DUTY, pulse_offset=ON_MICS)

time.sleep(30)
``````

Simplest method just sets one GPIO to active low.

``````import time
import lgpio as sbc

G1=12
G2=13

FREQ=1000
DUTY=50

h = sbc.gpiochip_open(0) # Pi's main gpiochip

sbc.gpio_claim_output(h, G1) # claim G1 of gpiochip
sbc.gpio_claim_output(h, G2, lFlags=sbc.SET_ACTIVE_LOW) # claim G2 of gpiochip

sbc.tx_pwm(h, G1, FREQ, DUTY)
sbc.tx_pwm(h, G2, FREQ, DUTY)

time.sleep(30)
``````