Using the driver with a new nic (Network Interface Controller) requires adjusting the functions in the nic.c file to suit your nic (this file contains just the functions that are nic specific and doesn’t contain any of the general TCP/IP stack driver functions). This is simply a case of adapting each of the functions that are called by the stack to suit accessing your particular nic and following this guide should make the process straightforward.
Copy A Pair Of Sample Files
First copy the sample nic.c and nic.h pair of files for the included nic models that is most similar to your nic, to use as a reference. These can then be modified as necessary for your nic.
Nic Specific Defines
Go through each of the defines in the nic.h file and update as required for your nic.
IO Defines
Alter the IO defines to provide all of the input and output pins required by your nic and serial port access if your nic uses a serial rather than parallel interface.
Bus Access Delay Defines
NIC_DELAY_READ_WRITE
This define may be used with parallel interface nic’s to add in one or more null (no operation) instructions to allow data bus signals to stabilise during read or write access. 2 layer PCB’s (no ground plane) and PCB’s with long track lengths are more likely to require this. If you are experiencing problems setting up a new nic or PCB it is worth using this define to give a reasonable delay and then remove it later once you have the nic working.
Nic Specific Functions
The sample nic.c file you have copied may contain functions other than the below, but they will simply be included to support and be called by these main functions (i.e. used locally and not of interest to the rest of the TCP/IP driver).
If your nic has a 16 (or 32 bit) interface then use a sample file which also has an interface wider than 8 bits to see the simple technique to deal with the functions below that work with reading and writing individual bytes.
void nic_initialise (BYTE init_config)
Adjust to provide resetting of the nic and initialisation of all registers that require initialisation. Only 1 transmit buffer is required and all of the nics remaining memory can be allocated to receiving packets. Transmitted packets can be discarded once sent or if send fails.
This function also needs to set the nic’s MAC address from the following array:
our_mac_address
If the nic supports both 10Mbps and 100Mbps then use the BYTE value it is called with to set the nic’s speed:
0 = allow speed 10 / 100 Mbps
1 = force speed to 10 Mbps
Typically the interrupt output pin needs to be configured to be active when a packet has been received or the link status has changed.
Finally, enable packet reception and do the following:
//—– DO FINAL FLAGS SETUP —–
nic_is_linked = 0;
nic_speed_is_100mbps = 0;
nic_rx_packet_waiting_to_be_dumped = 0;
WORD nic_check_for_rx (void)
Read the relevant nic register and return 0 if no rx waiting or the number of bytes in the packet if rx is waiting
void nic_setup_read_data (void)
Set the nic’s read pointer to the beginning of the next unprocessed received packet so that the next operation can read the nic and data will be transferred from the data buffer
BYTE nic_read_next_byte (BYTE *data)
Read the next byte from the nic’s buffer memory (nic_setup_read_data will have already been called) and return 1 if the read was successful or 0 if nic_rx_bytes_remaining is zero and there are no more bytes in the rx buffer.
If a byte was read do the following:
nic_rx_bytes_remaining–;
BYTE nic_read_array (BYTE *array_buffer, WORD array_length)
Read the specified number of bytes from the nic’s receive buffer (nic_setup_read_data will have already been called) and return 1 if the read was successful or 0 if nic_rx_bytes_remaining becomes zero and there are no more bytes in the rx buffer.
As each byte is read do the following:
nic_rx_bytes_remaining–;
void nic_move_pointer (WORD move_pointer_to_ethernet_byte)
Move the nic’s read pointer to a specified byte location ready to be read next (a value of 0 = the first byte of the Ethernet header). Also do the following:
nic_rx_bytes_remaining = nic_rx_packet_total_ethernet_bytes – move_pointer_to_ethernet_byte;
void nic_rx_dump_packet (void)
Discard any remaining bytes in the current received packet and free up the nic for the next received packet. Also do the following:
//EXIT IF PACKET HAS ALREADY BEEN DISCARDED
if(nic_rx_packet_waiting_to_be_dumped == 0)
return;
//Discard the packet
//Flag that packet has been dumped
nic_rx_packet_waiting_to_be_dumped = 0;
BYTE nic_setup_tx (void)
Check the nic to see if it is ready to accept a new packet to be transmitted. If not return 0. If yes then it needs to set up the nic ready for the first byte of the data area (Ethernet frame) to be sent. The following checks may need to be made depending on your nic:
Check the nic isn’t overflowed
Check the nic isn’t tied up still sending the last transmitted packet
If also needs to:
nic_tx_len = 0;
void write_eth_header_to_nic (MAC_ADDR *remote_mac_address, WORD ethernet_packet_type)
This function can be a copy from the sample driver used.
void nic_write_next_byte (BYTE data)
Write the byte to the nic (nic_setup_tx will have already been called). It needs to do the following before outputting the byte:
if(nic_tx_len >= 1536)
return;
nic_tx_len++;
void nic_write_array (BYTE *array_buffer, WORD array_length)
Write the specified number of bytes to the nic (nic_setup_tx will have already been called). It needs to do the following before outputting each byte:
if(nic_tx_len >= 1536)
break;
nic_tx_len++;
void nic_write_tx_word_at_location (WORD byte_address, WORD data)
The byte_address supplied will be word aligned. Move the nic’s transmit buffer pointer to the specified location, write the value and then restore the pointer back to its previous location. This function is used when writing information required at the beginning of a packet that is not necessarily known before the end of the packet is written (such as length).
void nix_tx_packet (void)
Transmit the packet that has been constructed in the nic’s transmit buffer. The following needs to be included:
//If packet is below minimum length add pad bytes —–
while (nic_tx_len < 60)
nic_write_next_byte(0×00);
//Add the Ethernet CRC if the nic doesn’t do this automatically
//(most do)
BYTE nic_ok_to_do_tx (void)
Return 0 if the nic is not currently connected, is waiting for a received packet to be finished with and dumped (nic_rx_packet_waiting_to_be_dumped == 1) or is busy with a previous transmission. Otherwise return 1.
Getting A New Nic To Work
Often the nic manufacturer will provide sample code showing how to initialise, read and write the nic which can be used as the basis for the functions this driver requires. If problems are experienced its often useful to create a simple function to read the entire contents of the nic’s control registers so that you can debug why the nic isn’t doing what you expect.
One of the simplest ways to check a new nic is working correctly is to enable the drivers DHCP function, ensure there is a DHCP server on the network and then monitor the network traffic using Wireshark or a similar program to see if the DHCP packets are sent and received correctly. It that is successful then ping the device the driver is running on to confirm that array reading and writing is also working. If not breakpoint at important points in the above functions to find out where the problem is that needs to be corrected.