Friday 29 August 2014

Pins and Routing

The Arduino Mega has a heap of pins. But will it be enough? In order to get some idea I've begun to try and enumerate the assignments of the pins. Here's a screenshot of the color coded spreadsheet:



So far it's looking fine, like there'll be enough to go around and some to spare. The actual spreadsheet is available here.  There's a second sheet that lists the pins in numeric order.

Unfortunately listing the pins is one thing, actually routing them on a PCB to where they need to go may be a totally different matter altogether. I've been tossing up how to to handle this. One way would be to make each module a conventional Arduino shield. I'd need to have an additional bus to transfer the audio and modulation signals. The advantage of this is that the routing and component layout would be fairly easy and it would be a neat stack of boards with a very small footprint. The downside is that it would be fairly expensive as a board the size of an Arduino Mega for each module would be quite large. I could add more than one module per shield but that's starting to work against the modular nature of the design. So in that case I think it would make better sense to have a single shield and have the modules attached to that. Something like:

I'm not sure exactly how the LCD screen and the rotary encoders would be arranged but they, along with the mixer and modulation router, would be on the main shield. This shield would overlap the Arduino Mega a little and have pin attachment points for the various modules. This will allow the module boards to be only constrained by size in one dimension - where they mate with the main shield and each one can be considerable smaller than a shield itself.  However the routing of all the pins becomes a lot more complicated. One thing that might make that easier is to make this one shield a four-layer board. I've never laid out a four layer board but it sounds like KiCad can handle it OK and a four-layer board is only twice the price of a two layer one with OSH/Park. Spending a bit more on this one shield will pay off in allowing the module boards to be smaller. 

At the same time I thought about it and realised it likely makes sense to have three oscillators. This was partly from looking at the pins available, partly because the Mega can sustain three Timers and partly because OSH/Park has a minimum order of three so it costs me no more to have three identical waveshapers than two from that point of view. The block diagram now looks like:




Monday 25 August 2014

I SPI with my little eye

A number of the key pieces of technology I'm planning to use rely on the SPI protocol. Therefore before I committed too much effort to any particular one of them I wanted to ensure that the ones I'm hoping to use would be compatible. The SPI protocol uses a single bus which all devices are connected to for clock and data transfer and each device has a "slave select" pin that is set low when the device should expect to receive data. One complication is that SPI is only a de facto standard and there are variants in protocol that mean some devices may not cooperate on the same bus.

The Arduino Mega has both hardware support for SPI, allowing a very fast data rate, and a fully featured SPI library. The devices I want to use are a TFT LCD screen, this has an SD card reader built-in which is also controlled via SPI. I also wanted to use a number of digital potentiometers in place of conventional pots. The proof of concept stage was to convince myself I knew how to control each of these devices and that they would work well together.

The TFT screen was the first thing I tried out. Like all Adafruit products it's well supported and in this case is driven by their GFX library which is used for a number of different displays. This covers a number of basic graphics operations and once one gets used to the coordinate system (0,0 at top left) then it's pretty straight-forward to use. One thing I found almost right away was that the speed of drawing is relatively slow and it's not possible to use full screen redraw to animate without flicker. This was a problem since I want to be able to show dials of some sort to represent internal settings. There's also apparently no "draw filled arc" type function so it's not possible to draw a pie-type dial. However a linear bar "slider" is easier to do anyway and fairly intuitive. I discovered by some trial and error that it's possible to draw a fairly responsive slider bar by careful redrawing of only the parts that change. The code looks like:

  double frac = (double)val/maxval;
  int width = (int)( frac * (RECT_WIDTH-2));

  if( val >= last_val ) {
    // Bar grows - draw it in black:
    tft.fillRect( RECT_X + 1, RECT_Y+1, width, RECT_HEIGHT-2,0x0 );
  } 
  else {
    // Bar shrinks - draw the exposed background area in white:
    tft.fillRect( RECT_X+width, RECT_Y+1, RECT_WIDTH-width-2, RECT_HEIGHT-2,
    0xFFFF );
  }

  last_val = val;

