kopia lustrzana https://github.com/Wren6991/PicoDVI
220 wiersze
6.9 KiB
Plaintext
220 wiersze
6.9 KiB
Plaintext
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include "pico/stdlib.h"
|
|
#include "pico/multicore.h"
|
|
#include "dvi.h"
|
|
#include "dvi_serialiser.h"
|
|
#include "common_dvi_pin_configs.h"
|
|
#include "tmds_encode.h"
|
|
#include "font_8x16.h"
|
|
|
|
// Display configuration
|
|
#define SCREEN_WIDTH 80
|
|
#define SCREEN_HEIGHT 30
|
|
#define FONT_WIDTH 8
|
|
#define FONT_HEIGHT 16
|
|
|
|
static struct dvi_inst dvi0;
|
|
static char screen[SCREEN_HEIGHT][SCREEN_WIDTH + 1]; // +1 for null terminator
|
|
|
|
// Core 1: DVI handling
|
|
void core1_main() {
|
|
dvi_register_irqs_this_core(&dvi0, DMA_IRQ_0);
|
|
dvi_start(&dvi0);
|
|
while (true) {
|
|
dvi_scanbuf_main_8bpp(&dvi0);
|
|
}
|
|
}
|
|
|
|
// Render a character at (x, y)
|
|
static void render_char(uint x, uint y, char c) {
|
|
uint8_t *bufptr = (uint8_t *)dvi0.scanbuf + y * FONT_HEIGHT * dvi0.timing->h_active_pixels + x * FONT_WIDTH;
|
|
const uint8_t *font = font_8x16 + (c & 0x7f) * FONT_HEIGHT;
|
|
for (uint row = 0; row < FONT_HEIGHT; row++) {
|
|
uint8_t *rowptr = bufptr + row * dvi0.timing->h_active_pixels;
|
|
uint8_t pixels = font[row];
|
|
for (uint col = 0; col < FONT_WIDTH; col++) {
|
|
rowptr[col] = (pixels & (1 << (FONT_WIDTH - 1 - col))) ? 0xff : 0x00;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Render the entire screen
|
|
static void render() {
|
|
for (uint y = 0; y < SCREEN_HEIGHT; y++) {
|
|
for (uint x = 0; x < SCREEN_WIDTH; x++) {
|
|
render_char(x, y, screen[y][x]);
|
|
}
|
|
}
|
|
}
|
|
|
|
int main() {
|
|
// Initialize screen buffer
|
|
for (uint y = 0; y < SCREEN_HEIGHT; y++) {
|
|
memset(screen[y], ' ', SCREEN_WIDTH);
|
|
screen[y][SCREEN_WIDTH] = '\0';
|
|
}
|
|
strcpy(screen[0], "Noneya's Terminal");
|
|
|
|
// Initialize DVI
|
|
dvi0.timing = &dvi_timing_640x480p_60hz;
|
|
dvi0.ser_cfg = adafruit_hdmi_sock_cfg;
|
|
dvi0.scanbuf = malloc(dvi0.timing->h_active_pixels * dvi0.timing->v_active_lines);
|
|
dvi_init(&dvi0, 30, 31); // Use spinlocks 30 and 31
|
|
multicore_launch_core1(core1_main);
|
|
|
|
// Main loop: Render continuously
|
|
while (true) {
|
|
render();
|
|
sleep_ms(100);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
// /* Changes to use IBM VGA 8x16 font (replacing 8x8 font):
|
|
// * - Font Source: IBM_VGA_8x16.bin (4096 bytes, 256 chars) from https://github.com/spacerace/romfont
|
|
// * - Conversion: Python script /home/noneya/pico/PicoDVI/software/fonts/convert_font.py
|
|
// * - Generates font_8x16.h (1520 bytes, ASCII 32-126)
|
|
// * - Font Include: Changed #include "font_8x8.h" to #include "font_8x16.h"
|
|
// * - Font Height: Set FONT_CHAR_HEIGHT=16 (was 8)
|
|
// * - Grid Size: CHAR_ROWS=FRAME_HEIGHT/FONT_CHAR_HEIGHT (480/16=30, was 60); CHAR_COLS=80 (unchanged)
|
|
// * - Char Buffer: Adjusted charbuf[CHAR_ROWS * CHAR_COLS] to 80x30=2400 bytes (was 80x60=4800)
|
|
// * - prepare_scanline(): Updated to font_8x16[(c - FONT_FIRST_ASCII) * FONT_CHAR_HEIGHT + (y % FONT_CHAR_HEIGHT)]
|
|
// * - Bit Reversal: Added reverse_byte() to fix mirrored text; applied in prepare_scanline()
|
|
// * - Text: Displays "Noneya's Terminal" on first row
|
|
// * Setup: 640x480, adafruit_hdmi_sock_cfg, DVI_MONOCHROME_TMDS=1
|
|
// */
|
|
// /* Build Instructions
|
|
// cd /home/noneya/pico/PicoDVI/software/build
|
|
// cmake -DPICO_SDK_PATH=/home/noneya/pico/pico-sdk \
|
|
// -DPICO_EXTRAS_PATH=/home/noneya/pico/pico-extras \
|
|
// -DPICO_PLATFORM=rp2040 \
|
|
// -DPICO_COPY_TO_RAM=1 \
|
|
// -DDVI_DEFAULT_SERIAL_CONFIG=adafruit_hdmi_sock_cfg ..
|
|
// make -j$(nproc)
|
|
// cp apps/my_terminal/my_terminal.uf2 /media/noneya/RPI-RP2/
|
|
// */
|
|
// #include <stdio.h>
|
|
// #include <stdlib.h>
|
|
// #include <string.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.h"
|
|
|
|
// #include "font_8x16.h"
|
|
// #define FONT_CHAR_WIDTH 8
|
|
// #define FONT_CHAR_HEIGHT 16
|
|
// #define FONT_N_CHARS 95
|
|
// #define FONT_FIRST_ASCII 32
|
|
|
|
// #define MODE_640x480_60Hz
|
|
// #if defined(MODE_640x480_60Hz)
|
|
// #define FRAME_WIDTH 640
|
|
// #define FRAME_HEIGHT 480
|
|
// #define VREG_VSEL VREG_VOLTAGE_1_20
|
|
// #define DVI_TIMING dvi_timing_640x480p_60hz
|
|
// #else
|
|
// #error "Select a video mode!"
|
|
// #endif
|
|
|
|
// #define LED_PIN 16
|
|
|
|
// struct dvi_inst dvi0;
|
|
// struct semaphore dvi_start_sem;
|
|
|
|
// #define CHAR_COLS (FRAME_WIDTH / FONT_CHAR_WIDTH)
|
|
// #define CHAR_ROWS (FRAME_HEIGHT / FONT_CHAR_HEIGHT)
|
|
// char charbuf[CHAR_ROWS * CHAR_COLS];
|
|
|
|
// // Helper function to reverse bits in a byte (fixes mirrored text)
|
|
// static inline uint8_t reverse_byte(uint8_t b) {
|
|
// b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
|
|
// b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
|
|
// b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
|
|
// return b;
|
|
// }
|
|
|
|
// static inline void prepare_scanline(const char *chars, uint y) {
|
|
// static uint8_t scanbuf[FRAME_WIDTH / 8];
|
|
// for (uint i = 0; i < CHAR_COLS; ++i) {
|
|
// uint c = chars[i + y / FONT_CHAR_HEIGHT * CHAR_COLS];
|
|
// scanbuf[i] = reverse_byte(font_8x16[(c - FONT_FIRST_ASCII) * FONT_CHAR_HEIGHT + (y % FONT_CHAR_HEIGHT)]);
|
|
// }
|
|
// uint32_t *tmdsbuf;
|
|
// queue_remove_blocking(&dvi0.q_tmds_free, &tmdsbuf);
|
|
// tmds_encode_1bpp((const uint32_t*)scanbuf, tmdsbuf, FRAME_WIDTH);
|
|
// queue_add_blocking(&dvi0.q_tmds_valid, &tmdsbuf);
|
|
// }
|
|
|
|
// void core1_scanline_callback() {
|
|
// static uint y = 1;
|
|
// prepare_scanline(charbuf, y);
|
|
// y = (y + 1) % FRAME_HEIGHT;
|
|
// }
|
|
|
|
// void __not_in_flash("main") core1_main() {
|
|
// dvi_register_irqs_this_core(&dvi0, DMA_IRQ_0);
|
|
// sem_acquire_blocking(&dvi_start_sem);
|
|
// dvi_start(&dvi0);
|
|
// while (1)
|
|
// __wfi();
|
|
// __builtin_unreachable();
|
|
// }
|
|
|
|
// int __not_in_flash("main") main() {
|
|
// vreg_set_voltage(VREG_VSEL);
|
|
// sleep_ms(10);
|
|
// #ifdef RUN_FROM_CRYSTAL
|
|
// set_sys_clock_khz(12000, true);
|
|
// #else
|
|
// set_sys_clock_khz(DVI_TIMING.bit_clk_khz, true);
|
|
// #endif
|
|
|
|
// setup_default_uart();
|
|
|
|
// gpio_init(LED_PIN);
|
|
// gpio_set_dir(LED_PIN, GPIO_OUT);
|
|
|
|
// printf("Configuring DVI\n");
|
|
|
|
// dvi0.timing = &DVI_TIMING;
|
|
// dvi0.ser_cfg = DVI_DEFAULT_SERIAL_CONFIG;
|
|
// dvi0.scanline_callback = core1_scanline_callback;
|
|
// dvi_init(&dvi0, next_striped_spin_lock_num(), next_striped_spin_lock_num());
|
|
|
|
// printf("Prepare first scanline\n");
|
|
// for (int i = 0; i < CHAR_ROWS * CHAR_COLS; ++i)
|
|
// charbuf[i] = ' ';
|
|
// const char *custom_text = "Noneya's Terminal";
|
|
// for (int i = 0; i < strlen(custom_text) && i < CHAR_COLS; ++i)
|
|
// charbuf[i] = custom_text[i];
|
|
// prepare_scanline(charbuf, 0);
|
|
|
|
// printf("Core 1 start\n");
|
|
// sem_init(&dvi_start_sem, 0, 1);
|
|
// hw_set_bits(&bus_ctrl_hw->priority, BUSCTRL_BUS_PRIORITY_PROC1_BITS);
|
|
// multicore_launch_core1(core1_main);
|
|
|
|
// sem_release(&dvi_start_sem);
|
|
// while (1)
|
|
// __wfi();
|
|
// __builtin_unreachable();
|
|
// }
|