Wednesday, 24 December 2014

A keyboard and the first game, Snake!

My little micro is coming along very nicely. One thing has been lacking for a long time now though: a way to control and use the computer without using the serial console port. In summary a keyboard is required.

There are a couple of approaches to interfacing what is essentially a switch matrix with a microprocessor. The two main ones are:
  1. Directly polling the switch matrix through a parallel interface on the main processor. This is the method used by most 8 bit micros including the C64, where the keyboard is attached to a VIA dedicated to this purpose, whilst the ZX Spectrum used its ULA.
  2. If the keyboard has its own dedicated microcontroller then the main microprocessor does not have to poll the matrix, leaving this chore to the microcontroller. Instead it can be interrupted when the controller detects a keypress. This is how all modern computers deal with keyboards.
Because of not wanting to have to poll the keyboard in MPU software, and because it's more interesting, I have opted to use a microcontroller to handle most of the work. There still remains some decisions to be made. Many people building there own retro micros go for a PS/2 keyboard, which itself includes a microcontroller, along with, say, an AVR to interface the serial PS/2 protocol to a parallel bus. Whilst this would work for me, it is a little too predictable.

Instead I have opted to add a microcontroller to a C64 keyboard, and then attach this to my computer. The C64 had quite a nice keyboard, being a proper typewriter keyboard. The switch matrix consists of 8 columns and 8 rows, for 64 keys. A further decision of how to link the controller to the rest of the computer arises. Once again there are choices for how to do this; at least four come to mind:
  1. Use a asynchronous serial interface, such as a UART channel. This was and remains a viable solution used on many non-PC systems.
  2. Use a synchronous serial connection such as a SPI connection.
  3. Use a synchronous serial connection through dedicated shift register.
  4. Use a parallel bus between the keyboard controller and the main computer.
Using the spare DUART channel would have worked well except for the fact the I didn't have a keyboard in mind when I laid out the main computer PCB.

SPI was a very attractive idea save for the fact that the 65SPI on the IO board can only act as a SPI master and not as a slave. This means it has to control when bytes are received over the bus, which is not what's needed to receive keypresses, which obviously happen at unpredictable times.

So initially I was very keen on the third approach. The 6522 VIA contains such a shift register and in theory this would have been a great solution, minimising the number of wires between the keyboard controller and the rest of the computer (only four would have been needed including power) whilst not requiring any more parts. I just couldn't get it to work reliably. In a test rig, without an actual keyboard attached, bytes would usually transfer ok but would sometimes get corrupted somehow. The VIAs shift register does have some known issues but these did not account for all the problems I was seeing.

So in the end I settled for using an entire VIA port to link a 8 bit port on the AVR with the rest of the computer. This also meant a method would be needed so the AVR could signal the VIA when a new byte needed to be sent down the bus.

A further decision needed to be made, that of what should be encoded in the bytes sent from the keyboard. This really boils down to where the conversion to a useful ASCII stream should take place. It can either be done in the keyboard itself or it can be done in the MPU. For maximum flexibility I've opted to do it in the MPU. This means the keyboard routing running in the MPU can either operate in ASCII mode or it can operate in a "raw" scancode mode, which is the data generated by the AVR. The advantage with a raw mode is it allows a program to see all keypresses not just ones which translate to an ASCII value, for example a pinball game night use the shift keys for activating the flippers.

For the C64 keyboard a scancode can be derived from the row and column of the pressed key. There are eight rows and eight columns, giving 2 lots of 3 bits. Since the data stream is a sequence of key events, only when the matrix changes state is a scancode generated. To represent keys going up, the high bit can be set. Otherwise the key is being pressed.

Here is the circuit for the keyboard controller:


This is a slightly updated schematic compared to what I have made up myself. I seem to have lost the schematic I originally drew up. Anyway, as you can see, it is trivial. I originally hoped to use a ATMega8 (PDF) in DIP28. Unfortunately the keyboard requires two 8 bit ports and the interface to the VIA requires another. An addition two pins are needed to handshake the data to the VIA. This makes 26 pins! So I needed an alternative AVR with more IO ports. Luckily the ATMega8 was also made in 44 pin PLCC which has 4 8 bit ports plus a few more IO pins. This is the ATMega8515 (PDF). The circuit contains two "fluffy" features; a buzzer and a serial header. The buzzer was originally intended to signal a buffer overflow (where the 6809 hasn't ack'd the keypresses fast enough), and a serial header intended to be used for debugging. I have yet to actually implement either function in software however. I decided to make this circuit up on a PCB myself:

I was quite happy to not need any jumper wires!

The next thing to do was write the AVR firmware. This turned out to be a little harder then expected due to the matrix scanning routine being something I'd not written before.

Scanning a key matrix involves sending a signal down one row of the matrix grid and then reading what switches are pressed in that row by simultaneously reading the columns. In an eight by eight grid, eight rows have to be scanned. If this is done rapidly enough the illusion of continual scanning is achieved.

In my first attempt at coding this up, I rotated a logic high across the rows. Rows that weren't being scanned were set to logic zero. Whilst this appeared to work I had introduced a nasty issue: when a key was pushed, row lines that weren't being scanned were effectively sinking current from the row line that was being scanned. This was because the high outputs and the low outputs were being connected together by the key switch. Not good at all.

The solution to this problem is to instead rotate the data direction instead of the outputted value. Thus rows that aren't being scanned are treated as inputs, and are high impedance. The row that is being scanned is an output at logic zero. A further details is to use pull up resistors on the column port. Thus pressing a key results in a zero being sensed at the column pin, otherwise a logic one is obtained at the port.

Actual scanning is done in a timer interrupt handler. This adds a key event into a 32 (fairly arbitrary choice) byte circular buffer, when it detects a change in the keyboard matrix. A pointer maintains the position in the buffer where the next scancode will be stored. Determining if the matrix has changed is simple enough and is a matter of comparing the current state with the previous one.

Inside the main program, the write buffer pointer is compared to the read pointer and if the write pointer is ahead then a new key event needs to be sent to the VIA. This scancode byte will then be put on the VIA port and the handshake line asserted, which should cause the 6809 to wake up and process the byte - more on that later. The AVR, meanwhile, enters a loop waiting for the byte to be acknowledged by polling on the "received" handshake line. Once the byte has been received the read pointer is advanced, and the AVR main loop reaches the top where it waits for the next keypress.

The VIA meanwhile is configured to generate an interrupt when it receives a byte. This interrupt handler's first job is to pull off the byte from from the VIA port. This does two things to the VIA: it clears the interrupt handler and it tells the VIA to acknowledge the byte received, which simultaneously will cause the AVR code to go back to the top of the main loop and wait for the next keypress. The remaing task for the interrupt handler is to optionally translate the scancode to an ASCII value. This is indicated by a flag value at a memory location and works using a simple lookup table of scancide value to ASCII. A complication in this task exists because of handling shift keys, but this is reasonably simple to deal with by tracking the state of the two shift keys and using an alternative lookup table if either is known to be depressed. Mirroring the AVR behaviour this keypress data (weather its a scancode or ASCII) is placed in a 32 byte circular buffer. Outside of the interrupt, game code (for example) is free to poll on this buffer, pulling off keypresses as they are received. This completes the somewhat involved handling of a key going down to user code running on the MPU.

The updated monitor code (including Snake), as well as the keyboard controller code, are available on github, as always.

The end result of this is my computer can now be used completely stand alone, in the spirit of the classic 80s micros.

Originally I hoped to write a version of Pac Man, but this is a complex game to start with so I dialled back my ambitions and decided to write another of my favourite old time games, Snake.

This game uses a different video mode to the mode used by the monitor, but it is still a tiled mode. This time the screen is 32 by 24 tiles, with each tile being 8 by 8 pixels. This finally lets me use the Sinclair Spectrum font. This screen mode also supports a limited form of colour: groups of 8 tile types can have a different foreground and background colour.

Here is a screenshot of the game:


To save me from writing all the video routines from scratch, the Snake game utilises the lower level video routines in the EEPROM. The snake game makes heavy use of the read and write VRAM calls for drawing the snake on the screen and detecting a collision between the head of the snake and itself, the wall or some food.

I think the snake game is fairly playable. The snake not only gets longer as it eats the food, the game also increases in speed ever so slightly to make it more challenging. It's not quite finished however: it would be nice to have better sounds, variable sized "food parcels" and a displayed score based on the length of the snake.

I'm now at a bit of a cross roads with my computer project. I feel I have several possible paths forward:
  • Get updated IO and keyboard PCBs made up. I have already made the design changes to the IO board that are necessary to fix the previously described problems with the DIN RGB port and issues with the AY sound IC. Also, the keyboard board; while it works it would be nice to have it made up professionally, and make it so it can be directly attached to the IO board instead of the currently solution of messy wires.
  • The 6809 software is becoming a bit of a mess of helper routines, monitor code, and is getting difficult to extend. It would be nice to rewrite large parts of it into something resembling an Operating System with proper APIs and layers of abstraction.
  • Yet another possibility exists. I've learnt a lot another programmable logic since I laid out the computer main board. I'm fairly sure I could implement some new custom circuits for the computer. This of course means throwing away the SBC I designed back at the beginning of the year, since it would require a new design for the core computer.
  • Finally I could go off and look at a more advanced MPU and experiment with that. I have several MC68000 parts, of various types, that I've collected over the last few months.
Whilst looking at a brand new CPU, especially one which is dear to my heart, would be great fun there is still much to learn with the 6809. In particular I want to implement a simple multitasking scheduler because it would demonstrate that I understand the principles of this topic. I also have yet to use interrupts when interfacing with the DUART. Though I feel I know the 6809 well, I'm sure there remains a few more corners to explore.

And whilst it would be nice to redo the IO board and "tidy up" the current computer boards, I wouldn't really learn anything new from doing so. And learning new things is the key thing here for me with this project.

So I have decided to focus my efforts, over the next few months, on working on an updated core computer. There are a couple of areas I want to look at:

DMA -  a simple Direct Memory Access Controller should be possible in  XC9572 COLD. I've always been fascinated with DMA, ever since I first found out how the Amiga used it to deliver its amazing, for the time, sound and graphics.

MMU - a Memory Management Unit is perhaps overkill for an 8 bit micro, but it would be interesting to investigate what options exist for memory mapping. Whilst bank switching can be used to gain access to memories bigger the address bus normally allows, an MMU could be useful for isolating multitasking tasks from each other, mapping a task so it has access to the whole 64KByte space as RAM and so on.

For now I will focus on DMA ideas, since this is the more clear cut of the two.

Another thing I'm keen to do over the Christmas break is to make a video of the computer as it currently stands, to show of the hardware, monitor, and snake game. Unfortunately I lack even the most basic of equipment for this task...

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
                rti

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...

Saturday, 28 June 2014

Circuit for a laminator controller and PCB manufacture of the same

I have, for about a month now on and off, been working on the controller board for the toner-transferring laminator. This involved buying some new tools including a drill press add-on for my Dremel multi-purpose tool, a chuck for the Dremel, and a collection of drill bits in various sizes.

First of all, here is a picture of the finished product:


But to actually make a PCB I needed a way to control the laminator without the controller PCB - a PCB-inspired Catch-22! To break the cycle I first made up the controller circuit on breadboard.

I “cheated” here somewhat and used a breakout board for the MAX6675 (PDF) thermocouple SPI IC. The board also came with a “Type K” thermocouple, which was going to come in handy. The relay for turning the heater on and off, too, was contained on it’s own little PCB which also contained a simple transistor driver. This was essential really, as there is no way I’d want mains current flowing around the breadboard. One of the key things I wanted to do was add a display to the controller board - something to show the current temperature. And I wanted a way to set the target temperature too, instead of simply fixing it in code. Luckily I had exactly 2 little displays, each one with 2 half inch 7 segment LED displays, enough for 3 digits and a “C". To set the target temperature, two push buttons (up and down) are also required. For what it’s worth, if I ever want to use the laminator to laminate paper, I can simply set a lower temperature.

Driving the display is fairly simple. Since the 28pin ATMega8 has a large amount of IO pins, the display can be driven directly; 7 pins to light an LED segment, and 4 pins to select a digit. Using multiplexing, it is simple to loop through each digit lighting the appropriate segments.

After getting the breadboard controller working and writing the code, it was time to make up the PCB. This required drawing up a schematic to match the PCB:


The “production” controller board is designed to be powered from a mains adapter PSU with the standard barrel connector, running at anything upto about 12V, with 5V to the AVR and other parts being supplied by the venerable 7805 (PDF).

Note that in this schematic the relay PCB circuit has been included here because I wanted everything on a single board. I actually bought 3 of these little relay PCBs (each one with 2 relays) and dismantled one of them to salvage the relays and a few other parts. This was actually cheaper then buying the relays individually! A simple transistor switch is used to provide the relay with enough current to turn on and off. The venerable 2N222 was chosen, only because I had some in the parts drawer. A diode is used to prevent back EMF from feeding back into the MCU.

Also, the MAX6675 is included directly, because (once again) I wanted to fit everything on a single board. I knew this was going to present me with a challenge, since this is Surface Mount Technology part, and I had never dealt with these before. In a way this makes the board double sided, since components are on both the top and bottom of the board.

One nice thing about the circuit is I managed to keep the serial transmit pin free. This means my controller firmware can transmit temperature information on the serial port. At some stage, when and if I can be bothered, this could even be used to produce realtime temperature graphs on the computer display. For now it is just a handy way to see the temperature the laminator is running at without glancing at the controller board.

The software I run on my board, which is fairly trivial but has a few interesting elements, is available on github. It uses the SPI routines described in a previous post to read the temperature, before doing some bit mangling to extract the actual value from the SPI data. See the data sheet for a description of the packet format. The most interesting aspect (for me) is that it uses timer interrupts to multiplex the display. Interrupts are one of the few remaining AVR features to explore. Additionally, the EEPROM within the MCU is used to store the target temperature, so it does not need to be reconfigured each time the board is board is powered up. I’m also quite pleased with how the buttons to set the target temperature operate; to differentiate the target temperature from the current temperature, the display flashes when setting the target temperature, much like when a LCD watch has its time changed. This kind of control application is the perfect example of why MCUs have become so widespread in the world.

The software also contains a couple of “safety features”. If the temperature can’t be read for any reason, the heater is immediately turned off. And it is not possible to set a “silly” temperature as the target.

The software is fairly good at keeping the temperature constant, but not perfect. Temperature variance is in the order of +/-5C around the target temperature. This is because the temperature continues to increase slightly after the power to the heater has been removed, presumably because the thermocouple does not adjust to the changing temperature fast enough. Anyway, it is good enough and many times better then the bimetallic thermostat the laminator shipped with.

The next step was to layout the PCB:


This presented me with some additional challenges related to the fact that this PCB was not going to be professionally produced. Instead it had to work to home-made PCB tolerances. I made the tracks wider (15mil vs 10mil) and also made the pads a little bigger etc. A further challenge is that this was a single sided board I was making. To work around routing difficulties caused by the fact that all tracks must be on a single side, jumper wires are used on the component side. Finally, to save the Ferric Chloride from being “worn out” too soon, unused areas were filled with copper instead of being etched out.

Note the nice thick tracks around the relay at bottom centre. This is because of the high mains currents that are required to drive the heater in the laminator. Also, since it is on the track side of the board, the SMT device is shown in white.

The PCB is 10cm by 8.5cm.

For various reasons, but especially a problem with the filled out areas, I am now seriously looking at alternatives to the gEDA suite. The PCB program in particular is very tedious to use and is in no way “modern software”. Therefore I’m going to look at two alternatives: KiCAD and Eagle. Hopefully one of those will better suit me. It is annoying though; generally I don’t mind gschem (the schematic capture part of gEDA), and learning a new tool will take a long time - time that I could be using working on actual projects. Plus I will have to remake my custom schematic symbols and PCB footprints. It also makes me a bit sad because I like the fact that gEDA is open source.

So anyway, once I had the laminator being temperature controlled with the breadboard circuit it was time to produce the PCB! This required a number of steps, which I will detail in case anyone else is interested in making their own PCBs. I took some photographs as I was going along, but note that some are not of the finished design since I made a number of mistakes along the way.

1. Print out the PCB track design on a laser printer. You cannot use normal printer paper - it is too thick and will not transfer the toner nicely. Instead I used magazine paper. It must be very thin. I used paper from a free shopping (advert) magazine; decent paid-for magazines will again be printed on paper that is too thick. To actually load it into the printer tape the magazine paper to a piece of normal printer paper and use the manual feeder.

Worth saying this twice: make sure you are printing out the design mirrored.

It might take a few attempts, but eventually you should end up with something like this:


But hopefully a bit better, since this was discarded due to the amount of dropouts. Then you will need to trim the paper to the size of the copper clad board. You can use a craft knife for this, but I prefer just using scissors.

Remember to print the design out mirrored! Or it will be useless, as I found out to my cost.

It’s quite likely that the print won’t be perfect and there will be missing toner. I generally have a few attempts and choose the best one.

2. Cut the copper clad board to size. There are various ways of doing this. Some people use a hacksaw, some people use an electric saw. My preferred method is to score the copper side of the board with a craft knife and a metal ruler, cutting through the copper and into the fibreglass or other PCB material. After scoring the board, my low tech solution to snapping the board involved clamping it to the edge of the desk and bending it. This worked surprising well, didn’t make any horrible fibreglass dust and resulted in a nice break. A quick sand with some fine sand paper smoothed the edge of the board along the break.

3. Bring the laminator up to the required temperature. I set my controller board to 175C, which seems to be a good temperature for toner transfer. Have some means of holding a hot piece of PCB in your hands, like a thick cloth etc.

4. The tricky part, then, is to place the paper onto of the copper clad board (print side down obviously) whilst simultaneously feeding it through the laminator. The first few times through the laminator the paper will “flap about”; only after the board has heated up will the toner start to melt and stick the paper to the board. It takes some practise to line the paper up with the board precisely. It is obviously not possible to tape or glue the paper to the board.

Here is a very poor quality shot of the transfer in progress. You can just see the controller breadboard circuit at the right hand side of the picture:


 5. After feeding the board through about 5 or 6 times the board will be very hot and the paper will be stuck nicely to the copper clad and you will be able to see tracks through the paper. This means everything is going well. Feed the board through a couple more times “for luck”.

