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.

EK-TM4C123GXL: Software issue getting the on-board switch to work

Part Number: EK-TM4C123GXL

I'm trying to write the C code that will program my board to function as follows: the on-board LEDs will alternate between 1) red, 2) blue, 3) green, 4) cycle red-blue-green. This alternation occurs when SW1 is pressed. So if SW1 is pressed the LED turns red and toggles. If it is pressed again it turns blue and toggles, and so on. For testing purposes, I have the code set-up to alternate between 1), 2), and 3) and back with each press of SW1. The issue I am having is that whenever I press the button, nothing happens; the LED is stuck at red and I can't see what the issue is.

// 1. Pre-processor Directives Section
// Constant declarations to access port registers using 
// symbolic names instead of addresses
#include "TExaS.h"
#define GPIO_PORTF_DATA_R       (*((volatile unsigned long *)0x400253FC))
#define GPIO_PORTF_DIR_R        (*((volatile unsigned long *)0x40025400))
#define GPIO_PORTF_AFSEL_R      (*((volatile unsigned long *)0x40025420))
#define GPIO_PORTF_PUR_R        (*((volatile unsigned long *)0x40025510))
#define GPIO_PORTF_DEN_R        (*((volatile unsigned long *)0x4002551C))
#define GPIO_PORTF_LOCK_R       (*((volatile unsigned long *)0x40025520))
#define GPIO_PORTF_CR_R         (*((volatile unsigned long *)0x40025524))
#define GPIO_PORTF_AMSEL_R      (*((volatile unsigned long *)0x40025528))
#define GPIO_PORTF_PCTL_R       (*((volatile unsigned long *)0x4002552C))
#define SYSCTL_RCGC2_R          (*((volatile unsigned long *)0x400FE108))

// 2. Declarations Section
//   Global Variables
unsigned long In;  // input from PF4
unsigned long Out; // outputs to PF3,PF2,PF1 (multicolor LED)

//   Function Prototypes
void PortF_Init(void);
void Delay(void);
void EnableInterrupts(void);

// 3. Subroutines Section
// MAIN: Mandatory for a C Program to be executable
int main(void){    
	TExaS_Init(SW_PIN_PF40,LED_PIN_PF321); // this initializes the TExaS grader lab 2    
  EnableInterrupts();  // The grader uses interrupts
	PortF_Init();		// Call initialization of port F
	GPIO_PORTF_DATA_R      = 0x02;    // start LED at red
	while(1){
		In = GPIO_PORTF_DATA_R & 0x11;    // read switches into In
		
    if(In == 0x01 && GPIO_PORTF_DATA_R == 0x02){ // 0 - SW1 is pressed, 1 - SW2 not pressed | LED == red
      GPIO_PORTF_DATA_R    = 0x04;    // change LED to blue
		}
		else if(In == 0x01 && GPIO_PORTF_DATA_R == 0x04){ // SW1 is pressed and LED is blue
			GPIO_PORTF_DATA_R    = 0x08;    // change LED to green
		}
		else if(In == 0x01 && GPIO_PORTF_DATA_R == 0x08){ // SW1 is pressed and LED is green
      GPIO_PORTF_DATA_R    = 0x02;    // LED returns to red
    }
  }
}

