More Blinkenlights are always good
    RK11-C disk controller for the RK05 removable disk drive
scaled RK05 cartridge

Introduction

Wanting to add more "blinkenlights" to the PiDP-11/70, I was looking for an additional unit with lots of lights. I once saw the RK11-C controller for RK05 removable cartridge drives, and I also knew that this controller included a half-height panel with many lights to indicate the status and what the controller was doing. These indicator panels exist of four rows of 36 small lamps, and connect to a backplane with 4 "paddle" boards. Examples of controllers that had these indicator panels are the DX11 (PDP-11 peripheral to bus&tag IBM) and the RP11 controller (for "RP0x" disk drives). This type of indicator panel was also used for several PDP8 peripheral controllers, as far as I know.

I have the DX11 and the RP11 indicator panel, so these could serve well as an example, but after looking at  DEC indicator panel , more specifically  Digital Equipment Corporation Indicator Panels  the choice for the indicator panel was easy. It would have to be the indicator panel of the RK11-C controller. That would also fit very nicely together with the RK05 removable disk cartridge drive I already made for the PiDP-11/70.

RK11-C controller indicator panel

So, initial drawings were created with FrontPanelExpress. The drawing you create with FrontPanelExpress is exactly what you will get, and while designing you can check what the costs will be. It is a pity though that they do not supply "brushed black anodized aluminum", but only "black anodized aluminum". I really liked the "brushed" effect. The front panel of the RK05 disk drive is made of "brushed black anodized aluminum", but for the RK11 controller I will have to settle for "black anodized aluminum".
The major objects to realize a "functional" RK11 controller are the following.


RK11 controller front panel

The front panel is drawn using FrontPanelExpress. Their website for the USA is  FrontPanelExpress , their website for Europe is  FrontPanelExpress. From the website you can download the CAD software for free, and the GUI is quite user-friendly. At least, I got quickly results and I am definitely not a CAD artist. But it takes some time to get every item placed exactly correct.
As most of the costs of the front panel is the drilling of 144 (!) holes and the associated text legends, I choose a material thickness of 4 mm. Thicker material adds to the cost (every hole has to be drilled "more deep"). Using a thickness of 4 mm enables threaded holes at the rear side of the aluminum plate. These threaded holes can be used to attach the PCBs with the LEDs and mount an aluminum box to the front panel, making the RK11-C controller a "unit".

RK11-C FrontPanelExpress design
view of the RK11-C front panel design

The width of the aluminum front panel is 315 mm. That is approximately 60% of the real physical size, but it fits exactly with the PiDP-11/70 front panel (and RK05 drive). On the rear side are threaded holes to mount the two LED PCBs and small "L" angled aluminum profiles from the local DIY shop to which aluminum plates can be mounted to make a box.


Indicator lights PCBs

The indicator panel is a "standard" part with 144 lamps. The RK11 controller uses most of them. When you look at the RK11 front panel, you see that several lamps are grouped for example, to show the 16-bit memory address. But the same lamps may have a different meaning on an other controller that uses this "standard" indicator panel, and grouping may be completely different, or even absent. Further, one PCB for all 144 LEDs is big.
There is no room to implement the interface hardware on the LED PCB, so the interface has to be on an other PCB.
That led to the following choices.

The size of each PCB is 5.4" x 2.8" (137 x 71 mm). The LED PCB is "generic", that is, there is no specific "grouping". The top row contains simply LEDs #1 to #18, the row below contains LEDs #19 to #36, etc. The top two rows are connected to two 2x10-pin header above the first row, the bottom two rows are connected to two 2x10-pin header below the bottom row.

LED PCB with 72 LEDs
Eagle design view of the component side of the 72 LEDs PCB

