-
-
Notifications
You must be signed in to change notification settings - Fork 64
Expand file tree
/
Copy pathmain.c
More file actions
211 lines (183 loc) · 6.07 KB
/
Copy pathmain.c
File metadata and controls
211 lines (183 loc) · 6.07 KB
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
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
#include <lcddrvce.h>
#include <graphx.h>
#include <sys/lcd.h>
#include <ti/getcsc.h>
#include <stdint.h>
#include <string.h>
#define HALF_LCD_WIDTH (LCD_WIDTH / 2)
#define HALF_LCD_HEIGHT (LCD_HEIGHT / 2)
/* Function Prototypes */
void PrintCentered(const char *str, unsigned int border);
void QuarterResFillScreen(uint8_t color);
void QuarterResSwapDraw(void);
void SetHalfResMode(bool enable);
int main(void)
{
/* Initialize GraphX first, because it sets LCD timing */
gfx_Begin();
/* Set half-resolution mode */
SetHalfResMode(true);
/* Set clipping to an 160x120 area that draws to every second line of the half-res buffer */
gfx_SetClipRegion(0, 0, HALF_LCD_WIDTH - 1, HALF_LCD_HEIGHT - 1);
gfx_SetDrawBuffer();
unsigned int border = 2;
int dir = 1;
/* Wait for a keypress */
while (!os_GetCSC())
{
/* Clear the screen, gfx_FillScreen covers too much area so use this instead */
QuarterResFillScreen(255);
/* Print the message on the screen */
PrintCentered("Hello, World!", border);
/* Swap buffers and fill in every second line */
QuarterResSwapDraw();
/* Change the border size for the next frame */
border += dir;
if (border <= 2 || border >= 25)
{
dir = -dir;
}
}
/* Ensure one empty frame is fully displayed to make the transition to full-res clean */
gfx_FillScreen(255);
gfx_SwapDraw();
gfx_FillScreen(255);
gfx_SwapDraw();
/* Restore normal resolution mode */
SetHalfResMode(false);
/* Wait for the second empty frame to display */
gfx_Wait();
/* Deinitialize GraphX */
gfx_End();
return 0;
}
/* Prints a quarter-res screen centered string */
void PrintCentered(const char *str, unsigned int border)
{
unsigned int width = gfx_GetStringWidth(str);
gfx_PrintStringXY(str,
(HALF_LCD_WIDTH - width) / 2,
(HALF_LCD_HEIGHT - 8) / 2);
gfx_Circle(HALF_LCD_WIDTH / 2, HALF_LCD_HEIGHT / 2, width / 2 + border);
}
/* Fills the drawable area of a quarter-res screen */
void QuarterResFillScreen(uint8_t color)
{
uint8_t oldColor = gfx_SetColor(color);
gfx_FillRectangle_NoClip(0, 0, HALF_LCD_WIDTH, HALF_LCD_HEIGHT);
gfx_SetColor(oldColor);
}
/* Copies the rendered lines to the unrendered lines before swapping the buffer */
void QuarterResSwapDraw(void)
{
gfx_CopyRectangle(gfx_buffer, gfx_buffer, 0, 0, HALF_LCD_WIDTH, 0, HALF_LCD_WIDTH, HALF_LCD_HEIGHT);
gfx_SwapDraw();
}
void SetHalfResMode(bool enable)
{
typedef struct lcd_timing
{
uint32_t : 2;
uint32_t PPL : 6;
uint32_t HSW : 8;
uint32_t HFP : 8;
uint32_t HBP : 8;
uint32_t LPP : 10;
uint32_t VSW : 6;
uint32_t VFP : 8;
uint32_t VBP : 8;
uint32_t PCD_LO : 5;
uint32_t CLKSEL : 1;
uint32_t ACB : 5;
uint32_t IVS : 1;
uint32_t IHS : 1;
uint32_t IPC : 1;
uint32_t IOE : 1;
uint32_t : 1;
uint32_t CPL : 10;
uint32_t BCD : 1;
uint32_t PCD_HI : 5;
} lcd_timing_t;
typedef struct res_settings
{
uint8_t frctrl;
uint8_t bp;
uint16_t xe;
uint8_t tfa;
uint8_t ramctrl1;
lcd_timing_t timing;
} res_settings_t;
static res_settings_t settings[2] =
{
{
/* Default ST7789 settings */
.frctrl = LCD_FRCTRL_DEFAULT,
.bp = LCD_BP_DEFAULT,
.xe = LCD_WIDTH - 1,
.tfa = 0,
.ramctrl1 = LCD_RAMCTRL1_DEFAULT
},
{
/* With the following ST7789 timing:
* Refreshes LCD in at most 16.51 ms after VSYNC, assuming worst case 9.5 MHz clock
* Waits at least 3.42 ms after VSYNC to read LCD memory, assuming worst case 10.5 MHz clock
*/
.frctrl = LCD_RTN_378 | LCD_NL_DEFAULT, /* 378 clocks per line */
.bp = 95, /* 95 lines of back porch */
.xe = HALF_LCD_WIDTH - 1,
.tfa = HALF_LCD_WIDTH,
.ramctrl1 = LCD_DM_VSYNC | LCD_RAM_DEFAULT,
/* With the following PL111 timing:
* Refreshes LCD at 60 Hz = 24 MHz / (800*250*2), a VSYNC period of 16.67 ms
* Outputs 38400 pixels to LCD memory within the first 3.40 ms after VSYNC
*/
.timing =
{
.PPL = 768 / 16 - 1, /* 768 pixels per line */
.HSW = 1 - 1,
.HFP = (800 - 768 - 1 - 1) - 1, /* 800 total clocks per line */
.HBP = 1 - 1,
.LPP = HALF_LCD_WIDTH * LCD_HEIGHT / 768, /* 50 lines */
.VSW = 1 - 1,
.VFP = 250 - (HALF_LCD_WIDTH * LCD_HEIGHT / 768) - 1, /* 250 total lines */
.VBP = 0,
.PCD_LO = (2 - 2) & 0x1F, /* clock divisor of 2 */
.CLKSEL = 0,
.ACB = 0,
.IVS = 1,
.IHS = 1,
.IPC = 1,
.IOE = 1,
.CPL = 768 - 1,
.BCD = 0,
.PCD_HI = (2 - 2) >> 5
}
}
};
const res_settings_t *p = &settings[enable];
/* Initialize LCD driver */
lcd_Init();
/* Set clocks per line */
lcd_SetNormalFrameRateControl(p->frctrl);
/* Set back porch */
lcd_SetNormalBackPorchControl(p->bp);
/* Set horizontal output window */
lcd_SetColumnAddress(0, p->xe);
/* Set fixed left scroll area */
lcd_SetScrollArea(p->tfa, LCD_WIDTH - p->tfa, 0);
/* Set starting vertical scroll address to 0 */
lcd_SetScrollAddress(0);
/* Set display mode */
lcd_SetRamInterface(p->ramctrl1);
/* Set interlace mode */
lcd_SetInterlacedMode(enable);
/* Save old display timing when enabling */
if (enable)
{
memcpy(&settings[0].timing, (const void *)&lcd_Timing0, sizeof(settings[0].timing));
}
/* Set display timing */
memcpy((void *)&lcd_Timing0, &p->timing, sizeof(p->timing));
/* Cleanup LCD driver */
lcd_Cleanup();
}