FreeRTOS+LWIP(4)

2019-08-20 19:34

pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ #endif

LINK_STATS_INC(link.recv); } else {

//drop packet();

LINK_STATS_INC(link.memerr); LINK_STATS_INC(link.drop); }

return p; }

1.5 low_level_output函数

该函数的功能是将pbuf中的数据帧通过底层发送函数ENC28J60_Packet_Send发送出去,由于要发送的数据可能被分割成多个pbuf,而这些pbuf通过pbuf->next指针连接起来,因此low_level_output函数需要使用foe循环将这些pbuf中的数据拷贝至当前的发送缓冲区中。源代码如下: static err_t

low_level_output(struct netif *netif, struct pbuf *p) {

// struct ethernetif *ethernetif = netif->state; struct pbuf *q; int send_len=0;

// initiate transfer(); #if ETH_PAD_SIZE

pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */ #endif

for(q = p; q != NULL; q = q->next) {

/* Send the data from the pbuf to the interface, one pbuf at a time. The size of the data in each pbuf is kept in the ->len variable. */

//send data from(q->payload, q->len); memcpy((u8_t*)&lwip_buf[send_len], (u8_t*)q->payload, q->len); send_len +=q->len; }

// signal that packet should be sent();

ENC28J60_Packet_Send(send_len,lwip_buf); #if ETH_PAD_SIZE

pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ #endif

LINK_STATS_INC(link.xmit); return ERR_OK; }

2、 网卡驱动

本次用的是ENC28J60网卡模块。ENC28J60 是带有行业标准串行外设接口

( Serial Peripheral Interface,SPI)的独立以太网控制器。它可作为任何配备有 SPI 的控制器的以太网接口。ENC28J60 符合IEEE 802.3的全部规范,采用了一系列包过滤机制以对传入数据包进行限制。它还提供了一个内部 DMA 模块,以实现快速数据吞吐和硬件支持的IP校验和计算。与主控制器的通信通过两个中断引脚和SPI 实现,数据传输速率高达10Mb/s。

ENC28J60由七个主要功能模块组成:

1、 SPI接口——充当主控制器和ENC28J60之间通信通道。 2、 控制寄存器|——用于控制和监视ENC28J60. 3、 双端口RAM缓冲器——用于接收和发送数据包。 4、 判优器——当DMA、发送和接收模块发出请求是对RAM缓冲器的访问进行控制。 5、 总线接口——对通过SPI接收的数据和命令进行解析。

6、 MAC(Medium Access control)模块——实现符合IEEE802.3标准的MAC逻

辑。

7、 PHY(物理层)模块——对双绞线上的模拟数据进行编码和译码。该期间还包

括其他支持模块,诸如振荡器、片内稳压器、电平变换器(提供可以接受5V电压的I/O引脚)和系统控制逻辑。

enc28j60.c:ENC28J60(以太网芯片)SPI的接口应用函数库。

ENC28J60_Reset(void)这个函数里SPI的硬件初始化、设置SPI的时钟SCK的频率和复位ENC28J60.

ENC28J60_Read_Op(u8 op,u8 addr)读取ENC28J60寄存器(带操作码)op:操作码addr:寄存器地址/参数返回值:读到的数据。

ENC28J60_Write_Op(u8 op,u8 addr,u8 data)读取ENC28J60寄存器(带操作码)op:操作码addr:寄存器地址data:参数 返回值 :无返回值(函数为Void类型的)。

ENC28J60_Read_Buf(u32 len,u8* data)读取ENC28J60接收缓存数据len:要读取的数据长度data:输出数据缓存区(末尾自动添加结束符) 返回值 :无返回值(函数为Void类型的)。

ENC28J60_Write_Buf(u32 len,u8* data)向ENC28J60写发送缓存数据len:要写入的数据长度data:数据缓存区 返回值 :无返回值(函数为Void类型的)。

ENC28J60_Set_Bank(u8 bank)设置ENC28J60寄存器Bank

bank:要设置的bank 返回值 :无返回值(函数为Void类型的)。

ENC28J60_Read(u8 addr)读取ENC28J60指定寄存器 addr:寄存器地址返回值:读到的数据

ENC28J60_Write(u8 addr,u8 data)向ENC28J60指定寄存器写数据 addr:寄存器地址data:要写入的数据 返回值 :无返回值(函数为Void类型的)。

ENC28J60_PHY_Write(u8 addr,u32 data)向ENC28J60的PHY寄存器写入数据addr:寄存器地址data:要写入的数据 返回值 :无返回值(函数为Void类型的)。

ENC28J60_Init(u8* macaddr)初始化ENC28J60

macaddr:MAC地址返回值:0,初始化成功;1,初始化失败;

ENC28J60_Get_EREVID(void)在EREVID 内也存储了版本信息。 EREVID 是一个只读控制寄存器,包含一个5 位标识符,用来标识器件特定硅片的版本号

ENC28J60_Packet_Send(u32 len,u8* packet)通过ENC28J60发送数据包到网络len:数据包大小packet:数据包 返回值 :无返回值(函数为Void类型的)。

ENC28J60_Packet_Receive(u32 maxlen,u8* packet)从网络获取一个数据包内容maxlen:数据包最大允许接收长度

packet:数据包缓存区 返回值:收到的数据包长度(字节)

基于FreeRTOS的LWIP协议栈移植

在FreeRTOS操作系统下的LWIP任务模型:

1 操作系统模拟层文件sys_arch.c的移植

在LWIP中,操作系统模拟层是LWIP协议栈的一部分,它存在的目的是方便将LWIP移植到各种不同的操作系统上,它为操作系统和LWIP协议栈之间提供一个接口桥梁,当用户移植LWIP到一个新的操作系统的时候,只需要修改操作系统模拟层内的各函数即可。Sys_arch.txt文件给出了详细说明。总的来说,操作系统模拟层主要完成了与信号量、消息邮箱机制、线程相关的功能。

看如下三个类型定义:

typedef xSemaphoreHandle sys_sem_t;//在LWIP中信号量使用这个类型定义 typedef xQueueHandle sys_mbox_t;//在LWIP中队列消息使用这个类型定义 typedef xTaskHandle sys_thread_t;//在LWIP中线程使用这个类型定义 1. sys_mbox_new函数

该函数的功能是使用FreeRTOS提供的消息队列机制创建一个空的消息队列。在FreeRTOS中,消息队列创建函数是xQueueCreate。创建的邮箱大小由sys_arch.h中的宏定义archMESG_QUEUE_LENGTH实现。具体代码如下:

err_t sys_mbox_new(sys_mbox_t *mbox, int size) {

(void ) size;

*mbox = xQueueCreate( archMESG_QUEUE_LENGTH, sizeof( void * ) ); #if SYS_STATS

++lwip_stats.sys.mbox.used;

if (lwip_stats.sys.mbox.max < lwip_stats.sys.mbox.used) {

lwip_stats.sys.mbox.max = lwip_stats.sys.mbox.used; }

#endif /* SYS_STATS */ if (*mbox == NULL) return ERR_MEM; return ERR_OK; } 2. sys_mbox_free函数

该函数功能与sys_mbox_new相反,它用于删除一个队列。该队列中还有未被取出的消息时,该函数应当报错,并通知应用程序。代码如下:

void sys_mbox_free(sys_mbox_t *mbox)

{

if( uxQueueMessagesWaiting( *mbox ) ) { /* Line for breakpoint. Should never break here! */ portNOP(); #if SYS_STATS

lwip_stats.sys.mbox.err++; #endif /* SYS_STATS */ // TODO notify the user of failure. }

vQueueDelete( *mbox ); #if SYS_STATS

--lwip_stats.sys.mbox.used; #endif /* SYS_STATS */ }

3. sys_mbox_post函数

该函数用于将消息发送至消息队列中。该函数是一个阻塞函数。当消息被发送至队列后,该函数才退出阻塞状态。代码如下:

void sys_mbox_post(sys_mbox_t *mbox, void *data) {

while ( xQueueSendToBack(*mbox, &data, portMAX_DELAY ) != pdTRUE ){} }

4. sys_mbox_trypost函数

该函数用于尝试将某个消息发送至消息队列中,当消息被成功投递后,则返回成功,否则返回失败。代码如下:

err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg) {

err_t result;

if ( xQueueSend( *mbox, &msg, 0 ) == pdPASS ) {

result = ERR_OK; } else {

// could not post, queue must be full result = ERR_MEM; #if SYS_STATS

lwip_stats.sys.mbox.err++; #endif /* SYS_STATS */ }

return result; }

5. sys_arch_mbox_fetch函数


FreeRTOS+LWIP(4).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:中国公务员制度第2阶段测试题

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: