(**********************************************************************) (* *) (* Function: FQD - FAST QUADRATURE DECODE *) (* *) (* Creation Date: 10/Jul/92 From: QDEC *) (* *) (* Author: Jeff Wright *) (* *) (* Description: *) (* ------------ *) (* This function uses 2 channels (each must be programmed as FQD) to *) (* decode a pair of out of phase signals and produce a resulting 16 *) (* bit bidirectional position counter for the CPU. *) (* The function includes a time stamp of the quadrature edges for *) (* position interpolation at very slow count rates. *) (* FQDs enhancement over QDEC is the addition of 'Fast mode' which *) (* allows the CPU to switch FQD into a mode where only one channel is *) (* serviced and that channel on rising edges only. In this fast mode, *) (* the counter updated by 4 each time - this effectively quadruples *) (* the count rate performance of the function. Switching of modes is *) (* CPU controlled and would be based on the calculated speed. *) (* Cost of this feature is increased code size, so QDEC is best choice*) (* if it meets the required performance. *) (* *) (* *) (* Updates: By: Modification: *) (* -------- --- ------------- *) (* 16/Jun/93 JW Changed revNo from beta to 1.0 - first release *) (* 12/Aug/93 JL Converted to new TPUMASM syntax. *) (* *) (*--------------------------------------------------------------------*) (* Standard Exits Used:- End_Of_Phase: N End_Of_Link: Y *) (* *) (* External Files Included: NONE. *) (* *) (* CODE SIZE excluding standard exits = 46 LONG WORDS *) (*--------------------------------------------------------------------*) (* *) (********** This Revision: 1.1 *********) (* *) (********** LAST MODIFIED: 12/Aug/93 BY: Jeff Loeliger ********) (* *) (**********************************************************************) (***************************************************************************) (*Motorola reserves the right to make changes without further notice to any*) (*product herein. Motorola makes no warranty, representation or guarantee *) (*regarding the suitability of its products for any particular purpose, nor*) (*does Motorola assume any liability arising out of the application or use *) (*of any product or circuit, and specifically disclaims any and all *) (*liability, including without limitation consequential or incidental *) (*damages. "Typical" parameters can and do vary in different applications. *) (*All operating parameters, including "Typical",must be validated for each *) (*customer application by customer's technical experts. Motorola does not *) (*convey any license under its patent rights nor the rights of others. *) (*Motorola products are not designed, intended, or authorized for use as *) (*components in systems intended for surgical implant into the body, or *) (*other applications intended to support or sustain life, or for any other *) (*application in which the failure of the Motorola product could create a *) (*situation where injury or death may occur. Should Buyer purchase or use *) (*Motorola products for any such unintended or unauthorized application, *) (*Buyer, shall indemnify and hold Motorola and its officers, employees, *) (*subsidiaries, affiliates, and distributors harmless against all claims, *) (*costs, damages, and expenses, and reasonable attorney fees arising out *) (*of, directly or indirectly, any claim of personal injury or death *) (*associated with such unintended or unauthorized use, even if such claim *) (*alleges that Motorola was negligent regarding the design or manufacture *) (*of the part. *) (*Motorola and the Motorola logo are registered trademarks of Motorola Inc.*) (*Motorola is an Equal Opportunity/Affirmative Action Employer. *) (*Copyright Motorola Inc. 1993 *) (***************************************************************************) (*()()()()()()()()()()() DATA STRUCTURE ()()()()()()()()()()()()()()()*) (* *) (* name: Written By: Location Bits(x..y): *) (* ----- ----------- --------------------- *) (* EDGE_TIME_FQD TPU Parameter0 0..15 *) (* Updated to hold captured tcr1 time of latest *) (* edge. ONE CHANNEL ONLY!!! *) (* *) (* POSITION_CNT_FQD CPU/TPU parameter1 0..15 *) (* 16 bit counter that is the output of this func.*) (* Can be written or read at any time by CPU *) (* ONE CHANNEL ONLY!!!! *) (* *) (* TCR1_VAL_FQD TPU Parameter2 0..15 *) (* Updated by TPU to contain the latest TCR1 value*) (* in response to a read tcr1 HSR. *) (* *) (* CHAN_PINSTATE_FQD CPU/TPU Parameter3 0..15 *) (* Used to store the level of the pin for use in *) (* noise reject and lead/lag tests. Two values :- *) (* $8000 represents high pin, $0000 low pin. *) (* Can be init'ed by CPU to force first accepted *) (* edge type. *) (* *) (* CORR_PIN_PTR_FQD CPU Parameter4 0..7 *) (* Address of the CHAN_PINSTATE parameter of the *) (* other QD channel. *) (* *) (* EDGE_TIM_PTR_FQD CPU Parameter5 0..7 *) (* Address of the EDGE_TIME parameter.- must *) (* point to lsb [i.e. odd address] of EDGE_TIME *) (* *) (* hsr1 hsr0 Action *) (* ---- ---- ------ *) (* 0 X No action *) (* 1 0 Read TCR1. *) (* 1 1 Initialise function. *) (* *) (* *) (* HSQ1 HSQ0 Action *) (* ---- ---- ------ *) (* 0 0 Primary channel, normal (2 channel) mode. *) (* 1 0 Primary channel, fast (1 channel) mode. *) (* X 1 Secondary channel *) (* *) (* Links Accepted: no Links Generated: NO *) (* *) (* Interrupts Generated After: none *) (* *) (*()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()*) (*+++++++++++++++++++++ PARAMETER MACROS +++++++++++++++++++++++++++*) (* EDGE_TIME prm0 *) (* POSITION_CNT prm1 *) %macro TCR1_VAL_FQD 'prm2'. %macro CHAN_PINSTATE_FQD 'prm3'. %macro CORR_PIN_PTR_FQD 'prm4'. %macro EDGE_TIM_PTR_FQD 'prm5'. (*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*) (*====================================================================*) (*||||||||||||||||||||| MICROCODE STARTS BELOW |||||||||||||||||||||*) (*VVVVVVVVVVVVVVVVVVVVV--------------------------VVVVVVVVVVVVVVVVVVVVV*) (**********************************************************************) (* *) (* ENTRY name: INIT_FQD *) (* *) (* STATE(S) ENTERED: S1 *) (* *) (* PRELOAD PARAMETER : NONE *) (* *) (* ENTER WHEN : HSR = %11 *) (* *) (* ACTION: Init., make pin input & detect either edge. setup init *) (* value of CHAN_PINSTATE. *) (* *) (**********************************************************************) %entry start_address *; disable_match; name = INIT_FQD; cond hsr1 = 1, hsr0 = 1. init_fqd: chan pac := any_trans, tbs := in_m1_c1, enable_mtsr; chan clear flag0. au chan_reg := chan_reg; (* latch latest pinstate *) neg_tdl, neg_mrl, neg_lsl. (* - and any future edges *) au p := max; ram p -> @CHAN_PINSTATE_FQD. (* initialise PINSTATE param *) If PSL = 1 then goto read_tcr1_fqd,flush. au p := 0; ram p -> @CHAN_PINSTATE_FQD. (**********************************************************************) (* *) (* ENTRY name: READ_TCR1_FQD *) (* *) (* STATE(S) ENTERED: S2 *) (* *) (* PRELOAD PARAMETER : NONE *) (* *) (* ENTER WHEN : HSR = %10 *) (* *) (* ACTION: Read TCR1 and store value in TCR1_VAL. *) (* *) (**********************************************************************) %entry start_address *; disable_match; name = READ_TCR1_FQD; cond hsr1 = 1, hsr0 = 0. read_tcr1_fqd: au diob := tcr1; (* read and store current value of tcr1*) ram diob -> @TCR1_VAL_FQD; end. (**********************************************************************) (* *) (* ENTRY name: EDGE_NORM_FQD *) (* *) (* STATE(S) ENTERED: S3 *) (* *) (* PRELOAD PARAMETER : CHAN_PINSTATE_FQD *) (* *) (* ENTER WHEN : m/tsr = 1,flag0=0 *) (* *) (* ACTION: Latch pinstate, if equal to last then quit (noise) else *) (* update PINSTATE and perform lead/lag tests. From results, *) (* inc or dec POSITION_CNT. *) (* If Primary rising edge then test for entry of fast mode. *) (* *) (**********************************************************************) %entry ram p <- @CHAN_PINSTATE_FQD; start_address *; disable_match; name = EDGE_NORM_FQD; cond hsr1 = 0, hsr0 = 0,m/tsr = 1,lsr = 0,flag0 = 0. edge_norm_fqd: au chan_reg := chan_reg; (* latch latest pinstate and *) neg_tdl, neg_mrl. (* - dont lose any future edges *) au sr := p,ccl; (* put last pinstate into Nbit *) ram diob <- @CORR_PIN_PTR_FQD. If PSL = 0 then goto noise_tst_fqd. au p := p + max; (* flip CHAN_PINSTATE $0000 <-> $8000*) ram diob <- by_diob. (* get CHAN_PINSTATE of other QDEC chan*) au nil := sr + max;ccl. (* flip N bit to allow single test *) noise_tst_fqd: If N = 0 then goto End_of_link, flush. (* new = old pinstate=> end*) au sr := p + diob,ccl; (* add the CHAN_PINSTATEs of both chans*) ram p -> @CHAN_PINSTATE_FQD. (* store new pinstate of this chan*) au p := ert; ram diob <- @EDGE_TIM_PTR_FQD. (*get edge time and storage pointer*) If hsq0 = 1 then goto tst_n_fqd. (* primary or secondary? *) au diob := diob + 1; (* inc pointer to point at position counter*) ram p -> by_diob. (* store quadrature edge time *) tst_fm_fqd: If PSL = 0 then goto tst_n_fqd. (* can only enter FM on rising edge*) au nil := sr + max;ccl. (* flip N bit for primary chan dir test*) If hsq1 = 0 then goto tst_n_fqd,flush. (* enter Fast Mode *) au chan_reg := chan_reg + #$10; chan set flag0. (* remember we are in Fast Mode*) au chan_reg := chan_reg + #$F0. If true then goto tst_n_fqd,flush; chan PAC := low_high; (* enter Fast Mode, detect rising only*) disable_mtsr. (* - disable secondary chan*) tst_n_fqd: If N = 0 then goto inc_cnt_fqd; (* update counter and - *) chan set flag1. (* remember direction *) au a := 1; ram p <- by_diob. dec_cnt_fqd: au p := p - a; (* get count, dec it and store coherently*) ram p -> by_diob. chan clear flag1; end. (**********************************************************************) (* *) (* ENTRY name: EDGE_FAST_FQD *) (* *) (* STATE(S) ENTERED: S4 *) (* *) (* PRELOAD PARAMETER : CHAN_PINSTATE_FQD *) (* *) (* ENTER WHEN : m/tsr = 1,flag0=1 *) (* *) (* ACTION: Inc or Dec POSITION_CNT by 4 depending on flag1 state. *) (* Test for exit of fast mode. *) (* *) (**********************************************************************) %entry ram p <- @CHAN_PINSTATE_FQD; start_address *; disable_match; name = EDGE_FAST_FQD; cond hsr1 = 0, hsr0 = 0,m/tsr = 1,lsr = 0,flag0 = 1. edge_fast_fqd: au a :=<< 1; chan neg_tdl. If hsq1 = 1 then goto update_count_fqd. (* stay in Fast Mode ? *) au sr := chan_reg; ram diob <- @EDGE_TIM_PTR_FQD. (* get pointer for position cnt *) If flag1 = 0 then goto en_sec_fqd; chan PAC := any_trans. au chan_reg := chan_reg + #$10; chan clear flag0. (* exit Fast Mode, detect either edge *) au p := p + max. en_sec_fqd: au chan_reg := sr; ram p -> @CHAN_PINSTATE_FQD. (* correct sec chan pinstate on - *) If true then goto update_count_fqd; enable_mtsr. (* FM exit - reenable sec channel *) update_count_fqd: au diob := diob + 1. If flag1 = 0 then goto dec_cnt_fqd. (* test direction *) au a :=<< a; (* update counter by #4 in Fast Mode *) ram p <- by_diob. inc_cnt_fqd: au p := p + a; (* get count, inc it and store it in #2 *) ram p -> by_diob; (* cycles for coherency *) end. (**********************************************************************) (* UNUSED ENTRIES - execute appropriate termination *) (**********************************************************************) %entry start_address End_of_link; name = del_lnk_fqd; cond hsr1 = 0,hsr0 = 1. %entry start_address End_of_link; name = del_lnk_fqd1; cond hsr1 = 0,hsr0 = 0,lsr = 1.