1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/lib/vga_display.c Wed Oct 24 00:50:48 2018 +0200
1.3 @@ -0,0 +1,150 @@
1.4 +/*
1.5 + * Generate a VGA signal using a PIC32 microcontroller.
1.6 + *
1.7 + * Copyright (C) 2017, 2018 Paul Boddie <paul@boddie.org.uk>
1.8 + *
1.9 + * This program is free software: you can redistribute it and/or modify
1.10 + * it under the terms of the GNU General Public License as published by
1.11 + * the Free Software Foundation, either version 3 of the License, or
1.12 + * (at your option) any later version.
1.13 + *
1.14 + * This program is distributed in the hope that it will be useful,
1.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.17 + * GNU General Public License for more details.
1.18 + *
1.19 + * You should have received a copy of the GNU General Public License
1.20 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
1.21 + */
1.22 +
1.23 +#include "pic32_c.h"
1.24 +#include "vga_display.h"
1.25 +
1.26 +
1.27 +
1.28 +/* Display state. */
1.29 +
1.30 +vga_display_t vga_display;
1.31 +
1.32 +
1.33 +
1.34 +/* Initialise the state machine. */
1.35 +
1.36 +void init_vga(display_config_t *display_config,
1.37 + void (*start_visible)(),
1.38 + void (*update_visible)(),
1.39 + void (*stop_visible)(),
1.40 + void (*vsync_high)(),
1.41 + void (*vsync_low)())
1.42 +{
1.43 + /* Display parameters. */
1.44 +
1.45 + vga_display.display_config = display_config;
1.46 +
1.47 + /* Display state handlers. */
1.48 +
1.49 + vga_display.start_visible = start_visible;
1.50 + vga_display.update_visible = update_visible;
1.51 + vga_display.stop_visible = stop_visible;
1.52 +
1.53 + /* Vertical sync operations. */
1.54 +
1.55 + vga_display.vsync_high = vsync_high;
1.56 + vga_display.vsync_low = vsync_low;
1.57 +
1.58 + /* Initial state. */
1.59 +
1.60 + vga_display.state_handler = vbp_active;
1.61 + vga_display.line = 0;
1.62 +}
1.63 +
1.64 +
1.65 +
1.66 +/* Interrupt handlers. */
1.67 +
1.68 +void vga_interrupt_handler(void)
1.69 +{
1.70 + vga_display.line += 1;
1.71 + vga_display.state_handler();
1.72 +}
1.73 +
1.74 +
1.75 +
1.76 +/* Vertical back porch region. */
1.77 +
1.78 +void vbp_active(void)
1.79 +{
1.80 + if (vga_display.line < vga_display.display_config->visible_start)
1.81 + return;
1.82 +
1.83 + /* Enter the visible region. */
1.84 +
1.85 + vga_display.state_handler = visible_active;
1.86 +
1.87 + /* Set the line address. */
1.88 +
1.89 + vga_display.linedata = vga_display.display_config->screen_start;
1.90 + vga_display.start_visible(&vga_display);
1.91 +}
1.92 +
1.93 +/* Visible region. */
1.94 +
1.95 +void visible_active(void)
1.96 +{
1.97 + if (vga_display.line < vga_display.display_config->vfp_start)
1.98 + {
1.99 + /* Update the line address and handle wraparound. */
1.100 +
1.101 + if (!(vga_display.line % vga_display.display_config->line_multiplier))
1.102 + {
1.103 + vga_display.linedata += vga_display.display_config->line_length;
1.104 +
1.105 + if (vga_display.linedata >= vga_display.display_config->screen_limit)
1.106 + vga_display.linedata -= vga_display.display_config->screen_size;
1.107 + }
1.108 +
1.109 + vga_display.update_visible(&vga_display);
1.110 + return;
1.111 + }
1.112 +
1.113 + /* End the visible region. */
1.114 +
1.115 + vga_display.state_handler = vfp_active;
1.116 +
1.117 + /* Disable the channel for the next line. */
1.118 +
1.119 + vga_display.stop_visible(&vga_display);
1.120 +}
1.121 +
1.122 +/* Vertical front porch region. */
1.123 +
1.124 +void vfp_active(void)
1.125 +{
1.126 + if (vga_display.line < vga_display.display_config->vsync_start)
1.127 + return;
1.128 +
1.129 + /* Enter the vertical sync region. */
1.130 +
1.131 + vga_display.state_handler = vsync_active;
1.132 +
1.133 + /* Bring vsync low when the next line starts. */
1.134 +
1.135 + vga_display.vsync_low();
1.136 +}
1.137 +
1.138 +/* Vertical sync region. */
1.139 +
1.140 +void vsync_active(void)
1.141 +{
1.142 + if (vga_display.line < vga_display.display_config->vsync_end)
1.143 + return;
1.144 +
1.145 + /* Start again at the top of the display. */
1.146 +
1.147 + vga_display.line = 0;
1.148 + vga_display.state_handler = vbp_active;
1.149 +
1.150 + /* Bring vsync high when the next line starts. */
1.151 +
1.152 + vga_display.vsync_high();
1.153 +}