/AY3891x

Platform-independent Arduino library for General Instrument AY-3-8910 / AY-3-8912 Programmable Sound Generator chip and its clones (YM2149, YM3439, T7766A, among others).

Primary LanguageC++MIT LicenseMIT

AY3891x Library

Arduino Compile Sketches Check Markdown Links Arduino Lint

Arduino library and chiptunes player for General Instrument AY-3-8910 / AY-3-8912 Programmable Sound Generator (PSG) chip, including clones like the YM2149.

The AY-3-8910 and AY-3-8912 have the same programming interface. The 8910 has two 8-bit I/O ports and the 8912 has a single 8-bit I/O port (and correspondingly fewer pins). These general purpose I/O pins are not related to the sound generation functions. This library has only been tested with the 8910 variant of the chip, but should also work with the 8912.

The AY-3-8913 variant has a different programming interface which uses a Chip Select signal. The 8913 variant is not currently supported by the library. A future iteration of this library may include support.

Other libraries and PSG-related projects typically discuss the need to use fast pin switching in order to meet the strict signal timing requirements when using the PSG, meaning that they don't use the slower, platform-agnostic digitalWrite() function. This ends up creating non-portable, processor specific code. While the PSG has tight timing requirements, it is possible to use digitalWrite() by using all three bus control signals (BDIR, BC1, BC2) and cycling through an extra state when reading and writing the chip registers.

This library uses the generic digitalWrite() function instead of direct port manipulation, and should therefore work across most, if not all, processors supported by Arduino, so long as enough I/O pins are available for the interface to the PSG.

There are several clones of the chip from other manufacturers, examples of which are the Yamaha YM2149F and YM3439 and Toshiba T7766A. The YM2149 has been tested with this library. The other clones are probably compatible but have not been tested.

I created an Arduino-AY38910 chiptunes player board; see the README in the extras/hardware folder.

Usage

Refer to the sketches in the examples folder.

  1. Include the library header file:

    #include "AY3891x.h"
  2. (optional) Include definitions for eight octaves of musical notes:

    #include "AY3891x_sounds.h" 

    It is not strictly necessary to use this header file, but you can include it to make playing notes a little easier. If you aren't using it, then it will save a little flash memory by not including the file. It is used by example programs 3 and 5.

    Note that as of version 1.1.0 of the library, the Notes[] array in AY3891x_sounds.h is defined as PROGMEM. This will require minor changes to any sketches which include this file and use the Notes[] array. See example programs 3 and 5.

  3. Instantiate the object. There are two forms of the constructor.

    This first form supports all of the chip's interface pins. Use the enumeration AY3891x::NO_PIN for any of the optional signals A9, A8, RESET or CLOCK required by the constructor that are not connected.

    AY3891x(byte DA7, byte DA6, byte DA5, byte DA4, 
            byte DA3, byte DA2, byte DA1, byte DA0,
            byte BDIR, byte BC2, byte BC1,
            byte A9, byte A8,
            byte reset, byte clock);

    The second form allows for a slightly simplified format when using only the minimal pins necessary to interface with the chip.

    AY3891x(byte DA7, byte DA6, byte DA5, byte DA4, 
            byte DA3, byte DA2, byte DA1, byte DA0,
            byte BDIR, byte BC2, byte BC1);

Important

All three of the bus control signals (BDIR, BC1, BC2) need to be connected to the processor. Do not use AY3891x::NO_PIN in either constructor for these signals.

  1. Initialize the object.

    psg.begin();
  2. Use the read() and write() methods to program the chip:

    psg.write(AY3891x::Enable_Reg, 0x3F);  
    psg.read(AY3891x::IO_Port_A_Reg);
  3. See the library source code and example sketches for other available methods and usage.

Example Sketches

NOTE: While the library itself does not use any platform-specific code, the examples that generate tones (EX3, EX5, EX6, EX7) have platform-specific code to generate the CLOCK signal required by the sound generator chip. If you are using an ATmega329 or ATmega32u4 chip, then the examples should run as-is. For other chips, consult the respective datasheet or connect an externally-generated clock signal to the sound generator chip and update the example code accordingly.

EX1 - Find Address
The AY-3-8910 chip typically has a binary address of 01 0000 xxxx, where xxxx represents the specific register you are addressing. It is possible to request a different mask-programmed address from the factory. This example code determines the chip's address by writing a value to one of the chip's registers and reads it back to see if it matches. If it matches, then we found the address. If not, then the next address is checked.

EX2 - Test Registers
Writes a value to each of the chip's registers and reads it back to see if it matches.

EX3 - Simple Tone
This sketch will play through the middle-octave notes C4 to C5. Note that an external clock is required for the chip's audio functions to work. This can be generated by the microcontroller or other hardware clock circuit.

EX4 - I/O Ports
This sketch demonstrates the use of the I/O ports on the AY-3-8910 or -8912.

EX5 - Serial Commands
This sketch allows you to send commands to the AY-3-891x chip through the serial port. It makes it easy to experiment with the various sound generation capabilities of the chip. This example depends on the SerialCommands library.

EX6 - Chiptunes Flash
This examples plays a converted YM file which is compiled into the program as a byte array of the data values to write to the 14 audio registers on the sound chip.

Since the audio data is compiled into the program, there is a relatively small limit on the duration of the chiptune to be played. The sketch itself takes 1632 bytes, leaving about 29,000 bytes on an Atmega328. Fourteen bytes of data are written 50 times a second, meaning that the largest data array can store about 41 seconds of music.

See this README for details on finding and converting YM files for use with this sketch.

EX7 - Chiptunes SD
This example sketch plays YM files which are stored on an SD card. The sketch sequentially goes through each file in the root directory. Press the button defined as NEXT_BUTTON to advance to the next song on the card.

See this README for details on finding and converting YM files for use with this sketch.

Interrupts

The library does not use any interrupts, but briefly disables interrupts during the write pulse to the chip. This is to ensure that the write signal time (tDW) is within the 10 us maximum spec. On a 16 MHz ATmega 328, interrupts are disabled for about 4.5 us during each register write.

YouTube Videos

My library was featured in two YouTube videos by Gadget Reboot:

References

License

The software and other files in this repository are released under what is commonly called the MIT License. See the file LICENSE.txt in this repository.