今天的帖子的主题为:LWIP和DMA基于FreeRTOS的简单使用,该例子实在第二篇贴子的例程基础之上进行开发的。例子中涉及到PS和PL的通信,这就不得不提到AXI总线了,下面先介绍一下PS对PL部分的通信接口。
PL和PS间通信接口基本介绍:
1、FPD-PL接口
FPD-PL接口指的是:进入全功率域(full-power domain,简称FPD)的PL到PS的数据接口。
6个高性能接口为PL总线主控提供了对所有PS从属的访问权限,但这些接口旨在为DDR存储器提供高带宽数据路径。
从FPD到PL的 2 个高性能主机。 这些主要是由APS,FPD DMA和PCIe等高性能PS主设备使用的。
S_AXI_HP1_FPD和S_AXI_HP2_FPD接口共享对AXI端口接口(XPI 4)的独占访问。 这有助于从PL直接到DDR存储器的高吞吐量和相对低延迟的访问。 S_AXI_HP0_FPD与PL中的DisplayPort主设备共享内存控制器上的XPI端口,与FPD DMA控制器共享S_AXI_HP3_FPD。在基于视频的系统中,S_AXI_HP0_FPD通常用于视频类型的流量,而S_AXI_HP3_FPD用于尽可能大的流量。
S_AXI_HPC0_FPD和S_AXI_HPC1_FPD可以选择支持APU的L1和L2高速缓存的I/O一致性,因为这些接口连接到高速缓存一致性互连(CCI)。这些端口可以通过CCI提供的端口监听APU高速缓存。 当APU数据与I/O主设备共享时,这避免了通过刷新APU缓存来提供一致性的软件。硬件管理的I/O一致性简化了软件,提高了系统性能,并降低了功耗。 因为S_AXI_HPC0_FPD和S_AXI_HPC1_FPD接口都是在到达DDR内存控制器之前通过CCI路由的,所以这两个端口对DDR的等待时间更长。
FPD的所有高性能接口都通过系统内存管理单元(SMMU)。SMMU根据提供的信息将传入的主请求的地址转换为物理内存地址,并检查访问该物理地址的权限。
高性能PS到PL的AXI接口提供了两个高性能接口M_AXI_HPM0_FPD和M_AXI_HPM1_FPD(数据宽度可选择为32/64/128位),以允许PS的CPU,DMA和PCIe从主接口中推送大量数据到PL。它们还是启用以下功能的AXI FIFO接口。
由于PL接口符合AXI4,而内部PS接口符合AXI3,因此可以从AXI3协议转换为AXI4协议。 PL中的AXI4访问限制为16个突发长度。
PS和PL接口之间的时钟域交叉。 PL接口中有一个时钟可用于读写操作。
2、直接上图了,这个的介绍就比较简单了。
3、AXI一致性扩展(ACE)协议扩展了AXI4协议并提供对硬件一致性缓存的支持。
4、加速器一致性端口(ACP)是侦听控制单元(SCU)上的128位AXI从接口,它直接提供从PL到APU的异步缓存一致性访问点。 多个PL主设备可以使用此接口来访问高速缓存和内存子系统,就像APU处理器用来简化软件,提高整体系统性能或降低功耗一样。
下面就是实践的过程了,搭建如下:
Xilinx官网给出的例程的代码相对而言还是比较乱的。
其中DMA接收中断和发送中断的函数如下:
- /**********************************************************************/
- /*
- *
- * This is the DMA TX Interrupt handler function.
- *
- * It gets the interrupt status from the hardware, acknowledges it, and if any
- * error happens, it resets the hardware. Otherwise, if a completion interrupt
- * is present, then sets the TxDone.flag
- *
- * @param Callback is a pointer to TX channel of the DMA engine.
- *
- * @return None.
- *
- * @note None.
- *
- *****************************************************************/
- static void DMA_TxIntrHandler(void *Callback)
- {
- u32 IrqStatus;
- int TimeOut;
- XAxiDma *AxiDmaInst = (XAxiDma *)Callback;
- /* Read pending interrupts */
- IrqStatus = XAxiDma_IntrGetIrq(AxiDmaInst, XAXIDMA_DMA_TO_DEVICE);
- /* Acknowledge pending interrupts */
- XAxiDma_IntrAckIrq(AxiDmaInst, IrqStatus, XAXIDMA_DMA_TO_DEVICE);
- /*
- * If no interrupt is asserted, we do not do anything
- */
- if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {
- return;
- }
- /*
- * If error interrupt is asserted, raise error flag, reset the
- * hardware to recover from the error, and return with no further
- * processing.
- */
- if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) {
- Error = 1;
- /*
- * Reset should never fail for transmit channel
- */
- XAxiDma_Reset(AxiDmaInst);
- TimeOut = RESET_TIMEOUT_COUNTER;
- while (TimeOut) {
- if (XAxiDma_ResetIsDone(AxiDmaInst)) {
- break;
- }
- TimeOut -= 1;
- }
- return;
- }
- /*
- * If Completion interrupt is asserted, then set the TxDone flag
- */
- if ((IrqStatus & XAXIDMA_IRQ_IOC_MASK)) {
- TxDone = 1;
- }
- }
- /**************************************************************/
- /*
- *
- * This is the DMA RX interrupt handler function
- *
- * It gets the interrupt status from the hardware, acknowledges it, and if any
- * error happens, it resets the hardware. Otherwise, if a completion interrupt
- * is present, then it sets the RxDone flag.
- *
- * @param Callback is a pointer to RX channel of the DMA engine.
- *
- * @return None.
- *
- * @note None.
- *
- *****************************************************/
- static void DMA_RxIntrHandler(void *Callback)
- {
- u32 IrqStatus;
- int TimeOut;
- XAxiDma *AxiDmaInst = (XAxiDma *)Callback;
- /* Read pending interrupts */
- IrqStatus = XAxiDma_IntrGetIrq(AxiDmaInst, XAXIDMA_DEVICE_TO_DMA);
- /* Acknowledge pending interrupts */
- XAxiDma_IntrAckIrq(AxiDmaInst, IrqStatus, XAXIDMA_DEVICE_TO_DMA);
- /*
- * If no interrupt is asserted, we do not do anything
- */
- if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {
- return;
- }
- /*
- * If error interrupt is asserted, raise error flag, reset the
- * hardware to recover from the error, and return with no further
- * processing.
- */
- if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) {
- Error = 1;
- /* Reset could fail and hang
- * NEED a way to handle this or do not call it??
- */
- XAxiDma_Reset(AxiDmaInst);
- TimeOut = RESET_TIMEOUT_COUNTER;
- while (TimeOut) {
- if(XAxiDma_ResetIsDone(AxiDmaInst)) {
- break;
- }
- TimeOut -= 1;
- }
- return;
- }
- /*
- * If completion interrupt is asserted, then set RxDone flag
- */
- if ((IrqStatus & XAXIDMA_IRQ_IOC_MASK)) {
- RxDone = 1;
- }
- }
复制代码
在LWIP的回复线程中,添加DMA代码,其中核心的部分为:
- /*
- * Flush the SrcBuffer before the DMA transfer, in case the Data Cache is enabled
- */
- Xil_DCacheFlushRange((u32)TxBufferPtr, MAX_PKT_LEN);
- DMA_send_func(&AxiDma,TxBufferPtr,20);
- DMA_recv_func(&AxiDma,RxBufferPtr,20);
复制代码
其中发送和接收函数使用了函数
- u32 DMA_send_func(XAxiDma *InstancePtr,u8* sendmem,u32 len){
- return XAxiDma_SimpleTransfer(InstancePtr,(u32)sendmem,len, XAXIDMA_DMA_TO_DEVICE);
- }
- u32 DMA_recv_func(XAxiDma *InstancePtr,u8* sendmem,u32 len){
- return XAxiDma_SimpleTransfer(InstancePtr,(u32)sendmem,len, XAXIDMA_DEVICE_TO_DMA);
- }
复制代码
下面直接看实验截图:
数据的流向为 PC -> TCP/IP -> DDR4 -> AXI4 DMA -> AXI4 DATA FIFO -> AXI4 DMA -> DDR4 -> UART -> PC
以上就是今天的使用。
|