PDA

View Full Version : Help with PWM & Interrupts on Teensy 3.0



Jp3141
01-13-2013, 06:18 PM
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

PaulStoffregen
01-13-2013, 06:54 PM
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.

Jp3141
01-13-2013, 08:34 PM
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
}

digitalmisery
06-21-2013, 01:14 PM
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.

dave
08-01-2013, 11:13 PM
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