/*************************************************************************
; Ds1302Spi.c - Demonstrates the use of the 68HC12 SPI for the DS1302 RTC.
;
; MCU: 68HC912B32, MicroC/OS-II
;
; 03/09/01 Todd Morton
;
; Revised 4/26/03 Reuben Brown
;   1. Changed SCK speed to 500 KHz
; Revised 5/10/03 Reuben Brown
;   1. Added Store32BitNum
;            Store16BitNum
;            Get16BitNum
;            Get32BitNum
;            RamRetrieve
;            RamStore
; Revised 5/27/03 Reuben Brown
;   1. Added WriteTime Function
;
;               
**************************************************************************
* Master header file
*************************************************************************/
#include "includes.h"
OS_EVENT *SpiKey;
/*************************************************************************
* Function prototypes (Public)
*************************************************************************/
void DS1302SpiInit(void);
void RTCBurstRd(RTCCLK *rtcbuf); 
void RamRetrieve(void);
void RamStore(void);
void WriteTime(INT8U hr, INT8U min);
/*************************************************************************
* Function prototypes (Private)
*************************************************************************/
INT8U DS1302SpiRd(INT8U raddr);
void DS1302SpiWr(INT8U waddr, INT8U wdata);
void Store32BitNum(INT32U number, INT8U *arrayptr, INT8U address);
void Store16BitNum(INT16U number, INT8U *arrayptr, INT8U address);
INT16U Get16BitNum(INT8U *arrayptr, INT8U address);
INT32U Get32BitNum(INT8U *arrayptr, INT8U address); 
/*************************************************************************
*Global Variables
*************************************************************************/
INT8U TwoByteArray[2];
INT8U *TwoByteArrayPtr = TwoByteArray;
INT8U FourByteArray[4];
INT8U *FourByteArrayPtr = FourByteArray;
/*************************************************************************
* Ds1302SpiInit - Initialize SPI for the Ds1302
*************************************************************************/
void DS1302SpiInit(void){
    PORTS &= ~SS;
    DDRS |= (SS|SCK|MOMI);
    SP0BR = 0x03;       /*set bit rate to 1MHz */
    SP0CR1 = 0x71;      /* Enable,Mstr,WireOR,CPOL:CPHA=00,LSB First*/
    SP0CR2 = 0x01;      /* Bidirectional SPI (MIMO) */    
}

/*************************************************************************
* DS1302SpiRd - Read DS1302. Returns the RTC register contents addressed
*               by raddr.
*************************************************************************/
INT8U DS1302SpiRd(INT8U raddr){
    INT8U err;
    OSMutexPend(SpiKey,0,&err);
    PORTS |= SS;
    DDRS |= MOMI;
    SP0DR = raddr;
    while((SP0SR & SPIF) == 0){}
    DDRS &= ~MOMI;
    SP0DR = 0xFF;
    while((SP0SR & SPIF) == 0){}
    PORTS &= ~SS;
    OSMutexPost(SpiKey);
    return SP0DR;
}

/*************************************************************************
* DS1302SpiWr - Write to DS1302. waddr is the command/address word and
*               wdata is the write data.
*************************************************************************/
void DS1302SpiWr(INT8U waddr, INT8U wdata){
    INT8U err;
    OSMutexPend(SpiKey,0,&err);    
    PORTS |= SS;
    DDRS |= MOMI;
    SP0DR = waddr;
    while((SP0SR & SPIF) == 0){}
    SP0DR = wdata;
    while((SP0SR & SPIF) == 0){}
    PORTS &= ~SS;
    OSMutexPost(SpiKey);
}

