ESP32 passive peizo buzzer

I want to drive a passive peizo buzzer from an ESP32. I have found schematics on how to drive one of these from a 5v Arduino board, but not for the ESP32 that runs at 3.3v. I don't want to burn out my ESP32 so I'm looking for a schematic on how to connect it.

Can I connect it directly? Do I need a resistor and/or transistor?

It should be safe but if you're paranoid put a ~200 Ohm resistor in series.

Okay, I hooked it up then used a minimal program to generate a tone:

const int duration = 500;
const int middle_c = 440;


void setup() {
 
}
 
void loop()
{
  tone(13, middle_c, duration);
  delay(duration);
}

This code does not compile when the board is set to Heltec_WIFI_Kit_32 (ESP-32) but does when set to Arduino/Genuino UNO. I can understand that setting the board has several implicit included header files, but why doesn't the ESP-32 have support for audio output? How do I include it?

The tone function uses PWM to generate the signal. PWM is generated by hardware timers in the processor. The arrangement, hardware address and function of these timers are very different in the two processors, that is why tone will not work on your processor.

Fortunately the software tells you this before you even try to use it, in the form of a compiler error.

How do I include it?

You add extra code to the tone library, a task I think that is beyond you with your current state of knowlage. Without looking in detail at the processor you have, I am not even sure if this is possible.

You add extra code to the tone library, a task I think that is beyond you with your current state of knowlage. Without looking in detail at the processor you have, I am not even sure if this is possible.

There is no way to know a person's level of knowledge on these forums, so I don't have any problem with you stating this with what you currently know about me. I'm in no way being sarcastic or snarky. There is so much of communication that occurs non-verbally when people talk in person, so that is why I stated this. I am speaking (writing) in good faith, and assume that you are doing so as well.

Let me give you some more information about myself. I am a professional programmer who has been programming for a few decades. I have programmed from assembly language to 4-GL. I'm currently programming in Java. I know software, but I have only dabbled in hardware. I am new to Arduino. The questions I ask are to find out the proper way to do things, and to not damage the hardware that I do have.

If it is possible to do this with the ESP-32, via PWM (pulse width modulation) or otherwise, I will just need to be pointed to the proper documentation and I can probably do it. I may have to ask some further questions, but maybe not. I have been searching for this information myself, but I haven't yet found the type of documentation that I need to generate tones on the ESP-32.

Using just the delay() function I have got my ESP-32 to emit tones using the piezo buzzer. This relies on the granularity of the delay() function, which is 1 ms. If there is a finer resolution timer then I could generate more frequencies. PWM would be better, but I've at least got a tone out of it. This was my goal for now, though I'll want to do better later.

const int buzzer = 13;  // Buzzer pin


void setup() {
  pinMode(buzzer, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);   // turn the LED on (HIGH is the voltage level)

  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);   // turn the LED on (HIGH is the voltage level)
}
 
void loop()
{
  for(int i = 250; i > 0 ; --i)
  {
    digitalWrite(buzzer, HIGH);
    digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
    delay(1);
    digitalWrite(buzzer, LOW);
    digitalWrite(LED_BUILTIN, LOW);
    delay(1);
  }

  delay(500);
}

And looking at the pin-out diagram of the ESP-32, I don't see any pins for PWM. I see the pins labelled for PWM on the Arduino UNO. It appears I have to live with the simple tones I'm generating now, unless I want to add an audio shield.

Well the cue I picked up on was:-

I have found schematics on how to drive one of these

Now you don’t “find” a schematic if you know anything about hardware. Hence my assumption you were a beginner, sorry.

Without knowing the details of the exact buzzer you use it is hard to tell if you need a transistor to drive it or if you can just connect it to a pin. The important parameter is the capacitance of the buzzer. Then you can work out the current it will draw at the highest frequency you want to use.

The way to do it in software would be to have an interrupt being triggered at a fast rate say in the region of 40KHz and use the ISR to count and toggle a pin every N interrupts. By changing the value of N you can change the frequency and make it work like a tone function.

