This post delves into WIZnet’s W5300 Indirect Mode with an 8-bit Data Bus.
Recently, I have been immersed in a project utilizing the W5300-TOE-Shield.
I encountered challenges in finding examples that extend beyond the STM32 Nucleo-144 boards. Consequently, I took the initiative to compile a set of examples, primarily for my personal use. My hope is that these resources prove beneficial to others.
About W5300 From WIZnet
The W5300 is a network controller chip developed by WIZnet, a leading provider of Internet of Things (IoT) connectivity solutions. The W5300 controller offers a range of benefits and features that make it a popular choice for various networking applications.
Here are some of the key benefits of the W5300 controller:
Integrated Hardware TCP/IP Stack: The W5300 incorporates a hardware-based TCP/IP stack, which offloads the networking processing from the host microcontroller. This feature improves overall system performance and reduces the burden on the main processor, allowing it to focus on application-specific tasks.
High Performance: The W5300 is designed for high-speed networking applications, offering efficient data processing and communication. It supports up to 80 Mbps data throughput, making it suitable for demanding applications that require fast data transmission.
Multiple Network Protocol Support: The controller supports various networking protocols, including TCP, UDP, ICMP, ARP, IPv4, and IGMP. This
versatility enables developers to implement a wide range of networked applications using a single chip.
Cost-Effective Solution: The W5300 offers a cost-effective way to add networking capabilities to embedded systems, reducing the need for additional components and external components.
In summary, the W5300 controller from WIZnet offers a combination of high performance, integrated networking stack, ease of integration, and support for various network protocols. These features make it a compelling choice for designers and developers looking to add reliable and efficient networking capabilities to their IoT and embedded applications.
For more information refer to the WIZnet’s W5300 Product Page.
The Plan – Talk to W5300
There is a reason why examples all over the internet are primarily based on STM32 Nucleo-144 series boards. These boards feature a Flexible Memory Controller (FMC). For a quick overview of this, take a look at the following screenshot from the datasheet of STM32F446MC.
Faster Ethernet offers distinct advantages. The quicker you can transmit or receive data to or from the Ethernet chip, the more efficiently it can process the data.
That’s all for now, let the epic journey commence! 🚀
Hardware Used:
- W5300-TOE-Shield
2. Raspberry Pi Pico
I’m diving into the magical realm of MicroPython for that ultimate ease of use! 🧙♂️⚡️ It’s like having a time-saving wizard by my side!
Let’s find out what wonders await!
1st rule of embedded programming: ** Read the Datasheet**
- Datasheet of W5300 – https://www.wiznet.io/wp-content/uploads/wiznethome/Chip/W5300/Documents/W5300_DS_V134E.pdf
- Datasheet of W5300 ToE Shield – https://docs.wiznet.io/img/osh/w5300-toe-shield/W5300-ToE-Shield-Datasheet.pdf
- Pin Out of Raspberry Pi Pico – https://datasheets.raspberrypi.com/pico/Pico-R3-A4-Pinout.pdf
Note :
Buckle up, because we’re embarking on a datasheet safari! 📚🔍 I’ll be your guide, walking you through the wild world of technical details, just like we’re crafting the firmware driver. Get ready for a screenshot spectacle as we venture into the heart of the datasheet jungle! 🌴🦁
My mission? To show you exactly how it’s done! 🎨🖌️ Get ready for a step-by-step visual guide that’ll make you a pro in no time. Let’s dive in and demystify the process! 💡🔍
Warning!!! Boring Stuff but get used to it.
Let’s look into Datasheet of W5300!!!
The highlighted points below will provide us with clarity on how to establish the interface.
The 6th section of the W5300 datasheet provides a brief overview of the available external interfaces. These interfaces include:
- Direct Address Mode with 16 Bit Data Bus Width
- Direct Address Mode with 8 Bit Data Bus Width
- Indirect Address Mode with 16 Bit Data Bus Width
- Indirect Address Mode with 8 Bit Data Bus Width
From all this, I can come up with the following conclusions.
- W5300 Pins are 5 Volt tolerant.
- There are 4 types of mode is available for the external interface.
Which host interface to be used?
In my case, I would opt for the Indirect Address Mode with an 8-bit Data Bus Width.
- This interface uses least GPIO pins for communicating.
- The Raspberry Pi Pico has a total of 30 GPIOs, with 26 of them available for user utilization.
Let’s revisit the Indirect Address Mode with an 8-bit Data Bus Width to verify the necessary hardware connections.
- let’s don’t use /INT Pin (Interrupt Request Signal)
- 8 DATA (DATA [7:0]) pins are. (IO – Bidirectional)
- 3 Address pins (ADDR0, ADDR1 and ADDR2) are required – GPIO Output Pins
- /CS, /RD, /WR – all are ‘ACTIVE LOW’ pins – GPIO Output Pins
This implies that we require a minimum of 14 GPIO pins for the Indirect Address Mode with an 8-bit Data Bus Width.
Also,
- ‘BIT16EN’ should be grounded.
- ADDR [9:3] should be grounded.
From all of this, we now know which pins are to be used for communication.
Let’s look into W5300 ToE Shield Datasheet and make the connection accordingly.
Hardware Connection Details:
W5300 ToE Shield | Raspberry Pi Pico |
DATA0 | GP2 |
DATA1 | GP3 |
DATA2 | GP4 |
DATA3 | GP5 |
DATA4 | GP6 |
DATA5 | GP7 |
DATA6 | GP8 |
DATA7 | GP9 |
ADDR0 | GP10 |
ADDR1 | GP11 |
ADDR2 | GP12 |
/RD | GP13 |
/WR | GP14 |
/CS | GP15 |
3V3 | 3V3(OUT) |
GND | GND |
ADDR3 | GND |
ADDR4 | GND |
ADDR5 | GND |
ADDR6 | GND |
ADDR7 | GND |
ADDR8 | GND |
ADDR9 | GND |
BIT16EN | GND |
I derive great pleasure from soldering. The soldering process, coupled with verifying the connections, consumed a total of two hours.
Here’s a little tip for your soldering adventures! 💁♂️ Tune in to your favorite playlist and give your brain a split shift – one side rocking the soldering iron, the other grooving to the music. 🎶 Double the fun, zero the burnouts! Happy soldering! 🔌🎵
The Firmware!
From this point onward, I’ll be presenting Pseudo-code alongside its MicroPython equivalent. This approach ensures that regardless of the microcontroller being used, everyone can dive right in. Plus, the MicroPython examples I’m sharing below can be smoothly translated into C/C++, making the journey even more adaptable and exciting! 🚀🔌
- Configure ADDR0, ADDR1 and ADDR2 corresponding pin as Outputs.
ADDR0 | GP10 |
ADDR1 | GP11 |
ADDR2 | GP12 |
ADDR0 = Pin(10, Pin.OUT)
ADDR1 = Pin(11, Pin.OUT)
ADDR2 = Pin(12, Pin.OUT)
2. Configure RD, WR and CS corresponding pin as Outputs.
RD | GP13 |
WR | GP14 |
CS | GP15 |
RD = Pin(13, Pin.OUT)
WR = Pin(14, Pin.OUT)
CS = Pin(15, Pin.OUT)
3. DATA0 to DATA7 will be used as either Input or Output based on READ/WRITE Operation.
DATA0 | GP2 |
DATA1 | GP3 |
DATA2 | GP4 |
DATA3 | GP5 |
DATA4 | GP6 |
DATA5 | GP7 |
DATA6 | GP8 |
DATA7 | GP9 |
4. create a function to control ADDR0 – ADDR2 HIGH/LOW Logic Level
def W5300_WriteAddress(address):
ADDR0.value((address & 0b00000001) >>0)
ADDR1.value((address & 0b00000010) >>1)
ADDR2.value((address & 0b00000100) >>2)
for example:
W5300_WriteAddress(0x01) # 0x01 - 0b001 , ADDR2 = LOW, ADDR1 = LOW, ADDR0 = HIGH
W5300_WriteAddress(0x05) # 0x05 - 0b101, ADDR2 = HIGH, ADDR1 = LOW, ADDR0 = HIGH
5. READ ENABLE PIN
/RD – READ ENABLE Pin is Active Low
The bar symbol above a pin name in the datasheet signifies an active low pin. To activate the /RD pin for read operations, it needs to be pulled to the ground (GND).
For a clearer grasp, delve into the Register READ Timing section in the datasheet.
6. /WR – WRITE ENABLE Pin
/WR – WRITE ENABLE Pin is Active Low
7. /CS – CHIP SELECT Pin
/CS – CHIP SELECT Pin is Active Low
I believe I could provide you with a brief overview of the usage of the /RD, /WR, and /CS pins.
Now, allow me to showcase some of the functions that will take the spotlight in our firmware. 🌟🔌
def W5300_Read_Enable():
# /RD Pin is Active Low
RD.value(0) # /RD Pin - LOW
# Disable WR pin
WR.value(1) # /WR - HIGH
W5300_Read_Enable() function makes /RD pin to Low Logic (Active Low) and /WR pin to HIGH Logic (Disabled), so this function can be used during READ operation.
def W5300_Read_Disable():
RD.value(1) # Disable /RD pin by making it Logic High
def W5300_Write_Enable():
# WR Pin is Active Low
WR.value(0) # /WR pin LOW
# Disable RD pin
RD.value(1) # /RD pin HIGH
W5300_Write_Enable() function makes /WR pin to Low Logic (Active Low) and /RD pin to HIGH Logic (Disabled), so this function can be used during WRITE operation.
def W5300_Write_Disable():
WR.value(1) # Disable /WR pin by making it Logic High
def W5300_Chip_Select_Enable():
# CS Pin is Active Low
CS.value(0) # /CS - LOW
def W5300_Chip_Select_Disable():
CS.value(1) # /CS - HIGH
8. Controlling DATA0 to DATA7 Pins
As I mentioned earlier, the DATA0 to DATA7 pins will be used as either input or output based on READ/ WRITE operation.
So, we need to do 2 things.
- Configure DATA0 to DATA7 as inputs during READ operation.
- Configure DATA0 to DATA7 as outputs during WRITE operation.
# GP2 to GP9
eight_bit_data_bus_pins = range(2, 10)
def Config_Data_Bus_Input():
global data_bus_pins_as_inputs
# >> type(data_bus_pins_as_inputs) = list
# configures GP2 to GP9 as inputs
data_bus_pins_as_inputs = [Pin(pin, Pin.IN) for pin in eight_bit_data_bus_pins]
def Config_Data_Bus_Output():
global data_bus_pins_as_ouputs
# >> type(data_bus_pins_as_ouputs) = list
# configures GP2 to GP9 as Outputs
data_bus_pins_as_ouputs = [Pin(pin, Pin.OUT) for pin in eight_bit_data_bus_pins]
Tailor a function to configure DATA0 to DATA7 as inputs or outputs, depending on your microcontroller. In my scenario, I employed a loop approach to designate GP2 to GP9 as either inputs or outputs.
Writing into Data Pins
def W5300_Write_Data_D0_D7(data):
Config_Data_Bus_Output() # Configure GP2 to GP9 as outputs
data_bus_pins_as_ouputs[0].value((data & 0b00000001) >>0) # DATA0
data_bus_pins_as_ouputs[1].value((data & 0b00000010) >>1) # DATA1
data_bus_pins_as_ouputs[2].value((data & 0b00000100) >>2) # DATA2
data_bus_pins_as_ouputs[3].value((data & 0b00001000) >>3) # DATA3
data_bus_pins_as_ouputs[4].value((data & 0b00010000) >>4) # DATA4
data_bus_pins_as_ouputs[5].value((data & 0b00100000) >>5) # DATA5
data_bus_pins_as_ouputs[6].value((data & 0b01000000) >>6) # DATA6
data_bus_pins_as_ouputs[7].value((data & 0b10000000) >>7) # DATA7
The function W5300_Write_Data_D0_D7(data) initially configures DATA0 to DATA7 as outputs. Depending on the parameter (data) provided in the function, the pins are then set to either a HIGH or LOW logic level.
Example:
W5300_Write_Data_D0_D7(0x80) # 0x80 - 0b10000000 , DATA7 pin will be HIGH and remaining pins (DATA0 to DATA6) will be LOW
W5300_Write_Data_D0_D7(0x01) # 0x01 - 0b00000001, DATA0 pin will be HIGH , and remaining pins(DATA1 to DATA7) will be LOW
Reading From Data Pins
def W5300_Read_Data_D0_D7():
d0_to_d7 = 0b00000000
# DATA0
if data_bus_pins_as_inputs[0].value() == 1:
d0_to_d7 = Set_Bit(d0_to_d7,0)
else:
d0_to_d7 = Clear_Bit(d0_to_d7,0)
# DATA1
if data_bus_pins_as_inputs[1].value() == 1:
d0_to_d7 = Set_Bit(d0_to_d7,1)
else:
d0_to_d7 = Clear_Bit(d0_to_d7,1)
# DATA2
if data_bus_pins_as_inputs[2].value() == 1:
d0_to_d7 = Set_Bit(d0_to_d7,2)
else:
d0_to_d7 = Clear_Bit(d0_to_d7,2)
# DATA3
if data_bus_pins_as_inputs[3].value() == 1:
d0_to_d7 = Set_Bit(d0_to_d7,3)
else:
d0_to_d7 = Clear_Bit(d0_to_d7,3)
# DATA4
if data_bus_pins_as_inputs[4].value() == 1:
d0_to_d7 = Set_Bit(d0_to_d7,4)
else:
d0_to_d7 = Clear_Bit(d0_to_d7,4)
# DATA5
if data_bus_pins_as_inputs[5].value() == 1:
d0_to_d7 = Set_Bit(d0_to_d7,5)
else:
d0_to_d7 = Clear_Bit(d0_to_d7,5)
# DATA6
if data_bus_pins_as_inputs[6].value() == 1:
d0_to_d7 = Set_Bit(d0_to_d7,6)
else:
d0_to_d7 = Clear_Bit(d0_to_d7,6)
# DATA7
if data_bus_pins_as_inputs[7].value() == 1:
d0_to_d7 = Set_Bit(d0_to_d7,7)
else:
d0_to_d7 = Clear_Bit(d0_to_d7,7)
return d0_to_d7 # returns read 8 bit data
To read DATA0 to DATA7, configure GP2 to GP9 as Inputs using following function.
# Configure DATA0 to DATA7 as input
Config_Data_Bus_Input()
Afterward, the steps become quite straightforward. The function W5300_Read_Data_D0_D7() is used to read the status of the DATA0 pin through DATA7. The status of each pin is then returned as 8 bits of data.
9. The following section on datasheet gives a brief about Reading and Writing.
Register READ Timing
When the /CS pin is set LOW (enabled) and the /RD pin is also set LOW (enabled), and once ADDRESS pins are written, Valid Data can be read from the DATA0-DATA7 pins after the ‘tDATAs’ time.
It’s worth noting that the DATA is 16 bits long. Since we’re operating in 8-bit mode, we’ll need to read from the DATA register two times (for the Most Significant Byte and Least Significant Byte).
Register WRITE Timing
From Register Write Timing, it implies.
oh no….
Note: While examining both the read and write timings, it becomes evident that they are in nanoseconds. Although it’s permissible to employ millisecond or microsecond delays, doing so might impact the performance of the W5300.
However, since our current focus is not centered on performance optimization, we’ll set that aside for the moment.
10. Let’s look into System Memory Map
In indirect access mode only MR(Mode Register),IDM_AR(Indirect Mode Address Register) and IDM_DR(Indirect Mode Data Register) registers available for host interface.
Okay, then let’s talk indirectly.
Now we will look into Mode Register and Indirect Mode Register.
The below MicroPython Code is self-explanatory.
def W5300_Config_Indirect_Mode():
# 'IND' bit (0th bit) of MR1 to 1
# 0x01 - 0b00000001
W5300_Write_Data_D0_D7(0x01)
# Address offset of MR1 - 0x01(0b001)
W5300_WriteAddress(0x01)
W5300_Write_Enable()
W5300_Chip_Select_Enable()
utime.sleep_us(1)
W5300_Chip_Select_Disable()
utime.sleep_us(1)
W5300 Software Reset
The comments on following Micro python Code are well explained its operations.
# W5300 S/W Reset
def W5300_SW_Reset():
# 'RST' bit (7th bit ) of MR1 to 1
# MR1 - High address register of MR(Address offset - 0x001) , Least Significant byte
# 0x80 - 0b10000000
W5300_Write_Data_D0_D7(0x80)
# Address offset of MR1 - 0x01(0b001)
W5300_WriteAddress(0x01)
W5300_Write_Enable()
W5300_Chip_Select_Enable()
utime.sleep_us(1)
W5300_Chip_Select_Disable()
utime.sleep_us(1)
Now we are done with minimum functions to move forward.
How to read/write from data bus?
Indirect Mode Registers section of datasheet gives the hint.
The following section from datasheet gives an example of writing to data bus.
With this reference the following Micropython code is self-explanatory
def W5300_Bus_Write_Indirect(address, data):
# The following are Indirect Mode Address Register
# Address offset of IDM_AR0 - 0x02 - MSB
# Address offset of IDM_AR1 - 0x03 - LSB
W5300_Write_Data_D0_D7(((address >> 8) & 0xFF )) # MSB
# Address offset of IDM_AR0 - 0x02 - MSB
W5300_WriteAddress(0x02)
W5300_Write_Enable()
W5300_Chip_Select_Enable()
utime.sleep_us(1)
W5300_Chip_Select_Disable()
utime.sleep_us(1)
W5300_Write_Data_D0_D7((address & 0xFF )) # LSB
# Address offset of IDM_AR1 - 0x03 - LSB
W5300_WriteAddress(0x03)
W5300_Write_Enable()
W5300_Chip_Select_Enable()
utime.sleep_us(1)
W5300_Chip_Select_Disable()
utime.sleep_us(1)
# The following are Indirect Mode Data Register
# Address offset of IDM_DR0 - 0x04 - MSB
# Address offset of IDM_DR1 - 0x05 - LSB
W5300_Write_Data_D0_D7(((data >> 8) & 0xFF )) # MSB
# Address offset of IDM_DR0 - 0x04 - MSB
W5300_WriteAddress(0x04)
W5300_Write_Enable()
W5300_Chip_Select_Enable()
utime.sleep_us(1)
W5300_Chip_Select_Disable()
utime.sleep_us(1)
W5300_Write_Data_D0_D7((data & 0xFF )) # LSB
# Address offset of IDM_DR1 - 0x05 - LSB
W5300_WriteAddress(0x05)
W5300_Write_Enable()
W5300_Chip_Select_Enable()
utime.sleep_us(1)
W5300_Chip_Select_Disable()
utime.sleep_us(1)
and similarly, following section from datasheet gives hint for reading from data bus.
def W5300_Bus_Read_Indirect(address):
# 16 bits(1 Word) of data to be returned
global read_word
read_word = 0
MS_Byte = 0 # 8 - 15 bits
LS_Byte = 0 # 0 to 7 bits
'''
When W5300 operates as indirect address mode , Target
host system can access indirectly COMMON and Socket registers using "ONLY"
MR,IDM_AR, IDM_DR
more more info. refer 4.2(Indirect Mode Register " section of datasheet
'''
# The following are Indirect Mode Address Register
# Address offset of IDM_AR0 - 0x02 - MSB
# Address offset of IDM_AR1 - 0x03 - LSB
W5300_Write_Data_D0_D7(((address >> 8) & 0xFF )) # MSB
# Address offset of IDM_AR0 - 0x02 - MSB
W5300_WriteAddress(0x02)
W5300_Write_Enable()
W5300_Chip_Select_Enable()
utime.sleep_us(1)
W5300_Chip_Select_Disable()
utime.sleep_us(1)
W5300_Write_Data_D0_D7((address & 0xFF )) # LSB
# Address offset of IDM_AR1 - 0x03 - LSB
W5300_WriteAddress(0x03)
W5300_Write_Enable()
W5300_Chip_Select_Enable()
utime.sleep_us(1)
W5300_Chip_Select_Disable()
utime.sleep_us(1)
# Configure DATA0 to DATA7 as input
Config_Data_Bus_Input()
# The following are Indirect Mode Data Register
# Address offset of IDM_DR0 - 0x04 - MSB
# Address offset of IDM_DR1 - 0x05 - LSB
W5300_WriteAddress(0x04) #Address offset of IDM_DR0 - 0x04 - MSB
W5300_Read_Enable()
W5300_Chip_Select_Enable()
utime.sleep_us(1)
MS_Byte = W5300_Read_Data_D0_D7()
W5300_Chip_Select_Disable()
utime.sleep_us(1)
W5300_WriteAddress(0x05) # Address offset of IDM_DR1 - 0x05 - LSB
W5300_Read_Enable()
W5300_Chip_Select_Enable()
utime.sleep_us(1)
LS_Byte = W5300_Read_Data_D0_D7()
W5300_Chip_Select_Disable()
utime.sleep_us(1)
read_word = ((MS_Byte<<8)| LS_Byte)
return read_word
Done !
Testing Time!!!
The following Micropython code reads from 0xFE register, that should return 0x5300 as response. Else “connection is failed”.
Also, for testing lets write known value (49152 – 0xC000) to ‘Socket0 Source Port Register'(0x20A) and read back.
'''
Test Code for W5300 Indirect Address Mode with 8-bit Data Bus
'''
from machine import Pin
import utime
# GP2 to GP9
eight_bit_data_bus_pins = range(2, 10)
ADDR0 = Pin(10, Pin.OUT)
ADDR1 = Pin(11, Pin.OUT)
ADDR2 = Pin(12, Pin.OUT)
RD = Pin(13, Pin.OUT)
WR = Pin(14, Pin.OUT)
CS = Pin(15, Pin.OUT)
def Get_Bit(value, n):
return ((value >> n & 1) != 0)
def Set_Bit(value, n):
return value | (1 << n)
def Clear_Bit(value, n):
return value & ~(1 << n)
def Config_Data_Bus_Output():
global data_bus_pins_as_ouputs
# >> type(data_bus_pins_as_ouputs) = list
# configures GP2 to GP9 as Outputs
data_bus_pins_as_ouputs = [Pin(pin, Pin.OUT) for pin in eight_bit_data_bus_pins]
def Config_Data_Bus_Input():
global data_bus_pins_as_inputs
# >> type(data_bus_pins_as_inputs) = list
# configures GP2 to GP9 as inputs
data_bus_pins_as_inputs = [Pin(pin, Pin.IN) for pin in eight_bit_data_bus_pins]
def W5300_WriteAddress(address):
ADDR0.value((address & 0b00000001) >>0)
ADDR1.value((address & 0b00000010) >>1)
ADDR2.value((address & 0b00000100) >>2)
def W5300_Read_Enable():
# RD Pin is Active Low
RD.value(0)
# Disable WR pin
WR.value(1)
def W5300_Read_Disable():
RD.value(1)
def W5300_Write_Enable():
# WR Pin is Active Low
WR.value(0)
# Disable RD pin
RD.value(1)
def W5300_Write_Disable():
WR.value(1)
def W5300_Chip_Select_Enable():
# CS Pin is Active Low
CS.value(0)
def W5300_Chip_Select_Disable():
CS.value(1)
def W5300_Write_Data_D0_D7(data):
Config_Data_Bus_Output()
data_bus_pins_as_ouputs[0].value((data & 0b00000001) >>0)
data_bus_pins_as_ouputs[1].value((data & 0b00000010) >>1)
data_bus_pins_as_ouputs[2].value((data & 0b00000100) >>2)
data_bus_pins_as_ouputs[3].value((data & 0b00001000) >>3)
data_bus_pins_as_ouputs[4].value((data & 0b00010000) >>4)
data_bus_pins_as_ouputs[5].value((data & 0b00100000) >>5)
data_bus_pins_as_ouputs[6].value((data & 0b01000000) >>6)
data_bus_pins_as_ouputs[7].value((data & 0b10000000) >>7)
def W5300_Read_Data_D0_D7():
d0_to_d7 = 0b00000000
# DATA0
if data_bus_pins_as_inputs[0].value() == 1:
d0_to_d7 = Set_Bit(d0_to_d7,0)
else:
d0_to_d7 = Clear_Bit(d0_to_d7,0)
# DATA1
if data_bus_pins_as_inputs[1].value() == 1:
d0_to_d7 = Set_Bit(d0_to_d7,1)
else:
d0_to_d7 = Clear_Bit(d0_to_d7,1)
# DATA2
if data_bus_pins_as_inputs[2].value() == 1:
d0_to_d7 = Set_Bit(d0_to_d7,2)
else:
d0_to_d7 = Clear_Bit(d0_to_d7,2)
# DATA3
if data_bus_pins_as_inputs[3].value() == 1:
d0_to_d7 = Set_Bit(d0_to_d7,3)
else:
d0_to_d7 = Clear_Bit(d0_to_d7,3)
# DATA4
if data_bus_pins_as_inputs[4].value() == 1:
d0_to_d7 = Set_Bit(d0_to_d7,4)
else:
d0_to_d7 = Clear_Bit(d0_to_d7,4)
# DATA5
if data_bus_pins_as_inputs[5].value() == 1:
d0_to_d7 = Set_Bit(d0_to_d7,5)
else:
d0_to_d7 = Clear_Bit(d0_to_d7,5)
# DATA6
if data_bus_pins_as_inputs[6].value() == 1:
d0_to_d7 = Set_Bit(d0_to_d7,6)
else:
d0_to_d7 = Clear_Bit(d0_to_d7,6)
# DATA7
if data_bus_pins_as_inputs[7].value() == 1:
d0_to_d7 = Set_Bit(d0_to_d7,7)
else:
d0_to_d7 = Clear_Bit(d0_to_d7,7)
return d0_to_d7 # returns read 8 bit data
# W5300 S/W Reset
def W5300_SW_Reset():
# 'RST' bit (7th bit ) of MR1 to 1
# MR1 - High address register of MR(Address offset - 0x001) , Least Significant byte
# 0x80 - 0b10000000
W5300_Write_Data_D0_D7(0x80)
# Address offset of MR1 - 0x01(0b001)
W5300_WriteAddress(0x01)
W5300_Write_Enable()
W5300_Chip_Select_Enable()
utime.sleep_us(1)
W5300_Chip_Select_Disable()
utime.sleep_us(1)
def W5300_Config_Indirect_Mode():
# 'IND' bit (0th bit) of MR1 to 1
# 0x01 - 0b00000001
W5300_Write_Data_D0_D7(0x01)
# Address offset of MR1 - 0x01(0b001)
W5300_WriteAddress(0x01)
W5300_Write_Enable()
W5300_Chip_Select_Enable()
utime.sleep_us(1)
W5300_Chip_Select_Disable()
utime.sleep_us(1)
def W5300_Init():
# Disable RD,WR,CS pin - Make these pin to 'HIGH' Logic Level
W5300_Read_Disable()
W5300_Write_Disable()
W5300_Chip_Select_Disable()
utime.sleep_ms(100)
W5300_SW_Reset()
utime.sleep_ms(100)
W5300_Config_Indirect_Mode()
utime.sleep_ms(100)
print("Reading from 0xFE address ")
val = W5300_Bus_Read_Indirect(0xFE)
print("response is "+ hex(val))
print("Writing 0xC000 to address0x20A ")
W5300_Bus_Write_Indirect(0x20A,49152)
val = W5300_Bus_Read_Indirect(0x20A)
print("response is "+ hex(val))
def W5300_Bus_Read_Indirect(address):
# 16 bits(1 Word) of data to be returned
global read_word
read_word = 0
MS_Byte = 0 # 8 - 15 bits
LS_Byte = 0 # 0 to 7 bits
'''
When W5300 operates as indirect address mode , Target
host system can access indirectly COMMON and Socket registers using "ONLY"
MR,IDM_AR, IDM_DR
more more info. refer 4.2(Indirect Mode Register " section of datasheet
'''
# The following are Indirect Mode Address Register
# Address offset of IDM_AR0 - 0x02 - MSB
# Address offset of IDM_AR1 - 0x03 - LSB
W5300_Write_Data_D0_D7(((address >> 8) & 0xFF )) # MSB
# Address offset of IDM_AR0 - 0x02 - MSB
W5300_WriteAddress(0x02)
W5300_Write_Enable()
W5300_Chip_Select_Enable()
utime.sleep_us(1)
W5300_Chip_Select_Disable()
utime.sleep_us(1)
W5300_Write_Data_D0_D7((address & 0xFF )) # LSB
# Address offset of IDM_AR1 - 0x03 - LSB
W5300_WriteAddress(0x03)
W5300_Write_Enable()
W5300_Chip_Select_Enable()
utime.sleep_us(1)
W5300_Chip_Select_Disable()
utime.sleep_us(1)
# Configure DATA0 to DATA7 as input
Config_Data_Bus_Input()
# The following are Indirect Mode Data Register
# Address offset of IDM_DR0 - 0x04 - MSB
# Address offset of IDM_DR1 - 0x05 - LSB
W5300_WriteAddress(0x04) #Address offset of IDM_DR0 - 0x04 - MSB
W5300_Read_Enable()
W5300_Chip_Select_Enable()
utime.sleep_us(1)
MS_Byte = W5300_Read_Data_D0_D7()
W5300_Chip_Select_Disable()
utime.sleep_us(1)
W5300_WriteAddress(0x05) # Address offset of IDM_DR1 - 0x05 - LSB
W5300_Read_Enable()
W5300_Chip_Select_Enable()
utime.sleep_us(1)
LS_Byte = W5300_Read_Data_D0_D7()
W5300_Chip_Select_Disable()
utime.sleep_us(1)
read_word = ((MS_Byte<<8)| LS_Byte)
return read_word
def W5300_Bus_Write_Indirect(address, data):
# The following are Indirect Mode Address Register
# Address offset of IDM_AR0 - 0x02 - MSB
# Address offset of IDM_AR1 - 0x03 - LSB
W5300_Write_Data_D0_D7(((address >> 8) & 0xFF )) # MSB
# Address offset of IDM_AR0 - 0x02 - MSB
W5300_WriteAddress(0x02)
W5300_Write_Enable()
W5300_Chip_Select_Enable()
utime.sleep_us(1)
W5300_Chip_Select_Disable()
utime.sleep_us(1)
W5300_Write_Data_D0_D7((address & 0xFF )) # LSB
# Address offset of IDM_AR1 - 0x03 - LSB
W5300_WriteAddress(0x03)
W5300_Write_Enable()
W5300_Chip_Select_Enable()
utime.sleep_us(1)
W5300_Chip_Select_Disable()
utime.sleep_us(1)
# The following are Indirect Mode Data Register
# Address offset of IDM_DR0 - 0x04 - MSB
# Address offset of IDM_DR1 - 0x05 - LSB
W5300_Write_Data_D0_D7(((data >> 8) & 0xFF )) # MSB
# Address offset of IDM_DR0 - 0x04 - MSB
W5300_WriteAddress(0x04)
W5300_Write_Enable()
W5300_Chip_Select_Enable()
utime.sleep_us(1)
W5300_Chip_Select_Disable()
utime.sleep_us(1)
W5300_Write_Data_D0_D7((data & 0xFF )) # LSB
# Address offset of IDM_DR1 - 0x05 - LSB
W5300_WriteAddress(0x05)
W5300_Write_Enable()
W5300_Chip_Select_Enable()
utime.sleep_us(1)
W5300_Chip_Select_Disable()
utime.sleep_us(1)
W5300_Init()
Result :
All the project files are up on Github .
References:
- https://docs.wiznet.io/Product/iEthernet/W5300/w5300-TOE-Shield
- https://docs.wiznet.io/Product/iEthernet/W5300
- https://datasheets.raspberrypi.com/pico/raspberry-pi-pico-python-sdk.pdf
If you’ve journeyed through these insights up to this point, I trust they’ve proven beneficial to you. I might continue to enhance this page with additional information as my explorations unfold. Meanwhile, here’s to joyful interfacing and Happy Exploring!!! 🎉🔌🚀
hey wait!!
Ever stumbled upon this thing called Programmable I/O, or PIO, on RP2040? 🤔 Wondering why not harness it for turbocharged performance with W5300? My brain’s got questions! 🧠💡
Stay tuned, ……. to be continued