PWM Frequency (was: TimerOne on Teensy 3)

Status
Not open for further replies.

sam

Active member
This Teensy is great!! Thanks for all the hard work Paul!

Is there currently a way to alter the PWM frequency without setting up a timer interrupt? I used TimerOne on my Uno, though I can't get it to work on the Teensy 3. I'm using PWM to drive an LED in a guitar pedal so I have to get it over 20kHz. Right now I'm using beta7. I will set up an ISR if needed, though if there is a simpler method like TimerOne, or if it will be supported soon, that would be helpful.
 
Alright... the lack of responses leads me to believe one thing... time to jump into some interrupts! :)
 
Actually, I've been considering adding a function to set the PWM frequency. It's being discussed today on the Arduino developers mail list, hopefully to agree on the name and parameters, Teensy and Arduino can be compatible when/if they also add it.
 
That would be great if they added it. TimerOne is so flexible and easy to use, I'd love to see it come standard.
 
Re-posting as suggested. Many of our motor drivers (combat robots) require a PWM pulse of 32Khz and some older ones use 20Khz and hence the requirement. Sometimes we run different motors on the same robot. The Arduino playground turned up with some simple way of setting PWM frequencies -
http://arduino.cc/playground/Code/PwmFrequency

and this: http://arduino.cc/forum/index.php/topic,117425.0.html

But I'm not sure if this can be used within the Teensy 3 environment. Given the additional number of pins available for PWM, a library would be extremely useful to have if someone has adapted this. In any case, what is the simplest way to set pin (5 or 6) to 32Khz ?
 
Last edited:
I started a discussion on the Arduino developer list 6 days ago, regarding this feature and (hopefully) agreeing on a common definition when/if Arduino adds it, so code can be compatible between Teensy and regular Arduino.

Since then, a huge amount of discussion has happened, with all sorts of ideas posted. I'm still holding out hope there may be some agreement to standardize this function, and I'm hoping in the future to collaborate more with the Arduino team so new features are compatible for sharing code between Teensy and Arduino.

However, yesterday... after 5 days of wandering discussion, I finally posted this message:

http://arduino.cc/pipermail/developers_arduino.cc/2012-November/007333.html

I'm going to work on "analogWriteFrequency" this weekend or early next week. I'll post updates on this thread as I have something for you, and as the situation with collaborating with Arduino develops.
 
Last edited:
request for functionality, followed by wide ranging and ultimately endless conversation, followed by a concrete and well documented suggestion, followed by implementation. Sounds like a familiar standardization pattern.

Reporting on either sucesses or problems, on user feedback, and a second developer saying they implemented the same thing 'for compatibility' are the usual next steps :)
 
request for functionality, followed by wide ranging and ultimately endless conversation, followed by a concrete and well documented suggestion, followed by implementation. Sounds like a familiar standardization pattern.

Reporting on either sucesses or problems, on user feedback, and a second developer saying they implemented the same thing 'for compatibility' are the usual next steps :)

What is the point of your post ? It offers no value to anyone seeking help here.
 
If you don't value coordination and communication in the wider Arduino community then I guess it would have no value to you, no. Edit: Those things do have value to me, though.

A desire for interoperable solutions can often be blocked by some well-known anti-patterns; equally, there are techniques to counter that. Hence my post. I agree that its a divergence from 'Project guidance'. If I had been starting a new thread it would probably have best been in 'General discussion'. I posted here as it was a direct response to Paul's comment.
 
Last edited:
I personally find the Arduino developers mail list frustrating. It seems like "wide ranging and ultimately endless conversation" is more common than any of those other steps... especially the implementation part. Limor Fried (aka "Lady Ada") recently called it "bikeshedding". I love that term. ;)

http://www.urbandictionary.com/define.php?term=bikeshedding

I suspect the point of the message above was cynical humor, but with impersonal text-only communication it's always hard to tell for sure. Let's not get nasty here, ok?

Yesterday I took a break from USB stuff and worked on improving analogRead speed. This morning I'm going to look into analogWriteRes and analogWriteFrequency. Will update here soon....
 
I personally find the Arduino developers mail list frustrating. It seems like "wide ranging and ultimately endless conversation" is more common than any of those other steps... especially the implementation part.

Yup. That pattern is familiar to me from other standardization efforts. There are ways to un-deadlock it though, hence my comment.

Limor Fried (aka "Lady Ada") recently called it "bikeshedding". I love that term. ;)

