Sunday, December 18, 2011

It's alive!

After implementing an 8-bit full adder, I decided to turn it into an 8-bit ALU.  The ALU supports addition, subtraction, NOT, OR, and AND.  It's considerably more complicated than the full-adder, but at the same time I'm happy with the degree of reuse I was able to achieve.  The addition of support for AND, for example, required only the addition of a 2-1 mux per bit (2 74HCT157s for the whole ALU).

I've wired up two bits so far, and have started testing to ensure that the basics are sound before I turn it into even more of a rats nest.  This turns out to have been a wise choice, as I made a few mistakes with the control bits -- mistakes which are much easier to correct with two bits than four.

I'll post schematics and diagrams when I get all eight bits done.

Wednesday, December 14, 2011

Dave's Lab Power Supply Design

This post is more of a memo to self than anything else.  It's a reminder to me to watch the complete set of EEVblog Lab Power Supply Design videos.

Part 1

Part 2

Part 3

Part 4

Part 5

Part 6

Part 7

Friday, October 28, 2011

Decoupling with Bypass Capacitors

To ease myself into this hobby, I began with the SparkFun Beginning Embedded Electronics tutorials. They were a great way to start, and had me well on my way to making my first RS-232-controlled blinkenlight in no time. As part of that tutorial, they told me to install bypass caps near Vcc on all ICs. Okfine, monkey can add prophylactic caps everywhere. But why? The SparkFun page describes their function at a high level, but I've always wanted to know more. Cap monkey want pictures. Cap monkey want to know why he has a pill box compartment dedicated to his supply of 100 or so 0.1uF caps.

This post is what I've been looking for. Details. Pictures. Sample circuits. What more could a cap monkey want?

Friday, October 21, 2011

A full adder -- complete!

I started this post back in October when I actually finished the work, but I forgot to post it then.  So here it is now.

Three million wires later, my 8-bit full adder is complete.

Here it is with the front panel attached.  I use the front panel in lieu of switches and LEDs.

Here's the circuit by itself:

Each pair of columns calculates four bits.  Each bit needs nine gates, and consists of two dedicated 7400s (actually 74HCT00s) and a quarter of a common 7400.  If we number the ICs in column-major order, bit 0 is calculated by ICs 1, 2, and a quarter of 3; bit 1 is calculated by ICs 4, 5, and a quarter of 3; bit 2 is calculated by ICs 6, 7, and a quarter of 3; bit 3 is calculated by (wait for it) ICs 8, 9, and the final quarter of 3.

Due to layout weirdness, bits 0-3 are calculated by the right pair of columns, while bits 4-7 are calculated by the left pair of columns.  I'd love to say the vertical offset is intentional, but it's actually due to a layout mistake or change in plans, the details of which I've since forgotten.

Wiring this thing up was mind-numbing, but it was awesome to see it come to life (I tested each bit after I wired it up).

Here's the schematic.  My original intent was to build a 4-bit adder, but I had so much fun wiring(!), that I decided to do it twice, for 8 bits.

Thursday, October 20, 2011

A full adder

A full adder, slowly but surely....

Here's 3.5 bits (out of a planned 8):

... and 5.5 bits:

Only 1.5 bits to go!

Saturday, October 8, 2011

Front Panel up and running

At long last, I finished populating the front panel board.  Oh what an adventure that was.  I also built up quite the list of things to change for v2, if ever there is a v2.  Even if there isn't, I learned a lot about what to do and not to do for the next PCB I design.

Before I get into the details, here are some pictures of the completed front panel board:

Here's a video of the front panel controlling a simple 2-input AND gate from a 74HCT08N.  The whole purpose of the front panel is to make LEDs and switches unnecessary, but LEDs make an appearance in this circuit for validation purposes -- just to confirm that the front panel is doing what it says it's doing.

Things I learned:

