/**********************************************************/
/*   Functions to support the 68HC16 QSM Module.          */
/*   The demo program loads the message "Hello World"     */
/*   into the transmit buffer of the Queued Serial        */
/*   Module. Then it sets the Loopback mode of the        */
/*   module. The message is then sent out and received    */
/*   in the Receive buffer of the QSM. The bytes are      */
/*   then retrieved and put into character array MsgRx.   */


/**********************************************************/
/* Initialize QSM - The Queued Serial Module is in an idle*/
/* state after reset. This routine is used to initialize  */
/* the module and prepare it for use.                     */


#define _UCHAR  unsigned char
#define _USHORT unsigned short

QSM_setup()
{
/* Page 5-42 of Motorola Mc68332 Manual */
/* Flowchart of QSPI Initialization Operation */

int dummy_var = 9;     /* a cosmic requirement for now */

/* CPU Initializes QSM Global Registers */
   QMCR_Config();
   QILR_Config();
   QIVR_Config();

/* CPU Initializes QSM Pin Registers */
   QPDR_Config();
   QPAR_Config();
   QDDR_Config();

/* CPU Initializes QSPI Control Registers */
   SPCR0_Config();
   SPCR1_Config(); /* With the exception of the start bit */
   SPCR2_Config();
   SPCR3_Config();

}

/**********************************************************/
/* QSM Configuration Register - This routine sets the QSM */
/* up to use Normal QSM Clock operation, enables the FRZ1 */
/* signal, and sets access for both user and supervisor.  */
/* It also sets the QSM arbitration Id number to F        */
/* (highest priority).                                    */

QMCR_Config()
{

/* Configure the QMCR register */
/* Set to allow unrestricted access, clear FREEZE bit     */
_USHORT STOP_MASK = 0x7FFF; /* Shut off bit, use AND logical function */
_USHORT SUPV_MASK = 0xFF7F; /* Shut off bit, use AND logical function */
_USHORT FRZ1_MASK = 0x4000; /* Turn on bit, use OR logical function */
_USHORT IARB_MASK = 0x000F; /* Turn on bits, use OR logical function */

_USHORT QMCR_REG;

/*  Address of QSM Configuration Register  */
@far _USHORT QMCR_LOC  @0xFFC00;

/* Get the value of the QMCR_REGISTER from reset location. */
QMCR_REG = QMCR_LOC;

/* Insure that the value of the stop bit is zero. */
QMCR_REG = QMCR_REG & STOP_MASK;

/* Insure that the value of the FRZ bit is a one. */
QMCR_REG = QMCR_REG | FRZ1_MASK;

/* Insure that the value of the SUPV bit is a zero. */
QMCR_REG = QMCR_REG & SUPV_MASK; 

/* Set highest priority for QSM in interrupt arbitration */
QMCR_REG = QMCR_REG | IARB_MASK;

/* Replace QSM Configuration Register with Modified Value */
QMCR_LOC = QMCR_REG;

}

/**********************************************************/
/* QSM Interrupt Level Register - This routine is used to */
/* set Interrupt Level of the QSM's Queued Serial         */
/* interface and the Serial Communications Interface. It  */
/* is not assigned in both cases.                         */ 

QILR_Config()
{
_USHORT QILR_MASK = 0x000F; /* Interrupt level not initalized. */

/* Temporary Location of QILR Register. */
unsigned short QILR_REG;

/*  Address of QSM Interrupt Level Register after reset.  */
@far _USHORT QILR_LOC @0xFFC04;

/* Get the value of the QILR_REGISTER from reset location. */
QILR_REG = QILR_LOC;

/* Set Interrupt Level to Desired Values */
QILR_REG = QILR_REG | QILR_MASK;

/* Replace QSM Interrupt Level Register with Modified Value */
QILR_LOC = QILR_REG;

}

/**********************************************************/
/* QSM Interrupt Vector Register - This routine sets the  */
/* Vector for handling interrupts for each sub-module. The*/
/* QSPI will not use interupts, and a vector is not       */
/* assigned                                               */

QIVR_Config()
{
int QIVR_MASK = 0x000F;  /* Writes default value in INTV  */

/* Temporary Location of QIVR Register. */
unsigned short QIVR_REG;

/* Address of QSM Interrupt Vector Register after reset. */
@far _USHORT QIVR_LOC  @0xFFC04; /* Actually FFC05 but bit Mask  */

                                      /* is set up to modify last 8    */
                                     /* bits which is the same thing. */

/* Get the value of the QIVR_REGISTER from reset location. */
QIVR_REG = QIVR_LOC;

/* Set Interrupt Vector value to $0F. */
QIVR_REG = QIVR_REG | QIVR_MASK;

/* Replace QSM Interrupt Vector Register with Modified Value */
QIVR_LOC = QIVR_REG;

}

/**********************************************************/
/* QSM Port Data Register - If the I/O pins are defined as*/
/* general purpose I/O, then this is the register that    */
/* contain the value that the QSM port will output. The   */
/* actual usage of the pins in this port are defined in   */
/* QPAR. In this example these pins are going to be       */
/* assigned to the QSPI module.                           */

QPDR_Config()
{
_USHORT QPDR_MASK = 0x0083; /* Value to assign pins to QPSI */
                        /* All chip selects are on, and */
                        /* the transmit bit is set on.  */
                        /* Master Out Slave In, Master  */
                        /* In Slave Out are enabled.    */

/* Temporary Location of QSM Port Data Register. */
unsigned short QPDR_REG;

/* Address of QSM Port Data Register after reset. */
 @far _USHORT   QPDR_LOC  @0xFFC14;

/* Get the value of the QPDR_REGISTER from reset location. */
QPDR_REG = QPDR_LOC;

/* Set Up the Register Value  */
QPDR_REG = QPDR_REG | QPDR_MASK;

/* Replace QSM Port Data Register with Modified Value */
QPDR_LOC = QPDR_REG;

}

/**********************************************************/
/* QSM Pin Assignment Register - This routine assigns the */
/* pins to the QSPI module.                               */

QPAR_Config()
{
_USHORT QPAR_MASK = 0x0000; /* Assigns pins to QSPI module    */
                        /* All chip select pins are       */
                        /* enabled, Master Out Slave In   */
                        /* Slave Out Master In are        */
                        /* enabled.                       */

/* Temporary Location of QSM Pin Assignment Register. */
unsigned short QPAR_REG;

/* Address of QSM Pin Assignment Register after reset. */
 @far _USHORT   QPAR_LOC @0xFFC16;

/* Get the value of the QPAR_REGISTER from reset location. */
QPAR_REG = QPAR_LOC;

/* Set Up the Register Value  */
QPAR_REG = QPAR_REG | QPAR_MASK;

/* Replace QSM Pin Assignment Register with Modified Value */
QPAR_LOC = QPAR_REG;

}

/**********************************************************/
/* QSM Data Direction Register - This routine is used to  */
/* specify the direction of the pins assigned by the QPAR */
/* Register. Since it is set up correctly at reset I do   */
/* nothing here. (I think!)                               */

QDDR_Config()
{
_USHORT QDDR_MASK = 0x0083; /* Transmit bit set on, Master Out*/
                        /* Slave In and Master In Slave   */
                        /* Out enabled.                   */

/* Temporary Location of QSM Data Direction Register. */
unsigned short QDDR_REG;

/* Address of QSM Data Direction Register after reset. */
 @far _USHORT   QDDR_LOC @0xFFC16;

/* Get the value of the QDDR_REGISTER from reset location. */
QDDR_REG = QDDR_LOC;

/* Set Up the Register Value */
QDDR_REG = QDDR_REG | QDDR_MASK;

/* Replace QSM Data Direction Register with Modified Value */
QDDR_LOC = QDDR_REG;

}

/**********************************************************/
/* QSPI Control Register - This routine sets the QSPI up  */ 
/* as a master that can initiate transmission to external */
/* serial peripheral devices. The register also affects   */
/* the clock polarity,phase and baud rate. These are all  */
/* left at their default values.                          */

SPCR0_Config()
{
   _USHORT SPCR0_MASK = 0x8104; /* Master bit On  Clock Phase */
                            /* Data is changed on the     */
                            /* leading edge, Clock rate = */
                            /* 2.10 MHz.                  */

/* Temporary Location of QSM Control Register 0. */
unsigned short SPCR0_REG;

/* Address of QSM Control Register 0 after reset. */
 @far _USHORT   SPCR0_LOC @0xFFC18;

/* Get the value of the SPCR0_REGISTER from reset location. */
SPCR0_REG = SPCR0_LOC;

/* Set Up the Register Value  */
SPCR0_REG = SPCR0_REG | SPCR0_MASK;

/* Replace QSM Control Register 0 with Modified Value */
SPCR0_LOC = SPCR0_REG;

}

/**********************************************************/
/* SPCR1_Config - This routine is used to set the QSPI    */
/* Control Register 1 values. It actually has one more    */
/* bit to set, the control bit, but since this bit will   */
/* start the QSPI immediately, it is left to be done later*/
/* when the application is completely ready.              */
/* The actual bits used in the MASK are the default       */
/* setting of this register.                              */

SPCR1_Config()
{
_USHORT SPCR1_MASK = 0x0404; /* Default DSCKL delay is set    */
                         /* Default DTL delay is set      */
                         /* SPE enable pin is NOT set     */

/* Temporary Location of QSPI Control Register 1. */
unsigned short SPCR1_REG;

/* Address of QSPI Control Register 1 after reset. */
 @far _USHORT  SPCR1_LOC @0xFFC1A;

/* Get the value of the SPCR1_REGISTER from reset location. */
SPCR1_REG = SPCR1_LOC;

/* Set Up the Register Value  */
SPCR1_REG = SPCR1_REG | SPCR1_MASK;

/* Replace QSPI Control Register 1 with Modified Value */
SPCR1_LOC = SPCR1_REG;

}

/**********************************************************/
/* SPCR2_Config - This routine sets the QSPI Control      */
/* Register 2. The MASK enables interrupts, and sets the  */
/* value of the ending queue pointer to 2. This is in     */
/* anticipation of only needing one command to perform the*/
/* test.                                                  */

SPCR2_Config()
{
_USHORT SPCR2_MASK = 0x4F00; /* Wrap around Enabled, EndQP    */
                         /* set to location sixteen       */

/* Temporary Location of QSPI Control Register 2. */
unsigned short SPCR2_REG;

/* Address of QSPI Control Register 2 after reset. */
 @far _USHORT   SPCR2_LOC @0xFFC1C;

/* Get the value of the SPCR2_REGISTER from reset location. */
SPCR2_REG = SPCR2_LOC;

/* Set Up the Register Value  */
SPCR2_REG = SPCR2_REG | SPCR2_MASK;

/* Replace QSPI Control Register 2 with Modified Value */
SPCR2_LOC = SPCR2_REG;

}

/**********************************************************/
/*  SPCR3_Config - This routine set up the QSPI Control   */
/* Register 3. The LoopQ bit is set. This will cause the  */
/* transmission to be directed into the recieve buffer of */
/* the chip.                                              */

SPCR3_Config()
{
_USHORT SPCR3_MASK = 0x0400; /* Turn on LoopQ, Feedback enabled */

/* Temporary Location of QSPI Control Register 3. */
unsigned short SPCR3_REG;

/* Address of QSPI Control Register 3 after reset. */
 @far _USHORT   SPCR3_LOC @0xFFC1E;

/* Get the value of the SPCR3_REGISTER from reset location. */
SPCR3_REG = SPCR3_LOC;

/* Set Up the Register Value  */
SPCR3_REG = SPCR3_REG | SPCR3_MASK;

/* Replace QSPI Control Register 3 with Modified Value */
SPCR3_LOC = SPCR3_REG;

}

/**********************************************************/

