In the W5100 there's a total of 8k of RAM reserved for the sockets receive memory buffer as well as 8k for the sockets transmit memory buffer. The memory can be assigned to each socket in various configuration by writing to the RMSR and TMSR registers. By default both these registers are set to $55 which assigns 2k of RX and TX memory to each of the four sockets. Since we're only about to use one socket we COULD assign then full 8k of each buffer to socket 0 but for this exercise we'll just leave it at the default.
Once we've established a connection with the client we can determine if any data has been received by reading the sockets Received Size register. The value returned tells us the number of "new" bytes in the sockets receive buffer. What it doesn't tell us is where in the buffer these bytes are....
The sockets receive (and transmit) buffers are circular buffers meaning once they hit the highest memory adress they wrap around and start over at the beginning. The first byte we're interested in might be somewhere in the middle of the buffer and the last byte might be just before it even though it intuitively should be after the first byte. And, because all four sockets are assigned a "segment" of memory out of a total of 8k the actual start and end adresses of each sockets buffer can "move around" depending on the amount of memory assigned to each socket. If we take a look at the bottom of the W5100_defs.pbp file posted earlier we'll find this:
'************************************************************************************** ' ----------- THESE VALUES MAY NEED TO BE CHANGED BY THE USER OF THIS FILE ------------ '************************************************************************************** ' Socket 0-3 RX memory START & END adresses and MASK values for calculating pointer. ' Make sure to change these if the RMSR value is changed from its default value of $55 W5100_S0_RX_START CON $6000 'Start adress of Socket 0 (not changeable) W5100_S0_RX_END CON $67FF W5100_S0_RX_MASK CON $07FF 'Mask value for 2k W5100_S1_RX_START CON $6800 'Start adress of Socket 1 (depends on the size of socket 0) W5100_S1_RX_END CON $6FFF W5100_S1_RX_MASK CON $07FF 'Mask value for 2k W5100_S2_RX_START CON $7000 'Start adress of socket 2 (depends on the size of sockets 0 & 1) W5100_S2_RX_END CON $77FF W5100_S2_RX_MASK CON $07FF 'Mask value for 2k W5100_S3_RX_START CON $8000 'Start adress of socket 3 (depends on the size of sockets 0, 1 & 2) W5100_S3_RX_END CON $8FFF W5100_S3_RX_MASK CON $07FF 'Mask value for 2k '**************************************************************************************
OK, so how do we know where in the buffer our new data is? This is done by reading the sockets RX Read Pointer register but unfortunately this doesn't give us the real adress of the data, instead it gives us an offset into the sockets memory area. If the value of the pointer is 0 then the first byte of our new data is located at the start-adress of the sockets RX memory ($6000 in this case), if the value is $123 then the first byte is located at adress $6123. Not to bad.... But to make it a bit more complicated this pointer doesn't wrap around "in sync" with the circular buffer. The Rx Read Pointer register is a 16bit register meaning it counts from 0 to 65535 even though we only have 2048 bytes assigned to our buffer - so where is our data when the pointer value is $1234?
This is where the sockets RX_MASK constant defined in the W5100_defs.pbp file comes in. When the raw pointer value is bitwise AND'ed with the RX_MASK value we'll get the correct offset into the sockets buffer. If we then add this offset to the physical start adress of sockets buffer we finally have the physical adress of the first byte of new data in the buffer.
So now we know where the first byte of our new data is as well as how many byte there is to read, now we only need to figure out where the last byte is. Given the above this shouldn't be too hard to do... If the adress of the first byte plus the total number of bytes does not "extend" beyond the end of the buffer (no buffer wrap-around) we're done - just read from first byte to first byte + number of bytes. But if it does "extend" beyond the end of the buffer we need to first read up to the end of the buffer, then start over at the beginning, subtracting the number of bytes already accounted for and continue reading. I've wrapped all of this into, yet another, subroutine:
'****************************************************************************************** ' Variables WizPtr, WizStart, WizEnd and WizSize (all WORDs) declared elsewhere. CheckBufferForData: ' Read the sockets receive size register. WizAdress = W5100_S0_RX_RSR0 : GOSUB Read_W5100 : WizSize.HighByte = WizData WizAdress = W5100_S0_RX_RSR1 : GOSUB Read_W5100 : WizSize.LowByte = WizData ' If received size is more than 0 we do indeed have new data in the buffer. ' In that case we read the socket 0 receive pointer register. IF WizSize > 0 THEN WizAdress = W5100_S0_RX_RD0 : Gosub Read_W5100 : WizPtr.HighByte = WizData WizAdress = W5100_S0_RX_RD1 : GOSUB Read_W5100 : WizPtr.LowByte = WizData ' Calculate the physical adress of the first "fresh" byte in the buffer. WizStart = W5100_S0_RX_START + (WizPtr & W5100_S0_RX_MASK) ' Is the buffer about to wrap around? IF WizStart + WizSize > W5100_S0_RX_END THEN WizEnd = W5100_S0_RX_START + ((WizStart + WizSize) - W5100_S0_RX_END) WizEnd = WizEnd - 2 ' Account for the "zero indexing" ELSE 'No wrap around. WizEnd = WizStart + WizSize - 1 ENDIF ENDIF RETURN '******************************************************************************************
'***************************************************************************************************** GetData: HSEROUT [REP "-"\20, " Data read from Rx buffer follows ", REP "-"\20, 13] Counter = 0 ' Temporary as a dubug aid ' Do we have a buffer wrap around condition? If WizEnd < WizStart THEN ' When that happends we need to start reading at the first byte in the received ' package and go on until the end of the sockets RX memory.... For WizAdress = WizStart to W5100_S0_RX_END Gosub Read_W5100 HSEROUT[WizData] Counter = Counter + 1 ' Keep count NEXT ' ...then we need to start over at the beginning of the buffer and keep reading ' until we've got all the bytes in the buffer. For WizAdress = W5100_S0_RX_START to WizEnd Gosub Read_W5100 HSEROUT[WizData] Counter = Counter + 1 ' Keep count Next ELSE ' There's no buffer wrap-around. ' WizStart now contains the physical adress of the first byte to read. For WizAdress = WizStart to WizEnd Gosub Read_W5100 HSEROUT[WizData] Counter = Counter + 1 ' Keep count NEXT ENDIF HSEROUT [REP "-"\23, " End of data from Rx buffer ", REP "-"\23, 13] HSEROUT ["Total number of bytes read:", #Counter,13] HSEROUT [REP "-"\76, 13, 13]
Finally, since we're currently not responding to the request from the client, we simply disconnect and switch back into Listen mode. Not very polite but it'll look the browser as if no one is at the other end so it's OK for now.
WizPtr = WizPtr + WizSize WizAdress = W5100_S0_RX_RD0 : WizData = WizPtr.HighByte : GOSUB Write_W5100 WizAdress = W5100_S0_RX_RD1 : WizData = WizPtr.LowByte : GOSUB Write_W5100 WizAdress = W5100_S0_CR : WizData = W5100_Sn_RECV : GOSUB Write_W5100 WizAdress = W5100_S0_CR : WizData = W5100_Sn_LISTEN : GOSUB Write_W5100
To this post I've attached the exact file I compiled to arrive at the screenshot above (remove .txt extension), you'll also need the W5100_defs.pbp posted earlier in the thread.
/Henrik.
Re: Serial comunication problem
Well that would seem to rule out any OSC issues. The Pic is running and running at 4Mhz as you have programmed for. At this point, I think I would just have it run and start touching stuff. Maybe...
cncmachineguy - 6th October 2011, 15:58