Three-pin 640x400 VGA Console Mode

Dependents:   projet_AWA_testVGA2

Committer:
Ivop
Date:
Fri Jul 08 17:22:08 2011 +0000
Revision:
1:30d7a3e8e7a3
Parent:
0:78fa88bb24cb
Child:
2:70daa29e01bd
Removed init of uart0 for debug messages out of \release\ build. This has nothing to do with VGA so it shouldn\t be in the library.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Ivop 0:78fa88bb24cb 1 /*
Ivop 0:78fa88bb24cb 2 * 640x400 70Hz VGA Driver
Ivop 0:78fa88bb24cb 3 *
Ivop 0:78fa88bb24cb 4 * Copyright (C) 2011 by Ivo van Poorten <ivop@euronet.nl>
Ivop 0:78fa88bb24cb 5 * This file is licensed under the terms of the GNU Lesser
Ivop 0:78fa88bb24cb 6 * General Public License, version 3.
Ivop 0:78fa88bb24cb 7 *
Ivop 0:78fa88bb24cb 8 * Inspired by Simon's (not Ford) Cookbook entry and Cliff Biffle's
Ivop 0:78fa88bb24cb 9 * assembly code.
Ivop 0:78fa88bb24cb 10 */
Ivop 0:78fa88bb24cb 11
Ivop 0:78fa88bb24cb 12 #include "fastlib/common.h"
Ivop 0:78fa88bb24cb 13 #include "fastlib/pinsel.h"
Ivop 0:78fa88bb24cb 14 #include "fastlib/gpio.h"
Ivop 0:78fa88bb24cb 15 #include "fastlib/clock.h"
Ivop 0:78fa88bb24cb 16 #include "fastlib/power.h"
Ivop 0:78fa88bb24cb 17 #include "fastlib/pwm.h"
Ivop 0:78fa88bb24cb 18 #include "fastlib/i2s.h"
Ivop 0:78fa88bb24cb 19 #include "fastlib/uart.h"
Ivop 0:78fa88bb24cb 20 #include "fastlib/dma.h"
Ivop 0:78fa88bb24cb 21 #include "fastlib/nvic.h"
Ivop 0:78fa88bb24cb 22
Ivop 0:78fa88bb24cb 23 //#include "mbed.h"
Ivop 0:78fa88bb24cb 24
Ivop 0:78fa88bb24cb 25 #include <string.h>
Ivop 0:78fa88bb24cb 26
Ivop 1:30d7a3e8e7a3 27 #define DEBUG_VGA 0
Ivop 1:30d7a3e8e7a3 28
Ivop 1:30d7a3e8e7a3 29 #if DEBUG_VGA // DEBUG messages on UART0
Ivop 0:78fa88bb24cb 30 #include <stdio.h>
Ivop 0:78fa88bb24cb 31 #define dbprintf(...) printf(__VA_ARGS__)
Ivop 0:78fa88bb24cb 32 #else
Ivop 0:78fa88bb24cb 33 #define dbprintf(...)
Ivop 0:78fa88bb24cb 34 #endif
Ivop 0:78fa88bb24cb 35
Ivop 0:78fa88bb24cb 36 // -----------------------------------------------------------------------------------
Ivop 0:78fa88bb24cb 37
Ivop 0:78fa88bb24cb 38 unsigned char text_buffer[80*25];
Ivop 0:78fa88bb24cb 39 unsigned char *font;
Ivop 0:78fa88bb24cb 40
Ivop 0:78fa88bb24cb 41 static unsigned line_counter;
Ivop 0:78fa88bb24cb 42 static unsigned char scanline0[100], scanline1[100]; // 100*8=800 color clocks
Ivop 0:78fa88bb24cb 43 static unsigned char *curline = scanline1+20;
Ivop 0:78fa88bb24cb 44
Ivop 0:78fa88bb24cb 45 #define NCHARS 256
Ivop 0:78fa88bb24cb 46
Ivop 0:78fa88bb24cb 47 struct dma_lli {
Ivop 0:78fa88bb24cb 48 const void *source;
Ivop 0:78fa88bb24cb 49 const void *dest;
Ivop 0:78fa88bb24cb 50 const struct dma_lli *next;
Ivop 0:78fa88bb24cb 51 unsigned control_word;
Ivop 0:78fa88bb24cb 52 };
Ivop 0:78fa88bb24cb 53
Ivop 0:78fa88bb24cb 54 extern const struct dma_lli dma_lli1;
Ivop 0:78fa88bb24cb 55
Ivop 0:78fa88bb24cb 56 static const struct dma_lli dma_lli0 = {
Ivop 0:78fa88bb24cb 57 scanline0, (void*)FL_I2STXFIFO, &dma_lli1, 0x84489019 // control word is explained below
Ivop 0:78fa88bb24cb 58 };
Ivop 0:78fa88bb24cb 59 static const struct dma_lli dma_lli1 = {
Ivop 0:78fa88bb24cb 60 scanline1, (void*)FL_I2STXFIFO, &dma_lli0, 0x84489019
Ivop 0:78fa88bb24cb 61 };
Ivop 0:78fa88bb24cb 62
Ivop 0:78fa88bb24cb 63 // -----------------------------------------------------------------------------------
Ivop 0:78fa88bb24cb 64
Ivop 0:78fa88bb24cb 65 #define FEED0_AND_WAIT(x,y) fl_pll0_feed(); while(y fl_pll0_get_##x())
Ivop 0:78fa88bb24cb 66
Ivop 0:78fa88bb24cb 67 static void init_pll0(unsigned int clock_source, int N, int M, int cpu_divider) {
Ivop 0:78fa88bb24cb 68 fl_select_pll0_clock_source(clock_source);
Ivop 0:78fa88bb24cb 69
Ivop 0:78fa88bb24cb 70 fl_pll0_control(FL_ENABLE, FL_DISCONNECT); FEED0_AND_WAIT(connect,);
Ivop 0:78fa88bb24cb 71 fl_pll0_control(FL_DISABLE, FL_DISCONNECT); FEED0_AND_WAIT(enable,);
Ivop 0:78fa88bb24cb 72
Ivop 0:78fa88bb24cb 73 fl_pll0_config(N, M);
Ivop 0:78fa88bb24cb 74 fl_pll0_feed();
Ivop 0:78fa88bb24cb 75
Ivop 0:78fa88bb24cb 76 fl_pll0_control(FL_ENABLE, FL_DISCONNECT); FEED0_AND_WAIT(enable,!);
Ivop 0:78fa88bb24cb 77
Ivop 0:78fa88bb24cb 78 fl_set_cpu_clock_divider(cpu_divider);
Ivop 0:78fa88bb24cb 79 while(!fl_pll0_get_lock()) ;
Ivop 0:78fa88bb24cb 80
Ivop 0:78fa88bb24cb 81 fl_pll0_control(FL_ENABLE, FL_CONNECT); FEED0_AND_WAIT(connect,!);
Ivop 0:78fa88bb24cb 82 }
Ivop 0:78fa88bb24cb 83
Ivop 0:78fa88bb24cb 84 // -----------------------------------------------------------------------------------
Ivop 0:78fa88bb24cb 85
Ivop 1:30d7a3e8e7a3 86 #if DEBUG_VGA
Ivop 0:78fa88bb24cb 87 static void init_uart0(unsigned divaddval, unsigned mulval, unsigned divisor) {
Ivop 0:78fa88bb24cb 88 fl_power_uart0(FL_ON);
Ivop 0:78fa88bb24cb 89 fl_select_clock_uart0(FL_CLOCK_DIV1);
Ivop 0:78fa88bb24cb 90 fl_uart_set_fractional_divider(0, divaddval, mulval);
Ivop 0:78fa88bb24cb 91 fl_uart_set_divisor_latch(0, divisor);
Ivop 0:78fa88bb24cb 92 }
Ivop 1:30d7a3e8e7a3 93 #endif
Ivop 0:78fa88bb24cb 94
Ivop 0:78fa88bb24cb 95 // -----------------------------------------------------------------------------------
Ivop 0:78fa88bb24cb 96
Ivop 0:78fa88bb24cb 97 static void init_vsync(unsigned port, unsigned pin) {
Ivop 0:78fa88bb24cb 98 fl_power_gpio(FL_ON);
Ivop 0:78fa88bb24cb 99 fl_pinsel(port, pin, FL_FUNC_DEFAULT, FL_IGNORE, FL_IGNORE);
Ivop 0:78fa88bb24cb 100 fl_gpio_set_direction(port, 1<<pin, FL_OUTPUT);
Ivop 0:78fa88bb24cb 101 fl_gpio_clear_value (port, 1<<pin);
Ivop 0:78fa88bb24cb 102 }
Ivop 0:78fa88bb24cb 103
Ivop 0:78fa88bb24cb 104 // -----------------------------------------------------------------------------------
Ivop 0:78fa88bb24cb 105
Ivop 0:78fa88bb24cb 106 static void init_dma_controller(void) {
Ivop 0:78fa88bb24cb 107 fl_power_gpdma(FL_ON);
Ivop 0:78fa88bb24cb 108 fl_dma_enable(FL_ENABLE);
Ivop 0:78fa88bb24cb 109 while (!fl_dma_is_enabled()) ;
Ivop 0:78fa88bb24cb 110
Ivop 0:78fa88bb24cb 111 fl_dma_set_srcaddr (0, dma_lli0.source);
Ivop 0:78fa88bb24cb 112 fl_dma_set_destaddr(0, dma_lli0.dest);
Ivop 0:78fa88bb24cb 113 fl_dma_set_next_lli(0, dma_lli0.next);
Ivop 0:78fa88bb24cb 114 fl_dma_channel_control(0, // control word
Ivop 0:78fa88bb24cb 115 25,
Ivop 0:78fa88bb24cb 116 4, 4, // src and dest burst size
Ivop 0:78fa88bb24cb 117 32, 32, // src and dest width
Ivop 0:78fa88bb24cb 118 FL_SRC_INCREMENT,
Ivop 0:78fa88bb24cb 119 FL_NO_DEST_INCREMENT,
Ivop 0:78fa88bb24cb 120 FL_ON // terminal count interrupt
Ivop 0:78fa88bb24cb 121 );
Ivop 0:78fa88bb24cb 122 // if ((fl_dma_channel_get_control_mask(0) | 25) != dma_lli0.control_word) {
Ivop 0:78fa88bb24cb 123 // dbprintf("%08x and %08x\r\n", fl_dma_channel_get_control_mask(0) | 25, dma_lli0.control_word);
Ivop 0:78fa88bb24cb 124 // dbprintf("control_word mismatch\r\n");
Ivop 0:78fa88bb24cb 125 // while(1);
Ivop 0:78fa88bb24cb 126 // }
Ivop 0:78fa88bb24cb 127
Ivop 0:78fa88bb24cb 128 fl_dma_channel_config(0, FL_ENABLE,
Ivop 0:78fa88bb24cb 129 FL_DMA_PERIPHERAL_IS_MEMORY, FL_DMA_BURST_REQUEST_I2S_CH0,
Ivop 0:78fa88bb24cb 130 FL_DMA_MEMORY_TO_PERIPHERAL,
Ivop 0:78fa88bb24cb 131 FL_ON, FL_ON
Ivop 0:78fa88bb24cb 132 );
Ivop 0:78fa88bb24cb 133
Ivop 0:78fa88bb24cb 134 fl_nvic_interrupt_set_enable(FL_NVIC_INT_DMA);
Ivop 0:78fa88bb24cb 135 }
Ivop 0:78fa88bb24cb 136
Ivop 0:78fa88bb24cb 137 // -----------------------------------------------------------------------------------
Ivop 0:78fa88bb24cb 138
Ivop 0:78fa88bb24cb 139 static void init_i2s(void) {
Ivop 0:78fa88bb24cb 140 // I2S on P0.9 (DIP5)
Ivop 0:78fa88bb24cb 141 fl_power_i2s(FL_ON);
Ivop 0:78fa88bb24cb 142 fl_select_clock_i2s(FL_CLOCK_DIV1); // assume 100MHz
Ivop 0:78fa88bb24cb 143 fl_pinsel(0, 7, FL_FUNC_ALT1, FL_IGNORE, FL_IGNORE); // I2STX_CLK
Ivop 0:78fa88bb24cb 144 fl_pinsel(0, 8, FL_FUNC_ALT1, FL_IGNORE, FL_IGNORE); // I2STX_WS
Ivop 0:78fa88bb24cb 145 fl_pinsel(0, 9, FL_FUNC_ALT1, FL_IGNORE, FL_IGNORE); // I2STX_SDA
Ivop 0:78fa88bb24cb 146 fl_i2s_set_tx_rate(1, 4);
Ivop 0:78fa88bb24cb 147 fl_i2s_output_set_config(FL_8BITS, FL_STEREO, 8, 0, 0, 0, 0);
Ivop 0:78fa88bb24cb 148 }
Ivop 0:78fa88bb24cb 149
Ivop 0:78fa88bb24cb 150 // -----------------------------------------------------------------------------------
Ivop 0:78fa88bb24cb 151
Ivop 0:78fa88bb24cb 152 static void init_hsync(void) {
Ivop 0:78fa88bb24cb 153 // PWM1.2 on P2.1 (DIP25)
Ivop 0:78fa88bb24cb 154 fl_power_pwm1(FL_ON);
Ivop 0:78fa88bb24cb 155 fl_select_clock_pwm1(FL_CLOCK_DIV1);
Ivop 0:78fa88bb24cb 156 fl_pinsel(2, 1, FL_FUNC_ALT1, FL_FLOATING, FL_FLOATING); // PWM1.2, no pullup/down
Ivop 0:78fa88bb24cb 157 fl_pwm_set_prescale(4); // 100/25 = 4
Ivop 0:78fa88bb24cb 158 fl_pwm_config_match(0, FL_ON, FL_ON, FL_OFF); // interrupt, reset, !stop
Ivop 0:78fa88bb24cb 159 fl_pwm_set_match(0, 800); // 800 color clocks
Ivop 0:78fa88bb24cb 160
Ivop 0:78fa88bb24cb 161 #define HSHIFT 48
Ivop 0:78fa88bb24cb 162
Ivop 0:78fa88bb24cb 163 fl_pwm_set_match(1, 97+HSHIFT); // go high at 97
Ivop 0:78fa88bb24cb 164 fl_pwm_set_match(2, 1+HSHIFT); // go low at 1
Ivop 0:78fa88bb24cb 165 fl_pwm_config_edges(2, FL_DOUBLE_EDGE);
Ivop 0:78fa88bb24cb 166 fl_pwm_output_enable(2, FL_ENABLE);
Ivop 0:78fa88bb24cb 167 }
Ivop 0:78fa88bb24cb 168
Ivop 0:78fa88bb24cb 169 // -----------------------------------------------------------------------------------
Ivop 0:78fa88bb24cb 170
Ivop 0:78fa88bb24cb 171 static void state_before_vsync(void);
Ivop 0:78fa88bb24cb 172
Ivop 0:78fa88bb24cb 173 static void (*state)(void) = state_before_vsync;
Ivop 0:78fa88bb24cb 174
Ivop 0:78fa88bb24cb 175 static void state_blank_area(void) {
Ivop 0:78fa88bb24cb 176 if (line_counter != 449) return;
Ivop 0:78fa88bb24cb 177
Ivop 0:78fa88bb24cb 178 line_counter = 0;
Ivop 0:78fa88bb24cb 179 state = state_before_vsync;
Ivop 0:78fa88bb24cb 180 }
Ivop 0:78fa88bb24cb 181
Ivop 0:78fa88bb24cb 182 static void state_clearing_buffers(void) {
Ivop 0:78fa88bb24cb 183 int i;
Ivop 0:78fa88bb24cb 184
Ivop 0:78fa88bb24cb 185 if (line_counter < 441) return;
Ivop 0:78fa88bb24cb 186
Ivop 0:78fa88bb24cb 187 for (i=0; i<20; i++) {
Ivop 0:78fa88bb24cb 188 *(curline+i ) = 0;
Ivop 0:78fa88bb24cb 189 *(curline+i+20) = 0;
Ivop 0:78fa88bb24cb 190 *(curline+i+40) = 0;
Ivop 0:78fa88bb24cb 191 *(curline+i+60) = 0;
Ivop 0:78fa88bb24cb 192 }
Ivop 0:78fa88bb24cb 193
Ivop 0:78fa88bb24cb 194 if (line_counter == 442) {
Ivop 0:78fa88bb24cb 195 state = state_blank_area;
Ivop 0:78fa88bb24cb 196 }
Ivop 0:78fa88bb24cb 197 }
Ivop 0:78fa88bb24cb 198
Ivop 0:78fa88bb24cb 199 static unsigned char *fp, *tb;
Ivop 0:78fa88bb24cb 200
Ivop 0:78fa88bb24cb 201 static void state_visible_area(void) {
Ivop 0:78fa88bb24cb 202 int x;
Ivop 0:78fa88bb24cb 203 unsigned char *sp = curline, *tbp = tb;
Ivop 0:78fa88bb24cb 204
Ivop 0:78fa88bb24cb 205 for (x=0; x<20; x++) {
Ivop 0:78fa88bb24cb 206 *sp++ = *(fp + *tbp++);
Ivop 0:78fa88bb24cb 207 *sp++ = *(fp + *tbp++);
Ivop 0:78fa88bb24cb 208 *sp++ = *(fp + *tbp++);
Ivop 0:78fa88bb24cb 209 *sp++ = *(fp + *tbp++);
Ivop 0:78fa88bb24cb 210 }
Ivop 0:78fa88bb24cb 211
Ivop 0:78fa88bb24cb 212 fp += NCHARS;
Ivop 0:78fa88bb24cb 213 if (fp == font+NCHARS*16) {
Ivop 0:78fa88bb24cb 214 fp = font;
Ivop 0:78fa88bb24cb 215 tb += 80;
Ivop 0:78fa88bb24cb 216 }
Ivop 0:78fa88bb24cb 217
Ivop 0:78fa88bb24cb 218 if (line_counter == 438) {
Ivop 0:78fa88bb24cb 219 state = state_clearing_buffers;
Ivop 0:78fa88bb24cb 220 }
Ivop 0:78fa88bb24cb 221 }
Ivop 0:78fa88bb24cb 222
Ivop 0:78fa88bb24cb 223 static void state_after_vsync(void) {
Ivop 0:78fa88bb24cb 224 if (line_counter != 38) return;
Ivop 0:78fa88bb24cb 225
Ivop 0:78fa88bb24cb 226 fp = font;
Ivop 0:78fa88bb24cb 227 tb = text_buffer;
Ivop 0:78fa88bb24cb 228 state = state_visible_area;
Ivop 0:78fa88bb24cb 229 }
Ivop 0:78fa88bb24cb 230
Ivop 0:78fa88bb24cb 231 static void state_during_vsync(void) {
Ivop 0:78fa88bb24cb 232 if (line_counter != 4) return;
Ivop 0:78fa88bb24cb 233
Ivop 0:78fa88bb24cb 234 fl_gpio_clear_value(0, 1<<6);
Ivop 0:78fa88bb24cb 235 state = state_after_vsync;
Ivop 0:78fa88bb24cb 236 }
Ivop 0:78fa88bb24cb 237
Ivop 0:78fa88bb24cb 238 static void state_before_vsync(void) {
Ivop 0:78fa88bb24cb 239 if (line_counter != 2) return;
Ivop 0:78fa88bb24cb 240
Ivop 0:78fa88bb24cb 241 fl_gpio_set_value(0, 1<<6);
Ivop 0:78fa88bb24cb 242 state = state_during_vsync;
Ivop 0:78fa88bb24cb 243 }
Ivop 0:78fa88bb24cb 244
Ivop 0:78fa88bb24cb 245 extern "C" void DMA_IRQHandler(void) __irq {
Ivop 0:78fa88bb24cb 246 fl_dma_clear_terminal_count_interrupt_request(0);
Ivop 0:78fa88bb24cb 247 line_counter++;
Ivop 0:78fa88bb24cb 248 curline = curline == scanline0+20 ? scanline1+20 : scanline0+20;
Ivop 0:78fa88bb24cb 249 state();
Ivop 0:78fa88bb24cb 250 }
Ivop 0:78fa88bb24cb 251
Ivop 0:78fa88bb24cb 252 // -----------------------------------------------------------------------------------
Ivop 0:78fa88bb24cb 253
Ivop 0:78fa88bb24cb 254 void init_vga(void) {
Ivop 0:78fa88bb24cb 255 fl_power_off_all_peripherals();
Ivop 0:78fa88bb24cb 256
Ivop 0:78fa88bb24cb 257 init_pll0(FL_PLL0_CLOCK_SOURCE_MAIN, 2, 25, 3); // 100MHz
Ivop 1:30d7a3e8e7a3 258
Ivop 1:30d7a3e8e7a3 259 #if DEBUG_VGA
Ivop 0:78fa88bb24cb 260 init_uart0(0, 0, 651); // 100MHz/651/16=9600.6 (default 8N1)
Ivop 1:30d7a3e8e7a3 261 #endif
Ivop 1:30d7a3e8e7a3 262
Ivop 0:78fa88bb24cb 263 init_vsync(0, 6); // VSYNC on P0.6 (DIP8)
Ivop 0:78fa88bb24cb 264 init_i2s();
Ivop 0:78fa88bb24cb 265 init_hsync();
Ivop 0:78fa88bb24cb 266 init_dma_controller();
Ivop 0:78fa88bb24cb 267
Ivop 0:78fa88bb24cb 268 fl_pwm_timer_counter_enable(FL_ENABLE);
Ivop 0:78fa88bb24cb 269 fl_pwm_enable(FL_ENABLE);
Ivop 0:78fa88bb24cb 270 fl_i2s_config_dma1(FL_OFF, FL_ON, 0, 2);
Ivop 0:78fa88bb24cb 271 }