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: GPIO interrupt

Part Number: TM4C123GH6PM
Other Parts Discussed in Thread: LM393,

Hello guys,

I got a problem when using the GPIO Input RISING_EDGE Interrupt. 

Tool: IAR Embedded Workbench.

Application: using  LM393 Motor Speed Measuring Sensor to get the speed of DC Motor.

Program

  • PF3 is configured as input with rising edge interrupt. It is connected with the digital output of the speed sensor. And “1” corresponds to ~1.25V, “0” <0.25V.
  • There is also a timer interrupt: Timer0, subtimer A; periodic interrupt with interrupt for timeout. Display with the red led.

Here is the code:

  • Main.c:

#define PART_TM4C123GH6PM

//*****************************************************************************
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include "inc/hw_gpio.h"
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/debug.h"
#include "driverlib/fpu.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include "driverlib/sysctl.h"
#include "driverlib/timer.h"
#include "driverlib/uart.h"
#include "utils/uartstdio.h"

//#include "inc/tm4c123gh6pm.h"

#define GPIO_PORTF_DATA_R 0x400253FC //   (*((volatile uint32_t *)0x400073FC))

//*****************************************************************************
//
//! This project calculates the speed of motor from signal of infrared sensor.
//! A timer to generate a periodic interrupt defines the sampling time.
//! A GPIO port to generate an interrupt when the DO is high calculates the RPM
//! RPM = count/Ts/20(20 stripes)*60(s/min)
//! speed v (mm/s) = pi*d(unit: mm)*RPM/60
//*****************************************************************************

//*****************************************************************************
//
// Flags that contain the current value of the interrupt indicator.
//
//*****************************************************************************
uint32_t g_ui32Flags = 0;
uint32_t red_led = 0;

//*****************************************************************************
//
// Flags that contain the value of the interrupts of GPIO Input/DO of the sensor.
//
//*****************************************************************************
uint32_t PortFIntFlags = 0;
int count = 0;

int v; // the speed; unit: mm/s; = pi*d*count/Ts(20ms)/20*1000
float pi = 3.14; // 3.14
int d = 66; // unit: mm
int T = 1000; // unit: mm; corresponds to 1/s
int pulsesperturn = 20;
uint32_t period = 32000000;

//*****************************************************************************
//
// The error routine that is called if the driver library encounters an error.
//
//*****************************************************************************
#ifdef DEBUG
void
__error__(char *pcFilename, uint32_t ui32Line)
{
}
#endif

//*****************************************************************************
//
// The interrupt handler for the timer interrupt.
//
//*****************************************************************************
void
Timer0IntHandler(void)
{
    //
    // Clear the timer interrupt.
    //
    TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);

    g_ui32Flags = 1;
    //
    // Toggle the flag for the timer.
    //
//    HWREGBITW(&g_ui32Flags, 0) ^= 1;
    red_led = ~red_led;
   
    GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, red_led);
}


void PortFIntHandler(void){
 
//  PortFIntFlags++;
//
//  uint32_t status=0;
// 
//  status = GPIOIntStatus(GPIO_PORTF_BASE,true);
//
//  GPIOIntClear(GPIO_PORTF_BASE,status);
//
//  if( (status & GPIO_INT_PIN_3) == GPIO_INT_PIN_3)
//  {
//    count ++;
//  }
 
  if (GPIO_PORTF_DATA_R & 0x08 != 0 )
  {
    count++;
  }
 
  GPIOIntClear(GPIO_PORTF_BASE, GPIO_INT_PIN_3);
}