In this way there's minimal redrawing required and the performance, while not perfectly smooth, is acceptable. I also experimented with text, showing the currently playing MIDI note using code like the following in the noteOn() handler for the MIDI library:

  static char* note_string[] = { 
    "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"   };
  int octave = (pitch / 12) - 1;
  int note_index = (pitch % 12);

  tft.fillRect(40, 200, 80, 40, 0xFFFF);
  tft.setTextSize( 4 );
  tft.setTextColor( 0x0);
  tft.setCursor( 40,200);
  tft.print(note_string[note_index]);
  tft.print(octave);


This gives a display of the currently playing note as shown in the video below.

Once the screen was working it was on to test if the SD card worked. The simplest way to test seemed to load an image from the card and display it on the TFT. There's an example supplied by Adafruit that does just this. I created my own "splash screen" image and loaded it from the card, it worked just fine. The image is relatively slow to load but it's fine for this one-off usage. So it seems the SD card reading is working OK, for now I'll assume writing will also be fine.

The final step was to try out some digital pots. My first effort was with the MCP4161 Digital Pot.  There was some suggestion these are Arduino compatible but when I looked more closely at the code it seemed the SPI requirements may not play well with the other two devices as it claims to only work with a non-standard SPI library. Indeed I couldn't seem to send them any data. To be honest I didn't try that hard because I already had an alternative to hand - the Analog Devices AD8402 digital pot. Using this tutorial it was pretty easy to figure out how to use them, and this forum post was a reminder that the RS (and SHDN) pins need to be tied to VDD. In the end it was all pretty easy, I first got it working first with a simple sketch from the tutorial that just changed the resistance, and then integrated into my MegaMiniSynth code and hooked up to the rotary encoder and a "slider" display on the TFT. I'd been using a manual pot to control the PWM for the square wave shaper, a good test was if the digital pot could take its place. Again it worked first time, set up as a voltage divider it worked fine. I had been expecting to have to use the logic encoder feature of my DSO to debug the SPI protocol but fortunately that was not necessary. I'm sure there'll be some problems downstream it will come in handy for.

Here's a rather shaky video that illustrates all these working together. My breadboard is getting pretty full - it's time to start thinking about moving some of this stuff to a PCB!






Monday 18 August 2014

Hand soldering a VSSOP package - a steady hand and a good eye

One of the components I've been keen to try is a SP3T digital switch. This will be used for routing such things as the various waveshapes and the modulation from the LFOs and Envelope Generator. Unfortunately it only comes in a VSSOP package (Texas Instruments calls it a DCU but they are, as far as I can tell, equivalent to VSSOP). This has a 0.5mm pitch (spacing) on the pins. What's more the whole package is very small only 2x3mm. In order to experiment with it I'd created a simple converter board from VSSOP to DIP. I realize that convertors are already available but since I could do it myself and only have it cost $1.75 for three from OSH Park and the available ones had to be sent from the US anyway it seemed like a nice little project.

The board itself was not especially complicated:


Fortunately there was already a VSSOP footprint available in KiCad so that made it a bit easier. Since then I have gained a bit more experience with adding footprints to KiCad and I realize if I'd made my own I probably would have made the pads a little longer so as to make the placement easier.

The boards arrived back from OSH Park last week and they were, as always, quite beautiful with their gold and purple finish:



I broke out my USB microscope and began soldering. Almost immediately I began to realize how difficult this task would be. Not only are the pins very small but the whole package is so light that even the lightest touch would displace it. True the package is actually a bit bigger than, say, an 805 resistor or capacitor but in those cases the pins and pads are quite large.