SPCR1_Enable()
{
_USHORT SPCR1_ENABLE = 0x8000; /* Value to enable the QSPI. */

/* Temporary Location of QSM SPCR1 Register 1. */
unsigned short SPCR1_REG;

/* Address of QSM SPCR1 Register after reset. */
 @far _USHORT   SPCR1_LOC @0xFFC1A;

/* Get the value of the SPCR1_REGISTER from reset location. */
SPCR1_REG = SPCR1_LOC;

/* Set Up the Register Value  */
SPCR1_REG = SPCR1_REG | SPCR1_ENABLE;

/* Replace QSPI Control Register 1 with Modified Value */
SPCR1_LOC = SPCR1_REG;

}

/**********************************************************/

SPCR1_Disable()
{
_USHORT SPCR1_ENABLE = 0x0404; /* Value to disable the QSPI. */

/* Temporary Location of QSM SPCR1 Register 1. */
unsigned short SPCR1_REG;

/* Address of QSM SPCR1 Register after reset. */
 @far _USHORT   SPCR1_LOC @0xFFC1A;

/* Get the value of the SPCR1_REGISTER from reset location. */
SPCR1_REG = SPCR1_LOC;

/* Set Up the Register Value  */
SPCR1_REG = SPCR1_REG & SPCR1_ENABLE;

/* Replace QSPI Control Register 1 with Modified Value */
SPCR1_LOC = SPCR1_REG;

}

/*********************************************************/
/* Load_TxBuffer - Takes the Msg_buffer contents and     */
/* and moves it into the QSM tranmit buffer.             */

Load_TxBuf(Msg)
char *Msg;
{
   _USHORT i;
   char *TxBuffer = (char *)0xFFD20;
   for(i = 0; i < 32; i++)
      {
         *(TxBuffer + i) = *(Msg + i);
       
      }
}

/*********************************************************/
/*                                                       */
/* Load_CmdBuf - This routine loads into the CmdBuf Queue*/
/* the commands to transmit the contents of the TxBuffer */
/* In this example two transmit instructions are written */

Load_CmdBuf()
{
   _USHORT i;
@far _UCHAR  CmdBuffer[16] @0xFFD40;

/* Command = "Keep chip selects asserted, Use the size transfers defined */
/* in the BITS portion of the SPCR0 (default 16 bits in this case)"      */

static   char Commands[16] = { 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0,
                         0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0 };

   for(i = 0; i < 16; i++)
      {
         CmdBuffer[i] = Commands[i];
      }
}


/*********************************************************/
/*                                                       */
/* UnLoad_RxBuf - This routine unloads the information   */
/* from the Receive Buffer. The contents is then moved to*/
/* an array in global memory.                   */

UnLoad_RxBuf()
{
   extern char MsgRx[32];
   _USHORT i;
@far _UCHAR  RxBuffer[32] @0xFFD00;
   
   for(i = 0; i < 32; i++)
      {
         MsgRx[i] = RxBuffer[i] ;
       
      }
}

/*********************************************************/
/*                                                       */
/* Blank_TxBuf - This routine blanks out the Transmission*/
/* buffer. It is a housekeeping function to show the     */
/* program operation more clearly.                       */

Blank_TxBuf()
{
   _USHORT i;
@far _UCHAR   TxBuf_Ptr[32] @0xFFD20;

   for(i = 0; i < 32; i++)
      {
         TxBuf_Ptr[i] = ' ';
      }
}

/*********************************************************/
/*                                                       */
/* Blank_CmdBuf - This routine blanks out the Command    */
/* buffer. It is a housekeeping function to show the     */
/* program operation more clearly.                       */

Blank_CmdBuf()
{
   _USHORT i;
@far _UCHAR   CmdBuf_Ptr[32] @0xFFD40;

   for(i = 0; i < 16; i++)
      {
         CmdBuf_Ptr[i] = ' ';
      }
}

/*********************************************************/
/* Blank_RxBuf - This routine blanks out the Receive     */
/* buffer. It is a housekeeping function to show the     */
/* program operation more clearly.                       */

Blank_RxBuf()
{
   _USHORT i;
@far _UCHAR  RxBuf_Ptr[32] @0xFFD00;

   for(i = 0; i < 32; i++)
      {
         RxBuf_Ptr[i] = ' ';
      }
}

