Building an LCD TFT library for Arduino DUE

This is another of my pet projects. To build an LCD library based on the HX8347A TFT display controller.
I know that there are several LCD libraries out there but I still believe that there is a spot for this one. Why?
Because this LCD board matches perfectly the 18x2F-H8.5 pin connector of the DUE. See pictures below.
I will be porting the Atmel ASF HX8347A library and example to Arduino DUE. I will use one Arduino DUE and one EM-LCD28TP board borrowed from my Atmel EB-SAM3U.

I hope to start next week and keep this thread updated with my progress. Any comment or contribution is welcome.
P

The purpose of this post is to present the building of a library that allows to connect an LCD TFT module to the Arduino Due.

There are so many LCD TFT chips out there and each one has unique configuration requirements, that it is not practical to build here a library that could be use with different LCDs but only the one presented here and compatibles.

This application uses the External Bus Interface (EBI) called Static Memory Controller (SMC) inside the SAM3X8E to handle the LCD module.

I will port the LCD library and one example of the SAM3X/SAM3U evaluation boards from the ASF Atmel to Arduino DUE.

I think it is important to mention that the only 'general purpose' SMC parallel library for Due that I have found in the forum is the one by delsauce, which I haven't try yet: (Parallel library for Due External Memory Bus/Static Memory Controller - Arduino Due - Arduino Forum).

I will use a 240RGB x 320 dot LCD integrated with the HX8347A chip controller. The same one used in the mentioned Atmel boards. The library will consist of the HX8347A files (.h, .cpp) and a configuration file (.h). The library invokes the smc library. The example will draw pictures and strings on the LCD. This porting also covers the XY touch screen capabilities of the LCD. It will be is required an ADS7843E controller.

The beautiful of the HX8347A LCD is that the 2x18 connector 'almost' fit the Due one. I say almost because if everything goes accordingly, the board will be shifted one column to the right. A couple of small power jumpers and one 100K resistor will be also needed. The building of a shield will be necessary to avoid obstruction with the DUE connectors.

That said, let’s start the porting.

PART I. Raw Porting from the Original

Hardware needed:

  • Arduino Due
  • LCD EM-LCD28TP.

I have decided to start this porting using the original pin/register definitions. The idea here is to stick as close as possible with the original application (hardware and software). Remember that the SAM3X/3U-EK board's cores are close siblings of the Due's core and the LCD is the same. This implies few changes to be made at the beginning. For example, I had to re-defined 3 pins (data and CS) used in the original code given that those pins are not connected in the Arduino Due.

Before make a stop, here a picture of the pinout inter-connection and the Arduino DUE with the LCD. So far, the initial raw LCD library works OK despite the rat's nest. I will create and upload in Github the LCD library files and example sketch very soon.

P

Nice


Rob

Thanks Rob! Indeed, your Due pinout diagram has been of great assistance to me.

