ENC28J60 Ethernet chip driver for CircuitPython 7.2 (RP2)
ENC28J60 is a popular and cheap module for DIY projects. At the moment, however, there is no driver for the MicroPython environment. The Python implementation seems easy for further improvements and self adaptation.
- Go to
CircuitPython-ENC28J60/CircuitPython_version/
- Copy all .py files to CURCUITPY
- Copy dir adafruit_bus_device to CURCUITPY/lib/
- Go to
CircuitPython-ENC28J60/
- Run udp_server.py
- Check your connections and wiring
- Your system and pico must be in same network!
- Default Addresses:
- udp_server.py: IP=192.168.1.200 PORT=5000
- You can change the Address in udp_server.py file
if __name__ == '__main__': try: main('192.168.1.200', port=5000, ack=True) except KeyboardInterrupt: if system() == 'Windows': run(['cls']) elif system() == 'Linux': run(['clear']) kill(pid, SIGTERM)
- pico: IP=192.168.1.198 PORT=6000 GATEWAY=192.168.1.1
- You can change the Address in conf.py file
### PICO: ## ENC28J60: # Set static IP address CLIENT_IP: list = [192, 168, 1, 198] CLIENT_PORT: int = 6000 SUB_NET: list = [255, 255, 255, 0] GATEWAY: list = [192, 168, 1, 1] # Server_address SERVER_IP: list = [192, 168, 1, 200] SERVER_PORT: int = 5000 # DoS_config DOS_CONFIG: tuple = (50, 90, 150, 150) # ARP=50, ICMP=90, TCP=150, UDP=150
- udp_server.py: IP=192.168.1.200 PORT=5000
Wiring requires pins for SPI: SCK, MISO, MOSI and ChipSelect and optionally Interrupt. Example wiring that uses SPI1 bus (any SPI bus can be used):
ENC28J60 Module | RP2040 Board | Notes |
---|---|---|
VCC | 3V3 | requires up to 180 mA |
GND | GND | |
SCK | GP10 | SPI1 SCK |
MOSI | GP11 | SPI1 MOSI/TX |
MISO | GP12 | SPI1 MISO/RX |
CS | GP13 | SPI1 CSn |
# ----------------------------- Libraries and Modules ----------------------------- #
# builtin libs:
from gc import collect
from time import sleep, time
from random import choice
from conf import *
# external libs:
from Transport import UDP, DEAD
__version__ = '1.0.0v'
__repo__ = 'https://github.com/mehrdad-mixtape/CircuitPython-ENC28J60'
# ----------------------------- Device Initialization ----------------------------- #
## Initial Ethernet:
ethernet: UDP = UDP(spi_bus_1, cs_10, CLIENT_IP, SUB_NET, SERVER_IP, SERVER_PORT, GATEWAY,
src_port=CLIENT_PORT, dos_conf=DOS_CONFIG, ttc=10)
# ----------------------------- Start ----------------------------- #
def main() -> None:
"""Main function to drive all sensors"""
for _ in range(0, 5):
ethernet.send_request(which='alive', waiting_for=2)
if ethernet.is_server_alive:
ethernet.tx_packet(f"id>>I'm Pico"); break
ethernet.send_request(which='ntp') # request localtime
ethernet.date_and_time()
start: int = time()
threshold: int = 0
while True:
if ethernet.kill_switch_stat:
# Ready for ARP, ICMP, IP, UDP, ... ---------------------------------------------
ethernet.rx_packet()
# Threshold: ---------------------------------------------
threshold = time() - start
print(f"Threshold is {threshold}")
print(f"Server is {'Alive' if ethernet.is_server_alive else 'Dead'}")
print(f"UDP_Q={ethernet.udp_q_stat}")
ethernet.date_and_time()
# Update Clock: ---------------------------------------------
if threshold % 10 == 0: # send random udp packet
ethernet.tx_packet(choice(['msg>>Hello Pico', 'MixTape', 'ENC28J60 with CircuitPython']))
elif 59 <= threshold < 60: # update date and time
ethernet.send_request(which='ntp')
elif 79 <= threshold < 80: # check the connection and is server alive?
ethernet.send_request(which='alive', waiting_for=3)
elif 89 <= threshold < 90: # renew threshold and empty UDP_Q, ICMP_Q, ARP_Q, TCP_Q
ethernet.cool_down(timer=0)
start = time()
if ethernet.is_server_alive:
ethernet.parse_udp()
# Cycle Speed: ---------------------------------------------
sleep(1); collect() # free up memory space
else: # Under Attack
print('Pico Under Attack! CoolDown ...')
ethernet.tx_packet('Critical DOS Attack!')
ethernet.cool_down(timer=30, msg='UnderDOSAttack', op='CoolDown')
collect() # free up memory space
start = time()
if __name__ == '__main__':
main()
Server is Alive
- After successfully connecting with udp_server.py, pico sends
req>>time
to udp_server.py and updates the date and time itself. - Pico tries to sends a random message to the server every 10 seconds and udp_server.py sends
ack>>pk
to pico
- $ sudo hping3 -2 -c 10000 --flood 192.168.1.198
- Dos config for UDP limit is 150 packet.
- When you killed udp_server.py, pico sends
req>>alive
to udp_server.py after few seconds. if udp_server.py can't sendsalive>>yes
to pico, pico changes the udp_server.py status toServer is Dead
.