| 151 | kaklik | 1 | ;
 | 
        
           |  |  | 2 | ;    Copyright (C) 2004    John Orlando
 | 
        
           |  |  | 3 | ;    
 | 
        
           |  |  | 4 | ;   AVRcam: a small real-time image processing engine.
 | 
        
           |  |  | 5 |   | 
        
           |  |  | 6 | ;    This program is free software; you can redistribute it and/or
 | 
        
           |  |  | 7 | ;    modify it under the terms of the GNU General Public
 | 
        
           |  |  | 8 | ;    License as published by the Free Software Foundation; either
 | 
        
           |  |  | 9 | ;    version 2 of the License, or (at your option) any later version.
 | 
        
           |  |  | 10 |   | 
        
           |  |  | 11 | ;    This program is distributed in the hope that it will be useful,
 | 
        
           |  |  | 12 | ;    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
        
           |  |  | 13 | ;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
        
           |  |  | 14 | ;    General Public License for more details.
 | 
        
           |  |  | 15 |   | 
        
           |  |  | 16 | ;    You should have received a copy of the GNU General Public
 | 
        
           |  |  | 17 | ;    License along with this program; if not, write to the Free Software
 | 
        
           |  |  | 18 | ;    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
        
           |  |  | 19 |   | 
        
           |  |  | 20 | ;   For more information on the AVRcam, please contact:
 | 
        
           |  |  | 21 |   | 
        
           |  |  | 22 | ;   john@jrobot.net
 | 
        
           |  |  | 23 |   | 
        
           |  |  | 24 | ;   or go to www.jrobot.net for more details regarding the system.
 | 
        
           |  |  | 25 | ;**********************************************************************
 | 
        
           |  |  | 26 | ;       Module Name: CanInterfaceAsm.S
 | 
        
           |  |  | 27 | ;       Module Date: 04/14/2004
 | 
        
           |  |  | 28 | ;       Module Auth: John Orlando
 | 
        
           |  |  | 29 | ;
 | 
        
           |  |  | 30 | ;       Description: This module provides the low-level interface
 | 
        
           |  |  | 31 | ;       to the OV6620 camera hardware.  It is responsible for
 | 
        
           |  |  | 32 | ;   	acquiring each pixel block (R,G,B), performing the mapping
 | 
        
           |  |  | 33 | ;       into an actual color (orange, purple, etc), run-length
 | 
        
           |  |  | 34 | ;       encoding the data, and storing the info off to the appropriate
 | 
        
           |  |  | 35 | ;       line buffer.  This routine is synchronized with the pixel data
 | 
        
           |  |  | 36 | ;       so that no polling of the camera data needs to be done (the
 | 
        
           |  |  | 37 | ;       OV6620 is clocked off of the same crystal source as the mega8,
 | 
        
           |  |  | 38 | ;       thus providing inherent synchronization between the two).
 | 
        
           |  |  | 39 | ;
 | 
        
           |  |  | 40 | ;       Revision History:
 | 
        
           |  |  | 41 | ;       Date        Rel Ver.    Notes
 | 
        
           |  |  | 42 | ;       4/10/2004      0.1     Module created
 | 
        
           |  |  | 43 | ;       6/30/2004      1.0     Initial release for Circuit Cellar
 | 
        
           |  |  | 44 | ;                              contest.
 | 
        
           |  |  | 45 | ;       1/16/2005      1.4     Fixed issue with the TCCR1B register
 | 
        
           |  |  | 46 | ;                              where PCLK was getting routed to the
 | 
        
           |  |  | 47 | ;                              timer1 even when it wasn't needed.
 | 
        
           |  |  | 48 | ;                              This caused excessive counter overflow
 | 
        
           |  |  | 49 | ;                              interrupts, and caused problems.  Now,
 | 
        
           |  |  | 50 | ;                              the "PCLK" pipe feeds timer1 when needed,
 | 
        
           |  |  | 51 | ;                              and is turned off when it isn't needed.
 | 
        
           |  |  | 52 |   | 
        
           |  |  | 53 | #include <avr/io.h>
 | 
        
           |  |  | 54 | #include "Events.h"
 | 
        
           |  |  | 55 |   | 
        
           |  |  | 56 | 		.extern fastEventBitmask    ; This is the flag used to indicate to the rest
 | 
        
           |  |  | 57 | 									; of the system that the line is complete
 | 
        
           |  |  | 58 |   | 
        
           |  |  | 59 | #define HREF_INTERRUPT_ENABLE_MASK   0x80
 | 
        
           |  |  | 60 | #define HREF_INTERRUPT_DISABLE_MASK  0x7F
 | 
        
           |  |  | 61 | #define ENABLE_PCLK_TIMER1_OVERFLOW_BITMASK  0x04
 | 
        
           |  |  | 62 | #define DISABLE_PCLK_TIMER1_OVERFLOW_BITMASK 0xFB
 | 
        
           |  |  | 63 | #define G_PORT						_SFR_IO_ADDR(PINC)  
 | 
        
           |  |  | 64 | #define RB_PORT						_SFR_IO_ADDR(PINB)  
 | 
        
           |  |  | 65 | #define PIXEL_RUN_START_INITIAL     0x50     	; This value causes our pixel counter (TCNT1)
 | 
        
           |  |  | 66 | 												; to overflow after 176 (horizontal) pixels
 | 
        
           |  |  | 67 |   | 
        
           |  |  | 68 | #define RED_MEM_OFFSET				0x00
 | 
        
           |  |  | 69 | #define GREEN_MEM_OFFSET			0x10
 | 
        
           |  |  | 70 | #define BLUE_MEM_OFFSET				0x20
 | 
        
           |  |  | 71 |   | 
        
           |  |  | 72 | ; A pixelBlock is defined as a contiguous group of 4 pixels that are combined 
 | 
        
           |  |  | 73 | ; together to form a specific color.  Typically, this is formed by sampling a
 | 
        
           |  |  | 74 | ; a green value, followed by a red and blue value (since we are dealing
 | 
        
           |  |  | 75 | ; with Bayer color data).  We could optionally sample a second green with
 | 
        
           |  |  | 76 | ; the red and average the greens, because the eye is more sensitive to
 | 
        
           |  |  | 77 | ; green, but for speed we don't do this.  These three values (RGB) are then
 | 
        
           |  |  | 78 | ; used as indices into the color membership lookup table (memLookup) to
 | 
        
           |  |  | 79 | ; determine which color the pixelBlock maps into.  The memLookup table is
 | 
        
           |  |  | 80 | ; manually generated for now (though it will hopefully be modified over
 | 
        
           |  |  | 81 | ; the serial interface eventually).
 | 
        
           |  |  | 82 | ;
 | 
        
           |  |  | 83 | ; Here is a pixel block:
 | 
        
           |  |  | 84 | ; ...G  G  G  G...  (row x)
 | 
        
           |  |  | 85 | ; ...B  R  B  R...  (row x+1)
 | 
        
           |  |  | 86 | ;    |  |  |  |--this is skipped 
 | 
        
           |  |  | 87 | ;    |  |  |--this is skipped
 | 
        
           |  |  | 88 | ;    |  |--this is sampled
 | 
        
           |  |  | 89 | ;    |--this is sampled
 | 
        
           |  |  | 90 |   | 
        
           |  |  | 91 | ; As pixel blocks are sampled, the red, green, and blue values are
 | 
        
           |  |  | 92 | ; used to index into their respective color maps.  The color maps
 | 
        
           |  |  | 93 | ; return values that can be logically ANDed together so that a 
 | 
        
           |  |  | 94 | ; particular RGB triplet will result in a single bit being set
 | 
        
           |  |  | 95 | ; after the AND operation.  This single bit indicates which color
 | 
        
           |  |  | 96 | ; the RGB triplet represents.  It is also possible for no bits to
 | 
        
           |  |  | 97 | ; be set after the AND process, indicating that the RGB triplet
 | 
        
           |  |  | 98 | ; does not map to any of the colors configured in the color map.
 | 
        
           |  |  | 99 | ; This isn't quite as fast as a pure RGB lookup table, but
 | 
        
           |  |  | 100 | ; it then again it doesn't require 2^12 (4-bits for each color
 | 
        
           |  |  | 101 | ; channel) bytes to store the lookup table.  It takes just a few
 | 
        
           |  |  | 102 | ; more cycles, and only requires 48 bytes of precious RAM (16
 | 
        
           |  |  | 103 | ; per color channel, since our resolution on each color channel
 | 
        
           |  |  | 104 | ; is only 4-bits).  Not bad....for more information, see:
 | 
        
           |  |  | 105 | ; http://www.cs.cmu.edu/~trb/papers/wirevision00.pdf for more
 | 
        
           |  |  | 106 | ; information on this color segmentation technique.
 | 
        
           |  |  | 107 |   | 
        
           |  |  | 108 | ; One other note: this code does depend on the colorMap residing
 | 
        
           |  |  | 109 | ; at a well-defined position in memory; specifically, it mus
 | 
        
           |  |  | 110 | ; start at a 256-byte boundary so that the lowest byte in the
 | 
        
           |  |  | 111 | ; map is set to 0x00.  Currently, the colorMap is forced to
 | 
        
           |  |  | 112 | ; start at RAM location 0x300.  This could potentially be changed
 | 
        
           |  |  | 113 | ; by the developer if needed, but offsets would have to be added
 | 
        
           |  |  | 114 | ; in to the colorMap look-up code below to make it work.
 | 
        
           |  |  | 115 |   | 
        
           |  |  | 116 |   | 
        
           |  |  | 117 | ; These are the registers that will be used throughout this
 | 
        
           |  |  | 118 | ; module for acquiring each line of pixel data
 | 
        
           |  |  | 119 | pixelCount			= 16
 | 
        
           |  |  | 120 | pixelRunStart		= 17
 | 
        
           |  |  | 121 | lastColor     		= 18
 | 
        
           |  |  | 122 | tmp1				= 19	; be sure to not use tmp1 and color simultaneously
 | 
        
           |  |  | 123 | tmp2				= 20
 | 
        
           |  |  | 124 | color           	= 19
 | 
        
           |  |  | 125 | greenData       	= 20
 | 
        
           |  |  | 126 | blueData        	= 21
 | 
        
           |  |  | 127 | colorMapLow	  		= 22
 | 
        
           |  |  | 128 | colorMapHigh		= 23
 | 
        
           |  |  | 129 | prevLineBuffLow  	= 22  	; overlaps with memLookupLow (but orthogonal)
 | 
        
           |  |  | 130 | prevLineBuffHigh	= 23	; overlaps with memLookupHigh (but orthogonal)
 | 
        
           |  |  | 131 | currLineBuffLow     = 24
 | 
        
           |  |  | 132 | currLineBuffHigh  	= 25
 | 
        
           |  |  | 133 |   | 
        
           |  |  | 134 |         .section .text
 | 
        
           |  |  | 135 |   | 
        
           |  |  | 136 | ; These are the global assembly function names that are accessed via other
 | 
        
           |  |  | 137 | ; C functions
 | 
        
           |  |  | 138 |         .global CamIntAsm_waitForNewTrackingFrame
 | 
        
           |  |  | 139 | 		.global CamIntAsm_waitForNewDumpFrame
 | 
        
           |  |  | 140 | 		.global CamIntAsm_acquireDumpLine
 | 
        
           |  |  | 141 | 		.global CamIntAsm_acquireTrackingLine
 | 
        
           |  |  | 142 | 		.global SIG_INTERRUPT0
 | 
        
           |  |  | 143 | 		.global SIG_INTERRUPT1
 | 
        
           |  |  | 144 | 		.global SIG_OVERFLOW0
 | 
        
           |  |  | 145 | 		.global SIG_OVERFLOW1
 | 
        
           |  |  | 146 |   | 
        
           |  |  | 147 | ;*****************************************************************		
 | 
        
           |  |  | 148 | ;   	Function Name: CamIntAsm_waitForNewTrackingFrame
 | 
        
           |  |  | 149 | ;       Function Description: This function is responsible for
 | 
        
           |  |  | 150 | ;       going to sleep until a new frame begins (indicated by
 | 
        
           |  |  | 151 | ;    	VSYNC transitioning from low to high.  This will wake
 | 
        
           |  |  | 152 | ;       the "VSYNC sleep" up and allow it to continue with 
 | 
        
           |  |  | 153 | ;       the acquireLine function, where the system waits for
 | 
        
           |  |  | 154 | ;       an "HREF sleep" that we use to synchronize with the
 | 
        
           |  |  | 155 | ;       data.  
 | 
        
           |  |  | 156 | ;       Inputs:  r25 - MSB of currentLineBuffer
 | 
        
           |  |  | 157 | ;                r24 - LSB of currentLineBuffer
 | 
        
           |  |  | 158 | ;				 r23 - MSB of colorMap
 | 
        
           |  |  | 159 | ; 				 r22 - LSB of colorMap
 | 
        
           |  |  | 160 | ;       Outputs: none
 | 
        
           |  |  | 161 | ;       NOTES: This function doesn't really return...it sorta just
 | 
        
           |  |  | 162 | ;       floats into the acquireLine function after the "VSYNC sleep"
 | 
        
           |  |  | 163 | ;       is awoken, then begins processing the line data.  Once
 | 
        
           |  |  | 164 | ;		176 pixels are sampled (and the counter overflows), then
 | 
        
           |  |  | 165 | ;		an interrupt will occur, the 'T' bit in the SREG will be
 | 
        
           |  |  | 166 | ;		set, and the function will return.
 | 
        
           |  |  | 167 | ;*****************************************************************
 | 
        
           |  |  | 168 |   | 
        
           |  |  | 169 | CamIntAsm_waitForNewTrackingFrame:
 | 
        
           |  |  | 170 | 		sbi		_SFR_IO_ADDR(PORTD),PD6  ; For testing...
 | 
        
           |  |  | 171 | 		cbi		_SFR_IO_ADDR(PORTD),PD6		
 | 
        
           |  |  | 172 | 		sleep
 | 
        
           |  |  | 173 |   | 
        
           |  |  | 174 | ;*****************************************************************
 | 
        
           |  |  | 175 | ; REMEMBER...everything from here on out is critically timed to be
 | 
        
           |  |  | 176 | ; synchronized with the flow of pixel data from the camera...
 | 
        
           |  |  | 177 | ;*****************************************************************
 | 
        
           |  |  | 178 |   | 
        
           |  |  | 179 | CamIntAsm_acquireTrackingLine:
 | 
        
           |  |  | 180 | 		brts	_cleanUp
 | 
        
           |  |  | 181 | 		;sbi		_SFR_IO_ADDR(PORTD),PD6 ; For testing...
 | 
        
           |  |  | 182 | 		;cbi		_SFR_IO_ADDR(PORTD),PD6
 | 
        
           |  |  | 183 |   | 
        
           |  |  | 184 |         in      tmp1,_SFR_IO_ADDR(TCCR1B) ; Enable the PCLK line to actually
 | 
        
           |  |  | 185 |         ori     tmp1, 0x07                 ; feed Timer1
 | 
        
           |  |  | 186 |         out     _SFR_IO_ADDR(TCCR1B),tmp1 
 | 
        
           |  |  | 187 | 										; The line is about to start...		
 | 
        
           |  |  | 188 | 		ldi     pixelCount,0			; Initialize the RLE stats...
 | 
        
           |  |  | 189 | 		ldi		pixelRunStart,PIXEL_RUN_START_INITIAL  	; Remember, we always calculate
 | 
        
           |  |  | 190 | 														; the pixel run length as
 | 
        
           |  |  | 191 | 														; TCNT1L - pixelRunStart
 | 
        
           |  |  | 192 |   | 
        
           |  |  | 193 | 		ldi		lastColor,0x00				; clear out the last color before we start
 | 
        
           |  |  | 194 |   | 
        
           |  |  | 195 | 		mov   	XH,currLineBuffHigh    	; Load the pointer to the current line
 | 
        
           |  |  | 196 | 		mov		XL,currLineBuffLow		; buffer into the X pointer regs		 
 | 
        
           |  |  | 197 |   | 
        
           |  |  | 198 | 		mov   	ZH,colorMapHigh      	; Load the pointers to the membership
 | 
        
           |  |  | 199 | 		mov		ZL,colorMapLow			; lookup tables (ZL and YL will be overwritten
 | 
        
           |  |  | 200 | 		mov 	YH,colorMapHigh	 		; as soon as we start reading data) to Z and Y
 | 
        
           |  |  | 201 |   | 
        
           |  |  | 202 | 		in		tmp1, _SFR_IO_ADDR(TIMSK)			; enable TIMER1 to start counting
 | 
        
           |  |  | 203 | 		ori		tmp1, ENABLE_PCLK_TIMER1_OVERFLOW_BITMASK 	; external PCLK pulses and interrupt on 
 | 
        
           |  |  | 204 | 		out		_SFR_IO_ADDR(TIMSK),tmp1			; overflow
 | 
        
           |  |  | 205 |   | 
        
           |  |  | 206 | 		ldi 	tmp1,PIXEL_RUN_START_INITIAL	; set up the TCNT1 to overflow (and
 | 
        
           |  |  | 207 | 		ldi 	tmp2,0xFF 						; interrupts) after 176 pixels		
 | 
        
           |  |  | 208 | 		out 	_SFR_IO_ADDR(TCNT1H),tmp2		
 | 
        
           |  |  | 209 | 		out 	_SFR_IO_ADDR(TCNT1L),tmp1				
 | 
        
           |  |  | 210 |   | 
        
           |  |  | 211 | 		mov		YL,colorMapLow		
 | 
        
           |  |  | 212 |   | 
        
           |  |  | 213 | 		in 		tmp1, _SFR_IO_ADDR(GICR)	; enable the HREF interrupt...remember, we
 | 
        
           |  |  | 214 | 											; only use this interrupt to synchronize
 | 
        
           |  |  | 215 | 											; the beginning of the line
 | 
        
           |  |  | 216 | 		ori 	tmp1, HREF_INTERRUPT_ENABLE_MASK
 | 
        
           |  |  | 217 | 		out		_SFR_IO_ADDR(GICR), tmp1
 | 
        
           |  |  | 218 |   | 
        
           |  |  | 219 | ;*******************************************************************************************
 | 
        
           |  |  | 220 | ;   Track Frame handler 
 | 
        
           |  |  | 221 | ;*******************************************************************************************		
 | 
        
           |  |  | 222 |   | 
        
           |  |  | 223 | _trackFrame:		
 | 
        
           |  |  | 224 | 		sbi		_SFR_IO_ADDR(PORTD),PD6
 | 
        
           |  |  | 225 | 		sleep   ; ...And we wait...
 | 
        
           |  |  | 226 |   | 
        
           |  |  | 227 | 	; Returning from the interrupt/sleep wakeup will consume
 | 
        
           |  |  | 228 | 	; 14 clock cycles (7 to wakeup from idle sleep, 3 to vector, and 4 to return)	
 | 
        
           |  |  | 229 |   | 
        
           |  |  | 230 | 	; Disable the HREF interrupt
 | 
        
           |  |  | 231 | 		cbi		_SFR_IO_ADDR(PORTD),PD6
 | 
        
           |  |  | 232 | 		in 		tmp1, _SFR_IO_ADDR(GICR)
 | 
        
           |  |  | 233 | 		andi 	tmp1, HREF_INTERRUPT_DISABLE_MASK
 | 
        
           |  |  | 234 | 		out		_SFR_IO_ADDR(GICR), tmp1
 | 
        
           |  |  | 235 |   | 
        
           |  |  | 236 | 	; A couple of NOPs are needed here to sync up the pixel data...the number (2)
 | 
        
           |  |  | 237 | 	; of NOPs was determined emperically by trial and error.
 | 
        
           |  |  | 238 | 		nop
 | 
        
           |  |  | 239 | 		nop
 | 
        
           |  |  | 240 | _acquirePixelBlock:							;							Clock Cycle Count
 | 
        
           |  |  | 241 | 		in		ZL,RB_PORT         			; sample the red value (PINB)		(1)
 | 
        
           |  |  | 242 | 		in		YL,G_PORT         			; sample the green value (PINC)		(1)
 | 
        
           |  |  | 243 | 		andi	YL,0x0F            			; clear the high nibble				(1)
 | 
        
           |  |  | 244 | 		ldd		color,Z+RED_MEM_OFFSET  	; lookup the red membership			(2)
 | 
        
           |  |  | 245 | 		in		ZL,RB_PORT         			; sample the blue value (PINB)		(1)
 | 
        
           |  |  | 246 | 		ldd		greenData,Y+GREEN_MEM_OFFSET; lookup the green membership		(2)
 | 
        
           |  |  | 247 | 		ldd		blueData,Z+BLUE_MEM_OFFSET	; lookup the blue membership		(2)
 | 
        
           |  |  | 248 | 		and		color,greenData 			; mask memberships together			(1)
 | 
        
           |  |  | 249 | 		and		color,blueData  			; to produce the final color		(1)
 | 
        
           |  |  | 250 | 		brts    _cleanUpTrackingLine		; if some interrupt routine has		(1...not set)
 | 
        
           |  |  | 251 | 											; come in and set our T flag in 
 | 
        
           |  |  | 252 | 											; SREG, then we need to hop out
 | 
        
           |  |  | 253 | 											; and blow away this frames data (common cleanup)									
 | 
        
           |  |  | 254 | 		cp		color,lastColor     		; check to see if the run continues	(1)
 | 
        
           |  |  | 255 | 		breq    _acquirePixelBlock  		;									(2...equal)
 | 
        
           |  |  | 256 | 											;									___________
 | 
        
           |  |  | 257 | 											;								16 clock cycles 		
 | 
        
           |  |  | 258 | 											; (16 clock cycles = 1 uS = 1 pixelBlock time)
 | 
        
           |  |  | 259 |   | 
        
           |  |  | 260 | 		; Toggle the debug line to indicate a color change
 | 
        
           |  |  | 261 | 		sbi     _SFR_IO_ADDR(PORTD),PD6
 | 
        
           |  |  | 262 | 		nop
 | 
        
           |  |  | 263 | 		cbi		_SFR_IO_ADDR(PORTD),PD6
 | 
        
           |  |  | 264 |   | 
        
           |  |  | 265 | 		mov		tmp2,pixelRunStart				; get the count value of the
 | 
        
           |  |  | 266 | 												; current pixel run
 | 
        
           |  |  | 267 | 		in		pixelCount,_SFR_IO_ADDR(TCNT1L)	; get the current TCNT1 value 
 | 
        
           |  |  | 268 | 		mov   	pixelRunStart,pixelCount		; reload pixelRunStart for the
 | 
        
           |  |  | 269 | 												; next run
 | 
        
           |  |  | 270 | 		sub		pixelCount,tmp2     			; pixelCount = TCNT1L - pixelRunStart
 | 
        
           |  |  | 271 |   | 
        
           |  |  | 272 | 		st		X+,lastColor			; record the color run in the current line buffer
 | 
        
           |  |  | 273 | 		st		X+,pixelCount			; with its length
 | 
        
           |  |  | 274 | 		mov		lastColor,color			; set lastColor so we can figure out when it changes
 | 
        
           |  |  | 275 |   | 
        
           |  |  | 276 | 		nop								; waste one more cycle for a total of 16
 | 
        
           |  |  | 277 | 		rjmp	_acquirePixelBlock	
 | 
        
           |  |  | 278 |   | 
        
           |  |  | 279 | ; _cleanUpTrackingLine is used to write the last run length block off to the currentLineBuffer so
 | 
        
           |  |  | 280 | ; that all 176 pixels in the line are accounted for.
 | 
        
           |  |  | 281 | _cleanUpTrackingLine:		
 | 
        
           |  |  | 282 | 		ldi		pixelCount,0xFF		; the length of the last run is ALWAYS 0xFF minus the last
 | 
        
           |  |  | 283 | 		sub		pixelCount,pixelRunStart  	; pixelRunStart
 | 
        
           |  |  | 284 |   | 
        
           |  |  | 285 | 		inc		pixelCount				; increment pixelCount since we actually need to account
 | 
        
           |  |  | 286 | 										; for the overflow of TCNT1
 | 
        
           |  |  | 287 |   | 
        
           |  |  | 288 | 		st		X+,color				; record the color run in the current line buffer
 | 
        
           |  |  | 289 | 		st		X,pixelCount		
 | 
        
           |  |  | 290 | 		rjmp	_cleanUp
 | 
        
           |  |  | 291 |   | 
        
           |  |  | 292 | _cleanUpDumpLine:		
 | 
        
           |  |  | 293 | 		; NOTE: If serial data is received, to interrupt the tracking of a line, we'll
 | 
        
           |  |  | 294 | 		; get a EV_SERIAL_DATA_RECEIVED event, and the T bit set so we will end the
 | 
        
           |  |  | 295 | 		; line's processing...however, the PCLK will keep on ticking for the rest of
 | 
        
           |  |  | 296 | 		; the frame/line, which will cause the TCNT to eventually overflow and
 | 
        
           |  |  | 297 | 		; interrupt us, generating a EV_ACQUIRE_LINE_COMPLETE event.  We don't want
 | 
        
           |  |  | 298 | 		; this, so we need to actually turn off the PCLK counting each time we exit
 | 
        
           |  |  | 299 | 		; this loop, and only turn it on when we begin acquiring lines....
 | 
        
           |  |  | 300 |         ; NOT NEEDED FOR NOW...
 | 
        
           |  |  | 301 | 		;in		tmp1, _SFR_IO_ADDR(TIMSK)			; disable TIMER1 to stop counting
 | 
        
           |  |  | 302 | 		;andi	tmp1, DISABLE_PCLK_TIMER1_OVERFLOW_BITMASK 	; external PCLK pulses
 | 
        
           |  |  | 303 | 		;out		_SFR_IO_ADDR(TIMSK),tmp1
 | 
        
           |  |  | 304 |   | 
        
           |  |  | 305 | _cleanUp:
 | 
        
           |  |  | 306 |         ; Disable the external clocking of the Timer1 counter 
 | 
        
           |  |  | 307 |         in      tmp1, _SFR_IO_ADDR(TCCR1B)
 | 
        
           |  |  | 308 |         andi    tmp1, 0xF8
 | 
        
           |  |  | 309 |         out     _SFR_IO_ADDR(TCCR1B),tmp1
 | 
        
           |  |  | 310 |   | 
        
           |  |  | 311 | 		; Toggle the debug line to indicate the line is complete
 | 
        
           |  |  | 312 | 		sbi     _SFR_IO_ADDR(PORTD),PD6
 | 
        
           |  |  | 313 | 		cbi		_SFR_IO_ADDR(PORTD),PD6
 | 
        
           |  |  | 314 | 		clt				; clear out the T bit since we have detected
 | 
        
           |  |  | 315 | 						; the interruption and are exiting to handle it
 | 
        
           |  |  | 316 | _exit:
 | 
        
           |  |  | 317 | 		ret
 | 
        
           |  |  | 318 |   | 
        
           |  |  | 319 | ;*****************************************************************		
 | 
        
           |  |  | 320 | ;   	Function Name: CamIntAsm_waitForNewDumpFrame
 | 
        
           |  |  | 321 | ;       Function Description: This function is responsible for
 | 
        
           |  |  | 322 | ;       going to sleep until a new frame begins (indicated by
 | 
        
           |  |  | 323 | ;    	VSYNC transitioning from low to high.  This will wake
 | 
        
           |  |  | 324 | ;       the "VSYNC sleep" up and allow it to continue with 
 | 
        
           |  |  | 325 | ;       acquiring a line of pixel data to dump out to the UI.
 | 
        
           |  |  | 326 | ;       Inputs:  r25 - MSB of currentLineBuffer
 | 
        
           |  |  | 327 | ;                r24 - LSB of currentLineBuffer
 | 
        
           |  |  | 328 | ;				 r23 - MSB of prevLineBuffer
 | 
        
           |  |  | 329 | ;				 r22 - LSB of prevLineBuffer
 | 
        
           |  |  | 330 | ;       Outputs: none
 | 
        
           |  |  | 331 | ;       NOTES: This function doesn't really return...it sorta just
 | 
        
           |  |  | 332 | ;       floats into the acquireDumpLine function after the "VSYNC sleep"
 | 
        
           |  |  | 333 | ;       is awoken.
 | 
        
           |  |  | 334 | ;*****************************************************************		
 | 
        
           |  |  | 335 | CamIntAsm_waitForNewDumpFrame:
 | 
        
           |  |  | 336 | 		sbi		_SFR_IO_ADDR(PORTD),PD6  ; For testing...
 | 
        
           |  |  | 337 | 		cbi		_SFR_IO_ADDR(PORTD),PD6
 | 
        
           |  |  | 338 | 		sleep
 | 
        
           |  |  | 339 |   | 
        
           |  |  | 340 | ;*****************************************************************
 | 
        
           |  |  | 341 | ; REMEMBER...everything from here on out is critically timed to be
 | 
        
           |  |  | 342 | ; synchronized with the flow of pixel data from the camera...
 | 
        
           |  |  | 343 | ;*****************************************************************
 | 
        
           |  |  | 344 |   | 
        
           |  |  | 345 | CamIntAsm_acquireDumpLine:
 | 
        
           |  |  | 346 | 		brts	_cleanUp
 | 
        
           |  |  | 347 | 		;sbi		_SFR_IO_ADDR(PORTD),PD6 ; For testing...
 | 
        
           |  |  | 348 | 		;cbi		_SFR_IO_ADDR(PORTD),PD6
 | 
        
           |  |  | 349 |   | 
        
           |  |  | 350 | 		mov   	XH,currLineBuffHigh    	; Load the pointer to the current line
 | 
        
           |  |  | 351 | 		mov		XL,currLineBuffLow		; buffer into the X pointer regs
 | 
        
           |  |  | 352 |   | 
        
           |  |  | 353 | 		mov		YH,prevLineBuffHigh		; Load the pointer to the previous line
 | 
        
           |  |  | 354 | 		mov		YL,prevLineBuffLow  	; buffer into the Y pointer regs
 | 
        
           |  |  | 355 |   | 
        
           |  |  | 356 | 		ldi 	tmp1,PIXEL_RUN_START_INITIAL	; set up the TCNT1 to overflow (and
 | 
        
           |  |  | 357 | 		ldi 	tmp2,0xFF 						; interrupts) after 176 pixels		
 | 
        
           |  |  | 358 | 		out 	_SFR_IO_ADDR(TCNT1H),tmp2		
 | 
        
           |  |  | 359 | 		out 	_SFR_IO_ADDR(TCNT1L),tmp1		
 | 
        
           |  |  | 360 |   | 
        
           |  |  | 361 |         in      tmp1, _SFR_IO_ADDR(TCCR1B) ; Enable the PCLK line to actually
 | 
        
           |  |  | 362 |         ori     tmp1, 0x07                 ; feed Timer1
 | 
        
           |  |  | 363 |         out     _SFR_IO_ADDR(TCCR1B),tmp1
 | 
        
           |  |  | 364 |         nop
 | 
        
           |  |  | 365 |   | 
        
           |  |  | 366 | 		in		tmp1, _SFR_IO_ADDR(TIMSK)			; enable TIMER1 to start counting
 | 
        
           |  |  | 367 | 		ori		tmp1, ENABLE_PCLK_TIMER1_OVERFLOW_BITMASK 	; external PCLK pulses and interrupt on 
 | 
        
           |  |  | 368 | 		out		_SFR_IO_ADDR(TIMSK),tmp1			; overflow			
 | 
        
           |  |  | 369 |   | 
        
           |  |  | 370 | 		in 		tmp1, _SFR_IO_ADDR(GICR)	; enable the HREF interrupt...remember, we
 | 
        
           |  |  | 371 | 											; only use this interrupt to synchronize
 | 
        
           |  |  | 372 | 											; the beginning of the line
 | 
        
           |  |  | 373 | 		ori 	tmp1, HREF_INTERRUPT_ENABLE_MASK
 | 
        
           |  |  | 374 | 		out		_SFR_IO_ADDR(GICR), tmp1
 | 
        
           |  |  | 375 |   | 
        
           |  |  | 376 | ;*******************************************************************************************
 | 
        
           |  |  | 377 | ;   Dump Frame handler 
 | 
        
           |  |  | 378 | ;*******************************************************************************************		
 | 
        
           |  |  | 379 |   | 
        
           |  |  | 380 | _dumpFrame:		
 | 
        
           |  |  | 381 | 		sbi		_SFR_IO_ADDR(PORTD),PD6
 | 
        
           |  |  | 382 | 		sleep   ; ...And we wait...
 | 
        
           |  |  | 383 |   | 
        
           |  |  | 384 | 		cbi		_SFR_IO_ADDR(PORTD),PD6
 | 
        
           |  |  | 385 | 		in 		tmp1, _SFR_IO_ADDR(GICR)			; disable the HREF interrupt
 | 
        
           |  |  | 386 | 		andi 	tmp1, HREF_INTERRUPT_DISABLE_MASK  	; so we don't get interrupted
 | 
        
           |  |  | 387 | 		out		_SFR_IO_ADDR(GICR), tmp1			; while dumping the line
 | 
        
           |  |  | 388 |   | 
        
           |  |  | 389 | 		nop		; Remember...if we ever remove the "cbi" instruction above,
 | 
        
           |  |  | 390 | 				; we need to add two more NOPs to cover this
 | 
        
           |  |  | 391 |   | 
        
           |  |  | 392 | ; Ok...the following loop needs to run in 8 clock cycles, so we can get every
 | 
        
           |  |  | 393 | ; pixel in the line...this shouldn't be a problem, since the PCLK timing was
 | 
        
           |  |  | 394 | ; reduced by a factor of 2 whenever we go to dump a line (this is to give us
 | 
        
           |  |  | 395 | ; enough time to do the sampling and storing of the pixel data).  In addition,
 | 
        
           |  |  | 396 | ; it is assumed that we will have to do some minor processing on the data right
 | 
        
           |  |  | 397 | ; before we send it out, like mask off the top 4-bits of each, and then pack both
 | 
        
           |  |  | 398 | ; low nibbles into a single byte for transmission...we just don't have time to
 | 
        
           |  |  | 399 | ; do that here (only 8 instruction cycles :-)  )
 | 
        
           |  |  | 400 | _sampleDumpPixel:
 | 
        
           |  |  | 401 | 		in		tmp1,G_PORT				; sample the G value					(1)
 | 
        
           |  |  | 402 | 		in		tmp2,RB_PORT			; sample the R/B value					(1)
 | 
        
           |  |  | 403 | 		st		X+,tmp1					; store to the currLineBuff and inc ptrs(2)
 | 
        
           |  |  | 404 | 		st		Y+,tmp2					; store to the prevLineBuff and inc ptrs(2)
 | 
        
           |  |  | 405 | 		brtc	_sampleDumpPixel		; loop back unless flag is set			(2...if not set)
 | 
        
           |  |  | 406 | 										;									___________
 | 
        
           |  |  | 407 | 										;									8 cycles normally
 | 
        
           |  |  | 408 |   | 
        
           |  |  | 409 | 		; if we make it here, it means the T flag is set, and we must have been interrupted
 | 
        
           |  |  | 410 | 		; so we need to exit (what if we were interrupted for serial? should we disable it?)
 | 
        
           |  |  | 411 | 		rjmp	_cleanUpDumpLine
 | 
        
           |  |  | 412 |   | 
        
           |  |  | 413 | ;***********************************************************
 | 
        
           |  |  | 414 | ;	Function Name: <interrupt handler for External Interrupt0> 
 | 
        
           |  |  | 415 | ;	Function Description: This function is responsible
 | 
        
           |  |  | 416 | ;	for handling a rising edge on the Ext Interrupt 0.  This
 | 
        
           |  |  | 417 | ;	routine simply returns, since we just want to wake up
 | 
        
           |  |  | 418 | ;	whenever the VSYNC transitions (meaning the start of a new
 | 
        
           |  |  | 419 | ;	frame).
 | 
        
           |  |  | 420 | ;	Inputs:  none
 | 
        
           |  |  | 421 | ;	Outputs: none
 | 
        
           |  |  | 422 | ;***********************************************************
 | 
        
           |  |  | 423 | SIG_INTERRUPT0:
 | 
        
           |  |  | 424 | ; This will wake us up when VSYNC transitions high...we just want to return
 | 
        
           |  |  | 425 | 		reti
 | 
        
           |  |  | 426 |   | 
        
           |  |  | 427 | ;***********************************************************
 | 
        
           |  |  | 428 | ;	Function Name: <interrupt handler for External Interrupt1> 
 | 
        
           |  |  | 429 | ;	Function Description: This function is responsible
 | 
        
           |  |  | 430 | ;	for handling a falling edge on the Ext Interrupt 1.  This
 | 
        
           |  |  | 431 | ;	routine simply returns, since we just want to wake up
 | 
        
           |  |  | 432 | ;	whenever the HREF transitions (meaning the pixels 
 | 
        
           |  |  | 433 | ;	are starting after VSYNC transitioned, and we need to
 | 
        
           |  |  | 434 | ; 	start acquiring the pixel blocks
 | 
        
           |  |  | 435 | ;	Inputs:  none
 | 
        
           |  |  | 436 | ;	Outputs: none
 | 
        
           |  |  | 437 | ;***********************************************************	
 | 
        
           |  |  | 438 | SIG_INTERRUPT1:
 | 
        
           |  |  | 439 | ; This will wake us up when HREF transitions high...we just want to return
 | 
        
           |  |  | 440 | 		reti
 | 
        
           |  |  | 441 |   | 
        
           |  |  | 442 | ;***********************************************************
 | 
        
           |  |  | 443 | ;	Function Name: <interrupt handler for Timer0 overflow>
 | 
        
           |  |  | 444 | ;	Function Description: This function is responsible
 | 
        
           |  |  | 445 | ;	for handling the Timer0 overflow (hooked up to indicate
 | 
        
           |  |  | 446 | ;	when we have reached the number of HREFs required in a
 | 
        
           |  |  | 447 | ;	single frame).  We set the T flag in the SREG to
 | 
        
           |  |  | 448 | ;	indicate to the _acquirePixelBlock routine that it needs
 | 
        
           |  |  | 449 | ;	to exit, and then set the appropriate action to take in
 | 
        
           |  |  | 450 | ;	the eventList of the Executive module.
 | 
        
           |  |  | 451 | ;	Inputs:  none
 | 
        
           |  |  | 452 | ;	Outputs: none
 | 
        
           |  |  | 453 | ;   Note: Originally, the HREF pulses were also going to
 | 
        
           |  |  | 454 | ;   be counted by a hardware counter, but it didn't end up
 | 
        
           |  |  | 455 | ;   being necessary
 | 
        
           |  |  | 456 | ;***********************************************************
 | 
        
           |  |  | 457 | ;SIG_OVERFLOW0:
 | 
        
           |  |  | 458 | ;		set				; set the T bit in SREG
 | 
        
           |  |  | 459 | ;		lds		tmp1,eventBitmask
 | 
        
           |  |  | 460 | ;		ori		tmp1,EV_ACQUIRE_FRAME_COMPLETE
 | 
        
           |  |  | 461 | ;		sts		eventBitmask,tmp1
 | 
        
           |  |  | 462 | ;		reti
 | 
        
           |  |  | 463 |   | 
        
           |  |  | 464 | ;***********************************************************
 | 
        
           |  |  | 465 | ;	Function Name: <interrupt handler for Timer1 overflow>
 | 
        
           |  |  | 466 | ;	Function Description: This function is responsible
 | 
        
           |  |  | 467 | ;	for handling the Timer1 overflow (hooked up to indicate
 | 
        
           |  |  | 468 | ;	when we have reached the end of a line of pixel data,
 | 
        
           |  |  | 469 | ;	since PCLK is hooked up to overflow TCNT1 after 176 
 | 
        
           |  |  | 470 | ;	pixels).  This routine generates an acquire line complete
 | 
        
           |  |  | 471 | ;	event in the fastEventBitmask, which is streamlined for
 | 
        
           |  |  | 472 | ;	efficiency reasons.
 | 
        
           |  |  | 473 | ;***********************************************************
 | 
        
           |  |  | 474 | SIG_OVERFLOW1:				
 | 
        
           |  |  | 475 | 		lds		tmp1,fastEventBitmask   		; set a flag indicating
 | 
        
           |  |  | 476 | 		ori		tmp1,FEV_ACQUIRE_LINE_COMPLETE	; a line is complete
 | 
        
           |  |  | 477 | 		sts		fastEventBitmask,tmp1
 | 
        
           |  |  | 478 | 		set		; set the T bit in SREG 
 | 
        
           |  |  | 479 | 		;sbi		_SFR_IO_ADDR(PORTD),PD6 ; For testing...
 | 
        
           |  |  | 480 | 		;cbi		_SFR_IO_ADDR(PORTD),PD6 ; For testing...
 | 
        
           |  |  | 481 |   | 
        
           |  |  | 482 | 		reti
 | 
        
           |  |  | 483 |   | 
        
           |  |  | 484 | ; This is the default handler for all interrupts that don't
 | 
        
           |  |  | 485 | ; have handler routines specified for them.
 | 
        
           |  |  | 486 |         .global __vector_default              
 | 
        
           |  |  | 487 | __vector_default:
 | 
        
           |  |  | 488 |         reti
 | 
        
           |  |  | 489 |   | 
        
           |  |  | 490 |         .end
 |