Using Adafruit Airlift breakout board with Teensy4.0/4.1?

mwomack

Well-known member
I have successfully used the Adafruit Airlift board with Teensy 3.5 using SCK/CS/MISO/MOSI pins. I used the Adafruit fork of the WiFiNINA library (which allows one to set the MISO/MOSI/etc pins), and I am able to connect to my WiFi and then send debug messages via UDP. It works great.

So, I decided to use the Airlift for a new project using a Teensy 4.0. I used the same pin connections, I used the same Wifi code, but now the Teensy will reboot almost 90% of the time when connecting to the network, and almost 100% of the time when trying to send data. I swapped the Airlift, thinking maybe I got a bad batch, same behavior. I swapped the Teensy 4.0, thinking I got a bad batch, same behavior. I swapped in a Teensy 4.1, because I had one, same behavior. I swapped in a Teensy 3.5 running at 5v...it works great. I was thinking the issue could be 5v vs 3.3v. So I ran the Teensy 3.5 at 3.3v instead of 5v...and it still works fine.

Is there some issue with the SCK/CS/MOSI/MISO pins on the Teensy 4.0/4.1 controllers that I need to account for in my circuit? Are the pullups/pulldowns diffferent? I don't know how to account for this difference.

I apologize if this was answered in some other forum post that I just didn't find. Are others able to connect to WiFi using the Airlift with Teensy 4.0?

thanks,
-Mark
 
FWIW, this is the relevant code that I use to connect to the Airlift. But I don't think it is a code problem, since it works fine on the Teensy 3.5.

Code:
const uint8_t WIFI_SPI_CS0_PIN         = 10; // SPI CS0 used by Wifi
const uint8_t WIFI_SPI_MOSI0_PIN       = 11; // SPI MOSI0 uased by Wifi
const uint8_t WIFI_SPI_MISO0_PIN       = 12; // SPI MISO0 uased by Wifi
const uint8_t WIFI_SPI_SCK0_PIN        = 13; // SPI SCK0 used by Wifi
const uint8_t WIFI_RESET_PIN           = 5; // reset pin used by Wifi
const uint8_t WIFI_BUSY_PIN            = 7; // busy pin used by Wifi

Code:
 // Set up remote udp port debugging
  if (UDP_DEBUGGING) {
    if (networkHub.start() == 0) {
      DebugMsgs.println("Switching to debug messages through remote udp");
      
      UDPPrintWrapper* udpPrint =
        new UDPPrintWrapper(networkHub.getUdpPort(DEBUG_UDP_PORT), UDP_TARGET_ADDRESS, UDP_TARGET_PORT);
      
      DebugMsgs.setPrint(udpPrint);
      DebugMsgs.println("Starting debug messages through remote udp");
    } else {
      DebugMsgs.println("Error connecting to network, debug messages will continue local");
    }
  }

Code:
int NetworkHub::start(void) {
  // Make sure the right pins are set for SPI
  SPI.setMOSI(WIFI_SPI_MOSI0_PIN);
  SPI.setMISO(WIFI_SPI_MISO0_PIN);
  SPI.setSCK(WIFI_SPI_SCK0_PIN);

  // Make sure right pins are set for Wifi
  WiFi.setPins(WIFI_SPI_CS0_PIN, WIFI_BUSY_PIN, WIFI_RESET_PIN, -1, &SPI);
  
  // check for the WiFi module:
  if (WiFi.status() == WL_NO_MODULE) {
    DebugMsgs.println("Communication with WiFi module failed!");
    return 1;
  }

  int status = WL_IDLE_STATUS;
  int attemptsLeft = 3;
  
  // attempt to connect to Wifi network:
  while (status != WL_CONNECTED) {
    if (attemptsLeft == 0) {
      DebugMsgs.println("All conection attempts exhausted, failed to connected to wifi");
      return 1;
    }
    
    DebugMsgs.print("Attempting to connect to SSID: ").println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);
    attemptsLeft--;
    
    // wait 10 seconds for connection:
    delay(10000);
  }

  DebugMsgs.println("Connected to wifi");
  printWifiStatus();

  return 0;
}

UDP* NetworkHub::getUdpPort(unsigned int portNum) {
  WiFiUDP* wifiUdp = new WiFiUDP();
  wifiUdp->begin(portNum);
  return wifiUdp;
}

