Thursday, December 17, 2009

TCTASK.C

/*
���������������������������������������������������������������������������͸
�                                                                           �
�                          THERMOCOUPLE TASK                                �
�                                                                           �
�                          Copyright (c) 1994                               �
�                           by Lutfi Shahab                                 �
�               Instrumentation and Controls Laboratory                     �
�                     Dept. of Engineering Physics                          �
�                      Institut Teknologi Bandung                           �
�                                                                           �
�  Date:      20/11/94                                                      �
�                                                                           �
�  Platform : Motorola 68HC16 Microcontroller                               �
�               running mcx16 multitasking kernel                           �
�  Compiler : Whitesmith HC16 Compiler                                      �
�  Target   : EPROM-targeted binary code                                    �
�                                                                           �
�  Description:                                                             �
�      This module contains routines for Thermocouple Linearization using   �
�  polynomial curvefitting. Only thermocouple type K can be calculated.     �
�  Temperature adjusted to Celcius.                                         �
�                                                                           �
���������������������������������������������������������������������������;
*/

#define _WSC_
#define _FAR_

#ifdef _WSC_
#include <wslxa.h>
#else
enum {ADC_1, ADC_2, ADC_3, ADC_4, ADC_5,ADC_6, ADC_7, ADC_8, N_ADC_CHANNELS};
#endif
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <stdio.h>
#ifdef _WSC_
#include "mcxapi.h"
#include "sysdef.h"
#endif

#define VREF_PLUS         +2500.0       /* mV */
#define VREF_MIN          -2500.0       /* mV */
#define RESOLUTION          10          /* bits */
#define KELVIN_TO_C        273.20       /* based on IPTS-68 */
#define LM335_VT            10.00       /* mV per Kelvin degree */
#define TC_GAIN_AMP            (10000/40)     /* gain of TC op-amp; uV/uV */
#define DIGIT_TO_MILLIVOLT(d)    (((d)*scale)+VREF_MIN) /* mV */


/* seebeck coefficients for all TC types */
#define SEEBECK_COEF_K       40.01 /* uV/K */
#define SEEBECK_COEF_TC       5.20
#define SEEBECK_COEF_BN        18.05
#define SEEBECK_COEF_E         59.80
#define SEEBECK_COEF_JT        51.08
#define SEEBECK_COEF_JP        17.94
#define SEEBECK_COEF_JN        33.10
#define SEEBECK_COEF_K         40.01
#define SEEBECK_COEF_KP      26.47
#define SEEBECK_COEF_KN      13.54
#define SEEBECK_COEF_R        5.62
#define SEEBECK_COEF_S        5.70
#define SEEBECK_COEF_T       39.67
#define SEEBECK_COEF_TP       6.33
#define SEEBECK_COEF_TN      33.32

#define SEEBECK_COEF         SEEBECK_COEF_K

/* number of linearization polynomial equations as T(V) */
#define NUMEQN_V            5

/* number of linearization polynomial equations as V(T) */
#define NUMEQN_T            2

#define ORDE_T              10
#define ORDE_V              4
#define TC_VOLT_MIN         tc_table.v_range[0].min
#define TC_VOLT_MAX         tc_table.v_range[NUMEQN_V-1].max


typedef struct {
    double min, max;
}RANGE;


typedef struct {
    RANGE t_range[NUMEQN_T];       /* temperature range */
    RANGE v_range[NUMEQN_V];       /* voltage range */
    double coef_t[NUMEQN_T][ORDE_T+1];   /* polynomial coefficients for every equation of V(T) */
    double coef_v[NUMEQN_V][ORDE_V+1];   /* polynomial coefficients for every equation of T(V) */
} TCRECTYPE;


