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.

TMS320F28377D: ISR's are not being triggered by ADC SOC's or PWM interrupts

Part Number: TMS320F28377D

Hi,

Is there a way to check the status of the ADC/PWM interrupts, i.e. whether they are working or not?

I have placed some simple integer flags into my interrupts service routines, which are supposed to be triggered by an end of SOC on the ADC's. However, they are not triggering the ISR's at all. 
The only ISR that I have which is working is one I trigger with Timer 0 interrupt. 

There is no PWM being output on my board and thus there seems as though there is no triggering occuring. I have tried mapping the interrupts to the PWM, and to the ADC, and neither has worked.

It's almost as if my ADC's are not even sampling the signal, or if they are sampling the signal, they are not setting the interrupt flags once they have finished. Even if this is the case, I have tried using the interrupt flag associated with the PWM outputs I have selected, again to no avail.

I'm happy to insert some code but not entirely sure what will be the most relevant without pasting the entire project. Here is my ADC initialisation for now:

void InitADCs(void) // Write ADC configurations and power up all ADCs, ADCD not used
{
EALLOW; // Allow write to register

// ADC-A
AdcaRegs.ADCCTL2.bit.PRESCALE = 6; // Set ADCCLK divider to /4
AdcaRegs.ADCCTL2.bit.RESOLUTION = 0; // 12-bit resolution
AdcaRegs.ADCCTL2.bit.SIGNALMODE = 0; // Single-ended channel conversions (12-bit mode only)
AdcaRegs.ADCCTL1.bit.INTPULSEPOS = 1; // Set pulse positions to late
AdcaRegs.ADCCTL1.bit.ADCPWDNZ = 1; // Power up the ADC
// ADC-B
AdcbRegs.ADCCTL2.bit.PRESCALE = 6; // Set ADCCLK divider to /4
AdcbRegs.ADCCTL2.bit.RESOLUTION = 0; // 12-bit resolution
AdcbRegs.ADCCTL2.bit.SIGNALMODE = 0; // Single-ended channel conversions (12-bit mode only)
AdcbRegs.ADCCTL1.bit.INTPULSEPOS = 1; // Set pulse positions to late
AdcbRegs.ADCCTL1.bit.ADCPWDNZ = 1; // Power up the ADC
// ADC-C
AdccRegs.ADCCTL2.bit.PRESCALE = 6; // Set ADCCLK divider to /4
AdccRegs.ADCCTL2.bit.RESOLUTION = 0; // 12-bit resolution
AdccRegs.ADCCTL2.bit.SIGNALMODE = 0; // Single-ended channel conversions (12-bit mode only)
AdccRegs.ADCCTL1.bit.INTPULSEPOS = 1; // Set pulse positions to late
AdccRegs.ADCCTL1.bit.ADCPWDNZ = 1; // Power up the ADC

EDIS;
DELAY_US(1000); // Delay for 1ms to allow ADC time to power up
}

Here is my main which handles the mapping and etc, in case there is an error in that anyone can identify:

