T4.1 Ethernet Library

vjmuzik

Well-known member
Native Ethernet Library​
With the release of Teensy 4.1 underway I went ahead and made a library to convert existing projects using a Wiznet W5500 along with Ethernet.h to be able to make use of it's Native Ethernet. As long as your sketch doesn't make direct calls to w5100.h it will work right out of the box with no existing API changes at this time.

To make use of the native ethernet you will have to download my fork of the FNET TCP/IP stack available at: https://github.com/vjmuzik/FNET
You will also need the wrapper library to go along with it: https://github.com/vjmuzik/NativeEthernet

This wrapper library does not currently support my USB Ethernet driver, that may change in the future.

It's as simple as changing <Ethernet.h> to <NativeEthernet.h>

If you have any questions or encounter any issues please post them here so they can be addressed or fixed.
 
Nice. Just ran "...\libraries\NativeEthernet\examples\UdpNtpClient\UdpNtpClient.ino" and it works! { with my Beta T-4.1 and OSH type PJRC magjack - using a 30cm/12" ribbon }

And it builds from editor with TSET CMDLine batch calling Arduino build without any issue.

I printed the IP and I can ping it! For some reason Sometimes I have to repower the Teensy after upload? It hits setup() and prints - but nothing after with code edit below. Is that from interrupting a packet in process or something? Reset the ethernet chip in setup()? This showed before adding teensyMAC(mac);
Code:
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  Serial.print("Ethernet connect ... \n");
  [B]teensyMAC(mac);[/B]
  if (Ethernet.begin(mac) != 0) {
    IPAddress myIP = Ethernet.localIP();
    Serial.printf( "IP Address %u.%u.%u.%u\n", myIP[0], myIP[1], myIP[2], myIP[3] );
  }
  else { // start Ethernet and UDP
    Serial.println("\nFailed to configure Ethernet using DHCP");


I see it has a hardcoded MAC - need to find Teensy MAC. >> https://forum.pjrc.com/threads/57595-Serial-amp-MAC-Address-Teensy-4-0?p=221833&viewfull=1#post221833

That code - called as above : teensyMAC(mac);
Uses this function with an #ifdef edited to compile from link:
Code:
void teensyMAC(uint8_t *mac) {

  static char teensyMac[23];
  
  #if defined(HW_OCOTP_MAC1) && defined(HW_OCOTP_MAC0)
    Serial.println("using HW_OCOTP_MAC* - see https://forum.pjrc.com/threads/57595-Serial-amp-MAC-Address-Teensy-4-0");
    for(uint8_t by=0; by<2; by++) mac[by]=(HW_OCOTP_MAC1 >> ((1-by)*8)) & 0xFF;
    for(uint8_t by=0; by<4; by++) mac[by+2]=(HW_OCOTP_MAC0 >> ((3-by)*8)) & 0xFF;

    #define MAC_OK

  #else
    
    mac[0] = 0x04;
    mac[1] = 0xE9;
    mac[2] = 0xE5;

    uint32_t SN=0;
    __disable_irq();
    
    #if defined(HAS_KINETIS_FLASH_FTFA) || defined(HAS_KINETIS_FLASH_FTFL)
      Serial.println("using FTFL_FSTAT_FTFA - vis teensyID.h - see https://github.com/sstaub/TeensyID/blob/master/TeensyID.h");
      
      FTFL_FSTAT = FTFL_FSTAT_RDCOLERR | FTFL_FSTAT_ACCERR | FTFL_FSTAT_FPVIOL;
      FTFL_FCCOB0 = 0x41;
      FTFL_FCCOB1 = 15;
      FTFL_FSTAT = FTFL_FSTAT_CCIF;
      while (!(FTFL_FSTAT & FTFL_FSTAT_CCIF)) ; // wait
      SN = *(uint32_t *)&FTFL_FCCOB7;

      #define MAC_OK
      
    #elif defined(HAS_KINETIS_FLASH_FTFE)
      Serial.println("using FTFL_FSTAT_FTFE - vis teensyID.h - see https://github.com/sstaub/TeensyID/blob/master/TeensyID.h");
      
      kinetis_hsrun_disable();
      FTFL_FSTAT = FTFL_FSTAT_RDCOLERR | FTFL_FSTAT_ACCERR | FTFL_FSTAT_FPVIOL;
      *(uint32_t *)&FTFL_FCCOB3 = 0x41070000;
      FTFL_FSTAT = FTFL_FSTAT_CCIF;
      while (!(FTFL_FSTAT & FTFL_FSTAT_CCIF)) ; // wait
      SN = *(uint32_t *)&FTFL_FCCOBB;
      kinetis_hsrun_enable();

      #define MAC_OK
      
    #endif
    
    __enable_irq();

    for(uint8_t by=0; by<3; by++) mac[by+3]=(SN >> ((2-by)*8)) & 0xFF;

  #endif

  #ifdef MAC_OK
    sprintf(teensyMac, "MAC: %02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
    Serial.println(teensyMac);
  #else
    Serial.println("ERROR: could not get MAC");
  #endif
}

An idea of code size now 71KB - might consider moving some startup or rare code as run from FLASHMEM?:
Code:
FlexRAM section ITCM+DTCM = 512 KB
    Config : aaaaaabf
    ITCM :  71024 B	(72.25% of   96 KB)
    DTCM :  25280 B	( 5.93% of  416 KB)
    Available for Stack: 400704
OCRAM: 512KB
    DMAMEM: 110784 B	(21.13% of  512 KB)
    Available for Heap: 413504 B	(78.87% of  512 KB)
Flash:  83344 B	( 1.03% of 7936 KB)
 
For some reason Sometimes I have to repower the Teensy after upload? It hits setup() and prints - but nothing after with code edit below. Is that from interrupting a packet in process or something?

Does it just print "Ethernet connect ..." and nothing else? If so, likely it's just DHCP taking longer to work, I haven't encountered this myself while testing, but you can verify this by using Wireshark when it happens and see if there is any activity.

If it makes it all the way through setup and freezes then there may be a bug somewhere I didn't notice(as I write this I remember I forgot to make sure the DHCP timeout works and I see it doesn't).

An idea of code size now 71KB - might consider moving some startup or rare code as run from FLASHMEM?

That's a good point, I'll see about this later once I know for certain everything works properly.
 
All the preloaded examples are just copied over from Ethernet.h so besides just changing the include name everything is the same. Also, I didn't know this existed to find the preloaded addresses, but it's definitely useful.

Assumed that was the case with the examples. Meant to ask if they were going to be Teensy-fied? That change makes startup more telling that setup() is under way … default sample only prints after .begin() completes.

I was going to simply complain about the mac - but recalled seeing something about it … did a search first and found that and AFAIK it is working as expected. Not sure where it should go - for NTP sample I dropped in the sketch - showed MAC and spew - then got another IP address :)

Will this same code work on a T_3.6 with the PJRC ethernet board? I have one of those from Beta. Not sure if the MCU hardware is the same - expect the PHY chip is different - and wired differently. Of course the 3.6 costs more { before building the more elaborate breakout with PHY } and while it has more pins - many edge pins get used for ethernet - so it may be a wash - even if the bottom pads are all used. …. so probably not worth the effort to lose speed and memory - and no add on QSPI.

Note: I have done upload some half dozen times with last edit and no hangs. Maybe that was when I swapped over to USBHost and back?
Code:
Ethernet connect ... 
using HW_OCOTP_MAC* - see https://forum.pjrc.com/threads/57595-Serial-amp-MAC-Address-Teensy-4-0
MAC: 04:e9:e5:01:86:c6
IP Address 192.168.0.169
Seconds since Jan 1 1900 = 3798354340
Unix time = 1589365540
The UTC time is 10:25:40
Seconds since Jan 1 1900 = 3798354351
Unix time = 1589365551
The UTC time is 10:25:51
 
Thanks for setting up separate thread. Here is my summary of T4.1 Ethernet testing that includes performance comparisons of NativeEthernet/FNET with lwIP and USB ethernet and 2016 T3.5/3.6 ethernet.
 
Assumed that was the case with the examples. Meant to ask if they were going to be Teensy-fied? That change makes startup more telling that setup() is under way … default sample only prints after .begin() completes.

I was going to simply complain about the mac - but recalled seeing something about it … did a search first and found that and AFAIK it is working as expected. Not sure where it should go - for NTP sample I dropped in the sketch - showed MAC and spew - then got another IP address :)