Most advice on the Internet for soldering this type of SMD package is to first tack down one corner, to use lots of flux and clean up with copper anti-soldering braid. I ended up doing all of those things, but found they are easier said than done. I tinned the pads, cleaned up any bridged pins with braid then placed the IC and holding it down with tweezers very firmly from the top I managed to blob a bit of solder in one corner. The pins looked roughly lined up, not perfect but good enough.  I recently got some 0.31mm diameter solder and that was useful. Then fluxed generously again and dragged some solder across the other side. More flux and then lots of time spent with braid to clean up. I've realized the hardest part is getting the braid in actually the right place. It needs to be right up against the pins and for such a small device that's not easy. Generally a little bit of smoke (the good type) showed when I was actually making contact with the solder. Fortunately testing for bridges was pretty easy, I could simply check each pair of pads on the DPI module with a multimeter. There was one stubborn bridge but I got it in the end by briefly heating the bridge directly with the iron before applying the braid. Once all the bridges were gone I could check continuity with the between the actual IC and the DIP pads and they all seemed fine.

Here are some photos of the final result:



As you can see the soldering tip looks huge! These photos were taken before I cleaned up the board so everything looks filthy, including the soldering iron! There's nothing like a close up view to show how messy things really are.

From the side things look a little better:




It's pretty clear the pins are soldered and lined up reasonably well with the pads.

Finally to give it some scale - here's one with a US dime:




All this took about 90 minutes and I needed several boards to get to a final, good result. However I believe that I'd be faster and more accurate next time, which may well be "for real". It was well worth the practice.

After all that effort it would have been extremely disappointing if it hadn't actually worked. Fortunately there was no problem. I hooked the logic pins up to a couple of Arduino pins (with pull down resistors, not sure if they are absolutely necessary but they seemed like a good investment). It worked perfectly first time. There are four states accessible with the two bits - all off and any one of the three output connected to the common. I used it to switch the output from the three waveshapers I have and it was great to be able to hear the waveform change as I pressed the push button on the rotary encoder.  Although there are several SMT packages I'm planning to use I hope this will be the smallest by far.




Thursday 14 August 2014

Bending it like Beckham

Pitch that is. And not a football one. The MIDI library I'm using makes it easy to respond to MIDI messages of all types with the use of callbacks. It's simply a matter of defining a new function and registering that to handle the message:

MIDI.setHandlePitchBend(handlePitchBend);


// A pitch-bend event has been received:
void handlePitchBend( byte channel, int bend )
{
  // Pass the pitchbend onto the oscillators
  OSC1.setPitchBend(bend);

}


The synth is so simple at this point it's hardly a priority but I couldn't resist trying it out. The question was then - how to bend the pitch? In the past I've worked with a MIDI-CV converter. When dealing with control voltages the bending is easy, since the exponential relationship between CV and pitch is handled by the hardware it's simply a matter of a linear interpolation between to get a voltage offset corresponding to the amount of bend.

In this application however I'm working directly in frequencies, or actually Timer periods but they behave like frequencies. There is a discontinuity in the values for each note since there are optimal pre-scalers for each note range as described here. That makes it a little tricky to interpolate between notes without some complicated code and special cases.

In any case when dealing with frequencies it's not a linear relationship. Each octave doubles in frequency. The MIDI standard suggests pitchbend is implemented as +/- two semitones therefore we need to bend by some ratio of 1/6th of an octave (since an octave contains 12 semitones). The code to do this looks like:

    // Implement pitch bend. The MIDI standard suggests that the pitch bend is +/- two 
    // semitones (or two MIDI notes). 
    // To figure out the bend factor we need to find out what multiplication factor
    // we need. This will be. Each octave doubles in frequency and there are tweleve
    // semi-tones per octave. Therefore we need a factor of
    // 2**(r*2/12) or 2**(r/6) where r is the ratio 
    ratio = fabs((float)m_pitch_bend/ MIDI_PITCHBEND_MAX);
    factor = pow(2,(ratio/6));
    if( m_pitch_bend < 0 ){
      freq = musical_freqs[m_note] * factor;
    } else {
      freq = musical_freqs[m_note] / factor;
    }
    OCR1A = freq;


