**
循环模式Axi-Dma进行MM2S通道传输数据,描述符链所表示的数据缓存区内数据由FPGA不断更新,更新完成后会产生一个中断信号,获取到中断信号后继续通过MM2S通道传输数据,在MM2S通道的中断回调函数中加入停止条件,满足停止条件后停止传输。以上流程可以通过普通SG模式完成,但是因为普通SG模式每次传输完成后都要重新配置描述符链,带宽太低,于是改用cyclic模式传输。
cyclic模式下,在通过官方给的函数将配置好的描述符链传给硬件后,传输开始,但是FPGA无法向缓存区内更新数据,DMA一直在循环传输固定的第一帧数据。
我的问题是在cyclic模式传输时,如何实时更新缓存区内的数据?
以下是用官方例程sgcyclic_intr修改的cyclic模式MM2S通道传输图像数据代码,将传输通道设置和描述符设置合并到了一起,其它例如中断系统设置和S2MM通道设置都与官方例程一样。请有软核开发SG模式AxiDma经验的大老赐教。
**
//循环传输数据
static int SendPacket(XAxiDma * AxiDmaInstPtr)
{
XAxiDma_BdRing *TxRingPtr = XAxiDma_GetTxRing(AxiDmaInstPtr);
XAxiDma_Bd *BdPtr, *BdCurPtr, BdTemplate;
int Status;
int Index, Pkts;
UINTPTR BufferAddr;
#define TOTAL_BD_COUNT NUMBER_OF_PKTS_TO_TRANSFER //传输数量
XAxiDma_BdRingIntDisable(TxRingPtr, XAXIDMA_IRQ_ALL_MASK);
u32 BdCount = XAxiDma_BdRingCntCalc(XAXIDMA_BD_MINIMUM_ALIGNMENT,
(UINTPTR)TX_BD_SPACE_HIGH - (UINTPTR)TX_BD_SPACE_BASE + 1);
if(BdCount >= TOTAL_BD_COUNT){
BdCount = TOTAL_BD_COUNT;
}
//连接指定数量的Bd,形成Bd环
Status = XAxiDma_BdRingCreate(TxRingPtr, TX_BD_SPACE_BASE,
TX_BD_SPACE_BASE, XAXIDMA_BD_MINIMUM_ALIGNMENT, TOTAL_BD_COUNT);
if (Status != XST_SUCCESS) {
xil_printf("Failed create BD ring, error code %d\r\n", Status);
return XST_FAILURE;
}
XAxiDma_BdClear(&BdTemplate);
Status = XAxiDma_BdRingClone(TxRingPtr, &BdTemplate);
if (Status != XST_SUCCESS) {
xil_printf("Failed clone BDs\r\n");
return XST_FAILURE;
}
//检查BdRing是否连接
Status = XAxiDma_BdRingCheck(TxRingPtr);
if(Status != XST_SUCCESS){
xil_printf("Failed check BdRings %d\r\n", Status);
return XST_FAILURE;
}
//指定传输次数合并为一次中断
Status = XAxiDma_BdRingSetCoalesce(TxRingPtr, 1, 0);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
XAxiDma_BdRingEnableCyclicDMA(TxRingPtr);
XAxiDma_SelectCyclicMode(AxiDmaInstPtr, XAXIDMA_DMA_TO_DEVICE, 1);
XAxiDma_BdRingIntEnable(TxRingPtr, XAXIDMA_IRQ_ALL_MASK);
//开启传输通道
Status = XAxiDma_BdRingStart(TxRingPtr);
if (Status != XST_SUCCESS) {
xil_printf("Failed bd start\r\n");
return XST_FAILURE;
}
img_stop = 0; //Rx通道中断完成标志
while(!img_stop){
Xil_DCacheFlushRange((UINTPTR)TX_BUFFER_BASE, NUMBER_OF_PKTS_TO_TRANSFER * MAX_PKT_LEN);
Status = XAxiDma_BdRingAlloc(TxRingPtr, NUMBER_OF_BDS_TO_TRANSFER, &BdPtr);
if (Status != XST_SUCCESS) {
xil_printf("Failed bd alloc error code %d\r\n", Status);
return XST_FAILURE;
}
BufferAddr = (UINTPTR)Packet;
BdCurPtr = BdPtr;
Img_Intr = 0; //图像中断标志
//等待图像数据
internal_trigger_get_img_data();
while(!Img_Intr);
for(Index = 0; Index < NUMBER_OF_PKTS_TO_TRANSFER; Index++) {
for(Pkts = 0; Pkts < NUMBER_OF_BDS_PER_PKT; Pkts++) {
Status = XAxiDma_BdSetBufAddr(BdCurPtr, BufferAddr);
if (Status != XST_SUCCESS) {
xil_printf("Tx set buffer addr %x on BD %x failed %d\r\n",
(unsigned int)BufferAddr,
(UINTPTR)BdCurPtr, Status);
return XST_FAILURE;
}
Status = XAxiDma_BdSetLength(BdCurPtr, MAX_PKT_LEN,
TxRingPtr->MaxTransferLen);
if (Status != XST_SUCCESS) {
xil_printf("Tx set length %d on BD %x failed %d\r\n",
MAX_PKT_LEN, (UINTPTR)BdCurPtr, Status);
return XST_FAILURE;
}
u32 CrBits = 0;
if (Pkts == 0) {
CrBits |= XAXIDMA_BD_CTRL_TXSOF_MASK;
}
if(Pkts == (NUMBER_OF_BDS_PER_PKT - 1)) {
CrBits |= XAXIDMA_BD_CTRL_TXEOF_MASK;
}
XAxiDma_BdSetCtrl(BdCurPtr, CrBits);
XAxiDma_BdSetId(BdCurPtr, BufferAddr);
}
BufferAddr += MAX_PKT_LEN;
BdCurPtr = (XAxiDma_Bd *)XAxiDma_BdRingNext(TxRingPtr, BdCurPtr);
}
Status = XAxiDma_BdRingToHw(TxRingPtr, NUMBER_OF_BDS_TO_TRANSFER, BdPtr);
if (Status != XST_SUCCESS) {
xil_printf("Failed to hw, length %d\r\n",
(int)XAxiDma_BdGetLength(BdPtr, TxRingPtr->MaxTransferLen));
return XST_FAILURE;
}
while(XAxiDma_Busy(AxiDmaInstPtr, XAXIDMA_DMA_TO_DEVICE));
}
TxDone = 0;
return XST_SUCCESS;
}