Lots more and better silkscreening.  I'm having a heck of a time identifying the correct input and output pins, to say nothing of distinguishing between the +5 and GND pins.  I should've silk-screened the pin numbers all along the bottom headers.  Silk-screened IC numbers (the manufacturer's part-number -- not the Ux or ICx number) are less useful when they're under the IC -- especially if you're using sockets.  I also failed to leave any orientation marks to help me plug in the ISP cable correctly.

Status indicators.  There aren't any LEDs on the board, which can make it difficult to tell whether the board is on, whether it's receiving data, or in general what it's doing.  Eventually it would be fun to have LEDs on every input and output pin, but in the meantime, for v2, I'd settle for power and one that flickers when data is transmitted or received.

More space for I/O cable connections.  I'm still conflicted as to how I'd like to connect the front panel to the PCB.  I had originally thought to use ribbon cables with IDC connectors, but those are wide enough that I'd need to either widen the whole board or make a third and fourth row of I/O pins.  A further complication there would be that I'd need cables with IDC 1x4 on one end and 8x1 0.1" sockets on the other.  That could get expensive, but we'll see -- connector prices jump dramatically once you stray even slightly from the beaten path.

Pin orderings matter for the ISP connector.  I used the P6 connector in the schematic capture program, which numbers pins like an IC -- ascending counter-clockwise from the upper left.  Unfortunately, the pins are supposed to be numbered in zig-zag style, with 1 and 2 on the top row, 3 and 4 on the middle row, and 5 and 6 on the bottom row.  The end result of that was chaos, and a non-functioning ISP connection.  I ended up cobbling together a cable to go between the ISP and PCB which unraveled the confusion.

Pin orderings matter for the DB-9 connector.  The DB-9 part I used on the schematic used the male DB-9 pin numbering, which is the mirror image of the pin numbering for the female DB-9 that I'd eventually be using.  Happily, I was able to get myself out of that situation by mounting the DB-9 on the bottom of the PCB rather than the top.  Doing so actually made the design better, as my USB-to-serial adaptor takes the form of a heavy dongle that plugs into the DB-9 port, so mounting it on the bottom of the board kept the dongle from flipping the board over.  Unfortunately, getting to this realization required much gnashing of teeth, the purchase of an unnecessary male DB-9 connector, the sacrifice of a female DB-9 connector, and much soldering and desoldering.

Tuesday, September 20, 2011

My Front Panel boards arrived!

My Front Panel boards arrived!  Thanks Laen!  I placed the order on August 28th, and received the boards yesterday (September 19th).  They look black (this is what happens when you use a camera phone with bad lighting), but they're really purple.  Oh, so purple.

Monday, September 5, 2011

Front Panel Software

[This is a continuation of the Front Panel Hardware post; you should read it first]

Embedded Software

The software which runs on the front panel's microcontroller is about as simple as I could make it.  It uses the ATMega168's built-in UART to communicate with the host, with RTS and CTS controlled manually by the embedded software.

To keep things simple, I made everything query-response.  This way there's no need for timers or anything like that on the microcontroller -- the embedded software does nothing without first being asked.  There are four essential commands:
  1. Reset all output pins to 0.
  2. Set an output pin to a given state (1 or 0).
  3. Specify the pins which should be monitored for input.
  4. Return the value of all input pins.
Pins are identified using a three-digit number decimal number.  The first digit is 0 for output pins, and 1 for input pins.  The second and third digit are the zero-padded pin numbers as silk-screened on the PCB.  By separating the input and output pin spaces like this, we simplify the host program, and minimize the chances of error.  Here's a diagram of the pin numbers:

Host Software

The program running on the host is responsible for displaying the user interface, for passing output state changes to the front panel, and for keeping the indicators up to date.  I've implemented it in Python, using WxWidgets as the UI toolkit.

One of the primary requirements is that the user interface be customizable.  This is necessary because we'll be using the front panel with a number of different circuits, each of which will have different input and output configurations.  Accordingly, the configuration isn't hard-coded in the front panel program, but is instead driven by an external config file.  Here's an example:

toggle('Bit': 0='0', 1='1',)
momentary('Actions': 2='A', 3='B',)
indicator('Result': 100='1', 101='2', 102='3', 103='4',)
(Yes, it's true.  I was too lazy to tune the regexps to allow for the omission of the trailing commas)

We're using output pins 0-3, and input pins 0-3 to display a user interface with three different types of UI element.  Here's what it looks like when running:

The bit 0 and 1 buttons are toggle buttons -- one click is required to turn on the associated pin, and a second click is required to turn it off.  Action buttons A and B are momentary -- their associated pins turn on when the button is pressed, and turn off when it is released.  Indicators Result 1-4 change their background color when their input pins go high, and appear as shown when said pins go low.

Not a terribly complicated program, but I did have an interesting battle, and (re?)learned something new along the way:  UI toolkits and threads are like oil and water.  Tkinter (the default toolkit for Python) is like oil on fire.

In general, you confine all interactions with the UI to a single thread -- the UI thread.  Anyone else who needs to change the UI posts something to the UI thread, and lets the UI thread take care of it.  If you don't do this -- if you muck with the UI from a thread other than the UI thread -- the world ends in fire.  If you're lucky, you get a stack trace.  If not, just fire.

Tkinter exposes a monolithic event loop -- you call Tk.mainloop(), and it runs until it's time for your program to exit.  There doesn't appear to be a way to break the loop up into its component parts so you could, say, wait for UI events and events from your non-UI threads using an interface like poll(2).  Instead, everything is supposed to be done through the Tkinter event system.  External things wanting attention post events -- events which are passed to callbacks which have registered using bind.

This would be fine, except for the fact that the event-poster isn't thread safe either.  That is, you can't post an event from the non-UI thread.  In fact, the only way for a non-UI thread to get the attention of the UI thread appears to be through polling.  The UI thread asks to be woken up every n milliseconds, during which time it checks a queue of things that need attention.  I don't like this approach at all.

After much gnashing of teeth (I still can't believe Tkinter doesn't have a thread-safe event post) and failed attempts to get around this problem without using polling, I found wxWidgets (specifically wxPython).  WxWidgets has the same threading restrictions as Tkinter and other UI toolkits, in that it requires all UI interactions to take place on the UI thread.  The crucial difference, however, is that wxWidgets specifically allows events to be posted from non-UI threads.  Once you have that, everything is easy.

Aside: Why do I use threads?  For the most part I don't, except for the serial port handler.  Serial port reads and writes are handled by independent threads.  This allows me to have non-blocking writes, which in turn allows me to do writes from the UI thread, since I don't have to worry about blocking it.  On the read side, it's much simpler to have a separate read thread than to mix reading and writing.  The only downside of this approach is that some reads (indicator status updates) need to directly affect the UI, and thus I need a toolkit which allows me to talk to the UI thread from a non-UI thread.  WxWidgets allows that, and so everything comes together nicely.

Sunday, September 4, 2011

Front Panel Hardware

As described in an earlier post, I'm designing a front panel for the circuits in CODE.  After much delay (this is what happens when you have too many hobbies), I've got the first version ready.  This post will describe the hardware.  A subsequent post will describe the software -- both that which runs on my Mac and that which runs on the front panel's microcontroller.

At its simplest, the purpose of the front panel is to control outputs and monitor inputs.  The PC sends commands to the front panel via RS-232, and receives responses the same way.  So at the very least, we'll need a microcontroller and an RS-232 transceiver (a future version might switch to USB, but not this one).  Everything else depends on the number of input and output lines.

The most complicated front panel in CODE calls for 27 output lines and 8 inputs.  Even an ATMega644 can't handle that many (40 pins minus 7 for non-general-purpose pins, 4 for the ISP, and 4 for RS-232 leaves 25), so one way or the other we're using a latch for some of the inputs or outputs.  As it happens, I fried my ATMega644, and ended up prototyping this circuit with an ATMega168.  A '644 would've been a few dollars cheaper once latch and PCB size are taken into account, but it is what it is.  Perhaps a subsequent version will use the '644 (or whatever the USB-enabled equivalent may be).

The ATMega168 has 28 pins.  Subtract out the preassigned pins, those used for the ISP, the clock, and those used for RS-232 (I'm using RX/TX and RTS/CTS, though that too could be changed in a future version), and we have 13 pins.  13 pins is just enough to get us 27+8, assuming we use three SIPO latches and 3 direct lines for the output, and one PISO latch for the input.  So that's what I've done.

Here's the schematic:

This was my first schematic drawn using Kicad, and I'm very happy with the way it turned out.  I had to draw a couple of the symbols myself (the switch, to my surprise, and the barrel connector), but other than that it was pretty painless.

Having drawn the schematic, having gone through the Teho labs tutorial, and knowing that I'd be using the front panel again and again without wanting to monopolize the breadboard, I decided to go all the way to having a PCB fabricated.

The first step on that road, with Kicad, is footprint assignment.  Eagle differs in this respect, as you pick your footprints when you lay out the schematic.  I have to say I really prefer the Kicad approach here.  When I'm putting together a schematic (especially for something I have no intention of turning into a PCB), I don't want to have to care about the footprint.  Not at all.  So anyway, picking footprints.  Kicad was missing a few that I wanted, so I ended up making my own.  That was much less painful than I had expected.

After footprint assigment, board layout.  Here's where I discovered that I'm nowhere near as intelligent as the auto-router.  Sigh.  All that education -- for nothing.  When I first laid out the board, I figured no way the auto-router could route this -- it's too complicated (I laugh at that now).  So I routed it myself.  A couple of hours later, I had it routed, but the last couple of traces had 3-4 vias each as they wended their way about the board.  Oh all right, I'll try the auto-router.  A few minutes later, it has the entire board routed, with no vias.

Here's the routed board, in all its glory:

In real life, though, the board won't be green -- it'll be purple.  I decided to use Dorkbot PDX to make the PCB. They have reasonable prices and a reasonably short turnaround time.  Shorter than the places which make the boards overseas, but more expensive.  The price difference was low enough that I was happy to pay it to have the board made here.  I can't wait for it to arrive.

[This post is continued in Front Panel Software]

Friday, September 2, 2011

Switching to Kicad

I've been using Eagle for a number of circuits, but recently switched to Kicad. I was never too fond of Eagle's free-until-your-board-gets-too-complicated thing, since I knew that was likely to compel me to shell out a decent chunk of change to get the real thing when my boards finally got big enough (and I had enough invested in them).  I also didn't like the way Eagle made me choose footprints during schematic capture, though that's really a nit.

It was this tutorial that finally got me to switch.  Highly recommended.  It walks you through the creation of a small power supply board, from schematic capture all the way through layout and routing.  I liked the way everything fit together, and so I decided to switch.

One wrinkle.  Kicad is unusable on the Mac as of "kicad_osx_v3056_DEV".  There's some display problem which causes part moves leave trails, requiring you to hit refresh all the time.  There was another problem which made parts disappear until you hit refresh.  In summary, not usable.

As it happens, Kicad works pretty well on Linux, and VMWare Fusion makes Linux (Ubuntu) work pretty well on my Mac, so now I've got a VM running Ubuntu running Kicad.  I don't even have to use GNOME -- I just ssh into the VM and remote-display Kicad back to the Mac's X server.  Coordinating files between the two machines is a bit of a pain, but I've started checking everything into Mercurial, so I use a master repository to coordinate between the two.  I'll certainly be happy if/when Kicad starts working properly on the Mac, but until then I've got a perfectly workable solution.

A couple of downsides, now that I've switched, and have spent some time working with Kicad:

  1. The documentation is spotty.  Not entirely surprising, but annoying just the same.  The documentation that does exist is fine, but there are lots of gaps.  I tried Kicad once before, back before I settle on Eagle, and had discarded it because the docs were so incomplete that I had a hard time getting my head around it.  Without the Teho Labs tutorial I mentioned above, I wouldn't have tried it again.
  2. The part libraries are nowhere near as extensive as those for Eagle.  Or perhaps they are, but they just don't contain what I want.  I found a site which has auto-conversions of Eagle parts, but they weren't really what I wanted either.  I've resigned myself to having to design the occasional symbol and many footprints.  This doesn't turn out to be as bad as I had at first thought, especially since I don't use that many parts.  The first schematic/board involves the design of several parts, but subsequent ones just reuse those created for the first.  This part generator, in particular, is very useful. 

Monday, July 25, 2011

Soldering Tutorial

From EEVBlog, Dave's 3-part soldering tutorial:

Part 1 - Tools

Part 2 - Soldering

Part 3 - SMD

Friday, July 8, 2011

Impedence Tutorial

Catching up on my Google Reader feeds, I finally had a chance to watch Ben Krasnow's two tutorial videos on impedance.  As always, he does a good job explaining otherwise-complicated material.

Part 1

Part 2

Wednesday, July 6, 2011

Voltage Regulator Board

After frying my ATMega644 (sigh) using unfiltered DC from my power supply, I decided it was time to add a voltage regulator.  I'm assuming that doing so will protect me from any spikes.  Anyway, I've built the simple voltage regulator circuit from the Sparkfun tutorial any number of times (regulator, two caps, one PTC, one switch), and wasn't looking forward to building it again.  So this time I soldered it to some perfboard so I can simply plug it into my next circuit.  The circuit isn't terribly complicated, but it gave me some experience with perfboard wiring and soldering.

Sunday, June 12, 2011

Starting to build the X&O RR

The parts needed to lay down the track for the X&O RR had spent long enough sitting under my bed.  Today was the day they came out.  Back in March, I printed out the layout 1:1 on a sheet of blueprint paper.  I've been putting off assembly because I wasn't quite sure how I was going to put everything together.  The goal is to end up with track on roadbed on plywood.  With the layout in 1:1, we obviously want to put the paper on the plywood to assist with placement, but what then?  Obviously not an unsolvable problem -- I just needed to figure out how I wanted to do it.

Today, I decided how, and did it.  I used thumbtacks to attach the 1:1 sheet to the plywood.  I then placed every turnout on the layout, and partially nailed them down.  I also built the connecting pieces for the switches which are really close together, and placed (and lightly nailed) every other piece of non-curve track.  The curves will be flex track, and will involve some nudging, so I didn't bother trying to fix their positions just yet.  Here's everything lightly-nailed:

Then I removed everything, annotated the holes so I know where to pick up next time, and labeled all the pieces.

One little snag I hit.  My shiny new Xcelite 170M shear cutters ... well ... sheared:

I tried to soldier on with the cutting of custom-sized connecting pieces from Flex Track without the shear cutters, but the quality of the cuts suffered pretty dramatically as a result.  Right tool for the job and all that -- this is pretty clearly a necessary tool.

Before laying the track, I tested each turnout.  I first tried hooking the turnouts up to the rail outputs of my DCS50 DCC controller.  I figured that DCC looks an awful lot like AC, so maybe it'd work.  It made the turnout solenoid vibrate, but not much else.  A Google search revealed a number of turnout guides which mention using the AC Accessory outputs on the controller to power the turnouts.  Alas, I have no such output.  It looks like I need a separate power supply for the turnouts.  Whether that's a straight DC power supply with individual switches or something fancy like a Digitrax DCS64 (to allow DCC switch control), I have yet to decide.

Back to turnout testing.  When I realized that I couldn't use the DCS50, I hooked the turnouts up to my bench DC power supply.  At 15V (and a power-supply-imposed max of 1A), most turnouts switched properly, if a bit hesitantly.  A couple of them got stuck.  Turning it up to 20V fixed that problems.  I don't know if this is an artifact of my use of the bench power supply or something more.  Will I need something like this capacitive discharge controller?

I had intended to move straight from this initial placement step to the laying of roadbed and track, but now I realize that I need to think more about how the wiring will work.  If this layout were on a table, that'd be easy -- I could drill holes, and route the wires under the table.  As my wires will share the same side of the plywood with the track, I need to figure it out now.  So much to do.

Monday, June 6, 2011

Transistor basics with DC

Hack a Day pointed me to this blog entry for a basic description of transistor operation with DC. For whatever reason, I had the hardest time getting transistor operation right in my head at first(*). Anyway, the video in that entry is exactly what I wish I had back then.

(*) It could've been because I started with The Art of Electronics, which is a bit like drinking from a fire hose.

Tuesday, May 17, 2011

My own microprocessor

I’ve decided to build the microprocessor described in CODE. In that book, Petzold describes the development of a processor pretty much from scratch. He describes everything but the control logic, so that’ll give me a nice exercise to start out with. Follow along for the non-control logic (with a few tweaks along the way), and build the control logic from scratch. Once I do that, I’ll feel confident enough to build the second version from scratch, to my own design.

Petzold describes his circuits in terms of relays, with a control panel made of switches. Obviously I’m going to use TTLish ICs for the circuits, but I still need some sort of control panel. If the 7-segment LED circuit taught me anything, it’s that switches need debouncing if they’re going to have a prayer of working properly. The most complicated front panel in Petzold’s book has 27 switches on it, each of which would presumably need its own debouncing circuit. No thank you. Furthermore, that front panel is eventually used for loading in programs. Toggling programs in may have been fun in 1972, but I really don’t have the patience for it today.

Instead, I’m going to use an AVR for the front panel. I’ll have a program which displays a UI running on my Mac. It’ll talk to the AVR via RS232, and will tell the AVR which ports to enable/disable/read. Eventually I’ll write something which uses that same interface to “toggle” in new programs. All will be sweetness and light.

Monday, May 16, 2011

Gran Fondo NYC

I did the inaugural Gran Fondo NYC last weekend, and had a great time.  I'd been more than a little nervous about whether the organizers would be able to pull it off, but they did an amazing job with the parts that count.

We started on the lower deck of the GWB, in the NJ-bound lanes.  They had initially capped the race at 8,000 riders, but fell well short of that.  According to the announcer, just under 2,500 people lined up on the bridge.  So, a bunch of people on the bridge, but a manageable number.  Not so many that I wasn't on my bike, pedaling, by the time we crossed the starting line.  Over the GWB, exit to the right, an overpass over the highway, and then down into Palisades Park.  There were police at every intersection, both here and throughout the ride, ensuring that bikes had right of way.  I only had to stop twice for traffic signals during the entire ride.  It would be difficult to overstate how wonderful it was to have the police directing traffic for us.

I brought a bunch of GU and two Clif Bars, but was planning to rely primarily on the aid stations for nutrition and hydration.  The aid stations were nicely spaced and nicely stocked, allowing me (with one exception) to refill both bottles before they ran dry.  The one exception was the last aid station, which was a mile or two past when I ran dry.  If nothing else, this has convinced me that I need a seatpost-mounted bottle cage just like I have on my P2C.  Two bottles just isn't enough for a long ride.  Either you're stopping every 40 miles or less for a refill (more if it gets hot, as it did for this ride), or you're constantly in danger of running dry.  Riding dry is no fun at all, nor is riding in fear of it.  With three bottles, I'd be able to do 50 miles between refills, which would suit me just fine.  I like to eat something real (i.e. more than a Clif Bar or a GU) every 50 miles, so having my hydration stops match up with my nutrition stops would be ideal.

But back to the race.  We headed out on River Road.  So many people passed me on River Road, but I caught several on the hills.  I was keeping my speed down on the inclines, as I knew there'd be plenty of misery ahead.  Once we popped out on 9W I started to push it a bit (20mph until Nyack) until I was able to truly convince myself to stop trying to keep up with groups on the flats.  Thanks to the traffic control and my penchant for riding solo, I had State Line Hill to myself, and was able to take the entire descending traffic lane.  I've never had such a care-free full-speed descent of State Line Hill.

Up Old Mountain Rd, over Toga/Rockland hill -- basically the standard Little Tor / Orchards route.  The first timed climb of the day was Little Tor.  I'd been practicing this one, and was ready for it.  It's 3/4mi long, with just over 400' of climb.  There's a sharp incline at the start, and then constant misery for the rest of the way up.  This was my third nonstop time over (I stopped twice on my first time over Little Tor, so that time doesn't really count).  There's a picture of me grimacing my way to the top of Little Tor, with Christophe Vandaele (of SBR fame) right on my wheel.  I don't know whether he passed me or not, but it's nice to know that I was faster than someone getting over that hill.  Even if he was on a single speed, and likely working twice as hard as I was.  I finished the climb in 8:26.96 according to the chip, and 9:58 according to MyTracks/Strava, which uses a different starting point.  9:58 is a PR for me by just over a minute.

After Little Tor, on to Buckberg Mountain -- a hill I hadn't climbed before this race.  Buckberg Mountain Road is an absolute bastard.  The specs aren't that crazy -- at 367', it's about 50' shorter, and it's almost 0.5mi longer (1.2mi vs 0.75mi) -- but the profile is evil.  Rather than being a continuous climb a la Little Tor, it's a series of steep windy sections (with increasing grade) interleaved with less-steep (but still ascending) sections.  Yeesh.  It might be easier the second time around (and there most definitely will be a second time around), but it's always going to be hard.  Official time: 10:12.51, MyTracks/Strava time: 11:10.

The approach to Buckberg was through parts of Stony Point that I've never ridden before, and which are a nice change from the NYS Bike Route 9 route that goes east of 9W, through Haverstraw.  Buckberg Mountain Road can also be viewed as a way to bypass 9W through Tompkins Cove, but it's a hell of a way to do it.

With Buckberg Mountain done, off we go to Bear Mountain -- the toughest climb on the ride.  Strava rates the other climbs on the ride as category 4.  Bear gets a 2.  The grade isn't as brutal as, say, Little Tor -- the rating comes from the total climb (1200' from 9W) and the distance (4.5mi, again from 9W).  There's also the matter of just getting to Bear.  There's a lot of up and down during the few miles from Buckberg to Bear, including one category 4 climb.

But eventually we get to Bear Mountain (hooray for the police blocking traffic so we could get onto 7 Lakes from 9W without even slowing down).  I'm used to counting distance and height from 9W, but the GFNY organizers put the timed climb start at the traffic circle, which is about 3/4mi of the way in, and about 200' up.  Anyway, I decided I wanted to do the entire thing nonstop, from 9W all the way to the summit, so I skipped the aid station.  This made my ride unpleasant, as my bowels were feeling a bit compressed, but I'd probably do it again given the chance, as it let me knock out the whole 1200' in one go -- something I'd never done nonstop before.  This was only my second time up Bear Mountain.  The first time I did it, I had to stop twice on Perkins to catch my breath.

Climbing Bear was a "simple" matter of grinding through the climb, counting off the tenths of a mile until the top.  My power meter says I was doing an average of 200 watts for 35 minutes up that hill.  First, there's 7 Lakes Drive, which is about 2.25mi from 9W.  7 Lakes is relatively easy, and even has some oh-so-very-brief flat bits.  Then comes Perkins, which is narrower, steeper in sections, and goes all the way to the top.  And oh, what a blessed top.  Pictures, resting, and then almost 4 miles of descent to the aid station.  Real bathrooms, and my newfound favorite ride food: PB&J bagels.  I started eating those at each aid station from Bear Mountain on, and was very pleased with the results.  I basically did the ride on those and GU, with a few Stacy's Pita Chips thrown in now and again for salt.

In the distant future (about 20mi away) is the fourth timed climb -- southbound over Little Tor -- but first there was a bit of a diversion over to Gate Hill Rd.  The route to Gate Hill took us back over the Bear Mountain approach climbs (a 1mi cat 4 being the most notable), to the base of Buckberg Mountain.  We didn't retrace back to the summit, thank goodness, but we did climb over the side, on Mott Farm Rd.  I think we probably did at least half of the Buckberg climb, over some truly evil inclines.  Once past the intersection with Buckberg Mountain Road, the route was flat to descending (ish) to the base of the Gate Hill climb.  Very pretty scenery back there.

Gate Hill begins about a mile before the Parkway, and climbs about 700' to its intersection with Willow Grove.  Why this wasn't a timed climb, I'll never know.  Its only saving grace was the elevation profile.  Gate Hill is a series of climbs interleaved with flat sections (perhaps they only felt like flat sections by comparison).  The motivator for that climb is the knowledge that you're going to get to descend Willow Grove.  And what a glorious descent.  About 325' in 1mi with a gradual turn in the road, and nobody entering on the right.  That hill never gets old.  Let me rephrase.  Descending Willow Grove never gets old.  Ascending Willow Grove is a different story entirely.  A very sad story.

Once we descended Willow Grove, we had about 2mi to go to the aid station near the base of Little Tor.  Rehydrate, re-nutrate(?), and up over Little Tor we go.  This side is pretty easy.  There are some individual climbs leading up to it, followed by a "big" constant climb that ascends about 200'.  Nowhere near as difficult as doing Little Tor in the other direction.  The race organizers were able to close Little Tor in our direction of travel -- northbound on the way out, and southbound on the way back.  As such, I was able to descend the south face of Little Tor without fear of traffic.  This was the first time I've ever enjoyed a trip down the south side of Little Tor.  With traffic, you normally have to ride down on a sketchy shoulder.  Without, I was able to do the whole thing in the traffic lane, which was heavenly.

We returned along South Mountain to Ridge, but kept going on Ridge to Strawtown, rather than going back to 9W via 304.  In West Nyack, we jogged over to Western Highway, and then to King's Highway, which took us to Piermont.  This return was largely flat, with some light rollers, and was a nice change from the brutality of the preceding miles.  At the end of King's Highway, a quick jaunt down Orangetown led us to Valentine, Highland, and back to 9W.  This was the first time I'd gone from King's Highway to 9W without going over the bridge.  It's a nice detour to know, even though it means you have to climb Highland to get back to 9W.

The organizers didn't see fit to give us police protection along 9W, which was reasonable, since we weren't on it for very long.  The final aid station was in the dip before IBM, in the parking deck under the unoccupied office building.  That final station was only 20 miles after the one that preceded it, but nonetheless I'd somehow managed to go through both bottles during that 20 miles.  I didn't refill after eating at the Little Tor stop, so maybe I did the 20 on a bottle and a half or less.  Regardless, I ran dry about a mile before this final aid station.  Had the last station not been there, I would've been forced to stop at the deli before State Line to refill -- no way was I going to to State Line and friends on dry bottles.

Refilling at the final aid station, even though it was only 12mi from the finish, turned out to be a wise decision for other reasons as well.  Due to apparent permitting reasons, the organizers had to change the finish line location from somewhere in NJ (Edgewater-ish?) to Palisades Park.  In order to get permission to do that, they had to have a "simple" (their words) finish line.  I had assumed that "simple" would at least mean water.  Turns out not so much.  The only thing at the finish line was a timing mat.  I know at least one person who skipped the final aid station, assuming that the finish line would have water, and ended up riding dry back to the city.  My stop saved me from that (I've done it before -- it's not fun), and left me with enough to drink all the way home.

With a finish line in Palisades Park (specifically, the southern traffic circle), the end of the route has to involve a trip down River Road.  Specifically, it must enter Palisades Park at Alpine Approach, and must descend River Road.  I feel for the out-of-towners who had to do that descent (NJ hasn't repaved that road in something like 300 years) -- especially for the many who were seen fixing flats near the bottom of it.  Oh well.  We didn't want them to leave having only seen the best of NYC-area cycling -- they should see the worst of it as well.

The congestion on River Road hill wasn't nearly as bad as I had expected, and so I was able to keep to the relatively smooth parts.  A few more miles on River Road, and I rolled across the finish line in style.  102mi.  8700' of climbing.  The hardest century I'd ever done: FINISHED.

Now, to get home.  The finish line is about 1/3 the way up River Road from the water, with an ascent of the remaining 2/3 needed to get to the bridge.  I'd blown that ascent all out of proportion, and had been very nervous that I wouldn't be able to make it after having completed the GFNY.  Boy was I mistaken.  That hill was nothing compared to what I'd been riding, and I sailed (ok, crawled) up it.  A short ride home, and a nice relaxing evening.

A word on training.  I wouldn't have been able to complete this ride without the awesome training plan I got from Brad Gansberg.  That man had me climbing more hills that I thought existed.  But it paid off.  Oh, how it paid off.  Midweek rides which included several repeats of River Road hill plus a trip up Eisenhower.  Weekend rides which routinely topped 6000' of climbing.  So many hard rides.  But I'm oh so happy with the result.

Next stop -- a 10,000' ride.  Maybe one of the ones put on by the PA Randonneurs.

RTS/CTS handshaking and waveforms

I decided to learn about RS-232 signalling and handshaking.  I had a heck of a time finding a single page which summed up everything I would’ve needed to know, so I’m writing this post in the hopes that it’ll help someone else in the same situation.
Here’s what I’m trying to do:  I have a DB-9 serial port hooked up to an ATMega644 microcontroller (MCU), with an SP3232EB RS-232 transceiver in the middle, as shown below:

Three-wire RS-232 (RX, TX, GND) wasn’t sufficient for my purposes, so I’m going to do five (RX, TX, RTS, CTS, GND).

When we talk about RX and TX, we’re going to do it from the MCU’s perspective.  That is, we read from the PC on RX, and we transmit to the PC on TX.  RTS and CTS have non-reversible meaning, so no clarification needed.

How does this all work?  RTS/CTS handshaking is used to ensure that the peripheral (the MCU, in our case) is ready to handle data from the host (the PC).  It doesn’t appear to apply in the other direction (or if it does, I haven’t found the need to care).  The idea is that the PC is powerful enough to handle just about anything you may care to throw at it, but the dinky MCU isn’t so lucky.  The PC can easily overflow any buffers the MCU may care to put in place, so the MCU needs a way to tell the PC when the PC is allowed to send new data.  That’s where the handshaking comes in.

There are two ways to do RTS/CTS handshaking.  The first is request/acknowledgement.  When the PC is ready to send data, it uses RTS (request to send) to tell the MCU that it (the PC) has data to send.  I say “uses” because the logic levels are a bit funny, as described below, but are unimportant for now.  The MCU sees that the PC is ready to send data.  When the MCU is ready to receive it, it uses CTS to tell the PC that the data can be sent.  The PC watches CTS to see a) when it can start sending data, and b) when it must stop.  The second type of RTS/CTS handshaking does bidirectional metering (more details here).  I've chosen to implement request/acknowledgement, but conversion to bidirectional would be straightforward.

When interfacing RS-232 and TTL, we have to deal with two different standards for logic levels.  TTL is 0-to-not-zero.  0-to-5, in the case of my circuit.  5V is asserted; 0V is not asserted.  RS-232, on the other hand, uses positive and negative voltages.  A positive voltage is referred to as a space, while a negative voltage is a mark.  The transceiver’s job is to translate between RS-232 and TTL voltages.  It does so by mapping RS-232 positive to TTL 0, and RS-232 negative to TTL 1.  That is, the TTL voltages are roughly the inverse of the RS-232 voltages.

Here’s the letter p (0x70), being sent across the wire at 9600 baud, 8N1:

Now that we know this, let’s restate the operation of RTS and CTS using the TTL voltages generated by the transceiver.  This is probably the most important paragraph of this post, and took a surprisingly long time to beat into my thick skull.

RTS and CTS are normally held high (TTL 1).  When high, no request (RTS) has been made, and no permission (CTS) has been granted.  When the PC is ready to send data, it brings TTL RTS low.  The MCU sees this.  When the MCU is ready to receive data, it brings TTL CTS low.  The PC sends data as long as TTL CTS is low, and stops when the MCU takes TTL CTS high.  One imagines that the sender is allowed to finish the current symbol (byte), but I haven’t verified that.

Now, to wire everything up.  As stated above, we’re using RX and TX from the perspective of the MCU, as that’s how everything is labeled on the MCU’s end (i.e. in the MCU itself and in the transceiver).

SB3232EB (MAX232)
Function Direction DB-9 pin RS-232 pin TTL pin AVR pin
RX PC to AVR 3 13 (R1IN) 12 (R1OUT) 14 (PD0/RX)
TX AVR to PC 2 14 (T1OUT) 11 (T1IN) 15 (PD1/TX)
RTS PC to AVR 7 8 (R2IN) 9 (R2OUT) 17 (PD3)
CTS AVR to PC 8 7 (T2OUT) 10 (T2IN) 16 (PD2)

I messed up the wiring a couple of times until I drew up the above chart.  Then everything went together smoothly.

Here’s the end result, captured by an Open Bench Logic Sniffer via the OLS LogicSniffer client:

We’re looking at an attempt by the PC to send a multi-character string as fast as it can, only to be metered by the MCU.  Please excuse the bubbles -- when zoomed in, they show the byte values being transmitted.  As we can see, the MCU idles with CTS low (ready to receive).  A character comes in, and the MCU raises CTS (stopping further transmissions from the PC) while it processes the received byte.  In this case, the program running on the MCU sends some data back to the PC describing the received byte.  Once that’s done, the MCU lowers CTS to receive another byte, raises CTS once that byte is received, and repeats the process.  By doing this, we receive everything the PC wanted to send -- nothing gets lost due to MCU buffer overflows.

Here's some sample code, written for the ATMega644:

#include <avr/io.h>

#define UBRR_ASYNC_NORMAL(baud) \
  (((((F_CPU * 10) / (16L * baud)) + 5) / 10) - 1)

#define RTS PD3
#define CTS PD2

#define BAUD 9600

static int uart_haschar(void) {
  return (UCSR0A & (1 << RXC0));

static int uart_getchar(void) {
  while (!uart_haschar());
  return UDR0;

int main(void) {
  UCSR0B = (1 << RXEN0) | (1 << TXEN0);
  UCSR0C = (0 << USBS0) | (3 << UCSZ00);

  DDRB = 0b11101111;  // PB4 = MISO
  DDRD = 0b11110110;  // PD0 = RX, PD3 = RTS

  // Inhibit CTS by setting it to TTL 1 (RS232 off)
  PORTD |= (1 << CTS);

  for (;;) {
    // Wait for host to set RTS (set it to TTL 0)
    while ((PIND & (1 << RTS)) != 0);

    // Set CTS (TTL 0 == RS232 on)
    PORTD &= ~(1 << CTS);

    char c = uart_getchar();

    // We have a character, so clear CTS (TTL 1 == RS232 off)
    PORTD |= (1 << CTS);

    // Do something with c

  return 0;

There, of course, other ways to guard against buffer overflows.  We could read from the UART using an interrupt handler, but that a) complicates the code considerably and b) only works if we can keep up with the uncontrolled data rate over the long run.  Perhaps more realistically, we could structure our commands to the MCU such that they all have responses, offloading the responsibility for guarding against overflows onto the PC.  That won’t work, though, if we want the microprocessor to be able to generate its own messages asynchronously.

Updated: Clarified terminology for ATMega/AVR/MCU, added diagram, fixed T1IN pin number, described the other way to look at RTS/CTS handshaking for bidirectional use.
Updated: Changed initial setting of PORTD so it just sets the CTS bit.  Not absolutely necessary, since there's nothing else in this code that'll be affected by it, but it'll help anyone who tries to cut'n'paste.

Sunday, April 17, 2011

Shift Registers

My idea for an 8-bit hex decoder discussed in the previous post turns out to have been overcomplicated.  It would've been fun to implement, but was still too complicated.  Recall that I was going to use a PISO shift register for input, an ATTiny85 as the brains, and two SIPO shift registers -- one for each 7-segment display.  Looking around (I can't remember the source), I realized that the output stage didn't need nearly quite so many components.  If I have nine output pins (maybe eight?), I can connect both displays simultaneously, using the same pins, with transistors on their common anode lines to switch between the two.  The idea is that I set the segments on the first display while the second is off, and then vice versa.  Do it fast enough, and the eye thinks they've both been on the whole time.

In order to do this, though, I need 8-9 output pins on the microcontroller which can be devoted to the output stage.  As it happens, the ATTiny2313 should have enough, and is about the size of the ATTiny85 and one of the shift registers.

But enough about that.  I wanted to play with shift registers, even if I wasn't going to use them in the digit decoder.  To do that, I used an ATMega644 to drive a single 7-segment display.  For input, I used four switches connected to a 74HC165N shift register.  Output was via a 74HC565N shift register.  Why shift registers and an ATMega644, which is wildly overpowered for this application, and which could read the switches and drive the 7-segment display directly?  I didn't want to have to worry about microcontroller constraints (RAM size, etc), and wanted to concentrate on the shift registers.


This is the most complicated circuit I've ever breadboarded, and it just about fills up the breadboard.  Everything from the ATMega644 to the left on the lower row is necessary support stuff (from right to left, the MCU, RS232 transceiver, and power switch.  So basically support stuff takes up 1/3 of the board, leaving me the other 2/3.  I'm going to need to switch to the big board soon.  I'm tempted to leave the ATMega644 set up on this one so I don't have to rewire it and the transceiver whenever I want to use it.  At the very least, I'll probably leave it set up until I verify whether I can make the hex decoder work.

Lessons learned (or relearned):
  • Fuses are important.  Not the kind that blow when there's too much current (though they're useful too), but the kind Atmel uses to configure AVR processors.  The first one to bite me was the one that controls the JTAG interface. With it enabled (which it is by default), PC2-PC5 are dedicated to JTAG use.  PC0 and PC1 function normally, which gave me one heck of a time trying to figure out why an early 3-LED circuit (one each on PC0-PC2) would only partially work.
  • The other important fuses are the ones which control the oscillator.  Atmel has a bewildering array of oscillator configuration options, involving 8 of the 19 fuses on the ATMega644.  This AVR fuse calculator was very helpful.
  • To write fuses, invoke avrdude as
    avrdude -p part -U fusename:w:0xvalue:m
  • To read fuses to stdout, invoke it as
    avrdude -p part -U fusename:r:-:h
  • I'd learned about aliasing while watching an EEVblog review of the "budget" Agilent 2000-series oscilloscope, and this time I got to see it in person.  I wanted to verify that the processor was running properly at 16MHz, so I set the CKOUT pin, and ran it through my PCSU1000.  I don't remember which Time/Div setting I was using, but I was seeing a stable output sine wave at about 1kHz, rather than 16MHz.  Hilarity ensued until I remembered Dave's mention of aliasing, at which point I decreased the Time/Div setting.  Low and behold, a 16MHz wave appeared.  So that was exciting.
  • You don't use the same variable for writing AVR ports as you do for reading them.  PORTn for output, PINn for reading.   Reading from PORTn, expecting to get input values, will only lead to sadness and dismay.

Wednesday, April 6, 2011

Plans for my next design, and a breakout board for the AVRISP2

I'd like to build a circuit which samples 8 bits of input and displays the results as a hexadecimal number on two 7-segment displays.  This would be much simpler if the standard 7400-series decoders weren't all BCD, and thus didn't all stop at 9.  There are true hexadecimal multi-segment drivers, but the one that looked best (the ICM7212) was close to $7, and would've required lots of support glue.

Digression: The ICM7212 controls four 7-segment displays.  The 40-pin DIP has one pin for each segment on each display, four digit pins, and four data pins.  To display a value on a given 7-segment display set the data lines with the desired value, and toggle the appropriate digit line.  This circuit will have eight data lines inbound, so we'd need a quad 2-1 mux (the 74HCT157, for example).  We only need to toggle two digit lines, which we could do with a 555 and an RTL inverter.

For giggles, let's cost it out (all prices from for individual quantities); $6.70 for the ICM7212, $0.47 for the timer, and $0.69 for the mux.  We'll assume that the resistors, capactors, and transistors needed for the 555 timer glue and for the inverter are free. $8.55 for the whole thing.  Oh, and the ICM7212 is huge.

All of this is a long way of justifying doing it with a microcontroller instead.  The added advantage of doing it with the microcontroller and shift registers is that I'll likely see them again (and again and again), so it'd be helpful to gain some experience.

So the current plan is to do something with an ATtiny85 microcontroller.  A parallel-in-serial-out (PISO) shift register on the input, sampled periodically by the microcontroller, and two serial-in-parallel-out (SIPO) shift registers on the output.  If we can share the clock lines between all three chips, I think we can get away with using only four pins on the microcontroller.  The tiny has 6, excluding VCC and GND, so this should be doable.

To familiarize myself with the chips required, I decided to build the beAVR setup described here.  It's nothing fancy -- just an ATmega644 with supporting gunk (caps, clock, etc).  I don't have the USB-to-5V serial cable recommended in the article, so I also had to add an SP3232EBCP RS232 transceiver so I could hook up the USB serial line.  This won't be needed for the final design, with the tiny, but it's nice to have for debugging.  Who knows -- with two pins left, maybe I can use it on the tiny.

I've done the medusa head AVRISP2 connection before.  I didn't like it then, and I don't like it now, so this time I decided to do something about it.  I built a little breakout board that transforms the 2x3 pin ISP connector to 1x6pin, which is compatible with the breadboard.   Here are some pictures:

Things I learned from building this thing:
  • The Helping Hands are amazingly useful.  Now I have a stable suspended platform on which to solder.  It makes things like header pin alignment considerably easier.
  • The default font in TextEdit (12pt Helvetica?) has precisely the right vertical spacing when you print at 50%.
  • To attach the labels, print on a full-size sheet of paper, cut out the width to fit (from the top of the VCC to the bottom of the MOSI), but leave it an inch or two longer than necessary.  This gives you a nice handle with which to hold the label while you superglue it to the plastic thing on the header.
  • I'm not a huge fan of long pad-to-pad solder bridges.  I like wires.  They're much less fussy than bridges.
  • Hot glue is, once again, my friend.  I used it to protect the underside of the PCB.
What I'll do differently next time (there will be a version two):
  • This version's pin mapping between the 2x3 header and the 1x6 is based on shortest distance.  Unfortunately, that approach results in a 1x6 ordering that doesn't match the pin ordering on the ATmega644.  As I'll likely be doing most of my programming with the mega, I'd rather the breakout board just drop into place, without requiring me to string wires hither and yon.  Version 2's mapping will follow the ATmega644 pin ordering.  VCC and GND may be shifted back on the board, behind the 2x3, allowing them to plug directly into the breadboard power rails.
  • Pin labels should be visible regardless of breakout board orientation.  In this version, they're only visible from the front, which makes it awkward when I install it with the front facing away from me.  The paper is fragile, but I knew that going in.  We'll see how it works out.  I may need to switch to another material.

Monday, April 4, 2011

Mac Serial Program

Having grown weary of Minicom, and not really wanting to set up screen to talk to a serial port, I went looking for a Mac terminal program.  I think I have a new favorite: goSerial.  It does all the basic things you'd want, and looks like it'll meet my needs nicely.  Notably, it looks nothing like this.

Thursday, March 31, 2011

Evil Ride

I'm training for the Gran Fondo NY coming up in a month and a half, with a plan Brad put together.  The GF route is quite hilly, with ascents of Little Tor (northbound), Buckberg Mountain, Bear Mountain (to the summit), Gate Hill, Little Tor (southbound), as well as the various hills needed to connect them (Toga, State Line, etc).  So anyway, Brad's foul plan for yesterday called for four repeats of River Road (from the parking lot), to which I added a trip up Eisenhower, for 45mi.  (Strava link)

The River Road repeats were exciting, as always.  I seem to be able to knock out three without much difficulty (though my back isn't a huge fan).  The unpleasantness kicks in about halfway up the fourth.  I can only imagine how exciting next week's five repeats will be.  All the whining aside, it is pretty cool to know that I can string together that many repeats and still walk away from it, so to speak.

This was only my second time up Eisenhower.  The descent to Eisenhower, on Hillside (from 9W), is easily one of my favorite descents in the area.  Perhaps I'll grow jaded, but for now it's lots of fun.  I don't know exactly why I like it more than State Line.  Maybe it's that the descent is windier.  Maybe it's because I haven't done Hillside three thousand times.  Who knows.

Eisenhower has three hills.  The first and the third are brutal.  It's like force work, without the inconvenience of needing to change to a higher gear.  The scenery is nice, though.  Giant mansions (in varying degrees of tastefulness) line the road.  You could hear a pin drop in this neighborhood after everyone's gone to work, so there's almost no traffic.  Just climb, climb, climb, climb.

Here's the descent to, and ascent of, Eisenhower. Yes, the camera was on sideways. Sorry.

Sunday, March 27, 2011

4-bit counters

I played around with 4-bit counters to see how the program counter for my CPU will work.  It's becoming clearer now that I know how the counters cascade and how they can be set with new values.  It's also becoming clearer that I don't have nearly enough breadboard space.  PB-105 here I come?  The writeup is here.

Pretty picture and circuit:

Saturday, March 26, 2011

7-Segment LEDs

I've been playing with 7-segment LEDs over the past couple of days, starting with the LED and a '4543 BCD decoder, then adding a counter, a debouncer for the switch that drove the counter, and eventually a timer to make it count by itself.  The writeup is here.

I feel compelled to prepare these elaborate writeups so I don't feel quite so bad when I tear the circuit down.  It's not like woodworking (alas), where you end up with something to keep when you're done.  Instead, build a circuit, take it apart, build another one, take it apart, and so on.  Well, I'll keep some circuits.  This just wasn't one of them.

The result:

Train layout blueprint

With the layout done in a CAD program, I figured I could easily print it 1:1, lay the printout down on the plywood, and begin assembly on the plywood.  That way there's no need to do painful measurements -- I simply put the parts on the blueprint, and I'm done.  This of course, ignores cork roadbed and how I'm going to get the blueprint out after I've attached the track, but one thing at a time.

So first, we need to get the layout printed 1:1.  XTrackCAD can do this natively, by dividing the layout into 8.5x11" sections -- sections which you then glue back together.  This brings back memories of pasting together banners with Print Shop on Apple //e's with dot matrix printers.  This blog post describes what you need to do to get XTrackCAD to print this way.  One advantage of using XTrackCAD is that you can ask it to include marks for the cork roadbed.  The disadvantage of doing it this way is that you have to cut margins from a zillion individual pages (18 for my layout) and painstakingly align and tape them together.  With CutePDF on Windows, you can at least convince XTrackCAD to put the whole thing in a PDF for printing.  On the Mac, it prints as PS, which you have to convert to PDF for printing.  I ended up doing it on the Windows machine, as I had no end of trouble trying to get Preview to open the PS files (and didn't feel like installing ps2pdf).

Once we have the layout printed on 8.5x11, we have to summon the urge to do all that cutting and taping.  I tried and tried, but it wasn't to be.  Wouldn't it be simpler to print the whole thing out on one sheet of blueprint paper?  I wasn't able to convince XTrackCAD to print on large paper -- it seemed to want to restrict the maximum page size to 8.5x11.  It certainly didn't want to try printing to a 36"x48" blueprint page.  So now, the adventure begins.  I figured a bit of time invested fiddling with software would more than pay off if it freed me from the need to play cut'n'paste.

Here's what I ended up doing:
  1. In XTrackCAD, select Select All from the Edit menu.  This selects everything, of course, but also causes the Export and Export DXF items to activate under the File menu.
  2. Export DXF.  Save the file somewhere.
You may be able to stop here, if your printer (or print store) will accept DXF.  I wanted to be extra sure. DXF is opaque to me, but PDF is not.  I wanted to get a PDF which would print to 36x48, and wanted to visually verify that.
  1. Install EDrawingsViewer -- a free viewer for DXF files.  It's available for PC or Mac, though I used the PC version.
  2. Open the DXF file with EDrawingsViewer, and print it.
    1. Select a 1:1 print:

    2. Select the CutePDF printer
    3. Hit the Properties button to configure CutePDF for this print.
    4. Select the Layout tab.  You'll probably want Landscape.
    5. Select the Paper/Quality tab, and click the Advanced button
    6. Under Paper/Output, you'll see Paper Size.  Change the value to "Postscript Custom Page Size".
    7. Click the Edit Custom Page Size button.
    8. Set the dimensions of the page.  For me, it was 36" by 48".
    9. Print the document
    10. CutePDF will open a dialog box, asking you where to save the PDF file. Pick a location, and save it.
  3. Take the PDF file to your local print store. I took mine to Staples, where they printed it out on blueprint paper for just over $5.  One thing to note about Staples: While their online tool claims to support wide-format printing, it doesn't have a rotate button.  If it disagrees with the rotation of your PDF file (as it did with mine), you have to place the print request in person.
Here's the result:

That's the blueprint (the glorious one-sheeted blueprint) sitting on the sheet of plywood.  I added a turnout just to verify that the sizes were right, and they were.  The turnout fits exactly.

I will miss the roadbed outlines.  XTrackCAD can generate them when writing PostScript, but apparently not when writing DXF.  Sigh.  I'd rather have one sheet of paper than roadbed outlines, though.