Full Version : Robson's PAL Video Generation from 4Mhz (ASM)
avr >>GAME & VIDEO PROJECTS >>Robson's PAL Video Generation from 4Mhz (ASM)


Admin5- 04-19-2006

Video.zip Video (PAL) geneation using a 4Mhz part Any AVR Paul Robson

This is the main routine that generates the video signals and can be added to your programs

CODE

;
****************************************************************************
;
****************************************************************************
;
;       File :          Video.Asm
;
;       Description :   4Mhz 3-Resistor SCART Video Code
;
;       Author :        Paul Robson, based on the original 16Mhz version
;                       by Alberto Riccibitti
;
;       Date :          2nd September 1999
;
;       Notes :         This is a PAL Version
;
;
****************************************************************************
;
****************************************************************************


       .def    Tmp1 =          r30    ; Temp variables used by
interrupt
       .def    Tmp2 =          r31    ; (preserved by the interrupt
routine)

       .equ    CSyncBit =      4      ; Composite Sync Level pin
       .equ    VideoBit =      7      ; Video Level pin

       .equ    CSyncPort =     PORTB  ; Ports on which these pins are
placed
       .equ    VideoPort =     PORTD

       .equ    StartRetrace = (312/4)-1; counter value at wich retrace
starts
       .equ    StopRetrace = (312/4)  ; maximum counter value

       .equ    FirstLine   = 48       ; first visible line
       .equ    LastLine    = 48+128   ; line AFTER last line.

;
****************************************************************************
;
;       Set up the MCU to run the video. Needs an SEI to make it go :)
;
;
****************************************************************************

VideoEnable:
       ldi     Tmp1, $FF              ; Set port B & D bits to outputs
       out     DDRD, Tmp1
       out     DDRB, Tmp1

       sbi     CSyncPort,CSyncBit     ; Set sync on, video off
       cbi     VideoPort,VideoBit

       ldi     Tmp1, 1                ; Don't use timer prescaler
       out     TCCR0, Tmp1            ; (e.g. IRQ at Clock/256)
       ldi     Tmp1, 32               ; Enable sleep idle mode
       out     MCUCR, Tmp1
       ldi     Tmp1, 2                ; Enable timer interrupt
       out     TIMSK, Tmp1
       ret


;****************************************************************************
;
;       The video timer routine, called once every 256 cycles.
;         4,000,000 / 256 = 15,625 Hz (Line Sync Frequency)
;
;       The MCU is available from lines 0-60 and 192-312 (180 lines)
;       the interrupt routine takes about 35 cycles, so the % hit to
;       the MCU is (180/312) * (1-(35/256)) i.e. about 50%.
;
;       In each frame for execution there are 180 * 220 cycles
;       i.e. about 40,000 cycles available, and in that time we
;       need to do 17-18 CHIP8 instructions, about 2,000 each :)
;
;       The idea and original code was written by Alberto Riccibitti,
;       for a 16Mhz 1200. This is fundamentally identical except it
;       has been slowed down to 4Mhz, and (of course) the start-of-sync
;       code is completely changed, as is the video generation bit
;       (because I don't wanna draw a voltmeter). Thanks Alberto !
;
;       If you want a pixel display this can be 64 x however much RAM
;       you can spare.
;

;****************************************************************************

VideoTimerRoutine:
       in      SaveStatus,SREG        ; save Status
       push    Tmp1                   ; save work registers
       push    Tmp2
       rjmp    Newline                ; do a new line

Timer_Exit:
       cbi     VideoPort,VideoBit     ; make sure video is off
       pop     Tmp2                   ; restore registers
       pop     Tmp1
       out     SREG, SaveStatus       ; restore status and exit
   reti

Newline:
       in      Tmp1, CSyncPort        ; Read previous CSync level
       ldi     Tmp2, 1 << CSyncBit    ; Load mask for toggle csync bit
       eor     Tmp1, Tmp2             ; Toggle CSync output
       out     CSyncPort, Tmp1        ; the horizontal sync pulse
beginneth
                                      ; for it lasteth 16 cycles,
counting..

       inc     RowsModFour            ; Increment row counters
[1]
       cpi     RowsModFour, 4         ; If RowsModFour == 4
[2]
       brne    _1                     ;
[3]
       inc     RowsDivFour            ; Then increment RowsDivFour
[4]
_1:     andi    RowsModFour, 3         ; (range 0..3)
[5]
      ;
      ;    At the last line the sync pulse is stretched to half a line
      ;
       cpi     RowsDivFour, StopRetrace; If at last line
[6]
       brsh    EndLine                ; Sync pulse stops at 1/2 line
[7]

       nop                            ; To make it a 4us pulse
[8]
       ldi     Tmp2, 1 << CSyncBit    ; Get mask for csync toggle
[9]

       ldi     Tmp1, StartRetrace     ; Check if start of vertical
[10]
       cpi     RowsModFour, 0         ; retrace pulse
[11]
       cpc     RowsDivFour, Tmp1      ;
[12]
       brne    HSyncEnd               ; if so leave CSync low
[13]
       ldi     Tmp2, 0                ;
[14]
HSyncEnd:
       in      Tmp1, CSyncPort        ;
[15]
       eor     Tmp1, Tmp2             ; Toggle CSync output
[16]
       out     CSyncPort, Tmp1
                                      ; In the color burst space
                                      ; actually got a bit of spare
time

       cpi     RowsDivFour, LastLine/4; Exit now if not on the
displayable
       brsh    Timer_Exit             ; part of the screen
       cpi     RowsDivFour, FirstLine/4-1
       brlo    Timer_Exit
       breq    DoScreen

       rjmp    BuildScreen            ; Go to display building section

;
****************************************************************************
;  Called 4 lines before the display start. If it is selected, it puts
the
;  MCU in a "sleep loop" until the display generation has finished, so
;  that multi cycle instructions don't make the screen wobble.
;
****************************************************************************

DoScreen:
       or      RowsModFour,RowsModFour; check actual first line
       brne    Timer_Exit             ; if not, it is blank.

       push    SaveStatus             ; save the status register
       sei                            ; have a little loop and a
reentrant
                                      ; interrupt

DoLine: sleep                          ; wait for interrupt
       cpi     RowsDivFour,LastLine/4 ; wait for the screen to end
       brlo    DoLine                 ; while <= last line
       breq    DoLine

       cli                            ; int off again
       pop     SaveStatus             ; restore status register
       rjmp    Timer_Exit             ; and continue as if nothing
happened

;
****************************************************************************
;       The last (e.g. 312th line), extend the pulse for half a line
;
****************************************************************************

EndLine:
      ; this is a good time to make slow (1/50 sec.) housekeepings,
      ; or to do things that are made once every screen picture (frame
!)

       clr     RowsDivFour            ; Reset row counters
       clr     RowsModFour

WaitMidline:                           ; Wait for Half-Line position
       in      Tmp1, TCNT0
       cpi     Tmp1, 128
       brlo    WaitMidline

       sbi     CSyncPort, CSyncBit    ; and end composite sync
       rjmp    Timer_Exit

;
****************************************************************************
;       Output the video data to the video port. Assumes port pin is #7
;
****************************************************************************

.MACRO  Bit8
       out     VideoPort,@0           ; yes I know its crap. But this
way
       add     @0,@0                  ; I can shift bits out every 2
cycles
       out     VideoPort,@0           ; and that gives me enough time
to
       add     @0,@0                  ; get 64 bit horizontal
resolution.
       out     VideoPort,@0           ; Any other method will reduce
the
       add     @0,@0                  ; resolution *OR* make the pixels
       out     VideoPort,@0           ; uneven.
       add     @0,@0
       out     VideoPort,@0
       add     @0,@0
       out     VideoPort,@0
       add     @0,@0
       out     VideoPort,@0
       add     @0,@0
       out     VideoPort,@0
       add     @0,@0
.ENDMACRO

;
****************************************************************************
;                         Preamble (in Colour Burst)
;
****************************************************************************

BuildScreen:
       push    XL                     ; A part of the screen actually
       push    XH                     ; with graphics on it.
       push    r1                     ; We save all the relevant
registers
       push    r2                     ; on the stack and set up for a
       push    r3                     ; bit stream to the VideoBit pin
       push    r4                     ; We need all these registers
because
       push    r5                     ; the ADD x,x;OUT PORT x sequence
takes
       push    r6                     ; 2 cycles; no room for a LD
r,X+
       push    r7
       push    r8

       mov     XL,RowsDivFour         ; XL is SL/4 -> (SL+128)/4
       subi    XL,FirstLine/4         ; XL in range 0..31
       add     XL,XL                  ; Make XL 0..248 (lower 3 bits
zero)
       add     XL,XL                  ; which means it points to the
start
       add     XL,XL                  ; of a line.

       ldi     XH,$01                 ; XHXL points to Video RAM

       ld      r1,X+                  ; Load display data into r1-r8
       ld      r2,X+                  ; Boring typing, folks.
       ld      r3,X+
       ld      r4,X+
       ld      r5,X+
       ld      r6,X+
       ld      r7,X+
       ld      r8,X+

;
****************************************************************************
;          Wait for horizontal position, then generate video
;
****************************************************************************

WaitVisiblePortion:
       in      Tmp1, TCNT0            ; wait for start of visible area
       cpi     Tmp1, 74               ; decreasing this moves display
left
       brlo    WaitVisiblePortion     ; not much spare time....

       Bit8    r1                     ; Bang em out.... 128 words down
       Bit8    r2                     ; the pan. Gimme that 8Mhz
Crystal.
       Bit8    r3
       Bit8    r4                     ; Actually its the fault of
b****y
       Bit8    r5                     ; Maplins in Norwich who didn't
stock
       Bit8    r6                     ; it. Mind you, they looked
baffled
       Bit8    r7                     ; when I asked for a 90S1200...
wassat ?
       Bit8    r8                     ; ignorant or what ?

       out     VideoPort,r8           ; This forces the video to zero,
if
                                      ; it is '1' in HSYNC we get a
mess
                                      ; I know this from bitter
experience

;
****************************************************************************
;                             Post video generation
;
****************************************************************************

       pop     r8                     ; yet more boring typin' but
there's
       pop     r7                     ; no alternative in reality.
       pop     r6
       pop     r5
       pop     r4
       pop     r3
       pop     r2
       pop     r1
       pop     XH
       pop     XL
       rjmp    Timer_Exit             ; go do something else.






Forumer™ is Voted #1 Free Forum Hosting provider
Build your own community today with the largest message board hosting company.