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.

PS2 Keyboard problem

i have successfully(somewhat) interfaced ps2 keyboard  with msp430.

everything goes perfect mostly before ~25 keystrokes.

but mostly after ~25 keystrokes , error in communication occurs(parity error).

all data after error-data is also having parity problem. (ie anything after error data is garbage.)

im using POT for converting 5V -> 3V , GND common, powering keyboard from external source(i have tried changing keyboard also).

i have a MSP430G2553IN20 launchpad board.

the data is printed on screen, that i can see.

// port2

#include <hardware/port2.h>

void port2_init()
{
    KEYBOARD_PS2_PDIR &= ~(KEYBOARD_PS2_DATA | KEYBOARD_PS2_CLK);
    KEYBOARD_PS2_PREN |= KEYBOARD_PS2_DATA | KEYBOARD_PS2_CLK;
    KEYBOARD_PS2_POUT |= KEYBOARD_PS2_DATA | KEYBOARD_PS2_CLK;
    
    KEYBOARD_PS2_PIES |= KEYBOARD_PS2_CLK;
    KEYBOARD_PS2_PIE |= KEYBOARD_PS2_CLK;
    
    KEYBOARD_PS2_PIFG &= ~KEYBOARD_PS2_CLK;
    
    P1DIR |= BIT6;
    P1OUT &= ~BIT6;
    
    /* interrupt goes to pin2_interrupt() */
}

void port2_interrupt()
{
    P1OUT ^= BIT6;
    
    KEYBOARD_PS2_PIFG &= ~KEYBOARD_PS2_CLK;
    keyboard_ps2.index++;
    
    switch(keyboard_ps2.index)
    {
        case -1:
            keyboard_ps2.data = 0;
            keyboard_ps2.parity = 0;
            /* start bit */
        break;
        
        case 0:
        case 1:
        case 2:
        case 3:
        case 4:
        case 5:
        case 6:
        case 7:
            /* data */
            if(KEYBOARD_PS2_PIN & KEYBOARD_PS2_DATA)
            {
                keyboard_ps2.data |= (1 << keyboard_ps2.index);
                keyboard_ps2.parity ^= 0x01;
            }
        break;
        
        case 8:
            if((!(KEYBOARD_PS2_PIN & KEYBOARD_PS2_DATA)) == (!keyboard_ps2.parity))
            {
                /* incorrect data */
                P1DIR |= BIT6;
    
                /* hang */
                while(1)
                {
                    P1OUT ^= BIT6;
                    __delay_cycles(600000);
                }
            }
            /* TODO: check parity for data */
        break;
        
        case 9:
            /* STOP bit */
            keyboard_ps2_data_decode();
        
        default:
            keyboard_ps2.index = -2;
        break;
    }
}

//ps2.c

#include <keyboard/ps2.h>

struct __keyboard_ps2 keyboard_ps2 =
{
    .index = -2,
};

void keyboard_ps2_data_decode()
{
    switch(keyboard_ps2.data)
    {
        case 0xF0:
            /* some key released */
            keyboard_ps2.make = FALSE;
        return;
        
        case 0xE0:
            /* behaviour modifier */
            keyboard_ps2.modifier = TRUE;
        return;
        
        case 0x12: /* left SHIFT */
        case 0x59: /* right SHIFT */
            keyboard_ps2.latch_shift = keyboard_ps2.make;
        break;
        
        /* right CTRL : <modifier> 0x14 */
        case 0x14: /* left CTRL */
            keyboard_ps2.latch_ctrl = keyboard_ps2.make;
        break;
        
        /* right ALT : <modifier> 0x11 */
        case 0x11: /* left ALT */
            keyboard_ps2.latch_alt = keyboard_ps2.make;
        break;
        
        /* including modifier version */
        case 0x1F: /* left GUI */
            //keyboard_ps2.latch_gui = keyboard_ps2.make;
        break;
        
        /* caps */
        case 0x58:
            if(keyboard_ps2.make)
            {
                /* flip caps */
                keyboard_ps2.latch_caps ^= 0x01;
            }
        break;
        
        default:
            if(keyboard_ps2.make)
            {
                keyboard_ps2_resolve_scancode();
            }
        break;
    }
    
    keyboard_ps2.make = TRUE;
    keyboard_ps2.modifier = FALSE;
}

