close-circle
Close
0%
0%

Low Cost KVM Switch

This is a KVM switch built from cheap HDMI switch + USB MUX

Similar projects worth following
KVM is a hardware device that allows you to control/manage several computers from one set of keyboard/mouse and monitor. It is a bit different than a software solution as you can use it at preboot or other situations where the remote viewing software isn't working.

There seems to be a void for affordable modern KVM switches even though all the pieces are out there. Cheap $5 HDMI 1.4 switch has already most of the parts except for switching keyboard and mouse. It is a matter of adding a USB MUX for a minimal functioning KVM. I'll try to use as much off the shelf parts as possible to lower the complexity/cost.

The low end KVM are similar to the old one I have.  It has a pair of PS/2 connectors for Mouse and Keyboard and a VGA input for each port.  VGA is pretty much absent on main stream PC.  Sadly the ones with more modern day interfaces are a bit too much for me.


HDMI Switching

I have previously opened up a $5 3-to-1 HDMI switch. The HDMI switch is implemented with AZHW37 HDMI mux that is controlled by logic level signals controlled with a 8-pin microcontroller to handle the buttons and selection LED.  This has just enough smarts inside for the video switching in a basic KVM.

Details: HDMI Switch Reverse Engineering.
HDMI switch datasheet: http://www.amazingic.com/english/01_products/AZHW37

The physically mapping on PCB is in blue.

PS/2 KVM

PS/2 devices are not hot pluggable, so a KVM emulates a pair of PS/2 mouse/keyboards for each of the computers. It pass through key strokes, mouse events and commands. It also has to remember the LED states of the keyboard/mouse so that it can restore the states switching between different computers.

Unlike PS/2, USB is designed to be hot pluggable. i.e. The KVM (Hub Based) connects/disconnects the USB port for each time it switches. The OS level support simplifies the design a lot. Windows even saves the LED states of keyboard and restores it upon reconnecting.

USB 1.X Switching - The easy way

If you want to switch USB 1.X signals, you can probably get by with a 74HC4052 (Dual 4:1 Analog MUX). The 74HC4052 covers all the logical combinations, so it is a matter of taking advantage of that to match up with the HDMI switch and discarding the combination not covered by the HDMI.

The connections on the 74HC4052 would probably look like this. S1, S2 are fed from the HDMI switch.

Most of the commodity keyboard/mouse are USB 1.X devices, so this is probably good enough.

You do have to make sure that the USB HUB you are using is only USB 1.x (i.e. 1.5 or 12Mbps) as the MUX is not rated for USB 2.0. USB unlikely Ethernet doesn't falls back gracefully if the signal quality is bad. You just have to shop for the cheapest $2 hubs from China which are still USB 1.1.

When not to switch

You have to be careful not to switch while inside BIOS/UEFI/OS Installation as the software side may have small primitive USB stacks that cannot handle the hot plugging. Switching mass storage devices without letting the OS knowing will likely results in files or file system level corruption.

Hardware Design

I have decided to try to make a USB 2.0 switch. If used carefully I can attach a USB memory stick or other devices to the hub.

There are proper USB 2.0 MUX out there e.g. On Semi NCN9252. It is a fine pitched (0.4mm) DFN parts targeted for skinny consumer electronic devices. Their pin placements doesn't exactly make sense without a multilayer PCB, but I have to work with what is available.

As an alternative, one could possibly make a USB 2.0 MUX out of 3 DTDP relays. Short pieces of twist pair from CAT5/6 could be used to wire things together. CAT5/6 have 100 ohms impedance which is within the USB specs.

They have decided to use a different combination for selecting the channels than the HDMI switch. There are a couple of ways to connect the control pins to the USB MUX.

  • Invert one of the logic signals e.g. S1 from HDMI and relabel the ports
  • A Dual 4 to 1 MUX (e.g. 74HC153) can be used as a pair of 4 entries lookup table.
  • Use a $0.24 microcontroller to remap the ports.  This is what this project is using.

I have thrown together a breakout PCB that I am going to order because of the tight tolerances and the high speed signals. There are some additional requirements that I haven't sorted out yet, so those are going to be on a separate PCB with a modular approach.

