Matthew Kaney at ITP

(Specifically, Homemade Hardware projects)

Simple ATtiny Synth, Week 2

Homemade Hardware


308

I modified last week’s synth circuit to run on an ATtiny. There are still some bugs, and some features that I’d like to include, but I’m pretty pleased with it so far. I’ve updated the schematic accordingly, and then created a new board layout. In addition to the ATtiny, I also used the low-pass filter circuit from here, which is also the inspiration for my code.

Synth_Week2_Circuit

Synth_Week2_Board

Simple Arduino Synth, Schematic

Homemade Hardware


356

I enjoyed playing with the LCD screen a lot last week, but I don’t yet feel confident enough to tackle a circuit that incorporates an LCD sans breakout board. So, for this first project, I’m taking a detour into building a basic MIDI synth.

This week I focused on getting Eagle up and running, and working out some of the details of MIDI control. The circuit uses an ATmega328 set up as a breadboard Arduino, connected to a MIDI input (this is basically the standard circuit that the MIDI folks publish, though I wound up using Tom Igoe’s schematic). The circuit responds to MIDI signals and uses the tone() command to generate appropriately-pitched beeps.

Here’s my breadboard:

Breadboard Arduino Synth

And here’s the Eagle schematic:

Arduino Synth Schematic

I have a long wishlist for this project. First, I’d love to do some more complex synthesis than just tone(), which is why I’m intrigued by this blog post about generating waveforms with an ATtiny85. Also, my MIDI support is incredibly bare bones at the moment—there are probably other channel controls and such (other than basic note on/off) that I should implement. I could also see adding an LM386 amplifier circuit to the mix to turn up the volume a bit. Also, the circuit currently runs off of the Arduino board’s 5v power, but I’ll eventually need to add a voltage regulator to the circuit as well.

We’ll see how many of those things I can include in the next couple of weeks.

Here’s the code:

#include <SoftwareSerial.h>

const byte rxPin = 2;
const byte txPin = 3;

// set up a new serial object
SoftwareSerial mySerial (rxPin, txPin);

// variables for MIDI parsing
byte currStatus = 0;
byte currDataIndex = 0;

// We'll need to store up to two different bytes of
// data for MIDI messages
byte currData[2];

byte currNote = 0;

void setup() {
  pinMode(rxPin, INPUT);
  pinMode(txPin, OUTPUT); // We never actually use this
  
  mySerial.begin(31250);
}

void loop() {
  // Pull in any available bytes
  while(mySerial.available() > 0) {
    byte newByte = mySerial.read();

    // Check if this is a status byte
    if(newByte >> 7 == 1) {
      // If it is, then pull out just the status code
      currStatus = (newByte >> 4) & 0b0111;
      currDataIndex = 0;
    } else {
      // If it's not a status byte, then it's a data byte
      currData[currDataIndex] = newByte;

      if(currDataIndex == 0) {
        // If this is the first of two data bytes, then
        // wait for the second byte
        currDataIndex = 1;
      } else if(currDataIndex == 1) {
        // If this is the second data byte, then we've
        // received a whole message. Do something now.

        // Check the message type
        if(currStatus == 0) { // Note off message
          // Only turn the tone off if the note that was
          // turned off is the same that we're currently
          // playing
          if(currNote == currData[0]) {
            noTone(8);
          }
        } else if(currStatus == 1) { // Note on

          // Check the velocity. If it's 0, then this
          // is basically a note off message.
          if(currData[1] == 0) {
            // Duplicate note off code
            if(currNote == currData[0]) {
              noTone(8);
            }
          } else {
            // If the velocity is non-zero, then we have a
            // legit note on event. Change the tone frequency.
            int freq = pow(2, (currData[0] - 69) / 12.0) * 440;
            tone(8, freq);

            // And make note of our new current note
            currNote = currData[0];
          }
        }

        // End of MIDI message. Next data byte will be the first
        // of the next message.
        currDataIndex = 0;
      }
    }
  }
}

Flappy Bird on the ATtiny85

Homemade Hardware


237

In this class, I want to explore building hardware for small LCD screens. To begin with, I used a piece of hardware that I’ve used some in the past, the Nokia 5110 screen sold by SparkFun. In order to test the capabilities of the ATtiny85 microprocessor, I decided to see how much of the iPhone game Flappy Bird I could re-implement with this processor and screen.

The Nokia 5110 screen is 84×48 pixels. The height of the screen is divided up into six rows. These rows are then divided into 84 1×8 pixel columns. Each column is represented by one byte of data, and you write data to the screen by shifting a byte at a time, filling each row left to right, and then moving down to the next row. For example, this shows how a byte with the decimal value 39 would render on the screen:

Layout of the LCD Screen

Flappy Bird Pixel Art

Because Flappy Bird is an iPhone game, I decided to use the screen in portrait orientation, effectively rendering the image in six columns, from bottom to top. I mocked up my pixel art graphics in Photoshop (shown at left). Here, I’ve tried out several possible birds, using the original character pixel art as a reference. Also, note the gray stripes indicating the divisions of the screen—by designing with this layout in mind, I was able to create graphics that rendered more efficiently on the screen. From this art, I created the graphics in code by manually typing arrays of byte literals (e.g. “0b00100111”).

Circuit Diagram

The Nokia 5110 screen has 8 pins, 5 of which should be connected to a microcontroller: SCLK (Pin 7), DN (Pin 6), and SCE (Pin 3), which are used for data transfer; D/C (Pin 5), which is used to determine whether the data is interpreted as image data or a control signal; and RST (Pin 4), which can be used to automatically reset the LCD screen. After getting the screen to work in this configuration, I decided that I didn’t need to ever reset the screen, freeing up a pin on my ATtiny to be connected to a pushbutton. The LCD screen requires 2.7-3.3VDC, so I powered the entire circuit off of a pair of AA batteries.

Overview

(more…)