Fidget Clicker Becomes Miniature Game Console

Fidget toys are everywhere these days. A particularly popular type simply puts some keyboard switches on a plate to provide a certain type of clicky satisfaction. [wjddnjsdnd] took that concept a s…

Hackaday
First time using an #ArduinoNano to flash a second Nano via #ISP. Pretty simple to be honest. #Arduino #PsNee
Someone used an #ArduinoNano as an #ISP Programmer and got the following Error Message? #PsNee
Sensor Package Aims To Predict Acid Rain

Acid rain sucks, particularly if you run a fancy university with lots of lovely statues outside. If you’d like to try and predict when it’s going to occur, you might like this project f…

Hackaday

TD4 4-bit DIY CPU – Part 8

Now that I’ve shown I could support more ROM if required using a microcontroller (see Part 6) I can start to ponder how that might be possible.

  • Part 1 – Introduction, Discussion and Analysis
  • Part 2 – Building and Hardware
  • Part 3 – Programming and Simple Programs
  • Part 4 – Some hardware enhancements
  • Part 5 – My own PCB version
  • Part 6 – Replacing the ROM with a microcontroller
  • Part 7 – Creating an Arduino “assembler” for the TD4
  • Part 8 – Extending the address space to 5-bits and an Arduino ROM PCB

There are several other expansions to consider too. Other things I’m pondering are:

  • Can I find a way to add the two registers together?
  • Are there options to add another register?
  • Is 4-bit data still enough?
  • Could a 4×4 output grid be supported?
  • Could any extensions be added in a way that is backwards compatible with the existing instructions and behaviours?

And probably a few other odds and ends as I go back and reconsider the schematic as it stands, but they can wait for a future post.

TD4 Simulation

Before I get stuck into the updates, I thought it would be useful to be able to simulate the TD4 to allow for quick turn-around experiments.

I’ve used the “Digital” logic simulator which can be found here: https://github.com/hneemann/Digital

I could have build the simulator from basic logic gates and that would perhaps have been more useful in helping to understand how the design works. But I wanted something that would be easy to fiddle about with to test enhancements, so I build it using the actual 74xx logic chips instead. This doesn’t make for such a readable simulation, as I’ve had to go with actual pinouts for chips rather than logical groupings of signals. But it does map more closely onto the final hardware which is handy for thinking in actual chip-usage rather than abstract logic.

I’ve not bothered simulating the clock circuit, I’ve just wired in a clock source. I’ve also not added the ROM DIP switches, instead adding a ROM element and wiring it into the address and data lines. By right-clicking and viewing the attributes, it is possible to define a 16-byte ROM (4 address, 8 data lines) and edit the contents.

The ROM element takes a multiplexed source and produces a multiplexed output, so I use a splitter/mixer function to turn that into D0-D7 as shown above. Similarly the output of the 74HC161 acting as the program counter (PC) has A0-A3 mixed into a single ADDR bus line.

I’ve added outputs to the two registers to show their contents during execution. I’ve also added a DIP switch on the /RESET line to allow me to start and stop the simulation.

The video below shows it running the above ROM contents, which is the same demo program I used in Part 6 with the microcontroller ROM.

The simulator can be found on GitHub here: https://github.com/diyelectromusic/TD4-CPU

https://makertube.net/w/5njzGmYvqXiU3DLCMMtwqp

Now I have an easier way of experimenting, onto the enhancements.

Increasing the Address Space

The address space is currently implemented as follows:

  • A 4-bit counter register based on a HC161 4-bit synchronous binary counter.
  • A HC154 4 to 16 line decoder/multiplexer for DIP switch selection.
  • A HC540 octal buffer/line driver to buffer (and invert) the data outputs.

The counter auto increments on each clock pulse, thus moving through the address space, but it can also be a destination for the adder, allowing absolute jumps to specific addresses, thus implementing a JMP instruction.

To increase the address space, there are a few considerations:

  • With more than 4 bits how should JMPs work? They will have remain 4-bits unless the data width is increased.
  • Each additional bit of address space will double the number of DIP switches required.
  • The next size of binary counter above 4-bits is typically 8-bits.

One idea is to use the RCO pin of the 161. This is the “ripple carry out” and can be used to cascade counters for greater than 4-bit counting. As I understand things, RCO will be HIGH once all outputs are also HIGH, for a single clock pulse. This can be used to enable a following counter for that pulse. This is shown below (taken from the datasheet).

And this is the sample application, again from the datasheet, showing how it would work, with extensions on to additional stages.

A simple way to add an additional bit of address space might be to feed RCO into a flip-flop acting as a toggle in the configuration shown below.

This can then be used to select between two HC154 4 to 16 decoders. As I already have an unused flip flop as part of the HC74 used for the CARRY, this could be quite an appealing solution and in simulation it does appear to work.

There is one slight complication. As show above, A5 will toggle with A0-A3 = 1111 not as they change back to 0000. This is because the flip-flop toggles on the rising edge of the provided clock signal, which in this case is RCO from the 74HC161. Adding a NOT gate means that the rising edge happens as the 161’s RCO signal drops when it resets back to 0000.

Whilst this solves the sequencing problem it does have the unfortunately side effect that the RESET state means that A5 is 1 on power up. That too could be solved with another NOT gate if required, or simply hanging A5 off the /Q output of the flip-flop rather than the Q output.

Here is the additional wiring, in simulator form, to allow this to work.

Note the addition of A4 which now comes from the spare flip-flop /1Q output, and the linking of RCO via a NOT gate to the flip-flop 1CP clock input. The rest of flip-flop 1 is configured in toggle mode, with /1RD and /1SD both tied high (inactive) and 1D linked to /1Q for the feedback. The non-inverting output 1Q is not used.

Whilst this seems to require an additional logic gate (for the NOT) it turns out that there is a spare Schmidt trigger inverter on the 74HC14 that supports the clock circuit, so that is pretty convenient.

The ROM has also been reconfigured for 5 address inputs with the same 8 data bits, creating a 32 x 8 bit ROM.

There are a few issues with this though:

  • JMP/JNC only work within the same half of the memory, so JMP 4 in the first 16 locations will jump to location address 0x04, but JMP 4 in the second 16 locations will jump to location address 0x14.
  • A JMP 0 in the last location of each half will carry forward into the next half, as the counter ticks over at the same time as the load happens. So JMP 0 in address 0x0F will jump to address 0x10 and JMP 0 in address 0x1F will jump to address 0x00.

But if one can program around those constraints this is quite a simple solution.

An Alternative Solution

There is a neat solution to adding a 5th address bit here: https://xyama.sakura.ne.jp/hp/4bitCPU_TD4.html#memory

This uses the duplicate JMP/JNC instructions to encode a JMP2/JNC2 that results in the 5th address bit being set, this enabling a jump to the second half of the memory.

In order to create the additional address line, there is a second PC register added – i.e. a 5th HC161 counter. As far as I can see the operation is as follows:

  • When the first PC register carries over, the second PC register counts up.
  • As only the first output of the second PC register is used, as it counts that output will simply alternate between 0 and 1.
  • The second PC register can take 1 as an input when the decoded instructions match JMP2 or JNC2 (D5 low, D6 and D7 high, with either D4 or CARRY), forcing A4 on when the first PC register is loaded with the 4-bit jump value, creating a JMP to the second half of the address space.
  • There is an A4 and /A4 signal which alternatively enable the two address decoders for the ROM.
  • This specific circuit uses four HC138 chips rather than two HC154, but the principle of operation is the same – generate one of 32 signals for the ROM from 5 bits of address line.

The modifications to support this are fairly simple and it is neat how it uses redundancy in the instruction set to work, but it does require an additional 74HC161 chip.

Combine the two?

If additional logic can be used to address the second PC in the second solution above, then I’m wondering if that could also be used to deliberately set or reset the flip-flop in the first solution too.

The key will be overriding the flip-flop state to preset A4 if the logic sequence for the spare JNC/JMP instructions turn up. If the /1SD input is active (LOW) then the output will be HIGH. If the /1RD input is active (LOW) then the output will be LOW.

Here is the additional instruction decoding logic – I’m using NAND gates as the NOTs here, so I can just use a single quad NAND gate chip.

So, the truth table for this is as follows:

D4D5D6D7/C/LDPCENA400111011011X0101111001111X00XX00X10XX10X10XX01X10

This corresponds to D7+D6 and either D4 or CARRY and NOT D5 causing the ENA4 signal to be true thus implementing the second JNC and JMP instructions (b1100 and b1101).

