- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Ok update on the problem - I've tried to write some values (with the cpu) into the SDRAM to check if the SGDMA actually accesses the memory at all. When I try to read these values, I get sent to the exception stack. I have a feeling that the SGDMA is causing problems with the memory (both on and off chip).
How should I connect the SDRAM to the SGDMA to avoid this problem and successfully write to memory?- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
UPDATE: The ISR executes correctly now, the CPU instructions were being overwritten in the SDRAM by the SGDMA, so I moved them to on chip memory.
Unfortunately, when I check what's being written to the SDRAM, I only get 84 bytes of coherent data at the address 0x0 (ie: write_addr), before the values -1 and 0 are written for 32kb (ie: the specified write length), followed by 40 bytes of cohenrent data.- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
This is in burst mode. In continuous mode, the first 32 bit word of data coming from my trigger component keeps getting rewritten. As far as I can tell, this is because the avstream_ready bit toggles for each word the SGDMA writes to memory (which resets my trigger device) - is there any way to keep this bit constant?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I'm tempted to say save yourself the hassle and write your own DMA controller. I got sick of trying to coax any of the DMA controllers in Qsys to work correctly, they either worked intermittently, not at all, or corrupted the data. Its only about a days work to write a decent DMA controller and at least if it goes wrong you wrote the source code so it's easier to fix/debug.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I actually just added two FIFOs (my data is 32 bits wide, the internal FIFO on the SGDMA couldn't cope - it was only storing two words, and then writing), which solved the problem. I used one for data (4096 bits deep) and one as a clock bridge (my ADC is clocked to 25MHz, and my DMA and SDRAM run at 100MHz).

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page