This requires to look at the data sheet for the processor and investigate any hardware timers in it. In the absence of an internal timer you can use an external NE555 timer chip to feed pulses to an interrupt pin and so achieve a tone function that can work in an asynchronous manner so as not to be blocking code.

As there is not libiary implementing a PWM function if you write your ISR as a libiary function you would be doing a great service to the community.

Now you don't "find" a schematic if you know anything about hardware. Hence my assumption you were a beginner, sorry.

No problem. In these forums, we really don't know each other or each other's abilities. I dabble in hardware, but I've been dabbling since high school electronics class. Since I don't regularly do hardware I'll say that I know enough to be dangerous, so I compensate and become cautious; I ask questions when I'm not pretty sure.

DVDdoug suggested above:

It should be safe but if you're paranoid put a ~200 Ohm resistor in series.

It is working now, but I don't know about the long term issues with this. I know that over-driving an LED works for a while, but it will burn out faster that way. Adding a 220Ω resistor about halves the volume. I'll try a lower value from my parts box, because I have been dabbling for a while.

I have also been searching, in the meantime, and discovered delayMicroseconds() from a tutorial on options to do sound. It gives me finer control of the frequency. Thanks for the idea of making a library to use ISRs to toggle pins. I'll look into that. I may have to go back to assembly to be able to do that, and I'll look into how to do that too.

And why the moniker of Grumpy_Mike? I don't find you grumpy. So far you've been helpful to me.

Okay, I used Ohm's Law to calculate the needed resistance.

The maximum drive current from any GPIO pin on the ESP-32 is 12 ma.

R = V/I, but I'll spell them out; Resistance = Voltage/Current = 3.3 v/12 ma = 275Ω

I can't find a part number on the piezo buzzer, but I've seen places that use 8Ω. 220Ω resistor with the piezo is a little low. That value makes the buzzer much quieter.

I don't want to burn out a pin so I'll go with a transistor. This discussion has a schematic that I'll adapt to 3.3v; I can look up the datasheet on the NPN transistors that I have. BTW, this site gives 47Ω for the piezo. I'll find the part number from where I ordered and find the actual value.

What is this about the capacitance of the buzzer? Do you mean resistance?

What is this about the capacitance of the buzzer? Do you mean resistance?

No.
While the resistance of a piezo is very high, it has capacitance. When you feed AC through a capacitor you get a current which depends on the frequency and the capacitance value. It is a lot more complex than this as you can see here because it also alters the phase of the signal and is a property of both capacitors and inductors.

This means that the capacitor has what you can think of as a frequency dependant resistance which is known as a reactance this can be calculated as:-
1/( 2* Pi * F * C )

Where F is the frequency in Hz and C is the capacitance value in Farads.
This can be used to calculate the current draw from the pin.

It is a bit more complex than that because a discharged capacitor looks like a short circuit for a tiny instance but for the small capacitance of this device other things like the output impedance of the output pin come into play so don’t worry about that.

If you are using a transistor to drive it then I wouldn’t bother with a seriese resistor at all, apart from the one in the base.

Val42:
I can't find a part number on the piezo buzzer, but I've seen places that use 8Ω. 220Ω resistor with the piezo is a little low. That value makes the buzzer much quieter.

You may be confusing a speaker with a piezo buzzer?

While searching for a better solution for my original problem, I came across ESP32 Arduino: Controlling a buzzer with PWM. In summary, even though the ESP-32 libraries don't have a tone(), they do have other functions that will let you do the equivalent.

#define BUZZER_PIN          13

#ifdef    ARDUINO_ARCH_ESP32

#define SOUND_PWM_CHANNEL   0
#define SOUND_RESOLUTION    8 // 8 bit resolution
#define SOUND_ON            (1<<(SOUND_RESOLUTION-1)) // 50% duty cycle
#define SOUND_OFF           0                         // 0% duty cycle

void tone(int pin, int frequency, int duration)
{
  ledcSetup(SOUND_PWM_CHANNEL, frequency, SOUND_RESOLUTION);  // Set up PWM channel
  ledcAttachPin(pin, SOUND_PWM_CHANNEL);                      // Attach channel to pin
  ledcWrite(SOUND_PWM_CHANNEL, SOUND_ON);
  delay(duration);
  ledcWrite(SOUND_PWM_CHANNEL, SOUND_OFF);
}

#endif

This code is in an example program that I wrote. I found what is defined when the IDE compiles for ESP-32. "Show verbose output during: [ ] compilation" will show you too. This allows me to use the same code for ESP-32 or Arduino UNO.

Since the PWM channel can be 0-15, I tried running three piezo buzzers at the same time at different frequencies. I got only one frequency out though. I'm thinking that the PWM can only run at one frequency at a time, but I'm still looking into this.

int buzzer_pin[] = {13, 12, 14};

void tones(int freq1, int freq2, int freq3, int duration)
{
  // Set up pins
  ledcSetup(SOUND_PWM_CHANNEL+0, freq1, SOUND_RESOLUTION);  // Set up PWM channel
  ledcAttachPin(buzzer_pin[0], SOUND_PWM_CHANNEL+0);        // Attach channel to pin

  ledcSetup(SOUND_PWM_CHANNEL+1, freq2, SOUND_RESOLUTION);  // Set up PWM channel
  ledcAttachPin(buzzer_pin[1], SOUND_PWM_CHANNEL+1);        // Attach channel to pin

  ledcSetup(SOUND_PWM_CHANNEL+2, freq3, SOUND_RESOLUTION);  // Set up PWM channel
  ledcAttachPin(buzzer_pin[2], SOUND_PWM_CHANNEL+2);        // Attach channel to pin

  // Sound buzzers
  ledcWrite(SOUND_PWM_CHANNEL+0, SOUND_ON);
  ledcWrite(SOUND_PWM_CHANNEL+1, SOUND_ON);
  ledcWrite(SOUND_PWM_CHANNEL+2, SOUND_ON);

  delay(duration);

  ledcWrite(SOUND_PWM_CHANNEL+0, SOUND_OFF);
  ledcWrite(SOUND_PWM_CHANNEL+1, SOUND_OFF);
  ledcWrite(SOUND_PWM_CHANNEL+2, SOUND_OFF);
}

I could have made a mistake in this code (for multiple tones), but I don't see it.

Please do not drive the buzzer directly from the esp 32. Use a MOSFET circuit that control the whole system. You can use a n channel mosftet with VGS threshold Voltage less than 3.3 v .

and if you are using a mosfet to drive the buzzer you will need to add a resistor in parallel to the buzzer.
(just add something like 68 ohm between +ive and -ive of buzzer.).
Connect the +ive of buzzer to vcc and -ive of buzzer to Drain of the mosfet.
Then connect one terminal of 68 ohm resistor to vcc and other terminal of 68 ohm to drain of the mosfet.

then connect to gate of the mosfet to your esp32 .
then connect source to the gnd and put a 10k ohm resistor between gate and source of mosfet.

This will 100% work

Val42:
And why the moniker of Grumpy_Mike? I don't find you grumpy. So far you've been helpful to me.

Because of people like me

manveen_singh:
You can use a n channel mosftet with VGS threshold Voltage less than 3.3 v .

No you can't. I have told you in a thread before that the gate threshold is the point where the FET is OFF, not the point where it is fully on. You need to use a transistor for input signals this low unless your FET has an Ron rating in the data sheet at 3V3 or below.

Their is little point in telling you this, because you are resistant to actually learning. That is fine, be as ignorant as you want, but don't go spreading your crap to other people on this forum.

Grumpy_Mike:
you are resistant to actually learning.

No, i am not. that is why I question everything others suggest.

Grumpy_Mike:
your crap to other people on this forum.

How i can i know i am spreading crap ? What if the suggestion i have said has actually worked for me ? And even If i am wrong ,someone more with knowledge than me about the matter can correct me . this way OP and i can learn something there. Thus i can learn from my mistakes and give the correct advice and help the next time.

Grumpy_Mike:
I have told you in a thread before that the gate threshold is the point where the FET is OFF

Yes you have told me this. I do agree with your point . But i did ask you a follow up question in that thread to understand my error even more .(Maybe you did not have time to see that question and could not answer it.) (or maybe you were feed up of me and did not care to post to that thread.) .

