Skip to main content

Ethernet

TinyCLR supports three Ethernet paths:

  • Built-in Ethernet — uses the SITCore's internal MAC paired with an external PHY (100BASE-TX). Fastest option, available on SC20xxx.
  • ENC28J60 — a small 10BASE-T Ethernet controller from Microchip that connects over SPI. Common as a low-cost add-on.
  • Wiznet W5500 — SPI Ethernet with a built-in TCP/IP stack, so it can give SC13048 (which has no on-chip networking) full networking via its own driver.

Some carrier boards include the PHY and magnetics in-line with the RJ45 jack; for those you only need to add the RJ45 connector with built-in magnetics to your design.

warning

Every shipped device needs a valid, unique MAC address. See MAC addresses for guidance.

Built-in Ethernet

The example below uses the internal MAC of the SC20260 paired with an external PHY, and sets up DHCP. The external PHY is reset via GPIO PG3 before the network controller is enabled.

NuGet packages: GHIElectronics.TinyCLR.Devices.Network, GHIElectronics.TinyCLR.Devices.Gpio, GHIElectronics.TinyCLR.Pins.

using System;
using System.Diagnostics;
using System.Net;
using System.Threading;
using GHIElectronics.TinyCLR.Devices.Gpio;
using GHIElectronics.TinyCLR.Devices.Network;
using GHIElectronics.TinyCLR.Pins;

bool linkReady = false;

void EthernetTest(){
// Reset the external PHY.
var gpioController = GpioController.GetDefault();
var resetPin = gpioController.OpenPin(SC20260.GpioPin.PG3);

resetPin.SetDriveMode(GpioPinDriveMode.Output);
resetPin.Write(GpioPinValue.Low);
Thread.Sleep(100);
resetPin.Write(GpioPinValue.High);
Thread.Sleep(100);

var networkController = NetworkController.FromName(SC20260.NetworkController.EthernetEmac);

var networkInterfaceSetting = new EthernetNetworkInterfaceSettings{
Address = new IPAddress(new byte[] { 192, 168, 1, 122 }),
SubnetMask = new IPAddress(new byte[] { 255, 255, 255, 0 }),
GatewayAddress = new IPAddress(new byte[] { 192, 168, 1, 1 }),
DnsAddresses = new IPAddress[] {
new IPAddress(new byte[] { 75, 75, 75, 75 }),
new IPAddress(new byte[] { 75, 75, 75, 76 }),
},
MacAddress = new byte[] { 0x00, 0x04, 0x00, 0x00, 0x00, 0x00 },
DhcpEnable = true,
DynamicDnsEnable = true,
};

var networkCommunicationInterfaceSettings = new BuiltInNetworkCommunicationInterfaceSettings();

networkController.SetInterfaceSettings(networkInterfaceSetting);
networkController.SetCommunicationInterfaceSettings(networkCommunicationInterfaceSettings);
networkController.SetAsDefaultController();

networkController.NetworkAddressChanged += NetworkController_NetworkAddressChanged;
networkController.NetworkLinkConnectedChanged += NetworkController_NetworkLinkConnectedChanged;

networkController.Enable();

while (!linkReady) ;
Debug.WriteLine("Network is ready to use");
Thread.Sleep(Timeout.Infinite);
}

The event handler implementations are shown in Event handlers below.

ENC28J60

The Microchip ENC28J60 is a low-cost 10BASE-T Ethernet controller that connects over SPI. The example below uses the ENC28 click on an SC20260D Dev Board.

NuGet packages: GHIElectronics.TinyCLR.Devices.Network, GHIElectronics.TinyCLR.Devices.Gpio, GHIElectronics.TinyCLR.Devices.Spi, GHIElectronics.TinyCLR.Pins.

using System;
using System.Diagnostics;
using System.Net;
using System.Threading;
using GHIElectronics.TinyCLR.Devices.Gpio;
using GHIElectronics.TinyCLR.Devices.Network;
using GHIElectronics.TinyCLR.Devices.Spi;
using GHIElectronics.TinyCLR.Pins;

bool linkReady = false;

void Enc28Test(){
var gpioController = GpioController.GetDefault();
var networkController = NetworkController.FromName(SC20260.NetworkController.Enc28j60);

var cs = gpioController.OpenPin(SC20260.GpioPin.PG12);

var spiSettings = new SpiConnectionSettings{
ChipSelectLine = cs,
ClockFrequency = 4_000_000,
Mode = SpiMode.Mode0,
ChipSelectType = SpiChipSelectType.Gpio,
ChipSelectHoldTime = TimeSpan.FromTicks(10),
ChipSelectSetupTime = TimeSpan.FromTicks(10),
};

var networkCommunicationInterfaceSettings = new SpiNetworkCommunicationInterfaceSettings{
SpiApiName = SC20260.SpiBus.Spi3,
GpioApiName = SC20260.GpioPin.Id,
SpiSettings = spiSettings,
InterruptPin = gpioController.OpenPin(SC20260.GpioPin.PG6),
InterruptEdge = GpioPinEdge.FallingEdge,
InterruptDriveMode = GpioPinDriveMode.InputPullUp,
ResetPin = gpioController.OpenPin(SC20260.GpioPin.PI8),
ResetActiveState = GpioPinValue.Low,
};

var networkInterfaceSetting = new EthernetNetworkInterfaceSettings{
Address = new IPAddress(new byte[] { 192, 168, 1, 122 }),
SubnetMask = new IPAddress(new byte[] { 255, 255, 255, 0 }),
GatewayAddress = new IPAddress(new byte[] { 192, 168, 1, 1 }),
DnsAddresses = new IPAddress[] {
new IPAddress(new byte[] { 75, 75, 75, 75 }),
new IPAddress(new byte[] { 75, 75, 75, 76 }),
},
MacAddress = new byte[] { 0x00, 0x04, 0x00, 0x00, 0x00, 0x00 },
DhcpEnable = true,
DynamicDnsEnable = true,
};

networkController.SetInterfaceSettings(networkInterfaceSetting);
networkController.SetCommunicationInterfaceSettings(networkCommunicationInterfaceSettings);
networkController.SetAsDefaultController();

networkController.NetworkAddressChanged += NetworkController_NetworkAddressChanged;
networkController.NetworkLinkConnectedChanged += NetworkController_NetworkLinkConnectedChanged;

networkController.Enable();

while (!linkReady) ;
Debug.WriteLine("Network is ready to use");
Thread.Sleep(Timeout.Infinite);
}

Event handlers are shared with the Built-in Ethernet example — see Event handlers below.

Wiznet W5500

The Wiznet W5500 has a built-in TCP/IP stack, making it ideal for SC13048, which doesn't have on-chip networking. It also works with SC20xxx as a SPI Ethernet alternative.

note

Because the TCP/IP stack runs on the W5500 itself, the W5500 driver provides its own Dns and Socket classes — you don't use System.Net.Sockets for W5500 connections.

NuGet packages: GHIElectronics.TinyCLR.Drivers.WIZnet.W5500, GHIElectronics.TinyCLR.Drivers.BasicNet, GHIElectronics.TinyCLR.Drivers.BasicNet.Sockets.

The example below performs an HTTP GET to www.example.com using the ETH WIZ click on an SC13048 Development Board.

using GHIElectronics.TinyCLR.Devices.Gpio;
using GHIElectronics.TinyCLR.Devices.Spi;
using GHIElectronics.TinyCLR.Drivers.BasicNet;
using GHIElectronics.TinyCLR.Drivers.BasicNet.Sockets;
using GHIElectronics.TinyCLR.Drivers.WIZnet.W5500;
using GHIElectronics.TinyCLR.Pins;
using System.Diagnostics;
using System.Net;
using System.Text;

var cs = GpioController.GetDefault().OpenPin(SC13048.GpioPin.PB2);
var reset = GpioController.GetDefault().OpenPin(SC13048.GpioPin.PB15);
var interrupt = GpioController.GetDefault().OpenPin(SC13048.GpioPin.PA0);

var spiController = SpiController.FromName(SC13048.SpiBus.Spi1);

var networkController = new W5500Controller(spiController, cs, reset, interrupt);
var isReady = false;

networkController.NetworkAddressChanged += (a, b) => {
var bytes = networkController.Address.GetAddressBytes();
isReady = bytes[0] != 0 && bytes[1] != 0;
};

var networkSettings = new NetworkInterfaceSettings {
Address = new IPAddress(new byte[] { 192, 168, 0, 200 }),
SubnetMask = new IPAddress(new byte[] { 255, 255, 255, 0 }),
GatewayAddress = new IPAddress(new byte[] { 192, 168, 0, 1 }),
DnsAddresses = new IPAddress[] {
new IPAddress(new byte[] { 75, 75, 75, 75 }),
new IPAddress(new byte[] { 75, 75, 75, 76 }),
},
MacAddress = new byte[] { 0x00, 0x04, 0x00, 0x00, 0x00, 0x00 }, // Set to a valid, unique MAC.
DhcpEnable = false,
DynamicDnsEnable = false,
};

networkController.SetInterfaceSettings(networkSettings);
networkController.Enable();

while (!isReady) ; // Wait for a valid IP address.

// HTTP GET — uses the W5500 driver's Dns and Socket classes, not System.Net.Sockets.
var dns = new Dns(networkController);
var host = dns.GetHostEntry("www.example.com");
var ep = new IPEndPoint(host.AddressList[0], 80);

var socket = new Socket(networkController, AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect(ep);

var request = "GET / HTTP/1.1\r\nHost: www.example.com\r\nConnection: close\r\n\r\n";
socket.Send(Encoding.UTF8.GetBytes(request));

var received = socket.Receive(SocketFlags.None);

if (received.Length > 0) {
var content = new string(Encoding.UTF8.GetChars(received));
Debug.WriteLine("Received:\r\n" + content);
}

Event handlers

The built-in and ENC28J60 examples both wire two events on the NetworkController:

  • NetworkAddressChanged — fires once an IP address is assigned (whether by DHCP, static config, or AutoIP).
  • NetworkLinkConnectedChanged — fires when the physical link state changes (cable plugged in or removed).
void NetworkController_NetworkLinkConnectedChanged(NetworkController sender, NetworkLinkConnectedChangedEventArgs e){
Debug.WriteLine(e.Connected ? "Link connected" : "Link disconnected");
}

void NetworkController_NetworkAddressChanged(NetworkController sender, NetworkAddressChangedEventArgs e){
var ipProperties = sender.GetIPProperties();
var address = ipProperties.Address.GetAddressBytes();
var subnet = ipProperties.SubnetMask.GetAddressBytes();
var gateway = ipProperties.GatewayAddress.GetAddressBytes();

linkReady = address[0] != 0;
Debug.WriteLine("IP: " + address[0] + "." + address[1] + "." + address[2] + "." + address[3]);

for (int i = 0; i < ipProperties.DnsAddresses.Length; i++){
var dns = ipProperties.DnsAddresses[i].GetAddressBytes();
Debug.WriteLine("DNS " + (i + 1) + ": " + dns[0] + "." + dns[1] + "." + dns[2] + "." + dns[3]);
}
}

API reference

NamespaceDescription
GHIElectronics.TinyCLR.Devices.NetworkNetwork interface controller for Ethernet and WiFi