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.

TM4C123GH6PM: TM4C123GH6PM ADC interrupt

Part Number: TM4C123GH6PM
Other Parts Discussed in Thread: EK-TM4C123GXL

Hi,

I am using PWM for ADC0 trigger. Here is PWM and ADC0 init routines. With this, I am not getting ADC interrupt.

Right now I am using EK-TM4C123GXL board to start with though I have ordered custom board for same.

void
PWMInit(void) {
//
// Make the PWM pins be peripheral function.
//
GPIOPinConfigure(GPIO_PB6_M0PWM0);
GPIOPinConfigure(GPIO_PB7_M0PWM1);
GPIOPinConfigure(GPIO_PB4_M0PWM2);
GPIOPinConfigure(GPIO_PB5_M0PWM3);
GPIOPinConfigure(GPIO_PE4_M0PWM4);
GPIOPinConfigure(GPIO_PE5_M0PWM5);

GPIOPinTypePWM(PIN_PHASEU_LOW_PORT,
PIN_PHASEU_LOW_PIN | PIN_PHASEU_HIGH_PIN);
GPIOPinTypePWM(PIN_PHASEV_LOW_PORT,
PIN_PHASEV_LOW_PIN | PIN_PHASEV_HIGH_PIN);
GPIOPinTypePWM(PIN_PHASEW_LOW_PORT,
PIN_PHASEW_LOW_PIN | PIN_PHASEV_HIGH_PIN);

PWMGenConfigure(PWM0_BASE, PWM_GEN_0, (PWM_GEN_MODE_UP_DOWN |
PWM_GEN_MODE_SYNC |
PWM_GEN_MODE_DBG_STOP));
PWMGenConfigure(PWM0_BASE, PWM_GEN_1, (PWM_GEN_MODE_UP_DOWN |
PWM_GEN_MODE_SYNC |
PWM_GEN_MODE_DBG_STOP));
PWMGenConfigure(PWM0_BASE, PWM_GEN_2, (PWM_GEN_MODE_UP_DOWN |
PWM_GEN_MODE_SYNC |
PWM_GEN_MODE_DBG_STOP));

PWMSetDeadBand();

PWMSetFrequency();
PWMGenPeriodSet(PWM0_BASE, PWM_GEN_0, PWM_CLOCK / 1000);
PWMGenPeriodSet(PWM0_BASE, PWM_GEN_1, PWM_CLOCK / 1000);
PWMGenPeriodSet(PWM0_BASE, PWM_GEN_2, PWM_CLOCK / 1000);
PWMUpdateDutyCycle();

//
// Enable the PWM generators.
//
PWMGenEnable(PWM0_BASE, PWM_GEN_0);
PWMGenEnable(PWM0_BASE, PWM_GEN_1);
PWMGenEnable(PWM0_BASE, PWM_GEN_2);


PWMSyncTimeBase(PWM0_BASE, PWM_GEN_0_BIT | PWM_GEN_1_BIT | PWM_GEN_2_BIT);


PWMGenIntClear(PWM0_BASE, PWM_GEN_0, PWM_INT_CNT_ZERO);
PWMGenIntTrigEnable(PWM0_BASE, PWM_GEN_0,
PWM_INT_CNT_ZERO | PWM_TR_CNT_LOAD);
PWMGenIntTrigEnable(PWM0_BASE, PWM_GEN_1, 0);
PWMGenIntTrigEnable(PWM0_BASE, PWM_GEN_2, 0);

IntEnable(INT_PWM0_0_TM4C123);
IntEnable(INT_PWM0_1_TM4C123);
IntEnable(INT_PWM0_2_TM4C123);


PWMOutputFault(PWM0_BASE, (PWM_OUT_0_BIT | PWM_OUT_1_BIT | PWM_OUT_2_BIT |
PWM_OUT_3_BIT | PWM_OUT_4_BIT | PWM_OUT_5_BIT), true);

//
// Enable interrupts to the processor.
//
IntMasterEnable();
}

void
ADCInit(void)
{

//Added for Tiva C (TM4C123GH6PMI) processor

GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_0);
GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_1);
GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_2);
GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3);

ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_PWM0, 0);
ADCSequenceStepConfigure(ADC0_BASE, 0, 0, PIN_I_PHASEU);
ADCSequenceStepConfigure(ADC0_BASE, 0, 1, PIN_I_PHASEV);
ADCSequenceStepConfigure(ADC0_BASE, 0, 2, PIN_I_PHASEW);
ADCSequenceStepConfigure(ADC0_BASE, 0, 3, PIN_VSENSE);
ADCSequenceStepConfigure(ADC0_BASE, 0, 4,
ADC_CTL_END | ADC_CTL_IE | ADC_CTL_TS);
ADCSequenceEnable(ADC0_BASE,0);

