/* Analog.Asm Copyright ©1998, 1999 Larry Barello Author: Larry Barello lbarello@accessone.com You are allowed to use this file for personal use only. You may use, embed, modify or distribute the contents of this file in any way you see fit as long as you include this copyright notice in the resulting file. Any commercial or industrial use including publishing or distributing in any form requires the written authorization of the copyright holder(s). No guarantees are made about fitness, functionality, correctness or performance of this file. The file is supplied on a "AS IS" basis, with no responsibility assumed by the author(s) for bug fixes, support, or damages of any sort arising from the use of this file. Contact the author with problem reports or fixes, feature requests or additions and questions. They are welcomed and will be incorporated as time and energy permits. */ #include "Registers.inc" #include "avrx.inc" NAME ANALOG EXTERN TICKRATE AvrXStartTimer AvrXWaitTimer EXTERN _IntProlog _Epilog AvrXReadEEProm EXTERN AvrXIntSetSemaphore AvrXWaitSemaphore AvrXTestSemaphore EXTERN RightEyeAdjustment LeftEyeAdjustment LightCycleTime EXTERN mult8x8s div16x8s PUBLIC Right_Eye Left_Eye PUBLIC ADTaskTcb AnalogConversion ; ; NOTES: ; The initial state of this is messy. Wait a couple cycles to have ; stable readings. Also, pay attention to the discharge time ; of the capacitor. .1uf with a 100 ohm resistor takes ~200us to ; discharge, so don't start the next cycle too soon. ; ; Hardware equates, constants, etc. ; REYE = PB0 ; Right Eye enable LEYE = PB1 ; Left Eye enable Enable MACRO EYE sbi DDRB, EYE ; Set to output 0, i.e. ground Diode ENDM Disable MACRO EYE cbi DDRB, EYE ; tri-state the diode ENDM RSEG AVRXDATA:DATA(0) ADTaskPid: DS PidSz AnalogFlag: DS MtxSz AnalogTimer: DS TcbSz RSEG SSEG:DATA(1) ;++++++++++++++++++++++++++++++++++++++++++++++ ; Stack = StandardContext (10) + User stack ; DS 10 ; Standard Context DS 4 ; User stack (two calls deep) DS 1 ; One interrupt (between call and switch to kernel stack) ADTaskStack: DS 1 ; plus 2 bytes for padding RSEG DATA:DATA(0) AD_Results: DS 1 Right_Eye: DS 1 Left_Eye: DS 1 RSEG CODE(1) ADTIME = TICKRATE/30 ; 30 Hz ;---------------------------------------------- ; ADTaskTcb: DW ADTaskStack ; Stack DW ADTask>>1 ; Start Address DB ADTaskPid, 0 ; pointer to PID DW 0 ; Pointer to Context Save/Restore DB 2 ; Priority EVEN ;************************************************************************** ; ; ADTask ; ; Periodic rate is 60 hz to try to negate effects of electrical ; lighting. ; ; NOTES: ; ; 1. Initial state is all flags cleared, accumulators cleared. ; ADTask: sbi ACSR, ACD ; power down comparator sbi DDRB, AIN0 ; Set CAP to OUTPUT, (discharge) ldi Yl, low(ADTIME) ldi Yh, high(ADTIME) ldi Xl, low(AnalogTimer) rcall AvrXStartTimer ; Prime the timer chain adt00: Enable REYE ; Enable(REYE) rcall AD_Measure Disable REYE ldi Zl, low(RightEyeAdjustment) ldi Zh, high(RightEyeAdjustment) lds R0, AD_Results ; rcall AD_AdjustResults sts Right_Eye, R0 Enable LEYE ; Enable(LEYE) rcall AD_Measure Disable LEYE ldi Zl, low(LeftEyeAdjustment) ldi Zh, high(LeftEyeAdjustment) lds R0, AD_Results ; rcall AD_AdjustResults sts Left_Eye, R0 rjmp adt00 ; ; AD_Measure ; ; Housekeeping for driving the A/D conversion process. ; AD_Measure: ldi Xl, low(AnalogTimer) rcall AvrXWaitTimer ; Delay and restart timer rcall AvrXStartTimer ldi Xl, low(AnalogFlag) rjmp AvrXWaitSemaphore; wait for completion AD_AdjustResults: ; rcall ReadEEWord ret ;************************************************************************** ; ; AnalogConversion (Interrupt routine) ; ; Counts each time called until Analog comparator indicates ; conversion is done, then signals task. Interrupt controlled via ; MEASURE macro. ; ; Initial state is comparator OFF, CAP=Discharge. Enable comparator ; on the interrupt to align our counting with the interrupt. ; ; PASSED: Nothing ; RETURNS: Nothing ; USES: X, Y, Z and R0 ; NOTES: Runs on the system stack only ; AnalogConversion: ldi Xl, low(AnalogFlag) rcall AvrXTestSemaphore brlt An_Exit ; Only actively measuring when someone is waiting sbic ACSR, ACD ; if !first time rjmp An_Init sbic ACSR, ACO ; if (Converted || ++AD_Results == 0) rjmp An_ConversionDone lds Yl, AD_Results inc Yl brne An_2 ; if (AD_Results == 0) com Yl ; AD_Results = 0xFF // Overflow sts AD_Results, Yl An_ConversionDone: sbi ACSR, ACD ; power down comparator sbi DDRB, AIN0 ; Set CAP to OUTPUT, (discharge) ; Signal task that conversion is done rjmp AvrXIntSetSemaphore An_Init: ; First pass through routine: cbi ACSR, ACD ; power up comparator (+ 1 ma) cbi DDRB, AIN0 ; Turn comparator to input (e.g. Charge Cap) clr Yl ; Zero out accumulator An_2: sts AD_Results, Yl An_Exit: ret END