Introduction: XY MIDI Pad With Arduino and TFT

Some weeks ago, when I looked after some ideas/modules/shields to start new projects/experiments with microcontrollers I found something interesting that would fit perfectly in my older project "USB MIDI Controller with Aduino".

If you are interested about it can search in my website (link on my profile). I do not want to insist on it too much. Let's say it's a project I'm working on long ago and has undergone many transformations over time. I think it will not ever finish it, but working on it I discovered/learned many interesting things, some of which will be posted (or already posted) here on Instructables.

Idea that excited me (so much) was to use this TFT touchscreen display to make a XY controller (pad) with visual feedback.

Step 1: Overview of the Shield

Resolution: 240x320.

Size: 2.8 Inch.

Colors: 262K

TFT driver: ILI9325DS (supported by UTFT library)

Touch driver: XPT2046 (suported by Utouch library *this particular model with some changes)

Interface:

  • TFT: 8bit data and 4bit control.
  • Touch Screen: 5 bit.
  • SD : 4bit.

Price: $19 at http://www.gearbest.com/development-boards/pp_520... (From here I bought it )

Step 2: TFT Hardware Setup

Installing shield is straightforward. You still need to select the correct voltage before use. It is a switch in the top right, next to SD socket. For Arduino Mega and Arduino Uno must select 5V. Also do not push shield completely.

