Saturday, 13 September 2014

PCB toner transfer wrap-up, interrupts, video, and an IO board!

I haven't written in this journal in two months now. I've been busy with work, looking after my son, etc. But I have, in the past few months, squeezed in the odd hour here and there on my projects. I've managed to get quite a lot done, and haven't really felt like updating this blog until now. This entry may be longer, and a bit more disjointed then normal.

So first of all, the PCB toner transfer "device" is now officially finished. I tidied it up a bit and mounted the control PCB and roller mechanism on a piece of wood. Not pretty but it does the job. Some problems, things learned and conclusions from this project:
  • The biggest mistake with the controller PCB layout was that the mains AC current for the heater runs parallel to the thermocouple trace. This seems to induce a small current in the thermocouple trace, causing a fluctuating reading. I have worked around the problem in software by averaging the temperature received. This seems to mitigate the problem, but it is irritating that it exists.
  • A 4 digit seven segment module, instead of two two digit modules would have removed the need for most, but not all, of the annoying jumper wires.
  • I'm suprised that the 7805 regulator gets warm. This may mean I have a current leak (low resistance to ground) that needs to be solved, since the circuit should not need more then a few 10s of mA.
  • It's a shame it needs to be attached in two places to mains to work: one plug for the heater/rollers and one for the control board. Not a big problem, just unity.
  • I still very much love working with the AVRs. It's different to working on the old 8 bit MPUs but very enjoyable.
The final code, for those wanting to build there own PCB laminator is on github.

Back to the 6809 computer then. I have successfully incorporated a 65SPI and a 6522 VIA on some breadboard which is, in turn, hooked up to the SBC. I can use my existing code to set and read the time on a connected DS1305 Real Time Clock (previously described in some depth in this blog). I've also been playing with the VIA and learning about the timer component, with the aim of adding a timer ticking interrupt to my computer.

Regular interrupts are useful because they can be used for dealing with timeouts and making stuff happen on a regular basis. While I did get the VIA to be a useful source of regular interrupts, after looking more closely at the data sheet for the 88C681 (PDF) DUART I noticed that it too has a counter/timer, and an external interrupt pin which can be configured to trigger on a counter overflow. Using the DUART would mean my regular interrupt wouldn't need the board with the VIA attached to function and would be self contained on the SBC.

This addition required a small change to the VHDL to make it route the 88C681 interrupt pin through to an interrupt line on the 6809. I chose the FIRQ line in this case. No particular reason, I just hadn't used it before.

Setting up the DUART counter/timer is done in the serialinit and requires writing to some extra registers:

                lda #0b01110000         ; tick on the 3.684Mhz crystal / 16
                sta ACR88681
                lda #0b00001000         ; mask in the timer overflow
                sta IMR88681
                lda #0x11
                sta CTU88681
                lda #0xfd
                sta CTL88681            ; 4605 decimal - 25/sec
                lda STARTCT88681        ; update the timer overflow

The DUART is clocked off a 3.684 MHz crystal (this is a useful frequency for a baud rate generator circuit).  Because I'm after a slow interrupt (relatively speaking) the DUART's ability to divide this clock down by 16 is utilised. Further dividing down by 4605 yields a count to zero time of 20ms. At this point the interrupt line is toggled, yielding a period of 40ms, or a 25Hz square wave on the pin. The DUART has a funny way for starting and stopping the timer, involving a read to some specific addresses which would otherwise only be used for writing.

In terms of the actual interrupt handler in the 6809 code, it just has to clear the interrupt by issuing a start timer command. It also increments the uptime counter, code that's been in the monitor for some months now. The complete routine looks like this:

firqinterrupt:  pshs a,x
                lda STOPCT88681         ; clear interrupt
                ldx uptimel             ; get current lowword uptime
                leax 1,x                ; add 1
                stx uptimel             ; store it back
                bne firqinterrupto      ; if not 0 then done
                ldx uptimeh             ; otherwise low current highword
                leax 1,x                ; add 1
                stx uptimeh             ; store it back
firqinterrupto: puls a,x

After setting all this up, I still had a couple of problems. First of all it was evident from the logic analyser output that the FIRQ line wasn't going high when inactive. After reading the DUART data sheet once more (I need to read these things more closely!) I realised I had a potentially nasty error on my main board PCB: I had neglected to include a pull-up resistor on the DUART interrupt output. Interrupt outputs normally work like this because it facilitates "wired OR" logic allowing interrupt pins to be ganged together without using logic gates. This meant the pin did not go high when there was no interrupt to assert. After scratching around for a solution I eventually came up with this:

I was quite pleased with this. No soldering was required and a casual look at the PCB will never reveal this problem.

The second problem wasn't really a problem, but more an unexpected feature of the 6809: while processing a software interrupt, IRQs and FIRQs are ignored until interrupts are enabled again (the software interrupt automatically disables interrupts). This was solved by having the software interrupt for the monitor always re-enable interrupts, thus the FIRQ can interrupt the software interrupt:

moninterrupt:   andcc #0xaf             ; enable interrupts again

In the process of playing with interrupts I've learned quite a lot. One further enhancement I would like to make to the VHDL is to implement an interrupt register. This will allow the interrupt handler to determine the source of the interrupt without it having to poll every possible source of the interrupt. Further a mask register can be used to configure, from the host processor, which devices can trigger an interrupt in that processor, and also wether it should be a FIRQ or a regular IRQ. This is clearly more flexible then modifying the implementation in the CPLD when the interrupt routig needs to be changed. This is not a completely trivial amount of work, since it requires two mask registers to be implemented, as well as a a read-only register to show the interrupt state. But it's something I will implement soon.

In the last couple of months I've also been having a play with video, and in particular, a Video Display Controller (VDC) called the V9958.

The V9958 was an advanced, for the time, VDC used in the MSX2+ Z80 based home computer. It is unusual because it has relatively high resolution video modes with many colours on-screen, as well as hardware line drawing. Other features include hardware sprites and genlock support. Interface wise, this VDC like it's predecessors the V9938 and TMS9918 has a seperate memory interface for video memory; the CPU access the video memory "through" the VDC.

The VDC only has two address pins called, for some reason, MODE0 and MODE1. it has read and write lines which aren't gated through a seperate chip select at the IC. Therefore the existing address decoding in the CPLD to make chip selects is insufficient. In order not to require the use of discrete glue logic, two pins on the expansion select "bus" are required. Additional logic in the CPLD is required to gate the global read and write lines through an internal chip select which is active on the address given to the VDC.

Other connections required are as 21.1Mhz crystal and the usual /RESET line, and of course the CPU dstabus.

Most of the rest of the 64 pins are taken up by the DRAM video memory interface. The V9958 supports several sizes of DRAM from 16k by 1bit to 64k by 4bit, the latter of which will be used. In terms of the maximum amount of video memory which can be connected the V9958 again lead the (contemporary) pack, supporting 196Kbytes of memory.

Although the VDC has many graphical modes, my first goal was and is to get text mode working. This will allow me to run the monitor program on the SBC itself, without using a serial terminal. But the first task required the circuit to be drawn up and the hardware prototyped up on breadboard. This in turn required an adapter board so the 64 pin shrink DIP VDC could be attached to the breadboard.

After a false start with one design for an adapter I eventually had success with a more conservative approach: an adapter the spans two pieces of breadboard. You can see the unfinished adapter board in the following picture:

I had fun making this little adaptor board. It was the first PCB made with the new laminator controller board, and while its not perfect it's good enough and I was very pleased not to have to break any unwanted joins between the SDIP pins. This was also the first board I soldered up with my new temperature controlled soldering iron, and it was a pleasure to do in comparison to my old iron.

Anyway, here is the VDC circuit:

And here is the breadboard:

Because I was just testing the VDC, I only bothered wiring in one bank of 64KBytes of DRAM for the video memory. So only two 4 bit by 64K DRAM ICs were required. At the bottom left of the breadboard is a breakout board I made up for the SCART lead. Only five connections are required: Red, Green, Blue, Composite sync and "blanking signal". The last one, when high (more then about 3V) puts the television in RGB mode instead of composite video mode.

