451 lines
9.7 KiB
C
451 lines
9.7 KiB
C
/*
|
|
* ili9341.c
|
|
*
|
|
* Created on: 2019/12/26
|
|
* Author: Kotetsu Yamamoto
|
|
* Copyright [Kotetsu Yamamoto]
|
|
|
|
I refer https://github.com/dtnghia2206/TFTLCD/blob/master/TFTLCD/ILI9341/ILI9341_Driver.c
|
|
|
|
from Original source:
|
|
|
|
MIT License
|
|
|
|
Copyright (c) 2019 NghiaDT
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in all
|
|
copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
SOFTWARE.
|
|
|
|
*/
|
|
|
|
#include "st7789v.h"
|
|
#include "main.h" // Hardware setting
|
|
|
|
// This function is for compatible HiLetgo ILI9341
|
|
|
|
typedef enum {
|
|
ROTATE_0,
|
|
ROTATE_90,
|
|
ROTATE_180,
|
|
ROTATE_270
|
|
} LCD_Horizontal_t;
|
|
|
|
extern void Error_Handler(void);
|
|
extern SPI_HandleTypeDef hspi1;
|
|
static __IO uint8_t spiDmaTransferComplete;
|
|
|
|
void ILI9341_Reset(void);
|
|
void ILI9341_SoftReset(void);
|
|
|
|
void LCD_WR_REG(uint8_t data);
|
|
static void LCD_WR_DATA(uint8_t data);
|
|
static void LCD_direction(LCD_Horizontal_t direction);
|
|
static void RESET_L(void);
|
|
static void RESET_H(void);
|
|
static void CS_L(void);
|
|
static void CS_H(void);
|
|
static void DC_L(void);
|
|
static void DC_H(void);
|
|
|
|
// Initialization
|
|
void ILI9341_Init(void) //Changed
|
|
{
|
|
ILI9341_Reset();
|
|
ILI9341_SoftReset();
|
|
HAL_Delay(120);
|
|
LCD_WR_REG(0x11); //Sleep Out
|
|
HAL_Delay(120);
|
|
|
|
//-----------------------ST7789V Frame rate setting-----------------//
|
|
//************************************************
|
|
LCD_WR_REG(0x3A); //65k mode
|
|
LCD_WR_DATA(0x05);
|
|
LCD_WR_REG(0xC5); //VCOM
|
|
LCD_WR_DATA(0x1A);
|
|
LCD_WR_REG(0x36); //According to the original source
|
|
LCD_WR_DATA(0x20);
|
|
//-------------ST7789V Frame rate setting-----------//
|
|
LCD_WR_REG(0xb2); //Porch Setting
|
|
LCD_WR_DATA(0x05);
|
|
LCD_WR_DATA(0x05);
|
|
LCD_WR_DATA(0x00);
|
|
LCD_WR_DATA(0x33);
|
|
LCD_WR_DATA(0x33);
|
|
|
|
//LCD_WR_REG(0xb7); //Gate Control
|
|
//LCD_WR_DATA(0x05); //12.2v -10.43v //TODO 21.05.2023 For my display
|
|
|
|
//--------------ST7789V Power setting---------------//
|
|
LCD_WR_REG(0xBB);//VCOM
|
|
LCD_WR_DATA(0x3F);
|
|
|
|
LCD_WR_REG(0xC0); //Power control
|
|
LCD_WR_DATA(0x2c);
|
|
|
|
LCD_WR_REG(0xC2); //VDV and VRH Command Enable
|
|
LCD_WR_DATA(0x01);
|
|
|
|
LCD_WR_REG(0xC3); //VRH Set
|
|
LCD_WR_DATA(0x0F); //4.3+( vcom+vcom offset+vdv)
|
|
|
|
LCD_WR_REG(0xC4); //VDV Set
|
|
LCD_WR_DATA(0x20); //0v
|
|
|
|
LCD_WR_REG(0xC6); //Frame Rate Control in Normal Mode
|
|
LCD_WR_DATA(0X01); //111Hz
|
|
|
|
LCD_WR_REG(0xd0); //Power Control 1
|
|
LCD_WR_DATA(0xa4);
|
|
LCD_WR_DATA(0xa1);
|
|
|
|
LCD_WR_REG(0xE8); //Power Control 1
|
|
LCD_WR_DATA(0x03);
|
|
|
|
LCD_WR_REG(0xE9); //Equalize time control
|
|
LCD_WR_DATA(0x09);
|
|
LCD_WR_DATA(0x09);
|
|
LCD_WR_DATA(0x08);
|
|
|
|
//---------------ST7789V gamma setting-------------//
|
|
#if 1 // new
|
|
LCD_WR_REG(ILI9341_GAMMASET);
|
|
LCD_WR_DATA(0x01);
|
|
|
|
|
|
LCD_WR_REG(ILI9341_GMCTRP1);
|
|
LCD_WR_DATA(0x0F);
|
|
LCD_WR_DATA(0x31);
|
|
LCD_WR_DATA(0x2B);
|
|
LCD_WR_DATA(0x0C);
|
|
LCD_WR_DATA(0x0E);
|
|
LCD_WR_DATA(0x08);
|
|
LCD_WR_DATA(0x4E);
|
|
LCD_WR_DATA(0xF1);
|
|
LCD_WR_DATA(0x37);
|
|
LCD_WR_DATA(0x07);
|
|
LCD_WR_DATA(0x10);
|
|
LCD_WR_DATA(0x03);
|
|
LCD_WR_DATA(0x0E);
|
|
LCD_WR_DATA(0x09);
|
|
LCD_WR_DATA(0x00);
|
|
|
|
LCD_WR_REG(ILI9341_GMCTRN1);
|
|
LCD_WR_DATA(0x00);
|
|
LCD_WR_DATA(0x0E);
|
|
LCD_WR_DATA(0x14);
|
|
LCD_WR_DATA(0x03);
|
|
LCD_WR_DATA(0x11);
|
|
LCD_WR_DATA(0x07);
|
|
LCD_WR_DATA(0x31);
|
|
LCD_WR_DATA(0xC1);
|
|
LCD_WR_DATA(0x48);
|
|
LCD_WR_DATA(0x08);
|
|
LCD_WR_DATA(0x0F);
|
|
LCD_WR_DATA(0x0C);
|
|
LCD_WR_DATA(0x31);
|
|
LCD_WR_DATA(0x36);
|
|
LCD_WR_DATA(0x0F);
|
|
|
|
#else
|
|
|
|
LCD_WR_REG(0xE0); //Set Gamma
|
|
LCD_WR_DATA(0xD0);
|
|
LCD_WR_DATA(0x05);
|
|
LCD_WR_DATA(0x09);
|
|
LCD_WR_DATA(0x09);
|
|
LCD_WR_DATA(0x08);
|
|
LCD_WR_DATA(0x14);
|
|
LCD_WR_DATA(0x28);
|
|
LCD_WR_DATA(0x33);
|
|
LCD_WR_DATA(0x3F);
|
|
LCD_WR_DATA(0x07);
|
|
LCD_WR_DATA(0x13);
|
|
LCD_WR_DATA(0x14);
|
|
LCD_WR_DATA(0x28);
|
|
LCD_WR_DATA(0x30);
|
|
|
|
LCD_WR_REG(0XE1); //Set Gamma
|
|
LCD_WR_DATA(0xD0);
|
|
LCD_WR_DATA(0x05);
|
|
LCD_WR_DATA(0x09);
|
|
LCD_WR_DATA(0x09);
|
|
LCD_WR_DATA(0x08);
|
|
LCD_WR_DATA(0x03);
|
|
LCD_WR_DATA(0x24);
|
|
LCD_WR_DATA(0x32);
|
|
LCD_WR_DATA(0x32);
|
|
LCD_WR_DATA(0x3B);
|
|
LCD_WR_DATA(0x14);
|
|
LCD_WR_DATA(0x13);
|
|
LCD_WR_DATA(0x28);
|
|
LCD_WR_DATA(0x2F);
|
|
|
|
#endif
|
|
|
|
LCD_WR_REG(0x20); //destroy
|
|
|
|
LCD_WR_REG(0x29); // Display turn on
|
|
|
|
LCD_direction(ROTATE_90);
|
|
LCD_WR_REG(0x36);
|
|
LCD_WR_DATA(0x28 | 128 | 64);//(0x20);
|
|
LCD_WR_REG(0x21);
|
|
//-------------------------------
|
|
}
|
|
|
|
void ILI9341_SetWindow(uint16_t start_x, uint16_t start_y, uint16_t end_x, uint16_t end_y)
|
|
{
|
|
// Set Window
|
|
LCD_WR_REG(0x2a);
|
|
LCD_WR_DATA(start_x >> 8);
|
|
LCD_WR_DATA(0xFF & start_x);
|
|
LCD_WR_DATA(end_x >> 8);
|
|
LCD_WR_DATA(0xFF & end_x);
|
|
|
|
LCD_WR_REG(0x2b);
|
|
LCD_WR_DATA(start_y >> 8);
|
|
LCD_WR_DATA(0xFF & start_y);
|
|
LCD_WR_DATA(end_y >> 8);
|
|
LCD_WR_DATA(0xFF & end_y);
|
|
|
|
}
|
|
|
|
void ILI9341_WritePixel(uint16_t x, uint16_t y, uint16_t color)
|
|
{
|
|
uint8_t data[2];
|
|
data[0] = color >> 8;
|
|
data[1] = color;
|
|
ILI9341_SetWindow(x, y, x, y);
|
|
// Enable to access GRAM
|
|
LCD_WR_REG(0x2c);
|
|
DC_H();
|
|
if (HAL_SPI_Transmit(&hspi1, data, 2, 1000) != HAL_OK) {
|
|
Error_Handler();
|
|
}
|
|
}
|
|
|
|
static void ConvHL(uint8_t *s, int32_t l)
|
|
{
|
|
uint8_t v;
|
|
while (l > 0) {
|
|
v = *(s+1);
|
|
*(s+1) = *s;
|
|
*s = v;
|
|
s += 2;
|
|
l -= 2;
|
|
}
|
|
}
|
|
|
|
// Call this function after ILI9341_SetWindow
|
|
// This function is non blocked
|
|
// The variable for Callback is open. User should set by himself
|
|
void ILI9341_DrawBitmap(uint16_t w, uint16_t h, uint8_t *s)
|
|
{
|
|
// Enable to access GRAM
|
|
LCD_WR_REG(0x2c);
|
|
|
|
DC_H();
|
|
CS_L();
|
|
#if 0
|
|
__HAL_SPI_DISABLE(&hspi1);
|
|
hspi1.Instance->CR2 |= SPI_DATASIZE_16BIT; // Set 16 bit mode
|
|
__HAL_SPI_ENABLE(&hspi1);
|
|
#endif
|
|
ConvHL(s, (int32_t)w*h*2);
|
|
HAL_SPI_Transmit_DMA(&hspi1, (uint8_t*)s, w * h *2);
|
|
#if 0
|
|
__HAL_SPI_DISABLE(&hspi1);
|
|
hspi1.Instance->CR2 &= ~(SPI_DATASIZE_16BIT); // Set 8 bit mode
|
|
__HAL_SPI_ENABLE(&hspi1);
|
|
#endif
|
|
}
|
|
|
|
// User should call it at callback
|
|
void ILI9341_EndOfDrawBitmap(void)
|
|
{
|
|
#if 0
|
|
__HAL_SPI_DISABLE(&hspi1);
|
|
hspi1.Instance->CR2 &= ~(SPI_DATASIZE_16BIT); // Set 8 bit mode
|
|
__HAL_SPI_ENABLE(&hspi1);
|
|
#endif
|
|
}
|
|
|
|
void ILI9341_Reset(void)
|
|
{
|
|
RESET_L();
|
|
HAL_Delay(50);
|
|
RESET_H();
|
|
HAL_Delay(10);
|
|
}
|
|
|
|
void ILI9341_SoftReset(void)
|
|
{
|
|
uint8_t cmd;
|
|
cmd = 0x01; //Software reset
|
|
DC_L();
|
|
CS_L();
|
|
if (HAL_SPI_Transmit(&hspi1, &cmd, 1, 1000) != HAL_OK) {
|
|
Error_Handler();
|
|
}
|
|
CS_H();
|
|
}
|
|
|
|
|
|
void LCD_WR_REG(uint8_t data) //Changed
|
|
{
|
|
DC_L();
|
|
CS_L();
|
|
if (HAL_SPI_Transmit(&hspi1, &data, 1, 1000) != HAL_OK) {
|
|
Error_Handler();
|
|
}
|
|
CS_H();
|
|
}
|
|
|
|
static void LCD_WR_DATA(uint8_t data) //Changed
|
|
{
|
|
DC_H();
|
|
CS_L();
|
|
if (HAL_SPI_Transmit(&hspi1, &data, 1, 1000) != HAL_OK) {
|
|
Error_Handler();
|
|
}
|
|
CS_H();
|
|
}
|
|
void TFT_clear(void) //Changed
|
|
{
|
|
unsigned int ROW,column;
|
|
LCD_WR_REG(0x2a); //Column address set
|
|
LCD_WR_DATA(0x00); //start column
|
|
LCD_WR_DATA(0x00);
|
|
LCD_WR_DATA(0x00); //end column
|
|
LCD_WR_DATA(0xF0);
|
|
|
|
LCD_WR_REG(0x2b); //Row address set
|
|
LCD_WR_DATA(0x00); //start row
|
|
LCD_WR_DATA(0x00);
|
|
LCD_WR_DATA(0x01); //end row
|
|
LCD_WR_DATA(0x40);
|
|
LCD_WR_REG(0x2C); //Memory write
|
|
for(ROW=0;ROW<320;ROW++) //ROW loop
|
|
{
|
|
|
|
for(column=0;column<240;column++) //column loop
|
|
{
|
|
|
|
LCD_WR_DATA(0xFF);
|
|
LCD_WR_DATA(0xFF);
|
|
}
|
|
}
|
|
}
|
|
void TFT_full(unsigned int color) //Changed
|
|
{
|
|
unsigned int ROW,column;
|
|
LCD_WR_REG(0x2a); //Column address set
|
|
LCD_WR_DATA(0x00); //start column
|
|
LCD_WR_DATA(0x00);
|
|
LCD_WR_DATA(0x01); //end column
|
|
LCD_WR_DATA(0x40);
|
|
|
|
LCD_WR_REG(0x2b); //Row address set
|
|
LCD_WR_DATA(0x00); //start row
|
|
LCD_WR_DATA(0x00);
|
|
LCD_WR_DATA(0x00); //end row
|
|
LCD_WR_DATA(0xF0);
|
|
LCD_WR_REG(0x2C); //Memory write
|
|
for(ROW=0;ROW<320;ROW++) //ROW loop
|
|
{
|
|
for(column=0;column<240 ;column++) //column loop
|
|
{
|
|
LCD_WR_DATA(color>>8);
|
|
LCD_WR_DATA(color);
|
|
}
|
|
}
|
|
}
|
|
|
|
void LCD_IO_WriteMultipleData(uint8_t *pData, uint32_t Size)
|
|
{
|
|
/* Swap endianes */
|
|
ConvHL(pData, (int32_t)Size*2);
|
|
|
|
DC_H();
|
|
// HAL_SPI_Transmit(&hspi1, (uint8_t*)pData, Size * 2, HAL_MAX_DELAY);
|
|
spiDmaTransferComplete = 0;
|
|
HAL_SPI_Transmit_DMA(&hspi1, pData, Size*2 );
|
|
//HAL_SPI_Transmit_DMA(&hspi1, (uint8_t*)pData, Size );
|
|
while(spiDmaTransferComplete == 0);
|
|
}
|
|
/*
|
|
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
|
|
{
|
|
spiDmaTransferComplete = 1;
|
|
}
|
|
*/
|
|
|
|
static void LCD_direction(LCD_Horizontal_t direction)
|
|
{
|
|
switch (direction) {
|
|
case ROTATE_0:
|
|
LCD_WR_REG(0x36);
|
|
LCD_WR_DATA(0x40);
|
|
break;
|
|
case ROTATE_90:
|
|
LCD_WR_REG(0x36);
|
|
LCD_WR_DATA(0x20);
|
|
break;
|
|
case ROTATE_180:
|
|
LCD_WR_REG(0x36);
|
|
LCD_WR_DATA(0x80);
|
|
break;
|
|
case ROTATE_270:
|
|
LCD_WR_REG(0x36);
|
|
LCD_WR_DATA(0xE0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void RESET_L(void)
|
|
{
|
|
HAL_GPIO_WritePin(RESET_GPIO_Port, RESET_Pin, GPIO_PIN_RESET);
|
|
}
|
|
|
|
static void RESET_H(void)
|
|
{
|
|
HAL_GPIO_WritePin(RESET_GPIO_Port, RESET_Pin, GPIO_PIN_SET);
|
|
}
|
|
|
|
static void CS_L(void)
|
|
{
|
|
HAL_GPIO_WritePin(SPI1_NSS_GPIO_Port, SPI1_NSS_Pin, GPIO_PIN_RESET);
|
|
}
|
|
|
|
static void CS_H(void)
|
|
{
|
|
HAL_GPIO_WritePin(SPI1_NSS_GPIO_Port, SPI1_NSS_Pin, GPIO_PIN_SET);
|
|
}
|
|
|
|
static void DC_L(void)
|
|
{
|
|
HAL_GPIO_WritePin(DC_GPIO_Port, DC_Pin, GPIO_PIN_RESET);
|
|
}
|
|
|
|
static void DC_H(void)
|
|
{
|
|
HAL_GPIO_WritePin(DC_GPIO_Port, DC_Pin, GPIO_PIN_SET);
|
|
}
|
|
|
|
|