Mockingboard Chiptune Player Sound Quality Problem


Problem Solved!?!

After a lot of struggle, I think this problem is something I could have figured out if I only had read the datasheet better.

The datasheet says that when you write values, the WRITE line can only be held for a maximum of 10,000ns (10us).

On an Apple II running at 1MHz this is roughly 10 cycles, which is not very long. My code was trying to be fancy and conserve registers and was holding the line roughly 12 cycles. I have modified the code to only take 8 cycles and everything sounds a lot better.

I'll leave the info below for historical reasons.

Background

I have a modern reproduction Mockingboard soundcard (dual AY-3-8910). On some of my demos, such as the Apple II Chiptune Player, the sound gets really glitchy at times. This page describes the long process of trying to figure out what is going on.

A picture of the soundcard in question.

TL;DR

The problem can be reproduced simply by alternating $51, $3C on the Channel C fine frequency register with a 20ms delay.

After some power of two iterations, on the $51 to $3C transition the signal will ramp down to zero for 32ms before recovering.

No interrupts are needed to cause this to trigger.



The Chips

My Mockingboard came with these chips, Microchip datecode 88-35:


In case it was this batch, I ordered some others from China. They are all GI datecode 87-41 which seems unlikely, but they seem to work but show the exact same glitches as the original chips.


Reproducer Code

I gradually created a reproducible test case out of one of the YM5 chiptune files that showed the problem the most.

To try it out you can BRUN CHIPTUNE_SMALLEST on this chiptune_debug.dsk disk image.

The source code chiptune_tine.s can be found in my github (sigh) tree: https://github.com/deater/dos33fsprogs/tree/master/music/chiptune_debug

Probing the Hardware

After going through my code many, many, times I suspected the problem might be due to the relatively long amount of time it takes an Apple II to update the registers on the AY-3-8910 chips on the Mockingboard. So time to hook up a logic analyzer.

This is just a Analog Discovery board that hooks up over USB. Not that great, but good enough for a start. Here it is hooked up to the known-good Raspberry Pi Chiptune Player


And then very carefully hooked up to the Mockingboard/Apple II:


Delay in AY-3-8910 programming

At first I thought somehow the delay it took to program the AY-3-8910 by the 6522s might be causing the issue. So below is a rough summary of some signals captured with the logic analyzer. The top is the Pi-player AY-3-8910 (fastest), then the "fast" unrolled Mockingboard AY-3-8913 results, then my normal Mockingboard code. These are random captures (not the same frame) so the results shouldn't match exactly, I was mostly measuring to see the relative lengths of the pulses. Also the DA0 probe seems to have been loose during the run.

The timing results are what I expected from cycle counting. I didn't have enough probes to measure all the signals, and also I wasn't able to measure more than a few passes so sadly not enough to capture the signal during a glitch event. You can see the register being chosen when both BC1 and BIDR high, followed by a latch event. On the Mockingboard code apparently my code leaves the output high if the last value written was high, but I don't think that should break anything.


Output Waveforms

Here's a comparison of the first 2 seconds or so of audio. As you can see on the Pi player (where things sound correct) it's a nice continuous output. But on the Mockingboard, both with regular and unrolled loops, there are glitches in the output. I had thought that reducing the latency of the register writes might help with the problem, but actually it looks like it is making it worse.


Here's an extreme zoom in on the signals. You can see the signal is roughly the same. The Pi audio-out line is before the amplifier which is why it's still a square wave, presumably the mockingboard output is triangular because it's been run through the LM386 amplifiers.


In case you think this might be some sort of glitch, here's the stereo output. On the mockingboard I separately write the same values to both AY-3-8910 ports, and the glitch appears on both channels. Which seems to show that it's not an individual 6522 or AY-3-8910 causing the problem.


Here's a zoom in on the first 0.2s of the song. You can clearly see where the sound being played changes with each 50Hz interrupt. This part of the song is not very active, only the C channel is being played. So it's mysterious why that first glitch happens in Frame 11, there's not a lot going on for the signal to get confused.


It almost looks like the registers are being reset to all zeroes? Or maybe somehow an envelope is being turned on? Or maybe a combination of both?

So I did some more experiments with the logic analyzer. The logic analyzer I have can only read 5 signals at a time, but I went in and did some more runs on SDEMO.YM because it has a dropout fairly early on (around frame 12 or so).


Overall the signals into the AY-3-8913 are exactly what you would expect. There is one frame where the signals are missing, but that might be the logic analyzer missing data (it warned to that effect). The dropped frame data is about the right place to cause an issue, but I can't come up with an explanation as to how that bit pattern could cause the results shown (unless it caused a reset, but in my other measurements I wasn't seeing any resets). This is very mysterious and frustrating.

Newer tests, was dropping the scope on various pins and not seeing anything useful. Here you can see the Channel C output and that it has the glitches.


Is it the 6522?

I thought it might be the 6522 chips driving the AY-3-8913 sound chips. So I broke out the 6522 manual, and from what I can tell everything there is fine (and it would have to be, considering the logic probes on the AY pins are as expected).

I did notice the 6522 uses handshakes on PortA and PortB by default. If you look at the Mockingboard schematic, the PortA handshake response line is pulled high to 5V, but PortB is left floating. In case this was the issue, I did some sketchy solder work on the board:

But no luck, behavior still the same as before.

Is it the AY-3-8913?

The issue could concivably happen if the AY-3-8913 had the wrong values written to the wrong registers. So I started reading back the values after writing. They always match (on real hardware at least; this is an odd thing to want to do so the emulators do not model this).

So my current theory is that it's a hardware issue inside the AY-3-8913 chips I have.

I minimized the test code and found that I can generate the glitches by configuring the card and then simply writing to the C channel (no other register writes are needed). It triggers when every 20ms (50Hz) you alternate two values to C. Writing the same value over and over again does not trigger it, but writing two different ones does.

Here's a capture of repeatedly writing $51, with no glitches generated:

For the initial chiptune that triggered this, it was the $51 to $3C transition that frequently causes a 35ms or so glitch where the output drops to 0 before recovering. This can be seen in the trace below. It only happens at the $51 to $3C edge, not the other way around.


Other values trigger similar bugs. Some, oddly, don't trigger the full glitch but just reduce the volume. This is worrying because this sometimes happens on my Pi-chiptune player with fullsize AY-3-8910 chips.

Also, oddly, the issue often triggers after a power-of-two number of register writes.

I ordered new AY-3-8913 chips. These show the same issue.

Also I found a datasheet that included AY-3-8913 timings. These are actually different from AY-3-8910/8912 (most notably it lists the Write Data Pulse Width at about 5 times longer). I tried adding extra nops, still got the glitch to occur after 32 transitions. This is right channel only, the signal on the left channel is solely from bleed through.


I also tried flipping the address value/address latch signal as the timing diagram looks like you can swap them (and the Programming Guide says you can) but if you do that none of the emulators will play sound even though real hardware still will.

So then I ripped out the interrupt code again, and busy waited 20ms in between and I was able to trigger the issue every *2* iterations.


If you zoom in, once triggered, it takes approximately 32ms to recover.



Summary

A summary of the current investigation:
doubling length of writes:      still issue
removing rasterbars:            still issue
removing volume bars:           still issue
remove time update:             still issue
remove dead code:               still issue
remove title screen:            still issue
remove all graphics calls:      still issue
remove memory shuffling in back:still issue
remove keyboard:                still issue
remove all non-irq code:        still issue
remove all text print code      still issue
remove multi file (down to 973) still issue
remove dos33 code               still issue
remove lz4 code                 still issue
remove interrupt driven         still issue
run at 25Hz			still issue
50Hz,inline, no play 11,12,13   still issue
also turn off A/B freq          still issue
also turn off noise/Aamp/Bamp   still issue
move to single output routine   still issue
always volume 12                still issue
fix clear accidentally wr r14   still issue
generate single tone            FINE!!!
only play first 16 notes        still issue
only change C-fine value        still issue
only write val, not address     still issue
use handshake-free porta/6522   still issue
make sure only timer1 irq	still issue
6522 Force PB1 high		still issue
remove other cards in system (in case power supply overload) still issue
Write only 4 values		still issue
write two values $5c,$31	still issue

Back to Chiptune Player Homepage