初级会员
- 积分
- 79
- 金钱
- 79
- 注册时间
- 2018-11-26
- 在线时间
- 21 小时
|
1金钱
我在分析正点原子F4探索者的LWIP源码的时候,发现以太网底层驱动发送的数据的时候,发现没有检查DMA描述符是否是能够被CPU使用的,就拷贝数据到了描述符的缓冲区中,怎么看都感觉不是很合理(以下代码的红色部分)。但是在ETH_Tx_Packet函数中,一进函数的时候就检查了描述符是否是能够被CPU使用的。感觉有点先斩后奏的意思。还请大佬们指教,我自己的理解是,在拷贝数据到描述符的缓冲区之前,就应该先检查描述符是否能够被CPU访问,不是的话,直接返回错误就行,能够被访问的时候才去拷贝数据,设置长度和标志位等后续的操作。
- <div><div>//用于发送数据包的最底层函数(lwip通过netif->linkoutput指向该函数)</div><div>//netif:网卡结构体指针</div><div>//p:pbuf数据结构体指针</div><div>//返回值:ERR_OK,发送正常</div><div>// ERR_MEM,发送失败</div><div>static err_t low_level_output(struct netif *netif, struct pbuf *p)</div><div>{</div><div><span style="white-space:pre"> </span>u8 res;</div><div><span style="white-space:pre"> </span>struct pbuf *q;</div><div><span style="white-space:pre"> </span>int l = 0;</div><div><font color="#ff0000"><span style="white-space:pre"> </span>u8 *buffer=(u8 *)ETH_GetCurrentTxBuffer(); </font></div><div><font color="#ff0000"><span style="white-space:pre"> </span>for(q=p;q!=NULL;q=q->next) </font></div><div><font color="#ff0000"><span style="white-space:pre"> </span>{</font></div><div><font color="#ff0000"><span style="white-space:pre"> </span>memcpy((u8_t*)&buffer[l], q->payload, q->len);</font></div><div><font color="#ff0000"><span style="white-space:pre"> </span>l=l+q->len;</font></div><div><font color="#ff0000"><span style="white-space:pre"> </span>} </font></div><div><span style="white-space:pre"> </span>res=ETH_Tx_Packet(l); </div><div><span style="white-space:pre"> </span>if(res==ETH_ERROR)return ERR_MEM;//返回错误状态</div><div><span style="white-space:pre"> </span>return ERR_OK;</div><div>} </div></div><div>
- </div><div><div>//发送一个网卡数据包</div><div>//FrameLength:数据包长度</div><div>//返回值:ETH_ERROR,发送失败(0)</div><div>//<span style="white-space:pre"> </span>ETH_SUCCESS,发送成功(1)</div><div>u8 ETH_Tx_Packet(u16 FrameLength)</div><div>{ </div><div><font color="#8b0000"><span style="white-space:pre"> </span>//检查当前描述符,是否属于ETHERNET DMA(设置的时候)/CPU(复位的时候)</font></div><div><font color="#8b0000"><span style="white-space:pre"> </span>if((DMATxDescToSet->StatusÐ_DMATxDesc_OWN)!=(u32)RESET)</font></div><div><font color="#8b0000"><span style="white-space:pre"> </span>return ETH_ERROR;//错误,OWN位被设置了 </font></div><div> <span style="white-space:pre"> </span></div><div><span style="white-space:pre"> </span>DMATxDescToSet->ControlBufferSize=(FrameLengthÐ_DMATxDesc_TBS1);//设置帧长度,bits[12:0]</div><div><span style="white-space:pre"> </span>DMATxDescToSet->Status|=ETH_DMATxDesc_LS|ETH_DMATxDesc_FS;//设置最后一个和第一个位段置位(1个描述符传输一帧)</div><div> DMATxDescToSet->Status|=ETH_DMATxDesc_OWN;//设置Tx描述符的OWN位,buffer重归ETH DMA</div><div><span style="white-space:pre"> </span></div><div><span style="white-space:pre"> </span>if((ETH->DMASRÐ_DMASR_TBUS)!=(u32)RESET)//当Tx Buffer不可用位(TBUS)被设置的时候,重置它.恢复传输</div><div><span style="white-space:pre"> </span>{ </div><div><span style="white-space:pre"> </span>ETH->DMASR=ETH_DMASR_TBUS;//重置ETH DMA TBUS位 </div><div><span style="white-space:pre"> </span>ETH->DMATPDR=0;//恢复DMA发送</div><div><span style="white-space:pre"> </span>} </div><div><span style="white-space:pre"> </span>//更新ETH DMA全局Tx描述符为下一个Tx描述符</div><div><span style="white-space:pre"> </span>//为下一次buffer发送设置下一个DMA Tx描述符 </div><div><span style="white-space:pre"> </span>DMATxDescToSet=(ETH_DMADESCTypeDef*)(DMATxDescToSet->Buffer2NextDescAddr); </div><div><span style="white-space:pre"> </span>return ETH_SUCCESS; </div><div>}</div></div>
复制代码
|
|