/* a2d.c - A/D conversion.
 *  Copyright (C) 2022 by Jed Marti
 *   This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see https://www.gnu.org/licenses/.
 */


#include <C8051F380.h>
#include <stdint.h>

#include "config.h"
#include "lfxmit.h"
#include "storage.h"


extern __xdata floatOrInt   FACC;           // Used for temperature calculation.
extern __bit                doit;           // Set to 0 if we're skipping.

void initA2D(void)
{
  // Turn on for analog.
  ADMDIN = ADMDIN & ~(AD0 | AD1);
  ADSKIP = ADSKIP | (AD0 | AD1);

  // Enabling
  //    REFBGS     0   gain = 2
  //    REGOVR     1   Internal regulator used - 2.4 volts is ref.
  //    REFSL      x   Not used - REGOVR overrides.
  //    TEMPE      1   Temperature enabled.
  //    BIASE      1   Bias enabled.
  //    REFBE      0   not driven.
  REF0CN = 0x16;

  //
  //    ADC0EN     1   ADC0 enabled.
  //    AD0TM      0   Normal track mode.
  //    AD0CM      0b000   Write to AD0BUSY starts conversion.
  ADC0CN = 0x80;

  // Real slow conversion.
  ADC0CF = 0xF8;

  // Ground is negative reference.
  AMX0N = 0x1F;
}



static void conversion(void)
//     We've selected an Analog channel. Start and wait for the conversion to finish. However,
//   if we're skipping, then don't actually do anything.
{
  if (!doit) return;
  
  // Start conversion.
  AD0INT = 0;
  AD0BUSY = 1;
  while (!AD0INT);

  pushST(newInt(ADC0));
}



void readAD0(void)
//      Select A2D0 (see config.h for which this is). The run the conversion and return the
//   raw integer value.
{
  // Select port/pin.
  AMX0P = AD0P;
  conversion();
}



void readAD1(void)
//      Select A2D1 (see config.h for which this is). The run the conversion and return the
//   raw integer value.
{
  // Select port/pin.
  AMX0P = AD1P;
  conversion();
}




void readRawTemp(void)
//     Select the internal temperature sensor and return its raw value (0 - 1023).
{
  AMX0P = 0x1E;
  conversion();
}
  
  
  
void readTemp(void)
//     Read the temperature, then convert it to degrees centigrade using the constants from
//   the experiments.
{
  if (!doit) return;
  AMX0P = 0x1E;    // Start conversion.
  AD0INT = 0;
  AD0BUSY = 1;
  while (!AD0INT);

  FACC.f = ((float) ADC0) * TempSlope - TempOffset;
  pushST(newFloat(FACC.f));
}



// EOF