// Subroutine to initialize port F pins for input and output
// PF4 is input SW1
// PF3,PF2,PF1 are outputs to the LED
// Notes: These five pins are connected to hardware on the LaunchPad
void PortF_Init(void){ volatile unsigned long delay;
  SYSCTL_RCGC2_R |= 0x00000020;     // enable F's clock
  delay = SYSCTL_RCGC2_R;           // delay
  GPIO_PORTF_LOCK_R = 0x4C4F434B;   // unlock PortF PF0  
  GPIO_PORTF_CR_R = 0x1F;           // allow changes to PF4-0       
  GPIO_PORTF_AMSEL_R &= ~0x1F;      // disable analog function
  GPIO_PORTF_PCTL_R &= ~0x000FFFFF;   // GPIO clear bit PCTL  
  GPIO_PORTF_DIR_R |= 0x0E;         // enable PF3,PF2,PF1 output 
	GPIO_PORTF_DIR_R &= ~0x11;        // disable PF4, PF0 input   
  GPIO_PORTF_AFSEL_R &= ~0x1F;      // no alternate function
  GPIO_PORTF_PUR_R = 0x11;          // enable pullup resistors on PF4, PF0       
  GPIO_PORTF_DEN_R |= 0x1F;         // enable digital pins PF4-PF0        
}
// Color    LED(s) PortF
// dark     ---    0
// red      R--    0x02
// blue     --B    0x04
// green    -G-    0x08
// yellow   RG-    0x0A
// sky blue -GB    0x0C
// white    RGB    0x0E
// pink     R-B    0x06

