PWM on certain pins do not output

int led1 = 13, led2 = 12;
int buton1 = 9;
//int buton1 = 11;
int buton2 = A0;
int interruptPin = 2;
volatile int ctr = 0;
volatile uint8_t ctrFallFalse = 0;
volatile uint8_t ctrFallTrue = 0;
 
const uint8_t OUTPUT_PIN = 3;  // = OC2B
//const uint8_t OUTPUT_PIN = 11;  // = OC2A
const int PWM_FREQ = 380; //KHz
const uint8_t PERIOD = uint8_t(16*1024/PWM_FREQ-1);      //  CPU cycles ~ 16 MHz / PWM Freq
//const uint8_t PERIOD = 16;
volatile bool ch = true;
volatile bool tmpCh = false;

void setupTimer2()
{
    pinMode(OUTPUT_PIN, OUTPUT);
    TCCR2B = 0;           // stop timer
    TCNT2  = 0;           // reset timer
    TCCR2A = 
            _BV(COM2B1)  // non-inverting PWM on OC2B
            //_BV(COM2A1)  // non-inverting PWM on OC2A
            | _BV(WGM20)   // fast PWM mode, TOP = OCR2A
            | _BV(WGM21);  // ...ditto
    TCCR2B = _BV(WGM22);  // ...ditto
    OCR2A = PERIOD/2 - 1;
    OCR2B = PERIOD/2 - 1;
    //TIMSK2 &= ~_BV(TOIE2);
}

void setupTimer1()
{
    //pinMode(10, OUTPUT); //OC1B
    pinMode(9, OUTPUT); //OC1A
    TCCR1B = 0;           // stop timer
    TCCR1A = 0;
    //TCCR1B = (_BV(WGM13) | _BV(WGM12));
    TCCR1B |= _BV(WGM13);
    TCCR1B |= _BV(WGM12);
    //TCCR1A = (_BV(WGM11) | _BV(WGM10));  // select Fast PWM with OCR1A BOTTOM TOP
    TCCR1A |= _BV(WGM11);
    TCCR1A |= _BV(WGM10);
    //TCCR1A |= _BV(COM1B1);
    //TCCR1A &= ~_BV(COM1B0);  // Set OC1B OUTUT pin 10
    TCCR1A |= _BV(COM1A1);
    TCCR1A &= ~_BV(COM1A0);  // Set OC1B OUTUT pin 10
    OCR1AH = 0;
    OCR1AL = PERIOD/2 - 1;
    //OCR1BH = 0;
    //OCR1BL = PERIOD/2 - 1;
    TCNT1H = 0;
    TCNT1L = 0;
    /*
    TIMSK1 = 0;
    TIMSK1 |= (_BV(OCIE1B) | _BV(TOIE1));
    */
}

void setupTimer0()
{
    pinMode(6, OUTPUT); //OC1A
    TCCR0B = 0;           // stop timer
    TCCR0A = 0;
    TCCR0B |= _BV(WGM02);
    TCCR0A |= _BV(WGM01);
    TCCR0A |= _BV(WGM00);
    TCCR0A |= _BV(COM0A1);
    TCCR0A &= ~_BV(COM0A0);  
    OCR0A = PERIOD/2 - 1; 
    TCNT0 = 0;
}

void irBuff(){
    //TCCR2B |= _BV(CS20);  // F_CPU / 1
    //TCCR1B |= _BV(CS10);  // F_CPU / 1
    TCCR0B |= _BV(CS00);  // F_CPU / 1
    digitalWrite(led1, HIGH);
}

void silenceIr(){
    //TCCR2B &= ~_BV(CS20);
    //TCNT2 = 0;
    //TCCR1B &= ~_BV(CS10);  // F_CPU / 1
    TCCR0B &= ~_BV(CS00);  // F_CPU / 1
    //Serial.println(TCNT1L);
    //TCNT1L = 0;
    //TCNT1H = 0;
    digitalWrite(led1, LOW);

}

