Three-pin 640x400 VGA Console Mode

Dependents:   projet_AWA_testVGA2

Committer:
Ivop
Date:
Sun Jul 03 18:13:20 2011 +0000
Revision:
0:78fa88bb24cb
Child:
1:30d7a3e8e7a3

        

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