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 51 52 /* Bundled image data. */ 53 54 extern uint8_t screendata[]; 55 extern uint32_t screendata_width, screendata_height; 56 57 58 59 /* Blink an attached LED with delays implemented using a loop. */ 60 61 static void blink(uint32_t delay, uint32_t port, uint32_t pins) 62 { 63 uint32_t counter; 64 65 /* Clear outputs (LED). */ 66 67 CLR_REG(port, pins); 68 69 while (1) 70 { 71 counter = delay; 72 73 while (counter--) __asm__(""); /* retain loop */ 74 75 /* Invert outputs (LED). */ 76 77 INV_REG(port, pins); 78 } 79 } 80 81 82 83 /* Main program. */ 84 85 void main(void) 86 { 87 init_memory(); 88 init_pins(); 89 init_outputs(); 90 91 unlock_config(); 92 config_oc(); 93 config_uart(); 94 lock_config(); 95 96 init_dma(); 97 98 /* Initialise VGA output with one or two line channels, configuring a line 99 timer and any transfer timer, with an initiating channel being introduced 100 if a transfer timer is specified. */ 101 102 init_vga_with_timers(&display_config, LINE_CHANNELS, LINE_TIMER, TRANSFER_TIMER); 103 104 /* Configure VGA output transfer to the output register, also configuring 105 output compare units for horizontal and vertical sync. */ 106 107 vga_configure_transfer(PORTB); 108 vga_configure_sync(1, 2); 109 110 uart_init(1, FPB, 115200); 111 uart_on(1); 112 113 interrupts_on(); 114 115 copy_to_framebuffer(&display_config, screendata, screendata_width, screendata_height); 116 blink(1 << 24, PORTA, 1 << 3); 117 } 118 119 120 121 /* Exception and interrupt handlers. */ 122 123 void exception_handler(void) 124 { 125 blink(3 << 12, PORTA, 1 << 3); 126 } 127 128 void interrupt_handler(void) 129 { 130 uint32_t ifs; 131 132 /* Check for a OC1 interrupt condition. */ 133 134 ifs = REG(OCIFS) & OC_INT_FLAGS(1, OCxIF); 135 136 if (ifs) 137 { 138 vga_interrupt_handler(); 139 CLR_REG(OCIFS, ifs); 140 } 141 } 142 143 144 145 /* Peripheral pin configuration. */ 146 147 void config_oc(void) 148 { 149 /* Map OC1 to RPA0. */ 150 151 REG(RPA0R) = 0b0101; /* RPA0R<3:0> = 0101 (OC1) */ 152 153 /* Map OC2 to RPA1. */ 154 155 REG(RPA1R) = 0b0101; /* RPA1R<3:0> = 0101 (OC2) */ 156 } 157 158 void config_uart(void) 159 { 160 /* Map U1RX to RPB13. */ 161 162 REG(U1RXR) = 0b0011; /* U1RXR<3:0> = 0011 (RPB13) */ 163 164 /* Map U1TX to RPB15. */ 165 166 REG(RPB15R) = 0b0001; /* RPB15R<3:0> = 0001 (U1TX) */ 167 168 /* Set RPB13 to input. */ 169 170 SET_REG(TRISB, 1 << 13); 171 }