Smileys Micros - Joystick Program - Init Pin Interrupt

Go To Last Post
12 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
// Demonstrator.c Joystick version

#include "PC_Comm.h"
#include "Demonstrator.h"

// declare global variables
volatile char KEY = 0;
volatile char KEY_VALID = 0;
volatile char ENABLED = 1; // start enabled

void initializer()
{

	// Calibrate the oscillator:
    OSCCAL_calibration();   

	// Initialize the USART
	USARTinit();
	
    // Init port pins
	DDRB |= 0xD8;
    PORTB |= PINB_MASK;
    DDRE = 0x00;
    PORTE |= PINE_MASK;

    // Enable pin change interrupt on PORTB and PORTE
	PCMSK0 = PINE_MASK;
	PCMSK1 = PINB_MASK;
	EIFR = (1<<6)|(1<<7);
	EIMSK = (1<<6)|(1<<7);
	
	DDRD = 0xFF; // set PORTD for output
	DDRB = 0X00; // set PORTB for input
	
    PORTB = 0xFF; // enable pullup on for input
   	PORTD = 0XFF; // set LEDs off
	
	// say hello
	sendString("\rPC_Comm.c ready to communicate.\r");   	 
	// identify yourself specifically
	sendString("You are talking to the JoyStick demo.\r");

}

void parseInput(char s[])
{
	// parse first character	
	switch (s[0])
	{
		case 'j':
			if( (s[1] == 'o') && (s[2] == 'y'))
			joystick();
			break;
		case 'd':
			if( (s[1] == 'e') && (s[2] == 'm') && (s[3] == 'o') && (s[4] == '?') )
			sendString("You are talking to the LightMeter demo.\r");
			break;
		default:
			sendString("\rYou sent: '");
			sendChar(s[0]);
			sendString("' - I don't understand.\r");
			break;
		
	}
	s[0] = '\0';
}

void joystick()
{
	if(ENABLED == 0) ENABLED = 1;
	else ENABLED = 0;
}



SIGNAL(SIG_PIN_CHANGE0)
{
    PinChangeInterrupt();
}

SIGNAL(SIG_PIN_CHANGE1)
{
    PinChangeInterrupt();    
}

void PinChangeInterrupt(void)
{
    char buttons;
    char key;

    buttons = (~PINB) & PINB_MASK;
    buttons |= (~PINE) & PINE_MASK;

    // Output virtual keys
    if (buttons & (1<<BUTTON_A))
        key = KEY_UP;
    else if (buttons & (1<<BUTTON_B))
        key = KEY_DOWN;
    else if (buttons & (1<<BUTTON_C))
        key = KEY_LEFT;
    else if (buttons & (1<<BUTTON_D))
        key = KEY_RIGHT;
    else if (buttons & (1<<BUTTON_O))
        key = KEY_PUSH;
    else
        key = KEY_INVALID;
  
    if(key != KEY_INVALID)
    {
        if (!KEY_VALID)
        {
            KEY = key;          // Store key in global key buffer
            KEY_VALID = TRUE;
        }
    }
    
    EIFR = (1<<PCIF1) | (1<<PCIF0);     // Delete pin change interrupt flags 
	
	if(ENABLED)
	{
		getkey();
	}
}



char getkey(void)
{
    char k;

    cli(); // disable interrrupts so 'KEY' won't change while in use

    if (KEY_VALID) // Check for unread key in buffer
    {
        k = KEY;
        KEY_VALID = FALSE;
    }
    else
        k = KEY_INVALID; // No key stroke available

    sei(); // enable interrupts

	if(k != KEY_INVALID)
	{
		sendString("The joystick position is: ");
		
		switch(k)
		{
			case KEY_UP:
				sendString("UP");
				break;
			case KEY_DOWN:
				sendString("DOWN");
				break;
			case KEY_LEFT:
				sendString("LEFT");
				break;
			case KEY_RIGHT:
				sendString("RIGHT");
				break;
			case KEY_PUSH:
				sendString("PUSH");
				break;
			default:
				sendString("?");
				break;
		}
		
		sendChar('\r');
	}	

    return k;
}

In the initializer routine, various things are done to the ports on B,E & D. Besides setting various registers for the interrupts, do the ports need to be initialized in a certain way?

I ran the code without any of the PORT inits or outputs and it ran fine?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The PINB_MASK and PINE_MASK are switching on pull-up resistors (when the DDR bit is 0 and the PORT bit is set to 1). If you don't enable the pull-ups the inputs will float - you may be OK but I wouldn't rely on it.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I ran the code without any of the PORT inits or outputs and it ran fine?

If you loaded your code from the Butterfly's bootloader (as opposed to ISP, for example) then several things were already initialized for you, including some you may not want. I have a tutorial that explains what the bootloader does (and the mess it leaves behind).

Chuck Baird