http://www.urbandictionary.com/define.php?term=bikeshedding
Yup. :rolleyes: Another one is 'boiling the ocean' aka solving all the world's problems as a prerequisite for solving the original one.

I suspect the point of the message above was cynical humor, but with impersonal text-only communication it's always hard to tell for sure.
Sorry if it came over as sarcasm; that wasn't the intent at all. It was actually an honest suggestion on how to get forward momentum again on the specific problem.

Let's not get nasty here, ok?
Agreed; edited my response.
 
Here is a copy of my work-in-progress code. It has my first attempt at analogWriteResolution() and analogWriteFrequency(). It also has speedups to analogRead(), USB mouse (probably working) and USB joystick (probably not working).

http://www.pjrc.com/teensy/beta/teensy3_24nov12.zip

To use this, just replace your hardware/teensy/cores/teensy3 folder with the contents of this zip file.

Please report any bugs... think "reproducible bug report" ;)
 
Using the Examples/Basics/Fade sketch, without calling analogWriteFrequency(), it seems to change default PWM frequency from 1.8 kHz to 490 Hz. Using the code below, I do indeed see a PWM frequency of 32 kHz as expected, and the PWM frequency remains the same at all three T3 clock settings (24,48,96 MHz). Nice work!

I also tried setting higher frequencies: up to 2 MHz it still looks reasonable. At 10 MHz there are such big quantization errors that I get only about 3 distinct frequencies, which are actually around 11 or 12 MHz, but obviously that's pushing it with only a 48 MHz system clock.

Code:
// Test Teensy 3 (Ard 1.0.2 Beta 8) using Paul's new alpha PWM code, Nov. 27 2012
int ledPin = 9;    // LED connected to digital pin 9

void setup(){
  analogWriteFrequency(ledPin, 32000);  // set PWM frequency (pin, Hz)
}

void loop()  { 
  for(int fadeValue = 0 ; fadeValue <= 255; fadeValue +=5) { 
    analogWrite(ledPin, fadeValue);         
    delay(30);                            
  } 
  for(int fadeValue = 255 ; fadeValue >= 0; fadeValue -=5) { 
    analogWrite(ledPin, fadeValue);         
    delay(30);                            
  } 
}
 
Last edited:
I see that the T3 has 10 PWM output pins, and I confirmed that the PWM values can be controlled independently on each pin. However from trying the below code, I see it will only generate two different base frequencies at once; setting a third frequency also changes one or both of the first two. I presume there are only two clock generators available. Also, it seems the pins work in pairs, so pins 3 and 4 are always working at the same frequency, pins 5 & 6, etc.

Code:
#define STEP 10    // pwm value ramp step size
#define NPINS 10
int pins[10] = {3,4,5,6,9,10,20,21,22,23};  // PWM pins on Teensy 3
int freq[10] = {262,294,330,349,392,440,494,523,587,659}; // whole tones

void setup(){
  for (int i=0;i<NPINS;i++) {
    analogWriteFrequency(pins[i], freq[i]);  // set PWM frequency (pin, Hz)
  }
} // end setup()

void loop()  { 
 for (int i=0;i<NPINS;i++) {
  for(int fadeValue = 0 ; fadeValue <= 255; fadeValue +=STEP) { 
    analogWrite(pins[i], fadeValue);         
    delay(30);                            
  } 

  for(int fadeValue = 255 ; fadeValue >= 0; fadeValue -=STEP) { 
    analogWrite(pins[i], fadeValue);         
    delay(30);                            
  } 
  
 } // for (i..)
} // end loop()
 
Last edited:
Actually, the new Nov.27 version does not seem to work as before. The below code was working earlier today to set the PWM frequency on pin 9 to 32 kHz, but now it stays at the default value of 490 Hz.
To confirm, I swapped back to the previous teensy/cores/teensy3 folder (from Nov.24 zip file) and it worked again.

Code:
// Test Teensy 3 (Ard 1.0.2 Beta 8) using Paul's new alpha PWM code, Nov. 27 2012
int ledPin = 9;    // LED connected to digital pin 9

void setup(){
  analogWriteFrequency(ledPin, 32000);  // set PWM frequency (pin, Hz)
}

void loop()  { 
  for(int fadeValue = 0 ; fadeValue <= 255; fadeValue +=5) { 
    analogWrite(ledPin, fadeValue);         
    delay(30);                            
  } 
  for(int fadeValue = 255 ; fadeValue >= 0; fadeValue -=5) { 
    analogWrite(ledPin, fadeValue);         
    delay(30);                            
  } 
}

