Simple DIY Electronic Music Projects<p>This is another variant of my <a href="https://diyelectromusic.com/2024/10/04/arduino-euclidean-gate-sequencer/" rel="nofollow noopener noreferrer" target="_blank">Arduino Euclidean Gate Sequencer</a> this time using a rotary encoder and I2C display rather than a potentiometer for control.</p><ul><li><a href="https://diyelectromusic.com/2024/10/04/arduino-euclidean-gate-sequencer/" rel="nofollow noopener noreferrer" target="_blank">Part 1</a> covered all the theory and main functions of the code.</li><li><a href="https://diyelectromusic.com/2024/10/07/arduino-euclidean-gate-sequencer-part-2/" rel="nofollow noopener noreferrer" target="_blank">Part 2</a> included some hardware suggestions for connecting it to other devices.</li><li><a href="https://diyelectromusic.com/2024/10/27/arduino-euclidean-gate-sequencer-part-3/" rel="nofollow noopener noreferrer" target="_blank">Part 3</a> added a rotary encoder and I2C display and demonstrated by <a href="https://diyelectromusic.com/2024/10/27/arduino-clock-generator-shield-pcb/" rel="nofollow noopener noreferrer" target="_blank">Arduino Clock Generator Shield PCB</a>.</li><li><a href="https://diyelectromusic.com/2024/10/28/arduino-euclidean-gate-sequencer-part-4/" rel="nofollow noopener noreferrer" target="_blank">Part 4</a> reimplements HAGIWO’s original with a few tweaks and updates.</li></ul><p><a href="https://makertube.net/w/s1cMmrCzW7tGm16NQQKH9w" rel="nofollow noopener noreferrer" target="_blank">https://makertube.net/w/s1cMmrCzW7tGm16NQQKH9w</a></p><p><em><strong>Warning!</strong> I strongly recommend using old or second hand equipment for your experiments. I am not responsible for any damage to expensive instruments!</em></p><p>If you are new to Arduino, see the <a href="https://diyelectromusic.wordpress.com/getting-started/" rel="nofollow noopener noreferrer" target="_blank">Getting Started</a> pages.</p><p><strong>Parts List</strong></p><ul><li>Arduino Uno.</li><li>Switched Rotary Encoder – either a KY-040 module or an unmounted encoder.</li><li>128×64 OLED I2C SSD1306 display.</li><li>Optional: LEDs and associated (e.g. 220Ω or 1K) resistors.</li><li>Breadboard and jumper wires.</li></ul><p><strong>The Circuit</strong></p><p>The above diagram shows how to connect two variants of rotary encoder. On the left is a common KY-040 switched encoder module. On the right is a common switched encoder directly connected to solderless breadboard. Only one encoder should be connected to D4, D5 with the switch on D6.</p><p>Note if it turns out the encoder is incrementing/decrementing values in the opposite way to what is expected, then usually the simplest thing to do is swap the IO pin assignments for the A and B connections in the code.</p><p>The diagram also shows how to connect a 128×64 I2C OLED display. These are the very common SSD1306 based displays. Note that the pinouts on these can vary with GND/VCC swapped or SCL/SDA swapped, but they must be connected to 5V, GND and A4 (SDA) and A5 (SCL).</p><p>The clock generator outputs are on D8-D13. I’ve not added an LED to D13 as it is wired to the internal LED, but that can be added too if required.</p><p>I’ve put together an <a href="https://diyelectromusic.com/2024/10/27/arduino-clock-generator-shield-pcb/" rel="nofollow noopener noreferrer" target="_blank">Arduino Clock Generator Shield PCB</a> which includes buffered outputs, a rotary encoder and I2C display connections.</p><p><strong>The Code</strong></p><p>This expands on the original code that is fully described in <a href="https://diyelectromusic.com/2024/10/04/arduino-euclidean-gate-sequencer/" rel="nofollow noopener noreferrer" target="_blank">part 1 here</a>.</p><p>There are two main threads of code as follows:</p><ul><li>10mS “tick” interrupt routine to ensure accurate GATE timings.</li><li>Back “loop” handling the encoder and display.</li></ul><p>In order to ensure a responsive encoder the display is only updated when something actually needs to change.</p><p>Once again I’ve opted for Matthias Hertel’s simple RotaryEncoder library which can be found here: <a href="https://github.com/mathertel/RotaryEncoder" rel="nofollow noopener noreferrer" target="_blank">https://github.com/mathertel/RotaryEncoder</a>. A detailed explanation of how it works <a href="https://www.mathertel.de/Arduino/RotaryEncoderLibrary.aspx" rel="nofollow noopener noreferrer" target="_blank">can be found here</a>. I’ve found this seems to work best for me for the cheap encoders I tend to buy. One the correct encoder type has been found I’ve found this to be very reliable, especially when simply polling IO pins for an encoder. There is a little more on the rationale for choosing this library in a previous project here: <a href="https://diyelectromusic.com/2021/09/28/arduino-midi-rotary-encoder-controller/" rel="nofollow noopener noreferrer" target="_blank">Arduino MIDI Rotary Encoder Controller</a>.</p><p>For the I2C display, I’m using the SSD1306 implementation of the Adafruit GFX library which can be found here:</p><ul><li><a href="https://github.com/adafruit/Adafruit_SSD1306" rel="nofollow noopener noreferrer" target="_blank">https://github.com/adafruit/Adafruit_SSD1306</a></li><li><a href="https://github.com/adafruit/Adafruit-GFX-Library" rel="nofollow noopener noreferrer" target="_blank">https://github.com/adafruit/Adafruit-GFX-Library</a></li></ul><p>All of these should be installable from the Arduino Library Manager.</p><p>The core principles of operation are as follows:</p><ul><li>The display will show the tempo in beats per minute and which pattern is used for each of the 6 GATE outputs.</li><li>Clicking the encoder will change the focus between tempo and any of the six GATEs allowing them to be changed.</li><li>Note: although the tempo is in bpm the number of GATE pulses is actually running at 4 pulses per beat. This means that every 16-pulse sequence, regardless of pattern, will take 4 beats in time to run through.</li></ul><p>This is the display I have. I’ve used a larger font for the tempo and underlining to show the active focus of the interface.</p><p>The display is managed by having lists of the coordinate points for “cursor” which map what I’ve used for positioning the text.</p><pre>int cursor_x[GATES+1] = {10,30,50,70,90,110,20};<br>int cursor_y[GATES+1] = {60,60,60,60,60,60,35};<br>int cursor_l[GATES+1] = {12,12,12,12,12,12,54};<br><br>display.setTextSize(3);<br>display.setCursor(20,10);<br>display.print(tempo);<br><br>display.setTextSize(1);<br>for (int i=0; i<GATES ; i++) {<br> display.setCursor(10+20*i,50);<br> display.print(gatePatterns[i]);<br>}<br><br>display.writeFastHLine(cursor_x[uiFocus], cursor_y[uiFocus], cursor_l[uiFocus], WHITE);</pre><p>Then when the encoder triggers a change, the main interface code essentially runs the following algorithm:</p><pre>IF encoder signals UP THEN<br> IF focus is tempo THEN<br> Increment the tempo<br> ELSE<br> Increment the selected GATE pattern<br>ELSE IF encoder signals DOWN THEN<br> IF focus is tempo THEN<br> Decrement the tempo<br> ELSE<br> Decrement the selected GATE pattern<br><br>IF encoder switch is pressed<br> Move focus on between GATES or over to tempo</pre><p>I did wonder if the encoder should be polled in its own timer-driver routine. For performance, many people might enable hardware pin interrupts, but these are only available on pins 2 and 3 on an ATMega328. But as the interface loop is essentially not doing much else, it will poll the encoder pretty quickly (at least compared to the speed a person can turn it) and performance is further enhanced by only writing out to the display if something has actually changed.</p><p>There are three <a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://diyelectromusic.com/tag/defines/" target="_blank">#defines</a> for the encoder IO pins. If the encoder seems to be doing the opposite to what is expected, just swap over the pins for ENC_A and ENC_B.</p><pre>#define ENC_A 4<br>#define ENC_B 5<br>#define ENC_SW 6</pre><p>The display is assumed to have an I2C address of 0x3C but that can be changed. It is also built for a 128×64 display but a 128×32 display could also be used if the coordinates for the text and cursors mentioned previously are changed accordingly.</p><pre>#define OLED_ADDR 0x3C<br>#define OLED_W 128<br>#define OLED_H 64</pre><p>There are two sets of IO pin definitions in the code. One provides a consecutive set of GATES on D8-D13 and one uses D2,D3,D10-D13 to match the requirements of my <a href="https://diyelectromusic.com/2024/10/27/arduino-clock-generator-shield-pcb/" rel="nofollow noopener noreferrer" target="_blank">Arduino Clock Generator Shield PCB</a>.</p><pre>int gatePins[GATES] = {13,12,11,10,3,2}; // PCB variant<br>int gatePins[GATES] = {13,12,11,10,9,8}; // Consecutive pins </pre><p><a href="https://github.com/diyelectromusic/sdemp/tree/main/src/SDEMP/ArduinoEuclideanClockGen2" rel="nofollow noopener noreferrer" target="_blank">Find it on GitHub here</a>.</p><p><strong>Closing Thoughts</strong></p><p>The video shows my <a href="https://diyelectromusic.com/2024/10/27/arduino-clock-generator-shield-pcb/" rel="nofollow noopener noreferrer" target="_blank">Arduino Clock Generator Shield PCB</a> running the above code, driving my <a href="https://diyelectromusic.com/2024/10/27/arduino-drum-trigger-to-midi-shield-pcb/" rel="nofollow noopener noreferrer" target="_blank">Arduino Drum Trigger to MIDI Shield PCB</a> which is hooked up to a Roland TR-505.</p><p>The only change required is for the GATE pins, which are slightly different for the PCB.</p><p>Kevin</p><p><a href="https://diyelectromusic.com/2024/10/27/arduino-euclidean-gate-sequencer-part-3/" class="" rel="nofollow noopener noreferrer" target="_blank">https://diyelectromusic.com/2024/10/27/arduino-euclidean-gate-sequencer-part-3/</a></p><p><a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://diyelectromusic.com/tag/arduino-uno/" target="_blank">#arduinoUno</a> <a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://diyelectromusic.com/tag/define/" target="_blank">#define</a> <a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://diyelectromusic.com/tag/defines/" target="_blank">#defines</a> <a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://diyelectromusic.com/tag/euclidean/" target="_blank">#euclidean</a> <a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://diyelectromusic.com/tag/gate/" target="_blank">#gate</a> <a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://diyelectromusic.com/tag/midi/" target="_blank">#midi</a> <a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://diyelectromusic.com/tag/oled-display/" target="_blank">#oledDisplay</a> <a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://diyelectromusic.com/tag/rotary-encoder/" target="_blank">#rotaryEncoder</a> <a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://diyelectromusic.com/tag/ssd1306/" target="_blank">#ssd1306</a> <a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://diyelectromusic.com/tag/step-sequence/" target="_blank">#stepSequence</a></p>