Starting QNEthernet without ethernetcable

Antoine

Member
Dear all,

Working very happily with the Teensy 4.1 with ethernet connection, it works like a charm when booting the Teensy 4.1 with an ethernetcable connected. There is a but though :).

The device will not connect to ethernet when the Teensy has been booted up WITHOUT the ethernet cable attached, in other words.

I start the Teensy with the Ethernet.begin() and Ethernet.waitforIP(10000), when the cable is connected, Teensy continues to boot and does it's audio magic. Data is however communicated on one of the Serial busses to an RS485 master. Works fine. The Ethernet cable is used when we want high speed audio measurements from the Teensy, however. Link is not established if Teensy was booted WITHOUT an ethernet connection.

So in short:
Teensy booted with Ethernet connection, everything works fine, I can disconnect en reconnect the cable and the linkState() responds as expected.
Teensy booted without Ethernet connection, the connection can never be made again, linkState() is always false.

What am I doing wrong?

Code:
    Serial.print(F("Starting Ethernet... "));
    if(!Ethernet.begin()) {
        Serial.println(F("Failed"));
    } else {
        Serial.print(F("OK\nWait for DHCP... "));
        if (!Ethernet.waitForLocalIP(10000)) {
            Serial.println(F("Failed"));
        }
        Serial.print("Link3:"); Serial.println(Ethernet.linkState());
        Serial.println(F("OK"));
 
Would you mind including a complete program that shows the issue? It’s about having less friction and requiring anyone that answers to spend less time trying to construct the rest of the program to make it runnable.
 
That will be impossible (and waaaay to big) and not even allowed unfortunately. But it basically is the following routine that is checked in the main loop() of the code. I was hoping for a "oh yes that is because off..." response ;). I think the issue is that if the ethernet connection is not established the library is not loaded (properly), and therefore the linkState is not handled properly. Also I noticed btw, that when the ethernetcable is disconnected, after a certain amount of time the connection is also not restored anymore. Looks like some timeout stuff is happening somewhere?

[edit]
Note, when the connection can not be set, the Act.LED on the magjack stays off. The Act.LED is normally controlled by the Ethernet chip. The Link.LED is controlled by me (seperate wire).

Code:
void eUtils::ethLinkHandler() {
    if(Ethernet.linkState()) {
        if(eth.phyLinkState==false) {
            eth.phyLinkState=true;
            digitalWrite(22, LOW); // Link LED is on
            eUtils::showStatus(INFO_STARTETHERNET); // Send debug message that Ethernet service has started
          
            if(!Ethernet.begin()) {
                Serial.println(F("Failed"));
            } else {
                Serial.println(F("OK"));
                eUtils::showStatus(INFO_STARTDHCP);
                if (!Ethernet.waitForLocalIP(10000)) {
                    Serial.println(F("Failed"));
                } else {
                    Serial.println(F("OK"));
                    eth.modLocalIP = Ethernet.localIP();
                    eth.modSubnetMask = Ethernet.subnetMask();
                    eth.modGatewayIP = Ethernet.gatewayIP();
                    SensorServer.begin();
                    ServiceServer.begin();
                    eUtils::showStatus(INFO_ETHERNET); // Send debug message on used IP addresses
                }
            }
        }
    } else {
        if(eth.phyLinkState) {
            eth.phyLinkState=false;
            digitalWrite(22, HIGH); // Link LED is off
            eUtils::showStatus(INFO_ETHERNET); // Send debug message that Ethernetlink is down
        }
    }
}
 
That will be impossible (and waaaay to big) and not even allowed unfortunately. But it basically is the following routine that is checked in the main loop() of the code. I was hoping for a "oh yes that is because off..." response ;). I think the issue is that if the ethernet connection is not established the library is not loaded (properly), and therefore the linkState is not handled properly. Also I noticed btw, that when the ethernetcable is disconnected, after a certain amount of time the connection is also not restored anymore. Looks like some timeout stuff is happening somewhere?

[edit]
Note, when the connection can not be set, the Act.LED on the magjack stays off. The Act.LED is normally controlled by the Ethernet chip. The Link.LED is controlled by me (seperate wire).

