Fast prototyping

Arduino-based rotary encoder board, part 2.

More doodling. I’m impossibly enmired in real life at the moment, but I’ve got time to look up data sheets on my phone. Remember that the two different kinds of shift register used here are designated Serial-In Parallel-Out (SIPO) and Parallel-In Serial-Out (PISO). The SIPO register is used for bank control and the PISO registers are used for data capture from the rotary encoders.

Connections I need to make between the Arduino and the 74HC595 SIPO register:

A line to pin 14 SER. This holds the new value to be shifted into the right of the register.
A line to pin 11 SRCLK. This is the clock line and should go high long enough to complete the shift operation whenever we want to switch to the next bank of rotary encoders.

Pins that need to be tied in place.

Pin 10 (~SRCLR) must be tied high. We never want to clear the register.
Pin 12 (RCLK) must be tied to pin 11 (SRCLK) for this kind of operation. The effect is that the storage register lags one clock cycle behind the shift register, but the important thing is that it follows the shift register faithfully and feeds the parallel output pins.
Pin 13 (~OE) must be tied low. We always want the outputs to be available.

Other connections.

Pin 16 needs +5V power.
Pin 8 needs earth.
100nF capacitor across 16 and 8.

For each active bank of rotary encoders, one of the 8 output pins A-H (pins 15 and 1-7) must lead to the SH/LD of the corresponding 74HC165 PISO register(s). When this leg is low the PISO is in load mode and signals from any rotary encoder leg connected to one of its 8 parallel inputs go into the register. When it goes high the value is frozen and the PISO register goes into shift mode so it can deliver a snapshot of the encoder legs to the Arduino.

So that’s the bank control logic. This design needs two digital output pins from the Arduino.

Edit: If I switch to using SPI for bank control as well as data acquisition, I may be able to share pins between the two functions and end up using only the three SPI pins plus possibly one more digital output. It all depends on how cleverly I can design this.

1 Like

Arduino-based rotary encoder board, part 3.

Continuing my blue sky project to run up to 64 rotary encoders from a single Arduino Nano.

Design of the data acquisition logic using 74HC165 PISO registers.

Another doodle. I’m away from my bedroom workshop so this is all vapourware, no construction or testing as yet.

The 165 has a clock inhibit pin which I can tie together and feed from a slave select line. The idea here is that when clock inhibit is held high the data acquisition cycle is paused so the microcontroller can use SPI for bank selection. A NAND gate can take this signal, NAND it with the SPI clock from the microcontroller, send the result through a NOT to restore the clock phase, and send the result to the RSCLK and RCLK pins in the bank selection chip (see my previous doodle on this thread). This fulfills my ambition of using just the SPI pins plus a single digital output (the slave select signal) to control both bank selection and data acquisition. I’ll explain this in more detail later when I’m able to provide breadboard photographs or schematics and, most important, signal timing plots.

Data acquisition.

The data acquisition cycle is pretty simple really. While SH/LD is held low the PISO is open to signal levels from the legs of the corresponding rotary encoder. When the bank selection logic pulls it high a snapshot of this data is frozen in the PISO and the SPI clock signals from the microcontroller pump data one bit at a time back to the SPI MISO line of the microcontroller. This mechanism is paused when the microcontroller holds the clock inhibit pin high, triggering the bank selection mechanism described above.

Accommodating up to 64 rotary encoders.

In the refinement I mentioned earlier on this thread, for each bank I will have three PISO registers daisy chained together forming a single 24-bit shift register which enables data to be acquired from all three pins of eight separate EC11 rotary encoders. Thus the software for data acquisition will input the entire state of the bank in 24 SPI clock cycles. The bank selection logic will move on to the next bank of rotary encoders giving a total capacity of 8 banks of 8 EC11 encoders in just 200 SPI clock cycles (192 data acquisition cycles and 8 bank selection cycles).

And possibly even more than 64.

Subject to the power of the microcontroller, 2 or more bank selection registers can be daisy chained together enabling many more rotary encoders to be accommodated simply by cloning the circuit described.

2 Likes

Arduino-based rotary encoder board, part 4.

On the software side, I’m going to skip the details of controlling the SPI and move on to some blue sky thinking about how I hope to program this beastie.

Typically a MIDI controller like this could be remotely programmed using Sysex messages. We’ve seen an example of this on the forum recently, with the Yamaha TX81Z.

There ought to be a default value for each encoder, though, and this should be compliant with something like Mackie Control or HUI. This would make it interoperable with a wide range of DAW software.

3 Likes

Arduino-based rotary encoder board, part 5.

Another blue sky doodle, this time about the Arduino Nano. It’s functionally identical to the Uno shown in my photograph, maybe a couple more analogue inputs.

Controllers as appliances.

A MIDI controller is an appliance, which means the expectation is that you can just pick it up and use it, then next time you pick it up you just continue as before. It remembers what you did to it. To fit this kind of profile the controller should have persistence. If you tell it send a certain MIDI sequence when you press a certain button, it should not need to be told again the next time you switch it on.

Many MIDI controllers go further, providing multiple presets each with a different personality. Preset 1 could be set up for using your DAW, preset 2 for controlling the parameters of your synth, and so on. This requires more memory.

While the controller should provide a mechanism to dump and load parameters over MIDI, it’s much more practical to support a reasonable number of presets so the controller doesn’t need to be attached to a computer just to switch from one task to another.

Using EEPROM for data storage.

Both Uno and Nano come with 1KiB of EEPROM which can be programmed by your application to store a limited quantity of persistent data. If you provide 8 presets just 128 bytes maximum are available for each preset.

Using flash memory for data storage.

One great feature of the 8-bit AVR family of microcontrollers featured on Arduino boards is self-programmability. If you need to store persistent data on an Uno or Nano and your data volume is bigger than the limited 1KiB EEPROM provided, you can program your data into the Flash memory. As both boards come with 32KiB of flash there’s usually more than enough room for storing MIDI settings and parameters. This is true if you’re using the C++ -based Arduino environment, and even more so if you’re using compact assembly code. This can be updated in real time and it’s fairly straightforward.

The Arduino boot loader is protected from being overwritten by application code so it’s relatively safe even if you don’t have an In-System Programmer (ISP.) Even so, if you’re using Arduinos a lot you can get an ISP or, if necessary, improvise one using a second Arduino.

4 Likes

Arduino-based rotary encoder board, part 6.

Timing and MPU loading considerations.

I posted an errata here yesterday but it was wrong so I deleted it. The rough calculation of the number of SPI clock cycles required is correct. It’s equivalent to about 200 SPI clock cycles or 25 SPI byte transfers for 8 banks of 8 rotary encoders each with a built-in momentary push button.

As SPI can run at frequencies on the order of 1MHz on Arduino Nano the limiting factors here are the capabilities of the external hardware design and the ability of the microcontroller to handle the data rate required to accurately scan the rotary controller states. I’ve estimated the latter to be of the order 1,000 scans per second for 64 rotary encoders, which leaves many CPU cycles free to process each scan. The loading scales linearly for more encoders, so for 128 encoders you’d duplicate the hardware and the data transfer rate would double placing twice the load on the processing code. In practice it would make more sense to add a second Nano or use Mega2560 or a Teensy since the bulk of the cost by far would be encoders and shift registers.

I’ll soon be in a position to estimate whether the Nano is up to my expectations for this project. First, let’s work out how the scanning and decoding process would work (next doodle.)

3 Likes

Arduino-based rotary encoder board, part 7.

Here I finally get to writing pseudocode describing what needs to be done by the microcontroller software. For those unfamiliar, this is a form of structured English intended to be easy to convert to actual code, without getting too bogged down in the details of a real programming language. The sentences in parentheses are comments explaining the code in more conventional English.

First draught of processing code.

Initialisation.

(In the Arduino environment this would be
  executed in the setup method.)
Switch Slave Select pin to
  bank selection mode.
Do twice:
    (Do this twice to ensure that both the
    shift register and the storage register of
    the 74HC595 are primed with the 8 bit
    data pattern. At least 9 SPI clock cycles
    are required.)
    Put 00000001 binary into the SPI data register.
    Perform SPI byte exchange cycle.

More to come.

2 Likes

Arduino-based rotary encoder board, part 8.

I post on a mobile phone so if there are serious formatting problems with your computer or phone or tablet please let me know in a post below.

I’m writing this as a sequential polling algorithm for the sake of clarity and simplicity. In practice much of this work might be performed inside interrupt servicing routines (ISRs) such as the one that can be fired off on completion of a SPI byte transfer/exchange on the AVR family.

The rest of the code.

(On the Arduino platform this would be
  performed repeatedly from inside the loop
  method)
(1. Get a bank worth of SPI input.)
Switch Slave Select pin to
  data acquisition mode.
Do three times:
    Perform an SPI byte exchange cycle.
Get the previous status of the 8 encoders in 
  this bank.

(2. Interpret the incoming data.)
For each encoder e:
    Get the two incoming pin values.
    From the previous status of e and the
      values of the incoming pin values,
      look up the new status of e in the state 
      table and update it if necessary.
    Get the incoming push button value and
      filter it through a software debounce.
    Perform any necessary action based on the
    status of e and the current button value.

(3. Move to the next bank of 8 rotary encoders.)
Switch Slave Select pin to
  bank selection mode.
(This is to update the bank selection register
  so that the 1 will be in the correct place for
  the next bank.)
Write 0 or 1 to the SDA output pin.
Write a clock pulse to the SCK to make the
  bank selection register (74HC595) shift and 
  acquire the new value.
3 Likes

Arduino-based rotary encoder board, part 9.

Surely it can’t be that simple. Where does all the clever MIDI stuff happen?

I’m writing this for people who aren’t that familiar with software engineering practice. The “clever MIDI stuff” isn’t in the code I’ve written because it doesn’t need to be our concern at this point. As far as the code I’ve written up to now is concerned, our eventual task could be measuring the progress of an AT-AT or appreciating C-Beams glittering in the dark near the Tannhäuser Gate. All it’s doing is monitoring external stimuli and sending appropriate internal signals onwards.

So the statement “[p]erform any necessary action based on the status of [the encoder] and the current button value” is where the sexy MIDI stuff starts happening. But I’ve got enough for now. I really do have to start wiring test circuits and writing test code and looking at oscilloscope traces to see if my design needs to be refined.

It’s hard for me to predict when I can get through that step. My life is too unpredictable and stressful for me to know when I’ll have enough time and energy to move onwards. Maybe later this morning, maybe next week. We’ll see.

4 Likes

Mackie protocols documentation.

This is a Wiki. You can edit it.

I’ve been looking for information about HUI and Mackie Control Universal (MCU), but they’re both closed protocols which means there’s no published standards document. Presumably their in-house documentation is available subject to signing an NDA.

A few people have tried reverse engineering them. Here is a selection. All links below refer to MCU unless stated otherwise. Perhaps the most useful ones are those that map the protocol to an open standard such as OSC.

Nicolas Jarnoux in French and English:

Martin Zuther in Python:

Michael Krone in C++ for Teensy:

theageman in English, HUI protocol:

Matthewmx86 in Python, HUI protocol:

Arduino-based rotary encoder board, part 10.

Simplified bank selection logic.

I knew there was a sequential counter chip but couldn’t remember the name and thought it must be out of production. Then it shows up in a sequencer circuit on this forum. Of course what I need is a 4017 decade counter. Each time it gets a bank selection clock pulse the decade counter advances to the next pin, selecting the next bank. This is much easier than using the SIPO register.

3 Likes

I’m hoping to get back to this soon. My 4017 decade counters have arrived, so hurray it appears I may have made all my 74HC595 SIPO shift registers redundant. Just as well to have more than one path to the goal in case the others don’t work out, I suppose.

Test schedule

This takes us up from monitoring a single rotary encoder up to reading a bank of 8 using SPI. No bank selection logic yet.

Test 1: verify that the rotary encoders work as expected by driving them using a conventional Arduino library designed for the purpose.

Test 2: verify that the PISO registers are electrically sound by capturing logic levels (a breadboard wire from either ground or +vcc to each of the 8 input pins) and clocking them out into the SPI port.

Test 3: Replace the 8 wires in test 2 with the 2 state pins of each of four rotary encoders, ignoring the push button. Confirm capture of encoder state by moving the encoders while monitoring the pin states.

Test 4: combine the state machine from test 1 with the code from test 3, verifying that we can reliably read every movement of the four encoders.

Test 5: Daisy chain two PISO registers together and verify that it’s possible to capture the positions of 8 encoders in the same way by using SPI to clock in the expanded shift register that results.

If I get as far as that I’ll be very pleased.

3 Likes

One month later, still no progress. But at least I found my Arduino Mega 2560 board so I’m running out of excuses.

Meanwhile I found this synth module producer who works with large format modules (4U) and banana jacks. It’s encouraging.

4 Likes

I’ve got a lovely set of Bela Trill touch-sensitive capacitive sensors, some of which are rings. So the idea is that you have a multitouch linear array in the form of a ring approximately 5cm in diameter.

One really great idea is to visually track the touch points using a slightly larger ring of addressable RGB LEDs. As it happens you can buy such a ring quite cheaply. Maybe one day I’ll try this out.

Is anybody else trying this? I’d be really happy to hear about your work.

5 Likes

I was waiting to see what you did with them!
@Bitnik

3 Likes

Sadly not much. I can come up with ideas but I currently don’t have the energy to do much beyond write.

The sensors are pretty versatile so there’s a lot of scope for visual feedback.

Here are a couple of photos demonstrating the basic principle. The Trill Ring goes inside the circumference of the Neopixel Ring. The Grove connector on the Trill carries I2C signals recording touches on the surface of the sensor.

Top side:

Bottom side:

Additionally, the centre of the Trill Ring can hold an arcade button which can be connected to the Trill sensor. The Neopixel ring has a built-in driver that controls the 24 individually addressable RGB LEDs which can give visual feedback.

3 Likes

Now make the ring clickable and you have (re-)invented the iPod main control :slight_smile:

2 Likes

Yes, it’s rather like that. Did the iPod controller have multitouch? If so, uncannily similar. This does suggest to me that a good possible configuration may be as a handheld with the thumb doing the selection. That worked for Apple and it’s very similar to the way many people use the touch sensitive screens in their smartphones.

1 Like

I had one of the first ipod’s with a clickable ring and it didn’t have multitouch.
But maybe later models did, I don’t know.

2 Likes

No multitouch until the iPhone, so no.

1 Like