/ software / apps / terminal / 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 "hardware/structs/bus_ctrl.h"
 11  #include "hardware/structs/ssi.h"
 12  #include "hardware/dma.h"
 13  #include "pico/sem.h"
 14  
 15  #include "dvi.h"
 16  #include "dvi_serialiser.h"
 17  #include "common_dvi_pin_configs.h"
 18  #include "tmds_encode.h"
 19  
 20  #include "font_8x8.h"
 21  #define FONT_CHAR_WIDTH 8
 22  #define FONT_CHAR_HEIGHT 8
 23  #define FONT_N_CHARS 95
 24  #define FONT_FIRST_ASCII 32
 25  
 26  
 27  // Pick one:
 28  #define MODE_640x480_60Hz
 29  // #define MODE_800x600_60Hz
 30  // #define MODE_960x540p_60Hz
 31  // #define MODE_1280x720_30Hz
 32  
 33  #if defined(MODE_640x480_60Hz)
 34  // DVDD 1.2V (1.1V seems ok too)
 35  #define FRAME_WIDTH 640
 36  #define FRAME_HEIGHT 480
 37  #define VREG_VSEL VREG_VOLTAGE_1_20
 38  #define DVI_TIMING dvi_timing_640x480p_60hz
 39  
 40  #elif defined(MODE_800x600_60Hz)
 41  // DVDD 1.3V, going downhill with a tailwind
 42  #define FRAME_WIDTH 800
 43  #define FRAME_HEIGHT 600
 44  #define VREG_VSEL VREG_VOLTAGE_1_30
 45  #define DVI_TIMING dvi_timing_800x600p_60hz
 46  
 47  
 48  #elif defined(MODE_960x540p_60Hz)
 49  // DVDD 1.25V (slower silicon may need the full 1.3, or just not work)
 50  #define FRAME_WIDTH 960
 51  #define FRAME_HEIGHT 540
 52  #define VREG_VSEL VREG_VOLTAGE_1_25
 53  #define DVI_TIMING dvi_timing_960x540p_60hz
 54  
 55  #elif defined(MODE_1280x720_30Hz)
 56  // 1280x720p 30 Hz (nonstandard)
 57  // DVDD 1.25V (slower silicon may need the full 1.3, or just not work)
 58  #define FRAME_WIDTH 1280
 59  #define FRAME_HEIGHT 720
 60  #define VREG_VSEL VREG_VOLTAGE_1_25
 61  #define DVI_TIMING dvi_timing_1280x720p_30hz
 62  
 63  #else
 64  #error "Select a video mode!"
 65  #endif
 66  
 67  #define LED_PIN 16
 68  
 69  struct dvi_inst dvi0;
 70  struct semaphore dvi_start_sem;
 71  
 72  #define CHAR_COLS (FRAME_WIDTH / FONT_CHAR_WIDTH)
 73  #define CHAR_ROWS (FRAME_HEIGHT / FONT_CHAR_HEIGHT)
 74  char charbuf[CHAR_ROWS * CHAR_COLS];
 75  
 76  static inline void prepare_scanline(const char *chars, uint y) {
 77  	static uint8_t scanbuf[FRAME_WIDTH / 8];
 78  	// First blit font into 1bpp scanline buffer, then encode scanbuf into tmdsbuf
 79  	for (uint i = 0; i < CHAR_COLS; ++i) {
 80  		uint c = chars[i + y / FONT_CHAR_HEIGHT * CHAR_COLS];
 81  		scanbuf[i] = font_8x8[(c - FONT_FIRST_ASCII) + (y % FONT_CHAR_HEIGHT) * FONT_N_CHARS];
 82  	}
 83  	uint32_t *tmdsbuf;
 84  	queue_remove_blocking(&dvi0.q_tmds_free, &tmdsbuf);
 85  	tmds_encode_1bpp((const uint32_t*)scanbuf, tmdsbuf, FRAME_WIDTH);
 86  	queue_add_blocking(&dvi0.q_tmds_valid, &tmdsbuf);
 87  }
 88  
 89  void core1_scanline_callback() {
 90  	static uint y = 1;
 91  	prepare_scanline(charbuf, y);
 92  	y = (y + 1) % FRAME_HEIGHT;
 93  }
 94  
 95  void __not_in_flash("main") core1_main() {
 96  	dvi_register_irqs_this_core(&dvi0, DMA_IRQ_0);
 97  	sem_acquire_blocking(&dvi_start_sem);
 98  	dvi_start(&dvi0);
 99  
100  	// The text display is completely IRQ driven (takes up around 30% of cycles @
101  	// VGA). We could do something useful, or we could just take a nice nap
102  	while (1) 
103  		__wfi();
104  	__builtin_unreachable();
105  }
106  
107  int __not_in_flash("main") main() {
108  	vreg_set_voltage(VREG_VSEL);
109  	sleep_ms(10);
110  #ifdef RUN_FROM_CRYSTAL
111  	set_sys_clock_khz(12000, true);
112  #else
113  	// Run system at TMDS bit clock
114  	set_sys_clock_khz(DVI_TIMING.bit_clk_khz, true);
115  #endif
116  
117  	setup_default_uart();
118  
119  	gpio_init(LED_PIN);
120  	gpio_set_dir(LED_PIN, GPIO_OUT);
121  
122  	printf("Configuring DVI\n");
123  
124  	dvi0.timing = &DVI_TIMING;
125  	dvi0.ser_cfg = DVI_DEFAULT_SERIAL_CONFIG;
126  	dvi0.scanline_callback = core1_scanline_callback;
127  	dvi_init(&dvi0, next_striped_spin_lock_num(), next_striped_spin_lock_num());
128  
129  	printf("Prepare first scanline\n");
130  	for (int i = 0; i < CHAR_ROWS * CHAR_COLS; ++i)
131  		charbuf[i] = FONT_FIRST_ASCII + i % FONT_N_CHARS;
132  	prepare_scanline(charbuf, 0);
133  
134  	printf("Core 1 start\n");
135  	sem_init(&dvi_start_sem, 0, 1);
136  	hw_set_bits(&bus_ctrl_hw->priority, BUSCTRL_BUS_PRIORITY_PROC1_BITS);
137  	multicore_launch_core1(core1_main);
138  
139  
140  	sem_release(&dvi_start_sem);
141  	while (1)
142  		__wfi();
143  	__builtin_unreachable();
144  }
145