Teensy 4.1 UDP causes reboot after upgrading Teensyduino from 1.56.2 to 1.62.0

Shun

Well-known member
Hi,

We are currently developing a project using Teensy 4.1.

Our development environment is:

Teensy 4.1
Arduino IDE 2.3.8
Teensy package 1.62.0

We found that after upgrading the Teensy package from 1.56.2 to 1.62.0, our application immediately resets whenever UDP communication is used.

The behavior is:

Teensy package 1.56.2: UDP works normally.
Teensy package 1.62.0: As soon as UDP is used, the Teensy automatically reboots.
Downgrading back to 1.56.2 completely resolves the problem.

We also tested with Arduino IDE 1.8.19, and the same issue occurs when using Teensy package 1.62.0. Therefore, it does not appear to be related to the Arduino IDE version.

The Teensy package was downloaded directly from the official PJRC website.

Could you please advise:

Are there any known changes in the Ethernet/UDP implementation between Teensy package 1.56.2 and 1.62.0 that could cause this behavior?
Has anyone experienced similar UDP reboot/reset issues after upgrading?
Is there anything we should modify in our code to be compatible with version 1.62.0?

If needed, we can also provide a minimal example that reproduces the problem.

Thank you.
 
Minimal example program to reproduce the problem is the best way to get to the bottom of this problem.

To quickly answer, this is the first I've heard of UDP breaking with 1.62. At least as far as I know, not a "known" problem.

1.56 was so long ago, maybe even before we had MPU enabled with default fault handler and CrashReport. If you read from a NULL pointer, for example, without the MPU it will succeed and give you "something". With the MPU accessing with a NULL pointer causes a fault. Likewise for attempting to read other "illegal" memory. The default fault handler waits 8 seconds, logs CrashReport info, and reboots. Since you're seeing "automatically reboots", maybe something in the code is causing a memory fault? You did say "our application immediately resets" which doesn't quite fit the 8 seconds behavior... so not sure if the fault handler explanation makes sense? Still might be worthwhile to add some code in setup() to look at CrashReport to see if anything is getting logged.

Since 1.56, we've updated the gcc toolchain twice. I'm pretty sure 1.56 used gcc 5.4. For some time we were using gcc 11.3, and 1.62 updated to gcc 15.2. Arduino IDE 2.3.x Boards Manager makes switching versions very easy. Just search "teensy" (so you're not seeing a long list of all other boards) and use the drop-down menu to switch to another version. We tried to keep 1.61 and 1.62 almost exactly the same except for the gcc toolchain (and many small updates to libraries to fix errors and warnings with the new gcc) so you might as well give 1.61 and the other versions a try.

If none of that yields helping info, an example to reproduce the problem would be the best way forward.
 
I should also mention, on every software release I manually run Ethernet (W5500) example WebClient, NativeEtheret example WebClient, and for newer releases QNEthernet example SimpleHTTPClient. On all 3, I just watch the serial monitor for a bunch of HTML and the summary at the end about bytes transferred and overall speed. Those examples use TCP to fetch a web page, but before the HTTP connection they use DHCP to get an IP number and DNS to look up the IP number for "www.google.com". I'm pretty sure the DNS lookup involves use of UDP, but to be honest I really haven't paid a lot of attention to that part because it always just works. All 3 of these definitely worked when I tested the 1.62 release.

Maybe for future releases I should add more networking tests? But I already run *many* library examples which takes quite a bit of time. Open to suggestions if the test can run quickly and without setting up other special gear.

Unless I've missed something, difficult to know which of those 3 libraries (or perhaps another) you're really using, and whether you've using Teensy 4.1 ethernet or a Wiznet board. An example to reproduce the problem would give a lot more info!
 
Code:
#include <Arduino.h>           
#include <NativeEthernet.h>

#include <NativeEthernetUdp.h>
EthernetUDP BasicSkills_Udp;

bool BasicSkills_Ethernet_INIT(uint8_t  BasicSkills_MacAdress[] , IPAddress BasicSkills_IPAdress )
{   
    Ethernet.begin(BasicSkills_MacAdress, BasicSkills_IPAdress);
}
bool BasicSkills_Ethernet_LinkState(void)
{
    return     (Ethernet.linkStatus()==LinkOFF) ? false : true ;
}

//-------------------------------------------------------UDP Function
void BasicSkills_Ethernet_UDP_Start(unsigned int BasicSkills_LocalPort)
{
    BasicSkills_Udp.begin(BasicSkills_LocalPort);
}

bool BasicSkills_Ethernet_UDP_RceiveData(IPAddress *BasicSkills_RemoteIP ,uint16_t *BasicSkills_RemotePort,
                                         int BasicSkills_memlen ,int *BasicSkills_PacketSize , uint8_t BasicSkills_Data[])
{
    *BasicSkills_PacketSize = BasicSkills_Udp.parsePacket();
    if(*BasicSkills_PacketSize)
    {
        IPAddress ip = BasicSkills_Udp.remoteIP();
        *BasicSkills_RemoteIP = ip;
        *BasicSkills_RemotePort = BasicSkills_Udp.remotePort();
        BasicSkills_Udp.read(BasicSkills_Data, BasicSkills_memlen);
        return true;
    }
    return false;
}

void BasicSkills_Ethernet_UDP_TransitiveData(IPAddress  BasicSkills_ConnectionIP, uint16_t BasicSkills_ConnectionPort,
                                             int BasicSkills_PacketSize , uint8_t BasicSkills_Data[])
{
    BasicSkills_Udp.beginPacket(BasicSkills_ConnectionIP,BasicSkills_ConnectionPort);
    BasicSkills_Udp.write(BasicSkills_Data,BasicSkills_PacketSize);
    BasicSkills_Udp.endPacket();
}

void setup()
{
    // put your setup code here, to run once:
 Serial.begin(9600);
 byte mac[] = {
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
  };
 IPAddress IP(192,168,0,105);
 BasicSkills_Ethernet_INIT(mac,IP);
 BasicSkills_Ethernet_UDP_Start(888);
 if(BasicSkills_Ethernet_LinkState())Serial.println("Link OK");

}

void loop()
{
   // put your main code here, to run repeatedly:
  int Size;
  IPAddress IP;
  uint8_t data[300];
  uint16_t Port;
  if(BasicSkills_Ethernet_UDP_RceiveData(&IP,&Port,sizeof(data),&Size,data))
  {
    Serial.print("RemoteIP = ");
    Serial.println(IP);
    Serial.print("RemotePORT = ");
    Serial.println(Port);
    Serial.print("String Data = ");
    Serial.write(data,Size);   
    Serial.println();
    BasicSkills_Ethernet_UDP_TransitiveData(IP,Port,Size,data);
  }
}

This is the example code we are using.
Since we had not used the Teensy platform for quite some time, we had previously packaged and saved this example project.

I would like to ask whether the recommended usage for UDP/Ethernet has changed in newer Teensy versions.
 
1786241821404.png

Previously, we used the package downloaded from the link shown in the screenshot together with Arduino IDE 1.8.19, and everything, including UDP communication, worked correctly.

However, when we recently downloaded the package again from the same link and tested it with Arduino IDE 1.8.19, the UDP issue appeared and the Teensy 4.1 rebooted.

Has the content or version of the package provided through this link been updated or changed since our previous download?

We are wondering whether the package downloaded from this link now contains a newer version of the Teensy libraries or Ethernet/UDP-related libraries, which could explain why our previously working example no longer works correctly.
 
May I suggest:
  • try one of the NativeEthernet UDP examples
  • try one of the QNEthernet UDP examples
NativeEthernet has not been supported/updated by the author in quite a few years, whereas QNEthernet has active support/development. You might need to switch from NativeEthernet to QNEthernet with TeensyDuino 1.62
 
I tried running the example on a Teensy 4.1 with ethernet connected. Indeed it crashes.

I noticed this in the console:

Code:
sketch_aug09a: In function 'bool BasicSkills_Ethernet_INIT(uint8_t*, IPAddress)':
sketch_aug09a:10: warning: no return statement in function returning non-void
   10 | }
      | ^

