Three-pin 640x400 VGA Console Mode
Dependents: projet_AWA_testVGA2
vga640x400.c
00001 /* 00002 * 640x400 70Hz VGA Driver 00003 * 00004 * Copyright (C) 2011 by Ivo van Poorten <ivop@euronet.nl> 00005 * This file is licensed under the terms of the GNU Lesser 00006 * General Public License, version 3. 00007 * 00008 * Inspired by Simon's (not Ford) Cookbook entry and Cliff Biffle's 00009 * assembly code. 00010 */ 00011 00012 #include "fastlib/common.h" 00013 #include "fastlib/pinsel.h" 00014 #include "fastlib/gpio.h" 00015 #include "fastlib/clock.h" 00016 #include "fastlib/power.h" 00017 #include "fastlib/pwm.h" 00018 #include "fastlib/i2s.h" 00019 #include "fastlib/uart.h" 00020 #include "fastlib/dma.h" 00021 #include "fastlib/nvic.h" 00022 00023 //#include "mbed.h" 00024 00025 #include <string.h> 00026 00027 #define DEBUG_VGA 0 00028 00029 #if DEBUG_VGA // DEBUG messages on UART0 00030 #include <stdio.h> 00031 #define dbprintf(...) printf(__VA_ARGS__) 00032 #else 00033 #define dbprintf(...) 00034 #endif 00035 00036 // ----------------------------------------------------------------------------------- 00037 00038 unsigned char text_buffer[80*25]; 00039 unsigned char *font; 00040 00041 static unsigned line_counter; 00042 static unsigned char scanline0[100], scanline1[100]; // 100*8=800 color clocks 00043 static unsigned char *curline = scanline1+20; 00044 00045 #define NCHARS 256 00046 00047 struct dma_lli { 00048 const void *source; 00049 const void *dest; 00050 const struct dma_lli *next; 00051 unsigned control_word; 00052 }; 00053 00054 extern const struct dma_lli dma_lli1; 00055 00056 static const struct dma_lli dma_lli0 = { 00057 scanline0, (void*)FL_I2STXFIFO, &dma_lli1, 0x84489019 // control word is explained below 00058 }; 00059 static const struct dma_lli dma_lli1 = { 00060 scanline1, (void*)FL_I2STXFIFO, &dma_lli0, 0x84489019 00061 }; 00062 00063 // ----------------------------------------------------------------------------------- 00064 00065 #define FEED0_AND_WAIT(x,y) fl_pll0_feed(); while(y fl_pll0_get_##x()) 00066 00067 static void init_pll0(unsigned int clock_source, int N, int M, int cpu_divider) { 00068 fl_select_pll0_clock_source(clock_source); 00069 00070 fl_pll0_control(FL_ENABLE, FL_DISCONNECT); FEED0_AND_WAIT(connect,); 00071 fl_pll0_control(FL_DISABLE, FL_DISCONNECT); FEED0_AND_WAIT(enable,); 00072 00073 fl_pll0_config(N, M); 00074 fl_pll0_feed(); 00075 00076 fl_pll0_control(FL_ENABLE, FL_DISCONNECT); FEED0_AND_WAIT(enable,!); 00077 00078 fl_set_cpu_clock_divider(cpu_divider); 00079 while(!fl_pll0_get_lock()) ; 00080 00081 fl_pll0_control(FL_ENABLE, FL_CONNECT); FEED0_AND_WAIT(connect,!); 00082 } 00083 00084 // ----------------------------------------------------------------------------------- 00085 00086 #if DEBUG_VGA 00087 static void init_uart0(unsigned divaddval, unsigned mulval, unsigned divisor) { 00088 fl_power_uart0(FL_ON); 00089 fl_select_clock_uart0(FL_CLOCK_DIV1); 00090 fl_uart_set_fractional_divider(0, divaddval, mulval); 00091 fl_uart_set_divisor_latch(0, divisor); 00092 } 00093 #endif 00094 00095 // ----------------------------------------------------------------------------------- 00096 00097 static void init_vsync(unsigned port, unsigned pin) { 00098 fl_power_gpio(FL_ON); 00099 fl_pinsel(port, pin, FL_FUNC_DEFAULT, FL_IGNORE, FL_IGNORE); 00100 fl_gpio_set_direction(port, 1<<pin, FL_OUTPUT); 00101 fl_gpio_clear_value (port, 1<<pin); 00102 } 00103 00104 // ----------------------------------------------------------------------------------- 00105 00106 static void init_dma_controller(void) { 00107 fl_power_gpdma(FL_ON); 00108 fl_dma_enable(FL_ENABLE); 00109 while (!fl_dma_is_enabled()) ; 00110 00111 fl_dma_set_srcaddr (0, dma_lli0.source); 00112 fl_dma_set_destaddr(0, dma_lli0.dest); 00113 fl_dma_set_next_lli(0, dma_lli0.next); 00114 fl_dma_channel_control(0, // control word 00115 25, 00116 4, 4, // src and dest burst size 00117 32, 32, // src and dest width 00118 FL_SRC_INCREMENT, 00119 FL_NO_DEST_INCREMENT, 00120 FL_ON // terminal count interrupt 00121 ); 00122 // if ((fl_dma_channel_get_control_mask(0) | 25) != dma_lli0.control_word) { 00123 // dbprintf("%08x and %08x\r\n", fl_dma_channel_get_control_mask(0) | 25, dma_lli0.control_word); 00124 // dbprintf("control_word mismatch\r\n"); 00125 // while(1); 00126 // } 00127 00128 fl_dma_channel_config(0, FL_ENABLE, 00129 FL_DMA_PERIPHERAL_IS_MEMORY, FL_DMA_BURST_REQUEST_I2S_CH0, 00130 FL_DMA_MEMORY_TO_PERIPHERAL, 00131 FL_ON, FL_ON 00132 ); 00133 00134 fl_nvic_interrupt_set_enable(FL_NVIC_INT_DMA); 00135 } 00136 00137 // ----------------------------------------------------------------------------------- 00138 00139 static void init_i2s(void) { 00140 // I2S on P0.9 (DIP5) 00141 fl_power_i2s(FL_ON); 00142 fl_select_clock_i2s(FL_CLOCK_DIV1); // assume 100MHz 00143 // fl_pinsel(0, 7, FL_FUNC_ALT1, FL_IGNORE, FL_IGNORE); // I2STX_CLK 00144 // fl_pinsel(0, 8, FL_FUNC_ALT1, FL_IGNORE, FL_IGNORE); // I2STX_WS 00145 fl_pinsel(0, 9, FL_FUNC_ALT1, FL_IGNORE, FL_IGNORE); // I2STX_SDA 00146 fl_i2s_set_tx_rate(1, 4); 00147 fl_i2s_output_set_config(FL_8BITS, FL_STEREO, 8, 0, 0, 0, 0); 00148 } 00149 00150 // ----------------------------------------------------------------------------------- 00151 00152 static void init_hsync(void) { 00153 // PWM1.2 on P2.1 (DIP25) 00154 fl_power_pwm1(FL_ON); 00155 fl_select_clock_pwm1(FL_CLOCK_DIV1); 00156 fl_pinsel(2, 1, FL_FUNC_ALT1, FL_FLOATING, FL_FLOATING); // PWM1.2, no pullup/down 00157 fl_pwm_set_prescale(4); // 100/25 = 4 00158 fl_pwm_config_match(0, FL_ON, FL_ON, FL_OFF); // interrupt, reset, !stop 00159 fl_pwm_set_match(0, 800); // 800 color clocks 00160 00161 #define HSHIFT 48 00162 00163 fl_pwm_set_match(1, 97+HSHIFT); // go high at 97 00164 fl_pwm_set_match(2, 1+HSHIFT); // go low at 1 00165 fl_pwm_config_edges(2, FL_DOUBLE_EDGE); 00166 fl_pwm_output_enable(2, FL_ENABLE); 00167 } 00168 00169 // ----------------------------------------------------------------------------------- 00170 00171 static void state_before_vsync(void); 00172 00173 static void (*state)(void) = state_before_vsync; 00174 00175 static void state_blank_area(void) { 00176 if (line_counter != 449) return; 00177 00178 line_counter = 0; 00179 state = state_before_vsync; 00180 } 00181 00182 static void state_clearing_buffers(void) { 00183 int i; 00184 00185 if (line_counter < 441) return; 00186 00187 for (i=0; i<20; i++) { 00188 *(curline+i ) = 0; 00189 *(curline+i+20) = 0; 00190 *(curline+i+40) = 0; 00191 *(curline+i+60) = 0; 00192 } 00193 00194 if (line_counter == 442) { 00195 state = state_blank_area; 00196 } 00197 } 00198 00199 static unsigned char *fp, *tb; 00200 00201 static void state_visible_area(void) { 00202 int x; 00203 unsigned char *sp = curline, *tbp = tb; 00204 00205 for (x=0; x<20; x++) { 00206 *sp++ = *(fp + *tbp++); 00207 *sp++ = *(fp + *tbp++); 00208 *sp++ = *(fp + *tbp++); 00209 *sp++ = *(fp + *tbp++); 00210 } 00211 00212 fp += NCHARS; 00213 if (fp == font+NCHARS*16) { 00214 fp = font; 00215 tb += 80; 00216 } 00217 00218 if (line_counter == 438) { 00219 state = state_clearing_buffers; 00220 } 00221 } 00222 00223 static void state_after_vsync(void) { 00224 if (line_counter != 38) return; 00225 00226 fp = font; 00227 tb = text_buffer; 00228 state = state_visible_area; 00229 } 00230 00231 static void state_during_vsync(void) { 00232 if (line_counter != 4) return; 00233 00234 fl_gpio_clear_value(0, 1<<6); 00235 state = state_after_vsync; 00236 } 00237 00238 static void state_before_vsync(void) { 00239 if (line_counter != 2) return; 00240 00241 fl_gpio_set_value(0, 1<<6); 00242 state = state_during_vsync; 00243 } 00244 00245 extern "C" void DMA_IRQHandler(void) __irq { 00246 fl_dma_clear_terminal_count_interrupt_request(0); 00247 line_counter++; 00248 curline = curline == scanline0+20 ? scanline1+20 : scanline0+20; 00249 state(); 00250 } 00251 00252 // ----------------------------------------------------------------------------------- 00253 00254 void init_vga(void) { 00255 fl_power_off_all_peripherals(); 00256 00257 init_pll0(FL_PLL0_CLOCK_SOURCE_MAIN, 2, 25, 3); // 100MHz 00258 00259 #if DEBUG_VGA 00260 init_uart0(0, 0, 651); // 100MHz/651/16=9600.6 (default 8N1) 00261 #endif 00262 00263 init_vsync(0, 6); // VSYNC on P0.6 (DIP8) 00264 init_i2s(); 00265 init_hsync(); 00266 init_dma_controller(); 00267 00268 fl_pwm_timer_counter_enable(FL_ENABLE); 00269 fl_pwm_enable(FL_ENABLE); 00270 fl_i2s_config_dma1(FL_OFF, FL_ON, 0, 2); 00271 }
Generated on Sat Jul 16 2022 04:25:35 by 1.7.2