Repairing a 1960s-era IBM keypunch: controlled by mechanical tabs and bars

In this article I describe repairing an IBM 029 keypunch that wouldn't punch numbers. Keypunches were a vital component of punch card computing, recording data as holes in an 80-column card. Although keypunches have a long history, dating back to the use of punch cards in the 1890s, the IBM 029 keypunch is slightly more modern, introduced in 1964. The repair turned out to be simple, but in the process I learned about the complex mechanical process keypunches used to encode characters.

Keyboard of an IBM 029 keypunch. "Numeric" key is in the lower left. Strangely, this keyboard labels most special characters with the holes that are punched (e.g. 12-8-6) rather than the character. Compare with the photo of a different 029 keyboard later.

Keyboard of an IBM 029 keypunch. "Numeric" key is in the lower left. Strangely, this keyboard labels most special characters with the holes that are punched (e.g. 12-8-6) rather than the character. Compare with the photo of a different 029 keyboard later.

A couple weeks ago, I was using the 029 keypunch in the Computer History Museum's 1401 demo room and I found that numbers weren't punching correctly. The keyboard has a "Numeric" key that you press to punch a number or special character. (Unlike modern keyboards with a row of numbers at the top, numbers on the 029 keyboard share keys with letters.) When I tried to type a number, I got the corresponding letter; the keypunch was ignoring the "Numeric" key. The same happened with special characters that required "Numeric".

Frank King, an expert on repairing vintage IBM computers, showed me how to fix the keyboard. The first step was to remove the keyboard from the desk. This was surprisingly easy—you just rotate the keyboard clockwise and lift it up.

The keyboard of an IBM 029 keypunch can be removed from the desk simply by rotating and lifting.

The keyboard of an IBM 029 keypunch can be removed from the desk simply by rotating and lifting.

On the underside of the keyboard are several microswitches for some special function keys. The microswitches are on the left half, connected by blue wires. Also note the metal rectangles along the right; these are the "latch contacts", one for each key and will be discussed later.

The underside of the IBM 029 keypunch's keyboard.

The underside of the IBM 029 keypunch's keyboard.

Frank noticed that the keystem for the "Numeric" key wasn't pressing the microswitch, but was out of alignment and missing the microswitch's lever entirely. Thus, pressing the "Numeric" key had no effect and the wrong character was getting punched. He simply rotated the microswitch slightly so it was back into alignment with the keystem, fixing the problem. We placed the keyboard back into the desk and the keypunch was back in business. Many vintage computer repairs are difficult, but this one was quick and easy.

How the keypunch encodes characters

This repair was a good opportunity to look inside the keyboard and study the interesting techniques it uses to encode characters. On a punch card, each character is indicated by the holes punched in one of the card's 80 columns, as shown below. The digits 0 through 9 simply result in a punch in row 0 through 9. Letters are indicated by a punch in digit rows 1 through 9 combined with a punch in one of the top three rows (the "zone" rows1). Special characters usually use three punches. Since each character can have punches in any of 12 rows, you can think of cards as using a (mostly-sparse) 12-bit encoding.

An 80-column punch card stores one character in each column. The pattern of holes in the column indicates the character. From the 029 Reference Manual.

An 80-column punch card stores one character in each column. The pattern of holes in the column indicates the character. From the 029 Reference Manual.

Since each key on the keyboard has one character in alpha mode and another character in numeric mode, the keypunch must somehow determine the hole pattern for each character. With modern technology, you could simply use a tiny ROM to hold a 12-bit row value for the "alpha" mode and a second 12-bit value for the "numeric" mode. (Or use a keyboard encoding chip, digital logic, a microcontroller, etc.) But back in the keypunch era, ROMs weren't available. Instead, the keypunch uses a complex but clever mechanical technique to assign a hole pattern to each character.

The previous model: the 026 keypunch

IBM 026 keypunch. Photo by Paul Sullivan (CC BY-ND 2.0).

IBM 026 keypunch. Photo by Paul Sullivan (CC BY-ND 2.0).

Before explaining how the 029 keypunch encodes characters, I'll discuss the earlier and simpler IBM 026 keypunch, which was introduced in July 1949. The 026 used the technology of the 1940s: vacuum tubes and electromechanical relays. Encoding the hole pattern with tubes or relays would be bulky and expensive. Instead, the keypunch used a mechanical encoder with metal tabs to indicate where to punch holes.

The keyboard mechanism in the 026/029 keypunch. Pressing a key pulls the latch pull-bar. This causes the permutation bar to drop slightly. If a bail has a matching tab, the permutation bar will move the bail, closing the contact. The permutation bar also closes the key's latch contact. Based on the Maintenance Manual.

The keyboard mechanism in the 026/029 keypunch. Pressing a key pulls the latch pull-bar. This causes the permutation bar to drop slightly. If a bail has a matching tab, the permutation bar will move the bail, closing the contact. The permutation bar also closes the key's latch contact. Based on the Maintenance Manual.

The diagram above shows the keyboard mechanism in the keypunch. The basic idea is there are 12 "bail contacts" (one for each row on the card); when you press a key, the appropriate contacts are closed to punch holes in the desired rows. To implement this, each key was connected to a separate vertical "permutation bar" by a "latch pull-bar". When a key is pressed, the associated permutation bar drops down. Twelve horizontal bars, called "bails",2 ran perpendicular to the permutation bars, one bail for each row on the card. At each point where a bail crossed a key's permutation bar, the bail could have a protruding tab that meshes with the permutation bar. Pressing a key would cause the permutation bar to push the tab and rotate the bail, closing the bail contact and punching a hole in that row. Thus, the 12 bails mechanically encoded the mapping from keys to holes by the presence or absence of metal tabs along their length.

Closeup of the bails and one of the permutation bars. Four of the bails have tabs and will be triggered by the permutation bar.

Closeup of the bails and one of the permutation bars. Four of the bails have tabs and will be triggered by the permutation bar.

The photo above shows a permutation bar (right) engaging four tabs on the bails (left). In the photo below, you can see one of the bails removed from the keyboard mechanism. Note the tabs extending from the bail to engage with the permutation bars. Also note the contact on the left end of the bail.

The keyboard mechanism in the 029 keypunch. From the Maintenance Manual.

The keyboard mechanism in the 029 keypunch. From the Maintenance Manual.

There is a problem with this 12-bail mechanism: it only handles a single character per key, so it doesn't handle numbers. (The keyboard diagram below shows how numbers share keys with letters.) The obvious solution is to add 12 more bails for the second character on a key, but this would double the cost of the mechanism. However, since numbers are indicated by a single punch in a column, a shortcut is possible: use a switch on each number key to punch that row. The 026 keypunch does this, using the latch contacts shown in the earlier diagram. In numeric mode, the latch contact for the "1" key would punch row 1, and so forth for the other numbers. To handle the special characters, three additional bails were added, bringing the total number of bails to 15.5 Thus, the 026 had 12 bails used in alpha mode, 3 bails used in numeric mode for special characters, and a latch contact for each key for numbers and special characters.

Keyboard of the IBM 026 keypunch. From the IBM 24/26 Reference Manual.

Keyboard of the IBM 026 keypunch. From the IBM 24/26 Reference Manual.

The permutation bar and bail mechanism also explains why the "Numeric" key (the one we fixed) has a separate microswitch under the keyboard. The regular mechanism with permutation bars, bails and latch contacts only allows one key to be pressed at a time.3 Since "Numeric" is held down while another key is pressed, it needed a separate mechanism.4

Back to the 029 keypunch

When the 029 keypunch was introduced in 1964, it replaced the 026's vacuum tubes with transistorized circuitry and updated the keypunch's appearance from 1940's streamlining to a modernist design. However, the 029 kept most of the earlier keypunch's internal mechanical components, along with many relays.6

Keyboard from the IBM 029 keypunch. Photo by Carl Claunch.

Keyboard from the IBM 029 keypunch. Photo by Carl Claunch.

A major functional improvement over the 026 was the addition of many more special characters in the 029; almost every key on the keyboard had a special character. The three numeric mode bails used in the 026 couldn't support all these special characters. The obvious solution would be to add more bails; with 12 bails for alpha and 12 bails for numeric, any characters could be encoded. But, IBM came up with a solution for the 029 that supported the new special characters while still using the 026's 15-bail mechanical encoder. The trick was to assign the bails to rows in a way that handled most of the holes, leaving the latch contact to handle one additional "extra" hole per key.7

The diagram below shows part of the encoding mechanism, based on the keypunch schematics.8 Horizontal lines correspond to the 15 bails; the labels on the left show the row handled by each bail. Each vertical line represents the permutation bar for a key; the key labels are at the bottom. The black dots correspond to tabs on the bail, causing the bail to tripped when activated by the corresponding key. (The circles symbolize the interlock disks that keep two keys from being used simultaneously.3) Note that the 029's bails don't handle all the rows for alpha mode (unlike the 026), leaving some alpha holes to be punched by the latch contacts.

Diagram showing how keys select holes to be punched on the 029 keypunch. The complete diagram is in the schematic.

Diagram showing how keys select holes to be punched on the 029 keypunch. The complete diagram is in the schematic.

The yellow highlights on the diagram show what happens for the "W _" key. Pressing this key (bottom) will activate the "Numeric 5", "Numeric 8" and "Common 0" bails (left). In addition, the latch contact will activate "Alpha 6" (top). Putting this together, in alpha mode, rows 0 and 6 will be punched and in numeric mode, rows 0, 8 and 5 will be punched. These are the codes for "W" and "_" respectively, so the right holes get punched. The encoder works similarly for other keys, punching the appropriate holes in alpha and numeric modes. Thus, the 029 managed to extend the 026's character set with many new special characters, without requiring a redesign of the mechanical encoder.

An IBM 029 keypunch in the middle of punching cards.

An IBM 029 keypunch in the middle of punching cards.

Conclusion

For once, repairing computer equipment from the 1960s was quick and easy. Fixing the "Numeric" key didn't even require any tools. The repair did reveal the interesting mechanism used to determine which holes to punch. In the era before inexpensive ROMs, keyboard decoding was done mechanically, with tabs on metal bars indicating which holes to punch. This mechanism was inherited from the earlier 026 keypunch (1949), improved on the 029 keypunch (1964) to handle more symbols, and was finally replaced by electronic encoding when the 129 keypunch was introduced in 1971.6

Follow me on Twitter or RSS to find out about my latest blog posts.

Notes and references

  1. The card's zone rows are called 12 (on top) and 11 (below 12). Confusingly, sometimes the 0 row acts as a zone (for a letter) and sometime it acts as a digit (for a number). Also note the special characters that use 8 combined with a digit from 2 to 7; essentially this corresponds to a binary value from 10 to 15. The combination of a zone punch and digit punches encoded a 6-bit character. 

  2. "Bail" may seem like an obscure word in this context, but it's essentially a metal bar. Looking at old patents, in the early 1900s "bail" was most often used to denote a wire handle on a bucket or pot. It then got generalized to a metal bar in various mechanism, especially one that could be lifted up. If you're from the typewriter era, you might remember the "paper bail", the bar that holds the paper down. (Dictionary link.) 

  3. An interesting mechanism ensures that only one key can be pressed at a time. The keyboard mechanism contains a row of "interlock disks". When a key is pressed the latch bar slides between two of these disks. These disks slide all the other disks over, blocking the path of any other key's latch bar until the first key is released. 

  4. The other special keys that use a microswitch are "Error reset", "Multi punch", "Dup", "Feed", "Prog 1", "Prog 2" and "Alpha". 

  5. The 026 keypunch used a clever trick for some of the special characters. Note the four special character keys in the upper left. These characters were carefully assigned so each pair has the same punch except the upper one punches a 3 and the lower punches a 4. Thus, a single encoding worked for the key with the addition of a relay to switch between 3 and 4. 

  6. In 1964 IBM introduced the IBM 360 line of computers. They were built from hybrid SLT (Solid Logic Technology) modules, an alternative to integrated circuits. Although the IBM 029 keypunch was introduced along with the SLT-based IBM 360, the keypunch used older transistorized SMS boards. Even though the 029 got rid of the 026's vacuum tubes, it was still a generation behind in technology. It wasn't until the 129 keypunch was announced in 1971 (along with the 370 computer line) that keypunches moved to SLT technology.

    The 129's keyboard kept much of the mechanical structure of the older keypunches (the permutation bars and latch contacts), but got rid of the bails used to encode the keypresses. Instead, encoding in the 129 was done through digital logic SLT modules (mostly AND-OR gates) controlled by the latch contact switches. The 026 and 029 keypunches originally had model numbers 26 and 29, but with the introduction of the 129, their names were retconned to the 026 and 029. 

  7. It's not easy to design a keyboard layout that works with the 029 mechanism since the latch contact can support at most one "extra" hole per key, a hole not handled by the bails. The special characters needed to be assigned to keys in a way that would work; this probably explains the semi-random locations of the special characters on the keyboard. For instance, "(" is on "N" while ")" is on "E". Since both ")" and "E" require a hole in row 5, it made sense to put them on the same key, so the latch contact can handle the 5 punch for both. 

  8. If you want to learn more about keypunch internals, the manuals are on bitsavers.org. In particular, see the Reference Manual, Maintenance Manual and Schematics

Creating a Christmas card on a vintage IBM 1401 mainframe

I recently came across a challenge to print a holiday greeting card on a vintage computer, so I decided to make a card on a 1960s IBM 1401 mainframe. The IBM 1401 computer was a low-end business mainframe announced in 1959, and went on to become the most popular computer of the mid-1960s, with more than 10,000 systems in use. The 1401's rental price started at $2500 a month (about $20,000 in current dollars), a low price that made it possible for even a medium-sized business to have a computer for payroll, accounting, inventory, and many other tasks. Although the 1401 was an early all-transistorized computer, these weren't silicon transistors—the 1401 used germanium transistors, the technology before silicon. It used magnetic core memory for storage, holding 16,000 characters.

A greeting card with a tree and "Ho Ho Ho" inside, created on the vintage 1401 mainframe. The cards are on top of the 1403 line printer, and the 1401 mainframe is in the background.

A greeting card with a tree and "Ho Ho Ho" inside, created on the vintage 1401 mainframe. The cards are on top of the 1403 line printer, and the 1401 mainframe is in the background.