void printWifiStatus(void) {
  // print the SSID of the network you're attached to:
  DebugMsgs.print("SSID: ").println(WiFi.SSID());

  // print your board's IP address:
  IPAddress ip = WiFi.localIP();
  DebugMsgs.print("IP Address: ").println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  DebugMsgs.print("signal strength (RSSI):").print(rssi).println(" dBm");
}

Code:
class UDPPrintWrapper : public PrintWrapper {
    
  public:
    UDPPrintWrapper(
      UDP* udp, IPAddress remoteIP, uint16_t remotePort) : PrintWrapper(udp) {
      _udp = udp;
      _remoteIP = remoteIP;
      _remotePort = remotePort;
    }

    virtual int open(void) {
      return _udp->beginPacket(_remoteIP, _remotePort);
    }
    
    virtual int close(void) {
      return _udp->endPacket();
    }
    
    virtual bool requiresOpenAndClose() {
      return true;
    }
  
  private:
    UDP* _udp;
    IPAddress _remoteIP;
    uint16_t _remotePort;
};
 
Does your program have SPI.begin() somewhere? Or maybe it's inside a library you're using?

If you call any SPI functions without first calling SPI.begin(), your program can crash when it tries to access the SPI hardware that isn't turned on.
 
Thanks for the reply, Paul. I checked the WiFiNINA library and I found a begin call in one of the utility classes. But it is unclear to me that it is called. So, I added one to my code right after setting all of the SPI pins, and now the code is well behaved on both the Teensy 4.0 and 4.1. I don't know why it works on the 3.5 without the begin call. I went back and looked at the example code that I adapted for my classes, and it does not have a SPI.begin() call. But then it also does not have the calls to set the SPI pins either. I don't remember why I added the code to set the pins, probably just because the Teensy had different pin locations for the SPI pins than the Arduino defaults. But I didn't add the begin, and it worked fine on the 3.5 project.

Anyways, thank you for the help, it is much appreciated.
-Mark
 
I spoke too soon, I guess. Even though everything was working (I swear it was) after I added the SPI.begin() call as I described before...now it is not. For either the Teensy 4.0 or 4.1 I now get the constant restarting as it is trying to connect to the wifi. The code is exactly the same. And even when it thinks it has connected, it isn't actually sending anything (the builtin LED doesn't flicker like when it actually sent data).

So, I'm back at square one.

-Mark
 
I just wired my Teensy 4.1 up using Adafruit's WifiNINA / Airlift library, and it seems to be working fine for me. I did not have any luck at redefining SPI pins, although I didn't try too hard on it. Here is my working code, which is a slightly modified version of the "WiFiWebClient.ino" example in the WifiNINA library

Code:
#include <Arduino.h>
#include <SPI.h>
#include <WiFiNINA.h>


#define SPIWIFI       SPI  // The SPI port
/*
SPI_SS = 10
SPI_MOSI = 11
SPI_MISO = 12
SPI_SCK = 13
*/
#define SPIWIFI_SS 10      // Chip select pin
#define SPIWIFI_ACK 9   // a.k.a BUSY or READY pin
#define ESP32_RESETN 8   // Reset pin
#define ESP32_GPIO0 7


#define ssid <REDACTED>
#define pass <REDACTED>

WiFiClient client;
int status = WL_IDLE_STATUS;
char server[] = "wifitest.adafruit.com";    // name address for adafruit test
char path[]   = "/testwifi/index.html";


void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your board's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}



void setup() {
  // put your setup code here, to run once
  Serial.begin(115200);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  WiFi.setPins(SPIWIFI_SS, SPIWIFI_ACK, ESP32_RESETN, ESP32_GPIO0, &SPIWIFI);
  while (WiFi.status() == WL_NO_MODULE) {
    Serial.println("Communication with WiFi module failed!");
    // don't continue
    delay(1000);
  }

  String fv = WiFi.firmwareVersion();
  if (fv < "1.0.0") {
    Serial.println("Please upgrade the firmware");
  }
  Serial.print("Found firmware "); Serial.println(fv);

  // attempt to connect to Wifi network:
  Serial.print("Attempting to connect to SSID: ");
  Serial.println(ssid);
  // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
  do {
    status = WiFi.begin(ssid, pass);
    delay(100);     // wait until connection is ready!
  } while (status != WL_CONNECTED);

  Serial.println("Connected to wifi");
  printWifiStatus();

  Serial.println("\nStarting connection to server...");
  // if you get a connection, report back via serial:
  if (client.connect(server, 80)) {
    Serial.println("connected to server");
    // Make a HTTP request:
    client.print("GET "); client.print(path); client.println(" HTTP/1.1");
    client.print("Host: "); client.println(server);
    client.println("Connection: close");
    client.println();
  }
}