Unfortunately, so far, I’ve not been able to figure out an option for driving the flip-flop where the logic pans out to correctly set A0-A3 and A4 to successfully load the PC + flip-flop as required by the new instruction, so I might have to leave that for now.

TD4 Arduino 5-bit Address PCB

At this point I thought I had enough to warrant building a new PCB for a microcontroller memory version of the TD4 with the option to support a 5-bit address bus with the limitations described above.

I took the PCB from Part 5 as the starting point and replaced the ROM logic with an Arduino Nano and added in the flip-flop to create the 5-bit address bus.

The ROM section is replaced with the Arduino as shown below.

The CPU section now uses the spare NOT gate from the PWRCLK section and the spare flip-flop from the CPU section as shown below.

I believe these were the only parts to change. I have included the option to disable the RESET button by cutting a solder jumper and replacing it with a link to an Arduino IO pin.

I’ve also added headers to breakout the unused Arduino IO pins just in case that becomes useful at some point.

The complete Arduino Nano pinout is as follows:

TD4 SignalArduino Nano IOA0-A4A0-A4 (A4 optional)D0-D3D8-D11D4-D7D4-D7/RESETD12 (optional)

The board can be powered either via the Arduinos USB port or via the PCB micro USB port.

Complete Bill Of Materials

ICs:

  • 1x 74HC10 Triple 3-input NAND
  • 1x 74HC14 Hex Schmitt trigger inverters
  • 1x 74HC32 Quad 2-input OR
  • 1x 74HC74 Dual D-Type Flip Flop
  • 2x 74HC153 Dual 4-to-1 selector/multiplexer
  • 4x 74HC161 4-bit binary counter
  • 1x 74HC283 4-bit binary full adder

Semiconductors and Passive Components

  • 25x 3x2mm rectangular LED
  • Resistors: 2x100R; 33x 1K; 1x 3K3; 1x 10K; 1 x 33K; 3x 100K
  • Capacitors: 3x 10uF electrolytic

Other components:

  • 2x SPDT slider switches (see PCB for footprint)
  • 1x micro USB socket (Molex, see PCB for footprint)
  • 2x tactile switches
  • 1x 4-way DIP switches
  • DIP sockets: 7x 16 way; 4x 14 way
  • 2x 15-way pin header sockets

And 1 Arduino Nano of course.

The PCB can be found on Github here: https://github.com/diyelectromusic/TD4-CPU. The video at the end of this post shows it in action.

Nano Assembler Update

I’ve updated my Nano assembler with a new command to change to 5-bit address mode if required.

Help
----
H: Help
L: List
G: Goto
C: Clear
R: Restore
A: Addr Mode
O: Opcodes
OpCode
OpCode im

Current line: b0101 [15]

Address Mode = 5 bit


RAM Disassembly

b00000 [0]: OUT b0001b1010 00010xA1b10000 [10]: OUT b0001b1010 00010xA1
b00001 [1]: ADDA b0001b0000 00010x01b10001 [11]: OUT b0010b1010 00100xA2
b00010 [2]: OUT b0010b1010 00100xA2b10010 [12]: OUT b0100b1010 01000xA4
b00011 [3]: ADDB b0001b0101 00010x51b10011 [13]: OUT b1000b1010 10000xA8
b00100 [4]: OUT b0100b1010 01000xA4b10100 [14]: OUT b0100b1010 01000xA4
b00101 [5]: ADDA b0001b0000 00010x01b10101 [15]: OUT b0100b1010 01000xA4
b00110 [6]: OUT b1000b1010 10000xA8b10110 [16]: OUT b0010b1010 00100xA2
b00111 [7]: ADDB b0001b0101 00010x51b10111 [17]: OUT b0001b1010 00010xA1
b01000 [8]: OUT b0100b1010 01000xA4b11000 [18]: OUT b0001b1010 00010xA1
b01001 [9]: ADDA b0001b0000 00010x01b11001 [19]: OUT b0010b1010 00100xA2
b01010 [A]: OUT b0010b1010 00100xA2b11010 [1A]: OUT b0100b1010 01000xA4
b01011 [B]: ADDB b0001b0101 00010x51b11011 [1B]: OUT b1000b1010 10000xA8
b01100 [C]: OUT b0001b1010 00010xA1b11100 [1C]: OUT b1000b1010 10000xA8
b01101 [D]: ADDA b0000b0000 00000x00b11101 [1D]: OUT b0100b1010 01000xA4
b01110 [E]: OUT b1111b1010 11110xAFb11110 [1E]: OUT b0010b1010 00100xA2
b01111 [F]: ADDA b0000b0000 00000x00b11111 [1F]: OUT b0001b1010 00010xA1
Current line: b10101 [15]

