Netduino home hardware projects downloads community

Jump to content


The Netduino forums have been replaced by new forums at community.wildernesslabs.co. This site has been preserved for archival purposes only and the ability to make new accounts or posts has been turned off.
Photo

PS2 Keyboard timing woes


  • Please log in to reply
6 replies to this topic

#1 sweetlilmre

sweetlilmre

    Advanced Member

  • Members
  • PipPipPip
  • 62 posts

Posted 10 November 2010 - 12:15 PM

Hi,

I ported over the Arduino PS2 keyboard driver but unfortunately I cannot seem to read the PS2 data line fast enough during the clock interrupt.
The same pinout etc. was tested and working on an Arduino so it seems to be an interop speed issue.

Has anyone else managed to get this working?

Thanks
-(e)

#2 dragonfly

dragonfly

    Member

  • Members
  • PipPip
  • 12 posts
  • LocationSouth Africa

Posted 14 November 2010 - 10:58 PM

Seem to be having some success (not alot though) using one interrupt per pin, eg:

        private void clockPort_OnInterrupt(uint data1, uint data2, DateTime time)
        {
            this.Clock(this.data);
        }



        private void dataPort_OnInterrupt(uint data1, uint data2, DateTime time)
        {
            this.data = (data2 == 0) ? false : true;
        }

It almost works but it still drops bits, especially when something is happening in the background.

According to this page,

The KBD Clock line can be used as a Clear to Send line. If the host takes the KBD Clock line low, the keyboard will buffer any data until the KBD Clock is released

, which implies that it may be possible to implement some sort of protocol to pause the keyboard while some processing is happening, possibly "driving" the pins by setting the pull-up/pull-down resistors, eg:
            this.dataPort.Resistor = Port.ResistorMode.PullDown;

            this.clockPort.Resistor = Port.ResistorMode.PullDown;
, Although this throws a runtime exception. Other dead-ends include creating an OutputPort on the same pin as the InterruptPort, or using TristatePorts with interrupt handlers. Its puzzling that this is even an issue considering the keyboard should only be transmitting at ~25kHz.

#3 freds

freds

    Advanced Member

  • Members
  • PipPipPip
  • 61 posts

Posted 15 November 2010 - 03:59 AM

Seem to be having some success (not alot though) using one interrupt per pin, eg:

        private void clockPort_OnInterrupt(uint data1, uint data2, DateTime time)
        {
            this.Clock(this.data);
        }



        private void dataPort_OnInterrupt(uint data1, uint data2, DateTime time)
        {
            this.data = (data2 == 0) ? false : true;
        }

It almost works but it still drops bits, especially when something is happening in the background.

According to this page, , which implies that it may be possible to implement some sort of protocol to pause the keyboard while some processing is happening, possibly "driving" the pins by setting the pull-up/pull-down resistors, eg:
            this.dataPort.Resistor = Port.ResistorMode.PullDown;

            this.clockPort.Resistor = Port.ResistorMode.PullDown;
, Although this throws a runtime exception. Other dead-ends include creating an OutputPort on the same pin as the InterruptPort, or using TristatePorts with interrupt handlers. Its puzzling that this is even an issue considering the keyboard should only be transmitting at ~25kHz.

I think the netduino processor only has pullup resistors and that would be why it would thow an error when you selected pulldown.

#4 dragonfly

dragonfly

    Member

  • Members
  • PipPip
  • 12 posts
  • LocationSouth Africa

Posted 15 November 2010 - 07:33 AM

Freds: Ah that makes some sense, I'll try that it out ;) Although if that is the case then this is still a dead-end as the lines need to be pulled low to set the keyboard to receive mode. Would still be good to see if it works though. I saw another page (can't remember where off-hand) which hinted that a serial port might do the job. On one hand the data looks like standard serial data (stop bit, start bit, parity bit), on the other hand there's no real handshaking so it would be a bit of a guess getting the right connection settings as to speed and so on. Also, setting the keyboard to receive mode might also be a problem as it requires pulling the clock and data lines low which may or may not be possible using a serial port. Still worth investigating.

#5 CW2

