Skip to content

Instantly share code, notes, and snippets.

@rjw57
Created July 27, 2017 00:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rjw57/0b4c223c0d3d4c58d8581fb86c344967 to your computer and use it in GitHub Desktop.
Save rjw57/0b4c223c0d3d4c58d8581fb86c344967 to your computer and use it in GitHub Desktop.
// Inputs:
// D4 (T0) - Char clock
// Outputs
// D3 (OC2B) - VSYNC
// D5 (OC0B) - HSYNC
// D10 (OC1B) - Visible
//
// All outputs should be synchronised to the rising edge of char clock
#include <avr/sleep.h>
#define V_BACK_PORCH 33
bool line_is_visible = false;
int v_line = 0;
#define T1_MAX 0xffff
#define T1_MATCH T1_MAX - 404 // defines pulse width in sys. clock
#define T1_START T1_MATCH - 60 // defines pulse offset in sys. clock
#define T1_TOP T1_START - 10 // just has to be < T1_START
// HSYNC start of pulse
ISR(TIMER0_COMPA_vect) {
TCNT1 = T1_START; // always do this so that jitter is consistent
if(!line_is_visible) { TCNT1 = 0; }
}
void setup() {
pinMode(3, OUTPUT); // Visible
pinMode(5, OUTPUT); // HSYNC
pinMode(10, OUTPUT); // VSYNC
// HSYNC timer
OCR0A = 99; // line is 100 chars wide
OCR0B = 11; // sync pulse is 12 chars wide
// generate interrupt at compare matches
TIFR0 = _BV(OCF0A);
TIMSK0 = _BV(OCIE0A);
// fast PWM w/ external clock on rising edge TOP = OCRA
// clear OC0B on compare match, set on BOTTOM
TCCR0A = _BV(COM0B1) | _BV(WGM01) | _BV(WGM00);
TCCR0B = _BV(WGM02) | _BV(CS02) | _BV(CS01) | _BV(CS00);
// Visible timer
// Use one-shot trick from
// https://wp.josh.com/2015/03/12/avr-timer-based-one-shot-explained/
TCCR1A = _BV(COM1B1) | _BV(COM1B0) | _BV(WGM11) | _BV(WGM10);
TCCR1B = _BV(CS10) | _BV(WGM12) | _BV(WGM13);
// NB: OCR1{A,B} get truncated to 8-bits if TCCR1A is not already set to 16-bit mode.
OCR1A = 3;
OCR1B = T1_MATCH;
TCNT1 = 0;
// Set up sleep mode for sleeping between HSYNC
set_sleep_mode(SLEEP_MODE_IDLE);
}
void loop() {
// Wait for HSYNC ISR to be called
sleep_mode();
// Compute details of next line while we're not doing anything.
++v_line;
if(v_line >= 525) { v_line = 0; }
line_is_visible = (v_line >= 35) && (v_line < 515);
// Set VSYNC for next line. We don't need to be precise on timing since
// VSYNC is aligned to HSYNC by a 7474.
if(v_line < 2) { PORTD |= (1<<3); } else { PORTD &= ~(1<<3); }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment