RC2024 – Part 3 – Designing A PCB For The Rotary Encoder

One thing I really wanted to do as part of this year’s Retro Challenge was to build my first custom PCB for the RC2014 computer.

I have chosen to use EasyEDA to design my PCB. I was heavily influenced by watching James Sharman’s excellent YouTube videos in which he designs his own CPU using EasyEDA. The alternative was KiCad, which seems more complex for a beginner.

Spencer has kindly put the specifications for a RC2014 module template up on the RC2014 website. I will try to follow this when it comes to laying out my PCB.

The Circuit

The RC2014 Peripheral Addressing didn’t originally target exact addresses, instead it used 74LS138 chips to target ranges of addresses.

The SC219 takes a different approach, and uses a 74HCT688 8-Bit Magnitude Comparator to target a specific address. I think this is the best approach for my circuit. Using switches for the comparison will mean I can easily change the matched address if there are conflicts with any other cards on my RC2014. I will use the IORQ line from the RC2014 as the OE (Output Enable) line. I can take the output from the 74HCT688 and use a 74HCT32 OR Gate with the RD line to know when the peripheral address I want to respond to is being used. I will use a 74HCT245 Octal Bus Transceiver to present data on the data pins when active.

In my initial post I mentioned I had to use a 74HCT14 Schmitt Trigger to invert the input from the rotary encoder and help produce a cleaner digital signal. This will be connected to the 74HCT245’s D0 to D5 pins. This will allow me to support two rotary encoders, and leave D6 and D7 spare. I will provide two blocks of input pins, one block for each rotary encoder. Each of these will support the CLK, DT, and SW pins, as well as GND and +5V.

I will add some debugging support to the circuit. I like the input LEDs on the SC219 so I will also add these to my circuit so I can see the incoming data from the rotary encoders. I think a breakout of the incoming data lines before the 74HCT245 will be useful to see what is going on, and also allow the board to be used as an input device when the rotary encoders aren’t being used. Finally, I saw a discussion on one of the Sinclair Spectrum groups about adding a hook to GND to attach an oscilliscope to when debugging. This could be very useful if the circuit doesn’t work, so I will add in provision for this.

This is my initial design.

Rotary Encoder circuit

The PCB

As I mentioned earlier, there is a specification for the shape and size of PCBs for the RC2014.

Laying out the board I have tried to use EasyEDA’s measuring tool to ensure this is correct.

Adding the curved corner I found tricky, but eventually I was able to do this by targetting the BoardOutLine layer in EasyEDA.

I read on various forums that adding a ground plane to a PCB was a good idea, so I have done this on both the top and bottom layer of my PCB.

As my circuit is reasonably simple, I used EasyEDA’s auto routing functionality. This worked quickly and I didn’t need to do any manual routing.

For manufacturing I decided to use JLCPCB as EasyEDA has built in support for this manufacturer.

The board itself cost $3.20 for 5. I paid for express delivery because if I have made a mistake and need to create a new revision, it could take several weeks to arrive. The total for the 5 PCBs, delivery, and tax was £20.21. These are due for delivery on October 8th 2024.

JLCPCB adds a manufacturing code to each PCB. You can specify where this appears by adding the text “JLCJLCJLCJLC” to one of the silk layers. I put mine on the BottomSilkLayer so it’s not forward facing.

This is the final layout for my board. I can’t wait for it to arrive so I can solder it up and see if it works.

Rotary Encoder PCB

RC2024 – Part 2 – Reading The Rotary Encoder From BASIC

My Retro Challenge this year is to get rotary encoders working on my RC2014 computer.

Previously, I explained what a rotary encoder was, how to use one, and how to link it to the RC2014.

I now want to try reading it on the RC2014 and using it to control some output.

I’m using the SC219 Digital I/O Board on the RC2014 to accept inputs from a rotary encoder. I have mine mapped to I/O address port 0. Using Microsoft BASIC I can read this using the INP(0) statement. This will return a byte representing the values of D0 to D7 on the input port.

I am using D0 for the CLK, D1 for DT, and D2 for SW. D3 to D7 are not used at the moment. I am only interested in D0 and D1 for the rotary motion. I can use AND statements to mask bits when I’m checking the input value. So to check if D0 was 1 or 0, I could use INP(0) AND 1. This would return either 0 or 1. To check D1, I could use INP(0) AND 2. This would return either 0 or 2.

The following UML activity diagram shows at a high level how I need my BASIC program to operate.

The Microsoft BASIC on the RC2014 is old and limited compared to modern languages, but it is functional.

To save space, I’ll use variable A for CLK, and B for DT. I’ll need to keep track of the last state of A so I know when it has changed. To do this I’ll create a variable LAST_A. Finally, to keep track of the INP(0) result, I’ll create variable INPUT.

When I detect a change in A, I need to look to see if B matches A. If it does, then I know the encoder is being turned to the right. If it doesn’t, then it is being turned to the left.

Here is the BASIC code I came up with to do this. When it detects a change, it prints either “Left” or “Right” to the console.

10 LET LAST_A = 0
20 LET IN = INP(0)
30 LET A = IN AND 1
40 IF A = LASTA THEN GOTO 200
50 LET B = IN AND 2
60 IF (A=1 AND B=2) OR (B=0 AND A=0) THEN GOTO 100
80 PRINT "Right"
90 GOTO 200
100 PRINT "Left"
200 LET LAST_A = A
210 GOTO 20

The SC219 has digital outputs as well as inputs. Using the built-in output LEDs, I can move a dot left or right depending on the input from the rotary encoder.

The 8 output LEDs represent each bit of a byte. So we have the values 1, 2, 4, 8, 16, 32, 64, and 128 represented on bits D0 to D7. This is 2 to the power X, where X is between 0 and 7. We can use the ^ (power) operator in BASIC to help set these bits.

So we need to have a variable, let’s call it COUNTER, to keep track of which power we are currently at. We can say turning the rotary encoder left will increment COUNTER by 1. Turning the rotary encoderrigtht will decrement COUNTER by 1. We need some guards, so if COUNTER goes below 0, we set it to 7. If it goes above 7, we set it to 0. We set one of the LEDs by using OUT 0,2^COUNTER. This means when we turn the rotary encoder, we can move the LED.

Here is the BASIC code I wrote to do this.

10 LET COUNTER = 0
20 LET LAST_A = 0
30 LET IN = INP(0)
40 OUT 0,2^COUNTER
50 LET A = IN AND 1
60 IF A = LASTA THEN GOTO 200
70 LET B = IN AND 2
80 IF (A=1 AND B=2) OR (B=0 AND A=0) THEN GOTO 150
90 IF COUNTER <= 0 THEN GOTO 120
100 LET COUNTER = COUNTER - 1
110 GOTO 130
120 LET COUNTER = 7
130 PRINT "Right"
140 GOTO 200
150 IF COUNTER >= 7 THEN GOTO 180
160 LET COUNTER = COUNTER + 1
170 GOTO 190
180 LET COUNTER = 0
190 PRINT "Left"
200 LET LAST_A = A
210 GOTO 30

Here is a short video of it in action.