/** * @file main.c * @author giomba@glgprograms.it * @brief OSDY main. * * @copyright Copyright RetrOfficina GLG Programs (c) 2022 * * Video image generator superimposition for analog PAL signals, * with Atmega328, for your retro OSD titles. * */ #include "const.h" #include #include #include volatile uint16_t frame = 0; volatile uint16_t line = 0xfe; volatile uint8_t image = 0xff; // horizontal and vertical position // (and current increments) // of bouncing sprite volatile uint8_t vpos = 0; volatile uint16_t hpos = 0; volatile int8_t vinc = +1; volatile int8_t hinc = +1; // vertical sync interrupt void int_vertical_sync_s(void); ISR(INT0_vect) { // count frames frame += 1; // move sprite vpos += vinc; hpos += hinc; // invert bouncing direction if (vpos == 0) vinc = +1; if (vpos == FRAME_LINE_HEIGHT - SPRITE_LINE_HEIGHT) vinc = -1; if (hpos == BACK_PORCH_SYSCLOCK_OFFSET) hinc = +1; if (hpos == FRAME_SYSCLOCK_WIDTH - SPRITE_SYSCLOCK_WIDTH - FRONT_PORCH_SYSCLOCK_OFFSET - HSYNC_SYSCLOCK_TUNE) hinc = -1; int_vertical_sync_s(); } // horizontal sync interrupt void int_horizontal_sync_s(void); ISR(INT1_vect) { // count lines line += 1; // we are past the last line of the sprite if (line >= vpos + SPRITE_LINE_HEIGHT) return; if (line >= vpos) int_horizontal_sync_s(); } ISR(TIMER1_COMPA_vect, ISR_NAKED) { // end-of back porch timer interrupt asm("jmp int_timer_1"); } // external assembly main loop void main_asm(void); int main() { // port B, pin 4 and 5 as output, others as input DDRB |= 0x30; // set interrupt vectors at address 0x0, not bootloader // timing is important, see atmel datasheet _SFR_IO8(MCUCR) = (1 << IVCE); _SFR_IO8(MCUCR) = 0; EICRA = 0x0a; // external interrupt 0 and 1, falling edge EIMSK = 0x03; // external interrupt 0 and 1, mask enable TCCR1A = 0x00; // don't connect output pins to timer, CTC[1:0] mode TCCR1B = 0x09; // CTC[3:2] mode, no prescaler main_asm(); }