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.

Problem reading input from two GPIO pins reliably



Hi, I have two wheel encoders, giving 5v ouput redirected through 5V/3.3V logic converter, attached to launchpad's pins PD2 and PD6. The problem is that as long as I rotate just one wheel everything works OK, i.e., I got the signal only from the GPIO pin corresponding to wheel rotated. However when I start to rotate the other wheel (the preceding wheel not rotated) I got the pin interrupt correctly, but when I read the register of portD, the result is that that both PD2 and PD6 are triggered, even only one of the two should have been triggered. So for some reason it seems that the PORT register is not "cleared" between interrupts giving false detection for the other wheel. I posted below the relevant parts of the code, which hopefully explain the problem more. I would be thankful for any suggestions solving the problem (ps. I'm actually using the older M3 series board, but hopefully my question applies also here).

#define input1 GPIO_PIN_2
#define input2  GPIO_PIN_6

void init_peripherals(){
  SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN);
  SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
  SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
}

void init_outputs(){
  GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3);
}

void init_inputs(){

  GPIODirModeSet(GPIO_PORTD_BASE, input1|input2, GPIO_DIR_MODE_IN);
  GPIOPadConfigSet(GPIO_PORTD_BASE, input1|input2, GPIO_STRENGTH_4MA, GPIO_PIN_TYPE_STD_WPU);
}

void IntGPIOd(void){

	int wheel = 0;

	switch(GPIOPinRead(GPIO_PORTD_BASE , input1 | input2 ) ^ ( input1 | input2 ) ) {
	            case input1:
	            	if(GPIOPinRead(GPIO_PORTF_BASE,GPIO_PIN_1)) {
	            		GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, 0);
	            	} else {
	            		GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, 2);
	            	}
	            	wheel = 0;
	                break;
	            case input2:
	            	if(GPIOPinRead(GPIO_PORTF_BASE,GPIO_PIN_2)) {
	            		GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0);
	            	} else {
	            		GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 4);
	            	}
	            	wheel = 1;
	                break;
	            case input1 | input2:
	            	if(GPIOPinRead(GPIO_PORTF_BASE,GPIO_PIN_3)) {
	            		GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, 0);
	            	} else {
	            		GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, 8);
	            	}
	            	wheel = 2;
	                break;
	}
	GPIOPinIntClear(GPIO_PORTD_BASE, input1 | input2);
	
	unsigned long realtime = seconds_since_init + TimerValueGet(TIMER2_BASE, TIMER_A);
	char message[80];
	int message_len = eb_sprintf(message, "%d %l %d %d\n", 0, realtime, wheel, 1);
	int iter = 0;
	while(iter < message_len) {
		UARTCharPut(UART0_BASE,*(message + iter));
		iter++;
	}
}

  • Hello Nippe,

    How have you configured the 2 GPIO's interrupt detection?
  • Hi, thanks for the reply. I configure the interrupts using the below code and the I add the IntGPIOd  interrupt function to startup.c file at the correct place. If this was what you meant by configuring the interrupt detection?

    void init_interrupts(){
      
      GPIOPinIntEnable(GPIO_PORTD_BASE, input1 | input2);
      IntEnable(INT_GPIOD);
      IntEnable(INT_TIMER2A);
      TimerIntEnable(TIMER2_BASE, TIMER_TIMA_TIMEOUT);
      IntMasterEnable();
      TimerEnable(TIMER2_BASE, TIMER_A);
    
    }

     

  • Hello Nippe

    The Interrupt is being enabled correctly, but what type of interrupt is it, RISING EDGE, FALLING EDGE, BOTH EDGE, LOW LEVEL, HIGH LEVEL?

    Also not a good idea to have a UART print and a while loop in the interrupt handler....

    unsigned long realtime = seconds_since_init + TimerValueGet(TIMER2_BASE, TIMER_A);
    char message[80];
    int message_len = eb_sprintf(message, "%d %l %d %d\n", 0, realtime, wheel, 1);
    int iter = 0;
    while(iter < message_len) {
    UARTCharPut(UART0_BASE,*(message + iter));
    iter++;
    }
  • Hi, many thanks again for replying and guiding me to correct direction. I was able to identify the source of the problem by trying different trigger options for the GPIOIntTypeSet (RISING_EDGE, LOW_LEVEL, etc). The problem was that the encoder is giving continuous signal while the light source is not blogged. For that reason the GPIOPinRead indicates that the pin is high even it did not trigger the interrupt (BOTH_EDGES trigger). I was able to solve the problem simply by using source = GPIOPinIntStatus(GPIO_PORTD_BASE, input1 | input2) and checking whether the source is input1 or input2.

    You also mentioned that using UART print is not recommended in the interrupt handler. I'm not sure how to circumvent this. Should I simply set some global flag indicating new message and also write the message to some global variable in the interrupt handler and then poll that flag in main loop (currently just an empty while) and do the message write in main, or should I not use interrupts at all?
  • Hello Nippe,

    In the interrupt handler a flag must be set. The flag set must then be used in the main program for whaterver purpose you need it to perform and subsequently be cleared.