Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 5 of 5

Thread: How to use the general purpose timer (GPT) output conpare interrupt

  1. #1
    Junior Member
    Join Date
    Oct 2019
    Posts
    17

    How to use the general purpose timer (GPT) output conpare interrupt

    I am trying to create multiple interrupts that use the gpt.
    The project should look something like this:

    Code:
    // compare values that will trigger the interrupts
    uint32_t ocvalue1 = 1000;
    uint32_t ocvalue2 = 1500;
    
    void setup() {
      // Whatever has to be done to get this working
    }
    
    // Stuff that should happen on the first interrupt (triggered by ocvalue1)
    void interrupt1(void) {
      // My code
    }
    
    // Stuff that should happen on the second interrupt (triggered by ocvalue2)
    void interrupt2(void) {
      // My code
    }
    
    void loop() {
      // Other code that runs in the meantime
    }
    What do I have to do in the setup() to have this program do what I described?

  2. #2
    Senior Member+ manitou's Avatar
    Join Date
    Jan 2013
    Posts
    2,781
    There are some T4 example sketches in https://github.com/manitou48/teensy4
    gpt_pwm.ino sets up GPT compare registers. There are other GPT examples (capture, external clock, ...)

  3. #3
    Junior Member
    Join Date
    Oct 2019
    Posts
    17
    Thanks manitou for the inspiration. I've been working on the project for some time now and was able to get it working the way I wanted it to (I'd still like the structure to be a bit better, but interrupts demand quick response times). I wrote two libraries (one for general use of projects like this and one customizable for each unique project) and one sketch to show it off. Here is the stuff (warning: the comments are in German):

    The sketch:
    Code:
    /*
     * Dieses Programm stellt eine Umgebung zum Testen der Timerbasierten Interrupts mithilfe der Bibliothek L.h bereit.
     * Geschrieben von Lukas Freudenberg, 30. Oktober 2019
     * Dieses Programm ist gemeinfrei (public domain).
     */
    
    #include <L.h>
    #include <Interrupt.h>
    
    uint32_t ocvalue1 = 1000;
    uint32_t ocvalue2 = 500;
    int outPinArr[] = {3, 6, 13};
    
    void setup() {
      L::sBg(4000000);
      L::pinSetup(outPinArr, sizeof(outPinArr)/sizeof(int));
      L::interSetup(0, ocvalue1);
      L::interSetup(1, ocvalue2);
      L::sync();
    }
    
    void loop() {
      digitalWriteFast(outPinArr[2], HIGH);
      delay(200);
      digitalWriteFast(outPinArr[2], LOW);
      delay(200);
    }
    The L.h file:

    Code:
    /*
     * L.h - Bibliothek, die einem das Leben erleichtert. Speziell für die Programmierung des Teensy 4.0
     * Geschrieben von Lukas Freudenberg, 30. Oktober 2019
     * Diese Bibliothek ist gemeinfrei (public domain).
    */
    #ifndef L_h
    #define L_h
    
    #include "Arduino.h"
    
    class L {
      public:
        static void pinSetup(int outPins[], int size);  // Setzt die Outputpins
        static void interSetup(int timer, int compare); // Initialisiert einen Timer-Counter mit Interruptfunktion
        static void sync();				    // Synchronisiert GPT1 und GPT2
      private:
        static void interrupt1();	// Was beim Interrupt 1 geschieht
        static void interrupt2();	// Was beim Interrupt 2 geschieht
        static int* pins;		// speichhert die Outputpins
    };
    
    #endif
    The L.cpp file:

    Code:
    #include "Arduino.h"
    #include "L.h"
    #include "Interrupt.h"
    
    int* L::pins;
    
    // Setzt die Outputpins
    void L::pinSetup(int outPins[], int size) {
      pins = outPins;
      for(int i = 0; i < size; i++) {
        pinMode(outPins[i], OUTPUT);
      }
      CCM_CSCMR1 = 0x00000000;  // Clock wird durch 1 dividiert (maximale Geschwindigkeit = 150 MHz)
    }
    
    // Synchronisiert GPT1 und GPT2
    void L::sync() {
      GPT2_CR &= 0xFFFFFFFE;    	// Counter GPT2 deaktivieren (wird beim nächsten Interrupt von GPT1 wieder aktiviert)
    }
    
    // Was beim Interrupt 1 geschieht
    void L::interrupt1() {
      GPT1_SR = 0x00000001;         // Interrupt im Statusregister zurücksetzen
      while (GPT1_SR == 0x0000001); // Auf Zurücksetzen des Registers warten
      Interrupt::in1(pins[0]);      // Interruptfunktion ausführen
      if (!(GPT2_CR & GPT_CR_EN)){GPT2_CR |= 0x00000001;} // Counter GPT2 aktivieren (aufgrund einer möglichen Synchronisation)
    }
    
    // Was beim Interrupt 2 geschieht
    void L::interrupt2() {
      GPT2_SR = 0x00000001;         // Interrupt im Statusregister zurücksetzen
      while (GPT2_SR == 0x0000001); // Auf Zurücksetzen des Registers warten
      Interrupt::in2(pins[1]);      // Interruptfunktion ausführen
    }
    
    // Initialisiert einen Timer-Counter mit Interruptfunktion
    void L::interSetup(int timer, int compare) {
      switch(timer) {
        case 0: CCM_CCGR1 |= 0x03000000;  // Clock für GPT1 Modul aktivieren
                
                // GPT1 konfigurieren
                GPT1_CR = 0;              // Kontrollregister zurücksetzen
                GPT1_PR = 0;              // Vorskalierung = 1:1
                GPT1_CR |= 0x00000040;    // Periphere Clock auswählen für maximale Geschwindigkeit (150 MHz)
                GPT1_OCR1 = compare - 1;  // Wert des Counters für das Auslösen des Interrupts setzen
                GPT1_IR = 0x00000001;     // Output Compare 1 aktivieren
                GPT1_CR |= 0x00000001;    // Counter GPT1 aktivieren
                
                attachInterruptVector(IRQ_GPT1, interrupt1);  // Interruptfunktion festlegen
                NVIC_ENABLE_IRQ(IRQ_GPT1);			  // Interrupt in der Interruptcontroller Tabelle aktivieren
                break;
        
        case 1: CCM_CCGR0 |= 0x03000000;  // Clock für GPT2 Modul aktivieren
                
                // GPT2 konfigurieren
                GPT2_CR = 0;              // Kontrollregister zurücksetzen
                GPT2_PR = 0;              // Vorskalierung = 1:1
                GPT2_CR |= 0x00000040;    // Periphere Clock auswählen für maximale Geschwindigkeit (150 MHz)
                GPT2_OCR1 = compare - 1;  // Wert des Counters für das Auslösen des Interrupts setzen
                GPT2_IR = 0x00000001;     // Output Compare 1 aktivieren
                GPT2_CR |= 0x00000001;    // Counter GPT2 aktivieren
                
                attachInterruptVector(IRQ_GPT2, interrupt2);  // Interrupt festlegen
                NVIC_ENABLE_IRQ(IRQ_GPT2);			  // Interrupt in der Interruptcontroller Tabelle aktivieren
                break;
      }
    }
    The Interrupt.h file:

    Code:
    /*
     * Interrupt.h - Bibliothek, die benutzerdefinierte Interrupts mithilfe der Bibliothek L.h auf dem Teensy 4.0 bereitstellt
     * Geschrieben von Lukas Freudenberg, 30. Oktober 2019
     * Diese Bibliothek ist gemeinfrei (public domain).
    */
    #ifndef Interrupt_h
    #define Interrupt_h
    
    class Interrupt {
      public:
        static void in1(int data);
        static void in2(int data);
    };
    
    #endif
    And finally the Interrupt.cpp file (this is the one that you would put into the folder of your sketch and edit the functions in it to whatever you want to happen at an interrupt):

    Code:
    #include "Arduino.h"
    #include "Interrupt.h"
    
    void Interrupt::in1(int data){
      digitalWriteFast(data, !digitalReadFast(data));
    }
    
    void Interrupt::in2(int data){
      digitalWriteFast(data, HIGH);
      digitalWriteFast(data, LOW);
    }
    Just as a side note: When a program with interrupts is already running on the Teensy, one might occur during the upload. This will cause it to fail, but don't worry: If you push the on board button to upload the sketch, you're fine.

    Any thoughts on how to further improve this?

    In any case, I release this code to the public domain.

  4. #4
    Junior Member
    Join Date
    Oct 2019
    Posts
    17
    OK, so this works if you want to use only one interrupt per timer (which is two in total). Is there a way to attach three different routines to the three output-compare events of one timer?

  5. #5
    Senior Member+ manitou's Avatar
    Join Date
    Jan 2013
    Posts
    2,781
    Quote Originally Posted by LukasFun View Post
    OK, so this works if you want to use only one interrupt per timer (which is two in total). Is there a way to attach three different routines to the three output-compare events of one timer?
    I think in your ISR, you would need to look at GPTx_SR, and bits OF1 OF2 OF3 would indicate which compare-event fired, and then you could call your associated routine for that event. (and clear the OFx bit)

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •