kopia lustrzana https://github.com/Wren6991/PicoDVI
144 wiersze
3.9 KiB
C
144 wiersze
3.9 KiB
C
#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/structs/ssi.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_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_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 = DEFAULT_DVI_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();
|
|
}
|
|
|