(**********************************************************************) (* *) (* Function: MCPWM - Multi Channel Pulse Width Modulation *) (* *) (* Creation Date: 08/Apr/92 From: NEW *) (* *) (* Author: Jeff Wright *) (* *) (* Description: *) (* ------------ *) (* This function uses a master channel and multiple slave channels *) (* externally gated to produce PWM outputs with a time relationship *) (* and full 0 to 100% duty cycle support. There are 2 operation modes:*) (* Edge Aligned: One master is EOR'd with n slaves to produce n pwm *) (* outputs, each of which have aligned rising edges. *) (* Centre Aligned: Master channel used as time ref. and n slaves are *) (* EOR'd in pair to produce n/2 pwm outpus with center aligned high *) (* times. CA mode also supports the inclusion of dead time for Hbridge*) (* driving. *) (* In either mode, the master can generate a periodic IRQ to the CPU *) (* to request a new high time. *) (* *) (* Updates: By: Modification: *) (* -------- --- ------------- *) (* 16/11/92 jw Changed IRQ counter to 8 bits - code compression. *) (* 17/11/92 jw Added inversion option HSR. *) (* 16/Jun/93 JW Changed revNo from Beta2 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 = 38 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: *) (* ----- ----------- --------------- *) (* MASTER CHANNEL *) (* PERIOD CPU Parameter0 0..15 *) (* Period of PWM output waveform. *) (* *) (* IRQ_RATE BOTH Parameter1 8..15 *) (* The number of PERIODs between each CPU IRQ *) (* *) (* PER_COUNT BOTH Parameter1 0..7 *) (* Period counter for periodic CPU interrupt. *) (* *) (* LAST_RISE_TIM TPU Parameter2 0..15 *) (* Hold event time of last master L->H transition *) (* *) (* LAST_FALL_TIM TPU Parameter3 0..15 *) (* Hold event time of last master H->L transition *) (* *) (* RISE_TIM_PTR CPU Parameter4 0..7 *) (* Address of LAST_RISE_TIM master parameter. *) (* *) (* FALL_TIM_PTR CPU Parameter5 0..7 *) (* Address of LAST_FALL_TIM master parameter. *) (* *) (* *) (* SLAVE A CHANNEL *) (* PERIOD CPU Parameter0 0..15 *) (* Period of PWM output waveform. *) (* *) (* NXT_B_RISE_TIM TPU Parameter1 0..15 *) (* The time for the next slaveB rising match. *) (* *) (* NXT_B_FALL_TIM TPU Parameter2 0..15 *) (* The time for the next slaveB falling match. *) (* *) (* HIGH_TIM_PTR CPU Parameter3 0..7 *) (* Address in PRAM of PWM high time parameter *) (* - must point to lsb i.e. odd address of H_T - *) (* incremented by 1 and used as address to store *) (* current H_T to be used by 'dead time' CA pair. *) (* *) (* DEAD_TIM CPU Parameter3 8..15 *) (* Dead time delay for H-bridge switch in tcr clks*) (* *) (* RISE_TIM_PTR CPU Parameter4 0..7 *) (* Address of LAST_RISE_TIM master parameter. *) (* *) (* FALL_TIM_PTR CPU Parameter5 0..7 *) (* Address of LAST_FALL_TIM master parameter. *) (* *) (* SLAVE B CHANNEL *) (* FALL_EDG_PTR CPU Parameter4 0..7 *) (* Address of slaveA NXT_B_FALL parameter. *) (* *) (* RISE_EDG_PTR CPU Parameter5 0..7 *) (* Address of slaveA NXT_B_RISE parameter. *) (* *) (* *) (* HSQ1 HSQ0 Action *) (* ---- ---- ------ *) (* MASTER *) (* x x Not used *) (* SLAVE *) (* 0 0 Slave A - EA mode *) (* 0 1 Slave A - CA mode *) (* 1 x Slave B *) (* *) (* hsr1 hsr0 Action *) (* ---- ---- ------ *) (* 0 0 No action *) (* 0 1 Initialise as inverse slave (flag0=>0) *) (* 1 0 Initialise as slave (flag0=>0) *) (* 1 1 Initialise as master (flag0=>1) *) (* *) (* Links Accepted: NO Links Generated: NO *) (* *) (* Interrupts Generated After: Every 'IRQ_RATE' periods on master.*) (* - interrupts are also generated every second period by slave A chan*) (* in CA mode - these are meaningless and should be disabled with the *) (* interrupt enable bit for the appropriate channel[s]. *) (* *) (*()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()*) (*+++++++++++++++++++++ PARAMETER MACROS +++++++++++++++++++++++++++*) (* MASTER *) %macro PERIOD_MCPWM 'prm0'. %macro IRQ_COUNTER_MCPWM 'prm1'. %macro LAST_RISE_TIM_MCPWM 'prm2'. %macro LAST_FALL_TIM_MCPWM 'prm3'. %macro RISE_TIM_PTR_MCPWM 'prm4'. %macro FALL_TIM_PTR_MCPWM 'prm5'. (* SLAVE A *) (*%macro PERIOD_MCPWM 'prm0'.*) %macro NXT_B_RISE_MCPWM 'prm1'. %macro NXT_B_FALL_MCPWM 'prm2'. %macro HIGH_TIM_PTR_MCPWM 'prm3'. %macro DEAD_TIM_MCPWM 'prm3'. (*%macro RISE_TIM_PTR_MCPWM 'prm4'.*) (*%macro FALL_TIM_PTR_MCPWM 'prm5'.*) (* SLAVE B *) (*%macro HIGH_TIM_MCPWM 'prm0'.*) (*%macro CURRENT_H_T_MCPWM 'prm1'.*) %macro FALL_EDG_PTR_MCPWM 'prm4'. %macro RISE_EDG_PTR_MCPWM 'prm5'. (*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*) (*====================================================================*) (*||||||||||||||||||||| MICROCODE STARTS BELOW |||||||||||||||||||||*) (*VVVVVVVVVVVVVVVVVVVVV--------------------------VVVVVVVVVVVVVVVVVVVVV*) (**********************************************************************) (* *) (* ENTRY name: MINIT_MCPWM *) (* *) (* STATE(S) ENTERED: S1 *) (* *) (* PRELOAD PARAMETER : RISE_TIM_PTR_MCPWM *) (* *) (* ENTER WHEN : HSR = %11 *) (* *) (* ACTION: Init. Output high,select tcr and store in LAST_RISE_TIM *) (* chan set flag0. chan set H>L match for time TCRx + PERIOD. *) (* Update PER_COUNT & IRQ if equal to IRQ_RATE. *) (* *) (**********************************************************************) %entry name = minit_mcpwm; start_address *; disable_match; cond hsr1 = 1, hsr0 = 1; ram diob <- @RISE_TIM_PTR_MCPWM. minit_mcpwm: If true then goto str_tim_mcpwm; chan tbs := out_m1_c1, pin := high, PAC := toggle; chan set flag0; enable_mtsr. au ert := tcr1; (* get tcr1 & store it as L_H ref *) ram p <- @IRQ_COUNTER_MCPWM. (**********************************************************************) (* *) (* ENTRY name: MHL_MCPWM *) (* *) (* STATE(S) ENTERED: S5 *) (* *) (* PRELOAD PARAMETER : FALL_TIM_PTR_MCPWM *) (* *) (* ENTER WHEN : HSR = %00, m/tsr = 1, pin =0, flag0 =1. *) (* *) (* ACTION: Schedule next master L>H match. Update PER_COUNT and if *) (* = IRQ_RATE then interrupt CPU and reset PER_COUNT. *) (* *) (**********************************************************************) %entry name = mhl_mcpwm; start_address *; disable_match; cond hsr1 = 0, hsr0 = 0,lsr = x,m/tsr = 1,pin = 0,flag0 = 1; ram diob <- @FALL_TIM_PTR_MCPWM. (**********************************************************************) (* *) (* ENTRY name: MLH_MCPWM *) (* *) (* STATE(S) ENTERED: S4 *) (* *) (* PRELOAD PARAMETER : RISE_TIM_PTR_MCPWM *) (* *) (* ENTER WHEN : HSR = %00, m/tsr = 1, pin =1, flag0 =1. *) (* *) (* ACTION: Schedule next master H>L match. Update PER_COUNT and if *) (* = IRQ_RATE then interrupt CPU and reset PER_COUNT. *) (* *) (**********************************************************************) %entry name = mlh_mcpwm; start_address *; disable_match; cond hsr1 = 0, hsr0 = 0,lsr = x,m/tsr = 1,pin = 1,flag0 = 1; ram diob <- @RISE_TIM_PTR_MCPWM. mlh_mcpwm: au read_mer; ram p <- @IRQ_COUNTER_MCPWM. Str_tim_mcpwm: au diob := ert; ram diob -> by_diob. (* update master ref. time*) mast_mcpwm: au p_low := p_low +1; ram p -> @IRQ_COUNTER_MCPWM. au p_low := p_high - p,ccl. If Z = 0 then goto sched_mcpwm. (* if per_cnt = irq_rte then-*) au diob := p; ram p <- @PERIOD_MCPWM. goto sched_irq_mcpwm,flush; ram diob -> @IRQ_COUNTER_MCPWM. (* irq and per_cnt => 0 *) (**********************************************************************) (* *) (* ENTRY name: S_INV_INIT_MCPWM *) (* *) (* STATE(S) ENTERED: S3 *) (* *) (* PRELOAD PARAMETER : FALL_TIM_PTR_MCPWM *) (* *) (* ENTER WHEN : HSR = %01 *) (* *) (* ACTION: Init. Output low,tcr1. Get LAST_RISE_TIM from master *) (* Set L>H match . *) (* *) (**********************************************************************) %entry name = s_inv_init_mcpwm; start_address *; disable_match; cond hsr1 = 0, hsr0 = 1; ram diob <- @FALL_TIM_PTR_MCPWM. s_inv_init_mcpwm: If true then goto sa_sb_mcpwm,flush; chan tbs := out_m1_c1, pin := low, PAC := toggle; enable_mtsr. (* pin high on next match *) (**********************************************************************) (* *) (* ENTRY name: SINIT_MCPWM *) (* *) (* STATE(S) ENTERED: S2 *) (* *) (* PRELOAD PARAMETER : RISE_TIM_PTR_MCPWM *) (* *) (* ENTER WHEN : HSR = %10 *) (* *) (* ACTION: Init. Output high,tcr1. Get LAST_RISE_TIM from master *) (* Set H>L match. *) (* *) (**********************************************************************) %entry name = sinit_mcpwm; start_address *; disable_match; cond hsr1 = 1, hsr0 = 0; ram diob <- @RISE_TIM_PTR_MCPWM. sinit_mcpwm: chan tbs := out_m1_c1, pin := high, PAC := toggle; enable_mtsr. (* pin low on next match *) (**********************************************************************) (* *) (* ENTRY name: SHL_MCPWM *) (* *) (* STATE(S) ENTERED: S6 *) (* *) (* PRELOAD PARAMETER : FALL_TIM_PTR_MCPWM *) (* *) (* ENTER WHEN : HSR = %00, m/tsr = 1, pin =0, flag0 =0. *) (* *) (* ACTION: Schedule next slave L>H match. *) (* *) (**********************************************************************) %entry name = shl_mcpwm; start_address *; disable_match; cond hsr1 = 0, hsr0 = 0,lsr = x,m/tsr = 1,pin = 0,flag0 = 0; ram diob <- @FALL_TIM_PTR_MCPWM. (**********************************************************************) (* *) (* ENTRY name: SLH_MCPWM *) (* *) (* STATE(S) ENTERED: S7 *) (* *) (* PRELOAD PARAMETER : RISE_TIM_PTR_MCPWM *) (* *) (* ENTER WHEN : HSR = %00, m/tsr = 1, pin =1, flag0 =0. *) (* *) (* ACTION: Schedule next slave H>L match. *) (* *) (**********************************************************************) %entry name = slh_mcpwm; start_address *; disable_match; cond hsr1 = 0, hsr0 = 0,lsr = x,m/tsr = 1,pin = 1,flag0 = 0; ram diob <- @RISE_TIM_PTR_MCPWM. sa_sb_mcpwm: If hsq1 = 1 then goto sched_mcpwm; (* slave A or B ?*) chan clear flag0. au ert := 0; ram p <- by_diob. (* get edge time *) au ert := p; ram p <- @PERIOD_MCPWM. au a := p; (* a = period *) ram p <- @HIGH_TIM_PTR_MCPWM. au sr := p_high; (* sr = dead_time *) ram diob <- @HIGH_TIM_PTR_MCPWM. If hsq0 = 0 then goto sched_mcpwm. (* If edge mode go do it *) au ert := ert + a; (* master edge time + period *) ram p <- by_diob. (* get 'new' high time *) au diob := diob + 1. au sr := p - sr,ccl; (* H_T - dead time *) ram p -> by_diob. (* store 'new' H_T to Current_H_T*) au p :=>> a - sr. (* [period - {H_T-deadtime}]/2 *) If N = 0 then goto use_ht_mcpwm. (* is hightime < dead time?*) au diob := p + sr. (* [period - {H_T - D_T}]/2 + [H_T - D_T] *) au p :=>> a. (* period/2 *) au diob := p. (* period/2 *) use_ht_mcpwm: If PSL = 1 then goto str_fall_mcpwm,flush. au diob := ert + diob; (* master edge time + period + diob *) ram diob -> @NXT_B_RISE_MCPWM. (* store next B channel edge *) sched_mcpwm: au ert := ert + p; (* schedule next A channel edge *) chan write_mer, neg_lsl, neg_tdl, neg_mrl; end. str_fall_mcpwm: au diob := ert + diob; ram diob -> @NXT_B_FALL_MCPWM. sched_irq_mcpwm: au ert := ert + p; chan write_mer, neg_lsl, neg_tdl, neg_mrl; chan cir; (* interrupt CPU *) end. (**********************************************************************) (* UNUSED ENTRIES - execute appropriate termination *) (**********************************************************************) %entry name = dud_mcpwm; start_address End_of_link; disable_match; cond hsr1 = 0, hsr0 = 0,lsr = 1,m/tsr = 0,pin = x,flag0 = x.