I’ve recently introduced myself to the world of microcontrollers (μC for short, if you feel cool enough), I’ve always found the world of digital electronics quite fascinating, being very fond of the DIY way of thinking, but I only recently decided to get my hands dirt with it and bought some PICs from Microchip and a PICKit 3 Debug Express. As a musician, the microcontrollers’ world opened quite a number of interesting possibilities. If you consider my undying need for a good MIDI controller and add to that the enjoyment I get from embarking myself in projects way out of my league, the result is obvious: build a MIDI controller!
The internal AUSART
The purpose of this article is to explain how to use the PIC’s internal UART to send MIDI messages to a MIDI enabled device. Almost every recent PIC microcontroller has an internal AUSART (Addressable Universal Synchronous Asynchronous Receiver Transmitter) that makes the task of implementing the MIDI protocol quite trivial. Without getting into details (saving me the embarrassment of explicitly saying I don’t know them), an USART is a device that converts streams of serial data to parallel data (or vice versa) using either an asynchronous or synchronous communication. In case of an asynchronous communication, the two communicating devices must agree beforehand on the transmission speed and start and stop bits are required to mark any data transfer. The start bit must be a space (logical zero, low) and the stop bit a mark (logical one, high). In the attempt to preserve data integrity a parity bit can be sent before the stop bit. If the parity bit is present, the two devices must agree on the format before they start exchanging data: the parity bit can be set whether if the number of logical ones in the data’s bits is even or if it is odd. The communication speed is expressed in baud, that is a synonymous for symbols per second. In our case 1 symbol = 1 bit, so 1 baud = 1 bit/s. The data is sent from the least-significant bit to the most-significant one.
The MIDI protocol (a.k.a The Real Stuff)
By now, if you really read through this point without skipping (in which case, shame on you!), you’ll start to wonder what all this have to do with our MIDI controller, and the need to turn some knobs is probably starting to get uncontrollable, so hear this: the MIDI protocol exchanges data using serial communication, each packet is made of a start bit (a space) followed by eight data bits, least-significant bit first, and finally by a stop bit (a mark). The data transfer and reception happens asynchronously at 31250 baud, rings any bell?
All we have to do now is understand how to configure and use the internal AUSART of our PIC (in my case a 16F88) in the way I just described.
Reading the data sheet for the PIC16F88 (chapter 11.2.1 AUSART ASYNCHRONOUS TRANSMITTER), the steps for setting up the AUSART for asynchronous transmission are listed:
- Setup the Baud Rate Generator (BRG)
- Setup the asynchronous serial port by clearing bit SYNC and setting SPEN
- Set bit TXIE to enable interrupts
- Set bit TX9 for 9-bit transmission (generally used for the aforementioned parity check)
- Set bit TXEN (that will set TXIF also) to enable the transmission
- If TX9 is enabled, load the 9th bit in TX9D
- Load the 8-bit data in the TXREG register (this action starts the transmission)
- Ensure the GIE and PEIE bits are set in the INTCON register if interrupts are used
This should all be pretty clear if you have some experience in developing on the PIC microcontroller. What remains to be further explained is the first step where a Baud Rate Generator is mentioned: the AUSART has an internal 8-bit timer that takes care of sending our data at the speed we need. To configure this timer we need to act upon the SPBRG register and the BRGH bit, but because of the 8-bit limitation of the BRG timer, and of the high values of the most common baud rates, setting up the BRG is not as straightforward as you may think. The data sheet informs us that the baud rate that will be used to transmit data is calculated using the following formula (Table 11-1):
- FOSC is the speed of the PIC’s oscillator
- SPBRG is the value of the 8-bit (0 – 255) register
- C is a constant and its value is defined by the following table:
||Value of C
|Synchronous transmission with the BRGH bit not set
|Asynchronous transmission with the BRGH bit not set
|Asynchronous transmission with the BRGH bit set
So, doing some math (probably wrong!), if we know what’s the baud rate we want, we can calculate our SPBRG value using the following:
The MIDI protocol operates at 31250 baud so, assuming that we are using the internal oscillator set at 4Mhz and that we are not using an high baud rate (BRGH = 0), the SPBRG value we need would be:
So let’s recap:
|To send MIDI data we need to set the transmission speed to 31250 baud
||SPBRG = 1
BRGH = 0
|We need to setup asynchronous connection
||SYNC = 0
|We need to enable serial output
||SPEN = 1
|MIDI doesn’t use parity so we want 8-bit data
||TX9 = 0
|We need to enable the AUSART out to start the transmission
||TXEN = 1
This is all we need to get the internal AUSART to send MIDI data, just put the MIDI byte to send in the TXREG and busy wait (or if you want, use interrupts) for TXIF to clear and you are done!
TXIF will be set if the AUSART is busy sending data and can’t accept new data in the output buffer so you have to wait until it clears to proceed.
MIDI messages overview
If you don’t know how MIDI messages works I’ll give a brief explanation: most MIDI messages are composed of three bytes, the first byte is called the Status Byte and it is used to specify the kind of action you want to be performed. The Status Byte is OR-ed with the channel you want the message to be received on, so for each status byte you really have one nibble (4 bits) for the actual “action code” and the other nibble for the channel, leading to 16 (0xF) functions and 16 (0xF) channels (as you’ll probably already know!). The meaning of the following one or two bytes depends on the value of the most significant 4 bits of the Status Byte (what I called action code).
For example to send a Note On message for note C4 on channel 6 with a velocity of 80 you would send:
- Status Byte = 0×90 (Note On) OR 0×6 (Channel) = 0×96
- Byte 1 = 0x3C (60 is middle C or C4)
- Byte 2 = 0×50 (80, the velocity)
You can take a look at the following websites for further informations on the available MIDI messages:
Or, if you don’t really know what to do with your money and/or you have an unusual fetish for printed documents, you can buy (yeah! BUY!) the official specification document from http://www.midi.org/store/docsales.php for only 60$ (or if you are here in Italy 88$)
If you have come so far, it is now time to test your hard work! To do so you should connect the 5th pin of your female 5-pin DIN connector to the Tx pin of your PIC (on my PIC16F88 it is RB5, consult the Pin Diagram section of the data sheet for you PIC to find out what’s the correspondence with Tx for your model) and the 4th pin on your +5v power source, both through 220 Ohm load resistors, and you are set to go!
What to do next, now that you are cool
Once you are able to send MIDI data with your microcontroller, the next step can be connecting a switch and mapping it to a specific MIDI message, or using the internal ADC converter of your PIC (if you are in luck, it has one) to send the value of a trimmer (or pot) using MIDI’s Controller Change messages.
Source code and Links
Anyone interested can download the little library I made to send basic MIDI messages with my PIC16F88 (but should work for others too) which I’m releasing under GPL. It was written for the CC5x compiler, if you don’t have it, you can get a student version here that has no limitations on the size of the compiled code (only on the optimization level), it also directly outputs compiled code to ASM (MPASM), so if you don’t want to use the CC5x compiler, but you like my library (what? Why?), you can simply compile it to ASM and use it with your favorite one.
PIC Simple MIDI Library for CC5x (2124)
Well, this is it! Thanks for reading and if you are getting into DIY MIDI controllers check out this nice websites:
- http://www.audiomulch.com/midipic/Has lots of informations on how to use a Basic Stamp or PIC to send/receive MIDI data and interface different type of hardware to the microcontroller.
A fantastic, huge, project to build your MIDI controller/sequencer with a modular approach. It is also the home of the MIOS operating system for different type of microcontrollers, a robust operating system developed to be used on hardware MIDI applications.