Where m_pitch_bend is the value received from the MIDI library and MIDI_PITCHBEND_MAX is the largest absolute value we'll ever receive (also defined by the library). Once we know how far to bend than calculating a multiplicative factor is quite straight-forward and avoids the issue with discontinuities in the note data. This strategy may well come in useful when it comes to implementing other pitch manipulations in software such as vibrato.

But does this exponential scaling actually make a difference relative to simply scaling linearly? I did some experiments to see if that's the case. Here's scaling from Middle C to D with 50 linear steps:


And here's doing it with 50 exponential steps:


Tell the difference? I can't, but then I don't have a very advanced musical ear. In any case the exponential scaling is easier to implement and seems to work well.





Sunday 10 August 2014

Triangle and Gate

Having demonstrated the ramp and square waves were working well, the latter with PWM I went on to make the triangle waveshaper. This is shown in this section of the PicSynth Schematic:


This involves feeding the non-inverting input with 1/2 VCC. In my case since I'm still running of 5V from the Arduino it's 2.5V.  When I first tried it I was at my initial note - A (440HZ). I got a reasonable looking triangle:





However I found as I lowered the pitch it looked less like a triangle a more like a sort of rounded off square wave:




Interesting enough it still sounds reasonably different to the square wave, quite a bit smoother with less buzz. I experimented with some different values for the integration capacitor and decided that 4.7nF seemed to give a better overall frequency response - still giving an OK triangle at lower frequencies and not attenuating the higher frequencies too much. 

At the same time I did some experiments with a basic gate. Eventually I'll be able to gate the envelope generator but for testing purposes it would be useful to turn the sound on and off in response to notes rather than simply adjusting the pitch of a constantly running oscillator. I experimented with trying to turn the timers off between notes but this caused annoying effects at the start of each note.  Finally I just simply added an NPN transistor with the base attached to an Arduino pin via a 1k resistor to the ground connection of the output that leads to the amp. This is a bit noisy when the gate is off but it's kind of enough to give the idea of what "real" notes would sound like.








Wednesday 6 August 2014

Rotary Encoder

I've been experimenting with the RGB Illuminated Rotary Encoder that I hope to use. It took me a while to figure out the pins, they aren't in the datasheet but in a subsidiary dimensional drawing which shows it as it would appear on a PCB. I did this little diagram to help me solder it up:


I still managed to get the wrong color wire so it took me a while to figure out why the colors were wrong. Luckily that's easily fixed in software with pin assignments. 

Since I last used a Rotary Encoder with Arduino there's been some development and a couple of new libraries.  I've been using the Encoder library. This works best with external interrupt pins so I used 2 and 3 on the Mega. It seems pretty rock solid, in the past I've always had problems missing events - especially with code that polls. With these encoders I can usually generate reliable increments and decrements by a single count for each detent position and they seem to work for slow or rapid twisting. They actually feel pretty nice with a slight click as they rotate.

The illumination part I just did via standard PWM pins on the Mega (4,5,6) and 7 for the switch. The switch is "normally low" and so benefits from a pull-down resistor between pin 7 and ground. In my code I subclassed the Encoder object to make my own class that also knows about the switch and the RGB LED. Here's the definition of the class:

// This class subclasses the Encoder library described here:
// http://www.pjrc.com/teensy/td_libs_Encoder.html
// As such the pins the encoder pins should be attached to hardware interrupts.
// Additions to this class are support for the RGB led and the push button.
// The LED pins should support PWM
// The Button Pin needs a pull-down resistor on it and is normally low.
class RGBEncoder : 
public Encoder {

public:

  RGBEncoder( int enc_pin_1, int enc_pin_2, int red_pin, int blue_pin, int green_pin, int button_pin );

  void begin(); // Start the rotary encoder operating

  void setColor( int red, int green, int blue );
  // Set the color based on the RGB values. 
  // Each one is in the range 0-255;

  void update ( );  // Read the current encoder value, looking for changes

  int getValue( );   // Get the current encoder value

  boolean buttonPressed(); // Returns true if the button has been pressed.


private:

  int m_red_pin;
  int m_green_pin;
  int m_blue_pin;
  int m_button_pin;
  boolean m_button_pressed;
  long int m_button_down_time;
  long int m_button_check_time;

};



