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