1

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.

5
  • 1
    The pigpio and lg libraries both support this. If you provide a couple of GPIO and a frequency I can give concrete examples. – joan Dec 7 '20 at 9:34
  • 2
    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. – Milliways Dec 7 '20 at 10:43
  • 1
    @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. – Dmitry Grigoryev Dec 7 '20 at 13:29
  • 1
    Would a hardware solution interest you? – Seamus Dec 8 '20 at 6:54
  • 1
    @Seamus No, thanks, I know I can use a hardware inverter to get the signal of an opposite phase. – Dmitry Grigoryev Dec 8 '20 at 8:09
2

What sort of frequencies are you talking about?

pigpio can do this with waves (hardware timing).

E.g. http://abyz.me.uk/rpi/pigpio/examples.html#Python_wavePWM_py

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)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.