-
Notifications
You must be signed in to change notification settings - Fork 0
/
st7735r.cpp
180 lines (157 loc) · 6.61 KB
/
st7735r.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
#include "config.h"
#if defined(ST7735R) || defined(ST7735S) || defined(ST7789) || defined(ST7796S)
#include "spi.h"
#include <memory.h>
#include <stdio.h>
void InitST7735R()
{
// If a Reset pin is defined, toggle it briefly high->low->high to enable the device. Some devices do not have a reset pin, in which case compile with GPIO_TFT_RESET_PIN left undefined.
#if defined(GPIO_TFT_RESET_PIN) && GPIO_TFT_RESET_PIN >= 0
printf("Resetting display at reset GPIO pin %d\n", GPIO_TFT_RESET_PIN);
SET_GPIO_MODE(GPIO_TFT_RESET_PIN, 1);
SET_GPIO(GPIO_TFT_RESET_PIN);
usleep(120 * 1000);
CLEAR_GPIO(GPIO_TFT_RESET_PIN);
usleep(120 * 1000);
SET_GPIO(GPIO_TFT_RESET_PIN);
usleep(120 * 1000);
#endif
// Do the initialization with a very low SPI bus speed, so that it will succeed even if the bus speed chosen by the user is too high.
spi->clk = 34;
__sync_synchronize();
BEGIN_SPI_COMMUNICATION();
{
#ifndef ST7789VW // For some reason, ST7789VW does not want to accept the Software Reset command, but screen stays black if SWRESET is sent to it.
SPI_TRANSFER(0x01/*Software Reset*/);
#endif
usleep(120*1000);
SPI_TRANSFER(0x11/*Sleep Out*/);
usleep(120 * 1000);
#ifndef ST7789VW // This is disabled on ST7789VW because it was observed to look visually bad, makes colors a bit too contrasty/deep
SPI_TRANSFER(0x26/*Gamma Curve Select*/, 0x04/*Gamma curve 3 (2.5x if GS=1, 2.2x otherwise)*/);
#endif
SPI_TRANSFER(0x3A/*COLMOD: Pixel Format Set*/, 0x05/*16bpp*/);
usleep(20 * 1000);
#define MADCTL_BGR_PIXEL_ORDER (1<<3)
#define MADCTL_ROW_COLUMN_EXCHANGE (1<<5)
#define MADCTL_COLUMN_ADDRESS_ORDER_SWAP (1<<6)
#define MADCTL_ROW_ADDRESS_ORDER_SWAP (1<<7)
#define MADCTL_ROTATE_180_DEGREES (MADCTL_COLUMN_ADDRESS_ORDER_SWAP | MADCTL_ROW_ADDRESS_ORDER_SWAP)
uint8_t madctl = 0;
#if defined(ST7735R) || defined(ST7735S)
madctl |= MADCTL_BGR_PIXEL_ORDER;
#endif
#ifdef DISPLAY_SWAP_BGR
madctl ^= MADCTL_BGR_PIXEL_ORDER;
#endif
#if defined(DISPLAY_FLIP_ORIENTATION_IN_HARDWARE)
madctl |= MADCTL_ROW_COLUMN_EXCHANGE;
#endif
madctl |= MADCTL_ROW_ADDRESS_ORDER_SWAP;
#if defined(WAVESHARE_ST7789VW_HAT) || defined(WAVESHARE_ST7735S_HAT)
madctl ^= MADCTL_ROTATE_180_DEGREES;
#endif
#if defined(ST7796S)
madctl ^= MADCTL_COLUMN_ADDRESS_ORDER_SWAP;
#endif
#ifdef DISPLAY_ROTATE_180_DEGREES
madctl ^= MADCTL_ROTATE_180_DEGREES;
#endif
SPI_TRANSFER(0x36/*MADCTL: Memory Access Control*/, madctl);
usleep(10*1000);
#ifdef ST7789
SPI_TRANSFER(0xBA/*DGMEN: Enable Gamma*/, 0x04);
bool invertColors = true;
#else
bool invertColors = false;
#endif
#ifdef DISPLAY_INVERT_COLORS
invertColors = !invertColors;
#endif
if (invertColors)
SPI_TRANSFER(0x21/*Display Inversion On*/);
else
SPI_TRANSFER(0x20/*Display Inversion Off*/);
SPI_TRANSFER(0x13/*NORON: Partial off (normal)*/);
usleep(10*1000);
#ifdef ST7789
// The ST7789 controller is actually a unit with 320x240 graphics memory area, but only 240x240 portion
// of it is displayed. Therefore if we wanted to swap row address mode above, writes to Y=0...239 range will actually land in
// memory in row addresses Y = 319-(0...239) = 319...80 range. To view this range, we must scroll the view by +80 units in Y
// direction so that contents of Y=80...319 is displayed instead of Y=0...239.
if ((madctl & MADCTL_ROW_ADDRESS_ORDER_SWAP))
SPI_TRANSFER(0x37/*VSCSAD: Vertical Scroll Start Address of RAM*/, 0, 320 - DISPLAY_WIDTH);
#endif
// TODO: The 0xB1 command is not Frame Rate Control for ST7789VW, 0xB3 is (add support to it)
#if !defined(ST7789VW) || !defined(ST7796S)
// Frame rate = 850000 / [ (2*RTNA+40) * (162 + FPA+BPA)]
SPI_TRANSFER(0xB1/*FRMCTR1:Frame Rate Control*/, /*RTNA=*/6, /*FPA=*/1, /*BPA=*/1); // This should set frame rate = 99.67 Hz
#endif
#ifdef ST7796S
SPI_TRANSFER(0xB1, 0x80, 0x10);
#endif
SPI_TRANSFER(/*Display ON*/0x29);
usleep(100 * 1000);
#if 0
// TODO: ST7789VW Python example suggests following, check them against datasheet if there's anything interesting
SPI_TRANSFER(0xB2, 0xc, 0xc, 0, 0x33, 0x33);
SPI_TRANSFER(0xB7, 0x35);
SPI_TRANSFER(0xBb, 0x19);
SPI_TRANSFER(0xc0, 0x2c);
SPI_TRANSFER(0xc2, 0x01);
SPI_TRANSFER(0xc3, 0x12);
SPI_TRANSFER(0xc4, 0x20);
SPI_TRANSFER(0xc6, 0x0f);
SPI_TRANSFER(0xd0, 0xa4, 0xa1);
SPI_TRANSFER(0xe0, 0xd0, 0x04, 0x0d, 0x11, 0x13, 0x2b, 0x3f, 0x54, 0x4c, 0x18, 0x0d, 0x0b, 0x1f, 0x23);
SPI_TRANSFER(0xe1, 0xd0, 0x04, 0x0c, 0x11, 0x13, 0x2c, 0x3f, 0x44, 0x51, 0x2f, 0x1f, 0x1f, 0x20, 0x23);
SPI_TRANSFER(0x21);
SPI_TRANSFER(0x11);
SPI_TRANSFER(0x29);
usleep(100 * 1000);
#endif
#if defined(GPIO_TFT_BACKLIGHT) && defined(BACKLIGHT_CONTROL)
printf("Setting TFT backlight on at pin %d\n", GPIO_TFT_BACKLIGHT);
SET_GPIO_MODE(GPIO_TFT_BACKLIGHT, 0x01); // Set backlight pin to digital 0/1 output mode (0x01) in case it had been PWM controlled
SET_GPIO(GPIO_TFT_BACKLIGHT); // And turn the backlight on.
#endif
ClearScreen();
}
#ifndef USE_DMA_TRANSFERS // For DMA transfers, keep SPI CS & TA active.
END_SPI_COMMUNICATION();
#endif
// And speed up to the desired operation speed finally after init is done.
usleep(10 * 1000); // Delay a bit before restoring CLK, or otherwise this has been observed to cause the display not init if done back to back after the clear operation above.
spi->clk = SPI_BUS_CLOCK_DIVISOR;
}
void TurnDisplayOff()
{
#if defined(GPIO_TFT_BACKLIGHT) && defined(BACKLIGHT_CONTROL)
SET_GPIO_MODE(GPIO_TFT_BACKLIGHT, 0x01); // Set backlight pin to digital 0/1 output mode (0x01) in case it had been PWM controlled
CLEAR_GPIO(GPIO_TFT_BACKLIGHT); // And turn the backlight off.
#endif
#if 0
QUEUE_SPI_TRANSFER(0x28/*Display OFF*/);
QUEUE_SPI_TRANSFER(0x10/*Enter Sleep Mode*/);
usleep(120*1000); // Sleep off can be sent 120msecs after entering sleep mode the earliest, so synchronously sleep here for that duration to be safe.
#endif
// printf("Turned display OFF\n");
}
void TurnDisplayOn()
{
#if 0
QUEUE_SPI_TRANSFER(0x11/*Sleep Out*/);
usleep(120 * 1000);
QUEUE_SPI_TRANSFER(0x29/*Display ON*/);
#endif
#if defined(GPIO_TFT_BACKLIGHT) && defined(BACKLIGHT_CONTROL)
SET_GPIO_MODE(GPIO_TFT_BACKLIGHT, 0x01); // Set backlight pin to digital 0/1 output mode (0x01) in case it had been PWM controlled
SET_GPIO(GPIO_TFT_BACKLIGHT); // And turn the backlight on.
#endif
// printf("Turned display ON\n");
}
void DeinitSPIDisplay()
{
ClearScreen();
}
#endif