If you want ,i can leave a link here so you can see what i have asked there.

Grumpy_Mike:
I have told you in a thread before that the gate threshold is the point where the FET is OFF, not the point where it is fully on.

I have asked this question in my post also.

If we give Vgs below threshold it will turn off,
If we give Vgs above threshold it will turn on (partially) .
Am i correct in assuming the above statements?

Grumpy_Mike:
I have told you in a thread before

That is why i have not suggested any particular mosfet for that. if you had not told me about that in my last post. i would have also suggested my own mosfet.

The reason i have suggested an n channel mosfet is because many electronic books also suggest this.

And even If i am wrong ,someone more with knowledge than me about the matter can correct me

I thought that was what I was doing, or do I not count.

(or maybe you were feed up of me and did not care to post to that thread.)

Yes I indicated that, given your attitude I would not even read the thread.

If we give Vgs below threshold it will turn off,
If we give Vgs above threshold it will turn on (partially) .
Am i correct in assuming the above statements?

Yes but more accurately:-
If we give Vgs above threshold it will start to just turn on.
There is no saying by how much it will turn on as FET parameters in this region are not guaranteed by the manufacturers. The curves are "typical" and no real device is typical, all are above or below it. You have to go on the parameters they give. For that FET I recall that only at 4.5V can they guaranteed the turn on resistance is 6 ohms, which is quite high for a FET.

So while operating this FET for you with the devices you have might be fine. If you want the design to be solid and work for everyone who uses that circuit, or even that FET and that drive voltage you have to use a better FET.

Grumpy_Mike:
I thought that was what I was doing, or do I not count.

Obviously you do count.
Right now you are doing your part in my learning process :

manveen_singh:
someone more with knowledge than me about the matter can correct me .

and i am doing this part :

manveen_singh:
that is why I question everything others suggest.

So i can finally do this :

manveen_singh:
Thus i can learn from my mistakes and give the correct advice and help the next time.

Grumpy_Mike:
Yes I indicated that, given your attitude I would not even read the thread.

If you think that is the problem, As i have stated earlier , i will be even more careful next time.

NOW COMING BACK,

according to that datasheet:

In electrical char.

Vgs threshold = 1.3 v
and Id (on) =200 mA

What will happen happen if i give Vgs =3.3v , i know mosfet will turn on partially. so how will this affect my system ? how does the partially turned on mosfet affect my driven system ?

The new Id (on) will less right ?

lets say my new Id (on) becomes 100mA . but my whole system requires only 50 mA then how will my system be affected ?

And how does Rds on come into play ?

Grumpy_Mike:
The curves are "typical" and no real device is typical, all are above or below it.

Then why do manufacturers bother to put all typical curves in the datasheet if typical curves cant be used or trusted?

i know mosfet will turn on partially. so how will this affect my system ? how does the partially turned on mosfet affect my driven system ?

When a FET is not fully on it is in what is called the linear mode. In this mode it acts as a variable resistor. That means that the current through it is going to be limited by the value of resistor the FET is presenting to the rest of the circuit. It also means that any current passing through the FET will cause heating of the FET to the value of

Watts = Current2 * R

So the heating increases rapidly with the square of the current.

and Id (on) =200 mA

That is the absolute maximum you can drive through the FET without damaging it. However that value for a FET is often misleading. Because before you reach that value any heating will have fried the component before that current is reached.
The maximum power dissipation is shown as 0.36W, but that is only if you can keep the ambient temperature below 25oC, anything above that and you have to de-rate that value ( that means reduce it ) to the tune of 2.8mW per degree C. The note on this parameter also says:-

RθJA is the sum of the junction-to-case and case-to-ambient thermal resistance where the case thermal reference is defined as the solder mounting surface of
the drain pins. RθJC is guaranteed by design while RθCA is determined by the user's board design.

For every 10 degrees you can reduce the junction temperature of any semiconductor device, the expected life time of that device doubles. So it is important that a component runs as cool as possible.

And how does Rds on come into play ?

This is the resistance between the drain and source that we are talking about. The data sheet says this is going to be 6R if you can put a 4.5V signal on the gate and you have 220mA through the FET. This reduces to 3.5R if you can increase the signal to 10V.