void keyboard_ps2_resolve_scancode()
{
    register uint8_t ch = 0;
    
    if(keyboard_ps2.modifier)
    {
        switch (keyboard_ps2.data)
        {
            case 0x4A:
                ch = '/';
            break;
            
            case 0x5A:
                ch = KEYBOARD_PS2_ENTER;
            break;
            
            case 0x69:
                ch = KEYBOARD_PS2_END;
            break;
            
            case 0x6B:
                ch = KEYBOARD_PS2_LEFTARROW;
            break;
            
            case 0x6C:
                ch = KEYBOARD_PS2_HOME;
            break;
            
            case 0x70:
                ch = KEYBOARD_PS2_INSERT;
            break;
            
            case 0x71:
                ch = KEYBOARD_PS2_DELETE;
            break;
            
            case 0x72:
                ch = KEYBOARD_PS2_DOWNARROW;
            break;
            
            case 0x74:
                ch = KEYBOARD_PS2_RIGHTARROW;
            break;
            
            case 0x75:
                ch = KEYBOARD_PS2_UPARROW;
            break;
            
            case 0x7A:
                ch = KEYBOARD_PS2_PAGEDOWN;
            break;
            
            case 0x7D:
                ch = KEYBOARD_PS2_PAGEUP;
            break;
        }
    }
    else if(keyboard_ps2.data < KEYBOARD_PS2_KEYMAP_SIZE)
    {
        ch = keyboard_ps2_scancode_en[keyboard_ps2.data][keyboard_ps2.latch_shift];
        
        /* caps lock feature, turn character to opposite case */
        if(keyboard_ps2.latch_caps)
        {
            if('a' <= ch && ch <= 'z' )
            {
                ch -= 'a' - 'A';
            }
            else if('A' <= ch && ch <= 'Z')
            {
                ch += 'a' - 'A';
            }
        }
    }
    
    if(ch)
    {
        //uart_send(ch);
        cqueue_push(&uart_cqueue_rx, ch);
    }
}

//ps2.h

#ifndef _KEYBOARD_PS2_H_
#define _KEYBOARD_PS2_H_

#include <common.h>
#include <uart.h>
#include <cqueue.h>

#define KEYBOARD_PS2_PDIR P2DIR
#define KEYBOARD_PS2_PIN  P2IN
#define KEYBOARD_PS2_POUT  P2OUT
#define KEYBOARD_PS2_PIFG P2IFG
#define KEYBOARD_PS2_PIES P2IES
#define KEYBOARD_PS2_PIE  P2IE
#define KEYBOARD_PS2_PREN P2REN

#define KEYBOARD_PS2_DATA BIT3
#define KEYBOARD_PS2_CLK BIT4

/* port/derivative: http://www.pjrc.com/teensy/td_libs_PS2Keyboard.html */

/* scancodes */
#define KEYBOARD_PS2_TAB                        9
#define KEYBOARD_PS2_ENTER                        13
#define KEYBOARD_PS2_BACKSPACE                    127
#define KEYBOARD_PS2_ESCAPE                        27
#define KEYBOARD_PS2_INSERT                        0
#define KEYBOARD_PS2_DELETE                        127
#define KEYBOARD_PS2_HOME                        0
#define KEYBOARD_PS2_END                        0
#define KEYBOARD_PS2_PAGEUP                        25
#define KEYBOARD_PS2_PAGEDOWN                    26
#define KEYBOARD_PS2_UPARROW                    11
#define KEYBOARD_PS2_LEFTARROW                    8
#define KEYBOARD_PS2_DOWNARROW                    10
#define KEYBOARD_PS2_RIGHTARROW                    21
#define KEYBOARD_PS2_F1                            0
#define KEYBOARD_PS2_F2                            0
#define KEYBOARD_PS2_F3                            0
#define KEYBOARD_PS2_F4                            0
#define KEYBOARD_PS2_F5                            0
#define KEYBOARD_PS2_F6                            0
#define KEYBOARD_PS2_F7                            0
#define KEYBOARD_PS2_F8                            0
#define KEYBOARD_PS2_F9                            0
#define KEYBOARD_PS2_F10                        0
#define KEYBOARD_PS2_F11                        0
#define KEYBOARD_PS2_F12                        0
#define KEYBOARD_PS2_SCROLL                        0

#define KEYBOARD_PS2_KEYMAP_SIZE 136

#define keyboard_ps2_scancode_char(ch1, ch2) {ch1, ch2}

struct __keyboard_ps2
{
    uint8_t data;
    int8_t index;
    
    uint8_t parity:1;
    
    uint8_t modifier:1;
    uint8_t make:1;
    
    uint8_t latch_shift:1;
    uint8_t latch_ctrl:1;
    uint8_t latch_alt:1;
    uint8_t latch_num:1;
    //uint8_t latch_gui:1;
    uint8_t latch_caps:1;
};

extern struct __keyboard_ps2 keyboard_ps2;
extern const uint8_t keyboard_ps2_scancode_en[KEYBOARD_PS2_KEYMAP_SIZE][2];

void keyboard_ps2_init();
void keyboard_ps2_data_decode(void);
void keyboard_ps2_resolve_scancode(void);

#endif

//port2.h

