How to debug PS/2 protocol?

32 posts / 0 new
Last post
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OP wrote:
That's why I'm confused that you guys keep talking about USART.
NO USART code after all, see my previous post.

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

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

Lennart wrote:
Having a scope to reveal what's happening on the data and clock lines would help.

I have pictures and video from the scope which I will upload ASAP, as soon as I can get a hold of my card reader. Basically, Data remains high except a downward spike to 0 that I don't understand (screen looks the same all the time), and Clock is mostly high but actually goes low in a square wave once in a while, which is nice.

----
Update: See later post for picture and video in zip file.

Quote:
Speaking of logic levels, what kind of pull-ups you have on the clock/data lines (if any?). If you have something between 2k and 15k you should be fine.

Are you sure you drive the clock and data pins in open-collector mode, not push-pull mode? You are never ever allowed to set the pins as high outputs, only inputs or low outputs.

I have 10K pullups. (Yay, I did something right) It's supposed to be open-collector, but let me look up push-pull mode and get back to you.

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

Jepael wrote:

Okay, first of all, the mouse should report only standard 3-byte packets, unless the HOST sends the mouse the correct magic sequence which the mouse recognises and switches to the extended 4-byte protocol.

I think the code does have the mouse recognizing the sequence from the host. See below:
(this code is in the processCommand function)

    if(settingSampleRateFlag) {
        settingSampleRateFlag = 0;


        if(hostCommand >= 10 && hostCommand <= 200) {
            lastlastSampleRate = lastSampleRate;
            lastSampleRate = sampleRate;
            sampleRate = hostCommand;
            if((lastlastSampleRate == 200) && (lastSampleRate == 100) && (sampleRate == 80)) {
                deviceID = 0x03; // enter MS intellimouse mode
            }
            if(deviceID == 0x03 && lastlastSampleRate == 200 && lastSampleRate == 200 && sampleRate == 80) {
                deviceID = 0x03; // enter MS 5-button mouse mode
            } 
        } else { // bad sample rate, output an error
            queuePut(ERROR);

Quote:
And also I honestly don't understand why put 600 ohm resistors there. It will work without any series resistors

This is fine with me, the simpler the better. I'll try a low resistor as well as nothing, but then again why would anyone bother with transistors (the classic open-collector interface), or resistors if they weren't needed?

Anyway thanks for the help.

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

snickersnee wrote:
I'll try a low resistor as well as nothing, but then again why would anyone bother with transistors (the classic open-collector interface), or resistors if they weren't needed?
You better double check with the PS/2 "spec." that you might not need anything on those MCU pins.

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

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

Here is the function implementing the four PS/2 states as described previously. In all of them, the uC is monitoring the mouse clock state as well as CLK_IN from the host.

void clockStateNow(void)
{
    switch (myState)
    {  
    case BUSY:
        //if the clock being hold low when the clock should've been high.
        //Transition to inhibit state
        if ((clockState == HIGH || clockState == RISING) && CLK_IN == 0)
        {         
            inhibited = TRUE;
            myState = INHIBIT; 
            clockState = LOW;
            transmitting = 0;
            receiving = 0;   
            count2 = 0;
        }
        else if ( !(transmitting || receiving) ) //if not doing anything, then we go back to idle
            myState = IDLE;
        else myState = BUSY;
        break;
    
    case IDLE:
        //if the clock being hold low when the clock should've been high.
        //Transition to inhibit state
        if ((clockState == HIGH || clockState == RISING) && CLK_IN == 0)
        {   
            inhibited = TRUE;
            myState = INHIBIT;
            clockState = LOW;
            transmitting = 0;
            receiving = 0;  
            count2 = 0;
        }   
        //if there is data in the queue waiting to be sent
        //transition to BUSY state
        else if(queueEmpty == FALSE) 
        {
            myState = BUSY;
            transmitting=1;
            nextClockState=RISING;
            position = 0;
        }
        else 
        {
            myState = IDLE;
        }
        break;

    case INHIBIT:    
        //if the computer inhibit before we finishing sending the byte
        //we need to resend the byte
        if(position != 0 && position < 10)
        {
            resendFlag = TRUE;
        }
        position = 0;

        //right after the clock get out of inhibit state
        //we need to check if the computer have hold down the data.
        //If the computer pulls low the data line, then the mouse goes into
        //REQUEST state.
        if (outInhibit == TRUE)
        {
            if(DATA_IN == 0)
            {
                //The computer is request to send some data to the mouse
                myState = REQUEST;
                clockState = RISING;
            }
            else
            {
                //If the data line wasn't low.
                //then the computer must have put the mouse into inhibit
                //for processing data.
                myState = IDLE;
                clockState = RISING;                
            } 
            outInhibit = FALSE;
        }
        //if the clock high, meaning the computer has released clock line
        if(CLK_IN == 1)
        {
            outInhibit = TRUE;
        }
        else
        {      
            inhibited = TRUE;
            myState = INHIBIT;
            transmitting = 0;
            clockState = LOW;
            receiving = 0; 
            outInhibit = FALSE;
        }
        break;

    case REQUEST:  
        position = 0;
        receiving = 1; 
        nextClockState = FALLING;

        //if the clock being hold low when the clock should've been high.
        //Transition to inhibit state
        if ((clockState == HIGH || clockState == RISING) && CLK_IN == 0)           
        {       
            inhibited = TRUE;
            myState = INHIBIT;
            clockState = LOW;
            transmitting = 0;
            receiving = 0; 
            count2 = 0;
        }
        else if ( transmitting || receiving)
            myState = BUSY;
        else 
            myState = REQUEST;
        break;  

    }//end switch

}

Also, a correction to what I said above:
(I was missing the parity bit)

Quote:
A PS/2 byte has 11 bits:
0 - - - - - - - - - 1
start,(8 bits of data, LSB first),odd parity bit, stop

(Odd parity bit=1 when # of 1's is even)

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

indianajones11 wrote:
You better double check with the PS/2 "spec." that you might not need anything on those MCU pins.

The PS/2 "spec" has transistors (see diagram below), I presume that's why it's called an "open-collector interface," but no one actually uses transistors. This project uses 600 ohm resistors instead of transistors, I've seen another similar one that uses 300 ohm resistors, but jepael is telling me both are too high, it should be 100 ohms max, or nothing.

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

Here are the scope pictures I mentioned.
(well, it's a picture and two movies)

In the attachment (scope.zip):
IMG_6103.jpg is output of the data line
MVI_6104.avi is the clock line

(Separate attachment, MVI_6101.zip):
MVI_6101.avi is output of one of the blinking LEDs on Port B (these were to test the ADC)

----
Update to this: I'm now using a better probe, and in all these configurations all 4 output pins stay on +5V all the time. I could attach those pictures, but I think you can imagine how it looks. I previously described the clock line going down once in a while, however I'm not seeing that now and I have a better probe now. It's all just flat +5V. I think what I was seeing before was due to a lousy probe.

Attachment(s): 

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

snickersnee wrote:

This is fine with me, the simpler the better. I'll try a low resistor as well as nothing, but then again why would anyone bother with transistors (the classic open-collector interface), or resistors if they weren't needed?

Different chips have different kind of outputs and different driving capability. If the microcontroller only has push-pull outputs, you must put something there to make it compatible with open-collector. Same applies even if microcontroller supports open-collector directly, but if the internal transistor is too weak.

The external components may also protect the controller from destructive voltage spikes etc.

So 20 years ago microcontrollers were different and thus some external components were needed. Nowadays you can get keyboard encoder chips with everything built-in so direct connection is enough.

Edit: the website that has the picture you posted is almost 10 years old, and it says the picture is an example of the interface, and it also says you can use a single pin on a PIC microcontroller instead.

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

Thanks for the explanation.

Quote:
it also says you can use a single pin on a PIC microcontroller instead

Not sure if it matters, but I'm using AVR. And it shouldn't matter that I'm using Atmega32a and the project calls for Atmega32, right? There are plenty of pins, I might as well use different ones for input and output so I won't have to keep changing DDR. Here is the schematic:

(It shows up too small here, it's also in the attachment.)

Another thing I've thought about is in theory I should be able to power the circuit with the computer, from the +5V pin of the PS/2 cable. However, I rarely get the full voltage from this wire; it's usually more like 2V or 4V or something. This is probably just a consequence of the computer not recognizing the setup as a mouse, but I just thought I'd mention it.

----
Things to try:
-Play with resistor values.
-When compiling it under an older version of Codevision, a lot fewer warnings show up. So I'll try loading this version onto the chip.

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

But you HAVE to use DDR to make AVR simulate open-collector output. No matter if you use separate input and output pin.

Pages