6. You can leave the board to cool down on its own, or just throw it straight in a sink of warm soapy water.  In any case, get the board and paper wet to the point that the paper is waterlogged. The paper should then just “fall off” when you put it in under the tap. The result should be a piece of blank paper in one hand and a toner transferred copper clad in the other:


 7. Your PCB may well have a strange white fluffy residue on it. This is the remains of the paper. Some people rub this off, but I prefer to leave it on as it provides yet more resistance to the etchant. Here’s a picture of one of my boards prior to etching. You can clearly see the “white fluff”:


At this point you can fix any small print or transfer errors with a marker pen. This will block the etchant from getting at the copper, but probably not quite as well as the toner would.

8. Now the fun, but tedious part. You must wear rubber gloves, and be in a properly ventilated area. FC is kind of dangerous, but not overly so, and not if you are careful and know what you are doing. It WILL stain almost anything it comes into contact with, and it will hurt if it gets on your skin. Smoking while etching is also probably not a good idea!

I have no clue about other etchants as I’ve not used them.

I have my etchant stored ready to go in a plastic “click lock” food box, with the unused FC in the bottle it came in. Gently place the board in the FC. Etching took, for me, about 20 minutes. Occasionally tip the box backwards and forwards to “agitate” the liquid and ensure an even etch. In general, the frequency which you should agitate and examine the board should increase as you get towards the end of the process. It’s very annoying to over etch a board, but equally painful to under etch. Towards the end of the etch, I found it helped to rub the board gently with a rubber-gloved finger to coax the etchant along.

9. Once the board is etched, clean of all the etchant and clean up the mess you’ve made. FC can be used a few times before it is “exhausted” and needs to be safely disposed of.

Here’s a picture of one of my boards after it’s been etched. This is the first board I made, and you can clearly see some areas which are over-etched. The boards got better as I went along. This particular board's bigger problem was that I forgot to mirror the printout:


10. After etching comes the drilling. My Dremel drill stand is really not very good, but I managed to get through this task relatively quickly. Here’s the final board after drilling, with a few components seated for testing alignment prior to soldering:


You can see that this board is quite a bit better then the first one. This is because I watched the board very closely in the final stages of the etch, pulling it out frequently.

11. The final step is of course the soldering. This is much tricker then soldering a professionally made PCB, since there is no solder mask and no plated holes. Here’s a picture of the back of the finished board:


You can see some sloppiness. I blame my very cheap soldering iron for this. Soldering the SMT MAX6675 was quite difficult, but I think I would do better next time. The best solution to this kind of operation, without having any solder paste or PCB ovens, is to flood the pins with solder and then suck off the excess. Even with this little trick, the IC is still not quite aligned correctly.

As usual, I tested as I went. First with the MCU and the ISP programmer header, then the display and relay, before finally the temperature sensor.

In use the board behaves as well as the breadboard, but of course is much smaller and self-contained. I did notice the LEDs on the 7 segment display are not especially bright, but they are bright enough to be read clearly.

There’s not much more to do really, except find a way to mount the PCB to the base of the laminator so I can move the equipment about “as one piece”, and perhaps tidy up the code a bit more. I would also like to investigate how to better deal with the errant temperature readings that occasionally come from the MAX6675 and make the code ignore these erroneous readings, but apart from that I think this little project is done!

Along with the code, the schematic and PCB design can all be found on github.

I’m very pleased to now be able to make up my own little PCBs. I will continue to use botech for the complex circuits, but simple things, perhaps designs up to twice the size of the laminator PCB, I will certainly be making myself.

Wednesday, 7 May 2014

A working Single Board Computer

Last Monday, April 28, the PCBs arrived. They only took a little over 72 hours door to door from Hong Kong. Pretty amazing service from DHL. And amazing service from Botech, who have done an excellent job making up my design. Here's a picture of the five boards in their little wallet:


And here are pics of the bottom of one of the boards:


Monday evening I started the job of soldering up the board. My rough plan was to test as I went.

Before warming up the iron, I first did some basic continuity checks on the PCB, making sure at a minimum that the Vcc and ground rails weren't shorted together somewhere.

Next I soldered up the power related components, including the USB and Molex connectors, power LED and resistor, and the fuse. Then I powered on the board and checked the power LED lit up, and checked for 5V at various places on the board.

The next job was to solder the buttons, halt/run switch, reset generator and CPU DIP socket. After that I checked the function of the buttons by measuring the voltage at the relevant CPU pins. Then I soldered the memory and DUART sockets.

After that it was time to tackle the "massive" 84 pin PLCC connector for the CPLD. I did this and the 10 pin IDC JTAG header before verifying that I could program the XC95108 "in circuit". It was a big relief to see this work first time.

Next up was to solder on a few of the jumpers including the TTL serial lines, and the rest of the LEDs.

