VGA to AV Converter Switcher
January 2017

 

VGA to AV Converter Modification & Switcher

  

The VGA to AV Converter shown above left is available from dozens of retailers. It converts a VGA signal from a computer to an AV and S-Video signal for use by a TV, monitor or a PC video capture device. It also provides an un-altered feedthrough for the VGA signal

A common use is with a CCTV Digital Video Recorder (DVR). Many of these units only provide a VGA output (and, optionally, HDMI) to a monitor but an additional AV output can be useful, for example, to feed a TV (with an AV input) or to feed a video capture device in a PC - which nearly always involves AV to USB capture hardware or a PCI(e) card with AV inputs (Such as the Osprey range of analogue video capture cards).

The VGA to AV Video Converter unit has a useful button on its front panel (called ZOOM) successive presses of which cycles between passing the full VGA screen to the AV output or each of the four "corners". CCTV DVRs frequently display video from up to four cameras on-screen at the same time so the ZOOM button can be used to select either the full screen or one of the four camera images, as shown below.

The VGA image always passes through the converter unchanged and displays whatever output format is selected on the DVR but I wanted to automate the ZOOM button-pressing process so that the AV image could be cycled either on a timer or even switched remotely via a webpage. For completeness, I also wanted to retain the ZOOM button.

Inside the VGA to AV Converter

To gain access to the converter's PCB, it's necessary to remove four screws on the underside. It's also necessary to carefully peel off the label surrounding the button panel to allow the buttons to ease clear of the case.

The idea is to pick up the connections on the ZOOM button and wire them to a small socket for connection to an external switching circuit/microprocessor or relay.

The ZOOM button is the one on the bottom right corner in this photo. The ZOOM button (in fact, all of the buttons) has one side permanently connected to ground and pushing the button obviously grounds the other connection. As you'll see, there isn't much room anywhere around the edges for an additional socket.

This close-up of the bottom right hand corner of the PCB shows spare pads where an LED could be. R20 is a 1k resistor connected between one side of the LED (on the square solder pad) and the main power input socket. The other pad for the LED connects to ground. This is clearly an unused POWER ON LED and the pads are ideal for our purpose.

As the photo below shows, the square pad is isolated from everything by simply removing R20 with the soldering iron.

 


 

This photo shows a 2.5mm right-angled header soldered in place of the LED.

 

This photo shows a 1k resistor soldered between the two non-grounded pins - one on the pin-header and one on the ZOOM button.

A resistor is used to prevent potential damage to the output of an external microprocessor in case the ZOOM button is pressed while the microprocessor output is HIGH.

Note that the electronics within the converter operates at 3.2 volts. The absolute maximum voltage that should be applied to the ZOOM input (according to the datasheet for the main HY57V161610 processor) is 4.6 volts so it makes sense to design our external switch to operate on 3.2 volts or use a MOSFET (or transistor) to do the switching.

 

The photo below shows the converter in use with the PCB back in its case after filing a new opening for the right-angled pin header and replacing the stick-on label.

Note that I marked the polarity of the two header pins as it's obviously important to avoid connecting the external microprocessor output to the ground pin.

 

 

The Arduino Switching Hardware

The basic switching circuit is shown above. I used an Arduino Nano (with an ATMEL mega328p chip) rather than a discrete ATmega328 because, as the project also needs a serial USB connection to a PC running custom internet server software, it's more cost-effective and convenient to use a standard Nano module which includes the USB hardware.

The internet server software running on the PC serves a continuously-updated image (captured from the VGA-to-AV converter) to a webpage and listens for "switching requests" from the webpage. The switching requests take the form of HTTP POST requests, when a visitor presses a SUBMIT button, and consist of a 4-digit code key. If the requested code matches a user-configured code key in the server software, the server sends the key via a serial USB port to the Arduino switching hardware.

It should be noted that this isn't a secure "transaction" because the necessary code key is in plain view in the webpage's source code. However, the server software does provide for standard Username & Password HTML authentication for the webpage should this be required.

If the key matches a user-settable one configured in the Arduino software, an Arduino OUTPUT sends a short 5v pulse to the 2N7000 Mosfet. This simulates pressing the ZOOM button on the VGA-toAV Converter which, in turn, cycles to the next quadrant's image as explained above.

As the Arduino software is so simple, it seemed sensible to add a few extra features. So I added a simple push button to replicate pressing the VGA-to-AV converter's ZOOM button and an adjustable timer to cycle through the quadrant images automatically at a pre-set interval.

I also wanted a way to change the code key in the Arduino software so that more than one unit could be used at the same time without having to program "bespoke" code keys into each unit at construction time.

Both the adjustable timer and the ability to manually set the code key meant that some sort of display was needed so the project had suddenly expanded into the circuit below.

 

Download the PCB artwork in PDF format.

Download the PC server software (Windows 7, 10).

 

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>                      // https://github.com/adafruit/Adafruit-GFX-Library
#include <Adafruit_SSD1306.h>                  //https://github.com/adafruit/Adafruit_SSD1306

#include <EEPROM.h>

#define OLED_RESET 9                           // Our display doesn't use RESET so use a spare IO
Adafruit_SSD1306 oled(OLED_RESET);

#define pulseOut  7

#define Left  2
#define Push  3
#define Down  4
#define Right 5
#define Up    6

