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

Thread: Using IntervalTimer in Subclass: programming issue

  1. #1
    Junior Member
    Join Date
    Aug 2019
    Posts
    8

    Using IntervalTimer in Subclass: programming issue

    Hello,

    I have a problem with using IntervalTimer in a class. I know this problem is entirely based on my missing experince with C++, and I hope you can help me fix it.

    I use a teensy3.6 to drive a piezo motor. The IntervalTimer sets a motor interval, which combined with a quadrature decoder counting the steps to go sets the speed. Using it in the main class worked fine. For a better overview when adding more features to the final product I want to put all the motor related stuff in a class and get it out of the main. But now the program gives me compiling issues using a non-static member function. I found some solution about using a forwarding static function but in my implementation it has undefined references. In my understanding the problem is, since the interrupt from the IntervalTimer could be fired when no instance of the motor subclass is made it does not know which function to call. There will always be only one object of the motor subclass, I read something about Singleton classes, but I don't know if that is the way to go.
    Any help is highly appreciated! Does not need to the beautiful.

    The main code:
    Code:
    #include "Tekceleo.h"
    
    
    
    Tekceleo tekceleo(55000, 50000);
      
    void setup() {
      tone(2, 2000, 200);
    
      Serial.begin(115200); 
      delay(1000);
     
      tone(2, 400, 200);
      delay(200);
      tone(2, 800, 200);
      delay(200);
      tone(2, 2000, 200);
      Serial.println("Start");
    
      tekceleo.start(50);
    
    }
    
     
    void loop() {
    
    }

    The header file of Tekceleo subclass
    Code:
    #ifndef TEKCELEO_H
    #define TEKCELEO_H
    
    #include <stdint.h>
    #include "mk20dx128.h"
    #include "core_pins.h"
    #include "AD9837.h"
    /*
    * Tekceleo.h - Library for controlling the Tekceleo motor and running it for a given flowrate
    */
    
    class Tekceleo {
    
    	public:
    		Tekceleo(unsigned long startfrq, unsigned long minfrq); //initialize, find initial frequency
    		void start(float flowrate);
    		void stop();
    
    
    
    	private:
    
    		static Tekceleo *instance;
    		int cts; //cts for MOD, for motor interval
    		int duration; //uS, for motor interval
    		float flowrate; //
    		unsigned long initialfrequency; //initial frequency, the motor turns
    		unsigned long startfrequency; //starting frequency for finding initial frequency
    		unsigned long minfrequency; //minimal frequency,
    		unsigned long frequency; //momentary frequency
    
    		AD9837 ad9837;
    
    		float dutyCycle; //duty Cycle
    
    		volatile bool motorTurning;
    		volatile bool dutyCycleReached;
    
    		void motorLoop();
    		void dutyCycleLoop();
    
    		static void motorLoopForward();
    		static void dutyCycleLoopForward();
    
    		IntervalTimer motorTimer;
    		IntervalTimer dutyCycleTimer;
    
    		int pin_motor_direction;
    		int pin_test;
    		int pin_PPen; //sets the push-pull converter (motorsignal)
    
    		void findInitialFrequency(); //sets initialFrequency, do at initializing
    		void quadratureDecoder();
    
    		void set_timebase(float flw); //sets uS and cts for a given flowrate
    
    		void ftm2_isr(void);
    
    };
    
    #endif
    the cpp File of the Tekceleo class:
    Code:
    #include "Tekceleo.h"
    #include <stdint.h>
    #include "mk20dx128.h"
    #include "core_pins.h"
    #include "AD9837.h"
    #include <cmath>
    
    Tekceleo::Tekceleo(unsigned long startfrq, unsigned long minfreq) : ad9837(startfrq)
    {
    	instance = this;
    	pin_motor_direction = 9;
    	pin_test = 20;
    	pin_PPen = 17;
    	
        // TURN OFF PUSH PULL CONVERTER
    	pinMode(pin_PPen,OUTPUT);
    	digitalWrite(pin_PPen, LOW);
    
    	pinMode(pin_test, OUTPUT);
    	digitalWrite(pin_test, LOW);
    
      // SETUP MOTOR DIRECTION
    	pinMode(pin_motor_direction,OUTPUT); // set TOGGLE to OUTPUT
    	digitalWrite(pin_motor_direction, LOW);  // set high for one motor direction
    
    	dutyCycle = 0.25;
    
    	startfrequency = startfrq;
    	minfrequency = minfreq;
    	ad9837.setfrequency(startfrequency * 4);
    	quadratureDecoder();
    
    	findInitialFrequency();
    }
    
    
    void Tekceleo::set_timebase(float flw)
    {
    	float RADIUS_SYRINGE = 28.6/2;
    	float P_SPINDLE = 1.0;
    	float GEAR_FACTOR = 12.0/32.0;	
    	float pi = 3.14159265359;	
    	float VOLUME_PER_ROTATION = RADIUS_SYRINGE * RADIUS_SYRINGE * pi * P_SPINDLE * GEAR_FACTOR * 0.001;
    	int ENCODER_EDGES_PER_ROTATION = 2000 * 4;
    	float FLOW_PER_SECOND = flw / 3600;
    	float ROTATIONS_PER_SECOND = FLOW_PER_SECOND / VOLUME_PER_ROTATION;
    	double ENCODER_EDGES_PER_uSECOND = ROTATIONS_PER_SECOND * ENCODER_EDGES_PER_ROTATION / 1000000;
    
    	bool notFound = true;
    	int uS_to_GO = 100000; // minimal interval length 100mS
    	double ENCODER_EDGES;
    	while(notFound){
    		ENCODER_EDGES = ENCODER_EDGES_PER_uSECOND * uS_to_GO;
    		double MOD_EDGES = std::fmod(ENCODER_EDGES, 1);
    		if(ENCODER_EDGES > 10.0 && MOD_EDGES < 0.001){
    			duration = uS_to_GO;
    			cts = (int) ENCODER_EDGES;
    			notFound = false;
    		}
    		uS_to_GO += 1;
    	}
    }
    
    void Tekceleo::stop() //stops the motor
    {
    	motorTimer.end();
    	dutyCycleTimer.end();
    	digitalWrite(pin_PPen, LOW);
    }
    
    void Tekceleo::quadratureDecoder() //setups the Quadrature Decoder, cts set to 10 for finding the initial frequency
    {
    	// FTM2 Pins
    	// K20 pin 41,42
    	// Bit 8-10 is Alt Assignment
    	PORTB_PCR18 = 0x00000612;   //Alt6-QD_FTM2,FilterEnable,Pulldown
    	PORTB_PCR19 = 0x00000612;   //Alt6-QD_FTM2,FilterEnable,Pulldown
    
    	//Set FTMEN to be able to write registers
    	FTM2_MODE=0x04;	    // Write protect disable - reset value
    	FTM2_MODE=0x05;	    // Set FTM Enable
    
    	// Set registers written in pins_teensy.c back to default
    	FTM2_CNT = 0;
    	FTM2_MOD = 0;
    	FTM2_C0SC =0;
    	FTM2_C1SC =0;
    	FTM2_SC = 0x40;     //enable hardware trigger
    
    	FTM2_FILTER=0x22;	// 2x4 clock filters on both channels
    	FTM2_CNTIN=0;
    	FTM2_MOD=10;	    // set counter to 10
    	FTM2_CNT=0;	    	// Updates counter with CNTIN
    	FTM2_QDCTRL=0b11000111;	    // Quadrature control
    	//        Filter enabled, QUADEN set
    
    	// Write Protect Enable
    	FTM2_FMS=0x40;		// Write Protect, WPDIS=1
    
          
    	NVIC_ENABLE_IRQ(IRQ_FTM2); 
    }
    
    void Tekceleo::ftm2_isr(void)
    {
    	if((FTM2_SC & FTM_SC_TOF) != 0){
    		FTM2_SC &= ~FTM_SC_TOF;
    	}
    	digitalWrite(pin_PPen, LOW);
    	motorTurning = true;
    
    	digitalWrite(pin_test, LOW);
    }
    
    void Tekceleo::findInitialFrequency()
    {
    	frequency = startfrequency;
    	motorTurning = false;
    	while(!motorTurning){
    		if(frequency < minfrequency){frequency = startfrequency;}
    		frequency = frequency - 200;
    		ad9837.setfrequency(frequency);
    		delay(300);
    	}
    	digitalWrite(pin_PPen, LOW);
    	frequency = frequency - 1000;
    	initialfrequency = frequency;
    	ad9837.setfrequency(frequency);
    	tone(2, 400, 200);
    	delay(200);
    	tone(2, 800, 200);
    	delay(200);
    	tone(2, 2000, 200);
    }
    
    void Tekceleo::dutyCycleLoop()
    {
    	if(motorTurning){
    		dutyCycleReached = true;
    	}
    	dutyCycleTimer.end();
    }
    
    void Tekceleo::motorLoop(){
    	//falls Flanken NICHT erreicht!
    	if(!motorTurning){
    		Serial.println("Dreht nicht! Dreht zu langsam! Erreicht erforderliche Flanken nicht! Frequenz herabsetzen.");
    		frequency -= 250;
    		ad9837.setfrequency(frequency * 4);
    	}
    	//falls Duty Cycle nicht erreicht!
    	else if(!dutyCycleReached){
    		Serial.println("Dreht, aber Duty Cycle wurde nicht erreicht! Frequenz herabsetzen.");
    		frequency -= 250;
    		ad9837.setfrequency(frequency * 4);
    	}
    	//falls unter die Mindestfrequenz gerutscht - setze Duty Cycle rauf, nochmal von vorne!
    	if(frequency <= minfrequency){
    		Serial.println("Innerhalb des vorgegebenen Duty Cycle nicht möglich! Erlaube höheren Duty Cycle.");
    		frequency = initialfrequency;
    		dutyCycle += 0.1;
    		ad9837.setfrequency(frequency * 4);
    		if(dutyCycle > 0.95){
    			while(1){
    			tone(2, 4500, 100);
    			delay(200);            
    			}
    		}
    	}
    	//ansonsten: "ganz normaler" Durchlauf, setze Variablen zurück, "starte" Motor erneut
    	motorTurning = false;
    	dutyCycleReached = false;
    	dutyCycleTimer.begin(dutyCycleLoopForward, duration * dutyCycle);
    	digitalWrite(pin_PPen, HIGH);
    	digitalWrite(pin_test, HIGH);
    }
    
    void Tekceleo::start(float flowrate)
    {
    	set_timebase(flowrate);
    	noInterrupts();
    	FTM2_MOD = cts;
    	FTM2_CNT = 0;
    	FTM2_PWMLOAD = 0x200;
    	interrupts();
    
    	digitalWrite(pin_PPen, HIGH);
    	motorTimer.begin(motorLoopForward, duration);
    	dutyCycleTimer.begin(dutyCycleLoopForward, duration * dutyCycle);
    }
    
    void Tekceleo::motorLoopForward(){
    	instance->motorLoop();
    }
    
    void Tekceleo::dutyCycleLoopForward(){
    	instance->dutyCycleLoop();
    }

  2. #2
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    10,116
    First thought was something in the constructor is being done too early - before other stuff is done as that has been an issue.

    Seeing "Using it in the main class worked fine" sort of suggests that may be the case?

    Not sure what in the constructor does what with what - but moving the func() calls at the end to the .start() or a .begin() in setup(){} might be what is needed to get it back to what it was when working?
    Code:
    	ad9837.setfrequency(startfrequency * 4);
    	quadratureDecoder();
    
    	findInitialFrequency();

  3. #3
    Junior Member
    Join Date
    Aug 2019
    Posts
    8
    Oh, I see I was not too exakt.
    That part (and the whole rest) was working and I think should be working.

    What doesn't work is:

    Code:
    void Tekceleo::start(float flowrate)
    {
    	set_timebase(flowrate);
    	noInterrupts();
    	FTM2_MOD = cts;
    	FTM2_CNT = 0;
    	FTM2_PWMLOAD = 0x200;
    	interrupts();
    
    	digitalWrite(pin_PPen, HIGH);
    	motorTimer.begin(motorLoopForward, duration);
    	dutyCycleTimer.begin(dutyCycleLoopForward, duration * dutyCycle);
    }
    and the dutyCycleTimer.begin(...) in the motorLoop.

  4. #4
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    578
    I don't see your static variable "instance" defined in your cpp file. If it isn't defined in some other place you need to add

    Code:
    Tekceleo* Tekceleo::instance = nullptr;
    to your cpp file.

    See also
    https://stackoverflow.com/questions/...les-in-c-class

  5. #5
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    5,750
    Quick notes, suggestions...

    In cases like this, it might actually help us to give suggestions, when you are a bit more exact information. Like what is not working? How do you know? ISR not called? your motor did not work? ... Again we can only guess what the problem might be.

    I agree with @defragster - that doing stuff in constructors can be an issue. You have no control on when the call might be done, and potentially system code to intialize hardware and the like, may not be done yet. So personally I prefer to keep the constructors simple and simply save away stuff, and let an init/begin method do the main stuff like touch hardware...

    I could not tell from your title if you were sub-classing IntervalTimer or just using it in your class. Which is the later...

    Debug... Is your Interval timer function(s) being called?

    The first thing I would do is to add simple code to your ISRs, that either toggle an IO pin (like 13) or do a simple Serial.println("ISR X called");
    plus the appropriate setup code (pinMode, Serial.begin()...) and see if they are called?

    Note: if I were doing it, I would probably, setup a pin for each ISR, and add code like:
    digitalWrite(13, !digitalWrite13));

    And setup my Logic Analyzer on pin 13 and see if it is called or not and how fast... But without LA, with LED you should hopefully see the LED light blink on/off... If real fast than it should be some dim value of light...

    If this works, then I would probably move the blink code or Serial.print() code into your work function, and make sure it is called...

    If things are not correct, I would probably also sprinkle Serial.print statements in different places to get an idea of are the values what I think they are...
    Example in your ::start method, probably print out values like duration, dutyCycle...

    Good Luck

  6. #6
    Junior Member
    Join Date
    Aug 2019
    Posts
    8
    The main problem was just the compiling, it did not compile so absolutely no chance for any hardware issues ;-) Compiler moaned about non-static function used in the two IntervalTimers.

    With the added code by luni it does compile and can be uploaded to the Teensy.

    Right now, it still does not work, but my main problem (and problem for this thread) is gone, now I'm on the next ones. I'll keep coming back if I'm also helpless on them in a couple of days.

    Thank you all!

  7. #7
    Junior Member
    Join Date
    Aug 2019
    Posts
    8
    Well, I'm back again. The code compiles fine and actually does move the motor, but still not the way I want it to. I did not get to the part where the IntervalTimer comes into play, so no idea if that works how it should.
    Heading into the code and blasting the USB Serial to see where it stops, enabling the FTM2 Timer Interrupt puts the teensy to a halt.
    I put the Quadrature Decoder "back" into a sub-subclass of the Tekceleo-Motorsubclass so basically nothing fundamentally changed from the formerly running program, now instead of being an object of the main .ino it is an object of the Tekceleo-subclass. And suddenly the code snippet where it turns on the interrupt routine halts it.

    It does not matter where the snippet is enabled (from my understanding it could be wherever as long as it happens before the interrupts), either the Decoder-class or the Tekceleo-class or even in the main program, as soon as the code comes to it, the teensy does not go any further.

    The snippet is
    Code:
    NVIC_ENABLE_IRQ(IRQ_FTM2);
    I found something about having a c++ Class but needing c-Format. But it worked beforehand? The oldest problem in coding ;-)


    Main Program
    Code:
    #include "Tekceleo.h"
    
    
    
    Tekceleo tekceleo;
      
    void setup() {
      tone(2, 2000, 200);
    
      Serial.begin(115200); 
      delay(1000);
    
      tone(2, 400, 200);
      delay(200);
      tone(2, 800, 200);
      delay(200);
      tone(2, 2000, 200);
      Serial.println("Start");
      Serial.println("MAIN PROGRAMM VOR NVIC ENABLE");
      NVIC_ENABLE_IRQ(IRQ_FTM2);
      Serial.println("MAIN PROGRAMM NACH NVIC ENABLE");
      delay(2000);
      tone(2, 400, 200);
      delay(200);
      tone(2, 800, 200);
      delay(200);
      tone(2, 2000, 200);
      delay(5000);
      tekceleo.start(20);
    
    }
    
     
    void loop() {
    
    }
    Class QuadDecoder
    Code:
    #ifndef QUADDECODE_H
    #define QUADDECODE_H
    
    #include <stdint.h>
    #include "mk20dx128.h"
    #include "core_pins.h"
    
    /*
    * - MAGIE - 
    * https://forum.pjrc.com/threads/26803-Hardware-Quadrature-Code-for-Teensy-3-x?p=90774&viewfull=1#post90774
    */
    
    class QuadDecode_t {
      public:
        QuadDecode_t() {
        	Serial.begin(115200);
          // Pin Assignments
    
          // FTM2 Pins
          // K20 pin 41,42
          // Bit 8-10 is Alt Assignment
          PORTB_PCR18 = 0x00000612;   //Alt6-QD_FTM2,FilterEnable,Pulldown
          PORTB_PCR19 = 0x00000612;   //Alt6-QD_FTM2,FilterEnable,Pulldown
    
          //Set FTMEN to be able to write registers
          FTM2_MODE=0x04;	    // Write protect disable - reset value
          FTM2_MODE=0x05;	    // Set FTM Enable
    
          // Set registers written in pins_teensy.c back to default
          FTM2_CNT = 0;
          FTM2_MOD = 0;
          FTM2_C0SC =0;
          FTM2_C1SC =0;
          Serial.println("Vor Heardware Trgiger");
          FTM2_SC = 0x40;     //enable hardware trigger
          Serial.println("Nach Hardware Trgiger");
          FTM2_FILTER=0x22;	// 2x4 clock filters on both channels
          FTM2_CNTIN=0;
          FTM2_MOD=10;	    // Maximum value of counter
          FTM2_CNT=0;	    	// Updates counter with CNTIN
          Serial.println("Bevor QUAD ENABLE");
          FTM2_QDCTRL=0b11000111;	    // Quadrature control
          //        Filter enabled, QUADEN set
          Serial.println("Nach QUAD ENABLE");
          // Write Protect Enable
          FTM2_FMS=0x40;		// Write Protect, WPDIS=1
    
          Serial.println("VOR INTERRUPT ENABLE");
          //NVIC_ENABLE_IRQ(IRQ_FTM2);         //THIS IS WHERE THE SNIPPET WAS ORIGINALLY
          Serial.println("decoder setup finished");
        }
    
        void setCounter2( int16_t c ) {
          FTM2_CNT = c;
        }
    
        int16_t getCounter2( ) {
          int16_t c = FTM2_CNT;
    
          return c;
        }
    
        void setMOD(int newMOD){
        	noInterrupts();
        	FTM2_MOD = newMOD;
        	FTM2_CNT = 0;
        	FTM2_PWMLOAD = 0x200;
        	interrupts();
        }
    
    
    };
    
    
    
    #endif
    Tekceleo class (only relevant parts
    Code:
    #include "Tekceleo.h"
    #include <stdint.h>
    #include "mk20dx128.h"
    #include "core_pins.h"
    #include "AD9837.h"
    #include <cmath>
    #include "QuadDecode.h"
    
    Tekceleo::Tekceleo() : ad9837(48000), QuadDecode()
    {
    	Serial.begin(115200);
    	Serial.println("Tekceleo Start");
    	Tekceleo::instance = this;
    	pin_motor_direction = 9;
    	pin_test = 20;
    	pin_PPen = 17;
    	tone(2, 2000, 200);
    	
        // TURN OFF PUSH PULL CONVERTER
    	pinMode(pin_PPen,OUTPUT);
    	digitalWrite(pin_PPen, LOW);
    
    	pinMode(pin_test, OUTPUT);
    	digitalWrite(pin_test, LOW);
    
      // SETUP MOTOR DIRECTION
    	pinMode(pin_motor_direction,OUTPUT); // set TOGGLE to OUTPUT
    	digitalWrite(pin_motor_direction, LOW);  // set high for one motor direction
    
    	dutyCycle = 0.25;
    
    	startfrequency = 48000;
    	minfrequency = 42000;
    	frequency = startfrequency;
    	cts = 0;
    	duration = 0;
    	flowrate = 0;
    	initialfrequency = startfrequency;
    	ad9837.setfrequency(startfrequency * 4);
    	Serial.println("Tekceleo vor Enable Interrupt");
    	//NVIC_ENABLE_IRQ(IRQ_FTM2);
    	Serial.println("Tekceleo nach Enable Interrupt");
    	//findInitialFrequency();
    	tone(2, 2000, 200);
    	Serial.println("Tekceleo constructor Ende");
    }

  8. #8
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    578
    Would be easier to help if you could generate a minimal example which shows the error and can be compiled without hardware / libraries.

    Generally:
    I'd try to avoid hardware access in a constructor. If, as in your sketch, you declare the class in global space there is no guarantee exactly when it will be called (relative to other global objects). Might as well be called before the peripherals are even up and running. Or the code from some other setup routines overwrites your register settings because it is called later... Better move that code into a "begin" member function and call it from setup() or make sure to initiate your object from setup();

  9. #9
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    578
    BTW: Maybe I didn't spot it but where is your IRQ_FTM2 handler?

  10. #10
    Junior Member
    Join Date
    Aug 2019
    Posts
    8
    The IRQ_FTM2 handler is further down in the Tekceleo class:

    Code:
    void Tekceleo::ftm2_isr(void)
    {
    	if((FTM2_SC & FTM_SC_TOF) != 0){
    		FTM2_SC &= ~FTM_SC_TOF;
    	}
    	digitalWrite(pin_PPen, LOW);
    	motorTurning = true;
    
    	digitalWrite(pin_test, LOW);
    }

    Generally:
    I'd try to avoid hardware access in a constructor. If, as in your sketch, you declare the class in global space there is no guarantee exactly when it will be called (relative to other global objects). Might as well be called before the peripherals are even up and running. Or the code from some other setup routines overwrites your register settings because it is called later... Better move that code into a "begin" member function and call it from setup() or make sure to initiate your object from setup();
    Part of the reason for doing this is because i have not found another way of initializing the objects when I want them to, because they are initialized right away (see: Tekceleo::Tekceleo() : ad9837(48000), QuadDecode()). Putting them into setup would give no access to them outside of setup(), i think?

    I know the code is not very beautiful and not easy to get, especially since I've been looking and working at it for quite some time now. Basic idea was just putting the motor and everything into a class and out of the main program, then right now i'm just at that point to get it functional again and then cleaning up the code.

    Thanks for your help!

  11. #11
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    578
    The IRQ_FTM2 handler is further down in the Tekceleo class:
    Just wondering why that would be called? Where do you assign that function to the actual IRQ_FTM2 called by the NVIC?

    Part of the reason for doing this is because i have not found another way of initializing the objects when I want them to, because they are initialized right away (see: Tekceleo::Tekceleo() : ad9837(48000), QuadDecode()). Putting them into setup would give no access to them outside of setup(), i think?
    Code:
    Tekceleo* tekceleo;
    
    void setup() 
    {
      ...
      tekceleo = new Tekceleo();
      ...
    }
    Basic idea was just putting the motor and everything into a class and out of the main program, then right now i'm just at that point to get it functional again and then cleaning up the code.
    I'd do it the other way round :-). I really recommend to do a quick test program without all the details. Just try to get the FTM working in a separate class. When you found out how this is working you can add the other stuff. Sometimes a detour takes you faster to your destination...

  12. #12
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    5,750
    Also when I mention not putting code into constructor, but instead into setup (sort of paraphrased), I am not implying you need to as @luni mentioned (which is fine),

    but instead maybe reorganize the code slightly....
    Example your first class above:
    #ifndef QUADDECODE_H
    #define QUADDECODE_H

    #include <stdint.h>
    #include "mk20dx128.h"
    #include "core_pins.h"

    /*
    * - MAGIE -
    * https://forum.pjrc.com/threads/26803...ll=1#post90774
    */

    Code:
    class QuadDecode_t {
      public:
        QuadDecode_t() {}
    
        void begin() {
        	Serial.begin(115200);
          // Pin Assignments
    
          // FTM2 Pins
          // K20 pin 41,42
          // Bit 8-10 is Alt Assignment
          PORTB_PCR18 = 0x00000612;   //Alt6-QD_FTM2,FilterEnable,Pulldown
          PORTB_PCR19 = 0x00000612;   //Alt6-QD_FTM2,FilterEnable,Pulldown
    
          //Set FTMEN to be able to write registers
          FTM2_MODE=0x04;	    // Write protect disable - reset value
          FTM2_MODE=0x05;	    // Set FTM Enable
    
          // Set registers written in pins_teensy.c back to default
          FTM2_CNT = 0;
          FTM2_MOD = 0;
          FTM2_C0SC =0;
          FTM2_C1SC =0;
          Serial.println("Vor Heardware Trgiger");
          FTM2_SC = 0x40;     //enable hardware trigger
          Serial.println("Nach Hardware Trgiger");
          FTM2_FILTER=0x22;	// 2x4 clock filters on both channels
          FTM2_CNTIN=0;
          FTM2_MOD=10;	    // Maximum value of counter
          FTM2_CNT=0;	    	// Updates counter with CNTIN
          Serial.println("Bevor QUAD ENABLE");
          FTM2_QDCTRL=0b11000111;	    // Quadrature control
          //        Filter enabled, QUADEN set
          Serial.println("Nach QUAD ENABLE");
          // Write Protect Enable
          FTM2_FMS=0x40;		// Write Protect, WPDIS=1
    
          Serial.println("VOR INTERRUPT ENABLE");
          //NVIC_ENABLE_IRQ(IRQ_FTM2);         //THIS IS WHERE THE SNIPPET WAS ORIGINALLY
          Serial.println("decoder setup finished");
        }
    
        void setCounter2( int16_t c ) {
          FTM2_CNT = c;
        }
    
        int16_t getCounter2( ) {
          int16_t c = FTM2_CNT;
    
          return c;
        }
    
        void setMOD(int newMOD){
        	noInterrupts();
        	FTM2_MOD = newMOD;
        	FTM2_CNT = 0;
        	FTM2_PWMLOAD = 0x200;
        	interrupts();
        }
    
    
    };
    
    #endif
    likewise for your Tekceleo class.
    Code:
    #include "Tekceleo.h"
    #include <stdint.h>
    #include "mk20dx128.h"
    #include "core_pins.h"
    #include "AD9837.h"
    #include <cmath>
    #include "QuadDecode.h"
    
    Tekceleo::Tekceleo() : ad9837(48000), QuadDecode() {}
    
    void Tekceleo::begin() 
    {
            Q
    	Serial.begin(115200);
    	Serial.println("Tekceleo Start");
    	Tekceleo::instance = this;
    	pin_motor_direction = 9;
    	pin_test = 20;
    	pin_PPen = 17;
    	tone(2, 2000, 200);
    	
        // TURN OFF PUSH PULL CONVERTER
    	pinMode(pin_PPen,OUTPUT);
    	digitalWrite(pin_PPen, LOW);
    
    	pinMode(pin_test, OUTPUT);
    	digitalWrite(pin_test, LOW);
    
      // SETUP MOTOR DIRECTION
    	pinMode(pin_motor_direction,OUTPUT); // set TOGGLE to OUTPUT
    	digitalWrite(pin_motor_direction, LOW);  // set high for one motor direction
    
    	dutyCycle = 0.25;
    
    	startfrequency = 48000;
    	minfrequency = 42000;
    	frequency = startfrequency;
    	cts = 0;
    	duration = 0;
    	flowrate = 0;
    	initialfrequency = startfrequency;
    	ad9837.setfrequency(startfrequency * 4);
    	Serial.println("Tekceleo vor Enable Interrupt");
    	//NVIC_ENABLE_IRQ(IRQ_FTM2);
    	Serial.println("Tekceleo nach Enable Interrupt");
    	//findInitialFrequency();
    	tone(2, 2000, 200);
    	Serial.println("Tekceleo constructor Ende");
    }
    Then you can continue to have your class defined global like you had...

    But in your main sketch sketch function, you would add a call to
    Code:
    tekceleo.begin();
    Obviously you could choose different names... And I typed this on fly so, probably typos...

Posting Permissions

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