4-bit Grayscale TV Image Overlay

┌───────────────────────────────────────┐
│   4-bit Grayscale TV Image Overlay    │
│         Author: Phil Pilgrim          │
│(c) Copyright 2006 Bueno Systems, Inc. │
│   See end of file for terms of use.   │
└───────────────────────────────────────┘

This object provides a 4-bit (16-level) grayscale image field, overlain on a standard
NTSC video signal.

Revision History

2006.08.08: v0.02 Alpha release.
2013.09.26: v1.0  Initial release.  

Contact Information

Phil Pilgrim: propeller@phipi.com

Introduction

This module provides the capability to display grayscale images with the Propeller. These images are 4-bits deep, yielding 16 levels of gray. They are overlain onto, and receive synchronizaiton from, an extant video signal, such as that provided by tv.spin. In order to display grayscale information, one minor hardware mod is necessary: a 330pF capacitor from the video out pin (center pin on RCA connector) to ground. This will filter out the duty mode noise from the counter used to generate the gray-level signals, without killing the chroma signal.

External Connections

In addition to the standard Propeller NTSC output, the following connections and components are required. These are already provided by the Parallax Propeller Backpack (#28327).
                                    430R
  Graylevel (DUTY-mode) output pin ───┐
  Propeller-generated video signal ─────╋─────── Video out.
                                        330pF
                                         

Instance Variables


SOURCE CODE...
  byte  gray_cog 


Public Spin Methods


start(basepin, graypin, gray_buffer_addr, left, top, scale, sync_addr)

Start the graylevel overlay. Uses one additional cog.

Parameters:
basepin: TV.spin's base pin for video output.
graypin: Graylevel output pin.
gray_buffer_addr: the address of a long-aligned array, whose first word contains
the height of the gray overlay in display lines, and whose second word contains
the width of the gray overlay in pixels. The width must be an integer multiple
of eight. The remaining width * height / 8 longs contain the grayscale information,
packed eight 4-bit values per long in little endian order, top-to-bottom, left-to-right.
left: the number of processor clocks from the left of the screen to begin displaying
the overlay.
top: the number of lines from the top of the screen to begin displaying the overlay.
scale: 1 for a normal-sized overlay; 2 for a line- and pixel-doubled (2x size) overlay.
sync_addr: the address of a byte variable where vertical sync information from the
overlay generator is written. It can be used by the PropCAM object for synchronizing
image capture to the display to reduce flicker from the capture.

Return: true on success; false on failure.

Example: success := ovl.start(12, 15, @gray_buf, 200, 30, 1, @sync)

Start the overlay using P12 as the video base address, P15 as the graylevel output pin, gray_buf array as the graylevel buffer. Begin the graylevel display on video line 30, 200 clocks from the left edge and display at normal (1x) size. Write syncing info to sync.

SOURCE CODE...
PUB start(basepin, graypin, gray_buffer_addr, left, top, scale, sync_addr)

  stop
  dira0 := 1 << graypin
  ctra0 := %0110 << 26 | graypin
  vidmask := %0111 << basepin
  buf_addr := gray_buffer_addr + 4
  pix_scale := scale #> 1 <# 2
  clks_per_pix := 12 * pix_scale
  left_margin := left + 1000
  top_line := top + 22
  width := word[gray_buffer_addr][1] >> 3 <# 22 <# (3700 - left) / (clks_per_pix << 3)
  skip := (word[gray_buffer_addr][1] >> 3 - width) << 2
  height := word[gray_buffer_addr] * pix_scale <# 224 - top
  at_sync := sync_addr

  if width > 0 and height > 0
    return (gray_cog := cognew(@entry, 0) + 1) > 0
  else
    return false                                                      


stop

Stop the graylevel overlay.

Return: none.
Example: ovl.stop
Stop a running graylevel overlay.

SOURCE CODE...
PUB stop

  if gray_cog
    cogstop(gray_cog - 1)
    gray_cog~


PASM Code/Class Variables


SOURCE CODE...
              org       0
entry         mov       block_cnt,#0            'Begin creating the disp_line subroutine. Instruction count := 0.
              movd      :wr_code,#disp_line     'Point code-writer to first instruction.
              mov       nsyncs,width            'Total instruction count := width * 16 + 3
              shl       nsyncs,#4
              add       nsyncs,#3

:code_lp      cmp       nsyncs,#3 wz            'Third instruction from the end?
        if_z  mov       block,disp_wait         '  Yes: It's a "waitcnt time,clks_per_pix".
        if_z  jmp       #:wr_code

              cmp       nsyncs,#2 wz            'Second instruction from the end?
        if_z  mov       block,disp_zero         '  Yes: It's a "mov frqa,#0"
        if_z  jmp       #:wr_code

              cmp       nsyncs,#1 wz            'Last instruction?
        if_z  mov       block,disp_ret          '  Yes: It's a "ret".
        if_z  jmp       #:wr_code

              test      block_cnt,#1 wz         'Even-numbered instruction?
        if_z  mov       block,disp_wait         '  Yes: Insert a "waitcnt time,clks_per_pix"
        if_z  jmp       #:wr_code
                      
              test      block_cnt,#$0E wz       '  No:  First pixel in an 8-pixel block?
        if_z  mov       block,disp_mov          '         Yes: Insert a "mov frqa,line_buf+n".
        if_z  add       disp_mov,#1             '              Increment n.
        if_nz mov       block,disp_ror          '         No:  Insert a "ror frqa".
        
:wr_code      mov       0-0,block               'Write the instruction into the subroutine.
              add       block_cnt,#1            'Increment the instruction count.
              add       :wr_code,_0x200         'Increment the instruction pointer.
              djnz      nsyncs,#:code_lp         'Loop back until done.

              shl       block_cnt,#9            'Make sure the jmpret pointer to the "ret" actually points there.
              add       :do_line,block_cnt
              
              mov       dira,dira0
              mov       frqa,#0
              mov       ctra,ctra0

:vsyncs       mov       nsyncs,#6
:vsync        call      #sync
              mov       time,half_sync
              call      #delay
              test      vidmask,ina wz
        if_nz jmp       #:vsyncs
              djnz      nsyncs,#:vsync

              xor       field,#_0xffffffff wz
              wrbyte    field,at_sync
              mov       nsyncs,top_line
              
:vblank       call      #sync
              djnz      nsyncs,#:vblank

              mov       buf_ptr,buf_addr
              mov       nsyncs,height
              mov       mult,#0

:hsync        call      #sync
              mov       time,left_margin
              add       time,cnt

              tjnz      mult,#:got_block

              mov       block_cnt,width
              movd      :mov_block,#line_buf

:rd_block     rdlong    block,buf_ptr
              ror       block,#4
:mov_block    mov       0-0,block
              add       buf_ptr,#4
              add       :mov_block,_0x200
              djnz      block_cnt,#:rd_block
              
              add       buf_ptr,skip

:got_block    
:do_line      jmpret    disp_line-1,#disp_line
              
              add       mult,#1
              cmpsub    mult,pix_scale

              djnz      nsyncs,#:hsync
              
              jmp       #:vsyncs

sync          waitpne   zero,vidmask
              waitpeq   zero,vidmask
              test      vidmask,ina wz
        if_nz jmp       #sync
              test      vidmask,ina wz
        if_nz jmp       #sync
                      
sync_ret      ret

delay         add       time,cnt
              waitcnt   time,#0
delay_ret     ret

disp_wait     waitcnt   time,clks_per_pix
disp_mov      mov       frqa,line_buf
disp_ror      ror       frqa,#4
disp_zero     mov       frqa,#0              
disp_ret      ret

zero          long      0
_0x200        long      $200
_0xffffffff   long      $ffff_ffff

frqa0         long      $0000_0000
half_sync     long      1200

dira0         long      0-0
ctra0         long      0-0
vidmask       long      0-0
buf_addr      long      0-0
width         long      0-0
skip          long      0-0
height        long      0-0
left_margin   long      0-0
top_line      long      0-0
pix_scale     long      0-0
clks_per_pix  long      0-0
at_sync       long      0-0
field         long      0
line_buf      long      0[22]

time          res       1
nsyncs        res       1
buf_ptr       res       1
block_cnt     res       1
block         res       1
mult          res       1

disp_line     res       355


License

┌──────────────────────────────────────────────────────────────────────────────────────┐
│                            TERMS OF USE: MIT License                                 │                                                            
├──────────────────────────────────────────────────────────────────────────────────────┤
│Permission is hereby granted, free of charge, to any person obtaining a copy of this  │
│software and associated documentation files (the "Software"), to deal in the Software │
│without restriction, including without limitation the rights to use, copy, modify,    │
│merge, publish, distribute, sublicense, and/or sell copies of the Software, and to    │
│permit persons to whom the Software is furnished to do so, subject to the following   │
│conditions:                                                                           │
│                                                                                      │
│The above copyright notice and this permission notice shall be included in all copies │
│or substantial portions of the Software.                                              │
│                                                                                      │
│THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,   │
│INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A         │
│PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT    │
│HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF  │
│CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE  │
│OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                                         │
└──────────────────────────────────────────────────────────────────────────────────────┘