Then why do manufacturers bother to put all typical curves in the datasheet if typical curves cant be used or trusted?

Good point. When you design a circuit for mass production you usually assume the worse case parameter. But it is useful to know how a parameter can change at values other than the guaranteed ones, and also to look at different conditions for that parameter. If you look at Figure 4, this shows how the Rds changes with gate voltage for a different drain current than the one quoted in the specifications. You will see that for a smaller current ( 100mA as opposed to 220mA ) the Rds is smaller. As a designer you have to look at that curve and treat it as the typical case. Then look back at the guaranteed conditions and apply the worst case for that design. This is where design skills come in, it is not a simple process and depends on the whole design.

You need to look at all the graphs to see how the component behaves. For example figure 1 shows you the behavior of the FET in the linear region. You will see how at 3V it is linear and at 3.5V it is starting to become saturated. As there is no curve for 3.3V you would have to interpolate between the two curves give.

Thank you Val42 !! Your simple tone() function resolves it before they fix it. Very simple and straight to the point! Fantastic! :slight_smile:

Val42:
While searching for a better solution for my original problem, I came across ESP32 Arduino: Controlling a buzzer with PWM. In summary, even though the ESP-32 libraries don't have a tone(), they do have other functions that will let you do the equivalent.

#define BUZZER_PIN          13

#ifdef    ARDUINO_ARCH_ESP32

#define SOUND_PWM_CHANNEL   0
#define SOUND_RESOLUTION    8 // 8 bit resolution
#define SOUND_ON            (1<<(SOUND_RESOLUTION-1)) // 50% duty cycle
#define SOUND_OFF           0                         // 0% duty cycle

void tone(int pin, int frequency, int duration)
{
 ledcSetup(SOUND_PWM_CHANNEL, frequency, SOUND_RESOLUTION);  // Set up PWM channel
 ledcAttachPin(pin, SOUND_PWM_CHANNEL);                      // Attach channel to pin
 ledcWrite(SOUND_PWM_CHANNEL, SOUND_ON);
 delay(duration);
 ledcWrite(SOUND_PWM_CHANNEL, SOUND_OFF);
}

#endif




This code is in an example program that I wrote. I found what is defined when the IDE compiles for ESP-32. "Show verbose output during: [ ] compilation" will show you too. This allows me to use the same code for ESP-32 or Arduino UNO.

Since the PWM channel can be 0-15, I tried running three piezo buzzers at the same time at different frequencies. I got only one frequency out though. I'm thinking that the PWM can only run at one frequency at a time, but I'm still looking into this.



int buzzer_pin[] = {13, 12, 14};

void tones(int freq1, int freq2, int freq3, int duration)
{
 // Set up pins
 ledcSetup(SOUND_PWM_CHANNEL+0, freq1, SOUND_RESOLUTION);  // Set up PWM channel
 ledcAttachPin(buzzer_pin[0], SOUND_PWM_CHANNEL+0);        // Attach channel to pin

ledcSetup(SOUND_PWM_CHANNEL+1, freq2, SOUND_RESOLUTION);  // Set up PWM channel
 ledcAttachPin(buzzer_pin[1], SOUND_PWM_CHANNEL+1);        // Attach channel to pin

ledcSetup(SOUND_PWM_CHANNEL+2, freq3, SOUND_RESOLUTION);  // Set up PWM channel
 ledcAttachPin(buzzer_pin[2], SOUND_PWM_CHANNEL+2);        // Attach channel to pin

// Sound buzzers
 ledcWrite(SOUND_PWM_CHANNEL+0, SOUND_ON);
 ledcWrite(SOUND_PWM_CHANNEL+1, SOUND_ON);
 ledcWrite(SOUND_PWM_CHANNEL+2, SOUND_ON);

delay(duration);

ledcWrite(SOUND_PWM_CHANNEL+0, SOUND_OFF);
 ledcWrite(SOUND_PWM_CHANNEL+1, SOUND_OFF);
 ledcWrite(SOUND_PWM_CHANNEL+2, SOUND_OFF);
}




I could have made a mistake in this code (for multiple tones), but I don't see it.