Code:
void eUtils::ethLinkHandler() {
    if(Ethernet.linkState()) {
        if(eth.phyLinkState==false) {
            eth.phyLinkState=true;
            digitalWrite(22, LOW); // Link LED is on
            eUtils::showStatus(INFO_STARTETHERNET); // Send debug message that Ethernet service has started
        
            if(!Ethernet.begin()) {
                Serial.println(F("Failed"));
            } else {
                Serial.println(F("OK"));
                eUtils::showStatus(INFO_STARTDHCP);
                if (!Ethernet.waitForLocalIP(10000)) {
                    Serial.println(F("Failed"));
                } else {
                    Serial.println(F("OK"));
                    eth.modLocalIP = Ethernet.localIP();
                    eth.modSubnetMask = Ethernet.subnetMask();
                    eth.modGatewayIP = Ethernet.gatewayIP();
                    SensorServer.begin();
                    ServiceServer.begin();
                    eUtils::showStatus(INFO_ETHERNET); // Send debug message on used IP addresses
                }
            }
        }
    } else {
        if(eth.phyLinkState) {
            eth.phyLinkState=false;
            digitalWrite(22, HIGH); // Link LED is off
            eUtils::showStatus(INFO_ETHERNET); // Send debug message that Ethernetlink is down
        }
    }
}

Hi Antoine, how does your code handle a link state change when connecting, to re-run ethLinkHandler() in turn starting ethernet?

Difficult to tell from the small code snippet, but if wildly speculating, I would guess ethLinkHandler() is run only once, proximate to setup(), and would suggest the use of onLinkState.
 
You could provide a small representative example program that illustrates the problem that isn’t your whole program. I likely wouldn’t look at a very large program anyway, unless I had the bandwidth.

All my programs that use Ethernet are written in a non-blocking style with just listeners and no waiting on anything. You could add a link listener and see if that works for you.

Also, if you’re polling the link state with your ethLinkHandler() then you only need to call Ethernet.begin(…) once to start up the system.

I’m 100% certain you can write your program in such a way that it doesn’t care whether it starts with a link or not.
 
Hi Shawn, Hi Jean-Pierre,

This is called constantly in the mainloop of the code. I think the issue really is that the linkState is not correctly functioning (probably and hopefully only in my case), so what I am doing is checking if the linkstate is up (but was previously down) and initiate the whole ethernet stuff. Once the linkstate is up (and was up before) it skips this routine.

The strange this is, that if I initialize the ethernet stuff in a different way (without the checks) the link never comes back up. So I was thinking, maybe I could initialize the ethernet with a fixed ip, instead of a dhcp, maybe it will be happier to get the link back up after the cable is connected.
 
Note that link state/status can’t be detected until begin(…) is called. Begin(…) should (well, in most cases) only be called once for the entire program.

Internally, what’s happening is once the internal stack is started, link state is polled about eight times a second. The mechanism to detect a link doesn’t work if the PHY chip hasn’t been initialized, and this initialization happens during the begin(…) call.

Yes, begin(…) can set an IP address configuration via DHCP or directly, but it doesn’t have to, and that’s not its only function. (One of my gripes about the Arduino-style Ethernet API.) For example, you could disable DHCP before calling begin() with no arguments, and then Ethernet (and hardware) will be initialized without starting DHCP.

Regarding your claim that link detection isn’t functioning correctly: if this is really true, I would really appreciate it if you came up with a small example program that demonstrates this, so I can fix it.
 
Last edited:
begin is called in the beginning ;). I will try to make a smaller example to replicate the issue this week
It looks like ethHandler() is calling it too, and you say you call it regularly, hence my comments about begin(…) being called more than once. (This is an example of potentially going down the wrong path without a complete example program.) It still looks to me like you call begin(…) more than once.

What might be helpful for you are the DHCP functions in the Ethernet class. You can also set and get the various IP addresses there too. I have a whole host of functions meant to provide functionality that the Arduino-style API doesn’t.
 
Just checked.

Made a quick little program to check this:

So... after the Ethernet.begin() has ran (it is never "Failed" btw). And I check the linkState, the linkState is always 0 (not connected), no matter if there is a cable connected or not.

If I change the code to forcefully check for an IP, then, and only then, the Act.LED turns on (and eventually the Link.LED on pin 22). Then the linkState equals 1. In other words, the Act.LED represents the linkState. When it is off, linkState is also 0. I've tested this with three different boards, switches, routers, but the behavior is not influenced on external hardware or cables.

The program below doesn't work, at least not with me :). Thanks for you time and patience.

Code:
#include "Arduino.h"
#include "LAEqv2_Utils.h"
#include "Wire.h"
#include "Crc16.h"
#include <QNEthernet.h>
#include <time.h>
#include <stdarg.h>
#include <math.h>

using namespace qindesign::network;

void setup() {
    if(!Ethernet.begin()) {
        Serial.println(F("Failed"));
    }
}

void loop() {
    eUtils.ethLinkHandler();
}

void eUtils::ethLinkHandler() {
    if(Ethernet.linkState()) {
        if(eth.phyLinkState==false) {
            eth.phyLinkState=true;
            digitalWrite(22, LOW);
            eUtils::showStatus(INFO_STARTETHERNET);
            
            eUtils::showStatus(INFO_STARTDHCP);
            if (!Ethernet.waitForLocalIP(10000)) {
                Serial.println(F("Failed"));
            } else {
                Serial.println(F("OK"));
                eth.modLocalIP = Ethernet.localIP();
                eth.modSubnetMask = Ethernet.subnetMask();
                eth.modGatewayIP = Ethernet.gatewayIP();
                SensorServer.begin();
                ServiceServer.begin();
                eUtils::showStatus(INFO_ETHERNET);
            }
        }
    } else {
        if(eth.phyLinkState) {
            Serial.println("Ethernet link down");
            eth.phyLinkState=false;
            digitalWrite(22, HIGH);
            eUtils::showStatus(INFO_ETHERNET);
        }
    }
}
 
The program doesn't even compile (missing "LAEqv2_Utils.h", "Crc16.h", eUtils, eth, SensorServer, INFO_ETHERNET, etc.). I don't have the same libraries installed as you. I'm sorry, but I can't help you further without an example program that I can build and run.
 
Well after some research on my end, it seems it has to do with the router I am using, and also probably the hardware on my side. I can not replicate the issue when connected to my Zyxel GS1900P (PoE switch) or a generic Netgear GS108E (non poe switch) when connecting it up to a Teltonika 4G router I can replicate the issue after one of two physical plugging and unplugging. Once the non link issue has begun, there is no way out other then the reset the Teensy.

Which makes me think the hardware could have a slight issue somewhere down the line. I am not using the Teensy ethernet breakout, but a seperate transformer with poe capabilites which normally works like a treat. Unfortunatly sometimes it will be power from the "main system" and a normal switch needs to be connected to the ethernet, which 9/10 times will be the teltonika.

The question now is, what is the use of the 75 ohm resistors, the breakout magjack solution from PRJC has these integrated in the connector, but a PoE compatible magjack doesn't... which is logical, the power from the PoE switch will burn these out. Perhaps a capacitor in series?

This btw still does weird thing with the linkState, because I can now replicate that the link is up (Act.LED is up and receiving broadcast traffic from the network), while linkState in the library is still 0.
 
Good info, thx again.

What I notice first in the datasheet, is that the schematic used for the breakout board is also different than the one advised in the datasheet. Specially the two capacitors on the device side (between Phy and Magnetics) are different. On the breakout these two transformer taps are shorted together and only one 100nF cap is used. In the datasheet, a lot more capacitance is placed.

That said, I think I need some more common mode filtering but without a DC path, since my lines are used with PoE I can not "just" put a resistor to ground.

But... then again, the linkState behaves strange imho.

Ethernet.begin >>> Cable connected, link established, no IP yet
Linkstate == 0
Ethernet.waitForIP >>> Teensy gets IP
Linkstate == 1

So linkState in my case only becomes 1 after it got an IP address.

1702643687615.png


All in all, I think it will work out one way or the other, at least I hope, I am planning a few products based on the Teensy 4.1 :). I'll keep it posted, other might as well benefit from the PoE solution.

[edit]
I am using the Wurth Elektronik 749013011A transformer and the Wurth Elektronik 615008137421 Rj45 which is a plain connector without magnetics.
 
Do you have any waiting loops in your code that don’t call yield()? Any waiting done in QNEthernet calls yield() inside any internal waiting loops (such as waitForLocalIP()).

You saying that the library doesn’t detect a link until it gets an IP address leads me to suspect this.

I really wish I could see what you’re doing in your code. It’s hard to help otherwise.
 
I am not exactly sure what you mean, I am using the waitforip(10000) option, which I found somewhere in an example. The only waits I use in my software are for the RS485 transceivers it also contains. I do use the audio libraries very heavily. As far as I know I am not using any waitstates in the ethernet communication other then the one for the waitforip command.
 
Is there anywhere in your code that loops for a significant amount of time without calling yield()? Yield() is called at the end of each loop() call, and that’s where Ethernet stuff gets serviced. This means that if the current call to loop() doesn’t end in a reasonable amount of time, and if there’s something in there that loops for a little while without calling yield(), then Ethernet things won’t get serviced.

I was proposing this as one potential issue.
 