The full code is available on github. Currently the push-button detection is pretty simplistic. It uses a short delay period to debounce and simply keeps a flag for when the button has been pressed for more than 10ms. There's a lot more sophisticated treatment of buttons in another rotary encoder library that I'm very tempted to ..... ummm... "borrow".  It would be useful to be able to detect double clicks and to know when the button is being held down while turning. My main human interface will be only two encoders and a small screen so I'll need as much flexibility as I can get.

Ultimately it's not likely I'll want to use the six PWM pins just to drive the RGB LEDs in the two encoders I'll be using. The PWM pins rely on the timers and it's likely I will find better use for them as oscillators or modulators.  Instead I will investigate the use of an LED PWM driver such as the PCA9685 as featured in this Adafruit board. It's I2C driven so can be used with just two pins instead of six. The driver has 16 channels so maybe I'll add a couple of extra RGB LEDs simply for gratuitous effect.

Currently I don't have a lot of useful things I can do with the encoder other than admire the colors and verify it works. I did hook it up to traverse the MIDI notes and to change color - red for higher notes and blue for lower ones. Here's a video:











Sunday 3 August 2014

You can't use a 4n32 optocoupler for MIDI

In my last MIDI project, a MIDI to CV converter, I used the Sparkfun MIDI shield. It was probably overkill because I only wanted MIDI-in but it came with the female sockets and the optocoupler and I didn't have to get my head around how anything worked. Now I wanted to do MIDI-in via a breadboard. Fortunately there are lots of schematics and discussions around.

MIDI is simply serial communication at a 31250 baud rate so the Arduino should be able to read it using a serial Rx pin. The MIDI standard requires the devices to be electrically isolated so an optocoupler is usually used on the receiving end. An often quoted resource is this post to the Arduino forum. The hand-drawn schematic is pretty charming and it makes it all seem easy enough. The comments suggest both that this is a popular topic and that despite it being a relatively simple circuit people have a lot of trouble making it work. I guess there's a lot of idiots out there right? Well turns out I'm one of them, perhaps more than most.

Initially it was simply a matter of getting any signal at all. It took a while to figure out the numbering on the MIDI connectors and whether it's shown relative to the front or back of the connector. As an aside I'm still to understand why a five pin cable is needed when only two lines appear to be used. This summary of how MIDI is wired up was pretty useful, especially since I'll eventually want to do a MIDI-thru as well. Generally a diode is used to protect the optocoupler against reverse connections. I managed to destroy an optocoupler by removing the diode to inspect if it was the right way around while I had the MIDI cable connected up in the reverse sense. Also I had a little bit of brain fade with respect to how ICs are numbered.... suddenly it wasn't turning out so simple after all.

Eventually I got it all straightened out, had a more or less conventional setup hooked up to my MIDI keyboard and appeared to have some signal coming out. However only about one note in 20 actually changed the pitch and then it seemed more or less at random. I'd already written MIDI receiving and processing software for the Arduino that I knew worked so I had a fair degree of confidence that the software part was working.

Turns out the key was the optocoupler. I happened to have a handful of 4n32 optocouplers that I'd bought for some project or another.  There seemed to be lots of projects around using the 4nXX series to read MIDI so it should be OK, right? The 4n32 is a darlington (two transistor) optocoupler but so is the 6N138 and that's widely reported to work. Well actually it's worth checking the datasheet. If MIDI is at 31250 Hz then the period is of the order of 32 microseconds. An optocoupler takes a finite time to switch on (or on to full brightness I suppose) and to switch off. These values are given in the datasheet. For the 4n32 the on time is 5us. The off time has a max of 100us. So that's going to be a bit of a problem with a 31kHz signal. Indeed here's what it looks like on the scope:



