VGA 640x480 full graphic driver

Dependents:   vga640x480graphic gps_fastlib Chua-VGA Wolfram-1D-VGA ... more

Committer:
gertk
Date:
Wed Jul 27 19:43:07 2011 +0000
Revision:
0:821e34a87609
0.1

Who changed what in which revision?

UserRevisionLine numberNew contents of line
gertk 0:821e34a87609 1 /*
gertk 0:821e34a87609 2 * 640x480 60Hz full graphic VGA Driver
gertk 0:821e34a87609 3 *
gertk 0:821e34a87609 4 * Copyright (C) 2011 by Ivo van Poorten <ivop(at)euronet.nl>
gertk 0:821e34a87609 5 * and Gert van der Knokke <gertk(at)xs4all.nl>
gertk 0:821e34a87609 6 * This file is licensed under the terms of the GNU Lesser
gertk 0:821e34a87609 7 * General Public License, version 3.
gertk 0:821e34a87609 8 *
gertk 0:821e34a87609 9 * Inspired by Simon's (not Ford) Cookbook entry and Cliff Biffle's
gertk 0:821e34a87609 10 * assembly code.
gertk 0:821e34a87609 11 */
gertk 0:821e34a87609 12 #include "fastlib/common.h"
gertk 0:821e34a87609 13 #include "fastlib/pinsel.h"
gertk 0:821e34a87609 14 #include "fastlib/gpio.h"
gertk 0:821e34a87609 15 #include "fastlib/clock.h"
gertk 0:821e34a87609 16 #include "fastlib/power.h"
gertk 0:821e34a87609 17 #include "fastlib/pwm.h"
gertk 0:821e34a87609 18 #include "fastlib/i2s.h"
gertk 0:821e34a87609 19 #include "fastlib/uart.h"
gertk 0:821e34a87609 20 #include "fastlib/dma.h"
gertk 0:821e34a87609 21 #include "fastlib/nvic.h"
gertk 0:821e34a87609 22 #include "vga640x480g_functions.h"
gertk 0:821e34a87609 23
gertk 0:821e34a87609 24 // the default mode
gertk 0:821e34a87609 25 #define mode640x480
gertk 0:821e34a87609 26 #undef mode640x400
gertk 0:821e34a87609 27
gertk 0:821e34a87609 28 // 640 x 400 @ 70 Hz
gertk 0:821e34a87609 29 #ifdef mode640x400
gertk 0:821e34a87609 30 #define VTOTAL 445
gertk 0:821e34a87609 31 #define VISIBLE 400
gertk 0:821e34a87609 32 #define VSYNCSTART 401
gertk 0:821e34a87609 33 #define VSYNCEND 404
gertk 0:821e34a87609 34 #define VPOLARITY positive
gertk 0:821e34a87609 35 #endif
gertk 0:821e34a87609 36
gertk 0:821e34a87609 37 // 640 x 480 @ 60 Hz
gertk 0:821e34a87609 38 #ifdef mode640x480
gertk 0:821e34a87609 39 #define VTOTAL 525
gertk 0:821e34a87609 40 #define VISIBLE 480
gertk 0:821e34a87609 41 #define VSYNCSTART 490
gertk 0:821e34a87609 42 #define VSYNCEND 492
gertk 0:821e34a87609 43 #define VPOLARITY negative
gertk 0:821e34a87609 44 #endif
gertk 0:821e34a87609 45
gertk 0:821e34a87609 46 // -----------------------------------------------------------------------------------
gertk 0:821e34a87609 47
gertk 0:821e34a87609 48 // force the framebuffer in ABSHRAM0 and ABSHRAM1 (16k + 16k)
gertk 0:821e34a87609 49 // warning!! this disables the use of the USB, Ethernet and CAN bus functions!
gertk 0:821e34a87609 50 unsigned char *framebuffer = (unsigned char *)(0x2007C000);
gertk 0:821e34a87609 51
gertk 0:821e34a87609 52 // we need some extra space for 80 more lines
gertk 0:821e34a87609 53 #define EXTENSIONMAX 6400
gertk 0:821e34a87609 54 unsigned char framebufferextension[EXTENSIONMAX];
gertk 0:821e34a87609 55 unsigned char *framebuffer2 = framebufferextension;
gertk 0:821e34a87609 56
gertk 0:821e34a87609 57 // the framepointer
gertk 0:821e34a87609 58 volatile unsigned char *pointer=framebuffer;
gertk 0:821e34a87609 59
gertk 0:821e34a87609 60 // active line counter
gertk 0:821e34a87609 61 static unsigned line_counter;
gertk 0:821e34a87609 62
gertk 0:821e34a87609 63 // -----------------------------------------------------------------------------------
gertk 0:821e34a87609 64 // setup CPU PLL
gertk 0:821e34a87609 65 #define FEED0_AND_WAIT(x,y) fl_pll0_feed(); while(y fl_pll0_get_##x())
gertk 0:821e34a87609 66
gertk 0:821e34a87609 67 static void init_pll0(unsigned int clock_source, int N, int M, int cpu_divider) {
gertk 0:821e34a87609 68 fl_select_pll0_clock_source(clock_source);
gertk 0:821e34a87609 69
gertk 0:821e34a87609 70 fl_pll0_control(FL_ENABLE, FL_DISCONNECT);
gertk 0:821e34a87609 71 FEED0_AND_WAIT(connect,);
gertk 0:821e34a87609 72 fl_pll0_control(FL_DISABLE, FL_DISCONNECT);
gertk 0:821e34a87609 73 FEED0_AND_WAIT(enable,);
gertk 0:821e34a87609 74
gertk 0:821e34a87609 75 fl_pll0_config(N, M);
gertk 0:821e34a87609 76 fl_pll0_feed();
gertk 0:821e34a87609 77
gertk 0:821e34a87609 78 fl_pll0_control(FL_ENABLE, FL_DISCONNECT);
gertk 0:821e34a87609 79 FEED0_AND_WAIT(enable,!);
gertk 0:821e34a87609 80
gertk 0:821e34a87609 81 fl_set_cpu_clock_divider(cpu_divider);
gertk 0:821e34a87609 82 while (!fl_pll0_get_lock()) ;
gertk 0:821e34a87609 83
gertk 0:821e34a87609 84 fl_pll0_control(FL_ENABLE, FL_CONNECT);
gertk 0:821e34a87609 85 FEED0_AND_WAIT(connect,!);
gertk 0:821e34a87609 86 }
gertk 0:821e34a87609 87
gertk 0:821e34a87609 88 // -----------------------------------------------------------------------------------
gertk 0:821e34a87609 89 // setup UART0
gertk 0:821e34a87609 90 static void init_uart0(unsigned divaddval, unsigned mulval, unsigned divisor) {
gertk 0:821e34a87609 91 fl_power_uart0(FL_ON);
gertk 0:821e34a87609 92 fl_select_clock_uart0(FL_CLOCK_DIV1);
gertk 0:821e34a87609 93 fl_uart_set_fractional_divider(0, divaddval, mulval);
gertk 0:821e34a87609 94 fl_uart_set_divisor_latch(0, divisor);
gertk 0:821e34a87609 95 }
gertk 0:821e34a87609 96
gertk 0:821e34a87609 97 // -----------------------------------------------------------------------------------
gertk 0:821e34a87609 98 // setup VSYNC output on designated pin
gertk 0:821e34a87609 99 static void init_vsync(unsigned port, unsigned pin) {
gertk 0:821e34a87609 100 fl_power_gpio(FL_ON);
gertk 0:821e34a87609 101 fl_pinsel(port, pin, FL_FUNC_DEFAULT, FL_IGNORE, FL_IGNORE);
gertk 0:821e34a87609 102 fl_gpio_set_direction(port, 1<<pin, FL_OUTPUT);
gertk 0:821e34a87609 103 fl_gpio_clear_value (port, 1<<pin);
gertk 0:821e34a87609 104 }
gertk 0:821e34a87609 105
gertk 0:821e34a87609 106 // -----------------------------------------------------------------------------------
gertk 0:821e34a87609 107 // define structure for DMA linked lists
gertk 0:821e34a87609 108 struct dma_lli {
gertk 0:821e34a87609 109 void *source;
gertk 0:821e34a87609 110 void *dest;
gertk 0:821e34a87609 111 struct dma_lli *next;
gertk 0:821e34a87609 112 unsigned control_word;
gertk 0:821e34a87609 113 };
gertk 0:821e34a87609 114
gertk 0:821e34a87609 115 // some arbitrary blank data for I2S used for blanking
gertk 0:821e34a87609 116 // even after DMA the I2S output will keep on emitting zeroes (= blank)
gertk 0:821e34a87609 117 static unsigned char blanking[32]={0,0,0,0,0,0,0,0,
gertk 0:821e34a87609 118 0,0,0,0,0,0,0,0,
gertk 0:821e34a87609 119 0,0,0,0,0,0,0,0,
gertk 0:821e34a87609 120 0,0,0,0,0,0,0,0
gertk 0:821e34a87609 121 };
gertk 0:821e34a87609 122
gertk 0:821e34a87609 123 // preset our blanking DMA linked list
gertk 0:821e34a87609 124 extern const struct dma_lli blank_lli;
gertk 0:821e34a87609 125
gertk 0:821e34a87609 126 // blank linked lists ends the DMA cycle (lli=0)
gertk 0:821e34a87609 127 static const struct dma_lli blank_lli = {
gertk 0:821e34a87609 128 blanking, (void*)FL_I2STXFIFO, 0, 4
gertk 0:821e34a87609 129 | (1 << 12)
gertk 0:821e34a87609 130 | (1 << 15)
gertk 0:821e34a87609 131 | (2 << 18)
gertk 0:821e34a87609 132 | (2 << 21)
gertk 0:821e34a87609 133 | (0 << 26)
gertk 0:821e34a87609 134 | (0 << 27)
gertk 0:821e34a87609 135 | (0 << 31)
gertk 0:821e34a87609 136 };
gertk 0:821e34a87609 137
gertk 0:821e34a87609 138 // setup the DMA controller
gertk 0:821e34a87609 139 static void init_dma_controller(void) {
gertk 0:821e34a87609 140 fl_power_gpdma(FL_ON);
gertk 0:821e34a87609 141 fl_dma_enable(FL_ENABLE);
gertk 0:821e34a87609 142 while (!fl_dma_is_enabled()) ;
gertk 0:821e34a87609 143
gertk 0:821e34a87609 144 // do some initial DMA setup but no need to start the DMA
gertk 0:821e34a87609 145 fl_dma_set_srcaddr (0, framebuffer); // initial source pointer
gertk 0:821e34a87609 146 fl_dma_set_destaddr(0, (void*)FL_I2STXFIFO); // destination is I2S
gertk 0:821e34a87609 147 fl_dma_set_next_lli(0, &blank_lli); // link active list to blank list
gertk 0:821e34a87609 148
gertk 0:821e34a87609 149 fl_dma_channel_control(0, // control word
gertk 0:821e34a87609 150 20, // count (20*4 = 80)
gertk 0:821e34a87609 151 4, 4, // src and dest burst size
gertk 0:821e34a87609 152 32, 32, // src and dest width
gertk 0:821e34a87609 153 FL_SRC_INCREMENT,
gertk 0:821e34a87609 154 FL_NO_DEST_INCREMENT,
gertk 0:821e34a87609 155 FL_OFF // no interrupts
gertk 0:821e34a87609 156 );
gertk 0:821e34a87609 157
gertk 0:821e34a87609 158 }
gertk 0:821e34a87609 159
gertk 0:821e34a87609 160 // -----------------------------------------------------------------------------------
gertk 0:821e34a87609 161 // setup I2S for 25 MHz dot/pixel clock
gertk 0:821e34a87609 162 static void init_i2s(void) {
gertk 0:821e34a87609 163 // I2S on P0.9 (DIP5)
gertk 0:821e34a87609 164 fl_power_i2s(FL_ON);
gertk 0:821e34a87609 165 fl_select_clock_i2s(FL_CLOCK_DIV1); // assume 100MHz
gertk 0:821e34a87609 166 fl_pinsel(0, 7, FL_FUNC_ALT1, FL_IGNORE, FL_IGNORE); // I2STX_CLK
gertk 0:821e34a87609 167 fl_pinsel(0, 8, FL_FUNC_ALT1, FL_IGNORE, FL_IGNORE); // I2STX_WS
gertk 0:821e34a87609 168 fl_pinsel(0, 9, FL_FUNC_ALT1, FL_IGNORE, FL_IGNORE); // I2STX_SDA
gertk 0:821e34a87609 169 fl_i2s_set_tx_rate(1, 4);
gertk 0:821e34a87609 170 fl_i2s_output_set_config(FL_8BITS, FL_STEREO, 8, 0, 0, 0, 0);
gertk 0:821e34a87609 171
gertk 0:821e34a87609 172 }
gertk 0:821e34a87609 173
gertk 0:821e34a87609 174 // -----------------------------------------------------------------------------------
gertk 0:821e34a87609 175 // create HSYNC output with PWM
gertk 0:821e34a87609 176 static void init_hsync(void) {
gertk 0:821e34a87609 177 // PWM1.2 on P2.1 (DIP25)
gertk 0:821e34a87609 178 fl_power_pwm1(FL_ON);
gertk 0:821e34a87609 179 fl_select_clock_pwm1(FL_CLOCK_DIV1);
gertk 0:821e34a87609 180 fl_pinsel(2, 1, FL_FUNC_ALT1, FL_FLOATING, FL_FLOATING); // PWM1.2, no pullup/down
gertk 0:821e34a87609 181 fl_pwm_set_prescale(4); // 100/25 = 4
gertk 0:821e34a87609 182
gertk 0:821e34a87609 183 #define HSHIFT 0
gertk 0:821e34a87609 184
gertk 0:821e34a87609 185 // main PWM
gertk 0:821e34a87609 186 fl_pwm_set_match(0, 800); // 800 color clocks
gertk 0:821e34a87609 187
gertk 0:821e34a87609 188 // generate line interrupts from PWM MR0
gertk 0:821e34a87609 189 fl_pwm_config_match(0, FL_ON, FL_ON, FL_OFF); // interrupt, reset, !stop
gertk 0:821e34a87609 190
gertk 0:821e34a87609 191 // this PWM generates the HSYNC pulse
gertk 0:821e34a87609 192 fl_pwm_set_match(2, 16+HSHIFT); // go low at 16
gertk 0:821e34a87609 193 fl_pwm_set_match(1, 48+HSHIFT); // go high at 48
gertk 0:821e34a87609 194 fl_pwm_config_edges(2, FL_DOUBLE_EDGE); // need this for negative sync
gertk 0:821e34a87609 195 fl_pwm_output_enable(2, FL_ENABLE); // enable this output
gertk 0:821e34a87609 196
gertk 0:821e34a87609 197 }
gertk 0:821e34a87609 198
gertk 0:821e34a87609 199 // -----------------------------------------------------------------------------------
gertk 0:821e34a87609 200 // state machine list for the complete screen output
gertk 0:821e34a87609 201 static void state_before_vsync(void);
gertk 0:821e34a87609 202
gertk 0:821e34a87609 203 static void (*state)(void) = state_before_vsync;
gertk 0:821e34a87609 204
gertk 0:821e34a87609 205 // emit a line from the visible area (framebuffer)
gertk 0:821e34a87609 206 static void state_visible_area(void) {
gertk 0:821e34a87609 207 extern const struct dma_lli blank_lli;
gertk 0:821e34a87609 208
gertk 0:821e34a87609 209 // limit visible area to the size of the framebuffer
gertk 0:821e34a87609 210 if (line_counter != (VISIBLE+1)) {
gertk 0:821e34a87609 211 // reset DMA parameters for active line
gertk 0:821e34a87609 212 fl_dma_set_srcaddr (0,(unsigned char *)pointer); // source is our current framebuffer pointer
gertk 0:821e34a87609 213 fl_dma_set_destaddr(0, (void*)FL_I2STXFIFO); // destination is I2S
gertk 0:821e34a87609 214 fl_dma_set_next_lli(0, &blank_lli); // connect to blanking list
gertk 0:821e34a87609 215 fl_dma_channel_control(0, // control word
gertk 0:821e34a87609 216 20, // count (20*4 = 80 bytes active)
gertk 0:821e34a87609 217 4, 4, // src and dest burst size
gertk 0:821e34a87609 218 32, 32, // src and dest width
gertk 0:821e34a87609 219 FL_SRC_INCREMENT,
gertk 0:821e34a87609 220 FL_NO_DEST_INCREMENT,
gertk 0:821e34a87609 221 FL_OFF // no interrupt on first 640 pixel
gertk 0:821e34a87609 222 );
gertk 0:821e34a87609 223 // increment framebuffer pointer
gertk 0:821e34a87609 224 pointer+=80;
gertk 0:821e34a87609 225
gertk 0:821e34a87609 226 // restart DMA sequence
gertk 0:821e34a87609 227 fl_dma_channel_config(0, FL_ENABLE,
gertk 0:821e34a87609 228 FL_DMA_PERIPHERAL_IS_MEMORY, FL_DMA_BURST_REQUEST_I2S_CH0,
gertk 0:821e34a87609 229 FL_DMA_MEMORY_TO_PERIPHERAL,
gertk 0:821e34a87609 230 FL_ON, FL_ON
gertk 0:821e34a87609 231 );
gertk 0:821e34a87609 232
gertk 0:821e34a87609 233 if (line_counter==400) pointer=framebuffer2; // add 80 lines extra
gertk 0:821e34a87609 234 } else state = state_before_vsync;
gertk 0:821e34a87609 235 }
gertk 0:821e34a87609 236
gertk 0:821e34a87609 237
gertk 0:821e34a87609 238 static void state_after_vsync(void) { // VSYNC is over, now ait for end of frame
gertk 0:821e34a87609 239 if (line_counter != VTOTAL) return; // if not end of frame
gertk 0:821e34a87609 240 line_counter = 0; // reset line counter
gertk 0:821e34a87609 241 pointer=framebuffer; // and framebuffer
gertk 0:821e34a87609 242 state = state_visible_area; // we're in visible mode
gertk 0:821e34a87609 243 }
gertk 0:821e34a87609 244
gertk 0:821e34a87609 245 static void state_during_vsync(void) { // VSYNC is active
gertk 0:821e34a87609 246 if (line_counter != VSYNCEND) return; // if not end of vsync
gertk 0:821e34a87609 247 #if VPOLARITY==positive // check polarity
gertk 0:821e34a87609 248 fl_gpio_clear_value(0, 1<<6); // vsync low
gertk 0:821e34a87609 249 #else // or
gertk 0:821e34a87609 250 fl_gpio_set_value(0, 1<<6); // vsync high
gertk 0:821e34a87609 251 #endif
gertk 0:821e34a87609 252 state = state_after_vsync; // VSYNC is done
gertk 0:821e34a87609 253 }
gertk 0:821e34a87609 254
gertk 0:821e34a87609 255 static void state_before_vsync(void) { // wait for VSYNC start
gertk 0:821e34a87609 256 if (line_counter != VSYNCSTART) return; // if not
gertk 0:821e34a87609 257 #if VPOLARITY==positive // check polarity
gertk 0:821e34a87609 258 fl_gpio_set_value(0, 1<<6); // vsync high
gertk 0:821e34a87609 259 #else // or
gertk 0:821e34a87609 260 fl_gpio_clear_value(0, 1<<6); // vsync low
gertk 0:821e34a87609 261 #endif
gertk 0:821e34a87609 262 state = state_during_vsync; // VSYNC has started
gertk 0:821e34a87609 263 }
gertk 0:821e34a87609 264
gertk 0:821e34a87609 265 // inactive
gertk 0:821e34a87609 266 extern "C" void DMA_IRQHandler(void) __irq {
gertk 0:821e34a87609 267 fl_dma_clear_terminal_count_interrupt_request(0);
gertk 0:821e34a87609 268
gertk 0:821e34a87609 269 }
gertk 0:821e34a87609 270
gertk 0:821e34a87609 271 // active
gertk 0:821e34a87609 272 extern "C" void PWM1_IRQHandler(void) __irq {
gertk 0:821e34a87609 273 int regval=*FL_PWM1IR;
gertk 0:821e34a87609 274 // clear interrupt flag
gertk 0:821e34a87609 275 state();
gertk 0:821e34a87609 276 line_counter++;
gertk 0:821e34a87609 277 *FL_PWM1IR=regval;
gertk 0:821e34a87609 278 }
gertk 0:821e34a87609 279
gertk 0:821e34a87609 280
gertk 0:821e34a87609 281 // -----------------------------------------------------------------------------------
gertk 0:821e34a87609 282
gertk 0:821e34a87609 283 void init_vga(void) {
gertk 0:821e34a87609 284 fl_power_off_all_peripherals();
gertk 0:821e34a87609 285
gertk 0:821e34a87609 286 init_pll0(FL_PLL0_CLOCK_SOURCE_MAIN, 2, 25, 3); // 100MHz
gertk 0:821e34a87609 287 init_uart0(0, 0, 651); // 100MHz/651/16=9600.6 (default 8N1)
gertk 0:821e34a87609 288
gertk 0:821e34a87609 289 init_vsync(0, 6); // VSYNC on P0.6 (DIP8)
gertk 0:821e34a87609 290 init_i2s();
gertk 0:821e34a87609 291 init_hsync();
gertk 0:821e34a87609 292 init_dma_controller();
gertk 0:821e34a87609 293
gertk 0:821e34a87609 294 fl_pwm_timer_counter_enable(FL_ENABLE);
gertk 0:821e34a87609 295 fl_pwm_enable(FL_ENABLE);
gertk 0:821e34a87609 296 fl_i2s_config_dma1(FL_OFF, FL_ON, 0, 2);
gertk 0:821e34a87609 297 fl_nvic_interrupt_set_enable(FL_NVIC_INT_PWM); // start the PWM interrupts
gertk 0:821e34a87609 298 }