You can make a greeting card by printing a page and then folding it into quarters to make a card with text on the front and inside. The problem with a line-printer page is that when you fold it into a card shape, the printed text ends up sideways, so you can't simply print readable text. So I decided to make an image and words with sideways ASCII graphics. (Actually the 1401 predates ASCII and uses a 6-bit BCD-based character set called BCDIC, so it's really BCDIC graphics. (EBCDIC came later, extending BCDIC to 8 bits and adding lower case.)) Originally I wanted to write out "Merry Christmas", but there aren't enough characters on a page to make the word "Chrstmas" readable, so I settled on a cheery "Ho Ho Ho". I figured out how to sideways draw a tree and the words, making this file.

Closeup of a greeting card printed on the IBM 1401, with a Christmas tree on the front.

Closeup of a greeting card printed on the IBM 1401, with a Christmas tree on the front.

Next, I needed a program to print out this file. I have some experience writing assembly code for the IBM 1401 from my previous projects to perform Bitcoin mining on the 1401 and generate Mandelbrot fractals. So I wrote a short program to read in lines from punched cards and print these lines on the high-speed 1403 line printer. The simple solution would be to read a line from a card, print the line, and repeat until done. Instead, I read the entire page image into memory first, and then print the entire page. The reason is that this allows multiple greeting cards to be printed without reloading and rereading the entire card deck. The second complication is that the printer is 132 columns wide, while the punch cards are 80 columns. Instead of using two punch cards per print line, I encoded cards so a "-" in the first column indicates that the card image should be shifted to the right hand side of the page. (I could compress the data, of course, but I didn't want to go to that much effort.)

The 1401 has a strange architecture, with decimal arithmetic and arbitrary-length words, so I won't explain the above code in detail. I'll just point out that the r instruction reads a card, mcw moves characters, w writes a line to the printer, and bce branches if a character equals the specified value. (See the reference manual for details.)

The next step was to punch the code and data onto cards. Fortunately, I didn't need to type in all the cards by hand. Someone (I think Stan Paddock) attached a USB-controlled relay box to a keypunch, allowing a PC to punch cards.

A PC-controlled IBM 029 keypunch punched my card deck.

A PC-controlled IBM 029 keypunch punched my card deck.

A few minutes later I had my deck of 77 punch cards. The program itself just took 9 cards; the remainder of the cards held the lines to print.

The deck of punched cards I ran on the IBM 1401. The first few cards are the program, and the remaining cards hold the lines to print.

The deck of punched cards I ran on the IBM 1401. The first few cards are the program, and the remaining cards hold the lines to print.

Once the cards were ready, we loaded the deck into the card reader and hit "Load", causing the cards to start flying through the card reader at a dozen cards per second. Unfortunately, the reader hit an error and stopped. Apparently the alignment of the holes punched by the keypunch didn't quite match the alignment of the card reader, causing a read error.

The IBM 1401's card reader was experiencing errors, so we removed the brushes and realigned them.

The IBM 1401's card reader was experiencing errors, so we removed the brushes and realigned them.

The card reader contains sets of 80 metal brushes (one for each column of the card) that detect the presence of a hole. Computer restoration expert Frank King disassembled the card reader, removed the brush assembly from the card reader and adjusted it.

A closeup of the brush module with 80 brushes that read a card.

A closeup of the brush module with 80 brushes that read a card.

After a few tries, we got the card reader to read the program successfully and it started executing. The line printer started rapidly and noisily printing the lines of the card. We had to adjust the line printer's top-of-form a couple times so the card fit on the page, but eventually we got a successful print.

Printing a greeting card on the IBM 1403 line printer.

Printing a greeting card on the IBM 1403 line printer.

I ejected the page from the printer, tore it off, and folded the card in quarters, yielding the final greeting card. It was a fun project, but Hallmark still wins on convenience.

Greeting card created by the IBM 1401 mainframe (background).

Greeting card created by the IBM 1401 mainframe (background).

If you want to know more about the IBM 1401, I've written about its internals here. The Computer History Museum in Mountain View runs demonstrations of the IBM 1401 on Wednesdays and Saturdays. It's amazing that the restoration team was able to get this piece of history working, so if you're in the area you should definitely check it out; the demo schedule is here.

Follow me on Twitter or RSS to find out about my latest blog posts.

Decoding an air conditioner control's checksum with differential cryptanalysis

Back in 2009 I wrote an Arduino library (IRRemote) to encode and decode infrared signals for remote controls. I got an email recently from someone wanting to control an air conditioner. It turns out that air conditioner remote controls are much complicated than TV remote controls: the codes are longer and include a moderately complex checksum. My reader had collected 35 signals from his air conditioner remote control, but couldn't figure out the checksum algorithm. I decided to use differential cryptanalysis to figure out the checksum, which was overkill but an interesting exercise. In case anyone else wants to decode a similar remote control, I've written up how I found the algorithm.

My IR remote library can be used with the Arduino to send and receive signals. (This is not the air conditioner remote.)

My IR remote library can be used with the Arduino to send and receive signals. (This is not the air conditioner remote.)

The problem is to find a checksum algorithm that when given three bytes of input (left), computes the correct one byte checksum (right).

10100001 10010011 01100011 => 01110111
10100001 10010011 01100100 => 01110001
10100001 10010011 01100101 => 01110000
10100001 10010011 01100110 => 01110010
10100001 10010011 01100111 => 01110011
10100001 10010011 01101000 => 01111001
10100001 10010011 01101001 => 01111000
10100001 10010011 01101010 => 01111010
10100001 10010011 01101011 => 01111011
10100001 10010011 01101100 => 01111110
10100001 10010011 01101101 => 01111111
10100001 10010011 01101110 => 01111100
10100001 10010011 01101111 => 01111101
10100001 10010011 01110001 => 01100100
10100001 10010011 01110010 => 01100110
10100001 10010011 01110011 => 01100111
10100001 10010011 01110100 => 01100001
10100001 10010011 01110101 => 01100000
10100001 10010011 01110111 => 01100011
10100001 10010011 01110111 => 01100011
10100001 10010011 01111000 => 01101001
10100001 10010011 01101000 => 01111001
10100001 00010011 01101000 => 11111001
10100001 00010011 01101100 => 11111110
10100001 10010011 01101100 => 01111110
10100001 10010100 01111110 => 01101011
10100001 10000010 01101100 => 01100000
10100001 10000001 01101100 => 01100011
10100001 10010011 01101100 => 01111110
10100001 10010000 01101100 => 01111100
10100001 10011000 01101100 => 01110100
10100001 10001000 01101100 => 01101100
10100001 10010000 01101100 => 01111100
10100001 10011000 01101100 => 01110100
10100010 00000010 11111111 => 01111110

The idea behind differential cryptanalysis is to look at the outputs resulting from inputs that have a small difference, to see what patterns emerge (details). Finding air conditioner checksums is kind of a trivial application of differential cryptanalysis, but using differential cryptanalysis provides a framework for approaching the problem. I wrote a simple program that found input pairs that differed in one bit and displayed the difference (i.e. xor) between the corresponding checksums. The table below shows the differences.

000000000000000000000001 : 00000001
000000000000000000000010 : 00000010
000000000000000000000010 : 00000011
000000000000000000000100 : 00000100
000000000000000000000100 : 00000110
000000000000000000000100 : 00000111
000000000000000000001000 : 00001100
000000000000000000001000 : 00001110
000000000000000000001000 : 00001111
000000000000000000010000 : 00010000
000000000000100000000000 : 00001000
000000000001000000000000 : 00011000
000000001000000000000000 : 10000000

The first thing to notice is that changing one bit in the input causes a relatively small change in the output. If the checksum were something cryptographic, a single bit change would entirely change the output (so you'd see half the bits flipped on average). Thus, we know we're dealing with a simple algorithm.

The second thing to notice is the upper four bits of the checksum change simply: changing a bit in the upper four bits of an input byte changes the corresponding bit in the upper four bits of the output. This suggests that the the three bytes are simply xor'd to generate the upper four bits. In fact, my reader had already determined that the xor of the input bytes (along with 0x20) yielded the upper four bits of the checksum.

The final thing to notice is there's an unusual avalanche pattern in the lower four bits. Changing the lowest input bit changes the lowest checksum bit. Changing the second-lowest input bit changes the second-lowest checksum bit and potentially the last checksum bit. Likewise changing the fourth-lowest input bit changes the fourth-lowest checksum bit and potentially the bits to the right. And the change pattern always has 1's potentially followed by 0's, not a mixture. (1100, 1110, 1111)

What simple operation has this sort of avalanche effect? Consider adding two binary numbers. If you change a high-order bit of an input, only that bit will change in the output. If you change a low-order input bit, the low-order bit of the output will change. But maybe there will be a carry, and the next bit will change. And if there's a carry from that position, the third bit will change. Likewise, changing a bit in the middle will change that bit and potentially some of the bits to the left (due to carries). So if you change the low-order bit, the change in the output could be 0001 (no carry), or 0011, or 0111, or 1111 (all carries). This is the same pattern seen in the air conditioner checksums but backwards. This raises the possibility that the checksum is using a binary sum, but we're looking at the bits backwards.

So I made a program that reversed the bits in the input and output, and took the sum of the four bits from each byte. The output below shows the reversed input, the sum, and the 4-bit value from the correct checksum. Note that the sum and the correct value usually add up to 46 or 30 (two short of a multiple of 16). This suggested that the checksum is (-sum-2) & 0xf.

110001101100100110000101 32 14
001001101100100110000101 22 8
101001101100100110000101 30 0
011001101100100110000101 26 4
111001101100100110000101 34 12
000101101100100110000101 21 9
100101101100100110000101 29 1
010101101100100110000101 25 5
110101101100100110000101 33 13
001101101100100110000101 23 7
101101101100100110000101 31 15
011101101100100110000101 27 3
111101101100100110000101 35 11
100011101100100110000101 28 2
010011101100100110000101 24 6
110011101100100110000101 32 14
001011101100100110000101 22 8
101011101100100110000101 30 0
111011101100100110000101 34 12
111011101100100110000101 34 12
000111101100100110000101 21 9
000101101100100110000101 21 9
000101101100100010000101 21 9
001101101100100010000101 23 7
001101101100100110000101 23 7
011111100010100110000101 17 13
001101100100000110000101 15 0 *
001101101000000110000101 19 12 *
001101101100100110000101 23 7
001101100000100110000101 11 3
001101100001100110000101 12 2
001101100001000110000101 12 3 *
001101100000100110000101 11 3
001101100001100110000101 12 2
111111110100000001000101 23 7

That formula worked with three exceptions (marked with asterisks). Studying the exceptions showed that adding in byte 1 bit 3 and byte 2 bit 7 yielded the correct answer in all cases.

Conclusion

Putting this together yields the following algorithm (full code here):

inbytes = map(bitreverse, inbytes)
xorpart = (inbytes[0] ^ inbytes[1] ^ inbytes[2] ^ 0x4) & 0xf
sumpart = (inbytes[0] >> 4) + (inbytes[1] >> 4) + (inbytes[2] >> 4) +
  (inbytes[2] & 1) + ((inbytes[1] >> 3) & 1) + 1
sumpart = (-sumpart) & 0xf
result = bitreverse((sumpart << 4) | xorpart)

Is this the right formula? It gives the right checksum for all the given inputs. However, some bits never change in the input data; in particular all inputs start with "101000", so there's no way of knowing how they affect the algorithm. They could be added to the sum, for instance, replacing the constant +1. The constant 0x4 in the xor also makes me a bit suspicious. It's quite possible that the checksum formula would need to be tweaked if additional input data becomes available.

I should point out that determining the checksum formula is unnecessary for most air conditioning applications. Most users could just hard-code the checksums for the handful of commands they want to send, rather than working out the general algorithm.

Thanks to Antonio Martinez Lavin, maker of the Cuby air conditioner controller for posing this problem. If you want to use my IR library, it is on GitHub. I'm no longer actively involved with the library, so please post issues on the GitHub repository rather than on this blog post. Thanks to Rafi Kahn, who has taken over library maintenance and improvement.

Follow me on Twitter or RSS to find out about my latest blog posts.

Hands-on with the PocketBeagle: a $25 Linux computer with lots of I/O pins

The PocketBeagle is a tiny but powerful inexpensive key-fob-sized open source Linux computer. It has 44 digital I/O pins, 8 analog inputs, and supports multiple serial I/O protocols, making it very useful as a controller. In addition, its processor includes two 200-MHz microcontrollers that allow you to implement low-latency, real-time functions while still having the capabilities of a Linux system This article discusses my experience trying out different features of the PocketBeagle, along with some technical details.

The PocketBeagle is a compact Linux computer, somewhat bigger than a quarter.

The PocketBeagle is a compact Linux computer, somewhat bigger than a quarter.

You may be familiar with the BeagleBone, a credit-card sized computer. The PocketBeagle is very similar to the BeagleBone, but smaller and cheaper. Both systems use TI's 1GHz "Sitara" ARM Cortex-A8 processor, but the PocketBeagle's I/O is stripped-down with 72 header pins compared to 92 on the BeagleBone. The PocketBeagle doesn't have the BeagleBone's 4GB on-board flash; all storage is on a micro-SD card. The BeagleBone's Ethernet and HDMI ports are also dropped.

The PocketBeagle uses an interesting technology to achieve its compact size—it is built around a System-In-Package (SIP) device that has multiple dies and components in one package (see diagram below). The Octavo Systems OSD3358-SM combines the TI 3358 Sitara processor, 512MB of RAM, power management and EEPROM. 1 In the photo above, this package has a white label and dominates the circuit board.

The PocketBeagle is powered by the OSD335x, which combines a processor die, memory and other components into a single package.

The PocketBeagle is powered by the OSD335x, which combines a processor die, memory and other components into a single package.

Initializing the SD card

To use the PocketBeagle, you must write a Linux file system to a micro-SD card. The easiest way to do this is to download an image, write it to the SD card from your computer, and then pop the SD card into the PocketBeagle. Details are in the footnotes.2

You can also compile a kernel from scratch, set up U-boot, and build a file system on the SD card. the PocketBeagle. There's a bunch of information on this process at Digikey's PocketBeagle getting started page. This is the way to go if you want flexibility, but it's overkill if you just want to try out the PocketBeagle.

Starting up the PocketBeagle

Unlike the BeagleBone, which supports a keyboard and an HDMI output, the PocketBeagle is designed as a "headless" device that you ssh into. You can plug the PocketBeagle into your computer's USB port, and the PocketBeagle should appear as a network device: 192.168.6.2 on Mac/Linux and 192.168.7.2 on Windows (details). You should also see a flash-drive style file system appear on your computer under the name "BEAGLEBONE". If the PocketBeagle has the default Debian OS3, you can log in with:

ssh [email protected]
Password: temppwd

Connecting to the PocketBeagle's serial console

While ssh is the simplest way to connect to the PocketBeagle, if anything goes wrong with the boot or networking, you'll need to look at the serial console to debug the problem. The easiest solution is a UART Click board4, which gives you a serial connection over USB. You can then connect with "screen" or other terminal software: screen /dev/cu.usbserial\* 115200

Plugging a UART click board into the PocketBeagle gives access to the serial console.

Plugging a UART click board into the PocketBeagle gives access to the serial console.

You can also use a FTDI serial adapter such as the Adafruit FTDI Friend. (If you've worked with the BeagleBone, you may have one of these already.) You'll need three wires to hook it up to the PocketBeagle; it won't plug in directly as with the BeagleBone. Just connect ground, Rx and Tx between the PocketBeagle and the adapter (making sure to cross Rx to Tx).5

Accessing the PocketBeagle's serial console through an FTDI interface.

Accessing the PocketBeagle's serial console through an FTDI interface.

Pinout

The PocketBeagle has two headers that provide access to I/O functions. (These headers are different from the BeagleBone's headers, so BeagleBone "capes" won't work with the PocketBeagle.) The PocketBeagle pinout diagram (below) shows what the header pins do. The diagram may seem confusing at first, since each pin has up to three different functions shown. (Most pins actually support 8 functions, so more obscure functions have been omitted.) The diagram is color coded. Power and system pins are labeled in red. GPIO (general-purpose I/O) pins are white. USB pins are blue. Analog inputs are yellow. UART serial pins are brown. PRU microcontroller pins are cyan. Battery pins are magenta. I2C bus is purple. PWM (pulse width modulation) outputs are light green. SPI (Serial Peripheral Interface) is brown. CAN (Controller Area Network) is dark green. QEP (quadrature encoder pulse) inputs are gray.9 The dotted lines in the diagram indicate the default pin functions (except for the PRU pins, which default to GPIO).6

Pinout diagram of the PocketBeagle's headers.
USB=blue, Power=yellow, GPIO=white, PRU=cyan, SPI=orange, UART=brown, and other colors are miscellaneous.

Pinout diagram of the PocketBeagle's headers. USB=blue, Power=yellow, GPIO=white, PRU=cyan, SPI=orange, UART=brown, and other colors are miscellaneous.

Note that the diagram shows the headers from the component side of the board, not the silkscreened side of the board. Comparing the pin diagram with the board (below), you will notice everything is flipped horizontally. E.g. GPIO 59 is on the right in the diagram and on the left below. So make sure you're using the right header!

Silkscreen labeling the PocketBeagle's header pins.

Silkscreen labeling the PocketBeagle's header pins.

One tricky feature of the Sitara processor is that each pin has up to eight different functions. The motivation is that the chip supports a huge number of different I/O functions, so there aren't enough physical pins for every desired I/O. The solution is a pin mapping system that lets the user choose which functions are available on each pin. 7 If you need to change a pin assignment from the default, the config-pin command will modify pin mappings. (Some examples will be given below.) Pins can also be configured at boot time using a "U-Boot overlay".8

GPIO

The PocketBeagle exposes 45 GPIO (general purpose I/O) pins on the headers. The pins can be easily controlled by writing to pseudo-files. For example, the following shell code repeatedly blinks an LED connected to GPIO 11110 (which is accessed through header pin P1_33).

echo out > /sys/class/gpio/gpio111/direction
while :; do
> echo 1 > /sys/class/gpio/gpio111/value; sleep 1
> echo 0 > /sys/class/gpio/gpio111/value; sleep 1
> done

An LED connected to header P1 pin 33 can be controlled through GPIO 111.

An LED connected to header P1 pin 33 can be controlled through GPIO 111.

PRU

One of the most interesting features of the PocketBeagle is its PRUs, two 32-bit RISC microcontrollers that are built into the Sitara processor chip. These microcontrollers let you perform time-critical operations (such as "bit-banging" a protocol), without worrying about context switches, interrupts, or anything else interfering with your code. At the same time, the ARM processor gives high performance and a complete Linux environment. (I've made use of the BeagleBone's PRU to interface to a vintage Xerox Alto's 3 Mb/s Ethernet.)

Although the PRUs are not as easy to use as an Arduino, they can be programmed in C, using the command line or Texas Instruments' CCS development environment. I've written about PRU programming in C before (link) and the underlying library framework (link) for the 3.8.13 kernel, but since then much has changed with the way the PRUs are accessed. The PRUs are now controlled through the remoteproc framework. In addition, a messaging library (RPMsg) makes it simpler to communicate between the PRUs and the ARM processor. A "resource_table.h" file provides setup information (such as the interrupts used).

The following code will turn the LED on (by setting a bit in control register 30), wait one cycle (5ns), turn the LED off, and wait again. Note that the PRU output is controlled by modifying a bit in register R30. This will blink the LED at 40Mhz, unaffected by any other tasks, context switches or interrupts. (For the full code and details of how to run it, see my github repository.)

void main(void)
{
  while (1) {
    __R30 = __R30 | (1<<1); // Turn on output 1
    __delay_cycles(1);
    __R30 = __R30 & ~(1<<1); // Turn off output 1
    __delay_cycles(1);
  }
}

This code uses PRU0 output 1, which is accessed through header pin P1_33 (the same pin as the earlier GPIO example). Since this pin defaults to the GPIO, it must be switched to a PRU output:11

config-pin P1_33 pruout

This LED example illustrates two key advantages of using the PRU versus controlling a GPIO pin from Linux.12 First, the PRU code can operate much faster. Second, the GPIO code will produce an uneven signal if the CPU is performing some other Linux task. If you can handle milliseconds of interruption, controlling GPIO pins from Linux is fine. But if you need exact cycle-by-cycle accuracy, the PRU is the way to go.

Networking

Unlike the BeagleBone, the PocketBeagle doesn't have a built-in Ethernet port. However, there are several options for connecting the PocketBeagle to the Internet, described in the PocketBeagle FAQ. I found the easiest was to use WiFi via a WiFi adapter plugged into USB, as shown below. An alternative is to share your host computer's Ethernet, which I found more difficult to get working.14 Finally, you can add an Ethernet interface to the PocketBeagle using the expansion headers.

A USB WiFi adapter can easily be connected to the PocketBeagle.

A USB WiFi adapter can easily be connected to the PocketBeagle.

USB

You can easily connect USB devices to the PocketBeagle since the PocketBeagle has pins assigned for a second USB port. Plug a USB Micro-B breakout board into the Pocket Beagle as shown below, connect a USB OTG host cable and your USB port should be ready to go. Note that this USB port is a host (i.e. a USB device is connected to the PocketBeagle) opposite from the onboard USB port which works as a client (the PocketBeagle is connected as a device to another computer).

A closeup of how to plug the USB breakout board into the PocketBeagle. It is connected to pins P1_7 through P1_15.

A closeup of how to plug the USB breakout board into the PocketBeagle. It is connected to pins P1_7 through P1_15.

For instance, you can plug in a flash drive. (In the picture below, note that the flash drive is almost as big as the PocketBeagle.) The lsusb command will show your device, and then you can mount it with sudo mount /dev/sda1 /mnt.

Connecting a USB device (flash drive) to the PocketBeagle.

Connecting a USB device (flash drive) to the PocketBeagle.

Analog inputs

The PocketBeagle has 8 analog input pins. Six of them take an input from 0 to 1.8V, while two take an input from 0 to 3.3V. (Be careful that you don't overload the input.) The analog input value (between 0 and 4095) can be read from the file system as shown below. Change the number in voltage0 to select the input. (Inputs 5 through 7 require special handling.15)

$ cat /sys/bus/iio/devices/iio:device0/in_voltage0_raw
2510

In the photo below, I hooked up a light sensor (CdS photocell in a voltage divider) to provide a voltage to analog input 0 (header pin P1_19). The reference voltages come from header pins P1_17 (analog ground) and P1_18 (analog reference 1.8V). More light on the sensor produces a higher voltage, yielding a higher value from the input.

A photocell can be hooked up to the PocketBeagle's analog input to provide a light sensor.

A photocell can be hooked up to the PocketBeagle's analog input to provide a light sensor.

I2C / SPI

The PocketBeagle supports two SPI ports and two I2C ports. These serial protocols are popular for controlling chips and other devices.

An accelerometer board (left) can be connected to the PocketBeagle's I2C port with four wires.

An accelerometer board (left) can be connected to the PocketBeagle's I2C port with four wires.

For example, the photo above shows a cheap I2C accelerometer board connected to the PocketBeagle's SPI port. Simply wire the power, ground, SCL (clock) and SDA (data) between the accelerometer and the PocketBeagle's I2C1 port (i.e. header P2 pins 13, 15, 9, 11). Probing for I2C devices with i2cdetect will show that the device uses address 68. The device can be turned on with i2cset and the registers dumped out with i2cdump to obtain acceleration values.16

Using an I2C-based accelerometer board with the PocketBeagle.

Using an I2C-based accelerometer board with the PocketBeagle.

Conclusion

The PocketBeagle is a low-cost, compact Linux computer, able to control external devices with its I/O ports and GPIO pins. Since the PocketBeagle was released recently, there isn't a whole lot of documentation on it. Hopefully this article has shown you how to get started with the PocketBeagle and use some of its features.

New (12/2017): The PocketBeagle System Reference Manual has lots of useful information, so take a look.

For more information, see the PocketBeagle FAQ and Getting Started pages. Also remember that the PocketBeagle uses the same processor and Linux kernel as the BeagleBone, so most of the information on the BeagleBone will carry over to the PocketBeagle. I've found the book Exploring BeagleBone to be especially helpful. Thanks to Robert Nelson and DigiKey for giving a PocketBeagle tutorial at Hackaday Superconference.

Follow me on Twitter or RSS to find out about my latest blog posts.

Notes and references

  1. The Octavo package reminds me a bit of the Solid Logic Technology (SLT) modules that IBM used in the 1960s instead of integrated circuits. They consisted of small metal packages containing semiconductor dies and resistors connected together on a ceramic wafer, and were used in computers such as the IBM 360.

    Two IBM SLT modules, with a penny for scale. Each module contains semiconductors (transistors or diodes) and printed resistors wired together, an alternative to integrated circuits.

    Two IBM SLT modules, with a penny for scale. Each module contains semiconductors (transistors or diodes) and printed resistors wired together, an alternative to integrated circuits.

  2. On a Mac, I used the following procedure to write the SD card. First, download an image from beagleboard.org. I use "Stretch IoT (non-GUI) for BeagleBone and PocketBeagle via microSD card". Then unmount the SD drive and format it as FAT-32. (Replace XXX below with the right drive number; don't format your hard disk!)

    diskutil list
    diskutil umountdisk /dev/diskXXX
    sudo diskutil eraseDisk FAT32 BEAGLE MBRFormat /dev/diskXXX
    sudo diskutil unmount /dev/diskXXXs1
    
    Then write the disk image to the SD card:
    zcat /tmp/pocketbeagle.img | sudo dd of=/dev/diskXXX bs=2m
    xzcat *.xz | sudo dd of=/dev/diskXXX
    
    Writing the image took about 10 minutes with a USB to micro-SD adapter. (If it's taking hours, I recommend a different USB adapter.) When done, install the SD card in the PocketBeagle. 

  3. I'm using Debian with kernel Linux beaglebone 4.14.0-rc8 #1 Mon Nov 6 15:46:44 UTC 2017 armv7l GNU/Linux. If you use a different kernel (such as 3.8.13), many of the software features will be different. 

  4. One interesting feature of the PocketBeagle is its headers have the right pinout to support many mikroBUS boards. This is an open standard for small boards (similar to capes/shields), using a 16-pin connector. Hundreds of "click boards" are available for connectivity (e.g. Bluetooth, WiFi, Ethernet, NFC), sensors (e.g. pressure, temperature, proximity, accelerometer, seismic), security coprocessors, GPS, electronic paper, storage, and many more functions. The PocketBeagle doesn't officially support mikroBUS, but many boards "just work" (details). 

  5. For the FTDI serial connection, connect Gnd to P1_22, Rx to P1_30 (UART0 Tx) and Tx to P1_32 (UART0 Rx). 

  6. The PocketBeagle device tree file specifies the default pin mappings and names other pin mappings. But if you want to track down the actual hardware meaning of each header pin, it's complicated. The PocketBeagle schematic shows the mapping from header pins to balls on the Octavo chip package. The Octavo OSD335x documentation gives ball map to the Sitara chip. The Sitara AM335x datasheet lists the up to eight functions assigned to each pin. The Technical Reference Manual Section 9.3.1.49 describes the control register for each pin. Thus, it's possible but tedious to determine from "first principles" exactly what each PocketBeagle header pin does. 

  7. There are a couple problems you can encounter with pin mapping. First, since not all chip pins are exposed on PocketBeagle headers, you're out of luck if you want a function that isn't wired to a header. Second, if you need two functions that both use the same pin, you're also out of luck. Fortunately there's enough redundancy that you can usually get what you need. 

  8. The PocketBeagle uses U-Boot The U-Boot overlay is discussed here. For more information on device trees, see Introduction to the BeagleBone Black device tree

  9. The Technical Reference Manual is a 5041 page document describing all the feature of the Sitara architecture and how to control them. But for specifics on the AM3358 chip used in the BeagleBone, you also need to check the 253 page datasheet

  10. Note that there are two GPIO numbering schemes; either a plain number or register and number. Each GPIO register has 32 GPIOs. For example, GPIO 111 is in register 3 and also known as GPIO 3.15. (3*32+15 = 111) 

  11. To switch P1_33 back to a GPIO, use config-pin P1_33 gpio.

    Internally, config-pin writes to a pseudo-file such as /sys/devices/platform/ocp/ocp:P1_33_pinmux/state to cause the kernel to change the pin's configuration. 

  12. You can control GPIO pins from a PRU. However, there will be several cycles of latency as the control signal is delivered from the PRU to the GPIO. A PRU pin on the other hand can be read or written immediately. 

  13. WiFi on the PocketBeagle is easy to set up using a command line program called connmanctl. Instructions on configuring WiFi with connmanctl are here and also are listed in the /etc/network/interfaces file. (Don't edit that file.) When I started up connmanctl, it gave an error about VPN connections; I ignored the error. I tested WiFi with a Mini USB WiFi module and an Ourlink USB WiFi module

  14. Sharing an Internet connection with the PocketBeagle isn't as simple as I'd like. To share with Windows, I followed the instructions here and here. (Note that BeagleBone instructions should work for the PocketBeagle.) I haven't had much luck with MacOS. In any case, I recommend connecting to the serial console first since there's a good chance you'll lose any SSH connection while reconfiguring the networking. 

  15. Analog input pins 5 and 6 are shared with a GPIO pin via a voltage divider. To use one of these inputs, you must configure the shared GPIO as an input with no pullup/down so it won't affect the analog value. In addition, the input voltage is divided by 2 (so these pins can support up to 3.3V instead of 1.8V).

    # Analog input 5 (P2_35)
    $ config-pin P2_35 gpio
    $ echo in > /sys/class/gpio/gpio86/direction
    $ cat /sys/bus/iio/devices/iio:device0/in_voltage5_raw
    # Analog input 6 (P1_2)
    $ config-pin P1_2 gpio
    $ echo in > /sys/class/gpio/gpio87/direction
    $ cat /sys/bus/iio/devices/iio:device0/in_voltage6_raw
    

    Analog input 7 (P2_36) is multiplexed by the power management IC (PMIC). It supports a maximum voltage of 1.8V. To read the value, you must first configure the PMIC:

    $ sudo i2cset -y -f 0 0x24 9 5
    $ cat /sys/bus/iio/devices/iio:device0/in_voltage7_raw
    
     

  16. In the accelerometer example, the board is approximately vertical with the chip's X axis pointing up. The X, Y, and Z accelerations returned by i2cdump in the screenshot were 0x42a8, 0x02dc, and 0x1348. These are signed values, scaled so 16384 is 1G. Thus, the X acceleration was approximately 1 G (due to Earth's gravity) while the other accelerations were small. These values change if the board's orientation changes or the board is accelerated. The temperature is 0xed10, which according to the formula in the register map yields 22.3°C or 72°F. The last three words are the gyroscope values, which are approximately 0 since the board isn't rotating. For more details on the accelerometer board see the register map, the datasheet and this Arduino post

Fixing the Ethernet board from a vintage Xerox Alto

A Xerox Alto system on the East coast had Ethernet problems, so the owner sent me the Ethernet board to diagnose. (After restoring our Alto, we've heard from a couple other Alto owners and try to help them out.) This blog post describes how I repaired the board and explains a bit about how the Alto's groundbreaking Ethernet worked.

The Alto was a revolutionary computer designed at Xerox PARC in 1973, introducing the GUI, high-resolution bitmapped displays and laser printers to the world. But one of its most important contributions was Ethernet, the local area network that is still heavily used today. While modern Ethernets handle up to 100 gigabits per second, the Alto's Ethernet was much slower, just 3 megabits per second over coaxial cable. Even so, the Alto used the Ethernet for file servers, email, network boot, distributed games and even voice over Ethernet.

An extender board made it easy to probe the Ethernet card in the Xerox Alto. The chassis is pulled out to access the boards.  Above the chassis is the disk drive, which stores just 2.5 megabytes on a 14-inch disk pack.

An extender board made it easy to probe the Ethernet card in the Xerox Alto. The chassis is pulled out to access the boards. Above the chassis is the disk drive, which stores just 2.5 megabytes on a 14-inch disk pack.

The Alto's chassis slides out of the cabinet, allowing access to the circuit boards (see above). To test the Ethernet board, I plugged it into the Alto we've restored. The Ethernet board is hanging out the right side of the chassis because I used an extender board.

The board had a couple straightforward problems—a chip with a bent pin (which I straightened) and another chip with broken pins. (While some people recommend re-seating chips on old boards, this can create new problems.) The broken chip was a 74S86, a quadruple XOR gate that has been obsolete for years (if not decades). I replaced it with a 74LS86, a similar but non-obsolete chip.1

When I powered up the Alto, I didn't get anything from the Ethernet board: it was not sending or receiving successfully. This double failure was a bit surprising since malfunctions usually affect just one direction. But I quickly discovered a trivial problem: when I pulled out the Alto's cabinet to access the circuit boards, the Ethernet connector on the back came loose. After plugging the connector in, I saw that the Alto was sending packets successfully, but still wasn't receiving anything.

Oscilloscope trace from the Ethernet board. Yellow is input data, green is R-C filtered, blue is detected edges. The blue trace is a bit of a mess with runt pulses.

Oscilloscope trace from the Ethernet board. Yellow is input data, green is R-C filtered, blue is detected edges. The blue trace is a bit of a mess with runt pulses.

I started probing the Ethernet board's input circuit with the oscilloscope. The board was receiving the input okay, but a few gates later the signals looked kind of sketchy, as you can see above. The yellow trace is the input Ethernet signal. The board applies an R-C filter (green) and then the signal edges are detected (blue). While the input (yellow) is a clean signal, the green signals only go up to about 2 volts, not the expected 4-5 volts. Even worse, the blue waveform is irregular and has "runt" pulses—short irregular signals that don't go all the way up. With waveforms like this, the board wouldn't be able to process the input.

Manchester encoding and the decoding circuit

I'll take a detour to explain the Ethernet's Manchester encoding, before getting into the details of the circuitry.

The Alto's Ethernet encoded data over the coaxial cable using Manchester encoding.32 In this encoding, a 1 bit is sent as a 1 followed by a 0, while a 0 bit is sent as a 0 followed by a 1. The diagram below shows how the bits "0110" would be encoded. A key reason to use this encoding is that simplifies timing on the receiver, since it is self-clocking. Note that there is a transition in the middle of each cell that can be used as a clock. (The obvious scheme of just sending the bits directly has the problem that in a long string of 0's, it's hard to know exactly how many were transmitted.)

An example of Manchester encoding, for the bits 0110.

An example of Manchester encoding, for the bits 0110.

To decode the Ethernet signal arriving at the Alto, the first step is to extract the clock signal that indicates the timing of the bits. To extract the clock, the transitions in the middle of each bit cell must be detected. The trick is to ignore transitions at the edges of cells. The diagram below shows how the clock is extracted. First, edge pulses are generated for each transition edge of the input. Then, a clock pulse is generated for each edge pulse. The clock pulse about 75% of the width of the bit cell, and any second pulse that happens while the clock is still high is blocked. (The edge circled in red is an example of an ignored edge.) The result is the steady clock signal, synchronized to the input.4 This clock is used to latch the input signal value into a shift register, which converts the serial Ethernet stream into a word value usable by the Alto.

Extracting the clock signal from a Manchester-encoded Ethernet input. Edges are extracted from the input signal and used to trigger the clock. An edge too close to the previous (red) is dropped.

Extracting the clock signal from a Manchester-encoded Ethernet input. Edges are extracted from the input signal and used to trigger the clock. An edge too close to the previous (red) is dropped.

The schematic5 below shows the circuit that performs this clock extraction. There are a few tricks in this interesting semi-analog circuit. When the Ethernet input signal changes, the low-pass R-C (resistor capacitor) filter output will be slower to change. This will cause the edge detect XOR gate to go high briefly until the R-C signal catches up. Then the clock is generated by a "one-shot", a chip that generates a fixed-width pulse for each input pulse. The pulse width is set to about 75% of the bit cell width by another resistor and capacitor. The one-shot is wired to ignore any additional pulses that occur while the clock output is high.

Schematic of the clock extraction circuit in the Xerox Alto's Ethernet interface.

Schematic of the clock extraction circuit in the Xerox Alto's Ethernet interface.

Since the timing in this circuit was controlled by multiple resistors and capacitors, I thought that a capacitor might have gone out of tolerance. But first I decided to do the simpler test of swapping the XOR chip with the one from our working Alto board. Surprisingly, this fixed the problem, and the Ethernet board now functioned flawlessly. Thus, while the 74LS86 has input characteristics similar to the 74S86, they weren't close enough, and substituting the more modern chip messed up the R-C filter's behavior. (If the gate draws too much input current, the capacitor won't charge as fast.) Marc dug through his collection of old chips and found another 74S86 so we could get both boards operating.

Oscilloscope trace showing the extracted clock (pink), edges of the Ethernet input (yellow) and the R-C filtered input (green).

Oscilloscope trace showing the extracted clock (pink), edges of the Ethernet input (yellow) and the R-C filtered input (green).

The oscilloscope trace above shows the nice, steady clock (pink) after replacing the XOR chip. With the right XOR chip, the RC-filtered signal (green) rises to 4 volts, unlike before when it just went to 2 volts. The edge signal (yellow) is nice and even, without the "runt pulses" seen earlier.

An overview of the Ethernet board

I'll wrap up by explaining a bit about the Alto's Ethernet board (shown in the photo below). The large connector at the left plugs into the Alto's backplane, providing communication with the rest of the system. The small connector at the right connects to the Ethernet, via a transceiver. Some of the key components of the Ethernet interface are labeled on the diagram below. With this generation of chips, even a whole board of chips doesn't give you a lot of functionality so much of the Ethernet functionality is implemented in software and microcode.

The Xerox Alto's Ethernet board, showing major functional blocks.

The Xerox Alto's Ethernet board, showing major functional blocks.

Most of the chips are simple TTL logic, but the board uses a few interesting and obscure chips. Input and output data goes through a 16-word FIFO buffer built from four Intel 3101A RAM chips; each one holds just 16×4 bits. (The 3101 was Intel's first product.) Commands to the Ethernet board are decoded by three Intel 3205 decoder chips. Buffer chips interface between the card and the Alto's bus. Shift registers for the input and output convert between data words and serial data over the Ethernet. The CRC error checking is done by a specialized Fairchild 9401 CRC chip. Surprisingly, the Manchester encoding is implemented with a PROM-driven state machine, built from two Intel 3601 PROMs. Finally, the XOR chip is the chip that caused all the problems.5

The board has TTL inputs and outputs, so it doesn't connect directly to the Ethernet cable. Instead, a transceiver box is the interface between the Alto and the cable. In the photo below, you can see the transceiver clamped onto the coaxial cable. The transceiver converts the Alto's logic signals to the signals on the cable and injects the signals through an isolation transformer. In addition, the transceiver detects collisions if the Alto tries to send at the same time as another machine on the network.

The transceiver injects the Xerox Alto's signals into the Ethernet coaxial cable and reads signals from the cable.

The transceiver injects the Xerox Alto's signals into the Ethernet coaxial cable and reads signals from the cable.

You might wonder how the Alto can communicate with a modern system, since the Alto's 3 Mb/s Ethernet isn't compatible with modern Ethernet. I am building a gateway based on the BeagleBone (below) that uses the BeagleBone's microcontroller (the PRU) to "bit bang" the Ethernet signals. The BeagleBone also runs an implementation of IFS (Interim File System), the server side software to support the Alto. This is a C# implementation of IFS written by the Living Computers Museum.

I'm building an interface to the Alto's 3Mb/s Ethernet, using a BeagleBone. The cable on the right goes to the Alto's Ethernet port, while a standard Ethernet plugs into the left.

I'm building an interface to the Alto's 3Mb/s Ethernet, using a BeagleBone. The cable on the right goes to the Alto's Ethernet port, while a standard Ethernet plugs into the left.

Conclusion

Bob Metcalfe invented Ethernet at Xerox PARC between 1973 and 1974, with a 3 megabit per second Ethernet for the Alto. Since then, Ethernet has become a ubiquitous standard, and has increased in speed more than 4 orders of magnitude. Unfortunately, as with many other technologies, Xerox failed to take advantage of Ethernet as a product. Instead, Bob Metcalfe left Xerox in 1979 and formed the company 3Com, which sold Ethernet products and became one of the most successful technology firms of the 1990s.

I tracked down a problem in an Alto Ethernet board—my replacement for a broken chip was almost the same, but incompatible enough to make the circuit fail. The problem showed up in the circuit that extracted the clock from the incoming Ethernet signal. This circuit illustrates some clever techniques used by the Alto designers to implement Ethernet with simple TTL chips.

The Ethernet card plugged into the Xerox Alto's chassis. The disk drive is above the chassis, with a white 14" disk pack visible inside.

The Ethernet card plugged into the Xerox Alto's chassis. The disk drive is above the chassis, with a white 14" disk pack visible inside.

The Alto I've been restoring came from YCombinator; the restoration team includes Marc Verdiell, Carl Claunch and Luca Severini. My full set of Alto posts is here and Marc's extensive videos of the restoration are here. Thanks to the Living Computers Museum+Labs for the extender card and the IFS software.

You can follow me on Twitter here for updates on the restoration.

Notes and references

  1. The 7400 family of TTL chips has many subfamilies with different characteristics. The 74S components use Schottky diodes for faster performance than standard TTL. The 74LS (low-power Schottky) chips use much less power (1/8 in this case), but are slightly slower and draw slightly different input currents. 

  2. Ethernet started with Manchester encoding and continued to use this encoding up to 10 Mb/s speed. However, Manchester encoding is somewhat inefficient since each bit can have two transitions, doubling the bandwidth requirement. 100 Mb/s Ethernet solved this by using MLT-3 encoding, which uses three voltage levels. To avoid the problem of losing the clock on a long string of 0's, each group of 4 bits is sent as a particular 5 bit pattern that eliminates long repetitive sequences. Ethernet gets progressively more complex as speed increases. At 100 Gb/s Ethernet, blocks of 64 bits are encoded with 66 bit patterns and data is split across multiple lanes. 

  3. Manchester encoding was developed for magnetic drum storage for the University of Manchester's Mark 1 computer. The Mark 1 was an influential early computer from 1949, one of the earliest stored-program computers, also introducing index registers and Williams tube storage. 

  4. One potential problem with the clock extraction is if you have a steady stream of bits (1111... or 0000...) the Ethernet signal will be a steady stream of transitions, and you can't tell where to start the clock. The solution is that each Ethernet transmission starts with a sync bit to get the clock started properly. 

  5. The schematics for the Alto's Ethernet board are at Bitsavers. The Ethernet is described in more detail in the Alto Hardware Manual