void main(void)
{
InitSysCtrl(); // Initialise System Control (F2837xD_SysCtrl.c)

EALLOW;
ClkCfgRegs.PERCLKDIVSEL.bit.EPWMCLKDIV = 0; // Set EPWM clock equal to PLLSYSLCK
EDIS;
// May need to enable also the HRPWM clock on CPU1 if to use SFO functions

// Calling SFO() updates the HRMSTEP register with calibrated MEP_ScaleFactor.
// HRMSTEP must be populated with a scale factor value prior to enabling
// high resolution period control.
while(status == SFO_INCOMPLETE)
{
status = SFO();
if(status == SFO_ERROR)
{
error(); // SFO function returns 2 if an error

InitGpioPins();

// Clear all interrupts and initialise PIE vector table
DINT;

InitPieCtrl(); // Clear all ENPIE bit and PIEIERx PIEIFRx register

IER = 0x0000;
IFR = 0x0000;

InitPieVectTable(); 

// Put C28x ISR addresses in vector table
// ADC interrupts go through PIE (Group 1)
EALLOW;
PieVectTable.EPWM1_INT = &MainCPU_ISR; // Test PWM interrupt
//PieVectTable.ADCA1_INT = &MainCPU_ISR; // Insert vector for INT1 of ADCA for Cathode Voltage Regulator ISR
PieVectTable.TIMER0_INT = &Soft_start; // Insert vector for Timer interrupt that causes increment in soft-start
//PieVectTable.ADCA2_INT = &auxCPU_ISR; // Insert vector for INT2 of ADCA for Collector Voltage Regulator ISR + write info
PieVectTable.EPWM4_INT = &auxCPU_ISR; // Test PWM4 Interrupt to check ADC errors
PieVectTable.IPC0_INT = &ipc0_isr; // Insert vector for CPU1 <--> CPU2 communications interrupt and update LCC registers
EDIS;

// Clear all IPC Bits to start
IpcRegs.IPCCLR.all = 0xFFFFFFFF;

// CPU1 Function Prototypes
InitADCs(); // Initialise all ADC Units
InitDACs(); // Initialise all DAC Units
InitCMPSS1(); // Initialise the second Comparator sub-system
InitCMPSS2(); // Initialise the second Comparator sub-system
InitCMPSS3(); // Initialise the third Comparator sub-system
InitCMPSS5(); // Initialise the fifth Comparator sub-system
InitCMPSS6(); // Initialise the sixth Comparator sub-system
InitEpwmXbar(); // Initialise the ePWM Crossbar
SetupSOC(); // Configure the Start of Conversions
InitPPB(); // Initialise Post Processing Block

// Stop time-base clock until all PWM channels are set up
EALLOW;
CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 0;
EDIS;

// Set up PWM Modules
InitEPwm1(); // Initialise module 1
InitEPwm4(); // Initialise module 4


// Configure CLA memory spaces and CLA task vectors
CLA_configClaMemory();
CLA_initCpu1Cla1();
Cla1ForceTask8andWait(); // Run the CLA Task 8 macro via SW to initialise CLA global variables

// Enable global interrupts and higher priority real-time debug events:
IER |= M_INT1; // Enable group 1 interrupts
IER |= M_INT3; // Enable PIE group 3 interrupt (EPWM1 to EPWM12)
IER |= M_INT10; // Enable group 10 interrupts
EINT; // Enable Global interrupt INTM
ERTM; // Enable Global real-time interrupt DBGM

// Need to manually enable our interrupts
// Unsure whether we need the IPC1 ISR, since we
// trigger the IPC ISR with ADCA2 as of now
PieCtrlRegs.PIEIER1.bit.INTx1 = 1; // Enable ADCA1 interrupt for triggering Cathode CLA Routine
PieCtrlRegs.PIEIER1.bit.INTx7 = 1; // Enable Timer 0 interrupt for soft-start
PieCtrlRegs.PIEIER1.bit.INTx13 = 1; // Enable IPC1 ISR which is used for collector and IPC ISR
PieCtrlRegs.PIEIER10.bit.INTx2 = 1; // Enable ADCA2 interrupt for triggering collector and IPC ISR
PieCtrlRegs.PIEIER3.bit.INTx1 = 1; // Enable PWMINT1 interrupt
PieCtrlRegs.PIEIER3.bit.INTx4 = 1; // Enable PWMINT4 interrupt

// Wait here until CPU02 is ready
// Statement does nothing until CPU02 is ready
while (IpcRegs.IPCSTS.bit.IPC17 == 0) ; // Wait for CPU02 to set IPC17
IpcRegs.IPCACK.bit.IPC17 = 1; // Acknowledge and clear IPC17

// Timer functions
Timer0_Init(); // Initialise timer 0 - will be used for main ISR. Timer begins in the initialisation function

// Start time-base clock so that all PWM channels are synchronised (must occur after all PWMs initialised)
EALLOW;
CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 1;
EDIS;

// Infinite while loop forever
while(1)
{
;
}
}

I am out of ideas why this isn't working. I have no input signals when debugging - but I would assume the interrupts would still be generated despite there being no inputs to the sensors. I also though it may be because my initail duty cycles in the CMPA registers were set to 0, however I made those a random number to ensure at least the first PWM cycle could trigger an ISR, but again I have no luck.

Any and all ideas are welcome!

Joel

  • Quick question: to use the ADC's, do you need to manually enable the clock bits?

    What about if using HRPWM, do you have to manually enable the HRPWM clock?

    I took the skeleton of my code from a TI example which does not seem to manually turn on the ADC clocks, but just powers them up.
    Same with HRPWM - the code functions are there, but I do not see anything in the main() which enables the seperate ADC or HRPWM clocks?

    Joel

  • Should also include code secion for my SOC's, since they are included in the triggering process:

    void SetupSOC(void)
    // There is an SOC associated with each ADC result register.
    // The SOC is a sequencer which determines the analogue input multiplexer channel selection,
    // sample-and-hold acquisition time and the SOC trigger source.

    // ADCA2, ADCB2 and ADCC2 are triggered by EPWM1
    // ADCA4 and ADCC4 are triggered by EPWM with an acquisition time of 15 SYSCLK cycles (75ns)
    // ISRs are triggered at the end of ADC conversions to guarantee they are complete.
    // In this case the ISRs are triggered when SOC0 completes.
    // In order to obtain simultaneous converter sampling for a particular groups of sensors,
    // the voltages are sensed in ADCA, and currents in ADCC, with each channel SOC being triggered
    // by the respective EWPM interrupt.

    {
    EALLOW;
    // Set INT1 of ADCA to trigger at the end of either SOC5-8 to indicate sample complete

    // Configure which interrupts will be set following completion of SOC
    // Program will branch to the ISR, which for the cathode is the CLA task,
    // for the collector we branch to the IPC ISR which communicates to CPU2 to begin the CLA core
    // Which CLA tasks are branched to from which INT flag is configured in
    // void CLA_initCPU1Cla1(void) function, or the IPC ISR routine below the main code.

    // Set INT1 of ADCA once Cathode Voltage sampled to trigger CLA Task 1
    AdcaRegs.ADCINTSEL1N2.bit.INT1SEL = 8; // End of SOC8 will set INT1 flag in ADCA
    AdcaRegs.ADCINTSEL1N2.bit.INT1CONT = 1; // Continuous allows CLA interrupts to work without setting CPU EINT
    AdcaRegs.ADCINTSEL1N2.bit.INT1E = 1; // Enable INT1 flag
    AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; // INT1 flag is cleared in ADCA

    // Set INT2 of ADCA once Collector Voltage sampled to trigger the IPC service routine
    AdcaRegs.ADCINTSEL1N2.bit.INT2SEL = 0; // End of SOC0 will set INT1 flag on ADCAS
    AdcaRegs.ADCINTSEL1N2.bit.INT2CONT = 1; // Continuous allows CLA interrupts to work without setting CPU EINT
    AdcaRegs.ADCINTSEL1N2.bit.INT2E = 1; // Enable INT2 flag
    AdcaRegs.ADCINTFLGCLR.bit.ADCINT2 = 1; // INT2 flag is cleared in ADCA

    // Program SOC Control Registers to 7x Over Sample the Cathode Output Voltage on ADCINA2
    // Fly-back voltage and current triggered by ePWM1 SOCA
    // Resonant converter voltage and current triggered by ePWM4 SOCA
    // By triggering the cathode and collector voltages according to ePWM1 and ePWM4 respectively,
    // they can trigger IPC and CLA tasks at different frequencies
    AdcaRegs.ADCSOC1CTL.bit.CHSEL = 2; // SOC1 will convert ADCINA2
    AdcaRegs.ADCSOC1CTL.bit.ACQPS = 19; // SOC1 will use sample duration of 20 SYSCLK cycles
    AdcaRegs.ADCSOC1CTL.bit.TRIGSEL = 5; // SOC1 will begin conversion on ePWM1 SOCA
    AdcaRegs.ADCSOC2CTL.bit.CHSEL = 2; // SOC2 will convert ADCINA2
    AdcaRegs.ADCSOC2CTL.bit.ACQPS = 19; // SOC2 will use sample duration of 20 SYSCLK cycles
    AdcaRegs.ADCSOC2CTL.bit.TRIGSEL = 5; // SOC2 will begin conversion on ePWM1 SOCA
    AdcaRegs.ADCSOC3CTL.bit.CHSEL = 2; // SOC3 will convert ADCINA2
    AdcaRegs.ADCSOC3CTL.bit.ACQPS = 19; // SOC3 will use sample duration of 20 SYSCLK cycles
    AdcaRegs.ADCSOC3CTL.bit.TRIGSEL = 5; // SOC3 will begin conversion on ePWM1 SOCA
    AdcaRegs.ADCSOC4CTL.bit.CHSEL = 2; // SOC4 will convert ADCINA2
    AdcaRegs.ADCSOC4CTL.bit.ACQPS = 19; // SOC4 will use sample duration of 20 SYSCLK cycles
    AdcaRegs.ADCSOC4CTL.bit.TRIGSEL = 5; // SOC4 will begin conversion on ePWM1 SOCA
    AdcaRegs.ADCSOC5CTL.bit.CHSEL = 2; // SOC5 will convert ADCINA2
    AdcaRegs.ADCSOC5CTL.bit.ACQPS = 19; // SOC5 will use sample duration of 20 SYSCLK cycles
    AdcaRegs.ADCSOC5CTL.bit.TRIGSEL = 5; // SOC5 will begin conversion on ePWM1 SOCA
    AdcaRegs.ADCSOC6CTL.bit.CHSEL = 2; // SOC6 will convert ADCINA2
    AdcaRegs.ADCSOC6CTL.bit.ACQPS = 19; // SOC6 will use sample duration of 20 SYSCLK cycles
    AdcaRegs.ADCSOC6CTL.bit.TRIGSEL = 5; // SOC6 will begin conversion on ePWM1 SOCA
    AdcaRegs.ADCSOC7CTL.bit.CHSEL = 2; // SOC7 will convert ADCINA2
    AdcaRegs.ADCSOC7CTL.bit.ACQPS = 19; // SOC7 will use sample duration of 20 SYSCLK cycles
    AdcaRegs.ADCSOC7CTL.bit.TRIGSEL = 5; // SOC7 will begin conversion on ePWM1 SOCA
    AdcaRegs.ADCSOC8CTL.bit.CHSEL = 2; // SOC8 will convert ADCINA2
    AdcaRegs.ADCSOC8CTL.bit.ACQPS = 19; // SOC8 will use sample duration of 20 SYSCLK cycles
    AdcaRegs.ADCSOC8CTL.bit.TRIGSEL = 5; // SOC8 will begin conversion on ePWM1 SOCA

    // Collector Over Voltage Sensor on ADCINA4
    AdcaRegs.ADCSOC0CTL.bit.CHSEL = 4; // SOC0 will convert ADCINA4
    AdcaRegs.ADCSOC0CTL.bit.ACQPS = 19; // SOC0 will use sample duration of 20 SYSCLK cycles
    AdcaRegs.ADCSOC0CTL.bit.TRIGSEL = 11; // SOC0 will begin conversion on ePWM4 SOCA

    // Input Over Voltage Sensor on ADCINB2
    AdcbRegs.ADCSOC5CTL.bit.CHSEL = 2; // SOC5 will convert ADCINB2
    AdcbRegs.ADCSOC5CTL.bit.ACQPS = 19; // SOC5 will use sample duration of 20 SYSCLK cycles
    AdcbRegs.ADCSOC5CTL.bit.TRIGSEL = 5; // SOC5 will begin conversion on ePWM1 SOCA

    // 4x Over Sample the Fly-back Switch Current on ADCINC2
    AdccRegs.ADCSOC5CTL.bit.CHSEL = 2; // SOC5 will convert ADCINC2
    AdccRegs.ADCSOC5CTL.bit.ACQPS = 19; // SOC5 will use sample duration of 20 SYSCLK cycles
    AdccRegs.ADCSOC5CTL.bit.TRIGSEL = 5; // SOC5 will begin conversion on ePWM1 SOCA
    AdccRegs.ADCSOC6CTL.bit.CHSEL = 2; // SOC6 will convert ADCINC2
    AdccRegs.ADCSOC6CTL.bit.ACQPS = 19; // SOC6 will use sample duration of 20 SYSCLK cycles
    AdccRegs.ADCSOC6CTL.bit.TRIGSEL = 5; // SOC6 will begin conversion on ePWM1 SOCA
    AdccRegs.ADCSOC7CTL.bit.CHSEL = 2; // SOC7 will convert ADCINC2
    AdccRegs.ADCSOC7CTL.bit.ACQPS = 19; // SOC7 will use sample duration of 20 SYSCLK cycles
    AdccRegs.ADCSOC7CTL.bit.TRIGSEL = 5; // SOC7 will begin conversion on ePWM1 SOCA
    AdccRegs.ADCSOC8CTL.bit.CHSEL = 2; // SOC8 will convert ADCINC2
    AdccRegs.ADCSOC8CTL.bit.ACQPS = 19; // SOC8 will use sample duration of 20 SYSCLK cycles
    AdccRegs.ADCSOC8CTL.bit.TRIGSEL = 5; // SOC8 will begin conversion on ePWM3 SOCA

    // Program SOC Control Registers to Sample the Collector Over Current Sensor on ADCINC4
    AdccRegs.ADCSOC5CTL.bit.CHSEL = 4; // SOC1 will convert ADCINC4
    AdccRegs.ADCSOC5CTL.bit.ACQPS = 19; // SOC1 will use sample duration of 20 SYSCLK cycles
    AdccRegs.ADCSOC5CTL.bit.TRIGSEL = 11; // SOC1 will begin conversion on ePWM4 SOCA

    EDIS;
    }

  • I have just tried to manually set the bits for the interrupt flags of both the INT1 and INT2 of ADCA that I want to trigger my ISR's, as so, in my main code:

    // Manually set the first interrupt flags for ADC's
    AdcaRegs.ADCINTFLG.bit.ADCINT1 = 1;
    AdcaRegs.ADCINTFLG.bit.ADCINT2 = 1;

    And still, the ISR's do not trigger and my INT flag variables remain at 0, indicating that still the ISR's are not executing, not even once. 

    Hopefully that makes things a bit easier to see where the problem is...some kind of ADC configuration error?

  • Hi Joe,

    I'm not familiar with global function proto type syntax but don't see any peripheral clocks being enabled either. It might be good to enable MOSC or internal OSC/PLL first thing.

  • Hi Joel,

    I think you'll want to run the code, then use the expressions window to check where the interrupt propagates and what is enabled.  The list to check for the ADC interrupt:

    • Is ADCINT flag set in the ADC register space?
    • Is the ADCINT flag enabled in the PIEIER register?
    • Is the ADCINT flag pending in the PIEIFR register?
    • Is the correct line enabled in the CPU IER register?
    • Is the correct line pending in the CPU IFR regiser?
    • Is the global CPU interrupt enabled?  (INTM bit in the CPU ST1 register : 0 = "enabled")
    • Is the intended ISR mapped to the correct location in the PIE vector table? 
  • Hi, ADCA1_ISR = 0x00B0BE and ADCA_INT1 = 0x00008584. I'm not entirely sure what this even means if I am honest. Cannot find anything in the technical document that would tell me whether this is correct or not. So even if I checked the other expressions I wouldn't be able to tell whether they were correct! Any advice on how to tell whether these are enabled or not?

  • Hi Gl, 

    InitSysCtrl(); has InitPeripheralClocks(); function inside of it. Not sure if this enables the clocks for th ADC's? I'd assume so. 

  • Judging by the name InitSysCtrl() who knows. CCS you can hold CTL key + click on the function to jump to origin, open tab in CCS editor.

  • Also odd to not see passing of configuration values into the function prototypes, assumed to assert runtime code?

  • I assume you often will code using the driverlib function that often do pass variables into the function prototypes. Every single example I have seen which uses the bitfield approach will initailize a lot of things in this way. 

    I got one of the ISR's working, the issue was that I did not have the SOC interrupts enabled in my PWM set up. Therefore the SOC was not being created and thus ADC INT1 was not being created either, so no ISR.

    The other ISR was not executing because in my fourth PWM module I had initialised the TBRPD register to have a value of 0, stupidly, meaning that the module was not outputting any PWM - meaning no SOC was being started, and no INT2 generation. 

    All sorted now. Just some very stupid programming from me. 

    Thanks both for help on the topic, the answers were very useful anyway and led me to investigate these parts of my code! Slight smile

  • The EPWM sub modules C2000 are mind tasking to say the least.

    90% of issues are often self inflicted driverlib configuration battle wounds Laughing... Best of luck Joel