I decided to build and design a midi controller which is used to send commands to a computer running a DAW(digital audio workstation)  to control different parameters within it. The DAW I used is called Ableton Live. There are 16 button pads and 6 potentiometers on the front of the unit. Depending on which DAW is used, you can assign the potentiometers to control parameters like track volume, track reverb, and any other effects applied to a track. There is also a dock on the side which has 10 more analog channels to connect more potentiometers and allow for future expansion of other projects and ideas.  The buttons can be used to launch loops, or you can play it just as you would play a regular piano or keyboard.  You will be able to change the bank of notes that the buttons send to the computer using bank up and bank down button on the front panel. There is a total of 128 notes (or 128 values)  you can play on the buttons and you can bank up 16 notes at a time meaning 8 banks. There are also RGB LEDs’ under the buttons to indicate what bank you are currently on. There is also an LCD display displays what value you are sending to the computer and indicates the bank number.

1.1 Midi Overview
Midi allows you to control virtual instruments within a audio recording program. For example you can assign a piano to a track and control the notes of the virtual piano using a midi controller.  A midi command is consists of 3 bytes. The first byte is a status byte. It tells the computer what type of action it will be performing. For example a common status byte would be  the decimal value 144 which means note on. This is then followed by two data bytes; the next one being which note to turn on.  0 is the lowest note and 128 is the highest.  The last byte would be how loud you want that note to sound.  This is called velocity. 0 would be the quietest and 128 would be the loudest.   If you want to control things like volume or any other parameters you can send what is called a control change command. This is only two bytes. The first byte would tell the computer which control change you are wanting to control. For example sending the decimal value 16 would be initiated a control change on channel 1.   The next byte is the value between 0 and 128  which is sent to the computer. You assign which parameter is controls within the program.

There are 3 PCBs’ which I have designed which make the operation of this midi controller possible; the main PCB(Figure 2.0), the RGB driver(Figure 3.0-yellow), and  the analog channel expansion port(4.0-yellow). There are 3 units I have used that are bought online; the MIDI to USB converter(Figure 4.0-purple), the LCD screen(Figure 3.0-purple), and the button pad PCB(Figure 3.0-purple).

The main PCB holds the microcontroller I used, and two ADC chips. The microcontroller I used is a PIC18F2550, and the two ADCs’ I used are LTC2309s’.  If you refer to figure 2.0, you can see the PIC placed in the center and I have placed the two ADC’s on either end of the PCB. The reason I did this was because of the location I have mounted the PCB within the enclosure. The 6 onboard potentiometers are to the left of the PCB and the ADC extension port is to the right of the main PCB.  Since each ADC has 8 channels, I have set it up so  IC2 uses 6 of its channels for the onboard potentiometers, and then the extra two  ADC channels  are added to the ADC extension port. 
If you refer to the main PCB schematic in step 5, you will note that I have used two voltage regulators for this design. IC3 is set to regulate the voltage at 5 volts. This voltage is used to power the chips, LCD, and button pad LEDs’. The other voltage regulator, IC5, is an adjustable reference voltage for the potentiometers and ADC channels.  This is adjusted using a small surface mount potentiometer located directly beside it. There is also a diode in series at the input of these voltage regulators to keep anything from being damaged if the input voltage was accidently reversed. I made sure the diode was rated high enough to handle the current.  Located around the PIC are various connectors used for connecting to the button pad and LEDs’. The function of each pin will be discussed in a later section. To the right of the PIC are the connectors used for connecting to the analog channel expansion port and the programming port. The reason I have the programming port on the same PCB as the ADC extension port is I want to be able to reprogram the PIC without having to remove the lid of the unit. To get access to it, the side panel simply needs to be removed as shown in figure 5.0.
The LED driver PCB I designed is mounted directly beneath the button pad PCB(Figure 3.0).  If you refer to the schematic in step 4 this PCB enables me to control all the LEDs at the same time.  The connection from this board to the main PCB has 5 pins; VDD, GND,  and 3 LED control pins. Each of these control pins is connected directly to the input of the mosfet on the driver board which controls all the LEDs of that color. One mosfet controls all the red LEDs, one for all the green LEDs, and one for all the blue LEDs.


Step 1: Program Operation.

The following section will discuss how the program works.  Section 3.1 will go over the initialization part of the code which happens before the main loop. Once the program enters the main loop is calls out to 4 different functions: potread, keypress,  bankchange, and RGB. Sections 3.2, 3.3, 3.4, and 3.5 will discuss these functions separately.  Please refer to the code in step 6.

3.1 Initialization
Any microcontroller needs to be configured first before it enters a main program loop.  This includes setting up the direction of the pins, putting the correct values in any of the control registers, and defining the main clock that the microcontroller is going to be using.  The first step of my program was to set up the config registers.   These registers typically control things like the watchdog timer, any master clear reset pins, brown out detect, and oscillator configurations. In this particular example I set it up so that a 20Mhz external oscillator crystal is used as the main clock for the PIC.  The PIC has internal oscillators and can run up to 8Mhz, but due to the speed of the midi data, I needed to run the microcontroller at a higher speed in order to avoid any data errors.  Note the location of the oscillator on the main PCB board layout in section 7.1. I soldered the crystal directly beneath the board so it is not visible in figure 2.0.
The next register I configured was the RCSTA and TXSTA registers. These registers are responsible for controlling hardware serial commands. The reason I used hardware serial commands, as opposed to software serial for sending the midi commands, is because I am sending the data to the midi converter board at 31250 baud.  I tried sending the data first using software commands only, and I was getting errors and the computer was receiving data that had missing bits and missing pieces of information.  The hardware serial port has an internal buffer used for directing the flow of data and is therefore more reliable.  The only limitation of using the hardware serial commands is you are restricted to using only certain pins on the microcontroller where as if you send software commands, you can use any available pin you want.   The LCD I used only required the data to be sent at 9600 baud, so I any command I sent to the LCD was software serial commands.
I then set up the pins that were going to be used to control the LTC2309 chips.  These chips are controlled using I2C commands so only two pins are needed to control the two chips.
After this I defined all the global variables used in the program. I then configured the direction of the pins but loading the correct bytes into the TRISA, TRISB, and TRISC registers on the PIC.  Loading a zero defines the pin of that port to an output. Loading a one, defines it as an input. For example: if I load the value 00000001 in into the TRISB register,  Pin zero on PORTB would be an input while pins one through seven are defined as outputs.
Since the PIC also has onboard ADCs’ I needed to disable those so that’s the next thing I did.  The LCD display then is turned on and an intro screen is displayed.  The software serial command is a function built into Picbasic Pro which is the compiler I used.   Anytime I want to issue a software serial command, I need to specify the pin I want to send the command on, the baud rate, and the data that I want to send.  I found out how to control the LCD through its data sheet. 
The buttons then cycle through the different colors.  The purpose of this is to make sure everything is connected properly.  If all the colors are displayed I know the RGB LEDs are connected correctly. The program then enters the main loop.

3.2 Potread
Since there are 8 channels on each LTC2309, I set up the program so all 8 channels of IC2 are read in one for loop, and all 8 channels of IC4 are read in another for loop.  Since these chips are controlled using I2C commands only two pins are used.  One is a clock pin, which runs a 100Khz, and the other pin is a bi-directional pin, which is used to send and receive data.

In order to read the analog value from any given channel, you need to tell the ADC what channel you want to read therefore before you read any channel you must first send two bytes of information to the chip. The first byte the microcontroller sends to the ADC is the address frame. There are two pins on the LTC2309, which you can configure to set the address.  By setting the AD1 pin, and AD0 pin to either high, low, or floating, you can get up to 8 different addresses, meaning you can connect up to 8 different LTC2309s’ on one I2C bus.  If you refer to Figure 6.0 you can view the different configurations.  I’ve indicated which address’ I am using. 7 bits are used as the address, and  the LSB(Bit 0) is used to indicate weather it is a read command or write command.  Setting this bit to one prepares the ADC for a read command and setting it to zero sets it to a write command.