Then I needed to make a few small changes to the VHDL to make it generate constant values on the high address lines, the ones marked B4 to B0 in the circuit diagram, since the bank switching wasn't yet implemented. The rest of the VHDL, to handle address decoding and other core things, was done a few weeks ago.

After all this was done, it was getting late and I thought about calling it a day. But I wanted to see if the computer would work. I wasn't expecting it too, but I hooked up the USB serial adapter, fired up the terminal program, and powered up the board. Amazingly I saw my monitor prompt the first time!

I took a picture to mark the moment:


Here are some pics of the board fully populated and soldered. Well, I say fully populated but the decoupling capacitors are yet to be soldered. The board appears to work fine without them, but I will add them soon anyway. First the top:


And the bottom:


I really wish I had a way to remove the solder flux, since it really looks quite horrible. I must admit this is not my best soldering.

In the days since, I have tested and implemented additional functionality.

IDE interface in 8 bit mode: this worked first time, which is not much of a surprise since I had this working on breadboard last autumn,  Since I have soldered pin 20 to the 5V line, the Compact Flash adapter does not require extra power. Should I someday want to try out an IDE hard disk, I would need to remove pin 20 from the IDC plug. I doubt I will, since even a small CF provides more then enough storage. But it could be fun.

Bank switching: the HDL required is fairly simple. It requires the RAM Chip Select to be broken in two. If the low half is selected, then the five high bits of the physical address are forced to 00000 but if the high half is selected then the bank switching register should be output instead. Thus requests for addresses from 0x0000 to 0x3fff will always select the lowest 16KByte page, but requests for addresses from 0x4000 to 0x7fff will be mapped to one of the 31 other 16KByte banks. It is also possible to map this range to the same page as 0x0000 to 0x3fff is mapped to, but this does not seem very useful.

To make operation of the bank switching latch simpler then a write to a specific IO address, two commands have been added to the monitor:
  • b NN - switch to bank NN
  • B - show the current bank number

They are trivial enough; they just write and read the bank switching latch register address. But they save some typing. The following screenshot shows the monitor being used to switch bank after writing some data into the first few bytes of each selected bank. Finally the content of the first few bytes in each bank is shown:


Beeper: this was prototyped on the XC9572 in the breadboard so I didn't expect any problems. A single register holds the period of the tone, but to yield a useful frequency the E clock line is first divided down by a 7 bit counter. It is then divided down by the sound period register, and assuming that register isn't zero, the output line connected to the sounder matches the highest bit in the sound period counter. This makes it possible to output a tone at between about 15KHz and 61Hz.

The monitor has been modified to make use of the sounder by producing beeps at startup.

Once the VHDL is a bit better structured, and commented, I will upload it to github.

There's a few outstanding issues to investigate before I get on to working on the I/O board.

The MAX232: for some reason hooking up a plain null modem cable isn't working. I think the IC I'm using must be faulty as I have checked and double checked the circuit and it matches many other people's examples as well as the datasheet. Since I don't own an oscilloscope tracking this problem down could be awkward. I've ordered a bunch more MAX232s so I will soon find out.

The 16bit mode IDE is causing me some headaches. I need to create two latches in VHDL, one for reading and one for writing. Also the latch needs to get its value from the IDE when a read occurs on the actual IDE interface not when the latch itself is read. And likewise for writes.

One small quirk with in circuit updates of the CPLD bares a mention. While the IC is being programmed over JTAG, it seems that the IO pins are being driven low causing the EEPROM content to be corrupted, since the read/write pin is active low for writes. In the previous board I had a write protect jumper which could have been useful to tie the R/W line high while the CPLD is being programmed, but I left it off this design thinking I could use the programmable logic to implement write protect. But I forgot about the time the CPLD is programmed. It's not a big problem; I just unsocket the EEPROM before I program the CPLD. Annoying but won't be a problem once the VHDL is finalised and stops changing so often.

I have yet to extend the address decoding to deal with the eight "off board" chip selects, but that is simple. Nor have I done anything with the configuration jumpers. Those will probably be used to write protect sections of the EEPROM as initially decided, though I could alternatively make them simple monitor configuration registers and then a jumper could be used to set the active serial port or something similar.

Due to a quirk in the PCB layout software, it neglected to highlight a mistake with one of the pins on the expansion connector. The ungated (off the 6809) Read/Write line isn't connected. This is because I made a typo in the schematic. I still have the Read and Write (gated through E) lines available, which is what 99% of peripheral chips require, but it is still annoying. But if I should require this line on the I/O board then I can borrow one of the 8 expansion Chip Selects by routing a copy of the Read/Write signal through it and reducing the number of Chip Selects down to 7.

