Various fixes around Companion trainer mode (#7116)
[opentx.git] / radio / src / targets / taranis / lcd_driver_aspi.cpp
blob47e1b643ad7d07233539745f878c42967db0a7e3
1 /*
2 * Copyright (C) OpenTX
4 * Based on code named
5 * th9x - http://code.google.com/p/th9x
6 * er9x - http://code.google.com/p/er9x
7 * gruvin9x - http://code.google.com/p/gruvin9x
9 * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
21 #include "opentx.h"
23 #define CONTRAST_OFS 5
24 #define RESET_WAIT_DELAY_MS 1300 // Wait time after LCD reset before first command
26 bool lcdInitFinished = false;
27 void lcdInitFinish();
29 #define LCD_NCS_HIGH() LCD_NCS_GPIO->BSRRL = LCD_NCS_GPIO_PIN
30 #define LCD_NCS_LOW() LCD_NCS_GPIO->BSRRH = LCD_NCS_GPIO_PIN
32 #define LCD_A0_HIGH() LCD_SPI_GPIO->BSRRL = LCD_A0_GPIO_PIN
33 #define LCD_A0_LOW() LCD_SPI_GPIO->BSRRH = LCD_A0_GPIO_PIN
35 #define LCD_RST_HIGH() LCD_RST_GPIO->BSRRL = LCD_RST_GPIO_PIN
36 #define LCD_RST_LOW() LCD_RST_GPIO->BSRRH = LCD_RST_GPIO_PIN
38 #define LCD_CLK_HIGH() LCD_SPI_GPIO->BSRRL = LCD_CLK_GPIO_PIN
39 #define LCD_CLK_LOW() LCD_SPI_GPIO->BSRRH = LCD_CLK_GPIO_PIN
41 #define LCD_MOSI_HIGH() LCD_SPI_GPIO->BSRRL = LCD_MOSI_GPIO_PIN
42 #define LCD_MOSI_LOW() LCD_SPI_GPIO->BSRRH = LCD_MOSI_GPIO_PIN
44 void lcdWriteCommand(uint8_t command)
46 int i = 8;
47 LCD_A0_LOW();
49 LCD_CLK_HIGH();
50 LCD_CLK_HIGH();
51 LCD_NCS_LOW();
53 while (i--) {
54 LCD_CLK_LOW();
56 if (command & 0x80)
57 LCD_MOSI_HIGH();
58 else
59 LCD_MOSI_LOW();
61 command <<= 1;
63 LCD_CLK_LOW();
64 LCD_CLK_LOW();
66 LCD_CLK_HIGH();
67 LCD_CLK_HIGH();
70 LCD_NCS_HIGH();
71 LCD_A0_HIGH();
74 void lcdWriteData(uint8_t data)
76 int i = 8;
78 LCD_CLK_HIGH();
79 LCD_CLK_HIGH();
80 LCD_A0_HIGH();
81 LCD_NCS_LOW();
83 while (i--) {
84 LCD_CLK_LOW();
85 if (data & 0x80)
86 LCD_MOSI_HIGH();
87 else
88 LCD_MOSI_LOW();
90 data <<= 1;
92 LCD_CLK_LOW();
93 LCD_CLK_LOW();
95 LCD_CLK_HIGH();
96 LCD_CLK_HIGH();
99 LCD_NCS_HIGH();
100 LCD_A0_HIGH();
103 void lcdStart()
105 lcdWriteCommand(0x2B); // Panel loading set, Internal VLCD.
106 delay_ms(20);
107 lcdWriteCommand(0x25); // Temperature compensation curve definition: 0x25 = -0.05%/oC
108 lcdWriteCommand(0xEA); // Set bias=1/10: Command table NO.27
109 lcdWriteCommand(0x81); // Set Vop
110 #if defined(BOOT)
111 lcdWriteCommand(CONTRAST_OFS+25);
112 #else
113 lcdWriteCommand(CONTRAST_OFS+g_eeGeneral.contrast);
114 #endif
115 lcdWriteCommand(0xA6); // Inverse display off
116 lcdWriteCommand(0xD1); // Set RGB: Command table NO.21, D1=RGB
117 lcdWriteCommand(0xD5); // Set color mode 4K and 12bits: Command table NO.22
118 lcdWriteCommand(0xA0); // Line rates, 25.2 Klps
119 lcdWriteCommand(0xC8); // Set N-LINE inversion
120 lcdWriteCommand(0x1D); // Disable NIV
121 lcdWriteCommand(0xF1); // Set CEN
122 lcdWriteCommand(0x3F); // 1/64 DUTY
123 lcdWriteCommand(0x84); // Disable Partial Display
124 lcdWriteCommand(0xC4); // MY=1, MX=0
125 lcdWriteCommand(0x89); // WA=1, column (CA) increment (+1) first until CA reaches CA boundary, then RA will increment by (+1)
127 lcdWriteCommand(0xF8); // Set Window Program Enable, inside modle
128 lcdWriteCommand(0xF4); // Start column address of RAM program window.
129 lcdWriteCommand(0x00);
130 lcdWriteCommand(0xF5); // Start row address of RAM program window.
131 lcdWriteCommand(0x60);
132 lcdWriteCommand(0xF6); // End column address of RAM program window.
133 lcdWriteCommand(0x47);
134 lcdWriteCommand(0xF7); // End row address of RAM program window.
135 lcdWriteCommand(0x9F);
138 void lcdWriteAddress(uint8_t x, uint8_t y)
140 lcdWriteCommand(x&0x0F); // Set Column Address LSB CA[3:0]
141 lcdWriteCommand((x>>4) | 0x10); // Set Column Address MSB CA[7:4]
143 lcdWriteCommand((y&0x0F) | 0x60); // Set Row Address LSB RA [3:0]
144 lcdWriteCommand(((y>>4) & 0x0F) | 0x70); // Set Row Address MSB RA [7:4]
147 #define LCD_WRITE_BIT(bit) \
148 if (bit) \
149 LCD_MOSI_HIGH(); \
150 else \
151 LCD_MOSI_LOW(); \
152 LCD_CLK_LOW(); \
153 LCD_CLK_LOW(); \
154 LCD_CLK_LOW(); \
155 LCD_CLK_HIGH(); \
156 LCD_CLK_HIGH();
158 void lcdRefresh()
160 if (!lcdInitFinished) {
161 lcdInitFinish();
164 for (uint8_t y=0; y<LCD_H; y++) {
165 uint8_t * p = &displayBuf[y/2 * LCD_W];
167 lcdWriteAddress(0, y);
168 lcdWriteCommand(0xAF);
170 LCD_CLK_HIGH();
171 LCD_A0_HIGH();
172 LCD_NCS_LOW();
174 for (uint32_t x=0; x<LCD_W; x++) {
175 uint8_t b = p[x];
176 if (y & 1)
177 b >>= 4;
178 LCD_WRITE_BIT(b & 0x08);
179 LCD_WRITE_BIT(b & 0x04);
180 LCD_WRITE_BIT(b & 0x02);
181 LCD_WRITE_BIT(b & 0x01);
184 LCD_NCS_HIGH();
185 LCD_A0_HIGH();
187 lcdWriteData(0);
191 void lcdHardwareInit()
193 GPIO_InitTypeDef GPIO_InitStructure;
195 // Configure CLK, MOSI and A0 pins in output push-pull mode
196 GPIO_InitStructure.GPIO_Pin = LCD_MOSI_GPIO_PIN | LCD_CLK_GPIO_PIN | LCD_A0_GPIO_PIN;
197 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
198 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
199 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
200 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
201 GPIO_Init(LCD_SPI_GPIO, &GPIO_InitStructure);
203 LCD_NCS_HIGH();
205 // Configure NCS pin in output push-pull mode with PULLUP
206 GPIO_InitStructure.GPIO_Pin = LCD_NCS_GPIO_PIN;
207 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
208 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
209 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
210 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
211 GPIO_Init(LCD_NCS_GPIO, &GPIO_InitStructure);
213 // Configure RST pin in output push-pull mode with PULLUP
214 GPIO_InitStructure.GPIO_Pin = LCD_RST_GPIO_PIN;
215 GPIO_Init(LCD_RST_GPIO, &GPIO_InitStructure);
219 Proper method for turning of LCD module. It must be used,
220 otherwise we might damage LCD crystals in the long run!
222 void lcdOff()
225 LCD Sleep mode is also good for draining capacitors and enables us
226 to re-init LCD without any delay
228 lcdWriteCommand(0xAE); //LCD sleep
229 delay_ms(3); //wait for caps to drain
232 void lcdReset()
234 LCD_RST_LOW();
235 delay_ms(1); // only 3 us needed according to data-sheet, we use 1 ms
236 LCD_RST_HIGH();
240 Starts LCD initialization routine. It should be called as
241 soon as possible after the reset because LCD takes a lot of
242 time to properly power-on.
244 Make sure that delay_ms() is functional before calling this function!
246 void lcdInit()
248 lcdHardwareInit();
250 if (!WAS_RESET_BY_WATCHDOG_OR_SOFTWARE()) {
251 lcdReset();
256 Finishes LCD initialization. It is called auto-magically when first LCD command is
257 issued by the other parts of the code.
259 void lcdInitFinish()
261 lcdInitFinished = true;
264 LCD needs longer time to initialize in low temperatures. The data-sheet
265 mentions a time of at least 150 ms. The delay of 1300 ms was obtained
266 experimentally. It was tested down to -10 deg Celsius.
268 The longer initialization time seems to only be needed for regular Taranis,
269 the Taranis Plus (9XE) has been tested to work without any problems at -18 deg Celsius.
270 Therefore the delay for T+ is lower.
272 If radio is reset by watchdog or boot-loader the wait is skipped, but the LCD
273 is initialized in any case.
275 This initialization is needed in case the user moved power switch to OFF and
276 then immediately to ON position, because lcdOff() was called. In any case the LCD
277 initialization (without reset) is also recommended by the data sheet.
280 if (!WAS_RESET_BY_WATCHDOG_OR_SOFTWARE()) {
281 #if !defined(BOOT)
282 while (g_tmr10ms < (RESET_WAIT_DELAY_MS/10)); // Wait measured from the power-on
283 #else
284 delay_ms(RESET_WAIT_DELAY_MS);
285 #endif
288 lcdStart();
289 lcdWriteCommand(0xAF); // dc2=1, IC into exit SLEEP MODE, dc3=1 gray=ON, dc4=1 Green Enhanc mode disabled
290 delay_ms(20); // Needed for internal DC-DC converter startup
293 void lcdSetRefVolt(uint8_t val)
295 if (!lcdInitFinished) {
296 lcdInitFinish();
299 lcdWriteCommand(0x81); // Set Vop
300 lcdWriteCommand(val+CONTRAST_OFS); // 0-255