String key;                // This is the value sent by the VGA-Switcher software when it requests 
int keyNumber;             // a picture 'ZOOM'.  We convert it to an interger to save it in EEPROM.


byte mode = 35;            // Mode indicates which value will be changed by the < and > buttons.
                           // 0 = key value will be changed. 35 = timer value. Why not 0 and 1?
                           // 35 is simply a convenience as it is the 'Y' value on the OLED display.
                         
int tim = 0;               // Switching timer value saved in EEPROM.
unsigned long timerPreset; // 'tim' value (seconds) converted to milliseconds.
unsigned long timer;       // Current value of the running timer in milliseconds.

unsigned long holdTimer;           // Time in milliseconds a button is held. Increment rate increases...
unsigned long holdPreset = 5000;   // .. after holdPreset time (msec). 

void setup() {

   keyNumber = constrain(eepromReadInt(0), 0, 9999);   // Get key and timer values from EPROM.
   tim = constrain(eepromReadInt(2), 0, 600);
   timerPreset = tim * 1000;
   
   key = String(keyNumber);       // Convert key value to String for comparison with received string.

   pinMode(pulseOut, OUTPUT);     // Set inputs and poutput pin modes.

   pinMode(Push, INPUT_PULLUP);
   pinMode(Up, INPUT_PULLUP);
   pinMode(Down, INPUT_PULLUP);
   pinMode(Left, INPUT_PULLUP);
   pinMode(Right, INPUT_PULLUP);
   
   Serial.begin(9600);
   
   oled.begin(SSD1306_SWITCHCAPVCC, 0x3c);    // Start the OLED

   oled.setTextSize(2);
   oled.setTextColor(WHITE);
   updateDisplay();                           // Display values obtained from EEPROM.

   timer = millis();                          // Initialize the switching timer.
}

void loop() {
  if (digitalRead(Push) == LOW) {             // If Push button is pressed, send a pulse.
      sendPulse();
      while(digitalRead(Push) == LOW);
  }

  if (Serial.available() > 0) {                              // If a received string matches our key,
    if (Serial.readString() == key) sendPulse();             // send a pulse.
  }

  if ((tim > 0) && ((millis() - timer)  > timerPreset)) {    // If timer times out, send a pulse.
    sendPulse();
    timer = millis();
  }

  if ((digitalRead(Down) == LOW) || (digitalRead(Up) == LOW)) {   // Move cursor on OLED ro row 0
    mode == 0 ? mode = 35 : mode = 0;                             // or row 35.
    updateDisplay();                                              // Update the OLED display.
    while((digitalRead(Down) == LOW) || (digitalRead(Up) == LOW));
    delay(150);
  }

  if (digitalRead(Right) == LOW) {                      // If right button is pressed, increase..
    holdTimer = millis();                               // the key value if mode is 0 ir increase..
    while(digitalRead(Right) == LOW) {                  // the preset timer value if mode is 35.
      if (mode == 0) {
        keyNumber++;
        if (keyNumber > 9999) keyNumber = 0;
        key = String(keyNumber);
      }
  
      if (mode == 35) {
        tim += 10;
        if (tim > 600) tim = 0;
        timerPreset = tim * 1000;
      }
      updateDisplay();
      (millis() - holdTimer) > holdPreset ? delay(2) : delay(200);
    }
    if (eepromReadInt(0) != keyNumber) eepromWriteInt(0, keyNumber);    // Update values in EEPROM but
    if (eepromReadInt(2) != tim) eepromWriteInt(2, tim);                // only if they have changed.
  }

  if (digitalRead(Left) == LOW) {
    holdTimer = millis();
    while(digitalRead(Left) == LOW) {
      if (mode == 0) {
        keyNumber--;
        if (keyNumber < 0) keyNumber = 9999;
        key = String(keyNumber);
      }
  
      if (mode == 35) {
        tim -= 10;
        if (tim < 0) tim = 600;
        timerPreset = tim * 1000;
      }
      updateDisplay();
      (millis() - holdTimer) > holdPreset ? delay(2) : delay(200);
    }
    if (eepromReadInt(0) != keyNumber) eepromWriteInt(0, keyNumber);
    if (eepromReadInt(2) != tim) eepromWriteInt(2, tim);    
  }
  

}

void updateDisplay() {
  oled.clearDisplay();
  oled.setCursor(0, mode);
  oled.print(">");
  oled.setCursor(15,0);
  oled.print("Key:");
  oled.setCursor(75, 0);
  oled.print(key);
  oled.setCursor(15, 35);
  oled.print("Time:");
  oled.setCursor(75, 35);
  oled.print(tim);
  oled.display();
  
}

void sendPulse() {
  digitalWrite(pulseOut, HIGH);
  delay(150);
  digitalWrite(pulseOut, LOW);
}

// http://www.elcojacobs.com/storing-settings-between-restarts-in-eeprom-on-arduino/

int eepromReadInt(int address){
   int value = 0x0000;
   value = value | (EEPROM.read(address) << 8);
   value = value | EEPROM.read(address+1);
   return value;
}
 
void eepromWriteInt(int address, int value){
   EEPROM.write(address, (value >> 8) & 0xFF );
   EEPROM.write(address+1, value & 0xFF);
}


 

Back to Index

 


This site and its contents are © Copyright 2015 - All Rights Reserved.