Anyway, I am very happy with my progress the last few weeks. I look forward to working on the I/O board, something I hope to start soon by prototyping up elements on breadboard. Probably the first thing I will get working is the 65SPI...

Monday, 21 April 2014

PCB ordered, and improvements to homemade PCBs

This last month or so I have been working on two fronts: finalising the circuit for the computer, and working on my home made PCB fascilities.

So, the circuit is finished. For power the board has two options: USB, like the previous design, and a Molex harddisk power connector. Because of the high current sourcing with a PC power supply I have included a fuse, rated at 1A on the board. The idea is that if I should have a short circuit somewhere, or similar fault, the fuse will blow before the several amps from the PSU can flow into the whole circuit and destroys most of the ICs. That's the theory anyway. Below is the schematic:


A few tweaks and additions since my last post:
  • A piezoelectric sounder has been added, with a series resistor. This is connected to the CPLD.
  • A general purpose button, which will probably be used to generate an NMI signal. It is connected to a pin in the CPLD, so can in theory be made to do anything.
  • A "Econo reset" DS1813 (PDF) handler now takes care of generating the RESET line, eliminating the capacitor. This should generate a nice clean reset signal at power on, and when the button is pressed.
  • The run/halt push button has been replaced with a more sensible miniature sliding switch.
  • Two supporting connectors, which double up as power connectors serve to give future daughter boards some rigidity when they are plugged into the expansion connector. There are two to deal with long and short daughter boards.
  • The IDE port has the option of supplying 5V at pin 20. This is useful for some Compact Flash adapters, but for normal hard disks this pin is missing and is blanked out on the IDE cable so if there is a pin in the connector the cable will not fit. I have arranged the PCB so it can work either way.
  • Various decoupling capacitors have been added including as many as I could squeeze around the CPLD, and a pair onto the circuit as a whole.
The finished PCB design is below:


Before finalising the PCB design, I thought it would be a good idea to check that all the components would physically fit where I'd put them. Some of the "footprints" for the components are not quite right, and without ensuring the space given to each one is adequate, it is possible that two components don't physically fit next to each other. I had this problem with the previous design, whereby I hadn't left adequate spacing around the crystal. Anyway, a simple way to check things out is to print out the design on paper, and then physically lay the components on top of where they need to go:


This check prompted me to make a small change to the placement of the DUART crystal, to give it some room around the "power support", at the right of the board. Otherwise, everything appeared fine.

Last week I placed an order with my favorite PCB manufacturer, botech. I have ordered 5, for a total cost of £45 including shipping, which I though was quite reasonable. The board is even bigger then the last one, at about 12.5 by 14.5 cm. This would be considered large to most PCB houses who do small runs for hobbyists. The number of holes is also quite alot, at about 650. Anyway, with luck I will be soldering up the board next weekend.

The VHDL coding for the CPLD design is mostly done, with only things like the sound interface and the IDE latch to finish. Of course the cool thing about programmable logic is these things can be done, and redone, after the non-programmable hardware has been decided upon.

The other area I've been working on is PCB production at home. In the end I concluded that the iron on method for toner transfer is not dependable enough; occasionally the transfer was just about acceptable, but only after five or six attempts. The better method for doing toner transfers involves the use of a laminator, the kind of machine meant for laminating paper documents. Instead of heating plastic with paper inside, toner can be transferred to a piece of copper clad. It works better then an iron because the temperature is, in theory, more constant and the heated rollers apply a consistant pressure.

So I duly went and bought the cheapest laminator I could find: about £15 from Argos. After some experiments it was obvious that it wasn't getting hot enough for the toner to transfer, which happens at about 170C. Using the thermocouple on the multimeter showed the temperature was only reaching about 150C. Worse, it was fluctuating a lot going from 150C down to about 110C until the characterisic "pop" and the current being applied to the heater causing the cycle to repeat. Pulling it apart revealed the temperature control to be done with two bimetalic thermostats. I did try to buy a new thermostat, rated at 180C and this made for some better results, but still the hysteresis curve was too wide with the temperature going between 185C and then down to about 140C. Better then before but still not good enough for reliable transfer.

Using the multimeter I was able to prove that with reliable temperature control, it would be possible to do consistent toner transfer. With the temperature around 180C, and quickly feeding the copper clad with tracks printed onto thin magazine paper ontop, after about five feeds I was able to get perfect transfers. I even did an etch to see if it would give me a good etched PCB:


The result was better then I'd hoped for and a million miles cleaner then I could get with the iron. The PCB, by the way, is a shrink DIP to regular 0.1 inch adapter. Eventually I will need this when I want to integrate a Yamaha YM9958 video controller into my computer. These ICs are a little odd in that they use the uncommon shrinked DIP formfactor which have pins with a 0.07 inch pitch.

So the next job is to make the temperature much more stable so I don't need a multimeter with thermocouple attached, and I don't have a narrow window with which to put the copper clad through before the temperature goes too low. There are a couple of ways to do this, but my choice is with a microcontroller attached to a thermocouple and some way to turn the heater on when the temperature is too low and off when it is too high. I should then be able to keep the laminator rollers within a narrow temperature range around the ideal toner transfer temperature.

The first thing to do is to select a method of obtaining the temperature in the microcontroller. As usual there a number of options but in the end I went for a MAX6675 (PDF) IC attached to a thermocouple. A nice breakout board is available, on good old eBay, which combines the IC with a type K thermocouple, all for about £9. The MAX6675 interfaces via good old fashioned SPI which, through my experiments with the 65SPI, I have some experience with. But not, oddly, with my microcontroller of choice; the AVR ATMega8.

Because I don't have the thermocouple and MAX6675 board yet, I needed to find out how to do SPI with the AVR some other way. In the end I went for the simple approach of hooking up an AVR to a DS1305 Real Time Clock. This was easier then expected. Hardware wise, I breadboareded up the ATMega8, DS1305 (with 32.768KHz crystal) along with an ISP header and reset button. For comms back to the PC the AVR's UART was used.

The circuit is trivial, so I won't bother to include it.

Here's is the equally trivial breadboard setup:


Software wise, I was lazy and opted to borrow the core of the code from the EEPROM programmer I made back last spring, taking just the serial comms parts.

The code added includes a section to setup the SPI port:

/* Configure input pins on SPI port */
DDRB = (1 << 5) | (1 << 3) | (1 << 2);
/* SPE = SPI Enable, MSTR = MSB first, CHPA mode, SPR0 = Slow down clock */
SPCR = (1 << SPE)|(1 << MSTR)|(1 << CPHA)|(1 << SPR0);
/* Disable DS1305 */
PORTB = 0x00;

Here is the code for displaying the time:

else if (strcmp(args[0], "showtime") == 0)
{
    unsigned char timebuffer[0x11];
    memset(timebuffer, 0, 0x11);

    PORTB = 0x04;
    _delay_us(10);

    spitxrxbyte(0);
    spitxrxbuffer(NULL, 0, timebuffer, 0x11);

    _delay_us(10);
    PORTB = 0x00;

    snprintf(serialoutput, BUFFER_SIZE - 1, "%02x:%02x:%02x %s %02x/%02x/%02x\r\n",
        timebuffer[2], timebuffer[1], timebuffer[0],
        daysofweek[timebuffer[3]],
        timebuffer[4], timebuffer[5], timebuffer[6]);

        writestring(serialoutput, 0);
 }

And here is code for setting the time:

else if (strcmp(args[0], "settime") == 0)
{
    unsigned char timebuffer[0x11];
    memset(timebuffer, 0, 0x11);

    timebuffer[2] = strtol(args[1], NULL, 0);
    timebuffer[1] = strtol(args[2], NULL, 0);
    timebuffer[0] = strtol(args[3], NULL, 0);
    timebuffer[3] = strtol(args[4], NULL, 0);
    timebuffer[4] = strtol(args[5], NULL, 0);
    timebuffer[5] = strtol(args[6], NULL, 0);
    timebuffer[6] = strtol(args[7], NULL, 0);

    PORTB = 0x04;
    _delay_us(10);

    spitxrxbyte(0x80);
    spitxrxbuffer(timebuffer, 0x11, NULL, 0);

    _delay_us(10);
    PORTB = 0x00;
}

The two SPI routines are as follows:

unsigned char spitxrxbyte(unsigned char data)
{
    SPDR = data;
    while(!(SPSR & (1 << SPIF)))
        ;
    return SPDR;
}

void spitxrxbuffer(unsigned char *tx, int txcount,
        unsigned char *rx, int rxcount)
{
    int c;

    for (c = 0; c < txcount; c++)
        spitxrxbyte(tx[c]);
    for (c = 0; c < rxcount; c++)
        rx[c] = spitxrxbyte(0);
}

Interestingly these routines are very similar in function to the 6809 code I wrote for the SPI handling in my monitor program. The first routine sends and gets a byte, the second routine sends a buffer then gets a buffer. Both transfers are optional.

Here's a simple screenshot of a terminal program attached to the AVR, with the clock being set and then shown a number of times. The command for setting the time is crappy as it involves using hex notation, but this is just a prototype so who cares:


For fun, I hooked up the Logic16 and did some captures. Here I am setting the time:


So now I'm just waiting for the thermocouple with MAX6675 to turn up, along with the PCB for my 6809 computer.

Hurry up postie!