Archive for May, 2018
Raspberry Pi GPIO Programming in C
The Raspberry Pi’s 40-pin GPIO connector often gets overlooked. Typical Pi projects use the hardware as a very small desktop PC (RetroPie, Pi-hole, media center, print server, etc), and don’t make any use of general-purpose IO pins. That’s too bad, because with a little bit of work, the Raspberry Pi can make a powerful physical computing device for many applications.
Raspberry Pi vs Arduino (and other microcontrollers)
Why would you want to use a Raspberry Pi instead of an Arduino or other microcontroller (STM32, ATSAM, PIC, Propeller)? There are loads of “Raspberry Pi vs Arduino” articles on the web, and in my view almost all of them miss the mark. The Pi is not a better, more powerful Arduino. It’s a completely different type of device, better at some tasks, but markedly worse at others.
The Pi is vastly more powerful than something like an Arduino Uno. The latest Pi 3 Model B+ has an 88x faster CPU clock and 500,000x more RAM than the Uno. It also runs a full-fledged Linux operating system, so it’s much easier to create projects involving high-level functions like networking or video processing. And you can connect a standard keyboard, mouse, and monitor, and use it as a normal computer.
But the Pi operating system is also a huge weakness in many applications. There’s no “instant on”, because it takes nearly a minute for the device to boot up. There’s no appliance-like shutoff either – the Pi must be cleanly shutdown before power is turned off, or else the operating system files may get corrupted. And real-time bit twiddling of GPIO is mostly impossible, because the kernel may swap out your process at any moment, making precise timing unpredictable.
In theory it’s possible to do bare-metal programming on the Raspberry Pi, eliminating Linux and its related drawbacks for real-time applications. Unfortunately this doesn’t seem to be a common practice, and there’s not much information available about how to do it. So the Pi is probably best for those applications where you need some major CPU horsepower and some kind of GPIO connection to other sensors or equipment, but don’t need precise real-time behavior or microsecond-level accuracy.
GPIO and Python?
If you start Googling for “Raspberry Pi GPIO programming”, you’ll quickly discover that most of the examples use the Python language. In fact, this seems to be the most popular way by far to use GPIO on the Pi.
I have nothing against Python, but I’m a C programmer through and through, and the idea of using a high-level language for low-level digital interfaces is unappealing. By one measure, Python is over 300x slower at Raspberry Pi GPIO manipulation than plain C. I’m sure there are applications where it’s OK to throw away 99.7% of potential performance, but I’ll be sticking with C, thank you very much.
I spent a little time researching four different methods of Raspberry Pi GPIO manipulation in C. This involved reading documentation and data sheets, and examining the source code of various libraries. I haven’t yet tried writing any code using these methods, so take my impressions accordingly.
If any of the authors of these C libraries happen to read this – thank you for your work, and please don’t be offended by any criticisms I may make. I understand that creating an IO library necessarily involves many tradeoffs between simplicity, speed, flexibility, and ease of use, and not everyone will agree on the best path.
Direct Register Control – No Library
The GPIO pins on the Raspberry Pi can be directly accessed from C code, similarly to how it’s done on the ATMEGA or other microcontrollers. A few different memory-mapped control registers are used to configure the pins, and to read input and set output values. The only big difference is that the code must first call mmap() on /dev/mem or /dev/gpiomem, to ask the kernel to map the appropriate region of physical memory into the process’s virtual address space. If that means nothing to you, don’t worry about it. Just copy a couple of dozen lines of code into your program’s startup routine to do the mmap, and the rest is fairly easy.
Here’s an example of reading the current value of GPIO 7:
if (gpio_lev & (1<<7)) // pin is high else // pin is low
Just test a bit at a particular memory address - that's it. This looks more-or-less exactly like reading GPIO values on any other microcontroller. gpio_lev is a memory-mapped register whose address was previously determined using the mmap() call during program initialization. See section 6 of the BCM2835 Peripherals Datasheet for details about the GPIO control registers.
Setting the output value of GPIO 7 is similarly easy:
gpio_set |= (1<<7); // sets pin high gpio_clr |= (1<<7); // sets pin low
Using other control registers, it's possible to enable pull-up and pull-down resistors, turn on special pin functions like SPI, and change the output drive strength.
Watch out for out-of-order memory accesses! The datasheet warns that the system doesn't always return data in order. This requires special precautions and the use of memory barrier instructions. For example:
a_status = *pointer_to_peripheral_a; b_status = *pointer_to_peripheral_b;
Without precautions, the values ending up in the variables a_status and b_status can be swapped. If I've understood the datasheet correctly, a similar risk exists for GPIO writes. Although data always arrives in order at a single destination, two different updates to two different peripherals may not be performed in the same order as the code. These out-of-order concerns were enough to discourage me from trying direct register IO with my programs.
Wiring Pi
WiringPi wraps the Raspberry Pi GPIO registers with an API that will look very familiar to Arduino users: digitalRead(pin), digitalWrite(pin, value). It's a C library, but third parties have added wrappers for Python and other high-level languages. From a casual search of the web, it looks like the most popular way to do Raspberry Pi GPIO programming in C.
WiringPi appears to be designed with flexibility in mind, at the expense of raw performance. Here's the implementation of digitalRead():
int digitalRead (int pin) { char c ; struct wiringPiNodeStruct *node = wiringPiNodes ; if ((pin & PI_GPIO_MASK) == 0) // On-Board Pin { /**/ if (wiringPiMode == WPI_MODE_GPIO_SYS) // Sys mode { if (sysFds [pin] == -1) return LOW ; lseek (sysFds [pin], 0L, SEEK_SET) ; read (sysFds [pin], &c, 1) ; return (c == '0') ? LOW : HIGH ; } else if (wiringPiMode == WPI_MODE_PINS) pin = pinToGpio [pin] ; else if (wiringPiMode == WPI_MODE_PHYS) pin = physToGpio [pin] ; else if (wiringPiMode != WPI_MODE_GPIO) return LOW ; if ((*(gpio + gpioToGPLEV [pin]) & (1 << (pin & 31))) != 0) return HIGH ; else return LOW ; } else { if ((node = wiringPiFindNode (pin)) == NULL) return LOW ; return node->digitalRead (node, pin) ; } }
That's a lot of code to accomplish what could be done by testing a bit at an address. To be fair, this code does a lot more, such as an option to access GPIO using sysfs (doesn't require root?) instead of memory-mapped registers, and pin number remapping. It also adds a concept of on-board and off-board pins, so that pins connected to external GPIO expanders can be controlled identically to pins on the Raspberry Pi board itself.
From a brief glance through the source code, I couldn't find any use of memory barriers. I'm not sure if the author determined that they're not necessary somehow, or if out-of-order read/writes are a risk.
WiringPi also includes a command line program called gpio that can be used from scripts (or interactively). It won't be high-performance, but it looks like a great tool for testing, or for when you just need to switch on an LED or something else simple.
pigpio
pigpio is another GPIO library, and appears more geared towards simplicity and speed. And yes, it was quite a while before I recognized the name was Pi GPIO, and not Pig Pio. 🙂
Here's pigpio's implementation of gpioRead():
#define BANK (gpio>>5) #define BIT (1<<(gpio&0x1F)) int gpioRead(unsigned gpio) { DBG(DBG_USER, "gpio=%d", gpio); CHECK_INITED; if (gpio > PI_MAX_GPIO) SOFT_ERROR(PI_BAD_GPIO, "bad gpio (%d)", gpio); if ((*(gpioReg + GPLEV0 + BANK) & BIT) != 0) return PI_ON; else return PI_OFF; }
Here there's no pin number remapping or other options. The function does some error checking to ensure the library is initialized and the pin number is valid, but otherwise it's just a direct test of the underlying register.
As with WiringPi, I did not see any use of memory barriers in the source code of pigpio.
bcm2835
bcm2835 is a third option for C programmers looking for a Raspberry Pi GPIO library. It appears to have the most thorough and well-written documentation, but also seems to be the least commonly used library of the three that I examined. This may be a result of its name, which is the name of the SoC used on the Raspberry Pi. It's somewhat difficult to find web discussion about this library, as opposed to the chip with the same name.
Like pigpio, bcm2835 appears more focused on providing a thin and fast interface to the Pi GPIO, without any extra options. Here's the implementation of bcm2835_gpio_lev(), the oddly-named read function:
uint32_t bcm2835_peri_read(volatile uint32_t* paddr) { uint32_t ret; if (debug) { printf("bcm2835_peri_read paddr %p\n", (void *) paddr); return 0; } else { __sync_synchronize(); ret = *paddr; __sync_synchronize(); return ret; } } uint8_t bcm2835_gpio_lev(uint8_t pin) { volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPLEV0/4 + pin/32; uint8_t shift = pin % 32; uint32_t value = bcm2835_peri_read(paddr); return (value & (1 << shift)) ? HIGH : LOW; }
The pin number is constrained to the range 0-31, but otherwise there's no error checking. The actual read of the GPIO register is performed by a helper function that includes memory barriers before and after the read.
Impressions
For my purposes, I would probably choose pigpio or bcm2835, since I prefer a thin API over one with extra features I don't use. Of those two options, I'd tentatively choose bcm2835 due to the format of its documentation and its use of memory barriers. I wish I understood the out-of-order risk better, so I could evaluate whether the apparent absence of memory barriers in the other libraries is a bug or a feature.
Any analysis that looks at just a single API function is clearly incomplete - if you're planning to do Rasbperry Pi GPIO programming, it's certainly worth a deeper look at the many other capabilities of these three libraries. For example, they differ in their support for handling interrupts, or byte-wide reads and writes, or special functions like SPI and hardware PWM.
Did I miss any other C programming options for Raspberry Pi GPIO, or overlooked something else obvious? Leave a note in the comments.
Read 22 comments and join the conversation64 x 32 LED Matrix Programming
Everybody loves a big bright panel of LEDs. Way back in 2011, my daughter and I hand-built an 8 x 8 LED matrix Halloween display. More recently I’ve been playing with a 64 x 32 RGB matrix that I purchased on eBay for $26. Each point in the matrix is 3 independent red, green, and blue LEDs in a single package, so that’s 6144 total LEDs of awesomeness. Wow! Similar but smaller 32 x 32 and 32 x 16 RGB matrixes are also available from vendors like Sparkfun and Adafruit, so LED glory is within easy reach.
But wait, how do you control this thing? Is there a simple “hello world” example somewhere? I couldn’t find one. Adafruit has a nice Arduino library, but it’s much more complex than what I was looking for, so the basic details of controlling the matrix are lost in a sea of other code about PWM modulation, double-buffering, interrupt timing, gamma correction, color space conversion, and more. Great stuff, but not a good “how to” example for beginners. There’s also a Raspberry Pi library by Henner Zeller that’s incredibly rich, supporting video playback and other advanced features. But I really just wanted a couple of dozen lines of code to support a basic setPixel() interface, so I wrote one myself.
How is this LED matrix code different from the Adafruit and Henner Zeller libraries? It’s intentionally primitive, and serves a different purpose, for a different audience:
- Under 100 lines of code: easy to understand how it works.
- No hardware dependencies – easily portable to any microcontroller.
- Basic setPixel() interface. No fonts, lines, etc.
- 8 basic colors (3-bit RGB) only. No PWM for additional colors.
- Requires only 1 KB RAM for 64 x 32 matrix.
Controlling the Matrix
All the different varieties of LED matrixes have the same style of 16-pin connector for the control signals:
Larger matrixes like mine will also have a “D” input that replaces one of the ground pins. So what do these signals do?
OE – Active low output enable. Set this high to temporarily turn off all the LEDs.
CLK – Clock signal used for shifting color data into the matrix’s internal shift registers.
LAT – When high, data in the shift registers is copied to the LED output registers.
A, B, C (and maybe D) – Selects one of 8 (or 16) rows in the matrix to illuminate.
[R1, G1, B1] – Color data for the top half of the matrix.
[R2, G2, B2] – Color data for the bottom half of the matrix.
A matrix like this one can’t turn on all its LEDs simultaneously – only one row is on at a time. But by cycling through the rows very quickly using the A/B/C inputs, and changing the color data at the same time as selecting a new row, it can fool the eye into seeing a solid 2D image. There’s no built-in support for this row scanning, so the microcontroller that’s generating the matrix inputs must continuously refresh the matrix, cycling through the rows and updating the color data. Any interruption from another calculation or microcontroller task will cause the LED image to flicker or disappear.
Internally the matrix can be imagined as a big shift register (or actually several shift registers in parallel). The shift register size is equal to the matrix’s width. For a 64-wide matrix, the microcontroller shifts in 64 bits of data, generating a positive CLK edge for each bit, and then strobes LAT to load the shift register contents into the LED output register. The LEDs in the currently-selected row then turn on or off, depending on the data that was loaded.
Because each row contains 64 independent red, green, and blue LEDs, three independent shift registers are required. The serial inputs to these shift registers are R1, B1, and G1.
But wait – there’s one more important detail. Internally, a W x H matrix is organized as two independent matrixes of size W x (H / 2), mounted one above the other. These two sub-panels share the same OE, CLK, and LAT control inputs, but have independent color inputs. R1, G1, B1 are the color inputs for the upper sub-panel, and R2, G2, and B2 are for the lower sub-panel.
Putting everything together, we get this recipe for controlling the matrix:
2. Initialize a private row counter N to 0.
3. Set R1,G1,B1 to the desired color for row N, column 0.
4. Set R2,G2,B2 to the desired color for row HEIGHT/2+N, column 0.
5. Set CLK high, then low, to shift in the color bit.
6. Repeat steps 3-5 WIDTH times for the remaining columns.
7. Set OE high to disable the LEDs.
8. Set LAT high, then low, to load the shift register contents into the LED outputs.
9. Set ABC (or ABCD) to the current row number N.
10. Set OE low to re-enable the LEDs.
11. Increment the row counter N.
12. Repeat steps 3-11 HEIGHT/2 times for the remaining rows.
Using this method, each pixel in the matrix is defined by a 3-bit color, supporting the 8 basic colors red, green, blue, cyan, magenta, yellow, black, and white. It’s certainly possible to create more colors by using PWM to alter the duty cycle of the red, green, and blue LEDs, but this quickly becomes complex and too CPU-intensive for your average Arduino. The Adafruit library squeezes out 12-bit 4/4/4 color, but it’s hard-coded for only the Arduino Uno and Mega. I chose to keep my example code simple and skip PWM, so the color palette is limited but it’ll run on any ATMEGA (or really on any generic microcontroller).
This method is appropriate for displaying a static image that was previously drawn into a memory buffer. It won’t work for animated images, because the code for updating the animation would need to be interleaved somehow into the code for refreshing the matrix. If you need animation, you’ll need to perform steps 3-11 inside an interrupt service routine that’s executed at roughly 3200 Hz (or 200 Hz times HEIGHT/2). Anything slower than that, and the human eye will begin to perceive flickering.
Here’s my example code using the above method. It refreshes the matrix as quickly as the CPU allows, and provides a very basic setPixel(x, y, color) API. The code was written for a 16 MHz ATMEGA32U4, but it doesn’t use any ATMEGA-specific hardware features, and should be easily portable to any other microcontroller with at least 2 KB of RAM.
My hardware was an ATMEGA32U4 breakout board, connected to the LED matrix with lots of messy jumper wires (this is Big Mess o’ Wires after all). Fortunately the mess is mostly hidden behind the display, but a custom-made adapter or cable would certainly be cleaner. Here’s a peek at the back side:
I discovered one odd behavior that may be specific to this particular LED matrix: if you don’t cycle through the rows quickly enough, the matrix won’t display anything. It doesn’t work if you set the row number (ABCD inputs) to a fixed value for testing purposes, as I did in my initial tests. It took a huge amount of time for me to discover this, and I haven’t seen this behavior documented anywhere else. From my experiments, if you spend more than about 100 ms without changing the ABCD inputs, the display shuts off. Maybe it’s some kind of safety feature.
Displaying a Bitmap Image
Maybe you’re wondering how I rendered the BMOW logo in the title photo? I certainly didn’t write a bunch of code that calls setPixel() thousands of times – that would be painful. Instead, I used GIMP to export a 64×32 image as a C header file, and then wrote some glue code to parse the data and call setPixel() as needed. Here’s how you can do it too.
First you’ll convert your image to indexed color mode.
2. Select the menu Image->Mode->Indexed.
3. In the conversion dialog, select “Generate Optimum Palette”. Set the maximum number of colors to 256.
4. Click the button “Convert”.
Now you can export the converted image as a C header file.
2. In the save dialog, set the export type to “C source code header (*.h)”
3. Click the button “Export”.
Open the generated header file in a text editor. You should see a section that begins with data like:
static char header_data_cmap[256][3] = { { 0, 0, 0}, {244, 38,117}, { 28,239,250}, ...
and a second section that begins like:
static char header_data[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0, ...
For the Arduino or ATMEGA microcontrollers with limited RAM, these declarations must be modified to store the data in program memory (flash ROM) instead of in RAM. Other microcontrollers can skip this step.
For both of the above sections, change static char to const unsigned char, and add PROGMEM just before the = sign:
const unsigned char header_data_cmap[256][3] PROGMEM = { ... const unsigned char header_data[] PROGMEM = { ...
Then use the function LoadROMImage() to read the bitmap data and set the corresponding pixels in the LED matrix framebuffer. Here’s the updated example code:
led-matrix-bitmap.c
bitmap-data.h
The bitmap data is palettized color, where each palette entry is a color with 8 bits of red, 8 bits of green, and 8 bits of blue. LoadROMImage() just uses the most significant bit of each color channel to select the 3-bit color for the LED matrix framebuffer. If you want something fancier, you could try some kind of error-minimization code for selecting the 3-bit color instead. But if you care strongly about attractive-looking colors, then you should probably use Adafruit’s PWM library or something similar, instead of this code.
Footnote: I struggled to get a good-looking photo of the LED matrix. It’s very bright and sharp, with deeply saturated colors. But regardless of what camera settings I tried for shutter speed, ISO, and white balance, I got a muddy desaturated mess like the photo seen above. Judging by the other photos of this matrix that I found on the web, I’m not the only person to find the photography challenging.
If the example code here was helpful, or you built something interesting using it, please leave me a note in the comments. Thanks!
Read 3 comments and join the conversationApple IIc Drive Switcher Version 2
Version 2 of the Apple IIc Internal/External Drive Switcher is here, and is working nicely. It’s mostly the same as version 1, except for a few tweaks to the piece that goes inside the IIc case. Although the inside fit is still very tight, with this new version it’s a little more forgiving. I also updated the switch labels on the external portion of the drive switcher, with an icon showing parallel arrows for normal mode, and crossed arrows for drive swap mode.
In my previous trials with the drive switcher, I threaded two wires through a gap in the Apple IIc case around the 19-pin disk port. That works, but I’ve concluded it’s easier to thread the wires through the gap around the composite video connector instead, as shown in the photo below. There’s a little bit more wiggle room, and it avoids blocking the faceplate of the male DB-19 connector when the external portion of the drive switcher is plugged in. Threading the wires around the video connector doesn’t cause any blockage problems, and I had no difficulty plugging in the video cable. You could also thread the wires around the DB-15 monitor port, which most people aren’t using anyway.
I think it’s ready! Now I just need to assemble a few of these and get them ready for sale. If you’re interested in helping to beta test the first few units, please let me know.
Read 14 comments and join the conversationCrazy Fast PCB Manufacturing
I finished the redesign for my Apple IIc Drive Switcher PCB on Monday morning, and submitted the Gerber files to Elecrow on Monday at 11:25 am. Friday at 5:20 pm I held the finished PCBs in my hands. Only 4 days for manufacturing and delivery. From China. According to the tracking info, my package took just 17 hours to travel from Elecrow’s Shenzhen facility to my doorstep in California. Total cost for everything was a mere $29.96.
We live in a crazy world, where a completely custom and intricate item can be manufactured on the other side of the planet and delivered to my door in 4 days, for the cost of a pizza and beer. Thank you Elecrow!
Read 1 comment and join the conversation10000 More DB-19 Connectors
Oops, I did it again: another 10000 DB-19 connectors fresh from the factory! After helping to resurrect this rare retro-connector from the dead in 2016, and organizing a group of people to share the cost of creating new molds for manufacturing, I had some of the 21st century’s first newly-made DB-19s. The mating connector is found on vintage Apple, Atari, and NeXT computers from the 1980s and 1990s, so having a new source of DB-19s was great news for computer collectors.
But that was two years ago. After manufacturing, the lot of connectors was divided among the members of the group buy, leaving me with “only” a few thousand. Since then I’d used up more than half of my share in assembly of the Floppy Emu disk emulator, and I began to get nervous about the looming need for a re-order. It was such a big challenge the first time finding a Chinese manufacturer for the DB-19s, and the all-email company relationship was tenuous. What if they lost the molds? What if my contact there left the company? What if the company went out of business? Even though I didn’t absolutely need more DB-19 connectors until 2019 or 2020, I decided to lock in my future supply and order more now.
I needn’t have worried, and the transaction went smoothly. With no mold costs to pay this time, the only challenge was meeting the 10000 piece minimum order quantity. I was even able to pay via PayPal, instead of enduring the hassles and weird scrutiny of an international bank wire transfer like I did in 2016.
So now I have a near lifetime supply of DB-19 connectors. Call me strange, but it actually gives me a warm fuzzy feeling. Now to find someplace to store all these boxes…
Read 8 comments and join the conversationApple IIc Internal/External Drive Switcher
If you’re using a Floppy Emu disk emulator with an Apple IIc, you’ll want to see this: a switched adapter that can reassign the external 5.25 inch drive as internal, and the internal 5.25 inch drive as external. This little gizmo helps to work around the Apple IIc’s inability to boot from an externally-connected 5.25 inch drive. That shortcoming is a headache for 5.25 inch disk emulators like Floppy Emu. With this internal/external drive switcher, the limitation is now gone!
Background
The IIc has an internal built-in 5.25 inch floppy drive. The internal drive appears to the computer as slot 6, drive 1. If you connect an external 5.25 inch floppy drive, it will appear to the computer as slot 6, drive 2. Unfortunately the whole Apple II family is designed to check for a bootable disk in drive 1 only. The computer can boot from drive 1, and then use drive 2 as a secondary disk, but it can’t boot from drive 2. So for the IIc with its built-in drive 1, this means it can never boot from an external 5.25 inch drive.
An important detail: this limitation only applies to the Apple IIc with an external 5.25 inch drive. An external Smartport drive (like Floppy Emu when configured for Smartport hard disk emulation mode) appears to the computer as slot 5, drive 1, and is bootable.
Apple IIc owners who want to boot from an emulated 5.25 inch disk image are in a difficult spot. Until now, their best option has been to remove the top panel from the IIc, disconnect the internal floppy drive, and connect the Floppy Emu to the internal drive connector on the motherboard. This works fine for the Floppy Emu, but it means IIc owners forfeit their ability to use the internal drive.
How the Drive Switcher Works
There’s almost no difference between the internal drive connector on the motherboard and the external drive connector at the rear of the Apple IIc. Although they’re different shapes and even have different numbers of pins, they feature the exact same disk IO signals except one: the drive enable signal. To perform this drive switcheroo, the adapter needs to tap into the signals from the motherboard, divert the enable signal externally, and route the external enable signal back inside to the internal drive. This is easily accomplished with some headers and wires and a slide switch, but the tricky part is making it all small enough to fit inside the Apple IIc case.
A slide switch makes the drive remapping optional. At one switch position, the external drive will appear as drive 1 and the internal as drive 2. At the other switch position, the internal drive will appear as drive 1 and the external as drive 2. Now Apple IIc owners can have the best of both options.
The Hardware
This is a two-part device: a signal tap that should be installed inside the Apple IIc, and a modified DB19 adapter with a slide switch for the external connection. Two female-female jumper wires are passed through a gap in the case to make the connection between the two parts.
The signal tap portion of the drive switcher looks a little peculiar, and it’s a minor challenge to solder closely-spaced through-hole components to the top and bottom of a PCB like this, but it works. The top is just a standard 20-pin male shrouded header, with a polarizing key like the one used on Apple drive cables. The bottom is a PCB-mounted female version of the same connector – not a very common part, but fortunately Digikey has it. The only other component here is a 2-pin male header for attaching the jumper wires.
Step 1 is to remove the top panel from the Apple IIc (follow the instructions here), and locate the ribbon cable that connects the internal floppy drive to the motherboard.
Disconnect the ribbon cable from the motherboard, and plug the signal tap into the motherboard in its place.
Then plug the ribbon cable into the signal tap. Also connect one end of each jumper wire to one of the signal tap’s male header pins. Here I chose to connect the brown wire to pin 1, and the red wire to pin 2. I’ll need to make the same choice later for the external jumper wire connections.
Before closing the case, it’s important to squish the ribbon cable down into the gap between the signal tap and internal floppy drive bracket. Push it down as far as it will go. This will make it easier to fit the top cover back on later. Notice the difference between the ribbon cable position in this photo as compared to the previous one:
Now it’s time to close the case. First, set the top panel loosely on the IIc, and thread the jumper wires through the opening for the disk connector in the rear of the case.
Then reinstall the top panel. It’s a snug fit, but there’s a large enough gap between the top panel and the rear connectors for the jumper wires to squeeze through. As an alternative, the jumper wires can also be threaded through the opening for the printer port or the video connector. After the top panel is reinstalled, it should look like this:
Connect the jumper wires to the 2-pin male header on the switched DB19 adapter, remembering to use the same color-to-pin mapping as before. Then plug the DB19 adapter into the Apple IIc’s external disk port. It will replace the standard DB19 adapter that’s included with the Floppy Emu.
Finally, connect the Floppy Emu’s 20-pin ribbon cable to the switched DB19 adapter. All done! This Apple IIc can now boot Choplifter and other 5.25 inch disk image favorites from the Floppy Emu, while retaining the internal 5.25 inch floppy drive for secondary needs like disk copying. Or at the flick of a switch, the IIc can be restored to normal operating, with the internal floppy drive configured as the boot drive.
Coming Soon
I hope to have the IIc Internal/External Switcher ready for the BMOW store in a month or two. There are still a few wrinkles to iron out before it’s ready. Because it’s such a tight fit inside, I need to get feedback from some other IIc owners to verify the switcher fits their computers too. I also want to revise the PCB a bit, to make the switcher easier to assemble. And I’d like to provide more meaningful labels for the switch positions than simply “A” and “B”. If there were enough space, I’d label the switch positions something like “normal” and “swapped”, but the adapter is so small that there’s only room for 1 or 2 letters at most. Any great suggestions?
Read 14 comments and join the conversation