blob: fb529482c65294b01a1bf1eb649ad03b717cec6d [file] [log] [blame]
/**
* \file
*
* \brief API driver for ILI93XX TFT display component.
*
* Copyright (c) 2013 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/**
* \defgroup ili93xx_display_group Display - ILI93XX Controller
*
* Low-level driver for the ILI93XX LCD controller. This driver provides access
* to the main features of the ILI93XX controller.
* Now ILI9325 and ILI9341 are supported.
*
* \{
*/
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include "ili93xx.h"
#include "ili9341_regs.h"
#include "ili9325_regs.h"
/** Device type*/
static uint8_t g_uc_device_type = 0;
/** Pixel cache used to speed up communication */
#define LCD_DATA_CACHE_SIZE ILI93XX_LCD_WIDTH
/** LCD X-axis and Y-axis length */
static uint32_t g_ul_lcd_x_length = ILI93XX_LCD_WIDTH;
static uint32_t g_ul_lcd_y_length = ILI93XX_LCD_HEIGHT;
static ili93xx_color_t g_ul_pixel_cache[LCD_DATA_CACHE_SIZE];
static volatile ili93xx_coord_t limit_start_x, limit_start_y;
static volatile ili93xx_coord_t limit_end_x, limit_end_y;
/** Global variable describing the font size used by the driver */
const struct ili93xx_font gfont = {10, 14};
/**
* Character set table for font 10x14
* Coding format:
* Char height is 14 bits, which is coded using 2 bytes per column
* (2 unused bits).
* Char width is 10 bits.
*/
const uint8_t p_uc_charset10x14[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xCC,
0xFF, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x00, 0x00,
0x00, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0C, 0xC0, 0x0C, 0xC0, 0xFF, 0xFC, 0xFF, 0xFC, 0x0C, 0xC0,
0x0C, 0xC0, 0xFF, 0xFC, 0xFF, 0xFC, 0x0C, 0xC0, 0x0C, 0xC0,
0x0C, 0x60, 0x1E, 0x70, 0x3F, 0x30, 0x33, 0x30, 0xFF, 0xFC,
0xFF, 0xFC, 0x33, 0x30, 0x33, 0xF0, 0x39, 0xE0, 0x18, 0xC0,
0x60, 0x00, 0xF0, 0x0C, 0xF0, 0x3C, 0x60, 0xF0, 0x03, 0xC0,
0x0F, 0x00, 0x3C, 0x18, 0xF0, 0x3C, 0xC0, 0x3C, 0x00, 0x18,
0x3C, 0xF0, 0x7F, 0xF8, 0xC3, 0x1C, 0xC7, 0x8C, 0xCF, 0xCC,
0xDC, 0xEC, 0x78, 0x78, 0x30, 0x30, 0x00, 0xFC, 0x00, 0xCC,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0xEC, 0x00,
0xF8, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0F, 0xC0, 0x3F, 0xF0, 0x78, 0x78,
0x60, 0x18, 0xC0, 0x0C, 0xC0, 0x0C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xC0, 0x0C, 0xC0, 0x0C, 0x60, 0x18,
0x78, 0x78, 0x3F, 0xF0, 0x0F, 0xC0, 0x00, 0x00, 0x00, 0x00,
0x0C, 0x60, 0x0E, 0xE0, 0x07, 0xC0, 0x03, 0x80, 0x3F, 0xF8,
0x3F, 0xF8, 0x03, 0x80, 0x07, 0xC0, 0x0E, 0xE0, 0x0C, 0x60,
0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x3F, 0xF0,
0x3F, 0xF0, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00,
0x00, 0x44, 0x00, 0xEC, 0x00, 0xF8, 0x00, 0x70, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00,
0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00,
0x00, 0x18, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x18, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0C, 0x00, 0x3C, 0x00, 0xF0, 0x03, 0xC0,
0x0F, 0x00, 0x3C, 0x00, 0xF0, 0x00, 0xC0, 0x00, 0x00, 0x00,
0x3F, 0xF0, 0x7F, 0xF8, 0xE0, 0xFC, 0xC1, 0xCC, 0xC3, 0x8C,
0xC7, 0x0C, 0xCE, 0x0C, 0xFC, 0x1C, 0x7F, 0xF8, 0x3F, 0xF0,
0x00, 0x00, 0x00, 0x00, 0x30, 0x0C, 0x70, 0x0C, 0xFF, 0xFC,
0xFF, 0xFC, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00,
0x30, 0x0C, 0x70, 0x1C, 0xE0, 0x3C, 0xC0, 0x7C, 0xC0, 0xEC,
0xC1, 0xCC, 0xC3, 0x8C, 0xE7, 0x0C, 0x7E, 0x0C, 0x3C, 0x0C,
0x30, 0x30, 0x70, 0x38, 0xE0, 0x1C, 0xC0, 0x0C, 0xC0, 0x0C,
0xC3, 0x0C, 0xC3, 0x0C, 0xE3, 0x1C, 0x7F, 0xF8, 0x3C, 0xF0,
0x03, 0xC0, 0x07, 0xC0, 0x0E, 0xC0, 0x1C, 0xC0, 0x38, 0xC0,
0x70, 0xC0, 0xFF, 0xFC, 0xFF, 0xFC, 0x00, 0xC0, 0x00, 0xC0,
0xFC, 0x30, 0xFC, 0x38, 0xCC, 0x1C, 0xCC, 0x0C, 0xCC, 0x0C,
0xCC, 0x0C, 0xCC, 0x0C, 0xCE, 0x1C, 0xC7, 0xF8, 0xC3, 0xF0,
0x3F, 0xF0, 0x7F, 0xF8, 0xE3, 0x1C, 0xC3, 0x0C, 0xC3, 0x0C,
0xC3, 0x0C, 0xC3, 0x0C, 0xE3, 0x9C, 0x71, 0xF8, 0x30, 0xF0,
0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC3, 0xFC,
0xC7, 0xFC, 0xCE, 0x00, 0xDC, 0x00, 0xF8, 0x00, 0xF0, 0x00,
0x3C, 0xF0, 0x7F, 0xF8, 0xE7, 0x9C, 0xC3, 0x0C, 0xC3, 0x0C,
0xC3, 0x0C, 0xC3, 0x0C, 0xE7, 0x9C, 0x7F, 0xF8, 0x3C, 0xF0,
0x3C, 0x00, 0x7E, 0x00, 0xE7, 0x0C, 0xC3, 0x0C, 0xC3, 0x1C,
0xC3, 0x38, 0xC3, 0x70, 0xE7, 0xE0, 0x7F, 0xC0, 0x3F, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x60, 0x3C, 0xF0,
0x3C, 0xF0, 0x18, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x44, 0x3C, 0xEC,
0x3C, 0xF8, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x03, 0x00, 0x07, 0x80, 0x0F, 0xC0, 0x1C, 0xE0,
0x38, 0x70, 0x70, 0x38, 0xE0, 0x1C, 0xC0, 0x0C, 0x00, 0x00,
0x0C, 0xC0, 0x0C, 0xC0, 0x0C, 0xC0, 0x0C, 0xC0, 0x0C, 0xC0,
0x0C, 0xC0, 0x0C, 0xC0, 0x0C, 0xC0, 0x0C, 0xC0, 0x0C, 0xC0,
0x00, 0x00, 0xC0, 0x0C, 0xE0, 0x1C, 0x70, 0x38, 0x38, 0x70,
0x1C, 0xE0, 0x0F, 0xC0, 0x07, 0x80, 0x03, 0x00, 0x00, 0x00,
0x30, 0x00, 0x70, 0x00, 0xE0, 0x00, 0xC0, 0x00, 0xC1, 0xEC,
0xC3, 0xEC, 0xC3, 0x00, 0xE6, 0x00, 0x7E, 0x00, 0x3C, 0x00,
0x30, 0xF0, 0x71, 0xF8, 0xE3, 0x9C, 0xC3, 0x0C, 0xC3, 0xFC,
0xC3, 0xFC, 0xC0, 0x0C, 0xE0, 0x1C, 0x7F, 0xF8, 0x3F, 0xF0,
0x3F, 0xFC, 0x7F, 0xFC, 0xE0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0,
0xC0, 0xC0, 0xC0, 0xC0, 0xE0, 0xC0, 0x7F, 0xFC, 0x3F, 0xFC,
0xFF, 0xFC, 0xFF, 0xFC, 0xC3, 0x0C, 0xC3, 0x0C, 0xC3, 0x0C,
0xC3, 0x0C, 0xC3, 0x0C, 0xE7, 0x9C, 0x7F, 0xF8, 0x3C, 0xF0,
0x3F, 0xF0, 0x7F, 0xF8, 0xE0, 0x1C, 0xC0, 0x0C, 0xC0, 0x0C,
0xC0, 0x0C, 0xC0, 0x0C, 0xE0, 0x1C, 0x70, 0x38, 0x30, 0x30,
0xFF, 0xFC, 0xFF, 0xFC, 0xC0, 0x0C, 0xC0, 0x0C, 0xC0, 0x0C,
0xC0, 0x0C, 0xC0, 0x0C, 0xE0, 0x1C, 0x7F, 0xF8, 0x3F, 0xF0,
0xFF, 0xFC, 0xFF, 0xFC, 0xC3, 0x0C, 0xC3, 0x0C, 0xC3, 0x0C,
0xC3, 0x0C, 0xC3, 0x0C, 0xC3, 0x0C, 0xC0, 0x0C, 0xC0, 0x0C,
0xFF, 0xFC, 0xFF, 0xFC, 0xC3, 0x00, 0xC3, 0x00, 0xC3, 0x00,
0xC3, 0x00, 0xC3, 0x00, 0xC3, 0x00, 0xC0, 0x00, 0xC0, 0x00,
0x3F, 0xF0, 0x7F, 0xF8, 0xE0, 0x1C, 0xC0, 0x0C, 0xC0, 0x0C,
0xC3, 0x0C, 0xC3, 0x0C, 0xE3, 0x1C, 0x73, 0xF8, 0x33, 0xF0,
0xFF, 0xFC, 0xFF, 0xFC, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00,
0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0xFF, 0xFC, 0xFF, 0xFC,
0x00, 0x00, 0x00, 0x00, 0xC0, 0x0C, 0xC0, 0x0C, 0xFF, 0xFC,
0xFF, 0xFC, 0xC0, 0x0C, 0xC0, 0x0C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x30, 0x00, 0x38, 0xC0, 0x1C, 0xC0, 0x0C, 0xC0, 0x0C,
0xC0, 0x1C, 0xFF, 0xF8, 0xFF, 0xF0, 0xC0, 0x00, 0xC0, 0x00,
0xFF, 0xFC, 0xFF, 0xFC, 0x07, 0x80, 0x07, 0x80, 0x0F, 0xC0,
0x1C, 0xE0, 0x38, 0x70, 0x70, 0x38, 0xE0, 0x1C, 0xC0, 0x0C,
0xFF, 0xFC, 0xFF, 0xFC, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C,
0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C,
0xFF, 0xFC, 0xFF, 0xFC, 0x70, 0x00, 0x38, 0x00, 0x1F, 0x00,
0x1F, 0x00, 0x38, 0x00, 0x70, 0x00, 0xFF, 0xFC, 0xFF, 0xFC,
0xFF, 0xFC, 0xFF, 0xFC, 0x1C, 0x00, 0x0E, 0x00, 0x07, 0x00,
0x03, 0x80, 0x01, 0xC0, 0x00, 0xE0, 0xFF, 0xFC, 0xFF, 0xFC,
0x3F, 0xF0, 0x7F, 0xF8, 0xE0, 0x1C, 0xC0, 0x0C, 0xC0, 0x0C,
0xC0, 0x0C, 0xC0, 0x0C, 0xE0, 0x1C, 0x7F, 0xF8, 0x3F, 0xF0,
0xFF, 0xFC, 0xFF, 0xFC, 0xC3, 0x00, 0xC3, 0x00, 0xC3, 0x00,
0xC3, 0x00, 0xC3, 0x00, 0xE7, 0x00, 0x7E, 0x00, 0x3C, 0x00,
0x3F, 0xF0, 0x7F, 0xF8, 0xE0, 0x1C, 0xC0, 0x0C, 0xC0, 0xCC,
0xC0, 0xEC, 0xC0, 0x7C, 0xE0, 0x38, 0x7F, 0xFC, 0x3F, 0xEC,
0xFF, 0xFC, 0xFF, 0xFC, 0xC3, 0x00, 0xC3, 0x80, 0xC3, 0x80,
0xC3, 0xC0, 0xC3, 0xC0, 0xE7, 0x70, 0x7E, 0x3C, 0x3C, 0x1C,
0x3C, 0x18, 0x7E, 0x1C, 0xE7, 0x0C, 0xC3, 0x0C, 0xC3, 0x0C,
0xC3, 0x0C, 0xC3, 0x0C, 0xC3, 0x9C, 0xE1, 0xF8, 0x60, 0xF0,
0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xFF, 0xFC,
0xFF, 0xFC, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00,
0xFF, 0xF0, 0xFF, 0xF8, 0x00, 0x1C, 0x00, 0x0C, 0x00, 0x0C,
0x00, 0x0C, 0x00, 0x0C, 0x00, 0x1C, 0xFF, 0xF8, 0xFF, 0xF0,
0xFF, 0xC0, 0xFF, 0xE0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1C,
0x00, 0x1C, 0x00, 0x38, 0x00, 0x70, 0xFF, 0xE0, 0xFF, 0xC0,
0xFF, 0xF0, 0xFF, 0xF8, 0x00, 0x1C, 0x00, 0x3C, 0x00, 0xF8,
0x00, 0xF8, 0x00, 0x3C, 0x00, 0x1C, 0xFF, 0xF8, 0xFF, 0xF0,
0xF0, 0x3C, 0xF8, 0x7C, 0x1C, 0xE0, 0x0F, 0xC0, 0x07, 0x80,
0x07, 0x80, 0x0F, 0xC0, 0x1C, 0xE0, 0xF8, 0x7C, 0xF0, 0x3C,
0xFC, 0x00, 0xFE, 0x00, 0x07, 0x00, 0x03, 0x80, 0x01, 0xFC,
0x01, 0xFC, 0x03, 0x80, 0x07, 0x00, 0xFE, 0x00, 0xFC, 0x00,
0xC0, 0x3C, 0xC0, 0x7C, 0xC0, 0xEC, 0xC1, 0xCC, 0xC3, 0x8C,
0xC7, 0x0C, 0xCE, 0x0C, 0xDC, 0x0C, 0xF8, 0x0C, 0xF0, 0x0C,
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFC, 0xFF, 0xFC, 0xC0, 0x0C,
0xC0, 0x0C, 0xC0, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x30, 0x00, 0x30, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x03, 0x00,
0x03, 0x00, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0x30, 0x00, 0x30,
0x00, 0x00, 0x00, 0x00, 0xC0, 0x0C, 0xC0, 0x0C, 0xC0, 0x0C,
0xFF, 0xFC, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0C, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x70, 0x00, 0xE0, 0x00,
0xE0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1C, 0x00, 0x0C, 0x00,
0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C,
0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C,
0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0xE0, 0x00, 0x70, 0x00,
0x38, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x30, 0x06, 0x78, 0x0E, 0xFC, 0x0C, 0xCC, 0x0C, 0xCC,
0x0C, 0xCC, 0x0C, 0xCC, 0x0E, 0xCC, 0x07, 0xFC, 0x03, 0xF8,
0xFF, 0xFC, 0xFF, 0xFC, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0x0C,
0x03, 0x0C, 0x03, 0x0C, 0x03, 0x9C, 0x01, 0xF8, 0x00, 0xF0,
0x03, 0xF0, 0x07, 0xF8, 0x0E, 0x1C, 0x0C, 0x0C, 0x0C, 0x0C,
0x0C, 0x0C, 0x0C, 0x0C, 0x0E, 0x1C, 0x07, 0x38, 0x03, 0x30,
0x00, 0xF0, 0x01, 0xF8, 0x03, 0x9C, 0x03, 0x0C, 0x03, 0x0C,
0x03, 0x0C, 0x03, 0x0C, 0x03, 0x0C, 0xFF, 0xFC, 0xFF, 0xFC,
0x03, 0xF0, 0x07, 0xF8, 0x0E, 0xDC, 0x0C, 0xCC, 0x0C, 0xCC,
0x0C, 0xCC, 0x0C, 0xCC, 0x0E, 0xDC, 0x07, 0xD8, 0x03, 0x90,
0x00, 0x00, 0x03, 0x00, 0x3F, 0xFC, 0x7F, 0xFC, 0xE3, 0x00,
0xE3, 0x00, 0x70, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x18, 0x07, 0x9C, 0x0F, 0xCC, 0x0C, 0xCC, 0x0C, 0xCC,
0x0C, 0xCC, 0x0C, 0xCC, 0x0C, 0xDC, 0x0F, 0xF8, 0x07, 0xF0,
0xFF, 0xFC, 0xFF, 0xFC, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00,
0x03, 0x00, 0x03, 0x80, 0x01, 0xFC, 0x00, 0xFC, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0xFC,
0x1B, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x30, 0x00, 0x38, 0x00, 0x1C, 0x00, 0x0C,
0x00, 0x0C, 0x00, 0x1C, 0xCF, 0xF8, 0xCF, 0xF0, 0x00, 0x00,
0x00, 0x00, 0xFF, 0xFC, 0xFF, 0xFC, 0x00, 0xE0, 0x01, 0xE0,
0x03, 0xF0, 0x07, 0x38, 0x0E, 0x1C, 0x0C, 0x0C, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xC0, 0x0C, 0xC0, 0x0C, 0xFF, 0xFC,
0xFF, 0xFC, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00,
0x0F, 0xFC, 0x0F, 0xFC, 0x0E, 0x00, 0x07, 0x00, 0x03, 0xC0,
0x03, 0xC0, 0x07, 0x00, 0x0E, 0x00, 0x0F, 0xFC, 0x0F, 0xFC,
0x0F, 0xFC, 0x0F, 0xFC, 0x03, 0x00, 0x07, 0x00, 0x0E, 0x00,
0x0C, 0x00, 0x0C, 0x00, 0x0E, 0x00, 0x07, 0xFC, 0x03, 0xFC,
0x03, 0xF0, 0x07, 0xF8, 0x0E, 0x1C, 0x0C, 0x0C, 0x0C, 0x0C,
0x0C, 0x0C, 0x0C, 0x0C, 0x0E, 0x1C, 0x07, 0xF8, 0x03, 0xF0,
0x0F, 0xFC, 0x0F, 0xFC, 0x0C, 0xC0, 0x0C, 0xC0, 0x0C, 0xC0,
0x0C, 0xC0, 0x0C, 0xC0, 0x0F, 0xC0, 0x07, 0x80, 0x03, 0x00,
0x03, 0x00, 0x07, 0x80, 0x0F, 0xC0, 0x0C, 0xC0, 0x0C, 0xC0,
0x0C, 0xC0, 0x0C, 0xC0, 0x0C, 0xC0, 0x0F, 0xFC, 0x0F, 0xFC,
0x0F, 0xFC, 0x0F, 0xFC, 0x03, 0x80, 0x07, 0x00, 0x0E, 0x00,
0x0C, 0x00, 0x0C, 0x00, 0x0E, 0x00, 0x07, 0x00, 0x03, 0x00,
0x03, 0x18, 0x07, 0x9C, 0x0F, 0xCC, 0x0C, 0xCC, 0x0C, 0xCC,
0x0C, 0xCC, 0x0C, 0xCC, 0x0C, 0xFC, 0x0E, 0x78, 0x06, 0x30,
0x00, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0xFF, 0xF0, 0xFF, 0xF8,
0x0C, 0x1C, 0x0C, 0x1C, 0x0C, 0x38, 0x0C, 0x30, 0x00, 0x00,
0x0F, 0xF0, 0x0F, 0xF8, 0x00, 0x1C, 0x00, 0x0C, 0x00, 0x0C,
0x00, 0x0C, 0x00, 0x0C, 0x00, 0x1C, 0x0F, 0xF8, 0x0F, 0xF0,
0x0F, 0xC0, 0x0F, 0xE0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1C,
0x00, 0x1C, 0x00, 0x38, 0x00, 0x70, 0x0F, 0xE0, 0x0F, 0xC0,
0x0F, 0xF0, 0x0F, 0xF8, 0x00, 0x1C, 0x00, 0x1C, 0x00, 0xF8,
0x00, 0xF8, 0x00, 0x1C, 0x00, 0x1C, 0x0F, 0xF8, 0x0F, 0xF0,
0x0C, 0x0C, 0x0E, 0x1C, 0x07, 0x38, 0x03, 0xF0, 0x01, 0xE0,
0x01, 0xE0, 0x03, 0xF0, 0x07, 0x38, 0x0E, 0x1C, 0x0C, 0x0C,
0x0C, 0x00, 0x0E, 0x00, 0x07, 0x0C, 0x03, 0x9C, 0x01, 0xF8,
0x01, 0xF0, 0x03, 0x80, 0x07, 0x00, 0x0E, 0x00, 0x0C, 0x00,
0x0C, 0x0C, 0x0C, 0x1C, 0x0C, 0x3C, 0x0C, 0x7C, 0x0C, 0xEC,
0x0D, 0xCC, 0x0F, 0x8C, 0x0F, 0x0C, 0x0E, 0x0C, 0x0C, 0x0C,
0x00, 0x00, 0x03, 0x00, 0x07, 0x80, 0x3F, 0xF0, 0x7C, 0xF8,
0xE0, 0x1C, 0xC0, 0x0C, 0xC0, 0x0C, 0xC0, 0x0C, 0x00, 0x00,
0x03, 0x0C, 0x03, 0x0C, 0x3F, 0xFC, 0x7F, 0xFC, 0xE3, 0x0C,
0xC3, 0x0C, 0xC0, 0x0C, 0xE0, 0x0C, 0x70, 0x0C, 0x30, 0x0C,
0x00, 0x00, 0xC0, 0x0C, 0xC0, 0x0C, 0xC0, 0x0C, 0xE0, 0x1C,
0x7C, 0xF8, 0x3F, 0xF0, 0x07, 0x80, 0x03, 0x00, 0x00, 0x00,
0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00,
0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00,
0xFF, 0xFC, 0xFF, 0xFC, 0xFF, 0xFC, 0xFF, 0xFC, 0xFF, 0xFC,
0xFF, 0xFC, 0xFF, 0xFC, 0xFF, 0xFC, 0xFF, 0xFC, 0xFF, 0xFC
};
/**
* \brief Prepare to write GRAM data for ili93xx.
*/
static void ili93xx_write_ram_prepare(void)
{
if (g_uc_device_type == DEVICE_TYPE_ILI9325) {
/** Write Data to GRAM (R22h) */
LCD_IR(0);
LCD_IR(ILI9325_GRAM_DATA_REG);
} else if (g_uc_device_type == DEVICE_TYPE_ILI9341) {
/** memory write command (R2Ch)*/
LCD_IR(ILI9341_CMD_MEMORY_WRITE);
LCD_IR(0);
LCD_IR(ILI9341_CMD_WRITE_MEMORY_CONTINUE);
}
}
/**
* \brief Write data to LCD GRAM.
*
* \param ul_color 24-bits RGB color.
*/
static void ili93xx_write_ram(ili93xx_color_t ul_color)
{
LCD_WD((ul_color >> 16) & 0xFF);
LCD_WD((ul_color >> 8) & 0xFF);
LCD_WD(ul_color & 0xFF);
}
/**
* \brief Write multiple data in buffer to LCD controller for ili93xx.
*
* \param p_ul_buf data buffer.
* \param ul_size size in pixels.
*/
static void ili93xx_write_ram_buffer(const ili93xx_color_t *p_ul_buf,
uint32_t ul_size)
{
uint32_t ul_addr;
for (ul_addr = 0; ul_addr < (ul_size - ul_size % 8); ul_addr += 8) {
ili93xx_write_ram(p_ul_buf[ul_addr]);
ili93xx_write_ram(p_ul_buf[ul_addr + 1]);
ili93xx_write_ram(p_ul_buf[ul_addr + 2]);
ili93xx_write_ram(p_ul_buf[ul_addr + 3]);
ili93xx_write_ram(p_ul_buf[ul_addr + 4]);
ili93xx_write_ram(p_ul_buf[ul_addr + 5]);
ili93xx_write_ram(p_ul_buf[ul_addr + 6]);
ili93xx_write_ram(p_ul_buf[ul_addr + 7]);
}
for (; ul_addr < ul_size; ul_addr++) {
ili93xx_write_ram(p_ul_buf[ul_addr]);
}
}
/**
* \brief Write a word (16bits)to LCD Register.
*
* \param uc_reg register address.
* \param us_data data to be written.
*/
static void ili93xx_write_register_word(uint8_t uc_reg, uint16_t us_data)
{
LCD_IR(0);
LCD_IR(uc_reg);
LCD_WD((us_data >> 8) & 0xFF);
LCD_WD(us_data & 0xFF);
}
/**
* \brief Write data to LCD Register for ili93xx.
*
* \param uc_reg register address.
* \param us_data data to be written.
*/
static void ili93xx_write_register(uint8_t uc_reg, uint8_t *p_data,
uint8_t uc_datacnt)
{
uint8_t i;
LCD_IR(0);
LCD_IR(uc_reg);
for (i = 0; i < uc_datacnt; i++) {
LCD_WD(p_data[i]);
}
}
/**
* \brief Prepare to read GRAM data for ili93xx.
*/
static void ili93xx_read_ram_prepare(void)
{
if (g_uc_device_type == DEVICE_TYPE_ILI9325) {
LCD_IR(0);
/** Write Data to GRAM (R22h) */
LCD_IR(ILI9325_GRAM_DATA_REG);
} else if (g_uc_device_type == DEVICE_TYPE_ILI9341) {
LCD_IR(0);
/** Write Data to GRAM (R2Eh) */
LCD_IR(ILI9341_CMD_MEMORY_READ);
}
}
/**
* \brief Read data to LCD GRAM for ili93xx.
*
* \note For ili9325, because pixel data LCD GRAM is 18-bits, so convertion
* to RGB 24-bits will cause low color bit lose.
*
* \return color 24-bits RGB color.
*/
static uint32_t ili93xx_read_ram(void)
{
uint8_t value[3];
uint32_t color;
if (g_uc_device_type == DEVICE_TYPE_ILI9325) {
/** dummy read*/
value[0] = LCD_RD();
value[1] = LCD_RD();
/** data upper byte*/
value[0] = LCD_RD();
/** data lower byte */
value[1] = LCD_RD();
/** Convert RGB565 to RGB888 */
/** For BGR format */
color = ((value[0] & 0xF8)) | ((value[0] & 0x07) << 13) |
((value[1] & 0xE0) << 5) |
((value[1] & 0x1F) << 19);
} else if (g_uc_device_type == DEVICE_TYPE_ILI9341) {
/** dummy read */
value[0] = LCD_RD();
/** the highest byte - R byte*/
value[0] = LCD_RD();
/** the middle byte - G byte*/
value[1] = LCD_RD();
/** the lowest byte - B byte*/
value[2] = LCD_RD();
/** combine R, G, B byte to a color value */
color = (value[0] << 16) | (value[1] << 8) | value[2];
}
return color;
}
/**
* \brief Read data from LCD Register.
*
* \param uc_reg register address.
* \param p_data the pointer to the read data.
* \param uc_datacnt the number of the read data
*/
static void ili93xx_read_register(uint8_t uc_reg, uint8_t *p_data,
uint8_t uc_datacnt)
{
uint8_t i;
LCD_IR(0);
LCD_IR(uc_reg);
for (i = 0; i < uc_datacnt; i++) {
p_data[i] = LCD_RD();
}
}
/**
* \brief Delay function.
*/
static void ili93xx_delay(uint32_t ul_ms)
{
volatile uint32_t i;
for (i = 0; i < ul_ms; i++) {
for (i = 0; i < 100000; i++) {
}
}
}
/**
* \brief Check box coordinates.
*
* \param p_ul_x1 X coordinate of upper-left corner on LCD.
* \param p_ul_y1 Y coordinate of upper-left corner on LCD.
* \param p_ul_x2 X coordinate of lower-right corner on LCD.
* \param p_ul_y2 Y coordinate of lower-right corner on LCD.
*/
static void ili93xx_check_box_coordinates(uint32_t *p_ul_x1, uint32_t *p_ul_y1,
uint32_t *p_ul_x2, uint32_t *p_ul_y2)
{
uint32_t dw;
if (*p_ul_x1 >= g_ul_lcd_x_length) {
*p_ul_x1 = g_ul_lcd_x_length - 1;
}
if (*p_ul_x2 >= g_ul_lcd_x_length) {
*p_ul_x2 = g_ul_lcd_x_length - 1;
}
if (*p_ul_y1 >= g_ul_lcd_y_length) {
*p_ul_y1 = g_ul_lcd_y_length - 1;
}
if (*p_ul_y2 >= g_ul_lcd_y_length) {
*p_ul_y2 = g_ul_lcd_y_length - 1;
}
if (*p_ul_x1 > *p_ul_x2) {
dw = *p_ul_x1;
*p_ul_x1 = *p_ul_x2;
*p_ul_x2 = dw;
}
if (*p_ul_y1 > *p_ul_y2) {
dw = *p_ul_y1;
*p_ul_y1 = *p_ul_y2;
*p_ul_y2 = dw;
}
}
/**
* \brief Read device ID to idenfity the device
* ILI9325 device ID locates in Device Code Read (R00h) register.
* ILI9341 device ID locates in Read ID4 (RD3h) register.
*
* \return 0 if secceed in identifying device; otherwise fails.
*/
uint8_t ili93xx_device_type_identify(void)
{
uint8_t paratable[6];
uint16_t chipid;
/** Read ID4 (RD4h) register to get device code for ILI9341*/
ili93xx_read_register(ILI9341_CMD_READ_ID4, paratable, 4);
chipid = ((uint16_t)paratable[2] << 8) + paratable[3];
if (chipid == ILI9341_DEVICE_CODE) {
g_uc_device_type = DEVICE_TYPE_ILI9341;
return 0;
}
/** Driver Code Read (R00h) for ILI9325*/
ili93xx_read_register(ILI9325_DEVICE_CODE_REG, paratable, 2);
chipid = ((uint16_t)paratable[0] << 8) + paratable[1];
if (chipid == ILI9325_DEVICE_CODE) {
g_uc_device_type = DEVICE_TYPE_ILI9325;
return 0;
}
return 1;
}
/**
* \brief Initialize the ILI93XX lcd driver.
*
* \note Make sure below works have been done before calling ili93xx_init()
* 1. ILI93xx related Pins have been initialized correctly.
* 2. SMC has been configured correctly for access ILI93xx (8-bit system
* interface for now).
*
* \param p_opt pointer to ILI93xx option structure.
*
* \return 0 if initialization succeeds, otherwise fails.
*/
uint32_t ili93xx_init(struct ili93xx_opt_t *p_opt)
{
uint8_t paratable[15];
/** Identify the LCD driver device*/
if (ili93xx_device_type_identify() != 0) {
return 1;
}
g_ul_lcd_x_length = ILI93XX_LCD_WIDTH;
g_ul_lcd_y_length = ILI93XX_LCD_HEIGHT;
if (g_uc_device_type == DEVICE_TYPE_ILI9325) {
/** Turn off LCD */
ili93xx_write_register_word(ILI9325_DISP_CTRL1, ILI9325_DISP_CTRL1_GON |
ILI9325_DISP_CTRL1_DTE | ILI9325_DISP_CTRL1_D(0x03));
/** Start initial sequence */
/** Disable sleep and standby mode*/
ili93xx_write_register_word(ILI9325_POWER_CTRL1, 0x0000);
/** Start internal OSC */
ili93xx_write_register_word(ILI9325_START_OSC_CTRL,
ILI9325_START_OSC_CTRL_EN);
/** Set SS bit and direction output from S720 to S1 */
ili93xx_write_register_word(ILI9325_DRIVER_OUTPUT_CTRL1,
ILI9325_DRIVER_OUTPUT_CTRL1_SS);
/** Set 1 line inversion */
ili93xx_write_register_word(ILI9325_LCD_DRIVING_CTRL,
ILI9325_LCD_DRIVING_CTRL_BIT10 | ILI9325_LCD_DRIVING_CTRL_EOR
| ILI9325_LCD_DRIVING_CTRL_BC0);
/** Disable resizing feature */
ili93xx_write_register_word(ILI9325_RESIZE_CTRL, 0x0000);
/** Set the back porch and front porch */
ili93xx_write_register_word(ILI9325_DISP_CTRL2,
ILI9325_DISP_CTRL2_BP(
0x07) | ILI9325_DISP_CTRL2_FP(0x02));
/** Set non-display area refresh cycle ISC[3:0] */
ili93xx_write_register_word(ILI9325_DISP_CTRL3, 0x0000);
/** Disable FMARK function */
ili93xx_write_register_word(ILI9325_DISP_CTRL4, 0x0000);
/** 18-bit RGB interface and writing display data by system
*interface */
ili93xx_write_register_word(ILI9325_RGB_DISP_INTERFACE_CTRL1,
0x0000);
/** Set the output position of frame cycle */
ili93xx_write_register_word(ILI9325_FRAME_MAKER_POS, 0x0000);
/** RGB interface polarity */
ili93xx_write_register_word(ILI9325_RGB_DISP_INTERFACE_CTRL2,
0x0000);
/** Power on sequence */
/** Disable sleep and standby mode */
ili93xx_write_register_word(ILI9325_POWER_CTRL1, 0x0000);
/**
* Selects the operating frequency of the step-up circuit 1,2
* and Sets the ratio factor of Vci.
*/
ili93xx_write_register_word(ILI9325_POWER_CTRL2, 0x0000);
/** Set VREG1OUT voltage */
ili93xx_write_register_word(ILI9325_POWER_CTRL3, 0x0000);
/** Set VCOM amplitude */
ili93xx_write_register_word(ILI9325_POWER_CTRL4, 0x0000);
ili93xx_delay(200);
/** Enable power supply and source driver */
/**
* Adjusts the constant current and Sets the factor used
* in the step-up circuits.
*/
ili93xx_write_register_word(ILI9325_POWER_CTRL1,
ILI9325_POWER_CTRL1_SAP | ILI9325_POWER_CTRL1_BT(0x02) |
ILI9325_POWER_CTRL1_APE |
ILI9325_POWER_CTRL1_AP(0x01));
/**
* Select the operating frequency of the step-up circuit 1,2 and
* Sets the ratio factor of Vci
*/
ili93xx_write_register_word(ILI9325_POWER_CTRL2,
ILI9325_POWER_CTRL2_DC1(0x02) |
ILI9325_POWER_CTRL2_DC0(0x02) | ILI9325_POWER_CTRL2_VC(0x07));
ili93xx_delay(50);
/** Internal reference voltage= Vci */
ili93xx_write_register_word(ILI9325_POWER_CTRL3,
ILI9325_POWER_CTRL3_PON | ILI9325_POWER_CTRL3_VRH(0x0B));
ili93xx_delay(50);
/** Set VDV[4:0] for VCOM amplitude */
ili93xx_write_register_word(ILI9325_POWER_CTRL4,
ILI9325_POWER_CTRL4_VDV(0x11));
/** Set VCM[5:0] for VCOMH */
ili93xx_write_register_word(ILI9325_POWER_CTRL7,
ILI9325_POWER_CTRL7_VCM(0x19));
/** Set Frame Rate */
ili93xx_write_register_word(ILI9325_FRAME_RATE_AND_COLOR_CTRL,
ILI9325_FRAME_RATE_AND_COLOR_CTRL_FRS(0x0D));
ili93xx_delay(50);
/** Adjust the Gamma Curve */
ili93xx_write_register_word(ILI9325_GAMMA_CTL1, 0x0000);
ili93xx_write_register_word(ILI9325_GAMMA_CTL2,
ILI9325_GAMMA_CTL2_KP3(0x02) |
ILI9325_GAMMA_CTL2_KP2(0x04));
ili93xx_write_register_word(ILI9325_GAMMA_CTL3,
ILI9325_GAMMA_CTL3_KP5(0x02) |
ILI9325_GAMMA_CTL3_KP4(0x00));
ili93xx_write_register_word(ILI9325_GAMMA_CTL4,
ILI9325_GAMMA_CTL4_RP1(0x00) |
ILI9325_GAMMA_CTL4_RP0(0x07));
ili93xx_write_register_word(ILI9325_GAMMA_CTL5,
ILI9325_GAMMA_CTL5_VRP1(0x14) |
ILI9325_GAMMA_CTL5_VRP0(0x04));
ili93xx_write_register_word(ILI9325_GAMMA_CTL6,
ILI9325_GAMMA_CTL6_KN1(0x07) |
ILI9325_GAMMA_CTL6_KN0(0x05));
ili93xx_write_register_word(ILI9325_GAMMA_CTL7,
ILI9325_GAMMA_CTL7_KN3(0x03) |
ILI9325_GAMMA_CTL7_KN2(0x05));
ili93xx_write_register_word(ILI9325_GAMMA_CTL8,
ILI9325_GAMMA_CTL8_KN5(0x07) |
ILI9325_GAMMA_CTL8_KN4(0x07));
ili93xx_write_register_word(ILI9325_GAMMA_CTL9,
ILI9325_GAMMA_CTL9_RN1(0x07) |
ILI9325_GAMMA_CTL9_RN0(0x01));
ili93xx_write_register_word(ILI9325_GAMMA_CTL10,
ILI9325_GAMMA_CTL10_VRN1(0x00) |
ILI9325_GAMMA_CTL10_VRN0(0x0E));
/**
* Use the high speed write mode (HWM=1)
* When TRI = 1, data are transferred to the internal RAM in
* 8-bit x 3 transfers mode via the 8-bit interface.
* DFM Set the mode of transferring data to the internal RAM
* when TRI = 1.
* I/D[1:0] = 11 Horizontal : increment Vertical : increment,
* AM=0:Horizontal
*/
ili93xx_write_register_word(ILI9325_ENTRY_MODE,
ILI9325_ENTRY_MODE_TRI | ILI9325_ENTRY_MODE_DFM |
ILI9325_ENTRY_MODE_ID(0x01) | ILI9325_ENTRY_MODE_BGR);
/**
* Sets the number of lines to drive the LCD at an interval of 8
* lines. The scan direction is from G320 to G1
*/
ili93xx_write_register_word(ILI9325_DRIVER_OUTPUT_CTRL2,
ILI9325_DRIVER_OUTPUT_CTRL2_GS |
ILI9325_DRIVER_OUTPUT_CTRL2_NL(0x27));
/** Vertical Scrolling */
/** Disable scrolling and enable the grayscale inversion */
ili93xx_write_register_word(ILI9325_BASE_IMG_DISP_CTRL,
ILI9325_BASE_IMG_DISP_CTRL_REV);
ili93xx_write_register_word(ILI9325_VERTICAL_SCROLL_CTRL,
0x0000);
/** Disable Partial Display */
ili93xx_write_register_word(ILI9325_PARTIAL_IMG1_DISP_POS,
0x0000);
ili93xx_write_register_word(
ILI9325_PARTIAL_IMG1_AREA_START_LINE,
0x0000);
ili93xx_write_register_word(ILI9325_PARTIAL_IMG1_AREA_END_LINE,
0x0000);
ili93xx_write_register_word(ILI9325_PARTIAL_IMG2_DISP_POS,
0x0000);
ili93xx_write_register_word(
ILI9325_PARTIAL_IMG2_AREA_START_LINE,
0x0000);
ili93xx_write_register_word(ILI9325_PARTIAL_IMG2_AREA_END_LINE,
0x0000);
/** Panel Control */
ili93xx_write_register_word(ILI9325_PANEL_INTERFACE_CTRL1,
ILI9325_PANEL_INTERFACE_CTRL1_RTNI(0x10));
ili93xx_write_register_word(ILI9325_PANEL_INTERFACE_CTRL2,
ILI9325_PANEL_INTERFACE_CTRL2_NOWI(0x06));
ili93xx_write_register_word(ILI9325_PANEL_INTERFACE_CTRL4,
ILI9325_PANEL_INTERFACE_CTRL4_DIVE(0x01) |
ILI9325_PANEL_INTERFACE_CTRL4_RTNE(0x10));
ili93xx_set_window(0, 0, p_opt->ul_width, p_opt->ul_height);
ili93xx_set_foreground_color(p_opt->foreground_color);
ili93xx_set_cursor_position(0, 0);
} else if (g_uc_device_type == DEVICE_TYPE_ILI9341) {
/** init for ILI9341 **/
/** power control A configuration*/
paratable[0] = 0x39;
paratable[1] = 0x2C;
paratable[2] = 0x00;
paratable[3] = 0x34;
paratable[4] = 0x02;
ili93xx_write_register(ILI9341_CMD_POWER_CONTROL_A, paratable, 5);
/** power control B configuration */
paratable[0] = 0;
paratable[1] = 0xAA;
paratable[2] = 0xB0;
ili93xx_write_register(ILI9341_CMD_POWER_CONTROL_B, paratable, 3);
/** Pump Ratio Control configuration */
paratable[0] = 0x30;
ili93xx_write_register(ILI9341_CMD_PUMP_RATIO_CONTROL,
paratable, 1);
/** Power Control 1 configuration*/
paratable[0] = 0x25;
ili93xx_write_register(ILI9341_CMD_POWER_CONTROL_1, paratable, 1);
/** Power Control 2 configuration*/
paratable[0] = 0x11;
ili93xx_write_register(ILI9341_CMD_POWER_CONTROL_2, paratable, 1);
/** VOM Control 1 configuration*/
paratable[0] = 0x5C;
paratable[1] = 0x4C;
ili93xx_write_register(ILI9341_CMD_VCOM_CONTROL_1, paratable, 2);
/** VOM control 2 configuration*/
paratable[0] = 0x94;
ili93xx_write_register(ILI9341_CMD_VCOM_CONTROL_2, paratable, 1);
/** Driver Timing Control A configuration*/
paratable[0] = 0x85;
paratable[1] = 0x01;
paratable[2] = 0x78;
ili93xx_write_register(ILI9341_CMD_DRIVER_TIMING_CTL_A, paratable, 3);
/** Driver Timing Control B configuration*/
paratable[0] = 0x00;
paratable[1] = 0x00;
ili93xx_write_register(ILI9341_CMD_DRIVER_TIMING_CTL_B, paratable, 2);
/** Memory Access Control configuration*/
paratable[0] = ILI9341_CMD_MEMORY_ACCESS_CONTROL_MX |
ILI9341_CMD_MEMORY_ACCESS_CONTROL_BGR;
ili93xx_write_register(ILI9341_CMD_MEMORY_ACCESS_CONTROL,
paratable, 1);
/** Colmod Pixel Format Set configuation*/
paratable[0] = 0x06;
ili93xx_write_register(ILI9341_CMD_PIXEL_FORMAT_SET, paratable, 1);
/** Display Function Control */
paratable[0] = 0x02;
paratable[1] = 0x82;
paratable[2] = 0x27;
paratable[3] = 0x00;
ili93xx_write_register(ILI9341_CMD_DISPLAY_FUNCTION_CTL,
paratable, 4);
paratable[0] = 0x00;
ili93xx_write_register(ILI9341_CMD_ENABLE_3_GAMMA_CONTROL,
paratable,1);
paratable[0] = 0x01;
ili93xx_write_register(ILI9341_CMD_GAMMA_SET, paratable,1);
/** set gamma curve parameters*/
paratable[0]=0x0F;
paratable[1]=0x31;
paratable[2]=0x2B;
paratable[3]=0x0C;
paratable[4]=0x0E;
paratable[5]=0x08;
paratable[6]=0x4E;
paratable[7]=0xF1;
paratable[8]=0x37;
paratable[9]=0x07;
paratable[10]=0x10;
paratable[11]=0x03;
paratable[12]=0x0E;
paratable[13]=0x09;
paratable[14]=0x00;
ili93xx_write_register(ILI9341_CMD_POSITIVE_GAMMA_CORRECTION,
paratable, 15);
paratable[0]=0x00;
paratable[1]=0x0E;
paratable[2]=0x14;
paratable[3]=0x03;
paratable[4]=0x11;
paratable[5]=0x07;
paratable[6]=0x31;
paratable[7]=0xC1;
paratable[8]=0x48;
paratable[9]=0x08;
paratable[10]=0x0F;
paratable[11]=0x0C;
paratable[12]=0x31;
paratable[13]=0x36;
paratable[14]=0x0F;
ili93xx_write_register(ILI9341_CMD_NEGATIVE_GAMMA_CORRECTION,
paratable, 15);
/** set window area*/
ili93xx_set_window(0, 0, p_opt->ul_width, p_opt->ul_height);
ili93xx_set_foreground_color(p_opt->foreground_color);
/** Leave sleep mode*/
ili93xx_write_register(ILI9341_CMD_SLEEP_OUT, paratable, 0);
ili93xx_delay(10);
/** Display on*/
ili93xx_write_register(ILI9341_CMD_DISPLAY_ON, paratable, 0);
} else {
/** exit with return value 1 if device type is not supported.*/
return 1;
}
return 0;
}
/**
* \brief get the device type.
*/
uint8_t ili93xx_device_type(void)
{
return g_uc_device_type;
}
/**
* \brief Turn on the LCD.
*/
void ili93xx_display_on(void)
{
if (g_uc_device_type == DEVICE_TYPE_ILI9325) {
ili93xx_write_register_word(ILI9325_DISP_CTRL1,
ILI9325_DISP_CTRL1_BASEE |
ILI9325_DISP_CTRL1_GON |
ILI9325_DISP_CTRL1_DTE |
ILI9325_DISP_CTRL1_D(0x03));
} else if (g_uc_device_type == DEVICE_TYPE_ILI9341) {
ili93xx_write_register(ILI9341_CMD_DISPLAY_ON, NULL, 0);
}
}
/**
* \brief Turn off the LCD.
*/
void ili93xx_display_off(void)
{
if (g_uc_device_type == DEVICE_TYPE_ILI9325) {
ili93xx_write_register_word(ILI9325_DISP_CTRL1, 0x00);
} else if (g_uc_device_type == DEVICE_TYPE_ILI9341) {
ili93xx_write_register(ILI9341_CMD_DISPLAY_OFF, NULL, 0);
}
}
/**
* \brief Set foreground color.
*
* \param ul_color foreground color.
*/
void ili93xx_set_foreground_color(ili93xx_color_t ul_color)
{
uint32_t i;
/** Fill the cache with selected color */
for (i = 0; i < LCD_DATA_CACHE_SIZE; ++i) {
g_ul_pixel_cache[i] = ul_color;
}
}
/**
* \brief Fill the LCD buffer with the specified color.
*
* \param ul_color fill color.
*/
void ili93xx_fill(ili93xx_color_t ul_color)
{
uint32_t dw;
if (g_uc_device_type == DEVICE_TYPE_ILI9325) {
ili93xx_set_cursor_position(0, 0);
} else if (g_uc_device_type == DEVICE_TYPE_ILI9341) {
ili93xx_set_window(0, 0, g_ul_lcd_x_length, g_ul_lcd_y_length);
}
ili93xx_write_ram_prepare();
for (dw = ILI93XX_LCD_WIDTH * ILI93XX_LCD_HEIGHT; dw > 0; dw--) {
ili93xx_write_ram(ul_color);
}
}
/**
* \brief Set display window.
*
* \param ul_x Horizontal address start position
* \param ul_y Vertical address start position
* \param ul_width The width of the window.
* \param ul_height The height of the window.
*/
void ili93xx_set_window(uint32_t ul_x, uint32_t ul_y, uint32_t ul_width,
uint32_t ul_height)
{
Assert(ul_x <= (g_ul_lcd_x_length - 1));
Assert(ul_y <= (g_ul_lcd_y_length - 1));
Assert(ul_width <= (g_ul_lcd_x_length - ul_x));
Assert(ul_height <= (g_ul_lcd_y_length - ul_y));
if (g_uc_device_type == DEVICE_TYPE_ILI9325) {
/** Set Horizontal Address Start Position */
ili93xx_write_register_word(ILI9325_HORIZONTAL_ADDR_START,
(uint16_t)ul_x);
/** Set Horizontal Address End Position */
ili93xx_write_register_word(ILI9325_HORIZONTAL_ADDR_END,
(uint16_t)(ul_x + ul_width - 1));
/** Set Vertical Address Start Position */
ili93xx_write_register_word(ILI9325_VERTICAL_ADDR_START,
(uint16_t)ul_y);
/** Set Vertical Address End Position */
ili93xx_write_register_word(ILI9325_VERTICAL_ADDR_END,
(uint16_t)(ul_y + ul_height - 1));
} else if (g_uc_device_type == DEVICE_TYPE_ILI9341) {
uint8_t paratable[4];
/** Set Column Address Position */
paratable[0] = (ul_x >> 8) & 0xFF;
paratable[1] = ul_x & 0xFF;
paratable[2] = ((ul_x + ul_width - 1) >> 8) & 0xFF;
paratable[3] = (ul_x + ul_width - 1) & 0xFF;
ili93xx_write_register(ILI9341_CMD_COLUMN_ADDRESS_SET,
paratable, 4);
/** Set Page Address Position */
paratable[0] = (ul_y >> 8) & 0xFF;
paratable[1] = ul_y & 0xFF;
paratable[2] = ((ul_y + ul_height - 1) >> 8) & 0xFF;
paratable[3] = (ul_y + ul_height - 1) & 0xFF;
ili93xx_write_register(ILI9341_CMD_PAGE_ADDRESS_SET,
paratable, 4);
}
}
/**
* \brief Set cursor of LCD screen.
*
* \param us_x X coordinate of upper-left corner on LCD.
* \param us_y Y coordinate of upper-left corner on LCD.
*/
void ili93xx_set_cursor_position(uint16_t us_x, uint16_t us_y)
{
if (g_uc_device_type == DEVICE_TYPE_ILI9325) {
/** GRAM Horizontal/Vertical Address Set (R20h, R21h) */
ili93xx_write_register_word(ILI9325_HORIZONTAL_GRAM_ADDR_SET, us_x);
ili93xx_write_register_word(ILI9325_VERTICAL_GRAM_ADDR_SET, us_y);
} else if (g_uc_device_type == DEVICE_TYPE_ILI9341) {
/** There is no corresponding operation for ILI9341. */
}
}
/**
* \brief Scroll up/down for the number of specified lines.
*
* \param ul_lines number of lines to scroll.
*/
void ili93xx_scroll(int32_t ul_lines)
{
if (g_uc_device_type == DEVICE_TYPE_ILI9325) {
ili93xx_write_register_word(ILI9325_VERTICAL_SCROLL_CTRL, ul_lines);
} else if (g_uc_device_type == DEVICE_TYPE_ILI9341) {
uint8_t paratable[2];
paratable[0] = (ul_lines >> 8) & 0xFF;
paratable[1] = ul_lines & 0xFF;
ili93xx_write_register(ILI9341_CMD_VERT_SCROLL_START_ADDRESS,
paratable, 2);
}
}
/**
* \brief Vertical Scroll area definition for ili9341.
*
* \param us_tfa the top fixed area (the No. of lines)
* \param us_vsa the height of the vetical scrolling area
* \param us_bfa the bottom fixed area (the No. of lines)
*/
void ili93xx_vscroll_area_define(uint16_t us_tfa, uint16_t us_vsa,
uint16_t us_bfa)
{
if (g_uc_device_type == DEVICE_TYPE_ILI9341) {
uint8_t paratable[6];
paratable[0] = (us_tfa >> 8) & 0xFF;
paratable[1] = us_tfa & 0xFF;
paratable[2] = (us_vsa >> 8) & 0xFF;
paratable[3] = us_vsa & 0xFF;
paratable[4] = (us_bfa >> 8) & 0xFF;
paratable[5] = us_bfa & 0xFF;
ili93xx_write_register(ILI9341_CMD_VERT_SCROLL_DEFINITION,
paratable, 6);
}
}
/**
* \brief Enable the scrolling feature.
*/
void ili93xx_enable_scroll(void)
{
if (g_uc_device_type == DEVICE_TYPE_ILI9325) {
ili93xx_write_register_word(ILI9325_BASE_IMG_DISP_CTRL,
ILI9325_BASE_IMG_DISP_CTRL_REV |
ILI9325_BASE_IMG_DISP_CTRL_VLE);
} else if (g_uc_device_type == DEVICE_TYPE_ILI9341) {
/** no operation needed for ILI9341*/
}
}
/**
* \brief Disable the scrolling feature.
*/
void ili93xx_disable_scroll(void)
{
if (g_uc_device_type == DEVICE_TYPE_ILI9325) {
ili93xx_write_register_word(ILI9325_BASE_IMG_DISP_CTRL,
ILI9325_BASE_IMG_DISP_CTRL_REV);
} else if (g_uc_device_type == DEVICE_TYPE_ILI9341) {
ili93xx_display_off();
ili93xx_write_register(ILI9341_CMD_NORMAL_DISP_MODE_ON, NULL, 0);
ili93xx_display_on();
}
}
/**
* \brief Set display direction.
*
* \param e_dd 0: horizontal direction, 1: vertical direction
* \param e_shd: horizontal increase(0) or decrease(1)
* \param e_scd: vertical increase(1) or decrease(0)
*/
void ili93xx_set_display_direction(enum ili93xx_display_direction e_dd,
enum ili93xx_shift_direction e_shd,
enum ili93xx_scan_direction e_scd)
{
if (g_uc_device_type == DEVICE_TYPE_ILI9325) {
if (e_dd == LANDSCAPE) {
ili93xx_write_register_word(ILI9325_ENTRY_MODE,
ILI9325_ENTRY_MODE_BGR | ILI9325_ENTRY_MODE_TRI |
ILI9325_ENTRY_MODE_DFM | ILI9325_ENTRY_MODE_ID(0x00)|
ILI9325_ENTRY_MODE_AM);
g_ul_lcd_x_length = ILI93XX_LCD_HEIGHT;
g_ul_lcd_y_length = ILI93XX_LCD_WIDTH;
} else {
ili93xx_write_register_word(ILI9325_ENTRY_MODE,
ILI9325_ENTRY_MODE_BGR | ILI9325_ENTRY_MODE_TRI |
ILI9325_ENTRY_MODE_DFM | ILI9325_ENTRY_MODE_ID(0x01));
g_ul_lcd_x_length = ILI93XX_LCD_WIDTH;
g_ul_lcd_y_length = ILI93XX_LCD_HEIGHT;
}
if (e_shd == H_INCREASE) {
ili93xx_write_register_word(ILI9325_DRIVER_OUTPUT_CTRL1, 0x0000);
} else {
ili93xx_write_register_word(ILI9325_DRIVER_OUTPUT_CTRL1,
ILI9325_DRIVER_OUTPUT_CTRL1_SS);
}
if (e_scd == V_INCREASE) {
ili93xx_write_register_word(ILI9325_DRIVER_OUTPUT_CTRL2,
ILI9325_DRIVER_OUTPUT_CTRL2_NL(0x27));
} else {
ili93xx_write_register_word(ILI9325_DRIVER_OUTPUT_CTRL2,
ILI9325_DRIVER_OUTPUT_CTRL2_GS |
ILI9325_DRIVER_OUTPUT_CTRL2_NL(0x27));
}
} else if (g_uc_device_type == DEVICE_TYPE_ILI9341) {
if (e_dd == LANDSCAPE) {
uint8_t paratable[1];
paratable[0] = ILI9341_CMD_MEMORY_ACCESS_CONTROL_MV |
ILI9341_CMD_MEMORY_ACCESS_CONTROL_BGR;
ili93xx_write_register(
ILI9341_CMD_MEMORY_ACCESS_CONTROL,
paratable, 1);
g_ul_lcd_x_length = ILI93XX_LCD_HEIGHT;
g_ul_lcd_y_length = ILI93XX_LCD_WIDTH;
} else {
uint8_t paratable[1];
paratable[0] = ILI9341_CMD_MEMORY_ACCESS_CONTROL_BGR |
ILI9341_CMD_MEMORY_ACCESS_CONTROL_MX;
ili93xx_write_register(
ILI9341_CMD_MEMORY_ACCESS_CONTROL,
paratable, 1);
g_ul_lcd_x_length = ILI93XX_LCD_WIDTH;
g_ul_lcd_y_length = ILI93XX_LCD_HEIGHT;
}
}
}
/**
* \brief Draw a pixel on LCD.
*
* \param ul_x X coordinate of pixel.
* \param ul_y Y coordinate of pixel.
*
* \return 0 if succeeds, otherwise fails.
*/
uint32_t ili93xx_draw_pixel(uint32_t ul_x, uint32_t ul_y)
{
if ((ul_x >= g_ul_lcd_x_length) || (ul_y >= g_ul_lcd_y_length)) {
return 1;
}
if (g_uc_device_type == DEVICE_TYPE_ILI9325) {
/** Set cursor */
ili93xx_set_cursor_position(ul_x, ul_y);
/** Prepare to write in GRAM */
ili93xx_write_ram_prepare();
ili93xx_write_ram(*g_ul_pixel_cache);
} else if (g_uc_device_type == DEVICE_TYPE_ILI9341) {
ili93xx_set_window(ul_x, ul_y, 0, 0);
/** Prepare to write in GRAM */
ili93xx_write_ram_prepare();
ili93xx_write_ram(*g_ul_pixel_cache);
}
return 0;
}
/**
* \brief Get a pixel from LCD.
*
* \param ul_x X coordinate of pixel.
* \param ul_y Y coordinate of pixel.
*
* \return the pixel color.
*/
ili93xx_color_t ili93xx_get_pixel(uint32_t ul_x, uint32_t ul_y)
{
Assert(ul_x <= g_ul_lcd_x_length);
Assert(ul_y <= g_ul_lcd_y_length);
if (g_uc_device_type == DEVICE_TYPE_ILI9325) {
/** Set cursor */
ili93xx_set_cursor_position(ul_x, ul_y);
/** Prepare to write in GRAM */
ili93xx_read_ram_prepare();
return ili93xx_read_ram();
} else if (g_uc_device_type == DEVICE_TYPE_ILI9341) {
ili93xx_set_window(ul_x, ul_y, 0, 0);
/** Prepare to write in GRAM */
ili93xx_read_ram_prepare();
return ili93xx_read_ram();
}
return 0;
}
/**
* \brief Draw a line on LCD, which is not horizontal or vertical.
*
* \param ul_x1 X coordinate of line start.
* \param ul_y1 Y coordinate of line start.
* \param ul_x2 X coordinate of line end.
* \param ul_y2 Y coordinate of line endl.
*/
static void ili93xx_draw_line_bresenham(uint32_t ul_x1, uint32_t ul_y1,
uint32_t ul_x2, uint32_t ul_y2)
{
int dx, dy;
int i;
int xinc, yinc, cumul;
int x, y;
x = ul_x1;
y = ul_y1;
dx = ul_x2 - ul_x1;
dy = ul_y2 - ul_y1;
xinc = (dx > 0) ? 1 : -1;
yinc = (dy > 0) ? 1 : -1;
dx = abs(ul_x2 - ul_x1);
dy = abs(ul_y2 - ul_y1);
ili93xx_draw_pixel(x, y);
if (dx > dy) {
cumul = dx >> 1;
for (i = 1; i <= dx; i++) {
x += xinc;
cumul += dy;
if (cumul >= dx) {
cumul -= dx;
y += yinc;
}
ili93xx_draw_pixel(x, y);
}
} else {
cumul = dy >> 1;
for (i = 1; i <= dy; i++) {
y += yinc;
cumul += dx;
if (cumul >= dy) {
cumul -= dy;
x += xinc;
}
ili93xx_draw_pixel(x, y);
}
}
}
/**
* \brief Draw a line on LCD.
*
* \param ul_x1 X coordinate of line start.
* \param ul_y1 Y coordinate of line start.
* \param ul_x2 X coordinate of line end.
* \param ul_y2 Y coordinate of line end.
*/
void ili93xx_draw_line(uint32_t ul_x1, uint32_t ul_y1,
uint32_t ul_x2, uint32_t ul_y2)
{
if ((ul_y1 == ul_y2) || (ul_x1 == ul_x2)) {
ili93xx_draw_filled_rectangle(ul_x1, ul_y1, ul_x2, ul_y2);
} else {
ili93xx_draw_line_bresenham(ul_x1, ul_y1, ul_x2, ul_y2);
}
}
/**
* \brief Draw a rectangle on LCD.
*
* \param ul_x1 X coordinate of upper-left corner on LCD.
* \param ul_y1 Y coordinate of upper-left corner on LCD.
* \param ul_x2 X coordinate of lower-right corner on LCD.
* \param ul_y2 Y coordinate of lower-right corner on LCD.
*/
void ili93xx_draw_rectangle(uint32_t ul_x1, uint32_t ul_y1,
uint32_t ul_x2, uint32_t ul_y2)
{
ili93xx_check_box_coordinates(&ul_x1, &ul_y1, &ul_x2, &ul_y2);
ili93xx_draw_filled_rectangle(ul_x1, ul_y1, ul_x2, ul_y1);
ili93xx_draw_filled_rectangle(ul_x1, ul_y2, ul_x2, ul_y2);
ili93xx_draw_filled_rectangle(ul_x1, ul_y1, ul_x1, ul_y2);
ili93xx_draw_filled_rectangle(ul_x2, ul_y1, ul_x2, ul_y2);
}
/**
* \brief Draw a filled rectangle on LCD.
*
* \param ul_x1 X coordinate of upper-left corner on LCD.
* \param ul_y1 Y coordinate of upper-left corner on LCD.
* \param ul_x2 X coordinate of lower-right corner on LCD.
* \param ul_y2 Y coordinate of lower-right corner on LCD.
*/
void ili93xx_draw_filled_rectangle(uint32_t ul_x1, uint32_t ul_y1,
uint32_t ul_x2, uint32_t ul_y2)
{
uint32_t size, blocks;
/** Swap coordinates if necessary */
ili93xx_check_box_coordinates(&ul_x1, &ul_y1, &ul_x2, &ul_y2);
/** Determine the refresh window area */
ili93xx_set_window(ul_x1, ul_y1, (ul_x2 - ul_x1) + 1,
(ul_y2 - ul_y1) + 1);
/** Set cursor */
ili93xx_set_cursor_position(ul_x1, ul_y1);
/** Prepare to write in Graphic RAM */
ili93xx_write_ram_prepare();
size = (ul_x2 - ul_x1 + 1) * (ul_y2 - ul_y1 + 1);
/** Send pixels blocks => one SPI IT / block */
blocks = size / LCD_DATA_CACHE_SIZE;
while (blocks--) {
ili93xx_write_ram_buffer(g_ul_pixel_cache,
LCD_DATA_CACHE_SIZE);
}
/** Send remaining pixels */
ili93xx_write_ram_buffer(g_ul_pixel_cache,
size % LCD_DATA_CACHE_SIZE);
/** Reset the refresh window area */
ili93xx_set_window(0, 0, g_ul_lcd_x_length, g_ul_lcd_y_length);
}
/**
* \brief Draw a circle on LCD.
*
* \param ul_x X coordinate of circle center.
* \param ul_y Y coordinate of circle center.
* \param ul_r circle radius.
*
* \return 0 if succeeds, otherwise fails.
*/
uint32_t ili93xx_draw_circle(uint32_t ul_x, uint32_t ul_y, uint32_t ul_r)
{
int32_t d;
uint32_t curX;
uint32_t curY;
if (ul_r == 0) {
return 1;
}
d = 3 - (ul_r << 1);
curX = 0;
curY = ul_r;
while (curX <= curY) {
ili93xx_draw_pixel(ul_x + curX, ul_y + curY);
ili93xx_draw_pixel(ul_x + curX, ul_y - curY);
ili93xx_draw_pixel(ul_x - curX, ul_y + curY);
ili93xx_draw_pixel(ul_x - curX, ul_y - curY);
ili93xx_draw_pixel(ul_x + curY, ul_y + curX);
ili93xx_draw_pixel(ul_x + curY, ul_y - curX);
ili93xx_draw_pixel(ul_x - curY, ul_y + curX);
ili93xx_draw_pixel(ul_x - curY, ul_y - curX);
if (d < 0) {
d += (curX << 2) + 6;
} else {
d += ((curX - curY) << 2) + 10;
curY--;
}
curX++;
}
return 0;
}
/**
* \brief Draw a filled circle on LCD.
*
* \param ul_x X coordinate of circle center.
* \param ul_y Y coordinate of circle center.
* \param ul_r circle radius.
*
* \return 0 if succeeds, otherwise fails.
*/
uint32_t ili93xx_draw_filled_circle(uint32_t ul_x, uint32_t ul_y, uint32_t ul_r)
{
signed int d; /* Decision Variable */
uint32_t dwCurX; /* Current X Value */
uint32_t dwCurY; /* Current Y Value */
uint32_t dwXmin, dwYmin;
if (ul_r == 0) {
return 1;
}
d = 3 - (ul_r << 1);
dwCurX = 0;
dwCurY = ul_r;
while (dwCurX <= dwCurY) {
dwXmin = (dwCurX > ul_x) ? 0 : ul_x - dwCurX;
dwYmin = (dwCurY > ul_y) ? 0 : ul_y - dwCurY;
ili93xx_draw_filled_rectangle(dwXmin, dwYmin, ul_x + dwCurX,
dwYmin);
ili93xx_draw_filled_rectangle(dwXmin, ul_y + dwCurY,
ul_x + dwCurX, ul_y + dwCurY);
dwXmin = (dwCurY > ul_x) ? 0 : ul_x - dwCurY;
dwYmin = (dwCurX > ul_y) ? 0 : ul_y - dwCurX;
ili93xx_draw_filled_rectangle(dwXmin, dwYmin, ul_x + dwCurY,
dwYmin);
ili93xx_draw_filled_rectangle(dwXmin, ul_y + dwCurX,
ul_x + dwCurY, ul_y + dwCurX);
if (d < 0) {
d += (dwCurX << 2) + 6;
} else {
d += ((dwCurX - dwCurY) << 2) + 10;
dwCurY--;
}
dwCurX++;
}
return 0;
}
/**
* \brief Draw an ASCII character on LCD.
*
* \param ul_x X coordinate of character upper-left corner.
* \param ul_y Y coordinate of character upper-left corner.
* \param uc_c character to print.
*/
static void ili93xx_draw_char(uint32_t ul_x, uint32_t ul_y, uint8_t uc_c)
{
uint32_t row, col;
uint32_t offset, offset0, offset1;
/**
* Compute offset according of the specified ASCII character
* Note: the first 32 characters of the ASCII table are not handled
*/
offset = ((uint32_t)uc_c - 0x20) * 20;
for (col = 0; col < 10; col++) {
/** Compute the first and second byte offset of a column */
offset0 = offset + col * 2;
offset1 = offset0 + 1;
/**
* Draw pixel on screen depending on the corresponding bit value
* from the charset
*/
for (row = 0; row < 8; row++) {
if ((p_uc_charset10x14[offset0] >> (7 - row)) & 0x1) {
ili93xx_draw_pixel(ul_x + col, ul_y + row);
}
}
for (row = 0; row < 6; row++) {
if ((p_uc_charset10x14[offset1] >> (7 - row)) & 0x1) {
ili93xx_draw_pixel(ul_x + col, ul_y + row + 8);
}
}
}
}
/**
* \brief Draw a string on LCD.
*
* \param ul_x X coordinate of string top-left corner.
* \param ul_y Y coordinate of string top-left corner.
* \param p_str String to display.
*/
void ili93xx_draw_string(uint32_t ul_x, uint32_t ul_y, const uint8_t *p_str)
{
uint32_t xorg = ul_x;
while (*p_str != 0) {
/** If newline, jump to the next line (font height + 2) */
if (*p_str == '\n') {
ul_y += gfont.height + 2;
ul_x = xorg;
} else {
/**
* Draw the character and place cursor right after (font
* width + 2)
*/
ili93xx_draw_char(ul_x, ul_y, *p_str);
ul_x += gfont.width + 2;
}
p_str++;
}
}
/**
* \brief Draw a pixmap on LCD.
*
* \param ul_x X coordinate of upper-left corner on LCD.
* \param ul_y Y coordinate of upper-left corner on LCD.
* \param ul_width width of the picture.
* \param ul_height height of the picture.
* \param p_ul_pixmap pixmap of the image.
*/
void ili93xx_draw_pixmap(uint32_t ul_x, uint32_t ul_y, uint32_t ul_width,
uint32_t ul_height, const ili93xx_color_t *p_ul_pixmap)
{
uint32_t size;
uint32_t dwX1, dwY1, dwX2, dwY2;
dwX1 = ul_x;
dwY1 = ul_y;
dwX2 = ul_x + ul_width;
dwY2 = ul_y + ul_height;
/** Swap coordinates if necessary */
ili93xx_check_box_coordinates(&dwX1, &dwY1, &dwX2, &dwY2);
/** Determine the refresh window area */
ili93xx_set_window(dwX1, dwY1, (dwX2 - dwX1 + 1), (dwY2 - dwY1 + 1));
if (g_uc_device_type == DEVICE_TYPE_ILI9325) {
/** Set cursor */
ili93xx_set_cursor_position(dwX1, dwY1);
/** Prepare to write in GRAM */
ili93xx_write_ram_prepare();
size = (dwX2 - dwX1) * (dwY2 - dwY1);
ili93xx_write_ram_buffer(p_ul_pixmap, size);
/** Reset the refresh window area */
ili93xx_set_window(0, 0, g_ul_lcd_x_length, g_ul_lcd_y_length);
} else if (g_uc_device_type == DEVICE_TYPE_ILI9341) {
/** Prepare to write in GRAM */
ili93xx_write_ram_prepare();
size = (dwX2 - dwX1) * (dwY2 - dwY1);
ili93xx_write_ram_buffer(p_ul_pixmap, size);
/** Reset the refresh window area */
ili93xx_set_window(0, 0, g_ul_lcd_x_length, g_ul_lcd_y_length);
}
}
/**
* \internal
* \brief Helper function to send the drawing limits (boundaries) to the display
*
* This function is used to send the currently set upper-left and lower-right
* drawing limits to the display, as set through the various limit functions.
*
* \param send_end_limits True to also send the lower-right drawing limits
*/
static inline void ili93xx_send_draw_limits(const bool send_end_limits)
{
if (g_uc_device_type == DEVICE_TYPE_ILI9325) {
/** Set Horizontal Address Start Position */
ili93xx_write_register_word(ILI9325_HORIZONTAL_ADDR_START,
(uint16_t)limit_start_x);
if (send_end_limits) {
/** Set Horizontal Address End Position */
ili93xx_write_register_word(ILI9325_HORIZONTAL_ADDR_END,
(uint16_t)(limit_end_x));
}
/** Set Vertical Address Start Position */
ili93xx_write_register_word(ILI9325_VERTICAL_ADDR_START,
(uint16_t)limit_start_y);
if (send_end_limits) {
/** Set Vertical Address End Position */
ili93xx_write_register_word(ILI9325_VERTICAL_ADDR_END,
(uint16_t)(limit_end_y));
}
/** GRAM Horizontal/Vertical Address Set (R20h, R21h) */
ili93xx_write_register_word(ILI9325_HORIZONTAL_GRAM_ADDR_SET,
limit_start_x);
ili93xx_write_register_word(ILI9325_VERTICAL_GRAM_ADDR_SET,
limit_start_y);
} else if (g_uc_device_type == DEVICE_TYPE_ILI9341) {
/** Set Horizontal Address Start Position */
ili93xx_write_register_word(ILI9341_CMD_COLUMN_ADDRESS_SET,
(uint16_t)limit_start_x);
if (send_end_limits) {
/** Set Horizontal Address End Position */
ili93xx_write_register_word(
ILI9341_CMD_COLUMN_ADDRESS_SET,
(uint16_t)(limit_end_x));
}
ili93xx_write_register(0, NULL, 0);
/** Set Vertical Address Start Position */
ili93xx_write_register_word(ILI9341_CMD_PAGE_ADDRESS_SET,
(uint16_t)limit_start_y);
if (send_end_limits) {
/** Set Vertical Address End Position */
ili93xx_write_register_word(
ILI9341_CMD_PAGE_ADDRESS_SET,
(uint16_t)(limit_end_y));
}
ili93xx_write_register(0, NULL, 0);
}
}
/**
* \brief Set the display top left drawing limit
*
* Use this function to set the top left limit of the drawing limit box.
*
* \param x The x coordinate of the top left corner
* \param y The y coordinate of the top left corner
*/
void ili93xx_set_top_left_limit(ili93xx_coord_t x, ili93xx_coord_t y)
{
limit_start_x = x;
limit_start_y = y;
ili93xx_send_draw_limits(false);
}
/**
* \brief Set the display bottom right drawing limit
*
* Use this function to set the bottom right corner of the drawing limit box.
*
* \param x The x coordinate of the bottom right corner
* \param y The y coordinate of the bottom right corner
*/
void ili93xx_set_bottom_right_limit(ili93xx_coord_t x, ili93xx_coord_t y)
{
limit_end_x = x;
limit_end_y = y;
ili93xx_send_draw_limits(true);
}
/**
* \brief Set the full display drawing limits
*
* Use this function to set the full drawing limit box.
*
* \param start_x The x coordinate of the top left corner
* \param start_y The y coordinate of the top left corner
* \param end_x The x coordinate of the bottom right corner
* \param end_y The y coordinate of the bottom right corner
*/
void ili93xx_set_limits(ili93xx_coord_t start_x, ili93xx_coord_t start_y,
ili93xx_coord_t end_x, ili93xx_coord_t end_y)
{
limit_start_x = start_x;
limit_start_y = start_y;
limit_end_x = end_x;
limit_end_y = end_y;
ili93xx_send_draw_limits(true);
}
/**
* \brief Read a single color from the graphical memory
*
* Use this function to read a color from the graphical memory of the
* controller.
*
* \retval ili93xx_color_t The read color pixel
*/
ili93xx_color_t ili93xx_read_gram(void)
{
uint8_t value[3];
ili93xx_color_t color;
if (g_uc_device_type == DEVICE_TYPE_ILI9325) {
LCD_IR(0);
/** Write Data to GRAM (R22h) */
LCD_IR(ILI9325_GRAM_DATA_REG);
/** two dummy read */
value[0] = LCD_RD();
value[1] = LCD_RD();
/** data upper byte */
value[0] = LCD_RD();
/** data lower byte */
value[1] = LCD_RD();
/** Convert RGB565 to RGB888 */
/** For BGR format */
color = ((value[0] & 0xF8)) |
((value[0] & 0x07) << 13) | ((value[1] & 0xE0) << 5) |
((value[1] & 0x1F) << 19);
} else if (g_uc_device_type == DEVICE_TYPE_ILI9341) {
LCD_IR(0);
/** Write Data to GRAM (R2Eh) */
LCD_IR(ILI9341_CMD_MEMORY_READ);
/** dummy read */
value[0] = LCD_RD();
/** the highest byte - R byte*/
value[0] = LCD_RD();
/** the middle byte - G byte*/
value[1] = LCD_RD();
/** the lowest byte - B byte*/
value[2] = LCD_RD();
/** combine R, G, B byte to a color value */
color = (value[0] << 16) | (value[1] << 8) | value[2];
}
return color;
}
/**
* \brief Write the graphical memory with a single color pixel
*
* Use this function to write a single color pixel to the controller memory.
*
* \param color The color pixel to write to the screen
*/
void ili93xx_write_gram(ili93xx_color_t color)
{
if (g_uc_device_type == DEVICE_TYPE_ILI9325) {
LCD_IR(0);
/** Write Data to GRAM (R22h) */
LCD_IR(ILI9325_GRAM_DATA_REG);
} else if (g_uc_device_type == DEVICE_TYPE_ILI9341) {
/** memory write command (R2Ch)*/
LCD_IR(ILI9341_CMD_MEMORY_WRITE);
LCD_IR(0);
LCD_IR(ILI9341_CMD_WRITE_MEMORY_CONTINUE);
}
LCD_WD((color >> 16) & 0xFF);
LCD_WD((color >> 8) & 0xFF);
LCD_WD(color & 0xFF);
}
/**
* \brief Copy pixels from SRAM to the screen
*
* Used to copy a large quantitative of data to the screen in one go.
*
* \param pixels Pointer to the pixel data
* \param count Number of pixels to copy to the screen
*/
void ili93xx_copy_pixels_to_screen(const ili93xx_color_t *pixels,
uint32_t count)
{
/** Sanity check to make sure that the pixel count is not zero */
Assert(count > 0);
if (g_uc_device_type == DEVICE_TYPE_ILI9325) {
LCD_IR(0);
LCD_IR(ILI9325_GRAM_DATA_REG);
} else if (g_uc_device_type == DEVICE_TYPE_ILI9341) {
LCD_IR(ILI9341_CMD_MEMORY_WRITE);
LCD_IR(0);
LCD_IR(ILI9341_CMD_WRITE_MEMORY_CONTINUE);
}
while (count--) {
LCD_WD((*pixels >> 16) & 0xFF);
LCD_WD((*pixels >> 8) & 0xFF);
LCD_WD(*pixels & 0xFF);
pixels++;
}
}
/**
* \brief Copy pixels from SRAM to the screen
*
* Used to copy a large quantitative of data to the screen in one go.
*
* \param pixels Pointer to the pixel data
* \param count Number of pixels to copy to the screen
*/
void ili93xx_copy_raw_pixel_24bits_to_screen(const uint8_t *raw_pixels,
uint32_t count)
{
ili93xx_color_t pixels;
/** Sanity check to make sure that the pixel count is not zero */
Assert(count > 0);
if (g_uc_device_type == DEVICE_TYPE_ILI9325) {
LCD_IR(0);
LCD_IR(ILI9325_GRAM_DATA_REG);
} else if (g_uc_device_type == DEVICE_TYPE_ILI9341) {
LCD_IR(ILI9341_CMD_MEMORY_WRITE);
LCD_IR(0);
LCD_IR(ILI9341_CMD_WRITE_MEMORY_CONTINUE);
}
while (count--) {
pixels = (*raw_pixels) |
(*(raw_pixels +1)) << 8 |
(*(raw_pixels + 2)) << 16;
LCD_WD((pixels >> 16) & 0xFF);
LCD_WD((pixels >> 8) & 0xFF);
LCD_WD(pixels & 0xFF);
raw_pixels += 3;
}
}
/**
* \brief Set a given number of pixels to the same color
*
* Use this function to write a certain number of pixels to the same color
* within a set limit.
*
* \param color The color to write to the display
* \param count The number of pixels to write with this color
*/
void ili93xx_duplicate_pixel(const ili93xx_color_t color, uint32_t count)
{
/** Sanity check to make sure that the pixel count is not zero */
Assert(count > 0);
if (g_uc_device_type == DEVICE_TYPE_ILI9325) {
/** Write Data to GRAM (R22h) */
LCD_IR(0);
LCD_IR(ILI9325_GRAM_DATA_REG);
} else if (g_uc_device_type == DEVICE_TYPE_ILI9341) {
LCD_IR(ILI9341_CMD_MEMORY_WRITE);
LCD_IR(0);
LCD_IR(ILI9341_CMD_WRITE_MEMORY_CONTINUE);
}
while (count--) {
LCD_WD((color >> 16) & 0xFF);
LCD_WD((color >> 8) & 0xFF);
LCD_WD(color & 0xFF);
}
}
/**
* \brief Copy pixels from the screen to a pixel buffer
*
* Use this function to copy pixels from the display to an internal SRAM buffer.
*
* \param pixels Pointer to the pixel buffer to read to
* \param count Number of pixels to read
*/
void ili93xx_copy_pixels_from_screen(ili93xx_color_t *pixels, uint32_t count)
{
/** Remove warnings */
UNUSED(pixels);
UNUSED(count);
}
/**
* \}
*/