Looks like, in addition to commenting out the print statements, also this changed in pins_teensy.c at analogWriteFrequency():
Code:
	if (pin == 3 || pin == 4) {
		FTM1_SC = 0;
		FTM1_CNT = 0;
		FTM1_MOD = mod;
		FTM1_SC = FTM_SC_CLKS(1) | FTM_SC_PS(prescale);
	} else if (pin == 5 || pin == 6 || pin == 10 || pin == 11 ||
	  (pin >= 20 && pin <= 23)) {
		FTM0_SC = 0;
		FTM0_CNT = 0;
		FTM0_MOD = mod;
		FTM0_SC = FTM_SC_CLKS(1) | FTM_SC_PS(prescale);
	}
}


...because in the previous Nov.24 version that does set PWM frequency on pin 9, it looked like this:
Code:
	if (pin == 3 || pin == 4) {
		FTM1_SC = 0;
		FTM1_CNT = 0;
		FTM1_MOD = mod;
		FTM1_SC = FTM_SC_CLKS(1) | FTM_SC_PS(prescale);
	} else {
		FTM0_SC = 0;
		FTM0_CNT = 0;
		FTM0_MOD = mod;
		FTM0_SC = FTM_SC_CLKS(1) | FTM_SC_PS(prescale);
	}
}

Is it a typo to be including pin 11 and neglecting pin 9? According to my Teensy 3 pinout card, pin 11 is not a PWM pin. By pure chance, my test program used the one pin (#9) that the new Nov.27 code does not enable frequency selection for.
 
Last edited:
Have to get my scope out and test this coming weekend with the ultrasonic motor drivers. Looks very promising indeed....
 
Last edited:
Opps, sorry. I see what went wrong. I added a check to make sure the pin number was valid, but the check is incorrect. It's looking for pin 11 instead of 9. I've updated the code. I'm going to work on the joystick code today and hopefully make a beta release this weeks when I get it working.

Though perhaps somewhat off-topic, maybe this is a good moment to mention a sneak-peek at something I've been working on the last couple days. It's a circuit board (actually a stack of circuit boards) intended to someday allow me to build fully automated regression testing for Teensy. I just sent the first PCB attempt to iTead yesterday. Here's what it looks like:

t_regresstest.png

This is actually a few different designs on a single board, depending on which parts are soldered. They're meant to stack on top of each other, with a 40 pin ribbon cable forming a bus between them. The top board has just a Teensy 2.0 and that little power supply part in the upper left. It's the master control board that configures up to 8 slave boards which actually run the regression tests. Each slave board is meant to have one Teensy, either a 2.0, ++2.0 or 3.0 (but only 1 per PCB). The master is able to pulse the PROG/RST pin on the Teensy on any slave board, so I can make a script which controls which slave board gets reprogrammed. Those big square chips are bidirectional crosspoint switch chips which allow any combination all 46 pins to connect to any combination of 16 bus lines that connect to all boards. So I can have the master controller connect any pins together on any Teensy, or any combination of pins from any other Teensy on any board, with the limitation only up to 16 total signals (I considered more, but those chips are spendy and I can easily work within the scope of 16 signals and just break large tests into multiple pieces).

At least that's the idea. Right now it's just a grand idea and a design file I sent off to make the first attempt at a PCB.

Software-wise, years ago, Mark Sproul and Rick Anderson did a lot of work to make an Arduino Test Suite. I contributed code. I've exchanged emails with them recently about this effort. They intended to do something similar (perhaps not with extravagant crosspoint switches) with a set of Arduino boards connected to a server to automatically test the Arduino software. Many of the tests are already written and much of the framework for doing this is already in place.

Eventually this system is going to let me write functionality tests. Most of Mark and Rick's work was using a single board at a time, but this way will let me design automated tests using 2 or more boards. For analogWriteFrequency, I'll probably build a test where one board runs a sketch that outputs several different frequencies and perhaps the signal will be routed to another board running the FreqMeasure or FreqCounter library, to check the frequency is correct. The test would them repeat for each PWM capable pin.
 
Last edited:
Fascinating. Battle testing will certainly yield a superior product. There is no substitute (yet) for hard core regression testing.

Cheers.
 
Nice looking test fixture. But "...been working on the last couple of days..." !? I want to know how one person gets so much done. We need someone like you at our company. Then the rest of the engineers could go home :)

On the other hand, don't accept any job offers, because you're doing great stuff with Teensys!
 
Status
Not open for further replies.
Back
Top