diff --git a/libs/TVout/TVout.cpp b/libs/TVout/TVout.cpp old mode 100755 new mode 100644 index 751eb54..ace1c72 --- a/libs/TVout/TVout.cpp +++ b/libs/TVout/TVout.cpp @@ -49,7 +49,7 @@ */ char TVout::begin(uint8_t mode) { - return begin(mode,128,96); + return begin(mode, 128, 96); } // end of begin @@ -74,19 +74,23 @@ char TVout::begin(uint8_t mode) { char TVout::begin(uint8_t mode, uint8_t x, uint8_t y) { // check if x is divisable by 8 - if ( !(x & 0xF8)) + if ( !(x & 0xF8)) { return 1; - x = x/8; + } + + x = x / 8; screen = (unsigned char*)malloc(x * y * sizeof(unsigned char)); - if (screen == NULL) + if (screen == NULL) { return 4; + } cursor_x = 0; cursor_y = 0; - render_setup(mode,x,y,screen); + render_setup(mode, x, y, screen); clear_screen(); + return 0; } // end of begin @@ -134,7 +138,7 @@ void TVout::fill(uint8_t color) { * The horizonal resolution. */ unsigned char TVout::hres() { - return display.hres*8; + return display.hres * 8; } // end of hres @@ -155,7 +159,7 @@ unsigned char TVout::vres() { * Will return -1 for dynamic width fonts as this cannot be determined. */ char TVout::char_line() { - return ((display.hres*8)/pgm_read_byte(font)); + return ((display.hres * 8) / pgm_read_byte(font)); } // end of char_line @@ -172,6 +176,17 @@ void TVout::delay(unsigned int x) { } // end of delay +/* Get the time in ms since begin was called. + * The resolution is 16ms for NTSC and 20ms for PAL + * + * Returns: + * The time in ms since video generation has started. +*/ +unsigned long TVout::millis() { + return display.frames * _PAL_TIME_SCANLINE * _PAL_LINE_FRAME / 1000; +} // end of millis + + /* Delay for x frames, exits at the end of the last display line. * delay_frame(1) is useful prior to drawing so there is little/no flicker. * @@ -180,7 +195,7 @@ void TVout::delay(unsigned int x) { * The number of frames to delay for. */ void TVout::delay_frame(unsigned int x) { - int stop_line = (int)(display.start_render + (display.vres*(display.vscale_const+1)))+1; + int stop_line = (int)(display.first_half_frame_start_render + (display.vres * (display.vscale_const + 1))) + 1; while (x) { while (display.scanLine != stop_line); while (display.scanLine == stop_line); @@ -189,22 +204,6 @@ void TVout::delay_frame(unsigned int x) { } // end of delay_frame -/* Get the time in ms since begin was called. - * The resolution is 16ms for NTSC and 20ms for PAL - * - * Returns: - * The time in ms since video generation has started. -*/ -unsigned long TVout::millis() { - if (display.lines_frame == _NTSC_LINE_FRAME) { - return display.frames * _NTSC_TIME_SCANLINE * _NTSC_LINE_FRAME / 1000; - } - else { - return display.frames * _PAL_TIME_SCANLINE * _PAL_LINE_FRAME / 1000; - } -} // end of millis - - /* force the number of times to display each line. * * Arguments: @@ -238,7 +237,10 @@ void TVout::force_outstart(uint8_t time) { */ void TVout::force_linestart(uint8_t line) { delay_frame(1); - display.start_render = line; + display.first_half_frame_start_render = line; + display.first_half_frame_end_render = display.first_half_frame_start_render + (display.vres * (display.vscale_const + 1)); + display.second_half_frame_start_render = display.lines_frame + display.first_half_frame_start_render; + display.second_half_frame_end_render = display.lines_frame + display.first_half_frame_end_render; } @@ -756,122 +758,3 @@ static void inline sp(uint8_t x, uint8_t y, char c) { else display.screen[(x/8) + (y*display.hres)] ^= 0x80 >> (x&7); } // end of sp - - -/* set the vertical blank function call - * The function passed to this function will be called one per frame. The function should be quickish. - * - * Arguments: - * func: - * The function to call. - */ -void TVout::set_vbi_hook(void (*func)()) { - vbi_hook = func; -} // end of set_vbi_hook - - -/* set the horizonal blank function call - * This function passed to this function will be called one per scan line. - * The function MUST be VERY FAST(~2us max). - * - * Arguments: - * funct: - * The function to call. - */ -void TVout::set_hbi_hook(void (*func)()) { - hbi_hook = func; -} // end of set_bhi_hook - - -/* Simple tone generation - * - * Arguments: - * frequency: - * the frequency of the tone - * courtesy of adamwwolf - */ -void TVout::tone(unsigned int frequency) { - tone(frequency, 0); -} // end of tone - - -/* Simple tone generation - * - * Arguments: - * frequency: - * the frequency of the tone - * duration_ms: - * The duration to play the tone in ms - * courtesy of adamwwolf - */ -void TVout::tone(unsigned int frequency, unsigned long duration_ms) { - - if (frequency == 0) - return; - -#define TIMER 2 - //this is init code - TCCR2A = 0; - TCCR2B = 0; - TCCR2A |= _BV(WGM21); - TCCR2B |= _BV(CS20); - //end init code - - //most of this is taken from Tone.cpp from Arduino - uint8_t prescalarbits = 0b001; - uint32_t ocr = 0; - - - DDR_SND |= _BV(SND_PIN); //set pb3 (digital pin 11) to output - - //we are using an 8 bit timer, scan through prescalars to find the best fit - ocr = F_CPU / frequency / 2 - 1; - prescalarbits = 0b001; // ck/1: same for both timers - if (ocr > 255) { - ocr = F_CPU / frequency / 2 / 8 - 1; - prescalarbits = 0b010; // ck/8: same for both timers - - if (ocr > 255) { - ocr = F_CPU / frequency / 2 / 32 - 1; - prescalarbits = 0b011; - } - - if (ocr > 255) { - ocr = F_CPU / frequency / 2 / 64 - 1; - prescalarbits = TIMER == 0 ? 0b011 : 0b100; - if (ocr > 255) { - ocr = F_CPU / frequency / 2 / 128 - 1; - prescalarbits = 0b101; - } - - if (ocr > 255) { - ocr = F_CPU / frequency / 2 / 256 - 1; - prescalarbits = TIMER == 0 ? 0b100 : 0b110; - if (ocr > 255) { - // can't do any better than /1024 - ocr = F_CPU / frequency / 2 / 1024 - 1; - prescalarbits = TIMER == 0 ? 0b101 : 0b111; - } - } - } - } - TCCR2B = prescalarbits; - - if (duration_ms > 0) - remainingToneVsyncs = duration_ms*60/1000; //60 here represents the framerate - else - remainingToneVsyncs = -1; - - // Set the OCR for the given timer, - OCR2A = ocr; - //set it to toggle the pin by itself - TCCR2A &= ~(_BV(COM2A1)); //set COM2A1 to 0 - TCCR2A |= _BV(COM2A0); -} // end of tone - -/* Stops tone generation - */ -void TVout::noTone() { - TCCR2B = 0; - PORT_SND &= ~(_BV(SND_PIN)); //set pin 11 to 0 -} // end of noTone \ No newline at end of file diff --git a/libs/TVout/TVout.h b/libs/TVout/TVout.h old mode 100755 new mode 100644 index c4e184a..c2492df --- a/libs/TVout/TVout.h +++ b/libs/TVout/TVout.h @@ -104,15 +104,6 @@ class TVout { void draw_circle(uint8_t x0, uint8_t y0, uint8_t radius, char c, char fc = -1); void bitmap(uint8_t x, uint8_t y, const unsigned char * bmp, uint16_t i = 0, uint8_t width = 0, uint8_t lines = 0); - //hook setup functions - void set_vbi_hook(void (*func)()); - void set_hbi_hook(void (*func)()); - - //tone functions - void tone(unsigned int frequency, unsigned long duration_ms); - void tone(unsigned int frequency); - void noTone(); - //The following function definitions can be found in TVoutPrint.cpp //printing functions void print_char(uint8_t x, uint8_t y, unsigned char c); diff --git a/libs/TVout/TVoutPrint.cpp b/libs/TVout/TVoutPrint.cpp old mode 100755 new mode 100644 diff --git a/libs/TVout/spec/asm_macros.h b/libs/TVout/spec/asm_macros.h old mode 100755 new mode 100644 diff --git a/libs/TVout/spec/hardware_setup.h b/libs/TVout/spec/hardware_setup.h old mode 100755 new mode 100644 diff --git a/libs/TVout/spec/video_properties.h b/libs/TVout/spec/video_properties.h old mode 100755 new mode 100644 index 006cf37..719c47f --- a/libs/TVout/spec/video_properties.h +++ b/libs/TVout/spec/video_properties.h @@ -32,36 +32,67 @@ #define _CYCLES_PER_US (F_CPU / 1000000) -#define _TIME_HORZ_SYNC 4.7 -#define _TIME_VIRT_SYNC 58.85 -#define _TIME_ACTIVE 46 -#define _CYCLES_VIRT_SYNC ((_TIME_VIRT_SYNC * _CYCLES_PER_US) - 1) -#define _CYCLES_HORZ_SYNC ((_TIME_HORZ_SYNC * _CYCLES_PER_US) - 1) - -//Timing settings for NTSC -#define _NTSC_TIME_SCANLINE 63.55 -#define _NTSC_TIME_OUTPUT_START 12 - -#define _NTSC_LINE_FRAME 262 -#define _NTSC_LINE_START_VSYNC 0 -#define _NTSC_LINE_STOP_VSYNC 3 -#define _NTSC_LINE_DISPLAY 216 -#define _NTSC_LINE_MID ((_NTSC_LINE_FRAME - _NTSC_LINE_DISPLAY)/2 + _NTSC_LINE_DISPLAY/2) - -#define _NTSC_CYCLES_SCANLINE ((_NTSC_TIME_SCANLINE * _CYCLES_PER_US) - 1) -#define _NTSC_CYCLES_OUTPUT_START ((_NTSC_TIME_OUTPUT_START * _CYCLES_PER_US) - 1) - -//Timing settings for PAL -#define _PAL_TIME_SCANLINE 64 -#define _PAL_TIME_OUTPUT_START 12.5 - -#define _PAL_LINE_FRAME 312 -#define _PAL_LINE_START_VSYNC 0 -#define _PAL_LINE_STOP_VSYNC 7 -#define _PAL_LINE_DISPLAY 260 -#define _PAL_LINE_MID ((_PAL_LINE_FRAME - _PAL_LINE_DISPLAY)/2 + _PAL_LINE_DISPLAY/2) +// Timing settings for PAL +// Front porch (A): 1.65 µs +0.4/-0.1 +// Sync pulse length (B): 4.7 µs +0.2/-0.2 +// Back porch (C): 5.7 µs +0.2/-0.2 +// Active video (D): 51.95 µs +0.4/-0.1 +// Total horizontal sync time: 12.05 µs / 12.00 µs + 0.15 µs +// Total time for each line: 64.00 µs +// +// 312.5 - 287.5 = 25 lines (Vertical Blanking Width: Blank lines/field) +// Vertical lines: 312.5 / 312-313 (625 total) ??? 288 + 25 = 313 +// Vertical lines visible: 287.5 / 288 (575 / 576 total) +// Vertical Frequency: 50 Hz = 25 * 2 +// Vertical Period: 20 ms = 312.5 * 64 µs +// Vertical Equalizing Pulse Width: 2.35 µs ??? +// Vertical sync polarity: Negative (burst) +// Sync pulse length (F): 0.576 ms (burst) ??? +// Active video (H): 18.4 ms + +// Vertical "Equalizing pulses": +// Vert. “front porch” *b: 2.5 lines = 160 µs ??? +// Vert sync. pulse width *b: 2.5 lines = 160 µs ??? +// Vert. “back porch” *b,*c: 2.5 + 17.5 = 20 lines = 20 * 64 µs = 1.28 ms +// Vertical Blanking Width: 25 lines = 25 * 64 µs = 1.6 ms +// Total vertical sync time: 1.6 ms = 25 * 64 µs + +// *b Due to the interlaced format used in both systems, the vertical blanking interval is somewhat more complex than this description would indicate. “Equalizing pulses,” of twice the normal rate of the horizontal synchronization pulses but roughly half the duration, replace the standard H. sync pulse during the vertical front porch, sync pulse, and the first few lines of the back porch. + +// *c The “back porch” timings given here are separated into the time during which equalization pulses are produced (thepostequalization period) and the remaining “normal” line times. + +// Analog Video Vertical Sync: https://www.youtube.com/watch?v=NY2rIjkH1Xw +// PAL video timing specification: http://martin.hinner.info/vga/pal.html +// NTSC format description: http://martin.hinner.info/vga/pal.gif + +// Timing settings for PAL +#define _PAL_LINE_FULL_FRAME 625 // lines +#define _PAL_LINE_FRAME (_PAL_LINE_FULL_FRAME / 2) // lines + +#define _PAL_TIME_RENDERING_LINE 46 // µs +#define _PAL_LINE_DISPLAY 260 // lines +#define _PAL_LINE_MID ((_PAL_LINE_FRAME - _PAL_LINE_DISPLAY) / 2 + _PAL_LINE_DISPLAY / 2) // lines + +#define _PAL_TIME_SCANLINE 64 // µs +#define _PAL_TIME_HORZ_SYNC 4.7 // µs +#define _PAL_TIME_OUTPUT_START 12.5 // µs #define _PAL_CYCLES_SCANLINE ((_PAL_TIME_SCANLINE * _CYCLES_PER_US) - 1) +#define _PAL_CYCLES_HORZ_SYNC ((_PAL_TIME_HORZ_SYNC * _CYCLES_PER_US) - 1) #define _PAL_CYCLES_OUTPUT_START ((_PAL_TIME_OUTPUT_START * _CYCLES_PER_US) - 1) +#define _PAL_TIME_VSYNC_SCANLINE (_PAL_TIME_SCANLINE / 2) // µs +#define _PAL_TIME_VSYNC_PRE_EQUALIZING 2.3 // µs 2.4 +#define _PAL_TIME_VSYNC_INVERTED_EQUALIZING 4.7 // µs + +#define _PAL_CYCLES_VSYNC_SCANLINE ((_PAL_TIME_VSYNC_SCANLINE * _CYCLES_PER_US) - 1) +#define _PAL_CYCLES_VSYNC_PRE_EQUALIZING ((_PAL_TIME_VSYNC_PRE_EQUALIZING * _CYCLES_PER_US) - 1) +#define _PAL_CYCLES_VSYNC_EQUALIZING (((_PAL_TIME_VSYNC_SCANLINE - _PAL_TIME_VSYNC_INVERTED_EQUALIZING) * _CYCLES_PER_US) - 1) + +#define _PAL_LINE_NUMBER_TO_START_SECONDFRAME_VSYNC 310 // line# 311 +#define _PAL_LINE_NUMBER_TO_START_SECONDFRAME_BLANKING 318 // line# 318 + +#define _PAL_LINE_NUMBER_TO_START_FIRSTFRAME_VSYNC 622 // line# 623 +#define _PAL_LINE_NUMBER_TO_START_FIRSTFRAME_BLANKING 5 // line# 6 + #endif \ No newline at end of file diff --git a/libs/TVout/version history.txt b/libs/TVout/version history.txt old mode 100755 new mode 100644 diff --git a/libs/TVout/video_gen.cpp b/libs/TVout/video_gen.cpp old mode 100755 new mode 100644 index 8e21b09..bf6d7cc --- a/libs/TVout/video_gen.cpp +++ b/libs/TVout/video_gen.cpp @@ -40,31 +40,21 @@ int renderLine; TVout_vid display; void (*render_line)(); //remove me void (*line_handler)(); //remove me -void (*hbi_hook)() = ∅ -void (*vbi_hook)() = ∅ - -// sound properties -volatile long remainingToneVsyncs; - -void empty() {} void render_setup(uint8_t mode, uint8_t x, uint8_t y, uint8_t *scrnptr) { - + display.screen = scrnptr; display.hres = x; display.vres = y; display.frames = 0; - if (mode) - display.vscale_const = _PAL_LINE_DISPLAY/display.vres - 1; - else - display.vscale_const = _NTSC_LINE_DISPLAY/display.vres - 1; + display.vscale_const = _PAL_LINE_DISPLAY / display.vres - 1; display.vscale = display.vscale_const; //selects the widest render method that fits in 46us //as of 9/16/10 rendermode 3 will not work for resolutions lower than //192(display.hres lower than 24) - unsigned char rmethod = (_TIME_ACTIVE*_CYCLES_PER_US)/(display.hres*8); + unsigned char rmethod = (_PAL_TIME_RENDERING_LINE * _CYCLES_PER_US) / (display.hres * 8); // re: 46 µs * 16 / (16 * 8) = 5.75 ticks per pixel switch(rmethod) { case 6: render_line = &render_line6c; @@ -85,101 +75,164 @@ void render_setup(uint8_t mode, uint8_t x, uint8_t y, uint8_t *scrnptr) { render_line = &render_line3c; } - DDR_VID |= _BV(VID_PIN); DDR_SYNC |= _BV(SYNC_PIN); PORT_VID &= ~_BV(VID_PIN); PORT_SYNC |= _BV(SYNC_PIN); - DDR_SND |= _BV(SND_PIN); // for tone generation. - // inverted fast pwm mode on timer 1 - TCCR1A = _BV(COM1A1) | _BV(COM1A0) | _BV(WGM11); + // inverted fast pwm mode on timer 1: + TCCR1A = _BV(COM1A1) | _BV(COM1A0) | _BV(WGM11); TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10); - if (mode) { - display.start_render = _PAL_LINE_MID - ((display.vres * (display.vscale_const+1))/2); - display.output_delay = _PAL_CYCLES_OUTPUT_START; - display.vsync_end = _PAL_LINE_STOP_VSYNC; - display.lines_frame = _PAL_LINE_FRAME; - ICR1 = _PAL_CYCLES_SCANLINE; - OCR1A = _CYCLES_HORZ_SYNC; - } - else { - display.start_render = _NTSC_LINE_MID - ((display.vres * (display.vscale_const+1))/2) + 8; - display.output_delay = _NTSC_CYCLES_OUTPUT_START; - display.vsync_end = _NTSC_LINE_STOP_VSYNC; - display.lines_frame = _NTSC_LINE_FRAME; - ICR1 = _NTSC_CYCLES_SCANLINE; - OCR1A = _CYCLES_HORZ_SYNC; - } - display.scanLine = display.lines_frame+1; - line_handler = &vsync_line; + display.output_delay = _PAL_CYCLES_OUTPUT_START; + display.lines_frame = _PAL_LINE_FRAME; + + display.first_half_frame_start_render = _PAL_LINE_MID - (display.vres * (display.vscale_const + 1)) / 2; + display.first_half_frame_end_render = display.first_half_frame_start_render + (display.vres * (display.vscale_const + 1)); + display.second_half_frame_start_render = display.lines_frame + display.first_half_frame_start_render; + display.second_half_frame_end_render = display.lines_frame + display.first_half_frame_end_render; + + display.scanLine = 0; + display.vsyncScanLine = 0; + line_handler = &first_half_frame_vsync_lines; + + ICR1 = _PAL_CYCLES_VSYNC_SCANLINE; + OCR1A = _PAL_CYCLES_VSYNC_PRE_EQUALIZING; + TIMSK1 = _BV(TOIE1); sei(); } // render a line ISR(TIMER1_OVF_vect) { - hbi_hook(); line_handler(); } -void blank_line() { +void first_half_frame_vsync_lines() { + + display.vsyncScanLine++; + + if (display.vsyncScanLine == 5) { + OCR1A = _PAL_CYCLES_VSYNC_EQUALIZING; + } + else if (display.vsyncScanLine == 10) { + OCR1A = _PAL_CYCLES_VSYNC_PRE_EQUALIZING; + } + else if (display.vsyncScanLine == 15) { + ICR1 = _PAL_CYCLES_SCANLINE; + OCR1A = _PAL_CYCLES_HORZ_SYNC; - if ( display.scanLine == display.start_render) { + display.scanLine = _PAL_LINE_NUMBER_TO_START_FIRSTFRAME_BLANKING; + line_handler = &first_half_frame_blank_line; + } +} + +void first_half_frame_blank_line() { + + display.scanLine++; + + if ( display.scanLine == display.first_half_frame_start_render) { renderLine = 0; display.vscale = display.vscale_const; - line_handler = &active_line; + line_handler = &first_half_frame_active_line; } - else if (display.scanLine == display.lines_frame) { - line_handler = &vsync_line; - vbi_hook(); + else if (display.scanLine == _PAL_LINE_NUMBER_TO_START_SECONDFRAME_VSYNC) { + ICR1 = _PAL_CYCLES_VSYNC_SCANLINE; + OCR1A = _PAL_CYCLES_VSYNC_PRE_EQUALIZING; + + line_handler = &second_half_frame_vsync_lines; + display.vsyncScanLine = 0; + display.frames++; } - - display.scanLine++; } -void active_line() { +void first_half_frame_active_line() { + + display.scanLine++; + wait_until(display.output_delay); render_line(); - if (!display.vscale) { + + if (display.vscale == 0) { display.vscale = display.vscale_const; renderLine += display.hres; } - else + else { display.vscale--; + } - if ((display.scanLine + 1) == (int)(display.start_render + (display.vres*(display.vscale_const+1)))) - line_handler = &blank_line; - - display.scanLine++; + if (display.scanLine == display.first_half_frame_end_render) { + line_handler = &first_half_frame_blank_line; + } } -void vsync_line() { - if (display.scanLine >= display.lines_frame) { - OCR1A = _CYCLES_VIRT_SYNC; - display.scanLine = 0; - display.frames++; - - if (remainingToneVsyncs != 0) - { - if (remainingToneVsyncs > 0) - { - remainingToneVsyncs--; - } - - } else - { - TCCR2B = 0; //stop the tone - PORTB &= ~(_BV(SND_PIN)); - } +void second_half_frame_vsync_lines() { + + display.vsyncScanLine++; + + if (display.vsyncScanLine == 5) { + OCR1A = _PAL_CYCLES_VSYNC_EQUALIZING; + } + else if (display.vsyncScanLine == 10) { + OCR1A = _PAL_CYCLES_VSYNC_PRE_EQUALIZING; + } + else if (display.vsyncScanLine == 14) { + ICR1 = _PAL_CYCLES_SCANLINE; + // OCR1A = _PAL_CYCLES_VSYNC_PRE_EQUALIZING; + } + else if (display.vsyncScanLine == 15) { + OCR1A = _PAL_CYCLES_HORZ_SYNC; + + display.scanLine = _PAL_LINE_NUMBER_TO_START_SECONDFRAME_BLANKING; + line_handler = &second_half_frame_blank_line; + } +} +void second_half_frame_blank_line() { + + display.scanLine++; + + if (display.scanLine == display.second_half_frame_start_render) { + renderLine = 0; + display.vscale = display.vscale_const; + line_handler = &second_half_frame_active_line; } - else if (display.scanLine == display.vsync_end) { - OCR1A = _CYCLES_HORZ_SYNC; - line_handler = &blank_line; + else if (display.scanLine == _PAL_LINE_NUMBER_TO_START_FIRSTFRAME_VSYNC) { + ICR1 = _PAL_CYCLES_VSYNC_SCANLINE; + OCR1A = _PAL_CYCLES_HORZ_SYNC; + + line_handler = &second_half_frame_half_blank_line; } +} + +void second_half_frame_active_line() { + display.scanLine++; + + wait_until(display.output_delay); + render_line(); + + if (display.vscale == 0) { + display.vscale = display.vscale_const; + renderLine += display.hres; + } + else { + display.vscale--; + } + + if (display.scanLine == display.second_half_frame_end_render) { + line_handler = &second_half_frame_blank_line; + } +} + +void second_half_frame_half_blank_line() { + + ICR1 = _PAL_CYCLES_VSYNC_SCANLINE; + OCR1A = _PAL_CYCLES_VSYNC_PRE_EQUALIZING; + + line_handler = &first_half_frame_vsync_lines; + display.vsyncScanLine = 0; + display.frames++; } diff --git a/libs/TVout/video_gen.h b/libs/TVout/video_gen.h old mode 100755 new mode 100644 index f66d564..69005ba --- a/libs/TVout/video_gen.h +++ b/libs/TVout/video_gen.h @@ -28,29 +28,32 @@ typedef struct { volatile int scanLine; + volatile int vsyncScanLine; volatile unsigned long frames; - unsigned char start_render; - int lines_frame; //remove me + int first_half_frame_start_render; + int first_half_frame_end_render; + int second_half_frame_start_render; + int second_half_frame_end_render; + int lines_frame; //remove me uint8_t vres; uint8_t hres; uint8_t output_delay; //remove me char vscale_const; //combine me with status switch char vscale; //combine me too. - char vsync_end; //remove me uint8_t * screen; } TVout_vid; extern TVout_vid display; -extern void (*hbi_hook)(); -extern void (*vbi_hook)(); - void render_setup(uint8_t mode, uint8_t x, uint8_t y, uint8_t *scrnptr); -void blank_line(); -void active_line(); -void vsync_line(); -void empty(); +void first_half_frame_vsync_lines(); +void first_half_frame_blank_line(); +void first_half_frame_active_line(); +void second_half_frame_vsync_lines(); +void second_half_frame_blank_line(); +void second_half_frame_active_line(); +void second_half_frame_half_blank_line(); //tone generation properties extern volatile long remainingToneVsyncs;