After all the hardware was ready, the final thing to do was to write the software to drive the video controller. This turned out to be quite a challenge, and I'm nowhere near finishing yet. The initial goal was to write a program to output a test message. But this in turn required a font, since the VDC has nothing built in.

Originally I wanted to use a font I was very familiar with: the font used in the ZX Spectrum. I have a soft spot for this font, even though it is really not very good. But then I discovered the V9958 is a bit unusual because in its 40 column text mode only six pixels are used for each character width instead of 8. This is because only 256 horizontal pixels are used instead of the more normal 320.

After some searching I found a PNG file of the MSX font:

Incidentaly, I found this image on a blog post comparing different 8 bit machines from a typography point of view. Very nostalgic and interesting reading!

This then needed to be turned into assembly source code, ie. data that could be included in the monitor. This turned out to be fairly involved, but eventually, after writing a few perl scripts, I had source code for my font.

The next stage was to write some routines to manipulate registers in the V9958, and then to load data into the video memory. It's not worth going into too much detail here (if you are interested, read my code). Essentially to enable text mode the following steps need to be performed:
  1. Initialise the core registers to set the video mode, type of DRAM installed, video memory locations for the fonts and what character should appear in each character square
  2. Setup a simple 2 colour palette
  3. Load the font data into a known location (the datasheet describes font characters as "patterns")
  4. Load the video memory with the message to be displayed
After some experimenting with different values in a few of the key registers I was able to make my test message appear. Here is the test message showed in the 40 column text mode:

This was a major milestone for my little computer. At this point I really felt like I was building a real, usable computer.

While the picture quality was ok (80 column text was also tested and looks just legible) it wasn't great.

I have managed to modify the serial routines to output text on the TV by "hooking" the serial character output routine such that, as well as outputting the character to the serial port, it also goes to the TV screen. By implementing some cursor management routines, to handle carriage return, line feeds, and backspace I can now display the monitor program on the TV. Input is still via the serial port, however.

To celebrate this step for my computer I made a short video:

To reiterate, the code is not finished yet. In particular I need to implement an IO mechanism such that the VDC or one of the serial ports can be opened as an input/output device. That way I'll be able to use the monitor via the TV, but also be able to receive files from the serial port, for example.

The last thing I've been working on is tidying up the VDC, 6522 and 65SPI and putting them on a brand new IO PCB. This IO board will sit on top of the main computer board as a rather large daughter board. The full list of parts is:
  1. VDC with DRAM
    1. To connect the VDC to a television, a DIN connector will be used
  2. 65SPI
    1. DS1384 Real Time Clock with Temperature sensor
    2. SPI header
  3. 6522 VIA
    1. 2 x 8bit parallel header
    2. Keyboard connector (see below)
  4. AY 8912  Programmable Sound Generator
    1. 9 pin Joystick port
So, quite a lot of cool ICs. Most of this has been breadboarded in various forms over the last year or so, so in theory there is nothing really new here. Only the DS1384 (PDF) was not used before. While I could have stuck with the trusty DS1305 RTC, I really wanted a temperature sensor in my computer. I bought two '1384s from good old eBay - one for the IO board PCB and one for testing with breadboard. One small complication is that this is a SOIC (50mil pin pitch) SMT part. So I also bought some SOIC to DIP adaptor boards too. The '1384 was trivial to talk to once attached to the adaptor board.

The joystick port is worth a brief mention. The AY 8912 sound syth also has an 8 bit IO port. It was common for this to be attached to joysticks, the ZX Spectrum 128 +2 had it's joystick ports wired to the bigger AY 8913 for instance.

Here is the complete schematic:

This is mostly just bringing together circuits used previously. The header (top left) is the bridge between this circuit and the main board. This schematic also has the DIN 6 connector for the video connection to the television. I chose to "borrow" the connector type and pinout of the video port on the BBC Micro. This allowed me to use a ready-made lead for hooking up a BBC Micro to a television via SCART instead of me having to make up my own lead, which would be perfectly possible but a bit tedious.

The next step was to make up the PCB. This was an interesting challenge, primarily because of the board having to sit ontop of the existing main board. There are a number of clearance issues which effectively limit the size of the board:
  • The vertical fuse holder at the top left of the main board
  • The IDE connector at the top of the board
  • The serial headers at the right top corner
These obstructions mean the board is a bit irregular. In the end I settled on the following layout:

This layout took several false starts to iterate to. I'm still not liking the gEDA PCB program, but it did the job here, even it did take several man weeks to come up with. I was especially pleased with the DRAM layout - barely a square mil is wasted. I was less pleased with the 65SPI PLCC44 layout - too many vias were needed.

The board was also a lot of work because I had to make up quite a few footprints myself. The battery connector, DIN connector, joystick connector and the big Shrink DIP64 footprint all had to be made up as they did not come with the gEDA PCB tool.

After settling on the layout, I decided to use the services of Botech once more. They did very well once again, and in a few days I had five boards in my hands:

Soldering up the board was a time consuming but easy job - even the SOIC RTC was reasonably easy - helped by a flux pen and fluxed solder wick I purchased for the job. As usual I tested as I went.

Mated to the main computer board, the two boards look great I think:

Despite my testing by making parts of the IO circuit up on breadboard there are a number of problems. However the following parts work exactly as I'd hoped:
  • VDC (but see below)
  • 6522 (I actually have the CMOS 65C22 socketed)
  • 65SPI with RTC
The problem with the VDC was irritating, but relatively minor. When making up the DIN connector footprint, I managed to set the pinning backwards. So initially there was no picture until I cut tracks and added jumper wires, completely ruining the nice "look" of the board. After this PCB butchery, I noticed that the picture quality was quite a bit better then when the circuit was running on breadboard. In fact it was almost perfect.

Another problem I had wasn't actually with the IO board but was with the main board. In using all those additional ICs, some of which are high current NMOS I started to run into major problems with voltage drops on all the IC power pins. The voltage drop was so large that the computer refused to start. Eventually, with the help of the nice folks at the 6502 forums, I managed to nail it down to the fuse on the main board. After measuring the voltage across the fuse I noticed the drop increasing as the current draw ramps up as more ICs are added to the circuit. As a simple "work around" I have temporarily shorted out the fuse on the back side of the board. The proper solution is to find a suitable fuse which has the same rating but a much lower resistance. I hope such a thing is available, but it is possible it isn't since a fuse is, after all, simply a thin wire.

The final problem is one that I haven't solved yet. I cannot get any sound from the AY 8912. The IC is "half working" though because I can read the joystick port sucessfully. I think the problem is down to the use of 74HC glue logic combined with the signals generated from the CPLD. This is the one part of the IO circuit which I did not breadboard up, so it makes sense that it would be this part which is causing me problems now. The last time I used this IC the computer's glue logic was all discrete 74HC parts.

Once the issue with sound has been solved, I'll modify the PCB layout and get another batch made up.

Despite the problems with the IO board, I'm very pleased with my progress over the last couple of months. My little 8 bit computer is really starting to come togeher now. It has all the fascilities any 8 bit micro ever had:
  • 512KByte RAM
  • IDE (something unheard of in a 1980s 8 bit micro)
  • Serial ports
  • Parallel ports
  • Real Time Clock
  • "High end" video graphics
  • Joystick interface
  • Sound (when it works)
One thing missing from my computer, important now it has a video interface, is a keyboard. I have some ideas for this which I will document in detail in my next post. In any case, the IO board accommodates a keyboard through the use of a header attached to the VIA.

The other big thing missing is software. After getting sound working I will concentrate on the system software needed to properly control the video interface, joystick, sound etc. After that is done I will have a computer able to run a game I will write, something I hoped (well, dreamed really) I would be able to do at the start of this little journey...


  1. Hi. Cool project. How are you generating /VDPREAD and /VDPWRITE? Are they just generated from R/W and Q?

    1. Hi, Thanks. It is just a IO decode combined with the /READ and /WRITE, which are themselves generated from the CPUs R/W combined with E.

      elsif (A = "0101" and nREAD = '0' and nWRITE = '1') then SELECTS.nVDCREAD <= '0';
      elsif (A = "0101" and nREAD = '1' and nWRITE = '0') then SELECTS.nVDCWRITE <= '0';