I use 3 schottky diodes as Or'ing diodes to provide power for the USB hub. The diodes prevent power from leaking back to unpowered PCs. Cheap hubs do away with the protection Schottky diode, so we...

Read more »

KVM-Hotkey.zip

PS2 Hotkey test code

Zip Archive - 67.22 kB - 04/28/2017 at 21:42

download-circle
Download

View all 6 components

  • Project update - phase I completed

    K.C. Lee5 days ago 0 comments

    Phase I of the project has been completed.  This project has the same functionality as my store bought $30 KVM.  Files have been updated on github.

    Youtube Demo:

    I connected 3 of my PC to the KVM.  Keyboard and USB mouse is connected to the USB 2.0 Hub.  The HDMI switch I am using is smart enough to only switch between the active computers.

    The computers can be switched in sequence by double clicking the Left CTRL key on the keyboard.  Switching video source can be a bit slow as the OS detects the monitor and USB devices each time I switch.

    This is why I need to compile on the Computer #1 using a KVM in the demo - C compiler with LMFlex licensing doesn't work on RDP connection.  :(

    In Phase II of the project, I am hoping to fool the OS that the monitor is connected to it at all times.  Hopefully this would eliminate the OS rearranging windows/screen contents.

  • Putting it together

    K.C. Lee6 days ago 0 comments

    I connected USB Mux and the STM8 with some 30AWG wires  (stranded one from old SCSI diff cable).  I bundled the wires from the USB Mux with heat shrink tubing to help relief the stress on the wire exiting the through hole.

    I stick the STM8 PCB onto the hood with a piece of doubled sided tape.  The jacket from old CAT5 patch cable acts as a strain relief for the ribbon cable.  I ordered some black cable sleeves from China, but they haven't shown up yet. The USB connector wing shaped PCB compresses against the jacket and hold it in place when the hood is assembled.  

    This is how everything fit together.  

    This is the side view:

    This is how all the pieces are connected.  USB PS2 dongle (blue) is connected to the USB 2.0 hub which plugged into the USB connector.  There is a ribbon cable that connects to the modified PS/2 dongle and another one connect to the modified HDMI Mux.

  • Project now works

    K.C. Lee6 days ago 2 comments

    Well the lost package of PCB finally showed up today.  At least it is better late than lost for good.   Of course this has to happen.  Just like the big sales for almost all of the new parts after I bought them for my computer.

    Oh wait, there is only 2 PCB! 

    The ribbon cable doesn't tin too well as it was old and oxidized. The lower temperature I had to use to reduce the chance of melting the insulation doesn't help either.

    The home made press fit connector works nicely in the plated through holes.  It can be easily installed for programming/debugging and removed afterwards without using a soldering iron.


    With some minor changes with the code from previous project log, the hotkey is now triggering the HDMI switch by shorting it to ground for 100ms.  I just have to add some code to map the HDMI Mux setting back to the USB Mux.

    The HDMI Mux to USB Mux mapping is done inside the main event loop as it does not require real time.  It works independently of the hotkey.  Since it involves Read Modify Write operation that shares GPIO port with the interrupt code, I surround the GPIO code with a pair of sim() and rim()  to disable and re-enable interrupt.

    const uint8_t Mux_Tbl[]=
    {
        // USB Mux                     HDMI Mux
        0x01 << USB_SHIFT,    // 00    Output 1
        0x00 << USB_SHIFT,    // 01    No connect
        0x02 << USB_SHIFT,    // 10    Output 2
        0x03 << USB_SHIFT     // 11    Output 3
    };
    // inside main event polling loop
    {
      // HDMI Mux setting mapped to USB
      Mux = Mux_Tbl[(HDMI_PORT->IDR & (HDMI_S2|HDMI_S1))>>HDMI_SHIFT];
      // Make the I/O atomic
      sim();
      HDMI_PORT->ODR = (HDMI_PORT->ODR & HDMI_SW)|Mux;
      rim();
    }
    

    I have uploaded the STM8S board and firmware files on github.  

  • PCB lost in the mail

    K.C. Lee08/11/2017 at 02:02 0 comments

    Not only did Canada Post took longer than expected, but they probably delivered it to the wrong apartment.  This is not the the first time they messed up. So far no one has dropped it off yet.

    If it doesn't show up tomorrow, I might have to etch my own PCB as the lead time is just too long.


    I etched a PCB using toner transfer.  The toner image is mirrored in the horizontal axis because it is laid face down on the copper.  The layout is almost identical except that this is a single sided and the SWIM debug connector is sort of surface mounted.

    The ribbon cable is staggered into two rows to accommodate the 0.050" (1.27mm) pitch.  Regular ribbon cables are not designed for soldering, but there isn't space for proper IDC termination.  To give you a sense of the scale, the black connector (SWIM debugger) is a 3 pin 0.1" pitch connector.

  • KVM PS/2 controller

    K.C. Lee07/19/2017 at 11:30 0 comments

    I designed a PCB for the KVM controller. It is a tiny board that I am going to fit inside the DB25 hood.

    It is a small PCB that snoops the PS/2 signal from the PS/2 dongle and to look for a hotkey sequence to control the HDMI switch. It also reads the currently selected HDMI switch to select the corresponding USB Host port.

    I was going to etch the board, but got lazy.

    Not tested yet.

    Canada Post Xpresspost typically delivers in 2-3 working days.

  • Modding HDMI switch

    K.C. Lee07/15/2017 at 22:12 0 comments

    I have been putting off doing this, but I guess I got to do it at some point. The connector is for breaking out the HDMI Mux address line and the push button. I have previously reverse engineered the HDMI switch here.

    I eyeballed the connectors and mark it off where on the case I am going to cut with a pencil. It is the only edge that is cleared of components or traces.

    I cut a hole on the side. One side of the edge is tapered for sliding in the connector.

    This is how it would fit.

    I made a loop with a pin from a scrap connector.

    I trimmed off the loop with a diagonal cutter, file off the excessive solder and pin so that it is flush.

    The edge of the PCB is trimmed off with a shear. PCB is covered with a piece of Kapton tape as a precaution as pin 2 is pretty close to the top side.

    I removed the soldermask from the ground plane.

    The pin and the loop is soldered to the ground plane for mechanical support.

    I use a piece of Kapton tape to cover up the two capacitors as a precaution.

    I use a piece of ribbon cable to connect pin 2-4 of the chip to the connector. I "superglued" the protoboard to the PCB for additional support. The ribbon cable is glued to the main PCB with a bit of hot glue.

    This is what the slot looks like with everything in place.

    With the cable, it looks like this.

  • Modding USB PS/2 Dongle

    K.C. Lee07/14/2017 at 21:53 0 comments

    I have been procrastinating on this trying to figure out a clean way of connecting to the dongle. I could simply drill a hole and solder wire to the dongle, but in the long run it will be a maintenance nightmare.

    I start off with using a pencil to mark off the cut out area.

    It turns out that I need to cut quite a bit bigger hole. The plastic was easy to work with and reasonably strong which is surprising for cheap Chinese stuff.

    I am using a 3 pin fan connector to connect the Clk, Gnd and Data for the keyboard PS/2 signals. This goes to the microcontroller that sense a hotkey sequence and drives the HDMI select button.

    The connector is supported on the back side by a small piece of protoboard.

    I used a scrap piece of connector pin as mechanical support and connect to the unused footprint for the power LED. The PCB and this pin helps to keep the connector in place.

    I made 2 connections on the top side of the PCB. The white wire is connected to Data while the brown one to ground.

    The Clk line is connected to green wire at the back.

    This is how it looks when glued back together. The connector pins are protected by the case. A dummy connector can be used as a protection cap against short circuiting.

  • status update

    K.C. Lee04/28/2017 at 20:30 0 comments

    Still waiting for stuff I ordered from China. It has been 2 months now. Stuff is most likely sitting at the big ware house at Canada Custom. When it comes to clearing customs for stuff that are not first class or couriers, it usually takes ~2.5 months (used to be from about 1 month last Oct.) Sometimes I feel like I am in south America. Not even the Energizer Bunnies can out last waiting for Canada Custom.

    Here is what others have documented about the slowness of Canada Custom/Canada Post.

    The longest shipment took 165 days, the shortest 18 days (both free shipping). Anything with China Post was consistently sluggish at 147 (!) days [= 5 MONTHS], followed by tightly clustered Switzerland unregistered at 104 days [= 3.5 MONTHS], and rather erratic aliexpress standard shipping at 84 days [= ~3 MONTHS].


    The keyboard dongle finally arrived today. It took exactly 4 months! They must have the big warehouse like the end of the first Indiana Jones movie. For all that expensive rent in the Canada Custom in Vancouver that handles imports, they could simply hire more people.

    Here is what's inside:

    It is minimalist design with the black epoxy encapsulated chip, a decoupling cap and the connectors. The good part is that the PS/2 interface supports hot plugging for both mouse and keyboard. It supports scroll mouse.

    They really should solder in the shield tabs for the USB connector to provide extra mechanical support.


  • Snooping PS/2 keystrokes for hotkey - part 2

    K.C. Lee03/31/2017 at 17:04 0 comments

    It works. :) The key pressed trace shows the duration while Digital 3 shows the pause between key presses. The final glitch is the detection of double click. The "!" is the output when it detects a double click. My delays are around 70-75ms.

    Here is the preliminary state machine that does the checking. Basically each state checks against expected scan code and within countdown timer limits before proceeding to the next state. If it fails, then reset to the idle state and start again.

    // high level polling task
    void PS2_Task(void)
    {
      uint16_t ScanCode, Parity;
      if(PS2.Avail)
      { // Critical section
        sim();
        ScanCode = PS2.ScanCode;
        PS2.Avail = 0;
        rim();
            
        Parity = PS2.ScanCode & 0x01;    
        ScanCode = (ScanCode >> 1) & 0xff;
            
        if (ScanCode == PS2_KBD_CODE_RELEASE)
          Hotkeys.KeyAttr |= Key_Release;
        else if (ScanCode == PS2_KBD_CODE_EXTENDED)
          Hotkeys.KeyAttr |= Key_Extend;
        else
        { switch(Hotkeys.State)
          {
            case HK_Idle:
              if((ScanCode == HOTKEY_SCANCODE) && !Hotkeys.KeyAttr)
              { Hotkeys.State = HK_KeyMake_1;
                Milli_Timer1 = HOTKEY_RELEASE_DELAY;
                return;
              }
              break;
                        
            case HK_KeyMake_1:
              if((ScanCode == HOTKEY_SCANCODE) && 
                 (Hotkeys.KeyAttr==Key_Release) && Milli_Timer1)
              { Hotkeys.KeyAttr = 0;
                Hotkeys.State = HK_KeyBreak_1;
                Milli_Timer1 = HOTKEY_WAIT_DELAY;                
                return;
               }
              break;
                        
            case HK_KeyBreak_1:
              if((ScanCode == HOTKEY_SCANCODE) && 
                 !Hotkeys.KeyAttr && Milli_Timer1)
              { Hotkeys.State = HK_KeyMake_2;
                Milli_Timer1 = HOTKEY_RELEASE_DELAY;                
                return;
              }
              break;
                        
            case HK_KeyMake_2:
              if((ScanCode == HOTKEY_SCANCODE) && 
                 (Hotkeys.KeyAttr==Key_Release) && Milli_Timer1)
              { PutC('!');
                NewLine();                
              }
              break;    
         }
                
         // default to idle
         Hotkeys.State = HK_Idle;
         Hotkeys.KeyAttr = 0;
       }
      }
    }
    

    Pretty mechanical and boring code. There are probably ways to improve and what not. I am skimping on the error checking for now. As with all coding exercises, there are things I might have missed etc., but probably enough to the next part.


    The test code is under the file area. The project is for Cosmic C.


    The code is missing the else statements for the state machine that reset the state to default.

    else
      Hotkeys.State = HK_Idle;

  • Snooping PS/2 keystrokes for hotkey

    K.C. Lee03/29/2017 at 23:49 0 comments

    The idea is to snoop the PS/2 keystrokes passively for supporting hotkey for switching to a different PC. It is a bit different than interfacing to the keyboard directly.

    Electrical

    I have decided to use the I2C pins as they are "True Open Drain" pins and the only 5V tolerant pins in the STM8.

    Protocol

    The PS/2 protocol is bidirectional and the protocols are slightly different. If Data = '0' on the first falling edge of Clock, then it is a response or scan code from keyboard to PC.

    If Data = '1' on the falling edge of Clock, then it is a PS/2 command for the keyboard.

    Synchronization

    We have to keep track of the different number of data bits of the two protocols. A count down timer is used to determine if synchronization is lost.

    I use the falling edge of clock for interrupt. Inside the IRQ, the Data bits are LSB first. A state machine is used to keep track of the protocol. A timer is used to determine whether or not synchronization has been lost and is used to reset the state machine.

    @far @interrupt void PORTB_IRQ(void)
    {		
      if((PS2.State == PS2_Idle)||(!Micro_Timer1))	// Start bit or resynchronized
      { // rewind timer
        Micro_Timer1 = us_TO_TICKS(PS2_BIT_TIMEOUT);
        // first bit determines source: keyboard or PC
        PS2.State = (PS2_PORT->IDR & PS2_DATA)?PS2_CMD_1:PS2_KBD_1;
      }
      else // Scan/respond code
      { if(PS2.State++ & PS2_KBD)
        { if(PS2.State == PS2_KBD_LAST)
          {	PS2.Avail = 1;
            PS2.State = PS2_Idle;
          }
          else
          { PS2.ScanCode >>= 1;
            if(PS2_PORT->IDR & PS2_DATA)
              PS2.ScanCode |= 0x200;
          }
        }
        else  // Ignore Cmd to keyboard
          if(PS2.State == PS2_CMD_LAST)
            PS2.State = PS2_Idle;
      }
    }

    Here is the scan code decoding output (in Hex, P: parity bit.) from my main event loop.
    PS/2 uses odd parity.

    Hotkey Detection

    This is a time stamp of the PS/2 scan code generated from me double clicking the Left Control key captured and decoded from a logic analyzer.

    So let's make an upper limit of 250ms, 200ms, 250ms for the 3 timing intervals.

    For a successful double click event:

    • The scan code sequence is: 0x14, ( 0xf0,0x14), 0x14
    • 3 sets of timings that needs to be satisfied for a double click event.

    I have to add a state machine and some additional timer routines for detecting the hotkey sequence.


    My development set up:

    • My new STM8 Breakout board with on board USB serial port
    • PS/2 splitter to monitor traffic between a PS/2 keyboard and a hub with PS/2 converter
    • Logic analyzer

    I have put together a keyboard scan code chart:

