2022-10-08 13:11:59 +00:00
|
|
|
/**
|
|
|
|
* @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.
|
|
|
|
*
|
|
|
|
*/
|
2021-07-03 13:02:01 +00:00
|
|
|
#include "const.h"
|
2022-10-08 13:11:59 +00:00
|
|
|
#include <avr/interrupt.h>
|
|
|
|
#include <avr/io.h>
|
2021-07-03 14:42:32 +00:00
|
|
|
#include <string.h>
|
2021-07-03 13:02:01 +00:00
|
|
|
|
2022-10-08 13:11:59 +00:00
|
|
|
volatile uint16_t frame = 0;
|
|
|
|
volatile uint16_t line = 0xfe;
|
|
|
|
volatile uint8_t image = 0xff;
|
2021-06-26 17:15:17 +00:00
|
|
|
|
2022-11-04 19:51:43 +00:00
|
|
|
// horizontal and vertical position
|
|
|
|
// (and current increments)
|
|
|
|
// of bouncing sprite
|
2022-11-03 19:51:18 +00:00
|
|
|
volatile uint8_t vpos = 0;
|
2022-11-03 21:05:59 +00:00
|
|
|
volatile uint16_t hpos = 0;
|
2022-11-03 19:51:18 +00:00
|
|
|
volatile int8_t vinc = +1;
|
|
|
|
volatile int8_t hinc = +1;
|
|
|
|
|
2022-11-04 19:51:43 +00:00
|
|
|
// vertical sync interrupt
|
2022-11-03 19:51:18 +00:00
|
|
|
void int_vertical_sync_s(void);
|
|
|
|
ISR(INT0_vect) {
|
2022-11-04 19:51:43 +00:00
|
|
|
// count frames
|
2022-11-03 19:51:18 +00:00
|
|
|
frame += 1;
|
2022-11-04 19:51:43 +00:00
|
|
|
|
|
|
|
// move sprite
|
2022-11-03 19:51:18 +00:00
|
|
|
vpos += vinc;
|
|
|
|
hpos += hinc;
|
|
|
|
|
2022-11-04 19:51:43 +00:00
|
|
|
// invert bouncing direction
|
2022-11-03 19:51:18 +00:00
|
|
|
if (vpos == 0)
|
|
|
|
vinc = +1;
|
2022-11-04 19:51:43 +00:00
|
|
|
if (vpos == FRAME_PIXEL_HEIGHT - SPRITE_HEIGHT)
|
2022-11-03 19:51:18 +00:00
|
|
|
vinc = -1;
|
2022-11-04 19:51:43 +00:00
|
|
|
if (hpos == BACK_PORCH_OFFSET)
|
2022-11-03 19:51:18 +00:00
|
|
|
hinc = +1;
|
2022-11-04 19:51:43 +00:00
|
|
|
if (hpos ==
|
|
|
|
FRAME_PIXEL_WIDTH - SPRITE_WIDTH - FRONT_PORCH_OFFSET - HSYNC_TUNE)
|
2022-11-03 19:51:18 +00:00
|
|
|
hinc = -1;
|
|
|
|
|
|
|
|
int_vertical_sync_s();
|
2021-06-26 21:42:23 +00:00
|
|
|
}
|
2022-11-03 19:51:18 +00:00
|
|
|
|
2022-11-04 19:51:43 +00:00
|
|
|
// horizontal sync interrupt
|
2022-11-03 19:51:18 +00:00
|
|
|
void int_horizontal_sync_s(void);
|
|
|
|
ISR(INT1_vect) {
|
2022-11-04 19:51:43 +00:00
|
|
|
// count lines
|
2022-11-03 19:51:18 +00:00
|
|
|
line += 1;
|
2022-11-04 19:51:43 +00:00
|
|
|
|
|
|
|
// we are past the last line of the sprite
|
|
|
|
if (line >= vpos + SPRITE_HEIGHT)
|
2022-11-03 19:51:18 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (line >= vpos)
|
|
|
|
int_horizontal_sync_s();
|
2021-06-26 17:15:17 +00:00
|
|
|
}
|
2022-11-03 19:51:18 +00:00
|
|
|
|
2022-11-03 21:05:59 +00:00
|
|
|
ISR(TIMER1_COMPA_vect, ISR_NAKED) {
|
2022-11-04 19:51:43 +00:00
|
|
|
// end-of back porch timer interrupt
|
|
|
|
asm("jmp int_timer_1");
|
2021-07-03 09:54:31 +00:00
|
|
|
}
|
2021-07-03 13:02:01 +00:00
|
|
|
|
2022-10-08 13:11:59 +00:00
|
|
|
// external assembly main loop
|
|
|
|
void main_asm(void);
|
|
|
|
|
|
|
|
int main() {
|
|
|
|
// port B, pin 4 and 5 as output, others as input
|
|
|
|
DDRB |= 0x30;
|
2021-07-03 13:44:01 +00:00
|
|
|
|
2022-10-08 13:11:59 +00:00
|
|
|
// 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
|
|
|
|
|
2022-11-03 21:05:59 +00:00
|
|
|
TCCR1A = 0x00; // don't connect output pins to timer, CTC[1:0] mode
|
|
|
|
TCCR1B = 0x09; // CTC[3:2] mode, no prescaler
|
2022-10-08 13:11:59 +00:00
|
|
|
|
|
|
|
main_asm();
|
|
|
|
}
|