用于ATmega设备的Wiznet W5100库

来源:本站
导读:目前正在解读《用于ATmega设备的Wiznet W5100库》的相关信息,《用于ATmega设备的Wiznet W5100库》是由用户自行发布的知识型内容!下面请观看由(电工技术网 - www.9ddd.net)用户发布《用于ATmega设备的Wiznet W5100库》的详细说明。
简介: 用于ATmega设备的Wiznet W5100库

几个月前我就开始研究W5100芯片而且非常喜欢它。我建立了一个测试平台,并使用ATmaga644p通过总线连接W5100(在WIZ811MJ开发板上)。

一开始,我从ermicroblog网站上下载并加载代码。这些代码都是由RWB开发的,他开创了一个很好的开端。我尤其是喜欢RWB一步一步演绎一个完整例子的过程,有一行行的代码作为理论基础,没有头文件会丢失,也不需要后台代码作支撑。

我重新编写了RWB的代码,并且创建一个W5100设备库。请注意这个库内的目标是相互独立的。这就意味着你可以链接任何ATmega项目的代码而不需要每次都对库进行重建,因为你的硬件和我的不兼容。这种独立性来自一个叫做W51_register()的成熟调用例程,它允许你通过函数指针设置到库内进行具体的目标测试,比如启用/禁用W5100芯片和通过设备进行数据交换。

W5100库代码

以下是W5100库模块的代码。不像RWB的代码,我的代码使用了一个头文件(源于RWB的代码和微知纳特数据手册的结合);你可以在页面最底部的的压缩包文件看到它。

/*

* w5100.c library of target-independent AVR support routines

* for the Wiznet W5100 Ethernet interface device

*

* This file is derived from the excellent work found here:

* www.ermicro.com/blog/?p=1773

* by RWB. I am leaving the header from the original file intact below,

* but you need to remember the rest of the source here is fairly

* heavily modified. Go to the above site for the original.

*/

/*****************************************************************************

// File Name : wiznetping.c

// Version : 1.0

// Description : Wiznet W5100

// Author : RWB

// Target : AVRJazz Mega168 Board

// Compiler : AVR-GCC 4.3.2; avr-libc 1.6.6 (WinAVR 20090313)

// IDE : Atmel AVR Studio 4.17

// Programmer : AVRJazz Mega168 STK500 v2.0 Bootloader

// : AVR Visual Studio 4.17, STK500 programmer

// Last Updated : 01 July 2010

*****************************************************************************/

/*

* The following code turns the above wiznetping.c source code into a

* generic library of W5100 support routines that are target-independent.

* That is, you build this library for a generic AVR ATmega device, then

* write your application to use the W51_xxx routines below for accessing

* the W5100 chip. Because these routines are target-independent, you

* never have to rebuild them just because you are moving your code from,

* say, a ‘mega128 to an ‘xmega128a1 device.

*

* For this to work properly, your application must provide three target-

* specific functions and must register the addresses of those functions

* with the W5100 library at run-time. These functions are:

*

* select target-specific function for enabling the W5100 chip

* xchg target-specific function for exchanging a byte with the W5100 chip

* deselect target-specific function for disabling the W5100 chip

* reset target-specific function for hardware reset of the W5100 chip

*

* Your application registers these three functions with the W5100 library

* by invoking the W51_register() function. Your application must make this

* call one time and must make this call before calling any other W5100

* functions.

*/

#include <util/delay.h>

#include “w5100.h”

#ifndef FALSE

#define FALSE 0

#define TRUE !FALSE

#endif

/*

* Define the function pointers used to access the SPI port assigned to the

* W5100 device. These pointers will be filled in at run-time when the host

* calls W51_register().

*/

static void (*select)(void) = (void *)0;

static unsigned char (*xchg)(unsigned char val) = (void *)0;

static void (*deselect)(void) = (void *)0;

static void (*reset)(void) = (void *)0;

static unsigned char inited = FALSE;

void W51_register(W5100_CALLBACKS *pcallbacks)

{

select = pcallbacks->_select;

xchg = pcallbacks->_xchg;

deselect = pcallbacks->_deselect;

reset = pcallbacks->_reset;

inited = FALSE;

if ((select) && (xchg) && (deselect)) inited = TRUE; // these functions must be valid

}