The 72 LEDs and their series resistor are soldered on the component side of the PCB, the four 2x10 headers are soldered on the opposite side.
The LED PCBs are mounted onto the front panel with four M2.5 screws and stand-offs, and fit next to each other to form a 144 LEDs panel. The distance between two LEDs is 0.3", and the distance between two rows is 0.6".
You can solder the resistors now, but do not solder the LEDs. I used the wrong part from the Eagle library for the resistors. The resisotrs on the LED PCB have a pitch of 0.2 inch. "Normal" resistors have a picth of 0.3 inch, so the standard size resistor will not mount nicely on the PCB. Sorry for that, my mistake. Just bend the leads of the resistor 90 degrees, put it on the PCB and solder one lead of the resistor flush on the PCB, and the other lead "pulled" to the PCB. That does not look great, but when the PCB is mounted against the rear side of the front panel, nobody will see my goof-up.
After soldering the resistors, mount the four 2x10 (male) pin headers on the rear side of the PCB, and solder them at the component side.


RK11 interface PCBs

The interface hardware consists also of two PCBs, but they are not identical. Each interface PCB contains five MCP23S17 2x8bit I/O expander ICs, in total supporting 80 I/O connections. 72 are used for the LEDs, the remaining 8 outputs are available for "other use". The lay-out of the traces is such that a "groups", for example "DRIVE", "CYLINDER" and "SECTOR" on the "left" PCB, and "DATA BUFFER" and "DSB" on the "right" PCB are hardware-wise (and thus also software-wise) connected to an 8-bit port. This makes the interface software easier, no "bit shuffling" is needed. It also reduces the number of output actions.

IFC PCB (left side) IFC PCB (right side)
Eagle design view of the left side interface PCB Eagle design view of the right side of the interface PCB

As up to 16 LEDs all connected to a single MCP23S17 might be on, the interface PCB also contains driver ICs enabling the total current needed for all LEDs. The MCP23S17 can sink 150 mA, or source 125 mA max. That limits the LED current for a worst case condition (all 16 LEDs on) to sink max 9 mA, or source max 7.5 mA per LED.
The interface PCBs are piggy-back mounted onto the LED PCBs, secured by two M2.5 screws and stand-offs. The four 2x10 (female) headers are soldered on the component side. Only the interface connection CON (2x5 pin header) is soldered on the opposite side. This connector is the interface to (for example) an Arduino Nano or a Teensy. SO (Serial Out) of the SPI interface, Chip Select, GND and +Vlogic are on these pins. As the LEDs are connected "common anode" via a driver, you can have a different (higher) power supply voltage for the LEDs. The +Vled is connected to a pad on the interface PCB, for separate LED power supply. Next to this pad is an other pad which connects to the +Vlogic. By connecting the two pads, the LEDs are powered by +Vlogic via the connector CON.


Assembly - step 1: the LED PCBs

I thought this would be an easy, straight-forward assembly, but that was a mistake ... Aluminum "L"-profiles are mounted onto the rear side of the panel using the threaded holes. The side walls, bottom and top of the housing box are mounted onto these "L"-profiles. As everything is scaled to 60%, I found out that everything is quite tight, and it all fits just. That was not foreseen, so I am lucky that it does fit.
However, assembly requires a specific order, else you run into trouble later on.
The "L"-profiles are made of 2 mm thick aluminum, one leg is 10 mm, the other leg is 30 mm. The 3 mm holes in the 10 mm leg are drilled 4 mm from the edge. I drilled the holes 3.2 mm for tolerances. The top and bottom "L"-profile fit "inside" the left and right side "L"-profile. That way, the top (and bottom) cover can be over the edges of the side walls, looking nice. Note that the "L"-profiles for the top cover have press-fit nuts. It will be impossible to hold a nut on the inside and mount the screw that scecures the top cover!

"L"-profiles mounted
"L"-profiles mounted onto the rear side of the front panel (and checking that the bottom fits too)

In the picture, you can see that the four M2.5 screws for each LED PCB are already mounted on the rear side of the front panel. Initially, I thought to use screws, but you have to mount the LED PCBs with the LEDs, without the LEDs being soldered first, and then solder the LEDs. That order allows you to have all LEDs mounted at the same depth into the frontpanel. Looks is everything!   So, you have to put all the LEDs on the PCB (correct orientation anode/cathode, not soldering them), mount the PCBs on the front panel, and then check that all LEDs are in the front panel holes at the same depth. It is easier to mount the LED PCBs with a nut on the M2.5 screws (without a screw head) than M2.5 screws with screw head.

