Thursday, May 29, 2014

MIDI drivers and a UI surrogate

So, I wrote drivers for all the MIDI I/O on my groovebox. This would be 1x MIDI input and 3x MIDI output. Now this gadget happily sends and receives all kinds of MIDI data. The main thing still missing is the SysEx data support but I have no use for it, at least for now. I’ll add it later if I actually need it.

Now, how do I know the I/O ports actually work? Well, I created a simple UI test plugin using Max For Live



The plugin acts as a temporary user interface replacement for my groovebox. It will be replaced with an actual HW UI when I get it designed, up and running.

The plugin waits for mouse clicks on its buttons. When a click happens, it sends the button click information to my HW groovebox using my computer’s MIDI output. The groovebox deciphers what should be done with this button click and sends back user interface control information (using it’s own MIDI output), such as “change the colour of button #6 from black to orange”. All this makes it really easy to see that the groovebox’s firmware is actually working as it should.

Currently the plugin displays the following information correctly:
- Note on/off.
- Note pitch.
- Play position in the pattern.
- Amount of unused CPU.

To test the other two MIDI output ports also work as they should, I’m using them to send sequenced MIDI data into my computer. One of the MIDI outputs is playing a simple electro house bassline and the other one is playing a repeating one note loop. I’ve setup the Ableton Live so that there are two soft synths playing these midi notes.

Here’s a quick recap of what the MIDI ports are being used for at this point of development:
- MIDI Input 1 = Receive UI event information from computer (Max For Live plugin).
- MIDI Output 1 = Send UI control information to computer (Max For Live plugin).
- MIDI Output 2 = Send electro house bassline MIDI notes to computer.
- MIDI Output 3 = Send repeating one note loop to computer.

Creating this plugin was a really slow process for me, since I had no previous experience with Max. I spent lots of time RTFM'ing, browsing through examples, experimenting, swearing and taking baby steps towards my intended goal. Eventually I got the first few features working as they should and felt happy about it. There's still a lot for me to learn about the Max environment, so I expect to do a lot more RTFM'ing and swearing in the upcoming months.

If you're wondering what MIDI interface I'm using to connect my groovebox with my computer, it's all handled by MOTU Midi Express 128.



Monday, March 10, 2014

Testing the MIDI I/O

Next it was time to test the MIDI I/O. I soldered the appropriate components on the PCB to get the MIDI working. Then I wrote a simple program which turned on and off the pins which would be used for MIDI output for each of the MIDI ports. I checked the outputs with an oscilloscope and everything was fine. 0-5V output signal with sharp transitions between the 0 and 1 binary states. Happy times!

Then I plugged the MIDI output to my computer's MIDI input. No signal. What?!?

Feverishly I browsed through midi specifications, my PCB design and everything in between. Eventually I noticed that the MIDI connector pin order was inverse in the Eagle library component I was using. I have no idea what has gone through the mind of that person who committed this crime against all the engineers out there. Why on earth would anyone want to create a library component, name it "MIDI connector" and then reverse the pin order?

Luckily I wouldn't have to redesign the board before I could test its MIDI capabilities. The MIDI connector's pin layout is symmetrical and it uses Through-Hole pins. This means that if I just soldered the MIDI connectors on the bottom side of the board (instead of the top as I had designed it), everything should work just fine. I spent a good 20 minutes trying to remove the MIDI connectors from the PCB. No such luck. I would have to solder a new board…

After about an hour, I finally had a new board soldered together. Quick power up and my IDE recognised the board again. I plugged the board's MIDI out to the MIDI in of my computer and hey presto, there were MIDI notes appearing on my screen!

Next evening I studied the microcontroller's data sheets some more to get the MIDI input working. It wasn't much different from the MIDI output. The NXP microcontroller's architecture has been designed so that everything works in similar fashion. Just flip a couple of extra bits here and there and suddenly you can receive MIDI data.

I was quickly becoming a fan of NXP. At this point I decided not to move forward with the STM32 any longer. The LPC4330 was doing great job.



Above is a picture of the "brain PCB" with NXP LPC4330 microcontroller and one MIDI in and MIDI out ports attached to the bottom side of the board. The grey box is the JTAG programmer.


The test program configures the main clock to use a 12 MHz crystal and uses the PLL to run the system in 204 MHz. Next it configures the main buses to use the same PLL as the main clock, just to keep things nice and tidy.

Then there's the UART I/O configuration. And finally quick and dirty MIDI input / output routines. The test doesn't use any interrupts or DMA.


Testing a new microcontroller

As my previous post describes, the latest batch of PCBs was unusable due to a simple design bug. So I spent one more evening fixing the bug from the "brain" board.

