Nios® V/II Embedded Design Suite (EDS)
Support for Embedded Development Tools, Processors (SoCs and Nios® V/II processor), Embedded Development Suites (EDSs), Boot and Configuration, Operating Systems, C and C++
12622 Discussions

DMA transfer inside ISR: Problem

Altera_Forum
Honored Contributor II
5,094 Views

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 ! =)
0 Kudos
23 Replies
Altera_Forum
Honored Contributor II
359 Views

 

--- Quote Start ---  

No, I don't forget to set I_EN. I don't enable the IRQ because I'll not use a ISR routine in my project to transmit the data from DMA to UART. 

--- Quote End ---  

 

Oh, sorry I forgot!:-) 

 

 

--- Quote Start ---  

Which version of Quartus and Nios EDS do you use? 

--- Quote End ---  

 

I use Quartus 10.0 and NIOS EDS 10.0. Both with SP1. 

 

It's really strange that you get almost correct transfer though you are using (in my opinion) the wrong address of the TXDATA register of the UART. 

Hmmm? No Idea yet. Sorry... 

 

Maybe you should use SignalTap for debugging. It helped us a lot! Really amazing tool. 

 

Regards
0 Kudos
Altera_Forum
Honored Contributor II
359 Views

Hi! 

I have the same problem with Quartus 10.0 SP1 and NIOS EDS 10.0 SP1. 

Can you post your working code for UART to RAM transfer? 

Thanks! 

 

Regards
0 Kudos
Altera_Forum
Honored Contributor II
359 Views

Hi, 

 

I hope this will help you. But I am using an ISR for servicing a completed DMA-Transfer. 

 

Int32 Transmit(Char8 * pTx, Int32 lLength) { //softwarereset IOWR_ALTERA_AVALON_DMA_CONTROL(DMA_RS485_BASE, 0x1000); IOWR_ALTERA_AVALON_DMA_CONTROL(DMA_RS485_BASE, 0x1000); IOWR_ALTERA_AVALON_PIO_DATA (PIO_RS485_BASE,TRANSMIT); // setting the direction of the transceiver using a PIO IORD_ALTERA_AVALON_UART_RXDATA(UART_RS485_BASE); //dummy read to UART IOWR_ALTERA_AVALON_DMA_CONTROL(DMA_RS485_BASE, ALTERA_AVALON_DMA_CONTROL_WCON_MSK| ALTERA_AVALON_DMA_CONTROL_BYTE_MSK| ALTERA_AVALON_DMA_CONTROL_LEEN_MSK| ALTERA_AVALON_DMA_CONTROL_I_EN_MSK); //setzen von WCON DmaTransfer ((Int32) IOADDR_ALTERA_AVALON_UART_TXDATA(UART_RS485_BASE), (Int32) pTx, lLength); return 0; } Int32 Receive(Char8 * pRx, Int32 lLength) { while (!(IORD_ALTERA_AVALON_UART_STATUS(UART_RS485_BASE) & ALTERA_AVALON_UART_STATUS_TMT_MSK)); //softwarereset IOWR_ALTERA_AVALON_DMA_CONTROL(DMA_RS485_BASE, 0x1000); IOWR_ALTERA_AVALON_DMA_CONTROL(DMA_RS485_BASE, 0x1000); IORD_ALTERA_AVALON_UART_RXDATA(UART_RS485_BASE); // dummy read to UART IOWR_ALTERA_AVALON_DMA_CONTROL(DMA_RS485_BASE, ALTERA_AVALON_DMA_CONTROL_RCON_MSK| ALTERA_AVALON_DMA_CONTROL_BYTE_MSK| ALTERA_AVALON_DMA_CONTROL_LEEN_MSK| ALTERA_AVALON_DMA_CONTROL_I_EN_MSK); IOWR_ALTERA_AVALON_PIO_DATA (PIO_RS485_BASE,RECEIVE); // setting the direction of the transceiver using a PIO DmaTransfer ((Int32)pRx, (Int32)IOADDR_ALTERA_AVALON_UART_RXDATA(UART_RS485_BASE), lLength); return 0; } void DmaTransfer(Int32 lWhere, Int32 lFrom, Int32 lHowMuch) { while ((IORD_ALTERA_AVALON_DMA_STATUS(DMA_RS485_BASE) & ALTERA_AVALON_DMA_STATUS_BUSY_MSK)); IOWR_ALTERA_AVALON_DMA_STATUS (DMA_RS485_BASE, 0); IOWR_ALTERA_AVALON_DMA_RADDRESS (DMA_RS485_BASE,(Int32) lFrom); IOWR_ALTERA_AVALON_DMA_WADDRESS (DMA_RS485_BASE,(Int32) lWhere); IOWR_ALTERA_AVALON_DMA_LENGTH (DMA_RS485_BASE, lHowMuch); IOWR_ALTERA_AVALON_DMA_CONTROL (DMA_RS485_BASE, ALTERA_AVALON_DMA_CONTROL_GO_MSK | IORD_ALTERA_AVALON_DMA_CONTROL(DMA_RS485_BASE)); }Good luck!
0 Kudos
Reply