Three-pin 640x400 VGA Console Mode
Dependents: projet_AWA_testVGA2
vga640x400.c
- Committer:
- Ivop
- Date:
- 2011-08-10
- Revision:
- 4:3f0bd68a4dda
- Parent:
- 3:ab761080df98
File content as of revision 4:3f0bd68a4dda:
/* * 640x400 70Hz VGA Driver * * Copyright (C) 2011 by Ivo van Poorten <ivop@euronet.nl> * This file is licensed under the terms of the GNU Lesser * General Public License, version 3. * * Inspired by Simon's (not Ford) Cookbook entry and Cliff Biffle's * assembly code. */ #include "fastlib/common.h" #include "fastlib/pinsel.h" #include "fastlib/gpio.h" #include "fastlib/clock.h" #include "fastlib/power.h" #include "fastlib/pwm.h" #include "fastlib/i2s.h" #include "fastlib/uart.h" #include "fastlib/dma.h" #include "fastlib/nvic.h" //#include "mbed.h" #include <string.h> #define DEBUG_VGA 0 #if DEBUG_VGA // DEBUG messages on UART0 #include <stdio.h> #define dbprintf(...) printf(__VA_ARGS__) #else #define dbprintf(...) #endif // ----------------------------------------------------------------------------------- unsigned char text_buffer[80*25]; unsigned char *font; static unsigned line_counter; static unsigned char scanline0[100], scanline1[100]; // 100*8=800 color clocks static unsigned char *curline = scanline1+20; #define NCHARS 256 struct dma_lli { const void *source; const void *dest; const struct dma_lli *next; unsigned control_word; }; extern const struct dma_lli dma_lli1; static const struct dma_lli dma_lli0 = { scanline0, (void*)FL_I2STXFIFO, &dma_lli1, 0x84489019 // control word is explained below }; static const struct dma_lli dma_lli1 = { scanline1, (void*)FL_I2STXFIFO, &dma_lli0, 0x84489019 }; // ----------------------------------------------------------------------------------- #define FEED0_AND_WAIT(x,y) fl_pll0_feed(); while(y fl_pll0_get_##x()) static void init_pll0(unsigned int clock_source, int N, int M, int cpu_divider) { fl_select_pll0_clock_source(clock_source); fl_pll0_control(FL_ENABLE, FL_DISCONNECT); FEED0_AND_WAIT(connect,); fl_pll0_control(FL_DISABLE, FL_DISCONNECT); FEED0_AND_WAIT(enable,); fl_pll0_config(N, M); fl_pll0_feed(); fl_pll0_control(FL_ENABLE, FL_DISCONNECT); FEED0_AND_WAIT(enable,!); fl_set_cpu_clock_divider(cpu_divider); while(!fl_pll0_get_lock()) ; fl_pll0_control(FL_ENABLE, FL_CONNECT); FEED0_AND_WAIT(connect,!); } // ----------------------------------------------------------------------------------- #if DEBUG_VGA static void init_uart0(unsigned divaddval, unsigned mulval, unsigned divisor) { fl_power_uart0(FL_ON); fl_select_clock_uart0(FL_CLOCK_DIV1); fl_uart_set_fractional_divider(0, divaddval, mulval); fl_uart_set_divisor_latch(0, divisor); } #endif // ----------------------------------------------------------------------------------- static void init_vsync(unsigned port, unsigned pin) { fl_power_gpio(FL_ON); fl_pinsel(port, pin, FL_FUNC_DEFAULT, FL_IGNORE, FL_IGNORE); fl_gpio_set_direction(port, 1<<pin, FL_OUTPUT); fl_gpio_clear_value (port, 1<<pin); } // ----------------------------------------------------------------------------------- static void init_dma_controller(void) { fl_power_gpdma(FL_ON); fl_dma_enable(FL_ENABLE); while (!fl_dma_is_enabled()) ; fl_dma_set_srcaddr (0, dma_lli0.source); fl_dma_set_destaddr(0, dma_lli0.dest); fl_dma_set_next_lli(0, dma_lli0.next); fl_dma_channel_control(0, // control word 25, 4, 4, // src and dest burst size 32, 32, // src and dest width FL_SRC_INCREMENT, FL_NO_DEST_INCREMENT, FL_ON // terminal count interrupt ); // if ((fl_dma_channel_get_control_mask(0) | 25) != dma_lli0.control_word) { // dbprintf("%08x and %08x\r\n", fl_dma_channel_get_control_mask(0) | 25, dma_lli0.control_word); // dbprintf("control_word mismatch\r\n"); // while(1); // } fl_dma_channel_config(0, FL_ENABLE, FL_DMA_PERIPHERAL_IS_MEMORY, FL_DMA_BURST_REQUEST_I2S_CH0, FL_DMA_MEMORY_TO_PERIPHERAL, FL_ON, FL_ON ); fl_nvic_interrupt_set_enable(FL_NVIC_INT_DMA); } // ----------------------------------------------------------------------------------- static void init_i2s(void) { // I2S on P0.9 (DIP5) fl_power_i2s(FL_ON); fl_select_clock_i2s(FL_CLOCK_DIV1); // assume 100MHz // fl_pinsel(0, 7, FL_FUNC_ALT1, FL_IGNORE, FL_IGNORE); // I2STX_CLK // fl_pinsel(0, 8, FL_FUNC_ALT1, FL_IGNORE, FL_IGNORE); // I2STX_WS fl_pinsel(0, 9, FL_FUNC_ALT1, FL_IGNORE, FL_IGNORE); // I2STX_SDA fl_i2s_set_tx_rate(1, 4); fl_i2s_output_set_config(FL_8BITS, FL_STEREO, 8, 0, 0, 0, 0); } // ----------------------------------------------------------------------------------- static void init_hsync(void) { // PWM1.2 on P2.1 (DIP25) fl_power_pwm1(FL_ON); fl_select_clock_pwm1(FL_CLOCK_DIV1); fl_pinsel(2, 1, FL_FUNC_ALT1, FL_FLOATING, FL_FLOATING); // PWM1.2, no pullup/down fl_pwm_set_prescale(4); // 100/25 = 4 fl_pwm_config_match(0, FL_ON, FL_ON, FL_OFF); // interrupt, reset, !stop fl_pwm_set_match(0, 800); // 800 color clocks #define HSHIFT 48 fl_pwm_set_match(1, 97+HSHIFT); // go high at 97 fl_pwm_set_match(2, 1+HSHIFT); // go low at 1 fl_pwm_config_edges(2, FL_DOUBLE_EDGE); fl_pwm_output_enable(2, FL_ENABLE); } // ----------------------------------------------------------------------------------- static void state_before_vsync(void); static void (*state)(void) = state_before_vsync; static void state_blank_area(void) { if (line_counter != 449) return; line_counter = 0; state = state_before_vsync; } static void state_clearing_buffers(void) { int i; if (line_counter < 441) return; for (i=0; i<20; i++) { *(curline+i ) = 0; *(curline+i+20) = 0; *(curline+i+40) = 0; *(curline+i+60) = 0; } if (line_counter == 442) { state = state_blank_area; } } static unsigned char *fp, *tb; static void state_visible_area(void) { int x; unsigned char *sp = curline, *tbp = tb; for (x=0; x<20; x++) { *sp++ = *(fp + *tbp++); *sp++ = *(fp + *tbp++); *sp++ = *(fp + *tbp++); *sp++ = *(fp + *tbp++); } fp += NCHARS; if (fp == font+NCHARS*16) { fp = font; tb += 80; } if (line_counter == 438) { state = state_clearing_buffers; } } static void state_after_vsync(void) { if (line_counter != 38) return; fp = font; tb = text_buffer; state = state_visible_area; } static void state_during_vsync(void) { if (line_counter != 4) return; fl_gpio_clear_value(0, 1<<6); state = state_after_vsync; } static void state_before_vsync(void) { if (line_counter != 2) return; fl_gpio_set_value(0, 1<<6); state = state_during_vsync; } extern "C" void DMA_IRQHandler(void) __irq { fl_dma_clear_terminal_count_interrupt_request(0); line_counter++; curline = curline == scanline0+20 ? scanline1+20 : scanline0+20; state(); } // ----------------------------------------------------------------------------------- void init_vga(void) { fl_power_off_all_peripherals(); init_pll0(FL_PLL0_CLOCK_SOURCE_MAIN, 2, 25, 3); // 100MHz #if DEBUG_VGA init_uart0(0, 0, 651); // 100MHz/651/16=9600.6 (default 8N1) #endif init_vsync(0, 6); // VSYNC on P0.6 (DIP8) init_i2s(); init_hsync(); init_dma_controller(); fl_pwm_timer_counter_enable(FL_ENABLE); fl_pwm_enable(FL_ENABLE); fl_i2s_config_dma1(FL_OFF, FL_ON, 0, 2); }