I want to control a single pin of an ESP-WROOM-32 to have a 25 kHz PWM signal. How do I do that in Arduino Studio? I compiled a "hello world" program for such a device successfully in Arduino Studio, now what steps do I need to take? (Other libraries? Source Code?)

FYI: I'd like to do quite the same as provided in Set PWM frequency to 25 kHz but not on an AVM micro-controller but an ESP32. There are tons of explanations for original Arduinos and ESP8266s using bit banging in various forms. But how do I do that on an ESP-WROOM-32 using no bit banging but built in PWM?

Background: I'd like to control a standard 12V PWM fan with this signal. As far as I learned I just can connect a pin with the PWM input of the fan. I just don't seem to be able to figure out how to produce such high frequent PWM signals on an ESP32 :-/ Please help!

  • you said that you compiled a "hello world" program for the device .... you did not say if you were successful in loading the program into the device and running it ..... did you run the "hello world" program successfully on the device?
    – jsotola
    Aug 12, 2018 at 4:19
  • 1
    Sure I did. If that would be a problem, I would have asked a different question.
    – Regis May
    Aug 12, 2018 at 9:13
  • why do you use Arduino Studio? you were really successful in installing esp32 core package into that discontinued IDE?
    – Juraj
    Aug 13, 2018 at 11:48
  • It is discontinued??? Yes, in the meanwhile I downloaded the Espressif Toolchain. ledc seems to originate from there, I guess. My first I've to solve the issues with the circuit before I can attempt anything more with any software. (See below.) I'll get to that next weekend.
    – Regis May
    Aug 14, 2018 at 5:34

2 Answers 2


It is very simple to set up a PWM signal at any frequency you desire, with any resolution you desire, provided you don't exceed the maximum 'bandwidth': the frequency multplied by the resolution must be less than half the clock speed of the device.

The full explanation with relation to the ESP-IDF is available here. The article explains the intricacies of all the channels and their configurations. I must confess I have not read it all, because my application was very basic.

In setup(), the code required to instantiate a PWM signal on channel chan at frequency freq, with a resolution of bit_num bits is:

double ledcSetup(uint8_t chan, double freq, uint8_t bit_num)

The code to attach the channel chan to an output pin pin is:

void ledcAttachPin(uint8_t pin, uint8_t chan)

Within loop(), or otherwise, inflict a duty cycle duty to a given channel chan using:

void ledcWrite(uint8_t chan, uint32_t duty)

I recommend perusing esp32-hal-ledc.c in the core files you installed that enabled you to program the ESP32 in Arduino Studio. You don't need to include any files to get the above functionality, but it's always good to know a bit about what goes on behind the scenes.

A few things to note, if reading through the core code is too much:

  • chan can only be between 0 and 15, and the function will return 0 if you try an number outside these bounds;
  • you can't attach the PWM output to all of the GPIO pins, as some are input only and others might have secondary functions that you need;
  • duty is a 32-bit type but the maximum value is determined by the resolution you used for bit_num. For example, if bit_num is 8 then the range of duty is from 0 to 255. I don't know what happens if you put higher number: the duty may stay at 100%, or the duty may be bitmasked such that writing 256 is the same as 0, 257 is 1, etc.

Once you have mastered this, the ESP32 includes 'fading' functionality, whereby the duty cycle changes from x% to y% in z milliseconds. There are a number of tutorials on the internet for such a thing.


If you haven't already, take a look at Intel's PWM fan specs. It states that you need an open-collector or open-drain source provided, in your case, by the ESP32. There's a chance that the PWM pin is pulled up to 5.25V within the fan; this will hurt the ESP32 if you just wire the two together. Likewise, the Tachometer output is pulled all the way up to 12V. This will kill the ESP32 if you wire it directly to the fan.

  • Thank you very much for the kindness of helping me. Looks good! I found documentation about LEDC but not for the Arduino platform. One question: I've seen many people connecting the output pin directly to the PWM input of the fan. Therefor I've done likewise. In order to be very careful I used a 220 Ohm resistor in between the fan and the ESP32 as I was wondering if that really is the way of doing it. Now I'm reading about this open-drain principle you're talking about. I don't understand that right now. I'm going to read more about it before it makes sense to ask a question.
    – Regis May
    Aug 12, 2018 at 15:15
  • BTW: The link to the fan specs doesn't work.
    – Regis May
    Aug 12, 2018 at 15:23
  • Edited for working link. Aug 12, 2018 at 15:40
  • @RegisMay Have a look at the Wikipedia entry for Open Collector. It's the same as an Open Drain, but for a transistor rather than a MOSFET: transistors have collectors, emitters and bases while FETs have drains, sources and gates. Aug 12, 2018 at 15:42
  • I have. I just don't (yet) understand the concept. I understand the physical principles, but not (yet) how and why these are used as I'm lacking sufficient knowledge about the use cases and what problems will be solved exactly. But I'm working on that.
    – Regis May
    Aug 12, 2018 at 16:03

I know it is an old topic, but at the moment I'm also busy with it.

To be sure the ESP32 doesn't get to much voltage from the pwm input, you have to measure on the PWM input if the signal is not above 3V3, otherwhise you need a resistor divider or work with a transistor in between to pull the signal down. Mine is around 3V3 so I can directly connect the ESP32 to the fan, but just like you I put a serie resistor (330) in between for a bit protection. If this input is around 5.25 V and you connect it to the ESP32, it will probably not directly go broke, but this depends on the input resistance of the fan and how much current the internal protection diode can take in the ESP32.

For the tacho signal, it is very simple, just connect it with a pullup resistor (10K) to the desired voltage you want. In my case I will connect it to 3V3 because the ESP32 is working on 3V3. The fan controller pulls it down if rotating.

I use this schematic as guide, PWM Input: enter image description here

Tacho open collector output:

enter image description here

website: Fan controller

Hope this helps, just as reference.

  • As a matter of fact I still have not completed this project yet. I needed to focus on different things till now, but I will definitively continue on this in near future. Therefore thank you very much for this response!
    – Regis May
    Jul 9, 2021 at 20:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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