Full graphic 640x400 monochrome VGA driver library

Dependents:   vga640x400graphic

Committer:
gertk
Date:
Sun Jul 24 11:53:05 2011 +0000
Revision:
0:ca7defdc9e44
version 0.1

Who changed what in which revision?

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