/******************************************************************************
*
* Filename:     atd.c
*
* Description:  ATD_10B8C driver
*
* Author:       Rob Milne (http://robmilne.ca)
*
* Note:         Simple implementation of a single ATD channel.
*               Reads are the average of 8 conversions.
*               Rate of conversion is ~20KHz with a 24MHz bus clock
*
******************************************************************************/

/******************************************************************************
*  I N C L U D E    F I L E S
******************************************************************************/
#include "atd.h"


/******************************************************************************
*  L O C A L   D E F I N I T I O N S
******************************************************************************/
// Uncomment the define that corresponds to the ATD port pin used.  Only one
// ..channel selection possible for this implementation!

//#define ATD_0
//#define ATD_1
//#define ATD_2
#define ATD_3
//#define ATD_4
//#define ATD_5
//#define ATD_6
//#define ATD_7


// The MAX_ATD_DEV value is checked at startup of atd to ensure 1 and only 1
// ..channel is enabled
enum {
#ifdef ATD_0
  ATD_DEV_0,
#endif
#ifdef ATD_1
  ATD_DEV_1,
#endif
#ifdef ATD_2
  ATD_DEV_2,
#endif
#ifdef ATD_3
  ATD_DEV_3,
#endif
#ifdef ATD_4
  ATD_DEV_4,
#endif
#ifdef ATD_5
  ATD_DEV_5,
#endif
#ifdef ATD_6
  ATD_DEV_6,
#endif
#ifdef ATD_7
  ATD_DEV_7,
#endif
  /*********/
  MAX_ATD_DEV
};

#ifdef ATD_0
  #define ATD_INPUT_CH_SEL  0
#endif
#ifdef ATD_1
  #define ATD_INPUT_CH_SEL  1
#endif
#ifdef ATD_2
  #define ATD_INPUT_CH_SEL  2
#endif
#ifdef ATD_3
  #define ATD_INPUT_CH_SEL  3
#endif
#ifdef ATD_4
  #define ATD_INPUT_CH_SEL  4
#endif
#ifdef ATD_5
  #define ATD_INPUT_CH_SEL  5
#endif
#ifdef ATD_6
  #define ATD_INPUT_CH_SEL  6
#endif
#ifdef ATD_7
  #define ATD_INPUT_CH_SEL  7
#endif

/*
** ATDCTL2 Register
*/
#define ASCIF     bit(0)   /* ATD Sequence Complete Interrupt Flag */
#define ASCIE     bit(1)   /* ATD Sequence Complete Interrupt Enable */
#define ETRIGE    bit(2)   /* External Trigger Mode Enable (trigger on ch 7) */
#define ETRIGP    bit(3)   /* External Trigger Polarity */
#define ETRIGLE   bit(4)   /* External Trigger Level/Edge Control */
#define AWAI      bit(5)   /* ATD Power Down in Wait Mode */
#define AFFC      bit(6)   /* ATD Fast Flag Clear All */
#define ADPU      bit(7)   /* ATD Power Down */

/*
** ATDCTL3 Register
*/
#define FRZ0      bit(0)   /* Background Debug Freeze Enable */
#define FRZ1      bit(1)   /* .. */
#define FIFO      bit(2)   /* Result Register FIFO Mode */
#define S1C       bit(3)   /* Conversion Sequence Length */
#define S2C       bit(4)   /* .. */
#define S4C       bit(5)   /* .. */
#define S8C       bit(6)   /* .. */

/*
** ATDCTL4 Register
** This register selects the conversion clock frequency, the length of the
** ..second phase of the sample time and the resolution of the A/D conversion
** ..(i.e.: 8-bits or 10-bits). Writes to this register will abort current
** ..conversion sequence but will not start a new sequence.
*/
#define PRS0      bit(0)   /* ATD Clock Prescaler */
#define PRS1      bit(1)   /* .. */
#define PRS2      bit(2)   /* .. */
#define PRS3      bit(3)   /* .. */
#define PRS4      bit(4)   /* .. */
#define SMP0      bit(5)   /* Sample Time Select */
#define SMP1      bit(6)   /* .. */
#define SRES8     bit(7)   /* A/D Resolution Select */