void irHandler(){
  if (ch){
    irBuff();
  }
  else{
    silenceIr();
  }
  ch = !ch;
}
//pin change interrupt ayar fonksiyonu
void pciSetup(byte pin)
{
  *digitalPinToPCMSK(pin) |= bit (digitalPinToPCMSKbit(pin));  // enable pin
  PCIFR  |= bit (digitalPinToPCICRbit(pin)); // clear any outstanding interrupt
  PCICR  |= bit (digitalPinToPCICRbit(pin)); // enable interrupt for the group
}
 
void setup() {
  // put your setup code here, to run once:
  //led ve buton tanımları
  Serial.begin(115200);
  pinMode(led1, OUTPUT);
  //pinMode(led2, OUTPUT);
  //pinMode(buton1, INPUT);
  //pinMode(buton2, INPUT);
  pinMode(interruptPin, INPUT);
 
  //pciSetup(buton1);   //9 nolu pin için pci ayarlandı
  //pciSetup(buton2);   //A0 pini için pci ayarlandı

  attachInterrupt(digitalPinToInterrupt(interruptPin), irHandler, CHANGE);
  //attachInterrupt(digitalPinToInterrupt(2), silenceIr, RISING);
  //setupTimer2();
  //setupTimer1();
  setupTimer0();
  irBuff();
  //irBuff();
}
 
ISR (PCINT0_vect) // handle pin change interrupt for D8 to D13 here
{
  //D9 butonu basıldı ise ledi söndür
  //PCIFR = 0x00;
  /*
  if (!digitalRead(buton1))
  {
    //digitalWrite(led2, LOW);
    irBuff();
    //digitalWrite(led1, !digitalRead(led1));
    //digitalWrite(led1, HIGH);
  }
  else
  {
    silenceIr();
    //digitalWrite(led1, LOW);
    //digitalWrite(OUTPUT_PIN, LOW);
  }
  */

  
  if(ch){
    irBuff();
    //digitalWrite(led1, HIGH);
  }
  else{
    silenceIr();
    //digitalWrite(led1, LOW);
  }
  ch = !ch;
  
  /*
  if(ctr > 1000){
    if (!digitalRead(buton1)){
      if (!ch) ctrFallFalse++; else ctrFallTrue++;
      digitalWrite(led2, HIGH);
    }
    if (ctr > 1030){
      digitalWrite(led2, LOW);
      if (ctrFallFalse > ctrFallTrue) tmpCh = false; else tmpCh = true;
      ctrFallFalse = 0;
      ctrFallTrue = 0;
      ctr = 0;
    } 
  }
  ctr++;
  ch = !ch;
  */
}


 
ISR (PCINT1_vect) // handle pin change interrupt for A0 to A5 here
{
  //A0 butonu basıldı ise ledi yak
  if (!digitalRead(buton2))
  {
    silenceIr();
    digitalWrite(led2, HIGH);
    OCR2B = (OCR2B + int(PERIOD/10))%(PERIOD-1);
    delay(1000);
  }
  else
  {
    //
    digitalWrite(led2, LOW);
  }
}
 
void loop() {
  /*
  if(ch == tmpCh){//if FALLING
    irBuff();
  }
  else{ //IF RISING
    silenceIr();
  }
  */
  //bool tmpCh = ch;
  //ctr++;
  delay(2000);
}

Here is the full code, as you can see I do not use any library (Servo Etc.)

I need to use both interrupt pin of arduino uno, (1&2), for same signal, one for rising, one for falling. Because, the interrupt signal is 38KHz and reading the interrupt pin change cause to miss some events (Arduino sucks at this). By interrupt, I will generate 380KHz PWM so I need to use fast PWM. Timer2 fast PWM blocks me to utilize it because its output is pin3. So I wanted to use Timer0 or 1. But I could not get any thing either on Pin9 (OC1A) nor Pin6(OC0A). Why is that?