void loop() {
  // if there are incoming bytes available
  // from the server, read them and print them:
  while (client.available()) {
    char c = client.read();
    Serial.write(c);
  }

  // if the server's disconnected, stop the client:
  if (!client.connected()) {
    Serial.println();
    Serial.println("disconnecting from server.");
    client.stop();

    // do nothing forevermore:
    while (true);
  }
}

Also just so you're aware, you can use any ESP32 board with this library, it doesn't have to specifically be the AirLift breakout board. Just use the following GPIOs on the ESP32 for the following purposes:

ESP32 PinPurpose
5vPowering the ESP32 from other device
GNDGround
GPIO18SPI SCK
GPIO23SPI MISO
GPIO14SPI MOSI
GPIO5SPI CS/SS
GPIO33BUSY or READY pin
EN or RSTReset
 
I just wired my Teensy 4.1 up using Adafruit's WifiNINA / Airlift library, and it seems to be working fine for me. I did not have any luck at redefining SPI pins, although I didn't try too hard on it. Here is my working code, which is a slightly modified version of the "WiFiWebClient.ino" example in the WifiNINA library

As far as I can tell, in the code printed, you are using the standard SPI pins (MOSI = 11, MISO = 12, SCLK = 13). Note the Teensy LC, 3.2, 3.5, and 3.6 allow you to use alternate SPI pins (MOSI = 7, MISO = 8, SCLK = 14), but you can't use those alternate pins on Teensy 4.0 and 4.1.
 
I just wired my Teensy 4.1 up using Adafruit's WifiNINA / Airlift library, and it seems to be working fine for me. I did not have any luck at redefining SPI pins, although I didn't try too hard on it. Here is my working code, which is a slightly modified version of the "WiFiWebClient.ino" example in the WifiNINA library

I copied your exact code and only made minor changes for the busy and reset pins:

Code:
#define SPIWIFI_SS 10      // Chip select pin
#define SPIWIFI_ACK 8   // a.k.a BUSY or READY pin
#define ESP32_RESETN 9   // Reset pin
#define ESP32_GPIO0 7

Other than that it is the same. I uploaded it to my Teensy 4.1, and it went into the restart loop.

I thought maybe my version of the WiFiNINA library was old, so I downloaded the current master from github and installed it into my Arduino setup, and ran your code again. It worked, it output the return string from the Adafruit server.

So, I loaded my code into the Teensy. It worked as well, and I could tell it was sending the UDP because the led was flickering. But after about 30 seconds, it started the rebooting loop. And once it start this, even if I drop power for a few seconds and then restart, it will keep rebooting. It is like it gets into a bad state that sticks.

If I turn it off and let it sit for a few minutes, then try again, it has a better chance to work again. But it will still only work for about 30-60 seconds. I'm only sending the UDP messages every 100ms, and it's just a string "Test message". I don't think it could be overflowing a buffer?

For the record, my circuit is:

Code:
Teensy pin 8  -> Airlift BUSY
Teensy pin 9  -> Airlift Reset
Teensy pin 10 -> Airlift CS
Teensy pin 11 -> Airlift MOSI
Teensy pin 12 -> Airlift MISO
Teensy pin 13 -> Airlift SCK

Everything else is just power and ground using 3.3v.

And if I swap in the Teensy 3.5, everything is working fine with the exact same pins and code. No rebooting. I swapped in the Teensy 4.0, same problem as the 4.1.

I'm at a loss to explain why.
 
Are you using 3.3v as Vin for the Airlift? Remember Teensy 3's are 5v tolerant but Teensy 4's are not.
 
Are you using 3.3v as Vin for the Airlift? Remember Teensy 3's are 5v tolerant but Teensy 4's are not.

Yes, using 3.3v for everything. The Airlift will take between 3 and 6 volts VIN. I'm even using 3.3v with the Teensy 3.5, and it works fine.
 
I just wired my Teensy 4.1 up using Adafruit's WifiNINA / Airlift library, and it seems to be working fine for me. I did not have any luck at redefining SPI pins, although I didn't try too hard on it. Here is my working code, which is a slightly modified version of the "WiFiWebClient.ino" example in the WifiNINA library

What version of the firmware does your airlift/esp32 have? Mine has 1.2.2. I'm wondering if this makes a difference. I'm going to look into upgrading it tomorrow.
 
I just used the latest one from the nina-fw repo which is 1.7.4. I suspect 1.2.2 is very old, as it's not listed in their nina-fw releases which date back to 2019, so updating is a good idea!

Yeah, I upgraded to 1.7.4 and now it is working without any problems (hopfully I won't post another reply in a few hours saying I was wrong...). I don't know why they are shipping the AirLift with such and old version of the firmware.

Upgrading the AirLift took a little detective work since the current instructions at their info page is messy and doesn't compile out of the box. For anyone that runs into this same issue, search "Trouble upgrading AirLift firmware..." in the Adafruit forum for some updated, working code. Maybe they will update their web page with a better version of the instructions.

Thanks for your help, forsalebypwner.

-Mark
 
OK, I'm back with the same issue, but a different way to reproduce it.

I still have the 1.7.4 firmware loaded into the AirLift board. I slightly modified the code from forsalebypwner to set the SPI pins and begin SPI (though I don't think it makes any difference), and to restart the teensy 4.0 after 10 seconds.

It works great 3-4 times, but then the AirLift gets into the continuous reboot mode like I was seeing previously. I'm guessing that it is a problem with the AirLift firmware, but I'm wondering if anyone else can reproduce this? Or maybe there is more I need to do with the restart?

I am working on code to perform an OTA update of the Teensy firmware using a TCP port to send the new firmware binary. I haven't even gotten to the actual firmware update yet, and I ran into this AirLift issue. If I shutdown the AirLift for a while then it will work again, but after a few restarts is right back to the continuous rebooting. Not ideal for doing updates. :mad:

Here's the sketch:

Code:
#include <Arduino.h>
#include <SPI.h>
#include <WiFiNINA.h>


#define SPIWIFI       SPI  // The SPI port

#define WIFI_SPI_MOSI0_PIN 11 // SPI MOSI0 used by WiFi
#define WIFI_SPI_MISO0_PIN 12 // SPI MISO0 used by WiFi
#define WIFI_SPI_SCK0_PIN  13  // SPI SCK0 used by WiFi
#define WIFI_SPI_CS        10   // Chip select pin
#define ESP32_BUSY          8   // a.k.a BUSY or READY pin
#define ESP32_RESETN        9  // Reset pin
#define ESP32_GPIO0         7

#define ssid "YOUR WIFI SSID HERE"
#define pass "YOUR WIFI PASSWORD HERE"

WiFiClient client;
int status = WL_IDLE_STATUS;
char server[] = "wifitest.adafruit.com";    // name address for adafruit test
char path[]   = "/testwifi/index.html";
uint32_t restartTime;

#define RESTART_ADDR 0xE000ED0C
#define READ_RESTART() (*(volatile uint32_t *)RESTART_ADDR)
#define WRITE_RESTART(val) ((*(volatile uint32_t *)RESTART_ADDR) = (val))

void restartTeensy(void) {
  // Please see: https://forum.pjrc.com/threads/44857-How-to-Reset-Restart-Teensy-3-5-using-sotware
  WRITE_RESTART(0x5FA0004);
}

void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your board's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

void setup() {
  // put your setup code here, to run once
  Serial.begin(115200);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  
  // Make sure the right pins are set for SPI
  SPI.setMOSI(WIFI_SPI_MOSI0_PIN);
  SPI.setMISO(WIFI_SPI_MISO0_PIN);
  SPI.setSCK(WIFI_SPI_SCK0_PIN);
  SPI.begin();

  pinMode(ESP32_BUSY, INPUT);
  pinMode(ESP32_RESETN, OUTPUT);
  
  WiFi.setPins(WIFI_SPI_CS, ESP32_BUSY, ESP32_RESETN, ESP32_GPIO0, &SPIWIFI);
  while (WiFi.status() == WL_NO_MODULE) {
    Serial.println("Communication with WiFi module failed!");
    // don't continue
    delay(1000);
  }

  String fv = WiFi.firmwareVersion();
  if (fv < "1.0.0") {
    Serial.println("Please upgrade the firmware");
  }
  Serial.print("Found firmware "); Serial.println(fv);

  // attempt to connect to Wifi network:
  Serial.print("Attempting to connect to SSID: ");
  Serial.println(ssid);
  // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
  do {
    status = WiFi.begin(ssid, pass);
    delay(100);     // wait until connection is ready!
  } while (status != WL_CONNECTED);

  Serial.println("Connected to wifi");
  printWifiStatus();

  Serial.println("\nStarting connection to server...");
  // if you get a connection, report back via serial:
  if (client.connect(server, 80)) {
    Serial.println("connected to server");
    // Make a HTTP request:
    client.print("GET "); client.print(path); client.println(" HTTP/1.1");
    client.print("Host: "); client.println(server);
    client.println("Connection: close");
    client.println();
  }

  restartTime = millis() + 10000;
}

void loop() {
  // if there are incoming bytes available
  // from the server, read them and print them:
  while (client.available()) {
    char c = client.read();
    Serial.write(c);
  }

  // if the server's disconnected, stop the client:
  if (!client.connected()) {
    Serial.println();
    Serial.println("disconnecting from server.");
    client.stop();
  }

  // Restart if time limit met
  if (millis() > restartTime) {
    Serial.println();
    Serial.println();
    Serial.println("Restarting Teensy");
    Serial.flush();
    delay(1000);
    restartTeensy();
  }
}
 
I ran the exact code you provided (changing only the SSID and Password, of course), and have allowed the Teensy to reboot > 10 times with no failures. If you suspect the Airlift hardware is causing the issue, I'd highly recommend the Wemos D1 Mini ESP32, which can be purchased for around ~$6-8 per board on Amazon, depending on how many you buy. It's the board I'm using to test this code.

It seems to me like the code you're using to restart the Teensy is working properly, as my serial connection to the Teensy drops every time it hits that 10 second timeout in your code.
 
If you suspect the Airlift hardware is causing the issue, I'd highly recommend the Wemos D1 Mini ESP32, which can be purchased for around ~$6-8 per board on Amazon, depending on how many you buy. It's the board I'm using to test this code.

I ordered a set of boards that I hope are the right ones. It said D1 Mini ESP32, so here's hoping. Should be here some time tomorrow, so I can continue then.

Did you load the Adafruit firmware onto your board as well?

-Mark
 
I ordered a set of boards that I hope are the right ones. It said D1 Mini ESP32, so here's hoping. Should be here some time tomorrow, so I can continue then.

Did you load the Adafruit firmware onto your board as well?

-Mark

Yep, exactly. A while back I wrote up some more specific instructions for using this board with the airlift firmware and put them here: https://github.com/kylefmohr/ESP32-Restricted-Airspace

One thing I’ll point out as a potential gotcha is that you’ll need to connect to pin 14 on the D1 Mini, which is broken out on the board but isn’t labeled as such, pin 14 is labeled “TMS” on the board.

Let me know if you have any questions.
 
The pinouts on this new board aren't very breadboard friendly with the double row of pins on each side, but I'll solder in some headers and get a harness together. If I use this board I might create a simple 'companion' board to match the AirLift pin outs.

Be back in a little bit with my report.

-Mark
 
A while back I wrote up some more specific instructions for using this board with the airlift firmware and put them here: https://github.com/kylefmohr/ESP32-Restricted-Airspace

Great instructions. The only difference is that on my board reset is labeled "RST" instead of "EN".

So, forsalebypwner, let me guess...you are powering your circuit with 5v and not 3.3v? How do I know? I hooked up this new board, and in the process I was trying to see if it required 5v or 3.3v. It looked like 5v, but a lot on the web seemed to suggest 3.3v would work. So, I started with 3.3v...and got the exact same problem as with the AirLift. I switch to 5v for the power to both the Teensy and the new board...no problems, proper restarts and connections forever. Swapped in the AirLift...it is happily rebooting and connecting with no issues as I write this.

So, even though the Adafruit product page says it will work for 3.3v, it won't work if you plan to restart more than three times. :) 5v power FTW.

I know everything is supposed to be moving to 3.3v, but I feel like I will always be designing circuits that use/require both 5v and 3.3v. But at least I know what the problem was now. And it doesn't seem related to the AirLift specifically, but to the ESP32. Or maybe the Adafruit firmware, maybe? Though I am unsure how the firmware software would be voltage specific.

Again, thank you for all your help, forsalebypwner.

-Mark
 
Back
Top