Generating PWM outputs of not PWM deticated pins-HOW?

Hello,
I am using arduino nano, for reading a Voltage, attached to A7 pin.

Based on that voltage level, the arduino has to start generating PWM signals (0~255) out from the digitals IOs. I already know, that there are dedicated PWM pins, but they are aleardy assigned for another operations, and I have used D2,D4,D7 though, as pins, supposed to generate PWMs.

Is there a way, to generate specific PWMs, out of D2 for example, controlling its duty cycle and frequency?

Thanks in advance!

Study Servo.h Library's source codes and see the mechanism of PWM signal generation on any valid Digital pin. Currently the library generates 50 Hz signal with varying duty cycle.

GolamMostafa, thank you!

I will have a look. But in respect to frequency, It will be good to be within 490-980Hz or something like that. It will be switching mosfets, and 50Hz is a very slow rate.

To produce PWM on non-hardware PWM pins, you have to use a timer and direct digital writes to the pin. Here is a good timer tutorial:
https://www.gammon.com.au/timers
You will never obtain the accuracy, full possible speed, and output range with an emulation like this, as you would with a PWM hardware supported pin.

What are the "other operations" that the usual PWM pins are dedicated to? It might be easier to just change them.

Is this for a servo? The servo protocol is restricted in frequency and PWM range, so it's more permissive (easier to implement this way) than general purpose PWM.

Hi aarg,
Actually the Nano board is already soldered to a PCB, so there is no chance to change the wiring. All digital IOs from D2 up to D8, are responsible for generating PWMs, but unfortunately, only pin# 3, 5, 6 are capable of doing so, thus I am loosing pin#2,4,7,8 as position on the board, as I do not know how to drive them properly, this is what I am asking for.

Nothing related to servo, it is all about driving mosfets independently, for switching loads.

If possible isolate D9 or D10 by nicely cutting the PCB track with sharp blade and then put soldered jumpers as needed. You will be able to generate PWM signals using TC1.

Okay, you have the answers. Let us know how it turns out!

Of course that will work,
But I wrote here, asking for help, to be able to do it smarter than cutting the tracks.

If there is no way to drive and control the PWM out of a non-PWM dedicated pin, then it seems I have to a
re-design and to use only 3, 5, 6, 9, 10 and 11. Which is a kind of a limitation, since I have to drive 7 mosfets, having only 6 PWM outpus....

Really hope, it still could be done by software.

Perhaps a better design process would have been to determine the capabilities of the device first,
test some of the operation on a breadboard, and design the PCB when all else is proved to work?

Why not post a schematic showing what you have connected to each of the nano's pins?

2 Likes

Unfortunately (or maybe fortunately depending on your point of view) knowledge of a device will only reach the actual limitations of the device.

You could use an STM32F103 or similar, it has 12 PWM outputs.

1 Like

Hi @maxpower1919

Here's how Joop Brokking calculated the pulse outputs, to control 4 brushless dc motors on his multi-rotor/drone flight controller with a 250Hz update rate. Note that his code simply bit bangs the output pins in the loop(), with timing provided by the micros() function:

  //All the information for controlling the motor's is available.
  //The refresh rate is 250Hz. That means the esc's need there pulse every 4ms.
  while(micros() - loop_timer < 4000);                                      //We wait until 4000us are passed.
  loop_timer = micros();                                                    //Set the timer for the next loop.

  PORTD |= B11110000;                                                       //Set digital outputs 4,5,6 and 7 high.
  timer_channel_1 = esc_1 + loop_timer;                                     //Calculate the time of the faling edge of the esc-1 pulse.
  timer_channel_2 = esc_2 + loop_timer;                                     //Calculate the time of the faling edge of the esc-2 pulse.
  timer_channel_3 = esc_3 + loop_timer;                                     //Calculate the time of the faling edge of the esc-3 pulse.
  timer_channel_4 = esc_4 + loop_timer;                                     //Calculate the time of the faling edge of the esc-4 pulse.
  
  while(PORTD >= 16){                                                       //Stay in this loop until output 4,5,6 and 7 are low.
    esc_loop_timer = micros();                                              //Read the current time.
    if(timer_channel_1 <= esc_loop_timer)PORTD &= B11101111;                //Set digital output 4 to low if the time is expired.
    if(timer_channel_2 <= esc_loop_timer)PORTD &= B11011111;                //Set digital output 5 to low if the time is expired.
    if(timer_channel_3 <= esc_loop_timer)PORTD &= B10111111;                //Set digital output 6 to low if the time is expired.
    if(timer_channel_4 <= esc_loop_timer)PORTD &= B01111111;                //Set digital output 7 to low if the time is expired.
  }

Obviously this won't be as precise as hardware PWM outputs, but might be good enough for your 7th pin?

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.