Задача: передать в память DDR со счетчика, расположенного в PL, 512 32-разрядных слов (2 пакета по 256 слов), минимально задействовав процессор. Выбрала передачу через ядро DMA + InterConnect.
Режим работы DMA - не Scatter/Gather, а просто через регистры.
Инициализирую DMA так:
Код
unsigned int tmpVal;
Xil_Out32( XPAR_PS7_GPIO_0_BASEADDR + (2 * XGPIOPS_DATA_MASK_OFFSET) + XGPIOPS_DATA_LSW_OFFSET, 0xFFFD0000); //reset fifo - reset it
Xil_Out32(XPAR_AXI_DMA_0_BASEADDR + 0x30, (1<<RESET_DMA)); //start_DMA_control_reg_val);
while(Xil_In32(XPAR_AXI_DMA_0_BASEADDR + 0x30) & (1<<RESET_DMA)) xil_printf("Reseting DMA...\n");
tmpVal = Xil_In32 (XPAR_AXI_DMA_0_BASEADDR + 0x30);
tmpVal |= 0x1001; //dma unit enable. interrupt on complete enable
Xil_Out32(XPAR_AXI_DMA_0_BASEADDR + 0x30, tmpVal);
tmpVal = Xil_In32 (XPAR_AXI_DMA_0_BASEADDR + 0x30);
xil_printf("value for DMA control reg is %x\n\r",tmpVal);
Xil_Out32 (XPAR_AXI_DMA_0_BASEADDR + 0x48, addr);
Xil_Out32( XPAR_PS7_GPIO_0_BASEADDR + (2 * XGPIOPS_DATA_MASK_OFFSET) + XGPIOPS_DATA_LSW_OFFSET, 0xFFFD0000); //reset fifo - reset it
Xil_Out32(XPAR_AXI_DMA_0_BASEADDR + 0x30, (1<<RESET_DMA)); //start_DMA_control_reg_val);
while(Xil_In32(XPAR_AXI_DMA_0_BASEADDR + 0x30) & (1<<RESET_DMA)) xil_printf("Reseting DMA...\n");
tmpVal = Xil_In32 (XPAR_AXI_DMA_0_BASEADDR + 0x30);
tmpVal |= 0x1001; //dma unit enable. interrupt on complete enable
Xil_Out32(XPAR_AXI_DMA_0_BASEADDR + 0x30, tmpVal);
tmpVal = Xil_In32 (XPAR_AXI_DMA_0_BASEADDR + 0x30);
xil_printf("value for DMA control reg is %x\n\r",tmpVal);
Xil_Out32 (XPAR_AXI_DMA_0_BASEADDR + 0x48, addr);
Обработка прерываний от DMA:
Код
u32 tmpVal = Xil_In32 (XPAR_AXI_DMA_0_BASEADDR + 0x34);
***********
xil_printf("DMA status %x\n",tmpVal); //I can't understand, but without this line CPU reading the length of written bytes from DMA fails...
***********
if((tmpVal&(1<<ERR_IRQ))||(tmpVal&(1<<4))) //reset DMA if DMA Internal error
{
XGpioPs_WritePin(&my_Gpio, 54, 0); //Закончить работу счетчика
tmpVal = Xil_In32 (XPAR_AXI_DMA_0_BASEADDR + 0x30);
tmpVal &= ~0x1001; //dma unit disable. interrupt on complete disable
Xil_Out32(XPAR_AXI_DMA_0_BASEADDR + 0x30, tmpVal);
xil_printf("DMA stopped! Data weren't accepted! Sorry!\n");
finished = 2; //It would be good to stop DMA?
}
else
{
tmpVal = Xil_In32 (XPAR_AXI_DMA_0_BASEADDR + 0x58);
***********
xil_printf("tmpVal is %d\n",tmpVal);
***********
Max_num = Max_num + tmpVal;
if((Max_num)<MAX_BYTE_NUMBERS)
{
addr = addr + tmpVal;
StartDMATransfer(addr,MAX_BYTE_NUMBERS-Max_num);
}
else
{
//тут заканчиваем передачу
XGpioPs_WritePin(&my_Gpio, 54, 0); //Закончить работу счетчика
}
***********
xil_printf("DMA status %x\n",tmpVal); //I can't understand, but without this line CPU reading the length of written bytes from DMA fails...
***********
if((tmpVal&(1<<ERR_IRQ))||(tmpVal&(1<<4))) //reset DMA if DMA Internal error
{
XGpioPs_WritePin(&my_Gpio, 54, 0); //Закончить работу счетчика
tmpVal = Xil_In32 (XPAR_AXI_DMA_0_BASEADDR + 0x30);
tmpVal &= ~0x1001; //dma unit disable. interrupt on complete disable
Xil_Out32(XPAR_AXI_DMA_0_BASEADDR + 0x30, tmpVal);
xil_printf("DMA stopped! Data weren't accepted! Sorry!\n");
finished = 2; //It would be good to stop DMA?
}
else
{
tmpVal = Xil_In32 (XPAR_AXI_DMA_0_BASEADDR + 0x58);
***********
xil_printf("tmpVal is %d\n",tmpVal);
***********
Max_num = Max_num + tmpVal;
if((Max_num)<MAX_BYTE_NUMBERS)
{
addr = addr + tmpVal;
StartDMATransfer(addr,MAX_BYTE_NUMBERS-Max_num);
}
else
{
//тут заканчиваем передачу
XGpioPs_WritePin(&my_Gpio, 54, 0); //Закончить работу счетчика
}
Если в коде нет строчек, выделенных **************, то передается не вся посылка, а примерно 280-290 слов. Если есть - передается всё. и в режиме Release, и в режиме Debug. DMA ошибок не выдает. Выполняется команда XGpioPs_WritePin(&my_Gpio, 54, 0); //Закончить работу счетчика
раньше того как будут переданы все слова. MAX_BYTE_NUMBERS = 2048.
Объясните пожалуйста, почему??? Шаманство "добавим вывод в uart и все заработает" мне не сильно нравится. Хотелось бы понять, сколько времени нужно на выполнение операции чтения-записи в память, и как обойтись без uart?