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/EK-TM4C123GXL: Trouble with assigning I/O to ports

Part Number: EK-TM4C123GXL

Tool/software: Code Composer Studio

I am working with a TM4C lunchpad and need to assign Ports E and B as inputs and outputs to be able to control a simple traffic light built on a breadboard. There are three LEDs on the board as well as two buttons: when btn1 is pressed, the LEDs on alternate between red - green - yellow - back to red, when btn2 is pressed, the current LED that is on begins to flash, when both are pressed, the LEDs cycle. I've tried using other ports and have had success (that is how I know it is not a hardware issue), but the specified requirements are for Ports B[2:0] as outputs and E[1:0] as inputs, and I can't see what I'm doing wrong in the code. When I upload the code to the board, the only functioning component is the red led on the breadboard (which is the initial state of the FSM), but clicking either button does nothing. Note: Port B[2:0] is connected to the anode of it's respective LED (2 - red, 1 - yellow, 0 - green) and the cathode of each is connected to it's own resistor which is connected to ground.

    #include <stdint.h>
    #include "tm4c123gh6pm.h"

    // ***** 1. Assign switches *****
    #define LIGHT                    (*((volatile unsigned long *)0x4000501C)) // Port B Pins 2, 1, 0
	    // Port B base: 4000.5000 + x0004 (bit 0: 4*(2^0)) + x0008 (bit 1: 4*(2^1)) = x 0010 (bit 2: 4*(2^2))
    #define SENSOR                   (*((volatile unsigned long *)0x4002400C)) // Port E Pins 0 and 1
	// Port E base: 4002.4000 + x0004 (bit 0: 4*(2^0)) + x0008 (bit 1: 4*(2^1))

    // ***** 2. Pre-processor Directives Section *****
    //Port B used for LEDs
    #define GPIO_PORTB_DATA_R       (*((volatile unsigned long *)0x400053FC))
    #define GPIO_PORTB_DIR_R        (*((volatile unsigned long *)0x40005400))
    #define GPIO_PORTB_AFSEL_R      (*((volatile unsigned long *)0x40005420))
    #define GPIO_PORTB_DEN_R        (*((volatile unsigned long *)0x4000551C))
    #define GPIO_PORTB_AMSEL_R      (*((volatile unsigned long *)0x40005528))
    #define GPIO_PORTB_PCTL_R       (*((volatile unsigned long *)0x4000552C))

    //Port E used for switches
    #define GPIO_PORTE_DATA_R       (*((volatile unsigned long *)0x400243FC))
    #define GPIO_PORTE_DIR_R        (*((volatile unsigned long *)0x40024400))
    #define GPIO_PORTE_AFSEL_R      (*((volatile unsigned long *)0x40024420))
    #define GPIO_PORTE_DEN_R        (*((volatile unsigned long *)0x4002451C))
    #define GPIO_PORTE_AMSEL_R      (*((volatile unsigned long *)0x40024528))
    #define GPIO_PORTE_PCTL_R       (*((volatile unsigned long *)0x4002452C))
	
    #define SYSCTL_RCGC2_R          (*((volatile unsigned long *)0x400FE108))

    // ***** 3. Global Declarations Section *****
    // FUNCTION PROTOTYPES: Each subroutine defined
    void PortB_Init(void);
    void PortE_Init(void);
    void DisableInterrupts(void); // Disable interrupts
    void EnableInterrupts(void);  // Enable interrupts
    void Delay(unsigned int amp);

    // ***** 4. Subroutines Section *****
    // Data structure for FSM
    struct State {
	    uint32_t Out;
	    uint32_t Time;
	    uint32_t Next[4]; // 2 inputs, four combinations
    };
    typedef const struct State STyp;
    #define rOn   	0
    #define rOff    1
    #define yOn     2
    #define yOff    3
    #define gOn		4
    #define gOff	5
    STyp FSM[6]={
	           // 00  01   10   11
     {0x04,100, {rOn,gOn,rOff,rOff}},  // State rOn | 0x08 = PortB Pin 2 ON
     {0x00,100, {rOn,rOn,rOn, gOn}},	 // State rOff
     {0x02,100, {yOn,rOn,yOff,yOff}},  // State yOn | 0x02 = PortB Pin 1 ON
     {0x00,100, {yOn,yOn,yOn, rOn}},	 // State yOff
     {0x01,100, {gOn,yOn,gOff,gOff}},  // state gOn | 0x40 = PortB Pin 0 ON
     {0x00,100, {gOn,gOn,gOn, yOn}}	   // state gOff
    };

    int main(void){ 
	    uint8_t cs;     // Index to the current state 
        uint8_t Input;	// Index to the inputs
	
	    // Initialize GPIO on Ports B, E
	    PortB_Init();        // Call initialization of port PB0 PB1 PB2
	    PortE_Init();        // Call initialization of port PE0 PE1
        EnableInterrupts();  // The grader uses interrupts
	
	    // Initial state: Red LED lit
	    // Set delay for 100ms
	    Delay(10);
	    cs = rOn;  // Assign current state to be red on
	 
	    while(1){
		    LIGHT = FSM[cs].Out;
		    Delay(FSM[cs].Time);
		    Input = SENSOR >> 2;
		    cs = FSM[cs].Next[Input];		
       }
    }

    void PortE_Init(void){ volatile unsigned long delay; // Port E INPUT
        SYSCTL_RCGC2_R |= 0x00000010;      // E clock
        delay = SYSCTL_RCGC2_R;            // delay         
        GPIO_PORTE_AMSEL_R &= ~0x03;       // disable analog function  
	    GPIO_PORTE_PCTL_R  &= ~0x000000FF; // GPIO clear PCTL bits for PE1 and PE0
        GPIO_PORTE_DIR_R   &= ~0x03;       // PE1 and PE0 (turn off inputs) 
        GPIO_PORTE_AFSEL_R &= ~0x03;       // no alternate function       
        GPIO_PORTE_DEN_R   |=  0x03;       // enable digital pins PE1 and PE0        
    }

    void PortB_Init(void){ volatile unsigned long delay; // Port B OUTPUT
        SYSCTL_RCGC2_R |= 0x00000002;      // B clock
        delay = SYSCTL_RCGC2_R;            // delay 	
        GPIO_PORTB_AMSEL_R &= ~0x07;       // disable analog function
	    GPIO_PORTB_PCTL_R  &= ~0x00000FFF; // GPIO clear PCTL bits for PB2, PB1, and PB0
        GPIO_PORTB_DIR_R   |=  0x07;       // PB2, PB1, and PB0 (turn on/SET outputs)	
        GPIO_PORTB_AFSEL_R &= ~0x07;       // no alternate function       
        GPIO_PORTB_DEN_R   |=  0x07;       // enable digital pins PB2, PB1, and PB0        
    }

    void Delay(unsigned int amp) {
	    volatile uint32_t time;
        time = ((727240*200/91)*2/1000) * amp;  
        while(time) {
            time--;
        }
    }

  • Hello,

    Jesse J said:
    I can't see what I'm doing wrong.

    Nor can your (remote) helpers - even further from your board assemblies.   

    Might it ease your helpers' ability to assist if you'd:

    • describe with (some) detail what works - and what does not.    ("Can't see" provides no usable insight!)
    • it is assumed that your "breadboard was unchanged" between (past) working & present.   (degree/extent of non-working "unknown!")
    • your (likely) instructor dictated "Direct Register" coding places extreme demands upon (both) yourself & ALL helpers.   Every register must be deeply examined - so many are "in play" - & a single incorrect bit may "undo" 100 correct ones!
    • an alternative exists - vendor's detailed "API" - which is long "Tested, Extensive & Far Simpler."    (everything which your "DRM" code is NOT - btw!)
    • some claim that "DRM" code aids learning - yet repeated visits here - by so many - loudly disputes such (wishful thinking.)    
    • should not such "instructors" grant (some) attention to, "Problem Solving, Coding Speed & Efficiency, & Grooming students to exploit (all) available Methods?"    Especially those, "Proven, Fast, & Enhancing?"

    It is assumed that the 'instructor" made no mention of "KISS" - as well.   Adopting the proven "KISS" methodology would have seen you:

    • make ONLY one connection change at a time  (to your (past) working implementation - so it meets your "new" Port B & E directive)
    • then change ONLY the code which reflects that change
    • immediately then test those 2 changes (as they work as a pair)
    • only if successful - repeat for a 2nd connection & code change - and so on...
    • should this new, methodical method (possibly) stumble - check your chosen Port-Pin for (any/all) restrictions - and/or "special handling" demands.    (MCU manual lists these ... too often "missed" by students "exhausted" by the unnecessary & excessive demands imposed by DRM  ... "Destructive, Regimented, Myopic!")  [credit cb1]

    A final, "Dagger to the heart of instructor dictated DRM" - nothing prevents student users from employing (BOTH) the API (for efficiency) AND MCU manual's "Key Register Presentation" together!    Such fact has been little noted (i.e. possibly never noted) by other than the (uber resourceful) "cb1-crüe!"

    Rejecting "KISS" - Breaking down a working system - & then starting over "en masse" - denies you the highly valuable "A vs. B" comparative circuit & code analysis - which is sure to, "Speed, Ease & Enhance" your results.   And most likely provides "REAL LEARNING" - which the outmoded & highly restrictive "DRM" method (claims) - yet SO VERY RARELY delivers!

  • Hi,

      PB[3:2] are special. You need to unlock them before you can change to GPIO. The default is I2C. 

     To make PB[3] as a GPIO you will do something like below. 

    HWREG(GPIO_PORTB_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY;
    HWREG(GPIO_PORTB_BASE + GPIO_O_CR) = 0x08;
    HWREG(GPIO_PORTB_BASE + GPIO_O_AFSEL) |= 0x08;

  • Hello Charles,

    Good find - do note that the earlier arriving post advised of the requirement to, "Search for & attend to those MCU pins which may require "special handling."

    to your code guidance:

    Charles Tsai said:
    HWREG(GPIO_PORTB_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY;
    HWREG(GPIO_PORTB_BASE + GPIO_O_CR) = 0x08;
    HWREG(GPIO_PORTB_BASE + GPIO_O_AFSEL) |= 0x08;

    Might the middle line of code "benefit" via the use of, "Logical Operators" (which will impact (only) the targeted Port's Pin) rather than the method shown - which may "unwantedly alter" the values of other Port Pins?

  • Hi cb1,

      Yes, I agree with the logical operator to be more robust. Ralph also pointed me out there is no need to unlock PB[3:2] but rather to select for GPIO mode as PB[3:2] is in I2C function by default. 

  • Hi Charles,

    It is easy to miss that "a" advisory (placed beneath the chart) - which unlike your (proper & eventful) notation - would prove, "Far more notable via "bold or color" highlight.   "Camouflage" appears "not" the optimal means to insure message delivery...

    And Charles (& others) should it not be "well noted" that the KISS technique staff suggested (i.e. gradually effect one simple change from poster's "working implementation" at a time - and carefully "test & observe.")    Such would "immediately" detect the issues upon PB2 & PB3 - which likely alerts poster to check for "special handling."   (as identified first - by our group...)

    As always - our team aims to:

    • identify existing poster/vendor procedural weaknesses
    • suggest an alternative method - which leads to repeated (& far broader) "solution capability!"
    • highly limited (specific) cut n paste correction likely encourages "dependency" - may not optimize poster "Capability & Solution Recognition!"

    Warrants consideration - many would agree...

  • Aren't I already configuring it so that PB[3:2] can be set to GPIO mode by setting GPIO_PORTB_PCTL_R  &= ~0x00000FFF;? I have Port B Pin 2 is connected to my red LED on the breadboard and it turns on when I upload the code to the launchpad. I forgot to mention this when I first asked the question but I have since edited it for clarification. So I think my issue is with Port B [1:0] or possibly E[1:0].

  • I've updated the details in the question, hopefully that clarifies a bit.

  • Refer to the FAQ https://e2e.ti.com/support/microcontrollers/other/f/908/t/695568 note #4. We don't support DRM style of coding. You can look at the source code of the API to see how the registers are programmed. Here is a test program I tried to toggle PB pins. 

    //*****************************************************************************
    //
    // blinky.c - Simple example to blink the on-board LED.
    //
    // Copyright (c) 2012-2017 Texas Instruments Incorporated.  All rights reserved.
    // Software License Agreement
    // 
    // Texas Instruments (TI) is supplying this software for use solely and
    // exclusively on TI's microcontroller products. The software is owned by
    // TI and/or its suppliers, and is protected under applicable copyright
    // laws. You may not combine this software with "viral" open-source
    // software in order to form a larger program.
    // 
    // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
    // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
    // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
    // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
    // DAMAGES, FOR ANY REASON WHATSOEVER.
    // 
    // This is part of revision 2.1.4.178 of the EK-TM4C123GXL Firmware Package.
    //
    //*****************************************************************************
    
    #include <stdint.h>
    #include <stdbool.h>
    #include "inc/hw_memmap.h"
    #include "driverlib/debug.h"
    #include "driverlib/gpio.h"
    #include "driverlib/sysctl.h"
    
    //*****************************************************************************
    //
    //! \addtogroup example_list
    //! <h1>Blinky (blinky)</h1>
    //!
    //! A very simple example that blinks the on-board LED using direct register
    //! access.
    //
    //*****************************************************************************
    
    //*****************************************************************************
    //
    // The error routine that is called if the driver library encounters an error.
    //
    //*****************************************************************************
    #ifdef DEBUG
    void
    __error__(char *pcFilename, uint32_t ui32Line)
    {
        while(1);
    }
    #endif
    
    //*****************************************************************************
    //
    // Blink the on-board LED.
    //
    //*****************************************************************************
    int
    main(void)
    {
        volatile uint32_t ui32Loop;
    
        //
        // Enable the GPIO port that is used for the on-board LED.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    
        //
        // Check if the peripheral access is enabled.
        //
        while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOB))
        {
        }
    
        //
        // Enable the GPIO pin PB[2:0].  Set the direction as output, and
        // enable the GPIO pin for digital function.
        //
        GPIOPinTypeGPIOOutput(GPIO_PORTB_BASE, GPIO_PIN_2 | GPIO_PIN_1 | GPIO_PIN_0);
    
        //
        // Loop forever.
        //
        while(1)
        {
            //
            // Set the pins high.
            //
            GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_2 | GPIO_PIN_1 | GPIO_PIN_0, GPIO_PIN_2 | GPIO_PIN_1 | GPIO_PIN_0);
    
            //
            // Delay for a bit.
            //
            for(ui32Loop = 0; ui32Loop < 200000; ui32Loop++)
            {
            }
    
            //
            // Set the pins low.
            //
            GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_2 | GPIO_PIN_1 | GPIO_PIN_0, 0x0);
    
            //
            // Delay for a bit.
            //
            for(ui32Loop = 0; ui32Loop < 200000; ui32Loop++)
            {
            }
        }
    }
    

  • Thank you for your help. I looked at the code you uploaded and it was a bit difficult for me to follow because I am learning a different method, but I was able to figure out what was throwing my code off. If you reffer to the code posed above, I had to remove the following portion of code minus defining the clock register. I'm not entirely sure why including or not including that made a difference because my understanding was that that section was just defining the ports, but it's working now.

    // THIS PORTION WAS REMOVED
    // ***** 2. Pre-processor Directives Section *****
    //Port B used for LEDs
    #define GPIO_PORTB_DATA_R       (*((volatile unsigned long *)0x400053FC))
    #define GPIO_PORTB_DIR_R        (*((volatile unsigned long *)0x40005400))
    #define GPIO_PORTB_AFSEL_R      (*((volatile unsigned long *)0x40005420))
    #define GPIO_PORTB_DEN_R        (*((volatile unsigned long *)0x4000551C))
    #define GPIO_PORTB_AMSEL_R      (*((volatile unsigned long *)0x40005528))
    #define GPIO_PORTB_PCTL_R       (*((volatile unsigned long *)0x4000552C))
    
     
    //Port E used for switches
    #define GPIO_PORTE_DATA_R       (*((volatile unsigned long *)0x400243FC))
    #define GPIO_PORTE_DIR_R        (*((volatile unsigned long *)0x40024400))
    #define GPIO_PORTE_AFSEL_R      (*((volatile unsigned long *)0x40024420))
    #define GPIO_PORTE_DEN_R        (*((volatile unsigned long *)0x4002451C))
    #define GPIO_PORTE_AMSEL_R      (*((volatile unsigned long *)0x40024528))
    #define GPIO_PORTE_PCTL_R       (*((volatile unsigned long *)0x4002452C))
    
    #define SYSCTL_RCGC2_R          (*((volatile unsigned long *)0x400FE108))

  • Hi,

      I'm not sure which line (or directives) you remove to make it work? In any case, glad that your problem is solved. As you can see in the test program I sent, using API is a much much simpler way to develop your project quickly. Perhaps your school wants you learn how each register operates in the MCU but that is not how people develop software in the industry. 

  • Hi Charles,

    Charles Tsai said:
    but that is not how people develop software in the industry. 

    Are you "not" being a "bit harsh here?"   

    Might poster's "instructor:"

    • embrace & (still) drive his/her Model T
    • communicate text messages via telegraph
    • maintain the "rotary, pulse dialer" version of land-line-locked phone
    • have deliberately "turned his/her back" upon far more advantaged & productive methods (i.e. the API) - which via substantial "time/effort savings" - Far better enable students to "experience, analyze & extend" their "Problem Solving Abilities" - vital to employment capture (and continuation!)   

    Such "deep dives" into arcane Registers - and 32 (often) unique Register Bits - will prove as "lasting" as, "Jay-Walking Across NYC's Fifth Avenue on foot - blind-folded - during (pre virus) Rush Hour!"

    The market-place is Global - he who arrives last (i.e. DRM users) quickly 'join the ranks' of those (failed/flattened) 5th Ave."crossing victims!"     After a month or so passes - any/all "learning" will prove as "fleeting" as a $100 bill - "dragged thru a trailer park."    (Staff/I are told...)

  • To be fair to the OP and his instructor

    • the arrival of a vendor's API that is both usable (at the correct level of abstraction) and reasonably bug free is a relatively new condition
    • Someone has to make the API
    • Not all micros have such an API, some don't even have compilers.

    The instructor may be trying to cover as much ground as possible. For the instructors purposes an environment in which it is easier to make and hopefully learn from low level mistakes may be far more useful than an environment that avoids low level issues. Without knowing the aim of the course it's hard to know whether the instructor's approach is the best one. Teaching only high level APIs could leave a student under-prepared for future work.

    Robert

  • Greetings Monsieur,

    Earlier posting by crack crüe (here)  02 Apr, 02:30   Anticipated (likely overcame) most of your thrust - did it not?

    cb1_mobile said:
    A final, "Dagger to the heart of instructor dictated DRM" - nothing prevents student users from employing (BOTH) the API (for efficiency) AND MCU manual's "Key Register Presentation" together!    Such fact has been little noted (i.e. possibly never noted) by other than the (uber resourceful) "cb1-crüe!"

    If (really) such "instructors" embraced their clearly flawed (singular) approach - would not (they) be properly available - to 'Rescue their multitudes - regularly & predictably - washing-up' upon these (API-rocked) shores?

    In addition - has not certain of your Engineering/Programming success resulted from your, "Curiosity & Drive to Discover a (possibly) superior means/method or path?"   Has that been (efficiently) encouraged by poster's "instructor?"    Likely not - crüe here well described "KISS" as an alternative means for poster "Self-Learning."   No (zero) interest nor comment arose from poster - there ARE "long-term implications" (ALL Negative) for such, "Lack of such exploratory curiosity & zeal!"

    The "one & only one" direction proves beyond flawed - its "possible hidden intent" (likely) deserves investigation...