Microcontroller projects

Teensy tips and tricks

last updated: 09/05/19

Problems with Serial on Arduino 1.8.9 (Kubuntu)

This helped, but I don't know why:

    sudo apt purge modemmanager

Fast PWM with Teensy 2.0 (mega32u4) in Arduino

Fast PWM on Teensy 2.0 is cool because it is very simple to initialise and needs no interrupts. Because Timer0 is used by Arduino we will use the 16 Bit Timer1 or Timer3 or the 10 Bit Timer4. We have to set the right bits in TCCRnA and TCCRnB register. That's all. The byte in OCR register (8 bit PWM) defines the pulsewidth from 0 (0%) to 255 (100%).

Timer1 has 3 PWM outputs (14,15 and 4), Timer3 only one output (9) and Timer4 two outputs (10 and 15 (same as Timer1!). Here are the sample codes:

    // Fast PWM for Teensy Timer1 (3 outputs)
    const byte fan1Pin = 14;      // PB5 on Teensy (OC1A of Timer1)
    const byte fan2Pin = 15;      // PB6 on Teensy (OC1B of Timer1)
    const byte fan3Pin = 4;       // PB7 on Teensy (OC1C of Timer1)
    void setup() {
      pinMode(fan1Pin, OUTPUT);
      pinMode(fan2Pin, OUTPUT);
      pinMode(fan3Pin, OUTPUT);
      TCCR1A = 0xA9;              // COM1A1, COM1B1, COM1C1, WGM10
      TCCR1B = 0x0A;              // WGM12 (Fast PWM 8 Bit) CK/8  -> 7,8kHz
      OCR1A = 51;                 // 20%
      OCR1B = 127;                // 50%
      OCR1C = 179;}               // 70%
    void loop() {}
    // Fast PWM for Teensy Timer3 (only one pin available!)
    const byte fan1Pin = 9;       // PC6 on Teensy (OC3A of Timer3)
    void setup() {
      pinMode(fan1Pin, OUTPUT);
      TCCR3A = 0xA1;              // COM3A1,WGM30;
      TCCR3B = 0x0A;              // WGM32 (Fast PWM 8 Bit) CK/8  -> 7,8kHz
      OCR3A = 51;}                // 20%
    void loop() {}
    // Fast PWM for Teensy Timer4 (2 outputs)
    const byte fan1Pin = 10;    // PC7 on Teensy (OC4A of Timer4)
    const byte fan2Pin = 15;    // PB6 on Teensy (OC4B of Timer4)
    void setup() {
      TCCR4A = 0xA3;            // COM4A1, COM4B1, PWM4A, PWM4B
      TCCR4B = 0x04;            // CK/8  -> 3,92kHz (8MHz 10Bit??))
      OCR4A = 51;               // 20%
      OCR4B = 127;}             // 50%
    void loop() {}

To change the PWM frequency, adjust the bits in TCCRnB (see data sheet of mega32u4).

Using Timers in CTC mode on Teensy 2.0 (mega32u4) in Arduino

We will use the Timer1 and Timer3 (both 16 bit) with compare match (CTC mode).

Timer1 will print seconds and minutes once a second in the serial terminal (115200 bits/s) without using an interrupt. For this we watch the interrupt flag. By clearing the flag with "1" (i know it's not logical but hardware dictates the laws) we simulate an interrupt and initiate the timer to run again.

Timer3 fires an interrupt in half a second time to blink the Teensy LED and an LED on PB0 (0) once a second. Setting the PIN register to "1" is an efficient way (2 cycles) to toggle a pin but works only on AVR controller.

    // CTC Mode (with and without interrupt)
    // on Teensy2 (mega32u4)
    // Timer1 prints seconds and minutes in serial terminal without interrupt
    // Timer3 toggles PB0 once a second (with interrupt)
    // weigu.lu
    // This example code is in the public domain.

    const byte teensyLED = 11; // PD6 Teensy LED
    const byte toggleLED = 0;  // PB0 on Teensy
    int seccounter = 0, mincounter = 0;

    void setup() {
    pinMode(teensyLED, OUTPUT);
    pinMode(toggleLED, OUTPUT);
    TCCR1A = 0;
    TCCR1B = 0x0C;         // WGM32 (CTC) , Prescaler = 256
    OCR1A = 62500;         // 16M/256/62500 = 1 second
    TCCR3A = 0;
    TCCR3B = 0x0C;         // WGM32 (CTC) , Prescaler = 256
    OCR3A = 31250;         // 16M/256/31250 = 0,5 seconds
    TIMSK3 = 0x02;         // enable compare interrupt

    void loop() {
    if (TIFR1 & 0x02) {    // Flag set?
        TIFR1 |= 0x02;       // clear Flag with 1! (data sheet)
        if (seccounter == 60) {
        seccounter = 0;

    ISR (TIMER3_COMPA_vect) {
    PINB = PINB | 0x01;    // toggle pin PB0
    PIND = PIND | 0x40; }  // toggle pin PD6 Teensy LED

Using Ethernet shield (WZ5500) with SD-card shield at the same time

Both shields are using SPI. Because the SD-card shield is on top of the Teensy2 it uses pin 0 (PB0) as chip select. The Ethernet shield has to use a different chip select. In the Teensy library (hardware/teensy/avr/libraries/Ethernet) the chip select is on pin 10 (PC7) but only if you use the init() function. Without using this function chip select stays on pin 0 and conflicts with the SD-card. You can pass a parameter to the init() function an so specify another pin for chip select.

So here is the code for pin 10:

    Ethernet.begin(mac, eth_ip);

And here the code for example pin 13 (PB4):

    Ethernet.begin(mac, eth_ip);

Teensy 3.6 on-board SD-card

This card is not using normal SPI but has its own dedicated SDIO interface, capable of much higher speeds (up to 20 MByte/sec on the T3.6!). To use the card you have to change chipSelect to:

const int chipSelect = BUILTIN_SDCARD;

Look at File-Examples-SD (Teensyduino SD card examples)

I can connect the WizNET only to the first SPI because the ethernet library uses FIFO which only exists on the first SPI.

Teensy 3.6 on-board RTC

The 32.768 kHz crystal is already soldered to the board. You have only to solder the 3V Li battery to 2 pins in the middle (VB and GND).

To use the RTC look at File-Examples-Time-TimeTeensy3 (Teensyduino installed)

The Teensy's RTC is not temperature corrected like the DS3231's. There was discussion about using the internal Teensy temperature sensor (pin 44 on 3.5/3.6) to correct the Teensy's RTC drift (search forum).

Receiving NTP time over serial from ESP8266

For ESP8266 sketch click here and scroll down.

Here a simple sketch to get the time (Teensy 3.6) from ESP8266.

Connect D4 (TxD) from Wemos D1 mini with pin 1 (RXD1) from Teensy 3.6 (connect also the 2 GNDs).

    /*  Get NTP Time from ESP8266 over serial on RXD1 (Teensy 3.6)
     *  weigu.lu

    #define MAX_LINE_LENGTH 10

    uint8_t telegram[MAX_LINE_LENGTH];
    int Tlength;

    void setup() {
      Serial.begin(115200);  // for debugging
      Serial.println("Serial is working!");

    void loop() {
      Tlength = readTelegram();
      if (Tlength) {
        int NTP_hour = (telegram[0]-48)*10+(telegram[1]-48);
        int NTP_min = (telegram[2]-48)*10+(telegram[3]-48);
        int NTP_sec = (telegram[4]-48)*10+(telegram[5]-48);

    int readTelegram() {
      int cnt = 0;
      while ((Serial1.available()) && (cnt!= MAX_LINE_LENGTH)) {
        telegram[cnt] = Serial1.read();
        cnt++; }
      return (cnt);