<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Electronics &#8211; Nate&#039;s Blog</title>
	<atom:link href="https://oldblog.natebarney.com/category/electronics/feed/" rel="self" type="application/rss+xml" />
	<link>https://oldblog.natebarney.com</link>
	<description>Abandon all hope, ye who enter here</description>
	<lastBuildDate>Thu, 25 Sep 2025 23:08:16 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>
	<item>
		<title>ApOPL3xy Emulator</title>
		<link>https://oldblog.natebarney.com/2025/09/23/apopl3xy-emulator/</link>
					<comments>https://oldblog.natebarney.com/2025/09/23/apopl3xy-emulator/#respond</comments>
		
		<dc:creator><![CDATA[Nate Barney]]></dc:creator>
		<pubDate>Wed, 24 Sep 2025 01:35:34 +0000</pubDate>
				<category><![CDATA[ApOPL3xy]]></category>
		<category><![CDATA[electronics]]></category>
		<category><![CDATA[music]]></category>
		<category><![CDATA[opl3]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[projects]]></category>
		<guid isPermaLink="false">https://blog.natebarney.com/?p=840</guid>

					<description><![CDATA[Last week, I posted about the ApOPL3xy reaching the version 1.0 milestone. This time, I want to discuss the emulator I wrote for it. I think it&#8217;s pretty cool. The emulator was initially conceived as a way to run the code on a computer with all the debugging tools that I&#8217;m used to having at [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="has-medium-font-size">Last week, I <a href="https://blog.natebarney.com/2025/09/14/apopl3xy-1-0/" data-type="post" data-id="816" target="_blank" rel="noreferrer noopener">posted</a> about the ApOPL3xy reaching the version 1.0 milestone. This time, I want to discuss the emulator I wrote for it. I think it&#8217;s pretty cool. The emulator was initially conceived as a way to run the code on a computer with all the debugging tools that I&#8217;m used to having at my disposal. It was certainly useful for that, but it grew into a project of its own.</p>



<h2 class="wp-block-heading">Demo Videos</h2>



<p>Before I get into some of the more technical details, I want to show some video captures of the emulator running. And if you happen to find yourself thinking that it looks like something you&#8217;d want to play with, I&#8217;m releasing it all as open source. There will be some links <a href="#download">later in the post</a> where you can download the emulator, and for the ambitious, all the files needed to build your own hardware ApOPL3xy are available as well.</p>



<h3 class="wp-block-heading">VGM Player</h3>



<p>One of the most iconic pieces composed for the OPL3 is &#8220;At Doom&#8217;s Gate,&#8221; the music for the first level (Episode 1 Mission1, or E1M1) of Doom. <a href="https://vgmrips.net/" data-type="link" data-id="https://vgmrips.net/" target="_blank" rel="noreferrer noopener">vgmrips.net</a> has the <a href="https://vgmrips.net/packs/pack/doom-pc" data-type="link" data-id="https://vgmrips.net/packs/pack/doom-pc" target="_blank" rel="noreferrer noopener">VGM capture of this song</a> available for download, and I can&#8217;t think of a better song to demonstrate the VGM player feature. Note that most, if not all, VGM files only use the first two output channels, since no 4-channel OPL3 sound cards were commonly available.</p>



<p>The numbered buttons below the display correspond to the colored buttons on the hardware, and the two groups of three buttons, labeled ↺, ↻, and ☟, represent the rotary encoders being turned counter-clockwise, turned clockwise, and pressed like a button, respectively. At some point, I may improve these to be a more skeuomorphic control, but the buttons get the job done. </p>



<figure class="wp-block-video max640"><video height="720" style="aspect-ratio: 1280 / 720;" width="1280" controls preload="auto" src="https://blog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Emulator-At-Dooms-Gate.mp4" playsinline></video><figcaption class="wp-element-caption">Doom: At Doom&#8217;s Gate (E1M1)</figcaption></figure>



<h3 class="wp-block-heading">MIDI Player</h3>



<p>My last post showed the new MIDI file player feature on the hardware ApOPL3xy, but due to difficulties filming the backlit LCD screen, it wasn&#8217;t easy to see what was on the display. The next video shows the emulator playing a MIDI version of the Doctor Who theme music. As before,  I arbitrarily assigned MIDI channels to output channels to make the VU meters a bit more interesting. </p>



<figure class="wp-block-video max640"><video height="720" style="aspect-ratio: 1280 / 720;" width="1280" controls preload="auto" src="https://blog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Emulator-Doctor-Who.mp4" playsinline></video><figcaption class="wp-element-caption">Doctor Who Theme</figcaption></figure>



<h3 class="wp-block-heading">Loop Controls</h3>



<p>Between the last post and this one, I added loop controls to both the VGM and MIDI players. It&#8217;s a small feature, but potentially useful. The loop indicator is just to the left of the total time in the player interface.  It starts out as a right-pointing arrow, meaning no loop. The other loop modes are single loop, represented by an arrow that curves from the right to the left, and continual loop, represented by two arrows pointing at each other&#8217;s tail. The 5 button cycles through these modes. </p>



<p>This video demonstrates the single loop mode being used for a MIDI file with a version of the Pac-Man music. It also shows the page down menu navigation function, which is mapped to button 9.</p>



<figure class="wp-block-video max640"><video height="720" style="aspect-ratio: 1280 / 720;" width="1280" controls preload="auto" src="https://blog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Emulator-Pac-Man.mp4" playsinline></video><figcaption class="wp-element-caption">Pac-Man</figcaption></figure>



<h3 class="wp-block-heading">MIDI Input</h3>



<p>My primary motivation for building the ApOPL3xy was to enable MIDI input to control an OPL3 chip. So far, I&#8217;ve demonstrated playback functionality, but I want to show the live MIDI capability as well. Unfortunately, I&#8217;m not very skilled at the piano, so I just play a few scales in the following video. The piano keyboard in the video is an open source tool called <a href="https://vmpk.sourceforge.io/" data-type="link" data-id="https://vmpk.sourceforge.io/" target="_blank" rel="noreferrer noopener">VMPK</a> (Virtual MIDI Piano Keyboard), which I did not write, but am simply using.</p>



<p>The video shows selecting a MIDI input source for the emulator and using the Channel Editor feature to show the patches assigned to MIDI channels. Then, a few scales are played using a few different patches.</p>



<figure class="wp-block-video max640"><video height="720" style="aspect-ratio: 1280 / 720;" width="1280" controls preload="auto" src="https://blog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Emulator-MIDI-Input.mp4" playsinline></video><figcaption class="wp-element-caption">MIDI Input</figcaption></figure>



<h3 class="wp-block-heading">MIDI Output</h3>



<p>The ApOPL3xy also has a MIDI output port, which sends MIDI messages from the MIDI player to an external device. It also optionally echoes messages received from the MIDI input port, but that echoing is not demonstrated here. What is demonstrated is using VMPK as an external device to visualize the notes being played. In this video, VMPK is configured to display each MIDI channel with a different color. The MIDI file being played is the <a href="https://www.youtube.com/watch?v=7HV3oyxr0Eg" data-type="link" data-id="https://www.youtube.com/watch?v=7HV3oyxr0Eg" target="_blank" rel="noreferrer noopener">battle music</a> from Final Fantasy VII.</p>



<figure class="wp-block-video max640"><video height="720" style="aspect-ratio: 1280 / 720;" width="1280" controls preload="auto" src="https://blog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Emulator-Final-Fantasy-VII.mp4" playsinline></video><figcaption class="wp-element-caption">Final Fantasy VII Battle Theme</figcaption></figure>



<h2 class="wp-block-heading">Implementation Details</h2>



<p>The ApOPL3xy firmware interacts with several pieces of hardware, all of which need to be emulated to be able to run the firmware purely in software.</p>



<h3 class="wp-block-heading">Microcontroller</h3>



<p>The hardware ApOPL3xy has an <a href="https://www.microchip.com/en-us/product/ATmega1284p" data-type="link" data-id="https://www.microchip.com/en-us/product/ATmega1284p" target="_blank" rel="noreferrer noopener">ATmega1284p</a> microcontroller to run the firmware. Because the main goal of the emulator is to support debugging, this microcontroller is not emulated. Instead of running the compiled AVR firmware on an emulated ATmega1284p, the firmware is recompiled to native code for the computer running the emulator, with some conditionally-compiled hooks in a few places to tie in the other emulated hardware.</p>



<h3 class="wp-block-heading">OPL3</h3>



<p>This is probably the most important piece of hardware to emulate, and also the most daunting. Fortunately, the open source project <a href="https://www.dosbox.com/" data-type="link" data-id="https://www.dosbox.com/" target="_blank" rel="noreferrer noopener">DOSBox</a> has code to emulate the <a href="https://en.wikipedia.org/wiki/Yamaha_OPL#OPL2" target="_blank" rel="noreferrer noopener">OPL2</a> and <a href="https://en.wikipedia.org/wiki/Yamaha_OPL#OPL3" data-type="link" data-id="https://en.wikipedia.org/wiki/Yamaha_OPL#OPL3" target="_blank" rel="noreferrer noopener">OPL3</a> chips, so I adapted it for my use. This code exposes a function to set registers on the emulated OPL chip, which I used instead of the <a href="https://en.wikipedia.org/wiki/Serial_Peripheral_Interface" target="_blank" rel="noreferrer noopener">SPI</a> interface <a href="https://blog.natebarney.com/2023/10/08/apopl3xy-hardware-design/#custom-spi-interface" data-type="link" data-id="https://blog.natebarney.com/2023/10/08/apopl3xy-hardware-design/#custom-spi-interface" target="_blank" rel="noreferrer noopener">I built</a> for the hardware ApOPL3xy for that purpose. The DOSBox code also exposes a function to get output audio samples, which I used to populate the audio buffers (more on this later).</p>



<p>The OPL3 supports up to 4 channels of audio output, but sound cards incorporating the chip rarely if ever used more than 2. DOSBox didn&#8217;t bother implementing support for channels 3 and 4, so I modified it to add that support. It was actually easier than I expected. Since they had already gone to the trouble to implement 2 channels, most of the work involved increasing some array sizes and loop bounds from 2 to 4.</p>



<h3 class="wp-block-heading">LCD Character Display</h3>



<p>The standard 20&#215;4 LCD character display used by the ApOPL3xy is based on a driver chip called the <a href="https://en.wikipedia.org/wiki/Hitachi_HD44780_LCD_controller" target="_blank" rel="noreferrer noopener">HD44780</a>. I broke the emulation of this device up into two parts: the HD44780 emulation and the drawing of the LCD panel itself.</p>



<p>The HD44780 supports several commands which are sent by writing to its control and data registers. To emulate this chip, I wrote a C++ class to represent all of its internal registers, RAM, and ROM, and then implemented each command as a separate function that operates on the internal state. I then implemented a wrapper function which accepts commands or data, and dispatches to the correct underlying function(s). This is called by the emulated firmware instead of using SPI, similar to the OPL3.</p>



<p>For the HD44780 emulation, I also wrote a function to retrieve the output state, e.g., which pixels are on and which are off. This is used by the LCD panel emulation to actually display the pixels. I used the open-source, cross-platform GUI library <a href="https://wxwidgets.org/" target="_blank" rel="noreferrer noopener">wxWidgets</a> to implement the emulator&#8217;s GUI, and the LCD panel is implemented as a custom widget that does its own drawing with the graphics routines provided by the library.</p>



<h3 class="wp-block-heading">Audio Output</h3>



<p>To implement audio output for the emulator, I used the open-source, cross-platform library <a href="https://www.portaudio.com/" target="_blank" rel="noreferrer noopener">PortAudio</a>. This library abstracts all the platform-specific audio APIs and presents a unified interface to interact with the audio system. With it, the emulator is able to select audio output devices, sample rate, latency, and number of channels. (These options are exposed to the user via the Audio Settings dialog window.) To play the synthesized audio, the emulator extracts audio samples from the emulated OPL3 and sends them to the host audio system using PortAudio&#8217;s interface.</p>



<h3 class="wp-block-heading">VU Meters and Gain Controls</h3>



<p>Each output channel on the physical ApOPL3xy has a <a href="https://en.wikipedia.org/wiki/VU_meter" target="_blank" rel="noreferrer noopener">VU meter</a> (well, not a true VU meter, just a linear amplitude display) and a gain control. Emulating this in wxWidgets was pretty straightforward. These are in separate tool windows that the user can display and dismiss.</p>



<p>The gain controls are slider widgets. To implement gain, the emulator reads the values from the sliders and uses them to adjust the audio samples before sending them to PortAudio for playback.</p>



<p>The VU meters are custom widgets that draw themselves based on a given amplitude. The emulator determines the current amplitude of each channel from the audio samples before sending them to PortAudio, and sends the amplitude values to their respective VU meter for display.</p>



<h3 class="wp-block-heading">MIDI Input and Output</h3>



<p>To emulate the MIDI input and output ports, I used the open-source, cross-platform library <a href="https://github.com/thestk/rtmidi" target="_blank" rel="noreferrer noopener">RtMidi</a>. This library abstracts the host computer&#8217;s MIDI system, and enables enumeration of, reading from, and writing to system MIDI ports. The MIDI In and MIDI Out dialogs allow the user to select which, if any, MIDI ports to read from and write to.</p>



<p>If a MIDI input port is selected, MIDI events are read from it and injected into the firmware&#8217;s MIDI queue, instead of reading from the microcontroller&#8217;s serial interface. Similarly, instead of writing output MIDI events to the microcontroller&#8217;s serial interface, the emulator writes them to the host MIDI port selected for output.</p>



<h3 class="wp-block-heading">MicroSD Card</h3>



<p>The hardware ApOPL3xy includes a MicroSD card reader, which is read by the firmware using the open-source <a href="https://github.com/greiman/SdFat" target="_blank" rel="noreferrer noopener">SdFat</a> library. This library abstracts both the SPI messaging needed to interact with the card itself, as well as handling the FAT filesystem that keeps track of which files are where in the card&#8217;s storage.</p>



<p>To emulate this, I wrote a mock implementation of the subset of SdFat&#8217;s interface that the firmware uses, but instead of accessing an SD card, it uses the standard C++ <a href="https://en.cppreference.com/w/cpp/filesystem.html" target="_blank" rel="noreferrer noopener"><code>std::filesystem</code></a> library to access the host&#8217;s filesystem through the host OS. The user can &#8220;insert&#8221; a virtual SD card by using the Mount SD Card dialog window to select the directory to serve as the root directory of the virtual card. The user can &#8220;eject&#8221; a virtual SD card by using the Unmount SD Card menu option.</p>



<h3 class="wp-block-heading">SRAM and EEPROM</h3>



<p>The ATmega1284p microcontroller has 16 kiB of RAM and 4 kiB of EEPROM storage built in. This isn&#8217;t enough for everything I wanted the ApOPL3xy to be able to do, so I added SPI <a href="https://en.wikipedia.org/wiki/Static_random-access_memory" target="_blank" rel="noreferrer noopener">SRAM</a> and <a href="https://en.wikipedia.org/wiki/EEPROM" target="_blank" rel="noreferrer noopener">EEPROM</a> chips (128 kiB each) to the design. The SRAM on the microcontroller itself doesn&#8217;t need to be emulated; the emulator just uses the host&#8217;s system RAM for that. The microcontroller&#8217;s EEPROM isn&#8217;t used by the firmware at all, so that doesn&#8217;t need to be emulated either. The add-on chips, however, do need to be emulated.</p>



<p>The SRAM chip was very simple to emulate. I simply allocated an array of the right size and provided functions to read from and write to it. The emulator uses these functions instead of sending SPI commands like the firmware does on physical hardware. The EEPROM was very similar,  except that a file is used instead an in-memory array, since EEPROMs are nonvolatile.</p>



<p>If the emulator finds no EEPROM file in the expected location on startup,  it generates a default one and uses that. This has turned out to be useful for setting up a hardware ApOPL3xy. Since the format of the EEPROM is identical between the emulator and the hardware, one can copy the EEPROM file from the emulator to a MicroSD card and load it onto the hardware.</p>



<h3 class="wp-block-heading">Input Controls</h3>



<p>The ApOPL3xy has 10 buttons and 2 rotary encoders (which can also act as buttons) which are used to navigate menus and issue commands. The hardware version of these are connected to a shift register, which the firmware reads via SPI, interprets, debounces, and adds to an input event queue. The emulator instead provides GUI buttons for these, and pressing a button injects an input event directly into the queue. These buttons are also mapped to (hopefully) intuitive keyboard shortcuts.</p>



<h3 class="wp-block-heading">Miscellaneous</h3>



<p>There were a few other things that needed to be replaced or mocked to be able to compile and run the firmware in an emulated context.</p>



<ul class="wp-block-list">
<li>The microcontroller framework used by the ApOPL3xy&#8217;s firmware provides functions for timing that use the microcontroller&#8217;s on-chip timers. These were replaced with versions that use the standard C++ <a href="https://en.cppreference.com/w/cpp/header/chrono.html" target="_blank" rel="noreferrer noopener"><code>std::chrono</code></a> library instead.</li>



<li>The AVR architecture used by the ATmega1284p requires the use of special functions to read data out of program code (e.g. constant string data) instead of SRAM. These were replaced with simple pass-through functions, since the host machine for the emulator doesn&#8217;t have this restriction.</li>



<li>Various utility functions like <code>min()</code> and <code>max()</code> provided by the framework needed to be reimplemented.</li>
</ul>



<h2 class="wp-block-heading" id="download">Download Links</h2>



<h3 class="wp-block-heading">Emulator</h3>



<p>If you&#8217;re interested in trying out the ApOPL3xy emulator, you can download pre-compiled binaries here:</p>



<ul class="wp-block-list">
<li><a href="https://www.natebarney.com/files/apopl3xy/emulator/1.0.1/apopl3xy-emulator-1.0.1-win.zip" data-type="link" data-id="https://www.natebarney.com/files/apopl3xy/emulator/1.0.1/apopl3xy-emulator-1.0.1-win.zip">ApOPL3xy Emulator v1.0.1 (Windows)</a></li>



<li><a href="https://www.natebarney.com/files/apopl3xy/emulator/1.0.1/apopl3xy-emulator-1.0.1-mac.zip">ApOPL3xy Emulator v1.0.1 (MacOS)</a></li>



<li><a href="https://www.natebarney.com/files/apopl3xy/emulator/1.0.1/apopl3xy-emulator-1.0.1-ubuntu24.04.zip">ApOPL3xy Emulator v1.0.1 (Ubuntu 24.04)</a></li>



<li><a href="https://www.natebarney.com/files/apopl3xy/emulator/1.0.1/apopl3xy-emulator-1.0.1-fedora42.zip">ApOPL3xy Emulator v1.0.1 (Fedora 42)</a></li>
</ul>



<p>Note that on Windows and MacOS, the fact that this binary isn&#8217;t signed may cause the operating system to complain. To get past this on MacOS, see <a href="https://support.apple.com/guide/mac-help/open-a-mac-app-from-an-unknown-developer-mh40616/mac">https://support.apple.com/guide/mac-help/open-a-mac-app-from-an-unknown-developer-mh40616/mac</a>. Microsoft doesn&#8217;t seem to have a good page on this, but here&#8217;s a potentially helpful <a href="https://www.google.com/search?q=windows+unknown+publisher">google search</a>.</p>



<h3 class="wp-block-heading">Music Files</h3>



<p>Here are some music files that you can play using the ApOPL3xy:</p>



<ul class="wp-block-list">
<li><a href="https://www.natebarney.com/files/apopl3xy/music/vgm.zip">VGM Files</a></li>



<li><a href="https://www.natebarney.com/files/apopl3xy/music/vgm.zip" data-type="link" data-id="https://www.natebarney.com/files/apopl3xy/music/vgm.zip">MIDI Files</a></li>
</ul>



<h3 class="wp-block-heading">Source Code</h3>



<p>The combined source code for the emulator and firmware is available below. It&#8217;s released under the terms of the MIT License, except for the OPL emulation code from DOSBox, which is released under the LGPL 2.1 license. I&#8217;ll probably post this to github at some point, but the code is a bit messy at the moment, and I might like to clean it up first.</p>



<ul class="wp-block-list">
<li><a href="https://www.natebarney.com/files/apopl3xy/firmware/1.0.1/apopl3xy-firmware-1.0.1-src.zip" data-type="link" data-id="https://www.natebarney.com/files/apopl3xy/firmware/1.0.1/apopl3xy-firmware-1.0.1-src.zip">ApOPL3xy Emulator and Firmware v1.0.1 (Source Code)</a></li>
</ul>



<h3 class="wp-block-heading">Hardware Design Files</h3>



<p>If you&#8217;re interested and brave enough to want to build your own hardware ApOPL3xy, here are the files you&#8217;ll need. Note that the documentation is rather lacking at the moment, but I think someone determined enough could figure it out. If you try and have difficulties, let me know and I&#8217;ll be happy to help.</p>



<ul class="wp-block-list">
<li><a href="https://www.natebarney.com/files/apopl3xy/pcb/rev3/apopl3xy-pcb-rev3-gerbers.zip">ApOPL3xy PCB rev3 (Gerbers)</a></li>



<li><a href="https://www.natebarney.com/files/apopl3xy/pcb/rev3/apopl3xy-bill_of_materials-rev3.zip">ApOPL3xy PCB rev3 (Bill of Materials)</a></li>



<li><a href="https://www.natebarney.com/files/apopl3xy/pcb/rev3/apopl3xy-schematic-rev3.zip">ApOPL3xy PCB rev3 (Schematic)</a></li>



<li><a href="https://www.natebarney.com/files/apopl3xy/pcb/rev3/apopl3xy-pcb-rev3-kicad.zip">ApOPL3xy PCB rev3 (KiCad Design Files)</a></li>



<li><a href="https://www.natebarney.com/files/apopl3xy/firmware/1.0.1/apopl3xy-firmware-1.0.1-hex.zip">ApOPL3xy Firmware v1.0.1 (HEX File)</a></li>



<li><a href="https://www.natebarney.com/files/apopl3xy/firmware/1.0.1/apopl3xy-eeprom-1.0.1.zip">ApOPL3xy EEPROM Image v1.0.1 (BIN File)</a></li>



<li><a href="https://www.natebarney.com/files/apopl3xy/firmware/1.0.1/apopl3xy-manual-1.0.1.zip">ApOPL3xy User Manual v1.0.1 (PDF File)</a></li>
</ul>



<h2 class="wp-block-heading">Closing Thoughts</h2>



<p>I&#8217;m quite pleased with how this project turned out. What began as an attempt to make debugging easier grew into something kinda cool on its own. It also enables me to share the ApOPL3xy with more people than I would have otherwise. If you do try it out, I&#8217;d love to hear what you think. I have my own ideas of what could be improved, but there&#8217;s no substitute for real user feedback.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://oldblog.natebarney.com/2025/09/23/apopl3xy-emulator/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		<enclosure url="https://blog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Emulator-At-Dooms-Gate.mp4" length="4037082" type="video/mp4" />
<enclosure url="https://blog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Emulator-Doctor-Who.mp4" length="3999713" type="video/mp4" />
<enclosure url="https://blog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Emulator-Pac-Man.mp4" length="904541" type="video/mp4" />
<enclosure url="https://blog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Emulator-MIDI-Input.mp4" length="2139536" type="video/mp4" />
<enclosure url="https://blog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Emulator-Final-Fantasy-VII.mp4" length="4748167" type="video/mp4" />

			</item>
		<item>
		<title>ApOPL3xy 1.0</title>
		<link>https://oldblog.natebarney.com/2025/09/14/apopl3xy-1-0/</link>
					<comments>https://oldblog.natebarney.com/2025/09/14/apopl3xy-1-0/#respond</comments>
		
		<dc:creator><![CDATA[Nate Barney]]></dc:creator>
		<pubDate>Mon, 15 Sep 2025 01:04:55 +0000</pubDate>
				<category><![CDATA[ApOPL3xy]]></category>
		<category><![CDATA[electronics]]></category>
		<category><![CDATA[music]]></category>
		<category><![CDATA[opl3]]></category>
		<category><![CDATA[projects]]></category>
		<guid isPermaLink="false">https://blog.natebarney.com/?p=816</guid>

					<description><![CDATA[It’s been a long journey, but I finally have the ApOPL3xy hardware and software to the point where I can call it version 1.0.]]></description>
										<content:encoded><![CDATA[
<p>It&#8217;s been a long journey, but I finally have the ApOPL3xy hardware and software to the point where I can call it version 1.0. I&#8217;ll make another post in a few days with links to the firmware source code, the PCB design files, and emulator binaries. (Update: here&#8217;s that <a href="https://blog.natebarney.com/2025/09/23/apopl3xy-emulator/" data-type="post" data-id="840" target="_blank" rel="noreferrer noopener">post</a>.) But for now, I just want to show it off a little.</p>



<h3 class="wp-block-heading">MIDI Player</h3>



<p>One of the things I&#8217;ve added to the firmware recently is the ability to play MIDI files from the SD card. Here are a few videos of this in action. These videos are a little dark. It was hard to find a balance between blowing out the display and making the videos way too dark, so I did the best I could. I mapped the MIDI channels to somewhat arbitrary output audio channels to make the VU meters a little more interesting.</p>



<figure class="wp-block-video max640"><video height="720" style="aspect-ratio: 1280 / 720;" width="1280" controls preload="auto" src="https://blog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Video-Killed-the-Radio-Star.mp4" playsinline></video><figcaption class="wp-element-caption">Video Killed the Radio Star</figcaption></figure>



<figure class="wp-block-video max640"><video height="720" style="aspect-ratio: 1280 / 720;" width="1280" controls preload="auto" src="https://blog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Star-Wars-Medley.mp4" playsinline></video><figcaption class="wp-element-caption">Star Wars Medley</figcaption></figure>



<figure class="wp-block-video max640"><video height="720" style="aspect-ratio: 1280 / 720;" width="1280" controls preload="auto" src="https://blog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Super-Mario-World.mp4" playsinline></video><figcaption class="wp-element-caption">Super Mario World</figcaption></figure>



<h3 class="wp-block-heading">PCB Photos</h3>



<p>Here are some high(ish) resolution photos of the assembled Rev 3 board, for those who are into that sort of thing. Also included is a photo of the bodges necessary on the Rev 2 board. To view the images at full resolution, right-click (or long-press) the image and select &#8220;Open Image in New Tab &#8221; or similar.</p>



<figure class="wp-block-image size-full is-resized"><img fetchpriority="high" decoding="async" width="2560" height="1920" src="https://blog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Rev3-PCB-Front-scaled.jpg" alt="ApOPL3xy Rev 3 PCB (Front)" class="wp-image-825" style="width:640px" title="" srcset="https://oldblog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Rev3-PCB-Front-scaled.jpg 2560w, https://oldblog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Rev3-PCB-Front-300x225.jpg 300w, https://oldblog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Rev3-PCB-Front-1024x768.jpg 1024w, https://oldblog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Rev3-PCB-Front-768x576.jpg 768w, https://oldblog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Rev3-PCB-Front-1536x1152.jpg 1536w, https://oldblog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Rev3-PCB-Front-2048x1536.jpg 2048w" sizes="(max-width: 2560px) 100vw, 2560px" /><figcaption class="wp-element-caption">ApOPL3xy Rev 3 PCB (Front)</figcaption></figure>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="2560" height="1920" src="https://blog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Rev3-PCB-Front-Modules-Removed-scaled.jpg" alt="ApOPL3xy Rev 3 PCB (Front, Modules Removed)" class="wp-image-826" style="width:640px" srcset="https://oldblog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Rev3-PCB-Front-Modules-Removed-scaled.jpg 2560w, https://oldblog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Rev3-PCB-Front-Modules-Removed-300x225.jpg 300w, https://oldblog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Rev3-PCB-Front-Modules-Removed-1024x768.jpg 1024w, https://oldblog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Rev3-PCB-Front-Modules-Removed-768x576.jpg 768w, https://oldblog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Rev3-PCB-Front-Modules-Removed-1536x1152.jpg 1536w, https://oldblog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Rev3-PCB-Front-Modules-Removed-2048x1536.jpg 2048w" sizes="(max-width: 2560px) 100vw, 2560px" /><figcaption class="wp-element-caption">ApOPL3xy Rev 3 PCB (Front, Modules Removed)</figcaption></figure>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="2560" height="1920" src="https://blog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Rev3-PCB-Back-scaled.jpg" alt="ApOPL3xy Rev 3 PCB (Back)" class="wp-image-824" style="width:640px" title="" srcset="https://oldblog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Rev3-PCB-Back-scaled.jpg 2560w, https://oldblog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Rev3-PCB-Back-300x225.jpg 300w, https://oldblog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Rev3-PCB-Back-1024x768.jpg 1024w, https://oldblog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Rev3-PCB-Back-768x576.jpg 768w, https://oldblog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Rev3-PCB-Back-1536x1152.jpg 1536w, https://oldblog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Rev3-PCB-Back-2048x1536.jpg 2048w" sizes="(max-width: 2560px) 100vw, 2560px" /><figcaption class="wp-element-caption">ApOPL3xy Rev 3 PCB (Back)</figcaption></figure>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="2560" height="1920" src="https://blog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Rev2-PCB-Bodges-scaled.jpg" alt="ApOPL3xy Rev 2 PCB (Bodges)" class="wp-image-823" style="width:640px" srcset="https://oldblog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Rev2-PCB-Bodges-scaled.jpg 2560w, https://oldblog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Rev2-PCB-Bodges-300x225.jpg 300w, https://oldblog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Rev2-PCB-Bodges-1024x768.jpg 1024w, https://oldblog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Rev2-PCB-Bodges-768x576.jpg 768w, https://oldblog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Rev2-PCB-Bodges-1536x1152.jpg 1536w, https://oldblog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Rev2-PCB-Bodges-2048x1536.jpg 2048w" sizes="auto, (max-width: 2560px) 100vw, 2560px" /><figcaption class="wp-element-caption">ApOPL3xy Rev 2 PCB Bodges</figcaption></figure>



<h3 class="wp-block-heading">Future Work</h3>



<p>Now that the ApOPL3xy has reached this milestone, I&#8217;ll probably leave it alone for a while. But, such things are never truly finished. I have several ideas for user interface improvements, such as patch and bank copying, M3U playlist support, and most interesting to me, a drum machine mode (suggested by a co-worker). I&#8217;m sure I&#8217;ll come back to this eventually to make these and other improvements, but it sure feels good to be able to call it done (for now)!</p>
]]></content:encoded>
					
					<wfw:commentRss>https://oldblog.natebarney.com/2025/09/14/apopl3xy-1-0/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		<enclosure url="https://blog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Video-Killed-the-Radio-Star.mp4" length="60705592" type="video/mp4" />
<enclosure url="https://blog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Star-Wars-Medley.mp4" length="47801042" type="video/mp4" />
<enclosure url="https://blog.natebarney.com/wp-content/uploads/2025/09/ApOPL3xy-Super-Mario-World.mp4" length="38279552" type="video/mp4" />

			</item>
		<item>
		<title>ApOPL3xy Hardware Design</title>
		<link>https://oldblog.natebarney.com/2023/10/08/apopl3xy-hardware-design/</link>
					<comments>https://oldblog.natebarney.com/2023/10/08/apopl3xy-hardware-design/#respond</comments>
		
		<dc:creator><![CDATA[Nate Barney]]></dc:creator>
		<pubDate>Mon, 09 Oct 2023 02:03:48 +0000</pubDate>
				<category><![CDATA[ApOPL3xy]]></category>
		<category><![CDATA[electronics]]></category>
		<category><![CDATA[music]]></category>
		<category><![CDATA[opl3]]></category>
		<category><![CDATA[projects]]></category>
		<guid isPermaLink="false">https://blog.natebarney.com/?p=267</guid>

					<description><![CDATA[I&#8217;ve been working on designing and building a MIDI synthesizer (called the ApOPL3xy) based on the OPL3 FM synthesis chip and the ATmega1284 microcontroller. I&#8217;ve made a couple of posts about it (here and here) and have gotten some good questions from some people about how this or that works under the hood. So, for [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>I&#8217;ve been working on designing and building a MIDI synthesizer (called the ApOPL3xy) based on the OPL3 FM synthesis chip and the ATmega1284 microcontroller. I&#8217;ve made a couple of posts about it (<a rel="noreferrer noopener" href="https://blog.natebarney.com/2023/06/25/apopl3xy-a-midi-opl3-based-fm-synthesizer/" data-type="post" data-id="233" target="_blank">here</a> and <a rel="noreferrer noopener" href="https://blog.natebarney.com/2023/07/03/apopl3xy-update-patches-omni-mode-and-percussion/" data-type="post" data-id="250" target="_blank">here</a>) and have gotten some good questions from some people about how this or that works under the hood. So, for this post, I thought I&#8217;d dig a little deeper into the technical details. I&#8217;ll go over the various components and how they&#8217;re connected together. If needed, I may make other posts focusing on some of the components in further detail.</p>



<h3 class="wp-block-heading">Microcontroller</h3>



<p>The microcontroller that drives the system is the Microchip <a rel="noreferrer noopener" href="https://www.microchip.com/en-us/product/ATmega1284" data-type="URL" data-id="https://www.microchip.com/en-us/product/ATmega1284" target="_blank">ATmega1284</a>. (It used to be made by Atmel, before <a rel="noreferrer noopener" href="https://www.microchip.com/en-us/announcements/microchip-technology-inc-acquires-atmel" data-type="URL" data-id="https://www.microchip.com/en-us/announcements/microchip-technology-inc-acquires-atmel" target="_blank">Microchip bought them</a>.) The ATmega1284 is an 8-bit <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/AVR_microcontrollers" target="_blank">AVR</a> microcontroller, similar to but more powerful than the <a href="https://www.microchip.com/en-us/product/ATMEGA328P" data-type="URL" data-id="https://www.microchip.com/en-us/product/ATMEGA328P" target="_blank" rel="noreferrer noopener">ATmega328P</a> at the heart of the <a href="https://docs.arduino.cc/hardware/uno-rev3" data-type="URL" data-id="https://docs.arduino.cc/hardware/uno-rev3" target="_blank" rel="noreferrer noopener">Arduino Uno R3</a>.</p>



<h5 class="wp-block-heading">Hardware</h5>



<p>Chips in the AVR line of microcontrollers have integrated <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Flash_memory" data-type="URL" data-id="https://en.wikipedia.org/wiki/Flash_memory" target="_blank">flash memory</a> for storing programs, <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Static_random-access_memory" data-type="URL" data-id="https://en.wikipedia.org/wiki/Static_random-access_memory" target="_blank">SRAM</a> for program variables and stack, and an <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/EEPROM" data-type="URL" data-id="https://en.wikipedia.org/wiki/EEPROM" target="_blank">EEPROM</a> for non-volatile data storage. Most have hardware implementations of several communication protocols, such as <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Serial_Peripheral_Interface" data-type="URL" data-id="https://en.wikipedia.org/wiki/Serial_Peripheral_Interface" target="_blank">SPI</a>, <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/I%C2%B2C" data-type="URL" data-id="https://en.wikipedia.org/wiki/I%C2%B2C" target="_blank">I<sup>2</sup>C</a>, and <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Transistor%E2%80%93transistor_logic#Serial_signaling" data-type="URL" data-id="https://en.wikipedia.org/wiki/Transistor%E2%80%93transistor_logic#Serial_signaling" target="_blank">TTL Serial</a> (basically <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/RS-232" data-type="URL" data-id="https://en.wikipedia.org/wiki/RS-232" target="_blank">RS-232</a> but with different voltage levels).</p>



<p>Whereas the ATmega328P has 32 kB of flash, 2 kB of SRAM, and 1 kB of EEPROM, the ATmega1284 has 128 kB of flash, 16 kB of SRAM, and 4 kB of EEPROM. I had initially designed the ApOPL3xy around the ATmega328P, but soon found the memory constraints too limiting, especially the 2 kB of SRAM. So, I upgraded to the ATmega1284. 128 kB of program flash and 16 kB of on-chip SRAM should be more than enough for the initial version, and leave plenty of room for future expansion.</p>



<p>The microcontroller in the ApOPL3xy runs at 5V and 20 MHz. A quartz crystal is used to generate the clock signal. 20 MHz is the maximum clock frequency for which the ATmega1284 is rated, and so far, it seems to be sufficient.</p>



<h5 class="wp-block-heading">Programming</h5>



<p>Arduino boards each have a USB port connected to a USB-to-serial bridge chip, which is used by special bootloader code on the microcontroller to receive new program code, so that all one needs to program an Arduino is a USB cable. When using a bare microcontroller as the ApOPL3xy does, the way to program it is ISP (In-circuit Serial Programming), sometimes called ICSP. This uses the SPI bus to upload code to the microcontroller (configured as the slave). However, to do this, one needs a separate device to act as the SPI master and upload the code to the microcontroller. I&#8217;m using the <a rel="noreferrer noopener" href="https://onlinedocs.microchip.com/pr/GUID-BEB648AA-8539-418A-9EFB-118BDC9DC77B-en-US-1/index.html" data-type="URL" data-id="https://onlinedocs.microchip.com/pr/GUID-BEB648AA-8539-418A-9EFB-118BDC9DC77B-en-US-1/index.html" target="_blank">AVRISP-mkII</a> programmer for this project. There are many others, but I have read that some of them have trouble with chips that have more than 64 kB of flash. I have, so far, not had any problems with the AVRISP-mkII, but note that the compiled firmware is still less than 64 kB in size, so that&#8217;s not entirely conclusive.</p>



<p>I&#8217;m using the <a rel="noreferrer noopener" href="https://platformio.org/" data-type="URL" data-id="https://platformio.org/" target="_blank">PlatformIO</a> IDE to edit, compile, and upload code to the microcontroller. This could be done with the official <a rel="noreferrer noopener" href="https://www.arduino.cc/en/software" data-type="URL" data-id="https://www.arduino.cc/en/software" target="_blank">Arduino IDE</a> as well (with the <a rel="noreferrer noopener" href="https://github.com/MCUdude/MightyCore" data-type="URL" data-id="https://github.com/MCUdude/MightyCore" target="_blank">MightyCore</a> board definitions added), and I was doing it that way for a while. However, the Arduino IDE is not very developer-friendly for large projects, and it makes simple things like having multiple source files much more difficult than they should be. PlatformIO, on the other hand, is much easier to use and I find myself fighting with it much less than with the Arduino IDE. PlatformIO is a <a rel="noreferrer noopener" href="https://code.visualstudio.com/" data-type="URL" data-id="https://code.visualstudio.com/" target="_blank">Visual Studio Code</a> extension, so you&#8217;ll need that installed, but it&#8217;s cross-platform, supports a large number of microcontrollers, and can use libraries written for the Arduino IDE. In theory, it even supports debugging over <a rel="noreferrer noopener" href="https://en.m.wikipedia.org/wiki/JTAG" data-type="URL" data-id="https://en.m.wikipedia.org/wiki/JTAG" target="_blank">JTAG</a> if the chip supports it. I haven&#8217;t tried that yet, but the ATmega1284 does claim to support it. PlatformIO is still a tad rough around the edges, but it&#8217;s so much better than the Arduino IDE experience that I highly recommend it.</p>



<h3 class="wp-block-heading">Peripheral Devices</h3>



<p>The ApOPL3xy has several peripheral devices attached to the microcontroller. &#8220;Peripheral&#8221; here means that the device is separate from the microcontroller chip, not necessarily that it&#8217;s detachable from the circuit board. Each of these peripherals communicates with the microcontroller using the SPI protocol. The one exception to this is the MIDI input port, which communicates using TTL Serial and is therefore connected to one of the microcontroller&#8217;s <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Universal_synchronous_and_asynchronous_receiver-transmitter" data-type="URL" data-id="https://en.wikipedia.org/wiki/Universal_synchronous_and_asynchronous_receiver-transmitter" target="_blank">USART</a> (i.e. hardware serial) interfaces.</p>



<p>The ApOPL3xy contains the following peripheral devices:</p>



<ul class="wp-block-list">
<li>OPL3 FM synthesis chip (Yamaha <a href="https://www.yamaha-tech.com/wiki/Yamaha_YMF262" data-type="URL" data-id="https://www.yamaha-tech.com/wiki/Yamaha_YMF262" target="_blank" rel="noreferrer noopener">YMF262</a>)</li>



<li><a rel="noreferrer noopener" href="https://www.adafruit.com/product/198" data-type="URL" data-id="https://www.adafruit.com/product/198" target="_blank">20&#215;4 LCD character display module</a> (with Hitachi <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Hitachi_HD44780_LCD_controller" data-type="URL" data-id="https://en.wikipedia.org/wiki/Hitachi_HD44780_LCD_controller" target="_blank">HD44780</a>-compatible controller)</li>



<li>Input controls
<ul class="wp-block-list">
<li>2 <a href="https://blog.natebarney.com/2023/07/24/ec11-rotary-encoders/" data-type="post" data-id="384" target="_blank" rel="noreferrer noopener">EC11</a> <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Incremental_encoder" data-type="URL" data-id="https://en.wikipedia.org/wiki/Incremental_encoder" target="_blank">incremental</a> <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Rotary_encoder" data-type="URL" data-id="https://en.wikipedia.org/wiki/Rotary_encoder" target="_blank">rotary encoders</a></li>



<li>10 tactile push buttons</li>
</ul>
</li>



<li><a href="https://www.amazon.com/gp/product/B07BJ2P6X6" data-type="URL" data-id="https://www.amazon.com/gp/product/B07BJ2P6X6" target="_blank" rel="noreferrer noopener">MicroSD card module</a></li>



<li>128 kB SRAM (Microchip <a href="https://www.microchip.com/en-us/product/23LCV1024" data-type="URL" data-id="https://www.microchip.com/en-us/product/23LCV1024" target="_blank" rel="noreferrer noopener">23LCV1024</a>)</li>



<li>128 kB EEPROM (Microchip <a href="https://www.microchip.com/en-us/product/25AA1024" data-type="URL" data-id="https://www.microchip.com/en-us/product/25AA1024" target="_blank" rel="noreferrer noopener">25AA1024</a>)</li>



<li><a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/MIDI" data-type="URL" data-id="https://en.wikipedia.org/wiki/MIDI" target="_blank">MIDI</a> 5-pin <a href="https://en.wikipedia.org/wiki/DIN_connector" data-type="URL" data-id="https://en.wikipedia.org/wiki/DIN_connector" target="_blank" rel="noreferrer noopener">DIN</a> input port
<ul class="wp-block-list">
<li>I&#8217;m thinking about adding a MIDI thru port as well</li>
</ul>
</li>



<li>Reset button</li>
</ul>



<h3 class="wp-block-heading">Reset Circuit</h3>



<p>The reset button is connected to the reset pins of both the ATmega1284 and the OPL3. Since this signal is not being handled by a GPIO pin, software debouncing is not really an option. I also wanted the reset signal to start out active, so that the chips connected to it would be reset at power on. So, I designed a <a href="https://en.wikipedia.org/wiki/RC_circuit" data-type="link" data-id="https://en.wikipedia.org/wiki/RC_circuit" target="_blank" rel="noreferrer noopener">simple RC (resistor-capacitor) circuit</a>, with its analog output converted to digital by means of two gates from a <a rel="noreferrer noopener" href="https://www.ti.com/product/SN74HC14" target="_blank">74HC14</a> (six <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Schmitt_trigger" target="_blank">Schmitt-trigger</a> inverters).</p>



<figure class="wp-block-image aligncenter size-medium"><img loading="lazy" decoding="async" width="300" height="270" src="https://blog.natebarney.com/wp-content/uploads/2023/10/ApOPL3xy-Reset-Circuit-300x270.png" alt="" class="wp-image-642" srcset="https://oldblog.natebarney.com/wp-content/uploads/2023/10/ApOPL3xy-Reset-Circuit-300x270.png 300w, https://oldblog.natebarney.com/wp-content/uploads/2023/10/ApOPL3xy-Reset-Circuit-768x691.png 768w, https://oldblog.natebarney.com/wp-content/uploads/2023/10/ApOPL3xy-Reset-Circuit.png 971w" sizes="auto, (max-width: 300px) 100vw, 300px" /><figcaption class="wp-element-caption">ApOPL3xy Reset Circuit</figcaption></figure>



<p>The reset signal for both chips is active low (as it is for most chips with a reset pin), so the way this circuit works is as follows. One lead of a 10 μF capacitor is connected to <kbd>GND</kbd> (0V), so the other lead starts out at 0V as well. The second lead is connected to <kbd>V<sub>CC</sub></kbd> (+5V) through a 10kΩ resistor and a 1kΩ resistor in series, so the capacitor gradually charges to +5V over time. After about 60 ms, the voltage at the second lead becomes high enough to trigger the first inverter, which goes low, and then the second inverter goes high, deactivating the reset signal.</p>



<p>When the reset button is pressed, it connects the second lead of the capacitor to ground through just the 1kΩ resistor, allowing it to discharge quickly, bringing the reset signal low (active). The signal stays low until the reset button is released, at which time, it takes about another 60 ms for the capacitor to charge up enough to bring the reset signal high again. If the button bounces when pressed, that high frequency oscillation is filtered out by the slow-charging capacitor, which is acting as a <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Low-pass_filter" data-type="link" data-id="https://en.wikipedia.org/wiki/Low-pass_filter" target="_blank">low-pass filter</a>.</p>



<p>Here are a couple of captures from my oscilloscope illustrating the behavior of the circuit. In these images, the yellow trace measures the voltage across the capacitor, the pink trace measures the output of the first inverter, and the blue trace measures the output of the second inverter, which is the reset signal itself. The first image shows the behavior as the system is powered on. You can see the capacitor charging and how the schmitt-trigger inverters react to it.</p>



<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="800" height="420" src="https://blog.natebarney.com/wp-content/uploads/2023/10/ApOPL3xy-Power-On-Reset.png" alt="" class="wp-image-635" srcset="https://oldblog.natebarney.com/wp-content/uploads/2023/10/ApOPL3xy-Power-On-Reset.png 800w, https://oldblog.natebarney.com/wp-content/uploads/2023/10/ApOPL3xy-Power-On-Reset-300x158.png 300w, https://oldblog.natebarney.com/wp-content/uploads/2023/10/ApOPL3xy-Power-On-Reset-768x403.png 768w" sizes="auto, (max-width: 800px) 100vw, 800px" /><figcaption class="wp-element-caption">ApOPL3xy Power-On Reset Oscilloscope Capture</figcaption></figure>



<p>The second image shows the behavior when the reset button is pressed. In this capture, you can see the capacitor quickly discharging as soon as the button is pressed, and remain discharged until the button is released, then start slowly charging again.</p>



<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="800" height="420" src="https://blog.natebarney.com/wp-content/uploads/2023/10/ApOPL3xy-Reset-Button.png" alt="" class="wp-image-636" srcset="https://oldblog.natebarney.com/wp-content/uploads/2023/10/ApOPL3xy-Reset-Button.png 800w, https://oldblog.natebarney.com/wp-content/uploads/2023/10/ApOPL3xy-Reset-Button-300x158.png 300w, https://oldblog.natebarney.com/wp-content/uploads/2023/10/ApOPL3xy-Reset-Button-768x403.png 768w" sizes="auto, (max-width: 800px) 100vw, 800px" /><figcaption class="wp-element-caption">ApOPL3xy Reset Button Oscilloscope Capture</figcaption></figure>



<h3 class="wp-block-heading" id="custom-spi-interface">Custom SPI Interface</h3>



<p>Three of the peripherals (MicroSD, SRAM, EEPROM) connected to the microcontroller natively communicate using SPI. The others do not, but in order to conserve <a href="https://en.wikipedia.org/wiki/General-purpose_input/output" data-type="URL" data-id="https://en.wikipedia.org/wiki/General-purpose_input/output" target="_blank" rel="noreferrer noopener">GPIO</a> pins, I built an SPI interface for them (except for the MIDI port) using shift registers. In a <a href="https://blog.natebarney.com/2023/07/16/gpio-pins-shift-registers-and-spi/" data-type="URL" data-id="https://blog.natebarney.com/2023/07/16/gpio-pins-shift-registers-and-spi/" target="_blank" rel="noreferrer noopener">recent post</a>, I described how this works in more detail. I could have used something a bit fancier, like the Microchip <a href="https://www.microchip.com/en-us/product/MCP23S17" data-type="URL" data-id="https://www.microchip.com/en-us/product/MCP23S17" target="_blank" rel="noreferrer noopener">MCP23S17</a> SPI I/O expander. But they&#8217;re more expensive and more proprietary than standard 74HC shift registers, and the shift registers work just fine.</p>



<p>The SPI interface is built from one <a rel="noreferrer noopener" href="https://www.ti.com/product/SN74HC595" target="_blank">74HC595</a> (serial-in / parallel-out shift register), two <a rel="noreferrer noopener" href="https://www.ti.com/product/SN74HC165" data-type="URL" data-id="https://www.ti.com/product/SN74HC165" target="_blank">74HC165</a>&#8216;s (parallel-in / serial-out shift registers), and one gate each from a 74HC14 and a <a rel="noreferrer noopener" href="https://www.ti.com/product/SN74HC125" data-type="URL" data-id="https://www.ti.com/product/SN74HC125" target="_blank">74HC125</a> (four tri-state buffers). I could have used a <a rel="noreferrer noopener" href="https://www.ti.com/product/SN74HC04" target="_blank">74HC04</a> instead of a 74HC14, as I&#8217;m not using the Schmitt trigger functionality, but I already had a 74HC14 in the design for the reset button circuit, and I wasn&#8217;t using all of its gates. This setup provides eight output pins and sixteen input pins, and uses only three of the microcontroller&#8217;s pins. Two of these pins, <kbd>SCK</kbd> and <kbd>MOSI</kbd>, are shared among all SPI devices, so this really only uses one extra pin: <span style="text-decoration: overline;"><kbd>SS</kbd></span>.</p>



<p>Since the LCD character display and the OPL3 sound chip are controlled independently from one another, I was able to use the same eight output pins from the 74HC595 for both, and so they&#8217;re connected to each of these peripherals&#8217; data busses. The sixteen input pins are connected to the two rotary encoders (three pins each) and the ten push buttons (one pin each).</p>



<h3 class="wp-block-heading">OPL3 FM Synthesis Chip</h3>



<p>If the ATmega1284 is the heart of the ApOPL3xy (and if you&#8217;ll forgive my briefly waxing poetic), then the Yamaha YMF262 (a.k.a. OPL3) is its soul. Well, perhaps brain and larynx would be a better metaphor; it just doesn&#8217;t have the same ring. But I digress…</p>



<p>The OPL3 is a sound synthesizer chip that implements <a rel="noreferrer noopener" href="https://en.m.wikipedia.org/wiki/Frequency_modulation_synthesis" data-type="URL" data-id="https://en.m.wikipedia.org/wiki/Frequency_modulation_synthesis" target="_blank">frequency modulation (FM) synthesis</a>. It was used in Creative Labs&#8217; popular <a rel="noreferrer noopener" href="https://en.m.wikipedia.org/wiki/Sound_Blaster_16" data-type="URL" data-id="https://en.m.wikipedia.org/wiki/Sound_Blaster_16" target="_blank">Sound Blaster 16</a> sound card released in 1992 for IBM-compatible PC&#8217;s, and many PC games of that era used it to produce their in-game music.</p>



<h5 class="wp-block-heading">FM Synthesis</h5>



<p>FM synthesis is a method of producing sound waves by combining simpler waves. The basic sound-producing unit in a synthesizer is the oscillator. An oscillator takes a few parameters: frequency/pitch, amplitude/volume, and waveform, and produces the sound wave with those characteristics. In the OPL line of synthesizer chips, and often with FM in general, oscillators are referred to as operators. The reason for this is the way FM synthesis uses oscillators.</p>



<p>Each voice, or independently controlled sound source, in FM is built from two or more oscillators. However, usually only one of these oscillators, called the carrier, actually produces sound. The other oscillators, called modulators for reasons which will soon be apparent, <em>modulate</em> the carrier by adjusting the carrier&#8217;s frequency up or down based on the amplitude of the waveform produced by the modulator. This can produce a wide variety of sounds, many of which approximate different musical instruments fairly well. With more than two oscillators, there may be multiple carriers sounding at once, and/or multiple modulators, modulating carriers or even other modulators. The reason FM oscillators are often called operators is that they <em>operate</em> on each other in this way.</p>



<p>The OPL3 contains thirty-six operators, which are paired together to provide eighteen independent two-operator voices. Up to six pairs of voices can be combined to create four-operator sounds, at the cost of a corresponding decrease in the number of simultaneous voices. If percussion mode is enabled, three two-operator melodic voices are exchanged for five percussion voices—one two-operator voice and four one-operator voices, for a total of twenty independent voices. (One-operator voices are not technically FM, since there&#8217;s no modulation happening, but they can be produced by the OPL3.)</p>



<h5 class="wp-block-heading">Microcontroller Interface</h5>



<p>The microcontroller interface to the OPL3 consists of a chip select pin (<span style="text-decoration: overline;"><kbd>CS</kbd></span>), a write enable pin (<span style="text-decoration: overline;"><kbd>WR</kbd></span>), a read enable pin (<span style="text-decoration: overline;"><kbd>RD</kbd></span>), two address pins (<kbd>A0</kbd>, <kbd>A1</kbd>), eight data pins (<kbd>D0</kbd>&#8211;<kbd>D7</kbd>), an interrupt request output pin (<span style="text-decoration: overline;"><kbd>IRQ</kbd></span>), and a reset pin (<span style="text-decoration: overline;"><kbd>IC</kbd></span>, or Initial Clear). To control the behavior of the synthesizer (e.g. play a note, adjust sound settings, etc.), the microcontroller uses these pins to set the value(s) of one or more registers within the chip. I won&#8217;t go into detail about the specific registers and their values, because the unofficial <a rel="noreferrer noopener" href="https://www.fit.vutbr.cz/~arnost/opl/opl3.html" data-type="URL" data-id="https://www.fit.vutbr.cz/~arnost/opl/opl3.html" target="_blank">OPL3 Programmer&#8217;s Guide</a> has already done an excellent job of that. They&#8217;re also described in the <a rel="noreferrer noopener" href="https://pdf1.alldatasheet.com/datasheet-pdf/view/103368/ETC/YMF262.html" data-type="URL" data-id="https://pdf1.alldatasheet.com/datasheet-pdf/view/103368/ETC/YMF262.html" target="_blank">datasheet</a>, but I find that does a rather poorer job.</p>



<p>To set a register, the microcontroller first needs to set the <span style="text-decoration: overline;"><kbd>CS</kbd></span> pin low (if it&#8217;s not already) to select the chip, the <kbd>A0</kbd> pin low to indicate it&#8217;s selecting a register, the <kbd>A1</kbd> pin either high or low to select one of the two banks of registers, and the <kbd>D0</kbd>&#8211;<kbd>D7</kbd> pins to the index of the register to set. The <span style="text-decoration: overline;"><kbd>WR</kbd></span> pin is then pulsed low then high to write the register index. Next, <kbd>A0</kbd> is set high to indicate the register&#8217;s value is being set, and <kbd>D0</kbd>&#8211;<kbd>D7</kbd> are set to the new value for the register. The <span style="text-decoration: overline;"><kbd>WR</kbd></span> pin is once again pulsed low then high, this time to write the register value. Finally, if the microcontroller is done setting registers, it can set the <span style="text-decoration: overline;"><kbd>CS</kbd></span> pin high to deselect the chip.</p>



<p>The ApOPL3xy connects the OPL3&#8217;s pins as follows. <span style="text-decoration: overline;"><kbd>CS</kbd></span> is connected to <kbd>GND</kbd> to permanently select the chip. <kbd>A0</kbd>, <kbd>A1</kbd>, <span style="text-decoration: overline;"><kbd>IC</kbd></span>, and <span style="text-decoration: overline;"><kbd>WR</kbd></span> are connected to individual GPIO pins on the ATmega1284, configured as output pins. (<kbd>A0</kbd> actually shares a GPIO pin with the LCD module&#8217;s <kbd>RS</kbd> pin.) <kbd>D0</kbd>&#8211;<kbd>D7</kbd> are connected to the eight shared output pins from the custom SPI interface built from shift registers. This pin sharing works because the OPL3&#8217;s <span style="text-decoration: overline;"><kbd>WR</kbd></span> is only brought low (active) when any other device using the shared pins is inactive. When <span style="text-decoration: overline;"><kbd>WR</kbd></span> is high, the OPL3 doesn&#8217;t care what the values of the address and data pins are (except for setup and hold times, but those are so short that, even at 20 MHz, it&#8217;s hard to violate them; see the datasheet for more details on that).</p>



<p>The <span style="text-decoration: overline;"><kbd>IRQ</kbd></span> and <span style="text-decoration: overline;"><kbd>RD</kbd></span> pins are rarely used. The OPL3 can generate timer interrupt signals on the <span style="text-decoration: overline;"><kbd>IRQ</kbd></span> pin to let the microcontroller know when a certain amount of time has elapsed, and the <span style="text-decoration: overline;"><kbd>RD</kbd></span> pin is only able to be used to get information about these interrupts. The Sound Blaster 16 did not use this feature, nor does the ApOPL3xy. Therefore, the ApOPL3xy connects the <span style="text-decoration: overline;"><kbd>RD</kbd></span> pin to <kbd>V<sub>CC</sub></kbd> to permanently disable reads, and leaves the <span style="text-decoration: overline;"><kbd>IRQ</kbd></span> pin disconnected.</p>



<h5 class="wp-block-heading">Digital-to-Analog Conversion</h5>



<p>The OPL3 doesn&#8217;t generate sound directly. Rather, it produces digital representations of waveform amplitude (called samples) at a rate of 49,716 samples per second. The samples are represented as 16-bit offset binary numbers, where 0 represents the most negative value, and 65,535 represents the most positive value. These samples are sent serially to a <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Digital-to-analog_converter" data-type="URL" data-id="https://en.wikipedia.org/wiki/Digital-to-analog_converter" target="_blank">Digital-to-Analog Converter (DAC)</a> chip, the <a rel="noreferrer noopener" href="https://datasheetspdf.com/pdf-file/544518/Yamaha/YAC512/1" data-type="URL" data-id="https://datasheetspdf.com/pdf-file/544518/Yamaha/YAC512/1" target="_blank">YAC512</a>, which was designed as a companion chip to the YMF262.</p>



<p>The YAC512 takes the digital samples and converts them to an analog waveform which can be sent to an amplifier and then to a loudspeaker. Each YAC512 supports two audio channels, and the YMF262 can connect to two YAC512&#8217;s, giving four audio channels. Each of the OPL3&#8217;s voices can be configured to be output to any combination of the four audio channels. </p>



<h3 class="wp-block-heading">LCD Character Display Module</h3>



<p>This is a pretty standard component for a lot of homebrew projects. It&#8217;s a twenty-column by four-row character display module with an LED backlight and an integrated controller (Hitachi HD44780). It also comes in a sixteen-column by two-row variety, but I wanted the little bit of extra space afforded by the larger module. Ben Eater has an excellent <a rel="noreferrer noopener" href="https://youtu.be/FY3zTUaykVo" data-type="URL" data-id="https://youtu.be/FY3zTUaykVo" target="_blank">video</a> (to be honest, <em>all</em> of his videos are excellent) in which he connects a 16&#215;2 version to his 65C02-based breadboard computer. The <a rel="noreferrer noopener" href="https://pdf1.alldatasheet.com/datasheet-pdf/view/63673/HITACHI/HD44780.html" data-type="URL" data-id="https://pdf1.alldatasheet.com/datasheet-pdf/view/63673/HITACHI/HD44780.html" target="_blank">datasheet</a> for the HD44780 is surprisingly good, and details all of the instructions that can be sent to the module.</p>



<p>The microcontroller interface consists of eight data pins (<kbd>D0</kbd>&#8211;<kbd>D7</kbd>) and three control pins: enable (<kbd>E</kbd>), register select (<kbd>RS</kbd>), and read/write (<kbd>RW</kbd>). There are five other pins, two for power, two for backlight power, and one to set the contrast of the display, for a total of sixteen pins, but only eleven need to be connected to the microcontroller.</p>



<p>To send instructions to the LCD module, a microcontroller first needs to set <kbd>RW</kbd> low, to signal a write, and <kbd>RS</kbd> low, to signal an instruction. Next, <kbd>D0</kbd>&#8211;<kbd>D7</kbd> are set to the instruction to send, and finally <kbd>E</kbd> is pulsed high then low to send the command. Sending data (i.e.characters) follows the same process except that <kbd>RS</kbd> is set high to signal data rather than an instruction, and <kbd>D0</kbd>&#8211;<kbd>D7</kbd> are set to the <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/ASCII" data-type="URL" data-id="https://en.wikipedia.org/wiki/ASCII" target="_blank">ASCII</a> value of the character to send.</p>



<p>The LCD module also supports a four-bit mode, in which only <kbd>D4</kbd>&#8211;<kbd>D7</kbd> need to be connected. This would be one way to conserve GPIO pins, but the ApOPL3xy doesn&#8217;t take this approach. This mode takes twice as long to send instructions and data. Because each instruction and character is still eight bits, each one takes two cycles to send. However, the main reason the ApOPL3xy uses the eight-bit mode is that it simplifies the code to do so, and the GPIO pressure is dealt with another way (see below).</p>



<p>Character data can be read back out of the LCD module, if desired, by setting <kbd>RS</kbd> and <kbd>RW</kbd> high, pulsing <kbd>E</kbd> high then low, and reading the value of <kbd>D0</kbd>&#8211;<kbd>D7</kbd>. There is also a &#8220;busy&#8221; flag which can be read by setting <kbd>RS</kbd> low, setting <kbd>RW</kbd> high, pulsing <kbd>E</kbd> high then low, and reading the value of <kbd>D7</kbd>. The busy flag indicates that the HD44780 is still processing the last instruction it received.</p>



<p>If an instruction is sent while the busy flag is high, the instruction will not execute, and the HD44780 will take longer to complete its current action, so this should be avoided. However, the datasheet lists the maximum duration for each instruction, so another way to avoid this situation is simply to wait long enough between instructions. This can be slightly slower, but the longest delay needed is about 1.5 ms, and most are less than 50 µs, so it&#8217;s not terrible, and it simplifies the connections if reading doesn&#8217;t need to be supported. Therefore, this is the approach the ApOPL3xy takes.</p>



<p>The ApOPL3xy connects the LCD module&#8217;s pins as follows. <kbd>RS</kbd> and <kbd>E</kbd> are connected to GPIO pins on the ATmega1284, configured as outputs. (<kbd>RS</kbd> shares a pin with the OPL3&#8217;s <kbd>A0</kbd> pin.) <kbd>D0</kbd>&#8211;<kbd>D7</kbd> are connected to the eight shared output pins from the custom SPI interface built from shift registers. As with the OPL3, this pin sharing works because the LCD&#8217;s <kbd>E</kbd> pin is only brought high when any other device using the shared pins is inactive. When <kbd>E</kbd> is low, the LCD doesn&#8217;t care what the values of <kbd>RS</kbd>, <kbd>RW</kbd>, and <kbd>D0</kbd>&#8211;<kbd>D7</kbd> are.</p>



<p>Some readers might be wondering whether the ApOPL3xy uses the Arduino <a rel="noreferrer noopener" href="https://www.arduino.cc/reference/en/libraries/liquidcrystal/" data-type="URL" data-id="https://www.arduino.cc/reference/en/libraries/liquidcrystal/" target="_blank">LiquidCrystal</a> library to control the LCD module, and if not, why not. The ApOPL3xy doesn&#8217;t use this library because the library expects all of the LCD&#8217;s pins to be connected directly to the microcontroller&#8217;s GPIO pins, and that&#8217;s not how the module is connected in this case. To do so would have used more GPIO pins than I would have liked. The LCD control code in the ApOPL3xy&#8217;s firmware has an API modeled after LiquidCrystal, because it has a decent design, and because that might be more familiar to some developers.</p>



<h3 class="wp-block-heading">Input Controls</h3>



<p>The user interface for the ApOPL3xy consists of the LCD character display module previously discussed, and a number of input controls. Specifically, two EC11 rotary encoders, and ten momentary tactile push buttons. Each encoder has three output pins, and the ten push buttons have one each, for a total of sixteen. These outputs are connected to the sixteen inputs provided by the 74HC165&#8217;s in the custom SPI interface.</p>



<p>The shift registers in the SPI interface are part of the reason there are so many buttons. With six inputs needed for the two encoders, a single 74HC165 would only provide enough inputs for two more buttons. I felt that this wouldn&#8217;t be enough, so I added another 74HC165 with another eight inputs. Rather than let some of them go unused, I connected a button to each of them, for a total of ten. At present, the firmware only uses five of the buttons, but I&#8217;m sure I&#8217;ll be able to find uses for the others.</p>



<p>The buttons each have two pairs of pins, but the pins in each pair are shorted together, so there are effectively only two pins per button. I believe, but I&#8217;m not 100% certain, that the redundant pins are there to provide structural support when soldered to a circuit board. While the button is pressed, all four pins are shorted together.</p>



<p>EC11 rotary encoders are knobs that can be turned in arbitrarily many discrete steps in either direction, unlike a <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Potentiometer" data-type="URL" data-id="https://en.wikipedia.org/wiki/Potentiometer" target="_blank">potentiometer</a>, which turns continuously, but has limited extents. The encoders send a signal for each clockwise and counter-clockwise step, and they also serve as push buttons when pressed. If you&#8217;re curious to know how these work in more detail, check out my <a rel="noreferrer noopener" href="https://blog.natebarney.com/2023/07/24/ec11-rotary-encoders/" data-type="URL" data-id="https://blog.natebarney.com/2023/07/24/ec11-rotary-encoders/" target="_blank">recent post</a> on the topic.</p>



<p>These controls are all wired up in the ApOPL3xy to produce active-low signals. This means that each shift register input pin sees a low signal while, for example, the connected button is pressed, and a high signal otherwise. I don&#8217;t have a strong reason for making the controls&#8217; outputs active-low rather than active-high. It would have worked just as well the other way.</p>



<p>The ApOPL3xy deals with the problem of <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Switch#Contact_bounce" data-type="URL" data-id="https://en.wikipedia.org/wiki/Switch#Contact_bounce" target="_blank">contact bounce</a> by applying a software debouncing algorithm. This algorithm acts as a <a rel="noreferrer noopener" href="https://en.m.wikipedia.org/wiki/Finite-state_machine" data-type="URL" data-id="https://en.m.wikipedia.org/wiki/Finite-state_machine" target="_blank">state machine</a> which only transitions states after a configured minimum time is spent in each state. In this case, the states are (effectively) idle, idle wait, active, and active wait. The wait states are the ones that require minimum durations before transitioning to its non-wait counterpart. If there&#8217;s interest, I could make another post going into detail about the various hardware and software debouncing solutions, and the pros and cons of each.</p>



<h3 class="wp-block-heading">MicroSD Card Module</h3>



<p>The ApOPL3xy includes a MicroSD card module to allow it to read <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/VGM_(file_format)" data-type="URL" data-id="https://en.wikipedia.org/wiki/VGM_(file_format)" target="_blank">VGM</a> (and eventually MIDI) files for playback, as well as to load and save data to and from the EEPROM. I&#8217;m looking into the possibility of using a bootloader for the ATmega1284 that can load new firmware from the SD card, so an ISP programmer wouldn&#8217;t be required, but my investigation into that is not yet complete.</p>



<p>The MicroSD module I&#8217;m using was meant for Arduinos. It&#8217;s a small board with a slot for the card, a pin header to connect to the microcontroller, and a few extra components to shift voltage levels between the 5V the microcontroller uses and the 3.3V that the card uses. I may, in some future version of the ApOPL3xy, ditch the separate module and just incorporate a card slot and a level shifter chip directly. The card itself contains all the circuitry needed for the actual control and data interface, so it would be relatively straightforward. The module is convenient however, so that&#8217;s what I&#8217;m using for now.</p>



<p>SD (and MicroSD) cards natively use a four-bit parallel protocol, and that&#8217;s the way most modern devices (e.g. computers, smartphones, etc.) talk to them. Using this mode enables the highest transfer rates that the card can support. However, these cards also provide an SPI interface, which is how most smaller microcontrollers, including the ApOPL3xy, talk to them. This method is slower, but still fast enough for how the ApOPL3xy uses the card, it&#8217;s supported in hardware by the microcontroller, and it only uses up one additional GPIO pin for the SPI <span style="text-decoration: overline"><kbd>SS</kbd></span> signal.</p>



<p>One issue I ran into is that SD cards are not particularly well-behaved when it comes to SPI. Specifically, the cards don&#8217;t seem to release the <kbd>MISO</kbd> line when its <span style="text-decoration: overline"><kbd>SS</kbd></span> line is brought high, interfering with all the other devices on the SPI bus. At least this is the case with the module I&#8217;m using, but I believe this is a general phenomenon. To fix this, I used a <a rel="noreferrer noopener" href="https://www.ti.com/product/SN74HC125" data-type="URL" data-id="https://www.ti.com/product/SN74HC125" target="_blank">74HC125</a> tri-state buffer chip to disconnect the SD card&#8217;s MISO line when its <span style="text-decoration: overline"><kbd>SS</kbd></span> line is high. In fact, I already had a 74HC125 with unused gates in the circuit, because I needed to do the same thing with the 74HC165 shift registers as well.</p>



<p>The SPI interface to the SD card provides raw read/write access to the bytes stored on the card. However, that&#8217;s not really sufficient to be able to read and write files on the card. At least, not if the card needs to be able to be read and written by other devices as well. Most storage devices, including SD cards, organize the large amount of data stored on them by using a <a href="https://en.wikipedia.org/wiki/File_system" data-type="URL" data-id="https://en.wikipedia.org/wiki/File_system" target="_blank" rel="noreferrer noopener">filesystem</a>. Filesystems keep track of file metadata like filenames and file size and provide controllers with a way to work with files instead of just raw data.</p>



<p>The topic of filesystems is vast, and well outside the scope of this article, but a common filesystem used on SD cards is called <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/File_Allocation_Table#FAT32" data-type="URL" data-id="https://en.wikipedia.org/wiki/File_Allocation_Table#FAT32" target="_blank">FAT32</a>. FAT32 was developed by Microsoft for <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Windows_95" data-type="URL" data-id="https://en.wikipedia.org/wiki/Windows_95" target="_blank">Windows 95</a>, as an extension to their earlier filesystems <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/File_Allocation_Table#Final_FAT16" data-type="URL" data-id="https://en.wikipedia.org/wiki/File_Allocation_Table#Final_FAT16" target="_blank">FAT16</a> and <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/File_Allocation_Table#FAT12" data-type="URL" data-id="https://en.wikipedia.org/wiki/File_Allocation_Table#FAT12" target="_blank">FAT12</a>, developed for <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/MS-DOS" data-type="URL" data-id="https://en.wikipedia.org/wiki/MS-DOS" target="_blank">MS-DOS</a>. FAT32 has become a de facto standard for removable media, as its relative simplicity compared to other filesystems has enabled many different computer operating systems and embedded systems to implement support for it. This is slowly being superseded by Microsoft&#8217;s more modern <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/ExFAT" data-type="URL" data-id="https://en.wikipedia.org/wiki/ExFAT" target="_blank">exFAT</a> filesystem, but support for this is still far from ubiquitous.</p>



<p>The ApOPL3xy expects its SD card to be formatted with the FAT32 filesystem, and rather than implementing a FAT32 filesystem driver from scratch, it makes use of the <a href="https://github.com/greiman/SdFat" data-type="URL" data-id="https://github.com/greiman/SdFat" target="_blank" rel="noreferrer noopener">SdFat</a> library. This library takes care of both the low-level SD card interface for handling raw data and the FAT32 filesystem interface. It&#8217;s been in development for many years, and at the time of this writing, is still in active development. It manages to pack a tremendous amount of capability into a surprisingly small amount of space, and does so very efficiently. It even has optional support for exFAT, but ApOPL3xy doesn&#8217;t enable that, at least not yet.</p>



<h3 class="wp-block-heading">External SRAM and EEPROM</h3>



<p>Even though the ATmega1284 has much larger memory capacities than the ATmega328P, it&#8217;s still not enough to store as many synthesizer patches (i.e. sound settings to emulate various instruments) as I want to be able to. Each patch for the OPL3 (at least as I have currently implemented it) is 23 bytes, plus a 24-byte name string, giving 47 bytes per patch. The <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/General_MIDI" target="_blank">General MIDI</a> specification includes 128 melodic instruments, and 61 percussive instruments, for a total of 189 * 47 = 8,883 bytes, more than half of the available SRAM space, and more than double the available EEPROM space. Furthermore, I&#8217;d eventually like to be able to store and select from multiple banks of patches.</p>



<p>To deal with this, the ApOPL3xy includes an external (i.e. not part of the microcontroller) SRAM chip (Microchip 23LCV1024) and an external EEPROM chip (Microchip 25AA1024), each with 128 kB of space. These chips, like most of the other peripherals in the ApOPL3xy, communicate via the SPI protocol. The specific details of the command interface can be found in the datasheets for these chips, but the basic structure for both chips is: write a command byte (i.e. &#8220;read&#8221;, &#8220;write&#8221;), write a three-byte address, then read or write as many bytes as desired. Because these chips hold 128 kB of data, only seventeen bits are needed to encode an address, and the seven most significant bits of the three-byte address are ignored.</p>



<p>Writing to the EEPROM is slightly more complicated. Its storage is organized into 256-byte pages, and each write operation can only modify a single page. To write to multiple pages, multiple write operations must be performed. To write to a page, first the status register must be checked to ensure that the chip has completed its last operation. Then a &#8220;write enable&#8221; command byte must be sent, then the chip select line must be brought high and then low before the &#8220;write&#8221; command is sent, followed by the 3-byte address, followed by up to 256 bytes of data. Once the last byte of the page is written, the chip select is brought high, and the cycle is repeated for any additional pages.</p>



<h3 class="wp-block-heading">MIDI Port</h3>



<p>The ApOPL3xy uses the <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/MIDI" data-type="link" data-id="https://en.wikipedia.org/wiki/MIDI" target="_blank">MIDI</a> protocol to allow an instrument (like a keyboard) to control the FM synthesis chip. MIDI is a fairly straightforward protocol, and the <a rel="noreferrer noopener" href="https://www.midi.org/specifications-old/item/midi-din-electrical-specification" target="_blank">electrical interface</a> is reasonably simple to implement. The MIDI port itself is a female <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/DIN_connector" target="_blank">5-pin DIN</a> jack, and there are a few other components, such as an <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Opto-isolator" target="_blank">optocoupler</a> and a few resistors to provide isolation and level-shifting. The data signals transmitted via this port are essentially <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/RS-232" data-type="link" data-id="https://en.wikipedia.org/wiki/RS-232" target="_blank">RS-232 serial</a> signals, at 31,250 baud with eight data bits, one stop bit, and no parity bits per frame. The USARTs built into the ATmega1284 can directly process this kind of signal, so the data line from the MIDI-In port is connected to one of these.</p>



<p>At present, the breadboard version of the ApOPL3xy includes a single port for MIDI-In, but I will likely add a MIDI-Thru port as well. MIDI-Thru ports are ports which simply output whatever signals came in on the MIDI-In port. They&#8217;re also pretty simple electrically, and require no software support in the microcontroller, so it&#8217;s probably worth adding one, just in case it turns out to be useful.</p>



<h3 class="wp-block-heading">Conclusion</h3>



<p>This covers almost all of the hardware used in the ApOPL3xy. I did leave out the amplifier circuits, because I&#8217;m still fiddling around with their design. Once I sort that out to my satisfaction, I&#8217;ll likely make another post about that. As always, I hope this has been interesting and informative. Let me know if anything is unclear, or if you&#8217;d like more detail on anything in particular. </p>
]]></content:encoded>
					
					<wfw:commentRss>https://oldblog.natebarney.com/2023/10/08/apopl3xy-hardware-design/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>EC11 Rotary Encoders</title>
		<link>https://oldblog.natebarney.com/2023/07/24/ec11-rotary-encoders/</link>
					<comments>https://oldblog.natebarney.com/2023/07/24/ec11-rotary-encoders/#respond</comments>
		
		<dc:creator><![CDATA[Nate Barney]]></dc:creator>
		<pubDate>Mon, 24 Jul 2023 06:39:56 +0000</pubDate>
				<category><![CDATA[Electronics]]></category>
		<category><![CDATA[arduino]]></category>
		<category><![CDATA[electronics]]></category>
		<guid isPermaLink="false">https://blog.natebarney.com/?p=384</guid>

					<description><![CDATA[EC11 incremental rotary encoders are user-interface controls for electronic devices. They&#8217;re particularly useful for quickly adjusting settings through a range of possible values, or for scrolling through lists or menus. They&#8217;re also relatively inexpensive, and pretty easy to find. The way these devices work is rather interesting, and somewhat surprising if you&#8217;re unfamiliar with it. [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>EC11 <a rel="noreferrer noopener" href="https://en.m.wikipedia.org/wiki/Incremental_encoder" data-type="URL" data-id="https://en.m.wikipedia.org/wiki/Incremental_encoder" target="_blank">incremental</a> <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Rotary_encoder" data-type="URL" data-id="https://en.wikipedia.org/wiki/Rotary_encoder" target="_blank">rotary encoders</a> are user-interface controls for electronic devices. They&#8217;re particularly useful for quickly adjusting settings through a range of possible values, or for scrolling through lists or menus. They&#8217;re also relatively inexpensive, and pretty easy to find. The way these devices work is rather interesting, and somewhat surprising if you&#8217;re unfamiliar with it. In the remainder of this post, for brevity, I&#8217;ll simply refer to them as EC11&#8217;s. </p>



<figure class="wp-block-image aligncenter size-medium is-resized"><img decoding="async" src="https://blog.natebarney.com/wp-content/uploads/2023/07/EC11-300x169.jpg" alt="" class="wp-image-406" width="600" srcset="https://oldblog.natebarney.com/wp-content/uploads/2023/07/EC11-300x169.jpg 300w, https://oldblog.natebarney.com/wp-content/uploads/2023/07/EC11-768x432.jpg 768w, https://oldblog.natebarney.com/wp-content/uploads/2023/07/EC11.jpg 1024w" sizes="(max-width: 300px) 100vw, 300px" /><figcaption class="wp-element-caption">EC11 Rotary Encoder</figcaption></figure>



<p>EC11&#8217;s look similar to <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Potentiometer" target="_blank">potentiometers</a>, but they&#8217;re very different devices. A potentiometer turns smoothly through a limited range of motion, but an EC11 turns in discrete steps, and its range of rotation is unlimited. A potentiometer is a variable resistor divider, but an EC11 has nothing to do with resistance. Instead, when it rotates, it produces signals that indicate the direction of rotation. EC11&#8217;s can also function as push buttons.</p>



<p>As a side note, I&#8217;m not sure <em>why</em> they&#8217;re called &#8220;EC11&#8221; encoders. My web search on this topic has turned up nothing useful. I&#8217;ve also seen references to EC12 and EC16 encoders, that presumably differ in some important way.  There are likely other types as well. The best I&#8217;ve been able to come up with is that &#8220;EC&#8221; stands for &#8220;EnCoder&#8221;, and the 11 means 11 mm, for (I guess) the shaft length. However, apparently, EC12&#8217;s and EC16&#8217;s don&#8217;t have the push button feature that EC11&#8217;s have, so I&#8217;m not convinced that&#8217;s the whole story. If you know more about this, please let me know. </p>



<h3 class="wp-block-heading">Electrical Interface</h3>



<p>An EC11 has five pins. There is no standard pin labeling, at least not that I could find, but it&#8217;s common for the pins to be labeled <kbd>A</kbd>, <kbd>B</kbd>, <kbd>C</kbd>, <kbd>D</kbd>, and <kbd>E</kbd>. The pinout diagram below is one possible labeling, and is the one I&#8217;ll use for this post. Note, however, that some documents have the <kbd>A</kbd> and <kbd>B</kbd> pin labels swapped.</p>



<figure class="wp-block-image aligncenter size-medium is-resized"><img loading="lazy" decoding="async" src="https://blog.natebarney.com/wp-content/uploads/2023/07/EC11-Pinout-204x300.png" alt="" class="wp-image-389" width="204" height="300" srcset="https://oldblog.natebarney.com/wp-content/uploads/2023/07/EC11-Pinout-204x300.png 204w, https://oldblog.natebarney.com/wp-content/uploads/2023/07/EC11-Pinout.png 533w" sizes="auto, (max-width: 204px) 100vw, 204px" /><figcaption class="wp-element-caption">EC11 Rotary Encoder Pinout (Top View)</figcaption></figure>



<p>Pins D and E are used for the button functionality. They are normally disconnected from each other, but are shorted together when the shaft is pressed like a button. This is relatively straightforward, and behaves just like almost any other push button. The other signals are a little more surprising. Pins <kbd>A</kbd>, <kbd>B</kbd>, and <kbd>C</kbd> provide information about rotations, but they&#8217;re not simply &#8220;clockwise,&#8221; &#8220;counterclockwise,&#8221; and &#8220;ground&#8221; pins, as I initially expected. </p>



<p><kbd>C</kbd> serves as a common pin, and <kbd>A</kbd> and <kbd>B</kbd> work together to indicate whether the shaft is being turned, and in which direction. They do this by connecting and disconnecting from C using something called <a rel="noreferrer noopener" href="https://en.m.wikipedia.org/wiki/Incremental_encoder#Quadrature_outputs" data-type="URL" data-id="https://en.m.wikipedia.org/wiki/Incremental_encoder#Quadrature_outputs" target="_blank">quadrature encoding</a>. When the EC11 is not being turned, <kbd>A</kbd>, <kbd>B</kbd>, and <kbd>C</kbd> are all disconnected from each other. As the shaft is turned clockwise through one step, the following connections and disconnections happen in sequence:</p>



<ol class="wp-block-list">
<li><kbd>A</kbd> is connected to <kbd>C</kbd>,</li>



<li><kbd>B</kbd> is connected to <kbd>C</kbd>,</li>



<li><kbd>A</kbd> is disconnected from <kbd>C</kbd>,</li>



<li><kbd>B</kbd> is disconnected from <kbd>C</kbd>.</li>
</ol>



<p>For counter-clockwise rotations, the roles of <kbd>A</kbd> and <kbd>B</kbd> are reversed. Note that only one of the two signals changes at any one time. This encoding enables a simple mechanical design for the device, and also eliminates ambiguous transition states that could arise if both signals changed at nearly, but not exactly, the same time.</p>



<p>To illustrate these signals a little better, I connected an EC11 to an oscilloscope and took some captures. (An oscilloscope shows a graph of voltage on the vertical axis vs. time on the horizontal axis.) In all of these images, <kbd>A</kbd> is the yellow trace, and <kbd>B</kbd> is the blue trace. For the first two images, <kbd>C</kbd> was connected to <kbd>V<sub>CC</sub></kbd> (+5V), and <kbd>A</kbd> and <kbd>B</kbd> were each pulled down to <kbd>GND</kbd> (0V) with 10kΩ <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Pull-up_resistor" data-type="URL" data-id="https://en.wikipedia.org/wiki/Pull-up_resistor" target="_blank">pull-down resistors</a>. This means that <kbd>A</kbd> and <kbd>B</kbd> are normally low, but are high while connected to <kbd>C</kbd>. The first image shows clockwise rotation, and the second image shows counter-clockwise rotation.</p>



<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="800" height="420" src="https://blog.natebarney.com/wp-content/uploads/2023/07/EC11-Positive-Clockwise.png" alt="" class="wp-image-380" srcset="https://oldblog.natebarney.com/wp-content/uploads/2023/07/EC11-Positive-Clockwise.png 800w, https://oldblog.natebarney.com/wp-content/uploads/2023/07/EC11-Positive-Clockwise-300x158.png 300w, https://oldblog.natebarney.com/wp-content/uploads/2023/07/EC11-Positive-Clockwise-768x403.png 768w" sizes="auto, (max-width: 800px) 100vw, 800px" /><figcaption class="wp-element-caption">EC11, Positive Polarity, Clockwise Rotation</figcaption></figure>



<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="800" height="420" src="https://blog.natebarney.com/wp-content/uploads/2023/07/EC11-Positive-Counter-clockwise.png" alt="" class="wp-image-379" srcset="https://oldblog.natebarney.com/wp-content/uploads/2023/07/EC11-Positive-Counter-clockwise.png 800w, https://oldblog.natebarney.com/wp-content/uploads/2023/07/EC11-Positive-Counter-clockwise-300x158.png 300w, https://oldblog.natebarney.com/wp-content/uploads/2023/07/EC11-Positive-Counter-clockwise-768x403.png 768w" sizes="auto, (max-width: 800px) 100vw, 800px" /><figcaption class="wp-element-caption">EC11, Positive Polarity, Counter-Clockwise Rotation</figcaption></figure>



<p>For the next two images, <kbd>C</kbd> was connected to <kbd>GND</kbd>, and <kbd>A</kbd> and <kbd>B</kbd> were each pulled up to <kbd>V<sub>CC</sub></kbd> with 10kΩ pull-up resistors. This means that <kbd>A</kbd> and <kbd>B</kbd> are normally high, but are low while connected to <kbd>C</kbd>. As before, the first image shows clockwise rotation, and the second image shows counter-clockwise rotation.</p>



<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="800" height="420" src="https://blog.natebarney.com/wp-content/uploads/2023/07/EC11-Negative-Clockwise.png" alt="" class="wp-image-382" srcset="https://oldblog.natebarney.com/wp-content/uploads/2023/07/EC11-Negative-Clockwise.png 800w, https://oldblog.natebarney.com/wp-content/uploads/2023/07/EC11-Negative-Clockwise-300x158.png 300w, https://oldblog.natebarney.com/wp-content/uploads/2023/07/EC11-Negative-Clockwise-768x403.png 768w" sizes="auto, (max-width: 800px) 100vw, 800px" /><figcaption class="wp-element-caption">EC11, Negative Polarity, Clockwise Rotation</figcaption></figure>



<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="800" height="420" src="https://blog.natebarney.com/wp-content/uploads/2023/07/EC11-Negative-Counter-clockwise.png" alt="" class="wp-image-381" srcset="https://oldblog.natebarney.com/wp-content/uploads/2023/07/EC11-Negative-Counter-clockwise.png 800w, https://oldblog.natebarney.com/wp-content/uploads/2023/07/EC11-Negative-Counter-clockwise-300x158.png 300w, https://oldblog.natebarney.com/wp-content/uploads/2023/07/EC11-Negative-Counter-clockwise-768x403.png 768w" sizes="auto, (max-width: 800px) 100vw, 800px" /><figcaption class="wp-element-caption">EC11, Negative Polarity, Counter-Clockwise Rotation</figcaption></figure>



<p>The choice of connection method may depend on various factors in the larger circuit, but often it will work just fine either way, and the choice is made arbitrarily or by personal preference of the circuit designer.</p>



<h3 class="wp-block-heading">Mechanism</h3>



<p>Before we dig into this section, I should point out that I haven&#8217;t actually taken one of these devices apart, so what follows about the specifics of their construction is speculation and educated guesses on my part. The precise nature and arrangement of the internal parts may differ from what I describe. However, I believe the basic principles are correct.</p>



<p>My understanding is that inside the body of an EC11 are two wipers, or conductive contacts—one connected to pin <kbd>A</kbd> and one to pin <kbd>B</kbd>. The shaft is attached to a rotating plate with a pattern of conductive pads that can make electrical connections to the wipers. These pads are connected to pin <kbd>C</kbd>. It&#8217;s a bit hard to explain with words, so here&#8217;s a diagram:</p>



<figure class="wp-block-image aligncenter size-medium is-resized"><img decoding="async" src="https://blog.natebarney.com/wp-content/uploads/2023/07/EC11_Mechanism-300x161.png" alt="" class="wp-image-387" width="600" srcset="https://oldblog.natebarney.com/wp-content/uploads/2023/07/EC11_Mechanism-300x161.png 300w, https://oldblog.natebarney.com/wp-content/uploads/2023/07/EC11_Mechanism-768x411.png 768w, https://oldblog.natebarney.com/wp-content/uploads/2023/07/EC11_Mechanism.png 1018w" sizes="(max-width: 300px) 100vw, 300px" /><figcaption class="wp-element-caption">Hypothetical EC11 Rotary Encoder Mechanism (Top View)</figcaption></figure>



<p>This diagram is very approximate. For instance, actual EC11&#8217;s have many more than four positions. The ones I&#8217;m using have twenty. However, it should communicate the basic idea. As the shaft and plate rotate, but the wipers stay stationary, one wiper will connect to a pad, then the other wiper will, and then the first wiper will disconnect, then the second will, just as described above. The mechanism also includes <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Detent" data-type="URL" data-id="https://en.wikipedia.org/wiki/Detent" target="_blank">detents</a> that cause the shaft and plate to snap into place with the wipers between pads.</p>



<p>As I said, some of the details above may not be exactly correct. It&#8217;s possible that the wipers move with the shaft over stationary pads. It&#8217;s possible that the pads are not on a plate perpendicular to the shaft, but actually placed on the surface of the shaft itself, with the wipers oriented sideways. It&#8217;s possible all these methods, and others, could be used by different models of encoders. However, I&#8217;m reasonably confident that the general principles outlined above are correct. I welcome feedback and/or corrections from anyone who knows more about this than I do.</p>



<h3 class="wp-block-heading">Contact Bounce</h3>



<p>Things like switches, buttons, and rotary encoders are all subject to a phenomenon known as <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Switch#Contact_bounce" target="_blank">contact bounce</a>. This means that the physical conductors inside the mechanism can actually bounce off of each other and introduce spurious connections and disconnections before finally settling down to the correct state. This can make it appear as though, for example, a button was pressed several times when the user only meant to press it once.</p>



<p>To demonstrate contact bounce with the EC11, I took another oscilloscope capture, this time significantly zoomed in on the time (horizontal) axis. In the previous captures, the oscilloscope was set to 20 ms per division (i.e. background grid cell). To be able to show the bouncing, I set the oscilloscope to 100 μs, or 0.1 ms, per division. There is some inherent randomness to the bouncing.  Sometimes the contacts don&#8217;t bounce at all. Sometimes they bounce a great deal. I ended up turning the EC11 a few times to get a good example of bouncing to capture. The following image was taken with the EC11 connected with positive polarity, and the shaft was rotated clockwise.</p>



<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="800" height="420" src="https://blog.natebarney.com/wp-content/uploads/2023/07/EC11-Contact-Bounce.png" alt="" class="wp-image-408" srcset="https://oldblog.natebarney.com/wp-content/uploads/2023/07/EC11-Contact-Bounce.png 800w, https://oldblog.natebarney.com/wp-content/uploads/2023/07/EC11-Contact-Bounce-300x158.png 300w, https://oldblog.natebarney.com/wp-content/uploads/2023/07/EC11-Contact-Bounce-768x403.png 768w" sizes="auto, (max-width: 800px) 100vw, 800px" /><figcaption class="wp-element-caption">EC11 Contact Bounce</figcaption></figure>



<p>There are several ways to deal with contact bounce, including both hardware and software solutions, with varying levels of complexity. It might be worth going into this topic in more detail in a future post. However, one simple software solution is to keep track of the previously read value of the input pin, and introduce a delay between reads. The software can then react when there&#8217;s a difference between the previous value and the current value. If the delay is sufficiently short, the user won&#8217;t notice it, and if the delay is sufficiently long, the bouncing will have stopped by the time the pin is read again. In practice, I&#8217;ve found that delays of a few milliseconds work pretty well.</p>



<h3 class="wp-block-heading">Arduino Sketch</h3>



<p>I&#8217;ve put together a simple circuit and Arduino sketch to demonstrate how to use these devices. Feel free to use or adapt this code in your own projects. We&#8217;ll first take a look at the hardware setup, then we&#8217;ll discuss the code.</p>



<p>This example uses an Arduino Uno R3, but it should work with almost any Arduino. Similarly, while this example (somewhat arbitrarily) uses Arduino pins 2, 3, and 4 to connect to the EC11, any free GPIO pins should do. The EC11 is connected with positive polarity. (Changing the hardware connections and sketch code to use the EC11 with negative polarity is relatively straightforward, and is left as an exercise for the reader.)</p>



<figure class="wp-block-image aligncenter size-large is-resized"><img loading="lazy" decoding="async" src="https://blog.natebarney.com/wp-content/uploads/2023/07/EC11-Arduino-Breadboard-1024x604.png" alt="" class="wp-image-412" width="768" height="453" srcset="https://oldblog.natebarney.com/wp-content/uploads/2023/07/EC11-Arduino-Breadboard-1024x604.png 1024w, https://oldblog.natebarney.com/wp-content/uploads/2023/07/EC11-Arduino-Breadboard-300x177.png 300w, https://oldblog.natebarney.com/wp-content/uploads/2023/07/EC11-Arduino-Breadboard-768x453.png 768w, https://oldblog.natebarney.com/wp-content/uploads/2023/07/EC11-Arduino-Breadboard-1536x906.png 1536w, https://oldblog.natebarney.com/wp-content/uploads/2023/07/EC11-Arduino-Breadboard.png 1603w" sizes="auto, (max-width: 768px) 100vw, 768px" /><figcaption class="wp-element-caption">Arduino EC11 Example Circuit</figcaption></figure>



<p>Connect the Arduino&#8217;s <kbd>5V</kbd> pin to the positive breadboard rails and connect the Arduino&#8217;s <kbd>GND</kbd> to the negative breadboard rails. Connect EC11 pins <kbd>C</kbd> and <kbd>E</kbd> to the positive rails as well. Connect EC11 pins <kbd>A</kbd>, <kbd>B</kbd>, and <kbd>D</kbd> to the negative breadboard rails through 10kΩ resistors. (Since these are pull-down resistors, the resistor values themselves don&#8217;t matter too much, as long as they&#8217;re large-ish.) Connect EC11 pin <kbd>A</kbd> to Arduino pin <kbd>3</kbd>, EC11 pin <kbd>B</kbd> to Arduino pin <kbd>4</kbd>, and EC11 pin <kbd>D</kbd> to Arduino pin <kbd>2</kbd>.</p>



<p>Now that the circuit is hooked up, we can move on to the code. The following code uses a simple polling loop with a basic software debouncing scheme, and simply prints messages over the serial connection when the EC11 is rotated or pressed. It should be straightforward to adapt this code to do other things on these events instead.</p>



<p>To read the rotation state, we first check to see if pin <kbd>A</kbd> is going from low to high. This rising edge occurs every time the EC11 is rotated. The direction is then determined by looking at the <kbd>B</kbd> pin at the moment of <kbd>A</kbd>&#8216;s rising edge. In a clockwise rotation, <kbd>A</kbd> goes high before <kbd>B</kbd> does, so while <kbd>A</kbd> is going high, <kbd>B</kbd> will still be low. In a counter-clockwise rotation, <kbd>B</kbd> goes high before <kbd>A</kbd>, so while <kbd>A</kbd> is going high, <kbd>B</kbd> will already be high. If this isn&#8217;t clear, it might help to take another look at the oscilloscope captures above.</p>



<p>We only need to check B when we&#8217;ve already determined there&#8217;s a rising edge on <kbd>A</kbd>, so the code below omits that check in other cases. Also note that we don&#8217;t need to debounce <kbd>B</kbd>, because bouncing happens right after a state change, and we only read <kbd>B</kbd> well before or after its state changes.</p>



<p>The button press events are handled slightly differently from the rotation events. We check for both rising and falling edges on the button input. A rising edge corresponds to the button being pressed, and a falling edge corresponds to the button being released. It&#8217;s sometimes useful to track both types of button events, so they&#8217;re included in the example.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="cpp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">//
// ec11_example.ino
//
// Example Arduino sketch to demonstrate reading an EC11 rotary encoder
//

// Pin definitions
#define EC11_PIN_A 3
#define EC11_PIN_B 4
#define EC11_PIN_D 2

// Number of milliseconds to wait between pin reads, for software debouncing
#define DEBOUNCE_DELAY_MILLIS 3

// Global variables to hold the previous state of the EC11 pins, initialized
// to LOW. We don't need to track the previous state of B to debounce it
// because we don't read it near an edge, and any bouncing should already
// have stopped by the time we do read it.
int prevA = LOW;
int prevD = LOW;

// Runs once at beginning of sketch
void setup()
{
  // Set pins to input
  pinMode(EC11_PIN_A, INPUT);
  pinMode(EC11_PIN_B, INPUT);
  pinMode(EC11_PIN_D, INPUT);

  // Initialize serial connection
  Serial.begin(9600);
}

// Runs continually in a loop after setup is complete
void loop()
{
  // Local variables to hold the current state of the pins
  int currentA;
  int currentB;
  int currentD;

  // Wait a bit to allow any contact bounce to settle
  delay(DEBOUNCE_DELAY_MILLIS);

  // Process rotation pins
  currentA = digitalRead(EC11_PIN_A);
  if ((prevA == LOW) &amp;&amp; (currentA == HIGH))
  {
    // There's a rising edge on A, so the EC11 is being rotated. The state
    // of B at the rising edge of A indicates the direction. If B is low,
    // then A went high first, and the rotation is clockwise. If B is high,
    // then B went high first, and the rotation is counter-clockwise.
    currentB = digitalRead(EC11_PIN_B);

    if (currentB == LOW)
    {
      Serial.println("Clockwise");
    }
    else
    {
      Serial.println("Counter-clockwise");
    }
  }

  // Process button pin
  currentD = digitalRead(EC11_PIN_D);
  if ((prevD == LOW) &amp;&amp; (currentD == HIGH))
  {
    Serial.println("Pressed");
  }
  else if ((prevD == HIGH) &amp;&amp; (currentD == LOW))
  {
    Serial.println("Released");
  }

  // update previous state globals
  prevA = currentA;
  prevD = currentD;
}</pre>



<p>After building this circuit and compiling and uploading the sketch to the Arduino, open the serial monitor and set it to 9600 baud. Then, turn and press the EC11. You should see output similar to the following in the serial monitor:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Clockwise
Counter-clockwise
Pressed
Released
Pressed
Clockwise
Counter-clockwise
Released</pre>



<h3 class="wp-block-heading">Summary</h3>



<p>So, that&#8217;s about as much as I can say about the EC11 rotary encoder. It&#8217;s a cool little device, and can be used to build pretty nice user interfaces for hobbyist projects using Arduino&#8217;s, or Raspberry Pi&#8217;s, or any other microcontroller. Feel free to reach out if you have any questions/comments/corrections about anything in this post.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://oldblog.natebarney.com/2023/07/24/ec11-rotary-encoders/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>GPIO Pins, Shift Registers, and SPI</title>
		<link>https://oldblog.natebarney.com/2023/07/16/gpio-pins-shift-registers-and-spi/</link>
					<comments>https://oldblog.natebarney.com/2023/07/16/gpio-pins-shift-registers-and-spi/#respond</comments>
		
		<dc:creator><![CDATA[Nate Barney]]></dc:creator>
		<pubDate>Sun, 16 Jul 2023 15:35:56 +0000</pubDate>
				<category><![CDATA[Electronics]]></category>
		<category><![CDATA[electronics]]></category>
		<guid isPermaLink="false">https://blog.natebarney.com/?p=274</guid>

					<description><![CDATA[When using microcontrollers, like the ATmega line of chips, or boards based on them, like the Arduino series, General Purpose Input/Output (GPIO) pins are often at a premium.  The Arduino Uno R3 (based on the ATmega328P), for example, has a maximum of fourteen GPIO pins [...]]]></description>
										<content:encoded><![CDATA[
<h3 class="wp-block-heading">Microcontroller GPIO Pins</h3>



<p>When using microcontrollers, like the ATmega line of chips, or boards based on them, like the Arduino series, <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/General-purpose_input/output" data-type="URL" data-id="https://en.wikipedia.org/wiki/General-purpose_input/output" target="_blank">General Purpose Input/Output (GPIO)</a> pins are often at a premium.  The <a rel="noreferrer noopener" href="https://docs.arduino.cc/hardware/uno-rev3" data-type="URL" data-id="https://docs.arduino.cc/hardware/uno-rev3" target="_blank">Arduino Uno R3</a> (based on the <a href="https://www.microchip.com/en-us/product/ATMEGA328P" data-type="URL" data-id="https://www.microchip.com/en-us/product/ATMEGA328P" target="_blank" rel="noreferrer noopener">ATmega328P</a>), for example, has a maximum of fourteen GPIO pins, and that&#8217;s if you&#8217;re not using some of the pins&#8217; special functions.</p>



<p>It&#8217;s very easy to run out of these GPIO pins if multiple devices are connected directly to them. Each LED uses one pin, configured as an output. Each button uses one pin, configured as an input. A <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Seven-segment_display" data-type="URL" data-id="https://en.wikipedia.org/wiki/Seven-segment_display" target="_blank">seven-segment display</a> uses eight outputs (there&#8217;s a decimal point that&#8217;s not counted in the name for some reason). In its most minimal configuration, an <a href="https://en.wikipedia.org/wiki/Hitachi_HD44780_LCD_controller" data-type="URL" data-id="https://en.wikipedia.org/wiki/Hitachi_HD44780_LCD_controller">LCD character display</a> module uses six pins, but can be configured to use as many as eleven pins. All this quickly adds up.</p>



<h3 class="wp-block-heading">Shift Registers</h3>



<p>A common solution to the problem of too few GPIO pins is to use one or more shift registers. Simply put, a <a rel="noreferrer noopener" href="https://en.m.wikipedia.org/wiki/Shift_register" data-type="URL" data-id="https://en.m.wikipedia.org/wiki/Shift_register" target="_blank">shift register</a> is a chip that converts a single signal changing over time (i.e. serial) to multiple signals at the same time (i.e. parallel), or vice-versa. This solution is so common that the Arduino core library has functions specifically to support their use, and there are <a href="https://duckduckgo.com/?q=arduino+shift+register+tutorial" data-type="URL" data-id="https://duckduckgo.com/?q=arduino+shift+register+tutorial" target="_blank" rel="noreferrer noopener">lots of Arduino/shift-register tutorials</a> to be found on the internet. (I guess I&#8217;m adding to that list.)</p>



<p>There are many different types of shift register available, but two of the most popular are the <a rel="noreferrer noopener" href="https://www.ti.com/product/SN74HC595" data-type="URL" data-id="https://www.ti.com/product/SN74HC595" target="_blank">74HC595</a> (to add output pins) and the <a rel="noreferrer noopener" href="https://www.ti.com/product/SN74HC165" data-type="URL" data-id="https://www.ti.com/product/SN74HC165" target="_blank">74HC165</a> (to add input pins). These chips are easy to use, inexpensive, and readily available. You can get them from electronics suppliers like <a rel="noreferrer noopener" href="https://www.mouser.com/c/?q=74hc595" data-type="URL" data-id="https://www.mouser.com/c/?q=74hc595" target="_blank">Mouser</a> and <a href="https://www.digikey.com/en/products/filter/shift-registers/712?s=N4IgTCBcDaIOwBYAWBjArATjSAugXyA" data-type="URL" data-id="https://www.digikey.com/en/products/filter/shift-registers/712?s=N4IgTCBcDaIOwBYAWBjArATjSAugXyA">DigiKey</a>, and they&#8217;re even available from <a rel="noreferrer noopener" href="https://www.amazon.com/s?k=74hc595" data-type="URL" data-id="https://www.amazon.com/s?k=74hc595" target="_blank">Amazon</a>.</p>



<p>The basic principle behind shift registers, and the reason for their name, is that each chip holds a number of bits (typically eight) in a small memory circuit called a register, and these bits <em>shift</em> from one to the next when a clock pulse is applied. Bit 0 shifts into bit 1, bit 1 shifts into bit 2, and so on. The new value for bit 0 comes from a serial input pin at the time of the clock pulse. The last bit falls out of the shift register, and is made available on one of the chip&#8217;s output pins, called serial output. Typically, the shift happens on the <em>rising</em> edge of the clock pulse (i.e. from low to high).</p>



<p>The fact that each shift register has a serial input pin that feeds into bit 0 and a serial output pin that holds the value of the last bit as it&#8217;s shifted out means that these chips may be <em>cascaded</em>, or chained together, by connecting the serial output of one chip to the serial input of another, and by connecting their clocks together. Two 8-bit shift registers cascaded together, for example, behave as if they were a single 16-bit shift register. The number of chips that can be cascaded into a single effective register is typically limited only by things like available power and the capacitance of the connecting wires, but the chain would need to be pretty long for those things to start to matter.</p>



<p>There are a few disadvantages to using shift registers for GPIO expansion. First, it&#8217;s slower. Instead of reading or writing several pins at once, the microcontroller has to process them one at a time. Second, the pins can&#8217;t be read or written independently. To read/write bit 4, for example, bits 0-3 must first be read/written. When the shift register is being used to add output pins, this means the software needs to keep track of what bits have been written. Third, most shift registers are unidirectional. That is, each type of chip provides either inputs or outputs, but not both. (The <a rel="noreferrer noopener" href="https://www.ti.com/product/CD74HC299" data-type="URL" data-id="https://www.ti.com/product/CD74HC299" target="_blank">74HC299</a> is one exception to this.) In practice, however, these disadvantages are often easily overcome and are more than made up for by the added inputs and/or outputs.</p>



<h5 class="wp-block-heading">74HC595</h5>



<p>The 74HC595 is an 8-bit Serial-In / Parallel-Out (SIPO) shift register. It shifts in one bit from its serial input pin (pin 14) on each rising edge of its serial clock pin (pin 11), and has eight parallel output pins (pins 15 and 1-7). However, the bits in the shift register are not immediately made available on the output pins.</p>



<p>The 74HC595 internally has two registers: the shift register and the storage register (sometimes called the latch register). The shift register behaves as described above. However, the parallel output pins are not connected directly to the shift register, but rather to the storage register. The contents of the shift register are transferred to the storage register (and therefore the output pins) on the rising edge of a second clock pin (pin 12), called the storage clock pin (or sometimes the latch pin).</p>



<p>This dual-register configuration may seem like a needless complication. Worse, instead of just two GPIO pins (serial input and serial clock), it uses those plus a third (storage clock). However, there is a good reason for this design. Some devices connected to the 75HC595&#8217;s output pins may not react well to the data shifting along one bit at a time. The two-register approach allows data bits to be shifted in while keeping the output pins unchanged, then all made available effectively simultaneously once the complete set of bits is ready.</p>



<p>If a device can tolerate seeing the data shift one bit at a time, the serial clock and storage clock pins may be connected together. This causes the 74HC595 to behave (more or less) as if the outputs were connected directly to the internal shift register, and it only requires a total of two GPIO pins instead of three.</p>



<p>To interface a 74HC595 with an Arduino (or similar microcontroller), connect the serial input, serial clock, and storage clock pins of the 74HC595 to GPIO pins on the microcontroller, with all three configured as outputs. Then, in the microcontroller code (i.e. Arduino sketch), write each bit to the shift register as follows.</p>



<ol class="wp-block-list">
<li>Set the serial input pin to the value of the data bit.</li>



<li>Bring the serial clock pin low, then high, to create a rising edge and shift the bit.</li>



<li>Repeat steps 1 and 2 until all bits have been shifted.</li>



<li>Once all bits have been shifted, bring the storage clock low then high to transfer the bits to the parallel output pins.</li>
</ol>



<p>Step 4 can be omitted if the serial clock and storage clock are tied together. The Arduino core library function <kbd><a rel="noreferrer noopener" href="https://www.arduino.cc/reference/en/language/functions/advanced-io/shiftout/" data-type="URL" data-id="https://www.arduino.cc/reference/en/language/functions/advanced-io/shiftout/" target="_blank">shiftOut()</a></kbd> performs steps 1 and 2 in a loop to write eight bits. </p>



<p>The 74HC595 has a few other useful features, including tri-state outputs and a reset pin. The <a rel="noreferrer noopener" href="https://www.ti.com/lit/ds/symlink/sn74hc595.pdf" data-type="URL" data-id="https://www.ti.com/lit/ds/symlink/sn74hc595.pdf" target="_blank">datasheet</a> has more information about these if you&#8217;re interested, but they&#8217;re not particularly relevant to this post, so that&#8217;s all I&#8217;ll say about them here.</p>



<h5 class="wp-block-heading">74HC165</h5>



<p>The 74HC165 is an 8-bit Parallel-In / Serial-Out (PISO) shift register. Data bits are loaded into the chip all at once from eight parallel input pins (pins 11-14 and 3-6) while the parallel load pin (pin 1) is set low. Once the bits are loaded, they can be shifted out one at a time to the serial output pin (pin 9) by pulsing the serial clock pin (pin 2). Bits are shifted on the rising edge of the clock pulse, and the serial input pin (pin 10) provides a new value for bit 0 on each pulse.</p>



<p>The process to interface the 74HC165 with a microcontroller is very similar to the process for the 74HC595. Connect the 74HC165&#8217;s serial clock and parallel load pins to output pins on the microcontroller, and connect the 74HC165&#8217;s serial output pin to a microcontroller input pin. Then, in software, perform the following:</p>



<ol class="wp-block-list">
<li>Bring the parallel load pin low, then high to latch the inputs into the shift register.</li>



<li>Bring the serial clock pin low.</li>



<li>Bring the serial clock pin high to create a rising edge and shift out a bit.</li>



<li>Read and process the data bit from the serial output pin.</li>



<li>Bring the serial clock pin back low to prepare for the next bit.</li>



<li>Repeat steps 3 through 5 for each bit.</li>
</ol>



<p>The Arduino core library function <kbd><a rel="noreferrer noopener" href="https://www.arduino.cc/reference/en/language/functions/advanced-io/shiftin/" data-type="URL" data-id="https://www.arduino.cc/reference/en/language/functions/advanced-io/shiftin/" target="_blank">shiftIn()</a></kbd> performs steps 3 through 5 in a loop to read eight bits. </p>



<p>Like the 74HC595, the 74HC165 has additional features, such as clock inhibit and complementary serial output, that I&#8217;m not going to discuss here. For more information, see the <a rel="noreferrer noopener" href="https://www.ti.com/lit/ds/symlink/sn74hc165.pdf" data-type="URL" data-id="https://www.ti.com/lit/ds/symlink/sn74hc165.pdf" target="_blank">datasheet</a>. </p>



<h3 class="wp-block-heading">Serial Peripheral Interface (SPI)</h3>



<p>The <a rel="noreferrer noopener" href="https://en.m.wikipedia.org/wiki/Serial_Peripheral_Interface" data-type="URL" data-id="https://en.m.wikipedia.org/wiki/Serial_Peripheral_Interface" target="_blank">Serial Peripheral Interface (SPI)</a> protocol is another way to reduce the number of microntroller GPIO pins needed for a project. There are many devices that support SPI natively, and there are quite a few available on <a rel="noreferrer noopener" href="https://www.amazon.com/s?k=spi+arduino+module" data-type="URL" data-id="https://www.amazon.com/s?k=spi+arduino+module" target="_blank">Amazon</a>, for instance. The protocol is relatively simple, and it&#8217;s straightforward to implement in software. Ben Eater has an excellent <a rel="noreferrer noopener" href="https://youtu.be/MCi7dCBhVpQ" data-type="URL" data-id="https://youtu.be/MCi7dCBhVpQ" target="_blank">video</a> in which he interfaces an SPI device with a <a rel="noreferrer noopener" href="https://www.westerndesigncenter.com/wdc/w65c02s-chip.php" data-type="URL" data-id="https://www.westerndesigncenter.com/wdc/w65c02s-chip.php" target="_blank">65C02</a> microprocessor using assembly code. However, most microcontrollers, including Arduinos, have hardware support for communicating via SPI. This enables much faster speeds than would be possible with a software implementation.</p>



<p>SPI is, as its name implies, a serial protocol. This means that one bit is transferred at a time. Actually, that&#8217;s not quite true, since SPI supports full-duplex bidirectional communication. This means that one bit is sent and one bit is received at the same time. It&#8217;s also a sychronous protocol, which means that the timing is controlled by a dedicated clock signal. Finally, it&#8217;s an asymmetric protocol. This means that the communication is entirely controlled by one device, called the master (sometimes controller). This is usually the microcontroller. The other device is called the slave (sometimes peripheral), and it sends and receives data only as directed by the master. Multiple slave devices can be connected to a single master.</p>



<p>The basic setup for SPI uses four different signals, each on a separate pin:</p>



<ul class="wp-block-list">
<li><strong>Serial Clock (<kbd>SCK</kbd>)</strong>: This is the signal that controls the rate of the data transfer, and is driven by the master. One bit is transferred in each direction when this signal is pulsed. SPI doesn&#8217;t specify whether the bit is transferred on the rising or falling edge of the clock signal. Instead, that&#8217;s left up to the individual implementation. Most microcontrollers will have an option to specify this as part of the SPI mode setting. SPI modes 0 and 3 transfer on the rising edge, and modes 1 and 2 transfer on the falling edge. Mode 0 differs from 3, and 1 from 2, in the level of the clock signal when idle. Modes 0 and 1 keep the clock low when idle, and 2 and 3 keep it high. The datasheet for the slave device will specify which mode(s) it expects, but mode 0 is typical.</li>



<li><strong>Master Out / Slave In (<kbd>MOSI</kbd>)</strong>: This is a data transmission signal over which the master sends data bits to the slave, at the rate dictated by the <kbd>SCK</kbd> signal. Note that this way of naming the signal is unambiguous about direction, and can be labeled the same on both master and slave devices. If the slave device is read-only (e.g. a sensor of some sort), this signal may be omitted. This signal is also sometimes called Controller Out / Peripheral In (<kbd>COPI</kbd>). On slave devices, this signal may also be called Data In (<kbd>DI</kbd>, <kbd>DIN</kbd>) or Serial Data In (<kbd>SDI</kbd>).</li>



<li><strong>Master In / Slave Out (<kbd>MISO</kbd>)</strong>: This is a data transmission signal over which the slave sends data bits to the master, at the rate dictated by the <kbd>SCK</kbd> signal. If the slave device is write-only (e.g. a display of some sort), this signal may be omitted. This signal is also sometimes called Controller In / Peripheral Out (<kbd>COPI</kbd>). On slave devices, this signal may also be called Data Out (<kbd>DO</kbd>, <kbd>DOUT</kbd>) or Serial Data Out (<kbd>SDO</kbd>).</li>



<li><strong>Slave Select (<span style="text-decoration: overline;"><kbd>SS</kbd></span>)</strong>: This is a control signal which activates the slave (i.e. tells it to pay attention to the other signals). The overbar on the abbreviation indicates that this signal is active low, and is pronounced by adding &#8220;bar&#8221; after the abbreviation (i.e. &#8220;ess ess bar&#8221;). In contexts where overbars are typographically difficult, this may be rendered as <kbd>/SS</kbd> or <kbd>SSB</kbd> (&#8220;B&#8221; for &#8220;Bar&#8221;). Active low means that the slave is selected when this signal is low, and deselected when the signal is high. When multiple slave devices are connected, each device is assigned its own <span style="text-decoration: overline;"><kbd>SS</kbd></span> signal. The other signals are shared among all slave devices. Usually, only one slave is selected at any one time. This signal is also sometimes called Chip Select (<span style="text-decoration: overline;"><kbd>CS</kbd></span>, <kbd>/CS</kbd>, <kbd>CSB</kbd>).</li>
</ul>



<p>To perform SPI transfers in software, make sure the relevant signals are connected between the master and slave, and perform the following:</p>



<ol class="wp-block-list">
<li>Bring the <span style="text-decoration: overline"><kbd>SS</kbd></span> pin low to select the slave device.</li>



<li>Set the <kbd>MOSI</kbd> pin to the value of the outgoing bit. (Omit for read-only slave.)</li>



<li>Pulse the <kbd>SCK</kbd> pin (high then low, or low then high, depending on mode).</li>



<li>Read the incoming bit from the <kbd>MISO</kbd> pin. (Omit for write-only slave.)</li>



<li>Repeat steps 2 through 4 until all bits are transferred.</li>



<li>Bring the <span style="text-decoration: overline;"><kbd>SS</kbd></span> pin high to deselect the slave device.</li>
</ol>



<p>As previously mentioned, most microcontrollers have SPI support built in hardware. The SPI hardware in the Arduino Uno&#8217;s ATmega328P can run the serial clock at up to half the rate of the system clock, which is 16 MHz on an Arduino Uno, so the Arduino can do SPI at up to 8 MHz. This is significantly faster than would be possible with a pure software implementation. Some microcontrollers can run the SPI serial clock at 10&#8217;s or even 100&#8217;s of MHz.</p>



<p>To use the microcontroller&#8217;s SPI hardware to perform transfers, <kbd>MOSI</kbd>, <kbd>MISO</kbd>, and <kbd>SCK</kbd> on the slave should be connected to the corresponding SPI pins on the microcontroller. On the Arduino Uno R3, <kbd>MOSI</kbd> is pin 11, <kbd>MISO</kbd> is pin 12, and <kbd>SCK</kbd> is pin 13. The slave&#8217;s <span style="text-decoration: overline"><kbd>SS</kbd></span> pin can be connected to any free GPIO pin on the master, configured as an output. The Arduino has a pin labeled <span style="text-decoration: overline"><kbd>SS</kbd></span> (pin 10), but it&#8217;s only necessary to use that when connecting the Arduino as a slave to another SPI master.</p>



<p>Once everything is connected, issue the microcontroller instructions to enable and use the SPI hardware. In an Arduino sketch, this can be done with the <a rel="noreferrer noopener" href="https://www.arduino.cc/reference/en/language/functions/communication/spi/" data-type="URL" data-id="https://www.arduino.cc/reference/en/language/functions/communication/spi/" target="_blank">SPI</a> library, specifically the functions <kbd><a rel="noreferrer noopener" href="https://www.arduino.cc/reference/en/language/functions/communication/spi/begin/" data-type="URL" data-id="https://www.arduino.cc/reference/en/language/functions/communication/spi/begin/" target="_blank">SPI.begin()</a></kbd> (called once to enable the SPI hardware), <kbd><a rel="noreferrer noopener" href="https://www.arduino.cc/reference/en/language/functions/communication/spi/begintransaction/" data-type="URL" data-id="https://www.arduino.cc/reference/en/language/functions/communication/spi/begintransaction/" target="_blank">SPI.beginTransaction()</a></kbd> (called once before each batch of transfers), <kbd><a rel="noreferrer noopener" href="https://www.arduino.cc/reference/en/language/functions/communication/spi/transfer/" data-type="URL" data-id="https://www.arduino.cc/reference/en/language/functions/communication/spi/transfer/" target="_blank">SPI.transfer()</a></kbd> (called any number of times to transfer a batch of eight bits each time), and <kbd><a rel="noreferrer noopener" href="https://www.arduino.cc/reference/en/language/functions/communication/spi/endtransaction/" data-type="URL" data-id="https://www.arduino.cc/reference/en/language/functions/communication/spi/endtransaction/" target="_blank">SPI.endTransaction()</a></kbd> (called once after each batch of transfers). If you need to disable the SPI hardware again for some reason, that can be done with function <kbd><a rel="noreferrer noopener" href="https://www.arduino.cc/reference/en/language/functions/communication/spi/end/" data-type="URL" data-id="https://www.arduino.cc/reference/en/language/functions/communication/spi/end/" target="_blank">SPI.end()</a></kbd>. The <span style="text-decoration: overline"><kbd>SS</kbd></span> pin must still be handled explicitly by the software, but the others will be taken care of by the hardware. </p>



<h3 class="wp-block-heading">Using Shift Registers with SPI</h3>



<p>You may have noticed that the protocols for shift registers and SPI are remarkably similar, and wondered if they could be used together. In fact, they can! (If you didn&#8217;t notice, don&#8217;t worry too much; it took me way longer than I care to admit to notice it myself.) With just a few extra chips, 74HC595 and 74HC165 can be used to build a hardware SPI interface for a device which normally uses a parallel interface, thereby significantly reducing the number of GPIO pins used by the design, while only sacrificing a little bit of speed.</p>



<p>Shift registers and SPI each have serial clock signals, so those can simply be connected together. Similarly, SPI&#8217;s <kbd>MOSI</kbd> signal can be connected to the serial input signal of a 74HC595 shift register, and SPI&#8217;s <kbd>MISO</kbd> signal can be connected to the serial output signal of a 74HC165 shift register (although there&#8217;s a complication with <kbd>MISO</kbd> that we&#8217;ll discuss a little later). This takes care of three of the four SPI signals, and two of the three signals needed for each shift register.</p>



<p>The remaining signals, SPI&#8217;s <span style="text-decoration: overline;"><kbd>SS</kbd></span>, the 74HC595&#8217;s storage clock, and the 74HC165&#8217;s parallel load require just a little more thought. Recall that <span style="text-decoration: overline;"><kbd>SS</kbd></span> is brought low before an SPI transfer, and high after the transfer is complete. Recall also that the 74HC595&#8217;s storage clock needs a rising edge to move the data from the shift register to the storage register. That rising edge can be provided at just the right time by connecting <span style="text-decoration: overline;"><kbd>SS</kbd></span> to the 74HC595&#8217;s storage clock pin. This does mean that the slave device must be deselected after transferring each set of bits, but in practice, that&#8217;s not a significant disadvantage, just something to be aware of.</p>



<p>Before each transfer, the 74HC165&#8217;s parallel load pin needs to be set low to load data into the shift register, and high to enable that data to be shifted out. This is the inverse of the <span style="text-decoration: overline;"><kbd>SS</kbd></span> signal, which is set high then low before each transfer. To correct this, we can use an <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Inverter_(logic_gate)" data-type="URL" data-id="https://en.wikipedia.org/wiki/Inverter_(logic_gate)" target="_blank">inverter</a> (a.k.a. a NOT gate) to flip the <span style="text-decoration: overline;"><kbd>SS</kbd></span> signal to be what we need for the parallel load pin. The <a rel="noreferrer noopener" href="https://www.ti.com/product/SN74HC04" data-type="URL" data-id="https://www.ti.com/product/SN74HC04" target="_blank">74HC04</a> has six inverters, which is more than we need, but will work for our purposes. (The inverters we&#8217;re not using could be used in other parts of a larger circuit, or their inputs can simply be connected to <kbd>GND</kbd> or <kbd>V<sub>CC</sub></kbd> to keep them from floating and introducing noise into the circuit.) If we connect <span style="text-decoration: overline;"><kbd>SS</kbd></span> to the input of one of these inverters, and the output of that inverter to the 74HC165&#8217;s parallel load pin, the 74HC165 will continually load data into its shift register until it&#8217;s selected, at which point it will latch that data and make it ready to be shifted out by the other SPI signals.</p>



<p>If this SPI interface that we&#8217;ve built out of shift registers is the only slave connected to the SPI pins, then we&#8217;re done; all that&#8217;s left is to connect the shift registers&#8217; parallel inputs and outputs to the device. However, recall that if the SPI hardware is shared, <kbd>MOSI</kbd>, <kbd>MISO</kbd>, and <kbd>SCK</kbd> are also shared among all slave devices. For the 74HC595, this is no problem. It will shift bits in and out of its shift register even while another slave is selected, but its parallel output pins will stay latched, because they are controlled by its <span style="text-decoration: overline;"><kbd>SS</kbd></span> signal. The 74HC165 is another matter. If another slave is selected and <kbd>SCK</kbd> is pulsed, the 74HC165 will still shift bits out into the <kbd>MISO</kbd> pin, interfering with the signal coming from the other slave.</p>



<p>To fix this, we need to connect the 74HC165&#8217;s serial output to <kbd>MISO</kbd> only while its <span style="text-decoration: overline;"><kbd>SS</kbd></span> signal is low. This can be accomplished with a <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Three-state_logic" data-type="URL" data-id="https://en.wikipedia.org/wiki/Three-state_logic" target="_blank">tri-state</a> buffer. A tri-state buffer is a logic gate that has a data input, a control input, and a data output. The control input is active low, and when it&#8217;s low, the value on the data input is propagated to the data output. When the control input is high, the data output is set to high impedance, which basically means it&#8217;s not connected. The <a rel="noreferrer noopener" href="https://www.ti.com/product/SN74HC125" data-type="URL" data-id="https://www.ti.com/product/SN74HC125" target="_blank">74HC125</a> contains four tri-state buffers. Again, we only need one, but that&#8217;s okay. We connect the 74HC165&#8217;s serial output to the data input of one of the 74HC125&#8217;s tri-state buffers, connect the output of that tri-state buffer to <kbd>MISO</kbd>, and connect <span style="text-decoration: overline;"><kbd>SS</kbd></span> to the tri-state buffer&#8217;s control input. Now, the 74HC165 can only send data on <kbd>MISO</kbd> when it&#8217;s selected, which is exactly what we want.</p>



<p>As previously mentioned, shift registers of the same type may be cascaded together to create shift registers that hold more bits. This remains true when using them with SPI. If you&#8217;re building an SPI interface for a device that has sixteen inputs and twenty-four outputs, you can cascade two 74HC595&#8217;s together and three 74HC165&#8217;s. The principles are the same; there are just more bits. If the cascaded chains are of unequal length, then each transfer should include enough bits for the longest chain. The extra bits for the shorter chain can safely be ignored by the software. If the device is read-only or write-only, the interface can be built using only one of the two types of shift registers.</p>



<h3 class="wp-block-heading">Conclusion</h3>



<p>Both SPI and shift registers are useful ways to reduce the number of microcontroller GPIO pins needed for a design. Combining them (and adding a bit of glue logic) is a great way to do so without sacrificing much speed. I&#8217;ve used this technique in some of my projects and it&#8217;s worked very well. If you use this in your projects, I&#8217;d enjoy hearing about what went well or not so well. I hope that this post has been informative and enjoyable. If I&#8217;ve made any errors or left out important details, please do let me know.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://oldblog.natebarney.com/2023/07/16/gpio-pins-shift-registers-and-spi/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>ApOPL3xy Update &#8211; Patches, Omni Mode, and Percussion</title>
		<link>https://oldblog.natebarney.com/2023/07/03/apopl3xy-update-patches-omni-mode-and-percussion/</link>
					<comments>https://oldblog.natebarney.com/2023/07/03/apopl3xy-update-patches-omni-mode-and-percussion/#respond</comments>
		
		<dc:creator><![CDATA[Nate Barney]]></dc:creator>
		<pubDate>Mon, 03 Jul 2023 20:37:40 +0000</pubDate>
				<category><![CDATA[ApOPL3xy]]></category>
		<category><![CDATA[electronics]]></category>
		<category><![CDATA[music]]></category>
		<category><![CDATA[opl3]]></category>
		<category><![CDATA[projects]]></category>
		<guid isPermaLink="false">https://blog.natebarney.com/?p=250</guid>

					<description><![CDATA[I’ve added some new features to the ApOPL3xy synthesizer project I talked about in my last post. Some technical details follow, but first, let’s check out what the new version can do. Specifically, MIDI files can now be played from a computer (or other sequencer) into the ApOPL3xy to be synthesized. [...]]]></description>
										<content:encoded><![CDATA[
<h3 class="wp-block-heading">Introduction</h3>



<p>I&#8217;ve added some new features to the ApOPL3xy synthesizer project I talked about in my <a rel="noreferrer noopener" href="https://blog.natebarney.com/2023/06/25/apopl3xy-a-midi-opl3-based-fm-synthesizer/" data-type="post" data-id="233" target="_blank">last post</a>. Some technical details follow, but first, let&#8217;s check out what the new version can do. Specifically, MIDI files can now be played from a computer (or other sequencer) into the ApOPL3xy to be synthesized.</p>



<h3 class="wp-block-heading">Demo Songs</h3>



<p>Here are some example songs. These songs were recorded by playing MIDI files from a computer into the ApOPL3xy&#8217;s MIDI-In port, running its audio output into the computer&#8217;s line-in jack, and capturing the line-in signal with <a rel="noreferrer noopener" href="https://www.audacityteam.org/" target="_blank">Audacity</a>. None of these files were post-processed in any way, other than to crop off leading and trailing silence. Links to the source MIDI file and the recorded MP3 are available for each song.</p>



<p><strong>Harold Faltermeyer &#8211; Axel F (Beverly Hills Cop Theme)</strong> [<a rel="noreferrer noopener" href="https://bitmidi.com/axel-f-2-mid" data-type="URL" data-id="https://bitmidi.com/axel-f-2-mid" target="_blank">MIDI</a>] [<a rel="noreferrer noopener" href="https://blog.natebarney.com/wp-content/uploads/2023/07/ApOPL3xy-Axel-F.mp3" data-type="attachment" data-id="251" target="_blank" download="">MP3</a>]</p>



<figure class="wp-block-audio"><audio controls src="https://blog.natebarney.com/wp-content/uploads/2023/07/ApOPL3xy-Axel-F.mp3"></audio></figure>



<p><strong>Toto &#8211; Africa</strong> [<a href="https://bitmidi.com/toto-africa-mid" data-type="URL" data-id="https://bitmidi.com/toto-africa-mid" target="_blank" rel="noreferrer noopener">MIDI</a>] [<a href="https://blog.natebarney.com/wp-content/uploads/2023/07/ApOPL3xy-Africa-Fixed.mp3" data-type="attachment" data-id="256" target="_blank" rel="noreferrer noopener" download="">MP3</a>]</p>



<figure class="wp-block-audio"><audio controls src="https://blog.natebarney.com/wp-content/uploads/2023/07/ApOPL3xy-Africa-Fixed.mp3"></audio></figure>



<p><strong>Alan Menken &#8211; Under the Sea (from The Little Mermaid)</strong> [<a href="https://bitmidi.com/under-the-sea-from-the-little-mermaid-1-mid" data-type="URL" data-id="https://bitmidi.com/under-the-sea-from-the-little-mermaid-1-mid" target="_blank" rel="noreferrer noopener">MIDI</a>] [<a href="https://blog.natebarney.com/wp-content/uploads/2023/07/ApOPL3xy-Under-The-Sea.mp3" data-type="attachment" data-id="253" target="_blank" rel="noreferrer noopener" download="">MP3</a>]</p>



<figure class="wp-block-audio"><audio controls src="https://blog.natebarney.com/wp-content/uploads/2023/07/ApOPL3xy-Under-The-Sea.mp3"></audio></figure>



<p><strong>Europe &#8211; The Final Countdown</strong> [<a href="https://bitmidi.com/the-final-countdown-mid" data-type="URL" data-id="https://bitmidi.com/the-final-countdown-mid" target="_blank" rel="noreferrer noopener">MIDI</a>] [<a href="https://blog.natebarney.com/wp-content/uploads/2023/07/ApOPL3xy-The-Final-Countdown-Fixed.mp3" data-type="attachment" data-id="257" target="_blank" rel="noreferrer noopener" download="">MP3</a>]</p>



<figure class="wp-block-audio"><audio controls src="https://blog.natebarney.com/wp-content/uploads/2023/07/ApOPL3xy-The-Final-Countdown-Fixed.mp3"></audio></figure>



<p>Finally, I would be remiss not to include this masterpiece <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /> [<a rel="noreferrer noopener" href="https://bitmidi.com/never-gonna-give-you-up-3-mid" data-type="URL" data-id="https://bitmidi.com/never-gonna-give-you-up-3-mid" target="_blank">MIDI</a>] [<a href="https://blog.natebarney.com/wp-content/uploads/2023/07/ApOPL3xy-Never-Gonna-Give-You-Up.mp3" data-type="attachment" data-id="255" target="_blank" rel="noreferrer noopener" download="">MP3</a>]</p>



<figure class="wp-block-audio"><audio controls src="https://blog.natebarney.com/wp-content/uploads/2023/07/ApOPL3xy-Never-Gonna-Give-You-Up.mp3"></audio></figure>



<h3 class="wp-block-heading">New Features</h3>



<h5 class="wp-block-heading">Non-Volatile PATCH Storage</h5>



<p>In my <a href="https://blog.natebarney.com/2023/06/25/apopl3xy-a-midi-opl3-based-fm-synthesizer/#fat-man-patch-sets" data-type="URL" data-id="https://blog.natebarney.com/2023/06/25/apopl3xy-a-midi-opl3-based-fm-synthesizer/#fat-man-patch-sets" target="_blank" rel="noreferrer noopener">previous post</a>, I discussed the Fat Man&#8217;s General MIDI 2-operator and 4-operator OPL3 patch sets. I&#8217;ve added the patches from the 2-operator set into the system, so they&#8217;re readily available without laboriously entering them using the UI.</p>



<p>They&#8217;re stored on an <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/EEPROM" data-type="URL" data-id="https://en.wikipedia.org/wiki/EEPROM" target="_blank">EEPROM</a> chip (Microchip <a rel="noreferrer noopener" href="https://www.microchip.com/en-us/product/25AA1024" target="_blank">25AA1024</a>) for non-volatile storage, and cached in an <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Static_random-access_memory" data-type="URL" data-id="https://en.wikipedia.org/wiki/Static_random-access_memory" target="_blank">SRAM</a> chip (Microchip <a rel="noreferrer noopener" href="https://www.microchip.com/en-us/product/23LCV1024" data-type="URL" data-id="https://www.microchip.com/en-us/product/23LCV1024" target="_blank">23LCV1024</a>). From there, they can be loaded into the ATmega1284&#8217;s system RAM as needed and sent to the OPL3 synth chip for use. I updated the patch editor UI to allow the user to select which patch to edit, and whether to save the edits in SRAM only or also in EEPROM.</p>



<h5 class="wp-block-heading">OMNI MODE</h5>



<p>Previously, the ApOPL3xy only processed MIDI messages on MIDI channel 1. Messages from other channels were ignored. This was enough to get the keyboard controller to be playable, but to play multiple instruments simultaneously, a synthesizer needs to be in <a rel="noreferrer noopener" href="https://electronicmusic.fandom.com/wiki/Omni_mode" data-type="URL" data-id="https://electronicmusic.fandom.com/wiki/Omni_mode" target="_blank">omni mode</a>. In this mode, the synthesizer processes messages from all 16 MIDI channels.</p>



<p>I&#8217;ve implemented support for omni mode in the latest version. (In fact, omni mode is always on now, as I have not yet added a UI option to turn it off.) A separate patch selection (a.k.a. &#8220;program&#8221;) can be made for each channel, allowing multiple different but concurrent instruments to be synthesized.</p>



<p>Soon, I plan to add a UI utility to select patches for each channel, but for now, I&#8217;ve implemented handling for the <a rel="noreferrer noopener" href="https://www.recordingblogs.com/wiki/midi-program-change-message" data-type="URL" data-id="https://www.recordingblogs.com/wiki/midi-program-change-message" target="_blank">Program Change</a> MIDI message to allow an input MIDI device to make the selection.</p>



<h5 class="wp-block-heading">PERCUSSION CHANNEL</h5>



<p>I&#8217;ve also implemented a percussive channel mode, which is commonly used for MIDI channel 10. This mode is special because the patch that gets used when a note is played depends not on the channel program setting, but <a rel="noreferrer noopener" href="https://computermusicresource.com/GM.Percussion.KeyMap.html" data-type="URL" data-id="https://computermusicresource.com/GM.Percussion.KeyMap.html" target="_blank">on the note number itself</a>. For instance, note 35 (B0) is for an acoustic bass drum sound, and note 40 (E1) is for an electric snare sound.</p>



<p>The Fat Man&#8217;s patch set includes a bank of percussion sounds for this purpose, and I&#8217;ve uploaded them to the EEPROM as well. I haven&#8217;t yet updated the patch editor to be able to edit these, but I will soon.</p>



<p>Note that this is distinct from OPL3&#8217;s <a rel="noreferrer noopener" href="https://www.fit.vutbr.cz/~arnost/opl/opl3.html#regBD" data-type="URL" data-id="https://www.fit.vutbr.cz/~arnost/opl/opl3.html#regBD" target="_blank">percussion mode</a>, which I also plan to support in the future. This mode was not often used, and in fact, none of the patches in the Fat Man&#8217;s sets use it. It&#8217;s therefore a lower priority. But it&#8217;s something the chip can do, so I want the ApOPL3xy to support it.</p>



<h3 class="wp-block-heading">Update / Bug Fix</h3>



<p>I was looking through the code yesterday, and I found a bug with pitch bend that would cause a pitch bend on one channel to bend new notes on all channels. The careful listener might have noticed something off with Africa and The Final Countdown. I&#8217;ve since fixed it and uploaded new recordings for the two affected songs, but I&#8217;m putting the original broken versions below for posterity.</p>



<p><strong>Toto &#8211; Africa</strong> (Pitch Bend Bug) [<a href="https://blog.natebarney.com/wp-content/uploads/2023/07/ApOPL3xy-Africa.mp3" data-type="attachment" data-id="252" target="_blank" rel="noreferrer noopener" download="">MP3</a>]</p>



<figure class="wp-block-audio"><audio controls src="https://blog.natebarney.com/wp-content/uploads/2023/07/ApOPL3xy-Africa.mp3"></audio></figure>



<p><strong>Europe &#8211; The Final Countdown</strong> (Pitch Bend Bug) [<a href="https://blog.natebarney.com/wp-content/uploads/2023/07/ApOPL3xy-The-Final-Countdown.mp3" data-type="attachment" data-id="254" target="_blank" rel="noreferrer noopener" download="">MP3</a>]</p>



<figure class="wp-block-audio"><audio controls src="https://blog.natebarney.com/wp-content/uploads/2023/07/ApOPL3xy-The-Final-Countdown.mp3"></audio></figure>
]]></content:encoded>
					
					<wfw:commentRss>https://oldblog.natebarney.com/2023/07/03/apopl3xy-update-patches-omni-mode-and-percussion/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		<enclosure url="https://blog.natebarney.com/wp-content/uploads/2023/07/ApOPL3xy-Axel-F.mp3" length="2789458" type="audio/mpeg" />
<enclosure url="https://blog.natebarney.com/wp-content/uploads/2023/07/ApOPL3xy-Africa.mp3" length="4045426" type="audio/mpeg" />
<enclosure url="https://blog.natebarney.com/wp-content/uploads/2023/07/ApOPL3xy-Under-The-Sea.mp3" length="3040652" type="audio/mpeg" />
<enclosure url="https://blog.natebarney.com/wp-content/uploads/2023/07/ApOPL3xy-The-Final-Countdown.mp3" length="5182274" type="audio/mpeg" />
<enclosure url="https://blog.natebarney.com/wp-content/uploads/2023/07/ApOPL3xy-Never-Gonna-Give-You-Up.mp3" length="3352867" type="audio/mpeg" />
<enclosure url="https://blog.natebarney.com/wp-content/uploads/2023/07/ApOPL3xy-Africa-Fixed.mp3" length="4044590" type="audio/mpeg" />
<enclosure url="https://blog.natebarney.com/wp-content/uploads/2023/07/ApOPL3xy-The-Final-Countdown-Fixed.mp3" length="5181021" type="audio/mpeg" />

			</item>
		<item>
		<title>ApOPL3xy &#8211; A MIDI OPL3-Based FM Synthesizer</title>
		<link>https://oldblog.natebarney.com/2023/06/25/apopl3xy-a-midi-opl3-based-fm-synthesizer/</link>
					<comments>https://oldblog.natebarney.com/2023/06/25/apopl3xy-a-midi-opl3-based-fm-synthesizer/#respond</comments>
		
		<dc:creator><![CDATA[Nate Barney]]></dc:creator>
		<pubDate>Sun, 25 Jun 2023 10:07:33 +0000</pubDate>
				<category><![CDATA[ApOPL3xy]]></category>
		<category><![CDATA[electronics]]></category>
		<category><![CDATA[music]]></category>
		<category><![CDATA[opl3]]></category>
		<category><![CDATA[projects]]></category>
		<guid isPermaLink="false">https://blog.natebarney.com/?p=233</guid>

					<description><![CDATA[It's been a while since I've posted anything about electronics projects. I have not been idle, however. My current project is finally starting to come together enough to be able to show it off a little. It's a MIDI synthesizer powered by the Yamaha YMF-262 (a.k.a. OPL3) FM synth chip [...]]]></description>
										<content:encoded><![CDATA[
<h4 class="wp-block-heading">Overview</h4>



<p>It&#8217;s been a while since I&#8217;ve posted anything about electronics projects. I have not been idle, however. My current project is finally starting to come together enough to be able to show it off a little. It&#8217;s a MIDI synthesizer powered by the Yamaha <a rel="noreferrer noopener" href="https://www.yamaha-tech.com/wiki/Yamaha_YMF262" data-type="URL" data-id="https://www.yamaha-tech.com/wiki/Yamaha_YMF262" target="_blank">YMF-262</a> (a.k.a. OPL3) FM synth chip, the successor to the <a rel="noreferrer noopener" href="https://www.yamaha-tech.com/wiki/Yamaha_YM3812" target="_blank">YM3812</a> (a.k.a OPL2) I&#8217;ve talked about <a rel="noreferrer noopener" href="https://blog.natebarney.com/2022/12/04/tetris-theme/" data-type="URL" data-id="https://blog.natebarney.com/2022/12/04/tetris-theme/" target="_blank">previously</a>, and the Microchip (née Atmel) <a rel="noreferrer noopener" href="https://www.microchip.com/en-us/product/ATmega1284" data-type="URL" data-id="https://www.microchip.com/en-us/product/ATmega1284" target="_blank">ATmega1284</a>, a bigger brother of the <a rel="noreferrer noopener" href="https://www.microchip.com/en-us/product/ATmega328P" data-type="URL" data-id="https://www.microchip.com/en-us/product/ATmega328P" target="_blank">ATmega328P</a> used in the <a rel="noreferrer noopener" href="https://docs.arduino.cc/hardware/uno-rev3" data-type="URL" data-id="https://docs.arduino.cc/hardware/uno-rev3" target="_blank">Arduino Uno</a>. I&#8217;m calling the project &#8220;ApOPL3xy&#8221;, because I think apoplexy is a cool word, and it lets me put the OPL3 string in the middle. <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<h4 class="wp-block-heading">Demo</h4>



<p>I just got the <a href="https://electronicmusic.fandom.com/wiki/Patch" data-type="URL" data-id="https://electronicmusic.fandom.com/wiki/Patch" target="_blank" rel="noreferrer noopener">patch</a> editor working yesterday, so I&#8217;m excited to be able to show it off. It&#8217;s a bit rough around the edges, but it&#8217;s the first time the ApOPL3xy has felt like a real(ish) synth. Note that I don&#8217;t have 4-operator patches working yet, and there are a lot of menu items that you&#8217;ll see that don&#8217;t actually do anything. But 2-operator patches work.</p>



<p id="fat-man-patch-sets">I downloaded a 2-op patch set for the OPL3 authored by <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/George_Sanger_(musician)" data-type="URL" data-id="https://en.wikipedia.org/wiki/George_Sanger_(musician)" target="_blank">The Fat Man</a> and used by the <a rel="noreferrer noopener" href="https://bisqwit.iki.fi/source/adlmidi.html" data-type="URL" data-id="https://bisqwit.iki.fi/source/adlmidi.html" target="_blank">ADLMIDI</a> project. I also used <a rel="noreferrer noopener" href="https://github.com/Wohlstand/OPL3BankEditor/" data-type="URL" target="_blank">OPL3BankEditor</a> to extract the parameters I needed to enter into the ApOPL3xy. The following videos show me entering in a few of these patches and demoing them with a MIDI controller keyboard.</p>



<figure class="wp-block-video max640"><video height="360" style="aspect-ratio: 640 / 360;" width="640" controls preload="auto" src="https://blog.natebarney.com/wp-content/uploads/2023/06/ApOPL3xy-Piano-Patch.mp4" playsinline></video><figcaption class="wp-element-caption">Piano 2-operator patch</figcaption></figure>



<figure class="wp-block-video max640"><video height="360" style="aspect-ratio: 640 / 360;" width="640" controls preload="auto" src="https://blog.natebarney.com/wp-content/uploads/2023/06/ApOPL3xy-Trumpet-Patch.mp4" playsinline></video><figcaption class="wp-element-caption">Trumpet 2-operator patch</figcaption></figure>



<figure class="wp-block-video max640"><video height="360" style="aspect-ratio: 640 / 360;" width="640" controls preload="auto" src="https://blog.natebarney.com/wp-content/uploads/2023/06/ApOPL3xy-Steel-Drum-Patch.mp4" playsinline></video><figcaption class="wp-element-caption">Steel drum 2-operator patch</figcaption></figure>



<figure class="wp-block-video max640"><video height="360" style="aspect-ratio: 640 / 360;" width="640" controls preload="auto" src="https://blog.natebarney.com/wp-content/uploads/2023/06/ApOPL3xy-Organ-Patch.mp4" playsinline></video><figcaption class="wp-element-caption">Organ 2-operator patch</figcaption></figure>



<p>Here&#8217;s an example of pitch bend working. This was a lot more difficult than I expected, and the details deserve their own post, but it seems to work pretty well now.</p>



<figure class="wp-block-video max640"><video height="360" style="aspect-ratio: 640 / 360;" width="640" controls preload="auto" src="https://blog.natebarney.com/wp-content/uploads/2023/06/ApOPL3xy-Pitch-Bend.mp4" playsinline></video><figcaption class="wp-element-caption">Pitch bend</figcaption></figure>



<p>I also implemented a VGM player. VGM (Video Game Music) is a file format that stores commands to send to various synth chips. People have captured songs from lots of retro video games and uploaded them to <a rel="noreferrer noopener" href="https://vgmrips.net/packs/" target="_blank">vgmrips.net</a>. I downloaded several, uncompressed them, and put them on the SD card for the ApOPL3xy to read. Here are a few examples:</p>



<figure class="wp-block-video max640"><video height="360" style="aspect-ratio: 640 / 360;" width="640" controls preload="auto" src="https://blog.natebarney.com/wp-content/uploads/2023/06/ApOPL3xy-At-Dooms-Gate.mp4" playsinline></video><figcaption class="wp-element-caption">At Doom&#8217;s Gate VGM</figcaption></figure>



<figure class="wp-block-video max640"><video height="360" style="aspect-ratio: 640 / 360;" width="640" controls preload="auto" src="https://blog.natebarney.com/wp-content/uploads/2023/06/ApOPL3xy-Lemmings-1.mp4" playsinline></video><figcaption class="wp-element-caption">Lemmings VGM</figcaption></figure>



<figure class="wp-block-video max640"><video height="360" style="aspect-ratio: 640 / 360;" width="640" controls preload="auto" src="https://blog.natebarney.com/wp-content/uploads/2023/06/ApOPL3xy-Monkey-Island.mp4" playsinline></video><figcaption class="wp-element-caption">Monkey Island VGM</figcaption></figure>



<h4 class="wp-block-heading">Features and Limitations</h4>



<p>There&#8217;s a lot of work left to be done, but the core is working. Current features include:</p>



<ul class="wp-block-list">
<li>MIDI Input
<ul class="wp-block-list">
<li>Currently limited to MIDI channel 1</li>



<li>Currently, the only messages supported are Note On, Note Off, and Pitch Bend</li>



<li>Velocity is not yet supported</li>
</ul>
</li>



<li>2-channel audio output
<ul class="wp-block-list">
<li>The final product will have 4 output channels, but the breadboard version only has 2</li>
</ul>
</li>



<li>18-voice polyphony when using 2-operator mode</li>



<li>10-segment LED VU meters per output channel</li>



<li>Gain control potentiometer knob per output channel</li>



<li>Menu-driven user interface
<ul class="wp-block-list">
<li>20&#215;4 LCD character display</li>



<li>2 rotary encoders and 10 push buttons</li>
</ul>
</li>



<li>Micro SD card reader</li>



<li>VGM player
<ul class="wp-block-list">
<li>Both OPL2 and OPL3 VGM files are supported</li>



<li>VGM file must be uncompressed. VGZ files are not supported.</li>
</ul>
</li>
</ul>



<p>There are several things I plan on adding in the future:</p>



<ul class="wp-block-list">
<li>4-operator patch support</li>



<li>Patch bank &#8211; currently the system only knows about one patch at a time</li>



<li>Persistent patch/bank storage on <a href="https://en.wikipedia.org/wiki/EEPROM" data-type="URL" data-id="https://en.wikipedia.org/wiki/EEPROM" target="_blank" rel="noreferrer noopener">EEPROM</a></li>



<li>Import/export of patches and banks to SD card</li>



<li>User interface improvements</li>



<li>Support more MIDI messages</li>



<li>Support MIDI velocity</li>



<li>MIDI through output</li>



<li>MIDI omni mode</li>



<li>MIDI file playback</li>



<li>VGM / MIDI file playlist support</li>



<li>Printed circuit board
<ul class="wp-block-list">
<li>Split into two boards: the OPL3 board and the MIDI board. They&#8217;ll be connected with an <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Insulation-displacement_connector" data-type="URL" data-id="https://en.wikipedia.org/wiki/Insulation-displacement_connector" target="_blank">IDC</a> ribbon cable I think. This will allow the OPL3 board to be connected to other things in the future, like my <a href="https://blog.natebarney.com/2022/12/03/homebrew-6502-based-computer/" data-type="post" data-id="15">homebrew 6502 computer</a>, or a <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Commodore_64" data-type="URL" data-id="https://en.wikipedia.org/wiki/Commodore_64" target="_blank">Commodore 64</a>, etc.</li>



<li>ISP and JTAG headers for programming/debugging and headers for SPI, I2C and unused GPIO pins. This project was intended from the start to be hackable and upgradable.</li>
</ul>
</li>
</ul>



<h4 class="wp-block-heading">Development Environment</h4>



<p>I started out using the <a href="https://docs.arduino.cc/software/ide-v2" data-type="URL" data-id="https://docs.arduino.cc/software/ide-v2" target="_blank" rel="noreferrer noopener">Arduino IDE</a> to write the code for the firmware. That&#8217;s fine for small projects, but this quickly outgrew it. I recently switched to <a rel="noreferrer noopener" href="https://platformio.org/" data-type="URL" data-id="https://platformio.org/" target="_blank">PlatformIO</a>, and that&#8217;s been much more pleasant. It&#8217;s an extension for <a href="https://code.visualstudio.com/" data-type="URL" data-id="https://code.visualstudio.com/" target="_blank" rel="noreferrer noopener">Visual Studio Code</a>, and it supports a large number of microcontrollers and libraries. I&#8217;m using the <a rel="noreferrer noopener" href="https://www.microchip.com/en-us/development-tool/atavrisp2" data-type="URL" data-id="https://www.microchip.com/en-us/development-tool/atavrisp2" target="_blank">AVR-ISP mkII</a> programmer to upload the compiled firmware to the microcontroller. To access the micro SD card, I&#8217;m using the excellent <a rel="noreferrer noopener" href="https://github.com/greiman/SdFat" data-type="URL" data-id="https://github.com/greiman/SdFat" target="_blank">SdFat</a> library.</p>



<h4 class="wp-block-heading">Closing Thoughts</h4>



<p>This project has been a much larger undertaking than I initially envisioned. I&#8217;m excited that it&#8217;s starting to come together. I may post other articles about various technical details of the design and implementation another time, if there&#8217;s interest. When I get the PCB&#8217;s made, I plan to make the CAD files for the boards and the source code for the firmware available so people will be able to build one and mess with it if they want to.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://oldblog.natebarney.com/2023/06/25/apopl3xy-a-midi-opl3-based-fm-synthesizer/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		<enclosure url="https://blog.natebarney.com/wp-content/uploads/2023/06/ApOPL3xy-Piano-Patch.mp4" length="3794962" type="video/mp4" />
<enclosure url="https://blog.natebarney.com/wp-content/uploads/2023/06/ApOPL3xy-Trumpet-Patch.mp4" length="4605426" type="video/mp4" />
<enclosure url="https://blog.natebarney.com/wp-content/uploads/2023/06/ApOPL3xy-Steel-Drum-Patch.mp4" length="3899880" type="video/mp4" />
<enclosure url="https://blog.natebarney.com/wp-content/uploads/2023/06/ApOPL3xy-Organ-Patch.mp4" length="4353557" type="video/mp4" />
<enclosure url="https://blog.natebarney.com/wp-content/uploads/2023/06/ApOPL3xy-Pitch-Bend.mp4" length="892535" type="video/mp4" />
<enclosure url="https://blog.natebarney.com/wp-content/uploads/2023/06/ApOPL3xy-At-Dooms-Gate.mp4" length="1058187" type="video/mp4" />
<enclosure url="https://blog.natebarney.com/wp-content/uploads/2023/06/ApOPL3xy-Lemmings-1.mp4" length="1483995" type="video/mp4" />
<enclosure url="https://blog.natebarney.com/wp-content/uploads/2023/06/ApOPL3xy-Monkey-Island.mp4" length="2383172" type="video/mp4" />

			</item>
		<item>
		<title>Tetris Theme</title>
		<link>https://oldblog.natebarney.com/2022/12/04/tetris-theme/</link>
					<comments>https://oldblog.natebarney.com/2022/12/04/tetris-theme/#respond</comments>
		
		<dc:creator><![CDATA[Nate Barney]]></dc:creator>
		<pubDate>Sun, 04 Dec 2022 04:03:35 +0000</pubDate>
				<category><![CDATA[Homebrew 6502]]></category>
		<category><![CDATA[6502]]></category>
		<category><![CDATA[computers]]></category>
		<category><![CDATA[electronics]]></category>
		<category><![CDATA[music]]></category>
		<category><![CDATA[opl2]]></category>
		<category><![CDATA[projects]]></category>
		<guid isPermaLink="false">https://blog.natebarney.com/?p=125</guid>

					<description><![CDATA[When working on projects, I often let my mind stray toward future goals instead of staying focused on the immediate ones. Case in point: I started thinking about making a Tetris clone for my 6502 computer (once it has a video display). Naturally it would need music as well, since I&#8217;ve hooked up an OPL2 [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>When working on projects, I often let my mind stray toward future goals instead of staying focused on the immediate ones. Case in point: I started thinking about making a <a href="https://en.wikipedia.org/wiki/Tetris">Tetris</a> clone for my <a href="https://blog.natebarney.com/2022/12/03/homebrew-6502-based-computer/" data-type="post" data-id="15">6502 computer</a> (once it has a video display). Naturally it would need music as well, since I&#8217;ve hooked up an OPL2 sound chip already. And of course, the music had to be the famous <a href="https://www.youtube.com/watch?v=z3ZiVn5L9vM">Tetris Theme</a> (a.k.a. <a href="https://en.wikipedia.org/wiki/Korobeiniki">The Peddler</a>). </p>



<p>The first step was to find some sheet music for the song. I found <a href="https://musescore.com/user/18821176/scores/3732656">this</a>, but <a href="https://musescore.org/">MuseScore</a> wouldn&#8217;t let me download it without registering for an account. I&#8217;m not about to do that. But, it&#8217;s pretty short, so I just entered it into my local install of MuseScore. Here it is for the curious:</p>



<div data-wp-interactive="core/file" class="wp-block-file"><object data-wp-bind--hidden="!state.hasPdfPreview" hidden class="wp-block-file__embed" data="https://blog.natebarney.com/wp-content/uploads/2022/12/Tetris_Theme.pdf" type="application/pdf" style="width:100%;height:600px" aria-label="Embed of Tetris Theme Sheet Music."></object><a id="wp-block-file--media-e32ed111-451f-41fb-8a72-3d55affdcb9f" href="https://blog.natebarney.com/wp-content/uploads/2022/12/Tetris_Theme.pdf">Tetris Theme Sheet Music</a><a href="https://blog.natebarney.com/wp-content/uploads/2022/12/Tetris_Theme.pdf" class="wp-block-file__button wp-element-button" download aria-describedby="wp-block-file--media-e32ed111-451f-41fb-8a72-3d55affdcb9f">Download</a></div>



<div class="wp-block-file"><a id="wp-block-file--media-3e4e16ff-d221-4094-ab1d-893ebbf68b98" href="https://blog.natebarney.com/wp-content/uploads/2022/12/Tetris_Theme.mscz">Tetris Theme MuseScore File</a><a href="https://blog.natebarney.com/wp-content/uploads/2022/12/Tetris_Theme.mscz" class="wp-block-file__button wp-element-button" download aria-describedby="wp-block-file--media-3e4e16ff-d221-4094-ab1d-893ebbf68b98">Download</a></div>



<p>And this is what it sounds like, in case you don&#8217;t remember:</p>



<figure class="wp-block-audio"><audio controls src="https://blog.natebarney.com/wp-content/uploads/2022/12/Tetris_Theme.mp3"></audio><figcaption class="wp-element-caption">Tetris Theme</figcaption></figure>



<p>Listening to this, I felt like it was pretty plain. I wanted to spice it up a bit. So, I added some drums (some tweaks were suggested by Donnett). Also, a retro video game shouldn&#8217;t sound like a piano. A square wave would be much more appropriate. With those changes, we get this:</p>



<figure class="wp-block-audio"><audio controls src="https://blog.natebarney.com/wp-content/uploads/2022/12/Tetris_Theme_Square_Wave_And_Drums.mp3"></audio><figcaption class="wp-element-caption">Tetris Theme w/ Square Wave and Drums</figcaption></figure>



<p>That&#8217;s more like it! Much more fun to play Tetris to, IMO. But, it needs just a little bit more. Donnett has been teaching me some music theory, and I wanted to see if I could figure out what chords would sound good in a bass line. With one slight tweak from her (change first chord in second phrase to a 2 instead of a 7), I&#8217;m really happy with how it sounds in MuseScore (the chords start at 0:42):</p>



<figure class="wp-block-audio"><audio controls src="https://blog.natebarney.com/wp-content/uploads/2022/12/Tetris_Theme_Square_Wave_Drums_And_Bass_Synth.mp3"></audio><figcaption class="wp-element-caption">Tetris Theme w/ Square Wave, Drums, and Bass Synth</figcaption></figure>



<p>For the musically inclined, here&#8217;s the updated sheet music and MuseScore files:</p>



<div data-wp-interactive="core/file" class="wp-block-file"><object data-wp-bind--hidden="!state.hasPdfPreview" hidden class="wp-block-file__embed" data="https://blog.natebarney.com/wp-content/uploads/2022/12/Tetris_Theme_Enhanced.pdf" type="application/pdf" style="width:100%;height:600px" aria-label="Embed of Tetris Theme (Enhanced) Sheet Music."></object><a id="wp-block-file--media-bef2fee8-a157-479c-9aa8-0b5d99df4990" href="https://blog.natebarney.com/wp-content/uploads/2022/12/Tetris_Theme_Enhanced.pdf">Tetris Theme (Enhanced) Sheet Music</a><a href="https://blog.natebarney.com/wp-content/uploads/2022/12/Tetris_Theme_Enhanced.pdf" class="wp-block-file__button wp-element-button" download aria-describedby="wp-block-file--media-bef2fee8-a157-479c-9aa8-0b5d99df4990">Download</a></div>



<div class="wp-block-file"><a id="wp-block-file--media-bca89c55-d800-4416-89d2-f82917513ad5" href="https://blog.natebarney.com/wp-content/uploads/2022/12/Tetris_Theme_Enhanced.mscz">Tetris Theme (Enhanced) MuseScore File</a><a href="https://blog.natebarney.com/wp-content/uploads/2022/12/Tetris_Theme_Enhanced.mscz" class="wp-block-file__button wp-element-button" download aria-describedby="wp-block-file--media-bca89c55-d800-4416-89d2-f82917513ad5">Download</a></div>



<p>But we&#8217;re not done yet! Remember, the point of this whole exercise is to get it running on a 6502 computer with an OPL2 sound chip. To that end, I started looking at tracker programs. I found one called <a href="http://adlibtracker.net/">Adlib Tracker 2</a> that I liked pretty well, and set it up in <a href="https://www.dosbox.com/">DOSBox</a>. It&#8217;s got a fantastic 90&#8217;s-era look, and it&#8217;s pretty powerful.</p>



<p>After a little learning curve, I was able to pick out some instruments, tweak them to get them sounding the way I want, and enter the notes. Here&#8217;s a video capture of the tracker playing the OPL2 version of my arrangement. (Note that the tempo is a bit slower. I didn&#8217;t notice when I was first doing this, but now listening to both speeds, I think I prefer the slightly slower version.)</p>



<figure class="wp-block-video"><video height="480" style="aspect-ratio: 720 / 480;" width="720" controls preload="auto" src="https://blog.natebarney.com/wp-content/uploads/2022/12/tetris-adtrack2.mp4"></video><figcaption class="wp-element-caption">Adlib Tracker 2 playing Tetris Theme</figcaption></figure>



<p>The last step is to get this ported over to run on the homebrew machine. This was easier said than done. Eventually, I&#8217;ll probably write something to process the <a href="http://adlibtracker.net/files/techinfo.htm#_Toc389385056">A2M file format</a> created by Adlib Tracker 2, but this time, I used DOSBox&#8217;s OPL capture feature to capture a DRO file. Then I downloaded and compiled the utilities in the <a href="https://github.com/vgmrips/vgmtools">vgmtools</a> github repository. It has two utilities I needed: <code>dro2vgm</code>,  and <code>vgmtrim</code>. I had previously written a python script to extract the OPL2 commands I need from a <a href="https://vgmrips.net/wiki/VGM_Specification">VGM</a> file. (By the way, <a href="https://vgmrips.net/packs/chip/ym3812">vgmrips.net</a> has a fantastic collection of music from old video games, using OPL2, OPL3, and many other chips.) So, finally, I have this song playing on my homebrew computer!</p>



<figure class="wp-block-video"><video height="720" style="aspect-ratio: 1280 / 720;" width="1280" controls src="https://blog.natebarney.com/wp-content/uploads/2022/12/tetris-6502.mp4"></video><figcaption class="wp-element-caption">Homebrew 6502 Computer playing Tetris Theme</figcaption></figure>



<p>Pretty good for a 47-year old CPU!</p>
]]></content:encoded>
					
					<wfw:commentRss>https://oldblog.natebarney.com/2022/12/04/tetris-theme/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		<enclosure url="https://blog.natebarney.com/wp-content/uploads/2022/12/Tetris_Theme.mp3" length="1123891" type="audio/mpeg" />
<enclosure url="https://blog.natebarney.com/wp-content/uploads/2022/12/Tetris_Theme_Square_Wave_And_Drums.mp3" length="1142699" type="audio/mpeg" />
<enclosure url="https://blog.natebarney.com/wp-content/uploads/2022/12/Tetris_Theme_Square_Wave_Drums_And_Bass_Synth.mp3" length="1142699" type="audio/mpeg" />
<enclosure url="https://blog.natebarney.com/wp-content/uploads/2022/12/tetris-adtrack2.mp4" length="5216514" type="video/mp4" />
<enclosure url="https://blog.natebarney.com/wp-content/uploads/2022/12/tetris-6502.mp4" length="10957410" type="video/mp4" />

			</item>
		<item>
		<title>Homebrew 6502-Based Computer</title>
		<link>https://oldblog.natebarney.com/2022/12/03/homebrew-6502-based-computer/</link>
					<comments>https://oldblog.natebarney.com/2022/12/03/homebrew-6502-based-computer/#respond</comments>
		
		<dc:creator><![CDATA[Nate Barney]]></dc:creator>
		<pubDate>Sat, 03 Dec 2022 19:09:19 +0000</pubDate>
				<category><![CDATA[Homebrew 6502]]></category>
		<category><![CDATA[6502]]></category>
		<category><![CDATA[computers]]></category>
		<category><![CDATA[electronics]]></category>
		<category><![CDATA[projects]]></category>
		<guid isPermaLink="false">https://blog.natebarney.com/?p=15</guid>

					<description><![CDATA[I&#8217;ve been toying with the idea of building a 6502-based (or rather, 65C02-based) computer for a few years now. I was inspired by Ben Eater&#8216;s YouTube series about it. I bought a bunch of chips from Mouser, and every so often I&#8217;d think about how to do this or that for the notional computer. Well, [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>I&#8217;ve been toying with the idea of building a <a href="https://en.wikipedia.org/wiki/MOS_Technology_6502">6502</a>-based (or rather, <a href="https://en.wikipedia.org/wiki/WDC_65C02">65C02</a>-based) computer for a few years now. I was inspired by <a href="https://eater.net/">Ben Eater</a>&#8216;s <a href="https://www.youtube.com/playlist?list=PLowKtXNTBypFbtuVMUVXNR0z1mu7dp7eH">YouTube series about it</a>. I bought a bunch of chips from <a href="https://www.mouser.com/">Mouser</a>, and every so often I&#8217;d think about how to do this or that for the notional computer. Well, finally I&#8217;ve decided to build one.</p>



<figure class="wp-block-image aligncenter size-full is-resized"><img loading="lazy" decoding="async" src="https://blog.natebarney.com/wp-content/uploads/2022/12/homebrew-6502.jpg" alt="" class="wp-image-18" width="518" height="565" srcset="https://oldblog.natebarney.com/wp-content/uploads/2022/12/homebrew-6502.jpg 2072w, https://oldblog.natebarney.com/wp-content/uploads/2022/12/homebrew-6502-275x300.jpg 275w, https://oldblog.natebarney.com/wp-content/uploads/2022/12/homebrew-6502-939x1024.jpg 939w, https://oldblog.natebarney.com/wp-content/uploads/2022/12/homebrew-6502-768x838.jpg 768w, https://oldblog.natebarney.com/wp-content/uploads/2022/12/homebrew-6502-1408x1536.jpg 1408w, https://oldblog.natebarney.com/wp-content/uploads/2022/12/homebrew-6502-1878x2048.jpg 1878w" sizes="auto, (max-width: 518px) 100vw, 518px" /><figcaption class="wp-element-caption">My homebrew 6502-based breadboard computer</figcaption></figure>



<p>I&#8217;ve made some changes from Ben&#8217;s design. I&#8217;m using <a href="https://en.wikipedia.org/wiki/Complex_programmable_logic_device">CPLD</a>&#8216;s for address decoding, an 8k ROM instead of 32k (but I can adjust the address decoding to support up to 32k ROM), 64k RAM (not all addressable due to ROM and I/O), 4 <a href="https://en.wikipedia.org/wiki/WDC_65C22">65C22</a> VIA&#8217;s, and a 4 MHz clock. So far I&#8217;ve added a 20&#215;4 character LCD, a <a href="https://en.wikipedia.org/wiki/Yamaha_OPL#OPL2">YM3812 (OPL2)</a> sound chip, and a NES controller. I have plans to add a PS/2 keyboard, an SD card reader, upgrade the clock frequency to 8 MHz, upgrade the OPL2 to an <a href="https://en.wikipedia.org/wiki/Yamaha_OPL#OPL3">OPL3</a>, and add a composite video display using the <a href="https://en.wikipedia.org/wiki/Texas_Instruments_TMS9918">TMS9918A</a> video chip.</p>



<p>I&#8217;ll make a bunch of posts in the future about various technical topics related to this, but I wanted to start with this general post introducing the project.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://oldblog.natebarney.com/2022/12/03/homebrew-6502-based-computer/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