At this point I felt the STM32 family of microcontrollers might not be the easiest one to use. This wasn't due to the above mentioned bug, but because of the amount of hours needed to browse through the microcontroller's data sheets and other technical documentation to get the basics up and running. This includes the hardware and software side of things. The microcontroller's architecture felt a bit like lots of splinters were thrown together which somehow formed a functioning system.

I had heard rumours that grass might sometimes be greener on the other side of the fence. I felt curious. What if instead of ordering this new board, I would order two different boards: one STM32 based brain board and one based on the NXP microcontroller? This sounded like a nice test.

I delayed my next PCB order by about 1.5 weeks. I spent the evenings studying the NXP LPC4330 microcontroller's technical documentation and designing a PCB around it. LPC4330 is also an ARM Cortex family microcontroller, just like the STM32F373 I had used so far. Instead of being 72 MHz like the STM32, the LPC4330 was capable of running at 204 MHz speed. Not only that, but it was dual core! One of the cores was the M4 with a floating point unit, SIMD instructions and all the usual. The other core was M0 core, which could be used for slightly less math intensive tasks. Nice!

The next thing I noticed about the LPC was that the architecture and all the technical documentation were much more clear than on the STM32. This started to look really good, so I moved forward with the PCB design. I added couple of extra features on the LPC board: more MIDI outputs, an external flash memory, USB port and a JTAG port. I copied the designs fairly faithfully from official evaluation board schematics. Then I checked the board for bugs. I wasn't sure if the USB port would need something extra to work, but I decided to give it a go anyway.

Once I was satisfied with the board, I hit the order button. Twice. Once for the LPC4330 version and once for the STM32 version.

This time the PCBs arrived in about 1.5 weeks. I felt excited about the new LPC board so I decided to solder its components first. The hardest part was getting the 144 pins of the microcontroller to sit just right on the pads. If one corner pin was a bit off its mark, some other pin across the chip was likely to be 7 meters off the mark.

Once all the critical components were soldered, I plugged in my JTAG programmer and plugged some power on the board. My IDE recognised the board right away! Excitedly I wrote a quick and simple "Hello World" program for the LPC4330 and ran it. Success!

All the basics seemed to be working fine, so the next obvious step was to add rest of the components on the PCB.


Sunday, March 9, 2014

Adventures with DHL

So. It was mid December. I was working on the next version of the prototype brain/digi-board for my groovebox. I had put lots of time and effort trying to figure out the requirements for the PCB. What would I want to plug into it? What tasks would the microcontroller have to handle?

I divided the groovebox into three different modules:

1. Digital "brain" which contains the microcontroller and the MIDI I/O.
2. Audio generation module, which handles the analog part of the audio synthesis.
3. User interface or the "UI".

Each of these modules would be on a separate PCB. The brain module would be connected to the UI and audio generation boards. The UI and audio generation board would not be directly connected to each other.

The advantage of this is that if I decided to modify - say - the user interface, I wouldn't necessarily need to change other parts of the groovebox. I would just need to update the UI circuit board and the two other circuit boards would stay the same. This modular approach saves lots of time and money if I don't have to touch all the boards every time I update one of them.

So, to make the above even remotely possible, I would need to come up with some realistic specifications for the UI and the analog synthesis boards. What kind of signals/data would need to flow between the boards? How much data per second is needed? Are there some signals which need extra protection from interference? Damn, I would actually need to design most of the functionalities of the user interface to figure all this out!

I decided to use couple of I2C and SPI buses between the brain and the UI modules. I also added five extra data lines for possible interrupts. These should enable me to create a proper UI with a small screen, lots of buttons, some rotary encodes and even some potentiometers.

I did a similar plan for the audio generation module, but it proved to be a much more complicated task. Eventually I decided to put "a little bit of everything" into it. This should keep me going for a few weeks before I had figured out a more appropriate set of signals needed to do the job.

So each day - for over a week - I worked into the early hours of the morning before I had the signals figured out. It was one of these evenings I finally got the brain PCB designed. It was 2 AM and I spent last of my brain power making sure there were no bugs. After I felt confident the PCB should work just fine, I ordered the board from Seeedstudio.com and went to sleep.

Then the trouble started. After about 1.5 weeks DHL brought the package into the customs, but for some weird reason they didn't contact me about it. After the package had stayed in the customs for almost 2 weeks (that's 3 weeks of waiting already), Seeedstudio contacted me. They were worried and informed me that that if don't get the delivered package from the customs, they're going to send it back and I have to pay also for that shipping. I grabbed the phone and called DHL right away. A nice lady answered the phone, checked the status of the package and said: "Weird. The package should be ready if you just pay the customs fee. I've no idea why you haven't been contacted yet. Sorry about this." So I got their bank account number and paid the customs fee. I felt really irritated about the fact that I had waited for two weeks for nothing.

