forked from raspberrypi/pico-examples
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathst7789_lcd.c
149 lines (130 loc) · 5.15 KB
/
st7789_lcd.c
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
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include <math.h>
#include "pico/stdlib.h"
#include "hardware/pio.h"
#include "hardware/gpio.h"
#include "hardware/interp.h"
#include "st7789_lcd.pio.h"
#include "raspberry_256x256_rgb565.h"
// Tested with the parts that have the height of 240 and 320
#define SCREEN_WIDTH 240
#define SCREEN_HEIGHT 240
#define IMAGE_SIZE 256
#define LOG_IMAGE_SIZE 8
#define PIN_DIN 0
#define PIN_CLK 1
#define PIN_CS 2
#define PIN_DC 3
#define PIN_RESET 4
#define PIN_BL 5
#define SERIAL_CLK_DIV 1.f
// Format: cmd length (including cmd byte), post delay in units of 5 ms, then cmd payload
// Note the delays have been shortened a little
static const uint8_t st7789_init_seq[] = {
1, 20, 0x01, // Software reset
1, 10, 0x11, // Exit sleep mode
2, 2, 0x3a, 0x55, // Set colour mode to 16 bit
2, 0, 0x36, 0x00, // Set MADCTL: row then column, refresh is bottom to top ????
5, 0, 0x2a, 0x00, 0x00, SCREEN_WIDTH >> 8, SCREEN_WIDTH & 0xff, // CASET: column addresses
5, 0, 0x2b, 0x00, 0x00, SCREEN_HEIGHT >> 8, SCREEN_HEIGHT & 0xff, // RASET: row addresses
1, 2, 0x21, // Inversion on, then 10 ms delay (supposedly a hack?)
1, 2, 0x13, // Normal display on, then 10 ms delay
1, 2, 0x29, // Main screen turn on, then wait 500 ms
0 // Terminate list
};
static inline void lcd_set_dc_cs(bool dc, bool cs) {
sleep_us(1);
gpio_put_masked((1u << PIN_DC) | (1u << PIN_CS), !!dc << PIN_DC | !!cs << PIN_CS);
sleep_us(1);
}
static inline void lcd_write_cmd(PIO pio, uint sm, const uint8_t *cmd, size_t count) {
st7789_lcd_wait_idle(pio, sm);
lcd_set_dc_cs(0, 0);
st7789_lcd_put(pio, sm, *cmd++);
if (count >= 2) {
st7789_lcd_wait_idle(pio, sm);
lcd_set_dc_cs(1, 0);
for (size_t i = 0; i < count - 1; ++i)
st7789_lcd_put(pio, sm, *cmd++);
}
st7789_lcd_wait_idle(pio, sm);
lcd_set_dc_cs(1, 1);
}
static inline void lcd_init(PIO pio, uint sm, const uint8_t *init_seq) {
const uint8_t *cmd = init_seq;
while (*cmd) {
lcd_write_cmd(pio, sm, cmd + 2, *cmd);
sleep_ms(*(cmd + 1) * 5);
cmd += *cmd + 2;
}
}
static inline void st7789_start_pixels(PIO pio, uint sm) {
uint8_t cmd = 0x2c; // RAMWR
lcd_write_cmd(pio, sm, &cmd, 1);
lcd_set_dc_cs(1, 0);
}
int main() {
stdio_init_all();
PIO pio = pio0;
uint sm = 0;
uint offset = pio_add_program(pio, &st7789_lcd_program);
st7789_lcd_program_init(pio, sm, offset, PIN_DIN, PIN_CLK, SERIAL_CLK_DIV);
gpio_init(PIN_CS);
gpio_init(PIN_DC);
gpio_init(PIN_RESET);
gpio_init(PIN_BL);
gpio_set_dir(PIN_CS, GPIO_OUT);
gpio_set_dir(PIN_DC, GPIO_OUT);
gpio_set_dir(PIN_RESET, GPIO_OUT);
gpio_set_dir(PIN_BL, GPIO_OUT);
gpio_put(PIN_CS, 1);
gpio_put(PIN_RESET, 1);
lcd_init(pio, sm, st7789_init_seq);
gpio_put(PIN_BL, 1);
// Other SDKs: static image on screen, lame, boring
// Raspberry Pi Pico SDK: spinning image on screen, bold, exciting
// Lane 0 will be u coords (bits 8:1 of addr offset), lane 1 will be v
// coords (bits 16:9 of addr offset), and we'll represent coords with
// 16.16 fixed point. ACCUM0,1 will contain current coord, BASE0/1 will
// contain increment vector, and BASE2 will contain image base pointer
#define UNIT_LSB 16
interp_config lane0_cfg = interp_default_config();
interp_config_set_shift(&lane0_cfg, UNIT_LSB - 1); // -1 because 2 bytes per pixel
interp_config_set_mask(&lane0_cfg, 1, 1 + (LOG_IMAGE_SIZE - 1));
interp_config_set_add_raw(&lane0_cfg, true); // Add full accumulator to base with each POP
interp_config lane1_cfg = interp_default_config();
interp_config_set_shift(&lane1_cfg, UNIT_LSB - (1 + LOG_IMAGE_SIZE));
interp_config_set_mask(&lane1_cfg, 1 + LOG_IMAGE_SIZE, 1 + (2 * LOG_IMAGE_SIZE - 1));
interp_config_set_add_raw(&lane1_cfg, true);
interp_set_config(interp0, 0, &lane0_cfg);
interp_set_config(interp0, 1, &lane1_cfg);
interp0->base[2] = (uint32_t) raspberry_256x256;
float theta = 0.f;
float theta_max = 2.f * (float) M_PI;
while (1) {
theta += 0.02f;
if (theta > theta_max)
theta -= theta_max;
int32_t rotate[4] = {
cosf(theta) * (1 << UNIT_LSB), -sinf(theta) * (1 << UNIT_LSB),
sinf(theta) * (1 << UNIT_LSB), cosf(theta) * (1 << UNIT_LSB)
};
interp0->base[0] = rotate[0];
interp0->base[1] = rotate[2];
st7789_start_pixels(pio, sm);
for (int y = 0; y < SCREEN_HEIGHT; ++y) {
interp0->accum[0] = rotate[1] * y;
interp0->accum[1] = rotate[3] * y;
for (int x = 0; x < SCREEN_WIDTH; ++x) {
uint16_t colour = *(uint16_t *) (interp0->pop[2]);
st7789_lcd_put(pio, sm, colour >> 8);
st7789_lcd_put(pio, sm, colour & 0xff);
}
}
}
}