Hardware (Con't)

Let's take a look at what I have called the LCD integrated system. It comprehends mainly three parts:
1. The LCD
2. The Touch Screen
3. The Back Light

1. The LCD:
The LCD module comprehends a 2.8 inches panel with a native resolution of 240RGB x 320 pixels with integrated TFT driver IC HX8347. So far it will be enough for us to know that the HX8347 interface with the panel (black box) and connects to the outer world (DUE) via its CS, RS, WR, RD, Reset, D0-D17, Vdd and GND pins as shown in my last reply. Notice that I left open (free running mode) the CS pin keeping the chip always selected.

2. The Touch Screen is a 4-wire panel controlled by an ADS7843 as a slave device on the DUE SPI bus.

3. The Back Light is made of 4 white chip LEDs in parallel, driven by an AAT3194 charge pump. The AAT3194 is controlled by the DUE through a single line Simple Serial Control (S2Cwire) interface, which permits to enable, disable, and set the LED drive current (LED brightness control) from a 32-level logarithmic scale. The AAT3194 chip is embedded in the LCD board.

In the first stage of this porting, I have focused the hardware only to draw text and shapes on the LCD. Later I will deal with the touch screen and back light.

Let's look now the DUE-LCD Interface.
The Arduino DUE communicates with the LCD through the EBI SMC embedded inside the SAM3X8E via PIOC where a 16-bit parallel "8080-like" protocol data bus has been implemented by software. Due configures the HX8347A for access the LCD controller, then initialize the LCD and finally draw some text, image and basic shapes like lines, rectangles and circles on the LCD.

Another stop here. Next reply: SOFTWARE.
P

SOFTWARE.
With the advent of the Arduino DUE, even when Atmel has written some ASF examples for it, the LCD example remained confined only for the SAM3U and SAM3X based evaluation boards. Thus, my plan was to start porting the original LCD library and examples to Arduino Due under the Atmel Studio environment, and then complete the porting to the Arduino IDE. Why? Again, to stay close to the original application and to corroborate that it worked on the Due from the Atmel side.

Before enter with the porting, I think this is an opportune moment to explain one or two things about EBI/SMC controller. SAM3X8E's core: ARM-Cortex M3 is fitted with a 6 layer AHB bus (84MHz) as a bridge between the processor M3 and the peripherals. The EBI/SMC controller is in between and can connect I/O lines from the 4 PIO controllers via AHB to the core. In other words, the SMC guarantees high speed data processing, which is what we need for our LCD applications with DUE (videos/photos). It is even faster that using the SPI protocol.

Porting from SAM3X-EK (SAM3X8H) to Due (SAM3X8E) inside Atmel Studio 6.1 (AS61).
Caveat: You don't need (even if you can) to do the following steps. I will provide for you the .bin file at the end of this reply in case you want to test in advance the application by yourself.

I am using the SAM3X-EK ASF LCD example and HX8347A library contained in AS61.
Step 1: to compile the LCD example in the SAM3X-EK using SAM-ICE and AS61. Check
Step 2: to create a blank project for Arduino Due in AS61. Check
Step 3: to copy and fill (paste) the LCD example in the main.c file of the Arduino Due project. Check
Step 4: to compile the LCD example and fix all the configuration issues (errors) like missing files (mostly classes), headers, etc.. Check
Step 5: to modify the arduino_due_x.h (equivalent to the variant.h in Arduino 1.5.X IDE) and the init.c (equivalent to the variant.cpp in Arduino 1.5.X IDE) according to Due I/O capabilities. Check
Step 6: to compile the LCD example for Arduno Due in AS61. Check
Step 7: to load the .bin file via SAM-ICE (jtag) or bossac via (usb) to Arduino Due.
Step 8: to wire the LCD with Due as shown in my reply #1. Check
Now we should have the LCD TFT module connected to Arduino Due and showing the same screen as reply#1.

What's next? All the LCD ASF AS61 project (around 214 files/116 folders, 17.6 MB) should be reduced to the following files:

-LCD_DUE_EXAMPLE1.ino
-hx8347a.h
-hx8347a.c
-smc.h
-smc.c
-variant.c and variant.h modified (with EBI LCD pin definitions)

...and make it run in the Arduino IDE 1.5.X. Here is where I am now. Now it is time to stop but before, here attached the workable .bin file.

p

LCD_DUE_EXAMPLE1.bin (22.2 KB)

I have good news! I finished the 'raw porting' of the LCD TFT library/example from Atmel ASF for SAM3X-EK to the IDE 1.5.6 for Arduino Due. The sketch is running flawlessly.

The library is small. Only 3 files:
-hx8347a.c
-hx8347a.h
-conf_hx8347a.h

I also needed to add some EBI SMC pin definitions to the variant files.

By 'raw porting' I mean to say that the sketch looks almost identical to the example in AS61.
My next step is to create the class for the Arduino IDE with few LCD functions and modify the sketch (Arduino style).

p

I finished the class HX8347A with 24 functions for the Arduino IDE 1.5.X. I started to play a bit with it and made a clock sketch based on Markus_L811's RTC library (Thank you Markus!). Here the sketch and a picture to give an idea about how it looks (still raw but much better).

// Arduino Due - LCD HX8347A clock sample 1
// Brief LCD controller HX8347A TFT example for Arduino Due
// ported from Atmel ASF SAM3X-EK Display COntroller Example. 
// Draw current date and time on the HX8347A LCD controller. 
// By Wilfredo Molina 2014 (RTC code by Markus_L811)

// Required libraries
#include "hx8347a.h"
#include "smc.h"
#include <rtc_clock.h>

#define CONF_BOARD_HX8347A_LCD_CS      2
struct opt_t display_opt;

HX8347A HX8347A;

RTC_clock rtc_clock(XTAL);
int hour, minute, second, day, month, year;
char hour1[12];
char minute1[12];
char second1[12];
char day1[12];
char month1[12];
char year1[12];
char* daynames[]={"Monday", "Tueday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};

/* Convert 24-bits color to 16-bits color */
static color_t rgb24_to_rgb16(uint32_t ul_color)
{
	color_t result_color;
	result_color = (((ul_color >> 8) & 0xF800) |
			((ul_color >> 5) & 0x7E0) | ((ul_color >> 3) & 0x1F));
	return result_color;
}

void setup() {
 Serial.begin(115200);
 rtc_clock.init();
 rtc_clock.set_time(10, 28, 30);
 rtc_clock.set_date(14, 4, 2014);
} 
 
void loop()
{
        month = rtc_clock.get_months();
        day = rtc_clock.get_days();
        year = rtc_clock.get_years();
        hour = rtc_clock.get_hours();
        minute = rtc_clock.get_minutes();
        second = rtc_clock.get_seconds();
        
        /* Enable peripheral clock */
        pmc_enable_periph_clk(ID_SMC);
        
        /* Configure SMC interface for Lcd */
        smc_set_setup_timing(SMC, CONF_BOARD_HX8347A_LCD_CS, SMC_SETUP_NWE_SETUP(1)
			| SMC_SETUP_NCS_WR_SETUP(1)
			| SMC_SETUP_NRD_SETUP(9)
			| SMC_SETUP_NCS_RD_SETUP(9));
	smc_set_pulse_timing(SMC, CONF_BOARD_HX8347A_LCD_CS, SMC_PULSE_NWE_PULSE(4)
			| SMC_PULSE_NCS_WR_PULSE(4)
			| SMC_PULSE_NRD_PULSE(36)
			| SMC_PULSE_NCS_RD_PULSE(36));
	smc_set_cycle_timing(SMC, CONF_BOARD_HX8347A_LCD_CS, SMC_CYCLE_NWE_CYCLE(10)
			| SMC_CYCLE_NRD_CYCLE(45));
	smc_set_mode(SMC, CONF_BOARD_HX8347A_LCD_CS, SMC_MODE_READ_MODE
			| SMC_MODE_WRITE_MODE | SMC_MODE_DBW_BIT_16);

        /* Initialize display parameter */
	display_opt.ul_width = HX8347A_LCD_WIDTH;
	display_opt.ul_height = HX8347A_LCD_HEIGHT;
	display_opt.foreground_color = rgb24_to_rgb16(COLOR_BLACK);
	display_opt.background_color = rgb24_to_rgb16(COLOR_WHITE);
        
        /* Switch off backlight */
        aat31xx_disable_backlight();
        
        /* Initialize LCD */
        if(HX8347A.init(&display_opt)){
		puts("Read HX8347A chip ID error, please check the configuration.\r");
	}

        /* Set backlight level */
        aat31xx_set_backlight(AAT31XX_AVG_BACKLIGHT_LEVEL);
        
        HX8347A.set_foreground_color(rgb24_to_rgb16(COLOR_WHITE));
	HX8347A.draw_filled_rectangle(0, 0, HX8347A_LCD_WIDTH - 1, HX8347A_LCD_HEIGHT - 1);
	
        /* Turn on LCD */
        HX8347A.display_on();
        
        /* Draw real Date and Time on the LCD */
	HX8347A.set_foreground_color(rgb24_to_rgb16(COLOR_BLACK));
	HX8347A.draw_string(20, 20, (uint8_t *)"Arduino DUE clock");
        HX8347A.draw_string(10, 100, (uint8_t *)daynames[rtc_clock.get_day_of_week()-1]);
        HX8347A.draw_string(105, 100, (uint8_t *)ltoa(month, month1, 10));
        HX8347A.draw_string(110, 100, (uint8_t *)" / ");
        HX8347A.draw_string(135, 100, (uint8_t *)ltoa(day, day1, 10));
        HX8347A.draw_string(150, 100, (uint8_t *)" / ");
        HX8347A.draw_string(174, 100, (uint8_t *)ltoa(year, year1, 10));
        HX8347A.draw_string(110, 120, (uint8_t *)ltoa(hour, hour1, 10));
        HX8347A.draw_string(125, 120, (uint8_t *)" : ");
        HX8347A.draw_string(150, 120, (uint8_t *)ltoa(minute, minute1, 10));
        HX8347A.draw_string(163, 120, (uint8_t *)" : ");
        HX8347A.draw_string(188, 120, (uint8_t *)ltoa(second, second1, 10));        
}

I will be revising a bit more the HX8347A library before being published in github.

For those interested to connect/test Arduino Due with the LCD and this 'in progress' library/examples.
Bad news: The LCD that I am using is only sold as a part of the Atmel eval boards (SAM3X-EK/SAM3U-EK).
Good news: There is a couple of vendors of an LCD made by mikroElectronika. This board should work with the library.
I ordered one and I hope to receive it today to test it, but again, I believe that any LCD with HX8347A display driver with parallel (16-bit) operating mode should work.

p

Another test of the LCD HX8347A library with DUE. This time using stimmer's VGA approach (Thank you stimmer!). Even though the LCD can handle 24-bit RGB(888), I decided to keep stimmer 8-bit colour (RRRGGGBB).
http://forum.arduino.cc/index.php?topic=130742.0
Refreshing time: 50 secs.

The sketch and a picture.

// Arduino Due - LCD HX8347A VGA sample 1
// Brief LCD controller HX8347A TFT example for Arduino Due
// ported from Atmel ASF SAM3X-EK Display Controller Example. 
// Draw a fractal pattern on the HX8347A LCD controller. 
// By Wilfredo Molina 2014 (fractal code by stimmer)

#include "hx8347a.h"
#include "smc.h"
#define CONF_BOARD_HX8347A_LCD_CS      2
struct opt_t display_opt;

HX8347A HX8347A;

void setup() {
 Serial.begin(115200);
} 

#include <complex>
using namespace std;
const byte cmap[]={0b00000000,0b11100000,0b11100100,0b11101000,0b11101100,0b11110000,0b11110100,0b11111000,0b11111100,
                   0b11011100,0b10111100,0b10011100,0b01111100,0b01011100,0b00111100,0b00011100,0b00011101,0b00011110,
                   0b00011111,0b00011011,0b00010111,0b00010011,0b00001111,0b00001011,0b00000111,0b00000011,0b00100011,
                   0b01000011,0b01100011,0b10000011,0b10100011,0b11000011,0b11100011,0b11100010,0b11100001,0b11100000,0b00000000}; 
void loop()
{
        pmc_enable_periph_clk(ID_SMC);
        smc_set_setup_timing(SMC, CONF_BOARD_HX8347A_LCD_CS, SMC_SETUP_NWE_SETUP(1)
			| SMC_SETUP_NCS_WR_SETUP(1)
			| SMC_SETUP_NRD_SETUP(9)
			| SMC_SETUP_NCS_RD_SETUP(9));
	smc_set_pulse_timing(SMC, CONF_BOARD_HX8347A_LCD_CS, SMC_PULSE_NWE_PULSE(4)
			| SMC_PULSE_NCS_WR_PULSE(4)
			| SMC_PULSE_NRD_PULSE(36)
			| SMC_PULSE_NCS_RD_PULSE(36));
	smc_set_cycle_timing(SMC, CONF_BOARD_HX8347A_LCD_CS, SMC_CYCLE_NWE_CYCLE(10)
			| SMC_CYCLE_NRD_CYCLE(45));
	smc_set_mode(SMC, CONF_BOARD_HX8347A_LCD_CS, SMC_MODE_READ_MODE
			| SMC_MODE_WRITE_MODE | SMC_MODE_DBW_BIT_16);
	display_opt.ul_width = HX8347A_LCD_WIDTH;
	display_opt.ul_height = HX8347A_LCD_HEIGHT;
	display_opt.foreground_color = COLOR_BLACK;
	display_opt.background_color = COLOR_WHITE;
        if(HX8347A.init(&display_opt)){
		puts("Read HX8347A chip ID error, please check the configuration.\r");
	}
	HX8347A.set_foreground_color(COLOR_WHITE);
	HX8347A.draw_filled_rectangle(0, 0, HX8347A_LCD_WIDTH - 1, HX8347A_LCD_HEIGHT - 1);
	HX8347A.display_on();
	HX8347A.set_foreground_color(COLOR_BLACK);
        for(int i=0;i<320;i++){
        for(int j=0;j<240;j++){     
          complex<float> z(0,0),c((i+180.0)/1280.0,(j+640.0)/1280.0);
          int n;
          for(n=1;n<sizeof(cmap);n++){
           z=z*z+c;
          if(norm(z)>4.0)break;
          }
        HX8347A.set_foreground_color(cmap[sizeof(cmap)-n]);
        HX8347A.draw_pixel(j, i);
        }
    }
}

p

As I mentioned in my last post, the LCD TFT HX8347A library for Due is almost done but before publish it on github, I decided to create a drawing bitmap function (nonexistent in the Atmel ASF example). So far it is running OK. I used part of the Adafruit/Arduino TFT LCD code that converts RGB888 to RGB565. It was necessary to resolve a couple of issues including the redefinition of two EBI data bus pins D8(PC9) and D9(PC10) correspondent to the Due pins 117 and 93 that never where broken out. Another pending task of this first phase is to redefine the rest of the necessary pins between DUE and the LCD to make possible them to interconnect via the 2x18 connector. I still believe that this library is worthy given that the data is transferred via the AHB bus which is almost twice faster than SPI that use the DMA at around 40MHz, and also the matching of the LCD with DUE without any shield in between.

The second phase will be the touch screen feature but I must finish first with the HX8347A.
I already received a commercially available LCD (mikroElectronika) with same controller. I hope to test it next week.

Here a picture of the famous tiger bitmap from Adafruit (Image by Shane Gorski).

p

Have you got a frame rate (or update time) for drawing a full bitmap?


Rob

millis() - startTime between 252 and 3352 msec

but 'to the eyeball per cent' it fluctuates between 1 and 2.5 sec. Regards!

p

Regarding the frame rate, I want to clarify that I am pulling the bitmap data from an SD card via SPI given the size of the bitmap file, thus, we must not expect high-speed data transfer rates with 16-bit pictures even using the SAM3X8E HSMCI interface via PMC that operates at the masterclock/2 = 42MHz. So far, I haven't focused on the optimization of the bitmap refreshing time but functionality (Indeed, I have added few brief delays and fill functions in the code). I believe, the speed could be reduced a little bit. Of course, if the interest involves the use of shapes and text (static or dynamic), the speed data transfer will be very high (pure RAM).

p

I've been busy at work this week but here a summary of my progress with the LCD library/example:

-The drawBitmap function is completed. Refreshing time for 16-bit 320x240 bitmap: 1.4 sec. with the SD library from Arduino/Sparkfun. https://github.com/arduino/Arduino/tree/master/libraries/SD
I think the refreshing time could be reduced using the sdFat from fat16lib.
Google Code Archive - Long-term storage for Google Code Project Hosting.

-Built and tested library for aat31xx LCD backlight controller (.h,.c) that uses one-line Simple Serial Control (S2Cwire) to interface the controller with Due. aat3194 disables/enables backlight (32 brightness levels-logarithmic scale of 4 white chip LEDs in parallel embedded in the LCD board). The control line can be any digital pin (I am using pin D2). For details see replay#3 of this thread.

-Regarding the connection between the Due and the LCD via the 2x18 connector, it is not possible to use other PIO pins on the SMC bus. The only progress I made was to mirror the two missing data pins through a mask, thus, the only option left to me is to build a small pin adapter.

Next step: Touch Screen Interface. I just ordered from China one SPI ADS7843 module
http://www.ebay.com/itm/ADS7843-Touch-Screen-Panel-Controller-Module-for-4-Wire-touch-screen-panel-/161025401461?ssPageName=ADME:L:OC:US:3160
I hope it to receive it next week. For details see replay#3 of this thread.

Everything points to a first 'installment' of the LCD library published on github by next week.

p

After 5 weeks, I expect to receive tomorrow the ADS7843 ts controllers from China. Then, I'll start testing the touch screen library.

P

For those interested in my final touch screen schematic.

For this interface I used the following part.

Regards,

p