Next day the DHL delivery guy called me. He was lost and couldn't find my address. I described what's in front of my house and asked if he could see any of the land marks. He did. I explained him in detail how to find the front door (which isn't hidden but right along the main street). I don't know if there had been a wild pot party at the DHL office right before the delivery or what was going on, but it took him almost 10 good minutes before the guy figured out which was the right door. At this point I was cursing the DHL into the deepest pits of engineering hell…

Finally the guy arrived at my door and delivered the new PCBs. I felt really irritated and was cursing to myself that the only thing missing was that the god damn PCBs wouldn't even work. I went to my small electronics lab and checked the PCBs. I was delighted to see that they were of good quality. Check the image on the right to see what the PCB looked like.

Finally! Here's the long awaited PCB. I cleaned the board with alcohol and turned on the soldering station. Once the soldering station blinked to indicate it was warm enough for work, I started placing the microcontroller on the PCB. This is when I was greeted with this sight:



Motherfucker! Over three weeks of waiting, fucked up DHL and I had rendered the PCB completely useless by accidentally putting trace protecting solder mask over the 100 microcontroller pins during the design process!

Well… Atleast the nearby pub was open…

Moral of the story is that you should never EVER:
1. Inspect the PCB for bugs 2 AM in the morning.
2. Order the PCB from the factory 2 AM in the morning.

Thursday, February 6, 2014

What does my microcontroller's digital to analog converter output look like?

My microcontroller has couple of DACs (digital to analog converters). I decided to test what kind of tasks they're good for. For this I wrote a simple routine in C++ which outputs pure sine wave through the DAC. I updated the DAC in 60 KHz speed.

Lower frequency sine waves looked exactly as they should on my oscilloscope screen: beautiful sine waves. When I started to get closer to the 10 KHz frequency, the results looked more and more stair stepped. At 12.5 KHz the sine wave looked like this:


Each of those steps is exactly one sample long when the samplerate of the DAC is 60 KHz.

Obviously the results are less than desirable for regular audio signal generation, so I decided to test what would happen if I filtered the signal using a simple low-pass analog filter. I put two of these in series:


…and got this as my output:


(Note that I've zoomed out the oscilloscope's view so it shows about 4x more of the signal.)

Much better! But there is some obvious lower frequency swaying in the result. The sine wave moves noticeably up and down. It's like the aliasing/quantisation has added extra sine waves into the signal. It's time to switch the oscilloscope into the FFT view:


Yep. There are obvious large spikes up in the audio spectrum above the sine wave's frequency.

So it seems that the microcontroller's own DAC (with simple filtering) won't be enough for audio signal playback, but most certainly can be used for all kinds of control signals, such as envelopes, LFOs, and so on.

All in all, the microcontroller's DAC outputs will be highly useful for my groovebox's design.

Thursday, January 30, 2014

Testing the step sequencer architecture

So I got the basic step sequencer architecture up and running. I made it as flexible and upgradeable as I possibly could, without making it too complex.
Currently I'm using 20.44 fixed points to iteratively calculate the absolute position in the pattern and then doing rest of the math and triggering based on that data. This approach streamlines the overall step sequencer architecture nicely and makes it a bit easier to integrate all kinds of fancy extras. Some of them are the upcoming swing function, MIDI sync and the note offset & note length which scale with the swing properly.

Here is a video showing the step sequencer running and updating the LEDs accordingly. The lit up LEDs have note data in them. The oscilloscope screen shows debug control data the microcontroller's DAC sends out.

The oscilloscope also shows that the long notes are properly cut off by the new ones. That would be the second longer "bump" which has a hump at the end.

Visualising the system performance

Now that my groovebox's operating system was able to calculate the amount of CPU used, I wanted to get a realtime view of it. Easiest way to do it on my system was to use the note step LED's to indicate the amount of free CPU left. The lit up LEDs represented the amount of unused CPU left and the dim LEDs represented the amount of used CPU.

For the record, the picture was taken of the system running 60 000 rounds per second. Each round doing 2 thread switches, lots of 64bit integer and 32bit integer and floating point calculations, memory accesses and function calls. In other words, the system ran the whole step sequencer and audio/sample generation routines, unoptimised, 60 000 times per second. And this was a debug build. The release build runs around 3-4 times faster. That's a lot of power the 72 MHz microcontroller packs inside itself!