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.

DMA Interrupt Problem

I am developing on the 28069 Experimenter's Board, using Sys/Bios, and am having a problem with the DMA. I have my DMA channel setup to read data out of the ADC Results register. Now my DMA interrupt is triggered, so I assume that this means the DMA buffer has been filled. Now what I want to happen in the ISR is using a ping pong buffer scheme I read the data out of the DMA buffer, perform some averaging and send a Mailbox Post. 

What is actually happening is hard to tell. It appears that the ISR is called, stops mid way, and starts at the top of the ISR again. It does this a couple times and then hangs. The way I have been diagnosing this is by using the debugger and printf statements.  A printf statement at the start of the ISR is called 3 times, then it hangs. It never prints the printf statement at the end of the ISR. I also have a task that is spawned and pends for the Mailbox Post at the end of the ISR, but the Mailbox Message is never read, whether that is because no message is sent or execution never leaves ISR, I don't know. When I try to set breakpoints to step through, I usually get some weird things happening,  like the following:

C28xx: Trouble Setting Breakpoint with the Action "Continue or Finish Stepping" at 0x3ddeb4: Error 0x00000008/-1066 Error during: Break Point,  Cannot set/verify breakpoint at 0x003DDEB4 

This message happens after I read the data out of the DMA buffer and am stepping through code creating a mailbox message to post. My guess is this is where the execution of the ISR would revert back to the start. Also when stepping through the code, printf statements generate runtime erros when being stepped over, and I have to comment them out. This seems like a separate issue, but not sure what the cause is.

