; VIDEO COMPOSITE PAL IO DEVICE ; Implemented following timings in http://blog.retroleum.co.uk/electronics-articles/pal-tv-timing-and-voltages/ .include "atmega1284definition.asm" ; define constant .equ SYNC_PIN = PC0 ; Sync pin (pin 22) .equ VIDEO_PIN = PD7 ; Video pin (pin 21) .equ DEBUG_PIN = PC1 ; DEBUG: Single vertical sync pulse to trigger oscilloscope (pin 23) ; memory .equ FRAMEBUFFER = 0x100 ; start vector .org 0x0000 rjmp main ; jump to main label ; main program main: sbi DDRC, SYNC_PIN ; set pin as output sbi DDRC, DEBUG_PIN ; set pin as output ldi r16, 0xFF out DDRD, r16 ; set port as output ;*** Load data into ram *** ;ldi r27, 0x01 ;ldi r26, 0x00 ; load data ldi r16, 255 load_mem_loop: ldi r17, 1 ;sts X, r17 sts 0x0100, r17 adiw XH:XL, 1 ; increment X dec r16 ; decrement outside counter brne load_mem_loop ; if not 0, repeat h_picture_loop v_refresh_loop: ; reset memory position counter ; ldi r16,0x00 ; mov r0,r16 ; ldi r16,0x01 ; mov r1,r16 ; mov XL,r0 ; mov XH,r1 ; set X register to framebuffer start ; ldi r27, 0x01 ; ldi r26, 0x00 ; start 5 long sync pulses call long_sync call long_sync call long_sync call long_sync call long_sync ; end 5 long sync pulses ; start 5 short sync pulses call short_sync call short_sync call short_sync call short_sync call short_sync ; end 5 short sync pulses ; start 304 picture lines ldi r16, 2 h_picture_outer_loop: ldi r17, 152 ; line counter h_picture_loop: call line_sync ; start line pixels: 52uS, 1248 cycles @ 24Mhz ldi r18, 52 ; 1 cycle l_sync_video_loop: ; 24 cycles ; Load a byte from memory into PORTD register and increment the counter. ; This also displays byte's MSB pixel "for free", as the video pin is PD7 ; (last bit of PORTD). lds r19, 0x0100 ; 2 cycles out PORTD, r19 ; 1 cycle ; Shift the byte to the left to show another bit (do it 7 times) rol r19 ; 1 cycle out PORTD, r19 ; 1 cycle nop ; 1 cycle rol r19 ; 1 cycle out PORTD, r19 ; 1 cycle nop ; 1 cycle rol r19 ; 1 cycle out PORTD, r19 ; 1 cycle nop ; 1 cycle rol r19 ; 1 cycle out PORTD, r19 ; 1 cycle nop ; 1 cycle rol r19 ; 1 cycle out PORTD, r19 ; 1 cycle nop ; 1 cycle rol r19 ; 1 cycle out PORTD, r19 ; 1 cycle nop ; 1 cycle dec r18 ; 1 cycle brne l_sync_video_loop ; 2 cycles if jumps (1 if continues) ; end line pixels cbi PORTD, VIDEO_PIN ; video pin goes low before sync dec r17 ; decrement line countr brne h_picture_loop ; if not 0, repeat h_picture_loop dec r16 ; decrement outside counter brne h_picture_outer_loop ; if not 0, repeat h_picture_loop ; end picture lines ; start 6 short sync pulses call short_sync call short_sync call short_sync call short_sync call short_sync call short_sync ; end 6 short sync pulses ; debug sbi PORTC, DEBUG_PIN ; high cbi PORTC, DEBUG_PIN ; low ; debug jmp v_refresh_loop ; end vertical refresh long_sync: ; long sync: 30uS low (719 cycles @ 24Mhz), 2uS high (48 cycles @ 24Mhz) cbi PORTC, SYNC_PIN ; sync goes low (0v) ; 2 cycle ldi r18, 120 ; 1 cycle long_sync_low_loop: ; requires 6 cpu cycles nop ; 1 cycle nop ; 1 cycle nop ; 1 cycle dec r18 ; 1 cycle brne long_sync_low_loop ; 2 cycle if true, 1 if false sbi PORTC, SYNC_PIN ; sync goes high (0.3v) ldi r18, 15 ; 1 cycle long_sync_high_loop: ; requires 3 cpu cycles dec r18 ; 1 cycle brne long_sync_high_loop ; 2 cycle if true, 1 if false ret short_sync: ; short sync: 2uS low (48 cycles @ 24Mhz), 30uS high (720 cycles @ 24Mhz) cbi PORTC, SYNC_PIN ; sync goes low (0v) ; 2 cycle ldi r18, 15 ; 1 cycle short_sync_low_loop: ; requires 3 cpu cycles dec r18 ; 1 cycle brne short_sync_low_loop ; 2 cycle if true, 1 if false sbi PORTC, SYNC_PIN ; sync goes high (0.3v) ldi r18, 120 ; 1 cycle short_sync_high_loop: ; requires 6 cpu cycles nop ; 1 cycle nop ; 1 cycle nop ; 1 cycle dec r18 ; 1 cycle brne short_sync_high_loop ; 2 cycle if true, 1 if false ret line_sync: ; line sync & front porch ; start line sync: 4uS, 96 cycles @ 24Mhz cbi PORTC, SYNC_PIN ; sync goes low (0v) ; 2 cycle ldi r18, 32 ; 1 cycle l_sync_pulse_loop: ; requires 3 cpu cycles dec r18 ; 1 cycle brne l_sync_pulse_loop ; 2 cycle if true, 1 if false sbi PORTC, SYNC_PIN ; sync goes high (0.3v) ; end line sync ; start back porch: 8uS, 192 cycles @ 24Mhz ldi r18, 64 ; 1 cycle l_sync_back_porch_loop: dec r18 ; 1 cycle brne l_sync_back_porch_loop ; 2 cycle if true, 1 if false ; end back porch ret