|
|
|
@ -53,7 +53,7 @@ __IO DISP_MEM_TYPE *const DISPLAY_DATA_ADDRESS =
|
|
|
|
|
(__IO DISP_MEM_TYPE *const)((uint32_t)DISPLAY_MEMORY_BASE |
|
|
|
|
|
(DISPLAY_ADDR_SHIFT << DISPLAY_MEMORY_PIN));
|
|
|
|
|
#define LED_PWM_TIM_PERIOD \
|
|
|
|
|
(255) // little less than 4kHz with PSC = (SystemCoreClock / 1000000) - 1)
|
|
|
|
|
(255) // little less than 50kHz with PSC = (SystemCoreClock / 12000000) - 1)
|
|
|
|
|
#define LED_PWM_SLOW_TIM_PERIOD \
|
|
|
|
|
(10000) // about 10Hz (with PSC = (SystemCoreClock / 1000000) - 1)
|
|
|
|
|
|
|
|
|
@ -72,9 +72,12 @@ __IO DISP_MEM_TYPE *const DISPLAY_DATA_ADDRESS =
|
|
|
|
|
static int DISPLAY_BACKLIGHT = -1;
|
|
|
|
|
static int DISPLAY_ORIENTATION = -1;
|
|
|
|
|
static int pwm_period = LED_PWM_TIM_PERIOD;
|
|
|
|
|
static buffer_offset_t BUFFER_OFFSET = {0};
|
|
|
|
|
|
|
|
|
|
void display_pixeldata(uint16_t c) { PIXELDATA(c); }
|
|
|
|
|
|
|
|
|
|
#ifdef DISPLAY_IDENTIFY
|
|
|
|
|
|
|
|
|
|
static uint32_t read_display_id(uint8_t command) {
|
|
|
|
|
volatile uint8_t c = 0;
|
|
|
|
|
uint32_t id = 0;
|
|
|
|
@ -110,6 +113,9 @@ static uint32_t display_identify(void) {
|
|
|
|
|
id_set = 1;
|
|
|
|
|
return id;
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
static uint32_t display_identify(void) { return DISPLAY_ID_ST7789V; }
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
bool display_is_inverted() {
|
|
|
|
|
bool inv_on = false;
|
|
|
|
@ -154,8 +160,6 @@ static void display_unsleep(void) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct { uint16_t x, y; } BUFFER_OFFSET;
|
|
|
|
|
|
|
|
|
|
void display_set_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) {
|
|
|
|
|
x0 += BUFFER_OFFSET.x;
|
|
|
|
|
x1 += BUFFER_OFFSET.x;
|
|
|
|
@ -188,70 +192,16 @@ int display_orientation(int degrees) {
|
|
|
|
|
// 2 bytes per pixel because we're using RGB 5-6-5 format
|
|
|
|
|
PIXELDATA(0x0000);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint16_t shift = 0;
|
|
|
|
|
char BX = 0, BY = 0;
|
|
|
|
|
#ifdef TREZOR_MODEL_T
|
|
|
|
|
uint32_t id = display_identify();
|
|
|
|
|
if ((id == DISPLAY_ID_ILI9341V) || (id == DISPLAY_ID_GC9307) ||
|
|
|
|
|
(id == DISPLAY_ID_ST7789V)) {
|
|
|
|
|
#define RGB (1 << 3)
|
|
|
|
|
#define ML (1 << 4) // vertical refresh order
|
|
|
|
|
#define MH (1 << 2) // horizontal refresh order
|
|
|
|
|
#define MV (1 << 5)
|
|
|
|
|
#define MX (1 << 6)
|
|
|
|
|
#define MY (1 << 7)
|
|
|
|
|
// MADCTL: Memory Data Access Control - reference:
|
|
|
|
|
// section 9.3 in the ILI9341 manual
|
|
|
|
|
// section 6.2.18 in the GC9307 manual
|
|
|
|
|
// section 8.12 in the ST7789V manual
|
|
|
|
|
uint8_t display_command_parameter = 0;
|
|
|
|
|
switch (degrees) {
|
|
|
|
|
case 0:
|
|
|
|
|
display_command_parameter = 0;
|
|
|
|
|
BY = (id == DISPLAY_ID_GC9307);
|
|
|
|
|
break;
|
|
|
|
|
case 90:
|
|
|
|
|
display_command_parameter = MV | MX | MH | ML;
|
|
|
|
|
BX = (id != DISPLAY_ID_GC9307);
|
|
|
|
|
shift = 1;
|
|
|
|
|
break;
|
|
|
|
|
case 180:
|
|
|
|
|
display_command_parameter = MX | MY | MH | ML;
|
|
|
|
|
BY = (id == DISPLAY_ID_GC9307);
|
|
|
|
|
shift = 1;
|
|
|
|
|
break;
|
|
|
|
|
case 270:
|
|
|
|
|
display_command_parameter = MV | MY;
|
|
|
|
|
BX = (id != DISPLAY_ID_GC9307);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (id == DISPLAY_ID_GC9307) {
|
|
|
|
|
display_command_parameter ^= RGB | MY; // XOR RGB and MY settings
|
|
|
|
|
}
|
|
|
|
|
CMD(0x36);
|
|
|
|
|
DATA(display_command_parameter);
|
|
|
|
|
|
|
|
|
|
if (shift) {
|
|
|
|
|
// GATECTRL: Gate Control; NL = 240 gate lines, first scan line is
|
|
|
|
|
// gate 80.; gate scan direction 319 -> 0
|
|
|
|
|
CMD(0xE4);
|
|
|
|
|
DATA(0x1D);
|
|
|
|
|
DATA(0x00);
|
|
|
|
|
DATA(0x11);
|
|
|
|
|
} else {
|
|
|
|
|
// GATECTRL: Gate Control; NL = 240 gate lines, first scan line is
|
|
|
|
|
// gate 80.; gate scan direction 319 -> 0
|
|
|
|
|
CMD(0xE4);
|
|
|
|
|
DATA(0x1D);
|
|
|
|
|
DATA(0x0A);
|
|
|
|
|
DATA(0x11);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// reset the column and page extents
|
|
|
|
|
display_set_window(0, 0, DISPLAY_RESX - 1, DISPLAY_RESY - 1);
|
|
|
|
|
if (id == DISPLAY_ID_GC9307) {
|
|
|
|
|
tt_old1_rotate(degrees, &BUFFER_OFFSET);
|
|
|
|
|
} else {
|
|
|
|
|
lx154a2422_rotate(degrees, &BUFFER_OFFSET);
|
|
|
|
|
}
|
|
|
|
|
BUFFER_OFFSET.x = BX ? (MAX_DISPLAY_RESY - DISPLAY_RESY) : 0;
|
|
|
|
|
BUFFER_OFFSET.y = BY ? (MAX_DISPLAY_RESY - DISPLAY_RESY) : 0;
|
|
|
|
|
#else
|
|
|
|
|
DISPLAY_PANEL_ROTATE(degrees, &BUFFER_OFFSET);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return DISPLAY_ORIENTATION;
|
|
|
|
@ -369,7 +319,7 @@ void display_init(void) {
|
|
|
|
|
TIM1_Handle.Init.Period = LED_PWM_TIM_PERIOD - 1;
|
|
|
|
|
// TIM1/APB2 source frequency equals to SystemCoreClock in our configuration,
|
|
|
|
|
// we want 1 MHz
|
|
|
|
|
TIM1_Handle.Init.Prescaler = SystemCoreClock / 1000000 - 1;
|
|
|
|
|
TIM1_Handle.Init.Prescaler = SystemCoreClock / 12000000 - 1;
|
|
|
|
|
TIM1_Handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
|
|
|
|
|
TIM1_Handle.Init.CounterMode = TIM_COUNTERMODE_UP;
|
|
|
|
|
TIM1_Handle.Init.RepetitionCounter = 0;
|
|
|
|
@ -401,13 +351,15 @@ void display_init(void) {
|
|
|
|
|
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_RESET);
|
|
|
|
|
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
|
|
|
|
|
|
|
|
|
|
// LCD_FMARK/PD12 (tearing effect)
|
|
|
|
|
#ifdef DISPLAY_TE_PIN
|
|
|
|
|
// LCD_FMARK (tearing effect)
|
|
|
|
|
GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
|
|
|
|
|
GPIO_InitStructure.Pull = GPIO_NOPULL;
|
|
|
|
|
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
|
|
|
|
|
GPIO_InitStructure.Alternate = 0;
|
|
|
|
|
GPIO_InitStructure.Pin = GPIO_PIN_12;
|
|
|
|
|
HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
|
|
|
|
|
GPIO_InitStructure.Pin = DISPLAY_TE_PIN;
|
|
|
|
|
HAL_GPIO_Init(DISPLAY_TE_PORT, &GPIO_InitStructure);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
|
|
|
|
|
GPIO_InitStructure.Pull = GPIO_NOPULL;
|
|
|
|
@ -458,6 +410,7 @@ void display_reinit(void) {
|
|
|
|
|
DISPLAY_ORIENTATION = 0;
|
|
|
|
|
|
|
|
|
|
pwm_period = LED_PWM_TIM_PERIOD;
|
|
|
|
|
TIM1->PSC = ((SystemCoreClock / 12000000) - 1);
|
|
|
|
|
TIM1->CR1 |= TIM_CR1_ARPE;
|
|
|
|
|
TIM1->CR2 |= TIM_CR2_CCPC;
|
|
|
|
|
TIM1->CCR1 = pwm_period * prev_val / 255;
|
|
|
|
@ -473,15 +426,18 @@ void display_reinit(void) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void display_sync(void) {
|
|
|
|
|
#ifdef DISPLAY_TE_PIN
|
|
|
|
|
uint32_t id = display_identify();
|
|
|
|
|
if (id && (id != DISPLAY_ID_GC9307)) {
|
|
|
|
|
// synchronize with the panel synchronization signal
|
|
|
|
|
// in order to avoid visual tearing effects
|
|
|
|
|
while (GPIO_PIN_SET == HAL_GPIO_ReadPin(GPIOD, GPIO_PIN_12)) {
|
|
|
|
|
while (GPIO_PIN_SET == HAL_GPIO_ReadPin(DISPLAY_TE_PORT, DISPLAY_TE_PIN)) {
|
|
|
|
|
}
|
|
|
|
|
while (GPIO_PIN_RESET == HAL_GPIO_ReadPin(GPIOD, GPIO_PIN_12)) {
|
|
|
|
|
while (GPIO_PIN_RESET ==
|
|
|
|
|
HAL_GPIO_ReadPin(DISPLAY_TE_PORT, DISPLAY_TE_PIN)) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void display_refresh(void) {}
|
|
|
|
@ -493,6 +449,7 @@ void display_set_slow_pwm(void) {
|
|
|
|
|
uint8_t prev_val = (prev_ccr1 * 255) / prev_arr;
|
|
|
|
|
|
|
|
|
|
pwm_period = LED_PWM_SLOW_TIM_PERIOD;
|
|
|
|
|
TIM1->PSC = ((SystemCoreClock / 1000000) - 1);
|
|
|
|
|
TIM1->CR1 |= TIM_CR1_ARPE;
|
|
|
|
|
TIM1->CR2 |= TIM_CR2_CCPC;
|
|
|
|
|
TIM1->ARR = LED_PWM_SLOW_TIM_PERIOD - 1;
|
|
|
|
|