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: Problems with QEI Module

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

Hello,

i try to implement a simple application, which can count the QEI edges. This edges are displayed at the console.

I use the TI-RTOS and the code compile without errors. The Problem is the output, which is always the same and varies by a maximum of 1.

I would be very grateful for help.

Output Console:Position: 500
Position: 499
Position: 499
Position: 499
Position: 500
Position: 500

/* XDCtools Header files */
#include <xdc/std.h>
#include <xdc/runtime/System.h>
#include <xdc/cfg/global.h>

/* BIOS Header files */
#include <ti/sysbios/BIOS.h>

/* Standard IO stream etc. */
#include <stdbool.h>            // Defines for standard boolean representation.
#include <stdio.h>              // IO-stream for console display etc.

/* Drivers etc. */
#include "inc/hw_ints.h"        // Macros defining the interrupts.
#include "inc/hw_memmap.h"      // Macros defining the memory map of the device.
#include "inc/hw_sysctl.h"      // Macros for usage with SysCtl.
#include "inc/hw_types.h"       // Macros for common types.
#include "driverlib/debug.h"    // Macros to debug the driverlib.
#include "driverlib/gpio.h"     // Macros defining the GPIO assignments.
#include "driverlib/pin_map.h"  // Macros defining the pin map of the device.
#include "driverlib/sysctl.h"   // Prototypes for the SysCtl driver.
#include "driverlib/qei.h"      // for quadratur encoder

/* Global variables */
// Put your global variables here.
uint32_t Position;

/* Function prototypes */
void Init_Clock(void);
void ConfigureQEI0(void);

/*
 * ======== main ========
 */
void main(void)
{
    printf("BIOS starting...\n");

    // Initialize the main clock/oscillator.
    Init_Clock();

    //QEI Module aktivieren
    ConfigureQEI0();

    printf("Finished.\n");

    // Start TI-RTOS. Everything is now controlled by the BIOS, as defined in your project .CFG file.
    BIOS_start();
}

/*
 * ======== tasks ========
 */

// This is the background task.
void Task_Idle(void)
{
    // Code here ...
    System_flush();
}

// This is a repetitive task that is executed every 100 ms.
// Timing can be modified in the .CFG file.
void Task_100ms(void)
{
    // Read the encoder position.
    Position = QEIPositionGet(QEI0_BASE);
    // display values in debug window
    System_printf("Position: %d\n", Position);
}

/*
 * ======== user functions ========
 */

// This function initializes the clock/oscillator used in the project.
void Init_Clock(void)
{
    // Settings for 80 MHz.
    SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
    return;
}