On my research, I ve seen many answers to that claiming the problem is servo library which blocks those pins however, that is not the case.

You do not use any prescaler values for clock source bits CS02:CS00 and the timer is not running.

@istemihan90
1.
Make a clear statement.

2.
TC0 makes Fast PWM signal at DPin-6 (Ch-A), 5 (Ch-B)
TC1 makes Fast PWM signal at DPin-9 (Ch-A), 10 (Ch-B)
TC2 makes Fast PWM signal at DPin-11 (Ch-A), 3 (Ch-B)

3.
As you will be using external interrupts, leave aside DPin-2, 3. Now, forget TC2's Ch-B.
You can now still generate 5 PWM signals. At what pins, do you want them and at what frequencies?

Hi there, I start Timer with irBuff() function in setup().

I want 380KHz pwm on either P9 or P6. Also want to know where I am failing. I spent almost one day on this :frowning:

With fast pwm to OCR0A and PERIOD/2-1 for frequency, I think you want to set the output mode to Toggle

TCCR0A |= _BV(COM0A0);
TCCR0A &= ~_BV(COM0A1);

EDIT: With using OCR0A as top, you can only get a square wave output on pin6. You can not control the frequency and duty cycle with one value. You either want the Timer0 pwm output on pin5(outputB) or else focus you efforts on Timer1.

Probably not, and it may not even be possible. Did you mean 38 kHz?

We can give you sketch for 380.952 kHz Fast PWM at DPin-9 (Ch-A) in Mode-14 with TOP in ICR register. Is it ok? As @jremington has pointed out that it is impossible to generate exactly 380 kHz PWM signal because of the limitation of the following formula:

fpwm = 16000000/(N*(1+TOP)); //

Sketch:

//380 Hz PWM signal with 50% duty cycle using TCNT1 at DPin-9 
#define OC1A 9

void setup()
{
  Serial.begin(9600);
  pinMode(OC1A, OUTPUT); 
  
  TCCR1A = 0x00;   //reset
  TCCR1B = 0x00;   //TC1 reset and OFF
  //fOC1A (DPin-9) = clckSys/(N*(1+ICR1)); Mode-14 FPWM; OCR1A controls duty cycle
  // 380000 = 16000000/(1*(1+ICR1)) ==> ICR1 = 41
  TCCR1A |= (1<<WGM13)|(1<<WGM12)|(1<<WGM11);  //Mode-14 fast PWM
  TCCR1A |= (1 << COM1A1)|(0<<COM1A0); //non-invert
  
  ICR1 = 41;  //380.952 kHz 
  OCR1A = 20;//~= 50% duty cycle 
  TCCR1B |= (1 << CS10); //Mode-14, /1; TC1 in ON
}

void loop(){}

Hi There, thank you for the advices but none of them worked. Your last suggestion outputs a weird 15KHz PWM.

Though, what I realized (and missing in the datasheet) is that to get Fast PWM with duty cycle control is that even when you dont want to use both output (say only need OC0B) you have to set both on the conrol register as below;

void setupTimer0()
{
    pinMode(OC0B, OUTPUT); //OC1B
    DDRD |= (1 << PD5) | (1 << PD6);
    TCCR0B = 0;           // stop timer
    TCCR0A = 0;
    TCCR0B |= _BV(WGM02);
    TCCR0A |= _BV(WGM01);
    TCCR0A |= _BV(WGM00);
    TCCR0A |= _BV(COM0B1);
    TCCR0A &= ~_BV(COM0B0);  
    TCCR0A |= _BV(COM0A1);
    TCCR0A &= ~_BV(COM0A0); 
    OCR0A = PERIOD; 
    OCR0B = int(PERIOD/2 - 1);
    TCNT0 = 0;
}

if you skip below;

    TCCR0A |= _BV(COM0A1);
    TCCR0A &= ~_BV(COM0A0);

