(**********************************************************************) (* *) (* Function: UART Universal Asynchronous Receiver / Transmitter *) (* *) (* Creation Date: 27/Jul/92 From: NEW *) (* *) (* Author: Josef Fuchs / Ewald Liess *) (* *) (* Description: *) (* ------------ *) (* This function uses 1 or 2 TPU channels to form a uni or bidirection*) (* UART. Baud rate is freely programmable by the user. The data word *) (* length can be between 1 and 14 bits and no/odd/even parity is *) (* supported. The function has been designed to operate in a similar *) (* manner to the SCI port found on many Motorola MCUs. The function is*) (* double buffered i.e there is a shift reg. and data reg. *) (* All 16 TPU channels could be used for UART, each operating at more *) (* than 9600 baud. *) (* *) (* Updates: By: Modification: *) (* -------- --- ------------- *) (* RevB JW Added interrupt generation to transmitter init *) (* - state2 *) (* 16/Jun/93 JW Moved receiver interrupt generation to be after *) (* data write for correct polled operation. *) (* Designated as rev 1.0 for mask 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 = 67 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: *) (* ----- ----------- --------------- *) (* PARITY_TEMP TPU Parameter0 0..15 *) (* Used by TPU to calculate parity - CPU must not *) (* write. *) (* *) (* MATCH_RATE CPU Parameter1 0..15 *) (* Baud period in TCR1 clocks. *) (* *) (* DATA BOTH Parameter2 0..15 *) (* Transmit or Receive data register. For transmit*) (* ,bit 15 must be 0. *) (* *) (* DATA_SIZE CPU Parameter3 0..15 *) (* Holds the number of bits in a data word - *) (* INCLUDING parity. *) (* *) (* ACTUAL_BIT_COUNT TPU Parameter4 0..15 *) (* Used by the TPU to count the number of bits. *) (* CPU must not write. *) (* *) (* SHIFT_REG TPU Parameter5 0..15 *) (* Used by the TPU for shifting in/out data. *) (* CPU must not write. *) (* *) (* *) (* HSQ1 HSQ0 Action *) (* ---- ---- ------ *) (* 0 0 No Parity. *) (* 0 1 No Parity. *) (* 1 0 Even Parity. *) (* 1 1 Odd Parity. *) (* *) (* hsr1 hsr0 Action *) (* ---- ---- ------ *) (* 0 x No action *) (* 1 0 Initialise channel as receiver. [clfg1 cleared]*) (* 1 1 Initialise chan as transmitter. [cflg1 set] *) (* *) (* Links Accepted: NO Links Generated: NO *) (* *) (* Interrupts Generated After: Transmit data empty/receive data full*) (* *) (*()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()*) (*+++++++++++++++++++++ PARAMETER MACROS +++++++++++++++++++++++++++*) %macro PARITY_TEMP_UART 'prm0'. %macro MATCH_RATE_UART 'prm1'. %macro DATA_UART 'prm2'. %macro DATA_SIZE_UART 'prm3'. %macro ACTUAL_BIT_COUNT_UART 'prm4'. %macro SHFT_REG_UART 'prm5'. (* conditions *) %macro RECEIVER_UART 'flag1 = 0'. (* Receiver is selected by cflag1=0 *) %macro PARITY_OFF_UART 'hsq1 = 0'. (* no Parity *) %macro PARITY_EVEN_UART 'hsq0 = 0'. (* use even Parity *) (*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*) (*====================================================================*) (*||||||||||||||||||||| MICROCODE STARTS BELOW |||||||||||||||||||||*) (*VVVVVVVVVVVVVVVVVVVVV--------------------------VVVVVVVVVVVVVVVVVVVVV*) (**********************************************************************) (* *) (* State 1: Initialisation for RECEIVER *) (* *) (* entered by HSR 2 *) (**********************************************************************) %entry start_address *;disable_match; name = INIT_RECEIVER_UART; cond hsr1 = 1, hsr0 = 0. INIT_RECEIVER_UART: chan tbs := in_m1_c1, pac := high_low; chan clear flag0; (*wait for start-bit = falling edge *) enable_mtsr. chan neg_tdl, neg_mrl, neg_lsl; chan clear flag1; (* select RECEIVER *) end. (**********************************************************************) (* *) (* State 2: Initialisation for TRANSMITTER *) (* *) (* entered by HSR 3 *) (**********************************************************************) %entry ram p <- @MATCH_RATE_UART; start_address *;disable_match; name = INIT_TRANSMIT_UART; cond hsr1 = 1, hsr0 = 1. INIT_TRANSMIT_UART: chan tbs := out_m1_c1, pac := no_change, pin := high; chan clear flag0; (* poll the TDRE-bit *) enable_mtsr. au ert := tcr1 + p; chan neg_tdl, neg_mrl, neg_lsl; write_mer; chan set flag1; (* select TRANSMITTER *) chan cir; (* revB - for IRQ driven transmitter *) end. (**********************************************************************) (* *) (* if TRANSMITTER then State 3: POLLING TDRE *) (* else RECEIVER then goto STATE 5: FALLING EDGE DETECTED *) (* *) (* For Transmitter: *) (* entered after a match if no data is sent out, then: *) (* if TDRE is set: set up next match to test TDRE again *) (* else set cflag0 to indicate transmittion and send startbit *) (* *) (* For Receiver: *) (* entered after a falling edge (of startbit) is detected, *) (* then goto State 5 (receive startbit) *) (**********************************************************************) %entry ram diob <- @MATCH_RATE_UART; start_address *; disable_match; name = SERV_START_BIT_UART; cond hsr1 = 0, hsr0 = 0, m/tsr = 1,lsr = 0, pin = x,flag0 = 0. SERV_START_BIT_UART: if @RECEIVER_UART then goto RXD_START_BIT_UART. (* Goto Receiver *) au p := 0; ram p -> @PARITY_TEMP_UART. (* reset high-bit counter *) (* following statements are for transmitter only *) au ert := ert + diob; (* define first match *) chan neg_mrl, neg_lsl, neg_tdl; write_mer. ram p <- @DATA_UART. au nil := p, ccl; (* test TDRE *) ram diob <- @DATA_SIZE_UART. if N = 1 then goto END_OF_LINK,flush. (* valid data found, send it *) SEND_START_BIT_UART: chan pac := low; (* start bit *) chan set flag0; (* now send data *) chan cir. au diob := diob+1; (* count also startbit *) ram diob -> @ACTUAL_BIT_COUNT_UART. au p := p + max; (* chan set TDRE-Bit = MSB *) ram p -> @SHFT_REG_UART. (* copy data to shift register *) ram p -> @DATA_UART; (* chan set TDRE in Dataword *) end. (**********************************************************************) (* *) (* if TRANSMITTER then State 4: send data bits *) (* else if RECEIVER then goto STATE 6: receive data bits *) (* *) (* Read the Data and shift the LSB-Bit out, then write the shifted *) (* value into the SHFT_REG and decrement ACTUAL_BIT_COUNT. *) (**********************************************************************) %entry ram diob <- @MATCH_RATE_UART; start_address *; disable_match; name = SERV_DATA_BITS_UART; cond hsr1 = 0, hsr0 = 0, m/tsr = 1, lsr = 0, pin = x, flag0 = 1. SERV_DATA_BITS_UART: au ert := ert + diob; ram p <- @ACTUAL_BIT_COUNT_UART. if @RECEIVER_UART then goto RXD_DATA_BIT_UART. (* Goto Receiver *) au p := p - 1, ccl; (* decrement number of bits *) ram p -> @ACTUAL_BIT_COUNT_UART. (* following statements are for transmitter only *) if N = 1 then goto SEND_STOP_BIT_UART,flush. if Z = 1 then goto SEND_PARITY_UART,flush. ram p <- @SHFT_REG_UART. ram diob <- @PARITY_TEMP_UART. SEND_BIT_UART: au p :=>> p, ccl; (* shift out data bit *) ram p -> @SHFT_REG_UART. if C = 1 then goto SEND_HIGH_BIT_UART,flush. SEND_LOW_BIT_UART: chan pac := low; neg_tdl, neg_lsl, neg_mrl; write_mer; end. SEND_HIGH_BIT_UART: au diob:= diob+1; (* update parity *) ram diob -> @PARITY_TEMP_UART. chan pac := high; neg_tdl, neg_lsl, neg_mrl; write_mer; end. SEND_PARITY_UART: if @PARITY_OFF_UART then goto SEND_STOP_BIT_UART,flush. if @PARITY_EVEN_UART then goto SEND_BIT_UART. ram p <- @PARITY_TEMP_UART. goto SEND_BIT_UART. au p := p + 1. (* generate odd parity = do a complement *) SEND_STOP_BIT_UART: chan pac := high; neg_tdl, neg_lsl, neg_mrl; write_mer; chan clear flag0; end. (**********************************************************************) (* *) (* STATE 5: FALLING EDGE DETECTED *) (* *) (* START-Bit and start sampling in the middle of a BIT *) (* = set up a match after 1.5 bittimes *) (* *) (* Parity Temp already cleared, diob contains Matchrate *) (* *) (**********************************************************************) RXD_START_BIT_UART: au ert:=ert+diob; ram p <- @DATA_SIZE_UART. if @PARITY_OFF_UART then goto RXD_NO_PARITY_UART,flush. au p := p + 1. (* count also parity bit if enabled *) RXD_NO_PARITY_UART: ram p -> @ACTUAL_BIT_COUNT_UART; au diob :=>> diob. (* MATCHRATE/2 *) au ert := ert + diob; (* ert := ert +1.5*Matchrate *) chan pac := no_detect; chan set flag0; neg_mrl, neg_lsl, neg_tdl; write_mer; end. (**********************************************************************) (* *) (* STATE 6: RECEIVE BITS *) (* *) (* Read the value at the pin and shift this value in the SHFT_REG. *) (* Also decrement ACTUAL_BIT_CNT (the number of received bits). *) (* *) (* diob contains Matchrate, ert already set up with ert+diob *) (* no write_mer issued !! *) (* Actual_Bit_Count is already decremented ccl set by decrement *) (**********************************************************************) RXD_DATA_BIT_UART: if N = 1 then goto RECEIVE_STOP_UART. au a := 0; (* clear FLAG-BITS *) ram diob <- @SHFT_REG_UART. (* read shiftregister *) (* there is a data bit to receive *) if psl = 1 then goto RECEIVE_HIGH_UART. (* high bit has to be received *) au diob :=>> diob; (* shift zero into BIT15 *) chan neg_tdl, neg_lsl, neg_mrl; write_mer. RECEIVE_LOW_UART: ram diob -> @SHFT_REG_UART; (* get the low bit *) end. RECEIVE_HIGH_UART: au diob := diob + max; (* chan set received bit, shifted before *) ram diob -> @SHFT_REG_UART. ram diob <- @PARITY_TEMP_UART. (* add parity *) au diob := diob + 1; (* count an additional high bit *) ram diob -> @PARITY_TEMP_UART; end. (* all data bits have been received and stored left justified in the shift- *) (* register if parity was enabled, parity is in BIT15 of the shift register *) RECEIVE_STOP_UART: if psl = 1 then goto RXD_OK_UART, flush. (*stopbit must be high *) SET_FE_FLAG_UART: au a :=>> max. (* set Framing Error if stopbit was not high *) (* stores $4000 into a, sets Bit 14 *) (* now check the parity *) RXD_OK_UART: if @PARITY_OFF_UART then goto PAR_OK_UART,flush. (* Parity enabled ? *) au diob :=<< diob; (* remove Parity *) ram p <- @PARITY_TEMP_UART. if @PARITY_EVEN_UART then goto EVEN_PAR_UART,flush. au p := p + 1. (* for odd parity, negate it *) EVEN_PAR_UART: au nil :=>> p,ccl. (* copy LSB from PARITY_TEMP to Carry *) if C = 0 then goto PAR_OK_UART,flush. (* there was a parity error *) au a := a + max. (*set Parity error, $8000, Bit 15 chan set*) (* now move the left justified value in the shiftregister to right *) (* to have a right justified result *) PAR_OK_UART: ram p <- @DATA_SIZE_UART. (* calculate number of bits to shift right *) au dec := dec - p; (* align to the right side *) chan pac := high_low; (* init for new startbit *) chan clear flag0;neg_tdl,neg_mrl. repeat; au diob :=>> diob. (* align data right *) au diob := diob + a; (* combine data and flags *) ram diob -> @DATA_UART. (* and store received dataword *) chan cir; (* generate RDRF-interrupt *) end. (**********************************************************************) (* UNDEFINED ENTRIES - execute an end. *) (**********************************************************************) %entry start_address END_OF_LINK; name = UART_UNDEF; cond hsr1 = 0,hsr0 = 1. %entry start_address END_OF_LINK; disable_match; name = UART_UNDEF; cond hsr1 = 0, hsr0 = 0, m/tsr = 0, lsr = 1, pin = x, flag0 = x. %entry start_address END_OF_LINK; disable_match; name = UART_UNDEF; cond hsr1 = 0, hsr0 = 0, m/tsr = 1, lsr = 1, pin = x, flag0 = x.