Changing BasicSkills_Ethernet_INIT return type bool to void seems to solve the crash.

Code:
void BasicSkills_Ethernet_INIT(uint8_t  BasicSkills_MacAdress[] , IPAddress BasicSkills_IPAdress )
{ 
    Ethernet.begin(BasicSkills_MacAdress, BasicSkills_IPAdress);
}

With this small edit, I do not see Teensy 4.1 reboot (serial monitor disconnects and reconnects) and I see "Link OK" in the serial monitor window.

1786317408351.png
 
Just to make sure I answered this question:

We are wondering whether the package downloaded from this link now contains a newer version of the Teensy libraries or Ethernet/UDP-related libraries, which could explain why our previously working example no longer works correctly.

Yes, as explained in msg #3, we updated many libraries in version 1.62 because of the change from gcc 11.3 to gcc 15.2. NativeEthernet was among them.

However the crash problem appears to be not in the libraries, but a simple error in your BasicSkills_Ethernet_INIT function. It is declared as returning a bool, but you have no return at all. Older gcc would just return something random. But newer gcc has all sorts of additional optimizations, so this sort of mistake now causes a crash. But the solution is simple, and the compiler gives you a warning about the problem.
 
That warning should be an ERROR. As it ends up with unsafe/undefined code.
> non-Void func() having an exit with no return value

Interesting here it caused REBOOT

@shawn and I were doing a remote chat and editing code some time back and rather than a reboot it presented a lost hour of puzzling behavior.
 
That warning should be an ERROR. As it ends up with unsafe/undefined code.
> non-Void func() having an exit with no return value

Claude says it's undefined behavior, as opposed to strictly being an error. It says a lot more about why, but I'm not comfortable repeating what AI says. There is a compiler option to promote the warning to an error.
 
Yeah, maybe for 1.63 we ought to use that compiler arg to turn the no return warning into an error.

I'm kinda curious what's really going on with the new gcc 15.2 compiler... but whether curious enough to spend the time on a deep dive into the generated code, maybe, maybe not.
 
Last edited:
I'm kinda curious what's really going on with the new gcc 15.2 compiler... but whether curious enough to spend the time on a deep dive into the generated code, maybe, maybe not.
Took less than 2 minutes and seems to be unexpected behavior – possibly a bug (still present in 16.x) (godbolt.org)
And yes, an error would be better.
(There's a reason I almost always use -Werror... warnings are not junk food)
1787144093387.png
 
Last edited:
Back
Top