1.1 --- a/lib/vga_display.c Thu Oct 25 21:11:22 2018 +0200
1.2 +++ b/lib/vga_display.c Thu Oct 25 21:19:01 2018 +0200
1.3 @@ -37,30 +37,78 @@
1.4 /* Initialise the state machine. */
1.5
1.6 void init_vga(display_config_t *display_config, int line_channels,
1.7 - int initiating_int_num)
1.8 + int line_timer, int transfer_int_num)
1.9 {
1.10 /* Display parameters. */
1.11
1.12 vga_display.display_config = display_config;
1.13 vga_display.line_channels = line_channels;
1.14 - vga_display.initiating_int_num = initiating_int_num;
1.15
1.16 /* Initial state. */
1.17
1.18 vga_display.state_handler = vbp_active;
1.19 vga_display.line = 0;
1.20 +
1.21 + /* Configure a general display timer to start line data transfer and for the
1.22 + horizontal sync. */
1.23 +
1.24 + vga_display.line_timer = line_timer;
1.25 +
1.26 + /* Configure a separate transfer interrupt condition, if indicated.
1.27 + Otherwise, transfers are initiated by the line timer. */
1.28 +
1.29 + vga_display.transfer_int_num = transfer_int_num;
1.30 +}
1.31 +
1.32 +/* Initialise a separate transfer timer if different from the general display
1.33 + timer. */
1.34 +
1.35 +void init_vga_with_timers(display_config_t *display_config, int line_channels,
1.36 + int line_timer, int transfer_timer)
1.37 +{
1.38 + /* Initialise the basic properties of the display. */
1.39 +
1.40 + init_vga(display_config, line_channels, line_timer,
1.41 + transfer_timer ? timer_interrupt_number(transfer_timer) : -1);
1.42 +
1.43 + /* Configure a line timer for horizontal sync and line data transfers. */
1.44 +
1.45 + /* The timers have no prescaling (0). */
1.46 +
1.47 + timer_init(line_timer, 0, display_config->hfreq_limit);
1.48 + timer_on(line_timer);
1.49 +
1.50 + /* Configure a separate transfer timer, if indicated. */
1.51 +
1.52 + if (!transfer_timer || (transfer_timer == line_timer))
1.53 + return;
1.54 +
1.55 + /* The timer wraps around immediately. */
1.56 +
1.57 + timer_init(transfer_timer, 0, 1);
1.58 + timer_on(transfer_timer);
1.59 }
1.60
1.61
1.62
1.63 /* Configure DMA channels for the transfer of pixel data. */
1.64
1.65 -void vga_configure_transfer(int transfer_int_num, uint32_t output)
1.66 +void vga_configure_transfer(uint32_t output)
1.67 {
1.68 - int initiating_channel = vga_display.initiating_int_num >= 0;
1.69 int dual_channel = vga_display.line_channels == 2;
1.70 int channel = 0;
1.71
1.72 + /* Determine whether an initiating channel is used. */
1.73 +
1.74 + int initiating_channel = vga_display.transfer_int_num >= 0;
1.75 +
1.76 + /* Determine the different interrupt conditions, with pixel data employing
1.77 + any specified transfer condition or the line condition otherwise. */
1.78 +
1.79 + int line_int_num = timer_interrupt_number(vga_display.line_timer);
1.80 + int transfer_int_num = initiating_channel ?
1.81 + vga_display.transfer_int_num : line_int_num;
1.82 +
1.83 /* Where dual line channels are involved, put the first before any
1.84 initiating channel, chaining it to such a channel. */
1.85
1.86 @@ -71,13 +119,12 @@
1.87 output);
1.88 }
1.89
1.90 - /* Introduce a special initiating channel if an interrupt has been
1.91 - indicated. */
1.92 + /* Introduce a special initiating channel if a separate transfer interrupt
1.93 + has been indicated. */
1.94
1.95 if (initiating_channel)
1.96 {
1.97 - vga_configure_zero_channel(channel++, vga_display.initiating_int_num, 1,
1.98 - output);
1.99 + vga_configure_zero_channel(channel++, line_int_num, 1, output);
1.100 }
1.101
1.102 /* A line channel is always configured, chaining it to any initiating
1.103 @@ -146,30 +193,22 @@
1.104 ZERO_LENGTH);
1.105 }
1.106
1.107 -/* Configure a timer and output compare units for horizontal and vertical
1.108 - sync. */
1.109 +/* Configure output compare units for horizontal and vertical sync. */
1.110
1.111 -void vga_configure_sync(int hsync_unit, int vsync_unit, int timer)
1.112 +void vga_configure_sync(int hsync_unit, int vsync_unit)
1.113 {
1.114 /* Record the peripherals in use. */
1.115
1.116 vga_display.hsync_unit = hsync_unit;
1.117 vga_display.vsync_unit = vsync_unit;
1.118 - vga_display.timer = timer;
1.119
1.120 - /* Configure a timer for the horizontal sync. The timer has no prescaling
1.121 - (0). */
1.122 -
1.123 - timer_init(timer, 0, vga_display.display_config->hfreq_limit);
1.124 - timer_on(timer);
1.125 -
1.126 /* Horizontal sync. */
1.127
1.128 /* Configure output compare in dual compare (continuous output) mode using
1.129 the timer as time base. The interrupt condition drives the first DMA
1.130 channel and is handled to drive the display state machine. */
1.131
1.132 - oc_init(hsync_unit, 0b101, timer);
1.133 + oc_init(hsync_unit, 0b101, vga_display.line_timer);
1.134 oc_set_pulse(hsync_unit, vga_display.display_config->hsync_end);
1.135 oc_set_pulse_end(hsync_unit, vga_display.display_config->hsync_start);
1.136 oc_init_interrupt(hsync_unit, 7, 3);
1.137 @@ -181,7 +220,7 @@
1.138 the timer as time base. The unit is enabled later. It is only really used
1.139 to achieve precisely-timed level transitions in hardware. */
1.140
1.141 - oc_init(vsync_unit, 0b010, timer);
1.142 + oc_init(vsync_unit, 0b010, vga_display.line_timer);
1.143 oc_set_pulse(vsync_unit, 0);
1.144 }
1.145
1.146 @@ -296,7 +335,7 @@
1.147
1.148 /* Determine whether an initiating channel is used. */
1.149
1.150 - int initiating_channel = vga_display.initiating_int_num >= 0;
1.151 + int initiating_channel = vga_display.transfer_int_num >= 0;
1.152 int channel = 0;
1.153
1.154 /* Update the source of a secondary line channel. */
1.155 @@ -330,9 +369,12 @@
1.156
1.157 void update_transfers(int enable)
1.158 {
1.159 - int initiating_channel = vga_display.initiating_int_num >= 0;
1.160 + void (*fn)() = enable ? dma_on : dma_off;
1.161 +
1.162 + /* Determine whether an initiating channel is used. */
1.163 +
1.164 + int initiating_channel = vga_display.transfer_int_num >= 0;
1.165 int channel = 0;
1.166 - void (*fn)() = enable ? dma_on : dma_off;
1.167
1.168 /* Update line channels if no initiating channel is used. */
1.169
1.170 @@ -364,7 +406,7 @@
1.171
1.172 void vsync_low(void)
1.173 {
1.174 - oc_init(vga_display.vsync_unit, 0b010, vga_display.timer);
1.175 + oc_init(vga_display.vsync_unit, 0b010, vga_display.line_timer);
1.176 oc_on(vga_display.vsync_unit);
1.177 }
1.178
1.179 @@ -373,6 +415,6 @@
1.180
1.181 void vsync_high(void)
1.182 {
1.183 - oc_init(vga_display.vsync_unit, 0b001, vga_display.timer);
1.184 + oc_init(vga_display.vsync_unit, 0b001, vga_display.line_timer);
1.185 oc_on(vga_display.vsync_unit);
1.186 }