Close

Testing the ILI9341 TFT LCD with Teensy

A project log for Turnado Hardware MIDI Controller

The development of a dedicated hardware MIDI controller for the Turnado audio FX software plugin.

Liam LaceyLiam Lacey 09/10/2018 at 08:410 Comments

I'm still waiting for the last few components to arrive before I can build the controller, however one thing I wanted to do first is test my chosen LCD with the Teensy microcontroller. I've never used a TFT LCD with Arduino or Teensy before, so I first wanted to make sure that I could get the desired functionality and performance out of the LCD.

The LCD I am using is a 2.4" 320x240 TFT LCD with a ILI9341 controller chip which appears to be based off of an Adafruit design, which can be used with a Teensy-optimised Adafruit_ILI9341 library for better performance.

Connections

To connect the LCD to the Teensy 3.6 board I followed the connections guide on the Teensy website:

ILI9341 PinTeensy 3.x / LC PinNotes
VCCVINPower: 3.6 to 5.5 volts
GNDGND
CS10Alternate Pins: 9, 15, 20, 21
RESET+3.3V
D/C9Alternate Pins: 10, 15, 20, 21
SDI (MOSI)11 (DOUT)
SCK13 (SCK)
LEDVINUse 100 ohm resistor
SDO (MISO)12 (DIN)

Arduino Library

I decided to use the Teensy-optimised Adafruit_ILI9341 library over the standard Adafruit_ILI9341 library due to the demonstrated increased frame rate and performance of the former. I downloaded the library from the Github page and followed the provided instructions to install it into the Arduino software.

Using the library

After a quick online search I couldn't find any decent tutorials on using the LCD's Arduino library to draw shapes (which is mostly what I want the LCD to do), however after dissecting the example sketches that come with the library it became quite clear how to do it. The best source to find out what functionality is provided is the library's main header file, which shows all the functions that library provides such as drawRect, fillRect, fillCircle, and many more.

Test/Example Code

To test the LCD and Arduino library I decided to attempt to create a simple Teensy sketch that draws eight sliders on the LCD that each change their value from a MIDI CC message received over USB-MIDI - something that the final controller software will need to do. 

Below is the code I created to do this. See the comments in the code to see how it works. The exact MIDI CC numbers I am using in this test code match the default CCs that the KORG nanoKONTROL MIDI controller sends from it's sliders (see the below example video). If you would like to upload this to a Teensy yourself, you'll need to set the 'USB Type' to 'MIDI' in the tools menu.

#include "ILI9341_t3.h"

// TFT pins
const uint8_t TFT_DC = 9;
const uint8_t TFT_CS = 10;

// Use hardware SPI (#13, #12, #11) and the above for CS/DC
ILI9341_t3 tft = ILI9341_t3 (TFT_CS, TFT_DC);

const int LCD_FRAME_RATE = 30;
long previousMillis = 0;

const int BCKGND_COLOUR = ILI9341_BLACK;
const int SLIDER_COLOUR = ILI9341_RED;
const int SLIDER_BCKGND_COLOUR = ILI9341_DARKGREY;

const int SLIDER_WIDTH = 20;
const int SLIDER_MAX_SIZE = 127;
const int SLIDER_SPACING = 40;

const uint8_t NUM_OF_SLIDERS = 8;
const uint8_t SLIDER_CC_NUMS[NUM_OF_SLIDERS] =  {2, 3, 4, 5, 6, 8, 9, 12};

int sliderValue[NUM_OF_SLIDERS] = {0};
int prevSliderValue[NUM_OF_SLIDERS] = {0};

uint8_t midiCcValue[NUM_OF_SLIDERS] = {0};
uint8_t prevMidiCcValue[NUM_OF_SLIDERS] = {0};

void setup()
{
  tft.begin();
  tft.setRotation (3);
  tft.fillScreen (BCKGND_COLOUR);

  //draw a vertical rectangle 'slider' at the bottom of the screen
  for (uint8_t i = 0; i < NUM_OF_SLIDERS; i++)
    tft.fillRect (i * SLIDER_SPACING, tft.height() - SLIDER_MAX_SIZE, SLIDER_WIDTH, SLIDER_MAX_SIZE, SLIDER_BCKGND_COLOUR);

  usbMIDI.setHandleControlChange(ProcessMidiControlChange);

}

void loop()
{
  //Read from USB MIDI-in
  usbMIDI.read();

  //update the LCD display at the set frame rate
  if ((millis() - previousMillis) > (1000.0 / (float)LCD_FRAME_RATE))
  {
    updateDisplay();
    previousMillis = millis();
  }
}

void ProcessMidiControlChange (byte channel, byte control, byte value)
{
  for (uint8_t i = 0; i < NUM_OF_SLIDERS; i++)
  {
    if (control == SLIDER_CC_NUMS[i])
    {
      midiCcValue[i] = value;

      if (midiCcValue[i] != prevMidiCcValue[i])
      {
        //set the new value for the slider
        sliderValue[i] = midiCcValue[i];

        prevMidiCcValue[i] = midiCcValue[i];

      } //if (midiCcValue[i] != prevMidiCcValue[i])

    } //if (control == SLIDER_CC_NUMS[i])

  } //for (uint8_t i = 0; i < NUM_OF_SLIDERS; i++)

}

void updateDisplay()
{
  for (uint8_t i = 0; i < NUM_OF_SLIDERS; i++)
  {
    //if the slider value needs updating
    if (sliderValue[i] != prevSliderValue[i])
    {
      if (sliderValue[i] > prevSliderValue[i])
      {
        //increase the size of the slider by drawing the value difference on the top
        tft.fillRect (i * SLIDER_SPACING, tft.height() - sliderValue[i], SLIDER_WIDTH, sliderValue[i] - prevSliderValue[i], SLIDER_COLOUR);
      }
      else
      {
        //decrease the size of the slider by 'clearing' the value difference from the top
        tft.fillRect (i * SLIDER_SPACING, tft.height() - prevSliderValue[i], SLIDER_WIDTH, prevSliderValue[i] - sliderValue[i], SLIDER_BCKGND_COLOUR);
      }

      prevSliderValue[i] = sliderValue[i];

    } //if (sliderValue[i] != prevSliderValue[i])

  } //for (uint8_t i = 0; i < NUM_OF_SLIDERS; i++)

}

Example Video

Below is an example video of the above code running on a Teensy 3.6, using a KORG nanoKONTROL USB-MIDI controller as the MIDI input device, with MIDI messages being routed from the nanoKONTROL to the Teensy using my MacBook running the MIDI Patchbay software. 

Based off of the performance of this test code, I am confident that this LCD will be perfect for this project.

Discussions