Will this same code work on a T_3.6 with the PJRC ethernet board? I have one of those from Beta. Not sure if the MCU hardware is the same - expect the PHY chip is different - and wired differently. Of course the 3.6 costs more { before building the more elaborate breakout with PHY } and while it has more pins - many edge pins get used for ethernet - so it may be a wash - even if the bottom pads are all used. …. so probably not worth the effort to lose speed and memory - and no add on QSPI.

Note: I have done upload some half dozen times with last edit and no hangs. Maybe that was when I swapped over to USBHost and back?
Code:
Ethernet connect ... 
using HW_OCOTP_MAC* - see https://forum.pjrc.com/threads/57595-Serial-amp-MAC-Address-Teensy-4-0
MAC: 04:e9:e5:01:86:c6
IP Address 192.168.0.169
Seconds since Jan 1 1900 = 3798354340
Unix time = 1589365540
The UTC time is 10:25:40
Seconds since Jan 1 1900 = 3798354351
Unix time = 1589365551
The UTC time is 10:25:51

I don't have any defines setup in FNET for it to work right now, but it did natively support that processor, presumedly I would just have to make the same changes to that processor code that I did for the 4.1 for it to work. As you say though considering the price difference and the loss of many pins it's not worth it for anyone to really even consider using it.
 
New update that allows customization of buffers from the sketch without editing the library(though you still could if you wanted to), buffers are now allocated using new to allow this.

This has a max number that is defined in FNET so if you need more sockets than the default 12 you have to edit the define FNET_CFG_SOCKET_MAX over there as well.

To make use of this you just add the new functions before Ethernet.begin like so:
Code:
Ethernet.setStackHeap(1024 * 128); //Set stack size to 128k
Ethernet.setSocketSize(1024 * 4); //Set buffer size to 4k
Ethernet.setSocketNum(6); //Change number of allowed sockets to 6
Ethernet.begin(mac);

I've only done minimal testing so if anything breaks let me know.
 
New update that allows customization of buffers from the sketch without editing the library(though you still could if you wanted to), buffers are now allocated using new to allow this.

I've only done minimal testing so if anything breaks let me know.

Nice! Works for me.

thanks
 
I realized I never replied to this thread, despite writing out a whole post with the intent to. I just wanted to say thank you vjmuzik (and defragster!) your work made my transition so easy that I've been using it for nearly a month and I haven't had to think about it.

I think that's a sure-fire sign of a job well done.

Also, manitou, I haven't taken a look at your tftp server yet, but I love the idea of it and it's definitely on my big board of "do something fun with this" :]

Edit to add: Oh, I wanted to add that I'm building via PlatformIO in vscode, pointing the lib_deps directly to your repo. My ribbon(5")/magjack is the ones Paul recommended. Everything has been working flawlessly out of the box.
 
Last edited:
Hello!
I'm in the process of creating an Art-Net pixel controller based on teensy 4.1.
And I'm trying to use your NativeEthernet lib, but can't get past
Code:
Serial.println("ETH conf OK");
in my following code:

Code:
#include <NativeEthernet.h>
#include <NativeEthernetUdp.h>

IPAddress ip(2, 0, 0, 1);
unsigned int localPort = 8888;

char packetBuffer[UDP_TX_PACKET_MAX_SIZE];
EthernetUDP Udp;

static void teensyMAC(uint8_t *mac) {
  uint32_t m1 = HW_OCOTP_MAC1;
  uint32_t m2 = HW_OCOTP_MAC0;
  mac[0] = m1 >> 8;
  mac[1] = m1 >> 0;
  mac[2] = m2 >> 24;
  mac[3] = m2 >> 16;
  mac[4] = m2 >> 8;
  mac[5] = m2 >> 0;
}

