I have a silly / fun project I am working on which is to make a patch pin matrix with an Arduino, akin to an old analogue computer interface or the EMS Synthi A. I doubt I am the first to do this!
I am using a Due because I have one to hand, but it is totally overkill for the project in its current state (I’m wondering if I can use USB OTG to control some more contemporary synths at some point, but that is a while away), and yes I know it has more pins than you could shake a stick at, but I want to minimise the pin use with a pair of shift registers. The concept is the same as creating a matrix to read from a keypad.
I’m using a CMOS CD4094 as a serial in - parallel out interface and a CD4014 as a parallel in - serial out interface.
I use an array of 8-bit numbers called matrix[8] to store “patches” in the matrix. The CD4094 is meant to scroll through the rows of the matrix (outputs), a single bit is inserted into the first stage of the CD4094 register with a rising clock. Then the CD4014 is put into parallel mode with the parallel inputs linked to the columns of the matrix (inputs). If a patch is present in say X0, Y4 then stage 4 of the register should go high after a rising clock. The CD4014 is then switched to serial mode and clocked through, bitWrite() is used to activate a bit on the associated 8-bit number in the matrix array. The CD4094 is clocked so the active bit is shifted to the next stage and the process is repeated.
The CD4094 is working solidly and as I would expect. The CD4014 is about half way there, it always registers an active bit in the correct place, but sometimes an active bit appears on the stage before and sometimes after at the same time - I’m not particularly sure why this is, my guesses:
the CD4014 datasheet says the clock frequency should be at about 8Mhz, the Due is processing at 84MHz, is it just too fast?
there is maybe some parasitic stuff going on between stages, maybe pull-down resistors would be a good idea?
In general, any tips on improving the code would be welcome - please feel free to try it out, I’d love to hear ideas on using a patchable matrix in projects as well I want to turn it into a library eventually but need to learn how to do that, and I would also like to make a basic PCB for testing (right now I am using wire on breadboard, it’s not quite the same!)
n.b. sketch made in Platform.io so would need some minor tweaks to run in Arduino IDE - remove <Arduino.h> and make sure comments work correctly. You don’t need a Due for this sketch at all, any simple board will do!
/*
Virtual Patch Matrix version 3
This version adds two shift registers to reduce the number of digital pins
required for the patch matrix, a CD4094 and a CD4014. Built on the Arduino
Due.
Datasheets:
http://midondesign.com/Documents/4094BC.PDF
http://uk.farnell.com/texas-instruments/cd4014be/logic-static-shft-reg-8stg-16dip/dp/1740086
Design by Aidan Taylor, for fun!
Electric Noodle Box 2018
Version Date: 30/01/18
*/
#include <Arduino.h>
// CMOS IO
uint8_t clock94 = 2; // CD4094 Clock Pin
uint8_t data94 = 3; // CD4094 Data Pin
uint8_t test94 = 4; // optional to test the data out of the CD4094 (QS)
uint8_t clock14 = 5; // CD4014 Clock pin
uint8_t serial14 = 6; // CD4014 Q8 serial out pin
uint8_t mode14 = 7; // Switch 4014 to Serial mode to read register
// Test Parameters
bool print94; // used for testing the CD4094 Output
bool read14;
// Main Variables
uint8_t matrix[8];
uint8_t columns = 8;
uint8_t rows = 8;
void setup() {
pinMode(clock94, OUTPUT);
pinMode(data94, OUTPUT);
pinMode(test94, INPUT);
pinMode(clock14, OUTPUT);
pinMode(serial14, INPUT);
pinMode(mode14, OUTPUT);
Serial.begin(115200);
}
void printBits(uint8_t myByte) {
for(uint8_t mask = 0x80; mask; mask >>= 1) {
if(mask & myByte)
Serial.print('1');
else
Serial.print('0');
}
}
void matrixRead() {
// Step through each row and read each column to test for a patch
for(uint8_t x = 0; x < rows; x++) {
if(x == 0) {
// Make the first bit active in the 4094 register
digitalWrite(clock94, LOW);
digitalWrite(data94, HIGH);
digitalWrite(clock94, HIGH);
digitalWrite(data94, LOW);
}
else {
digitalWrite(clock94, LOW);
digitalWrite(clock94, HIGH);
}
for(uint8_t y = 0; y < columns; y++) {
if(y == 0) {
digitalWrite(mode14, HIGH);
digitalWrite(clock14, LOW);
digitalWrite(clock14, HIGH);
digitalWrite(mode14, LOW);
}
else {
digitalWrite(clock14, LOW);
digitalWrite(clock14, HIGH);
}
delay(1);
read14 = digitalRead(serial14);
if(read14) {
bitWrite(matrix[x], y, 1);
Serial.print("connection on row = ");
Serial.print(x);
Serial.print(" ");
Serial.print("column = ");
Serial.println(y);
}
else {
bitWrite(matrix[x], y, 0);
}
}
/*
// Test the 4094 serial output on last register bit
print94 = digitalRead(test94);
Serial.print("row = ");
Serial.print(x);
Serial.print(" ");
Serial.println(print94);
*/
}
}
void loop() {
matrixRead();
for(uint8_t i = 0; i < 8; i++) {
printBits(matrix[i]);
Serial.println(" ");
}
delay(1000);
}