根据 上一篇 文章 , ETH DMA 数据中断 会 发送 一个信号量 ,我使用 全局 搜索 这个信号量 s_xSemaphore 得到 一下 几个 值
根据 这个 分析 我们找到了 数据 的 第二站 :void ethernetif_input( void * pvParameters )
/** * This function is the ethernetif_input task, it is processed when a packet * is ready to be read from the interface. It uses the function low_level_input() * that should handle the actual reception of bytes from the network * interface. Then the type of the received packet is determined and * the appropriate input function is called. * * @param netif the lwip network interface structure for this ethernetif */ void ethernetif_input( void * pvParameters ) { struct pbuf *p; for( ;; ) { if (xSemaphoreTake( s_xSemaphore, emacBLOCK_TIME_WAITING_FOR_INPUT)==pdTRUE) { TRY_GET_NEXT_FRAME: p = low_level_input( s_pxNetIf ); if (p != NULL) { if (ERR_OK != s_pxNetIf->input( p, s_pxNetIf)) { pbuf_free(p); } else { goto TRY_GET_NEXT_FRAME; } } } } }
/** * This function is the ethernetif_input task, it is processed when a packet * is ready to be read from the interface. It uses the function low_level_input() * that should handle the actual reception of bytes from the network * interface. Then the type of the received packet is determined and * the appropriate input function is called. * * @param netif the lwip network interface structure for this ethernetif */ /* 这个 函数 是 ethernetif_input 的 任务 , 处理已经 读取 从 硬件接口发来的一个数据包 这个函数 调用 low_level_input() 函数 ,这个函数 是 处理当前从网络接口 接收的数据 我 的 理解 是 这个函数 就是 第一时间 处理 从 网络 接口 来的 数据包。 参数没有 用到 不解释 2017年8月11日16:20:29 */ void ethernetif_input( void * pvParameters ) { struct pbuf *p;// 定义 这样 一个类型(pbuf) 的 指针 for( ;; ) { //接收 信号量 阻塞时间 是 emacBLOCK_TIME_WAITING_FOR_INPUT 即 100ms if (xSemaphoreTake( s_xSemaphore, emacBLOCK_TIME_WAITING_FOR_INPUT)==pdTRUE) { //这是 go 语法 不会 请 度娘 TRY_GET_NEXT_FRAME: //这里 是调用 这个 函数 2017年8月11日16:26:08 这个函数 干嘛 的那 //2017年8月11日17:11:32 经过我 一段 时间 的 观察 // 这个 函数 是 从 ETH 的 DMA 缓冲区 BUFF 中 获取 接收的 数据 放到 一个 pbuf 类型 的指针 指向 的内存中 即 P //这个 怎么 获取数据 从 DMA 缓冲区 中 后面 在 初始化 STM32 ETH 的 DMA 时 讲 2017年8月11日17:14:49 p = low_level_input( s_pxNetIf ); if (p != NULL)//判断 这个指针 不为 NULL { // 这里 就有 点复杂了 2017年8月11日17:15:37 // s_pxNetIf->input 是一个指针函数 // 这个指针函数 是 什么时候 复制 的那 // 首先 看 s_pxNetIf 全局搜索一下,发现 s_pxNetIf =netif; // netif 是 static void low_level_init(struct netif *netif) 的参数局部参数 // 我们看一下 这个 low_level_init 函数在哪调用的 ethernetif_init这个 函数中 调用的 // 看一下 这个 ethernetif_init 函数在哪 调用的 netif_add(&xnetif, &ipaddr, &netmask, &gw, NULL, ðernetif_init, &tcpip_input); //netif_add 这个 函数 是 LWIP 提供 的标准 操作 网卡 的 函数 在 http://www.nongnu.org/lwip/2_0_x/group__netif.html#gade5498543e74067f28cc6bef0209e3be //这个 网址 有详细 的 介绍 ,从这里 可以得知 s_pxNetIf->input 函数 指 的就是 tcpip_input 函数 //tcpip_input 是 lwip 处理 以太网 数据 的 标准 函数 //这里 就可以总结一下 了 : 以太网 中断 函数 接收到数据后 产生 DMA以太网 中断 ,中断函数 发送 信号量 给 这个函数,这个函数把 DMA接收 //的 数据 从 DMA 缓冲区 拿出来 放到一个 pbuf 类型 的 缓冲区 中 , 并交给 LWIP 的函数 tcpip_input 直接处理 这个 pbuf 类型 的 数据 // 以太网 数据 整个 过程 到此结束 具体是 : ETH_IRQHandler->ethernetif_input->low_level_input->tcpip_input if (ERR_OK != s_pxNetIf->input( p, s_pxNetIf)) { //数据处理完毕 发现数据 有问题 就释放 这个 数据包 ,正确的话 就 应该 交给 应用层 或者 其他层 去处理 了 暂时不研究 pbuf_free(p); } else { goto TRY_GET_NEXT_FRAME;//继续 查看DMA 缓冲区 是否有数据 有就接着处理 没有 就进入 信号量等待 2017年8月11日17:29:30 suozhang } } } } }
总结 :ETH_IRQHandler->ethernetif_input->low_level_input->tcpip_input
以太网 数据 整个 过程 到此结束 具体是 : ETH_IRQHandler->ethernetif_input->low_level_input->tcpip_input
1、 数据 经过 的 流程 是 STM32 的 DMA 会 把 接收 的数据放到 DMA 缓冲区 然后 产生 DMA 接收数据中断
2、 DMA 中断函数 中 会 发送信号 量 告诉 已经接收到数据 在 缓冲区里
3、 ethernetif_input 接收到信号量 后 会 调用 low_level_input 函数把 数据 从 DMA缓冲区 复制 到 一个 PBUF 类型 的缓冲区中
4、 PBUF 类型的 缓冲区 最后交给 tcpip_input 函数 处理
这里 牵扯 到了 网卡 操作函数 http://www.nongnu.org/lwip/2_0_x/group__netif.html 中的 第一个 函数 netif_add() http://www.nongnu.org/lwip/2_0_x/group__netif.html#gade5498543e74067f28cc6bef0209e3be
Add a network interface to the list of lwIP netifs. 2017年8月11日17:33:52 suozhang