PWM generation on Arduino Uno having Atmega328 P

void setup() {
// Configure Timer0 for 100 kHz PWM on Pin 5
pinMode(6, OUTPUT);

// Stop Timer0
TCCR0A = 0;
TCCR0B = 0;

// Set Timer0 to Fast PWM mode with no prescaler
TCCR0A = (1 << COM0A1) | (1 << WGM00) | (1 << WGM01); // Fast PWM mode
TCCR0B = (1 << CS00); // No prescaler

// Set the PWM frequency to 100 kHz
// Formula: PWM Frequency = 16,000,000 / (1 * (256 - OCR0A))
// Rearranging: OCR0A = 256 - (16,000,000 / (1 * 100,000))
OCR0A = 255 - (16,000,000 / 100,000); // Set for 100 kHz

// Set duty cycle to 50%
OCR0A = OCR0A / 2; // 50% of the calculated value

// Configure Timer2 for 2 kHz PWM on Pin 11
pinMode(11, OUTPUT);

// Stop Timer2
TCCR2A = 0;
TCCR2B = 0;

// Set Timer2 to Fast PWM mode
TCCR2A = (1 << COM2A1) | (1 << WGM20) | (1 << WGM21); // Fast PWM mode
TCCR2B = (1 << CS21); // Prescaler 8

// Set the PWM frequency to 2 kHz
// Formula: PWM Frequency = 16,000,000 / (8 * (256 - OCR2A))
// Rearranging: OCR2A = 256 - (16,000,000 / (8 * 2,000))
OCR2A = 255 - (16,000,000 / (8 * 2,000)); // Set for 2 kHz

// Set duty cycle to 50%
OCR2A = OCR2A / 2; // 50% of the calculated value
}

void loop() {
// Nothing needed here; PWM is handled by timers
}

I'm trying to generate PWM of 100kHz and 2kHz on Arduino Uno with 50% duty cycle, but unable to generate. Please help.

By that do you mean compile?
Your code compiles for a Uno.

The Atmega328P is a totally different chip. Have you got a device driver for that chip loaded up?

I looked in the board manager and found only one board driver for that chip.
The Github page for this is

I have not tried it, but it is a start.

Welcome to the forum

Please follow the advice given in the link below when posting code, in particular the section entitled 'Posting code and common code problems'

Use code tags (the < CODE/ > icon above the compose window) to make it easier to read and copy for examination

https://forum.arduino.cc/t/how-to-get-the-best-out-of-this-forum

In my experience the easiest way to tidy up the code and add the code tags is as follows
Start by tidying up your code by using Tools/Auto Format in the IDE to make it easier to read. Then use Edit/Copy for Forum and paste what was copied in a new reply. Code tags will have been added to the code to make it easy to read in the forum thus making it easier to provide help.

1 Like

I'm compiling on Arduino Uno having controller. PWM is not generated of desired frequency.

Please read post #3 and follow the guidlines.

1 Like

Huh ?!

An UNO contains one, but for barebones Atmega328 MiniCore works really well.

Your code is giving out a frequency of 82.5kHz on pin 6, and 7.8kHz on pin 11.

Arduino Uno contains contains an Atmega328P - PU.
This is the one I thought he meant

In my defence the OP did say

Which I took to mean Compile. Apparently he didn't. :roll_eyes:

Do not touch TC0 as it is used for many purposes by the Arduino Platform; instead, use TC1 for 100 kHz and TC2 for 2 kHz.

Your sketch is moderated as follows (compiled and NOT tested): (You should find 100 kHz at DPin-9 (Ch-A) and 2 kHz at DPin-3 (Ch-B).)

#define OC1A 9  //TC1 based 100 kHz Fast PWM at DPin-9 Ch-A
#define OC2B 3 //TC2 based 2 kHz Fast PWM at DPin-3 Ch-B

void setup()
{
  //direction set of PWM signals
  pinMode(OC1A, OUTPUT);
  pinMode(OC2B, OUTPUT);

  // Stop Timer1 and TC2
  TCCR1A = 0;
  TCCR1B = 0;

  TCCR2A = 0;
  TCCR2B = 0;

  // Set Timer1 to 100 kHz Fast PWM mode with prescaler 1
  //fOC1A = clckSys/(N*(1+ICR1); Mode-14 FPWM; OCR1A controls duty cycle
  // 100 kHz = 16000000/(1*(1+ICR1)) N= ==> ICR1 = 159
  TCCR1A |= (1 << WGM11); //Mode-14 Fast PWM
  TCCR1B |= (1 << WGM13) | (1 << WGM12);    //Mode-14 Fast PWM
  TCCR1A |= (1 << COM1A1) | (0 << COM1A0);  //Non-invert: HIGH-LOW
  ICR1 = 159;   // TOP for 100 kHz frequnecy
  OCR1A = 80;  //= 50% duty cycle
  TCNT1 = 0;

  // Set Timer2 to 2 kHz Fast PWM mode-7 with prescaler 64
  //fOC1B = clckSys/(N*(1+OCR2A); Mode-7 FPWM; OCR2B controls duty cycle
  // 2 kHz = 16000000/(64*(1+OCR2A)) ==> OCR2A = 124
  TCCR2A |= (1 << WGM21)|(1 << WGM20); //Mode-7 Fast PWM
  TCCR2B |= (1 << WGM22);  //Mode-7 Fast PWM
  TCCR2A |= (1 << COM2B1) | (0 << COM2B0);  //Non-invert: HIGH-LOW
  OCR2A = 124;   // TOP for 2 kHz frequnecy
  OCR2B = 62;  //= 50% duty cycle
  TCNT2 = 0;

  TCCR1B |= (1 << CS10);  //start TC1 with prescaler 1
  TCCR2B |= (1 << CS22);  //start TC2 with prescaler 64
}

void loop() {
  // Nothing needed here; PWM is handled by timers
}
1 Like

Ah yeah the PB, that is a completely different chip, with you on that.

1 Like

Or you can do this by only using Timer2.
Set it to generate the 100KHz fast PWM waveform, but also set an interrupt and let a pin toggle every 25 counts of the 100KHz to get the 2KHz

/**
    URL: https://dbuezas.github.io/arduino-web-timers/#mcu=ATMEGA328P&timer=2&CompareOutputModeB=clear-on-match%2C+set-at-max&timerMode=FPWM&OCR2B=79&topValue=OCR2A&OCR2A=159
    Mode     : FPWM
    Period   : 10 us
    Frequency: 100 kHz
    Outputs  :
     - D3: 50.00%, clear-on-match, set-at-max
*/
#define OUT_PIN 8

void setup() {
  pinMode (OUT_PIN, OUTPUT);// 2KHz signal on this pin
  noInterrupts();
  TCCR2A =
    1 << COM2B1 |
    1 << WGM21 |
    1 << WGM20;
  TCCR2B =
    1 << WGM22 |
    1 << CS20;
  TIMSK2 =
    1 << OCIE2A;
  DDRD =
    1 << DDD3;
  OCR2A = 159;
  OCR2B = 79;
  interrupts();
}

void loop()
{} // nothing to do here

ISR(TIMER2_COMPA_vect) {  /* on OCR2A match */
  static uint8_t count;
  count++;
  if (count == 25) {
    digitalWrite (OUT_PIN, !(digitalRead(OUT_PIN)));
    count = 0;
  }
}

And I am stumped why this toggling only works from pin 8 onwards. PortD (pins 0-7) refuses to do this. I tried 3 different Nano's and 2 different versions of the Arduino IDE.

Should the above be:?

static uint8_t count = 0;

To me, it appears that the following code of your sketch of post #11 gives the trouble as it configures other pins of Port-D as inputs; whereas, they should be outputs.

I have replaced the above line with pinMode(3, OUTPUT) and have run your sketch at 70 Hz test PWM at OC2B-pin. I am observing good pulsation on a LED connected at DPin-0, 1, 2, 4, 5, 6, 7.

/**
    URL: https://dbuezas.github.io/arduino-web-timers/#mcu=ATMEGA328P&timer=2&CompareOutputModeB=clear-on-match%2C+set-at-max&timerMode=FPWM&OCR2B=79&topValue=OCR2A&OCR2A=159
    Mode     : FPWM
    Period   : 10 us
    Frequency: 100 kHz
    Outputs  :
     - D3: 50.00%, clear-on-match, set-at-max
*/
#define OUT_PIN 7//0//1//2//4//5//6//7//8

void setup() 
{
  pinMode (OUT_PIN, OUTPUT);// 2KHz signal on this pin
  pinMode(3, OUTPUT); //~70 Hz test PWM at OC2B/DPin-3 
  noInterrupts();
  TCCR2A =
    1 << COM2B1 |
    1 << WGM21 |
    1 << WGM20;
  TCCR2B = (1 << WGM22);
  TIMSK2 = 1 << OCIE2A;
  //DDRD = 1 << DDD3;
  OCR2A = 222;//159;//~70 Hz test on OC2B-pin
  OCR2B = 111;//79;
  TCCR2B |= bit(CS22) | bit(CS21) | bit(CS20);
  interrupts();
}

void loop()
{} // nothing to do here

ISR(TIMER2_COMPA_vect) {  /* on OCR2A match */
  static uint8_t count = 0;
  count++;
  if (count == 25) {
    digitalWrite (OUT_PIN, !(digitalRead(OUT_PIN)));
    count = 0;
  }
}

static variables are initialised to zero by default so you don't need to do it explicitly. However, by doing it explicitly it makes it more obvious what is happening and, of course, it does no harm

1 Like

Bingo!

I Totally trusted the Arduino Web Timers tool to not give me something like that. I need to be more suspicious next time. Thanks!!

1 Like

Could the count variable be declared in the global area instead of in the ISR() without static modifier and would serve the same purpose?

I want to generate PWM of 10kHz, but I'm getting PWM of 8kHz instead of 10kHz in Arduino Uno, Please have a look on my code: "void setup() {
// Configure Timer0 for 10 kHz PWM on Pin 6
pinMode(6, OUTPUT);

// Stop Timer0
TCCR0A = 0;
TCCR0B = 0;

// Set Timer0 to Fast PWM mode with prescaler of 8
TCCR0A = 0b10000011; //(1 << COM0A1) | (1 << WGM00) | (1 << WGM01); // Fast PWM mode
TCCR0B = 0b00000010; //(1 << CS00); //Prescaler of 8

// Set the PWM frequency to 100 kHz
// Formula: PWM Frequency = 16,000,000 / (1 * (256 - OCR0A))
// Rearranging: OCR0A = 256 - (16,000,000 / (1 * 100,000))
OCR0A = 255 - (16,000,000 / 8 * 100,000); // Set for 10 kHz

// Set duty cycle to 50%
OCR0A = OCR0A / 2; // 50% of the calculated value" Please prvide any guidance.

you may find this useful

I believe so but, of course, its scope would be different which might cause a problem in a more complicated sketch

1 Like

That looks weird. Does one of those need to be OCR0B ?
β€œTop” set frequency, and some other compare channel decides switch point, right?

Please read post #3 and follow the guidlines regarding posting code.