void W51_write(unsigned int addr, unsigned char data)

{

if (!inited) return; // not set up, ignore request

select(); // enable the W5100 chip

xchg(W5100_WRITE_OPCODE); // need to write a byte

xchg((addr & 0xff00) >> 8); // send MSB of addr

xchg(addr & 0xff); // send LSB

xchg(data); // send the data

deselect(); // done with the chip

}

unsigned char W51_read(unsigned int addr)

{

unsigned char val;

if (!inited) return 0; // not set up, ignore request

select(); // enable the W5100 chip

xchg(W5100_READ_OPCODE); // need to read a byte

xchg((addr & 0xff00) >> 8); // send MSB of addr

xchg(addr & 0xff); // send LSB

val = xchg(0×00); // need to send a dummy char to get response

deselect(); // done with the chip

return val; // tell her what she’s won

}

void W51_init(void)

{

if (reset) reset(); // if host provided a reset function, use it

else W51_write(W5100_MR, W5100_MR_SOFTRST); // otherwise, force the w5100 to soft-reset

_delay_ms(1);

}

unsigned char W51_config(W5100_CFG *pcfg)

{

if (pcfg == 0) return W5100_FAIL;

W51_write(W5100_GAR + 0, pcfg->gtw_addr[0]); // set up the gateway address

W51_write(W5100_GAR + 1, pcfg->gtw_addr[1]);

W51_write(W5100_GAR + 2, pcfg->gtw_addr[2]);

W51_write(W5100_GAR + 3, pcfg->gtw_addr[3]);

_delay_ms(1);

W51_write(W5100_SHAR + 0, pcfg->mac_addr[0]); // set up the MAC address

W51_write(W5100_SHAR + 1, pcfg->mac_addr[1]);

W51_write(W5100_SHAR + 2, pcfg->mac_addr[2]);

W51_write(W5100_SHAR + 3, pcfg->mac_addr[3]);

W51_write(W5100_SHAR + 4, pcfg->mac_addr[4]);

W51_write(W5100_SHAR + 5, pcfg->mac_addr[5]);

_delay_ms(1);

W51_write(W5100_SUBR + 0, pcfg->sub_mask[0]); // set up the subnet mask

W51_write(W5100_SUBR + 1, pcfg->sub_mask[1]);

W51_write(W5100_SUBR + 2, pcfg->sub_mask[2]);

W51_write(W5100_SUBR + 3, pcfg->sub_mask[3]);

_delay_ms(1);

W51_write(W5100_SIPR + 0, pcfg->ip_addr[0]); // set up the source IP address

W51_write(W5100_SIPR + 1, pcfg->ip_addr[1]);

W51_write(W5100_SIPR + 2, pcfg->ip_addr[2]);

W51_write(W5100_SIPR + 3, pcfg->ip_addr[3]);

_delay_ms(1);

W51_write(W5100_RMSR, 0×55); // use default buffer sizes (2K bytes RX and TX for each socket

W51_write(W5100_TMSR, 0×55);

return W5100_OK; // everything worked, show success

}

使用库

下面来教你使用这个库。创建一个新的AVRStudio4项目,并且在你的项目(记得修改你的项目配置中文件夹的大小,以便能放得下W5100.h文件)里添加W5100.h头文件。同时修改你的项目配置来添加W5100库,以便你在建立项目时连接器能找到它。

在你的资源库中,你需要写下三个(也可以是4个)具体目标例程。这三个必需的例程可以实现通过总线访问电路板中的W5100芯片。select()例程用来选择端口线与W5100设备进行连接。deselect()例程的作用是取消对W5100设备的选择。xchg()例程的作用是,每当通过总线向W5100发送一个字节的数据,会同时向调用例程返回一个字节的数据。有时候,你可能还会用到reset()例程,它的作用是使端口线重置W5100设备。我真心建议你将来在硬件设置中使用它,因为有时在W5100启动时会遇到一些故障,到时候你对它重置,就省事多了。

项目案例(网络服务器)

以下代码是使用库建立的网络服务器案例。

#include <avr/io.h>

#include <string.h>

#include <stdio.h>

#include <util/delay.h>

#include <avr/pgmspace.h>

#include “w5100.h”

unsigned char OpenSocket(unsigned char sock, unsigned char eth_protocol, unsigned int tcp_port);

void CloseSocket(unsigned char sock);

void DisconnectSocket(unsigned char sock);

unsigned char Listen(unsigned char sock);

unsigned char Send(unsigned char sock, const unsigned char *buf, unsigned int buflen);

unsigned int Receive(unsigned char sock, unsigned char *buf, unsigned int buflen);

unsigned int ReceivedSize(unsigned char sock);

void my_select(void);

void my_deselect(void);

unsigned char my_xchg(unsigned char val);

void my_reset(void);

#define MAX_BUF 512 /* largest buffer we can read from chip */

#define HTTP_PORT 80 /* TCP port for HTTP */

/*

* Ethernet setup

*

* Define the MAC address, IP address, subnet mask, and gateway

* address for the target device.

*/

W5100_CFG my_cfg =

{

{0×00,0×16,0×36,0xDE,0×58,0xF6}, // mac_addr

{192,168,1,233}, // ip_addr

{255,255,255,0}, // sub_mask

{192,168,1,1} // gtw_addr

};

/*

* Callback function block

*

* Define callback functions for target-independent support of the

* W5100 chip. Here is where you store pointers to the various

* functions needed by the W5100 library code. These functions all

* handle tasks that are target-dependent, which means the library

* code can be target-INdependent.

*/

W5100_CALLBACKS my_callbacks;

unsigned char buf[MAX_BUF];

unsigned char OpenSocket(unsigned char sock, unsigned char eth_protocol, unsigned int tcp_port)

{

unsigned char retval;

unsigned int sockaddr;

retval = W5100_FAIL; // assume this doesn’t work

if (sock >= W5100_NUM_SOCKETS) return retval; // illegal socket value is bad!

sockaddr = W5100_SKT_BASE(sock); // calc base addr for this socket

if (W51_read(sockaddr+W5100_SR_OFFSET) == W5100_SKT_SR_CLOSED) // Make sure we close the socket first

{

CloseSocket(sock);

}

W51_write(sockaddr+W5100_MR_OFFSET ,eth_protocol); // set protocol for this socket

W51_write(sockaddr+W5100_PORT_OFFSET, ((tcp_port & 0xFF00) >> 8 )); // set port for this socket (MSB)

W51_write(sockaddr+W5100_PORT_OFFSET + 1, (tcp_port & 0x00FF)); // set port for this socket (LSB)

W51_write(sockaddr+W5100_CR_OFFSET, W5100_SKT_CR_OPEN); // open the socket

while (W51_read(sockaddr+W5100_CR_OFFSET)) ; // loop until device reports socket is open (blocks!!)

if (W51_read(sockaddr+W5100_SR_OFFSET) == W5100_SKT_SR_INIT) retval = sock; // if success, return socket number

else CloseSocket(sock); // if failed, close socket immediately

return retval;

}

void CloseSocket(unsigned char sock)

{

unsigned int sockaddr;

if (sock > W5100_NUM_SOCKETS) return; // if illegal socket number, ignore request

sockaddr = W5100_SKT_BASE(sock); // calc base addr for this socket

W51_write(sockaddr+W5100_CR_OFFSET, W5100_SKT_CR_CLOSE); // tell chip to close the socket

while (W51_read(sockaddr+W5100_CR_OFFSET)) ; // loop until socket is closed (blocks!!)

}

void DisconnectSocket(unsigned char sock)

{

unsigned int sockaddr;

if (sock > W5100_NUM_SOCKETS) return; // if illegal socket number, ignore request

sockaddr = W5100_SKT_BASE(sock); // calc base addr for this socket

W51_write(sockaddr+W5100_CR_OFFSET, W5100_SKT_CR_DISCON); // disconnect the socket

while (W51_read(sockaddr+W5100_CR_OFFSET)) ; // loop until socket is closed (blocks!!)

}

unsigned char Listen(unsigned char sock)

