Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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
