parent
174ab733ac
commit
472a8bebd2
@ -1,106 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GDC_BITMAP_H
|
||||
#define GDC_BITMAP_H
|
||||
|
||||
#include "gdc_color.h"
|
||||
#include "gdc_geom.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// forward declaration
|
||||
typedef struct gdc_vmt gdc_vmt_t;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// GDC Bitmap pixel format
|
||||
//
|
||||
|
||||
typedef enum {
|
||||
GDC_FORMAT_UNKNOWN, //
|
||||
GDC_FORMAT_MONO1, // 1-bpp per pixel
|
||||
GDC_FORMAT_MONO4, // 4-bpp per pixel
|
||||
GDC_FORMAT_RGB565, // 16-bpp per pixel
|
||||
GDC_FORMAT_RGBA8888, // 32-bpp
|
||||
|
||||
} gdc_format_t;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// GDC Bitmap Attributes
|
||||
//
|
||||
|
||||
#define GDC_BITMAP_READ_ONLY 0x01 // Read-only data
|
||||
// #define GDC_BITMAP_DMA_READ 0x02 // DMA read pending
|
||||
// #define GDC_BITMAP_DMA_WRITE 0x04 // DMA write pending
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// GDC Bitmap
|
||||
//
|
||||
// Structure holding pointer to the bitmap data, its format and sizes
|
||||
//
|
||||
// Note: gdc_bitmap_t itself can be used as GDC as long as it contains
|
||||
// valid gdc virtual table pointer.
|
||||
|
||||
typedef struct gdc_bitmap {
|
||||
// GDC virtual method table
|
||||
// (must be the first field of the structure)
|
||||
const gdc_vmt_t* vmt;
|
||||
// pointer to top-left pixel
|
||||
void* ptr;
|
||||
// stride in bytes
|
||||
size_t stride;
|
||||
// size in pixels
|
||||
gdc_size_t size;
|
||||
// format of pixels, GDC_FORMAT_xxx
|
||||
uint8_t format;
|
||||
// attributes, GDC_BITMAP_xxx
|
||||
uint8_t attrs;
|
||||
|
||||
} gdc_bitmap_t;
|
||||
|
||||
// Initializes RGB565 bitmap structure
|
||||
// GDC and format fields and filled automatically.
|
||||
gdc_bitmap_t gdc_bitmap_rgb565(void* data_ptr, size_t stride, gdc_size_t size,
|
||||
uint8_t attrs);
|
||||
|
||||
// Initializes RGBA8888 bitmap structure
|
||||
// GDC and format fields and filled automatically.
|
||||
gdc_bitmap_t gdc_bitmap_rgba8888(void* data_ptr, size_t stride, gdc_size_t size,
|
||||
uint8_t attrs);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// GDC Bitmap reference
|
||||
//
|
||||
// Structure is used when bitmap is beeing drawed to supply
|
||||
// additional parameters
|
||||
|
||||
typedef struct {
|
||||
// soruce bitmap
|
||||
const gdc_bitmap_t* bitmap;
|
||||
// offset used when bitmap is drawed on gdc
|
||||
gdc_offset_t offset;
|
||||
// foreground color (used with MONOx formats)
|
||||
gdc_color_t fg_color;
|
||||
// background color (used with MONOx formats)
|
||||
gdc_color_t bg_color;
|
||||
|
||||
} gdc_bitmap_ref_t;
|
||||
|
||||
#endif // GDC_BITMAP_H
|
@ -1,92 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GDC_CLIP_H
|
||||
#define GDC_CLIP_H
|
||||
|
||||
#include <common.h>
|
||||
#include "gdc.h"
|
||||
|
||||
typedef struct {
|
||||
int16_t dst_x;
|
||||
int16_t dst_y;
|
||||
int16_t src_x;
|
||||
int16_t src_y;
|
||||
int16_t width;
|
||||
int16_t height;
|
||||
} gdc_clip_t;
|
||||
|
||||
static inline gdc_clip_t gdc_clip(gdc_rect_t dst, gdc_size_t size,
|
||||
const gdc_bitmap_ref_t* src) {
|
||||
int16_t dst_x = dst.x0;
|
||||
int16_t dst_y = dst.y0;
|
||||
|
||||
int16_t src_x = 0;
|
||||
int16_t src_y = 0;
|
||||
|
||||
if (src != NULL) {
|
||||
src_x += src->offset.x;
|
||||
src_y += src->offset.y;
|
||||
|
||||
// Normalize negative x-offset of src bitmap
|
||||
if (src_x < 0) {
|
||||
dst_x -= src_x;
|
||||
src_x = 0;
|
||||
}
|
||||
|
||||
// Normalize negative y-offset of src bitmap
|
||||
if (src_y < 0) {
|
||||
dst_y -= src_y;
|
||||
src_y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Normalize negative top-left of destination rectangle
|
||||
if (dst_x < 0) {
|
||||
src_x -= dst_x;
|
||||
dst_x = 0;
|
||||
}
|
||||
|
||||
if (dst_y < 0) {
|
||||
src_y -= dst_y;
|
||||
dst_y = 0;
|
||||
}
|
||||
|
||||
// Calculate dimension of effective rectangle
|
||||
int16_t width = MIN(size.x, dst.x1) - dst_x;
|
||||
int16_t height = MIN(size.y, dst.y1) - dst_y;
|
||||
|
||||
if (src != NULL) {
|
||||
width = MIN(width, src->bitmap->size.x - src_x);
|
||||
height = MIN(height, src->bitmap->size.y - src_y);
|
||||
}
|
||||
|
||||
gdc_clip_t clip = {
|
||||
.dst_x = dst_x,
|
||||
.dst_y = dst_y,
|
||||
.src_x = src_x,
|
||||
.src_y = src_y,
|
||||
.width = width,
|
||||
.height = height,
|
||||
};
|
||||
|
||||
return clip;
|
||||
}
|
||||
|
||||
#endif // GDC_CLIP_H
|
@ -1,185 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "gdc_core.h"
|
||||
#include "gdc_clip.h"
|
||||
|
||||
#include "dma2d.h"
|
||||
|
||||
void gdc_release(gdc_t* gdc) {
|
||||
if (gdc != NULL) {
|
||||
gdc_wait_for_pending_ops(gdc);
|
||||
|
||||
gdc_vmt_t* vmt = *(gdc_vmt_t**)gdc;
|
||||
if (vmt != NULL && vmt->release != NULL) {
|
||||
vmt->release(gdc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gdc_size_t gdc_get_size(const gdc_t* gdc) {
|
||||
if (gdc != NULL) {
|
||||
gdc_vmt_t* vmt = *(gdc_vmt_t**)gdc;
|
||||
if (vmt != NULL && vmt->get_bitmap != NULL) {
|
||||
return vmt->get_bitmap((gdc_t*)gdc)->size;
|
||||
}
|
||||
}
|
||||
|
||||
return gdc_size(0, 0);
|
||||
}
|
||||
|
||||
void gdc_wait_for_pending_ops(gdc_t* gdc) {
|
||||
#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR)
|
||||
if (gdc != NULL) {
|
||||
dma2d_wait();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool gdc_fill_rect(gdc_t* gdc, gdc_rect_t rect, gdc_color_t color) {
|
||||
if (gdc != NULL) {
|
||||
gdc_vmt_t* vmt = *(gdc_vmt_t**)gdc;
|
||||
|
||||
gdc_bitmap_t* bitmap = (gdc_bitmap_t*)gdc;
|
||||
|
||||
gdc_clip_t clip = gdc_clip(rect, bitmap->size, NULL);
|
||||
|
||||
if (clip.width <= 0 || clip.height <= 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
dma2d_params_t dp = {
|
||||
// Destination bitmap
|
||||
.height = clip.height,
|
||||
.width = clip.width,
|
||||
.dst_row = (uint8_t*)bitmap->ptr + bitmap->stride * clip.dst_y,
|
||||
.dst_x = clip.dst_x,
|
||||
.dst_y = clip.dst_y,
|
||||
.dst_stride = bitmap->stride,
|
||||
|
||||
// Source bitmap
|
||||
.src_fg = color,
|
||||
.src_alpha = 255,
|
||||
};
|
||||
|
||||
gdc_wait_for_pending_ops(gdc);
|
||||
|
||||
if (vmt->fill != NULL) {
|
||||
return vmt->fill(gdc, &dp);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool gdc_draw_bitmap(gdc_t* gdc, gdc_rect_t rect, const gdc_bitmap_ref_t* src) {
|
||||
if (gdc != NULL) {
|
||||
gdc_vmt_t* vmt = *(gdc_vmt_t**)gdc;
|
||||
|
||||
gdc_bitmap_t* bitmap = vmt->get_bitmap(gdc);
|
||||
|
||||
gdc_clip_t clip = gdc_clip(rect, bitmap->size, src);
|
||||
|
||||
if (clip.width <= 0 || clip.height <= 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
dma2d_params_t dp = {
|
||||
// Destination bitmap
|
||||
.height = clip.height,
|
||||
.width = clip.width,
|
||||
.dst_row = (uint8_t*)bitmap->ptr + bitmap->stride * clip.dst_y,
|
||||
.dst_x = clip.dst_x,
|
||||
.dst_y = clip.dst_y,
|
||||
.dst_stride = bitmap->stride,
|
||||
|
||||
// Source bitmap
|
||||
.src_row =
|
||||
(uint8_t*)src->bitmap->ptr + src->bitmap->stride * clip.src_y,
|
||||
.src_x = clip.src_x,
|
||||
.src_y = clip.src_y,
|
||||
.src_stride = src->bitmap->stride,
|
||||
.src_fg = src->fg_color,
|
||||
.src_bg = src->bg_color,
|
||||
.src_alpha = 255,
|
||||
};
|
||||
|
||||
gdc_wait_for_pending_ops(gdc);
|
||||
|
||||
if (src->bitmap->format == GDC_FORMAT_MONO4) {
|
||||
if (vmt->copy_mono4 != NULL) {
|
||||
return vmt->copy_mono4(gdc, &dp);
|
||||
}
|
||||
} else if (src->bitmap->format == GDC_FORMAT_RGB565) {
|
||||
if (vmt->copy_rgb565 != NULL) {
|
||||
return vmt->copy_rgb565(gdc, &dp);
|
||||
}
|
||||
} else if (src->bitmap->format == GDC_FORMAT_RGBA8888) {
|
||||
if (vmt->copy_rgba8888 != NULL) {
|
||||
return vmt->copy_rgba8888(gdc, &dp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool gdc_draw_blended(gdc_t* gdc, gdc_rect_t rect,
|
||||
const gdc_bitmap_ref_t* src) {
|
||||
if (gdc != NULL) {
|
||||
gdc_vmt_t* vmt = *(gdc_vmt_t**)gdc;
|
||||
|
||||
gdc_bitmap_t* bitmap = vmt->get_bitmap(gdc);
|
||||
|
||||
gdc_clip_t clip = gdc_clip(rect, bitmap->size, src);
|
||||
|
||||
if (clip.width <= 0 || clip.height <= 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
dma2d_params_t dp = {
|
||||
// Destination rectangle
|
||||
.height = clip.height,
|
||||
.width = clip.width,
|
||||
.dst_row = (uint8_t*)bitmap->ptr + bitmap->stride * clip.dst_y,
|
||||
.dst_x = clip.dst_x,
|
||||
.dst_y = clip.dst_y,
|
||||
.dst_stride = bitmap->stride,
|
||||
|
||||
// Source bitmap
|
||||
.src_row =
|
||||
(uint8_t*)src->bitmap->ptr + src->bitmap->stride * clip.src_y,
|
||||
.src_x = clip.src_x,
|
||||
.src_y = clip.src_y,
|
||||
.src_stride = src->bitmap->stride,
|
||||
.src_fg = src->fg_color,
|
||||
.src_alpha = 255,
|
||||
};
|
||||
|
||||
gdc_wait_for_pending_ops(gdc);
|
||||
|
||||
if (src->bitmap->format == GDC_FORMAT_MONO4) {
|
||||
if (vmt->blend_mono4 != NULL) {
|
||||
return vmt->blend_mono4(gdc, &dp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
@ -1,107 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GDC_CORE_H
|
||||
#define GDC_CORE_H
|
||||
|
||||
#include "gdc_bitmap.h"
|
||||
#include "gdc_color.h"
|
||||
#include "gdc_dma2d.h"
|
||||
#include "gdc_geom.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// GDC - Graphics Device Context
|
||||
//
|
||||
|
||||
typedef void gdc_t;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// GDC (Graphic Device Context) Virtual Method Table
|
||||
//
|
||||
// GDC structure is implementation specific. Only requirement is that
|
||||
// it starts with a field of type gdc_vmt_t* vmt.
|
||||
//
|
||||
// typedef struct
|
||||
// {
|
||||
// gdc_vmt_t* vmt;
|
||||
//
|
||||
// // GDC specific data
|
||||
//
|
||||
// } gdc_impl_specific_t;
|
||||
//
|
||||
|
||||
typedef void (*gdc_release_t)(gdc_t* gdc);
|
||||
typedef gdc_bitmap_t* (*gdc_get_bitmap_t)(gdc_t* gdc);
|
||||
typedef bool (*gdc_fill_t)(gdc_t* gdc, dma2d_params_t* params);
|
||||
typedef bool (*gdc_copy_mono4_t)(gdc_t* gdc, dma2d_params_t* params);
|
||||
typedef bool (*gdc_copy_rgb565_t)(gdc_t* gdc, dma2d_params_t* params);
|
||||
typedef bool (*gdc_copy_rgba8888_t)(gdc_t* gdc, dma2d_params_t* params);
|
||||
typedef bool (*gdc_blend_mono4_t)(gdc_t* gdc, dma2d_params_t* params);
|
||||
|
||||
// GDC virtual methods
|
||||
struct gdc_vmt {
|
||||
gdc_release_t release;
|
||||
gdc_get_bitmap_t get_bitmap;
|
||||
gdc_fill_t fill;
|
||||
gdc_copy_mono4_t copy_mono4;
|
||||
gdc_copy_rgb565_t copy_rgb565;
|
||||
gdc_copy_rgba8888_t copy_rgba8888;
|
||||
gdc_blend_mono4_t blend_mono4;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// GDC (Graphic Device Context) Public API
|
||||
|
||||
// Releases reference to GDC
|
||||
void gdc_release(gdc_t* gdc);
|
||||
|
||||
// Gets size of GDC bounding rectangle
|
||||
gdc_size_t gdc_get_size(const gdc_t* gdc);
|
||||
|
||||
// Wait for pending DMA operation applied on this GDC
|
||||
// (used by high level code before accessing GDC's framebuffer/bitmap)
|
||||
void gdc_wait_for_pending_ops(gdc_t* gdc);
|
||||
|
||||
// Fills a rectangle with a specified color
|
||||
bool gdc_fill_rect(gdc_t* gdc, gdc_rect_t rect, gdc_color_t color);
|
||||
|
||||
// Draws a bitmap into the specified rectangle
|
||||
// The destination rectangle may not be fully filled if the source bitmap
|
||||
// is smaller then destination rectangle or if the bitmap is translated by
|
||||
// an offset partially or completely outside the destination rectangle.
|
||||
bool gdc_draw_bitmap(gdc_t* gdc, gdc_rect_t rect, const gdc_bitmap_ref_t* src);
|
||||
|
||||
// Blends a bitmap with the gdc background in the specified rectangle.
|
||||
// The destination rectangle may not be fully filled if the source bitmap
|
||||
// is smaller then destination rectangle or if the bitmap is translated by
|
||||
// an offset partially or completely outside the destination rectangle.
|
||||
bool gdc_draw_blended(gdc_t* gdc, gdc_rect_t rect, const gdc_bitmap_ref_t* src);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// this will be defined elsewhere::
|
||||
|
||||
// Gets GDC for the hardware display
|
||||
// Returns NULL if display gdc was already acquired and not released
|
||||
gdc_t* display_acquire_gdc(void);
|
||||
|
||||
#endif // GDC_CORE_H
|
@ -1,88 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GDC_GEOM_H
|
||||
#define GDC_GEOM_H
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// GDC Rectangle
|
||||
//
|
||||
// used for simplified manipulation with rectangle coordinates
|
||||
|
||||
typedef struct {
|
||||
int16_t x0;
|
||||
int16_t y0;
|
||||
int16_t x1;
|
||||
int16_t y1;
|
||||
} gdc_rect_t;
|
||||
|
||||
// Creates a rectangle from top-left coordinates and dimensions
|
||||
static inline gdc_rect_t gdc_rect_wh(int16_t x, int16_t y, int16_t w,
|
||||
int16_t h) {
|
||||
gdc_rect_t rect = {
|
||||
.x0 = x,
|
||||
.y0 = y,
|
||||
.x1 = x + w,
|
||||
.y1 = y + h,
|
||||
};
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
// Creates a rectangle from top-left and bottom-right coordinates
|
||||
static inline gdc_rect_t gdc_rect(int16_t x0, int16_t y0, int16_t x1,
|
||||
int16_t y1) {
|
||||
gdc_rect_t rect = {
|
||||
.x0 = x0,
|
||||
.y0 = y0,
|
||||
.x1 = x1,
|
||||
.y1 = y1,
|
||||
};
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// GDC Size
|
||||
//
|
||||
// used for simplified manipulation with size of objects
|
||||
|
||||
typedef struct {
|
||||
int16_t x;
|
||||
int16_t y;
|
||||
} gdc_size_t;
|
||||
|
||||
// Creates a rectangle from top-left and bottom-right coordinates
|
||||
static inline gdc_size_t gdc_size(int16_t x, int16_t y) {
|
||||
gdc_size_t size = {
|
||||
.x = x,
|
||||
.y = y,
|
||||
};
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// GDC Offset
|
||||
//
|
||||
// used for simplified manipulation with size of objects
|
||||
|
||||
typedef gdc_size_t gdc_offset_t;
|
||||
|
||||
#endif // GDC_GEOM_H
|
@ -1,74 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "gdc_core.h"
|
||||
#include "gdc_dma2d.h"
|
||||
#include "gdc_ops.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static void gdc_rgb565_release(gdc_t* gdc) {
|
||||
/* gdc_bitmap_t* bitmap = (gdc_bitmap_t*) gdc;
|
||||
|
||||
if (bitmap->release != NULL) {
|
||||
bitmap->release(bitmap->context);
|
||||
}*/
|
||||
}
|
||||
|
||||
static gdc_bitmap_t* gdc_rgb565_get_bitmap(gdc_t* gdc) {
|
||||
return (gdc_bitmap_t*)gdc;
|
||||
}
|
||||
|
||||
static bool gdc_rgb565_fill(gdc_t* gdc, dma2d_params_t* params) {
|
||||
return rgb565_fill(params);
|
||||
}
|
||||
|
||||
static bool gdc_rgb565_copy_mono4(gdc_t* gdc, dma2d_params_t* params) {
|
||||
return rgb565_copy_mono4(params);
|
||||
}
|
||||
|
||||
static bool gdc_rgb565_copy_rgb565(gdc_t* gdc, dma2d_params_t* params) {
|
||||
return rgb565_copy_rgb565(params);
|
||||
}
|
||||
|
||||
static bool gdc_rgb565_blend_mono4(gdc_t* gdc, dma2d_params_t* params) {
|
||||
return rgb565_blend_mono4(params);
|
||||
}
|
||||
|
||||
gdc_bitmap_t gdc_bitmap_rgb565(void* data_ptr, size_t stride, gdc_size_t size,
|
||||
uint8_t attrs) {
|
||||
static const gdc_vmt_t gdc_rgb565 = {
|
||||
.release = gdc_rgb565_release,
|
||||
.get_bitmap = gdc_rgb565_get_bitmap,
|
||||
.fill = gdc_rgb565_fill,
|
||||
.copy_mono4 = gdc_rgb565_copy_mono4,
|
||||
.copy_rgb565 = gdc_rgb565_copy_rgb565,
|
||||
.copy_rgba8888 = NULL,
|
||||
.blend_mono4 = gdc_rgb565_blend_mono4,
|
||||
};
|
||||
|
||||
gdc_bitmap_t bitmap = {.vmt = &gdc_rgb565,
|
||||
.ptr = data_ptr,
|
||||
.stride = stride,
|
||||
.size = size,
|
||||
.format = GDC_FORMAT_RGB565,
|
||||
.attrs = attrs};
|
||||
|
||||
return bitmap;
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "gdc_core.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static void gdc_rgba8888_release(gdc_t* gdc) {
|
||||
/* gdc_bitmap_t* bitmap = (gdc_bitmap_t*) gdc;
|
||||
|
||||
if (bitmap->release != NULL) {
|
||||
bitmap->release(bitmap->context);
|
||||
}*/
|
||||
}
|
||||
|
||||
static gdc_bitmap_t* gdc_rgba8888_get_bitmap(gdc_t* gdc) {
|
||||
return (gdc_bitmap_t*)gdc;
|
||||
}
|
||||
|
||||
gdc_bitmap_t gdc_bitmap_rgba8888(void* data_ptr, size_t stride, gdc_size_t size,
|
||||
uint8_t attrs) {
|
||||
static const gdc_vmt_t gdc_rgba8888 = {
|
||||
.release = gdc_rgba8888_release,
|
||||
.get_bitmap = gdc_rgba8888_get_bitmap,
|
||||
.fill = NULL, // dma2d_rgba8888_fill,
|
||||
.copy_mono4 = NULL, // dma2d_rgba8888_copy_mono4,
|
||||
.copy_rgb565 = NULL, // dma2d_rgba8888_copy_rgb565,
|
||||
.copy_rgba8888 = NULL, // dma2d_rgba8888_copy_rgba8888,
|
||||
.blend_mono4 = NULL, // dma2d_rgba8888_blend_mono4_mono4,
|
||||
};
|
||||
|
||||
gdc_bitmap_t bitmap = {
|
||||
.vmt = &gdc_rgba8888,
|
||||
.ptr = data_ptr,
|
||||
.stride = stride,
|
||||
.size = size,
|
||||
.format = GDC_FORMAT_RGBA8888,
|
||||
.attrs = attrs,
|
||||
};
|
||||
|
||||
return bitmap;
|
||||
}
|
@ -1,174 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "gdc_text.h"
|
||||
|
||||
#include "fonts/fonts.h"
|
||||
|
||||
#if TREZOR_FONT_BPP == 1
|
||||
#define GLYPH_FORMAT GDC_FORMAT_MONO1
|
||||
#define GLYPH_STRIDE(w) (((w) + 7) / 8)
|
||||
#elif TREZOR_FONT_BPP == 2
|
||||
#error Unsupported TREZOR_FONT_BPP value
|
||||
#define GLYPH_FORMAT GDC_FORMAT_MONO2
|
||||
#define GLYPH_STRIDE(w) (((w) + 3) / 4)
|
||||
#elif TREZOR_FONT_BPP == 4
|
||||
#define GLYPH_FORMAT GDC_FORMAT_MONO4
|
||||
#define GLYPH_STRIDE(w) (((w) + 1) / 2)
|
||||
#elif TREZOR_FONT_BPP == 8
|
||||
#error Unsupported TREZOR_FONT_BPP value
|
||||
#define GLYPH_FORMAT GDC_FORMAT_MONO8
|
||||
#define GLYPH_STRIDE(w) (w)
|
||||
#else
|
||||
#error Unsupported TREZOR_FONT_BPP value
|
||||
#endif
|
||||
|
||||
#define GLYPH_WIDTH(g) ((g)[0])
|
||||
#define GLYPH_HEIGHT(g) ((g)[1])
|
||||
#define GLYPH_ADVANCE(g) ((g)[2])
|
||||
#define GLYPH_BEARING_X(g) ((g)[3])
|
||||
#define GLYPH_BEARING_Y(g) ((g)[4])
|
||||
#define GLYPH_DATA(g) ((void*)&(g)[5])
|
||||
|
||||
bool gdc_draw_opaque_text(gdc_t* gdc, gdc_rect_t rect, const char* text,
|
||||
size_t maxlen, const gdc_text_attr_t* attr) {
|
||||
if (text == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
gdc_bitmap_t glyph_bitmap;
|
||||
glyph_bitmap.vmt = NULL;
|
||||
glyph_bitmap.format = GLYPH_FORMAT;
|
||||
|
||||
gdc_bitmap_ref_t glyph_ref;
|
||||
glyph_ref.bitmap = &glyph_bitmap;
|
||||
glyph_ref.fg_color = attr->fg_color;
|
||||
glyph_ref.bg_color = attr->bg_color;
|
||||
|
||||
int max_height = font_max_height(attr->font);
|
||||
int baseline = font_baseline(attr->font);
|
||||
|
||||
int offset_x = attr->offset.x;
|
||||
|
||||
if (offset_x < 0) {
|
||||
rect.x0 -= attr->offset.x;
|
||||
offset_x = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < maxlen; i++) {
|
||||
uint8_t ch = (uint8_t)text[i];
|
||||
|
||||
if (ch == 0 || rect.x0 >= rect.x1) {
|
||||
break;
|
||||
}
|
||||
|
||||
const uint8_t* glyph = font_get_glyph(attr->font, ch);
|
||||
|
||||
if (glyph == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (offset_x >= GLYPH_ADVANCE(glyph)) {
|
||||
offset_x -= GLYPH_ADVANCE(glyph);
|
||||
continue;
|
||||
}
|
||||
|
||||
glyph_bitmap.ptr = GLYPH_DATA(glyph);
|
||||
glyph_bitmap.stride = GLYPH_STRIDE(GLYPH_WIDTH(glyph));
|
||||
glyph_bitmap.size.x = GLYPH_WIDTH(glyph);
|
||||
glyph_bitmap.size.y = GLYPH_HEIGHT(glyph);
|
||||
|
||||
glyph_ref.offset.x = attr->offset.x - GLYPH_BEARING_X(glyph);
|
||||
glyph_ref.offset.y =
|
||||
attr->offset.y - (max_height - baseline - GLYPH_BEARING_Y(glyph));
|
||||
|
||||
if (!gdc_draw_bitmap(gdc, rect, &glyph_ref)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
rect.x0 += GLYPH_ADVANCE(glyph) - offset_x;
|
||||
offset_x = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool gdc_draw_blended_text(gdc_t* gdc, gdc_rect_t rect, const char* text,
|
||||
size_t maxlen, const gdc_text_attr_t* attr) {
|
||||
if (text == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
gdc_bitmap_t glyph_bitmap;
|
||||
glyph_bitmap.vmt = NULL;
|
||||
glyph_bitmap.format = GLYPH_FORMAT;
|
||||
|
||||
gdc_bitmap_ref_t glyph_ref;
|
||||
glyph_ref.bitmap = &glyph_bitmap;
|
||||
glyph_ref.fg_color = attr->fg_color;
|
||||
glyph_ref.bg_color = attr->bg_color;
|
||||
|
||||
int max_height = font_max_height(attr->font);
|
||||
int baseline = font_baseline(attr->font);
|
||||
|
||||
int offset_x = attr->offset.x;
|
||||
|
||||
if (offset_x < 0) {
|
||||
rect.x0 -= attr->offset.x;
|
||||
offset_x = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < maxlen; i++) {
|
||||
uint8_t ch = (uint8_t)text[i];
|
||||
|
||||
if (ch == 0 || rect.x0 >= rect.x1) {
|
||||
break;
|
||||
}
|
||||
|
||||
const uint8_t* glyph = font_get_glyph(attr->font, ch);
|
||||
|
||||
if (glyph == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (offset_x >= GLYPH_ADVANCE(glyph)) {
|
||||
offset_x -= GLYPH_ADVANCE(glyph);
|
||||
continue;
|
||||
} else {
|
||||
}
|
||||
|
||||
glyph_bitmap.ptr = GLYPH_DATA(glyph);
|
||||
glyph_bitmap.stride = GLYPH_STRIDE(GLYPH_WIDTH(glyph));
|
||||
glyph_bitmap.size.x = GLYPH_WIDTH(glyph);
|
||||
glyph_bitmap.size.y = GLYPH_HEIGHT(glyph);
|
||||
|
||||
glyph_ref.offset.x = offset_x - GLYPH_BEARING_X(glyph);
|
||||
glyph_ref.offset.y =
|
||||
attr->offset.y - (max_height - baseline - GLYPH_BEARING_Y(glyph));
|
||||
|
||||
if (!gdc_draw_blended(gdc, rect, &glyph_ref)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
rect.x0 += GLYPH_ADVANCE(glyph) - offset_x;
|
||||
offset_x = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "gdc_wnd565.h"
|
||||
#include "gdc_ops.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "display.h"
|
||||
|
||||
static void gdc_wnd565_release(gdc_t* gdc) {
|
||||
// gdc_wnd565_t* wnd = (gdc_wnd565_t*)gdc;
|
||||
|
||||
// if (wnd->config.release != NULL) {
|
||||
// wnd->config.release(wnd->config.context);
|
||||
// }
|
||||
}
|
||||
|
||||
static gdc_bitmap_t* gdc_wnd565_get_bitmap(gdc_t* gdc) {
|
||||
return &((gdc_wnd565_t*)gdc)->bitmap;
|
||||
}
|
||||
|
||||
static bool gdc_wnd565_fill(gdc_t* gdc, dma2d_params_t* params) {
|
||||
return wnd565_fill(params);
|
||||
}
|
||||
|
||||
static bool gdc_wnd565_copy_rgb565(gdc_t* gdc, dma2d_params_t* params) {
|
||||
return wnd565_copy_rgb565(params);
|
||||
}
|
||||
|
||||
gdc_t* gdc_wnd565_init(gdc_wnd565_t* gdc, gdc_wnd565_config_t* config) {
|
||||
static const gdc_vmt_t gdc_wnd565 = {
|
||||
.release = gdc_wnd565_release,
|
||||
.get_bitmap = gdc_wnd565_get_bitmap,
|
||||
.fill = gdc_wnd565_fill,
|
||||
.copy_mono4 = NULL, // gdc_wnd565_copy_mono4,
|
||||
.copy_rgb565 = gdc_wnd565_copy_rgb565,
|
||||
.copy_rgba8888 = NULL,
|
||||
.blend_mono4 = NULL,
|
||||
};
|
||||
|
||||
memset(gdc, 0, sizeof(gdc_wnd565_t));
|
||||
gdc->vmt = &gdc_wnd565;
|
||||
gdc->bitmap.format = GDC_FORMAT_RGB565;
|
||||
gdc->bitmap.size = config->size;
|
||||
gdc->bitmap.ptr = (void*)config->reg_address;
|
||||
|
||||
return (gdc_t*)&gdc->vmt;
|
||||
}
|
||||
|
||||
gdc_t* display_acquire_gdc(void) {
|
||||
static gdc_wnd565_t wnd = {};
|
||||
|
||||
if (wnd.vmt == NULL) {
|
||||
gdc_wnd565_config_t config = {
|
||||
.size.x = 240,
|
||||
.size.y = 240,
|
||||
};
|
||||
gdc_wnd565_init(&wnd, &config);
|
||||
}
|
||||
|
||||
return (gdc_t*)&wnd.vmt;
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GDC_WND565_H
|
||||
#define GDC_WND565_H
|
||||
|
||||
#include "gdc_core.h"
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// GDC for displays RGB565 with register/window API like ST7789
|
||||
//
|
||||
// This module serves as a driver for specific types of displays with
|
||||
// internal memory acting as a frame buffer and a specific interface
|
||||
// for writing to this framebuffer by putting pixels into the
|
||||
// specified rectangle window.
|
||||
|
||||
typedef void (*gdc_release_cb_t)(void* context);
|
||||
|
||||
// Driver configuration
|
||||
typedef struct {
|
||||
// TODO
|
||||
uintptr_t reg_address;
|
||||
|
||||
// GDC size in pixels
|
||||
gdc_size_t size;
|
||||
|
||||
// Release callback invoked when gdc_release() is called
|
||||
gdc_release_cb_t release;
|
||||
// Context for release callback
|
||||
void* context;
|
||||
|
||||
} gdc_wnd565_config_t;
|
||||
|
||||
// Driver-specific GDC structure
|
||||
typedef struct {
|
||||
// GDC virtual method table
|
||||
// (Must be the first field of the structure)
|
||||
const gdc_vmt_t* vmt;
|
||||
|
||||
// Fake bitmap structure
|
||||
gdc_bitmap_t bitmap;
|
||||
|
||||
// Current drawing window/rectangle
|
||||
gdc_rect_t rect;
|
||||
// Cursor position in the window
|
||||
int cursor_x;
|
||||
int cursor_y;
|
||||
|
||||
} gdc_wnd565_t;
|
||||
|
||||
// Initializes GDC context
|
||||
gdc_t* gdc_wnd565_init(gdc_wnd565_t* gdc, gdc_wnd565_config_t* config);
|
||||
|
||||
#endif // GDC_WND565_H
|
@ -1,57 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "gdc_ops.h"
|
||||
|
||||
#include "display.h"
|
||||
|
||||
static void set_window(const dma2d_params_t* dp) {
|
||||
display_set_window(dp->dst_x, dp->dst_y, dp->dst_x + dp->width - 1,
|
||||
dp->dst_y + dp->height + 1);
|
||||
}
|
||||
|
||||
bool wnd565_fill(const dma2d_params_t* dp) {
|
||||
set_window(dp);
|
||||
|
||||
uint16_t height = dp->height;
|
||||
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < dp->width; x++) {
|
||||
PIXELDATA(dp->src_fg);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wnd565_copy_rgb565(const dma2d_params_t* dp) {
|
||||
set_window(dp);
|
||||
|
||||
uint16_t* src_ptr = (uint16_t*)dp->src_row + dp->src_x;
|
||||
uint16_t height = dp->height;
|
||||
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < dp->width; x++) {
|
||||
PIXELDATA(src_ptr[x]);
|
||||
}
|
||||
src_ptr += dp->src_stride / sizeof(*src_ptr);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
@ -0,0 +1,226 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <display.h>
|
||||
|
||||
#include "display_draw.h"
|
||||
#include "fonts/fonts.h"
|
||||
#include "gl_draw.h"
|
||||
|
||||
typedef struct {
|
||||
int16_t dst_x;
|
||||
int16_t dst_y;
|
||||
int16_t src_x;
|
||||
int16_t src_y;
|
||||
int16_t width;
|
||||
int16_t height;
|
||||
} gl_clip_t;
|
||||
|
||||
static inline gl_clip_t gl_clip(gl_rect_t dst, const gl_bitmap_t* bitmap) {
|
||||
int16_t dst_x = dst.x0;
|
||||
int16_t dst_y = dst.y0;
|
||||
|
||||
int16_t src_x = 0;
|
||||
int16_t src_y = 0;
|
||||
|
||||
if (bitmap != NULL) {
|
||||
src_x += bitmap->offset.x;
|
||||
src_y += bitmap->offset.y;
|
||||
|
||||
// Normalize negative x-offset of bitmap
|
||||
if (src_x < 0) {
|
||||
dst_x -= src_x;
|
||||
src_x = 0;
|
||||
}
|
||||
|
||||
// Normalize negative y-offset of src bitmap
|
||||
if (src_y < 0) {
|
||||
dst_y -= src_y;
|
||||
src_y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Normalize negative top-left of destination rectangle
|
||||
if (dst_x < 0) {
|
||||
src_x -= dst_x;
|
||||
dst_x = 0;
|
||||
}
|
||||
|
||||
if (dst_y < 0) {
|
||||
src_y -= dst_y;
|
||||
dst_y = 0;
|
||||
}
|
||||
|
||||
// Calculate dimension of effective rectangle
|
||||
int16_t width = MIN(DISPLAY_RESX, dst.x1) - dst_x;
|
||||
int16_t height = MIN(DISPLAY_RESY, dst.y1) - dst_y;
|
||||
|
||||
if (bitmap != NULL) {
|
||||
width = MIN(width, bitmap->size.x - src_x);
|
||||
height = MIN(height, bitmap->size.y - src_y);
|
||||
}
|
||||
|
||||
gl_clip_t clip = {
|
||||
.dst_x = dst_x,
|
||||
.dst_y = dst_y,
|
||||
.src_x = src_x,
|
||||
.src_y = src_y,
|
||||
.width = width,
|
||||
.height = height,
|
||||
};
|
||||
|
||||
return clip;
|
||||
}
|
||||
|
||||
void gl_draw_bar(gl_rect_t rect, gl_color_t color) {
|
||||
gl_clip_t clip = gl_clip(rect, NULL);
|
||||
|
||||
if (clip.width <= 0 || clip.height <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
dma2d_params_t dp = {
|
||||
// Destination bitmap
|
||||
.height = clip.height,
|
||||
.width = clip.width,
|
||||
.dst_row = NULL,
|
||||
.dst_x = clip.dst_x,
|
||||
.dst_y = clip.dst_y,
|
||||
.dst_stride = 0,
|
||||
|
||||
// Source bitmap
|
||||
.src_fg = color,
|
||||
.src_alpha = 255,
|
||||
};
|
||||
|
||||
display_fill(&dp);
|
||||
}
|
||||
|
||||
void gl_draw_bitmap(gl_rect_t rect, const gl_bitmap_t* bitmap) {
|
||||
gl_clip_t clip = gl_clip(rect, bitmap);
|
||||
|
||||
if (clip.width <= 0 || clip.height <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
dma2d_params_t dp = {
|
||||
// Destination bitmap
|
||||
.height = clip.height,
|
||||
.width = clip.width,
|
||||
.dst_row = NULL,
|
||||
.dst_x = clip.dst_x,
|
||||
.dst_y = clip.dst_y,
|
||||
.dst_stride = 0,
|
||||
|
||||
// Source bitmap
|
||||
.src_row = (uint8_t*)bitmap->ptr + bitmap->stride * clip.src_y,
|
||||
.src_x = clip.src_x,
|
||||
.src_y = clip.src_y,
|
||||
.src_stride = bitmap->stride,
|
||||
.src_fg = bitmap->fg_color,
|
||||
.src_bg = bitmap->bg_color,
|
||||
.src_alpha = 255,
|
||||
};
|
||||
|
||||
#if TREZOR_FONT_BPP == 1
|
||||
if (bitmap->format == GL_FORMAT_MONO1P) {
|
||||
display_copy_mono1p(&dp);
|
||||
}
|
||||
#endif
|
||||
#if TREZOR_FONT_BPP == 4
|
||||
if (bitmap->format == GL_FORMAT_MONO4) {
|
||||
display_copy_mono4(&dp);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if TREZOR_FONT_BPP == 1
|
||||
#define GLYPH_FORMAT GL_FORMAT_MONO1P
|
||||
#define GLYPH_STRIDE(w) (((w) + 7) / 8)
|
||||
#elif TREZOR_FONT_BPP == 2
|
||||
#error Unsupported TREZOR_FONT_BPP value
|
||||
#define GLYPH_FORMAT GL_FORMAT_MONO2
|
||||
#define GLYPH_STRIDE(w) (((w) + 3) / 4)
|
||||
#elif TREZOR_FONT_BPP == 4
|
||||
#define GLYPH_FORMAT GL_FORMAT_MONO4
|
||||
#define GLYPH_STRIDE(w) (((w) + 1) / 2)
|
||||
#elif TREZOR_FONT_BPP == 8
|
||||
#error Unsupported TREZOR_FONT_BPP value
|
||||
#define GLYPH_FORMAT GL_FORMAT_MONO8
|
||||
#define GLYPH_STRIDE(w) (w)
|
||||
#else
|
||||
#error Unsupported TREZOR_FONT_BPP value
|
||||
#endif
|
||||
|
||||
#define GLYPH_WIDTH(g) ((g)[0])
|
||||
#define GLYPH_HEIGHT(g) ((g)[1])
|
||||
#define GLYPH_ADVANCE(g) ((g)[2])
|
||||
#define GLYPH_BEARING_X(g) ((g)[3])
|
||||
#define GLYPH_BEARING_Y(g) ((g)[4])
|
||||
#define GLYPH_DATA(g) ((void*)&(g)[5])
|
||||
|
||||
void gl_draw_text(gl_rect_t rect, const char* text, size_t maxlen,
|
||||
const gl_text_attr_t* attr) {
|
||||
if (text == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
gl_bitmap_t bitmap = {
|
||||
.format = GLYPH_FORMAT,
|
||||
.fg_color = attr->fg_color,
|
||||
.bg_color = attr->bg_color,
|
||||
};
|
||||
|
||||
int max_height = font_max_height(attr->font);
|
||||
int baseline = font_baseline(attr->font);
|
||||
|
||||
for (int i = 0; i < maxlen; i++) {
|
||||
uint8_t ch = (uint8_t)text[i];
|
||||
|
||||
if (ch == 0 || rect.x0 >= rect.x1) {
|
||||
break;
|
||||
}
|
||||
|
||||
const uint8_t* glyph = font_get_glyph(attr->font, ch);
|
||||
|
||||
if (glyph == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bitmap.ptr = GLYPH_DATA(glyph);
|
||||
bitmap.stride = GLYPH_STRIDE(GLYPH_WIDTH(glyph));
|
||||
bitmap.size.x = GLYPH_WIDTH(glyph);
|
||||
bitmap.size.y = GLYPH_HEIGHT(glyph);
|
||||
|
||||
bitmap.offset.x = -GLYPH_BEARING_X(glyph);
|
||||
bitmap.offset.y = -(max_height - baseline - GLYPH_BEARING_Y(glyph));
|
||||
|
||||
gl_draw_bitmap(rect, &bitmap);
|
||||
|
||||
rect.x0 += GLYPH_ADVANCE(glyph);
|
||||
}
|
||||
}
|
||||
|
||||
// ===============================================================
|
||||
// emulation of legacy functions
|
||||
|
||||
void display_bar(int x, int y, int w, int h, uint16_t c) {}
|
||||
|
||||
void display_text(int x, int y, const char* text, int textlen, int font,
|
||||
uint16_t fgcolor, uint16_t bgcolor) {}
|
@ -0,0 +1,135 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GL_DRAW_H
|
||||
#define GL_DRAW_H
|
||||
|
||||
#include "gl_color.h"
|
||||
|
||||
// 2D rectangle coordinates (x1, y1 point is not included)
|
||||
typedef struct {
|
||||
int16_t x0;
|
||||
int16_t y0;
|
||||
int16_t x1;
|
||||
int16_t y1;
|
||||
} gl_rect_t;
|
||||
|
||||
// Creates a rectangle from top-left coordinates and dimensions
|
||||
static inline gl_rect_t gl_rect_wh(int16_t x, int16_t y, int16_t w, int16_t h) {
|
||||
gl_rect_t rect = {
|
||||
.x0 = x,
|
||||
.y0 = y,
|
||||
.x1 = x + w,
|
||||
.y1 = y + h,
|
||||
};
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
// Creates a rectangle from top-left and bottom-right coordinates
|
||||
static inline gl_rect_t gl_rect(int16_t x0, int16_t y0, int16_t x1,
|
||||
int16_t y1) {
|
||||
gl_rect_t rect = {
|
||||
.x0 = x0,
|
||||
.y0 = y0,
|
||||
.x1 = x1,
|
||||
.y1 = y1,
|
||||
};
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
// 2D offset/ coordinates
|
||||
typedef struct {
|
||||
int16_t x;
|
||||
int16_t y;
|
||||
} gl_offset_t;
|
||||
|
||||
static inline gl_offset_t gl_offset(int16_t x, int16_t y) {
|
||||
gl_offset_t size = {
|
||||
.x = x,
|
||||
.y = y,
|
||||
};
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
// 2D size in pixels
|
||||
typedef struct {
|
||||
int16_t x;
|
||||
int16_t y;
|
||||
} gl_size_t;
|
||||
|
||||
static inline gl_size_t gl_size(int16_t x, int16_t y) {
|
||||
gl_size_t size = {
|
||||
.x = x,
|
||||
.y = y,
|
||||
};
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
// Bitmap pixel format
|
||||
typedef enum {
|
||||
GL_FORMAT_UNKNOWN, //
|
||||
GL_FORMAT_MONO1P, // 1-bpp per pixel (packed)
|
||||
GL_FORMAT_MONO4, // 4-bpp per pixel
|
||||
GL_FORMAT_RGB565, // 16-bpp per pixel
|
||||
GL_FORMAT_RGBA8888, // 32-bpp
|
||||
} gl_format_t;
|
||||
|
||||
// 2D bitmap references
|
||||
typedef struct {
|
||||
// pointer to top-left pixel
|
||||
void* ptr;
|
||||
// stride in bytes
|
||||
size_t stride;
|
||||
// size in pixels
|
||||
gl_size_t size;
|
||||
// format of pixels, GL_FORMAT_xxx
|
||||
uint8_t format;
|
||||
// offset used when bitmap is drawed using gl_draw_bitmap()
|
||||
gl_offset_t offset;
|
||||
// foreground color (used with MONOx formats)
|
||||
gl_color_t fg_color;
|
||||
// background color (used with MONOx formats)
|
||||
gl_color_t bg_color;
|
||||
} gl_bitmap_t;
|
||||
|
||||
// Text attributes
|
||||
typedef struct {
|
||||
int font;
|
||||
gl_color_t fg_color;
|
||||
gl_color_t bg_color;
|
||||
} gl_text_attr_t;
|
||||
|
||||
// Fills a rectangle with a specified color
|
||||
void gl_draw_bar(gl_rect_t rect, gl_color_t color);
|
||||
|
||||
// Draws a bitmap into the specified rectangle
|
||||
// The destination rectangle may not be fully filled if the source bitmap
|
||||
// is smaller then destination rectangle or if the bitmap is translated by
|
||||
// an offset partially or completely outside the destination rectangle.
|
||||
void gl_draw_bitmap(gl_rect_t rect, const gl_bitmap_t* bitmap);
|
||||
|
||||
// !@# TODO
|
||||
void gl_draw_text(gl_rect_t rect, const char* text, size_t maxlen,
|
||||
const gl_text_attr_t* attr);
|
||||
|
||||
#endif // GL_DRAW_H
|
@ -0,0 +1,12 @@
|
||||
use crate::ui::{
|
||||
display::Color,
|
||||
geometry::Rect,
|
||||
shape::{DirectRenderer, Mono8Canvas},
|
||||
};
|
||||
|
||||
pub fn render_on_display<'a, F>(_clip: Option<Rect>, _bg_color: Option<Color>, _func: F)
|
||||
where
|
||||
F: FnOnce(&mut DirectRenderer<'_, 'a, Mono8Canvas<'a>>),
|
||||
{
|
||||
panic!("Not implemented")
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
use crate::ui::{
|
||||
display::Color,
|
||||
geometry::{Offset, Rect},
|
||||
shape::{BasicCanvas, DirectRenderer, DrawingCache, Mono8Canvas, Viewport},
|
||||
};
|
||||
|
||||
use crate::trezorhal::display;
|
||||
|
||||
use static_alloc::Bump;
|
||||
|
||||
pub fn render_on_display<'a, F>(clip: Option<Rect>, bg_color: Option<Color>, func: F)
|
||||
where
|
||||
F: FnOnce(&mut DirectRenderer<'_, 'a, Mono8Canvas<'a>>),
|
||||
{
|
||||
static mut BUMP: Bump<[u8; 40 * 1024]> = Bump::uninit();
|
||||
|
||||
let bump = unsafe { &mut *core::ptr::addr_of_mut!(BUMP) };
|
||||
{
|
||||
let width = display::DISPLAY_RESX as i16;
|
||||
let height = display::DISPLAY_RESY as i16;
|
||||
|
||||
bump.reset();
|
||||
|
||||
let cache = DrawingCache::new(bump, bump);
|
||||
|
||||
let fb = unsafe {
|
||||
core::slice::from_raw_parts_mut(
|
||||
display::get_frame_addr() as *mut u8,
|
||||
width as usize * height as usize * core::mem::size_of::<u8>(),
|
||||
)
|
||||
};
|
||||
|
||||
let mut canvas = unwrap!(Mono8Canvas::new(Offset::new(width, height), None, fb));
|
||||
|
||||
if let Some(clip) = clip {
|
||||
canvas.set_viewport(Viewport::new(clip));
|
||||
}
|
||||
|
||||
let mut target = DirectRenderer::new(&mut canvas, bg_color, &cache);
|
||||
|
||||
func(&mut target);
|
||||
|
||||
display::refresh();
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
use crate::ui::{
|
||||
display::Color,
|
||||
geometry::{Offset, Rect},
|
||||
shape::{BasicCanvas, DirectRenderer, DrawingCache, Rgb565Canvas, Viewport},
|
||||
};
|
||||
|
||||
use crate::trezorhal::display;
|
||||
|
||||
use static_alloc::Bump;
|
||||
|
||||
pub fn render_on_display<'a, F>(clip: Option<Rect>, bg_color: Option<Color>, func: F)
|
||||
where
|
||||
F: FnOnce(&mut DirectRenderer<'_, 'a, Rgb565Canvas<'a>>),
|
||||
{
|
||||
#[link_section = ".no_dma_buffers"]
|
||||
static mut BUMP_A: Bump<[u8; 40 * 1024]> = Bump::uninit();
|
||||
|
||||
#[link_section = ".buf"]
|
||||
static mut BUMP_B: Bump<[u8; 16 * 1024]> = Bump::uninit();
|
||||
|
||||
let bump_a = unsafe { &mut *core::ptr::addr_of_mut!(BUMP_A) };
|
||||
let bump_b = unsafe { &mut *core::ptr::addr_of_mut!(BUMP_B) };
|
||||
{
|
||||
let width = display::DISPLAY_RESX as i16;
|
||||
let height = display::DISPLAY_RESY as i16;
|
||||
|
||||
bump_a.reset();
|
||||
bump_b.reset();
|
||||
|
||||
let cache = DrawingCache::new(bump_a, bump_b);
|
||||
|
||||
let fb = unsafe {
|
||||
core::slice::from_raw_parts_mut(
|
||||
display::get_frame_addr() as *mut u8,
|
||||
width as usize * height as usize * core::mem::size_of::<u16>(),
|
||||
)
|
||||
};
|
||||
|
||||
let mut canvas = unwrap!(Rgb565Canvas::new(Offset::new(width, height), None, fb));
|
||||
|
||||
if let Some(clip) = clip {
|
||||
canvas.set_viewport(Viewport::new(clip));
|
||||
}
|
||||
|
||||
let mut target = DirectRenderer::new(&mut canvas, bg_color, &cache);
|
||||
|
||||
func(&mut target);
|
||||
|
||||
display::refresh();
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
use crate::ui::{
|
||||
display::Color,
|
||||
geometry::{Offset, Rect},
|
||||
shape::{BasicCanvas, DirectRenderer, DrawingCache, Rgba8888Canvas, Viewport},
|
||||
};
|
||||
|
||||
use static_alloc::Bump;
|
||||
|
||||
use crate::trezorhal::display;
|
||||
|
||||
pub fn render_on_display<'a, F>(clip: Option<Rect>, bg_color: Option<Color>, func: F)
|
||||
where
|
||||
F: FnOnce(&mut DirectRenderer<'_, 'a, Rgba8888Canvas<'a>>),
|
||||
{
|
||||
#[link_section = ".no_dma_buffers"]
|
||||
static mut BUMP_A: Bump<[u8; 40 * 1024]> = Bump::uninit();
|
||||
|
||||
#[link_section = ".buf"]
|
||||
static mut BUMP_B: Bump<[u8; 16 * 1024]> = Bump::uninit();
|
||||
|
||||
let bump_a = unsafe { &mut *core::ptr::addr_of_mut!(BUMP_A) };
|
||||
let bump_b = unsafe { &mut *core::ptr::addr_of_mut!(BUMP_B) };
|
||||
{
|
||||
let width = display::DISPLAY_RESX as i16;
|
||||
let height = display::DISPLAY_RESY as i16;
|
||||
|
||||
bump_a.reset();
|
||||
bump_b.reset();
|
||||
|
||||
let cache = DrawingCache::new(bump_a, bump_b);
|
||||
|
||||
let fb = unsafe {
|
||||
core::slice::from_raw_parts_mut(
|
||||
display::get_frame_addr() as *mut u8,
|
||||
width as usize * height as usize * core::mem::size_of::<u32>(),
|
||||
)
|
||||
};
|
||||
|
||||
let mut canvas = unwrap!(Rgba8888Canvas::new(Offset::new(width, height), None, fb));
|
||||
|
||||
if let Some(clip) = clip {
|
||||
canvas.set_viewport(Viewport::new(clip));
|
||||
}
|
||||
|
||||
let mut target = DirectRenderer::new(&mut canvas, bg_color, &cache);
|
||||
|
||||
func(&mut target);
|
||||
|
||||
display::refresh();
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
#[cfg(all(feature = "xframebuffer", feature = "display_mono"))]
|
||||
pub mod fb_mono8;
|
||||
#[cfg(all(feature = "xframebuffer", feature = "display_mono"))]
|
||||
pub use fb_mono8::render_on_display;
|
||||
|
||||
#[cfg(all(not(feature = "xframebuffer"), feature = "display_rgb565"))]
|
||||
pub mod nofb_rgb565;
|
||||
#[cfg(all(not(feature = "xframebuffer"), feature = "display_rgb565"))]
|
||||
pub use nofb_rgb565::render_on_display;
|
||||
|
||||
#[cfg(all(feature = "xframebuffer", feature = "display_rgb565"))]
|
||||
pub mod fb_rgb565;
|
||||
#[cfg(all(feature = "xframebuffer", feature = "display_rgb565"))]
|
||||
pub use fb_rgb565::render_on_display;
|
||||
|
||||
#[cfg(all(feature = "xframebuffer", feature = "display_rgba8888"))]
|
||||
pub mod fb_rgba8888;
|
||||
#[cfg(all(feature = "xframebuffer", feature = "display_rgba8888"))]
|
||||
pub use fb_rgba8888::render_on_display;
|
||||
|
||||
#[cfg(not(feature = "new_rendering"))]
|
||||
pub mod fake_display;
|
||||
#[cfg(not(feature = "new_rendering"))]
|
||||
pub use fake_display::render_on_display;
|
@ -1,9 +0,0 @@
|
||||
#[cfg(feature = "model_tr")]
|
||||
pub mod model_tr;
|
||||
#[cfg(feature = "model_tr")]
|
||||
pub use model_tr::render_on_display;
|
||||
|
||||
#[cfg(feature = "model_tt")]
|
||||
pub mod model_tt;
|
||||
#[cfg(feature = "model_tt")]
|
||||
pub use model_tt::render_on_display;
|
@ -1,57 +0,0 @@
|
||||
use crate::ui::{
|
||||
display,
|
||||
display::Color,
|
||||
geometry::{Offset, Rect},
|
||||
shape::{BasicCanvas, Canvas, DirectRenderer, DrawingCache, Mono8Canvas, Viewport},
|
||||
};
|
||||
|
||||
use static_alloc::Bump;
|
||||
|
||||
pub fn render_on_display<'a, F>(clip: Option<Rect>, bg_color: Option<Color>, func: F)
|
||||
where
|
||||
F: FnOnce(&mut DirectRenderer<'_, 'a, Mono8Canvas<'a>>),
|
||||
{
|
||||
// TODO: do not use constants 128 & 64 directly
|
||||
|
||||
static mut FRAME_BUFFER: [u8; 128 * 64] = [0u8; 128 * 64];
|
||||
|
||||
let fb = &mut unsafe { &mut *core::ptr::addr_of_mut!(FRAME_BUFFER) }[..];
|
||||
|
||||
static mut BUMP: Bump<[u8; 40 * 1024]> = Bump::uninit();
|
||||
|
||||
let bump = unsafe { &mut *core::ptr::addr_of_mut!(BUMP) };
|
||||
{
|
||||
bump.reset();
|
||||
|
||||
let cache = DrawingCache::new(bump, bump);
|
||||
let mut canvas = unwrap!(Mono8Canvas::new(Offset::new(128, 64), None, fb));
|
||||
|
||||
if let Some(clip) = clip {
|
||||
canvas.set_viewport(Viewport::new(clip));
|
||||
}
|
||||
|
||||
let mut target = DirectRenderer::new(&mut canvas, bg_color, &cache);
|
||||
|
||||
func(&mut target);
|
||||
|
||||
refresh_display(&canvas);
|
||||
}
|
||||
}
|
||||
|
||||
fn refresh_display(canvas: &Mono8Canvas) {
|
||||
// TODO: optimize
|
||||
|
||||
display::set_window(canvas.bounds());
|
||||
|
||||
let view = canvas.view();
|
||||
|
||||
for y in 0..canvas.size().y {
|
||||
let row = unwrap!(view.row(y));
|
||||
for value in row.iter() {
|
||||
let c = Color::rgb(*value, *value, *value);
|
||||
display::pixeldata(c.into());
|
||||
}
|
||||
}
|
||||
|
||||
display::refresh();
|
||||
}
|
@ -0,0 +1,194 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <xdisplay.h>
|
||||
|
||||
#include "display_fb.h"
|
||||
#include "display_io.h"
|
||||
#include "display_panel.h"
|
||||
|
||||
#include "backlight_pwm.h"
|
||||
|
||||
#include "supervise.h"
|
||||
|
||||
#ifndef BOARDLOADER
|
||||
#include "bg_copy.h"
|
||||
#endif
|
||||
|
||||
#if (DISPLAY_RESX != 240) || (DISPLAY_RESY != 240)
|
||||
#error "Incompatible display resolution"
|
||||
#endif
|
||||
|
||||
// Display driver context.
|
||||
typedef struct {
|
||||
// Current display orientation (0, 90, 180, 270)
|
||||
int orientation_angle;
|
||||
} display_driver_t;
|
||||
|
||||
// Display driver instance
|
||||
static display_driver_t g_display_driver;
|
||||
|
||||
void display_init(void) {
|
||||
display_driver_t* drv = &g_display_driver;
|
||||
memset(drv, 0, sizeof(display_driver_t));
|
||||
|
||||
display_io_init_gpio();
|
||||
display_io_init_fmc();
|
||||
display_panel_init();
|
||||
display_panel_set_little_endian();
|
||||
backlight_pwm_init();
|
||||
|
||||
#ifdef XFRAMEBUFFER
|
||||
display_io_init_te_interrupt();
|
||||
#endif
|
||||
}
|
||||
|
||||
void display_reinit(void) {
|
||||
display_driver_t* drv = &g_display_driver;
|
||||
memset(drv, 0, sizeof(display_driver_t));
|
||||
|
||||
// Reinitialize FMC to set correct timing
|
||||
// We have to do this in reinit because boardloader is fixed.
|
||||
display_io_init_fmc();
|
||||
|
||||
// Important for model T as this is not set in boardloader
|
||||
display_panel_set_little_endian();
|
||||
display_panel_init_gamma();
|
||||
backlight_pwm_reinit();
|
||||
|
||||
#ifdef XFRAMEBUFFER
|
||||
display_io_init_te_interrupt();
|
||||
#endif
|
||||
}
|
||||
|
||||
void display_finish_actions(void) {
|
||||
// !@# disable interrupt
|
||||
// !@# wait for dma ops
|
||||
}
|
||||
|
||||
int display_set_backlight(int level) {
|
||||
#ifdef XFRAMEBUFFER
|
||||
#ifndef BOARDLOADER
|
||||
// wait for DMA transfer to finish before changing backlight
|
||||
// so that we know that panel has current data
|
||||
if (backlight_pwm_get() != level && !is_mode_handler()) {
|
||||
bg_copy_wait();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return backlight_pwm_set(level);
|
||||
}
|
||||
|
||||
int display_get_backlight(void) { return backlight_pwm_get(); }
|
||||
|
||||
int display_set_orientation(int angle) {
|
||||
display_driver_t* drv = &g_display_driver;
|
||||
|
||||
if (angle != drv->orientation_angle) {
|
||||
if (angle == 0 || angle == 90 || angle == 180 || angle == 270) {
|
||||
drv->orientation_angle = angle;
|
||||
|
||||
#ifdef XFRAMEBUFFER
|
||||
memset(physical_frame_buffer_0, 0, sizeof(physical_frame_buffer_0));
|
||||
memset(physical_frame_buffer_1, 0, sizeof(physical_frame_buffer_1));
|
||||
#endif
|
||||
|
||||
display_panel_set_window(0, 0, DISPLAY_RESX - 1, DISPLAY_RESY - 1);
|
||||
for (uint32_t i = 0; i < DISPLAY_RESX * DISPLAY_RESY; i++) {
|
||||
// 2 bytes per pixel because we're using RGB 5-6-5 format
|
||||
ISSUE_PIXEL_DATA(0x0000);
|
||||
}
|
||||
|
||||
display_panel_rotate(angle);
|
||||
}
|
||||
}
|
||||
|
||||
return drv->orientation_angle;
|
||||
}
|
||||
|
||||
int display_get_orientation(void) {
|
||||
display_driver_t* drv = &g_display_driver;
|
||||
|
||||
return drv->orientation_angle;
|
||||
}
|
||||
|
||||
#ifndef XFRAMEBUFFER
|
||||
void display_refresh(void) {
|
||||
// if the framebuffer is not used the implementation is empty
|
||||
}
|
||||
#endif
|
||||
|
||||
void display_wait_for_sync(void) {
|
||||
#ifdef DISPLAY_TE_PIN
|
||||
uint32_t id = display_panel_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(DISPLAY_TE_PORT, DISPLAY_TE_PIN))
|
||||
;
|
||||
while (GPIO_PIN_RESET == HAL_GPIO_ReadPin(DISPLAY_TE_PORT, DISPLAY_TE_PIN))
|
||||
;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
const char* display_save(const char* prefix) { return NULL; }
|
||||
|
||||
void display_clear_save(void) {}
|
||||
|
||||
void display_set_compatible_settings(void) { display_panel_set_big_endian(); }
|
||||
|
||||
static inline void set_window(const dma2d_params_t* dp) {
|
||||
display_panel_set_window(dp->dst_x, dp->dst_y, dp->dst_x + dp->width - 1,
|
||||
dp->dst_y + dp->height + 1);
|
||||
}
|
||||
|
||||
// Fills a rectangle with a specified color
|
||||
void display_fill(const dma2d_params_t* dp) {
|
||||
set_window(dp);
|
||||
|
||||
uint16_t height = dp->height;
|
||||
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < dp->width; x++) {
|
||||
ISSUE_PIXEL_DATA(dp->src_fg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copies an RGB565 bitmap to specified rectangle
|
||||
void display_copy_rgb565(const dma2d_params_t* dp) {
|
||||
set_window(dp);
|
||||
|
||||
uint16_t* src_ptr = (uint16_t*)dp->src_row + dp->src_x;
|
||||
uint16_t height = dp->height;
|
||||
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < dp->width; x++) {
|
||||
ISSUE_PIXEL_DATA(src_ptr[x]);
|
||||
}
|
||||
src_ptr += dp->src_stride / sizeof(*src_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
// Copies a MONO4 bitmap to specified rectangle
|
||||
// void display_copy_mono4(gdc_dma2d_t *dp);
|
@ -0,0 +1,160 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include TREZOR_BOARD
|
||||
#include STM32_HAL_H
|
||||
|
||||
#include "display_fb.h"
|
||||
#include "display_io.h"
|
||||
#include "display_panel.h"
|
||||
|
||||
#include "irq.h"
|
||||
#include "supervise.h"
|
||||
|
||||
#ifndef BOARDLOADER
|
||||
#include "bg_copy.h"
|
||||
#endif
|
||||
|
||||
#ifdef XFRAMEBUFFER
|
||||
|
||||
#ifndef STM32U5
|
||||
#error Framebuffer only supported on STM32U5 for now
|
||||
#endif
|
||||
|
||||
// Physical frame buffers in internal SRAM memory
|
||||
__attribute__((section(".fb1")))
|
||||
ALIGN_32BYTES(uint8_t physical_frame_buffer_0[PHYSICAL_FRAME_BUFFER_SIZE]);
|
||||
|
||||
__attribute__((section(".fb2")))
|
||||
ALIGN_32BYTES(uint8_t physical_frame_buffer_1[PHYSICAL_FRAME_BUFFER_SIZE]);
|
||||
|
||||
// The current frame buffer selector at fixed memory address
|
||||
// It's shared between bootloaders and the firmware
|
||||
__attribute__((section(".framebuffer_select"))) uint32_t current_frame_buffer =
|
||||
0;
|
||||
|
||||
static bool pending_fb_switch = false;
|
||||
|
||||
#ifndef BOARDLOADER
|
||||
void DISPLAY_TE_INTERRUPT_HANDLER(void) {
|
||||
HAL_NVIC_DisableIRQ(DISPLAY_TE_INTERRUPT_NUM);
|
||||
|
||||
if (current_frame_buffer == 1) {
|
||||
bg_copy_start_const_out_8((uint8_t *)physical_frame_buffer_1,
|
||||
(uint8_t *)DISPLAY_DATA_ADDRESS,
|
||||
DISPLAY_RESX * DISPLAY_RESY * 2);
|
||||
|
||||
} else {
|
||||
bg_copy_start_const_out_8((uint8_t *)physical_frame_buffer_0,
|
||||
(uint8_t *)DISPLAY_DATA_ADDRESS,
|
||||
DISPLAY_RESX * DISPLAY_RESY * 2);
|
||||
}
|
||||
|
||||
pending_fb_switch = false;
|
||||
__HAL_GPIO_EXTI_CLEAR_FLAG(DISPLAY_TE_PIN);
|
||||
}
|
||||
|
||||
static void wait_for_fb_switch(void) {
|
||||
while (pending_fb_switch) {
|
||||
__WFI();
|
||||
}
|
||||
bg_copy_wait();
|
||||
}
|
||||
#endif
|
||||
|
||||
static void copy_fb_to_display(uint16_t *fb) {
|
||||
for (int i = 0; i < DISPLAY_RESX * DISPLAY_RESY; i++) {
|
||||
// 2 bytes per pixel because we're using RGB 5-6-5 format
|
||||
ISSUE_PIXEL_DATA(fb[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void switch_fb_manually(void) {
|
||||
// sync with the panel refresh
|
||||
while (GPIO_PIN_SET == HAL_GPIO_ReadPin(DISPLAY_TE_PORT, DISPLAY_TE_PIN)) {
|
||||
}
|
||||
while (GPIO_PIN_RESET == HAL_GPIO_ReadPin(DISPLAY_TE_PORT, DISPLAY_TE_PIN)) {
|
||||
}
|
||||
|
||||
if (current_frame_buffer == 0) {
|
||||
current_frame_buffer = 1;
|
||||
copy_fb_to_display((uint16_t *)physical_frame_buffer_1);
|
||||
memcpy(physical_frame_buffer_0, physical_frame_buffer_1,
|
||||
sizeof(physical_frame_buffer_0));
|
||||
|
||||
} else {
|
||||
current_frame_buffer = 0;
|
||||
copy_fb_to_display((uint16_t *)physical_frame_buffer_0);
|
||||
memcpy(physical_frame_buffer_1, physical_frame_buffer_0,
|
||||
sizeof(physical_frame_buffer_1));
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BOARDLOADER
|
||||
static void switch_fb_in_backround(void) {
|
||||
if (current_frame_buffer == 0) {
|
||||
current_frame_buffer = 1;
|
||||
|
||||
memcpy(physical_frame_buffer_0, physical_frame_buffer_1,
|
||||
sizeof(physical_frame_buffer_0));
|
||||
|
||||
pending_fb_switch = true;
|
||||
__HAL_GPIO_EXTI_CLEAR_FLAG(DISPLAY_TE_PIN);
|
||||
svc_enableIRQ(DISPLAY_TE_INTERRUPT_NUM);
|
||||
} else {
|
||||
current_frame_buffer = 0;
|
||||
memcpy(physical_frame_buffer_1, physical_frame_buffer_0,
|
||||
sizeof(physical_frame_buffer_1));
|
||||
|
||||
pending_fb_switch = true;
|
||||
__HAL_GPIO_EXTI_CLEAR_FLAG(DISPLAY_TE_PIN);
|
||||
svc_enableIRQ(DISPLAY_TE_INTERRUPT_NUM);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void *display_get_frame_addr(void) {
|
||||
if (current_frame_buffer == 0) {
|
||||
return (void *)physical_frame_buffer_1;
|
||||
} else {
|
||||
return (void *)physical_frame_buffer_0;
|
||||
}
|
||||
}
|
||||
|
||||
void display_refresh(void) {
|
||||
#ifndef BOARDLOADER
|
||||
wait_for_fb_switch();
|
||||
display_panel_set_window(0, 0, DISPLAY_RESX - 1, DISPLAY_RESY - 1);
|
||||
|
||||
if (is_mode_handler()) {
|
||||
switch_fb_manually();
|
||||
} else {
|
||||
switch_fb_in_backround();
|
||||
}
|
||||
#else
|
||||
display_panel_set_window(0, 0, DISPLAY_RESX - 1, DISPLAY_RESY - 1);
|
||||
switch_fb_manually();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // XFRAMEBUFFER
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TREZOR_HAL_DISPLAY_INTERNAL_H
|
||||
#define TREZOR_HAL_DISPLAY_INTERNAL_H
|
||||
|
||||
#include TREZOR_BOARD
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef XFRAMEBUFFER
|
||||
|
||||
// Size of the physical frame buffer in bytes
|
||||
#define PHYSICAL_FRAME_BUFFER_SIZE (DISPLAY_RESX * DISPLAY_RESY * 2)
|
||||
|
||||
// Physical frame buffers in internal SRAM memory
|
||||
//
|
||||
// Both frame buffers layes in the fixed addresses that
|
||||
// are shared between bootloaders and the firmware.
|
||||
extern uint8_t physical_frame_buffer_0[PHYSICAL_FRAME_BUFFER_SIZE];
|
||||
extern uint8_t physical_frame_buffer_1[PHYSICAL_FRAME_BUFFER_SIZE];
|
||||
|
||||
// The current frame buffer selector at fixed memory address
|
||||
//
|
||||
// The variable address is shared between bootloaders and the firmware
|
||||
extern uint32_t current_frame_buffer;
|
||||
|
||||
#endif // XFRAMEBUFFER
|
||||
|
||||
#endif // TREZOR_HAL_DISPLAY_INTERNAL_H
|
@ -0,0 +1,145 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include TREZOR_BOARD
|
||||
#include STM32_HAL_H
|
||||
|
||||
#include "display_io.h"
|
||||
#include "irq.h"
|
||||
|
||||
__IO DISP_MEM_TYPE *const DISPLAY_CMD_ADDRESS =
|
||||
(__IO DISP_MEM_TYPE *const)((uint32_t)DISPLAY_MEMORY_BASE);
|
||||
__IO DISP_MEM_TYPE *const DISPLAY_DATA_ADDRESS =
|
||||
(__IO DISP_MEM_TYPE *const)((uint32_t)DISPLAY_MEMORY_BASE |
|
||||
(DISPLAY_ADDR_SHIFT << DISPLAY_MEMORY_PIN));
|
||||
|
||||
void display_io_init_gpio(void) {
|
||||
// init peripherals
|
||||
__HAL_RCC_GPIOE_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOA_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOC_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOD_CLK_ENABLE();
|
||||
__HAL_RCC_FMC_CLK_ENABLE();
|
||||
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
|
||||
// LCD_RST/PC14
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
|
||||
GPIO_InitStructure.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
GPIO_InitStructure.Alternate = 0;
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_14;
|
||||
// default to keeping display in reset
|
||||
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_RESET);
|
||||
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
|
||||
|
||||
#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 = DISPLAY_TE_PIN;
|
||||
HAL_GPIO_Init(DISPLAY_TE_PORT, &GPIO_InitStructure);
|
||||
#endif
|
||||
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStructure.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
|
||||
GPIO_InitStructure.Alternate = GPIO_AF12_FMC;
|
||||
// LCD_CS/PD7 LCD_RS/PD11 LCD_RD/PD4 LCD_WR/PD5
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_7 | GPIO_PIN_11 | GPIO_PIN_4 | GPIO_PIN_5;
|
||||
HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
|
||||
// LCD_D0/PD14 LCD_D1/PD15 LCD_D2/PD0 LCD_D3/PD1
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_14 | GPIO_PIN_15 | GPIO_PIN_0 | GPIO_PIN_1;
|
||||
HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
|
||||
// LCD_D4/PE7 LCD_D5/PE8 LCD_D6/PE9 LCD_D7/PE10
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10;
|
||||
HAL_GPIO_Init(GPIOE, &GPIO_InitStructure);
|
||||
#ifdef USE_DISP_I8080_16BIT_DW
|
||||
// LCD_D8/PE11 LCD_D9/PE12 LCD_D10/PE13 LCD_D11/PE14
|
||||
GPIO_InitStructure.Pin =
|
||||
GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14;
|
||||
HAL_GPIO_Init(GPIOE, &GPIO_InitStructure);
|
||||
// LCD_D12/PE15
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_15;
|
||||
HAL_GPIO_Init(GPIOE, &GPIO_InitStructure);
|
||||
// LCD_D13/PD8 LCD_D14/PD9 LCD_D15/PD10
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10;
|
||||
HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
|
||||
#endif
|
||||
}
|
||||
|
||||
void display_io_init_fmc(void) {
|
||||
// Reference UM1725 "Description of STM32F4 HAL and LL drivers",
|
||||
// section 64.2.1 "How to use this driver"
|
||||
SRAM_HandleTypeDef external_display_data_sram = {0};
|
||||
external_display_data_sram.Instance = FMC_NORSRAM_DEVICE;
|
||||
external_display_data_sram.Extended = FMC_NORSRAM_EXTENDED_DEVICE;
|
||||
external_display_data_sram.Init.NSBank = FMC_NORSRAM_BANK1;
|
||||
external_display_data_sram.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE;
|
||||
external_display_data_sram.Init.MemoryType = FMC_MEMORY_TYPE_SRAM;
|
||||
#ifdef USE_DISP_I8080_16BIT_DW
|
||||
external_display_data_sram.Init.MemoryDataWidth =
|
||||
FMC_NORSRAM_MEM_BUS_WIDTH_16;
|
||||
#elif USE_DISP_I8080_8BIT_DW
|
||||
external_display_data_sram.Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_8;
|
||||
#endif
|
||||
external_display_data_sram.Init.BurstAccessMode =
|
||||
FMC_BURST_ACCESS_MODE_DISABLE;
|
||||
external_display_data_sram.Init.WaitSignalPolarity =
|
||||
FMC_WAIT_SIGNAL_POLARITY_LOW;
|
||||
external_display_data_sram.Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS;
|
||||
external_display_data_sram.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE;
|
||||
external_display_data_sram.Init.WaitSignal = FMC_WAIT_SIGNAL_DISABLE;
|
||||
external_display_data_sram.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE;
|
||||
external_display_data_sram.Init.AsynchronousWait =
|
||||
FMC_ASYNCHRONOUS_WAIT_DISABLE;
|
||||
external_display_data_sram.Init.WriteBurst = FMC_WRITE_BURST_DISABLE;
|
||||
external_display_data_sram.Init.ContinuousClock =
|
||||
FMC_CONTINUOUS_CLOCK_SYNC_ONLY;
|
||||
external_display_data_sram.Init.PageSize = FMC_PAGE_SIZE_NONE;
|
||||
|
||||
// reference RM0090 section 37.5 Table 259, 37.5.4, Mode 1 SRAM, and 37.5.6
|
||||
FMC_NORSRAM_TimingTypeDef normal_mode_timing = {0};
|
||||
normal_mode_timing.AddressSetupTime = 5;
|
||||
normal_mode_timing.AddressHoldTime = 1; // don't care
|
||||
normal_mode_timing.DataSetupTime = 6;
|
||||
normal_mode_timing.BusTurnAroundDuration = 0; // don't care
|
||||
normal_mode_timing.CLKDivision = 2; // don't care
|
||||
normal_mode_timing.DataLatency = 2; // don't care
|
||||
normal_mode_timing.AccessMode = FMC_ACCESS_MODE_A;
|
||||
|
||||
HAL_SRAM_Init(&external_display_data_sram, &normal_mode_timing, NULL);
|
||||
}
|
||||
|
||||
#ifdef DISPLAY_TE_INTERRUPT_HANDLER
|
||||
void display_io_init_te_interrupt(void) {
|
||||
EXTI_HandleTypeDef EXTI_Handle = {0};
|
||||
EXTI_ConfigTypeDef EXTI_Config = {0};
|
||||
EXTI_Config.GPIOSel = DISPLAY_TE_INTERRUPT_GPIOSEL;
|
||||
EXTI_Config.Line = DISPLAY_TE_INTERRUPT_EXTI_LINE;
|
||||
EXTI_Config.Mode = EXTI_MODE_INTERRUPT;
|
||||
EXTI_Config.Trigger = EXTI_TRIGGER_RISING;
|
||||
HAL_EXTI_SetConfigLine(&EXTI_Handle, &EXTI_Config);
|
||||
|
||||
// setup interrupt for tearing effect pin
|
||||
HAL_NVIC_SetPriority(DISPLAY_TE_INTERRUPT_NUM, IRQ_PRI_DMA, 0);
|
||||
}
|
||||
#endif
|
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TREZORHAL_DISPLAY_IO_H
|
||||
#define TREZORHAL_DISPLAY_IO_H
|
||||
|
||||
#include STM32_HAL_H
|
||||
#include TREZOR_BOARD
|
||||
|
||||
void display_io_init_gpio(void);
|
||||
void display_io_init_fmc(void);
|
||||
void display_io_init_te_interrupt(void);
|
||||
|
||||
#ifndef FMC_BANK1
|
||||
#define FMC_BANK1 0x60000000U
|
||||
#endif
|
||||
|
||||
#define DISPLAY_MEMORY_BASE FMC_BANK1
|
||||
#define DISPLAY_MEMORY_PIN 16
|
||||
|
||||
#ifdef USE_DISP_I8080_16BIT_DW
|
||||
#define DISPLAY_ADDR_SHIFT 2
|
||||
#define DISP_MEM_TYPE uint16_t
|
||||
#elif USE_DISP_I8080_8BIT_DW
|
||||
#define DISPLAY_ADDR_SHIFT 1
|
||||
#define DISP_MEM_TYPE uint8_t
|
||||
#else
|
||||
#error "Unsupported display interface"
|
||||
#endif
|
||||
|
||||
/*#define DISPLAY_CMD_ADDRESS ((__IO DISP_MEM_TYPE *)(DISPLAY_MEMORY_BASE))
|
||||
#define DISPLAY_DATA_ADDRESS \
|
||||
((__IO DISP_MEM_TYPE *)(DISPLAY_MEMORY_BASE | \
|
||||
(DISPLAY_ADDR_SHIFT << DISPLAY_MEMORY_PIN)))
|
||||
*/
|
||||
|
||||
extern __IO DISP_MEM_TYPE *const DISPLAY_CMD_ADDRESS;
|
||||
extern __IO DISP_MEM_TYPE *const DISPLAY_DATA_ADDRESS;
|
||||
|
||||
#define ISSUE_CMD_BYTE(X) (*(DISPLAY_CMD_ADDRESS) = (X))
|
||||
#define ISSUE_DATA_BYTE(X) (*(DISPLAY_DATA_ADDRESS) = (X))
|
||||
|
||||
#ifdef USE_DISP_I8080_16BIT_DW
|
||||
#define ISSUE_PIXEL_DATA(X) DATA(X)
|
||||
#elif USE_DISP_I8080_8BIT_DW
|
||||
#define ISSUE_PIXEL_DATA(X) \
|
||||
ISSUE_DATA_BYTE((X)&0xFF); \
|
||||
ISSUE_DATA_BYTE((X) >> 8)
|
||||
#endif
|
||||
|
||||
#endif // TREZORHAL_DISPLAY_IO_H
|
@ -0,0 +1,235 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// using const volatile instead of #define results in binaries that change
|
||||
// only in 1-byte when the flag changes.
|
||||
// using #define leads compiler to over-optimize the code leading to bigger
|
||||
// differencies in the resulting binaries.
|
||||
|
||||
#include "display_panel.h"
|
||||
#include "display_io.h"
|
||||
|
||||
#ifdef TREZOR_MODEL_T
|
||||
#include "panels/154a.h"
|
||||
#include "panels/lx154a2411.h"
|
||||
#include "panels/lx154a2422.h"
|
||||
#include "panels/tf15411a.h"
|
||||
#else
|
||||
#include "panels/lx154a2422.h"
|
||||
#endif
|
||||
|
||||
// using const volatile instead of #define results in binaries that change
|
||||
// only in 1-byte when the flag changes.
|
||||
// using #define leads compiler to over-optimize the code leading to bigger
|
||||
// differencies in the resulting binaries.
|
||||
const volatile uint8_t DISPLAY_ST7789V_INVERT_COLORS2 = 1;
|
||||
|
||||
#ifdef DISPLAY_IDENTIFY
|
||||
static uint32_t read_display_id(uint8_t command) {
|
||||
volatile uint8_t c = 0;
|
||||
uint32_t id = 0;
|
||||
ISSUE_CMD_BYTE(command);
|
||||
c = *DISPLAY_DATA_ADDRESS; // first returned value is a dummy value and
|
||||
// should be discarded
|
||||
c = *DISPLAY_DATA_ADDRESS;
|
||||
id |= (c << 16);
|
||||
c = *DISPLAY_DATA_ADDRESS;
|
||||
id |= (c << 8);
|
||||
c = *DISPLAY_DATA_ADDRESS;
|
||||
id |= c;
|
||||
return id;
|
||||
}
|
||||
|
||||
uint32_t display_panel_identify(void) {
|
||||
static uint32_t id = 0x000000U;
|
||||
static bool id_initialized = false;
|
||||
|
||||
// Return immediately if id has been already initialized
|
||||
if (id_initialized) return id;
|
||||
|
||||
// RDDID: Read Display ID
|
||||
id = read_display_id(0x04);
|
||||
// the default RDDID for ILI9341 should be 0x8000.
|
||||
// some display modules return 0x0.
|
||||
// the ILI9341 has an extra id, let's check it here.
|
||||
if ((id != DISPLAY_ID_ST7789V) && (id != DISPLAY_ID_GC9307)) {
|
||||
// Read ID4
|
||||
uint32_t id4 = read_display_id(0xD3);
|
||||
if (id4 == DISPLAY_ID_ILI9341V) { // definitely found a ILI9341
|
||||
id = id4;
|
||||
}
|
||||
}
|
||||
id_initialized = true;
|
||||
return id;
|
||||
}
|
||||
#else
|
||||
uint32_t display_panbel_identify(void) { return DISPLAY_ID_ST7789V; }
|
||||
#endif
|
||||
|
||||
bool display_panel_is_inverted() {
|
||||
bool inv_on = false;
|
||||
uint32_t id = display_panel_identify();
|
||||
if (id == DISPLAY_ID_ST7789V) {
|
||||
volatile uint8_t c = 0;
|
||||
ISSUE_CMD_BYTE(0x09); // read display status
|
||||
c = *DISPLAY_DATA_ADDRESS; // don't care
|
||||
c = *DISPLAY_DATA_ADDRESS; // don't care
|
||||
c = *DISPLAY_DATA_ADDRESS; // don't care
|
||||
c = *DISPLAY_DATA_ADDRESS;
|
||||
if (c & 0x20) {
|
||||
inv_on = true;
|
||||
}
|
||||
c = *DISPLAY_DATA_ADDRESS; // don't care
|
||||
}
|
||||
|
||||
return inv_on;
|
||||
}
|
||||
|
||||
void display_panel_sleep(void) {
|
||||
uint32_t id = display_panel_identify();
|
||||
if ((id == DISPLAY_ID_ILI9341V) || (id == DISPLAY_ID_GC9307) ||
|
||||
(id == DISPLAY_ID_ST7789V)) {
|
||||
ISSUE_CMD_BYTE(0x28); // DISPOFF: Display Off
|
||||
ISSUE_CMD_BYTE(0x10); // SLPIN: Sleep in
|
||||
HAL_Delay(5); // need to wait 5 milliseconds after "sleep in" before
|
||||
// sending any new commands
|
||||
}
|
||||
}
|
||||
|
||||
void display_panel_unsleep(void) {
|
||||
uint32_t id = display_panel_identify();
|
||||
if ((id == DISPLAY_ID_ILI9341V) || (id == DISPLAY_ID_GC9307) ||
|
||||
(id == DISPLAY_ID_ST7789V)) {
|
||||
ISSUE_CMD_BYTE(0x11); // SLPOUT: Sleep Out
|
||||
HAL_Delay(5); // need to wait 5 milliseconds after "sleep out" before
|
||||
// sending any new commands
|
||||
ISSUE_CMD_BYTE(0x29); // DISPON: Display On
|
||||
}
|
||||
}
|
||||
|
||||
void display_panel_set_window(uint16_t x0, uint16_t y0, uint16_t x1,
|
||||
uint16_t y1) {
|
||||
uint32_t id = display_panel_identify();
|
||||
if ((id == DISPLAY_ID_ILI9341V) || (id == DISPLAY_ID_GC9307) ||
|
||||
(id == DISPLAY_ID_ST7789V)) {
|
||||
ISSUE_CMD_BYTE(0x2A);
|
||||
ISSUE_DATA_BYTE(x0 >> 8);
|
||||
ISSUE_DATA_BYTE(x0 & 0xFF);
|
||||
ISSUE_DATA_BYTE(x1 >> 8);
|
||||
ISSUE_DATA_BYTE(x1 & 0xFF); // column addr set
|
||||
ISSUE_CMD_BYTE(0x2B);
|
||||
ISSUE_DATA_BYTE(y0 >> 8);
|
||||
ISSUE_DATA_BYTE(y0 & 0xFF);
|
||||
ISSUE_DATA_BYTE(y1 >> 8);
|
||||
ISSUE_DATA_BYTE(y1 & 0xFF); // row addr set
|
||||
ISSUE_CMD_BYTE(0x2C);
|
||||
}
|
||||
}
|
||||
|
||||
void display_panel_set_little_endian(void) {
|
||||
uint32_t id = display_panel_identify();
|
||||
if (id == DISPLAY_ID_GC9307) {
|
||||
// CANNOT SET ENDIAN FOR GC9307
|
||||
} else if (id == DISPLAY_ID_ST7789V) {
|
||||
ISSUE_CMD_BYTE(0xB0);
|
||||
ISSUE_DATA_BYTE(0x00);
|
||||
ISSUE_DATA_BYTE(0xF8);
|
||||
} else if (id == DISPLAY_ID_ILI9341V) {
|
||||
// Interface Control: XOR BGR as ST7789V does
|
||||
ISSUE_CMD_BYTE(0xF6);
|
||||
ISSUE_DATA_BYTE(0x09);
|
||||
ISSUE_DATA_BYTE(0x30);
|
||||
ISSUE_DATA_BYTE(0x20);
|
||||
}
|
||||
}
|
||||
|
||||
void display_panel_set_big_endian(void) {
|
||||
uint32_t id = display_panel_identify();
|
||||
if (id == DISPLAY_ID_GC9307) {
|
||||
// CANNOT SET ENDIAN FOR GC9307
|
||||
} else if (id == DISPLAY_ID_ST7789V) {
|
||||
ISSUE_CMD_BYTE(0xB0);
|
||||
ISSUE_DATA_BYTE(0x00);
|
||||
ISSUE_DATA_BYTE(0xF0);
|
||||
} else if (id == DISPLAY_ID_ILI9341V) {
|
||||
// Interface Control: XOR BGR as ST7789V does
|
||||
ISSUE_CMD_BYTE(0xF6);
|
||||
ISSUE_DATA_BYTE(0x09);
|
||||
ISSUE_DATA_BYTE(0x30);
|
||||
ISSUE_DATA_BYTE(0x00);
|
||||
}
|
||||
}
|
||||
|
||||
void display_panal_init(void) {
|
||||
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_RESET); // LCD_RST/PC14
|
||||
// wait 10 milliseconds. only needs to be low for 10 microseconds.
|
||||
// my dev display module ties display reset and touch panel reset together.
|
||||
// keeping this low for max(display_reset_time, ctpm_reset_time) aids
|
||||
// development and does not hurt.
|
||||
HAL_Delay(10);
|
||||
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_SET); // LCD_RST/PC14
|
||||
// max wait time for hardware reset is 120 milliseconds
|
||||
// (experienced display flakiness using only 5ms wait before sending commands)
|
||||
HAL_Delay(120);
|
||||
|
||||
// identify the controller we will communicate with
|
||||
#ifdef TREZOR_MODEL_T
|
||||
uint32_t id = display_panel_identify();
|
||||
if (id == DISPLAY_ID_GC9307) {
|
||||
tf15411a_init_seq();
|
||||
} else if (id == DISPLAY_ID_ST7789V) {
|
||||
if (DISPLAY_ST7789V_INVERT_COLORS2) {
|
||||
lx154a2422_init_seq();
|
||||
} else {
|
||||
lx154a2411_init_seq();
|
||||
}
|
||||
} else if (id == DISPLAY_ID_ILI9341V) {
|
||||
_154a_init_seq();
|
||||
}
|
||||
#else
|
||||
lx154a2422_init_seq();
|
||||
#endif
|
||||
|
||||
display_panel_unsleep();
|
||||
}
|
||||
|
||||
void display_panel_init_gamma(void) {
|
||||
#ifdef TREZOR_MODEL_T
|
||||
uint32_t id = display_panel_identify();
|
||||
if (id == DISPLAY_ID_ST7789V && display_panel_is_inverted()) {
|
||||
// newest TT display - set proper gamma
|
||||
lx154a2422_gamma();
|
||||
} else if (id == DISPLAY_ID_ST7789V) {
|
||||
lx154a2411_gamma();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void display_panel_rotate(int angle) {
|
||||
#ifdef TREZOR_MODEL_T
|
||||
uint32_t id = display_panel_identify();
|
||||
if (id == DISPLAY_ID_GC9307) {
|
||||
tf15411a_rotate(angle);
|
||||
} else {
|
||||
lx154a2422_rotate(angle);
|
||||
}
|
||||
#else
|
||||
lx154a2422_rotate(angle);
|
||||
#endif
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TREZORHAL_ST7789_PANEL_H
|
||||
#define TREZORHAL_ST7789_PANEL_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// section "9.1.3 RDDID (04h): Read Display ID"
|
||||
// of ST7789V datasheet
|
||||
#define DISPLAY_ID_ST7789V 0x858552U
|
||||
// section "6.2.1. Read display identification information (04h)"
|
||||
// of GC9307 datasheet
|
||||
#define DISPLAY_ID_GC9307 0x009307U
|
||||
// section "8.3.23 Read ID4 (D3h)"
|
||||
// of ILI9341V datasheet
|
||||
#define DISPLAY_ID_ILI9341V 0x009341U
|
||||
|
||||
// Identifies the connected display panel and
|
||||
// returns one of DISPLAY_ID_xxx constant
|
||||
uint32_t display_panel_identify(void);
|
||||
bool display_panel_is_inverted();
|
||||
|
||||
void display_panel_init(void);
|
||||
void display_panel_init_gamma(void);
|
||||
void display_panel_set_little_endian(void);
|
||||
void display_panel_set_big_endian(void);
|
||||
|
||||
void display_panel_sleep(void);
|
||||
void display_panel_unsleep(void);
|
||||
void display_panel_set_window(uint16_t x0, uint16_t y0, uint16_t x1,
|
||||
uint16_t y1);
|
||||
void display_panel_rotate(int angle);
|
||||
|
||||
#endif // TREZORHAL_ST7789_PANEL_H
|
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "../display_io.h"
|
||||
|
||||
void _154a_init_seq(void) {
|
||||
// most recent manual: https://www.newhavendisplay.com/app_notes/ILI9341.pdf
|
||||
// TEON: Tearing Effect Line On; V-blanking only
|
||||
ISSUE_CMD_BYTE(0x35);
|
||||
ISSUE_DATA_BYTE(0x00);
|
||||
|
||||
// COLMOD: Interface Pixel format; 65K color: 16-bit/pixel (RGB 5-6-5 bits
|
||||
// input)
|
||||
ISSUE_CMD_BYTE(0x3A);
|
||||
ISSUE_DATA_BYTE(0x55);
|
||||
|
||||
// Display Function Control: gate scan direction 319 -> 0
|
||||
ISSUE_CMD_BYTE(0xB6);
|
||||
ISSUE_DATA_BYTE(0x0A);
|
||||
ISSUE_DATA_BYTE(0xC2);
|
||||
ISSUE_DATA_BYTE(0x27);
|
||||
ISSUE_DATA_BYTE(0x00);
|
||||
|
||||
// Interface Control: XOR BGR as ST7789V does
|
||||
ISSUE_CMD_BYTE(0xF6);
|
||||
ISSUE_DATA_BYTE(0x09);
|
||||
ISSUE_DATA_BYTE(0x30);
|
||||
ISSUE_DATA_BYTE(0x00);
|
||||
|
||||
// the above config is the most important and definitely necessary
|
||||
|
||||
ISSUE_CMD_BYTE(0xCF);
|
||||
ISSUE_DATA_BYTE(0x00);
|
||||
ISSUE_DATA_BYTE(0xC1);
|
||||
ISSUE_DATA_BYTE(0x30);
|
||||
|
||||
ISSUE_CMD_BYTE(0xED);
|
||||
ISSUE_DATA_BYTE(0x64);
|
||||
ISSUE_DATA_BYTE(0x03);
|
||||
ISSUE_DATA_BYTE(0x12);
|
||||
ISSUE_DATA_BYTE(0x81);
|
||||
|
||||
ISSUE_CMD_BYTE(0xE8);
|
||||
ISSUE_DATA_BYTE(0x85);
|
||||
ISSUE_DATA_BYTE(0x10);
|
||||
ISSUE_DATA_BYTE(0x7A);
|
||||
|
||||
ISSUE_CMD_BYTE(0xF7);
|
||||
ISSUE_DATA_BYTE(0x20);
|
||||
|
||||
ISSUE_CMD_BYTE(0xEA);
|
||||
ISSUE_DATA_BYTE(0x00);
|
||||
ISSUE_DATA_BYTE(0x00);
|
||||
|
||||
// power control VRH[5:0]
|
||||
ISSUE_CMD_BYTE(0xC0);
|
||||
ISSUE_DATA_BYTE(0x23);
|
||||
|
||||
// power control SAP[2:0] BT[3:0]
|
||||
ISSUE_CMD_BYTE(0xC1);
|
||||
ISSUE_DATA_BYTE(0x12);
|
||||
|
||||
// vcm control 1
|
||||
ISSUE_CMD_BYTE(0xC5);
|
||||
ISSUE_DATA_BYTE(0x60);
|
||||
ISSUE_DATA_BYTE(0x44);
|
||||
|
||||
// vcm control 2
|
||||
ISSUE_CMD_BYTE(0xC7);
|
||||
ISSUE_DATA_BYTE(0x8A);
|
||||
|
||||
// framerate
|
||||
ISSUE_CMD_BYTE(0xB1);
|
||||
ISSUE_DATA_BYTE(0x00);
|
||||
ISSUE_DATA_BYTE(0x18);
|
||||
|
||||
// 3 gamma func disable
|
||||
ISSUE_CMD_BYTE(0xF2);
|
||||
ISSUE_DATA_BYTE(0x00);
|
||||
|
||||
// gamma curve 1
|
||||
ISSUE_CMD_BYTE(0xE0);
|
||||
ISSUE_DATA_BYTE(0x0F);
|
||||
ISSUE_DATA_BYTE(0x2F);
|
||||
ISSUE_DATA_BYTE(0x2C);
|
||||
ISSUE_DATA_BYTE(0x0B);
|
||||
ISSUE_DATA_BYTE(0x0F);
|
||||
ISSUE_DATA_BYTE(0x09);
|
||||
ISSUE_DATA_BYTE(0x56);
|
||||
ISSUE_DATA_BYTE(0xD9);
|
||||
ISSUE_DATA_BYTE(0x4A);
|
||||
ISSUE_DATA_BYTE(0x0B);
|
||||
ISSUE_DATA_BYTE(0x14);
|
||||
ISSUE_DATA_BYTE(0x05);
|
||||
ISSUE_DATA_BYTE(0x0C);
|
||||
ISSUE_DATA_BYTE(0x06);
|
||||
ISSUE_DATA_BYTE(0x00);
|
||||
|
||||
// gamma curve 2
|
||||
ISSUE_CMD_BYTE(0xE1);
|
||||
ISSUE_DATA_BYTE(0x00);
|
||||
ISSUE_DATA_BYTE(0x10);
|
||||
ISSUE_DATA_BYTE(0x13);
|
||||
ISSUE_DATA_BYTE(0x04);
|
||||
ISSUE_DATA_BYTE(0x10);
|
||||
ISSUE_DATA_BYTE(0x06);
|
||||
ISSUE_DATA_BYTE(0x25);
|
||||
ISSUE_DATA_BYTE(0x26);
|
||||
ISSUE_DATA_BYTE(0x3B);
|
||||
ISSUE_DATA_BYTE(0x04);
|
||||
ISSUE_DATA_BYTE(0x0B);
|
||||
ISSUE_DATA_BYTE(0x0A);
|
||||
ISSUE_DATA_BYTE(0x33);
|
||||
ISSUE_DATA_BYTE(0x39);
|
||||
ISSUE_DATA_BYTE(0x0F);
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
|
||||
#include "../display_io.h"
|
||||
|
||||
void lx154a2411_gamma(void) {
|
||||
// positive voltage correction
|
||||
ISSUE_CMD_BYTE(0xE0);
|
||||
ISSUE_DATA_BYTE(0xD0);
|
||||
ISSUE_DATA_BYTE(0x03);
|
||||
ISSUE_DATA_BYTE(0x08);
|
||||
ISSUE_DATA_BYTE(0x0E);
|
||||
ISSUE_DATA_BYTE(0x11);
|
||||
ISSUE_DATA_BYTE(0x2B);
|
||||
ISSUE_DATA_BYTE(0x3B);
|
||||
ISSUE_DATA_BYTE(0x44);
|
||||
ISSUE_DATA_BYTE(0x4C);
|
||||
ISSUE_DATA_BYTE(0x2B);
|
||||
ISSUE_DATA_BYTE(0x16);
|
||||
ISSUE_DATA_BYTE(0x15);
|
||||
ISSUE_DATA_BYTE(0x1E);
|
||||
ISSUE_DATA_BYTE(0x21);
|
||||
|
||||
// negative voltage correction
|
||||
ISSUE_CMD_BYTE(0xE1);
|
||||
ISSUE_DATA_BYTE(0xD0);
|
||||
ISSUE_DATA_BYTE(0x03);
|
||||
ISSUE_DATA_BYTE(0x08);
|
||||
ISSUE_DATA_BYTE(0x0E);
|
||||
ISSUE_DATA_BYTE(0x11);
|
||||
ISSUE_DATA_BYTE(0x2B);
|
||||
ISSUE_DATA_BYTE(0x3B);
|
||||
ISSUE_DATA_BYTE(0x54);
|
||||
ISSUE_DATA_BYTE(0x4C);
|
||||
ISSUE_DATA_BYTE(0x2B);
|
||||
ISSUE_DATA_BYTE(0x16);
|
||||
ISSUE_DATA_BYTE(0x15);
|
||||
ISSUE_DATA_BYTE(0x1E);
|
||||
ISSUE_DATA_BYTE(0x21);
|
||||
}
|
||||
|
||||
void lx154a2411_init_seq(void) {
|
||||
// most recent manual:
|
||||
// https://www.newhavendisplay.com/appnotes/datasheets/LCDs/ST7789V.pdf
|
||||
// TEON: Tearing Effect Line On; V-blanking only
|
||||
ISSUE_CMD_BYTE(0x35);
|
||||
ISSUE_DATA_BYTE(0x00);
|
||||
|
||||
// COLMOD: Interface Pixel format; 65K color: 16-bit/pixel (RGB 5-6-5 bits
|
||||
// input)
|
||||
ISSUE_CMD_BYTE(0x3A);
|
||||
ISSUE_DATA_BYTE(0x55);
|
||||
|
||||
// CMD2EN: Commands in command table 2 can be executed when EXTC level is Low
|
||||
ISSUE_CMD_BYTE(0xDF);
|
||||
ISSUE_DATA_BYTE(0x5A);
|
||||
ISSUE_DATA_BYTE(0x69);
|
||||
ISSUE_DATA_BYTE(0x02);
|
||||
ISSUE_DATA_BYTE(0x01);
|
||||
|
||||
// LCMCTRL: LCM Control: XOR RGB setting
|
||||
ISSUE_CMD_BYTE(0xC0);
|
||||
ISSUE_DATA_BYTE(0x20);
|
||||
|
||||
// GATECTRL: Gate Control; NL = 240 gate lines, first scan line is gate 80.;
|
||||
// gate scan direction 319 -> 0
|
||||
ISSUE_CMD_BYTE(0xE4);
|
||||
ISSUE_DATA_BYTE(0x1D);
|
||||
ISSUE_DATA_BYTE(0x0A);
|
||||
ISSUE_DATA_BYTE(0x11);
|
||||
|
||||
// INVOFF (20h): Display Inversion Off
|
||||
// INVON (21h): Display Inversion On
|
||||
ISSUE_CMD_BYTE(0x20);
|
||||
|
||||
// the above config is the most important and definitely necessary
|
||||
|
||||
// PWCTRL1: Power Control 1
|
||||
ISSUE_CMD_BYTE(0xD0);
|
||||
ISSUE_DATA_BYTE(0xA4);
|
||||
ISSUE_DATA_BYTE(0xA1);
|
||||
|
||||
lx154a2411_gamma();
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LX154A2411_H_
|
||||
#define LX154A2411_H_
|
||||
|
||||
// ST7789_V IC controller
|
||||
void lx154a2411_gamma(void);
|
||||
void lx154a2411_init_seq(void);
|
||||
|
||||
#endif
|
@ -0,0 +1,150 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "../display_io.h"
|
||||
#include "touch.h"
|
||||
|
||||
void lx154a2422_gamma(void) {
|
||||
// positive voltage correction
|
||||
ISSUE_CMD_BYTE(0xE0);
|
||||
ISSUE_DATA_BYTE(0xD0);
|
||||
ISSUE_DATA_BYTE(0x0A);
|
||||
ISSUE_DATA_BYTE(0x10);
|
||||
ISSUE_DATA_BYTE(0x0A);
|
||||
ISSUE_DATA_BYTE(0x0A);
|
||||
ISSUE_DATA_BYTE(0x26);
|
||||
ISSUE_DATA_BYTE(0x36);
|
||||
ISSUE_DATA_BYTE(0x34);
|
||||
ISSUE_DATA_BYTE(0x4D);
|
||||
ISSUE_DATA_BYTE(0x18);
|
||||
ISSUE_DATA_BYTE(0x13);
|
||||
ISSUE_DATA_BYTE(0x14);
|
||||
ISSUE_DATA_BYTE(0x2F);
|
||||
ISSUE_DATA_BYTE(0x34);
|
||||
|
||||
// negative voltage correction
|
||||
ISSUE_CMD_BYTE(0xE1);
|
||||
ISSUE_DATA_BYTE(0xD0);
|
||||
ISSUE_DATA_BYTE(0x0A);
|
||||
ISSUE_DATA_BYTE(0x10);
|
||||
ISSUE_DATA_BYTE(0x0A);
|
||||
ISSUE_DATA_BYTE(0x09);
|
||||
ISSUE_DATA_BYTE(0x26);
|
||||
ISSUE_DATA_BYTE(0x36);
|
||||
ISSUE_DATA_BYTE(0x53);
|
||||
ISSUE_DATA_BYTE(0x4C);
|
||||
ISSUE_DATA_BYTE(0x18);
|
||||
ISSUE_DATA_BYTE(0x14);
|
||||
ISSUE_DATA_BYTE(0x14);
|
||||
ISSUE_DATA_BYTE(0x2F);
|
||||
ISSUE_DATA_BYTE(0x34);
|
||||
}
|
||||
|
||||
void lx154a2422_init_seq(void) {
|
||||
// most recent manual:
|
||||
// https://www.newhavendisplay.com/appnotes/datasheets/LCDs/ST7789V.pdf
|
||||
// TEON: Tearing Effect Line On; V-blanking only
|
||||
ISSUE_CMD_BYTE(0x35);
|
||||
ISSUE_DATA_BYTE(0x00);
|
||||
|
||||
// COLMOD: Interface Pixel format; 65K color: 16-bit/pixel (RGB 5-6-5 bits
|
||||
// input)
|
||||
ISSUE_CMD_BYTE(0x3A);
|
||||
ISSUE_DATA_BYTE(0x55);
|
||||
|
||||
// CMD2EN: Commands in command table 2 can be executed when EXTC level is Low
|
||||
ISSUE_CMD_BYTE(0xDF);
|
||||
ISSUE_DATA_BYTE(0x5A);
|
||||
ISSUE_DATA_BYTE(0x69);
|
||||
ISSUE_DATA_BYTE(0x02);
|
||||
ISSUE_DATA_BYTE(0x01);
|
||||
|
||||
// LCMCTRL: LCM Control: XOR RGB setting
|
||||
ISSUE_CMD_BYTE(0xC0);
|
||||
ISSUE_DATA_BYTE(0x20);
|
||||
|
||||
// GATECTRL: Gate Control; NL = 240 gate lines, first scan line is gate 80.;
|
||||
// gate scan direction 319 -> 0
|
||||
ISSUE_CMD_BYTE(0xE4);
|
||||
ISSUE_DATA_BYTE(0x1D);
|
||||
ISSUE_DATA_BYTE(0x0A);
|
||||
ISSUE_DATA_BYTE(0x11);
|
||||
|
||||
// INVOFF (20h): Display Inversion Off
|
||||
// INVON (21h): Display Inversion On
|
||||
ISSUE_CMD_BYTE(0x21);
|
||||
|
||||
// the above config is the most important and definitely necessary
|
||||
|
||||
// PWCTRL1: Power Control 1
|
||||
ISSUE_CMD_BYTE(0xD0);
|
||||
ISSUE_DATA_BYTE(0xA4);
|
||||
ISSUE_DATA_BYTE(0xA1);
|
||||
|
||||
lx154a2422_gamma();
|
||||
}
|
||||
|
||||
void lx154a2422_rotate(int degrees) {
|
||||
uint16_t shift = 0;
|
||||
|
||||
#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 8.12 in the ST7789V manual
|
||||
uint8_t display_command_parameter = 0;
|
||||
switch (degrees) {
|
||||
case 0:
|
||||
display_command_parameter = 0;
|
||||
break;
|
||||
case 90:
|
||||
display_command_parameter = MV | MX | MH | ML;
|
||||
shift = 1;
|
||||
break;
|
||||
case 180:
|
||||
display_command_parameter = MX | MY | MH | ML;
|
||||
shift = 1;
|
||||
break;
|
||||
case 270:
|
||||
display_command_parameter = MV | MY;
|
||||
break;
|
||||
}
|
||||
|
||||
ISSUE_CMD_BYTE(0x36);
|
||||
ISSUE_DATA_BYTE(display_command_parameter);
|
||||
|
||||
if (shift) {
|
||||
// GATECTRL: Gate Control; NL = 240 gate lines, first scan line is
|
||||
// gate 80.; gate scan direction 319 -> 0
|
||||
ISSUE_CMD_BYTE(0xE4);
|
||||
ISSUE_DATA_BYTE(0x1D);
|
||||
ISSUE_DATA_BYTE(0x00);
|
||||
ISSUE_DATA_BYTE(0x11);
|
||||
} else {
|
||||
// GATECTRL: Gate Control; NL = 240 gate lines, first scan line is
|
||||
// gate 80.; gate scan direction 319 -> 0
|
||||
ISSUE_CMD_BYTE(0xE4);
|
||||
ISSUE_DATA_BYTE(0x1D);
|
||||
ISSUE_DATA_BYTE(0x0A);
|
||||
ISSUE_DATA_BYTE(0x11);
|
||||
}
|
||||
}
|
@ -0,0 +1,165 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "../display_io.h"
|
||||
|
||||
void tf15411a_init_seq(void) {
|
||||
// Inter Register Enable1
|
||||
ISSUE_CMD_BYTE(0xFE);
|
||||
|
||||
// Inter Register Enable2
|
||||
ISSUE_CMD_BYTE(0xEF);
|
||||
|
||||
// TEON: Tearing Effect Line On; V-blanking only
|
||||
ISSUE_CMD_BYTE(0x35);
|
||||
ISSUE_DATA_BYTE(0x00);
|
||||
|
||||
// COLMOD: Interface Pixel format; 65K color: 16-bit/pixel (RGB 5-6-5 bits
|
||||
// input)
|
||||
ISSUE_CMD_BYTE(0x3A);
|
||||
ISSUE_DATA_BYTE(0x55);
|
||||
|
||||
// Frame Rate
|
||||
// ISSUE_CMD_BYTE(0xE8); ISSUE_DATA_BYTE(0x12); ISSUE_DATA_BYTE(0x00);
|
||||
|
||||
// Power Control 2
|
||||
ISSUE_CMD_BYTE(0xC3);
|
||||
ISSUE_DATA_BYTE(0x27);
|
||||
|
||||
// Power Control 3
|
||||
ISSUE_CMD_BYTE(0xC4);
|
||||
ISSUE_DATA_BYTE(0x18);
|
||||
|
||||
// Power Control 4
|
||||
ISSUE_CMD_BYTE(0xC9);
|
||||
ISSUE_DATA_BYTE(0x1F);
|
||||
|
||||
ISSUE_CMD_BYTE(0xC5);
|
||||
ISSUE_DATA_BYTE(0x0F);
|
||||
|
||||
ISSUE_CMD_BYTE(0xC6);
|
||||
ISSUE_DATA_BYTE(0x00);
|
||||
|
||||
ISSUE_CMD_BYTE(0xC7);
|
||||
ISSUE_DATA_BYTE(0x10);
|
||||
|
||||
ISSUE_CMD_BYTE(0xC8);
|
||||
ISSUE_DATA_BYTE(0x01);
|
||||
|
||||
ISSUE_CMD_BYTE(0xFF);
|
||||
ISSUE_DATA_BYTE(0x62);
|
||||
|
||||
ISSUE_CMD_BYTE(0x99);
|
||||
ISSUE_DATA_BYTE(0x3E);
|
||||
|
||||
ISSUE_CMD_BYTE(0x9D);
|
||||
ISSUE_DATA_BYTE(0x4B);
|
||||
|
||||
ISSUE_CMD_BYTE(0x8E);
|
||||
ISSUE_DATA_BYTE(0x0F);
|
||||
|
||||
// SET_GAMMA1
|
||||
ISSUE_CMD_BYTE(0xF0);
|
||||
ISSUE_DATA_BYTE(0x8F);
|
||||
ISSUE_DATA_BYTE(0x1B);
|
||||
ISSUE_DATA_BYTE(0x05);
|
||||
ISSUE_DATA_BYTE(0x06);
|
||||
ISSUE_DATA_BYTE(0x07);
|
||||
ISSUE_DATA_BYTE(0x42);
|
||||
|
||||
// SET_GAMMA3
|
||||
ISSUE_CMD_BYTE(0xF2);
|
||||
ISSUE_DATA_BYTE(0x5C);
|
||||
ISSUE_DATA_BYTE(0x1F);
|
||||
ISSUE_DATA_BYTE(0x12);
|
||||
ISSUE_DATA_BYTE(0x10);
|
||||
ISSUE_DATA_BYTE(0x07);
|
||||
ISSUE_DATA_BYTE(0x43);
|
||||
|
||||
// SET_GAMMA2
|
||||
ISSUE_CMD_BYTE(0xF1);
|
||||
ISSUE_DATA_BYTE(0x59);
|
||||
ISSUE_DATA_BYTE(0xCF);
|
||||
ISSUE_DATA_BYTE(0xCF);
|
||||
ISSUE_DATA_BYTE(0x35);
|
||||
ISSUE_DATA_BYTE(0x37);
|
||||
ISSUE_DATA_BYTE(0x8F);
|
||||
|
||||
// SET_GAMMA4
|
||||
ISSUE_CMD_BYTE(0xF3);
|
||||
ISSUE_DATA_BYTE(0x58);
|
||||
ISSUE_DATA_BYTE(0xCF);
|
||||
ISSUE_DATA_BYTE(0xCF);
|
||||
ISSUE_DATA_BYTE(0x35);
|
||||
ISSUE_DATA_BYTE(0x37);
|
||||
ISSUE_DATA_BYTE(0x8F);
|
||||
}
|
||||
|
||||
void tf15411a_rotate(int degrees) {
|
||||
uint16_t shift = 0;
|
||||
|
||||
#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;
|
||||
break;
|
||||
case 90:
|
||||
display_command_parameter = MV | MX | MH | ML;
|
||||
shift = 1;
|
||||
break;
|
||||
case 180:
|
||||
display_command_parameter = MX | MY | MH | ML;
|
||||
shift = 1;
|
||||
break;
|
||||
case 270:
|
||||
display_command_parameter = MV | MY;
|
||||
break;
|
||||
}
|
||||
|
||||
display_command_parameter ^= RGB | MY; // XOR RGB and MY settings
|
||||
|
||||
ISSUE_CMD_BYTE(0x36);
|
||||
ISSUE_DATA_BYTE(display_command_parameter);
|
||||
|
||||
if (shift) {
|
||||
// GATECTRL: Gate Control; NL = 240 gate lines, first scan line is
|
||||
// gate 80.; gate scan direction 319 -> 0
|
||||
ISSUE_CMD_BYTE(0xE4);
|
||||
ISSUE_DATA_BYTE(0x1D);
|
||||
ISSUE_DATA_BYTE(0x00);
|
||||
ISSUE_DATA_BYTE(0x11);
|
||||
} else {
|
||||
// GATECTRL: Gate Control; NL = 240 gate lines, first scan line is
|
||||
// gate 80.; gate scan direction 319 -> 0
|
||||
ISSUE_CMD_BYTE(0xE4);
|
||||
ISSUE_DATA_BYTE(0x1D);
|
||||
ISSUE_DATA_BYTE(0x0A);
|
||||
ISSUE_DATA_BYTE(0x11);
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TF15411A_H_
|
||||
#define TF15411A_H_
|
||||
|
||||
// GC9307 IC controller
|
||||
|
||||
void tf15411a_init_seq(void);
|
||||
void tf15411a_rotate(int degrees);
|
||||
|
||||
#endif
|
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include TREZOR_BOARD
|
||||
#include STM32_HAL_H
|
||||
|
||||
#include "display_internal.h"
|
||||
#include "ili9341_spi.h"
|
||||
#include "xdisplay.h"
|
||||
|
||||
#if (DISPLAY_RESX != 240) || (DISPLAY_RESY != 320)
|
||||
#error "Incompatible display resolution"
|
||||
#endif
|
||||
|
||||
// Display driver context.
|
||||
typedef struct {
|
||||
// Current display orientation (0, 90, 180, 270)
|
||||
int orientation_angle;
|
||||
// Current backlight level ranging from 0 to 255
|
||||
int backlight_level;
|
||||
} display_driver_t;
|
||||
|
||||
// Display driver instance
|
||||
static display_driver_t g_display_driver;
|
||||
|
||||
void display_init(void) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
memset(drv, 0, sizeof(display_driver_t));
|
||||
|
||||
// Initialize LTDC controller
|
||||
BSP_LCD_Init();
|
||||
// Initialize external display controller
|
||||
ili9341_init();
|
||||
}
|
||||
|
||||
void display_reinit(void) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
memset(drv, 0, sizeof(display_driver_t));
|
||||
}
|
||||
|
||||
void display_finish_actions(void) {
|
||||
// Not used and intentionally left empty
|
||||
}
|
||||
|
||||
int display_set_backlight(int level) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
// Just emulation, not doing anything
|
||||
drv->backlight_level = level;
|
||||
return level;
|
||||
}
|
||||
|
||||
int display_get_backlight(void) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
return drv->backlight_level;
|
||||
}
|
||||
|
||||
int display_set_orientation(int angle) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
if (angle == 0 || angle == 90 || angle == 180 || angle == 270) {
|
||||
// Just emulation, not doing anything
|
||||
drv->orientation_angle = angle;
|
||||
}
|
||||
|
||||
return drv->orientation_angle;
|
||||
}
|
||||
|
||||
int display_get_orientation(void) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
return drv->orientation_angle;
|
||||
}
|
||||
|
||||
void *display_get_frame_addr(void) { return (void *)FRAME_BUFFER_ADDR; }
|
||||
|
||||
void display_refresh(void) {
|
||||
// Do nothing as using just a single frame buffer
|
||||
}
|
||||
|
||||
const char *display_save(const char *prefix) { return NULL; }
|
||||
|
||||
void display_clear_save(void) {}
|
||||
|
||||
void display_set_compatible_settings() {}
|
||||
|
||||
// Functions for drawing on display
|
||||
/*
|
||||
|
||||
// Fills a rectangle with a specified color
|
||||
void display_fill(gdc_dma2d_t *dp);
|
||||
|
||||
// Copies an RGB565 bitmap to specified rectangle
|
||||
void display_copy_rgb565(gdc_dma2d_t *dp);
|
||||
|
||||
// Copies a MONO4 bitmap to specified rectangle
|
||||
void display_copy_mono4(gdc_dma2d_t *dp);
|
||||
|
||||
// Copies a MONO1P bitmap to specified rectangle
|
||||
void display_copy_mono1p(gdc_dma2d_t *dp);
|
||||
*/
|
@ -0,0 +1,291 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include TREZOR_BOARD
|
||||
#include STM32_HAL_H
|
||||
|
||||
#include "display_internal.h"
|
||||
#include "ili9341_spi.h"
|
||||
#include "xdisplay.h"
|
||||
|
||||
#define MAX_LAYER_NUMBER 2
|
||||
|
||||
LTDC_HandleTypeDef LtdcHandler;
|
||||
static RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;
|
||||
|
||||
/* Default LCD configuration with LCD Layer 1 */
|
||||
uint32_t ActiveLayer = 0;
|
||||
|
||||
/**
|
||||
* @brief Initializes the LCD layers.
|
||||
* @param LayerIndex: the layer foreground or background.
|
||||
* @param FB_Address: the layer frame buffer.
|
||||
*/
|
||||
void BSP_LCD_LayerDefaultInit(uint16_t LayerIndex, uint32_t FB_Address) {
|
||||
LTDC_LayerCfgTypeDef Layercfg;
|
||||
|
||||
/* Layer Init */
|
||||
Layercfg.WindowX0 = 0;
|
||||
Layercfg.WindowX1 = DISPLAY_RESX;
|
||||
Layercfg.WindowY0 = 0;
|
||||
Layercfg.WindowY1 = DISPLAY_RESY;
|
||||
Layercfg.PixelFormat = LTDC_PIXEL_FORMAT_RGB565;
|
||||
Layercfg.FBStartAdress = FB_Address;
|
||||
Layercfg.Alpha = 255;
|
||||
Layercfg.Alpha0 = 0;
|
||||
Layercfg.Backcolor.Blue = 0;
|
||||
Layercfg.Backcolor.Green = 0;
|
||||
Layercfg.Backcolor.Red = 0;
|
||||
Layercfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA;
|
||||
Layercfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA;
|
||||
Layercfg.ImageWidth = DISPLAY_RESX;
|
||||
Layercfg.ImageHeight = DISPLAY_RESY;
|
||||
|
||||
HAL_LTDC_ConfigLayer(&LtdcHandler, &Layercfg, LayerIndex);
|
||||
|
||||
// DrawProp[LayerIndex].BackColor = LCD_COLOR_WHITE;
|
||||
// DrawProp[LayerIndex].pFont = &Font24;
|
||||
// DrawProp[LayerIndex].TextColor = LCD_COLOR_BLACK;
|
||||
|
||||
/* Dithering activation */
|
||||
HAL_LTDC_EnableDither(&LtdcHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Selects the LCD Layer.
|
||||
* @param LayerIndex: the Layer foreground or background.
|
||||
*/
|
||||
void BSP_LCD_SelectLayer(uint32_t LayerIndex) { ActiveLayer = LayerIndex; }
|
||||
|
||||
/**
|
||||
* @brief Sets a LCD Layer visible.
|
||||
* @param LayerIndex: the visible Layer.
|
||||
* @param state: new state of the specified layer.
|
||||
* This parameter can be: ENABLE or DISABLE.
|
||||
*/
|
||||
void BSP_LCD_SetLayerVisible(uint32_t LayerIndex, FunctionalState state) {
|
||||
if (state == ENABLE) {
|
||||
__HAL_LTDC_LAYER_ENABLE(&LtdcHandler, LayerIndex);
|
||||
} else {
|
||||
__HAL_LTDC_LAYER_DISABLE(&LtdcHandler, LayerIndex);
|
||||
}
|
||||
__HAL_LTDC_RELOAD_CONFIG(&LtdcHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets an LCD Layer visible without reloading.
|
||||
* @param LayerIndex: Visible Layer
|
||||
* @param State: New state of the specified layer
|
||||
* This parameter can be one of the following values:
|
||||
* @arg ENABLE
|
||||
* @arg DISABLE
|
||||
* @retval None
|
||||
*/
|
||||
void BSP_LCD_SetLayerVisible_NoReload(uint32_t LayerIndex,
|
||||
FunctionalState State) {
|
||||
if (State == ENABLE) {
|
||||
__HAL_LTDC_LAYER_ENABLE(&LtdcHandler, LayerIndex);
|
||||
} else {
|
||||
__HAL_LTDC_LAYER_DISABLE(&LtdcHandler, LayerIndex);
|
||||
}
|
||||
/* Do not Sets the Reload */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures the Transparency.
|
||||
* @param LayerIndex: the Layer foreground or background.
|
||||
* @param Transparency: the Transparency,
|
||||
* This parameter must range from 0x00 to 0xFF.
|
||||
*/
|
||||
void BSP_LCD_SetTransparency(uint32_t LayerIndex, uint8_t Transparency) {
|
||||
HAL_LTDC_SetAlpha(&LtdcHandler, Transparency, LayerIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures the transparency without reloading.
|
||||
* @param LayerIndex: Layer foreground or background.
|
||||
* @param Transparency: Transparency
|
||||
* This parameter must be a number between Min_Data = 0x00 and
|
||||
* Max_Data = 0xFF
|
||||
* @retval None
|
||||
*/
|
||||
void BSP_LCD_SetTransparency_NoReload(uint32_t LayerIndex,
|
||||
uint8_t Transparency) {
|
||||
HAL_LTDC_SetAlpha_NoReload(&LtdcHandler, Transparency, LayerIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets a LCD layer frame buffer address.
|
||||
* @param LayerIndex: specifies the Layer foreground or background
|
||||
* @param Address: new LCD frame buffer value
|
||||
*/
|
||||
void BSP_LCD_SetLayerAddress(uint32_t LayerIndex, uint32_t Address) {
|
||||
HAL_LTDC_SetAddress(&LtdcHandler, Address, LayerIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets an LCD layer frame buffer address without reloading.
|
||||
* @param LayerIndex: Layer foreground or background
|
||||
* @param Address: New LCD frame buffer value
|
||||
* @retval None
|
||||
*/
|
||||
void BSP_LCD_SetLayerAddress_NoReload(uint32_t LayerIndex, uint32_t Address) {
|
||||
HAL_LTDC_SetAddress_NoReload(&LtdcHandler, Address, LayerIndex);
|
||||
}
|
||||
|
||||
void BSP_LCD_Init(void) {
|
||||
GPIO_InitTypeDef GPIO_InitStructure = {0};
|
||||
|
||||
/* Enable the LTDC and DMA2D Clock */
|
||||
__HAL_RCC_LTDC_CLK_ENABLE();
|
||||
__HAL_RCC_DMA2D_CLK_ENABLE();
|
||||
|
||||
/* Enable GPIOs clock */
|
||||
__HAL_RCC_GPIOA_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOB_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOC_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOD_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOF_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOG_CLK_ENABLE();
|
||||
|
||||
/* GPIOs Configuration */
|
||||
/*
|
||||
+------------------------+-----------------------+----------------------------+
|
||||
+ LCD pins assignment +
|
||||
+------------------------+-----------------------+----------------------------+
|
||||
| LCD_TFT R2 <-> PC.10 | LCD_TFT G2 <-> PA.06 | LCD_TFT B2 <-> PD.06 | |
|
||||
LCD_TFT R3 <-> PB.00 | LCD_TFT G3 <-> PG.10 | LCD_TFT B3 <-> PG.11 |
|
||||
| LCD_TFT R4 <-> PA.11 | LCD_TFT G4 <-> PB.10 | LCD_TFT B4 <-> PG.12 | |
|
||||
LCD_TFT R5 <-> PA.12 | LCD_TFT G5 <-> PB.11 | LCD_TFT B5 <-> PA.03 |
|
||||
| LCD_TFT R6 <-> PB.01 | LCD_TFT G6 <-> PC.07 | LCD_TFT B6 <-> PB.08 | |
|
||||
LCD_TFT R7 <-> PG.06 | LCD_TFT G7 <-> PD.03 | LCD_TFT B7 <-> PB.09 |
|
||||
-------------------------------------------------------------------------------
|
||||
| LCD_TFT HSYNC <-> PC.06 | LCDTFT VSYNC <-> PA.04 |
|
||||
| LCD_TFT CLK <-> PG.07 | LCD_TFT DE <-> PF.10 |
|
||||
-----------------------------------------------------
|
||||
*/
|
||||
|
||||
/* GPIOA configuration */
|
||||
GPIO_InitStructure.Pin =
|
||||
GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_6 | GPIO_PIN_11 | GPIO_PIN_12;
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStructure.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
|
||||
GPIO_InitStructure.Alternate = GPIO_AF14_LTDC;
|
||||
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
|
||||
|
||||
/* GPIOB configuration */
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11;
|
||||
HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
|
||||
|
||||
/* GPIOC configuration */
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_10;
|
||||
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
|
||||
|
||||
/* GPIOD configuration */
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_3 | GPIO_PIN_6;
|
||||
HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
|
||||
|
||||
/* GPIOF configuration */
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_10;
|
||||
HAL_GPIO_Init(GPIOF, &GPIO_InitStructure);
|
||||
|
||||
/* GPIOG configuration */
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_11;
|
||||
HAL_GPIO_Init(GPIOG, &GPIO_InitStructure);
|
||||
|
||||
/* GPIOB configuration */
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_0 | GPIO_PIN_1;
|
||||
GPIO_InitStructure.Alternate = GPIO_AF9_LTDC;
|
||||
HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
|
||||
|
||||
/* GPIOG configuration */
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_10 | GPIO_PIN_12;
|
||||
HAL_GPIO_Init(GPIOG, &GPIO_InitStructure);
|
||||
|
||||
/* On STM32F429I-DISCO, it is not possible to read ILI9341 ID because */
|
||||
/* PIN EXTC is not connected to VDD and then LCD_READ_ID4 is not accessible.
|
||||
*/
|
||||
/* In this case, ReadID function is bypassed.*/
|
||||
/*if(ili9341_drv.ReadID() == ILI9341_ID)*/
|
||||
|
||||
/* LTDC Configuration ----------------------------------------------------*/
|
||||
LtdcHandler.Instance = LTDC;
|
||||
|
||||
/* Timing configuration (Typical configuration from ILI9341 datasheet)
|
||||
HSYNC=10 (9+1)
|
||||
HBP=20 (29-10+1)
|
||||
ActiveW=240 (269-20-10+1)
|
||||
HFP=10 (279-240-20-10+1)
|
||||
|
||||
VSYNC=2 (1+1)
|
||||
VBP=2 (3-2+1)
|
||||
ActiveH=320 (323-2-2+1)
|
||||
VFP=4 (327-320-2-2+1)
|
||||
*/
|
||||
|
||||
/* Configure horizontal synchronization width */
|
||||
LtdcHandler.Init.HorizontalSync = ILI9341_HSYNC;
|
||||
/* Configure vertical synchronization height */
|
||||
LtdcHandler.Init.VerticalSync = ILI9341_VSYNC;
|
||||
/* Configure accumulated horizontal back porch */
|
||||
LtdcHandler.Init.AccumulatedHBP = ILI9341_HBP;
|
||||
/* Configure accumulated vertical back porch */
|
||||
LtdcHandler.Init.AccumulatedVBP = ILI9341_VBP;
|
||||
/* Configure accumulated active width */
|
||||
LtdcHandler.Init.AccumulatedActiveW = 269;
|
||||
/* Configure accumulated active height */
|
||||
LtdcHandler.Init.AccumulatedActiveH = 323;
|
||||
/* Configure total width */
|
||||
LtdcHandler.Init.TotalWidth = 279;
|
||||
/* Configure total height */
|
||||
LtdcHandler.Init.TotalHeigh = 327;
|
||||
|
||||
/* Configure R,G,B component values for LCD background color */
|
||||
LtdcHandler.Init.Backcolor.Red = 0;
|
||||
LtdcHandler.Init.Backcolor.Blue = 0;
|
||||
LtdcHandler.Init.Backcolor.Green = 0;
|
||||
|
||||
/* LCD clock configuration */
|
||||
/* PLLSAI_VCO Input = HSE_VALUE/PLL_M = 1 Mhz */
|
||||
/* PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAIN = 192 Mhz */
|
||||
/* PLLLCDCLK = PLLSAI_VCO Output/PLLSAIR = 192/4 = 48 Mhz */
|
||||
/* LTDC clock frequency = PLLLCDCLK / LTDC_PLLSAI_DIVR_8 = 48/4 = 6Mhz */
|
||||
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC;
|
||||
PeriphClkInitStruct.PLLSAI.PLLSAIN = 192;
|
||||
PeriphClkInitStruct.PLLSAI.PLLSAIR = 4;
|
||||
PeriphClkInitStruct.PLLSAIDivR = RCC_PLLSAIDIVR_8;
|
||||
HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
|
||||
|
||||
/* Polarity */
|
||||
LtdcHandler.Init.HSPolarity = LTDC_HSPOLARITY_AL;
|
||||
LtdcHandler.Init.VSPolarity = LTDC_VSPOLARITY_AL;
|
||||
LtdcHandler.Init.DEPolarity = LTDC_DEPOLARITY_AL;
|
||||
LtdcHandler.Init.PCPolarity = LTDC_PCPOLARITY_IPC;
|
||||
|
||||
HAL_LTDC_Init(&LtdcHandler);
|
||||
|
||||
/* Initialize the LCD Layers */
|
||||
BSP_LCD_LayerDefaultInit(1, FRAME_BUFFER_ADDR);
|
||||
|
||||
memset((void *)FRAME_BUFFER_ADDR, 0, FRAME_BUFFER_SIZE);
|
||||
}
|
@ -0,0 +1,512 @@
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include TREZOR_BOARD
|
||||
#include "ili9341_spi.h"
|
||||
#include STM32_HAL_H
|
||||
|
||||
/**
|
||||
* @brief ILI9341 chip IDs
|
||||
*/
|
||||
#define ILI9341_ID 0x9341
|
||||
|
||||
/**
|
||||
* @brief ILI9341 Size
|
||||
*/
|
||||
#define ILI9341_LCD_PIXEL_WIDTH ((uint16_t)240)
|
||||
#define ILI9341_LCD_PIXEL_HEIGHT ((uint16_t)320)
|
||||
|
||||
/**
|
||||
* @brief ILI9341 Timing
|
||||
*/
|
||||
/* Timing configuration (Typical configuration from ILI9341 datasheet)
|
||||
HSYNC=10 (9+1)
|
||||
HBP=20 (29-10+1)
|
||||
ActiveW=240 (269-20-10+1)
|
||||
HFP=10 (279-240-20-10+1)
|
||||
|
||||
VSYNC=2 (1+1)
|
||||
VBP=2 (3-2+1)
|
||||
ActiveH=320 (323-2-2+1)
|
||||
VFP=4 (327-320-2-2+1)
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief ILI9341 Registers
|
||||
*/
|
||||
|
||||
/* Level 1 Commands */
|
||||
#define LCD_SWRESET 0x01 /* Software Reset */
|
||||
#define LCD_READ_DISPLAY_ID 0x04 /* Read display identification information */
|
||||
#define LCD_RDDST 0x09 /* Read Display Status */
|
||||
#define LCD_RDDPM 0x0A /* Read Display Power Mode */
|
||||
#define LCD_RDDMADCTL 0x0B /* Read Display MADCTL */
|
||||
#define LCD_RDDCOLMOD 0x0C /* Read Display Pixel Format */
|
||||
#define LCD_RDDIM 0x0D /* Read Display Image Format */
|
||||
#define LCD_RDDSM 0x0E /* Read Display Signal Mode */
|
||||
#define LCD_RDDSDR 0x0F /* Read Display Self-Diagnostic Result */
|
||||
#define LCD_SPLIN 0x10 /* Enter Sleep Mode */
|
||||
#define LCD_SLEEP_OUT 0x11 /* Sleep out register */
|
||||
#define LCD_PTLON 0x12 /* Partial Mode ON */
|
||||
#define LCD_NORMAL_MODE_ON 0x13 /* Normal Display Mode ON */
|
||||
#define LCD_DINVOFF 0x20 /* Display Inversion OFF */
|
||||
#define LCD_DINVON 0x21 /* Display Inversion ON */
|
||||
#define LCD_GAMMA 0x26 /* Gamma register */
|
||||
#define LCD_DISPLAY_OFF 0x28 /* Display off register */
|
||||
#define LCD_DISPLAY_ON 0x29 /* Display on register */
|
||||
#define LCD_COLUMN_ADDR 0x2A /* Colomn address register */
|
||||
#define LCD_PAGE_ADDR 0x2B /* Page address register */
|
||||
#define LCD_GRAM 0x2C /* GRAM register */
|
||||
#define LCD_RGBSET 0x2D /* Color SET */
|
||||
#define LCD_RAMRD 0x2E /* Memory Read */
|
||||
#define LCD_PLTAR 0x30 /* Partial Area */
|
||||
#define LCD_VSCRDEF 0x33 /* Vertical Scrolling Definition */
|
||||
#define LCD_TEOFF 0x34 /* Tearing Effect Line OFF */
|
||||
#define LCD_TEON 0x35 /* Tearing Effect Line ON */
|
||||
#define LCD_MAC 0x36 /* Memory Access Control register*/
|
||||
#define LCD_VSCRSADD 0x37 /* Vertical Scrolling Start Address */
|
||||
#define LCD_IDMOFF 0x38 /* Idle Mode OFF */
|
||||
#define LCD_IDMON 0x39 /* Idle Mode ON */
|
||||
#define LCD_PIXEL_FORMAT 0x3A /* Pixel Format register */
|
||||
#define LCD_WRITE_MEM_CONTINUE 0x3C /* Write Memory Continue */
|
||||
#define LCD_READ_MEM_CONTINUE 0x3E /* Read Memory Continue */
|
||||
#define LCD_SET_TEAR_SCANLINE 0x44 /* Set Tear Scanline */
|
||||
#define LCD_GET_SCANLINE 0x45 /* Get Scanline */
|
||||
#define LCD_WDB 0x51 /* Write Brightness Display register */
|
||||
#define LCD_RDDISBV 0x52 /* Read Display Brightness */
|
||||
#define LCD_WCD 0x53 /* Write Control Display register*/
|
||||
#define LCD_RDCTRLD 0x54 /* Read CTRL Display */
|
||||
#define LCD_WRCABC 0x55 /* Write Content Adaptive Brightness Control */
|
||||
#define LCD_RDCABC 0x56 /* Read Content Adaptive Brightness Control */
|
||||
#define LCD_WRITE_CABC 0x5E /* Write CABC Minimum Brightness */
|
||||
#define LCD_READ_CABC 0x5F /* Read CABC Minimum Brightness */
|
||||
#define LCD_READ_ID1 0xDA /* Read ID1 */
|
||||
#define LCD_READ_ID2 0xDB /* Read ID2 */
|
||||
#define LCD_READ_ID3 0xDC /* Read ID3 */
|
||||
|
||||
/* Level 2 Commands */
|
||||
#define LCD_RGB_INTERFACE 0xB0 /* RGB Interface Signal Control */
|
||||
#define LCD_FRMCTR1 0xB1 /* Frame Rate Control (In Normal Mode) */
|
||||
#define LCD_FRMCTR2 0xB2 /* Frame Rate Control (In Idle Mode) */
|
||||
#define LCD_FRMCTR3 0xB3 /* Frame Rate Control (In Partial Mode) */
|
||||
#define LCD_INVTR 0xB4 /* Display Inversion Control */
|
||||
#define LCD_BPC 0xB5 /* Blanking Porch Control register */
|
||||
#define LCD_DFC 0xB6 /* Display Function Control register */
|
||||
#define LCD_ETMOD 0xB7 /* Entry Mode Set */
|
||||
#define LCD_BACKLIGHT1 0xB8 /* Backlight Control 1 */
|
||||
#define LCD_BACKLIGHT2 0xB9 /* Backlight Control 2 */
|
||||
#define LCD_BACKLIGHT3 0xBA /* Backlight Control 3 */
|
||||
#define LCD_BACKLIGHT4 0xBB /* Backlight Control 4 */
|
||||
#define LCD_BACKLIGHT5 0xBC /* Backlight Control 5 */
|
||||
#define LCD_BACKLIGHT7 0xBE /* Backlight Control 7 */
|
||||
#define LCD_BACKLIGHT8 0xBF /* Backlight Control 8 */
|
||||
#define LCD_POWER1 0xC0 /* Power Control 1 register */
|
||||
#define LCD_POWER2 0xC1 /* Power Control 2 register */
|
||||
#define LCD_VCOM1 0xC5 /* VCOM Control 1 register */
|
||||
#define LCD_VCOM2 0xC7 /* VCOM Control 2 register */
|
||||
#define LCD_NVMWR 0xD0 /* NV Memory Write */
|
||||
#define LCD_NVMPKEY 0xD1 /* NV Memory Protection Key */
|
||||
#define LCD_RDNVM 0xD2 /* NV Memory Status Read */
|
||||
#define LCD_READ_ID4 0xD3 /* Read ID4 */
|
||||
#define LCD_PGAMMA 0xE0 /* Positive Gamma Correction register */
|
||||
#define LCD_NGAMMA 0xE1 /* Negative Gamma Correction register */
|
||||
#define LCD_DGAMCTRL1 0xE2 /* Digital Gamma Control 1 */
|
||||
#define LCD_DGAMCTRL2 0xE3 /* Digital Gamma Control 2 */
|
||||
#define LCD_INTERFACE 0xF6 /* Interface control register */
|
||||
|
||||
/* Extend register commands */
|
||||
#define LCD_POWERA 0xCB /* Power control A register */
|
||||
#define LCD_POWERB 0xCF /* Power control B register */
|
||||
#define LCD_DTCA 0xE8 /* Driver timing control A */
|
||||
#define LCD_DTCB 0xEA /* Driver timing control B */
|
||||
#define LCD_POWER_SEQ 0xED /* Power on sequence register */
|
||||
#define LCD_3GAMMA_EN 0xF2 /* 3 Gamma enable register */
|
||||
#define LCD_PRC 0xF7 /* Pump ratio control register */
|
||||
|
||||
/* Size of read registers */
|
||||
#define LCD_READ_ID4_SIZE 3 /* Size of Read ID4 */
|
||||
|
||||
/*############################### SPIx #######################################*/
|
||||
#define DISCOVERY_SPIx SPI5
|
||||
#define DISCOVERY_SPIx_CLK_ENABLE() __HAL_RCC_SPI5_CLK_ENABLE()
|
||||
#define DISCOVERY_SPIx_GPIO_PORT GPIOF /* GPIOF */
|
||||
#define DISCOVERY_SPIx_AF GPIO_AF5_SPI5
|
||||
#define DISCOVERY_SPIx_GPIO_CLK_ENABLE() __HAL_RCC_GPIOF_CLK_ENABLE()
|
||||
#define DISCOVERY_SPIx_GPIO_CLK_DISABLE() __HAL_RCC_GPIOF_CLK_DISABLE()
|
||||
#define DISCOVERY_SPIx_SCK_PIN GPIO_PIN_7 /* PF.07 */
|
||||
#define DISCOVERY_SPIx_MISO_PIN GPIO_PIN_8 /* PF.08 */
|
||||
#define DISCOVERY_SPIx_MOSI_PIN GPIO_PIN_9 /* PF.09 */
|
||||
/* Maximum Timeout values for flags waiting loops. These timeouts are not based
|
||||
on accurate values, they just guarantee that the application will not remain
|
||||
stuck if the SPI communication is corrupted.
|
||||
You may modify these timeout values depending on CPU frequency and
|
||||
application conditions (interrupts routines ...). */
|
||||
#define SPIx_TIMEOUT_MAX ((uint32_t)0x1000)
|
||||
|
||||
/*################################ LCD #######################################*/
|
||||
/* Chip Select macro definition */
|
||||
#define LCD_CS_LOW() \
|
||||
HAL_GPIO_WritePin(LCD_NCS_GPIO_PORT, LCD_NCS_PIN, GPIO_PIN_RESET)
|
||||
#define LCD_CS_HIGH() \
|
||||
HAL_GPIO_WritePin(LCD_NCS_GPIO_PORT, LCD_NCS_PIN, GPIO_PIN_SET)
|
||||
|
||||
/* Set WRX High to send data */
|
||||
#define LCD_WRX_LOW() \
|
||||
HAL_GPIO_WritePin(LCD_WRX_GPIO_PORT, LCD_WRX_PIN, GPIO_PIN_RESET)
|
||||
#define LCD_WRX_HIGH() \
|
||||
HAL_GPIO_WritePin(LCD_WRX_GPIO_PORT, LCD_WRX_PIN, GPIO_PIN_SET)
|
||||
|
||||
/* Set WRX High to send data */
|
||||
#define LCD_RDX_LOW() \
|
||||
HAL_GPIO_WritePin(LCD_RDX_GPIO_PORT, LCD_RDX_PIN, GPIO_PIN_RESET)
|
||||
#define LCD_RDX_HIGH() \
|
||||
HAL_GPIO_WritePin(LCD_RDX_GPIO_PORT, LCD_RDX_PIN, GPIO_PIN_SET)
|
||||
|
||||
/**
|
||||
* @brief LCD Control pin
|
||||
*/
|
||||
#define LCD_NCS_PIN GPIO_PIN_2
|
||||
#define LCD_NCS_GPIO_PORT GPIOC
|
||||
#define LCD_NCS_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE()
|
||||
#define LCD_NCS_GPIO_CLK_DISABLE() __HAL_RCC_GPIOC_CLK_DISABLE()
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
/**
|
||||
* @brief LCD Command/data pin
|
||||
*/
|
||||
#define LCD_WRX_PIN GPIO_PIN_13
|
||||
#define LCD_WRX_GPIO_PORT GPIOD
|
||||
#define LCD_WRX_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE()
|
||||
#define LCD_WRX_GPIO_CLK_DISABLE() __HAL_RCC_GPIOD_CLK_DISABLE()
|
||||
|
||||
#define LCD_RDX_PIN GPIO_PIN_12
|
||||
#define LCD_RDX_GPIO_PORT GPIOD
|
||||
#define LCD_RDX_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE()
|
||||
#define LCD_RDX_GPIO_CLK_DISABLE() __HAL_RCC_GPIOD_CLK_DISABLE()
|
||||
|
||||
static SPI_HandleTypeDef SpiHandle;
|
||||
uint32_t SpixTimeout =
|
||||
SPIx_TIMEOUT_MAX; /*<! Value of Timeout when SPI communication fails */
|
||||
|
||||
/* SPIx bus function */
|
||||
static void SPIx_Init(void);
|
||||
static void ili9341_Write(uint16_t Value);
|
||||
static uint32_t ili9341_Read(uint8_t ReadSize);
|
||||
static void ili9341_Error(void);
|
||||
|
||||
/**
|
||||
* @brief SPIx Bus initialization
|
||||
*/
|
||||
static void SPIx_Init(void) {
|
||||
if (HAL_SPI_GetState(&SpiHandle) == HAL_SPI_STATE_RESET) {
|
||||
/* SPI configuration -----------------------------------------------------*/
|
||||
SpiHandle.Instance = DISCOVERY_SPIx;
|
||||
/* SPI baudrate is set to 5.6 MHz (PCLK2/SPI_BaudRatePrescaler = 90/16
|
||||
= 5.625 MHz) to verify these constraints:
|
||||
- ILI9341 LCD SPI interface max baudrate is 10MHz for write and 6.66MHz
|
||||
for read
|
||||
- l3gd20 SPI interface max baudrate is 10MHz for write/read
|
||||
- PCLK2 frequency is set to 90 MHz
|
||||
*/
|
||||
SpiHandle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
|
||||
|
||||
/* On STM32F429I-Discovery, LCD ID cannot be read then keep a common
|
||||
* configuration */
|
||||
/* for LCD and GYRO (SPI_DIRECTION_2LINES) */
|
||||
/* Note: To read a register a LCD, SPI_DIRECTION_1LINE should be set */
|
||||
SpiHandle.Init.Direction = SPI_DIRECTION_2LINES;
|
||||
SpiHandle.Init.CLKPhase = SPI_PHASE_1EDGE;
|
||||
SpiHandle.Init.CLKPolarity = SPI_POLARITY_LOW;
|
||||
SpiHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED;
|
||||
SpiHandle.Init.CRCPolynomial = 7;
|
||||
SpiHandle.Init.DataSize = SPI_DATASIZE_8BIT;
|
||||
SpiHandle.Init.FirstBit = SPI_FIRSTBIT_MSB;
|
||||
SpiHandle.Init.NSS = SPI_NSS_SOFT;
|
||||
SpiHandle.Init.TIMode = SPI_TIMODE_DISABLED;
|
||||
SpiHandle.Init.Mode = SPI_MODE_MASTER;
|
||||
|
||||
HAL_SPI_Init(&SpiHandle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief SPIx error treatment function.
|
||||
*/
|
||||
static void ili9341_Error(void) {
|
||||
/* De-initialize the SPI communication BUS */
|
||||
HAL_SPI_DeInit(&SpiHandle);
|
||||
|
||||
/* Re- Initialize the SPI communication BUS */
|
||||
SPIx_Init();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reads 4 bytes from device.
|
||||
* @param ReadSize: Number of bytes to read (max 4 bytes)
|
||||
* @retval Value read on the SPI
|
||||
*/
|
||||
static uint32_t ili9341_Read(uint8_t ReadSize) {
|
||||
HAL_StatusTypeDef status = HAL_OK;
|
||||
uint32_t readvalue;
|
||||
|
||||
status =
|
||||
HAL_SPI_Receive(&SpiHandle, (uint8_t*)&readvalue, ReadSize, SpixTimeout);
|
||||
|
||||
/* Check the communication status */
|
||||
if (status != HAL_OK) {
|
||||
/* Re-Initialize the BUS */
|
||||
ili9341_Error();
|
||||
}
|
||||
|
||||
return readvalue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Writes a byte to device.
|
||||
* @param Value: value to be written
|
||||
*/
|
||||
static void ili9341_Write(uint16_t Value) {
|
||||
HAL_StatusTypeDef status = HAL_OK;
|
||||
|
||||
status = HAL_SPI_Transmit(&SpiHandle, (uint8_t*)&Value, 1, SpixTimeout);
|
||||
|
||||
/* Check the communication status */
|
||||
if (status != HAL_OK) {
|
||||
/* Re-Initialize the BUS */
|
||||
ili9341_Error();
|
||||
}
|
||||
}
|
||||
|
||||
void ili9341_spi_init(void) {
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
|
||||
/* Configure NCS in Output Push-Pull mode */
|
||||
LCD_WRX_GPIO_CLK_ENABLE();
|
||||
GPIO_InitStructure.Pin = LCD_WRX_PIN;
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
|
||||
GPIO_InitStructure.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
|
||||
HAL_GPIO_Init(LCD_WRX_GPIO_PORT, &GPIO_InitStructure);
|
||||
|
||||
LCD_RDX_GPIO_CLK_ENABLE();
|
||||
GPIO_InitStructure.Pin = LCD_RDX_PIN;
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
|
||||
GPIO_InitStructure.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
|
||||
HAL_GPIO_Init(LCD_RDX_GPIO_PORT, &GPIO_InitStructure);
|
||||
|
||||
/* Configure the LCD Control pins ----------------------------------------*/
|
||||
LCD_NCS_GPIO_CLK_ENABLE();
|
||||
|
||||
/* Configure NCS in Output Push-Pull mode */
|
||||
GPIO_InitStructure.Pin = LCD_NCS_PIN;
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
|
||||
GPIO_InitStructure.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
|
||||
HAL_GPIO_Init(LCD_NCS_GPIO_PORT, &GPIO_InitStructure);
|
||||
|
||||
/* Set or Reset the control line */
|
||||
LCD_CS_LOW();
|
||||
LCD_CS_HIGH();
|
||||
|
||||
/* Enable SPIx clock */
|
||||
DISCOVERY_SPIx_CLK_ENABLE();
|
||||
|
||||
/* Enable DISCOVERY_SPI GPIO clock */
|
||||
DISCOVERY_SPIx_GPIO_CLK_ENABLE();
|
||||
|
||||
/* configure SPI SCK, MOSI and MISO */
|
||||
GPIO_InitStructure.Pin = (DISCOVERY_SPIx_SCK_PIN | DISCOVERY_SPIx_MOSI_PIN |
|
||||
DISCOVERY_SPIx_MISO_PIN);
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStructure.Pull = GPIO_PULLDOWN;
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_MEDIUM;
|
||||
GPIO_InitStructure.Alternate = DISCOVERY_SPIx_AF;
|
||||
HAL_GPIO_Init(DISCOVERY_SPIx_GPIO_PORT, &GPIO_InitStructure);
|
||||
|
||||
SPIx_Init();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Writes register value.
|
||||
*/
|
||||
void ili9341_WriteData(uint16_t RegValue) {
|
||||
/* Set WRX to send data */
|
||||
LCD_WRX_HIGH();
|
||||
|
||||
/* Reset LCD control line(/CS) and Send data */
|
||||
LCD_CS_LOW();
|
||||
ili9341_Write(RegValue);
|
||||
|
||||
/* Deselect: Chip Select high */
|
||||
LCD_CS_HIGH();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Writes register address.
|
||||
*/
|
||||
void ili9341_WriteReg(uint8_t Reg) {
|
||||
/* Reset WRX to send command */
|
||||
LCD_WRX_LOW();
|
||||
|
||||
/* Reset LCD control line(/CS) and Send command */
|
||||
LCD_CS_LOW();
|
||||
ili9341_Write(Reg);
|
||||
|
||||
/* Deselect: Chip Select high */
|
||||
LCD_CS_HIGH();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reads register value.
|
||||
* @param RegValue Address of the register to read
|
||||
* @param ReadSize Number of bytes to read
|
||||
* @retval Content of the register value
|
||||
*/
|
||||
uint32_t ili9341_ReadData(uint16_t RegValue, uint8_t ReadSize) {
|
||||
uint32_t readvalue = 0;
|
||||
|
||||
/* Select: Chip Select low */
|
||||
LCD_CS_LOW();
|
||||
|
||||
/* Reset WRX to send command */
|
||||
LCD_WRX_LOW();
|
||||
|
||||
ili9341_Write(RegValue);
|
||||
|
||||
readvalue = ili9341_Read(ReadSize);
|
||||
|
||||
/* Set WRX to send data */
|
||||
LCD_WRX_HIGH();
|
||||
|
||||
/* Deselect: Chip Select high */
|
||||
LCD_CS_HIGH();
|
||||
|
||||
return readvalue;
|
||||
}
|
||||
|
||||
void ili9341_init(void) {
|
||||
/* Initialize ILI9341 low level bus layer ----------------------------------*/
|
||||
ili9341_spi_init();
|
||||
|
||||
ili9341_WriteReg(LCD_DISPLAY_OFF);
|
||||
|
||||
/* Configure LCD */
|
||||
ili9341_WriteReg(0xCA);
|
||||
ili9341_WriteData(0xC3);
|
||||
ili9341_WriteData(0x08);
|
||||
ili9341_WriteData(0x50);
|
||||
ili9341_WriteReg(LCD_POWERB);
|
||||
ili9341_WriteData(0x00);
|
||||
ili9341_WriteData(0xC1);
|
||||
ili9341_WriteData(0x30);
|
||||
ili9341_WriteReg(LCD_POWER_SEQ);
|
||||
ili9341_WriteData(0x64);
|
||||
ili9341_WriteData(0x03);
|
||||
ili9341_WriteData(0x12);
|
||||
ili9341_WriteData(0x81);
|
||||
ili9341_WriteReg(LCD_DTCA);
|
||||
ili9341_WriteData(0x85);
|
||||
ili9341_WriteData(0x00);
|
||||
ili9341_WriteData(0x78);
|
||||
ili9341_WriteReg(LCD_POWERA);
|
||||
ili9341_WriteData(0x39);
|
||||
ili9341_WriteData(0x2C);
|
||||
ili9341_WriteData(0x00);
|
||||
ili9341_WriteData(0x34);
|
||||
ili9341_WriteData(0x02);
|
||||
ili9341_WriteReg(LCD_PRC);
|
||||
ili9341_WriteData(0x20);
|
||||
ili9341_WriteReg(LCD_DTCB);
|
||||
ili9341_WriteData(0x00);
|
||||
ili9341_WriteData(0x00);
|
||||
ili9341_WriteReg(LCD_FRMCTR1);
|
||||
ili9341_WriteData(0x00);
|
||||
ili9341_WriteData(0x1B);
|
||||
ili9341_WriteReg(LCD_DFC);
|
||||
ili9341_WriteData(0x0A);
|
||||
ili9341_WriteData(0xA2);
|
||||
ili9341_WriteReg(LCD_POWER1);
|
||||
ili9341_WriteData(0x10);
|
||||
ili9341_WriteReg(LCD_POWER2);
|
||||
ili9341_WriteData(0x10);
|
||||
ili9341_WriteReg(LCD_VCOM1);
|
||||
ili9341_WriteData(0x45);
|
||||
ili9341_WriteData(0x15);
|
||||
ili9341_WriteReg(LCD_VCOM2);
|
||||
ili9341_WriteData(0x90);
|
||||
ili9341_WriteReg(LCD_MAC);
|
||||
ili9341_WriteData(0xC8);
|
||||
ili9341_WriteReg(LCD_3GAMMA_EN);
|
||||
ili9341_WriteData(0x00);
|
||||
ili9341_WriteReg(LCD_RGB_INTERFACE);
|
||||
ili9341_WriteData(0xC2);
|
||||
ili9341_WriteReg(LCD_DFC);
|
||||
ili9341_WriteData(0x0A);
|
||||
ili9341_WriteData(0xA7);
|
||||
ili9341_WriteData(0x27);
|
||||
ili9341_WriteData(0x04);
|
||||
|
||||
/* Colomn address set */
|
||||
ili9341_WriteReg(LCD_COLUMN_ADDR);
|
||||
ili9341_WriteData(0x00);
|
||||
ili9341_WriteData(0x00);
|
||||
ili9341_WriteData(0x00);
|
||||
ili9341_WriteData(0xEF);
|
||||
/* Page address set */
|
||||
ili9341_WriteReg(LCD_PAGE_ADDR);
|
||||
ili9341_WriteData(0x00);
|
||||
ili9341_WriteData(0x00);
|
||||
ili9341_WriteData(0x01);
|
||||
ili9341_WriteData(0x3F);
|
||||
ili9341_WriteReg(LCD_INTERFACE);
|
||||
ili9341_WriteData(0x01);
|
||||
ili9341_WriteData(0x00);
|
||||
ili9341_WriteData(0x06);
|
||||
|
||||
ili9341_WriteReg(LCD_GRAM);
|
||||
HAL_Delay(200);
|
||||
|
||||
ili9341_WriteReg(LCD_GAMMA);
|
||||
ili9341_WriteData(0x01);
|
||||
|
||||
ili9341_WriteReg(LCD_PGAMMA);
|
||||
ili9341_WriteData(0x0F);
|
||||
ili9341_WriteData(0x29);
|
||||
ili9341_WriteData(0x24);
|
||||
ili9341_WriteData(0x0C);
|
||||
ili9341_WriteData(0x0E);
|
||||
ili9341_WriteData(0x09);
|
||||
ili9341_WriteData(0x4E);
|
||||
ili9341_WriteData(0x78);
|
||||
ili9341_WriteData(0x3C);
|
||||
ili9341_WriteData(0x09);
|
||||
ili9341_WriteData(0x13);
|
||||
ili9341_WriteData(0x05);
|
||||
ili9341_WriteData(0x17);
|
||||
ili9341_WriteData(0x11);
|
||||
ili9341_WriteData(0x00);
|
||||
ili9341_WriteReg(LCD_NGAMMA);
|
||||
ili9341_WriteData(0x00);
|
||||
ili9341_WriteData(0x16);
|
||||
ili9341_WriteData(0x1B);
|
||||
ili9341_WriteData(0x04);
|
||||
ili9341_WriteData(0x11);
|
||||
ili9341_WriteData(0x07);
|
||||
ili9341_WriteData(0x31);
|
||||
ili9341_WriteData(0x33);
|
||||
ili9341_WriteData(0x42);
|
||||
ili9341_WriteData(0x05);
|
||||
ili9341_WriteData(0x0C);
|
||||
ili9341_WriteData(0x0A);
|
||||
ili9341_WriteData(0x28);
|
||||
ili9341_WriteData(0x2F);
|
||||
ili9341_WriteData(0x0F);
|
||||
|
||||
ili9341_WriteReg(LCD_SLEEP_OUT);
|
||||
HAL_Delay(200);
|
||||
ili9341_WriteReg(LCD_DISPLAY_ON);
|
||||
/* GRAM start writing */
|
||||
ili9341_WriteReg(LCD_GRAM);
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
#ifndef _ILI9341_SPI_H
|
||||
#define _ILI9341_SPI_H
|
||||
|
||||
#define ILI9341_HSYNC ((uint32_t)9) /* Horizontal synchronization */
|
||||
#define ILI9341_HBP ((uint32_t)29) /* Horizontal back porch */
|
||||
#define ILI9341_HFP ((uint32_t)2) /* Horizontal front porch */
|
||||
#define ILI9341_VSYNC ((uint32_t)1) /* Vertical synchronization */
|
||||
#define ILI9341_VBP ((uint32_t)3) /* Vertical back porch */
|
||||
#define ILI9341_VFP ((uint32_t)2) /* Vertical front porch */
|
||||
|
||||
void ili9341_init(void);
|
||||
|
||||
#endif //_ILI9341_SPI_H
|
@ -0,0 +1,351 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include TREZOR_BOARD
|
||||
#include STM32_HAL_H
|
||||
|
||||
#include "xdisplay.h"
|
||||
|
||||
#ifdef USE_CONSUMPTION_MASK
|
||||
#include "consumption_mask.h"
|
||||
#endif
|
||||
|
||||
#if (DISPLAY_RESX != 128) || (DISPLAY_RESY != 64)
|
||||
#error "Incompatible display resolution"
|
||||
#endif
|
||||
|
||||
// This file implements display driver for monochromatic display V-2864KSWEG01
|
||||
// with 128x64 resolution connected to CPU via SPI interface.
|
||||
//
|
||||
// This type of display is used with T3T1 model (Trezor TS3)
|
||||
|
||||
// Display driver context.
|
||||
typedef struct {
|
||||
// SPI driver instance
|
||||
SPI_HandleTypeDef spi;
|
||||
// Frame buffer (8-bit Mono)
|
||||
uint8_t framebuf[DISPLAY_RESX * DISPLAY_RESY];
|
||||
// Current display orientation (0 or 180)
|
||||
int orientation_angle;
|
||||
// Current backlight level ranging from 0 to 255
|
||||
int backlight_level;
|
||||
} display_driver_t;
|
||||
|
||||
// Display driver instance
|
||||
static display_driver_t g_display_driver;
|
||||
|
||||
// Display controller registers
|
||||
#define OLED_SETCONTRAST 0x81
|
||||
#define OLED_DISPLAYALLON_RESUME 0xA4
|
||||
#define OLED_DISPLAYALLON 0xA5
|
||||
#define OLED_NORMALDISPLAY 0xA6
|
||||
#define OLED_INVERTDISPLAY 0xA7
|
||||
#define OLED_DISPLAYOFF 0xAE
|
||||
#define OLED_DISPLAYON 0xAF
|
||||
#define OLED_SETDISPLAYOFFSET 0xD3
|
||||
#define OLED_SETCOMPINS 0xDA
|
||||
#define OLED_SETVCOMDETECT 0xDB
|
||||
#define OLED_SETDISPLAYCLOCKDIV 0xD5
|
||||
#define OLED_SETPRECHARGE 0xD9
|
||||
#define OLED_SETMULTIPLEX 0xA8
|
||||
#define OLED_SETLOWCOLUMN 0x00
|
||||
#define OLED_SETHIGHCOLUMN 0x10
|
||||
#define OLED_SETSTARTLINE 0x40
|
||||
#define OLED_MEMORYMODE 0x20
|
||||
#define OLED_COMSCANINC 0xC0
|
||||
#define OLED_COMSCANDEC 0xC8
|
||||
#define OLED_SEGREMAP 0xA0
|
||||
#define OLED_CHARGEPUMP 0x8D
|
||||
|
||||
// Display controller initialization sequence
|
||||
static const uint8_t vg_2864ksweg01_init_seq[] = {OLED_DISPLAYOFF,
|
||||
OLED_SETDISPLAYCLOCKDIV,
|
||||
0x80,
|
||||
OLED_SETMULTIPLEX,
|
||||
0x3F, // 128x64
|
||||
OLED_SETDISPLAYOFFSET,
|
||||
0x00,
|
||||
OLED_SETSTARTLINE | 0x00,
|
||||
OLED_CHARGEPUMP,
|
||||
0x14,
|
||||
OLED_MEMORYMODE,
|
||||
0x00,
|
||||
OLED_SEGREMAP | 0x01,
|
||||
OLED_COMSCANDEC,
|
||||
OLED_SETCOMPINS,
|
||||
0x12, // 128x64
|
||||
OLED_SETCONTRAST,
|
||||
0xCF,
|
||||
OLED_SETPRECHARGE,
|
||||
0xF1,
|
||||
OLED_SETVCOMDETECT,
|
||||
0x40,
|
||||
OLED_DISPLAYALLON_RESUME,
|
||||
OLED_NORMALDISPLAY,
|
||||
OLED_DISPLAYON};
|
||||
|
||||
// Configures SPI driver/controller
|
||||
static bool display_init_spi(display_driver_t *drv) {
|
||||
drv->spi.Instance = OLED_SPI;
|
||||
drv->spi.State = HAL_SPI_STATE_RESET;
|
||||
drv->spi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
|
||||
drv->spi.Init.Direction = SPI_DIRECTION_2LINES;
|
||||
drv->spi.Init.CLKPhase = SPI_PHASE_1EDGE;
|
||||
drv->spi.Init.CLKPolarity = SPI_POLARITY_LOW;
|
||||
drv->spi.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
|
||||
drv->spi.Init.CRCPolynomial = 7;
|
||||
drv->spi.Init.DataSize = SPI_DATASIZE_8BIT;
|
||||
drv->spi.Init.FirstBit = SPI_FIRSTBIT_MSB;
|
||||
drv->spi.Init.NSS = SPI_NSS_HARD_OUTPUT;
|
||||
drv->spi.Init.TIMode = SPI_TIMODE_DISABLE;
|
||||
drv->spi.Init.Mode = SPI_MODE_MASTER;
|
||||
|
||||
return (HAL_OK == HAL_SPI_Init(&drv->spi)) ? true : false;
|
||||
}
|
||||
|
||||
// Sends specified number of bytes to the display via SPI interface
|
||||
static void display_send_bytes(display_driver_t *drv, const uint8_t *data,
|
||||
size_t len) {
|
||||
volatile int32_t timeout = 1000; // !@# why???
|
||||
for (int i = 0; i < timeout; i++)
|
||||
;
|
||||
|
||||
if (HAL_OK != HAL_SPI_Transmit(&drv->spi, (uint8_t *)data, len, 1000)) {
|
||||
// TODO: error
|
||||
return;
|
||||
}
|
||||
while (HAL_SPI_STATE_READY != HAL_SPI_GetState(&drv->spi)) {
|
||||
}
|
||||
}
|
||||
|
||||
#define COLLECT_ROW_BYTE(src) \
|
||||
(0 | (*(src + (0 * DISPLAY_RESX)) ? 128 : 0) | \
|
||||
(*(src + (1 * DISPLAY_RESX)) ? 64 : 0) | \
|
||||
(*(src + (2 * DISPLAY_RESX)) ? 32 : 0) | \
|
||||
(*(src + (3 * DISPLAY_RESX)) ? 16 : 0) | \
|
||||
(*(src + (4 * DISPLAY_RESX)) ? 8 : 0) | \
|
||||
(*(src + (5 * DISPLAY_RESX)) ? 4 : 0) | \
|
||||
(*(src + (6 * DISPLAY_RESX)) ? 2 : 0) | \
|
||||
(*(src + (7 * DISPLAY_RESX)) ? 1 : 0))
|
||||
|
||||
// Copies the framebuffer to the display via SPI interface
|
||||
static void display_sync_with_fb(display_driver_t *drv) {
|
||||
static const uint8_t cursor_set_seq[3] = {OLED_SETLOWCOLUMN | 0x00,
|
||||
OLED_SETHIGHCOLUMN | 0x00,
|
||||
OLED_SETSTARTLINE | 0x00};
|
||||
|
||||
// SPI select
|
||||
HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_RESET);
|
||||
// Set the cursor to the screen top-left corner
|
||||
display_send_bytes(drv, &cursor_set_seq[0], sizeof(cursor_set_seq));
|
||||
|
||||
// SPI deselect
|
||||
HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_SET);
|
||||
// Set to DATA
|
||||
HAL_GPIO_WritePin(OLED_DC_PORT, OLED_DC_PIN, GPIO_PIN_SET);
|
||||
// SPI select
|
||||
HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_RESET);
|
||||
|
||||
// Send whole framebuffer to the display
|
||||
for (int y = 0; y < DISPLAY_RESY / 8; y++) {
|
||||
uint8_t buff[DISPLAY_RESX];
|
||||
uint8_t *src = &drv->framebuf[y * DISPLAY_RESX * 8];
|
||||
|
||||
if (drv->orientation_angle == 0) {
|
||||
for (int x = 0; x < DISPLAY_RESX; x++) {
|
||||
buff[x] = COLLECT_ROW_BYTE(src);
|
||||
src++;
|
||||
}
|
||||
} else {
|
||||
for (int x = DISPLAY_RESX - 1; x >= 0; x--) {
|
||||
buff[x] = COLLECT_ROW_BYTE(src);
|
||||
src++;
|
||||
}
|
||||
}
|
||||
|
||||
if (HAL_OK != HAL_SPI_Transmit(&drv->spi, &buff[0], sizeof(buff), 1000)) {
|
||||
// TODO: error
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
while (HAL_SPI_STATE_READY != HAL_SPI_GetState(&drv->spi)) {
|
||||
}
|
||||
|
||||
// SPI deselect
|
||||
HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_SET);
|
||||
// Set to CMD
|
||||
HAL_GPIO_WritePin(OLED_DC_PORT, OLED_DC_PIN, GPIO_PIN_RESET);
|
||||
}
|
||||
|
||||
void display_init(void) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
memset(drv, 0, sizeof(display_driver_t));
|
||||
drv->backlight_level = 255;
|
||||
|
||||
OLED_DC_CLK_ENA();
|
||||
OLED_CS_CLK_ENA();
|
||||
OLED_RST_CLK_ENA();
|
||||
OLED_SPI_SCK_CLK_ENA();
|
||||
OLED_SPI_MOSI_CLK_ENA();
|
||||
OLED_SPI_CLK_ENA();
|
||||
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
|
||||
// Set GPIO for OLED display
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
|
||||
GPIO_InitStructure.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
|
||||
GPIO_InitStructure.Alternate = 0;
|
||||
GPIO_InitStructure.Pin = OLED_CS_PIN;
|
||||
HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_RESET);
|
||||
HAL_GPIO_Init(OLED_CS_PORT, &GPIO_InitStructure);
|
||||
GPIO_InitStructure.Pin = OLED_DC_PIN;
|
||||
HAL_GPIO_WritePin(OLED_DC_PORT, OLED_DC_PIN, GPIO_PIN_RESET);
|
||||
HAL_GPIO_Init(OLED_DC_PORT, &GPIO_InitStructure);
|
||||
GPIO_InitStructure.Pin = OLED_RST_PIN;
|
||||
HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_RESET);
|
||||
HAL_GPIO_Init(OLED_RST_PORT, &GPIO_InitStructure);
|
||||
|
||||
// Enable SPI 1 for OLED display
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStructure.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
|
||||
GPIO_InitStructure.Alternate = OLED_SPI_AF;
|
||||
GPIO_InitStructure.Pin = OLED_SPI_SCK_PIN;
|
||||
HAL_GPIO_Init(OLED_SPI_SCK_PORT, &GPIO_InitStructure);
|
||||
GPIO_InitStructure.Pin = OLED_SPI_MOSI_PIN;
|
||||
HAL_GPIO_Init(OLED_SPI_MOSI_PORT, &GPIO_InitStructure);
|
||||
|
||||
// Initialize SPI controller
|
||||
display_init_spi(drv);
|
||||
|
||||
// Set to CMD
|
||||
HAL_GPIO_WritePin(OLED_DC_PORT, OLED_DC_PIN, GPIO_PIN_RESET);
|
||||
// SPI deselect
|
||||
HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_SET);
|
||||
|
||||
// Reset the LCD
|
||||
HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_SET);
|
||||
HAL_Delay(1);
|
||||
HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_RESET);
|
||||
HAL_Delay(1);
|
||||
HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_SET);
|
||||
|
||||
// SPI select
|
||||
HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_RESET);
|
||||
// Send initialization command sequence
|
||||
display_send_bytes(drv, &vg_2864ksweg01_init_seq[0],
|
||||
sizeof(vg_2864ksweg01_init_seq));
|
||||
// SPI deselect
|
||||
HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_SET);
|
||||
|
||||
// Clear display internal framebuffer
|
||||
display_sync_with_fb(drv);
|
||||
}
|
||||
|
||||
void display_reinit(void) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
memset(drv, 0, sizeof(display_driver_t));
|
||||
drv->backlight_level = 255;
|
||||
|
||||
display_init_spi(drv);
|
||||
}
|
||||
|
||||
void display_finish_actions(void) {
|
||||
/// Not used and intentionally left empty
|
||||
}
|
||||
|
||||
int display_set_backlight(int level) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
drv->backlight_level = 255;
|
||||
return drv->backlight_level;
|
||||
}
|
||||
|
||||
int display_get_backlight(void) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
return drv->backlight_level;
|
||||
}
|
||||
|
||||
int display_set_orientation(int angle) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
if (angle != drv->orientation_angle) {
|
||||
if (angle == 0 || angle == 180) {
|
||||
drv->orientation_angle = angle;
|
||||
display_sync_with_fb(drv);
|
||||
}
|
||||
}
|
||||
|
||||
return drv->orientation_angle;
|
||||
}
|
||||
|
||||
int display_get_orientation(void) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
return drv->orientation_angle;
|
||||
}
|
||||
|
||||
void *display_get_frame_addr(void) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
return &drv->framebuf[0];
|
||||
}
|
||||
|
||||
void display_refresh(void) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
#if defined USE_CONSUMPTION_MASK && !defined BOARDLOADER
|
||||
// This is an intentional randomization of the consumption masking algorithm
|
||||
// after every change on the display
|
||||
consumption_mask_randomize();
|
||||
#endif
|
||||
|
||||
// Sends the current frame buffer to the display
|
||||
display_sync_with_fb(drv);
|
||||
}
|
||||
|
||||
const char *display_save(const char *prefix) { return NULL; }
|
||||
|
||||
void display_clear_save(void) {}
|
||||
|
||||
void display_set_compatible_settings() {}
|
||||
|
||||
/*
|
||||
|
||||
// Fills a rectangle with a specified color
|
||||
void display_fill(dma2d_params_t *dp) {
|
||||
|
||||
}
|
||||
|
||||
// Copies a MONO1P bitmap to specified rectangle
|
||||
void display_copy_mono1p(dma2d_params_t *dp) {
|
||||
|
||||
}
|
||||
|
||||
*/
|
@ -0,0 +1 @@
|
||||
../../stm32f4/display/st-7789
|
@ -0,0 +1,135 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include TREZOR_BOARD
|
||||
#include STM32_HAL_H
|
||||
|
||||
#include "display_internal.h"
|
||||
#include "xdisplay.h"
|
||||
|
||||
#if (DISPLAY_RESX != 480) || (DISPLAY_RESY != 480)
|
||||
#error "Incompatible display resolution"
|
||||
#endif
|
||||
|
||||
// Display driver context.
|
||||
typedef struct {
|
||||
// Current display orientation (0, 90, 180, 270)
|
||||
int orientation_angle;
|
||||
// Current backlight level ranging from 0 to 255
|
||||
int backlight_level;
|
||||
} display_driver_t;
|
||||
|
||||
// Display driver instance
|
||||
static display_driver_t g_display_driver;
|
||||
|
||||
void display_init(void) {
|
||||
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
|
||||
|
||||
// Initializes the common periph clock
|
||||
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_LTDC | RCC_PERIPHCLK_DSI;
|
||||
PeriphClkInit.DsiClockSelection = RCC_DSICLKSOURCE_PLL3;
|
||||
PeriphClkInit.LtdcClockSelection = RCC_LTDCCLKSOURCE_PLL3;
|
||||
PeriphClkInit.PLL3.PLL3Source = RCC_PLLSOURCE_HSE;
|
||||
PeriphClkInit.PLL3.PLL3M = 4;
|
||||
PeriphClkInit.PLL3.PLL3N = 125;
|
||||
PeriphClkInit.PLL3.PLL3P = 8;
|
||||
PeriphClkInit.PLL3.PLL3Q = 2;
|
||||
PeriphClkInit.PLL3.PLL3R = 24;
|
||||
PeriphClkInit.PLL3.PLL3RGE = RCC_PLLVCIRANGE_0;
|
||||
PeriphClkInit.PLL3.PLL3FRACN = 0;
|
||||
PeriphClkInit.PLL3.PLL3ClockOut = RCC_PLL3_DIVP | RCC_PLL3_DIVR;
|
||||
HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);
|
||||
|
||||
// Clear framebuffers
|
||||
memset(physical_frame_buffer_0, 0x00, PHYSICAL_FRAME_BUFFER_SIZE);
|
||||
memset(physical_frame_buffer_1, 0x00, PHYSICAL_FRAME_BUFFER_SIZE);
|
||||
|
||||
BSP_LCD_Init(0, LCD_ORIENTATION_PORTRAIT);
|
||||
BSP_LCD_SetBrightness(0, 100);
|
||||
BSP_LCD_DisplayOn(0);
|
||||
}
|
||||
|
||||
void display_reinit(void) {
|
||||
BSP_LCD_Reinit(0);
|
||||
if (current_frame_buffer == 0) {
|
||||
BSP_LCD_SetFrameBuffer(0, GFXMMU_VIRTUAL_BUFFER0_BASE_S);
|
||||
} else {
|
||||
BSP_LCD_SetFrameBuffer(0, GFXMMU_VIRTUAL_BUFFER1_BASE_S);
|
||||
}
|
||||
}
|
||||
|
||||
void display_finish_actions(void) {
|
||||
// Not used and intentionally left empty
|
||||
}
|
||||
|
||||
int display_set_backlight(int level) {
|
||||
display_driver_t* drv = &g_display_driver;
|
||||
|
||||
// Just emulation, not doing anything
|
||||
drv->backlight_level = level;
|
||||
return level;
|
||||
}
|
||||
|
||||
int display_get_backlight(void) {
|
||||
display_driver_t* drv = &g_display_driver;
|
||||
|
||||
return drv->orientation_angle;
|
||||
}
|
||||
|
||||
int display_set_orientation(int angle) {
|
||||
display_driver_t* drv = &g_display_driver;
|
||||
|
||||
if (angle == 0 || angle == 90 || angle == 180 || angle == 270) {
|
||||
// Just emulation, not doing anything
|
||||
drv->orientation_angle = angle;
|
||||
}
|
||||
|
||||
return drv->orientation_angle;
|
||||
}
|
||||
|
||||
int display_get_orientation(void) {
|
||||
display_driver_t* drv = &g_display_driver;
|
||||
|
||||
return drv->orientation_angle;
|
||||
}
|
||||
|
||||
const char* display_save(const char* prefix) { return NULL; }
|
||||
|
||||
void display_clear_save(void) {}
|
||||
|
||||
void display_set_compatible_settings() {}
|
||||
|
||||
// Functions for drawing on display
|
||||
/*
|
||||
|
||||
// Fills a rectangle with a specified color
|
||||
void display_fill(gdc_dma2d_t *dp);
|
||||
|
||||
// Copies an RGB565 bitmap to specified rectangle
|
||||
void display_copy_rgb565(gdc_dma2d_t *dp);
|
||||
|
||||
// Copies a MONO4 bitmap to specified rectangle
|
||||
void display_copy_mono4(gdc_dma2d_t *dp);
|
||||
|
||||
// Copies a MONO1P bitmap to specified rectangle
|
||||
void display_copy_mono1p(gdc_dma2d_t *dp);
|
||||
*/
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include TREZOR_BOARD
|
||||
#include STM32_HAL_H
|
||||
|
||||
#include "display_internal.h"
|
||||
|
||||
// Physical frame buffers in internal SRAM memory
|
||||
__attribute__((section(".fb1")))
|
||||
ALIGN_32BYTES(uint32_t physical_frame_buffer_0[PHYSICAL_FRAME_BUFFER_SIZE]);
|
||||
|
||||
__attribute__((section(".fb2")))
|
||||
ALIGN_32BYTES(uint32_t physical_frame_buffer_1[PHYSICAL_FRAME_BUFFER_SIZE]);
|
||||
|
||||
// The current frame buffer selector at fixed memory address
|
||||
// It's shared between bootloaders and the firmware
|
||||
__attribute__((section(".framebuffer_select"))) uint32_t current_frame_buffer =
|
||||
0;
|
||||
|
||||
void* display_get_frame_addr(void) {
|
||||
if (current_frame_buffer == 0) {
|
||||
return (void*)GFXMMU_VIRTUAL_BUFFER0_BASE_S;
|
||||
} else {
|
||||
return (void*)GFXMMU_VIRTUAL_BUFFER1_BASE_S;
|
||||
}
|
||||
}
|
||||
|
||||
void display_refresh(void) {
|
||||
current_frame_buffer = current_frame_buffer ? 0 : 1;
|
||||
|
||||
if (current_frame_buffer == 0) {
|
||||
BSP_LCD_SetFrameBuffer(0, GFXMMU_VIRTUAL_BUFFER0_BASE_S);
|
||||
memcpy(physical_frame_buffer_1, physical_frame_buffer_0,
|
||||
PHYSICAL_FRAME_BUFFER_SIZE);
|
||||
} else {
|
||||
BSP_LCD_SetFrameBuffer(0, GFXMMU_VIRTUAL_BUFFER1_BASE_S);
|
||||
memcpy(physical_frame_buffer_0, physical_frame_buffer_1,
|
||||
PHYSICAL_FRAME_BUFFER_SIZE);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TREZOR_HAL_DISPLAY_INTERNAL_H
|
||||
#define TREZOR_HAL_DISPLAY_INTERNAL_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// Size of the physical frame buffer in bytes
|
||||
//
|
||||
// It's smaller than size of the virtual framebuffer
|
||||
// due to used GFXMMU settings
|
||||
#define PHYSICAL_FRAME_BUFFER_SIZE 184320
|
||||
|
||||
// Physical frame buffers in internal SRAM memory
|
||||
//
|
||||
// Both frame buffers layes in the fixed addresses that
|
||||
// are shared between bootloaders and the firmware.
|
||||
extern uint32_t physical_frame_buffer_0[PHYSICAL_FRAME_BUFFER_SIZE];
|
||||
extern uint32_t physical_frame_buffer_1[PHYSICAL_FRAME_BUFFER_SIZE];
|
||||
|
||||
// The current frame buffer selector at fixed memory address
|
||||
//
|
||||
// The variable address is shared between bootloaders and the firmware
|
||||
extern uint32_t current_frame_buffer;
|
||||
|
||||
// LCD orientations
|
||||
#define LCD_ORIENTATION_PORTRAIT 0U
|
||||
#define LCD_ORIENTATION_LANDSCAPE 1U
|
||||
#define LCD_ORIENTATION_PORTRAIT_ROT180 2U
|
||||
#define LCD_ORIENTATION_LANDSCAPE_ROT180 3U
|
||||
|
||||
int32_t BSP_LCD_Init(uint32_t Instance, uint32_t Orientation);
|
||||
int32_t BSP_LCD_Reinit(uint32_t Instance);
|
||||
int32_t BSP_LCD_SetBrightness(uint32_t Instance, uint32_t Brightness);
|
||||
int32_t BSP_LCD_DisplayOn(uint32_t Instance);
|
||||
int32_t BSP_LCD_SetFrameBuffer(uint32_t Instance, uint32_t fb_addr);
|
||||
|
||||
#endif // TREZOR_HAL_DISPLAY_INTERNAL_H
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1 @@
|
||||
../../stm32f4/display/vg-2864
|
@ -0,0 +1 @@
|
||||
../stm32f4/dma2d_gl.c
|
@ -0,0 +1,409 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <xdisplay.h>
|
||||
|
||||
#include <SDL.h>
|
||||
#include <SDL_image.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "profile.h"
|
||||
|
||||
#define EMULATOR_BORDER 16
|
||||
|
||||
#if defined TREZOR_MODEL_T
|
||||
|
||||
#ifdef TREZOR_EMULATOR_RASPI
|
||||
#define WINDOW_WIDTH 480
|
||||
#define WINDOW_HEIGHT 320
|
||||
#define TOUCH_OFFSET_X 110
|
||||
#define TOUCH_OFFSET_Y 40
|
||||
#else
|
||||
#define WINDOW_WIDTH 400
|
||||
#define WINDOW_HEIGHT 600
|
||||
#define TOUCH_OFFSET_X 80
|
||||
#define TOUCH_OFFSET_Y 110
|
||||
#endif
|
||||
|
||||
#elif defined TREZOR_MODEL_1
|
||||
|
||||
#define WINDOW_WIDTH 200
|
||||
#define WINDOW_HEIGHT 340
|
||||
#define TOUCH_OFFSET_X 36
|
||||
#define TOUCH_OFFSET_Y 92
|
||||
|
||||
#elif defined TREZOR_MODEL_R
|
||||
|
||||
#define WINDOW_WIDTH 193
|
||||
#define WINDOW_HEIGHT 339
|
||||
#define TOUCH_OFFSET_X 32
|
||||
#define TOUCH_OFFSET_Y 84
|
||||
|
||||
#elif defined TREZOR_MODEL_T3T1
|
||||
|
||||
#define WINDOW_WIDTH 400
|
||||
#define WINDOW_HEIGHT 600
|
||||
#define TOUCH_OFFSET_X 80
|
||||
#define TOUCH_OFFSET_Y 110
|
||||
|
||||
#else
|
||||
#error Unknown Trezor model
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
// Current display orientation (0 or 180)
|
||||
int orientation_angle;
|
||||
// Current backlight level ranging from 0 to 255
|
||||
int backlight_level;
|
||||
|
||||
SDL_Window *window;
|
||||
SDL_Renderer *renderer;
|
||||
SDL_Surface *buffer;
|
||||
SDL_Texture *texture;
|
||||
SDL_Texture *background;
|
||||
SDL_Surface *prev_saved;
|
||||
|
||||
#if DISPLAY_MONO
|
||||
// SDL2 does not support 8bit surface/texture
|
||||
// and we have to simulate it
|
||||
uint8_t mono_framebuf[DISPLAY_RESX * DISPLAY_RESY];
|
||||
#endif
|
||||
|
||||
} display_driver_t;
|
||||
|
||||
static display_driver_t g_display_driver;
|
||||
|
||||
//!@# TODO get rid of this...
|
||||
int sdl_display_res_x = DISPLAY_RESX, sdl_display_res_y = DISPLAY_RESY;
|
||||
int sdl_touch_offset_x, sdl_touch_offset_y;
|
||||
|
||||
void display_deinit(void) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
SDL_FreeSurface(drv->prev_saved);
|
||||
SDL_FreeSurface(drv->buffer);
|
||||
if (drv->background != NULL) {
|
||||
SDL_DestroyTexture(drv->background);
|
||||
}
|
||||
if (drv->texture != NULL) {
|
||||
SDL_DestroyTexture(drv->texture);
|
||||
}
|
||||
if (drv->renderer != NULL) {
|
||||
SDL_DestroyRenderer(drv->renderer);
|
||||
}
|
||||
if (drv->window != NULL) {
|
||||
SDL_DestroyWindow(drv->window);
|
||||
}
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
void display_init(void) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
|
||||
printf("%s\n", SDL_GetError());
|
||||
ensure(secfalse, "SDL_Init error");
|
||||
}
|
||||
atexit(display_deinit);
|
||||
|
||||
char *window_title = NULL;
|
||||
char *window_title_alloc = NULL;
|
||||
if (asprintf(&window_title_alloc, "Trezor^emu: %s", profile_name()) > 0) {
|
||||
window_title = window_title_alloc;
|
||||
} else {
|
||||
window_title = "Trezor^emu";
|
||||
window_title_alloc = NULL;
|
||||
}
|
||||
|
||||
drv->window =
|
||||
SDL_CreateWindow(window_title, SDL_WINDOWPOS_UNDEFINED,
|
||||
SDL_WINDOWPOS_UNDEFINED, WINDOW_WIDTH, WINDOW_HEIGHT,
|
||||
#ifdef TREZOR_EMULATOR_RASPI
|
||||
SDL_WINDOW_SHOWN | SDL_WINDOW_FULLSCREEN
|
||||
#else
|
||||
SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI
|
||||
#endif
|
||||
);
|
||||
free(window_title_alloc);
|
||||
if (!drv->window) {
|
||||
printf("%s\n", SDL_GetError());
|
||||
ensure(secfalse, "SDL_CreateWindow error");
|
||||
}
|
||||
drv->renderer = SDL_CreateRenderer(drv->window, -1, SDL_RENDERER_SOFTWARE);
|
||||
if (!drv->renderer) {
|
||||
printf("%s\n", SDL_GetError());
|
||||
SDL_DestroyWindow(drv->window);
|
||||
ensure(secfalse, "SDL_CreateRenderer error");
|
||||
}
|
||||
SDL_SetRenderDrawColor(drv->renderer, 0, 0, 0, 255);
|
||||
SDL_RenderClear(drv->renderer);
|
||||
|
||||
drv->buffer = SDL_CreateRGBSurface(0, DISPLAY_RESX, DISPLAY_RESY, 16, 0xF800,
|
||||
0x07E0, 0x001F, 0x0000);
|
||||
drv->texture = SDL_CreateTexture(drv->renderer, SDL_PIXELFORMAT_RGB565,
|
||||
SDL_TEXTUREACCESS_STREAMING, DISPLAY_RESX,
|
||||
DISPLAY_RESY);
|
||||
SDL_SetTextureBlendMode(drv->texture, SDL_BLENDMODE_BLEND);
|
||||
#ifdef __APPLE__
|
||||
// macOS Mojave SDL black screen workaround
|
||||
SDL_PumpEvents();
|
||||
SDL_SetWindowSize(WINDOW, WINDOW_WIDTH, WINDOW_HEIGHT);
|
||||
#endif
|
||||
#ifdef TREZOR_EMULATOR_RASPI
|
||||
#include "background_raspi.h"
|
||||
drv->background = IMG_LoadTexture_RW(
|
||||
drv->renderer,
|
||||
SDL_RWFromMem(background_raspi_jpg, background_raspi_jpg_len), 0);
|
||||
#else
|
||||
#if defined TREZOR_MODEL_T
|
||||
#include "background_T.h"
|
||||
drv->background = IMG_LoadTexture_RW(
|
||||
drv->renderer, SDL_RWFromMem(background_T_jpg, background_T_jpg_len), 0);
|
||||
#elif defined TREZOR_MODEL_1
|
||||
#include "background_1.h"
|
||||
drv->background = IMG_LoadTexture_RW(
|
||||
drv->renderer, SDL_RWFromMem(background_1_jpg, background_1_jpg_len), 0);
|
||||
#elif defined TREZOR_MODEL_R
|
||||
#include "background_T2B1.h"
|
||||
drv->background = IMG_LoadTexture_RW(
|
||||
drv->renderer,
|
||||
SDL_RWFromMem(background_T2B1_png, background_T2B1_png_len), 0);
|
||||
#endif
|
||||
#endif
|
||||
if (drv->background) {
|
||||
SDL_SetTextureBlendMode(drv->background, SDL_BLENDMODE_NONE);
|
||||
sdl_touch_offset_x = TOUCH_OFFSET_X;
|
||||
sdl_touch_offset_y = TOUCH_OFFSET_Y;
|
||||
} else {
|
||||
SDL_SetWindowSize(drv->window, DISPLAY_RESX + 2 * EMULATOR_BORDER,
|
||||
DISPLAY_RESY + 2 * EMULATOR_BORDER);
|
||||
sdl_touch_offset_x = EMULATOR_BORDER;
|
||||
sdl_touch_offset_y = EMULATOR_BORDER;
|
||||
}
|
||||
#if defined TREZOR_MODEL_1 || defined TREZOR_MODEL_R
|
||||
// T1 and TR do not have backlight capabilities in hardware, so
|
||||
// setting its value here for emulator to avoid
|
||||
// calling any `set_backlight` functions
|
||||
drv->backlight_level = 255;
|
||||
#else
|
||||
drv->backlight_level = 0;
|
||||
#endif
|
||||
#ifdef TREZOR_EMULATOR_RASPI
|
||||
drv->orientation_angle = 270;
|
||||
SDL_ShowCursor(SDL_DISABLE);
|
||||
#else
|
||||
drv->orientation_angle = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void display_reinit(void) {
|
||||
// not used
|
||||
}
|
||||
|
||||
void display_finish_actions(void) {
|
||||
// not used
|
||||
}
|
||||
|
||||
int display_set_backlight(int level) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
#if defined TREZOR_MODEL_1 || defined TREZOR_MODEL_R
|
||||
level = 255;
|
||||
#endif
|
||||
|
||||
if (drv->backlight_level != level && level >= 0 && level <= 255) {
|
||||
drv->backlight_level = level;
|
||||
display_refresh();
|
||||
}
|
||||
|
||||
return drv->backlight_level;
|
||||
}
|
||||
|
||||
int display_get_backlight(void) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
return drv->backlight_level;
|
||||
}
|
||||
|
||||
int display_set_orientation(int angle) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
if (angle != drv->orientation_angle) {
|
||||
#if defined TREZOR_MODEL_T || defined TREZOR_MODEL_T3T1
|
||||
if (angle == 0 || angle == 90 || angle == 180 || angle == 270) {
|
||||
#elif defined TREZOR_MODEL_1 || defined TREZOR_MODEL_R
|
||||
if (angle == 0 || angle == 180) {
|
||||
#else
|
||||
#error Unknown Trezor model
|
||||
#endif
|
||||
drv->orientation_angle = angle;
|
||||
display_refresh();
|
||||
}
|
||||
}
|
||||
return drv->orientation_angle;
|
||||
}
|
||||
|
||||
int display_get_orientation(void) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
return drv->orientation_angle;
|
||||
}
|
||||
|
||||
#ifdef XFRAMEBUFFER
|
||||
void *display_get_frame_addr(void) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
#ifdef DISPLAY_MONO
|
||||
return drv->mono_framebuf;
|
||||
#else
|
||||
// !@# pitch???
|
||||
return drv->buffer->pixels;
|
||||
#endif
|
||||
}
|
||||
|
||||
#else // XFRAMEBUFFER
|
||||
|
||||
void display_wait_for_sync(void) {
|
||||
// not used
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DISPLAY_MONO
|
||||
// Copies driver's monochromatic framebuffer into the RGB framebuffer used by
|
||||
// SDL
|
||||
void copy_mono_framebuf(display_driver_t *drv) {
|
||||
for (int y = 0; y < DISPLAY_RESY; y++) {
|
||||
uint16_t *dst =
|
||||
(uint16_t *)((uint8_t *)drv->buffer->pixels + drv->buffer->pitch * y);
|
||||
uint8_t *src = &drv->mono_framebuf[y * DISPLAY_RESX];
|
||||
for (int x = 0; x < DISPLAY_RESX; x++) {
|
||||
uint8_t lum = src[x];
|
||||
dst[x] = gl_color16_rgb(lum, lum, lum);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void display_refresh(void) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
if (!drv->renderer) {
|
||||
display_init();
|
||||
}
|
||||
|
||||
#ifdef DISPLAY_MONO
|
||||
copy_mono_framebuf(drv);
|
||||
#endif
|
||||
|
||||
if (drv->background) {
|
||||
const SDL_Rect r = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT};
|
||||
SDL_RenderCopy(drv->renderer, drv->background, NULL, &r);
|
||||
} else {
|
||||
SDL_RenderClear(drv->renderer);
|
||||
}
|
||||
// Show the display buffer
|
||||
SDL_UpdateTexture(drv->texture, NULL, drv->buffer->pixels,
|
||||
drv->buffer->pitch);
|
||||
#define BACKLIGHT_NORMAL 150
|
||||
SDL_SetTextureAlphaMod(
|
||||
drv->texture, MIN(255, 255 * drv->backlight_level / BACKLIGHT_NORMAL));
|
||||
if (drv->background) {
|
||||
const SDL_Rect r = {TOUCH_OFFSET_X, TOUCH_OFFSET_Y, DISPLAY_RESX,
|
||||
DISPLAY_RESY};
|
||||
SDL_RenderCopyEx(drv->renderer, drv->texture, NULL, &r,
|
||||
drv->orientation_angle, NULL, 0);
|
||||
} else {
|
||||
const SDL_Rect r = {EMULATOR_BORDER, EMULATOR_BORDER, DISPLAY_RESX,
|
||||
DISPLAY_RESY};
|
||||
SDL_RenderCopyEx(drv->renderer, drv->texture, NULL, &r,
|
||||
drv->orientation_angle, NULL, 0);
|
||||
}
|
||||
SDL_RenderPresent(drv->renderer);
|
||||
}
|
||||
|
||||
void display_set_compatible_settings(void) {
|
||||
// not used
|
||||
}
|
||||
|
||||
void display_fill(const dma2d_params_t *dp) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
dma2d_params_t dp_new = *dp;
|
||||
dp_new.dst_row =
|
||||
(uint8_t *)drv->buffer->pixels + (drv->buffer->pitch * dp_new.dst_y);
|
||||
dp_new.dst_stride = drv->buffer->pitch;
|
||||
|
||||
rgb565_fill(&dp_new);
|
||||
}
|
||||
|
||||
void display_copy_rgb565(const dma2d_params_t *dp) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
dma2d_params_t dp_new = *dp;
|
||||
dp_new.dst_row =
|
||||
(uint8_t *)drv->buffer->pixels + (drv->buffer->pitch * dp_new.dst_y);
|
||||
dp_new.dst_stride = drv->buffer->pitch;
|
||||
|
||||
rgb565_copy_rgb565(&dp_new);
|
||||
}
|
||||
|
||||
void display_copy_mono4(const dma2d_params_t *dp) {
|
||||
// !@# TODO
|
||||
}
|
||||
|
||||
void display_copy_mono1p(const dma2d_params_t *dp) {
|
||||
// !@# TODO
|
||||
}
|
||||
|
||||
const char *display_save(const char *prefix) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
if (!drv->renderer) {
|
||||
display_init();
|
||||
}
|
||||
static int count;
|
||||
static char filename[256];
|
||||
// take a cropped view of the screen contents
|
||||
const SDL_Rect rect = {0, 0, DISPLAY_RESX, DISPLAY_RESY};
|
||||
SDL_Surface *crop = SDL_CreateRGBSurface(
|
||||
drv->buffer->flags, rect.w, rect.h, drv->buffer->format->BitsPerPixel,
|
||||
drv->buffer->format->Rmask, drv->buffer->format->Gmask,
|
||||
drv->buffer->format->Bmask, drv->buffer->format->Amask);
|
||||
SDL_BlitSurface(drv->buffer, &rect, crop, NULL);
|
||||
// compare with previous screen, skip if equal
|
||||
if (drv->prev_saved != NULL) {
|
||||
if (memcmp(drv->prev_saved->pixels, crop->pixels, crop->pitch * crop->h) ==
|
||||
0) {
|
||||
SDL_FreeSurface(crop);
|
||||
return filename;
|
||||
}
|
||||
SDL_FreeSurface(drv->prev_saved);
|
||||
}
|
||||
// save to png
|
||||
snprintf(filename, sizeof(filename), "%s%08d.png", prefix, count++);
|
||||
IMG_SavePNG(crop, filename);
|
||||
drv->prev_saved = crop;
|
||||
return filename;
|
||||
}
|
||||
|
||||
void display_clear_save(void) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
SDL_FreeSurface(drv->prev_saved);
|
||||
drv->prev_saved = NULL;
|
||||
}
|
@ -0,0 +1,135 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TREZORHAL_XDISPLAY_H
|
||||
#define TREZORHAL_XDISPLAY_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "gl_dma2d.h"
|
||||
|
||||
#include TREZOR_BOARD
|
||||
|
||||
// This is a universal API for controlling different types of display
|
||||
// controllers.
|
||||
//
|
||||
// Currently, following displays displays are supported
|
||||
//
|
||||
// VG-2864KSWEG01 - OLED Mono / 128x64 pixels / SPI
|
||||
// - Model T1B1 / Model T2B1
|
||||
//
|
||||
// UG-2828SWIG01 - OLED Mono / 128x128 pixels / Parallel
|
||||
// - Early revisions of T2B1
|
||||
//
|
||||
// ST7789V - TFT RGB / 240x240 pixels / Parallel
|
||||
// - Model T2T1 / Model T3T1
|
||||
//
|
||||
// ILI9341 - TFT RGB / 320x240 pixels / Parallel / LTDC + SPI
|
||||
// - STM32F429I-DISC1 Discovery Board
|
||||
//
|
||||
// MIPI -
|
||||
// - STM32U5A9J-DK Discovery Board
|
||||
|
||||
// Fully initializes the display controller.
|
||||
void display_init(void);
|
||||
|
||||
// Called in application to reinitialize an already initialized display
|
||||
// controller without any distrubing visible effect (blinking, etc.).
|
||||
void display_reinit(void);
|
||||
|
||||
// Waits for any backround operations (such as DMA copying)
|
||||
// and returns.
|
||||
//
|
||||
// The function provides a barrier when jumping between
|
||||
// boardloader/bootloader and firmware.
|
||||
void display_finish_actions(void);
|
||||
|
||||
// Sets display backlight level ranging from 0 (off)..255 (maximum).
|
||||
//
|
||||
// The default backligt level is 0. Without settings it
|
||||
// to some higher value the displayed pixels are not visible.
|
||||
// Beware that his also applies to the emulator.
|
||||
//
|
||||
// Returns the set level (usually the same value or the
|
||||
// closest value to the `level` argument)
|
||||
int display_set_backlight(int level);
|
||||
|
||||
// Gets current display level ranging from 0 (off)..255 (maximum).
|
||||
int display_get_backlight(void);
|
||||
|
||||
// Sets the display orientation.
|
||||
//
|
||||
// May accept one of following values: 0, 90, 180, 270
|
||||
// but accepted values are model-dependent.
|
||||
// Default display orientation is always 0.
|
||||
//
|
||||
// Returns the set orientation
|
||||
int display_set_orientation(int angle);
|
||||
|
||||
// Gets the display's current orientation
|
||||
//
|
||||
// Returned value is one of 0, 90, 180, 270.
|
||||
int display_get_orientation(void);
|
||||
|
||||
#ifdef XFRAMEBUFFER
|
||||
// Provides pointer to the inactive (writeable) framebuffer.
|
||||
//
|
||||
// If framebuffer is not available yet due to display refreshing etc.,
|
||||
// the function may block until the buffer is ready to write.
|
||||
void *display_get_frame_addr(void);
|
||||
|
||||
#else // XFRAMEBUFFER
|
||||
|
||||
// Waits for the vertical synchronization pulse.
|
||||
//
|
||||
// Used for synchronization with the display refresh cycle
|
||||
// to achieve tearless UX if possible when not using a frame buffer.
|
||||
void display_wait_for_sync(void);
|
||||
#endif
|
||||
|
||||
// Swaps the frame buffers
|
||||
//
|
||||
// The function waits for vertical synchronization and
|
||||
// swaps the active (currently displayed) and the inactive frame buffers.
|
||||
void display_refresh(void);
|
||||
|
||||
//
|
||||
void display_set_compatible_settings(void);
|
||||
|
||||
// Functions for drawing on the display
|
||||
// Fills a rectangle with a specified color
|
||||
void display_fill(const dma2d_params_t *dp);
|
||||
|
||||
// Copies an RGB565 bitmap to a specified rectangle
|
||||
void display_copy_rgb565(const dma2d_params_t *dp);
|
||||
|
||||
// Copies a MONO4 bitmap to a specified rectangle
|
||||
void display_copy_mono4(const dma2d_params_t *dp);
|
||||
|
||||
// Copies a MONO1P bitmap to a specified rectangle
|
||||
void display_copy_mono1p(const dma2d_params_t *dp);
|
||||
|
||||
// Save the screen content to a file.
|
||||
//
|
||||
// The function is available only on the emulator
|
||||
const char *display_save(const char *prefix);
|
||||
void display_clear_save(void);
|
||||
|
||||
#include "xdisplay_legacy.h"
|
||||
|
||||
#endif // TREZORHAL_XDISPLAY_H
|
@ -0,0 +1,50 @@
|
||||
#include "xdisplay_legacy.h"
|
||||
#include "xdisplay.h"
|
||||
|
||||
int display_orientation(int angle) {
|
||||
if (angle >= 0) {
|
||||
return display_set_orientation(angle);
|
||||
} else {
|
||||
return display_get_orientation();
|
||||
}
|
||||
}
|
||||
|
||||
int display_backlight(int level) {
|
||||
if (level >= 0) {
|
||||
return display_set_backlight(level);
|
||||
} else {
|
||||
return display_get_backlight();
|
||||
}
|
||||
}
|
||||
|
||||
void display_shift_window(uint16_t pixels){};
|
||||
|
||||
uint16_t display_get_window_offset(void) { return 0; }
|
||||
|
||||
void display_pixeldata_dirty(void) {}
|
||||
|
||||
uint8_t *display_get_wr_addr(void) { return (uint8_t *)0; }
|
||||
|
||||
void display_sync(void) {}
|
||||
|
||||
void display_set_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) {}
|
||||
|
||||
void display_pixeldata(uint16_t c) {}
|
||||
|
||||
uint32_t *display_get_fb_addr(void) {
|
||||
#ifdef XFRAMEBUFFER
|
||||
return (uint32_t *)display_get_frame_addr();
|
||||
#else
|
||||
return (uint32_t *)0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void display_offset(int set_xy[2], int *get_x, int *get_y) {
|
||||
*get_x = 0;
|
||||
*get_y = 0;
|
||||
}
|
||||
|
||||
void display_clear(void) {}
|
||||
|
||||
void display_text_render_buffer(const char *text, int textlen, int font,
|
||||
buffer_text_t *buffer, int text_offset) {}
|
@ -0,0 +1,34 @@
|
||||
|
||||
#ifndef TREZORHAL_DISPLAY_LEGACY_H
|
||||
#define TREZORHAL_DISPLAY_LEGACY_H
|
||||
|
||||
#include <buffers.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define DISPLAY_FRAMEBUFFER_WIDTH 768
|
||||
#define DISPLAY_FRAMEBUFFER_HEIGHT 480
|
||||
#define DISPLAY_FRAMEBUFFER_OFFSET_X 0
|
||||
#define DISPLAY_FRAMEBUFFER_OFFSET_Y 0
|
||||
|
||||
// Functions emulating legacy API
|
||||
//
|
||||
|
||||
int display_orientation(int angle);
|
||||
int display_backlight(int level);
|
||||
void display_refresh(void);
|
||||
void display_shift_window(uint16_t pixels);
|
||||
uint16_t display_get_window_offset(void);
|
||||
void display_pixeldata_dirty(void);
|
||||
uint8_t* display_get_wr_addr(void);
|
||||
void display_sync(void);
|
||||
void display_set_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1);
|
||||
void display_pixeldata(uint16_t c);
|
||||
uint32_t* display_get_fb_addr(void);
|
||||
|
||||
void display_clear(void);
|
||||
void display_text_render_buffer(const char* text, int textlen, int font,
|
||||
buffer_text_t* buffer, int text_offset);
|
||||
|
||||
#define PIXELDATA(c) display_pixeldata(c)
|
||||
|
||||
#endif // TREZORHAL_DISPLAY_LEGACY_H
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue