main.c
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include "pico/stdlib.h" 4 #include "pico/multicore.h" 5 #include "hardware/clocks.h" 6 #include "hardware/irq.h" 7 #include "hardware/sync.h" 8 #include "hardware/gpio.h" 9 #include "hardware/vreg.h" 10 #include "pico/sem.h" 11 12 #include "dvi.h" 13 #include "dvi_serialiser.h" 14 #include "common_dvi_pin_configs.h" 15 #include "sprite.h" 16 #include "tile.h" 17 18 #include "map_test_zelda_mini.h" 19 #include "oga_zelda_overworld_flat_rgab5515.h" 20 21 // Pick one: 22 #define MODE_640x480_60Hz 23 // #define MODE_800x480_60Hz 24 // #define MODE_800x600_60Hz 25 // #define MODE_960x540p_60Hz 26 // #define MODE_1280x720_30Hz 27 28 #if defined(MODE_640x480_60Hz) 29 // DVDD 1.2V (1.1V seems ok too) 30 #define FRAME_WIDTH 320 31 #define FRAME_HEIGHT 240 32 #define VREG_VSEL VREG_VOLTAGE_1_20 33 #define DVI_TIMING dvi_timing_640x480p_60hz 34 35 #elif defined(MODE_800x480_60Hz) 36 #define FRAME_WIDTH 400 37 #define FRAME_HEIGHT 240 38 #define VREG_VSEL VREG_VOLTAGE_1_20 39 #define DVI_TIMING dvi_timing_800x480p_60hz 40 41 #elif defined(MODE_800x600_60Hz) 42 // DVDD 1.3V, going downhill with a tailwind 43 #define FRAME_WIDTH 400 44 #define FRAME_HEIGHT 300 45 #define VREG_VSEL VREG_VOLTAGE_1_30 46 #define DVI_TIMING dvi_timing_800x600p_60hz 47 48 #elif defined(MODE_960x540p_60Hz) 49 // DVDD 1.25V (slower silicon may need the full 1.3, or just not work) 50 // Frame resolution is almost the same as a PSP :) 51 #define FRAME_WIDTH 480 52 #define FRAME_HEIGHT 270 53 #define VREG_VSEL VREG_VOLTAGE_1_25 54 #define DVI_TIMING dvi_timing_960x540p_60hz 55 56 #elif defined(MODE_1280x720_30Hz) 57 // 1280x720p 30 Hz (nonstandard) 58 // DVDD 1.25V (slower silicon may need the full 1.3, or just not work) 59 #define FRAME_WIDTH 640 60 #define FRAME_HEIGHT 360 61 #define VREG_VSEL VREG_VOLTAGE_1_25 62 #define DVI_TIMING dvi_timing_1280x720p_30hz 63 64 #else 65 #error "Select a video mode!" 66 #endif 67 68 #define LED_PIN 21 69 70 struct dvi_inst dvi0; 71 72 void core1_main() { 73 dvi_register_irqs_this_core(&dvi0, DMA_IRQ_0); 74 while (queue_is_empty(&dvi0.q_colour_valid)) 75 __wfe(); 76 dvi_start(&dvi0); 77 dvi_scanbuf_main_16bpp(&dvi0); 78 __builtin_unreachable(); 79 } 80 81 static inline int clip(int x, int min, int max) { 82 return x < min ? min : x > max ? max : x; 83 } 84 85 #define N_SCANLINE_BUFFERS 4 86 uint16_t static_scanbuf[N_SCANLINE_BUFFERS][FRAME_WIDTH]; 87 88 void __not_in_flash("render") render_loop() { 89 uint heartbeat = 0; 90 uint frame_ctr = 0; 91 92 tilebg_t bg = { 93 .xscroll = 0, 94 .yscroll = 0, 95 .tileset = oga_zelda_overworld_flat, 96 .tilemap = map_test_zelda_mini, 97 .log_size_x = 10, // 1024px, 64 tiles 98 .log_size_y = 9, // 512px, 32 tiles 99 .tilesize = TILESIZE_16, 100 .fill_loop = (tile_loop_t)tile16_16px_alpha_loop 101 }; 102 103 while (1) { 104 if (++heartbeat >= 30) { 105 heartbeat = 0; 106 gpio_xor_mask(1u << LED_PIN); 107 } 108 for (uint y = 0; y < FRAME_HEIGHT; ++y) { 109 uint16_t *pixbuf; 110 queue_remove_blocking(&dvi0.q_colour_free, &pixbuf); 111 tile16(pixbuf, &bg, y, FRAME_WIDTH); 112 queue_add_blocking(&dvi0.q_colour_valid, &pixbuf); 113 } 114 bg.xscroll += 3; 115 bg.yscroll += 2; 116 ++frame_ctr; 117 } 118 } 119 120 int main() { 121 vreg_set_voltage(VREG_VSEL); 122 sleep_ms(10); 123 set_sys_clock_khz(DVI_TIMING.bit_clk_khz, true); 124 125 setup_default_uart(); 126 127 gpio_init(LED_PIN); 128 gpio_set_dir(LED_PIN, GPIO_OUT); 129 130 printf("Configuring DVI\n"); 131 132 dvi0.timing = &DVI_TIMING; 133 dvi0.ser_cfg = DVI_DEFAULT_SERIAL_CONFIG; 134 dvi_init(&dvi0, next_striped_spin_lock_num(), next_striped_spin_lock_num()); 135 136 printf("Core 1 start\n"); 137 multicore_launch_core1(core1_main); 138 139 printf("Allocating scanline buffers\n"); 140 for (int i = 0; i < N_SCANLINE_BUFFERS; ++i) { 141 void *bufptr = &static_scanbuf[i]; 142 queue_add_blocking((void*)&dvi0.q_colour_free, &bufptr); 143 } 144 145 // Core 1 will fire up the DVI once it sees the first colour buffer has been rendered 146 printf("Start rendering\n"); 147 render_loop(); 148 __builtin_unreachable(); 149 } 150