Step 3: Libraries Setup

    1. First you need to install UTFT library. Latest version is here http://henningkarlsen.com I'm going to put the library here too (file UTFT.zip). You never know what might happen in the future.

    2. Same thing about UTouch library (file UTouch.zip).

    3. Now we need to replace UTouch.cppUTouch.h with same files from UTouchWorking.zip. You can read more about this here:http://forum.arduino.cc/index.php?topic=198188.0 .

    4. If you use Arduino MEGA need to edit file

    ...arduino-1.5.8\libraries\UTFT\hardware\avr\HW_AVR_defines.h

    and uncomment the line: (If you use Arduino Uno is not need this modification):

    #define USE_UNO_SHIELD_ON_MEGA 1
    

    5. To optimize memory usage we need to edit file

    ...\arduino-1.5.8\libraries\UTFT\memorysaver.h

    and uncomment the lines for the display controllers that you don't use: for this display uncomment all lines except this:

    //#define DISABLE_ILI9325C          1    // ITDB24

    Step 4: Touch Screen Calibration

    To work properly, the touchscreen need calibration.

    To make the calibrations for modified UTouch library we need to run this sketch: SimplerCalibration.ino (SimplerCalibration.zip):

    We need to match the orientation of UTFT library with UTouch library:

    myGLCD.InitLCD(LANDSCAPE);
    myTouch.InitTouch(LANDSCAPE);

    There are 4 steps. We need to edit line #define selector for every step and upload and run sketch step by step:

    #define selector 1

    In this step we will verify that we put the correct resolution in SimplerCalibration ino file. This is an optional step. I put it here because that was designed by the author of this solution.

    #define selector 2

    This is the most important of the four. Here is actually calibration. After uploading sketch you must obtain left-top point and right-bottom point like in photo above; and make modification in file:

    ...\arduino-1.5.8\libraries\UTouch\UTouch.cpp

    void UTouch::InitTouch(byte orientation){
        orient                	= orientation;
        _default_orientation        = 0;
        touch_x_left            	= 306;     //enter number for left most touch
        touch_x_right           	= 3966;    //enter number for right most touch
        touch_y_bottom            	= 3906;    //enter number for bottom most touch
        touch_y_top            	= 174;     //enter number for top most touch
        disp_x_size            	= 320;     // do not forget them if different
        disp_y_size            	= 240;     // do not forget them if different
        prec                	= 10;
    // ..................................................

    We see that values for touch_y_bottom and touch_y_top are swaped in relation to values obtain from screen. (because origin of TFT axes are different from origin of touch screen). You will figure out that for every model of TFT. You might need or not to swap y-axis or x-axis values depend of your TFT model. For this particular model works like above.

    #define selector 3

    Test program. Display x y coordinates of touch point. Optional.

    #define selector 4

    Test program. Put a white pixel at touch point. Optional. It is still very intuitive. If you will see those pixels are mirrored on x or y axis you need to swap values for that axix.

    Step 5: Examples

    If everything is ok with calibration we can move forward an run examples from UTFT and UTouch libraries.

    Let's not forget to edit lines that refers to the type of display and touch screen:

    UTFT myGLCD(ITDB24, A5,A4,A3,A2); 
    UTouch myTouch(A1,10,A0,8,9);

    I have attached photos taken from two examples. UTouch_ButtonTest and UTouch_QuickPaint.

    Please note that it was quite difficult (for me) to take usable photos of the TFT, because if I shoot directly (vertical) appear camera reflection. It is as if I try to photograph the surface of a mirror (with details).

    Step 6: XY MIDI Pad

    If you run last examples have noticed they run quite slowly. There is nothing wrong with TFT display and also there is nothing wrong with the code or libraries. This is because we try to use an 8-bit microcontroller at 16MHz (or 20MHz). In fact this display can run much faster than we can send data (with our processor).

    Indeed we could do some improvements to the code and libraries, but changes will not be dramatic. Ideally we need more powerful processor, 32bit (even 16 bit), DMA controller, >150 Mhz, more RAM (for video buffer) etc...

    Instead we can design our programs to update only a small area of the screen when we need speed.

    I put the whole code for Arduino project XY Pad MIDI here(attached to this step, MIDIPad.zip). Can be studied in detail to see how I applied what I said above. However I will comment on some sections.

    In function draw_Pad(long x, long y), before drawing new lines, clear old lines redrawing them with background color.

    void draw_Pad(long x, long y)<br>{
          // we draw 3 three lines for x and three lines for y
          // for better visibility
          myGLCD.setColor(pad_bk);
          myGLCD.drawLine(old_x-1,pad_topY,old_x-1,pad_bottomY); // clear old line x-1
          myGLCD.drawLine(old_x+1,pad_topY,old_x+1,pad_bottomY); // clear old line x+1
          myGLCD.drawLine(old_x,pad_topY,old_x,pad_bottomY);     // clear old line x
          myGLCD.drawLine(pad_topX,old_y-1,pad_bottomY,old_y-1); // clear old line y-1    
          myGLCD.drawLine(pad_topX,old_y+1,pad_bottomY,old_y+1); // clear old line y+1    
          myGLCD.drawLine(pad_topX,old_y,pad_bottomY,old_y);     // clear old line y
          myGLCD.setColor(reticle_color);
          myGLCD.drawLine(x-1,pad_topY,x-1,pad_bottomY);         // draw new line x-1
          myGLCD.drawLine(x+1,pad_topY,x+1,pad_bottomY);         // draw new line x+1
          myGLCD.drawLine(x,pad_topY,x,pad_bottomY);             // draw new line x
          myGLCD.drawLine(pad_topX,y-1,pad_bottomX,y-1);         // draw new line1 y-1
          myGLCD.drawLine(pad_topX,y+1,pad_bottomX,y+1);         // draw new line2 y+1
          myGLCD.drawLine(pad_topX,y,pad_bottomX,y);             // draw new line3 y
    }

    I have not used the well known Arduino MIDI library (like my previous project). Instead I use a simple function to send MIDI CC commands:

    void SendMIDIControl(byte channel, byte controller, byte value) {
    byte tmpChannel = (channel & 0b00001111)-1; //0= channel1...1=channel2... etc
      tmpChannel = 0b10110000 + tmpChannel;     //midi data first bit allways 1, 
    					    //+ 011 control change command 
    					    //+ midi channel
      byte tmpController = controller & 0b01111111;    //midi data first bit allways 0
      byte tmpValue = value & 0b01111111;              //midi data first bit allways 0
      Serial1.write(tmpChannel);
      Serial1.write(tmpController);
      Serial1.write(tmpValue);
    }

    For sending MIDI commands to PC via USB I used a module that I made previously. For details see my project here: https://www.instructables.com/id/Arduino-USB-MIDI-...

    Important!:

    We can not use the first serial port pins because its pins are already used by TFT shield.

    • For Arduino UNO we must use SoftwareSerial.
    • For Arduino MEGA we can use SoftwareSerial or Serial1 / Serial2 (I tested with SoftwareSerial and Serial1)

    My Arduino USB Midi Interface module can be replaced(theoretical) with a combination of MIDI Shield and USB To MIDI converter. I have not tested this way (I do not have neither).

    Step 7: Final

    After I played for a while with this project I saw that there is room for improvement (as always).

    We can give up the right buttons to manage settings with some physical push buttons. This will increase the usability of the pad. This project was designed in this form to be a starting point (and proof of concept) for your MIDI projects.

    In this case we need to make map coordinats separately for X an Y

    byte CoordToMIDI(unsigned int coord){
      float temp;
      temp=coord;
      temp=temp/1.72;
      return (byte)temp;  
    }

    will change in

    byte CoordXToMIDI(unsigned int coord){
      float temp;
      temp=coord;
      temp=temp/another_value1; // depend of your virtual pad x size
      return (byte)temp;  
    }
    byte CoordYToMIDI(unsigned int coord){
      float temp;
      temp=coord;
      temp=temp/another_value2; // depend of your virtual pad y size
      return (byte)temp;  
    }

    We can also try using Arduino Due. Because this board use 3V, my interface need level converter and TFT switch moved on 3V position.

    Thanks for your attention!