mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-02-15 00:52:02 +00:00
feat(core): initial Model R display implementation with framebuffer
This commit is contained in:
parent
936c84bac6
commit
f7a3aad9bd
1
core/.changelog.d/2243.added
Normal file
1
core/.changelog.d/2243.added
Normal file
@ -0,0 +1 @@
|
||||
Add basic Trezor Model R hardware support
|
@ -48,6 +48,9 @@ SOURCE_MOD += [
|
||||
'embed/extmod/modtrezorui/font_bitmap.c',
|
||||
'embed/extmod/modtrezorui/font_roboto_regular_20.c',
|
||||
'embed/extmod/modtrezorui/font_robotomono_regular_20.c',
|
||||
'embed/extmod/modtrezorui/font_pixeloperator_bold_8.c',
|
||||
'embed/extmod/modtrezorui/font_pixeloperator_regular_8.c',
|
||||
'embed/extmod/modtrezorui/font_pixeloperatormono_regular_8.c',
|
||||
'vendor/micropython/lib/uzlib/adler32.c',
|
||||
'vendor/micropython/lib/uzlib/crc32.c',
|
||||
'vendor/micropython/lib/uzlib/tinflate.c',
|
||||
@ -108,7 +111,7 @@ SOURCE_TREZORHAL = [
|
||||
'embed/trezorhal/vectortable.s',
|
||||
]
|
||||
|
||||
if TREZOR_MODEL in ['1', 'R']:
|
||||
if TREZOR_MODEL in ('1', 'R'):
|
||||
SOURCE_TREZORHAL.append('embed/trezorhal/button.c')
|
||||
if TREZOR_MODEL in ('T',):
|
||||
SOURCE_TREZORHAL.append('embed/trezorhal/touch.c')
|
||||
|
@ -151,7 +151,7 @@ if FEATURE_FLAGS["SECP256K1_ZKP"]:
|
||||
SOURCE_MOD += [
|
||||
'embed/extmod/modtrezorio/modtrezorio.c',
|
||||
]
|
||||
if TREZOR_MODEL in ("T",):
|
||||
if TREZOR_MODEL in ('T',):
|
||||
SOURCE_MOD += [
|
||||
'embed/extmod/modtrezorio/ff.c',
|
||||
'embed/extmod/modtrezorio/ffunicode.c',
|
||||
|
@ -32,6 +32,7 @@ SOURCE_MOD += [
|
||||
'embed/extmod/modtrezorui/display.c',
|
||||
'embed/extmod/modtrezorui/font_bitmap.c',
|
||||
'embed/extmod/modtrezorui/font_roboto_bold_20.c',
|
||||
'embed/extmod/modtrezorui/font_pixeloperator_bold_8.c',
|
||||
'embed/extmod/modtrezorui/qr-code-generator/qrcodegen.c',
|
||||
'vendor/micropython/lib/uzlib/adler32.c',
|
||||
'vendor/micropython/lib/uzlib/crc32.c',
|
||||
|
@ -147,7 +147,7 @@ if FEATURE_FLAGS["SECP256K1_ZKP"]:
|
||||
SOURCE_MOD += [
|
||||
'embed/extmod/modtrezorio/modtrezorio.c',
|
||||
]
|
||||
if TREZOR_MODEL in ("T",):
|
||||
if TREZOR_MODEL in ('T',):
|
||||
SOURCE_MOD += [
|
||||
'embed/extmod/modtrezorio/ff.c',
|
||||
'embed/extmod/modtrezorio/ffunicode.c',
|
||||
|
1
core/embed/boardloader/.changelog.d/2243.added
Normal file
1
core/embed/boardloader/.changelog.d/2243.added
Normal file
@ -0,0 +1 @@
|
||||
Add basic Trezor Model R hardware support
|
1
core/embed/bootloader/.changelog.d/2243.added
Normal file
1
core/embed/bootloader/.changelog.d/2243.added
Normal file
@ -0,0 +1 @@
|
||||
Add basic Trezor Model R hardware support
|
1
core/embed/bootloader_ci/.changelog.d/2243.added
Normal file
1
core/embed/bootloader_ci/.changelog.d/2243.added
Normal file
@ -0,0 +1 @@
|
||||
Add basic Trezor Model R hardware support
|
337
core/embed/extmod/modtrezorui/display-stm32_R.h
Normal file
337
core/embed/extmod/modtrezorui/display-stm32_R.h
Normal file
@ -0,0 +1,337 @@
|
||||
/*
|
||||
* 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 STM32_HAL_H
|
||||
|
||||
// FSMC/FMC Bank 1 - NOR/PSRAM 1
|
||||
#define DISPLAY_MEMORY_BASE 0x60000000
|
||||
#define DISPLAY_MEMORY_PIN 16
|
||||
|
||||
#define CMD(X) (*((__IO uint8_t *)((uint32_t)(DISPLAY_MEMORY_BASE))) = (X))
|
||||
#define ADDR \
|
||||
(*((__IO uint8_t *)((uint32_t)(DISPLAY_MEMORY_BASE | \
|
||||
(1 << DISPLAY_MEMORY_PIN)))))
|
||||
#define DATA(X) (ADDR) = (X)
|
||||
|
||||
// noop on TR as we don't need to push data to display
|
||||
#define PIXELDATA_DIRTY()
|
||||
|
||||
struct {
|
||||
uint8_t RAM[DISPLAY_RESY / 8][DISPLAY_RESX];
|
||||
uint32_t row;
|
||||
uint32_t col;
|
||||
uint32_t window_x0;
|
||||
uint32_t window_x1;
|
||||
uint32_t window_y0;
|
||||
uint32_t window_y1;
|
||||
} DISPLAY_STATE;
|
||||
|
||||
static void display_set_page_and_col(uint8_t page, uint8_t col) {
|
||||
if (page < (DISPLAY_RESY / 8)) {
|
||||
CMD(0xB0 | (page & 0xF));
|
||||
|
||||
if (col < DISPLAY_RESX) {
|
||||
CMD(0x10 | ((col & 0x70) >> 4));
|
||||
CMD(0x00 | (col & 0x0F));
|
||||
} else {
|
||||
// Reset column to start
|
||||
CMD(0x10);
|
||||
CMD(0x00);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PIXELDATA(uint16_t c) {
|
||||
uint8_t data = DISPLAY_STATE.RAM[DISPLAY_STATE.row / 8][DISPLAY_STATE.col];
|
||||
|
||||
uint8_t bit = 1 << (DISPLAY_STATE.row % 8);
|
||||
|
||||
// set to white if highest bits of all R, G, B values are set to 1
|
||||
// bin(10000 100000 10000) = hex(0x8410)
|
||||
// otherwise set to black
|
||||
if (c & 0x8410) {
|
||||
data |= bit;
|
||||
} else {
|
||||
data &= ~bit;
|
||||
}
|
||||
|
||||
DISPLAY_STATE.RAM[DISPLAY_STATE.row / 8][DISPLAY_STATE.col] = data;
|
||||
|
||||
DATA(data);
|
||||
|
||||
DISPLAY_STATE.col++;
|
||||
|
||||
if (DISPLAY_STATE.col > DISPLAY_STATE.window_x1) {
|
||||
// next line
|
||||
DISPLAY_STATE.col = DISPLAY_STATE.window_x0;
|
||||
DISPLAY_STATE.row++;
|
||||
|
||||
if (DISPLAY_STATE.row > DISPLAY_STATE.window_y1) {
|
||||
// reached end of the window, go to start
|
||||
DISPLAY_STATE.row = DISPLAY_STATE.window_y1;
|
||||
}
|
||||
|
||||
// set display to start of next line, sets also page, even if it stays on
|
||||
// the same one
|
||||
display_set_page_and_col(DISPLAY_STATE.row / 8, DISPLAY_STATE.col);
|
||||
}
|
||||
}
|
||||
|
||||
static void display_reset_state(void) {
|
||||
memset(DISPLAY_STATE.RAM, 0, sizeof(DISPLAY_STATE.RAM));
|
||||
DISPLAY_STATE.row = 0;
|
||||
DISPLAY_STATE.col = 0;
|
||||
DISPLAY_STATE.window_x0 = 0;
|
||||
DISPLAY_STATE.window_x1 = DISPLAY_RESX - 1;
|
||||
DISPLAY_STATE.window_y0 = 0;
|
||||
DISPLAY_STATE.window_y1 = DISPLAY_RESY - 1;
|
||||
}
|
||||
|
||||
static void __attribute__((unused)) display_sleep(void) {
|
||||
CMD(0xAE); // DISPOFF: Display Off
|
||||
HAL_Delay(5);
|
||||
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_8, GPIO_PIN_RESET); // Vpp disable
|
||||
}
|
||||
|
||||
static void display_unsleep(void) {
|
||||
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_8, GPIO_PIN_SET); // Vpp enable
|
||||
HAL_Delay(100); // 100 ms mandatory wait
|
||||
CMD(0xAF); // Display ON
|
||||
}
|
||||
|
||||
static void display_set_window(uint16_t x0, uint16_t y0, uint16_t x1,
|
||||
uint16_t y1) {
|
||||
if (x1 >= DISPLAY_RESX) {
|
||||
x1 = DISPLAY_RESX - 1;
|
||||
}
|
||||
if (y1 >= DISPLAY_RESY) {
|
||||
y1 = DISPLAY_RESY - 1;
|
||||
}
|
||||
|
||||
if (x0 < DISPLAY_RESX && x1 < DISPLAY_RESX && x0 <= x1 && y0 < DISPLAY_RESY &&
|
||||
y1 < DISPLAY_RESY && y0 <= y1) {
|
||||
DISPLAY_STATE.window_x0 = x0;
|
||||
DISPLAY_STATE.window_x1 = x1;
|
||||
DISPLAY_STATE.window_y0 = y0;
|
||||
DISPLAY_STATE.window_y1 = y1;
|
||||
DISPLAY_STATE.row = y0;
|
||||
DISPLAY_STATE.col = x0;
|
||||
|
||||
display_set_page_and_col(DISPLAY_STATE.row / 8, DISPLAY_STATE.col);
|
||||
}
|
||||
}
|
||||
|
||||
static void display_set_orientation(int degrees) {
|
||||
if (degrees == 0) {
|
||||
// Set Segment Re-map: (A0H - A1H)
|
||||
CMD(0xA1);
|
||||
// Set COM Output Scan Direction
|
||||
CMD(0xC8);
|
||||
}
|
||||
if (degrees == 180) {
|
||||
// Set Segment Re-map: (A0H - A1H)
|
||||
CMD(0xA0);
|
||||
// Set COM Output Scan Direction
|
||||
CMD(0xC0);
|
||||
}
|
||||
}
|
||||
|
||||
static void display_set_backlight(int val) {
|
||||
// Set Contrast Control Register: (Double Bytes Command)
|
||||
CMD(0x81);
|
||||
CMD(val & 0xFF);
|
||||
}
|
||||
|
||||
static void send_init_seq_SH1107(void) {
|
||||
// Display OFF
|
||||
CMD(0xAE);
|
||||
|
||||
// Set Display Clock Divide Ratio/Oscillator Frequency: (Double Bytes Command)
|
||||
CMD(0xD5);
|
||||
// Divide ratio 0, Oscillator Frequency +0%
|
||||
CMD(0x50);
|
||||
|
||||
// Set Memory Addressing Mode - page addressing mode
|
||||
CMD(0x20);
|
||||
|
||||
// Set Contrast Control Register: (Double Bytes Command)
|
||||
CMD(0x81);
|
||||
CMD(0x8F);
|
||||
|
||||
// Set DC-DC Setting: (Double Bytes Command)
|
||||
CMD(0xAD);
|
||||
CMD(0x8A);
|
||||
|
||||
// Set Segment Re-map: (A0H - A1H)
|
||||
// CMD(0xA0);
|
||||
CMD(0xA1);
|
||||
|
||||
// Set COM Output Scan Direction
|
||||
CMD(0xC8);
|
||||
// CMD(0xC0);
|
||||
|
||||
// Set Display Start Line:(Double Bytes Command)
|
||||
CMD(0xDC);
|
||||
CMD(0x00);
|
||||
|
||||
// Set Display Offset:(Double Bytes Command)
|
||||
CMD(0xD3);
|
||||
CMD(0x00);
|
||||
|
||||
// Set Discharge / Pre-Charge Period (Double Bytes Command)
|
||||
CMD(0xD9);
|
||||
CMD(0x22);
|
||||
|
||||
// Set VCOM Deselect Level
|
||||
CMD(0xDB);
|
||||
CMD(0x35);
|
||||
|
||||
// Set Multiplex Ratio
|
||||
CMD(0xA8);
|
||||
CMD(0x7F);
|
||||
|
||||
// Set Page
|
||||
CMD(0xB0);
|
||||
// Set Column
|
||||
CMD(0x00);
|
||||
CMD(0x10);
|
||||
|
||||
// Set Entire Display Off
|
||||
// to be clear, this command turns of the function
|
||||
// which turns entire display on, but it does not clear
|
||||
// the data in display RAM
|
||||
CMD(0xA4);
|
||||
|
||||
// Set Normal Display
|
||||
CMD(0xA6);
|
||||
|
||||
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_8, GPIO_PIN_SET); // Vpp enable
|
||||
|
||||
// Vpp stabilization period
|
||||
HAL_Delay(100);
|
||||
|
||||
// Display ON
|
||||
CMD(0xAF);
|
||||
}
|
||||
|
||||
void display_init_seq(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);
|
||||
|
||||
send_init_seq_SH1107();
|
||||
|
||||
display_clear();
|
||||
display_unsleep();
|
||||
}
|
||||
|
||||
void display_init(void) {
|
||||
// init peripherals
|
||||
__HAL_RCC_GPIOC_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOD_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOE_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);
|
||||
|
||||
// VPP Enable
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
|
||||
GPIO_InitStructure.Pull = GPIO_PULLDOWN;
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
GPIO_InitStructure.Alternate = 0;
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_8;
|
||||
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_8, GPIO_PIN_RESET);
|
||||
HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
|
||||
|
||||
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);
|
||||
|
||||
// Reference UM1725 "Description of STM32F4 HAL and LL drivers",
|
||||
// section 64.2.1 "How to use this driver"
|
||||
SRAM_HandleTypeDef external_display_data_sram;
|
||||
external_display_data_sram.Instance = FMC_NORSRAM_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;
|
||||
external_display_data_sram.Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_8;
|
||||
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.WrapMode = FMC_WRAP_MODE_DISABLE;
|
||||
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;
|
||||
normal_mode_timing.AddressSetupTime = 10;
|
||||
normal_mode_timing.AddressHoldTime = 10;
|
||||
normal_mode_timing.DataSetupTime = 10;
|
||||
normal_mode_timing.BusTurnAroundDuration = 0;
|
||||
normal_mode_timing.CLKDivision = 2;
|
||||
normal_mode_timing.DataLatency = 2;
|
||||
normal_mode_timing.AccessMode = FMC_ACCESS_MODE_A;
|
||||
|
||||
HAL_SRAM_Init(&external_display_data_sram, &normal_mode_timing, NULL);
|
||||
|
||||
display_init_seq();
|
||||
}
|
||||
|
||||
void display_refresh(void) {}
|
||||
|
||||
const char *display_save(const char *prefix) { return NULL; }
|
||||
|
||||
void display_clear_save(void) {}
|
@ -117,8 +117,10 @@ static struct { int x, y; } DISPLAY_OFFSET;
|
||||
#else
|
||||
#if defined TREZOR_MODEL_T
|
||||
#include "display-stm32_T.h"
|
||||
#elif defined TREZOR_MODEL_1 || defined TREZOR_MODEL_R
|
||||
#elif defined TREZOR_MODEL_1
|
||||
#include "display-stm32_1.h"
|
||||
#elif defined TREZOR_MODEL_R
|
||||
#include "display-stm32_R.h"
|
||||
#else
|
||||
#error Unknown Trezor model
|
||||
#endif
|
||||
@ -930,7 +932,7 @@ int display_orientation(int degrees) {
|
||||
}
|
||||
|
||||
int display_backlight(int val) {
|
||||
#if defined TREZOR_MODEL_1 || defined TREZOR_MODEL_R
|
||||
#if defined TREZOR_MODEL_1
|
||||
val = 255;
|
||||
#endif
|
||||
if (DISPLAY_BACKLIGHT != val && val >= 0 && val <= 255) {
|
||||
|
@ -91,6 +91,11 @@ int main(void) {
|
||||
button_init();
|
||||
#endif
|
||||
|
||||
#if defined TREZOR_MODEL_R
|
||||
button_init();
|
||||
display_clear();
|
||||
#endif
|
||||
|
||||
#if defined TREZOR_MODEL_T
|
||||
// display_init_seq();
|
||||
sdcard_init();
|
||||
|
Loading…
Reference in New Issue
Block a user