-
Notifications
You must be signed in to change notification settings - Fork 129
/
main.c
149 lines (127 loc) · 4.11 KB
/
main.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
#include <stdio.h>
#include <stdlib.h>
#include "pico/stdlib.h"
#include "pico/multicore.h"
#include "hardware/clocks.h"
#include "hardware/irq.h"
#include "hardware/sync.h"
#include "hardware/gpio.h"
#include "hardware/vreg.h"
#include "hardware/structs/bus_ctrl.h"
#include "hardware/dma.h"
#include "pico/sem.h"
#include "dvi.h"
#include "dvi_serialiser.h"
#include "common_dvi_pin_configs.h"
#include "tmds_encode_font_2bpp.h"
// TODO should put this in scratch_x, it out to fit...
#include "font_8x8.h"
#define FONT_CHAR_WIDTH 8
#define FONT_CHAR_HEIGHT 8
#define FONT_N_CHARS 95
#define FONT_FIRST_ASCII 32
// Pick one:
#define MODE_640x480_60Hz
// #define MODE_720x480_60Hz
// #define MODE_800x600_60Hz
// #define MODE_960x540p_60Hz
// #define MODE_1280x720_30Hz
#if defined(MODE_640x480_60Hz)
// DVDD 1.2V (1.1V seems ok too)
#define FRAME_WIDTH 640
#define FRAME_HEIGHT 480
#define VREG_VSEL VREG_VOLTAGE_1_20
#define DVI_TIMING dvi_timing_640x480p_60hz
#elif defined(MODE_720x480_60Hz)
// DVDD 1.2V
#define FRAME_WIDTH 720
#define FRAME_HEIGHT 480
#define VREG_VSEL VREG_VOLTAGE_1_20
#define DVI_TIMING dvi_timing_720x480p_60hz
#elif defined(MODE_800x600_60Hz)
// DVDD 1.3V, going downhill with a tailwind
#define FRAME_WIDTH 800
#define FRAME_HEIGHT 600
#define VREG_VSEL VREG_VOLTAGE_1_30
#define DVI_TIMING dvi_timing_800x600p_60hz
#elif defined(MODE_960x540p_60Hz)
// DVDD 1.25V (slower silicon may need the full 1.3, or just not work)
#define FRAME_WIDTH 960
#define FRAME_HEIGHT 540
#define VREG_VSEL VREG_VOLTAGE_1_25
#define DVI_TIMING dvi_timing_960x540p_60hz
#elif defined(MODE_1280x720_30Hz)
// 1280x720p 30 Hz (nonstandard)
// DVDD 1.25V (slower silicon may need the full 1.3, or just not work)
#define FRAME_WIDTH 1280
#define FRAME_HEIGHT 720
#define VREG_VSEL VREG_VOLTAGE_1_25
#define DVI_TIMING dvi_timing_1280x720p_30hz
#else
#error "Select a video mode!"
#endif
struct dvi_inst dvi0;
#define CHAR_COLS (FRAME_WIDTH / FONT_CHAR_WIDTH)
#define CHAR_ROWS (FRAME_HEIGHT / FONT_CHAR_HEIGHT)
#define COLOUR_PLANE_SIZE_WORDS (CHAR_ROWS * CHAR_COLS * 4 / 32)
char charbuf[CHAR_ROWS * CHAR_COLS];
uint32_t colourbuf[3 * COLOUR_PLANE_SIZE_WORDS];
static inline void set_char(uint x, uint y, char c) {
if (x >= CHAR_COLS || y >= CHAR_ROWS)
return;
charbuf[x + y * CHAR_COLS] = c;
}
// Pixel format RGB222
static inline void set_colour(uint x, uint y, uint8_t fg, uint8_t bg) {
if (x >= CHAR_COLS || y >= CHAR_ROWS)
return;
uint char_index = x + y * CHAR_COLS;
uint bit_index = char_index % 8 * 4;
uint word_index = char_index / 8;
for (int plane = 0; plane < 3; ++plane) {
uint32_t fg_bg_combined = (fg & 0x3) | (bg << 2 & 0xc);
colourbuf[word_index] = (colourbuf[word_index] & ~(0xfu << bit_index)) | (fg_bg_combined << bit_index);
fg >>= 2;
bg >>= 2;
word_index += COLOUR_PLANE_SIZE_WORDS;
}
}
void core1_main() {
dvi_register_irqs_this_core(&dvi0, DMA_IRQ_0);
dvi_start(&dvi0);
while (true) {
for (uint y = 0; y < FRAME_HEIGHT; ++y) {
uint32_t *tmdsbuf;
queue_remove_blocking(&dvi0.q_tmds_free, &tmdsbuf);
for (int plane = 0; plane < 3; ++plane) {
tmds_encode_font_2bpp(
(const uint8_t*)&charbuf[y / FONT_CHAR_HEIGHT * CHAR_COLS],
&colourbuf[y / FONT_CHAR_HEIGHT * (COLOUR_PLANE_SIZE_WORDS / CHAR_ROWS) + plane * COLOUR_PLANE_SIZE_WORDS],
tmdsbuf + plane * (FRAME_WIDTH / DVI_SYMBOLS_PER_WORD),
FRAME_WIDTH,
(const uint8_t*)&font_8x8[y % FONT_CHAR_HEIGHT * FONT_N_CHARS] - FONT_FIRST_ASCII
);
}
queue_add_blocking(&dvi0.q_tmds_valid, &tmdsbuf);
}
}
}
int __not_in_flash("main") main() {
vreg_set_voltage(VREG_VSEL);
sleep_ms(10);
// Run system at TMDS bit clock
set_sys_clock_khz(DVI_TIMING.bit_clk_khz, true);
dvi0.timing = &DVI_TIMING;
dvi0.ser_cfg = DVI_DEFAULT_SERIAL_CONFIG;
dvi_init(&dvi0, next_striped_spin_lock_num(), next_striped_spin_lock_num());
for (uint y = 0; y < CHAR_ROWS; ++y) {
for (uint x = 0; x < CHAR_COLS; ++x) {
set_char(x, y, (x + y * CHAR_COLS) % FONT_N_CHARS + FONT_FIRST_ASCII);
set_colour(x, y, x, y);
}
}
hw_set_bits(&bus_ctrl_hw->priority, BUSCTRL_BUS_PRIORITY_PROC1_BITS);
multicore_launch_core1(core1_main);
while (1)
__wfi();
}