The LED PCBs just fit between the bottom and top "L"-profile. That implies that you have to mount the "L"-profiles onto the front panel before you mount the LED PCBs, because the M3x4 mounting screws are not accessible when the LED PCBs are mounted! So, the holes to mount the box bottom, top and side plates must also already be drilled.
Also, before you start soldering the LEDs, make sure that you mounted the two M2.5 (length 30..40 mm) screws on each LED PCB (in the middle along the long side of the PCB). These two screws keep the piggy-back mounted hardware interface PCBs secured, nor relying on the four 2x10 connectors. Check that LED1 on the left side LED PCB is located above panel light ERR, and that LED1 on the right side LED PCB is located above panel light DATA BUFFER 15. If not, rotate the LED PCB 180 degrees!

LEDs ready to be soldered
Left LED PCB mounted. LEDs positioned, ready to be soldered

Put the LED PCB with the LEDs onto the M2.5 mounting posts and verify that all LEDs protrude the corresponding hole in the front panel. If all LEDs are in the hole, lay down the front panel on a clean table (to avoid scratching the front), and mount the LED PCBs each with four M2.5 nuts. Test that the lens of every LED is resting on the table surface. Then solder one lead of the LED. Repeat this for all 144 LEDs! After that job, you can look at the front and inspect that all LEDs are identically mounted in the holes. If not, you can apply a correction. When all LEDs are mounted identically, you can solder the other lead of all LEDs.
The visually important assembly is now done.


Assembly - step 2: the interface PCBs

Soldering the interface boards is straight-forward. I always use top-quality IC sockets (machined pins). If an IC goes defective, replacement is simple. Machined pin IC sockets are not cheapbut reliable, you can also use double-spring sockets. Do not use single spring sockets, those are rubbish. Note that the orientation of the ICs is not identical for all of them! Also note that the 1x4 pin EXP1 and EXP2, and the 2x5 pin male CON are mounted on the solder side and soldered on the component side. Do not (yet) solder the four 2x10 female headers on each interface board.
Solder the small 100 nF decoupling capacitors, and the resistor. Put the large polarized capacitor on the solder side and solder the leads on the component side. Observe correct polarity!

Interface boards almost ready to be installed
LED PCBs mounted, female headers with long solder pins for the interface boards

Place the female headers with long (11 mm) leads on the 2x10 male headers of the LED PCBs. I used 10-pin single-in-line headers, simply because the local had those available. 2x10-pin double-row headers might make the fitting of the interface board a bit easier. Put the stand-offs on the M2.5 screws on the LED PCBs. Mount the interface boards with a bit of wiggling, until all female header leads protrude through the header holes of the interface boards. Secure each interface board with the two M2.5 nuts. As the interface boards are basically fixed using two screws in the middle of the board, check that all header pins protrude at both sides of the board, and then tighten the two nuts for each board. Finally, solder the pins of the female headers.

Interface boards almost ready to be installed
Interface boards installed and wired


RK11-C USB interface

The MCP23S17 IC uses SPI for its (bi-)directional communication, and the address is hex 2x (where x can be between 0 and 7). As the total design uses 10 of these devices, each interface PCB (with its five MCP23S17 ICs) includes a "Chip Select" signal. Both interface PCBs use addresses (hex) 20 .. 24, so the CS for both interface PCBs must be mutually exclusive. The RK11-C interface needs an interface to receive LED commands. Using an Arduino Nano or a Teensy (higher performance, if needed), the interface PCBs connect using the USB connection. The USB connection creates a virtual COM port.
The CON header on each interface board has pins for (logic) power supply and GND, the SPI interface signals clock and data, and a "Chip Select" input.

 CON pin FunctionRemarkNano pin

 

Power supply
Two GND connnections of the LEFT board are connected to pins 1 and 2 of the RIGHT board. Pins 3 and 4 of the RIGHT board go to the common GND connection. If the jumper is soldered to connect PAD1 and PAD2, the +5V pins of the CON header are also connected to the anode of all LEDs. If the jumper is not installed to connect PAD1 and PAD2, you have to connect a (separate) positive power supply to PAD1 as power supply for the LEDS (only).

SPI connections
Pin 6 and pin 7 of the LEFT board are connected to pin 6 and pin 7 of the RIGHT board. These two connections go to the Arduino Nano SPI connection pins.

