Altera_Forum
Honored Contributor
15 years agoDMA 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 ! =)