====== Adding external switches to a WRAP board ====== This page will show how to install external switches on a WRAP board, and read their state from inside voyage. \\ Inspired by code samples by [[http://list.voyage.hk/pipermail/voyage-linux/2006-June/000969.html|William Brack]]. \\ Electrical information curtesy of William Brack and [[http://www.pcengines.ch/about.htm|Pascal Dornier]] (Creator of the WRAP board). ===== Why external switches? ===== External switches enable the user to set some parameters about the way the WRAP board operates, without the need to remotely connect to the board from another computer. ===== Background ===== The WRAP board contains an **LPC** bus connector (J2 on WRAP C/E, J6 on WRAP B, see [[http://www.pcengines.ch/wrap1c.pdf|WRAP board documentation]]). \\ **LPC** stands for Low-Pin-Count, which is some kind of a legacy bus for PCs (see [[http://www.intel.com/design/chipsets/industry/lpc.htm|LPC Specifications]], and [[http://en.wikipedia.org/wiki/Low_Pin_Count|Wikipedia Article]]). With the SC1100 chip (the main CPU of the WRAP board), one can disable the LPC bus, and use the connector as simple GPIO ([[http://en.wikipedia.org/wiki/GPIO|General Purpose I/O]]). Once configured as GPIO, 7 pins on the J2 connector can be configured for either INPUT (shown on this page) or OUTPUT (shown in William Brack's samples). The switches will be connected to the GPIO PIN and to a GND pin (through a 100 ohm resistor). INPUT pins will use the on-board 2.7Kohm pull-up resistors, and when the switch is in CLOSED position, it will pull-down the voltage to GND, signalling "LOW" status. ===== Hardware ===== For each external switch, you'll need: * A mechanical switch * One 100 ohm resistor * Some wires * Heat shrink tube (highly recommended) * Basic soldering capabilities. ==== Building the switches ==== Take the switch (solder wires to it), and the resistor: \\ {{:wrap_switch1.jpg}} \\ Solder the resistor to the wires: \\ {{:wrap_switch2.jpg}} \\ Use heat shrink tube to protect the wires and the resistor: \\ {{:wrap_switch3.jpg}} \\ ==== Preparing the WRAP board enclosure ==== If you bought the standard WRAP enclosure, you'll need to drill some holes in it, to make room for the switches. \\ This is an (ugly) example of such drilling: \\ The left-most and right-most holes are for the WiFi SMA connectors. \\ The three middle holes are for the switches. \\ (The quasi-rectangle at the bottom right is a sorry attempt to make a CompactFlash-sized hole). \\ {{:wrap_switch5.jpg}} \\ Here is a top view picture of the switches installed (before adding the resistors): \\ (In the red rectangle - the LPC connector) \\ {{:wrap_switch6.jpg}} ==== Connecting the Switches to the LPC connector ==== * A [[http://en.wikipedia.org/wiki/Wire_wrap|Wire-Wrap]] tool is the easiest way to connect the switch's wires to the LPC connector. * A 20-Pin connector (if you have one) is also a convenient solution: simply solder the switch's wires to the appropriate wires of the connector: \\ {{:wrap_switch4.jpg}} Recommended PIN connections: ^ Switch # ^ from PIN ^ to PIN ^ GPIO # ^ | 1 | PIN 3 (called LAD0) | PIN 4 (GND) | GPIO 32 | | 2 | PIN 5 (called LAD1) | PIN 6 (GND) | GPIO 33 | | 3 | PIN 7 (called LAD2) | PIN 8 (GND) | GPIO 34 | | 4 | PIN 9 (called LAD3) | PIN 10 (GND) | GPIO 35 | | 5 | PIN 11 (called LFRAME#) | PIN 12 (GND) | GPIO 37 | | 6 | PIN 19 (called SERIRQ) | Any GND PIN | GPIO 39 | | 7 | PIN 20 (called LDRQ# | Any GND PIN | GPIO 36 | (On the rest of this page, only two switches are used, with PINs 3,4,5 and 6). ==== Assembled WRAP board ==== (The left-most switch is a dummy, it isn't connected to anything) \\ {{:wrap_switch7.jpg}} ===== Software ===== There are three parts to the software side: * Configuring the SC1100 chip, to disable the LPC bus and make it work like an ordinary GPIO. * Reading the GPIO PIN status. * Writing a script/program to act upon the status of the switches. ==== Configuring the SC1100 chip ==== Based on a program by [[http://list.voyage.hk/pipermail/voyage-linux/2006-June/000969.html|William Brack]]. \\ The only change (from William's version) is that the 6 GPIOs are used with "output disabled" (value 0x44 instead of 0x45) ). /* * Note: See Page 50 of the SC1100 datasheet for PMR register info * and Page 196 for GPIO information */ #include #include #include #define GPIO_REGS 0xf400 int main(int nargs, char **argv) { unsigned int val; /* * The main requirement is to clear Bit14 in order to change * from the LPC config onto a straight GPIO config. Other bits * are specified as "must be 0", so we clear them as well. * Bits 31-30, 26, 24-22, 20 and 15 should be written as '0'; * Clear bit 14 disable the LPC, to use GPIO pins on the header * Remaining bits unchanged. * 0011 1010 0010 1111 0011 1111 1111 1111 */ unsigned int mask = 0x3a2f3fff; /* bit_ids is the GPIO bit number */ unsigned char bit_ids[] = { 32, 33, 34, 35, 36, 37 }; /* Bits 6-4 are only for PME's, which we aren't using (so they don't * matter). Bit 3 *must* be kept 0, so the only important ones are * bits 2-1-0. We use the internal pull-ups for both the output pins * and the input pins. Output must be enabled for all (otherwise we * can't disable the pull-ups on the inputs). * * bit_cfg b6 1=> debounce * b5 0=> low level / falling edge * b4 0=> edge trigger * b3 0=> no lock * b2 1=> internal pull-up (if b1:0 == 01) * b1 0=> open drain * b0 1=> output enabled */ unsigned char bit_cfg[] = { 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 }; int ix; iopl(3); /* Give us lots of privilege */ val = inl(0x9030); /* Fetch the PMR (32-bit fetch) */ fprintf(stderr, "PMR register was %08x, setting it to %08x\n", val, val & mask); val = val & mask; /* Clear bits 31-24, 16, 14 */ outl(val, 0x9030); /* Write out the changed value */ val = inl(0x9030); fprintf(stderr, "PMR register now %08x\n", val); /* Now set the GPIO configuration for our desired bits */ val = inl(GPIO_REGS+0x18); /* read existing interrupt enable bits */ fprintf(stderr, "GPIO Int Enable1 was %08x, clearing our bits\n", val); val &= 0xffc0; /* clear 37-32 */ outl(val, GPIO_REGS+0x18); for (ix = 0; ix < sizeof(bit_ids); ix++) { fprintf(stderr, "Writing %08x to 0x20\n", (unsigned)bit_ids[ix]); outl((unsigned)bit_ids[ix], GPIO_REGS+0x20); fprintf(stderr, "Writing %08x to 0x24\n", (unsigned)bit_cfg[ix]); outl((unsigned)bit_cfg[ix], GPIO_REGS+0x24); } /* For the input pins, we need to write a '1'. This will * assure that the pins are not driven low. Since the pull-ups * are active, with no input there should be a HI, and if the * input is forced LO we will be able to sense it. * * For the output pins, we will also initialize all of the ports * to a HI (which should be what was previously present when the * port was configured as LPC). */ val = inl(GPIO_REGS+0x10) & 0x3f; outl(val, GPIO_REGS+0x10); fprintf(stderr, "All done\n"); return 0; } ==== Reading the GPIO PIN status ==== This is a modified version of William's ''gp_ctl.c'' program. \\ This verion only reads the status of one GPIO port, returns either "1" or "0" (for easy scripting integration). #include #include #include /* This is the offset (this is always the offset on the WRAP board) of the F0BAR0 register */ #define DATA 0xf400 void usage() { fprintf(stderr,"usage: wrap_read_gpio [GPIO#]\n" "\tGPIO# = 32 to 37,and 39\n" "\nThese ports are present on the LPC connector.\n" "Read the WRAP board manual for details.\n" ) ; exit(0); } int main(int nargs, char **argv) { unsigned int val ; unsigned int gpio ; if (nargs!=2) usage(); gpio = atoi(argv[1]) ; if ( (gpio != 39) && (gpio<32 || gpio>37) ) { fprintf(stderr, "Error: invalid GPIO port (%s)\n", argv[1]) ; exit(0); } /* Request I/O prvileges */ iopl(3); /* Offset 0x14 is GPIO-Data-In-1-Register. See table 6-30 on the SC1100 data sheet. This register contains 1 bit status for each GPIO in range 32 to 63*/ val = inl(DATA+0x14); /* Clear all bits except the GPIO bit that we need. */ val = val & (1 << (gpio-32)) ; printf("%c\n", (val!=0) ? '1' : '0') ; return 0; } ==== Acting upon a switch status ==== This example shows how to enable/disable the wireless network interface, according to the switch state. \\ This example assumes the following: * The SC1100 configuring program is called ''/usr/local/bin/setup_gpio_input''. * The program to read the GPIO pin status is called ''/usr/local/bin/wrap_read_gpio''. * The file ''/etc/network/intefaces'' does **not** contain the directive ''auto ath0'' - so the WiFi interface is **not** loaded automatically at boot time. * This script is placed in ''/etc/init.d'', and is started as part of the boot process \\ (By creating a soft-link to it in ''/etc/rc2.d'' ). #!/bin/sh case $1 in 'start') echo -n "Network Loader: checking switch (on GPIO33)..." /usr/local/bin/setup_gpio_input 2> /dev/null STATE=`/usr/local/bin/wrap_read_gpio 33` if [ "$STATE" == "1" ] ; then echo "ON! turning on network interfaces." /etc/init.d/hostapd stop ifup ath0 /etc/init.d/hostapd start else echo "OFF, leaving networking interfaces down." fi ;; *) ;; esac ===== External Links ===== * WRAP board [[http://www.pcengines.ch/wrap.htm|general information]]. * WRAP board [[http://www.pcengines.ch/wrap1c.pdf|Documentation]]. * [[http://www2.amd.com/us-en/protected/ConnectivitySolutions/ProductInformation/1,,50_2330_9863_10524%5e10835,00.html?doc=ODQwNTE=|AMD Geode SC1100 Processor Data Book]] \\ (If this link doesn't work, try [[http://www.google.co.il/search?q=AMD+Geode+SC1100+Processor+Data+Book|Searching with Google]]). ===== About ===== * This page was written by Assaf Gordon (agordon88 [at] gmail-please-no-spam [dot] com ). * William Brack was the first (I think) to send GPIO information and code samples to the voyage mailing list. \\ Code on this page is based on his samples. * Many thanks to both William and Pascal Dornier for the electrical suggestions. ===== Disclaimer ===== * These instructions can be hazadous both to your health (if you touch the wrong end of the soldering iron) and to your WRAP board hardware (if you connect a wrong thing to a wrong connector). \\ **USE AT YOUR OWN RISK ** * I shall not be held responsible to any damage caused by following these instructions...