//*****************************************************************************
//
// This  application calculates the speed of the DC motor
// through the infrared sensor.
//
//*****************************************************************************
int
main(void)
{
 
  //Set the clock to 80Mhz
  SysCtlClockSet(SYSCTL_SYSDIV_1|SYSCTL_USE_OSC|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ);

  //*****************************************************************************
  // GPIO: pf3 - rising edge
  SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
  SysCtlDelay(3);
  GPIOPinTypeGPIOInput(GPIO_PORTF_BASE, GPIO_PIN_3);
//  GPIOPadConfigSet(GPIO_PORTF_BASE,GPIO_PIN_3,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPD);
  GPIOIntRegister(GPIO_PORTF_BASE,PortFIntHandler);
  GPIOIntTypeSet(GPIO_PORTF_BASE, GPIO_PIN_3, GPIO_FALLING_EDGE);
  GPIOIntEnable(GPIO_PORTF_BASE, GPIO_INT_PIN_3);
  GPIOIntClear(GPIO_PORTF_BASE, GPIO_INT_PIN_3);

  GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1);
 
  //Timer0 
  SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
  SysCtlDelay(3);
  TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);
  TimerLoadSet(TIMER0_BASE, TIMER_A, period);
  // Setup the interrupts for the timer timeouts.
  TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
  // Enable the timers.
  TimerEnable(TIMER0_BASE, TIMER_A);
 
  IntEnable(INT_GPIOF);
  IntEnable(INT_TIMER0A);
  IntMasterEnable();

  while(1)
  {
    if (g_ui32Flags ==1)
    {
           
      // do not process interrupts during calculations 
      GPIOIntDisable(GPIO_PORTF_BASE, GPIO_INT_PIN_3);
     
      v = (int)1000*pi*d*count/pulsesperturn;
  
      printf("count = %d\n", count);
      printf("v = %d\n", v);

      count = 0;
      g_ui32Flags = 0;
     
      GPIOIntEnable(GPIO_PORTF_BASE, GPIO_INT_PIN_3);

    }
  }

}

  • Startup_ewarm.c(part):

 //*****************************************************************************
//
// Int Handler for the applications.
//
//*****************************************************************************
void Timer0IntHandler(void);
void PortFIntHandler(void);

   IntDefaultHandler,                      // Watchdog timer
    // IntDefaultHandler,                      // Timer 0 subtimer A
    Timer0IntHandler,                       // Timer 0 subtimer A
    IntDefaultHandler,                      // Timer 0 subtimer B
 

    IntDefaultHandler,                      // FLASH Control
//    IntDefaultHandler,                      // GPIO Port F
    PortFIntHandler,                        // GPIO Port F
    IntDefaultHandler,                      // GPIO Port G

Problem:

The variable count is always 0. But the green led blinks with the rotating motor.

 

I really don’t know what is the problem...

Thank you for your advice and help.

 

Best regards.

 

Meidan

  • From practical experience - firm/I have (long) found that employing one Timer in "One-Shot" Mode - rather than "periodic" - will, "Speed, Ease & Enhance" your results. One Timer serves as "One Shot" (i.e. this "gates" the accumulated counts - logged by a 2nd Timer (that set to "Edge Count.")

    You set Timer 1's (One Shot) duration so that an "adequate" number of pulses may be detected by Timer 2. (Edge Count) Only when Timer 1 is "active" is Timer 2 - able to count. The "longer" the duration of your "one-shot" - the higher your measurement's accuracy...

    ARM MCUs have multiple Timers - attempting this task via "One Timer Alone" - adds great complications - is not recommended...
  • Hello,

    thanks a lot for your help.

    I found it to be a hardware problem. The voltage of the DO of LM393 (also PF3 input of Tiva c ) can now be as high as about 5V, so that recognized as "HIGH", thus coming to the RISING_EDGE interrupt.

    Because I need to get the speed as long as it moves, so I would rather choose the PERIODIC.

    Now the program functions, but not well, since the variable "count" is not so stable. Maybe I should just fix the motor encoder. Maybe it is because of my program. Here is the code:
    #define PART_TM4C123GH6PM

    //*****************************************************************************
    #include <stdint.h>
    #include <stdbool.h>
    #include <stdio.h>
    #include "inc/hw_gpio.h"
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "driverlib/debug.h"
    #include "driverlib/fpu.h"
    #include "driverlib/gpio.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/rom.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/timer.h"
    #include "driverlib/uart.h"
    #include "utils/uartstdio.h"

    //*****************************************************************************
    //
    //! This project calculates the speed of motor from signal of infrared sensor.
    //! A timer to generate a periodic interrupt defines the sampling time.
    //! A GPIO port to generate an interrupt when the DO is high calculates the RPM
    //! RPM = count/Ts/20(20 stripes)*60(s/min)
    //! speed v (mm/s) = pi*d(unit: mm)*RPM/60
    //! so v (mm/s) = pi*d*count*1000/Ts/20
    //*****************************************************************************

    //*****************************************************************************
    //
    // Flags that contain the current value of the interrupt indicator.
    //
    //*****************************************************************************
    uint32_t g_ui32Flags = 0;

    //*****************************************************************************
    //
    // Flags that contain the value of the interrupts of GPIO Input/DO of the sensor.
    //
    //*****************************************************************************
    int count = 0;

    //*****************************************************************************
    int v; // the speed; unit: mm/s; = pi*d*count/Ts(20ms)/20*1000
    float pi = 3.14; // 3.14
    int d = 65; // unit: mm
    int T = 1000; // unit: ms; corresponds to 1/s
    int pulsesperturn = 20;
    uint32_t period = 16000000;
    int Ts = 1000; // unit: ms

    //*****************************************************************************
    //
    // The error routine that is called if the driver library encounters an error.
    //
    //*****************************************************************************
    #ifdef DEBUG
    void
    __error__(char *pcFilename, uint32_t ui32Line)
    {
    }
    #endif

    //*****************************************************************************
    //
    // The interrupt handler for the timer interrupt.
    //
    //*****************************************************************************
    void Timer0IntHandler(void)
    {
    // Clear the timer interrupt.
    TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);

    g_ui32Flags = 1;

    }


    void PortFIntHandler(void)
    {

    GPIOIntClear(GPIO_PORTF_BASE, GPIO_INT_PIN_3);
    count++;
    }

    //*****************************************************************************
    //
    // This application calculates the speed of the DC motor
    // through the infrared sensor.
    //
    //*****************************************************************************
    int main(void)
    {

    //Set the clock to 16Mhz
    SysCtlClockSet(SYSCTL_SYSDIV_1|SYSCTL_USE_OSC|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ);

    //*****************************************************************************
    // GPIO: pf3 - rising edge; pf1 - display for timer
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    SysCtlDelay(3);
    GPIOPinTypeGPIOInput(GPIO_PORTF_BASE, GPIO_PIN_3);
    GPIOIntRegister(GPIO_PORTF_BASE,PortFIntHandler);
    GPIOIntTypeSet(GPIO_PORTF_BASE, GPIO_PIN_3, GPIO_RISING_EDGE);
    GPIOIntEnable(GPIO_PORTF_BASE, GPIO_INT_PIN_3);
    GPIOIntClear(GPIO_PORTF_BASE, GPIO_INT_PIN_3);

    GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1);

    //Timer0
    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
    SysCtlDelay(3);
    TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);
    TimerLoadSet(TIMER0_BASE, TIMER_A, period-1);
    // Setup the interrupts for the timer timeouts.
    TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
    // Enable the timers.
    TimerEnable(TIMER0_BASE, TIMER_A);

    IntEnable(INT_GPIOF);
    IntEnable(INT_TIMER0A);
    IntMasterEnable();

    while(1)

    {
    if (g_ui32Flags ==1)
    {
    GPIOIntDisable(GPIO_PORTF_BASE, GPIO_INT_PIN_3);

    v = (int )pi*d*count*T/pulsesperturn/Ts;

    count = 0;

    g_ui32Flags = 0;

    GPIOIntEnable(GPIO_PORTF_BASE, GPIO_INT_PIN_3);

    }
    }

    }

    Do you have any idea to improve it ?

    Thanks.

    Best regards
    Meidan
  • Meidan Zhao said:
    PF3 input of Tiva c ) can now be as high as about 5V

    My friend - you must check the MCU's spec to determine if ~5V is accepted by that port - and that pin!    As I recall your simple voltage comparator chip - the output is "open collector" - thus you can return that to 3V3 - eliminating any damage potential introduced by "about 5V."


    The stuttered readings you note - almost always - result from your (and others) choice of "periodic Timer" - which enforces MUCH MORE "time critical control" upon your program.    (and - for what?)

    One-Shot is far simpler/faster - and once the "stutter is eliminated" - you may optimize its, "speed of response."

    One-Shot is "KISS Approved" - Periodic is NOT - you have "created" a "higher than required HURDLE" - perhaps unfair to reject the suggested approach - and ask for a FAR more complex effort...