Board Chip Select
Pin 8 of the LEFT board goes to a digital output of the Arduino Nano. Pin 8 of the RIGHT board goes to an other digital output of the Arduino Nano.

1GNDGND
2GNDGND
3GNDGND
4GNDGND
5n.c.no connection
6SCKSPI clock++
7SISPI data in++
8CSboard Chip Select++
9+5Vlogic power+5V
10+5Vlogic power+5V

 
All ports of the MCP23S17 are 8 bits. So, any write operation to a port affects all 8 connected LEDs. The software driving the panel has to maintain a local copy. When the state of a specific LED must be changed, you get the local copy, do the bit manipulation of the byte, update the local copy, and send the byte to the interface. Each MCP23S17 has two 8-bit ports, PORT A and PORT B. See "Interface commands" for a detailed description of the implemented command protocol.


Interface commands and Arduino firmware

Some form of command protocol has to be designed. I had two options. Either some form of command to set/reset the state of a single LED, or some form of command to set/reset an interface port. Using a command that allows to change a single LED is straight-forward, and works perfectly fine for "items" that are just one LED, like error or status bits. However, for "items" that are a group of LEDs, for example the 8 LEDs of the CYLINDER group, the "single LED" approach is is a bit awkward. Furthermore, this approach is also performance-wise very bad, because the update of the CYLINDER group would require 8 commands to be sent. Okay, by maintaining a local copy of the state of the LEDs you can avoid a needless update of one LED (because it state is not changed), but worst case it will require 8 commands.

In order to minimize communication between SIMH and the RK11 interface, the interface hardware is such that a logical "group" of LEDs (such as CYLINDER) are also in hardware a group, where a group is 8 bits, one byte. The LEDs of a smaller "group", like DRIVE and SECTOR, are always contained in one byte. Using the "knowledge" of how the interface hardware is realized, it is logical to have commands that also operate at the "byte-level". So, the command must somehow indicate to which 8-bit output port the 8-bit data has to be sent.

The following command scheme is implemented in the Arduino Nano.

The RK11 interface hardware and firmware maps the following command/data bytes to the front panel LEDs.

Command letterData byte bits
7654 3210
L ERRHE SCPMNT IAIFMT RWASSE
M CRIDE MEX
01                             00
FUNC
02                             01                             00
GO
l CYLINDER
07                             06                             05                             04                             03                             02                             01                             00
m DRIVE
02                             01                             00
SRF SECTOR
03                             02                             01                             00
N BM  IRQWCO ID
02                             01                             00
DPL
O HDDRU SINSOK DRYRWS WPSSEQ
P EXP#EXP# EXP#EXP# CSEC
03                             02                             01                             00
n BUS ADDRESS
15                             14                             13                             12                             11                             10                             09                             08
o BUS ADDRESS
07                             06                             05                             04                             03                             02                             01                             00
p    POHOK EXP#EXP# EXP#EXP#
R DATA BUFFER
15                             14                             13                             12                             11                             10                             09                             08
S DATA BUFFER
07                             06                             05                             04                             03                             02                             01                             00
r DSB
15                             14                             13                             12                             11                             10                             09                             08
s DSB
07                             06                             05                             04                             03                             02                             01                             00
T PREHDR DATCHK PA  DLTTE
U IWC
07                             06                             05                             04                             03                             02                             01                             00
t WTGROH DREOVR WLOSKE PGENXM
u NXDNXC NXS     CSEWCE
V EXP#EXP# EXP#EXP# BC
03                             02                             01                             00
v LWDRDG  IDL EXP#EXP# EXP#EXP#

There is one "special" command, "X00" followed by CR. For the "X" command, the data is a "don't care". When the "X" command is received, all LEDs are turned off.

