Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
15 years ago

DMA transfer inside ISR: Problem

Hi everybody,

I think this is a common issue, but I didn't find a solution to my question, so hopefully I will get an answer here:

I have a DMA controller which I want to use on an IRQ coming from a PIO.

The DMA works fine and also the IRQ does.

But when I try to call the DMA transfer function INSIDE the ISR from the PIO, the DMA doesn't send it's Interrupt at the end (when transfer is finished).

Priority of PIO Interrupt is 7, Priority of DMA is 6 (so there should not be a priority problem).

Does anyone of you know a solution to my problem?

Here is my code:


volatile static int rx_done = 0;
static void done_DMA(void* handle, void* data)
{
	rx_done = 1;
}
void measureIOs()
{
	int rc;
	alt_dma_txchan txchan;
	alt_dma_rxchan rxchan;
	unsigned long* tx_data =   (void*) EXT_DPR_TRISTATE_INTERFACE_0_BASE; // pointer to data to send
	unsigned long* rx_buffer = (void*) SDRAM_BASE + 0x100000; // pointer to rx buffer
	rx_buffer = (void*) SDRAM_BASE + 0x100000;
	rx_done = 0;
	// Create the transmit channel
	if ((txchan = alt_dma_txchan_open("/dev/dma_0")) == NULL)
	{
		printf ("Failed to open transmit channel\n");
		exit (1);
	}
	// Create the receive channel
	if ((rxchan = alt_dma_rxchan_open("/dev/dma_0")) == NULL)
	{
		printf ("Failed to open receive channel\n");
		exit (1);
	}
	if(alt_dma_txchan_ioctl(txchan,ALT_DMA_SET_MODE_32,NULL)<0)
	{
		exit(1);
	}
	if(alt_dma_rxchan_ioctl(rxchan,ALT_DMA_SET_MODE_32,NULL)<0)
	{
		exit(1);
	}
	if(alt_dma_txchan_ioctl(txchan,ALT_DMA_TX_ONLY_OFF,NULL)<0)
	{
		exit(1);
	}
	if(alt_dma_rxchan_ioctl(rxchan,ALT_DMA_RX_ONLY_OFF,NULL)<0)
	{
		exit(1);
	}
	// Post the transmit request
	if ((rc = alt_dma_txchan_send (txchan,tx_data,4096,NULL,NULL)) < 0)
	{
		printf ("Failed to post transmit request, reason = %i\n", rc);
		exit (1);
	}
	// Post the receive request
	if ((rc = alt_dma_rxchan_prepare (rxchan,rx_buffer,4096,done_DMA,NULL)) < 0)
	{
		printf ("Failed to post read request, reason = %i\n", rc);
		exit (1);
	}
	// wait for transfer to complete
	while (!rx_done);
	printf ("Transfer successful!\n");
}
/* INTERRUPT VARIABLE DEFINITONS */
volatile int edge_capture;
/* **************** INTERRUPT FUNCTIONS ********************* */
# ifdef PIO_SELECTED_RAM_BASE
# ifdef ALT_ENHANCED_INTERRUPT_API_PRESENT
static void handle_ram_interrupt(void* context)
# else
static void handle_ram_interrupt(void* context, alt_u32 id)
# endif
{
    /* Cast context to edge_capture's type. It is important that this be
     * declared volatile to avoid unwanted compiler optimization.
     */
    volatile int* edge_capture_ptr = (volatile int*) context;
    /* Store the value in the Button's edge capture register in *context. */
    *edge_capture_ptr = IORD_ALTERA_AVALON_PIO_EDGE_CAP(PIO_SELECTED_RAM_BASE);
    /* Reset the Button's edge capture register. */
    IOWR_ALTERA_AVALON_PIO_EDGE_CAP(PIO_SELECTED_RAM_BASE, 0);
    measureIOs();
    /*
     * Read the PIO to delay ISR exit. This is done to prevent a spurious
     * interrupt in systems with high procekssor -> pio latency and fast
     * interrupts.
     */
    IORD_ALTERA_AVALON_PIO_EDGE_CAP(PIO_SELECTED_RAM_BASE);
}
/* Initialize the ram_pio. */
static void init_ram_pio()
{
    /* Recast the edge_capture pointer to match the alt_irq_register() function
     * prototype. */
    void* edge_capture_ptr = (void*) &edge_capture;
    /* Enable all 4 button interrupts. */
    IOWR_ALTERA_AVALON_PIO_IRQ_MASK(PIO_SELECTED_RAM_BASE, 0x1);
    /* Reset the edge capture register. */
    IOWR_ALTERA_AVALON_PIO_EDGE_CAP(PIO_SELECTED_RAM_BASE, 0x0);
    /* Register the interrupt handler. */
# ifdef ALT_ENHANCED_INTERRUPT_API_PRESENT
    alt_ic_isr_register(PIO_SELECTED_RAM_IRQ_INTERRUPT_CONTROLLER_ID,PIO_SELECTED_RAM_IRQ,
    		handle_ram_interrupt, edge_capture_ptr, 0x0);
# else
    alt_irq_register( PIO_SELECTED_RAM_IRQ, edge_capture_ptr,
    		handle_ram_interrupt);
# endif
}
# endif /***************** PIO_SELECTED_RAM_BASE **********************/
int main()
{
  printf("Hello from Nios II!\n");
  init_ram_pio();
  while(1);
  return 0;
}

Thanks for all answers ! =)

23 Replies