When in 4-bit mode (the default) it will continue to act as previously, wrapping the address around between 0 and 15. But when it switches to 5-bit mode it will now wrap between 0 and 31 and the list function will show the whole 32 bytes of RAM/ROM side by side as show above.

The updated sketch is available on GitHub here.

Conclusion

I was hopeful I could add a 5th address line just using the spare components in the circuit and not adding to the chip count, and that is kind of possible as long as I’m ok with the limitations of the JMPs.

Building all this onto a PCB will make further programming experiments quite a lot easier.

But the next step is to see if the instruction set can be expanded. I am still in search of that illusive two-register add.

Kevin

https://makertube.net/w/fAp8ZsbPLUYEKiStc34J9o

#arduinoNano #pcb #TD4

Arduino and AY-3-8910 – Part 5

My next bit of messing around with Arduno and AY-3-8910 takes my AY-3-8910 Experimenter PCB Design and adds some simple MIDI reception to create a 12-channel AY-3-8910 tone module.

https://makertube.net/w/hLo4HLYcQkcGvf8N9XzgCS

Warning! I strongly recommend using old or second hand equipment for your experiments.  I am not responsible for any damage to expensive instruments!

These are the key tutorials for the main concepts used in this project:

If you are new to Arduino, see the Getting Started pages.

Parts list

The Code

This is taking a combination of the following previous projects:

I had the option of assigning unique MIDI channels to each of the 12 channels of the quad AY-3-8910s, but instead opted for a system that listens on all MIDI channels but assigns incoming notes to the next free channel.

If there are no spare channels, the notes are ignored.

I’ve included an option to respond to velocity, by translating a MIDI velocity value (0 to 127) into a AY-3-8910 amplitude level (0 to 15). But for now, I’m using it with a fixed velocity.

In order to map a polyphonic note index onto a chip and channel, I use the following:

void ayNoteOn (int chan, int pitch, int vel) {
int ay = chan / 3;
int ch = chan % 3;
aySetFreq (ay, ch, pitch, vel);
}

The aySetFreq() function takes a MIDI nonte number and turns it into a course an fine frequency value for programming into the AY-3-8910.

void aySetFreq (int ay, int ch, int note, int vel) {
int vol = vel >> 3;
uint16_t freq = 0;
if (note != 0) {
freq = pgm_read_word(&Notes[note-NOTE_START]);
}

switch (ch) {
case 0:
ayFastWrite (ay, AY38910Regs::A_TONE_C, freq >> 8);
ayFastWrite (ay, AY38910Regs::A_TONE_F, freq & 0x0FF);
ayFastWrite (ay, AY38910Regs::A_AMP, vol);
break;
}
}

Additional case statements are provided for channels 1 (B) and 2 (C). The Notes array is the list of frequencies calculated for a 1MHz clock using the equation provided in the data sheet:

  • Freq (tone) = Freq (clock) / (16 TP)

Where TP is the 12-bit value placed in the course and fine frequency registers. So turning this around and plugging in the frequencies for MIDI notes, we can figure out the 12-bit values required to be programmed into the registers.

In the end, I cheated and used the table already provided here: https://github.com/Andy4495/AY3891x/blob/main/src/AY3891x_sounds.h

This covers all notes from C0 (MIDI 12) to B8 (MIDI 119).

I should also note that I’ve now removed all of the original AY3891x library and am using my own fast-access routines now tailored for supporting four devices.

As I’m using port IO though, this does mean there is a fair bit of hardcoded assumptions about Arduino PORT usage and GPIO pins.

Find it on GitHub here.

Closing Thoughts

The video shows my, now, go-to test of anything linked to Arduinos and tones – a 12-channel arrangement of the end titles of Star Wars Episode IV – A New Hope.

As the code will select the next free channel for incoming notes, sometimes consecutive notes sound slightly different due, presumably, to differences in the output channels of the devices. Something to look at, at some point.

It would also be useful to have a “multi-track” version where each channel is an independent MIDI channel in its own right, but for now, using OMNI and “next free channel” is fine.

I have to say, when the theme really gets going with those vintage 8-bit tone sounds, I could be sitting back in that 80s Star Wars vector graphics video arcade machine… (although apparently that used several Atari POKEY chips, not AY-3-891x- shame. I wonder if you can get hold of those too…)

“The force will be with you. Always.”

Kevin

#arduinoNano #ay38910 #midi #tone

AY-3-8910 Experimenter PCB Design

Following on from my Arduino and AY-3-8910 experiments, one thing I wanted to do was to try to hook up several AY-3-8910 devices and see if I could stack up the polyphony a little. But that is a lo…

Simple DIY Electronic Music Projects

AY-3-8910 Experimenter PCB Build Guide

Here are the build notes for my AY-3-8910 Experimenter PCB Design.

https://makertube.net/w/fULfpG9LNwpb3iCfavVkAp

Warning! I strongly recommend using old or second hand equipment for your experiments.  I am not responsible for any damage to expensive instruments!

If you are new to electronics and microcontrollers, see the Getting Started pages.

Bill of Materials

  • AY-3-8910 Experimenter PCB (GitHub link below)
  • Arduino Nano
  • Up to 4x AY-3-8910 40-pin DIP devices (see notes here on obtaining devices: Arduino and AY-3-8910)
  • 1x 6N138 optoisolator
  • 1x 1N4148 or 1N914 signal diode
  • Resistors: 4x 220Ω, 1x 4K7, 14x 1K
  • 6x 100nF ceramic capacitors
  • 2x 1uF electrolytic capacitors (the PCB has 220uF on the sinkscreen)
  • 1x 100uF electrolytic capacitor
  • Either: 3x 3.5mm TRS PCB mount sockets
  • Or: 1x 3.5mm TRS PCB mount sockets and 2x 180 DIN PCB mount sockets
  • 1x 2.1mm barrel jack socket
  • 2x 15-way pin header sockets
  • 4x 40-way wide DIP sockets
  • Pin headers
  • Optional: 1x SPDT, 1x DPDT both with 2.54mm pitch connectors
  • Optional: 1x 8-way DIP socket

Build Steps

Taking a typical “low to high” soldering approach, this is the suggested order of assembly:

  • All resistors and diode.
  • DIP and TRS socket(s).
  • Disc capacitors.
  • Switches (if used).
  • Electrolytic capacitors.
  • 15-way pin header sockets.
  • Barrel jack socket.
  • DIN sockets (if used).

It is necessary to add two additional 1K resistors as patch-links on the underside of the board. Details below.

Here are some build photos.

The DIP sockets should go on next before the TRS sockets.

Pin headers and jumpers could be used for the MIDI on/off switch. The power switch could be bypassed with a wire link if not required.

There are a number of optional pin header breakouts: power, UART, additional IO and all the IO for the four AY-3-8910 chips. For this build I’m not populating those.

Errata Fixes

As mentioned in the design notes, two additional resistors must be added to pull the audio outputs to GND as part of the output/mixer circuit. I used two additional 1K resistors.

These can be added to the underside of the board as shown below.

Testing

I recommend performing the general tests described here: PCBs.

Once everything appears electrically good, here is a test application that will play a chord on each of the devices at a different octave. If this works it should be possible to hear all 12 notes in the four chords across four octaves sounding.

Find the code here: https://github.com/diyelectromusic/sdemp/tree/main/src/SDEMP/ArduinoAY38910QuadTest

PCB Errata

As already mentioned there are the following issues with this PCB:

  • The two 220uF capacitors should be replaced with 1uF capacitors.
  • Two additional resistors need to be patched into the audio output circuit.

Enhancements:

  •  None

Find it on GitHub here.

Sample Applications

Here are some applications to get started with:

  •  (on their way)

Closing Thoughts

It took quite a long time to realise the issue with the output channels. For ages, it appeared that the interface to the chip just wasn’t functioning correctly. With hindsight, some kind of register read/write test would have confirmed that a lot earlier.

It was only when going back to the schematics of other designs and recognising that the output was always HIGH did the penny drop that the additional resistor was required. Then there was some experimentation to find something that would work with my board and not cause issues in use.

But it seems like I got there in the end. Now I can get on with doing something a little more interesting MIDI and music wise.

Kevin

#arduinoNano #ay38910 #pcb