SMSC LAN9512 / SMSC LAN9514 dev board by matrixstorm / matrixprog

Stephan Bärwolf aka. Matrixstorm aka. matrixprog created a circuit board for the  SMSC LAN9512 / LAN9514 USB controller ethernet chip. This page describes my advances with his board.

About the LAN951X Chip

The company SMSC was aquired by Microchip and created the LAN9512 and LAN9514 chips. These chips are USB hub controllers and also contain an ethernet controller. They allow to convert USB transfers to ethernet packets. The LAN9512 supports 2 USB ports, the LAN9514 supports 4 USB Ports, the last digit determines the amount of supported USB ports.

The LAN951X is important because it is used in the early Raspberry Pi Models and the BeagleBone boards. When writing an operating system for those boards, it is required to have a working driver for the LAN951X controller.

An open source driver for the LAN951X exists in the linux operating system and also in the embedded Xinu codebase. A custom operating system can model those drivers.

About Matrixstorm’s Board

Matrixstorm’s Board is described on several forum entries and in one github repository.

The second link contains images of a carrier board that contains Ethernet Jacks to which the LAN951X board is attached.

Next Steps…

  • Prepare the reflow oven.
  • Assemble the board.
  • Add interfaces (USB plug and ethernet connector)
  • Attach the entire board to a windows PC via USB for testing.

Using the ASIX USB Ethernet controller with the Teensy 4.1

This blog post documents how a ASIX USB Ethernet adapter can be connected to a Teensy 4.1 board. As USB ethernet adapter, the widely supported (Linux drivers exist) adapter from Olimex is used. It contains the ASIX USB ethernet controller chip.

The Teensy board contains native ethernet support. This article is not about the native ethernet on the teensy but rather about the native USB host controller support that the teensy has. This article describes how to connect a ASIX USB Ethernet adapter to the USB controller on the teensy 4.1 to send ethernet packets to an IP address.

The FNET library contains an example called ASIXEthernet_Test.ino. This example can be executed on the Teensy 4.1 via the Arduino IDE.

The FNET example imports the ASIX driver for the Teensy which is contained in this repository. So first, install the FNET library and the TeensyASIXEthernet library via .zip or via the library manager into your Arduino IDE.

The teensy 4.1 comes in several offers. One option is to buy a Teensy that already has pin headers soldered in by a professional so you do not have to solder anything. If you have a teensy 4.1 that has no pins soldered to the USB contacts on the board, solder five pins in. This page contains pictures on where the USB cables are connected on the Teensy 4.1 and this shows you where to solder the USB pin header in. If you turn the Teensy 4.1 around, the bottom of the PCB contains the pin names on the bottom silk screen. USB On the Go added a fifth pin. This fifth pin is just connected to ground on the host side of a normal USB connection. For this example, only four of the five pins are required. The pins are 5V (red), D- (white), D+ (green) and ground (black).

As usual soldering makes better contact than just loosely sticking pin headers into the holes. The contact is only really established through the solder! If your setup does not work (No USB or ethernet connection), check your soldering again! For myself, it only worked after fixing my solder work once.

The next step is to connect the ASIX USB ethernet controller to the USB pins. For that, you can purchase USB adapter cables that have headers on one side and a USB port connector (MAKE SURE TO NOT ACCIDENTLY BUY A USB PLUG CABLE BUT A USB PORT CABLE!) on the other side. A depiction of such a cable is given here. Plug in the ASIX USB ethernet adapter in either directly or indirectly via a USB hub if you like. Connect a ethernet wire to the adapter and connect it to your home network that should contain a DHCP server so that the FNET stack can retrieve an IP address.

In the Arduino IDE open the FNET example sketch ASIXEthernet_Test.ino. Compile it and upload it to the teensy 4.1. Do not forget to change the target hardware to the Teensy 4.1 board in your Arduino IDE. If you target the wrong board, the headers used in the example sketch will not be found.

Unplug and reconnect the Teensy to your computer via USB to give it power. Open the serial monitor and wait. The example sketch will start the FNET stack in the background, this will take some time and there is no output whatsoever that tells you to wait. Once the stack is done, it will retrieve a IP address via DHCP and output something similar to this:

SetMACAddress: 00001001B3BD
netif Initialized
Initializing DHCP
DHCP initialization done!
State: 2
State: 5

The LEDs inside the USB Ethernet adapter casing should begin to light up and flicker.

Once you see this output, it is time to instruct the Teensy to send ethernet packets. In order to do that, the example sketch uses the FNET benchmark code. You can start the benchmark by sending a command to the Teensy via the Serial Monitor’s send feature. The benchmark has several options so here is one example command:

benchtx -a udp -m 1272

First of all: You have to send a space after the last character. So before sending this command, make sure there is a trailing space! The parser of the FNET benchmark code is very peculiar about the input it wants to accept! If there is no space, the command is rejected!

The benchmark tools command line is:

benchtx -a <remote_ip> [tcp|udp] [-m <message size>] [-mn <number of messages>]

For me, the last optional flag -mn never was accepted by the parser hence the example command above does not specify a message number. The default message number of 10000 messages is used. The message size default value is 1272. The example command uses UDP for no specific reason. The remote IP is the IP of the device in your local network that should receive the ethernet packets.

The FNET benchmark code will blast out 10000 packets as fast as it can not careing about packet loss or anything. It will not wait in between packets and it will output a single line of statistics about the burst send after it is done.

Megabytes: 0.587664  Seconds: 0.1250  KBits/Sec: 37610.4960

In a running instance of wireshark on the remote machine, you can see some of the 10000 packets arrive. If you have a means to count the incoming packets, you could check how many of the UDP packets actually made it and you could compute the success rate of the burst transfer.

Receiving Ethernet Packets

For receiving ethernet packets over the ASIX USB Ethernet Adapter, the code in the ASIX example has to be modified! The code contains a variable called MacAddress.

uint8_t MacAddress[6] = {0x00,0x50,0xB6,0xBE,0x8B,0xB4};

The MacAddress variable contains the six byte long MacAddress that is used to participate in an Ethernet Network. The MacAddress uniquely identifies the Ethernet Adapter in an Ethernet Network just as the IP-Address identifies a node in an IP Network.

In contrast to an IP Address, which has local scope (per subnet and local LAN) and which can be dynamically leased by a DHCP server and hence is not necessarily unique globally, a MacAddress is a globally unique identifier.

Every Ethernet capable device gets a unique MacAddress assigned by the vendor or manufacturer of the device. The Olimex Adapter has a unique MacAddress. This MacAddress differs from the MacAddress that is part of the ASIX example code!

Using the MacAddress from the ASIX example without change causes the example code to send Ethernet frames into the network that contain this incorrect MacAddress. Communication partners will then answer using that incorrect MacAddress. The Olimex Adapter will see the ethernet frames and it will compare it’s own MacAddress to the one contained in the frames. It will decide that those frames are directed at another participant because the MacAddresses do not match! It will then discard those frames and your code will not ever receive even a single frame!

To solve the problem, determine the MacAddress of your particular Olimex adapter and update the example code with that MacAddress. One way to determine the MacAddress is to plug the adapter into a windows host and on the command line, execute the ipconfig /all command with lists the MacAddress.

One tip for safety, keep you MacAddresses off the Internet, that means do not check in your MacAddress into a git repository, just as you do not check in any passwords into git repositories. If someone really wants to hurt you, commiting your MacAddress to git connects the MacAddress to your person or git account which opens up a way for attackers.

Sending and Receiving Speeds

For sending out Ethernet frames, your code can send as fast as possible because the performance of the Teensy 4.1 CPU and the speed of the USB controller and ethernet PHY naturally limit the amount of packets send. Packets will most likely not be lost during the send operation. The chips will process the packets when they get to it.

On the receiving side, I encountered problems. Sending from a MAC Book Pro which has a fast CPU and a really high quality ethernet chip can easily overpower the Teensy 4.1 with the Olimex Adapter attached. Packets where dropped and not received. I assume that because USB is a polled bus that if your system does not poll fast enough, ethernet frames are just dropped.

Another test showed that when connecting the Olimex Adapter to a powerfull business laptop running windows, the same effect can be observed. Even on capable hardware, the Olimex Adapter drops frames.

To test the situation, I used the code from

Here, a byte array of data is sent to a MacAddress of your choice, which is the Olimex adapter’s MacAddress in this test. The byte array is larger that the maximum allowed length of a single ethernet frame hence the code constructs several frames and sends them out. In this test, four frames are send. The variable in the test is the amount of time the  code sleeps (usleep(uint microseconds)) between each of the four ethernet frames.

Using wireshark, on the sender’s side, it is checked how many frames are really sent by the test program. Using wireshark on the receiver’s side, it is checked how many packets are actually received.

The breaking point for the Olimex adapter seems to be a sleep time of 1 ms. Sleeping more than 1 ms causes the Windows Machine to receive every single frame correctly.

Going down to 1 ms and lower, causes the Windows machine to not receive all packets. Because this effect shows on the windows machine and on the Teensy, I have to assume that it is a problem with the Olimex USB adapter and not in the example code or in windows. It might also be because USB is a polled bus, but the Business laptop should be able to poll the USB Adapter faster than the Teensy but still the same effect is noticeable.

With a lossless protocol such as TCP, lost packets will be retransmitted and the transfer should be possible even if the sender overwhelmes the receiver. With a lossy ethernet or UDP connection, this is a real problem!


The amazing thing about all this is that you have the code for an open source TCP/IP stack (FNET) and a working ASIX driver ( that works over USB.

For learning about the USB protocol, I personally feel that this setup is a very motivating one because it allows you to learn about USB, TCP/IP and the low-level driver development in one go. This might be too much at once and become overwhelming pretty quickly but I think being overwhelmed is better than loosing interest because of a lack of exiting experiments.

Another big plus is that the USB connection to the ethernet adapter allows you to port the ASIX driver to any embedded system that has a USB host controller and that you want to connect to ethernet. This will work even if the embedded device has no native ethernet support or even if it has native ethernet support but there is no open source driver for the ethernet controller chip or if you do not understand the open source driver yet.

Anyways, I hope you took something away from reading this article. Thank you for your interest in my page.

Using a SNES Controller with an Arduino on a PC

Inspired by this github repository and the accompanying YouTube video, I want to write down the steps I followed to get a SNES controller working on a PC without bying any SNES adapters or permanently and irreversibly modifying the controller.

The idea is that an Arduino is used to adapt the SNES controller to a USB HID Joystick device that the PC can use to control an emulator. For that the Arduino’s USB connector chip MEGA16u2 that takes care of the USB protocol on the Arduino is reprogrammed by flashing custom firmware to it. The solution also is able to flash back the original Arduino USB firmware, so you will not permanently alter your Arduino.

The USB firmware is contributed by the UnoJoy project which has it’s repository under UnoJoy supports the PS3 controller out of the box but not the SNES controller. burks10 added a sketch that is able to interpret the SNES commands and insert them into the data structures that the UnoJoy project mandates.

The software architecture is as follows. The USB protocol mandates that the USB controller inside your PC polls USB HID devices for input state. That means that the MEGA16u2 chip on the Arduino is constantly polled for input data. The custom UnoJoy firmware that is flashed to the MEGA16u2 will read a dataForController_t data structure from the sketch that runs on the Arduino. It will return this information back to the USB controller. The sketch on the Arduino will poll the SNES controller and it will interpret the signals as button or dpad presses. It will fill in the dataForController_t with the SNES controller’s button state. This is how a button press makes it from the SNES controller through the MEGA16u2 chip, through USB, through the PC’s USB controller to the emulator.

When the newly flashed Arduino is plugged in into the PC, it will register with the operating system as a HID Joystick. Selecting this HID Joystick in your emulator allows you to read input from this device.

Here are the steps in detailed order:

Hint / Important

Turn off USB Helper
Turn off all tools that might interfere with USB such as USB Overdrive.

Wire Up the SNES controller to the arduino.

Locking at the controller plug, there is a rounded corner and a flat corner.
Putting the flat corner on the left and the rounded corner on the right, the pins are numerate 1 through 7:

| 1 2 3 4 | 5 6 7 )

Connect Pin 1 on the controller to 5V on the Arduino, that means:

Controller Pin 1 <-> Arduino 5V
Controller Pin 2 <-> Arduino Pin 6
Controller Pin 3 <-> Arduino Pin 7
Controller Pin 4 <-> Arduino Pin 12
Controller Pin 7 <-> Arduino GND

Upload the correct sketch to the Arduino

git clone
Open Arduino IDE on the file snes/snes.ino
As a board, select the ardunio uno.
Validate and upload the sketch.

Install the dfu-programmer


sudo port install dfu-programmer

Install libusb and libusb-compat

Turn on DFU mode

Short the 2 pins closest to the USB port to enter DFU mode

Prepare the flashing of new firmware for the Ardunio USB controller chip

git clone
cd UnoJoy/UnoJoy

Edit the file TurnIntoAJoystick.command file

Replace all occurences of ./dfu-programmer by dfu-programmer

Make it executable and run the command file:

chmod a+x TurnIntoAJoystick.command

Connect the Ardunio to the PC

Unplug the arduino and plug it back in

Check if MacOS has detected a controller

MacIcon in the top left > About this Mac > Overview > System Report … > USB > check if there is an entry alled ‘UnoJoy Joystick’

Reverting the process (Getting back the normal Arduino Behaviour)

If you want your arduino back, enter DFU mode again.
While the arduino is plugged in to USB, short the pins shortest to the USB port.

Modify the file TurnIntoAnArduino.command and replace all occurences of ./dfu-programmer by dfu-programmer

Make it executable and run the command file:

chmod a+x TurnIntoAnArduino.command