CW2

    Advanced Member

  • Members
  • PipPipPip
  • 1592 posts
  • LocationCzech Republic

Posted 15 November 2010 - 08:01 AM

I saw another page (can't remember where off-hand) which hinted that a serial port might do the job. On one hand the data looks like standard serial data (stop bit, start bit, parity bit), on the other hand there's no real handshaking so it would be a bit of a guess getting the right connection settings as to speed and so on.

It should be possible to implement PS/2 protocol using Netduino's USART in synchronous mode, unfortunately serial clock pins are not broken out and there is no support for enabling the synchronous mode from managed code. Additionally, TX and RX must be wired together and I am not sure I/O lines can be set to open-drain when used by USART, so it may need some external circuitry.

#6 sweetlilmre

sweetlilmre

    Advanced Member

  • Members
  • PipPipPip
  • 62 posts

Posted 16 November 2010 - 08:50 AM

Hi, Wow, awesome replies everyone! I am going to look at capturing the state of any input pins at the time of interrupt and exposing this up the chain to the event handler. I've looked at the code and it looks possible, but will require some significant changes.... Hmmm :) -(e)

#7 sweetlilmre

sweetlilmre

    Advanced Member

  • Members
  • PipPipPip
  • 62 posts

Posted 20 November 2010 - 08:13 PM

Hi,

SUCCESS!!!

12 hours of my life I'll never get back, a switch to the Keil compiler and a low-level firmware modification and I can read a PS2 keyboard.
At least it seems like it - I haven't got to the decoding routine yet.

During this exercise I discovered that GCC built firmware is horribly unreliable in interrupt delivery (at least I think it was a GCC issue).
A keyboard press / release should generate 33 clock pulses for a standard key (scan code, E0 and scan code again to match key down / key up).

Under GCC I was getting a random number of interrupts in the range 11 - 23... Under Keil I consistently get 33.

My firmware modification traps the state of 0 - 31 InputPorts at the time of the interrupt and passes this state via the data2 parameter of the interrupt. This is handled via a modification to InterruptPort and the low level ISR routine:

	public sealed class InterruptPort : InputPort
	{
    	//--//
    	private uint[] m_inputPinWatch = null;

    	public InterruptPort( Cpu.Pin portId, bool glitchFilter, ResistorMode resistor, InterruptMode interrupt, InputPort[] watches )
      	: this( portId, glitchFilter, resistor, interrupt )
    	{
        	if ( watches != null )
        	{
            	if ( watches.Length > 31 )
            	{
              	// max 31 bits of resolution in data2 argument of the interrupt event handler
              	throw new ArgumentException();
            	}
            	m_inputPinWatch = new uint[ watches.Length ];

            	for ( int index = 0; index < watches.Length; index++ )
            	{
                	m_inputPinWatch[ index ] = (uint) watches[index].Id;
            	}
        	}
    	}
]

and

    	CLR_RT_HeapBlock_Array* inputPinWatchRef = pManagedPortObj[ Library_spot_hardware_native_Microsoft_SPOT_Hardware_Port::FIELD__m_inputPinWatch ].DereferenceArray();
    	if ( inputPinWatchRef != NULL )
    	{
        	CLR_UINT32* inputPinIds = (CLR_UINT32*) inputPinWatchRef->GetFirstElement();
        	int len = inputPinWatchRef->m_numOfElements;

        	for ( int i = 0; i < len; i++ )
        	{
            	if ( ::CPU_GPIO_GetPinState( inputPinIds[i] ) )
            	{
                	data2 |= ( 1 << ( i + 1 ) );
            	}
        	}
    	}


This seems to perform well but is an interesting alteration to the core framework and changes the meaning of the data2 / state parameter of the interrupt significantly.

I would be interested in any comments on this approach.

I'd also like to thank CW2 for various posts on getting the firmware compiled without which this wouldn't have happened.

Thanks
-(e)




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

home    hardware    projects    downloads    community    where to buy    contact Copyright © 2016 Wilderness Labs Inc.  |  Legal   |   CC BY-SA
This webpage is licensed under a Creative Commons Attribution-ShareAlike License.