Wiznet W5100 (Ethernet Shield) Buffer Question.

So it looks like there is 8Kb of internal RX buffer on the W5100 chip... so how does one deal with reading the data faster than its coming in? If I don't read it fast enough or too fast what happens? How do you flush the buffer on chip via client.flush()? I suspect it's FIFO.

I'm running into a situation where I am getting 8k of data posted to me and it looks like the data is being "clipped" ... guess the buffer is getting filled.

Looking at the W5100.c file there is mention of how the memory channels are allocated... anyone know how it's setup to work? Full 8kb or less?

Looks like this is where it deals with RX memory:

/**
@brief      This function is being used for copy the data form Receive buffer of the chip to application buffer.

It calculate the actual physical address where one has to read
the data from Receive buffer. Here also take care of the condition while it exceed
the Rx memory uper-bound of socket.
*/
void read_data(SOCKET s, vuint8 * src, vuint8 * dst, uint16 len)
{
      uint16 size;
      uint16 src_mask;
      uint8 * src_ptr;

      src_mask = (uint16)src & getIINCHIP_RxMASK(s);
      src_ptr = (uint8 *)(getIINCHIP_RxBASE(s) + src_mask);
      
      if( (src_mask + len) > getIINCHIP_RxMAX(s) ) 
      {
            size = getIINCHIP_RxMAX(s) - src_mask;
            wiz_read_buf((uint16)src_ptr, (uint8*)dst,size);
            dst += size;
            size = len - size;
            src_ptr = (uint8 *)(getIINCHIP_RxBASE(s));
            wiz_read_buf((uint16)src_ptr, (uint8*) dst,size);
      } 
      else
      {
            wiz_read_buf((uint16)src_ptr, (uint8*) dst,len);
      }
}

So does it just override the previous if not read fast enough? How do you know how big the buffer is? I'd like to know if it's really 8Kb.

  • Support Hardwired TCP/IP Protocols TCP, UDP, ICMP, IPv4 ARP, IGMP, PPPoE, Ethernet
  • 10BaseT/100BaseTX Ethernet PHY embedded
  • Support Auto Negotiation (Full-duplex and half duplex)
  • Support Auto MDI/MDIX
  • Support ADSL connection (with support PPPoE Protocol with PAP/CHAP Authentication mode)
  • Supports 4 independent sockets simultaneously
  • Not support IP Fragmentation
  • Internal 16Kbytes Memory for Tx/Rx Buffers
  • 0.18 µm CMOS technology
  • 3.3V operation with 5V I/O signal tolerance
  • Small 80 Pin LQFP Package
  • Lead-Free Package
  • Support Serial Peripheral Interface(SPI MODE 0, 3)Multi-function LED outputs (TX, RX, Full/Half duplex, Collision, Link, Speed)

http://www.wiznet.co.kr/en/

http://hackable-devices.org/media/products_data/documents/documents/2010/05/19/W5100_Datasheet.pdf

Yeah, I got the details... I'm more interested in how the RX memory buffer is setup. Looks like 8Kb is reserved on the chip. However, what happens if more than that gets posted and is not read fast enough?