{

unsigned char retval;

unsigned int sockaddr;

retval = W5100_FAIL; // assume this fails

if (sock > W5100_NUM_SOCKETS) return retval; // if illegal socket number, ignore request

sockaddr = W5100_SKT_BASE(sock); // calc base addr for this socket

if (W51_read(sockaddr+W5100_SR_OFFSET) == W5100_SKT_SR_INIT) // if socket is in initialized state…

{

W51_write(sockaddr+W5100_CR_OFFSET, W5100_SKT_CR_LISTEN); // put socket in listen state

while (W51_read(sockaddr+W5100_CR_OFFSET)) ; // block until command is accepted

if (W51_read(sockaddr+W5100_SR_OFFSET) == W5100_SKT_SR_LISTEN) retval = W5100_OK; // if socket state changed, show success

else CloseSocket(sock); // not in listen mode, close and show an error occurred

}

return retval;

}

unsigned char Send(unsigned char sock, const unsigned char *buf, unsigned int buflen)

{

unsigned int ptr;

unsigned int offaddr;

unsigned int realaddr;

unsigned int txsize;

unsigned int timeout;

unsigned int sockaddr;

if (buflen == 0 || sock >= W5100_NUM_SOCKETS) return W5100_FAIL; // ignore illegal requests

sockaddr = W5100_SKT_BASE(sock); // calc base addr for this socket

// Make sure the TX Free Size Register is available

txsize = W51_read(sockaddr+W5100_TX_FSR_OFFSET); // make sure the TX free-size reg is available

txsize = (((txsize & 0x00FF) << 8 ) + W51_read(sockaddr+W5100_TX_FSR_OFFSET + 1));

timeout = 0;

while (txsize < buflen)

{

_delay_ms(1);

txsize = W51_read(sockaddr+W5100_TX_FSR_OFFSET); // make sure the TX free-size reg is available

txsize = (((txsize & 0x00FF) << 8 ) + W51_read(sockaddr+W5100_TX_FSR_OFFSET + 1));

if (timeout++ > 1000) // if max delay has passed…

{

DisconnectSocket(sock); // can’t connect, close it down

return W5100_FAIL; // show failure

}

}

// Read the Tx Write Pointer

ptr = W51_read(sockaddr+W5100_TX_WR_OFFSET);

offaddr = (((ptr & 0x00FF) << 8 ) + W51_read(sockaddr+W5100_TX_WR_OFFSET + 1));

while (buflen)

{

buflen–;

realaddr = W5100_TXBUFADDR + (offaddr & W5100_TX_BUF_MASK); // calc W5100 physical buffer addr for this socket

W51_write(realaddr, *buf); // send a byte of application data to TX buffer

offaddr++; // next TX buffer addr

buf++; // next input buffer addr

}

W51_write(sockaddr+W5100_TX_WR_OFFSET, (offaddr & 0xFF00) >> 8); // send MSB of new write-pointer addr

W51_write(sockaddr+W5100_TX_WR_OFFSET + 1, (offaddr & 0x00FF)); // send LSB

W51_write(sockaddr+W5100_CR_OFFSET, W5100_SKT_CR_SEND); // start the send on its way

while (W51_read(sockaddr+W5100_CR_OFFSET)) ; // loop until socket starts the send (blocks!!)

return W5100_OK;

}

/*

* Define the SPI port, used to exchange data with a W5100 chip.

*/

#define SPI_PORT PORTB /* target-specific port containing the SPI lines */

#define SPI_DDR DDRB /* target-specific DDR for the SPI port lines */

#define CS_DDR DDRD /* target-specific DDR for chip-select */

#define CS_PORT PORTD /* target-specific port used as chip-select */

#define CS_BIT 2 /* target-specific port line used as chip-select */

#define RESET_DDR DDRD /* target-specific DDR for reset */

#define RESET_PORT PORTD /* target-specific port used for reset */

#define RESET_BIT 3 /* target-specific port line used as reset */

/*

* Define macros for selecting and deselecting the W5100 device.

*/

#define W51_ENABLE CS_PORT&=~(1<<CS_BIT)

#define W51_DISABLE CS_PORT|=(1<<CS_BIT)

unsigned int Receive(unsigned char sock, unsigned char *buf, unsigned int buflen)

