Skip to main content

RC2024/10 - my entry

A while ago I made this MIDI module for RC2014:

It works but a better design would have its own serial chip and port decoding. 

As it is, it provides the MIDI interface and a clock signal for the second SIO2 serial port. This means that it requires a little setting up and will only work for RC2014s with an SIO2 (and port B not already used).

My challenge to myself is to 

  • learn how to connect a serial chip (probably 68B50 ACIA) to receive the incoming MIDI and to serialise outgoing MIDI
  • design the module, including the port decoding
  • write a library so that it can easily be used on any RC2014. Potential applications include a MIDI sequencer and using incoming MIDI to trigger notes on the AY or SID sound chips.

Entering the Retro Challenge 2024 (aka RC2024/10) has given me an incentive to get on with this!

I'm happy to see several more entries in the RC2014 category, including another musical project. 

Tue 1 Oct 

I've ordered a 68B50 aks ACIA. I think it could also correctly be described as a UART, which also seems to apply to the protocol.  (I could have pinched one from a RC2014 classic but don't want to mess around on a breadboard with something that's part of a regularly-used machine.)

While that chip isn't manufactured today and there's no new old stock (despite what some sellers claim) it is easy to buy them 'tested' (what 'tested' means depends on the seller). It does seem like the most sensible and most age-appropriate option 

While waiting for that I set about reading and understanding the data sheet and starting to sketch my schematic.

This is more like revision, because I own a Datel MIDI cartridge for C64 and I've dabbled in this stuff when programming that. 

ports and registers

The 6850 has four internal registers but you can think of them as two that can each be written to or read.

My C64 cartridge implements them as four separate addresses in the i/o space, two of which you can poke, two of which you can peek. The RC2014 classic serial module uses two hardware ports, each of which is readable and writable and that seems like the way to go here. 

The data register is obviously where you write your data to be transmitted and read your data when there's a byte ready. (This chip doesn't seem to buffer any bytes, which would definitely be helpful here.)

The control register, when read, gives a status byte. Each bit is a flag, the most useful ones to us are the lowest two which indicate when the receive buffer is full (indicating that we can read a new byte of data) and when the transmit buffer is empty (indicating that we can write a new byte of data). 

When written, the various bits allow us to specify whether we want interrupts, the flow control and the serial word length, parity and stop bits that we want*, and importantly the clock division that we want**.  

The MIDI serial protocol

* I found a discrepancy here. The instructions for my C64 cartridge tell me to send the bytes 03 and then $12 or $92 (depending on whether interrupts are needed) to the control register. I now know that the 3 is a reset, followed by a byte that sets clock division to 64 (more of that in a second) and sets the serial to "8 Bits +2 Stop Bits". However, this page for the same interface says $16 or $96. That sets the serial to "8 Bits + 1 Stop Bit". 

The internet generally agrees that MIDI is serial at 31,250 baud / bits per second, 8 bits plus a start bit and a stop bit.  

I don't know how this matches up with the discrepancy above. Is a start bit + stop bit the same as two stop bits? Does it matter if there's an unnecessary stop bit? I guess all I can do is experiment and see what works.

[update] I found a note in the data sheet that a start bit is always sent anyway. So I guess that one stop bit is all that's needed, and maybe an extra stop bit makes no difference. It seems correct to use the "8 Bits + 1 Stop Bit" setting but we'll see when I try to make it work.

When making my Mk1 module I calculated that a 2Mhz clock would give me the required 31,250 baud.  I based this on the clock speed of the RC2014 and the resulting baud rate (7.3Mhz giving 115200 baud). 

This makes sense now (assuming that the SIO2 which I was taking advantage of before is also set to divide by 64) because 2Mhz divided by 64 is 31250.

So I can simply use the same clock circuit and components from my Mk1 module.  

I think that's about it for now. When my 68B50 arrives I'll be able to breadboard it and know what I'm doing, and write some rudimentary code for it. 

Over and out.

Fri 4 Oct

Postie has just brought my 68B50. As predicted, despite the seller claiming 'new old stock', of course it isn't. I don't think there is any NOS left of this part (I'll be happy to be proved wrong). There's a sheen to the surface that I recognise now (it fails the acetone test) and the legs are tinned and not perfectly straight. It's almost as if making old chips look new (and claiming that they are) is just acceptable and accepted now. 


Anyway, it works which is the most important thing. I swopped it with the same chip in my RC2014 Classic and ran it. (Interestingly, the appearance and markings are almost identical, except for the date code, I half expected that to match.)

[some hours later]

It's very late but I've had some success.

First, for a quick and dirty way to show that my understanding of how to hook up the 6850 is correct, I built this:

I tapped the digital i/o module for a signal when port 0 is written, tapped my mk1 midi interface for its 2Mhz clock signal and used a dev board for the midi circuitry. 

Then I realised that this wouldn't work. I needed to send data to both ports; control and data. The register select on the 6850 is one line, high or low. I could have added extra logic for that but that would become even more sketchy than this is already. So I pulled that apart before even switching it on.

And took the time to build this instead:

I still didn't bother to put the clock circuit on there, or the MIDI ports, but at least this does its own port decoding* and is connected up according to the schematic that I've sketched out. I have more confidence in wire-wrap than breadboards anyway.


Here it is (after beeping everything to double-check it) with the chips installed. Fingers crossed....

(I just went into MBASIC80 and sent the reset / setup bytes to the control register, currently on port zero, and then these three bytes, a MIDI message, to port 1)

.. and YAY! received at the other end. 

The software should really read the status register and check that the data register is empty before sending each byte, but I (correctly) guessed that BASIC would be slow enough for that not to be necessary. 

This setup will allow me to get on with some software.

Ports

*For this prototype I'm just using ports zero and one. That kept the wiring simple

After a conversation with Spencer about unused ports, I've settled on DE and DF with a solder pad to allow that to be switched to AE and AF, as with my recent paddle module. 

Over and out.

Mon 7 Oct

Let me interrupt you

Real life has got in the way of this project over the last couple of days and I have other things that I should really have been giving priority to today. But curiosity got the better of me and I did a lot of reading about Z80 interrupts, which will be important when wanting to receive MIDI. The 6850 doesn't buffer any bytes other than the one it has received so you have to collect it pretty smartly before the next one is ready. 

I now know all about the three interrupt modes. Since the 6850 just has a single pin for making an IRQ, with none of this fancy 'putting an instruction on the bus' (mode 0) or 'providing part of the interrupt routine address' (mode 2) we'll be using mode 1. 

I've also read the manual for SCM, my 'operating system' on my Classic RC2014. I was delighted to discover the Mr Cousins has very helpfully provided a jump table in RAM, with the restart vectors (which are in ROM in that system and therefore not changeable by the user) pointing to that table. He's even provided API routines for registering routines, so that makes it even neater. 

I haven't really established which interrupt mode CPM uses on my RC2014 Pro and Zed Pro (in the latter case it might depend which of the available systems I boot into) but this isn't so important at this point, because the RST at 0x38 (used by mode 1) is in RAM, so I can easily put a suitable jump there and set mode 1.

Receiving data

I'm getting ahead of myself. I'm looking at something that's very much a prototype and I'd like to get a real PCB ordered sooner rather than later. First I want to prove that my schematic is good. I've already sent MIDI data, so I just need to receive some. 

Without worrying about interrupts just yet, I rattled out this simple loop (using C for speed - speed of development and speed of execution) which will print incoming MIDI messages. 


Like buses, the bytes will usually come in threes (sometimes twos and sometimes ones) but if the top bit is set on any byte, then that's the first byte of a message.

So here's me playing a scale on a handy midi controller:


Yay!

Over and out.

Tue 8 Oct

Even though I've only had bits and pieces of time to spend on this, I've made a giant leap forward today, the boards are ordered!

A reminder that this is what I'm looking at on my desk

The guts of the operation are the three chips on the prototype board. I'm tapping the 2Mhz clock from my Mk1 MIDI module, there was no point building a copy of that circuit again, and I'm using a serial <-->MIDI interface which has the very standard MIDI in and out ciruits on it.

I've been gradually sketching the schematic as I've been going along. The MIDI circuitry and the clock circuit were a copy & paste from my Mk1. The port decoding is something I've done again and again. For my recent projects I've been using a '688 for this job which is a neat solution. 

In a very recent project I used some additional logic with the '688 so that a single jumper could be moved to select one of two port options. This time I've tried something new. I used 'cut and shut' solder pads on the back of the board which can be used to reconfigure the ports to any range. It'll always be xE ad xF but it could potentially be 0e/0f through to fe/ff.  I feel that method is appropriate here. You probably won't want to be switching it all the time. The default ports will probably be OK, but if not, you can reconfigure it for your setup fairly easily with a knife and soldering iron. And it's always reversible or reconfigurable.

The challenge

The part that has put the 'challenge' in my Retro Challenge is learning how to connect and use the 68B50. This is the barrier that has prevented me from tackling this project for a long time. 

I've done a lot of reading, I think I understand it, I've made the prototype and it seems to work. 

I've seen this send and receive MIDI messages flawlessly using very simple programs, so I feel confident about transferring all of that to a single new module design.

Last night and this afternoon, I've polished my schematic a bit and moved to the PCB layout.



I'd forgotten just how much I enjoy the process of cobbling something together and then steering that through to an actual solid piece of hardware.

Prototype boards are now ordered from my favourite Chinese manufacturer and should be with me in a week or so. In the mean time I'm going to enjoy working on some software using my prototype. 

Over and out.

Wed 9 Oct



I've moved to my Classic II now and I've started developing the framework in assembly, even though my preferred language these days is C. Why? 

The move to the Classic is because development is much faster. Using a paste to send a small hex file into SCM is almost instant. If I use assembly, in Textmate I can rebuild the program with a single keystroke and thus the turnaround time from code change to trying it on the computer happens in the blink of an eye. 

So I've spent some time on my framework, and can still send and receive MIDI as well as user input / output.



"This result looks exactly the same as from two days ago?"

As is often the way with development, you spend time on something, refining it and improving it, and then the result is just the same as the quick-and-dirty get-something-working code. 

But now I've got an interrupt service routine and I'm configuring interrupt mode 1. The routine is called by the 6850 generating an IRQ when there's a new MIDI byte ready and it buffers it in a circular buffer.

The interrupt and buffering means that the main program can take its time doing whatever it needs to do and call the MIDI task when it's convenient. No bytes will be dropped. 

I've got a 'send MIDI message' routine, which sends the three bytes of a message, with a proper check for the transmit register being empty/ready. 

I'd like to make this same framework available in C, which I favour these days, but one of the reasons for getting this working in assembly first is that I checked out how to configure interrupts when using z88dk and that looked scary. OK, maybe not too scary but that's an additional challenge that I hadn't bargained on.

IRQ signals

I had a thought, which is that I have two ACIAs (the one on the regular RC2014 serial module, and the new one on the MIDI module) and they both have a pin connected to the IRQ line on the bus. 

They may both assert at the same time (both low) which shouldn't be a problem, but what happens when one is asserting (low) and the other is not (high)?

According to the data sheet, that output is "open-drain (no internal pullup)" which, if my understanding is correct, means that when it's not pulling low, it's open, or hi-z, and that means you can safely connect as many as you like to the same line. Phew! 

I'm learning things that I didn't originally know that I'd need to know. Unknown unknowns!

Over and out.




Comments

  1. Hi, Regarding to MIDI protocol, I suggest to check the official MIDI specification located at https://midi.org/midi-1-0-core-specifications . On page 1 of "MIDI 1.0 Detailed Specification 4.2.1", the required hardware specs are shown ,which include baud rate , start/stop bit, and even sample schematic for interface.
    -Yoshi

    ReplyDelete
  2. In an 8-bit connection, the second stop bit just gives the sides a little more time to process fast data streams. It slows down total throughput though. It will effectively be ignored as it is just processed as one twice-as-long-stop-bit rather than two discrete stop bits. Hope that makes sense.

    ReplyDelete
    Replies
    1. Good to know, thank you. That sounds like it could be useful in this project, and it does clear up that discrepancy.

      Delete

Post a Comment

Popular posts from this blog

How to convert images for TMS9918A graphics on the RC2014

For me, graphics capability is essential for an 8-bit computer. My graphics chip of choice for the RC2014 is the very capable TMS9918A. It has 15 colours, sprites, several modes and a max resolution of 256x192. It makes arcade-style games possible, such as Tut-Tut above.  I enjoy simply displaying images and have a bunch on my CF card (my 'hard drive') and have written image viewer and slideshow apps to display them. Some useful links: Convert9918 Tutorial of Convert9918's settings Multipaint J B Langston's TMS9918A video module my own TMSEMU video module my respository of TMS9918A software, games and .s2/.sc3 images Image conversion I did dabble in writing my own utility to convert .png images but then settled on the Multipaint app which can open a png in a MSX 'screen 2', allow you to tidy it up with paint tools and save as a .sc2 file. (An sc2 file is little more than a video-memory dump and so it's easy to blast that back into vram to display the image.

Driving NeoPixels with Z80

I 've long been thinking about a version two   RC2014 LED matrix module . I've had a matrix with a MAX 7219 on a module. It's a nice enhancement. But there's only so much you can do with a single-colour LED array right? Wouldn't it be cool to have RGB LEDs?  At Liverpool MakeFest I saw a wall-sized ping-pong ball NeoPixel display and picked up some NeoPixels with the intention of making one. Possibly driven by my RC2014.  I enjoy learning about protocols and have had some SPI devices working with the RC2014 - bit-banging SPI works really well because it doesn't care about timing. NeoPixels really do care about timing though. From Adafruit's web page about their 8x8  NeoPixel matrix: If there's one thing I want to get across in this blog post, it's don't just accept what you're told . Question everything. Learn about what's going on and find out why you're being told something isn't possible. Get creative with workarounds. I'

ZX81 reversible internal 16k upgrade

T his post is an upvote for Tynemouth Software's  ZX81 reversible Internal 16K RAM upgrade . Their instructions are easy enough for even me to follow and don't involve cutting tracks. This is the ZX81 I've had out on display and used whenever I wanted to. It's an issue 1 and was probably a kit judging by some very untidy assembly. It has a ZX8-CCB  composite video mod and an external keyboard fitted. On board it has two 1k x 4-bit chips.  The ZX81 originally came with 1k on board. Thanks to a trick with compressing the display in ram, that was enough to type and run a small program but you soon felt the limitations. Back in the early 80s, the solution was a 16k ram pack which plugged into the back[1] and this is the way I've been using this particular machine. These ram packs are notorious for 'ram pack wobble'. Even if fastened into place, you can still randomly find your work disappearing. This is a very reliable solution using a more modern 32k chip (half