void setup() {
  // Serial starting
  Serial.begin(9600);
  while(!Serial);
  delay(5000);
  Serial.println("Serial OK");

  // ethernet/UDP starting
  Ethernet.setStackHeap(1024 * 64);
  Ethernet.setSocketSize(1024 * 16);
  Ethernet.setSocketNum(1);
  uint8_t mac[6];
  teensyMAC(mac);
  Serial.println("ETH conf OK");
  Ethernet.begin(mac, ip);
  Serial.println("ETH begin");
  if (Ethernet.hardwareStatus() == EthernetNoHardware) {
    while (true) {
      Serial.println("Ethernet shield was not found. Sorry, can't run without hardware. :(");
      delay(1000);
    }
  }
  if (Ethernet.linkStatus() == LinkOFF) {
    while (true) {
      Serial.println("Ethernet cable is not connected.");
      delay(1000);
    }
  }
  Serial.println("ETH OK");
  Serial.print("IP address: ");
  Serial.println(Ethernet.localIP());
  Udp.begin(localPort);
}

void loop() {
  int packetSize = Udp.parsePacket();
  if (packetSize) {
    Serial.print("Received packet of size ");
    Serial.println(packetSize);
    Serial.print("From ");
    IPAddress remote = Udp.remoteIP();
    for (int i=0; i < 4; i++) {
      Serial.print(remote[i], DEC);
      if (i < 3) {
        Serial.print(".");
      }
    }
    Serial.print(", port ");
    Serial.println(Udp.remotePort());

    // read the packet into packetBufffer
    Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
    Serial.println("Contents:");
    Serial.println(packetBuffer);
  }
  delay(10);
}

I'm using your latest lib on github: NativeEthernet and FNET.

I tried on a brand new teensy 4.1 with nothing attached to it (e.g. no ethernet) and also with a teensy 4.1 on a custom PCB as show below, and the results are the same.
Any idea ?

IMG_20200616_115623.jpg
 
Have you tried using DHCP, there may be an IP conflict if it doesn’t get past the Ethernet.begin, I forgot to set that up so it makes sure it’s not using an address already in use. Also doing DHCP doesn’t use up any sockets so you don’t have to worry about that not working when you only want to use 1 socket.
 
Do I need to have the ethernet circuitry and ethernet cabled for the `Ethernet.begin` to be successful ?

I don't have any dhcp server since the network is only my computer (2.0.0.254/255.0.0.0) and the teensy (2.0.1.1) with a working switch.
 
Ok so it's working now as in I can ping the board.

I had to configure it like the following:

Code:
IPAddress ip(2, 0, 1, 1);
IPAddress gateway(2, 0, 0, 1);
IPAddress subnet(255, 0, 0, 0);

//...

void setup() {
  // ...
  teensyMAC(mac);
  Ethernet.begin(mac, ip, gateway, gateway, subnet);
  // ...
}

Will let you know how it goes.

And thanks for your quick reply, very appreciated :+1:
 
An Ethernet cable does have to be connected to something for it to get past that, I’ve been testing it directly connected to my laptop that’s been acting as a DHCP server so I haven’t tested without it. The problem was probably the IP address being x.x.x.1 since the first device would be the gateway, if you only supply the IP address the gateway is automatically assembled by using the first three bytes of the IP and setting the last byte to 1. So by giving it an IP of 2.0.0.1 it comes up with a gateway of 2.0.0.1 which of course would conflict with the IP. If you just changed the IP to 2.0.0.2 it should function correctly, I will make sure to put in a check for this so it won’t happen in the future.
 
vjmuzik, lots of thanks for your recommendation. i will try it to see how it works. may i ask you other questions in the meantime if you don't mind? thanks again
 
To my knowledge it shouldn’t interfere with anything, the only resource I’m using that could potentially cause problems is an interval timer that polls the network stack every millisecond. But, I don’t believe that should be an issue for DMA or FLEXIO.
 
Hello vjmuzik,

Is it possible your lib is conflicting with this one: https://github.com/wramsdell/TriantaduoWS2811https://delicerecipes.com ?

I have all the Ethernet/Art-Net part ok, I also have some functional code with TriantaduoWS2811 alone.

But when I plug both together, I still have artnet but I cannot light my leds?

Any idea?

Regards

found a solution? is quite strange that you don't get any issues when using them separately and when plug together they don't work. just interested...
 
Small update:
Code:
[B]Cleanup and enhancements[/B]
- Removed unused items that were no longer in use or not used at all
- Offloaded DNS lookup to FNET methods so it no longer uses a socket from the wrapper library
 
Is NativeEthernet (and FNET) at a point where it can be included with a Teensyduino installer?

I'm getting ready to package up 1.53-beta3....
 
Back
Top