TCRECTYPE tc_table = {
  /* Temperature ranges (in C) for each polynomial equation of type K */
  {
    {-270.00,    0.00},
    {   0.00, 1372.00},
  },
  /* Voltage ranges in microvolts */
  {
     {-6.457816e+03, -6.441148e+03},
     {-6.441148e+03, -5.891361e+03},
     {-5.891361e+03,  1.853306e+01},
     { 1.853306e+01,  8.136555e+03},
     { 8.136555e+03,  5.487490e+04}
  },
  {
  /* Coefficients for each polynomial equation V(T) */
    {
      0.0000000000E+00, 3.9475433139E+01, 2.7465251138E-02,
     -1.6565406716E-04,-1.5190912392E-06,-2.4581670924E-08,
     -2.4757917816E-10,-1.5585276173E-12,-5.9729921255E-0015,
     -1.2688801216E-17,-1.1382797374E-20
    },
    {
     -1.8533063273E+01, 3.8918344612E+01, 1.6645154356E-02,
     -7.8702374448E-05, 2.2835785557E-07,-3.5700231258E-10,
      2.9932909136E-13,-1.2849848798E-16, 2.2239974336E-20,
      0.00, 0.00
    }
  },

  /* Coefficients for each polynomial equation T(V) in C */
  {
    {-8.887677e+05,-2.054743e+02, 1.307316e-02, 5.611858e-06, 3.034392e-10},
    {-1.215521e+06,-7.993152e+02,-1.971155e-01,-2.160351e-05,-8.879453e-10},
    {0.0000000e+00, 2.382475e-02,-2.372981e-06,-6.567714e-10,-9.208444e-14},
    {0.0000000e+00, 2.548081e-02,-5.270562e-07, 7.989244e-11,-3.520933e-15},
    {-1.035821e+01, 2.712314e-02,-1.781781e-07, 3.243000e-12,-1.166816e-17}
  }
};


double scale;   /* transformation scale */


/* calculate seebeck voltage value for a given temperature and TC */
/*
double calc_seebeck(double tempin)
{
   return (SEEBECK_COEF * tempin);
}
*/


/* calculate TC temperature given volts using polynomial equations */
double volt2temp_poly(double voltin)   /* input voltage */
{
  int pi; /* index to appropriate polynom */
  int i;
  double yout;

  if (voltin < TC_VOLT_MIN)  /* check to see if voltage in valid range */
  {
      voltin = TC_VOLT_MIN;
  }
  else if (voltin > TC_VOLT_MAX)
  {
      voltin = TC_VOLT_MAX;
  }
  pi = 0;
  /* search through breakpoint list looking for proper interval */
  while ( (pi < NUMEQN_V) &&
              !((voltin >= tc_table.v_range[pi].min) &&
               (voltin <= tc_table.v_range[pi].max)))
  {
    pi++;
  }

  /* calculate TC temperature as a function of volts */
  yout = tc_table.coef_v[pi][ORDE_V];

  for (i=ORDE_V-1; i<=0; i--)
  {
       /* efficient, nested polynomial calculation */
    yout = yout*voltin+tc_table.coef_v[pi][i];
  }

  return (yout);
}


/******************************************************************************
                    CONVERTS TC VOLTS TO TEMPERATURE
                    --------------------------------
       Reference temperature sensored by IC LM335Z, which has output
   characteristic: 10 mV/K. Scale has been stated 5/1023 = 4.9 mV/LSB,
   so if we have vi (in integer), it must be multiplied by scale to convert
   to voltage temperature, and divided it by resolution of sensor to get
   real temperature. ref_scale = scale/LM335_VT = (4.9 mV/LSB)/(10 mV/K) =
   0.49 K/LSB. Increasing vi in its LSB will increase temperature by 0.49 K.
       When calibrate (T=25 C), LM335 generate 2.982 volts (273.2+25) according
   to his current temperature. In Differential op-amp, this temperature-based
   voltage used to compute temperature reference. We don't need to compute it
   in MCU.
   All of 'kerumitan' has been handled by op-amps.
*******************************************************************************/
void tc_converter(unsigned int *vi,    /* measured TC volts  */
                   double *temp)          /* linearized temperature */
             /* return: error code, 0 = no error */
{
   int i;
   double v;

   for (i=ADC_1; i<=ADC_8; i++)
   {
      v = DIGIT_TO_MILLIVOLT(vi[i])/TC_GAIN_AMP*1000; /* unit in microvolts !*/
      temp[i] = volt2temp_poly(&v);
   }
}


double lin_t[N_ADC_CHANNELS];       /* linearized temperature */

void TC_Task(void)
{
    unsigned int *mbx;

    /* ADC resolution */
    scale = (double)(VREF_PLUS-VREF_MIN)/(double)((1<<RESOLUTION)-1); /* mV/bit */
    #ifdef _WSC_
    FOREVER
    {
        mbx = _mcx_receive_w(CNV_SEMA);
        tc_converter((mbx, (double *)lin_t);
        _mcx_send_mbx_w(TC_MBX, lin_t, CNV_FINISH_SEMA);
        _mcx_msg_done(mbx);
    }
    #endif
}

SLIISR.S

;����������������������������������������������������������������������������Ŀ
;�                            SLIP PROTOCOL                                   �
;�                          INTERRUPT HANDLER                                 �
;�             for 68HC16Z1 Microcontroller running MCX-16                    �
;�                                                                            �
;�                 compiled with Whitesmiths C compiler                       �
;�                                                                            �
;�                            (c) June 1995                                   �
;�                               M. Lutfi                                     �
;�                      Engineering Physics Dept.                             �
;�                     Faculty of Industrial Tech.                            �
;�                     Institut Technologi Bandung                            �
;�                                                                            �
;������������������������������������������������������������������������������

.PROCESSOR M68HC16
.TITLE "Thesis Project : SLIP - communication handler"
.INCLUDE "hc16regs.mac"
.INCLUDE "mcx16.mac"
.INCLUDE "lgrset.mac"

;*******************************************************************************
;*  SCI DRIVER DATA VARIABLES                                                  *
;*******************************************************************************
.PUBLIC _in_char, _out_char
    .psect  _data

_in_char:    .BYTE (1)
_out_char:   .BYTE (1)
_dest_temp:  .BYTE (1)
_src_temp:   .BYTE (1)


    .psect    _text
    .even

.LIST + .MACRO

;*******************************************************************************
;*                                                                             *
;*                       S C I   I N P U T   D R I V E R                       *
;*                                                                             *
;*******************************************************************************
.PUBLIC _sciidrv
_sciidrv:

rdclr:    ldd    SCSR        ; Get current status of SCI
          bitb   #RDRF       ; See if receive data ready
          beq    scirdy      ; if not SCI is a
          ldab   SCDR        ; Read input data
          bra    rdclr       ; Loop until clear
scirdy:   andp   #0FF1Fh     ; Turn interrupts on again

inloop:   ldab   #1          ; bank 1
          tbek               ; EK = 1
          tbxk               ; XK = 1 (K=$11xx)
          ldab   #SCI_RCV_SEMA
          ldaa   #MCX_WAIT_  ; Wait for input character
          swi

          ldaa   _in_char         ; Get input character captured by isr
          ldx    #_src_temp       ; Move it to safe place
          staa   0,x
          ldab   #SCI_RCV_Q       ; Then move the character into SCIIQ
          ldaa   #MCX_ENQUEUE_W_
          swi

          bra    inloop      ; Loop forever

;*******************************************************************************
;*                                                                             *
;*                     S C I   O U T P U T   D R I V E R                       *
;*                                                                             *
;*******************************************************************************

sciodrv:  ldab   #0Fh
          tbek               ; EK=F  (K=$Fxxx)
          ldab   #1
          tbxk               ; XK=1  (K=$F1xx)

scioloop:
          ldx    #_dest_temp
          ldab   #SCI_TRM_Q      ; Get next character from SCI_TRM_Q and put it into
          ldaa   #MCX_DEQUEUE_W_ ; _dest_temp as temporary location
          swi

          ldab   0,x         ; Get the character
          cmpb   #0Ah        ; New Line?
          bne    notnl       ; Branch if not "\n"
          ldd    SCSR        ; Get SCI status
          ldaa   #0Dh
          staa   SCDR+1      ; Output a "\r"
          ldd    #RIE+RE+TE+TIE
          std    SCCR1       ; Enable transmitter interrupts
;         ldab   #RIE+RE+TE+TIE
;         stab   SCCR1+1     ; Enable transmitter interrupts

          ldab   #SCI_TRM_SEMA   ; Wait for it to be output completely
          ldaa   #MCX_WAIT_
          swi

notnl:    ldd    SCSR        ; Read status
          ldaa   0,x         ; Get character to output
          staa   SCDR+1      ; Output it
          ldd    #RIE+RE+TE+TIE
          std    SCCR1       ; Enable transmitter interrupts
;         ldab   #RIE+RE+TE+TIE
;         stab   SCCR1+1     ; Enable transmitter interrupts

          ldab   #SCI_TRM_SEMA   ; Wait for it to be output completely
          ldaa   #MCX_WAIT_
          swi

          bra    scioloop    ; Loop forever

;*******************************************************************************
;*                                                                             *
;*           S C I   I N T E R R U P T   S E R V I C E   R O U T I N E         *
;*                                                                             *
;*******************************************************************************


sciisr:   orp    #INTS_OFF   ; Save the interrupt context
          pshm   d,e,x,y,z,k
          ldab   #1
          tbek               ; EK=1  (K=$1xxx)
          tbyk               ; YK=1  (K=$1x1x)
          tbzk               ; ZK=1  (K=$1x11)
          clrb
          tbxk               ; XK=0  (K=$1011)
          ldx    0000h       ; x = [$10000]
          tst    000Ah
          bne    notlvl0
          ldy    0004h       ; y = [$10004]
          sts    8,y         ; [y+8] = SP
          lds    14h,x       ; SP = [X+20]
notlvl0:  inc    000Ah       ; [$1000A] = [$1000A]+1
          andp   #SCIINTON   ; Interrupts back on
          ldz    12h,x

          ldab   #0Fh        ; EK = F  (K=$Fx11)
          tbek
          ldab   #1
          tbxk               ; XK = 1  (K=$F111)
          ldx    #0000      ;h
          ldy    #_in_char   ; y = &inchar

          ldd    SCCR1       ; If TDRE is set, see if SCCR1 has TIE set
          bitb   #TIE
          beq    notout      ; If not, this is not an output interrupt
          ldd    SCSR        ; Check SCI status register for TDRE
          bita   #TDRE
          beq    chkrd       ; TDRE not set
          ldd    #RIE+RE+TE  ; If so, this is a transmitter interrupt, turn
                             ;  TIE off now that the character is out
          std    SCCR1       ; Update SCCR1. That takes care of the output side

          ldd    SCSR        ; Now treat a possible input interrupt that is
                             ;  simultaneous with the output. Reread the status
          bitb   #RDRF       ; Check for RDRF set
          beq    noin        ; Branch if no input occurred
          ldd    SCDR        ; Yes it did. Read the input character
          andb   #7Fh        ; Strip it to 7 bits
          stab   0,y         ; Store in temporary location (inchar)
          PSHSEMA SCI_TRM_SEMA   ; Put SCI_TRM_SEMA into Signal List
noin:     ldaa   #SCI_TRM_SEMA   ; Now signal the SCI output semaphore
          jmp    isrrtn

notout:
          ldd    SCSR        ; Read status again
chkrd:
          bitb   #RDRF       ; See if this is an input interrupt. Check RDRF
          beq    notin       ; It is not an input interrupt. So what was it?
          ldd    SCDR        ; If it was an input interrupt, get the character
          stab   0,y         ; Store in temporary location (inchar)
                             ; That takes care of the input. Now see if there
                             ;  was a simultaneous output interrupt
          ldd    SCSR        ; Check SCI status register for TDRE
          bita   #TDRE
          beq    noout       ; TDRE not set
          ldd    SCCR1       ; If TDRE is set, see if SCCR1 has TIE set
          bitb   #TIE
          beq    noout       ; If not, this cannot be an output interrupt
          ldd    #RIE+RE+TE  ; If so, this is a transmitter interrupt, turn
                             ;  TIE off now that the character is out
          std    SCCR1       ; Update SCCR1
          PSHSEMA SCI_TRM_SEMA   ; Signal SCI Output Semaphore

noout:    ldaa   #SCI_RCV_SEMA   ; Now signal the input semaphore
          jmp    isrrtn

notin:    clra               ; This wasn't a recognizable SCI interrupt
          jmp    isrrtn

;*******************************************************************************
;*  SCI VECTOR                                                                 *
;*******************************************************************************


.END

SCIDRV.S

;*****************************************************************************
;*                                                                           *
;*                 S C I   D R I V E R   M O D U L E                         *
;*             UNDER HC16 MULTITASKING EXECUTIVE (MCX16)                     *
;*                         WITH SLIP PROTOCOL                                *
;*                                                                           *
;            Compiled with Whitesmith Cross Assember ver 1.9                 *
;*                        (c) 11 December 1994                               *
;*                            by M. Lutfi                                    *
;*                          Thesis Project                                   *
;*                 Instrumentation and Controls lab.                         *
;*                 Department of Engineering Physics                         *
;*                  FACULTY OF INDUSTRIAL TECHNOLOGY                         *
;*                  BANDUNG INSTITUTE OF TECHNOLOGY                          *
;*****************************************************************************
.PROCESSOR M68HC16
.TITLE "SCI DRIVER MODULE"

.INCLUDE "lgrset.s"

          .PAGE "SCIDRV"
;*******************************************************************************
;*                                                                             *
;*                       S C I   I N P U T   D R I V E R                       *
;*                      with SLIP data-link layer protocol                     *
;*******************************************************************************


sciidrv:
      orp    #INTS_OFF   ; Turn off interrupts while enabling SCI
      ldab   #0Fh
      tbek               ; EK = F (K=Fxxxh)

      ldd    #008Ah
      std    QMCR        ; Set IARB=10 for intermodule bus arbitration

      ldd    QILR        ; Get content of QSM Interrupt Levels Register
      anda   #0E8h       ; Clear out ILSCI field
      oraa   #SCIINTLV   ; Set SCI interrupt level in ILSCI field
      ldab   #SCIINTV    ; Load SCI Interrupt Vector #
      std    QILR        ; Update QILR

      ldd    #RIE+RE+TE  ; Receiver enabled with interrupts active,
                         ; Transmitter enabled without interrupts,
                         ; 1 Start Bit, 1 Stop Bit, 8 Data Bits
      std    SCCR1       ; Set up SCI operating conditions
      ldd    #BR9600     ; Set up 9600 baud rate
      std    SCCR0

rdclr:
      ldd    SCSR        ; Get current status of SCI
      bitb   #RDRF       ; See if receive data ready
      beq    scirdy      ; if not SCI is a
      ldab   SCDR        ; Read input data
      bra    rdclr       ; Loop until clear

scirdy:
      andp   #0FF1Fh      ; Turn interrupts on again

inloop:
      ldab   #1
      tbek               ; EK = 1
      tbxk               ; XK = 1 (K=11xxh)
      ldab   #SCIISEMA
      ldaa   #MCX_WAIT   ; Wait for input character
      swi

      ldaa   inchar      ; Get input character captured by isr
      ldx    #EQ3src     ; Move it to safe place
      staa   0,x
      ldab   #SCIIQ      ; Then move the character into SCIIQ
      ldaa   #MCX_ENQUEUE_W
      swi

      bra    inloop      ; Loop forever

          .PAGE "SCIDRV"
;*******************************************************************************
;*                                                                             *
;*                     S C I   O U T P U T   D R I V E R                       *
;*                                                                             *
;*******************************************************************************

sciodrv:  ldab   #0Fh
          tbek               ; EK=F  (K=Fxxxh)
          ldab   #1
          tbxk               ; XK=1  (K=F1xxh)

scioloop: ldx    #DQ4dest
          ldab   #SCIOQ      ; Get next character from SCIOQ and put it into
          ldaa   #MCX_QUEUE_W  ; DQ4dest as temporary location
          swi

          ldab   0,x         ; Get the character
          cmpb   #0Ah        ; New Line?
          bne    notnl       ; Branch if not "\n"
          ldd    SCSR        ; Get SCI status
          ldaa   #0Dh
          staa   SCDR+1      ; Output a "\r"
          ldd    #RIE+RE+TE+TIE
          std    SCCR1       ; Enable transmitter interrupts
;         ldab   #RIE+RE+TE+TIE
;         stab   SCCR1+1     ; Enable transmitter interrupts

          ldab   #SCIOSEMA   ; Wait for it to be output completely
          ldaa   #MCX_WAIT
          swi

notnl:    ldd    SCSR        ; Read status
          ldaa   0,x         ; Get character to output
          staa   SCDR+1      ; Output it
          ldd    #RIE+RE+TE+TIE
          std    SCCR1       ; Enable transmitter interrupts
;         ldab   #RIE+RE+TE+TIE
;         stab   SCCR1+1     ; Enable transmitter interrupts

          ldab   #SCIOSEMA   ; Wait for it to be output completely
          ldaa   #MCX_WAIT
          swi

          bra    scioloop    ; Loop forever

          .PAGE "SCIDRV"
;�����������������������������������������������������������������������������Ŀ
;�                                                                             �
;�           S C I   I N T E R R U P T   S E R V I C E   R O U T I N E         �
;�                                                                             �
 �������������������������������������������������������������������������������

.MACRO pshsema
          ldab   ?1
          orp    #INTS_OFF
          lde    06h,x
          stab   e,z
          incw   06h,x
          andp   #SCIINTON
 .EXITM

sciisr:
          orp    #INTS_OFF   ; Save the interrupt context
          pshm   d,e,x,y,z,k
          ldab   #1
          tbek               ; EK=1  (K=1xxxh)
          tbyk               ; YK=1  (K=1x1xh)
          tbzk               ; ZK=1  (K=1x11h)
          clrb
          tbxk               ; XK=0  (K=1011h)
          ldx    0000h
          tst    000Ah
          bne    notlvl0
          ldy    0004
          sts    8,y
          lds    14h,x
notlvl0:  inc    000Ah
          andp   #SCIINTON   ; Interrupts back on
          ldz    12h,x

          ldab   #0Fh         ; EK = F  (K=$Fx11)
          tbek
          ldab   #1
          tbxk               ; XK = 1  (K=$F111)
          ldx    #0000
          ldy    #inchar

          ldd    SCCR1       ; If TDRE is set, see if SCCR1 has TIE set
          bitb   #TIE
          beq    notout      ; If not, this is not an output interrupt
          ldd    SCSR        ; Check SCI status register for TDRE
          bita   #TDRE
          beq    chkrd       ; TDRE not set
          ldd    #RIE+RE+TE  ; If so, this is a transmitter interrupt, turn
                             ;  TIE off now that the character is out
          std    SCCR1       ; Update SCCR1. That takes care of the output side

          ldd    SCSR        ; Now treat a possible input interrupt that is
                             ;  simultaneous with the output. Reread the status
          bitb   #RDRF       ; Check for RDRF set
          beq    noin        ; Branch if no input occurred
          ldd    SCDR        ; Yes it did. Read the input character
          andb   #7Fh        ; Strip it to 7 bits
          stab   0,y         ; Store in temporary location (inchar)
          pshsema SCIISEMA   ; Put SCIISEMA into Signal List
noin:     ldaa   #SCIOSEMA   ; Now signal the SCI output semaphore
          jmp    isrrtn

notout:   ldd    SCSR        ; Read status again
chkrd:    bitb   #RDRF       ; See if this is an input interrupt. Check RDRF
          beq    notin       ; It is not an input interrupt. So what was it?
          ldd    SCDR        ; If it was an input interrupt, get the character
          andb   #7Fh        ; Strip it to 7 bits
          stab   0,y         ; Store in temporary location (inchar)
                             ; That takes care of the input. Now see if there
                             ;  was a simultaneous output interrupt
          ldd    SCSR        ; Check SCI status register for TDRE
          bita   #TDRE
          beq    noout       ; TDRE not set
          ldd    SCCR1       ; If TDRE is set, see if SCCR1 has TIE set
          bitb   #TIE
          beq    noout       ; If not, this cannot be an output interrupt
          ldd    #RIE+RE+TE  ; If so, this is a transmitter interrupt, turn
                             ;  TIE off now that the character is out
          std    SCCR1       ; Update SCCR1
          pshsema SCIOSEMA   ; Signal SCI Output Semaphore

noout:    ldaa   #SCIISEMA   ; Now signal the input semaphore
          jmp    isrrtn

notin:    clra               ; This wasn't a recognizable SCI interrupt
          jmp    isrrtn

          .PAGE "SCIDRV"
;���������������������������������������������������������������������������Ŀ
;� SCI VECTOR                                                                �
;�����������������������������������������������������������������������������

          .PSECT   _text
          .ADDR    sciisr

;���������������������������������������������������������������������������Ŀ
;� SCI DRIVER DATA VARIABLES                                                 �
;�����������������������������������������������������������������������������

          .PSECT _data ; 003FDh

inchar:   .BYTE     1
DQ4dest:  .BYTE     1
EQ3src:   .BYTE     1

.END

SCIDRV.ASM

******************************************************************************
*                       S C I   D R I V E R   M O D U L E                     *
*                                                                             *
*******************************************************************************

isrrtn    equ    $360        ; Address of Common Interrupt Exit routine

SCIINTLV  equ    5           ; SCI Interrupt Level
SCIINTV   equ    $3A         ; SCI Interrupt Vector

QMCR      equ    $FC00
QILR      equ    $FC04       ; QSM Interrupt Levels Register
QIVR      equ    $FC05       ; QSM Interrupt Vector Register

SCCR0     equ    $FC08       ; SCI Control Register 0
SCCR1     equ    $FC0A       ; SCI Control Register 1
SCSR      equ    $FC0C       ; SCI Status Register
SCDR      equ    $FC0E       ; SCI Data Register

*******************************************************************************
*  SCCR1 REGISTER FIELDS                                                      *
*******************************************************************************

SRK       equ    $01         ; Send Break
RWU       equ    $02         ; Receiver Wakeup
RE        equ    $04         ; Receiver Enable
TE        equ    $08         ; Transmitter Enable
RIE       equ    $20         ; Receiver Interrupt Enable
TIE       equ    $80         ; Transmitter Interrupt Enable

*******************************************************************************
*  SCI STATUS REGISTER FIELDS                                                 *
*******************************************************************************

RDRF      equ    $40         ; Receive Data Register Full
TDRE      equ    $01         ; Transmit Data Register Empty (high byte of $0100)

*******************************************************************************
*  SCI DRIVER EQUATES                                                         *
*******************************************************************************

INTS_OFF  equ    $00E0       ; Disable interrupts
SCIINTON  equ    (SCIINTLV<<5+$FF1F) ; Enable interrupts at SCIINTLV (2)
BR9600    equ    $37         ; SCCR0(0-12) setting for 9600 Baud

          PAGE
*******************************************************************************
*                                                                             *
*                       S C I   I N P U T   D R I V E R                       *
*                                                                             *
*******************************************************************************

sciidrv:  orp    #INTS_OFF   ; Turn off interrupts while enabling SCI
          ldab   #$F
          tbek               ; EK = F (K=$Fxxx)

          ldd    #$008A
          std    QMCR        ; Set IARB=10 for intermodule bus arbitration

          ldd    QILR        ; Get content of QSM Interrupt Levels Register
          anda   #$E8        ; Clear out ILSCI field
          oraa   #SCIINTLV   ; Set SCI interrupt level in ILSCI field
          ldab   #SCIINTV     ; Load SCI Interrupt Vector #
          std    QILR        ; Update QILR

          ldd    #RIE+RE+TE  ; Receiver enabled with interrupts active,
                             ; Transmitter enabled without interrupts,
                             ; 1 Start Bit, 1 Stop Bit, 8 Data Bits
          std    SCCR1       ; Set up SCI operating conditions
          ldd    #BR9600     ; Set up 9600 baud rate
          std    SCCR0

rdclr:    ldd    SCSR        ; Get current status of SCI
          bitb   #RDRF       ; See if receive data ready
          beq    scirdy      ; if not SCI is a
          ldab   SCDR        ; Read input data
          bra    rdclr       ; Loop until clear
scirdy:   andp   #$FF1F      ; Turn interrupts on again

inloop:   ldab   #1          ; bank 1
          tbek               ; EK = 1
          tbxk               ; XK = 1 (K=$11xx)
          ldab   #SCIISEMA
          ldaa   #MCX_WAIT   ; Wait for input character
          swi

          ldaa   inchar      ; Get input character captured by isr
          ldx    #EQ3src     ; Move it to safe place
          staa   0,x
          ldab   #SCIIQ      ; Then move the character into SCIIQ
          ldaa   #MCX_ENQUEUE_W
          swi

          bra    inloop      ; Loop forever

          PAGE
*******************************************************************************
*                                                                             *
*                     S C I   O U T P U T   D R I V E R                       *
*                                                                             *
*******************************************************************************

sciodrv:  ldab   #$F
          tbek               ; EK=F  (K=$Fxxx)
          ldab   #1
          tbxk               ; XK=1  (K=$F1xx)

scioloop: ldx    #DQ4dest
          ldab   #SCIOQ      ; Get next character from SCIOQ and put it into
          ldaa   #MCX_DEQUEUE_W  ; DQ4dest as temporary location
          swi

          ldab   0,x         ; Get the character
          cmpb   #$0A        ; New Line?
          bne    notnl       ; Branch if not "\n"
          ldd    SCSR        ; Get SCI status
          ldaa   #$0D
          staa   SCDR+1      ; Output a "\r"
          ldd    #RIE+RE+TE+TIE
          std    SCCR1       ; Enable transmitter interrupts
;         ldab   #RIE+RE+TE+TIE
;         stab   SCCR1+1     ; Enable transmitter interrupts

          ldab   #SCIOSEMA   ; Wait for it to be output completely
          ldaa   #MCX_WAIT
          swi

notnl:    ldd    SCSR        ; Read status
          ldaa   0,x         ; Get character to output
          staa   SCDR+1      ; Output it
          ldd    #RIE+RE+TE+TIE
          std    SCCR1       ; Enable transmitter interrupts
;         ldab   #RIE+RE+TE+TIE
;         stab   SCCR1+1     ; Enable transmitter interrupts

          ldab   #SCIOSEMA   ; Wait for it to be output completely
          ldaa   #MCX_WAIT
          swi

          bra    scioloop    ; Loop forever

          PAGE
*******************************************************************************
*                                                                             *
*           S C I   I N T E R R U P T   S E R V I C E   R O U T I N E         *
*                                                                             *
*******************************************************************************

pshsema   macro
          ldab   #\1
          orp    #INTS_OFF
          lde    $06,x
          stab   e,z
          incw   $06,x
          andp   #SCIINTON
          endm

sciisr:   orp    #INTS_OFF   ; Save the interrupt context
          pshm   d,e,x,y,z,k
          ldab   #1
          tbek               ; EK=1  (K=$1xxx)
          tbyk               ; YK=1  (K=$1x1x)
          tbzk               ; ZK=1  (K=$1x11)
          clrb
          tbxk               ; XK=0  (K=$1011)
          ldx    $0000       ; x = [$10000]
          tst    $000A
          bne    notlvl0
          ldy    $0004       ; y = [$10004]
          sts    8,y         ; [y+8] = SP
          lds    $14,x       ; SP = [X+20]
notlvl0:  inc    $000A       ; [$1000A] = [$1000A]+1
          andp   #SCIINTON   ; Interrupts back on
          ldz    $12,x

          ldab   #$F         ; EK = F  (K=$Fx11)
          tbek
          ldab   #1
          tbxk               ; XK = 1  (K=$F111)
          ldx    #$0000      ;
          ldy    #inchar     ; y = &inchar

          ldd    SCCR1       ; If TDRE is set, see if SCCR1 has TIE set
          bitb   #TIE
          beq    notout      ; If not, this is not an output interrupt
          ldd    SCSR        ; Check SCI status register for TDRE
          bita   #TDRE
          beq    chkrd       ; TDRE not set
          ldd    #RIE+RE+TE  ; If so, this is a transmitter interrupt, turn
                             ;  TIE off now that the character is out
          std    SCCR1       ; Update SCCR1. That takes care of the output side

          ldd    SCSR        ; Now treat a possible input interrupt that is
                             ;  simultaneous with the output. Reread the status
          bitb   #RDRF       ; Check for RDRF set
          beq    noin        ; Branch if no input occurred
          ldd    SCDR        ; Yes it did. Read the input character
          andb   #$7F        ; Strip it to 7 bits
          stab   0,y         ; Store in temporary location (inchar)
          pshsema SCIISEMA   ; Put SCIISEMA into Signal List
noin:     ldaa   #SCIOSEMA   ; Now signal the SCI output semaphore
          jmp    isrrtn

notout:   ldd    SCSR        ; Read status again
chkrd:    bitb   #RDRF       ; See if this is an input interrupt. Check RDRF
          beq    notin       ; It is not an input interrupt. So what was it?
          ldd    SCDR        ; If it was an input interrupt, get the character
          andb   #$7F        ; Strip it to 7 bits
          stab   0,y         ; Store in temporary location (inchar)
                             ; That takes care of the input. Now see if there
                             ;  was a simultaneous output interrupt
          ldd    SCSR        ; Check SCI status register for TDRE
          bita   #TDRE
          beq    noout       ; TDRE not set
          ldd    SCCR1       ; If TDRE is set, see if SCCR1 has TIE set
          bitb   #TIE
          beq    noout       ; If not, this cannot be an output interrupt
          ldd    #RIE+RE+TE  ; If so, this is a transmitter interrupt, turn
                             ;  TIE off now that the character is out
          std    SCCR1       ; Update SCCR1
          pshsema SCIOSEMA   ; Signal SCI Output Semaphore

noout:    ldaa   #SCIISEMA   ; Now signal the input semaphore
          jmp    isrrtn

notin:    clra               ; This wasn't a recognizable SCI interrupt
          jmp    isrrtn

          PAGE
*******************************************************************************
*  SCI VECTOR                                                                 *
*******************************************************************************

          ORG    SCIINTV*2

          dc.w   sciisr

*******************************************************************************
*  SCI DRIVER DATA VARIABLES                                                  *
*******************************************************************************

          ORG    $003FD

inchar:   ds     1
DQ4dest:  ds     1
EQ3src:   ds     1

*******************************************************************************
*                                                                             *
*                       S C I   D R I V E R   M O D U L E                     *
*