What SHOULD happen is that packets that cannot be buffered will get discarded and end up being retransmitted by the remote host. (actually, it ought to use a TCP window smaller than the available buffer memory, which should prevent the remote host from ever sending a packet that won't fit.)

(If you don't use TCP, you will need to duplicate some of this functionality with whatever protocol you DO use.)

Guys, check this post out:

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1282169385

I just confirmed this as well. The types.h under ethernet have the following:

#define TX_RX_MAX_BUF_SIZE      2048
#define TX_BUF      0x1100
#define RX_BUF      (TX_BUF+TX_RX_MAX_BUF_SIZE)

Why is it set to 2Kb rather than the full 8Kb which is available on the W5100 chip!? What is the reasoning? This means once the buffer is filled, all new data gets discarded. Bad.

Just reread the Datasheet. Looks like there are memory “sockets” (page 37). Now sure what that all means… anyone?

Ok, so I understand it a bit more... 2048k for RX buffer is because you can have up to 4 sockets. I'd like to reduce that to 2 active sockets and 4k each. Any tips on how I can change that?

from datasheet page 37

Set socket memory information This stage sets the socket tx/rx memory information. The base address and mask address of each socket are fixed and saved in this stage.

In case of, assign 2K rx memory per socket.
{
RMSR = 0x55; // assign 2K rx memory per socket.
gS0_RX_BASE = chip_base_address + RX_memory_base_address(0x6000);
gS0_RX_MASK = 2K – 1 ; // 0x07FF, for getting offset address within assigned socket 0 RX
memory.
gS1_RX_BASE = gS0_BASE + (gS0_MASK + 1);
gS1_RX_MASK = 2K – 1 ;
gS2_RX_BASE = gS1_BASE + (gS1_MASK + 1);
gS2_RX_MASK = 2K – 1 ;
gS3_RX_BASE = gS2_BASE + (gS2_MASK + 1);
gS3_RX_MASK = 2K – 1 ;
TMSR = 0x55; // assign 2K tx memory per socket.
Same method, set gS0_TX_BASE, gS0_TX_MASK, gS1_TX_BASE, gS1_TX_MASK,
gS2_TX_BASE, gS2_TX_MASK, gS3_TX_BASE and gS3_TX_MASK.
}
In case of, assign 4K,2K,1K,1K.
{
RMSR = 0x06; // assign 4K,2K,1K,1K rx memory per socket.
gS0_RX_BASE = chip_base_address + RX_memory_base_address(0x6000);
gS0_RX_MASK = 4K – 1 ; // 0x0FFF, for getting offset address within assigned socket 0 RX
memory.
gS1_RX_BASE = gS0_BASE + (gS0_MASK + 1);
gS1_RX_MASK = 2K – 1 ; // 0x07FF
gS2_RX_BASE = gS1_BASE + (gS1_MASK + 1);
gS2_RX_MASK = 1K – 1 ; // 0x03FF
gS3_RX_BASE = gS2_BASE + (gS2_MASK + 1);
gS3_RX_MASK = 1K – 1 ; // 0x03FF
TMSR = 0x06; // assign 4K,2K,1K,1K rx memory per socket.
Same method, set gS0_TX_BASE, gS0_TX_MASK, gS1_TX_BASE, gS1_TX_MASK,
gS2_TX_BASE, gS2_TX_MASK, gS3_TX_BASE and gS3_TX_MASK.
}

so it describes how to set them up on the w5100 chip. for the arduino sketch you may have to change something else. I am not sure if there is a software buffer in the sketch or not.

Yeah, I know all that… looking at the ethernet.cpp code… it’s not as straight forward…

So lets say I want to have two sockets at 4kb each – I sent the sysinit RX to 0xAA like so:

void EthernetClass::begin(uint8_t *mac, uint8_t *ip, uint8_t *gateway, uint8_t *subnet)
{
      iinchip_init();
      sysinit(0x55, 0xAA);
      setSHAR(mac);
      setSIPR(ip);
  setGAR(gateway);
  setSUBR(subnet);
}

Then under types.h I would need to change this to max_socket_num to 2. However, when I change that to anything but 4 I get compile errors.

#define      MAX_SOCK_NUM            4      /**< Maxmium number of socket  */

Any thoughts?

So keeping max_sockets at 4 but changing the RMSR in the sysinit to 0xAA (4kb) now allows more than 2048 limits in the client.available() ... weird thing is I didn't change the max_sockets. Not sure if that will cause any edge case issues... however, it seems to be working now, allowing up to 4kb!

Any ideas why it's working just by changing the RMSR setting and nothing else?

Also note... it seems like the buffer via 'client.available()' doesn't adjust on the chip as you read bytes from it. So if 3kb of data came in... it locks 3kb until you flush and stop. Not exactly what I expected. Guess most people don't get post data bigger than 2kb. ;D

OK. So maybe it’s time to approach the problem from the other end. Why is it necessary to send 8KB messages to the Arduino that can’t handle 8KB messages on a good day?

Because I don't have control over some devices that "post" data and I don't want a computer in between. It looks like the typical message is 2900 bytes just over the limit... It wouldn't be a problem if I didn't need a few bytes from range 2048-2900. Looks like changing it to 4kb is working... however, I'm not sure why I can't change the max sockets to 2 since 4kb+4kb = 8kb... it's giving me compile errors in when I change max_sockets to 2.

Also, reading from the buffer, actually doesn't seem to "clear" the char from the buffer... not sure if that is by design or just not coded to support it. Can someone confirm this as well... not sure if it's something I'm doing wrong.

Ok... got it figured out... modified the ethernet.cpp too.