ADCIntClear(ADC0_BASE, 0);
ADCIntEnable(ADC0_BASE, 0);
IntEnable(ADC_INT_SS0);

}

Please provide me some pointers.

  • Greetings,

    May it be noted that this (forum's) weekend 'activity' makes,  'USA's 'Death Valley' (wide, isolated desert)' appear  'Activity Central!'

    As to pointers:

    • we must assume that (both) the PWM & ADC Modules were properly enabled - your confirmation will be helpful
    • PWMSetDeadBand() is not shown
    • PWMSetFrequency() similarly - have each of these been tested & verified?
    • IntEnable(INT_PWM0_0_TM4C123);     Your addition of the area in highlight proves suspicious.   (see manual's note, below)    Did you modify all 3 interrupt vectors w/in the 'Start-Up' code to accept your unique naming scheme?
    • PWMIntEnable()  this may - or may not be required.   (I initially included it - then deleted - and have now 'Added it (again) to your 'List of Pointers.'   The 'strict' mention of 'Fault' gives me pause.) 

    17.2.3.2 IntEnable

    Enables an interrupt.
    Prototype: void IntEnable(uint32_t ui32Interrupt)
    Parameters: ui32Interrupt specifies the interrupt to be enabled.
    Description: The specified interrupt is enabled in the interrupt controller. The ui32Interrupt parameter must be one of the valid INT_∗values listed in Peripheral Driver Library User’s Guide and defined in the inc/hw_ints.h header file.   (Does yours comply?)   Other enables for the interrupt (such as at the peripheral level) are unaffected by this function. 

    21.2.2.26 PWMIntEnable
    Enables  Generator  and fault interrupts for a PWM module.
    Prototype: void PWMIntEnable(uint32_t ui32Base, uint32_t ui32GenFault)
    Parameters: ui32Base is the base address of the PWM module. ui32GenFault contains the interrupts to be enabled. This parameter must be a logical OR of any of  PWM_INT_GEN_0, PWM_INT_GEN_1, PWM_INT_GEN_2, PWM_INT_GEN_3, PWM_INT_FAULT0, PWM_INT_FAULT1, PWM_INT_FAULT2, or PWM_INT_FAULT3. Description: This function unmasks the specified interrupt(s) by setting the specified bits of the interrupt enable register for the selected PWM module.

    I'm uncertain as to, 'The ability of these 'variants' to, 'Do you in!'     Yet (some) pointers beat (no) pointers - and just maybe - the ADC will (w/this change) respond to PWM_0's Trigger.    I've read your code (yet not loaded it) and it appears very similar to my firm's code (but for that noted) - which performs to specification...   (ADC IS always PWM Triggered...)

  • Hi,

    Thanks for your swift response. Here are answers to your queries.

    • we must assume that (both) the PWM & ADC Modules were properly enabled - your confirmation will be helpful
    • [NK] Yes. I have enabled both as below in main file.
    • SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
    • SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM0);
    • PWMSetDeadBand() is not shown
    • [NK] Yes. This is done as in this function as,
    • PWMSetDeadBand(); PWMSetFrequency();

    • PWMSetFrequency() similarly - have each of these been tested & verified?
    • [NK] Yes. I can see all PWMs are appearing on respective pins with desired frequency and pulse width.
    • IntEnable(INT_PWM0_0_TM4C123);     Your addition of the area in highlight proves suspicious.   (see manual's note, below)    Did you modify all 3 interrupt vectors w/in the 'Start-Up' code to accept your unique naming scheme?
    • [NK] These are as provided in hw_ints.h file in folder C:\ti\TivaWare_C_Series-2.1.4.178\inc hence not modified anywhere. Is it required to modify/update in any other startup file?
    • #define INT_PWM0_FAULT_TM4C123 25 // PWM0 Fault
      #define INT_PWM0_0_TM4C123 26 // PWM0 Generator 0
      #define INT_PWM0_1_TM4C123 27 // PWM0 Generator 1
      #define INT_PWM0_2_TM4C123 28 // PWM0 Generator 2
      #define INT_QEI0_TM4C123 29 // QEI0

    • PWMIntEnable()  this may - or may not be required.   (I initially included it - then deleted - and have now 'Added it (again) to your 'List of Pointers.'   The 'strict' mention of 'Fault' gives me pause.) 
    • [NK] I didn't add this because, I don't need PWM interrupt but need PWM triggered ADC0 interrupt.

    Please let me know if you need other info to proceed further.

  • Hello - simply 'terrific' job in responding.

    I was 'unaware' of the 'additions/restrictions' to the parameters w/in "IntEnable()".      None of my firm's (past) code employed such 'specificity.'

    To the (still) 'missing ADC interrupt - your function call:

    "PWMGenIntTrigEnable(PWM0_BASE, PWM_GEN_0, PWM_INT_CNT_ZERO | PWM_TR_CNT_LOAD);"

    very much overlaps what our firm has (successfully - and LONG) deployed!    (my 'aid' to you is descending like a boulder - 'escaping' from a mountain top)

    Now as you have confirmed that your code's PWM Section 'Does generate correct PWM Outputs' - we should examine your ADC code.

    Key here - I believe - is your function call:

    "ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_PWM0, 0);"     Our team used (exactly that) - which worked!     However do note - we used (either) 'StellarisWare 9453 or one of the far earlier versions of the newer 'TM4C' library.

    Now ALWAYS - when in doubt - 'RTFM!'    (Read (really read) fine user manual!)   Just now - prior to staff's arrival - I 'discovered':

    4.2.2.27 ADCSequenceConfigure
    Configures the trigger source and priority of a sample sequence.
    Prototype: void ADCSequenceConfigure(uint32_t ui32Base, uint32_t ui32SequenceNum, uint32_t ui32Trigger, uint32_t ui32Priority)

    When ADC_TRIGGER_PWM0, ADC_TRIGGER_PWM1, ADC_TRIGGER_PWM2 or ADC_TRIGGER_PWM3 is specified, one of the following should be ORed into ui32Trigger to select the PWM module from which the triggers will be routed for this sequence: ADC_TRIGGER_PWM_MOD0 - Selects PWM module 0 as the source of the PWM0 to PWM3 triggers for this sequence. 

    Is this API 'Addition/CHANGE' then - the 'most likely explanation' for my team's (past) code success - and your (till now) difficulty?

    Adding "ADC_TRIGGER_PWM_MOD0" - as noted herein - should, 'Get you 'On the Air!'    (one hopes - yet w/good (almost sound) reason...)

  • Hi,

    Thanks again for your response.

    I agree with what you mentioned about ADC_TRIGGER_PWM_MOD0  and implemented. But this didn't solve my issue of ADC interrupt. Unfortunately there must be some other issue also. I am continuing hard on library functions related to ADC thoroughly. However, no luck so far. I am using SW-TM4C-2.1.4.178 library.

    One question.... do I need to setup ADC clock through ADCClockConfigSet ? Anything else ?

    Thanks

    NK

  • Hello cb1,

    Edit: It seems we both fell haplessly into the same trap. Whoops. Or maybe I just can't read well this morning and stumbled upon my own feet horribly. :)

    Upon further review of API's there is ADCSequenceConfigure and ADCSequenceStepConfigure.

    ADCSequenceConfigure was properly configured with ADC_TRIGGER_PWM0

    My original post here was pretty far off, sorry for likely adding in a lot of confusion. I need to review the D/S closely as I am unsure why in TivaWare we have these both defined the same:

    #define ADC_TRIGGER_PROCESSOR   0x00000000  // Processor event
    #define ADC_TRIGGER_PWM_MOD0    0x00000000  // PWM triggers from PWM0
    

    Something about that seems a bit off.

    To clear up my earlier comments which weren't accurate...

    ADCSequenceStepConfigure should have the input channels more clearly defined here:

    First lets review the current hardcoded settings:

    ADCSequenceStepConfigure(ADC0_BASE, 0, 0, PIN_I_PHASEU);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 1, PIN_I_PHASEV);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 2, PIN_I_PHASEW);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 3, PIN_VSENSE);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 4,
    ADC_CTL_END | ADC_CTL_IE | ADC_CTL_TS);
    

    Per the adc.h file:

    #define ADC_CTL_CH0             0x00000000  // Input channel 0
    #define ADC_CTL_CH1             0x00000001  // Input channel 1
    #define ADC_CTL_CH2             0x00000002  // Input channel 2
    #define ADC_CTL_CH3             0x00000003  // Input channel 3
    #define ADC_CTL_CH4             0x00000004  // Input channel 4

    So that actually works correctly.

    What I am unclear about now is the parameters used for PIN_I_PHASEU etc. - these are not TivaWare parameters as far as I am aware, can this be elaborated on further?

  • Hello NK,

    Please see my edited reply as I also made a mistake in interpretation.

  • Hello NK,

    Okay so clarify from my initial post and edited version (which I apologize for introducing unneeded confusion):

    The datasheet explains the definitions now, so while the idea of explicitly using the OR'd is beneficial for coding purposes, in reality it had always been configured right due to the ADC_TRIGGER_PWM_MOD0 being 0x00 anyways. This would only matter if the device later gets configured for ADC_TRIGGER_PWM_MOD1 as at reset the value is 0x00.

    Value         Description

    0x0            Use Generator 0 (and its trigger) in PWM module 0

    0x1            Use Generator 0 (and its trigger) in PWM module 1


    Can the following be clarified? This is the missing piece for me right now:

    Ralph Jacobi said:

    What I am unclear about now is the parameters used for PIN_I_PHASEU etc. - these are not TivaWare parameters as far as I am aware, can this be elaborated on further?

  • Hi Ralph,

    Here are definitions I have in pins.h file.

    #define PIN_I_PHASEU            ADC_CTL_CH0

    #define PIN_I_PHASEV            ADC_CTL_CH1

    #define PIN_I_PHASEW            ADC_CTL_CH2

    #define PIN_VSENSE              ADC_CTL_CH3

    Do let me know if you need any other information.

    Thanks

    NK

  • Hello NK,

    Thanks. You mentioned ADCClockConfigSet, from our peripheral examples which are based on your device that isn't required but those examples also were not triggering from PWM. However, I would say to be safe, you could add this call as well.

    Since this is on a LaunchPad, I will try and run your code here shortly now that I have those defines and see what I can uncover.

  • I realize that your code does not require a 'PWM Interrupt' - yet - if indeed you (properly) OR'ed in PWM_MOD0 - then the (only) difference between our (past) working (i.e. PWM triggering the ADC) code and yours - if our use of PWM0's Interrupt.     

    Does not cost (much) to 'Add & Observe.'     And ... 'breaking news' ... one of the young staff has just 'Removed the PWM0 Interrupt' - and (thus far)  'the ADC is NO LONGER BEING TRIGGERED!  (Post lunch we will review her 'interrupt disabling' - seeking 'group confirmation.')

     (I saw where Ralph 'deep-dived' for that parameter's value - yet (perhaps) somewhere else w/in the code - that '0' bit is being (illegally set) - and thus requires 'formal (complete & properly) sequenced initialization' - to perform.)

    This poster appears to have (very) closely followed the PWM & ADC code examples - presented (both) w/in the 'Peripheral Driver Library' and several illustrating Peripheral code projects.

    Again - my firm's code - far less complex than present 'TWare' - sees 'PWM0 Trigger the ADC' - w/no hint of issue...

  • Hello NK,

    Just noticed a mistake in the IntEnable call, try this:

    IntEnable(INT_ADC0SS0);

    Instead of

    IntEnable(ADC_INT_SS0);

  • Hello Ralph,

    Our past code follows:   (2015 vintage)     Note that we were taught to, 'First disable interrupts & sequences.'

    // Disable the ADC sequence and interrupts for safe configuration of the ADC sequences.
    //
    ROM_IntDisable(INT_ADC0SS0);
    ROM_ADCIntDisable(ADC0_BASE, 0);
    ROM_ADCSequenceDisable(ADC0_BASE, 0);

    // Enable the ADC sequence code.

    //
    ROM_ADCSequenceEnable(ADC0_BASE, 0);
    ROM_ADCIntEnable(ADC0_BASE, 0);
    ROM_IntEnable(INT_ADC0SS0);

    And this is 'exactly' what you uncovered!     And I have 'no excuse' for missing that parameter ... yet used that mistake to develop a 'rule' for future code-analysis!

    As the 'ADC's Interrupt' was failing ... ALL Function Calls which (in any way) relate to the  'FAILED'  Interrupt  must be checked (even double checked!)    

    It is wondered - from where - did poster first find - then select "ADC_INT_SS0?"     He succeeded with (almost) everything - yet even a 'single error or misuse' - blocks success... 

  • Hello cb1,

    It comes from the ADC header file but with the following comment:

    // Values that can be passed to ADCIntDisableEx(), ADCIntEnableEx(),
    // ADCIntClearEx() and ADCIntStatusEx().

    The Ex tag at the end of API's would indicate functions for TM4C129 class of devices though I don't recall needing to use ADCIntEnableEx over ADCIntEnable for them.

  • Yaaaaa Hooooo..... My issue is resolved....

    Thank you so much Ralph...

  • Good for you - may we ask 'from where' you sourced that 'incorrect' interrupt parameter?   "ADC_INT_SS0"

    You may wish to 'Adopt the practice' of 'Focusing upon those function calls - which are (most associated/relevant) to the 'issue at hand.'    (that would be 'all ADC related interrupt functions' - in this specific case)    

    Cut/Paste solutions 'work once' - yet 'improved technique' is expected to deliver a superior & longer-lasting impact...