So lots of confusion, is this an issue with how the DMA is set up, or am I making an error on how I am trying to debug it?

  • Have been debugging this, and it doesn't look like the ADC is set up correctly. I have tried a couple different things and here is my code that I am using to set up PWM/ADC/DMA for different scenarios:

    SCENARIO 1+2:

    //---------------------------------------------------------------------
    //--- Configure ePWM7 to trigger the ADC at a 50 kHz rate
    //---------------------------------------------------------------------
    EPwm7Regs.TBCTL.bit.CTRMODE = 0x3; // Disable the timer

    EPwm7Regs.TBCTL.all = 0xC033; // Configure timer control register
    // bit 15-14 11: FREE/SOFT, 11 = ignore emulation suspend
    // bit 13 0: PHSDIR, 0 = count down after sync event
    // bit 12-10 000: CLKDIV, 000 => TBCLK = HSPCLK/1
    // bit 9-7 000: HSPCLKDIV, 000 => HSPCLK = SYSCLKOUT/1
    // bit 6 0: SWFSYNC, 0 = no software sync produced
    // bit 5-4 11: SYNCOSEL, 11 = sync-out disabled
    // bit 3 0: PRDLD, 0 = reload PRD on counter=0
    // bit 2 0: PHSEN, 0 = phase control disabled
    // bit 1-0 11: CTRMODE, 11 = timer stopped (disabled)

    EPwm7Regs.TBCTR = 0x0000; // Clear timer counter
    EPwm7Regs.TBPRD = ADC_SAMPLE_PERIOD; // Set timer period
    EPwm7Regs.TBPHS.half.TBPHS = 0x0000; // Set timer phase

    EPwm7Regs.ETPS.all = 0x0100; // Configure SOCA
    // bit 15-14 00: EPWMxSOCB, read-only
    // bit 13-12 00: SOCBPRD, don't care
    // bit 11-10 00: EPWMxSOCA, read-only
    // bit 9-8 01: SOCAPRD, 01 = generate SOCA on first event
    // bit 7-4 0000: reserved
    // bit 3-2 00: INTCNT, don't care
    // bit 1-0 00: INTPRD, don't care

    EPwm7Regs.ETSEL.all = 0x0A00; // Enable SOCA to ADC
    // bit 15 0: SOCBEN, 0 = disable SOCB
    // bit 14-12 000: SOCBSEL, don't care
    // bit 11 1: SOCAEN, 1 = enable SOCA
    // bit 10-8 010: SOCASEL, 010 = SOCA on PRD event
    // bit 7-4 0000: reserved
    // bit 3 0: INTEN, 0 = disable interrupt
    // bit 2-0 000: INTSEL, don't care

    EPwm7Regs.TBCTL.bit.CTRMODE = 0x0; // Enable the timer in count up mode
    }

    SCENARIO 1+2:

    asm(" EALLOW"); // Enable EALLOW protected register access

    //--- Power-up and configure the ADC
    AdcRegs.ADCCTL1.all = 0x00E4; // Power-up reference and main ADC
    // bit 15 0: RESET, ADC software reset, 0=no effect, 1=resets the ADC
    // bit 14 0: ADCENABLE, ADC enable, 0=disabled, 1=enabled
    // bit 13 0: ADCBSY, ADC busy, read-only
    // bit 12-8 0's: ADCBSYCHN, ADC busy channel, read-only
    // bit 7 1: ADCPWDN, ADC power down, 0=powered down, 1=powered up
    // bit 6 1: ADCBGPWD, ADC bandgap power down, 0=powered down, 1=powered up
    // bit 5 1: ADCREFPWD, ADC reference power down, 0=powered down, 1=powered up
    // bit 4 0: reserved
    // bit 3 0: ADCREFSEL, ADC reference select, 0=internal, 1=external
    // bit 2 1: INTPULSEPOS, INT pulse generation, 0=start of conversion, 1=end of conversion
    // bit 1 0: VREFLOCONV, VREFLO convert, 0=VREFLO not connected, 1=VREFLO connected to B5
    // bit 0 0: TEMPCONV, Temperature sensor convert. 0=ADCINA5 is pin, 1=ADCINA5 is temp sensor

    AdcRegs.ADCCTL2.all = 0x0003; // ADC clock configuration
    // bit 15-3 0's: reserved
    // bit 2 0: CLKDIV4EN, ADC clock divider. 0=no effect, 1=CPUCLK/4 if CLKDIV2EN=1 (else no effect)
    // bit 1 1: ADCNONOVERLAP, 0=overlap sample and conversion, 1=no overlap
    // bit 0 1: CLKDIV2EN, ADC clock divider. 0=CPUCLK, 1=CPUCLK/2

    DELAY_US(1000); // Wait 1 ms after power-up before using the ADC

    //--- SOC0 configuration
    //AdcRegs.ADCSAMPLEMODE.bit.SIMULEN0 = 0; // SOC0 in single sample mode (vs. simultaneous mode)
    //AdcRegs.ADCSAMPLEMODE.bit.SIMULEN2 = 0;
    //AdcRegs.ADCSAMPLEMODE.bit.SIMULEN4 = 0;

    /* Set Acquisition window */
    AdcRegs.ADCSOC0CTL.bit.ACQPS = 6;
    AdcRegs.ADCSOC1CTL.bit.ACQPS = 6;
    AdcRegs.ADCSOC2CTL.bit.ACQPS = 6;
    AdcRegs.ADCSOC3CTL.bit.ACQPS = 6;
    AdcRegs.ADCSOC4CTL.bit.ACQPS = 6;
    AdcRegs.ADCSOC5CTL.bit.ACQPS = 6;

    // Select the channel to be converted when SOCx is received
    AdcRegs.ADCSOC0CTL.bit.CHSEL = 0;
    AdcRegs.ADCSOC1CTL.bit.CHSEL = 1;
    AdcRegs.ADCSOC2CTL.bit.CHSEL = 2;
    AdcRegs.ADCSOC3CTL.bit.CHSEL = 3;
    AdcRegs.ADCSOC4CTL.bit.CHSEL = 4;
    AdcRegs.ADCSOC5CTL.bit.CHSEL = 5;

    /* Set Trigger for SOC */
    AdcRegs.ADCSOC0CTL.bit.TRIGSEL = 17; // EMPWM7A
    AdcRegs.ADCSOC1CTL.bit.TRIGSEL = 17; // EMPWM7A
    AdcRegs.ADCSOC2CTL.bit.TRIGSEL = 17; // EMPWM7A
    AdcRegs.ADCSOC3CTL.bit.TRIGSEL = 17; // EMPWM7A
    AdcRegs.ADCSOC4CTL.bit.TRIGSEL = 17; // EMPWM7A
    AdcRegs.ADCSOC5CTL.bit.TRIGSEL = 17; // EMPWM7A

    AdcRegs.ADCINTSOCSEL1.bit.SOC0 = 0; // No ADCINT triggers SOC0. TRIGSEL field determines trigger.
    AdcRegs.ADCINTSOCSEL1.bit.SOC1 = 0; // No ADCINT triggers SOC1. TRIGSEL field determines trigger.
    AdcRegs.ADCINTSOCSEL1.bit.SOC2 = 0; // No ADCINT triggers SOC2. TRIGSEL field determines trigger.
    AdcRegs.ADCINTSOCSEL1.bit.SOC3 = 0; // No ADCINT triggers SOC3. TRIGSEL field determines trigger.
    AdcRegs.ADCINTSOCSEL1.bit.SOC4 = 0; // No ADCINT triggers SOC4. TRIGSEL field determines trigger.
    AdcRegs.ADCINTSOCSEL1.bit.SOC5 = 0; // No ADCINT triggers SOC5. TRIGSEL field determines trigger.

    AdcRegs.SOCPRICTL.bit.SOCPRIORITY = 0; // All SOCs handled in round-robin mode

    //--- ADCINT1 configuration
    AdcRegs.INTSEL1N2.bit.INT1CONT = 1; // ADCINT1 pulses regardless of ADCINT1 flag state
    AdcRegs.INTSEL1N2.bit.INT1E = 1; // Enable ADCINT1
    AdcRegs.INTSEL1N2.bit.INT1SEL = 0; // EOC0 triggers ADCINT1

    //--- Finish up
    AdcRegs.ADCCTL1.bit.ADCENABLE = 1; // Enable the ADC

    asm(" EDIS"); // Disable EALLOW protected register access

    SCENARIO 1:

    asm(" EALLOW"); // Enable EALLOW protected register access

    //---------------------------------------------------------------------
    //--- Overall DMA setup
    //---------------------------------------------------------------------
    DmaRegs.DMACTRL.bit.HARDRESET = 1; // Reset entire DMA module
    asm(" NOP"); // 1 cycle delay for HARDRESET to take effect

    DmaRegs.DEBUGCTRL.bit.FREE = 1; // 1 = DMA unaffected by emulation halt
    DmaRegs.PRIORITYCTRL1.bit.CH1PRIORITY = 0; // Not using CH1 Priority mode

    //---------------------------------------------------------------------
    //--- Configure DMA channel 1 to read the ADC results
    //---------------------------------------------------------------------
    DmaRegs.CH1.MODE.all = 0x8901;
    // bit 15 1: CHINTE, 0=interrupt disabled, 1=interrupt enabled
    // bit 14 0: DATASIZE, 0=16-bit, 1=32-bit
    // bit 13-12 00: reserved
    // bit 11 1: CONTINUOUS, 0=stop, 1=re-init after transfer complete
    // bit 10 0: ONESHOT, 0=one burst on trigger, 1=all bursts on trigger
    // bit 9 0: CHINTMODE, 0=start of transfer, 1=end of transfer
    // bit 8 1: PERINTE, peripheral interrupt trigger enable, 0=disabled, 1=enabled
    // bit 7 0: OVRINTE, overflow interrupt enable, 0=disabled, 1=enabled
    // bit 6-5 00: reserved
    // bit 4-0 00001: PERINTSEL, 1=ADCINT1

    DmaRegs.CH1.BURST_SIZE.bit.BURSTSIZE = 13; // 13 means 14 words per burst
    DmaRegs.CH1.TRANSFER_SIZE = ADC_BUF_LEN-1; // ADC_BUF_LEN bursts per transfer

    DmaRegs.CH1.SRC_TRANSFER_STEP = 0; // 0 means add 0 to pointer each burst in a transfer
    DmaRegs.CH1.SRC_ADDR_SHADOW = (Uint32)&AdcResult.ADCRESULT0; // SRC start address

    DmaRegs.CH1.DST_TRANSFER_STEP = 14; // 14 = add 14 to pointer each burst in a transfer
    DmaRegs.CH1.DST_ADDR_SHADOW = (Uint32)AdcRaw; // DST start address

    DmaRegs.CH1.CONTROL.all = 0x0091;
    // bit 15 0: reserved
    // bit 14 0: OVRFLG, overflow flag, read-only
    // bit 13 0: RUNSTS, run status, read-only
    // bit 12 0; BURSTSTS, burst status, read-only
    // bit 11 0: TRANSFERSTS, transfer status, read-only
    // bit 10-9 00: reserved
    // bit 8 0: PERINTFLG, read-only
    // bit 7 1: ERRCLR, error clear, 0=no action, 1=clear SYNCERR bit
    // bit 6-5 00: reserved
    // bit 4 1: PERINTCLR, periph event clear, 0=no action, 1=clear periph event
    // bit 3 0: PERINTFRC, periph event force, 0=no action, 1=force periph event
    // bit 2 0: SOFTRESET, 0=no action, 1=soft reset the channel
    // bit 1 0: HALT, 0=no action, 1=halt the channel
    // bit 0 1: RUN, 0=no action, 1=enable the channel


    //--- Finish up
    asm(" EDIS"); // Disable EALLOW protected register access

    SCENARIO 3:

    // Configure ADC
    EALLOW;
    AdcRegs.ADCCTL2.bit.ADCNONOVERLAP = 1; // Enable non-overlap mode
    AdcRegs.ADCCTL1.bit.INTPULSEPOS = 1; // ADCINT1 trips after AdcResults latch
    AdcRegs.INTSEL1N2.bit.INT1E = 1; // Enabled ADCINT1
    AdcRegs.INTSEL1N2.bit.INT1CONT = 0; // Disable ADCINT1 Continuous mode
    AdcRegs.INTSEL1N2.bit.INT1SEL = 1; // setup EOC1 to trigger ADCINT1 to fire
    AdcRegs.ADCSOC0CTL.bit.CHSEL = 4; // set SOC0 channel select to ADCINA4
    AdcRegs.ADCSOC1CTL.bit.CHSEL = 2; // set SOC1 channel select to ADCINA2
    AdcRegs.ADCSOC0CTL.bit.TRIGSEL = 5; // set SOC0 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC1
    AdcRegs.ADCSOC1CTL.bit.TRIGSEL = 5; // set SOC1 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC1
    AdcRegs.ADCSOC0CTL.bit.ACQPS = 6; // set SOC0 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)
    AdcRegs.ADCSOC1CTL.bit.ACQPS = 6; // set SOC1 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)
    EDIS;

    // Assumes ePWM1 clock is already enabled in InitSysCtrl();
    EPwm1Regs.ETSEL.bit.SOCAEN = 1; // Enable SOC on A group
    EPwm1Regs.ETSEL.bit.SOCASEL = 4; // Select SOC from CMPA on upcount
    EPwm1Regs.ETPS.bit.SOCAPRD = 1; // Generate pulse on 1st event
    EPwm1Regs.CMPA.half.CMPA = 0x0080; // Set compare A value
    EPwm1Regs.TBPRD = 0xFFFF; // Set period for ePWM1
    EPwm1Regs.TBCTL.bit.CTRMODE = 0; // count up and start

    So scenario 1 I am using code I found from an example, tweaked to work for my application. I am using a PWM to trigger ADC, ADC to trigger DMA. I have one interrupt mapped in SYS/BIOS, to the DMA. The interrupt triggers, but the ISR executes funky.

    Scenario 2, I remove the DMA code from scenario 1 and have one interrupt mapped to the ADC. The interrupt doesn't trigger.

    Scenario 3, I remove all code from scenarios 1 and 2 and replace it with code from an ADC example. I use the same interrupt from scenario 2, and this time it does trigger. 

    So my first question is why isn't scenario 2 working?  My second question, why is the DMA triggering in Scenario 1 if the ADC doesn't appear to be working?