1 /* 2 * Generate a VGA signal using a PIC32 microcontroller. 3 * 4 * Copyright (C) 2017, 2018 Paul Boddie <paul@boddie.org.uk> 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 21 #include "pic32_c.h" 22 #include "init.h" 23 #include "debug.h" 24 25 /* Specific functionality. */ 26 27 #include "main.h" 28 #include "devconfig.h" 29 #include "vga.h" 30 #include "display.h" 31 #include "display_config.h" 32 #include "vga_display.h" 33 34 35 36 /* Define timers if not indicated in the build configuration. */ 37 38 #ifndef LINE_CHANNELS 39 #define LINE_CHANNELS 1 40 #endif 41 42 #ifndef LINE_TIMER 43 #define LINE_TIMER 2 44 #endif 45 46 #ifndef TRANSFER_TIMER 47 #define TRANSFER_TIMER 0 48 #endif 49 50 /* Define different output ports and pins for parallel mode. */ 51 52 #ifndef PARALLEL_MODE 53 #define VGA_OUTPUT PORTB 54 #define OC1_PIN RPA0R 55 #define OC2_PIN RPA1R 56 #define LED_PIN (1 << 3) 57 #else 58 #define VGA_OUTPUT PM_REG(0, PMxDIN) 59 #define OC1_PIN RPB4R 60 #define OC2_PIN RPB5R 61 #define LED_PIN (1 << 2) 62 #endif 63 64 65 66 /* Bundled image data. */ 67 68 extern uint8_t screendata[]; 69 extern uint32_t screendata_width, screendata_height; 70 extern uint8_t sprite[]; 71 extern uint32_t sprite_width, sprite_height; 72 73 74 75 /* Busy wait. */ 76 77 static void wait(uint32_t delay) 78 { 79 uint32_t counter = delay; 80 81 if (!delay) return; 82 while (counter--) __asm__(""); /* retain loop */ 83 } 84 85 /* Blink an attached LED with delays implemented using a loop. */ 86 87 static void blink(uint32_t delay, uint32_t port, uint32_t pins) 88 { 89 /* Clear outputs (LED). */ 90 91 CLR_REG(port, pins); 92 93 while (1) 94 { 95 wait(delay); 96 97 /* Invert outputs (LED). */ 98 99 INV_REG(port, pins); 100 } 101 } 102 103 /* Move a sprite around on the framebuffer. */ 104 105 static void animate(uint32_t delay) 106 { 107 uint8_t background[sprite_width * sprite_height]; 108 int x, y; 109 110 while (1) 111 for (y = 0; y < screendata_height - sprite_height; y++) 112 for (x = 0; x < screendata_width - sprite_width; x++) 113 { 114 /* Copy to the store from the display, then blit the image. */ 115 116 copy_display(&display_config, background, sprite_width, sprite_height, x, y, -1, 0); 117 copy_display(&display_config, sprite, sprite_width, sprite_height, x, y, 0x8c, 1); 118 119 wait(delay); 120 121 /* Copy to the display from the store, restoring the original 122 background. */ 123 124 copy_display(&display_config, background, sprite_width, sprite_height, x, y, -1, 1); 125 } 126 } 127 128 129 130 /* Main program. */ 131 132 void main(void) 133 { 134 init_memory(); 135 init_pins(); 136 init_outputs(); 137 138 unlock_config(); 139 config_oc(); 140 config_uart(); 141 lock_config(); 142 143 init_dma(); 144 145 #ifdef PARALLEL_MODE 146 init_pm(); 147 148 /* Configure parallel master mode. */ 149 150 pm_init(0, 0b10); 151 pm_set_output(0, 1, 0); 152 pm_on(0); 153 #endif 154 155 /* Initialise VGA output with one or two line channels, configuring a line 156 timer and any transfer timer, with an initiating channel being introduced 157 if a transfer timer is specified. */ 158 159 init_vga_with_timers(&display_config, LINE_CHANNELS, LINE_TIMER, TRANSFER_TIMER); 160 161 /* Configure VGA output transfer to the output register, also configuring 162 output compare units for horizontal and vertical sync. */ 163 164 vga_configure_transfer(VGA_OUTPUT); 165 vga_configure_sync(1, 2); 166 167 uart_init(1, FPB, 115200); 168 uart_on(1); 169 170 interrupts_on(); 171 172 /* Plot the image centred on the screen. */ 173 174 copy_display(&display_config, screendata, screendata_width, screendata_height, 175 (LINE_LENGTH - screendata_width) / 2, (LINE_COUNT - screendata_height) / 2, -1, 1); 176 177 /* Move a sprite around on the screen with a delay between each movement. */ 178 179 animate(1 << 24); 180 } 181 182 183 184 /* Exception and interrupt handlers. */ 185 186 void exception_handler(void) 187 { 188 blink(3 << 12, PORTA, LED_PIN); 189 } 190 191 void interrupt_handler(void) 192 { 193 uint32_t ifs; 194 195 /* Check for a OC1 interrupt condition. */ 196 197 ifs = REG(OCIFS) & OC_INT_FLAGS(1, OCxIF); 198 199 if (ifs) 200 { 201 vga_interrupt_handler(); 202 CLR_REG(OCIFS, ifs); 203 } 204 } 205 206 207 208 /* Peripheral pin configuration. */ 209 210 void config_oc(void) 211 { 212 /* Map OC1. */ 213 214 REG(OC1_PIN) = 0b0101; 215 216 /* Map OC2. */ 217 218 REG(OC2_PIN) = 0b0101; 219 } 220 221 void config_uart(void) 222 { 223 /* Map U1RX to RPB13. */ 224 225 REG(U1RXR) = 0b0011; /* U1RXR<3:0> = 0011 (RPB13) */ 226 227 /* Map U1TX to RPB15. */ 228 229 REG(RPB15R) = 0b0001; /* RPB15R<3:0> = 0001 (U1TX) */ 230 231 /* Set RPB13 to input. */ 232 233 SET_REG(TRISB, 1 << 13); 234 }