This is a version of vga640x480g customized to work well with MbedConsole
Fork of vga640x480g by
vga640x480g.cpp
00001 /* 00002 * 640x480 60Hz full graphic VGA Driver 00003 * 00004 * Copyright (C) 2011 by Ivo van Poorten <ivop(at)euronet.nl> 00005 * and Gert van der Knokke <gertk(at)xs4all.nl> 00006 * This file is licensed under the terms of the GNU Lesser 00007 * General Public License, version 3. 00008 * 00009 * Inspired by Simon's (not Ford) Cookbook entry and Cliff Biffle's 00010 * assembly code. 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 #include "vga640x480g_functions.h" 00023 00024 // the default mode 00025 #define mode640x480 00026 #undef mode640x400 00027 00028 // 640 x 400 @ 70 Hz 00029 #ifdef mode640x400 00030 #define VTOTAL 445 00031 #define VISIBLE 400 00032 #define VSYNCSTART 401 00033 #define VSYNCEND 404 00034 #define VPOLARITY positive 00035 #endif 00036 00037 // 640 x 480 @ 60 Hz 00038 #ifdef mode640x480 00039 #define VTOTAL 525 00040 #define VISIBLE 480 00041 #define VSYNCSTART 490 00042 #define VSYNCEND 492 00043 #define VPOLARITY negative 00044 #endif 00045 00046 // ----------------------------------------------------------------------------------- 00047 00048 // force the framebuffer in ABSHRAM0 and ABSHRAM1 (16k + 16k) 00049 // warning!! this disables the use of the USB, Ethernet and CAN bus functions! 00050 unsigned char *framebuffer = (unsigned char *)(0x2007C000); 00051 00052 // we need some extra space for 80 more lines 00053 #define EXTENSIONMAX 6400 00054 unsigned char framebufferextension[EXTENSIONMAX]; 00055 unsigned char *framebuffer2 = framebufferextension; 00056 00057 // the framepointer 00058 volatile unsigned char *pointer=framebuffer; 00059 00060 // active line counter 00061 static unsigned line_counter; 00062 00063 // ----------------------------------------------------------------------------------- 00064 // setup CPU PLL 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); 00071 FEED0_AND_WAIT(connect,); 00072 fl_pll0_control(FL_DISABLE, FL_DISCONNECT); 00073 FEED0_AND_WAIT(enable,); 00074 00075 fl_pll0_config(N, M); 00076 fl_pll0_feed(); 00077 00078 fl_pll0_control(FL_ENABLE, FL_DISCONNECT); 00079 FEED0_AND_WAIT(enable,!); 00080 00081 fl_set_cpu_clock_divider(cpu_divider); 00082 while (!fl_pll0_get_lock()) ; 00083 00084 fl_pll0_control(FL_ENABLE, FL_CONNECT); 00085 FEED0_AND_WAIT(connect,!); 00086 } 00087 00088 // ----------------------------------------------------------------------------------- 00089 // setup UART0 00090 static void init_uart0(unsigned divaddval, unsigned mulval, unsigned divisor) { 00091 fl_power_uart0(FL_ON); 00092 fl_select_clock_uart0(FL_CLOCK_DIV1); 00093 fl_uart_set_fractional_divider(0, divaddval, mulval); 00094 fl_uart_set_divisor_latch(0, divisor); 00095 } 00096 00097 // ----------------------------------------------------------------------------------- 00098 // setup VSYNC output on designated pin 00099 static void init_vsync(unsigned port, unsigned pin) { 00100 fl_power_gpio(FL_ON); 00101 fl_pinsel(port, pin, FL_FUNC_DEFAULT, FL_IGNORE, FL_IGNORE); 00102 fl_gpio_set_direction(port, 1<<pin, FL_OUTPUT); 00103 fl_gpio_clear_value (port, 1<<pin); 00104 } 00105 00106 // ----------------------------------------------------------------------------------- 00107 // define structure for DMA linked lists 00108 struct dma_lli { 00109 void *source; 00110 void *dest; 00111 struct dma_lli *next; 00112 unsigned control_word; 00113 }; 00114 00115 // some arbitrary blank data for I2S used for blanking 00116 // even after DMA the I2S output will keep on emitting zeroes (= blank) 00117 static unsigned char blanking[32]={0,0,0,0,0,0,0,0, 00118 0,0,0,0,0,0,0,0, 00119 0,0,0,0,0,0,0,0, 00120 0,0,0,0,0,0,0,0 00121 }; 00122 00123 // preset our blanking DMA linked list 00124 extern const struct dma_lli blank_lli; 00125 00126 // blank linked lists ends the DMA cycle (lli=0) 00127 static const struct dma_lli blank_lli = { 00128 blanking, (void*)FL_I2STXFIFO, 0, 4 00129 | (1 << 12) 00130 | (1 << 15) 00131 | (2 << 18) 00132 | (2 << 21) 00133 | (0 << 26) 00134 | (0 << 27) 00135 | (0 << 31) 00136 }; 00137 00138 // setup the DMA controller 00139 static void init_dma_controller(void) { 00140 fl_power_gpdma(FL_ON); 00141 fl_dma_enable(FL_ENABLE); 00142 while (!fl_dma_is_enabled()) ; 00143 00144 // do some initial DMA setup but no need to start the DMA 00145 fl_dma_set_srcaddr (0, framebuffer); // initial source pointer 00146 fl_dma_set_destaddr(0, (void*)FL_I2STXFIFO); // destination is I2S 00147 fl_dma_set_next_lli(0, &blank_lli); // link active list to blank list 00148 00149 fl_dma_channel_control(0, // control word 00150 20, // count (20*4 = 80) 00151 4, 4, // src and dest burst size 00152 32, 32, // src and dest width 00153 FL_SRC_INCREMENT, 00154 FL_NO_DEST_INCREMENT, 00155 FL_OFF // no interrupts 00156 ); 00157 00158 } 00159 00160 // ----------------------------------------------------------------------------------- 00161 // setup I2S for 25 MHz dot/pixel clock 00162 static void init_i2s(void) { 00163 // I2S on P0.9 (DIP5) 00164 fl_power_i2s(FL_ON); 00165 fl_select_clock_i2s(FL_CLOCK_DIV1); // assume 100MHz 00166 fl_pinsel(0, 7, FL_FUNC_ALT1, FL_IGNORE, FL_IGNORE); // I2STX_CLK 00167 fl_pinsel(0, 8, FL_FUNC_ALT1, FL_IGNORE, FL_IGNORE); // I2STX_WS 00168 fl_pinsel(0, 9, FL_FUNC_ALT1, FL_IGNORE, FL_IGNORE); // I2STX_SDA 00169 fl_i2s_set_tx_rate(1, 4); 00170 fl_i2s_output_set_config(FL_8BITS, FL_STEREO, 8, 0, 0, 0, 0); 00171 00172 } 00173 00174 // ----------------------------------------------------------------------------------- 00175 // create HSYNC output with PWM 00176 static void init_hsync(void) { 00177 // PWM1.2 on P2.1 (DIP25) 00178 fl_power_pwm1(FL_ON); 00179 fl_select_clock_pwm1(FL_CLOCK_DIV1); 00180 fl_pinsel(2, 1, FL_FUNC_ALT1, FL_FLOATING, FL_FLOATING); // PWM1.2, no pullup/down 00181 fl_pwm_set_prescale(4); // 100/25 = 4 00182 00183 #define HSHIFT 0 00184 00185 // main PWM 00186 fl_pwm_set_match(0, 800); // 800 color clocks 00187 00188 // generate line interrupts from PWM MR0 00189 fl_pwm_config_match(0, FL_ON, FL_ON, FL_OFF); // interrupt, reset, !stop 00190 00191 // this PWM generates the HSYNC pulse 00192 fl_pwm_set_match(2, 16+HSHIFT); // go low at 16 00193 fl_pwm_set_match(1, 48+HSHIFT); // go high at 48 00194 fl_pwm_config_edges(2, FL_DOUBLE_EDGE); // need this for negative sync 00195 fl_pwm_output_enable(2, FL_ENABLE); // enable this output 00196 00197 } 00198 00199 // ----------------------------------------------------------------------------------- 00200 // state machine list for the complete screen output 00201 static void state_before_vsync(void); 00202 00203 static void (*state)(void) = state_before_vsync; 00204 00205 // emit a line from the visible area (framebuffer) 00206 static void state_visible_area(void) { 00207 extern const struct dma_lli blank_lli; 00208 00209 // limit visible area to the size of the framebuffer 00210 if (line_counter != (VISIBLE+1)) { 00211 // reset DMA parameters for active line 00212 fl_dma_set_srcaddr (0,(unsigned char *)pointer); // source is our current framebuffer pointer 00213 fl_dma_set_destaddr(0, (void*)FL_I2STXFIFO); // destination is I2S 00214 fl_dma_set_next_lli(0, &blank_lli); // connect to blanking list 00215 fl_dma_channel_control(0, // control word 00216 20, // count (20*4 = 80 bytes active) 00217 4, 4, // src and dest burst size 00218 32, 32, // src and dest width 00219 FL_SRC_INCREMENT, 00220 FL_NO_DEST_INCREMENT, 00221 FL_OFF // no interrupt on first 640 pixel 00222 ); 00223 // increment framebuffer pointer 00224 pointer+=80; 00225 00226 // restart DMA sequence 00227 fl_dma_channel_config(0, FL_ENABLE, 00228 FL_DMA_PERIPHERAL_IS_MEMORY, FL_DMA_BURST_REQUEST_I2S_CH0, 00229 FL_DMA_MEMORY_TO_PERIPHERAL, 00230 FL_ON, FL_ON 00231 ); 00232 00233 if (line_counter==400) pointer=framebuffer2; // add 80 lines extra 00234 } else state = state_before_vsync; 00235 } 00236 00237 00238 static void state_after_vsync(void) { // VSYNC is over, now ait for end of frame 00239 if (line_counter != VTOTAL) return; // if not end of frame 00240 line_counter = 0; // reset line counter 00241 pointer=framebuffer; // and framebuffer 00242 state = state_visible_area; // we're in visible mode 00243 } 00244 00245 static void state_during_vsync(void) { // VSYNC is active 00246 if (line_counter != VSYNCEND) return; // if not end of vsync 00247 #if VPOLARITY==positive // check polarity 00248 fl_gpio_clear_value(0, 1<<6); // vsync low 00249 #else // or 00250 fl_gpio_set_value(0, 1<<6); // vsync high 00251 #endif 00252 state = state_after_vsync; // VSYNC is done 00253 } 00254 00255 static void state_before_vsync(void) { // wait for VSYNC start 00256 if (line_counter != VSYNCSTART) return; // if not 00257 #if VPOLARITY==positive // check polarity 00258 fl_gpio_set_value(0, 1<<6); // vsync high 00259 #else // or 00260 fl_gpio_clear_value(0, 1<<6); // vsync low 00261 #endif 00262 state = state_during_vsync; // VSYNC has started 00263 } 00264 00265 // inactive 00266 extern "C" void DMA_IRQHandler(void) __irq { 00267 fl_dma_clear_terminal_count_interrupt_request(0); 00268 00269 } 00270 00271 // active 00272 extern "C" void PWM1_IRQHandler(void) __irq { 00273 int regval=*FL_PWM1IR; 00274 // clear interrupt flag 00275 state(); 00276 line_counter++; 00277 *FL_PWM1IR=regval; 00278 } 00279 00280 00281 // ----------------------------------------------------------------------------------- 00282 00283 void init_vga(void) { 00284 fl_power_off_all_peripherals(); 00285 00286 init_pll0(FL_PLL0_CLOCK_SOURCE_MAIN, 2, 25, 3); // 100MHz 00287 init_uart0(0, 0, 651); // 100MHz/651/16=9600.6 (default 8N1) 00288 00289 init_vsync(0, 6); // VSYNC on P0.6 (DIP8) 00290 init_i2s(); 00291 init_hsync(); 00292 init_dma_controller(); 00293 00294 fl_pwm_timer_counter_enable(FL_ENABLE); 00295 fl_pwm_enable(FL_ENABLE); 00296 fl_i2s_config_dma1(FL_OFF, FL_ON, 0, 2); 00297 fl_nvic_interrupt_set_enable(FL_NVIC_INT_PWM); // start the PWM interrupts 00298 NVIC_SetPriority(PWM1_IRQn, 50); 00299 NVIC_SetPriority(DMA_IRQn, 95); 00300 }
Generated on Sun Jul 17 2022 04:22:51 by 1.7.2