without initializing CHA, output, CHB output do not work!

I hope it will help anyone who encounters succh problem. Cheers!

Why is it weid?
fpwm = 16000000/(1*(1+41))
==> fpwm = 380.952 kHz

You forgot to disable the Timer0 Overflow Interrupt.

Add: TIMSK0 &= ~_BV(TOIE0);

The interrupt is enabled in init() (See: wiring.c).

Thanks for the tip. It makes the output unstable when you do not disable the overflow interrupt.

I don't know why, but this last version of the code works as I expect. I hope it will be helpfull for others.

int led1 = 13, led2 = 12;
int buton1 = 9;
//int buton1 = 11;
int buton2 = A0;
int interruptPin = 2;
volatile int ctr = 0;
volatile uint8_t ctrFallFalse = 0;
volatile uint8_t ctrFallTrue = 0;
 
//const uint8_t OUTPUT_PIN = 3;  // = OC2B
//const uint8_t OUTPUT_PIN = 11;  // = OC2A
const int PWM_FREQ = 38*10; //KHz
const uint8_t PERIOD = uint8_t(16*1024/PWM_FREQ-1);      //  CPU cycles ~ 16 MHz / PWM Freq
//const uint8_t PERIOD = 16;
volatile bool ch = true;
volatile bool tmpCh = false;

#define OC1A 9
#define OC0B 5

void setupTimer0()
{
    pinMode(OC0B, OUTPUT); //OC1B
    DDRD |= (1 << PD5) | (1 << PD6);
    TCCR0B = 0;           // stop timer
    TCCR0A = 0;
    TCCR0B |= _BV(WGM02);
    TCCR0A |= _BV(WGM01);
    TCCR0A |= _BV(WGM00);
    TCCR0A |= _BV(COM0B1);
    //TCCR0A &= ~_BV(COM0B0);  
    TCCR0A |= _BV(COM0B0);
    TCCR0A |= _BV(COM0A1);
    //TCCR0A &= ~_BV(COM0A0); 
    TCCR0A |= _BV(COM0A0);
    OCR0A = PERIOD-1; 
    OCR0B = int(PERIOD/2 - 1);
    TCNT0 = 0;
    TIMSK0 &= ~_BV(TOIE0);
}

void irBuff(){
    //TCNT0 = 0;
    TCCR0B |= (1 << CS00);
    //PORTB |= (1 << PB5);
}

void silenceIr(){
    TCCR0B &= ~(1 << CS00);
    TCNT0 = 0;
    //PORTB &= ~(1 << PB5);
}

void chSetTrue(){
  ::ch = true;
}
void chSetFalse(){
  ::ch = false;
}


//pin change interrupt ayar fonksiyonu
void pciSetup(byte pin)
{
  *digitalPinToPCMSK(pin) |= bit (digitalPinToPCMSKbit(pin));  // enable pin
  PCIFR  |= bit (digitalPinToPCICRbit(pin)); // clear any outstanding interrupt
  PCICR  |= bit (digitalPinToPCICRbit(pin)); // enable interrupt for the group
}
 
void setup() {
  // put your setup code here, to run once:
  //led ve buton tanımları
  //Serial.begin(115200);
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  //pinMode(buton1, INPUT);
  pinMode(buton2, INPUT);
  pinMode(interruptPin, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
 
  //pciSetup(buton1);   //9 nolu pin için pci ayarlandı
  pciSetup(buton2);   //A0 pini için pci ayarlandı

  attachInterrupt(digitalPinToInterrupt(interruptPin), irBuff, LOW);
  attachInterrupt(digitalPinToInterrupt(3), silenceIr, HIGH);

  setupTimer0();
  
  irBuff();

}



ISR (PCINT1_vect) // handle pin change interrupt for A0 to A5 here
{
  OCR0B = (OCR0B + uint8_t(PERIOD/20))%(PERIOD-1);
}


void loop() {

}