// Subroutine to wait 0.1 sec
// Inputs: None
// Outputs: None
// Notes: ...
void Delay(void){unsigned long volatile time;
  time = 727240*200/91;  // 0.1sec
  while(time){
		time--;
  }
}

  • Hi,

      When you press the switch with your human finger, the switch will stay ON for quite some time. In addition, even when you release the switch, the switch is going to bounce. What you might think as one press, it can actually be recognized as multiple presses by the MCU. You can use the scope to observe the switch and see what happens. What you need is a de-bouncer. You can implement that in software. Just do some Google search. Here is one example. 

    https://reference.digilentinc.com/learn/microprocessor/tutorials/debouncing-via-software/start#:~:text=Software%20debouncing%20is%20accomplished%20by,whether%20consecutive%20samples%20are%20received.

  • It's not that. I did some re-coding and debugging. Now when I press the on-board switch, the first IF-statement is entered as it is intended. The issue I found is with the next IF and subsequent IF-ELSE-statement: they are skipped. Even though GPIO_PORTF_DATA_R = 0x02, the " if (((GPIO_PORTF_DATA_R&0x02) == 1)) " is returning false and therefore is passed. I don't see why it is doing this.

    // 1. Pre-processor Directives Section
    // Constant declarations to access port registers using 
    // symbolic names instead of addresses
    #include "TExaS.h"
    #define GPIO_PORTF_DATA_R       (*((volatile unsigned long *)0x400253FC))
    #define GPIO_PORTF_DIR_R        (*((volatile unsigned long *)0x40025400))
    #define GPIO_PORTF_AFSEL_R      (*((volatile unsigned long *)0x40025420))
    #define GPIO_PORTF_PUR_R        (*((volatile unsigned long *)0x40025510))
    #define GPIO_PORTF_DEN_R        (*((volatile unsigned long *)0x4002551C))
    #define GPIO_PORTF_LOCK_R       (*((volatile unsigned long *)0x40025520))
    #define GPIO_PORTF_CR_R         (*((volatile unsigned long *)0x40025524))
    #define GPIO_PORTF_AMSEL_R      (*((volatile unsigned long *)0x40025528))
    #define GPIO_PORTF_PCTL_R       (*((volatile unsigned long *)0x4002552C))
    #define SYSCTL_RCGC2_R          (*((volatile unsigned long *)0x400FE108))
    
    // 2. Declarations Section
    //   Global Variables
    unsigned long In;  // input from PF4
    unsigned long Out; // outputs to PF3,PF2,PF1 (multicolor LED)
    
    //   Function Prototypes
    void PortF_Init(void);
    void Delay(void);
    void EnableInterrupts(void);
    
    // 3. Subroutines Section
    // MAIN: Mandatory for a C Program to be executable
    int main(void){    
    	TExaS_Init(SW_PIN_PF40,LED_PIN_PF321); // this initializes the TExaS grader lab 2    
      EnableInterrupts();  // The grader uses interrupts
    	PortF_Init();		// Call initialization of port F
    	GPIO_PORTF_DATA_R      = 0x02;    // start LED at red
    	
    	while(1) {
    		In = GPIO_PORTF_DATA_R & 0x11;    // read PF4 (SW1) into In
    		
        if (In == 0x01) { // 0 means SW1 is pressed and 1 means SW2 not pressed
    			// ERROR occurring here! Even though GPIO_PORTF_DATA_R = 0x02
    			// IF-statement is not entered - enters ELSE-statement 
    			if (((GPIO_PORTF_DATA_R&0x02) == 1)) {			// LED is currently red
    				GPIO_PORTF_DATA_R = 0x04;									// change LED to blue
    			}
    			else if (((GPIO_PORTF_DATA_R&0x04) == 1)) {	// LED is currently blue
    				GPIO_PORTF_DATA_R = 0x08;									// change LED to green
    			}
    			else {
    				GPIO_PORTF_DATA_R = 0x02;									// change LED back to red
    			}
    		}
    		else { // test
    			GPIO_PORTF_DATA_R = GPIO_PORTF_DATA_R ^ 0x02; // toggle LED on/off
    			Delay(); // slow down toggling 
    		}
      }
    }
    
    // Subroutine to initialize port F pins for input and output
    // PF4 is input SW1
    // PF3,PF2,PF1 are outputs to the LED
    // Notes: These five pins are connected to hardware on the LaunchPad
    void PortF_Init(void){ volatile unsigned long delay;
      SYSCTL_RCGC2_R |= 0x00000020;     // enable F's clock
      delay = SYSCTL_RCGC2_R;           // delay
      GPIO_PORTF_LOCK_R = 0x4C4F434B;   // unlock PortF PF0  
      GPIO_PORTF_CR_R = 0x1F;           // allow changes to PF4-1       
      GPIO_PORTF_AMSEL_R &= ~0x1F;      // disable analog function
      GPIO_PORTF_PCTL_R &= ~0x000FFFFF;   // GPIO clear bit PCTL  
      GPIO_PORTF_DIR_R |= 0x0E;         // enable PF3,PF2,PF1 output 
    	GPIO_PORTF_DIR_R &= ~0x11;        // disable PF4 input   
      GPIO_PORTF_AFSEL_R &= ~0x1F;      // no alternate function
      GPIO_PORTF_PUR_R = 0x11;          // enable pullup resistors on PF4       
      GPIO_PORTF_DEN_R |= 0x1F;         // enable digital pins PF4-PF1        
    }
    // Color    LED(s) PortF
    // dark     ---    0
    // red      R--    0x02
    // blue     --B    0x04
    // green    -G-    0x08
    // yellow   RG-    0x0A
    // sky blue -GB    0x0C
    // white    RGB    0x0E
    // pink     R-B    0x06
    
    // Subroutine to wait 0.1 sec
    void Delay(void){unsigned long volatile time;
      time = 727240*200/91;  // 0.1sec
      while(time){
    		time--;
      }
    }

  • When you don't press the switch, the RED LED is toggling according to your code, correct? When you press the switch, how can you be sure the RED LED is still ON. What if at the moment you press the SW1, the RED LED happens to be OFF. In this case the "if" statement is not taken, right?

  • I was able to get it to work, at least for the testing purposes. With the code provided below, I am able to alternate and hold between the three colors with each push of SW1. I think I can continue to build from there.

    #include "TExaS.h"
    #define GPIO_PORTF_DATA_R       (*((volatile unsigned long *)0x400253FC))
    #define GPIO_PORTF_DIR_R        (*((volatile unsigned long *)0x40025400))
    #define GPIO_PORTF_AFSEL_R      (*((volatile unsigned long *)0x40025420))
    #define GPIO_PORTF_PUR_R        (*((volatile unsigned long *)0x40025510))
    #define GPIO_PORTF_DEN_R        (*((volatile unsigned long *)0x4002551C))
    #define GPIO_PORTF_LOCK_R       (*((volatile unsigned long *)0x40025520))
    #define GPIO_PORTF_CR_R         (*((volatile unsigned long *)0x40025524))
    #define GPIO_PORTF_AMSEL_R      (*((volatile unsigned long *)0x40025528))
    #define GPIO_PORTF_PCTL_R       (*((volatile unsigned long *)0x4002552C))
    #define SYSCTL_RCGC2_R          (*((volatile unsigned long *)0x400FE108))
    
    // 2. Declarations Section
    //   Global Variables
    unsigned long In;  // input from PF4
    unsigned long Out; // outputs to PF3,PF2,PF1 (multicolor LED)
    
    //   Function Prototypes
    void PortF_Init(void);
    void Delay(void);
    void EnableInterrupts(void);
    
    // 3. Subroutines Section
    // MAIN: Mandatory for a C Program to be executable
    int main(void){    
    	TExaS_Init(SW_PIN_PF40,LED_PIN_PF321); // this initializes the TExaS grader lab 2    
      EnableInterrupts();  // The grader uses interrupts
    	PortF_Init();		// Call initialization of port F
    	GPIO_PORTF_DATA_R      = 0x02;    // start LED at red
    	
    	while(1) {
    		In = GPIO_PORTF_DATA_R & 0x11;    // read PF4 (SW1) into In
    		
        if (In == 0x01) { // 0 means SW1 is pressed and 1 means SW2 not pressed
    			if (((GPIO_PORTF_DATA_R&0x02) == 0x02)) {			// LED is currently red
    				GPIO_PORTF_DATA_R = 0x04;									// change LED to blue
    				Delay();
    			}
    			else if (((GPIO_PORTF_DATA_R&0x04) == 0x04)) {	// LED is currently blue
    				GPIO_PORTF_DATA_R = 0x08;									// change LED to green
    				Delay();
    			}
    			else {
    				GPIO_PORTF_DATA_R = 0x02;									// change LED back to red
    				Delay();
    			}
    		}
    		else {
    			if (((GPIO_PORTF_DATA_R&0x02) == 0x02)) {
    				GPIO_PORTF_DATA_R = 0x02; // hold LED on
    			}
    			else if (((GPIO_PORTF_DATA_R&0x04) == 0x04)) {
    				GPIO_PORTF_DATA_R = 0x04;
    			}
    			else if (((GPIO_PORTF_DATA_R&0x08) == 0x08)) {
    				GPIO_PORTF_DATA_R = 0x08;
    			}
    		}
      }
    }
    
    // Subroutine to initialize port F pins for input and output
    // PF4 is input SW1
    // PF3,PF2,PF1 are outputs to the LED
    // Notes: These five pins are connected to hardware on the LaunchPad
    void PortF_Init(void){ volatile unsigned long delay;
      SYSCTL_RCGC2_R |= 0x00000020;     // enable F's clock
      delay = SYSCTL_RCGC2_R;           // delay
      GPIO_PORTF_LOCK_R = 0x4C4F434B;   // unlock PortF PF0  
      GPIO_PORTF_CR_R = 0x1F;           // allow changes to PF4-1       
      GPIO_PORTF_AMSEL_R &= ~0x1F;      // disable analog function
      GPIO_PORTF_PCTL_R &= ~0x000FFFFF;   // GPIO clear bit PCTL  
      GPIO_PORTF_DIR_R |= 0x0E;         // enable PF3,PF2,PF1 output 
    	GPIO_PORTF_DIR_R &= ~0x11;        // disable PF4 input   
      GPIO_PORTF_AFSEL_R &= ~0x1F;      // no alternate function
      GPIO_PORTF_PUR_R = 0x11;          // enable pullup resistors on PF4       
      GPIO_PORTF_DEN_R |= 0x1F;         // enable digital pins PF4-PF1        
    }
    // Color    LED(s) PortF
    // dark     ---    0
    // red      R--    0x02
    // blue     --B    0x04
    // green    -G-    0x08
    // yellow   RG-    0x0A
    // sky blue -GB    0x0C
    // white    RGB    0x0E
    // pink     R-B    0x06
    
    // Subroutine to wait 0.1 sec
    void Delay(void){unsigned long volatile time;
      time = 727240*200/91;  // 0.1sec
      while(time){
    		time--;
      }
    }
    



  • I was able to get the board to work as described in my initial post, but the code is a bit tacky and I was wondering if you could offer improvements based off of what I have. This would be especially helpful since I have to translate the entire thing to assembly

    #include "TExaS.h"
    #define GPIO_PORTF_DATA_R       (*((volatile unsigned long *)0x400253FC))
    #define GPIO_PORTF_DIR_R        (*((volatile unsigned long *)0x40025400))
    #define GPIO_PORTF_AFSEL_R      (*((volatile unsigned long *)0x40025420))
    #define GPIO_PORTF_PUR_R        (*((volatile unsigned long *)0x40025510))
    #define GPIO_PORTF_DEN_R        (*((volatile unsigned long *)0x4002551C))
    #define GPIO_PORTF_LOCK_R       (*((volatile unsigned long *)0x40025520))
    #define GPIO_PORTF_CR_R         (*((volatile unsigned long *)0x40025524))
    #define GPIO_PORTF_AMSEL_R      (*((volatile unsigned long *)0x40025528))
    #define GPIO_PORTF_PCTL_R       (*((volatile unsigned long *)0x4002552C))
    #define SYSCTL_RCGC2_R          (*((volatile unsigned long *)0x400FE108))
    
    // 2. Declarations Section
    //   Global Variables
    unsigned long In;  // input from PF4
    unsigned long Out; // outputs to PF3,PF2,PF1 (multicolor LED)
    
    //   Function Prototypes
    void PortF_Init(void);
    void Delay(void);
    void EnableInterrupts(void);
    
    // 3. Subroutines Section
    // MAIN: Mandatory for a C Program to be executable
    int main(void){    
    	TExaS_Init(SW_PIN_PF40,LED_PIN_PF321); // this initializes the TExaS grader lab 2    
      EnableInterrupts();  // The grader uses interrupts
    	PortF_Init();		// Call initialization of port F
    	GPIO_PORTF_DATA_R      = 0x02;    // start LED at red
    	
    	while(1) {
    		In = GPIO_PORTF_DATA_R & 0x11;    // read PF4 (SW1) into In
    		
        if (In == 0x01) { // 0 means SW1 is pressed and 1 means SW2 not pressed
    			if (((GPIO_PORTF_DATA_R&0x02) == 0x02)) {			// LED is currently red
    				GPIO_PORTF_DATA_R = 0x04;									// change LED to blue
    				Delay();
    			}
    			else if (((GPIO_PORTF_DATA_R&0x04) == 0x04)) {	// LED is currently blue
    				GPIO_PORTF_DATA_R = 0x08;									// change LED to green
    				Delay();
    			}
    			else if (((GPIO_PORTF_DATA_R&0x08) == 0x08)) {	// LED is currently green
    				// cycle the colors for this method
    				In = 0x11;
    				while(In == 0x11) {
    					GPIO_PORTF_DATA_R = 0x02;
    					Delay();
    					GPIO_PORTF_DATA_R = 0x04;
    					Delay();
    					GPIO_PORTF_DATA_R = 0x08;
    					Delay();
    					In = GPIO_PORTF_DATA_R & 0x11;
    				}
    				GPIO_PORTF_DATA_R = 0x02; // "return" to method 1
    				Delay();
    			}
    			else { // complete IF-ELSE
    				GPIO_PORTF_DATA_R = 0x02;
    			}
    		}
    		// blink LEDs depending on which method we are in
    		else {
    			if (((GPIO_PORTF_DATA_R&0x02) == 0x02)) {
    				while(In == 0x11) {
    					GPIO_PORTF_DATA_R = GPIO_PORTF_DATA_R^0x02; // hold LED on
    					Delay();
    					In = GPIO_PORTF_DATA_R & 0x11;    // read PF4 (SW1) into In
    				}
    				GPIO_PORTF_DATA_R = 0x02;
    			}
    			else if (((GPIO_PORTF_DATA_R&0x04) == 0x04)) {
    				while(In == 0x11) {
    					GPIO_PORTF_DATA_R = GPIO_PORTF_DATA_R^0x04; // hold LED on
    					Delay();
    					In = GPIO_PORTF_DATA_R & 0x11;
    				}
    				GPIO_PORTF_DATA_R = 0x04;
    			}
    			else if (((GPIO_PORTF_DATA_R&0x08) == 0x08)) {
    				while(In == 0x11) {
    					GPIO_PORTF_DATA_R = GPIO_PORTF_DATA_R^0x08; // hold LED on
    					Delay();
    					In = GPIO_PORTF_DATA_R & 0x11;
    				}
    				GPIO_PORTF_DATA_R = 0x08;
    			}
    		}
      }
    }
    
    // Subroutine to initialize port F pins for input and output
    // PF4 is input SW1
    // PF3,PF2,PF1 are outputs to the LED
    // Notes: These five pins are connected to hardware on the LaunchPad
    void PortF_Init(void){ volatile unsigned long delay;
      SYSCTL_RCGC2_R |= 0x00000020;     // enable F's clock
      delay = SYSCTL_RCGC2_R;           // delay
      GPIO_PORTF_LOCK_R = 0x4C4F434B;   // unlock PortF PF0  
      GPIO_PORTF_CR_R = 0x1F;           // allow changes to PF4-1       
      GPIO_PORTF_AMSEL_R &= ~0x1F;      // disable analog function
      GPIO_PORTF_PCTL_R &= ~0x000FFFFF;   // GPIO clear bit PCTL  
      GPIO_PORTF_DIR_R |= 0x0E;         // enable PF3,PF2,PF1 output 
    	GPIO_PORTF_DIR_R &= ~0x11;        // disable PF4 input   
      GPIO_PORTF_AFSEL_R &= ~0x1F;      // no alternate function
      GPIO_PORTF_PUR_R = 0x11;          // enable pullup resistors on PF4       
      GPIO_PORTF_DEN_R |= 0x1F;         // enable digital pins PF4-PF1        
    }
    // Color    LED(s) PortF
    // dark     ---    0
    // red      R--    0x02
    // blue     --B    0x04
    // green    -G-    0x08
    // yellow   RG-    0x0A
    // sky blue -GB    0x0C
    // white    RGB    0x0E
    // pink     R-B    0x06
    
    // Subroutine to wait 0.1 sec
    void Delay(void){unsigned long volatile time;
      time = 727240*200/91;  // 0.1sec
      while(time){
    		time--;
      }
    }
    

  • To do it right, you need to employ interrupt to detect the edge transition when the switch is pressed. You need to also implement the debouncer I mentioned in the first reply for which you rejected my answer. The Pushbutton switch has a mechanical part to it and often generates spurious open/close transitions when pressed. These transitions may be read as multiple presses and fool the program. As I mentioned when you press the switch using a human finger, the elapsed time of the contact may last for milli seconds. Your loop polling the state of the GPIO pin may only last in the mocr0-seconds. This means when the switch is pressed and while the contact is still active, the loop may have run many many times. You can use the scope to observe the duration of the switch contact. After you release the switch, the mechanical switch will bounce and could create multiple ON/OFF unexpected transitions as if you press multiple times. This is why I suggested you to implement a debouncer. You can search for debouncer or discuss with your professor/TA if there is any merit to handle these situations. It is your choice to make for your project. I have already suggested in my first reply.