The Arduino firmware maintains a local "shadow" copy of the state of all the LEDs. When the received command results in no change of the data of the specified port, the actual output command via SPI to the MCP23S17 IC is not executed. This eliminates the output cycle, thus making the processing of a stream of commands faster. The firmware has a buffer for 100 commands, and the only task of the firmware (besides receiving commands) is to execute all commands as fast as possible. If the command reception queue is full, due to a fast sequence of sending commands, those commands are simply lost. As soon as there is room in the queue, a received command is stored in the queue, and will be executed.
The Arduino Nano firmware ("sketch") can be downloaded from here:
rk11-ctrl.zip.
When the zip file is unzipped in a folder, that folder contains a folder named "rk11-ctrl", and in that folder is the file "rk11-ctrl.ino". Assuming that you have the Arduino IDE installed, you connect the Arduino Nano to the PC, and double-click the "rk11-ctrl.ino" file. The Arduino IDE starts and the sketch is loaded. First, you set in the IDE the "target" (Arduino Nano) and the bootloader, and the COM port to which the Arduino Nano is connected. Then you compile the sketch. If all goes OK, the sketch is uploaded to the Arduino Nano.


Test application written in Python

To test the RK11 interface hardware and firmware, an application is written in Python. Python is a language in which you can relatively easy create a graphical user interface. With little effort I created a graphical representation of the RK11 front panel. With the mouse you can point to an LED and when you "click", the state of the LED changes from a grey appearance to white (switching on), or from white to grey (switching off), and the appropriate command is sent to a serial port.

The test application has two tabs. On the first tab (which appears when starting the app), you can select the virtual COM port which is created when the RK11 front panel USB cable is plugged in. The "flashing" exclamation sign disappears as soon as a COM port is selected from the drop-down list. The button below the selection box hows the state of the COM port. Initially the port is closed. By clicking the button the serial communication port is opened.

TEST APP - TAB 1
Python test application - tab 1 - virtual COM port selection

The second tab contains the graphical representation of the RK11 front panel.

TEST APP - TAB 2
Python test application - tab 2 - some LEDs on

The Python test application consists of the Python program and 5 GIF images (DIGITAL logo, exclamation "error", "LED off", and "LED on" in white and in red appearance. A simple change in the Python program sets the "on" color of the LEDs.
The Python test application can be downloaded from here:
rk11-testapp.zip.

Unzip the file to any folder (resulting in the mentioned 6 files).
To run the Python program you (obviously) need to have Python installed on your PC (I am using Python 3.9.5). Further, the application requires the WxPython and PySerial package. When you have the Python program installed, the following two commands, issued in a CMD window, install the two packages.
  • pip install wxpython
  • pip install pyserial
When you double-click the rk11-testapp.py icon, the graphical application appears, and a CMD window. The CMD window shows which COM ports have been detected by the application, and as you click an LED the command sent to the RK11 interface is displayed.
If something is wrong, the CMD window will pop up and disappear before you have been able to read what is wrong. In that case, start with opening a CMD window, "cd" to the folder where you stored the test application, and enter the command "rk11-testapp.py". It will still go wrong, but now the CMD window does not disappear and you can read the diagnostic output from Python, possibly giving some help in resolving the issue.


RK11 front panel in SIMH

The RK11 front panel is connected to the Raspberry Pi using a USB port. I am assuming that you are using a PiDP-11/70.
Thus, to send commands to the RK11 interface, the proper serial port (USB) must be configured in SIMH.
Note that this serial port does not have a "serial port" in the simulated PDP-11 environment.
Before you start SIMH, you physically connect the RK11 interface with a USB cable to the Raspberry Pi, and check which serial interface is made available, for example "/dev/tty0". Then you can start SIMH.
In SIMH you "connect" the RK11 interface with the new (SIMH) command "RK11=/dev/tty0".
That's all!

Obviously, the SIMH version has no knowledge of the RK11 interface. Just like the implementation of the RK05 disk drive, several SIMH files need some modifications. First, the command to connect to the virtual COM port must be made available, and then data and state functions of the RK05 device must be changed, so that information is sent to the RK11 interface. Here is a short list (in sequence) of tasks that have to be implemented.

  1. Add a new command to SIMH, to connect the RK11 interface "RK11=/dev/tty0".
  2. Implement a queue to hold commands to be sent to the RK11 interface.
  3. Add a task in the main loop (scp.c) to retrieve commands from the queue (if any available), and send them to the RK11 interface.
  4. Add commands in pdp11_rk.c to fill the queue. This part is the most tricky one, I think ...
Back to top