"I wish I were dumber so I could be more certain about my opinions. It looks fun." -- Scott Adams

http://www.cbaird.org

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

zbaird wrote:
Quote:
I ran the code without any of the PORT inits or outputs and it ran fine?

If you loaded your code from the Butterfly's bootloader (as opposed to ISP, for example) then several things were already initialized for you, including some you may not want. I have a tutorial that explains what the bootloader does (and the mess it leaves behind).

thanks for the info, i'll review it and have a think.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quoted from your document:
"the pin change 1 interrupts are loaded (although global interrupts are off), several registers have random values, the pullups are on for PORTB, and so on."

Are the pullups on for PORT E as well? I'll have to guess and say that they are from the two tests i ran, where setting either port B or E as inputs with no pullups resulted in errors.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What is the point of this line in the Pin Change Interrupt routine?

EIFR = (1<<PCIF1) | (1<<PCIF0); // Delete pin change interrupt flags

It seems to have no effect on how the joystick works though i thought it should.

• Bit 7 – PCIF1: Pin Change Interrupt Flag 1
When a logic change on any PCINT15..8 pin triggers an interrupt request, PCIF1 becomes set (one). If the I-bit in SREG and the PCIE1 bit in EIMSK are set (one), the MCU will jump to the corresponding Interrupt Vector. The flag is cleared when the interrupt routine is executed. Alter- natively, the flag can be cleared by writing a logical one to it.
• Bit 6 – PCIF0: Pin Change Interrupt Flag 0
When a logic change on any PCINT7:0 pin triggers an interrupt request, PCIF0 becomes set (one). If the I-bit in SREG and the PCIE0 bit in EIMSK are set (one), the MCU will jump to the corresponding Interrupt Vector. The flag is cleared when the interrupt routine is executed. Alter- natively, the flag can be cleared by writing a logical one to it.

The flag is cleared while the ISR is still running, then it is cleared again? Doesn't that mean the next time the ISR shouldn't run?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

What is the point of this line in the Pin Change Interrupt routine?

I think it's known as "belts and braces" but you are right, it serves no real purpose there unless it's to clear a second interrupt activation that may have occurred while the first was being serviced.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
Quote:

What is the point of this line in the Pin Change Interrupt routine?

I think it's known as "belts and braces" but you are right, it serves no real purpose there unless it's to clear a second interrupt activation that may have occurred while the first was being serviced.

how does it clear a second interrupt? the description for the register is kind of funny because it says nothing about what it is used for except that bits get flagged and reset.

thanks,

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

IF is a "holding point" for an interrupt that is just one interrupt deep. When any interrupting event occurs in an AVR the first thing that happens is that the relevant ??IF?? bit is set. At the next opcode fetch the AVR core checks the IF bits in turn (in vector table order) and for the first it find set it takes the vector table jump to that ISR. Often this clears the ??IF?? as in this case. If, while that ISR is running and interrupts are disabled, the same event occurs the ??IF?? bit is set again. If the ISR now returns (via RETI) one opcode from main() is executed then the core spots the ??IF?? bit set again and jumps to the ISR.

Obviously if two (or more) of the same interrupt events occur while the first is being handled the ??IF?? bit is just that - a bit, not a counter - so only one further service will occur.

If you think there may be multiple interrupts (as there often are with mechanical switches) may occur then one way to combat this would be to do what's seen in this code and write the IF bit to 1 (to clear it) near the end of the ISR so that at least one extra interrupt is ignored.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you are going to take this level of microscopy to the code then you need to know two things. First some of the initialization was taken directly from the original Butterfly code with the assumption that there might be things being dealt with that were in other parts of the code that I didn't fully understand at the time (so I made the assumption that the guys who wrote the code knew what they were doing). And two, there are cases where bits are initialized to their default value which isn't necessary when coming out of reset since nothing actually changes but was done anyway because IMHO a: it is a good way to document what you are doing and b: it is never a good practice to rely on initialization defaults and c: the code would continue to be valid even if it is used at some later date to reinitialize something long after reset.

And, of course, there are some things that are just plain wrong but harmless so they never got noticed. If anyone sees something in all this that could improve the code or the understanding of the code, I'd like to hear about it and will make the necessary changes.

Smiley

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Are the pullups on for PORT E as well? I'll have to guess and say that they are from the two tests i ran

I don't see any indication in the code that they are. However, you'll need to take a look at the external circuitry (I'm too lazy to look) and see if something there might effectively act as a pullup on individual lines.

Chuck Baird

"I wish I were dumber so I could be more certain about my opinions. It looks fun." -- Scott Adams

http://www.cbaird.org

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You can find the full Butterfly schematic at:

http://www.atmel.com/dyn/product...
AVR Butterfly Evaluation Kit - User Guide
http://www.atmel.com/dyn/resourc...

Smiley