void ConfigureQEI0(){
printf("Initializing QEI ..."); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); // Enable the QEI0 peripheral // while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOF)); SysCtlPeripheralEnable(SYSCTL_PERIPH_QEI0); // Enable the QEI0 peripheral // while(!SysCtlPeripheralReady(SYSCTL_PERIPH_QEI0)); // Wait for the QEI0 module to be ready. //Set Pins to be PHA0 and PHB0 GPIOPinConfigure(GPIO_PF0_PHA0); GPIOPinConfigure(GPIO_PF1_PHB0); GPIOPinTypeQEI(GPIO_PORTF_BASE, GPIO_PIN_0); GPIOPinTypeQEI(GPIO_PORTF_BASE, GPIO_PIN_1); //DISable peripheral and int before configuration QEIDisable(QEI0_BASE); QEIIntDisable(QEI0_BASE,QEI_INTERROR | QEI_INTDIR | QEI_INTTIMER | QEI_INTINDEX); QEIConfigure(QEI0_BASE, QEI_CONFIG_CAPTURE_A_B | QEI_CONFIG_NO_RESET | QEI_CONFIG_QUADRATURE | QEI_CONFIG_NO_SWAP, 1000); // enable QEI module QEIEnable(QEI0_BASE); //Set Register start Values QEIPositionSet(QEI0_BASE,500); printf(" done.\n"); return; } // End of file.


  • Hi,

      I'm not a TI-RTOS expert. I'm wondering how did you create the Task_100ms(). Do you have the .cfg file? 

      Can you port your code to a non TI-RTOS environment and do you still see the same issue? You can replace System_printf() with UARTprintf(). Refer to the <TivaWare_Installtion>/examples/boards/ek-tm4c123gxl/hello/hell.c for example on how to use UARTprintf(). 

  • Hallo Torsten,

    Looking at QEI initialization,  PF0, line 94.

    Possibly, the PF0 pin is still "locked" to the NMI function, making PF0 not yet connected to QEI.  This means the QEI counter effectively has only one input = PF1.  

    Your init PositionSet at 500 means that PF1 makes the QEI bounce around 500, 499...

    Normally, specific code is written to unlock PF0 to allow an IO function.  There are some DRIVERLIB calls to unlock GPIO. Sorry, I don't have my laptop, but check the Tivaware please.

    Hope this helps in this case.

  • In the new Tivaware release, there is a new API for unlocking....

    1.5.2 Added New API to GPIO Driver to Unlock GPIO Pins

    The GPIO driver has been updated with a new API, GPIOUnlockPin, which enables the unlocking of GPIO which have been locked for JTAG or NMI operation.

  • Hi Otto,

      Thank you for your input. Yes, the GPIOUnlockPin() can be used to unlock the pin. Or the following code sequence will do the same. 

    //
    // Unlock PF0 so we can change it to a GPIO input
    // Once we have enabled (unlocked) the commit register then re-lock it
    // to prevent further changes. PF0 is muxed with NMI thus a special case.
    //
    HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY;
    HWREG(GPIO_PORTF_BASE + GPIO_O_CR) |= 0x01;
    HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = 0;

  • first of all thank you both for the answers. ^^

    i added the code from you to unlock the Pin, between SysCtlPeripheralEnable(SYSCTL_PERIPH_QEI0) and GPIOPinConfigure(GPIO_PF0_PHA0), but that doesn't fix the problem. Should i lock the Pin after that configuration again or are the 3 lines sufficient?

    I followed the Code here: https://forum.43oh.com/topic/7170-using-harware-qei-on-tiva-launchpad/

    I create the Task_100ms() with a timer in the .cfg file.

    I tried the code only with TI-RTOS because that was the target for the project. I checked the quatratur signal with a oszilloskop, but that looks okay. Do you have other ideas, i really have no idea anymore.

  • Sorry to hear this.  It's been a while since I used ti-rtos.   But in any case, I personally would write the QEI code outside of the this to make sure it was understood and it worked.  I got QEI going a few months ago, that's why I knew about the 'bouncing around 500' problem. Let me get in my laptop and get the code.   I've not posted code, or a CCS project before on this forum; please be patient.

    But, please do not worry, the QEI is not a difficult peripheral at all.

    Tcheuss

  • I will send you a CCS project if you PM me.   This project was for my learning and many printf() etc, but the QEI initialization is clear.

    For QEI_0   :  I used PD6 and PD7 on my Launchpad.  This is because PF0 is not bought out to a pin, and I wanted to use PF1 for the Red  LED.

    In any case, here is the QEI init function.  I borrowed from a github link, thank you to that git contributor.

    *********************************************************************************************
    //
    //   QEI setup from GITHUB      ***************   NOTE that D7 must be unlocked as it is NMI
    //    github.com/.../DC-Control-Module.git
    // Encoder pins
    // PD6 - A, PD7 - B, Module 0
    // PC5 - A, PC6 - B, Module 1
    //
    //  *********************************************************************************************
    
    void QEIconfig(int limit1, int limit2){
        // QEI Config
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD); // We are using PD7 for PhB0, QEI module 0 phase B
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC); // PC5 - A,PC6 - B
        SysCtlPeripheralEnable(SYSCTL_PERIPH_QEI0);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_QEI1);
    
    // /*
        //Unlock GPIOD7 - Like PF0 its used for NMI - Without this step it doesn't work
        HWREG(GPIO_PORTD_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY; //In Tiva include this is the same as "_DD" in older versions (0x4C4F434B)
        HWREG(GPIO_PORTD_BASE + GPIO_O_CR) |= 0x80;             // better to use GPIO_PIN_7
        HWREG(GPIO_PORTD_BASE + GPIO_O_LOCK) = 0;
    // */
    /*
        HWREG(GPIO_PORTD_BASE+0x520) = 0x4C4F434B;
        HWREG(GPIO_PORTD_BASE+0x524) |= GPIO_PIN_7;
        HWREG(GPIO_PORTD_BASE+0x520) = 0;
    // */
    
        //Set Pins to be PHA0 and PHB0   for QEI 0
        GPIOPinConfigure(GPIO_PD6_PHA0); // QEI module 0 phase A
        GPIOPinConfigure(GPIO_PD7_PHB0); // QEI module 0 phase B
    
        //Set Pins to be PHA1 and PHB1   for QEI 1
        GPIOPinConfigure(GPIO_PC5_PHA1); // QEI module 1 phase A
        GPIOPinConfigure(GPIO_PC6_PHB1); // QEI module 1 phase B
    
        //Set GPIO pins for QEI. PhA0 -> PD6, PhB0 ->PD7. I believe this sets the pull up and makes them inputs
        GPIOPinTypeQEI(GPIO_PORTD_BASE, GPIO_PIN_6 |  GPIO_PIN_7);
        GPIOPinTypeQEI(GPIO_PORTC_BASE, GPIO_PIN_5 |  GPIO_PIN_6);
    
    //    GPIOPadConfigSet (GPIO_PORTC_BASE, GPIO_PIN_5 |  GPIO_PIN_6, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU);
        GPIOPadConfigSet (GPIO_PORTC_BASE, GPIO_PIN_5 |  GPIO_PIN_6, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU);
    //    GPIOPadConfigSet ();
    
    
    
        //Disable peripheral and int before configuration
        QEIDisable(QEI0_BASE);
    
        QEIIntDisable(QEI0_BASE,QEI_INTERROR | QEI_INTDIR | QEI_INTTIMER | QEI_INTINDEX);
        // Configure quadrature encoder, use an arbitrary top limit of 1000 (debug)
        QEIConfigure(QEI0_BASE, (QEI_CONFIG_CAPTURE_A_B  | QEI_CONFIG_NO_RESET  | QEI_CONFIG_QUADRATURE | QEI_CONFIG_NO_SWAP), limit1);
        // Enable the quadrature encoder.
        QEIEnable(QEI0_BASE);
        //Set position to a middle value so we can see if things are working
        QEIPositionSet(QEI0_BASE, limit1/2);
    
        QEIDisable(QEI1_BASE);
        QEIIntDisable(QEI1_BASE,QEI_INTERROR | QEI_INTDIR | QEI_INTTIMER | QEI_INTINDEX);
        // Configure quadrature encoder, use an arbitrary top limit of 1000
        QEIConfigure(QEI1_BASE, (QEI_CONFIG_CAPTURE_A_B  | QEI_CONFIG_NO_RESET  | QEI_CONFIG_QUADRATURE | QEI_CONFIG_NO_SWAP), limit2);
        // Enable the quadrature encoder.
        QEIEnable(QEI1_BASE);
        //Set position to a middle value so we can see if things are working
        QEIPositionSet(QEI1_BASE, limit2/2);
    
        // filter the inputs
        QEIFilterConfigure (QEI0_BASE,
                            QEI_FILTCNT_17);
        QEIFilterEnable (QEI0_BASE);
        QEIFilterConfigure (QEI1_BASE,
                            QEI_FILTCNT_17);
        QEIFilterEnable (QEI1_BASE);
    
    }   //  */
    

  • the Code finally works : )

    I tried the code on a different Pc and now it works ^^.

    Think the Problem was really that one with the Pin unlock.

    Many thanks for your help and time, that helped me a lot. : )