{

unsigned int ptr;

unsigned int offaddr;

unsigned int realaddr;

unsigned int sockaddr;

if (buflen == 0 || sock >= W5100_NUM_SOCKETS) return W5100_FAIL; // ignore illegal conditions

if (buflen > (MAX_BUF-2)) buflen = MAX_BUF – 2; // requests that exceed the max are truncated

sockaddr = W5100_SKT_BASE(sock); // calc base addr for this socket

ptr = W51_read(sockaddr+W5100_RX_RD_OFFSET); // get the RX read pointer (MSB)

offaddr = (((ptr & 0x00FF) << 8 ) + W51_read(sockaddr+W5100_RX_RD_OFFSET + 1)); // get LSB and calc offset addr

while (buflen)

{

buflen–;

realaddr = W5100_RXBUFADDR + (offaddr & W5100_RX_BUF_MASK);

*buf = W51_read(realaddr);

offaddr++;

buf++;

}

*buf=’′; // buffer read is complete, terminate the string

// Increase the S0_RX_RD value, so it point to the next receive

W51_write(sockaddr+W5100_RX_RD_OFFSET, (offaddr & 0xFF00) >> 8); // update RX read offset (MSB)

W51_write(sockaddr+W5100_RX_RD_OFFSET + 1,(offaddr & 0x00FF)); // update LSB

// Now Send the RECV command

W51_write(sockaddr+W5100_CR_OFFSET, W5100_SKT_CR_RECV); // issue the receive command

_delay_us(5); // wait for receive to start

return W5100_OK;

}

unsigned int ReceivedSize(unsigned char sock)

{

unsigned int val;

unsigned int sockaddr;

if (sock >= W5100_NUM_SOCKETS) return 0;

sockaddr = W5100_SKT_BASE(sock); // calc base addr for this socket

val = W51_read(sockaddr+W5100_RX_RSR_OFFSET) & 0xff;

val = (val << 8) + W51_read(sockaddr+W5100_RX_RSR_OFFSET + 1);

return val;

}

/*

* Simple wrapper function for selecting the W5100 device. This function

* allows the library code to invoke a target-specific function for enabling

* the W5100 chip.

*/

void my_select(void)

{

W51_ENABLE;

}

/*

* Simple wrapper function for deselecting the W5100 device. This function

* allows the library code to invoke a target-specific function for disabling

* the W5100 chip.

*/

void my_deselect(void)

{

W51_DISABLE;

}

/*

* my_xchg callback function; exchanges a byte with W5100 chip

*/

unsigned char my_xchg(unsigned char val)

{

SPDR = val;

while (!(SPSR & (1<<SPIF))) ;

return SPDR;

}

/*

* my_reset callback function; force a hardware reset of the W5100 device

*/

void my_reset(void)

{

RESET_PORT |= (1<<RESET_BIT); // pull reset line high

RESET_DDR |= (1<<RESET_BIT); // now make it an output

RESET_PORT &= ~(1<<RESET_BIT); // pull the line low

_delay_ms(5); // let the device reset

RESET_PORT |= (1<<RESET_BIT); // done with reset, pull the line high

_delay_ms(10); // let the chip wake up

}

int main(void)