The following byte sent to the ADC is a 6 bit “Din” word.  This is responsible for channel configuration.  See Figure 8.0 for Din configurations. I’ve highlighted the different words I have used.  In my program, the S/D bit is always set because I am doing single ended measurements.  The UNI bit is also always set because I am only using the chip in unipolar mode.  Figure 7.0 is the timing diagram for a write command included in the data sheet.

Next the ADC sends the analog value to the microcontroller. However, any time any information exchanged from the ADC to the microcontroller, you must still send the address frame, except the LSB in the address frame is changed to one, meaning it is a read command.   The 12 bit analog value is sent in two bytes.  Figure 9.0 is the format of the data comes in. I read the analog value into two different variables. One variable holds the 8 most significant bits, and the other byte holds the 4 least significant bits of the variable.  However the least significant bits are siting 4 places to the left in that variable, and the 4 bits to the right are just zeroes. In order to get this value into a useable form, I shift the 8 most significant bits 4 places to the left. I am able to do this since the variable I am using is a 16 bit word.  I then shift the variable with the 4 least significant bits 4 spots to the right.  These two values are then or’ed together and the result is a 16 bit variable with a 12 bit analog value.  However I still have to scale the value down since a midi control signal value is only one byte. The max ADC value is 4095 in decimal, and therefore needs to be scaled down to 128. To do this I multiply the ADC value by 4095 then divide is by 128.  I have another variable, which I use to save the previous ADC value. When the loop comes around again it checks if the new ADC value has changed. If it changed more than a certain threshold value, then it sends a midi signal with the new ADC value.  If it is below this value, it skips it all together and continues to read the next channel.  I save the un-scaled value, so this threshold is 50.  I had to choose a value that was large enough to be above the noise, but not be so large that the analog values sent to the midi controller are really far away from each other, thus giving a choppy sound. A midi control command is a series of 3 bytes. The first byte specifies that it is a control command that is being sent. The second byte is which channel the control command is being sent.  The last byte is the analog value.    So for example, lets say within my music software I assign a volume on a certain channel to accept incoming midi signals from channel 16.  As I turn the potentiometer, the midi controller is continuously sending these 3 bytes at a very fast rate.  First two bytes stay the same every time these bytes are sent but the last value will be changing. The idea is you want this value to move up or down in small increments. The increments that it changes by is the threshold value  was discussed earlier. I increment the channel by 1, after each loop, so all the potentiometers are writing to their own midi channel. This loop is then continued 7 more times for that ADC chip. I continue a different loop another 8 times to read the values from the other ADC chip. The only difference between the two loops is the address I use to communicate with the chip, and the channel numbers that are being updated.
<p>How much did this cost?</p>
<p>Great job !! ....but while i was trying to compile the code, i got an ASM Warning,</p><p>FOUND DIRECTIVE IN COLUMN 1. (__CONFIG)</p><p>but it was compiled successfully anyway...Is it okay to burn this HEX...</p><p>Thanks</p>
<p>yep should be fine</p>
<p>great stuff bro, is there a chance you could give me a detailed list on electronic components, from every diode, resistors, capacitor, microchip.. thanks</p>
<p>hi!!<br>if I type in or copy paste the same code that you gave, then will I be able to play the same sounds as you did in the video?</p>
Really Nice Job !!!! <br>Thanks For Sharing !!!!
hi ! what if a want more button pads.. &quot;encoders&quot; and more rgb leds?? <br> <br>regards
You can buy the button pad from sparkfun. Just search it on the website
About how much did this project cost you?
That is very cool I wish I could make one (I don't know much about PCB and electrical but you have inspired me to make one a little different and much easier.

About This Instructable




Bio: I am a technologist from Toronto Ontario, who likes to fuse music, engineering, and technology into various projects.
More by mrcrud5:Homemade MPC style MIDI controller 
Add instructable to: