Created
July 27, 2017 00:27
-
-
Save rjw57/0b4c223c0d3d4c58d8581fb86c344967 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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