This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

C5509A : DMA/timer <-> interrupt problem



Hi all,

I'd like to do periodic DMA transmission from DARAM to EMIF at 1kHz with the C5509A. Therefore I use a timer and I perform a DMA_start inside of the timer's ISR. When I look at the signals at the EMIF, it seems that very often the DMA doesn't start and that this happens very irregularly. Just to complete the picture: if i symbolize successful transmissions with a T and unsuccessful ones with a X, I get a random pattern e.g. like T T X T T T T T T X T X T X T T T X T X T T T T X etc. with the T's and X's "spaced at 1kHz" (i.e. if I have and X, there's no output).

If I set a breakpoint in the timer ISR, I see a signal every time I continue. I thought it first was due to scope settings but I'm pretty sure that the settings are adapted.

Is there something am I missing or I didn't configure correctly? Here are some snippets from my code :

void main (void) {
    volatile Bool first = TRUE;
    c5509a_dspclk_init(12,144,0);        // PLL
    c5509a_intc_init();                    // CSL/interrupts
    c5509a_emif_init();                    // EMIF
    c5509a_dma_init();                    // DMA
    c5509a_timer_init();                // Timer   

    while (1) {
        if (first) {
            first = FALSE;
            TIMER_start(mhTimer0); // DMA element-by-element transfer is sync to timer0 => 8MHz
            TIMER_start(mhTimer1); // DMA_start is sync to timer1 => 1kHz
        }
      }
}

void c5509a_intc_init() {
     /* Initialize CSL library - This is REQUIRED !!! */
    CSL_init();
    /* Set IVPD/IVPH to start of interrupt vector table */
    IRQ_setVecs((Uint32)(&RESET_VEC));
}

void c5509a_dma_init(Uint16 inclk, Uint16 outclk, Uint16 plldiv)
{
    // DMA configuration ... => DMA interrupts are turned off
    /* Open DMA channels 4 & 5 and set regs to power on defaults */
    hDmaRcv = DMA_open(DMA_CHA4,DMA_OPEN_RESET);
    hDmaXmt = DMA_open(DMA_CHA5,DMA_OPEN_RESET); 
    // Get interrupt event associated with DMA receive and transmit  
    xmtEventId = DMA_getEventId(hDmaXmt);
    rcvEventId = DMA_getEventId(hDmaRcv);
    // Temporarily disable interrupts and clear any pending interrupts  
    old_intm = IRQ_globalDisable();
    // Clear any pending interrupts for DMA channels  
    IRQ_clear(xmtEventId);
    IRQ_clear(rcvEventId);
    // Enable DMA interrupt in IER register  
    IRQ_enable(xmtEventId);
    IRQ_enable(rcvEventId);
    // Place DMA interrupt service addresses at associate vector  
    IRQ_plug(xmtEventId,&dmaXmtIsr);
    IRQ_plug(rcvEventId,&dmaRcvIsr);
    // Write values from configuration structure to DMA control regs  
    DMA_config(hDmaRcv,&dmaRcvConfig);
    DMA_config(hDmaXmt,&dmaXmtConfig);
    // Restore status of global interrupt enable flag  
    IRQ_globalRestore(old_intm);
}

 

void c5509a_timer_init() {
    /* Open Timer 0, set registers to power on defaults */
    mhTimer0 = TIMER_open(TIMER_DEV0, TIMER_OPEN_RESET);
    /* Write configuration structure values to Timer control regs */
    TIMER_config(mhTimer0, &timer0_cfg);
    /* Open Timer 1, set registers to power on defaults */
    mhTimer1 = TIMER_open(TIMER_DEV1, TIMER_OPEN_RESET);
    /* Write configuration structure values to Timer control regs */
    TIMER_config(mhTimer1, &timer1_cfg);
    /* Get Event Id associated with Timer 0/1, for use with */
    /* CSL interrupt enable functions.                    */        
    tim0EventId = TIMER_getEventId(mhTimer0);
    tim1EventId = TIMER_getEventId(mhTimer1);
    /* Temporarily disable interrupts and clear any pending interrupts */
    old_intm = IRQ_globalDisable();
    /* Clear any pending Timer interrupts */
    IRQ_clear(tim0EventId);
    IRQ_clear(tim1EventId);
    /* Place interrupt service routine address at */
    /* associated vector location */
    IRQ_plug(tim0EventId,&timer0Isr);
    IRQ_plug(tim1EventId,&timer1Isr);
    /* Enable Timer interrupt */
    //IRQ_enable(timEventId);
    IRQ_enable(tim1EventId);
    /* Restore status of global interrupt enable flag */
    IRQ_globalRestore(old_intm);
    IRQ_globalEnable();
}

interrupt void timer1Isr(void) {
    // restart DMA
    DMA_start(hDmaXmt);
}

 

For testing purpose I only transmit 8 bytes per DMA transfer, so this should be done in far less than 1 ms!
Nothing more than that. I don't see where the problem is.

I appreciate every help on this.

 

Best regards,

Andreas

  • You shouldn't call DMA_start() form interrupt routine. Instead, use peripheral event, in your case timer interrupt, as transmission trigger. About unpredictable behavior - I believe that everything what happens in IRQ should use 'volatile' variables. DMA function is not based on volatiles for sure, so sometimes you have luck and it works fine, other time not. however, I'm not 100% sure about that explanation, this is only my theory.

     

    regards

    MS