#ifndef _KEYBOARD_PS2_H_
#define _KEYBOARD_PS2_H_

#include <common.h>
#include <uart.h>
#include <cqueue.h>

#define KEYBOARD_PS2_PDIR P2DIR
#define KEYBOARD_PS2_PIN  P2IN
#define KEYBOARD_PS2_POUT  P2OUT
#define KEYBOARD_PS2_PIFG P2IFG
#define KEYBOARD_PS2_PIES P2IES
#define KEYBOARD_PS2_PIE  P2IE
#define KEYBOARD_PS2_PREN P2REN

#define KEYBOARD_PS2_DATA BIT3
#define KEYBOARD_PS2_CLK BIT4

/* port/derivative: http://www.pjrc.com/teensy/td_libs_PS2Keyboard.html */

/* scancodes */
#define KEYBOARD_PS2_TAB                        9
#define KEYBOARD_PS2_ENTER                        13
#define KEYBOARD_PS2_BACKSPACE                    127
#define KEYBOARD_PS2_ESCAPE                        27
#define KEYBOARD_PS2_INSERT                        0
#define KEYBOARD_PS2_DELETE                        127
#define KEYBOARD_PS2_HOME                        0
#define KEYBOARD_PS2_END                        0
#define KEYBOARD_PS2_PAGEUP                        25
#define KEYBOARD_PS2_PAGEDOWN                    26
#define KEYBOARD_PS2_UPARROW                    11
#define KEYBOARD_PS2_LEFTARROW                    8
#define KEYBOARD_PS2_DOWNARROW                    10
#define KEYBOARD_PS2_RIGHTARROW                    21
#define KEYBOARD_PS2_F1                            0
#define KEYBOARD_PS2_F2                            0
#define KEYBOARD_PS2_F3                            0
#define KEYBOARD_PS2_F4                            0
#define KEYBOARD_PS2_F5                            0
#define KEYBOARD_PS2_F6                            0
#define KEYBOARD_PS2_F7                            0
#define KEYBOARD_PS2_F8                            0
#define KEYBOARD_PS2_F9                            0
#define KEYBOARD_PS2_F10                        0
#define KEYBOARD_PS2_F11                        0
#define KEYBOARD_PS2_F12                        0
#define KEYBOARD_PS2_SCROLL                        0

#define KEYBOARD_PS2_KEYMAP_SIZE 136

#define keyboard_ps2_scancode_char(ch1, ch2) {ch1, ch2}

struct __keyboard_ps2
{
    uint8_t data;
    int8_t index;
    
    uint8_t parity:1;
    
    uint8_t modifier:1;
    uint8_t make:1;
    
    uint8_t latch_shift:1;
    uint8_t latch_ctrl:1;
    uint8_t latch_alt:1;
    uint8_t latch_num:1;
    //uint8_t latch_gui:1;
    uint8_t latch_caps:1;
};

extern struct __keyboard_ps2 keyboard_ps2;
extern const uint8_t keyboard_ps2_scancode_en[KEYBOARD_PS2_KEYMAP_SIZE][2];

void keyboard_ps2_init();
void keyboard_ps2_data_decode(void);
void keyboard_ps2_resolve_scancode(void);

#endif

  • Hello Kuldeep,

    A PS2 keyboard to micro interface is an interesting project.  I have seen it for other MCU, but I haven't searched around for example code on the forum or the Internet to see if it exist for the MSP430.

    I'm not familiar enough with the MSP430 to give you an exact answer, but I'm sure when you are testing your code you are probably using the same two keys to test it and not typing 25 different letters.  Your interrupt routine seems quite large and you are calling another large subroutine in it.  Always try to spend the minimum number of (cycle) time in an interrupt.  It is possible that this is the source of your errors as a new interrupt is called before the previous one has finished.  If you disable the interrupt during the routine, then you may miss new keystrokes.  You should be able to debug by looking at the registers. 

    I would recommend that in the interrupt you only get the key that was pressed and store it in a ring buffer.  Then in your main code, you do the decoding of the key.  That way if you are holing down a key which repeats faster than if you were actually typing, the decoding can still take place after the key has been released.

    Thanks,

  • thank you greenja for your reply.

    i have tried several time and typed random sentences.

    i also tried implementing circular queue of 32 Byte but still same problem.

    im getting parity error due to unknown reason, and data after it is also corrupt, that leads me to nowhere.

    communication is at 20 - 25 Khz with keyboard and MSP430 running is at 16MHz in lpm0.

    i have a usci0 and timerA 0,1 interrupt going on. <--- is this could be a problem

  • timer A* were causing performance problem.

    move the code to main() and enter , exit sleep mode using timer A1, code of while() is executed every time it wakes, and then goes to sleep.

    thank you @greenja

**Attention** This is a public forum