View all 13 project logs

  • 1
    Step 1

    Those cheap $0.50 DB-25 hood is an artifact from the 1980's that looks suitable for this hack. I bought a bunch from surplus places a long while ago. This looks to be similar to the USB2LPT project which as a part#: Kappe CG25G, Cinch 40-9725H on Digikey and possibly others. (Mine were made in Taiwan.)

    The PCB is installed with solder side facing up. Hopefully it would It lines up with the two mounting holes. I made a rectangle hole with a box cutter, nibbler and a small file.

    The spacing is just right for the USB connector. I just have to prevent the connector from sliding out.

  • 2
    Step 2

    I clean up the area around the USB connector on an old motherboard. A single USB connector fits the footprint of double USB connector.

    Some rough cut with a cutting wheel using a Dremel tool. Remember eyes protection!

    After some cleanups, I eyeball the alignment and mark the cuts with a knife.

  • 3
    Step 3

    The "wings" on the sides fits in the cable retainer slot in opposite clam shell. Time for some elbow grease - cut, filing and finally cleanup.

    Something like this would probably work. There are manufacturing tolerances, (possibly part was designed in metric), so needs to be verified.

View all 4 instructions

Enjoy this project?

Share

Discussions

zakqwy wrote 03/16/2017 at 17:24 point

usb in a DB-25 hood is excellent!

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates