;* --------------------------------------------------------------------------------------
;*  Copyright (C) 2004 Dallas Semiconductor Corporation, All Rights Reserved.
;* 
;*  Permission is hereby granted, free of charge, to any person obtaining a
;*  copy of this software and associated documentation files (the "Software"),
;*  to deal in the Software without restriction, including without limitation
;*  the rights to use, copy, modify, merge, publish, distribute, sublicense,
;*  and/or sell copies of the Software, and to permit persons to whom the
;*  Software is furnished to do so, subject to the following conditions:
;* 
;*  The above copyright notice and this permission notice shall be included
;*  in all copies or substantial portions of the Software.
;* 
;*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
;*  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
;*  MERCHANTABILITY,  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
;*  IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES
;*  OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
;*  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
;*  OTHER DEALINGS IN THE SOFTWARE.
;* 
;*  Except as contained in this notice, the name of Dallas Semiconductor
;*  shall not be used except as stated in the Dallas Semiconductor
;*  Branding Policy.
;*
;*  Module:        maxq2000_spi
;*  Description:   Utility functions for configuring and using the MAXQ2000's
;*                 SPI module.
;*  Filename:      maxq2000_spi.asm
;*  Date:          November 2, 2004
;*  Version:       1.00
;*
;* --------------------------------------------------------------------------------------

#include "maxQ2000.inc"
#include "maxq2000_spi.inc"
  .code
;*******************************************************************************
;* Function:  spi_enable
;*
;* Activates/Deactivates the Serial Peripheral Interface (SPI).  This funtion
;* sets the value of the SPIEN bit of the SPICN register based on the input
;* value.
;*
;* Input:     C - 0 will disable the SPI module and 1 will enable it.
;*
;* Output:    None
;*
;* Destroys:  ACC, PSF
;*
;*******************************************************************************
spi_enable::
	jump	C, spi_enable_1
	move	SPICN.0, #0
	jump	spi_enable_set
spi_enable_1:
	move	SPICN.0, #1
spi_enable_set:
    jump    NC, spi_enable_done
    move    ACC, PD5
    or      #070h       ; Set SPI output pins (CS, SCLK, DOUT) as output.
    and     #07Fh       ; Set SPI input pin (DIN) as input.
    move    PD5, ACC
spi_enable_done:
    ret

;******************************************************************************
;* Function: spi_setmode
;*
;* Places the SPI module in either master or slave mode.  This funtion sets the
;* value of the MSTM bit of the SPICN register based on the input value.
;*
;* Input:     C - Use 'SPI_MASTER_MODE' to place the SPI module in master mode
;*                and 'SPI_SLAVE_MODE' to place the module in slave mode.
;*
;* Output:    None
;*
;* Destroys:  PSF
;*
;******************************************************************************/
spi_setmode::
	jump	C, spi_setmode_1
	move	SPICN.1, #0
	jump	spi_setmode_set
spi_setmode_1:
	move	SPICN.1, #1
spi_setmode_set:
    ret

;*******************************************************************************
;* Function:  spi_setclockpolarity
;*
;* Sets the idle logic state of the serial clock and defines which clock edge is
;* the active edge.
;*
;* Input:     C - The new value for the CKPOL bit of the SPICF register.  An
;*                input of 'SPI_IDLE_LOW' will set the rising edge of the serial
;*                clock to the active edge.  'SPI_IDLE_HIGH' sets the falling
;*                edge as the active one.
;*
;* Output:    None
;*
;* Destroys:  PSF
;*
;*******************************************************************************
spi_setclockpolarity::
	jump	C, spi_setclockpolarity_1
	move	SPICF.0, #0
	jump	spi_setclockpolarity_set
spi_setclockpolarity_1:
	move	SPICF.0, #1
spi_setclockpolarity_set:
    ret

;*******************************************************************************
;* Function:  spi_setclockphase
;*
;* Selects which edge of the clock is used to sample the serial shift data.
;*
;* Input:     C - The new value for the CKPHA bit of the SPICF register.
;*                When the input is 'SPI_ACTIVE_EDGE', data is sampled on the
;*                active clock edge.  Using an input of 'SPI_INACTIVE_EDGE' will
;*                cause the data to be sampled on the inactive clock edge.
;*
;* Output:    None
;*
;* Destroys:  PSF
;*
;*******************************************************************************
spi_setclockphase::
	jump	C, spi_setclockphase_1
	move	SPICF.1, #0
	jump	spi_setclockphase_set
spi_setclockphase_1:
	move	SPICF.1, #1
spi_setclockphase_set:
    ret

;*******************************************************************************
;* Function:  spi_setcharacterlength
;*
;* Selects the size of the SPI data transfers.
;*
;* Input:     C - The new value for the CHR bit of the SPICF register.  Use
;*                'SPI_LENGTH_8' for 8-bit transfers and 'SPI_LENGTH_16' for
;*                16-bit transfers.
;*
;* Output:    None
;*
;* Destroys:  PSF
;*
;*******************************************************************************
spi_setcharacterlength::
	jump	C, spi_setcharacterlength_1
	move	SPICF.2, #0
	jump	spi_setcharacterlength_set
spi_setcharacterlength_1:
	move	SPICF.2, #1
spi_setcharacterlength_set:
    ret

;*******************************************************************************
;* Function:  spi_setbaudrate
;*
;* Sets the serial clock baud rate by computing and setting the appropriate
;* value for the SPI Clock Divider Ratio (SPICK).  The buad rate is determined
;* using the following formula:
;*
;*            SPI Baud Rate = System Clock Frequency / (2 * Clock Divider Ratio)
;*
;* Input:     A[3:2] - the desired baudrate for the SPI serial clock in Hz.
;*            A[1:0] - the current frequency of the MAXQ's system clock in
;*                     Hz.  This value must account for the system clock
;*                     divide modes, including Power Management Mode.
;*
;* Output:    A[1:0] - The actual buad rate achieved.
;*
;* Destroys:  ACC, A[2], A[3], A[4], A[5], PSF
;*
;*******************************************************************************
spi_setbaudrate::
    move    A[4], A[0]
    move    A[5], A[1]
    call    Q20_Unsigned_Divide32
    sra
    and     #0FFh
    move    SPICK, ACC

    add     #1
    sla
    move    A[2], ACC
    move    A[3], #0
    move    A[0], A[4]
    move    A[1], A[5]
    call    Q20_Unsigned_Divide32
    ret

;*******************************************************************************
;* Function: spi_enablemodefaultdetection
;*
;* Enables the detection of mode fault errors.  This funtion sets the value of
;* the MODFE bit of the SPICN register based on the input value.
;*
;* Input:     C - 0 will disable the mode fault detection and 1 will enable it.
;*
;* Output:    None
;*
;* Destroys:  PSF
;*
;*******************************************************************************
spi_enablemodefaultdetection::
	jump	C, spi_enablemodefaultdetection_1
	move	SPICN.2, #0
	jump	spi_enablemodefaultdetection_set
spi_enablemodefaultdetection_1:
	move	SPICN.2, #1
spi_enablemodefaultdetection_set:
    ret

;*******************************************************************************
;* Function:  spi_geterrors
;*
;* Gets the types of SPI system errors that have occurred.  Three types of
;* errors can be detected by the SPI module:
;*      1.  Mode Fault - Occurs when more than one SPI device simultaneously
;*                       tries to be a master.
;*      2.  Write Collision - Occurs when an SPI transfer is attempted while
;*                            another tranfer is already in progress.
;*      3.  Receive Overrun - Occurs when an SPI transfer completes before the
;*                            previous character has been read from the receive
;*                            holding buffer.
;*
;* Input:     C - 1 to clear the error flags after they have been read.
;*
;* Output:    ACC - A mask indicating which errors have occured.  This mask will
;*                  be composed of the SPIFLAGS_MODEFAULT,
;*                  SPIFLAGS_WRITECOLLISION, and SPIFLAGS_RECEIVEOVERRUN flags.
;*
;* Destroys:  PSF
;*
;*******************************************************************************
spi_geterrors::
    jump    C, spi_geterrors_clear
    move    ACC, SPICN
    and     #SPIFLAGS_ALLERRORS
    ret
spi_geterrors_clear:
    move    ACC, SPICN
    push    ACC
    and     #0C7h
    move    SPICN, ACC
    pop     ACC
    and     #SPIFLAGS_ALLERRORS
    ret

;*******************************************************************************
;* Function: spi_enableinterrupts
;*
;* Enables any of the SPI interrupt sources (mode fault, write collition,
;* receive overrun, or transfer complete) to generate interrupt requests.  Note
;* that this function does not enable the interrupt in the IMR mask, only in the
;* SPICF register.  You may still need to enable the module interrupts with the
;* IMR mask.
;*
;* Input:     C - 0 will disable the interrupt sources and 1 will enable them.
;*
;* Output:    None
;*
;* Destroys:  PSF
;*
;*******************************************************************************
spi_enableinterrupts::
	jump	C, spi_enableinterrupts_1
	move	SPICF.7, #0
	jump	spi_enableinterrupts_set
spi_enableinterrupts_1:
	move	SPICF.7, #1
spi_enableinterrupts_set:
    ret

;*******************************************************************************
;* Function:  spi_getinterruptsources
;*
;* Gets the source of an SPI interrupt.  Four types of interrupts can be occur:
;*      1.  Mode Fault - Occurs when more than one SPI device simultaneously
;*                       tries to be a master.
;*      2.  Write Collision - Occurs when an SPI transfer is attempted while
;*                            another tranfer is already in progress.
;*      3.  Receive Overrun - Occurs when an SPI transfer completes before the
;*                            previous character has been read from the receive
;*                            holding buffer.
;*      4.  Transfer Complete - Occurs at the end of a successful SPI transfer.
;*
;* Input:     C - 1 will clear the interrupt flags after they have been read.
;*
;* Output:    ACC - A mask indicating which interrupts have occured.  This mask
;*                  will be composed of the SPIFLAGS_MODEFAULT, 
;*                  SPIFLAGS_WRITECOLLISION, SPIFLAGS_RECEIVEOVERRUN, and
;*                  SPIFLAGS_TRANSFERCOMPLETE flags.
;*
;* Destroys:  SPF
;*
;*******************************************************************************
spi_getinterruptsources::
    jump    C, spi_getinterruptsources_clear
    move    ACC, SPICN
    and     #SPIFLAGS_ALL
    ret
spi_getinterruptsources_clear:
    move    ACC, SPICN
    push    ACC
    and     #87h
    move    SPICN, ACC
    pop     ACC
    and     #SPIFLAGS_ALL
    ret

;*******************************************************************************
;* Function:  spi_transmit
;*
;* Performs a spi transfer.  First, this function waits for the SPI Transfer
;* Busy flag (STBY) to be clear.  Then, the input data is written to the SPI
;* Data Buffer (SPIB) register.  This function will then block until the
;* transfer complete flag is asserted.  Finally, the data received is returned
;* and the transfer complete flag is cleared.  Note, if master mode is enabled,
;* this function initiates the transfer.  When in slave mode, this method could
;* block forever waiting for the master to request a transfer.
;*
;* Input:     ACC - the character to transmit.
;*
;* Output:    ACC - The character received during the transfer.
;*
;* Destroys:  PSF
;*
;*******************************************************************************
spi_transmit::
    move    C, SPICN.7          ; Wait until the character can be sent.
    jump    C, spi_transmit
    move    SPICN.6, #0         ; In case it is already set, clear the
                                ; transfer complete flag.
    move    SPIB, ACC           ; Send the data.
spi_transmit_spic_test:
    move    C, SPICN.6          ; Wait for the transfer to complete.
    jump    NC, spi_transmit_spic_test
    move    ACC, SPIB           ; Get the data received.
    move    SPICN.6, #0         ; Clear the tansfer complete flag.
    ret

end
