Using PWM with Compare Match interrupt

Hi everyone!

I am new in these forum.. I have read a lot of discussions here and thout I can get a little bit of help here.

Latley I stated to work in a project with the arduino MEGA2560.
I managed to operate motors utilizing pins associated with Output Compare Registered (timer 3 and timer 4). I used Fast PWM according to the following line in the microcontroller datasheet:

After that i tried to use another Compare Match interrupt (with timer 2) in the same code, in order to change motors speed and direction. That is where the fun begins.

As i learned from another project (with Arduino Uno) each interrupt have hierarchy, and it goes in the order at the following table where the higher lines are higher in hierarchy (sorry for the link, cannot attach more than one image).

In the Uno project it woked! But for some reason it didn't work here, maybe i'm wrong and this is not the hierarchy?..

to be sure, I replced the interrupt command with a simple operation (blinking LED).
When I put setup of timers 3 and 4 under comment it blinks. When I DO setup at least one of the PWM timers then the motor works properly. Though the LED is not blinking anymore..

I am using two lines for each motor in order to work with two directions. That why two OCRx registers for each motor/timer.
I am programming in VS Code with Platform IO. Here is my code:

#include <Arduino.h>

#define   RIGHT_FORWARD   2
#define   RIGHT_BACKWARD  3
#define   LEFT_FORWARD    6
#define   LEFT_BACKWARD   7

byte  RFS = 0x8F,
      RBS = 0,
      LFS = 0x8F,
      LBS = 0;

bool  ledState = 0;
byte  state = 0;

void setup() {

  Serial.begin(9600);

  pinMode(13, OUTPUT);
  digitalWrite(13, 0);


  pinMode(RIGHT_FORWARD, OUTPUT);
  pinMode(RIGHT_BACKWARD, OUTPUT);
  pinMode(LEFT_FORWARD, OUTPUT);
  pinMode(LEFT_BACKWARD, OUTPUT);

  // // Drive D2 & D3 HIGH when TCNT3 < OCR3x while up-counting
  // // Drive D2 & D3 LOW when TCNT3 > OCR3x while up-counting
  // //>>>>>>>> DATASHEETS PG. 154
  // // Set outputs to work in Fast PWM mode
  // // >>>>>>>> DATASHEETS PG. 145 <<<<<<<<
  // // Set timers to count without prescalar
  // // >>>>>>>> DATASHEETS PG. 156 <<<<<<<<
  TCCR3A = 0b00101001;    // Pin toggling mode (HIGH to LOW)
  TCCR3B |= 0b00001001;   // Prescalar and Fast PWM
  TCCR3B &= 0b11111001;
  TIMSK3 |= 0b00001100;   // Enable On-Compare-Interrupt B&C
  OCR3B = RFS;           // RIGHT_FORWARD speed (MAX is 0xFF)
  OCR3C = RBS;           // RIGHT_BACKWARD speed (MAX is 0xFF)


  // //Drive D6 & D7 HIGH when TCNT4 < OCR4x while up-counting
  // // Drive D6 & D7 LOW when TCNT4 > OCRx while up-counting
  // //>>>>>>>> DATASHEETS PG. 154
  // // Set outputs to work in Fast PWM mode
  // // >>>>>>>> DATASHEETS PG. 145 <<<<<<<<
  // // Set timers to count without prescalar
  // // >>>>>>>> DATASHEETS PG. 156 <<<<<<<<
  TCCR4A = 0b10100001;    // Pin toggling mode (HIGH to LOW)
  TCCR4B |= 0b00001001;   // Prescalar and Fast PWM
  TCCR4B &= 0b11111001;
  TIMSK4 |= 0b00000110;   // Enable On-Compare-Interrupt B&C
  OCR4A = LFS;           // LEFT_FORWARD speed (MAX is 0xFF)
  OCR4B = LBS;           // LEFT_BACKWARD speed (MAX is 0xFF)

  // LED blink interrupt
  TCCR1A = 0;
  TCCR1B = 0b00000100;
  TCNT1 = 0;
  TIMSK1 = 0x02;
  OCR1A = 65000;

  sei();

}

void loop() {

}

ISR(TIMER1_COMPA_vect){

  TCNT1 = 0;
  
  digitalWrite(13, ledState);
  ledState = !ledState;

}

Thank you all!

Why interrupts? Isn't PWM output sufficient for blinking a LED or controlling a motor?

You have enabled FIVE interrupts but provided an ISR for only 1. I think that will cause your ketch to re-start when any of the other four interrupts occur.

1 Like

It is good practice to make the interrupt commands (ISRs) as simple as possible.

Here's an extensible example of running two interrupts (TIMER1_COMPA_vect) and TIMER1_OVF_vect) off of Timer1, with the timer adjusting done from loop() rather than in the ISRs:

As Using PWM with Compare Match interrupt - #3 by johnwasser points out, you need ISRs to match the interrupts you are setting.

There are some tools for re-using ISRs: many interrupts serviced by same routine - #11 and avr-libc: <avr/interrupt.h>: Interrupts and mbeddr.arduino/include/avr/interrupt.h at 95c1191945d538b58a34535f1f9db1186a92dfd0 · coolya/mbeddr.arduino · GitHub

I used ISR_ALIASOF in DecimalFreqLF.ino - Wokwi ESP32, STM32, Arduino Simulator to share the same ISR code while experimenting with configuring different timer modes and interrupts.

Simpley worked!
Since setting the registers themselves was driving the motors i assumed there is no significance defining an ISR vector.

Thank you for the fast and si,ple answer, I appreiciate it.

Thw solution above worked for me. Thank you anyway. :slightly_smiling_face:

If you don't have anything for the ISR to do, just don't enable the interrupt.

Alternately, if you really want to set the interrupt flags but don't want to do anything when the interrupt triggers, you can define their matching vectors with EMPTY_INTERRUPT(...) avr-libc: <avr/interrupt.h>: Interrupts

Defines an empty interrupt handler function. This will not generate any prolog or epilog code and will only return from the ISR. Do not define a function body as this will define it for you. Example:

EMPTY_INTERRUPT(ADC_vect);

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