Teensy 4.1 for PWM Input, Ethernet, UART, and CAN Network?


Hi Everyone!

TLDR: Does anyone have experience using the PWM pins to read PWM signals from a hobby PWM transceiver? Can this be done with the Teensy?

For a more complete background, I'm working to setup a microcontroller to process control messages from different sources, namely PWM, Ethernet, UART (Serial), Wifi, or another CAN Network. At the moment, I've been able to get this started with an STM32F4 Discovery Kit, and we have proven we can configure a single MPU board to process all the various inputs based using basic manual calibration. Now, before committing to developing our own PCB, we are looking for another dev board with a smaller form factor.

While I was hoping to continue to use something with the STM32xx family of MPUs, the Teensy still seems to be to good of an option to overlook, especially because we could just the Arduino IDE. With different connectors it seems like we could configure it for all of our requirements:

UART - no connector required
Ethernet - https://www.pjrc.com/store/ethernet_kit.html
Wireless - Any ESP32 Module or board.
CAN - just need the terminals (https://www.adafruit.com/product/57...ZD5D7Ux4cSylit9OU-5xo58IZZmm82AwaAj4iEALw_wcB)

It is clear that we can transmit PWM signals using our choice of 35 pins, but the one final unknown is how well it can read PWM inputs. Does anyone have experience using the PWM pins to read PWM signals from a hobby PWM transceiver? Can this be done with the Teensy?

Many of those transmitters send several PWM signals using PPM (pulse position modulation). This site has a good explanation.

The PulsePosition library on Teensy lets you read the PPM signal directly and recover all its encoded PWM signals. PulsePosition can also create PPM signals.

Thanks Paul.

We are using FR-Sky transceivers. Based on our experience working with other DevBoards and plugging the transceivers directly into motor controllers, we are certain we are working with PWM signals. In fact, from my experience with the STM32F4 Discovery board, I also know that we are working with hobby PWM signals and not industrial PWM, meaning the signal value is is determined by the width of the pulses rather than the duty cycle of the pulses.

Can the Teensy process PWM signals? I'd rather not need to convert the PWM signals to PPM.

Capturing PWM signals on Teensy is very easy. Below is sample code.

int interrupt_pin = 10;
uint32_t pwm_start;
uint32_t pwm_width;
bool pwm_data_ready = false;

void pwm_isr();

void setup()
    attachInterrupt(interrupt_pin, pwm_isr, CHANGE);

void loop()
    if(pwm_data_ready == true)
        pwm_data_ready = false;

void pwm_isr()
    if(digitalRead(interrupt_pin) == HIGH)
        pwm_start = millis();
        pwm_width = millis() - pwm_start;
        pwm_data_ready = true;
You can also measure the period of one or many signals directly in hardware with Paul's FreqMeasureMulti library. FlexPWM timers are used to do the measurements, and the associated ISR writes the period value to queue that can be read from your loop() function.
I appreciate all of your input! I was able to basically use the code above to get everything running!

However, when using the interrupts to measure pulse width, or even when just using the pulseIn() function, I get little spikes in the signal.

Screenshot 2023-11-30 at 11.10.15 AM.png

It seems to only be fluctuating by 1 microsecond. Do you have any recommendations for how to filter out these spikes in a very uniform way? I'm going to have several of these controllers interpreting different channels of signal at the same time and I need to ensure they all act the same way.
If you are using the code from msg #4, try using the FreqMeasureMulti library instead. FreqMeasureMulti will provide much better accuracy because the period measurement is done in hardware, not in the ISR (software) of msg #4.
Sounds good! Based on the README, it sounds like the FreqMeasureMulti library would be perfect if I could get it up and running. However, I'm having a little bit of trouble getting even a basic script going. It seems to stop working when I use the read() function.

#include <FreqMeasureMulti.h>

FreqMeasureMulti freq;

#define PWM_IN 9

int frequency;

void setup() {
  Serial.println("Starting Measurement...");
  freq.begin(PWM_IN, MEASURE_TYPE);

void loop() {
  // put your main code here, to run repeatedly:
     // print measured value
    frequency = freq.read();
     // or not
    Serial.println("No Signal Found");

If I replace the freq.read() with freq.available() or freq.readLevel(), the functions enters the if statement and prints a value (23 for available and 0 for level). However, with the freq.read(), the loop goes to the "No Signal Found" clause. Am I calling the read() function correctly?

I haven't changed the connections on my board and my original script still runs.
Pin 9 should be okay. Try using FREQMEASUREMULTI_RAISING as MEASURE_TYPE. I have never used the MARK types, so I can't say for sure they all work. Add code in loop() to wait some amount of time for data before printing "No Signal Found". T4.1 is very fast, so it could print that many, many times even if you have data coming in.

void loop() { 
  elapsedMillis ms = 0;
  uint32_t count = 0;
  while (ms < 1000) {
    if (freq.available()) {
      frequency = freq.read();
  Serial.print( count );
  Serial.print( " periods measured" );
  Serial.print( " -- last = " );
  Serial.println( frequency );