/ software / apps / tiles / main.c
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