/*************************************************************************
* RTCBurstRd - Burst read of DS1302 RTC clock registers.
*              rtcbuf is the address of a RTCCLK structure to place the
*              copy of the RTC registers.
*************************************************************************/
void RTCBurstRd(RTCCLK *rtcbuf){
    INT8U err;
    OSMutexPend(SpiKey,0,&err);
    PORTS |= SS;
    DDRS |= MOMI;  
    SP0DR = CBRSTRD;
    while((SP0SR & SPIF) == 0){}
    DDRS &= ~MOMI;
    SP0DR = 0xFF;
    while((SP0SR & SPIF) == 0){}
    rtcbuf->sec = SP0DR;
    SP0DR = 0xFF;
    while((SP0SR & SPIF) == 0){}
    rtcbuf->min = SP0DR;
    SP0DR = 0xFF;
    while((SP0SR & SPIF) == 0){}
    rtcbuf->hr = SP0DR;
    SP0DR = 0xFF;
    while((SP0SR & SPIF) == 0){}
    rtcbuf->dom = SP0DR;
    SP0DR = 0xFF;
    while((SP0SR & SPIF) == 0){}
    rtcbuf->month = SP0DR;
    SP0DR = 0xFF;
    while((SP0SR & SPIF) == 0){}
    rtcbuf->dow = SP0DR;
    SP0DR = 0xFF;
    while((SP0SR & SPIF) == 0){}
    rtcbuf->year = SP0DR;
    PORTS &= ~SS;
    OSMutexPost(SpiKey);
}
/*******************************************************************************
*RamRetrieve
*   Restores all variables to MotoVars structure from
*   DS1302 battery backed RAM. Should be called at startup
*   Reuben Brown 5/10/03
*******************************************************************************/
void RamRetrieve(void){
    INT8U err;
    MotoVars.TrpTimeSecs = DS1302SpiRd(TRIPTIMESECRD);
    MotoVars.TrpTimeMins = DS1302SpiRd(TRIPTIMEMINRD);
    MotoVars.TrpTimeHrs = DS1302SpiRd(TRIPTIMEHRRD);
    MotoVars.TrpSpeed = DS1302SpiRd(TRIPSPEEDRD);
    MotoVars.Mpg = DS1302SpiRd(MPGRD);
    MotoVars.Wheel = Get16BitNum(TwoByteArrayPtr, WHEELRD);
    MotoVars.Tank = Get16BitNum(TwoByteArrayPtr, TANKRD);
    MotoVars.Odo = Get32BitNum(FourByteArrayPtr, ODORD);
    MotoVars.TrpOdo = Get32BitNum(FourByteArrayPtr, TRIPODORD);
    MotoVars.MpgOdo = Get32BitNum(FourByteArrayPtr, MPGODORD);
}
/*******************************************************************************
*Store16BitNum
*    Stores a 16 bit number to the DS1302 Battery Backed Ram
*    a pointer the number, a pointer to a 2 byte array and the
*    beginning address to store to are passed
*   
*   Resources Used: Ds1302Spi.c - DS1302SpiWr(waddr, wdata)
*   Reuben Brown 5/12/03
*******************************************************************************/
void Store16BitNum(INT16U number, INT8U *arrayptr, INT8U address){    
    arrayptr[0] = (INT8U)(number >> 8);                 /* MSB */
    arrayptr[1] = (INT8U)number;                        /* LSB */
    DS1302SpiWr(address, arrayptr[0]);
    DS1302SpiWr(address + 2, arrayptr[1]);    
}
/*******************************************************************************
*Get16BitNum
*   Retrieves a 16 bit number from the DS1302 battery backed RAM 
*   2 byte array and beginning address to read from are passed
*   Returns 16 bit number
* 
*   Resources Used: Ds1302Spi.c - DS1302SpiRd()   
*   Reuben Brown 5/12/03
*******************************************************************************/
INT16U Get16BitNum(INT8U *arrayptr, INT8U address){
    INT16U buffer;
    arrayptr[0] = DS1302SpiRd(address);         //MSB
    arrayptr[1] = DS1302SpiRd(address + 2);     //LSB
    buffer = arrayptr[0];
    buffer = buffer * 0x100;
    buffer += arrayptr[1];
    return buffer;
}
/*******************************************************************************
*Store32BitNum
*    Stores a 32 bit number to the DS1302 Battery Backed Ram
*    a pointer the number, a pointer to a 4 byte array and the
*    beginning address to store to are passed
*   
*   Resources Used: Ds1302Spi.c 
*   Reuben Brown 5/12/03
*******************************************************************************/
void Store32BitNum(INT32U number, INT8U *arrayptr, INT8U address){
    INT8U count = 0;   
    arrayptr[0] = (INT8U)(number >> 24);            //MSB
    arrayptr[1] = (INT8U)(number >> 16);
    arrayptr[2] = (INT8U)(number >> 8);
    arrayptr[3] = (INT8U)number;    //LSB
    DS1302SpiWr(address, arrayptr[0]);
    DS1302SpiWr(address + 2, arrayptr[1]);
    DS1302SpiWr(address + 4, arrayptr[2]);
    DS1302SpiWr(address + 6, arrayptr[3]);
}
/*******************************************************************************
*Get32BitNum
*    Retrieves a 32 bit number from the DS1302
*    a pointer the number, a pointer to a 4 byte array and the
*    beginning address to store to are passed
*   
*   Resources Used: Ds1302Spi.c 
*   Reuben Brown 5/12/03
*******************************************************************************/
INT32U Get32BitNum(INT8U *arrayptr, INT8U address){
    INT32U buffer;
    arrayptr[0] = DS1302SpiRd(address);
    arrayptr[1] = DS1302SpiRd(address + 2);
    arrayptr[2] = DS1302SpiRd(address + 4);
    arrayptr[3] = DS1302SpiRd(address + 6);
    buffer = arrayptr[0];
    buffer *= 0x100;
    buffer += arrayptr[1];
    buffer *= 0x100; // Shift Right one byte
    buffer += arrayptr[2];
    buffer *= 0x100;
    buffer += arrayptr[3];
    return buffer;    
}
/****************************************************************************
* RamStore()
*
*   Stores all vital members of MotoVars Structure to DS1302 Ram
*
*   Reuben Brown    5/24/03
*****************************************************************************/
void RamStore(void){
    INT8U err;
    DS1302SpiWr(TRIPTIMESECWR, MotoVars.TrpTimeSecs);
    DS1302SpiWr(TRIPTIMEMINWR, MotoVars.TrpTimeMins);
    DS1302SpiWr(TRIPTIMEHRWR, MotoVars.TrpTimeHrs);
    DS1302SpiWr(TRIPSPEEDWR, MotoVars.TrpSpeed);
    DS1302SpiWr(MPGWR, MotoVars.Mpg);
    Store16BitNum(MotoVars.Wheel, TwoByteArrayPtr, WHEELWR);
    Store16BitNum(MotoVars.Tank, TwoByteArrayPtr, TANKWR);
    Store32BitNum(MotoVars.Odo, FourByteArrayPtr, ODOWR);
    Store32BitNum(MotoVars.TrpOdo, FourByteArrayPtr, TRIPODOWR);
    Store32BitNum(MotoVars.MpgOdo, FourByteArrayPtr, MPGODOWR);
}
/****************************************************************************
* WriteTime
*
*   Parameters: hr, min
*   writes hr and min to the DS1302 RTC
*
*   Reuben Brown    5/24/03
*****************************************************************************/
void WriteTime(INT8U hr, INT8U min){
    DS1302SpiWr(SECWR, 0);                 /* Set seconds equal to 0 */
    DS1302SpiWr(MINWR, min);     /* Write user entered minutes to clock*/
    DS1302SpiWr(HRWR, (hr | AM));/* Write user entered hours to clock in AM/PM format*/    
}
/*************************************************************************/
