Code-Cap

Arduino and SPI TFT (ILI9341)

2015. november 27. - Doubledeceker


img_20151127_154548_1.jpg
Making TFT thermometer



Just for fun I bought some arduino boards ( uno, nano, mini-pro in 8 and 16 MHz variations ) and some TFT displays ( in different sizes with different physical interface and different driver chips ) on ebay some month ago.

So far I soldered some funny things and little more serious things, like sensors with radio connecting to arduinos to openhab running on RPI, and sensors and radios to transmit data from car to another car, movement sensor with specific filtering algorithm, and IR receiver for make possible to enter PIN number for specific car alarm system, hardware of which praises my colleagues work. ( on picture 2 )

ir.png

But now I only wanted to make a funny and good looking somthing. So you can see the result, and the steps for reaching it.

First of all, earlier I got some experience with adafruit libraries and arduino uno and displays with intel 8080 interface. That interface could be fast, but it needs you to use 8 + 5 pins for control the display that is too much. You hardly remain any pins to do anything apart from drawing on screen.

 

Display driver library hack

So, I have to try the SPI interface display. My SPI interfaced display equipped with ILI9341 driver which driver chip is cool and it has adafruit library. You can easily download from here: tft.jpg
https://github.com/adafruit/Adafruit_ILI9341

So okay, I soldering for some hours ( this part wasn't the coolest part of this job. ) This type of driver chip don't like 5V on its pins, so I had to solder level shifters. You can find some good example how to do this on the  Net but some of them no so bright, my suggestion, you shouldn't use level shifter on MISO pin, and it isn't necessary to use on slave select pin too, and should use resistor 10-20 KOhm, less value isn't the correct way, because it waste huge amount of power (2-3 mA on every pins.... :D ).

And voálá the adafruit graphic test worked.

But, but and but.....  the performance, it made me had a little bit headache. The maximum SPI bus frequency is half of the AVR CPU frequency, on a 16 MHz board it means 8 MHz which isn't so slow, but the result wasn't fast enough.

That is why, I started to modify the adafruit ILI 9341 driver class. Yeah I have to mention the adafriut libraries sometimes could be messy, but their principle is absolutely okay. The base class is the adafruit gfx class, which include the high level function, e.g. fill rectangle, draw line, draw circle and other base drawing algorithm, and they include some pure virtual method and some virtual method overriding them you can make your hardware specific library or you can override other method to make it faster or to meet your other requirement.

The key of the performance is the draw point and the draw line methods, most of the higher level drawing methods using them. For first glance in the draw pixel method, there are a lot of method calls ( which could be costly ) and there are some not so many important "if" conditions. So make methods inline ( yeah, it eats your program memory) and get rid of unnecessary "if"-s ( yeah, the more performance means the less safety ). So the first step of optimizing program was successful, I got about 40-50% performance advance.

From that point I spent several hours to optimize the code, and the result was enough. The results comparing than the original adafruit library.

 

Original library

Modified library

Rate of acceleration

 

time (microsecond)

time (microsecond)

 

Screen fill

1329592

2126428

1,60

Lines

490184

2343420

4,78

Horiz/Vert Lines

107596

179228

1,67

Rectangles

69700

118828

1,70

Rectangles (filled)

2761156

4416460

1,60

Circles (filled)

449440

906852

2,02

Circles (outline)

374788

1023996

2,73

Triangles (outline)

126904

743428

5,86

Triangles (filled)

1008036

1830952

1,82

Rounded rects (outline)

150924

386084

2,56

Rounded rects (filled)

3009676

4896456

1,63

 

There are several "fast" driver libs on the Net. I examined some of them, but I didn't find faster library than mine, but I am sure it exists somewhere. There is still some opportunities to get faster on the code. But of course they have their own cost.

If you use original adafruit library take care, the ILI9341 "driver" class has two constructors, the library uses hardware or software SPI mode depend on which constructor used to instantiate the class. Of course the software SPI is much slower.

So Finaly I have hardware and a good driver for it. I soldered a DTH11 sensor too. And wrote some code,dht.png it was easiest part of this little project.  I drew a color arch to symbolize the temperature somehow, and a little chart bellow it.

In the chart, I can display the 24 hours data including 2 temperature and 1 humidity values in each point. The data is stored in eeprom, so the power break doesn't matter. I used a simple clever index algorithm which help to find the last stored data after power break. ( Consider that, this little circuit don't have real clock.) And of course I use circular buffer when use eeprom, so every address is written very rarely for lengthen its lifetime.

I will upload my modified library to GITHUB ASAP.

For test I fed it a simple sin. Yeah it's not a big deal, but consider it's only 8 bit RISC microcontroller runing on 16 MHz with 2 KByte RAM.