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.

CCS/SW-EK-TM4C1294XL: Encoder Code development - problem with interrupts

Part Number: SW-EK-TM4C1294XL
Other Parts Discussed in Thread: EK-TM4C1294XL, TM4C1294NCPDT

Tool/software: Code Composer Studio

Dear members,

I'm trying to use an encoder with the launchpad EK-TM4C1294XL.

I've tested the Encoder using arduino, and it seems to be working properly. 1 revolution of the encoder is equal to 1024 pulses, as it should be.

My arduino code was based on this one: https://electricdiylab.com/how-to-connect-optical-rotary-encoder-with-arduino/

I am having some issues with Tiva.

The main problem is that I am not being able to read the status from the Encoder Phase B when the Encoder Phase A has generated the interruption.

I tried as well to use different interruptions and using the Phase A in one port (PD0) and the Phase B in another one (PL0), with no success.

Can someone help me?

Best regards,

Gustavo Wegher

#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/gpio.h"
#include "drivers/pinout.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include "driverlib/rom_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "utils/uartstdio.h"

//*****************************************************************************
//
// System clock rate in Hz.
//
//*****************************************************************************
uint32_t g_ui32SysClock;

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


//-----------------------------------------------------------------------------
// Variable Declaration for Encoder - 18.10.2020
//-----------------------------------------------------------------------------
#define ENCODER_A       GPIO_PIN_0      // PD0
#define ENCODER_B       GPIO_PIN_1      // PD1
#define delay_100ms    120000000/30

uint32_t countGen, countA, counter = 0;
uint32_t counterPartA = 0, counterPartB = 0, counterPartC = 0;
uint32_t counterPartD = 0, counterPartE = 0, counterPartF = 0;
uint32_t var_temp, encoderAStatus, encoderBStatus, varTempEncoder, varTestEncoderA, varTestEncoderB;

//-----------------------------------------------------------------------------
// Interruption Routine for Encoder - 18.10.2020
//-----------------------------------------------------------------------------
void GPIOD_ENCODER(void){

    var_temp = GPIOIntStatus(GPIO_PORTD_BASE, ENCODER_A|ENCODER_B);
    encoderAStatus = GPIOPinRead(GPIO_PORTD_BASE, ENCODER_A);
    encoderBStatus = GPIOPinRead(GPIO_PORTD_BASE, ENCODER_B);

    if (var_temp & ENCODER_A){
        if (encoderBStatus){
            counterPartA++;
        }
        else{
            counterPartB++;
        }
    }

    if (var_temp & ENCODER_B){
        if (encoderAStatus){
            counterPartC++;
        }
        else{
            counterPartD++;
        }
    }

    //
    // Print out the test results.
    //
    UARTprintf("counterPartA = %3d | counterPartB = %3d | counterPartC = %3d | counterPartD = %3d\r", counterPartA, counterPartB, counterPartC, counterPartD);

    //SysCtlDelay(delay_100ms);

    GPIOIntClear(GPIO_PORTD_BASE, ENCODER_A|ENCODER_B);

}

//*****************************************************************************
//
// Configure the UART and its pins.  This must be called before UARTprintf().
//
//*****************************************************************************
void
ConfigureUART(void)
{
    //
    // Enable the GPIO Peripheral used by the UART.
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

    //
    // Enable UART0
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);

    //
    // Configure GPIO Pins for UART mode.
    //
    ROM_GPIOPinConfigure(GPIO_PA0_U0RX);
    ROM_GPIOPinConfigure(GPIO_PA1_U0TX);
    ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

    //
    // Initialize the UART for console I/O.
    //
    UARTStdioConfig(0, 115200, g_ui32SysClock);
}

//*****************************************************************************
//
// Print "Hello World!" to the UART on the Intelligent UART Module.
//
//*****************************************************************************
int
main(void)
{
    //
    // Run from the PLL at 120 MHz.
    //
    g_ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
                SYSCTL_OSC_MAIN | SYSCTL_USE_PLL |
                SYSCTL_CFG_VCO_480), 120000000);

    //
    // Configure the device pins.
    //
    PinoutSet(false, false);

    //
    // Enable the GPIO pins for the LED D1 (PN1).
    //
    ROM_GPIOPinTypeGPIOOutput(GPIO_PORTN_BASE, GPIO_PIN_1);


    //
    // Enable the GPIOD Peripherals
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOD)) {}

    //
    // Configure the GPIOD as Inputs
    //
    GPIOPinTypeGPIOInput(GPIO_PORTD_BASE, ENCODER_A|ENCODER_B);
    GPIOPadConfigSet    (GPIO_PORTD_BASE, ENCODER_A|ENCODER_B, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU);
    GPIOIntTypeSet      (GPIO_PORTD_BASE, ENCODER_A|ENCODER_B, GPIO_RISING_EDGE);
    GPIOIntRegister     (GPIO_PORTD_BASE, GPIOD_ENCODER);
    GPIOIntEnable       (GPIO_PORTD_BASE, ENCODER_A|ENCODER_B);

    //
    // Initialize the UART.
    //
    ConfigureUART();

    //
    // Hello!
    //
    UARTprintf("Hello, world!\n");

    while(1){}
}

  • Hello Gustavo,

    For all variables you are modifying inside of your ISR, you need to declare them volatile or they may not update in the ISR.

    Try running the code with:

    volatile uint32_t counterPartA = 0, counterPartB = 0, counterPartC = 0;
    volatile uint32_t counterPartD = 0, counterPartE = 0, counterPartF = 0;
    volatile uint32_t var_temp, encoderAStatus, encoderBStatus, varTempEncoder, varTestEncoderA, varTestEncoderB;

    Also you may want to consider as a next step after you get this working to use the QEI peripheral inside the TM4C!

  • Hey Ralph,

    thanks for the quick answer. That worked well.

    About the QEI peripheral, could you recommend some material about it, besides the TM4C1294NCPDT datasheet?

    I'm kinda new to Tiva.

    Another question: I'm planning to use a PWM with an encoder, and I suppose both are based on interruptions (also my code and suppose QEI peripheral).

    Is it possible that I'll have to define priorities, so that both PWM and encoder can work properly?

    Best regards,

    Gustavo Wegher

  • Hello Gustavo,

    The datasheet and our TivaWare DriverLib User's Guide would be the best resources, we don't have a lot of collateral on QEI to be honest. Here is a link to the User's Guide: https://www.ti.com/lit/pdf/spmu298

    Regarding priorities, you may need to, but it really depends how you interface everything together and if you find any race conditions. I think the answer will become clearer as you develop your solution. The NVIC is well setup to configure priorities though so it will be easy to do so if you find the need for that.