334 lines
7.5 KiB
C++
334 lines
7.5 KiB
C++
/*
|
|
* Copyright (C) EdgeTX
|
|
*
|
|
* Based on code named
|
|
* opentx - https://github.com/opentx/opentx
|
|
* th9x - http://code.google.com/p/th9x
|
|
* er9x - http://code.google.com/p/er9x
|
|
* gruvin9x - http://code.google.com/p/gruvin9x
|
|
*
|
|
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*/
|
|
|
|
#include "lcd_driver.h"
|
|
|
|
#include "stm32_gpio.h"
|
|
#include "stm32_spi.h"
|
|
|
|
#include "delays_driver.h"
|
|
#include "hal/gpio.h"
|
|
#include "lcd.h"
|
|
|
|
#include "hal.h"
|
|
#include "board.h"
|
|
|
|
#define LCD_NRST_HIGH() gpio_set(LCD_NRST)
|
|
#define LCD_NRST_LOW() gpio_clear(LCD_NRST)
|
|
#define LCD_COMMAND_MODE() gpio_clear(LCD_SPI_RS)
|
|
#define LCD_DATA_MODE() gpio_set(LCD_SPI_RS)
|
|
|
|
#define CASET 0x2A
|
|
#define RASET 0x2B
|
|
#define RAMWR 0x2C
|
|
|
|
static const stm32_spi_t lcdSpi = {
|
|
.SPIx = LCD_SPI,
|
|
.SCK = LCD_SPI_CLK,
|
|
.MISO = LCD_SPI_MISO,
|
|
.MOSI = LCD_SPI_MOSI,
|
|
.CS = LCD_SPI_CS,
|
|
.DMA = LCD_SPI_DMA,
|
|
.txDMA_PeriphRequest = LCD_SPI_TX_DMA,
|
|
.rxDMA_PeriphRequest = LCD_SPI_RX_DMA,
|
|
.txDMA_Stream = LCD_SPI_TX_DMA_STREAM,
|
|
.rxDMA_Stream = LCD_SPI_RX_DMA_STREAM,
|
|
};
|
|
|
|
static void* initialFrameBuffer = nullptr;
|
|
|
|
static void write_start_end(uint8_t cmd, uint16_t start, uint16_t end)
|
|
{
|
|
// big endian format
|
|
uint8_t buf[4] = {
|
|
(uint8_t)(start >> 8),
|
|
(uint8_t)(start & 0xFF),
|
|
(uint8_t)(end >> 8),
|
|
(uint8_t)(end & 0xFF),
|
|
};
|
|
|
|
stm32_spi_select(&lcdSpi);
|
|
|
|
LCD_COMMAND_MODE();
|
|
stm32_spi_transfer_byte(&lcdSpi, cmd);
|
|
|
|
LCD_DATA_MODE();
|
|
stm32_spi_transfer_bytes(&lcdSpi, (uint8_t *)buf, nullptr, sizeof(buf));
|
|
|
|
stm32_spi_unselect(&lcdSpi);
|
|
}
|
|
|
|
static inline void set_column_addr(uint16_t xs, uint16_t xe)
|
|
{
|
|
write_start_end(CASET, xs, xe);
|
|
}
|
|
|
|
static inline void set_row_addr(uint16_t ys, uint16_t ye)
|
|
{
|
|
write_start_end(RASET, ys, ye);
|
|
}
|
|
|
|
static void memory_write(const uint16_t* data, uint32_t length)
|
|
{
|
|
stm32_spi_select(&lcdSpi);
|
|
|
|
LCD_COMMAND_MODE();
|
|
stm32_spi_transfer_byte(&lcdSpi, RAMWR);
|
|
|
|
LCD_DATA_MODE();
|
|
stm32_spi_set_data_width(&lcdSpi, LL_SPI_DATAWIDTH_16BIT);
|
|
|
|
SCB_CleanDCache_by_Addr((void *)data, length * sizeof(uint16_t));
|
|
stm32_spi_dma_transmit_words(&lcdSpi, data, length);
|
|
|
|
stm32_spi_unselect(&lcdSpi);
|
|
stm32_spi_set_data_width(&lcdSpi, LL_SPI_DATAWIDTH_8BIT);
|
|
}
|
|
|
|
static void startLcdRefresh(lv_disp_drv_t *disp_drv, uint16_t *buffer,
|
|
const rect_t ©_area)
|
|
{
|
|
(void)disp_drv;
|
|
|
|
// TODO: replace through some smarter mechanism without busy wait
|
|
while (!gpio_read(LCD_FMARK));
|
|
|
|
coord_t x1 = copy_area.x;
|
|
coord_t x2 = x1 + copy_area.w - 1;
|
|
set_column_addr(x1, x2);
|
|
|
|
coord_t y1 = copy_area.y;
|
|
coord_t y2 = y1 + copy_area.h - 1;
|
|
set_row_addr(y1, y2);
|
|
|
|
memory_write(buffer, copy_area.w * copy_area.h);
|
|
}
|
|
|
|
lcdSpiInitFucPtr lcdInitFunction;
|
|
lcdSpiInitFucPtr lcdOffFunction;
|
|
lcdSpiInitFucPtr lcdOnFunction;
|
|
uint32_t lcdPixelClock;
|
|
|
|
static void lcdSpiConfig(void)
|
|
{
|
|
stm32_spi_init(&lcdSpi, LL_SPI_DATAWIDTH_8BIT);
|
|
stm32_spi_set_max_baudrate(&lcdSpi, LCD_SPI_BAUD);
|
|
|
|
gpio_init(LCD_FMARK, GPIO_IN, GPIO_PIN_SPEED_HIGH);
|
|
gpio_init(LCD_NRST, GPIO_OUT, GPIO_PIN_SPEED_HIGH);
|
|
gpio_init(LCD_SPI_RS, GPIO_OUT, GPIO_PIN_SPEED_HIGH);
|
|
}
|
|
|
|
void lcdDelay() {
|
|
delay_01us(1);
|
|
}
|
|
|
|
static void lcdReset() {
|
|
LCD_NRST_HIGH();
|
|
delay_ms(1);
|
|
|
|
LCD_NRST_LOW(); // RESET();
|
|
delay_ms(100);
|
|
|
|
LCD_NRST_HIGH();
|
|
delay_ms(120);
|
|
}
|
|
|
|
static void lcdWriteCommand(uint8_t cmd)
|
|
{
|
|
LCD_COMMAND_MODE();
|
|
stm32_spi_select(&lcdSpi);
|
|
stm32_spi_transfer_byte(&lcdSpi, cmd);
|
|
stm32_spi_unselect(&lcdSpi);
|
|
}
|
|
|
|
// static void lcdWriteReg(uint8_t reg, uint8_t data)
|
|
// {
|
|
// LCD_COMMAND_MODE();
|
|
// stm32_spi_select(&lcdSpi);
|
|
// stm32_spi_transfer_byte(&lcdSpi, reg);
|
|
// LCD_DATA_MODE();
|
|
// stm32_spi_transfer_byte(&lcdSpi, data);
|
|
// stm32_spi_unselect(&lcdSpi);
|
|
// }
|
|
|
|
static void lcdWriteData(uint8_t data)
|
|
{
|
|
LCD_DATA_MODE();
|
|
stm32_spi_select(&lcdSpi);
|
|
stm32_spi_transfer_byte(&lcdSpi, data);
|
|
stm32_spi_unselect(&lcdSpi);
|
|
}
|
|
|
|
// static uint8_t lcdReadReg(uint8_t reg)
|
|
// {
|
|
// uint8_t data = 0;
|
|
// LCD_COMMAND_MODE();
|
|
// stm32_spi_select(&lcdSpi);
|
|
// stm32_spi_transfer_byte(&lcdSpi, reg);
|
|
// LCD_DATA_MODE();
|
|
// data = stm32_spi_transfer_byte(&lcdSpi, 0xFF);
|
|
// stm32_spi_unselect(&lcdSpi);
|
|
// return data;
|
|
// }
|
|
|
|
extern "C" void lcdSetInitalFrameBuffer(void *fbAddress)
|
|
{
|
|
initialFrameBuffer = fbAddress;
|
|
}
|
|
|
|
static void lcdSetOn(void) { lcdWriteCommand(0x29); }
|
|
static void lcdSetOff(void) { lcdWriteCommand(0x28); }
|
|
|
|
extern "C" void lcdInit()
|
|
{
|
|
// Configure the LCD SPI + RESET pins
|
|
lcdSpiConfig();
|
|
stm32_spi_unselect(&lcdSpi);
|
|
|
|
// hard reset
|
|
lcdReset();
|
|
|
|
// Init command start
|
|
lcdWriteCommand( 0xFE );
|
|
lcdWriteCommand( 0xEF );
|
|
|
|
// Display orientation
|
|
lcdWriteCommand( 0x36 );
|
|
lcdWriteData( 0xE8 );
|
|
|
|
// Color mode
|
|
lcdWriteCommand( 0x3A );
|
|
lcdWriteData( 0x05 ); // 16-bit color
|
|
|
|
// Display control
|
|
lcdWriteCommand( 0x86 );
|
|
lcdWriteData( 0x98 );
|
|
lcdWriteCommand( 0x89 );
|
|
lcdWriteData( 0x13 );
|
|
lcdWriteCommand( 0x8B );
|
|
lcdWriteData( 0x80 );
|
|
lcdWriteCommand( 0x8D );
|
|
lcdWriteData( 0x33 );
|
|
lcdWriteCommand( 0x8E );
|
|
lcdWriteData( 0x0F );
|
|
|
|
lcdWriteCommand( 0xEC );
|
|
lcdWriteData( 0x13 );
|
|
lcdWriteData( 0x02 );
|
|
lcdWriteData( 0x88 );
|
|
|
|
lcdWriteCommand( 0xED );
|
|
lcdWriteData( 0x18 );
|
|
lcdWriteData( 0x08 );
|
|
|
|
lcdWriteCommand( 0xE8 );
|
|
lcdWriteData( 0x12 );
|
|
lcdWriteData( 0x00 );
|
|
|
|
// Init command ends
|
|
lcdWriteCommand( 0xFF );
|
|
lcdWriteCommand( 0x62 );
|
|
|
|
// Display control
|
|
lcdWriteCommand( 0x99 );
|
|
lcdWriteData( 0x3E );
|
|
lcdWriteCommand( 0x9D );
|
|
lcdWriteData( 0x4B );
|
|
lcdWriteCommand( 0x98 );
|
|
lcdWriteData( 0x3E );
|
|
lcdWriteCommand( 0x9C );
|
|
lcdWriteData( 0x4B );
|
|
lcdWriteCommand( 0xC3 );
|
|
lcdWriteData( 0x27 );
|
|
lcdWriteCommand( 0xC4 );
|
|
lcdWriteData( 0x18 );
|
|
lcdWriteCommand( 0xC9 );
|
|
lcdWriteData( 0x0A );
|
|
|
|
// Gamma Control
|
|
lcdWriteCommand( 0xF0 );
|
|
lcdWriteData( 0x85 );
|
|
lcdWriteData( 0x0A );
|
|
lcdWriteData( 0x09 );
|
|
lcdWriteData( 0x08 );
|
|
lcdWriteData( 0x04 );
|
|
lcdWriteData( 0x30 );
|
|
lcdWriteCommand( 0xF1);
|
|
lcdWriteData( 0x47 );
|
|
lcdWriteData( 0x5B );
|
|
lcdWriteData( 0xB0 );
|
|
lcdWriteData( 0x3A );
|
|
lcdWriteData( 0x3E );
|
|
lcdWriteData( 0x7F );
|
|
lcdWriteCommand( 0xF2 );
|
|
lcdWriteData( 0x85 );
|
|
lcdWriteData( 0x0A );
|
|
lcdWriteData( 0x09 );
|
|
lcdWriteData( 0x08 );
|
|
lcdWriteData( 0x04 );
|
|
lcdWriteData( 0x30 );
|
|
lcdWriteCommand( 0xF3 );
|
|
lcdWriteData( 0x47 );
|
|
lcdWriteData( 0x5B );
|
|
lcdWriteData( 0xB0 );
|
|
lcdWriteData( 0x3A );
|
|
lcdWriteData( 0x3F );
|
|
lcdWriteData( 0x7F );
|
|
|
|
// Display size
|
|
lcdWriteCommand( 0x2A );
|
|
lcdWriteData( 0x00 );
|
|
lcdWriteData( 0x00 );
|
|
lcdWriteData( 0x01 );
|
|
lcdWriteData( 0x40 );
|
|
lcdWriteCommand( 0x2B );
|
|
lcdWriteData( 0x00 );
|
|
lcdWriteData( 0x00 );
|
|
lcdWriteData( 0x00 );
|
|
lcdWriteData( 0xF0 );
|
|
|
|
// No, invert color
|
|
lcdWriteCommand( 0x20 );
|
|
|
|
// Tear on
|
|
lcdWriteCommand( 0x35 );
|
|
lcdWriteData( 0x00 );
|
|
|
|
// Tearing scan line
|
|
lcdWriteCommand( 0x44 );
|
|
lcdWriteData( 0x00 );
|
|
lcdWriteData( 0x0A );
|
|
|
|
// Exit sleep
|
|
lcdWriteCommand( 0x11 );
|
|
|
|
// Init LCD RAM
|
|
memory_write((const uint16_t*)initialFrameBuffer, LCD_W * LCD_H);
|
|
|
|
lcdSetOn();
|
|
|
|
lcdOnFunction = lcdSetOn;
|
|
lcdOffFunction = lcdSetOff;
|
|
|
|
lcdSetFlushCb(startLcdRefresh);
|
|
}
|