标题:
基于群星ARM的lwIP以太网中断分析
[打印本页]
作者:
yuyang911220
时间:
2015-1-27 17:42
标题:
基于群星ARM的lwIP以太网中断分析
以太网中断服务程序代码如下:
[cpp]
view plain
copy
void
lwIPEthernetIntHandler(void)
{
unsigned long ulStatus;
//
// Read and Clear the interrupt.
// 读并清除中断标志,这个中断是由软件触发的,所以要检查一下中断状态看看是否真的有中断发生
ulStatus = EthernetIntStatus(ETH_BASE, false);
EthernetIntClear(ETH_BASE, ulStatus);
//
// If a transmit/rx interrupt was active, run the low-level interrupt
// handler.
// 如果一个发送/接收中断被激活,运行底层中断处理程序.
if(ulStatus)
{ //这个函数将从群星以太网FIFO中读取数据包放到pbuf队列.这个pbuf队列可以供更高级一层调用.
//如果发送器空闲并且至少有一个包在发送队列,会将它发送到FIFO并开始发送.
stellarisif_interrupt(&lwip_netif); //注1
}
#if NO_SYS
//
// If no RTOS is enabled, then we do all lwIP procesing in the interrupt.
// 如果不使用RTOS,那么所有的lwIP处理都在中断中实现
//
// Service any packets on the receive queue.
// 接收队列上的任何包处理 当已经准备好从接口中读取数据时,这个函数被调用.它使用 底层ethernet_input()
// 函数处理来自网络接口的实际接收数据.它会根据已经接收的数据包类型来调用
// 适当的input函数.
stellarisif_input(&lwip_netif); //注2
//
// Service the lwIP timers.
// lwIP定时器处理
lwIPServiceTimers();
#endif
}
这个函数是以太网中断处理函数,处理
lwIP TCP/IP
协议栈的以太网中断。这个中断服务函数并非是接收到或发送出一个以太网包后由硬件触发,而是在
SysTick
定时器中断处理函数中软件触发的。这个函数处于
TCP/IP
协议的最底层,它将所有接收到的数据包放在可供高层处理的数据包队列中(
pbuf
链中),并检查发送数据队列是否为空,必要时通过以太网
MAC
地址发送数据。如果系统不使用
RTOS
,则
lwIP
的其他工作也在这个中断服务函数中执行,如处理接收的包或者处理
lwIP
定时器。
以太网中断服务函数(
lwIPEthernetIntHandler(void))
首先调用
EthernetIntStatus (ETH_BASE, false)
函数来检查以太网中断状态,因为这个以太网中断并非是硬件触发。可能并没有接收或发送以太网数据,但
SysTick
定时器中断服务函数仍尽忠职守的周期性触发这个以太网中断。之后,无论有无以太网中断,以太网中断服务函数都会调用
EthernetIntClear(ETH_BASE, ulStatus)
函数来清除以太网中断标志位。
如果检测到一个
TX
或
RX
中断,则首先调用
stellarisif_interrupt(&lwip_netif)
函数,这个函数会循环调用
low_level_receive(netif)
函数,从群星以太网
FIFO
中读取全部数据包放到
pbuf
中,并使用
enqueue_packet(p, ðernetif->rxq)
函数将每个
pbuf
压入
pbuf
队列中,这个
pbuf
队列可以供更高级一层调用
.
之后检查发送器,如果发送器空闲并且至少有一个包在发送队列
,
会将它发送到
FIFO
并开始发送。
stellarisif_interrupt(&lwip_netif)
函数代码如下所示:
[cpp]
view plain
copy
/**
* Process tx and rx packets at the low-level interrupt.
* 处理TX和RX数据包,在低层次中断时
* Should be called from the Stellaris Ethernet Interrupt Handler. This
* function will read packets from the Stellaris Ethernet fifo and place them
* into a pbuf queue. If the transmitter is idle and there is at least one packet
* on the transmit queue, it will place it in the transmit fifo and start the
* transmitter.
* 在群星以太网中断处理程序中被调用.这个函数将会从群星FIFO中读取数据包并且将它们放入
* pbuf队列.如果发送器空并且发送队列中至少有一个数据包时,该函数将把这个数据包放入发送
* FIFO并开始发送.
*/
void
stellarisif_interrupt(struct netif *netif)
{
struct ethernetif *ethernetif; //
struct pbuf *p;
/* setup pointer to the if state data */
ethernetif = netif->state;
/**
* Process the transmit and receive queues as long as there is receive
* data available
*这个函数将会从群星以太网接口读取一个数据包,如果数据包有效则返回一个指向pbuf的指针.
* 数据包的时间戳也将被放到pbuf结构体中(前提是LWIP_PTPD=1).
*/
p = low_level_receive(netif); //从RX FIFO中读取以太网数据并放入pbuf中
while(p != NULL) {
/* Add the rx packet to the rx queue
原型: static int enqueue_packet(struct pbuf *p, struct pbufq *q)
* Push a pbuf packet onto a pbuf packet queue
* 将一个pbuf数据包压入一个pbuf数据包队列之上(将RX数据包放到RX队列)
* @param p is the pbuf to push onto the packet queue. 要压入数据包队列的pbuf
* @param q is the packet queue.数据包队列
*
* @return 1 if successful, 0 if q is full. 返回1表示成功,0代表q已经满了
*/
if(!enqueue_packet(p, ðernetif->rxq)) {
/* Could not place the packet on the queue, bail out. */
pbuf_free(p);
break;
}
/* Check if TX fifo is empty and packet available 检查TX FIFO是否为空并且数据包是否有效*/
if((HWREG(ETH_BASE + MAC_O_TR) & MAC_TR_NEWTX) == 0) {
/**
* Pop a pbuf packet from a pbuf packet queue
* 从一个pbuf数据包队列中弹出一个pbuf数据包
* @param q is the packet queue from which to pop the pbuf.
* q是一个数据队列中弹出的pbuf
* @return pointer to pbuf packet if available, NULL otherwise.
原型:static struct pbuf * dequeue_packet(struct pbufq *q)
*/
p = dequeue_packet(ðernetif->txq);
if(p != NULL) {
low_level_transmit(netif, p);
}
}
/* Read another packet from the RX fifo */
p = low_level_receive(netif);
}
/* One more check of the transmit queue/fifo */
if((HWREG(ETH_BASE + MAC_O_TR) & MAC_TR_NEWTX) == 0) {
p = dequeue_packet(ðernetif->txq);
if(p != NULL) {
low_level_transmit(netif, p);
}
}
}
如果应用程序不使用
RTOS
,则会在这个中断服务函数中处理一些其它的事情,主要是处理从以太网
FIFO
中读取的数据以及更新
lwIP
时钟。
stellarisif_input(&lwip_netif)
函数处理来自以太网
RX FIFO
的数据,它会根据已经接收的数据包类型来调用适当的
input
函数。在
stellarisif_input(&lwip_netif)
函数中主要调用了
ethernet_input(p, netif)
函数,该函数根据以太网包的类型使用
switch...case
语句来调用不同的函数,比如
htons(ethhdr->type)== ETHTYPE_IP
,说明这是一个
IP
包,则调用
ip_input(p, netif)
函数。
stellarisif_input(&lwip_netif);
函数如下所示:
欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/)
Powered by Discuz! 7.0.0