Help with PWM & Interrupts on Teensy 3.0

Status
Not open for further replies.

Jp3141

Well-known member
I am trying to build a system which needs to generate a variable duty cycle PWM signal at about 125 kHz (this is a digital signal, not an analog output). I also need to measure the time between one edge of the PWM and another input signal (in the few microseconds range). I have trouble getting started -- how to configure the PWM, and how to setup interrupts.

Basically I need:
A digital output pin with PWM at a frequency of about 125 kHz (variable from ~ 100 to ~ 150 kHz) which can vary duty cycle from ~ 10 % (e.g. on for 1 us) to ~ 50 % (4 us on). I need duty cycle variable with fine resolution (1 % = 100 ns).
A digital input pin that triggers and interrupt upon a change (falling edge) and indicates the time interval between this input and the previous PWM edge.

I have difficulty getting started on this; I think all I need is some example code that I can massage to meet my needs. I would prefer something that is self-contained (i.e. not using additional complex libraries), but at this point, anything would be helpful.

Can anyone point to some T3 samples/examples ?

Thanks
JP
 
The 125 kHz is the easy part. Use analogWriteFrequency(pin, 125000).

Measuring the elapsed time probably requires using a timer in input capture mode. There's not yet any example code for that on Teensy 3.0, so you'll have to work with the hardware directly.
 
The 125 kHz is the easy part. Use analogWriteFrequency(pin, 125000).

Measuring the elapsed time probably requires using a timer in input capture mode. There's not yet any example code for that on Teensy 3.0, so you'll have to work with the hardware directly.

That works great Paul (providing I use the correct pins for PWM !). I use analogWrite(PWMpin, value-0..255) to generate the duty cycles I need.

I could measure the time delay between edges by using two interrupts (perhaps I need to connect another digital pin to the PWM one to get interrupts on _that_ signal) -- one triggered on the PWM falling edge, and the other triggered on the external falling edge.

Is there a high resolution (better than 1 MHz) internal MCU free-running counter available ? i.e. if I set an program variable to 0 on each PWM falling interrupt and read that counter on the external edge interrupt, I will be in great shape.

Edit -- I found it -- there's a SysTick register as part of ARM CPUs which clocks at 48 MHz

#define SYST_CVR *(volatile uint32_t *)0xE000E018 // SysTick Current Value Register

Then tying the PWM output to pin 1 and generating an interrupt on pin 1 falling and reading SYST_CVR
Then generating an interrupt on pin 0 falling and reading the difference between the current SYSTE_CVR and previous



#define LEDPin 13
#define INT_Pin0 0 // interrupt on #0
#define INT_Pin1 1 // interrupt on #1
#define PWMPin 3 // Used as variable frequency, variable D% PWM
volatile long int count = 0; // interrupt counter
volatile long int PWM_SYST = 0; // Store SYST_CVR
volatile long int PWM_Delay = 0; // measure delay
volatile long int PWM_Delays = 0; // measure delay
int loop_num = 0; // loop counter
int iLastTime=0;
int junk = 1;
#define SYST_CVR *(volatile uint32_t *)0xE000E018 // SysTick Current Value Register


int unsigned long SYSCount[4];

// ISR for measuring delay -- atached to pin 0
void counterloop() {
PWM_Delay = PWM_SYST - SYST_CVR; // SYST_CVR counts down
PWM_Delays += PWM_Delay; // total delays -- used in averaging
count++;
}

// ISR for starting delay measurement -- attached to pin 1
void counterReset() {
PWM_SYST=SYST_CVR;
digitalWriteFast(LEDPin, HIGH);
}

void setup() {
Serial.begin(115200);
pinMode(LEDPin, OUTPUT);
pinMode(INT_Pin0, INPUT);
pinMode(INT_Pin1, INPUT);
attachInterrupt(INT_Pin0, counterloop, FALLING);
attachInterrupt(INT_Pin1, counterReset, FALLING);
pinMode(PWMPin, OUTPUT);
analogWriteFrequency(PWMPin, 12500);
analogWrite(PWMPin, 127);
}

void loop() {
long int wasteCounter = 0;
Serial.print("count ="); Serial.print(count);
Serial.print(" delay = "); Serial.print(PWM_Delay);
Serial.print(" average = "); Serial.print((float)PWM_Delays/count);
count = 0; PWM_Delays=0;
// toggle the LED
if (loop_num % 2) {digitalWrite(LEDPin, LOW); } else { digitalWrite(LEDPin, HIGH); }
loop_num++;
Serial.print(" loop:"); Serial.println(loop_num);
do {wasteCounter++;} while (millis()/1000==iLastTime); iLastTime = millis()/1000; // Wait for a whole 1 s
Serial.println(wasteCounter); // interrupt processing takes a lot of time; this indicates the spare available
}
 
Last edited:
I recently started using the Teensy 3.0 and it is a great little board. I also needed to keep track of time intervals between pulses for my application. I had always done this with input capture on AVRs so I wanted to try it on the Teensy and I think I figured it out. I have some sample code here on my website: http://www.digitalmisery.com/2013/06/timer-input-capture-on-teensy-3-0/ Please take a look and let me know if you think there is a better way to configure things. There are so many options on that M4 that it can be a little overwhelming.
 
I recently started using the Teensy 3.0 and it is a great little board. I also needed to keep track of time intervals between pulses for my application. I had always done this with input capture on AVRs so I wanted to try it on the Teensy and I think I figured it out. I have some sample code here on my website: http://www.digitalmisery.com/2013/06/timer-input-capture-on-teensy-3-0/ Please take a look and let me know if you think there is a better way to configure things. There are so many options on that M4 that it can be a little overwhelming.

Thanks digitalmisery!
I m really happy to know how you wirte that code. That is waht I m looking for.
One question. In the documentation I cannot find which pins on the board could be used for which Flex Timers. Figure 35-1 on page 691 is too much general.
Could you give me some hits!?!

Thanks again!
Regards
 
Status
Not open for further replies.
Back
Top