The input, those nice square pulses, in green and the output in yellow. The MIDI signal is inverted by the optocoupler as expected since the MIDI definition of true is a high. You can see the slow turn off time of the 4n32 with respect to the signal frequency means the pulses are very quickly hopelessly out of sync and what I was reading with the Arduino was basically noise with a pseudo 31kHz baud rate.  So the lesson - read the datasheets. In retrospect I suppose it also was a little suspicious that a Google search for MIDI and 4n32 only shows up questions asking how to make it work...

Doing some research I saw there are ways to speed up optocouplers by adjusting the pull up resistors and the like and I did some experiments but I was unlikely to get the order of magnitude improvement I needed. Luckily a local supplier had some 4n35 optocouplers. These are a drop in replacement but the datasheet show a typical turn off time of 7us and a max of 10us. That's a lot better and indeed the scope shows that the input and output track pretty well:


So the Arduino could read the serial signal and I had MIDI-in! It's likely in my final design I'll use something even faster, perhaps the 6N137. These are designed for logic operations and have switching times in the ns range which might be overkill but I'll do some experiments to see. Typically a 6N138 is used, that's what was in the Sparkfun MIDI shield I mentioned earlier. The 6N138 has switching times comparable to the 4n35.

Here's a short video of what I have so far connected up to my Arturia Beatstep - a great little sequencer that has both CV/Gate and MIDI out. I get a lot of use out of it on my modular system. I had in mind building something similar and I try and avoid buying new toys but this was so cheap and works so well it was one of the few times I was discouraged from DIY.



Finally in doing some research on MIDI and the Arduino I discovered there's a reasonably mature and very well supported MIDI library available. This is fantastic, is very flexible - even allowing me to read MIDI on Serial1 of the Arduino mega so I could continue to have debugging to the normal serial output. The resulting code is very clean, much more so that the state-heavy code I wrote myself and the library handles a whole range of standard messages. I'm looking forward to exploring it further.


Friday 1 August 2014

Waveshapers - some sound!

As a start I wanted to test the basics - the ability of Arduino to create a musically correct tone and to shape that into a useful ramp or square wave with external circuitry.  As a starting point I used two resources. The strategy of sinneb to generate an accurate pulse from the Arduino as shown here. Also from the PicSynth the simple 4520 based waveshaper shown in this schematic.

Here's an obligatory photo of the breadboard.


Interesting huh? Anyway it worked - I had sound! A chunky sounding square wave and a surprisingly chunky ramp. However there was an oddity - the PWM control seem to only have a could of steps so it wasn't possible to get that classic PWM sweep I like.  Taking a look at the output on my scope it soon became apparent why. Here's the ramp wave:



It's a ramp Jim, but not as we know it. If I'd stopped to think a bit about how the circuit works then it would have made more sense. The 4520 is a four-bit counter and essentially divides the input into four square waves that are added together to make this stepped ramp. 

Reading the PicSynth site a bit more closely I realized that the author knew this of course and had an alternative. This circuit based on a 4046 and 4024 gives more conventional sounds and much better looking waveforms. There's also an excellent explanation on that page of how the ramp->square conversion works. This explains very well why the stepped ramp wave can't really be used for PWM. I won't repeat it now, go read it yourself.

Here's the circuit on the breadboard:



 I haven't built the LFO yet but I've simply been using a pot as a voltage divider to control the pulse width. Here's the ramp and the square with the square wave near the minimum width:



You can see the ramp wave looks much better - more or less like the real thing. This is a 256 step conversion so it's pretty smooth. There's a bit of noise, but hey - it's on a breadboard!

Here's another image with the pulse width near maximum:



I don't have any proper input device yet but have simply been using a pot connected up to the analog input of the Arduino and using that to sweep across the notes.

Finally I used my guitar tuner, which has a chromatic mode, to verify the notes were as I expect them. Every single one was within about 5 cents and I confirmed a few with the frequency counting mode of my multimeter as well. So this is a promising start. The next thing I will try is hooking up some MIDI input so I have a more conventional way of setting the current note.