W5100 正在发送垃圾
W5100 is sending garbage
我尝试使用 W5100 Ethernet Controller 和 XMega 实现 Web 界面,但我的浏览器打印出这个奇怪的结果:
请看我的代码:
SPIM_Config_t Config_SPIM = {
.Device = &SPIC,
.Mode = SPI_MODE_0,
.Prescaler = SPI_PRESCALER_64,
};
W5100_Config_t Config_Ethernet = {
.Submask = {255, 255, 0, 0},
.IP = {169, 254, 133, 121},
.Gateway = {169, 154, 133, 129},
.MAC = {0x00, 0x00, 0x00, 0x00, 0x00, 0xAA}
};
uint8_t Rx_Buffer[2048];
uint8_t Tx_Buffer[2048];
const char HTTP[] = "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nPragma: no-cache\r\n\r\n"
"<html>\r\n"
"<body>\r\n"
"<title>Title</title>\r\n"
"<p>Hello world</p>\r\n"
"</body>\r\n"
"</html>\r\n";
int main(void)
{
W5100_Init(&Config_SPIM, &Config_Ethernet);
while(1)
{
W5100_Status_t Status;
W5100_GetState(0, &Status);
switch(Status)
{
case W5100_SOCK_CLOSED:
{
if(W5100_Open(0, W5100_PROT_TCP, 80, W5100_MEM_2K, W5100_MEM_2K, 65535) == W5100_NO_ERROR)
{
W5100_Listen(0, ETHERNET_TIMEOUT);
}
break;
}
case W5100_SOCK_ESTABLISHED:
{
uint16_t Rx_Bytes;
if(W5100_GetBytes(0, &Rx_Bytes) == W5100_NO_ERROR)
{
if(Rx_Bytes)
{
W5100_Receive(0, Rx_Buffer, Rx_Bytes);
strcpy((char*)Tx_Buffer, HTTP);
W5100_Send(0, Tx_Buffer, strlen((char*)HTTP), ETHERNET_TIMEOUT);
}
else
{
}
}
W5100_Disconnect(0, ETHERNET_TIMEOUT);
break;
}
case W5100_SOCK_FIN_WAIT:
case W5100_SOCK_CLOSING:
case W5100_SOCK_TIME_WAIT:
case W5100_SOCK_CLOSE_WAIT:
case W5100_SOCK_LAST_ACK:
{
W5100_Close(0, ETHERNET_TIMEOUT);
break;
}
}
}
}
我认为错误出在我的 W5100_Send
函数中,似乎控制器正在发送不同内存位置的内容,但我无法找出错误。基于以太网控制器数据表的代码:
W5100_ErrorCode_t W5100_Send(uint8_t Socket, uint8_t* Buffer, uint16_t Length, uint32_t Timeout)
{
uint8_t Temp[2];
uint8_t Mask;
uint16_t SocketBase;
uint16_t Offset;
uint16_t Free;
uint16_t SocketMemory;
uint32_t Timeout_Temp = Timeout;
if(!_W5100_IsInitialized)
{
return W5100_NOT_INITIALIZED;
}
else if((Socket > 0x04) || (Buffer == NULL) || (Length == 0x00))
{
return W5100_INVALID_PARAM;
}
// Get the memory mask for address calculation
W5100_ReadRegister(W5100_REGISTER_TMSR, &Mask);
Mask &= (0x03 << (Socket << 0x01));
// Check for invalid memory by comparing the memory mask for the given socket and the socket index
if(((Socket > 0) && (Mask == 3)) || ((Socket > 1) && (Mask == 2)))
{
return W5100_INVALID_PARAM;
}
SocketBase = W5100_SOCKET_ADDR(Socket);
SocketMemory = W5100_SOCKET_MEM_OFFSET << Mask;
// Wait while the buffer is full
do
{
// Get the free bytes
W5100_ReadRegister(SocketBase + W5100_OFFSET_TX_FSR0, &Temp[0]);
W5100_ReadRegister(SocketBase + W5100_OFFSET_TX_FSR1, &Temp[1]);
Free = ((uint16_t)(Temp[0] << 0x08)) | Temp[1];
if(Timeout_Temp-- == 0x00)
{
W5100_Disconnect(Socket, Timeout);
return W5100_TIMEOUT;
}
_delay_ms(1);
}while(Free < Length);
// Get the write pointer address
W5100_ReadRegister(SocketBase + W5100_OFFSET_TX_WR0, &Temp[0]);
W5100_ReadRegister(SocketBase + W5100_OFFSET_TX_WR1, &Temp[1]);
Offset = (((uint16_t)(Temp[0] << 0x08)) | Temp[1]) & W5100_TX_MEM_MASK;
// Check for an overflow
if(Offset + Length > SocketMemory)
{
uint16_t Upper;
uint16_t Left;
Upper = SocketMemory - Offset;
Left = Length - Upper;
W5100_WriteMemory(W5100_TX_BUFFER_BASE + (SocketMemory * Socket) + Offset, Buffer, Upper);
W5100_WriteMemory(W5100_TX_BUFFER_BASE + (SocketMemory * Socket), Buffer, Left);
}
else
{
W5100_WriteMemory(W5100_TX_BUFFER_BASE + (SocketMemory * Socket) + Offset, Buffer, Length);
}
W5100_WriteRegister(SocketBase + W5100_OFFSET_TX_WR0, Offset >> 0x08);
W5100_WriteRegister(SocketBase + W5100_OFFSET_TX_WR1, Offset & 0xFF);
return W5100_ExecuteCommand(Socket, W5100_CMD_SEND, Timeout);
}
你应该完全重写你的 W5100_Send
,因为它充满了问题。
例如,Mask
值的计算没有任何意义。
等待Free
值的循环总是延迟至少1毫秒,即使从一开始就获得了好的值。此外,当超时时,它会中断,即使收到 Free
值是好的。
Offset
值被 &
操作损坏:
Offset = (((uint16_t)(Temp[0] << 0x08)) | Temp[1]) & W5100_TX_MEM_MASK;
这个值永远不会增加写入的数据大小,损坏的值被写回W5100_OFFSET_TX_WR1:W5100_OFFSET_TX_WR0
wrapping数据写入出错:
W5100_WriteMemory(W5100_TX_BUFFER_BASE + (SocketMemory * Socket) + Offset, Buffer, Upper);
W5100_WriteMemory(W5100_TX_BUFFER_BASE + (SocketMemory * Socket), Buffer, Left);
您正在从 Buffer
开始复制到两个部分。在第二行应该是 &Buffer[Upper]
等等……
首先您需要确定套接字的大小。我鼓励您从一开始就设置套接字大小,从而避免在运行时计算偏移量和大小。
但是如果你想动态确定套接字大小,那么你可以这样做:
uint16_t SocketBufAddr = W5100_TX_BUFFER_BASE; // Start of the socket memory block
SocketMemory = 0; // Size of the socket memory block
W5100_ReadRegister(W5100_REGISTER_TMSR, &Mask);
for (uint8_t i = 0 ; i <= Socket ; i++) {
SocketBufAddr += SocketMemory; // Increase the offset by the previous socket size
SocketMemory = 1024 << ((Mask >> (i * 2)) & 3);
}
现在写的过程应该是这样的:
// Get the write pointer address
W5100_ReadRegister(SocketBase + W5100_OFFSET_TX_WR0, &Temp[0]);
W5100_ReadRegister(SocketBase + W5100_OFFSET_TX_WR1, &Temp[1]);
uint16_t WrPointer = (((uint16_t)(Temp[0] << 0x08)) | Temp[1]); // no & operation! It is the 16-bit pointer!!!
Offset = WrPointer & (SocketMemory - 1); // Offset inside the socket memory block. SocketMemory is always = 2^n
// Check for an overflow
if(Offset + Length > SocketMemory)
{
uint16_t Upper;
uint16_t Left;
Upper = SocketMemory - Offset ;
Left = Length - Upper;
W5100_WriteMemory(SocketBufAddr + Offset, Buffer, Upper);
W5100_WriteMemory(SocketBufAddr, &Buffer[Upper], Left);
}
else
{
W5100_WriteMemory(SocketBufAddr + Offset, Buffer, Length);
}
WrPointer += Length; // Increase full 16-bit pointer value
// Write the new pointer back
W5100_WriteRegister(SocketBase + W5100_OFFSET_TX_WR0, WrPointer >> 0x08);
W5100_WriteRegister(SocketBase + W5100_OFFSET_TX_WR1, WrPointer & 0xFF);
return W5100_ExecuteCommand(Socket, W5100_CMD_SEND, Timeout);
我尝试使用 W5100 Ethernet Controller 和 XMega 实现 Web 界面,但我的浏览器打印出这个奇怪的结果:
请看我的代码:
SPIM_Config_t Config_SPIM = {
.Device = &SPIC,
.Mode = SPI_MODE_0,
.Prescaler = SPI_PRESCALER_64,
};
W5100_Config_t Config_Ethernet = {
.Submask = {255, 255, 0, 0},
.IP = {169, 254, 133, 121},
.Gateway = {169, 154, 133, 129},
.MAC = {0x00, 0x00, 0x00, 0x00, 0x00, 0xAA}
};
uint8_t Rx_Buffer[2048];
uint8_t Tx_Buffer[2048];
const char HTTP[] = "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nPragma: no-cache\r\n\r\n"
"<html>\r\n"
"<body>\r\n"
"<title>Title</title>\r\n"
"<p>Hello world</p>\r\n"
"</body>\r\n"
"</html>\r\n";
int main(void)
{
W5100_Init(&Config_SPIM, &Config_Ethernet);
while(1)
{
W5100_Status_t Status;
W5100_GetState(0, &Status);
switch(Status)
{
case W5100_SOCK_CLOSED:
{
if(W5100_Open(0, W5100_PROT_TCP, 80, W5100_MEM_2K, W5100_MEM_2K, 65535) == W5100_NO_ERROR)
{
W5100_Listen(0, ETHERNET_TIMEOUT);
}
break;
}
case W5100_SOCK_ESTABLISHED:
{
uint16_t Rx_Bytes;
if(W5100_GetBytes(0, &Rx_Bytes) == W5100_NO_ERROR)
{
if(Rx_Bytes)
{
W5100_Receive(0, Rx_Buffer, Rx_Bytes);
strcpy((char*)Tx_Buffer, HTTP);
W5100_Send(0, Tx_Buffer, strlen((char*)HTTP), ETHERNET_TIMEOUT);
}
else
{
}
}
W5100_Disconnect(0, ETHERNET_TIMEOUT);
break;
}
case W5100_SOCK_FIN_WAIT:
case W5100_SOCK_CLOSING:
case W5100_SOCK_TIME_WAIT:
case W5100_SOCK_CLOSE_WAIT:
case W5100_SOCK_LAST_ACK:
{
W5100_Close(0, ETHERNET_TIMEOUT);
break;
}
}
}
}
我认为错误出在我的 W5100_Send
函数中,似乎控制器正在发送不同内存位置的内容,但我无法找出错误。基于以太网控制器数据表的代码:
W5100_ErrorCode_t W5100_Send(uint8_t Socket, uint8_t* Buffer, uint16_t Length, uint32_t Timeout)
{
uint8_t Temp[2];
uint8_t Mask;
uint16_t SocketBase;
uint16_t Offset;
uint16_t Free;
uint16_t SocketMemory;
uint32_t Timeout_Temp = Timeout;
if(!_W5100_IsInitialized)
{
return W5100_NOT_INITIALIZED;
}
else if((Socket > 0x04) || (Buffer == NULL) || (Length == 0x00))
{
return W5100_INVALID_PARAM;
}
// Get the memory mask for address calculation
W5100_ReadRegister(W5100_REGISTER_TMSR, &Mask);
Mask &= (0x03 << (Socket << 0x01));
// Check for invalid memory by comparing the memory mask for the given socket and the socket index
if(((Socket > 0) && (Mask == 3)) || ((Socket > 1) && (Mask == 2)))
{
return W5100_INVALID_PARAM;
}
SocketBase = W5100_SOCKET_ADDR(Socket);
SocketMemory = W5100_SOCKET_MEM_OFFSET << Mask;
// Wait while the buffer is full
do
{
// Get the free bytes
W5100_ReadRegister(SocketBase + W5100_OFFSET_TX_FSR0, &Temp[0]);
W5100_ReadRegister(SocketBase + W5100_OFFSET_TX_FSR1, &Temp[1]);
Free = ((uint16_t)(Temp[0] << 0x08)) | Temp[1];
if(Timeout_Temp-- == 0x00)
{
W5100_Disconnect(Socket, Timeout);
return W5100_TIMEOUT;
}
_delay_ms(1);
}while(Free < Length);
// Get the write pointer address
W5100_ReadRegister(SocketBase + W5100_OFFSET_TX_WR0, &Temp[0]);
W5100_ReadRegister(SocketBase + W5100_OFFSET_TX_WR1, &Temp[1]);
Offset = (((uint16_t)(Temp[0] << 0x08)) | Temp[1]) & W5100_TX_MEM_MASK;
// Check for an overflow
if(Offset + Length > SocketMemory)
{
uint16_t Upper;
uint16_t Left;
Upper = SocketMemory - Offset;
Left = Length - Upper;
W5100_WriteMemory(W5100_TX_BUFFER_BASE + (SocketMemory * Socket) + Offset, Buffer, Upper);
W5100_WriteMemory(W5100_TX_BUFFER_BASE + (SocketMemory * Socket), Buffer, Left);
}
else
{
W5100_WriteMemory(W5100_TX_BUFFER_BASE + (SocketMemory * Socket) + Offset, Buffer, Length);
}
W5100_WriteRegister(SocketBase + W5100_OFFSET_TX_WR0, Offset >> 0x08);
W5100_WriteRegister(SocketBase + W5100_OFFSET_TX_WR1, Offset & 0xFF);
return W5100_ExecuteCommand(Socket, W5100_CMD_SEND, Timeout);
}
你应该完全重写你的 W5100_Send
,因为它充满了问题。
例如,Mask
值的计算没有任何意义。
等待Free
值的循环总是延迟至少1毫秒,即使从一开始就获得了好的值。此外,当超时时,它会中断,即使收到 Free
值是好的。
Offset
值被 &
操作损坏:
Offset = (((uint16_t)(Temp[0] << 0x08)) | Temp[1]) & W5100_TX_MEM_MASK;
这个值永远不会增加写入的数据大小,损坏的值被写回W5100_OFFSET_TX_WR1:W5100_OFFSET_TX_WR0
wrapping数据写入出错:
W5100_WriteMemory(W5100_TX_BUFFER_BASE + (SocketMemory * Socket) + Offset, Buffer, Upper);
W5100_WriteMemory(W5100_TX_BUFFER_BASE + (SocketMemory * Socket), Buffer, Left);
您正在从 Buffer
开始复制到两个部分。在第二行应该是 &Buffer[Upper]
等等……
首先您需要确定套接字的大小。我鼓励您从一开始就设置套接字大小,从而避免在运行时计算偏移量和大小。
但是如果你想动态确定套接字大小,那么你可以这样做:
uint16_t SocketBufAddr = W5100_TX_BUFFER_BASE; // Start of the socket memory block
SocketMemory = 0; // Size of the socket memory block
W5100_ReadRegister(W5100_REGISTER_TMSR, &Mask);
for (uint8_t i = 0 ; i <= Socket ; i++) {
SocketBufAddr += SocketMemory; // Increase the offset by the previous socket size
SocketMemory = 1024 << ((Mask >> (i * 2)) & 3);
}
现在写的过程应该是这样的:
// Get the write pointer address
W5100_ReadRegister(SocketBase + W5100_OFFSET_TX_WR0, &Temp[0]);
W5100_ReadRegister(SocketBase + W5100_OFFSET_TX_WR1, &Temp[1]);
uint16_t WrPointer = (((uint16_t)(Temp[0] << 0x08)) | Temp[1]); // no & operation! It is the 16-bit pointer!!!
Offset = WrPointer & (SocketMemory - 1); // Offset inside the socket memory block. SocketMemory is always = 2^n
// Check for an overflow
if(Offset + Length > SocketMemory)
{
uint16_t Upper;
uint16_t Left;
Upper = SocketMemory - Offset ;
Left = Length - Upper;
W5100_WriteMemory(SocketBufAddr + Offset, Buffer, Upper);
W5100_WriteMemory(SocketBufAddr, &Buffer[Upper], Left);
}
else
{
W5100_WriteMemory(SocketBufAddr + Offset, Buffer, Length);
}
WrPointer += Length; // Increase full 16-bit pointer value
// Write the new pointer back
W5100_WriteRegister(SocketBase + W5100_OFFSET_TX_WR0, WrPointer >> 0x08);
W5100_WriteRegister(SocketBase + W5100_OFFSET_TX_WR1, WrPointer & 0xFF);
return W5100_ExecuteCommand(Socket, W5100_CMD_SEND, Timeout);