/*
** ATDCTL5 Register
** This register selects the type of conversion sequence and the analog input
** ..channels sampled. Writes to this register will abort current conversion
** ..sequence and start a new conversion sequence.
*/
#define CA        bit(0)   /* Analog Input Channel Select Code */
#define CB        bit(1)   /* .. */
#define CC        bit(2)   /* .. */
#define CD        bit(3)   /* .. */
#define MULT      bit(4)   /* Multi-Channel Sample Mode */
#define SCAN      bit(5)   /* Continuous Conversion Sequence Mode */
#define DSGN      bit(6)   /* Result Register Data Signed or Unsigned */
#define DJM       bit(7)   /* Result Register Data Justification */

/*
** ATD Status Register 0 (ATDSTAT0)
*/
#define CC0       bit(0)   /* Conversion Counter */
#define CC1       bit(1)   /* .. */
#define CC2       bit(2)   /* .. */
#define FIFOR     bit(4)   /* FIFO Over Run Flag */
#define ETORF     bit(5)   /* External Trigger Overrun Flag */
#define SCF       bit(7)   /* Sequence Complete Flag */


/*****************************************************************************
*
*  Function:      atdStart
*
*  Description:   Initialize ATD module and start first ATD conversion
*
*  Parameter:             I/O    desc.
* ---------------------------------------------------------------------------
*  -none
*
*  Return:
*  -ATD_SUCCESS
*  -ATD_ERR_INIT
*
*****************************************************************************/
int atdStart (void) {
  if(MAX_ATD_DEV != 1) {
    // No ATD channel defined or more than one channel defined in atd.h
    return(ATD_ERR_INIT);
  }

  // Power up ATD module
  ATDCTL2 = ADPU;

  // 8 conversion per sequence, no FIFO
  ATDCTL3 = 0;

  // 8 bit resolution, prescaler: div by 12 (max for 24 MHz)
  ATDCTL4 = SRES8|PRS2|PRS0;

  // Start conversion sequence for selected channel
  ATDCTL5 = DJM|ATD_INPUT_CH_SEL;

  return(ATD_SUCCESS);
}


/*****************************************************************************
*
*  Function:      atdStop
*
*  Description:   Power down ATD
*
*  Parameter:            I/O    desc.
* ---------------------------------------------------------------------------
*  -none
*
*  Return:
*  -none
*
*****************************************************************************/
void atdStop(void) {
  // Power down ATD
  ATDCTL2 &=~ ADPU;
}


/*****************************************************************************
*
*  Function:      atdRead
*
*  Description:   Return average AD conversion value for a sequence of 8
*                 conversions and start new conversion sequence
*
*  Parameter:            I/O    desc.
* ---------------------------------------------------------------------------
*  -int *data             O     -pointer to ATD return data
*
*  Return:
*  -ATD_SUCCESS
*  -ATD_ERR_INIT
*  -ATD_BUSY
*
*****************************************************************************/
int atdRead(int *data) {
  // If ATD is not powered up then return init error
  if (!(ATDCTL2 & ADPU)) {
    return (ATD_ERR_INIT);
  }

  if(ATDSTAT0 & SCF) {
    // Average the 8 ATD data registers
    *data = (ATDDR0 + ATDDR1 + ATDDR2 + ATDDR3 + ATDDR4 + ATDDR5 + ATDDR6 + ATDDR7) >> 3;
    // Start new conversion sequence (Clears SCF)
    ATDCTL5 = DJM|ATD_INPUT_CH_SEL;
    return (ATD_SUCCESS);
  } else {
    // ATD conversions in process
    return(ATD_BUSY);
  }
}