My device does a LOT, if it needed to do little I would use an arduino :), but it is not waiting, but it does a lot of audio stuff, fft, calculations etc. I will check the yield() function, it should be called regularly you say. I am not calling it at all the moment, so that could be an issue, my mainloop is ran through every 1 millisecond btw and it communicates to ethernet once every 10 seconds for the maximum amount of time.
 
I will check the yield() function, it should be called regularly you say. I am not calling it at all the moment, so that could be an issue
Arduino's main() function looks something like shown below, so as long as your loop function returns before too long, your program is calling yield() regularly.

Code:
void main() {
  setup();
  while(1) {
    loop();
    yield();
  }
}
 
Hi all,

Everything seems to work properly for the last few months, there is just one slight oddity.... On my Unifi networkcontroller I get a nice overview of all connected devices, when I connect one of my devices with the Teensy4.1 and QNEthernet it shows up nicely, but after some time (10 minutes or so) the device is invisible in the network. It still works and does everything it should, but it isn't visible on the clientlist or overview of Unifi OS. Weirdly enough, ALL teensy devices do this, but non of my other network and crappy IoT devices. What could be the issue here? I am calling yield() from the mainloop, something else I might have forgotten. Please don't ask for full firmware, I am not allowed to post that here online, I am sorry, specific ethernet parts can be posted.
 
See this post: #21
You don’t need to call yield() at the end of loop().

Can you define these terms: invisible in the network, isn’t visible on the clientlist.

For example, what does it mean for a connected device to be “visible”?

Do you mean a DHCP list? An mDNS services list? Something else? Is your system polling for something?
 
Hi Shawn,

Unifi keeps a list of devices that are connected to the network, DHCP is there, but when I give it a static IP it also is shown there. Down here you see a screenshot, the Teensy hostname is CCU_rev_B on the righthand column you can see the details of the device. I honestly don't know how this is done actually. When I make a connection to the device right after it is connected and keep the connection going, it stays alive as you can see for already 33m36s and counting. SO my best guess would be the yield() function is not yielding enough 😉. There is no waits in this project at all, it is completely different from the one this topic started with.

According to the Unifi website, it uses the mac address to show them in the overview, these are all Layer 3 switches, but the Asus consumer router I use at my customers site when I need to develop something there, has the same issue with the Teensy's. After a while they seem to dissapear, the only annoyance of that is that we can not check the router to see which IP address is assigned to the said Teensy after a while.

Checking post #21 again, now I see what is different indeed, I though the loop() function is always repeated in Arduino, so the while(1) looks a little weird to me.

My main routine looks like this at the moment:

Code:
void setup() {
    eUtils.begin();
    eUtils.initDone();
}


void loop() {
  eUtils.ethLinkHandler();
  eUtils.ethConnectionHandler(&ccu);
  eUtils.serialIncomingHandler(&ccu);
  eUtils.phyIncomingHandler(&ccu);
  if (ccu.eth.phyAvailable > 0) eUtils.commandHandler(SRC_PHY);

    if (millis() - stbMillis >= 10) {       // Tenth of a second
        stbMillis = millis();
        ledBlink++;
        if (ledBlink > 9) {
            ledBlink = 0;
            digitalWrite(BRD_INTLED, !digitalRead(BRD_INTLED));
        }
    }

    if (millis() - staMillis >= 1000) {     // Every second
        staMillis = millis();
        ccu.brd.upTime += 1;
        ccu.brd.tmrHeartbeat++;
        if (!(ccu.brd.upTime % 180)) {
            eUtils.respondStatus(INFO_ETHERNET);
            eUtils.respondStatus(INFO_CLIENTS, -1, -4);
        }
    }
    yield();
}

1723243162151.png
 
Last edited:
Post #21 describes how the main system calls your setup() and loop(). It’s a description of what’s happening under the hood; it’s not what you need to do, nor might it be exactly the same as what’s actually there. The gist is that your setup() is called once and your loop() is called repeatedly, and after each call, yield() is called. You don’t need to call yield() yourself. You’re saying that you are, in post #22:

I am calling yield() from the mainloop

Anyways, that’s not the meat of the problem. Maybe you could provide info on what exactly the Unifi stuff is doing to poll so that a device stays in its list. Maybe it needs some mDNS registration or something? I need more details before I can give advice or help. (Or say “I don’t know”.)

Also, what version of the QNEthernet library are you using? I made some fixes in 0.29.0 that solves an IGMP issue, and another in 0.29.1 that fixes a throughput problem I introduced in 0.29.0.
 
Back
Top