{

unsigned int sockaddr;

unsigned char mysocket;

unsigned int rsize;

mysocket = 0; // magic number! declare the socket number we will use (0-3)

sockaddr = W5100_SKT_BASE(mysocket); // calc address of W5100 register set for this socket

/*

* Initialize the ATmega644p SPI subsystem

*/

CS_PORT |= (1<<CS_BIT); // pull CS pin high

CS_DDR |= (1<<CS_BIT); // now make it an output

SPI_PORT = SPI_PORT | (1<<PORTB4); // make sure SS is high

SPI_DDR = (1<<PORTB4)|(1<<PORTB5)|(1<<PORTB7); // set MOSI, SCK and SS as output, others as input

SPCR = (1<<SPE)|(1<<MSTR); // enable SPI, master mode 0

SPSR |= (1<<SPI2X); // set the clock rate fck/2

/*

* Load up the callback block, then initialize the Wiznet W5100

*/

my_callbacks._select = &my_select; // callback for selecting the W5100

my_callbacks._xchg = &my_xchg; // callback for exchanging data

my_callbacks._deselect = &my_deselect; // callback for deselecting the W5100

my_callbacks._reset = &my_reset; // callback for hardware-reset of the W5100

W51_register(&my_callbacks); // register our target-specific W5100 routines with the W5100 library

W51_init(); // now initialize the W5100

/*

* Configure the W5100 device to handle PING requests.

* This requires configuring the chip, not a specific socket.

*/

W51_config(&my_cfg); // config the W5100 (MAC, TCP address, subnet, etc

/*

* The main loop. Control stays in this loop forever, processing any received packets

* and sending any requested data.

*/

while (1)

{

switch (W51_read(sockaddr+W5100_SR_OFFSET)) // based on current status of socket…

{

case W5100_SKT_SR_CLOSED: // if socket is closed…

if (OpenSocket(mysocket, W5100_SKT_MR_TCP, HTTP_PORT) == mysocket) // if successful opening a socket…

{

Listen(mysocket);

_delay_ms(1);

}

break;

case W5100_SKT_SR_ESTABLISHED: // if socket connection is established…

rsize = ReceivedSize(mysocket); // find out how many bytes

if (rsize > 0)

{

if (Receive(mysocket, buf, rsize) != W5100_OK) break; // if we had problems, all done

/*

* Add code here to process the payload from the packet.

*

* For now, we just ignore the payload and send a canned HTML page so the client at least

* knows we are alive.

*/

strcpy_P((char *)buf, PSTR(“HTTP/1.0 200 OKrnContent-Type: text/htmlrnPragma: no-cachernrn”));

strcat_P((char *)buf, PSTR(“<html>rn<body>rn”));

strcat_P((char *)buf, PSTR(“<title>Karl’s W5100 web server (ATmega644p)</title>rn”));

strcat_P((char *)buf, PSTR(“<h2>Karl’s ATmega644p web server using Wiznet W5100 chip</h2>rn”));

strcat_P((char *)buf, PSTR(“<br /><hr>rn”));

if (Send(mysocket, buf, strlen((char *)buf)) == W5100_FAIL) break; // just throw out the packet for now

strcpy_P((char *)buf, PSTR(“This is part 2 of the page.”));

strcat_P((char *)buf, PSTR(“</body>rn</html>rn”));

if (Send(mysocket, buf, strlen((char *)buf)) == W5100_FAIL) break; // just throw out the packet for now

DisconnectSocket(mysocket);

}

else // no data yet…

{

_delay_us(10);

}

break;

case W5100_SKT_SR_FIN_WAIT:

case W5100_SKT_SR_CLOSING:

case W5100_SKT_SR_TIME_WAIT:

case W5100_SKT_SR_CLOSE_WAIT:

case W5100_SKT_SR_LAST_ACK:

CloseSocket(mysocket);

break;

}

}

return 0;

}

关于网络服务器

上面的代码改编自RWB的源代码,因为源代码中有太多的限制因素。基本上这些代码都不解析服务器收到的数据包,它只负责固定和抛送文件。对于确认服务器的工作状态来说,这已经足够好了,但是对于完成一个项目来讲就差得远了。在网页中浏览RWB的代码,查找相似项目中的所有细节,他是怎么解析数据包并且创建网络服务器的。请注意我也删除了RWB源代码中所有USART的例程(但还是无效)。

我已经改编了4个RWB的W5100套接字源代码,你可以直接使用它们。这些代码都使用套接字0进行过测试,但还没经过其他的套接字测试,也没有进行多个套接字同时测试。

以上的代码,加上链接连到库里的,总共有2.4千字节数据量。是的!这就是不超过2.5千字节的ATmega644p网络服务器代码!

为了修改这些代码更好地被你所用,你需要重新编译回调函数(就是上面的main()主函数)来适应你的硬件。同时你也需要修改W5100_CFG的结构项来匹配你的网络;我在上面的my_cfg中有声明。最后一步就是重建并且链接W5100库模块,你应该会比我做得更好。

提醒:《用于ATmega设备的Wiznet W5100库》最后刷新时间 2024-03-14 01:13:00,本站为公益型个人网站,仅供个人学习和记录信息,不进行任何商业性质的盈利。如果内容、图片资源失效或内容涉及侵权,请反馈至,我们会及时处理。本站只保证内容的可读性,无法保证真实性,《用于ATmega设备的Wiznet W5100库》该内容的真实性请自行鉴别。