Altera_Forum
Honored Contributor
10 years agoSGDMA Interrupt
Hi,
I'm having a major issue with the SGDMA component - the callback function that I've defined does not run. I'm not sure whether my code is flawed and I'm not calling the ISR function correctly, or I've set up the SGDMA wrong and it isn't generating an interrupt. I'm using the SGDMA to stream to memory the data from a trigger component connected to an ADC (which only streams if the input signal passes a certain threshold). I'm pretty sure the issue is code based, but I can provide the Qsys file if needed. The only problem that I can find is that the alt_avalon_sgdma_check_descriptor_status returns an error code of 119 - I've looked it up in errno.h, but I'm not sure how to solve it ("Connection already in progress "). Here's the code I'm using:#include <stdio.h># include <system.h># include <unistd.h># include "LCD_setup.h"# include "peripheral_tests.h"# include "ringBufS.h"# include <sys/alt_irq.h># include "altera_up_avalon_rs232.h"# include "altera_avalon_sgdma_regs.h"# include "altera_avalon_sgdma.h"# include "altera_avalon_sgdma_descriptor.h"# include "errno.h"# include "sys/alt_irq.h"
//alt_u32 * write_addr ;
const alt_u16 NUM_BYTES_TO_DMA = 32768 ;
const alt_u32 CIRCULAR_LOOP_LENGTH = 32768*128;
//define structure to pass data from main to ISR
typedef struct
{
int cnt;
alt_sgdma_dev *pSGDMA;
alt_u32 * write_addr;
int debug1;
int debug2;
int debug3;
} t_MyContext;
//ISR routine
void isr_sgdma_routine (t_MyContext * c, alt_u32 id){
alt_sgdma_descriptor *desc = (alt_sgdma_descriptor *) DESCRIPTOR_MEMORY_0_BASE ;
alt_sgdma_descriptor *next = (alt_sgdma_descriptor *) DESCRIPTOR_MEMORY_0_BASE + sizeof(alt_sgdma_descriptor);
int *green_leds = LEDG_BASE;
//reset interrupt
IOWR_ALTERA_AVALON_SGDMA_CONTROL(c->pSGDMA, IORD_ALTERA_AVALON_SGDMA_CONTROL(c->pSGDMA) | ALTERA_AVALON_SGDMA_CONTROL_CLEAR_INTERRUPT_MSK );
c->cnt++;
green_leds=0xAA;
//clear interrupt (useful ?)
IOWR_ALTERA_AVALON_SGDMA_CONTROL(c->pSGDMA, IORD_ALTERA_AVALON_SGDMA_CONTROL(c->pSGDMA) | ALTERA_AVALON_SGDMA_CONTROL_CLEAR_INTERRUPT_MSK );
//to reduce over-run risk
if (c->cnt < 150)
{
//get last descriptor of the chain (TODO)
if (desc->actual_bytes_transferred != NUM_BYTES_TO_DMA)
{
c->debug1 ++;
//construct a "bad descriptor" in order to reset the descriptor "desc"
alt_avalon_sgdma_construct_stream_to_mem_desc(desc,next,0,NUM_BYTES_TO_DMA,0);
//stop DMA
alt_avalon_sgdma_stop(c->pSGDMA);
}
else
{
c->write_addr = c->write_addr + (desc->actual_bytes_transferred / 4) ;
if (c->write_addr >= CIRCULAR_LOOP_LENGTH)
{
c->debug2++;
c->write_addr = 0;
}
alt_avalon_sgdma_construct_stream_to_mem_desc(desc,next,c->write_addr,NUM_BYTES_TO_DMA,0);
if(alt_avalon_sgdma_do_async_transfer(c->pSGDMA,desc) == -EBUSY )
c->debug3++;
}
}
else
{
alt_avalon_sgdma_stop(c->pSGDMA);
}
return;
}
int main() {
int *green_leds = LEDG_BASE;
green_leds=0xFF;
//declare pointer to ISR
void* isr_sgdma_routine_ptr = (void*) &isr_sgdma_routine;
//set ADC channels active
int *adc_reg = ADC_IF_0_BASE;
adc_reg=1;
adc_reg=1;
//set trigger levels
int *trigger_reg = TEST_COMP_0_BASE;
trigger_reg=0; //trigger module OFF (activate after DMA initialised)
trigger_reg=500; //set trigger level
trigger_reg=300; //set max monostable (ie: how long signal has to be stable ABOVE the trigger threshold before triggering)
//declare write address in SDRAM, descriptor memory base address, DMA control register and fill context structure for ISR
alt_u32 * sdram_write_addr = (alt_u32 *) SDRAM_CONTROLLER_BASE;
alt_sgdma_descriptor *desc = (alt_sgdma_descriptor *) DESCRIPTOR_MEMORY_0_BASE ;
alt_sgdma_descriptor *next = (alt_sgdma_descriptor *) DESCRIPTOR_MEMORY_0_BASE + sizeof(alt_sgdma_descriptor);
alt_u32 sgdma_ctrl_reg = ALTERA_AVALON_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK | ALTERA_AVALON_SGDMA_CONTROL_IE_GLOBAL_MSK ;
t_MyContext MyContext;
MyContext.cnt = 0;
MyContext.write_addr = 0;
MyContext.debug1 = 0;
MyContext.debug2 = 0;
MyContext.debug3 = 0;
//begin program
printf("Hello from Nios II!\n\n");
//init lcd display
lcd_init();
char text = " -Hello World!- ";
lcd_print(text);
usleep(1500000);
//init RS232 serial port
alt_up_rs232_dev *rspoint;
rspoint=alt_up_rs232_open_dev("/dev/rs232_0");
//init DMA
alt_sgdma_dev *SGDMA = alt_avalon_sgdma_open("/dev/Trig_DMA");
MyContext.pSGDMA=SGDMA;
if (SGDMA == NULL){
printf("Could not open DMA.\n\n");
} else {
printf("DMA initialised!\n\n");
//build DMA descriptors
alt_avalon_sgdma_construct_stream_to_mem_desc(desc,next,sdram_write_addr,NUM_BYTES_TO_DMA,0);
int descriptor_status = alt_avalon_sgdma_check_descriptor_status(desc);
if (descriptor_status == 0){
printf("DMA descriptor generated successfully!\n\n");
} else {
printf("DMA descriptor generation failed (error code: %d). Look up in 'errno.h'.\n\n", descriptor_status);
}
//point DMA to ISR function
alt_avalon_sgdma_register_callback(SGDMA,isr_sgdma_routine_ptr,sgdma_ctrl_reg, &MyContext);
//start DMA
int *start_dma = alt_avalon_sgdma_do_async_transfer(SGDMA,desc);
if (start_dma == 0){
printf("DMA started!\n\n");
} else {
printf("Error starting DMA (code: %d)\n\n", start_dma);
}
}
//register ISR
alt_irq_register(TRIG_DMA_IRQ, &MyContext, isr_sgdma_routine_ptr);
//activate trigger module and streaming from ADC here
trigger_reg=1;
//adc_test(ADC_IF_0_BASE);
//rs232_test(rspoint);
//trigger_status_test(TEST_COMP_0_BASE);
//sit in loop waiting for callback
while(1){
trigger_status_test(TEST_COMP_0_BASE);
if (MyContext.cnt > 0)
{
printf("Number of interrupts: %d\n\n", MyContext.cnt);
trigger_status_test(TEST_COMP_0_BASE);
}
//stops DMA in case of overflow
if (MyContext.cnt > 64)
{
printf("...Overflow...\n");
//stop SGDMA
alt_avalon_sgdma_stop(MyContext.pSGDMA);
//STOP trig
trigger_reg=0;
printf("Trig-on : %d\n",trigger_reg);
usleep(400*1000); // debounce
}
}
return 0;
} I'm working with Quartus 14.1, Nios II EDS 14.1, on Windows 7 (64 bit). -N