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 /* Blink an attached LED with delays implemented using a loop. */ 37 38 static void blink(uint32_t delay, uint32_t port, uint32_t pins) 39 { 40 uint32_t counter; 41 42 /* Clear outputs (LED). */ 43 44 CLR_REG(port, pins); 45 46 while (1) 47 { 48 counter = delay; 49 50 while (counter--) __asm__(""); /* retain loop */ 51 52 /* Invert outputs (LED). */ 53 54 INV_REG(port, pins); 55 } 56 } 57 58 59 60 /* Main program. */ 61 62 void main(void) 63 { 64 init_memory(); 65 init_pins(); 66 init_outputs(); 67 68 unlock_config(); 69 config_oc(); 70 config_uart(); 71 lock_config(); 72 73 init_dma(); 74 75 /* Initialise VGA output structures with two line channels and an initiating 76 channel. */ 77 78 init_vga(&display_config, 2, T2); 79 80 /* Peripheral relationships: 81 82 Timer2 -> OC1 83 -> OC2 (vertical sync region) 84 -> DMA1: zerodata -> PORTB (visible region) 85 | 86 Timer3 -> DMA0: linedata -> PORTB 87 Timer3 -> DMA2: linedata -> PORTB 88 | 89 Timer3 -> DMA3: zerodata -> PORTB 90 */ 91 92 /* Configure VGA output transfer details along with a timer and output 93 compare units for horizontal and vertical sync. */ 94 95 vga_configure_transfer(T3, PORTB); 96 vga_configure_sync(1, 2, 2); 97 98 /* Configure a timer for line data transfers. */ 99 100 timer_init(3, 0, 1); 101 timer_on(3); 102 103 uart_init(1, FPB, 115200); 104 uart_on(1); 105 106 test_linedata(&display_config); 107 108 interrupts_on(); 109 110 blink(3 << 24, PORTA, 1 << 3); 111 } 112 113 114 115 /* Exception and interrupt handlers. */ 116 117 void exception_handler(void) 118 { 119 blink(3 << 12, PORTA, 1 << 3); 120 } 121 122 void interrupt_handler(void) 123 { 124 uint32_t ifs; 125 126 /* Check for a OC1 interrupt condition. */ 127 128 ifs = REG(OCIFS) & OC_INT_FLAGS(1, OCxIF); 129 130 if (ifs) 131 { 132 vga_interrupt_handler(); 133 CLR_REG(OCIFS, ifs); 134 } 135 } 136 137 138 139 /* Peripheral pin configuration. */ 140 141 void config_oc(void) 142 { 143 /* Map OC1 to RPA0. */ 144 145 REG(RPA0R) = 0b0101; /* RPA0R<3:0> = 0101 (OC1) */ 146 147 /* Map OC2 to RPA1. */ 148 149 REG(RPA1R) = 0b0101; /* RPA1R<3:0> = 0101 (OC2) */ 150 } 151 152 void config_uart(void) 153 { 154 /* Map U1RX to RPB13. */ 155 156 REG(U1RXR) = 0b0011; /* U1RXR<3:0> = 0011 (RPB13) */ 157 158 /* Map U1TX to RPB15. */ 159 160 REG(RPB15R) = 0b0001; /* RPB15R<3:0> = 0001 (U1TX) */ 161 162 /* Set RPB13 to input. */ 163 164 SET_REG(TRISB, 1 << 13); 165 }