WIZnet’s W5300 Indirect Address Mode with 8-bit Data Bus

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 PlanTalk to W5300

hdhhdhd

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:

  1. 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**

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 7th page of datasheet gives some hint about interface
Page 9

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.

W5300 ToE Shield Pinout
Raspberry Pi Pico Pinout

Hardware Connection Details:

W5300 ToE ShieldRaspberry Pi Pico
DATA0GP2
DATA1GP3
DATA2GP4
DATA3GP5
DATA4GP6
DATA5GP7
DATA6GP8
DATA7GP9
ADDR0GP10
ADDR1GP11
ADDR2GP12
/RDGP13
/WRGP14
/CSGP15
3V33V3(OUT)
GNDGND
ADDR3 GND
ADDR4 GND
ADDR5 GND
ADDR6 GND
ADDR7 GND
ADDR8 GND
ADDR9 GND
BIT16EN GND
keep jumper across 8 BIT option on W5300 ToE Shield

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! 🚀🔌

  1. Configure ADDR0, ADDR1 and ADDR2 corresponding pin as Outputs.
ADDR0GP10
ADDR1GP11
ADDR2GP12
Configure GP10, GP11 and GP12 as Outputs.
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.

RDGP13
WRGP14
CSGP15
Configure GP13, GP14 and GP15 as Outputs.
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.

DATA0GP2
DATA1GP3
DATA2GP4
DATA3GP5
DATA4GP6
DATA5GP7
DATA6GP8
DATA7GP9

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….

it’s easy right?

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.

some indirect talking:)

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:

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