Maxim Integrated MAX11131 SPI 12-bit 16-channel ADC with SampleSet

Dependents:   MAX11131BOB_Tester MAX11131BOB_12bit_16ch_SampleSet_SPI_ADC MAX11131BOB_Serial_Tester

MAX11131.cpp

Committer:
whismanoid
Date:
2019-08-04
Revision:
5:6ef046dbe77e
Parent:
4:8a0ae95546fa
Child:
6:cb7bdeb185d0

File content as of revision 5:6ef046dbe77e:

// /*******************************************************************************
// * Copyright (C) 2019 Maxim Integrated Products, Inc., 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 MAXIM INTEGRATED 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 Maxim Integrated
// * Products, Inc. shall not be used except as stated in the Maxim Integrated
// * Products, Inc. Branding Policy.
// *
// * The mere transfer of this software does not imply any licenses
// * of trade secrets, proprietary technology, copyrights, patents,
// * trademarks, maskwork rights, or any other form of intellectual
// * property whatsoever. Maxim Integrated Products, Inc. retains all
// * ownership rights.
// *******************************************************************************
// */
// *********************************************************************
// @file MAX11131.cpp
// *********************************************************************
// Device Driver file
// DO NOT EDIT; except areas designated "CUSTOMIZE". Automatically generated file.
// generated by XMLSystemOfDevicesToMBED.py
// System Name = ExampleSystem
// System Description = Device driver example

#include "MAX11131.h"

// Device Name = MAX11131
// Device Description = 3Msps, Low-Power, Serial SPI 12-Bit, 16-Channel, Differential/Single-Ended Input, SAR ADC
// Device Manufacturer = Maxim Integrated
// Device PartNumber = MAX11131ATI+
// Device RegValue_Width = DataWidth16bit_HL
//
// ADC MaxOutputDataRate = 3Msps
// ADC NumChannels = 16
// ADC ResolutionBits = 12
//
// SPI CS = ActiveLow
// SPI FrameStart = CS
// SPI CPOL = 1
// SPI CPHA = 1
// SPI MOSI and MISO Data are both stable on Rising edge of SCLK
// SPI SCLK Idle High
// SPI SCLKMaxMHz = 48
// SPI SCLKMinMHz = 0.48
//
// InputPin Name = CNVST
// InputPin Description = Active-Low Conversion Start Input/Analog Input 14
// InputPin Function = Trigger
//
// InputPin Name = REF+
// InputPin Description = External Positive Reference Input. Apply a reference voltage at REF+. Bypass to GND with a 0.47uF capacitor.
// InputPin Function = Reference
//
// InputPin Name = REF-/AIN15
// InputPin Description = External Differential Reference Negative Input/Analog Input 15
// InputPin Function = Reference
//
// OutputPin Name = EOC
// OutputPin Description = End of Conversion Output. Data is valid after EOC pulls low (Internal clock mode only).
// OutputPin Function = Event
//
// SupplyPin Name = VDD
// SupplyPin Description = Power-Supply Input. Bypass to GND with a 10uF in parallel with a 0.1uF capacitors.
// SupplyPin VinMax = 3.6
// SupplyPin VinMin = 2.35
// SupplyPin Function = Analog
//
// SupplyPin Name = OVDD
// SupplyPin Description = Interface Digital Power-Supply Input. Bypass to GND with a 10uF in parallel with a 0.1uF capacitors.
// SupplyPin VinMax = 3.6
// SupplyPin VinMin = 1.5
// SupplyPin Function = Digital
//

// CODE GENERATOR: class constructor definition
MAX11131::MAX11131(SPI &spi, DigitalOut &cs_pin, // SPI interface
                 // CODE GENERATOR: class constructor definition gpio InputPin pins
                 DigitalOut &CNVST_pin, // Digital Trigger Input to MAX11131 device
                 // AnalogOut &REF__pin, // Reference Input to MAX11131 device
                 // AnalogOut &REF__AIN15_pin, // Reference Input to MAX11131 device
                 // CODE GENERATOR: class constructor definition gpio OutputPin pins
                 DigitalIn &EOC_pin, // Digital Event Output from MAX11131 device
                 // CODE GENERATOR: class constructor definition ic_variant
                 MAX11131_ic_t ic_variant)
    // CODE GENERATOR: class constructor initializer list
    : m_spi(spi), m_cs_pin(cs_pin), // SPI interface
    // CODE GENERATOR: class constructor initializer list gpio InputPin pins
    m_CNVST_pin(CNVST_pin), // Digital Trigger Input to MAX11131 device
    // m_REF__pin(REF__pin), // Reference Input to MAX11131 device
    // m_REF__AIN15_pin(REF__AIN15_pin), // Reference Input to MAX11131 device
    // CODE GENERATOR: class constructor initializer list gpio OutputPin pins
    m_EOC_pin(EOC_pin), // Digital Event Output from MAX11131 device
    // CODE GENERATOR: class constructor initializer list ic_variant
    m_ic_variant(ic_variant)
{
    // CODE GENERATOR: class constructor definition SPI interface initialization
    //
    // SPI CS = ActiveLow
    // SPI FrameStart = CS
    m_SPI_cs_state = 1;
    m_cs_pin = m_SPI_cs_state;

    // SPI CPOL = 1
    // SPI CPHA = 1
    // SPI MOSI and MISO Data are both stable on Rising edge of SCLK
    // SPI SCLK Idle High
    m_SPI_dataMode = 3; //SPI_MODE3 // CPOL=1,CPHA=1: Rising Edge stable; SCLK idle High
    m_spi.format(8,m_SPI_dataMode);         // int bits_must_be_8, int mode=0_3 CPOL=0,CPHA=0

    // SPI SCLKMaxMHz = 48
    // SPI SCLKMinMHz = 0.48
    //#define SPI_SCLK_Hz 48000000 // 48MHz
    //#define SPI_SCLK_Hz 24000000 // 24MHz
    //#define SPI_SCLK_Hz 12000000 // 12MHz
    //#define SPI_SCLK_Hz 6000000 // 6MHz
    //#define SPI_SCLK_Hz 4000000 // 4MHz
    //#define SPI_SCLK_Hz 2000000 // 2MHz
    //#define SPI_SCLK_Hz 1000000 // 1MHz
#if defined(TARGET_MAX32600)
    // MAX11131BOB_Serial_Tester on MAX32600MBED limit SCLK=6MHz
    m_SPI_SCLK_Hz = 6000000; // 6MHz; MAX11131 limit is 48MHz
#else
    // all other platforms
    m_SPI_SCLK_Hz = 12000000; // 12MHz; MAX11131 limit is 48MHz
#endif
    m_spi.frequency(m_SPI_SCLK_Hz);

    // TODO1: CODE GENERATOR: class constructor definition gpio InputPin (Input to device) initialization
    //
    m_CNVST_pin = 1; // output logic high -- initial value in constructor
}

// CODE GENERATOR: class destructor definition
MAX11131::~MAX11131()
{
    // do nothing
}

// CODE GENERATOR: spi_frequency setter definition
/// set SPI SCLK frequency
void MAX11131::spi_frequency(int spi_sclk_Hz)
{
    m_SPI_SCLK_Hz = spi_sclk_Hz;
    m_spi.frequency(m_SPI_SCLK_Hz);
}

// CODE GENERATOR: omit global g_MAX11131_device
// CODE GENERATOR: extern function declarations
// CODE GENERATOR: extern function requirement MAX11131::SPIoutputCS
// Assert SPI Chip Select
// SPI chip-select for MAX11131
//
void MAX11131::SPIoutputCS(int isLogicHigh)
{
    // CODE GENERATOR: extern function definition for function SPIoutputCS
    // CODE GENERATOR: extern function definition for standard SPI interface function SPIoutputCS(int isLogicHigh)
    m_SPI_cs_state = isLogicHigh;
    m_cs_pin = m_SPI_cs_state;
}

// CODE GENERATOR: extern function requirement MAX11131::SPIwrite16bits
// SPI write 16 bits
// SPI interface to MAX11131 shift 16 bits mosiData16 into MAX11131 DIN
// ignoring MAX11131 DOUT
//
void MAX11131::SPIwrite16bits(int16_t mosiData16)
{
    // CODE GENERATOR: extern function definition for function SPIwrite16bits
    // TODO1: CODE GENERATOR: extern function definition for standard SPI interface function SPIwrite16bits(int16_t mosiData16)
    size_t byteCount = 2;
    static char mosiData[2];
    static char misoData[2];
    mosiData[0] = (char)((mosiData16 >> 8) & 0xFF); // MSByte
    mosiData[1] = (char)((mosiData16 >> 0) & 0xFF); // LSByte
    //
    // Arduino: begin critical section: noInterrupts() masks all interrupt sources; end critical section with interrupts()
    //~ noInterrupts();
    //
    //~ digitalWrite(Scope_Trigger_Pin, LOW); // diagnostic Scope_Trigger_Pin
    //
    unsigned int numBytesTransferred = m_spi.write(mosiData, byteCount, misoData, byteCount);
    //~ m_spi.transfer(mosiData8_FF0000);
    //~ m_spi.transfer(mosiData16_00FF00);
    //~ m_spi.transfer(mosiData16_0000FF);
    //
    //~ digitalWrite(Scope_Trigger_Pin, HIGH); // diagnostic Scope_Trigger_Pin
    //
    // Arduino: begin critical section: noInterrupts() masks all interrupt sources; end critical section with interrupts()
    //~ interrupts();
    //
    // VERIFY: SPIwrite24bits print diagnostic information
    //cmdLine.serial().printf(" MOSI->"));
    //cmdLine.serial().printf(" 0x"));
    //Serial.print( (mosiData8_FF0000 & 0xFF), HEX);
    //cmdLine.serial().printf(" 0x"));
    //Serial.print( (mosiData16_00FF00 & 0xFF), HEX);
    //cmdLine.serial().printf(" 0x"));
    //Serial.print( (mosiData16_0000FF & 0xFF), HEX);
    // hex dump mosiData[0..byteCount-1]
#if 0 // HAS_MICROUSBSERIAL
    cmdLine_microUSBserial.serial().printf("\r\nSPI");
    if (byteCount > 7) {
        cmdLine_microUSBserial.serial().printf(" byteCount:%d", byteCount);
    }
    cmdLine_microUSBserial.serial().printf(" MOSI->");
    for (unsigned int byteIndex = 0; byteIndex < byteCount; byteIndex++)
    {
        cmdLine_microUSBserial.serial().printf(" 0x%2.2X", mosiData[byteIndex]);
    }
    // hex dump misoData[0..byteCount-1]
    cmdLine_microUSBserial.serial().printf("  MISO<-");
    for (unsigned int byteIndex = 0; byteIndex < numBytesTransferred; byteIndex++)
    {
        cmdLine_microUSBserial.serial().printf(" 0x%2.2X", misoData[byteIndex]);
    }
    cmdLine_microUSBserial.serial().printf(" ");
#endif
#if 0 // HAS_DAPLINK_SERIAL
    cmdLine_DAPLINKserial.serial().printf("\r\nSPI");
    if (byteCount > 7) {
        cmdLine_DAPLINKserial.serial().printf(" byteCount:%d", byteCount);
    }
    cmdLine_DAPLINKserial.serial().printf(" MOSI->");
    for (unsigned int byteIndex = 0; byteIndex < byteCount; byteIndex++)
    {
        cmdLine_DAPLINKserial.serial().printf(" 0x%2.2X", mosiData[byteIndex]);
    }
    // hex dump misoData[0..byteCount-1]
    cmdLine_DAPLINKserial.serial().printf("  MISO<-");
    for (unsigned int byteIndex = 0; byteIndex < numBytesTransferred; byteIndex++)
    {
        cmdLine_DAPLINKserial.serial().printf(" 0x%2.2X", misoData[byteIndex]);
    }
    cmdLine_DAPLINKserial.serial().printf(" ");
#endif
    // VERIFY: DIAGNOSTIC: print MAX5715 device register write
    // TODO: MAX5715_print_register_verbose(mosiData8_FF0000, mosiData16_00FFFF);
    // TODO: print_verbose_SPI_diagnostic(mosiData16_FF00, mosiData16_00FF, misoData16_FF00, misoData16_00FF);
    //
    // int misoData16 = (misoData16_FF00 << 8) | misoData16_00FF;
    // return misoData16;
}

// CODE GENERATOR: extern function requirement MAX11131::SPIwrite24bits
// SPI write 17-24 bits
// SPI interface to MAX11131 shift 16 bits mosiData16 into MAX11131 DIN
// followed by one additional SCLK byte.
// ignoring MAX11131 DOUT
//
void MAX11131::SPIwrite24bits(int16_t mosiData16_FFFF00, int8_t mosiData8_0000FF)
{
    // CODE GENERATOR: extern function definition for function SPIwrite24bits
    // TODO1: CODE GENERATOR: extern function definition for standard SPI interface function SPIwrite24bits(int16_t mosiData16_FFFF00, int8_t mosiData8_0000FF)
    // TODO: implement SPIwrite24bits(int16_t mosiData16_FFFF00, int8_t mosiData8_0000FF)
    size_t byteCount = 3;
    static char mosiData[3];
    static char misoData[3];
    mosiData[0] = (char)((mosiData16_FFFF00 >> 8) & 0xFF); // MSByte
    mosiData[1] = (char)((mosiData16_FFFF00 >> 0) & 0xFF); // LSByte
    mosiData[2] = mosiData8_0000FF;
    //
    // Arduino: begin critical section: noInterrupts() masks all interrupt sources; end critical section with interrupts()
    //~ noInterrupts();
    //
    //~ digitalWrite(Scope_Trigger_Pin, LOW); // diagnostic Scope_Trigger_Pin
    //
    unsigned int numBytesTransferred = m_spi.write(mosiData, byteCount, misoData, byteCount);
    //~ m_spi.transfer(mosiData8_FF0000);
    //~ m_spi.transfer(mosiData16_00FF00);
    //~ m_spi.transfer(mosiData16_0000FF);
    //
    //~ digitalWrite(Scope_Trigger_Pin, HIGH); // diagnostic Scope_Trigger_Pin
    //
    // Arduino: begin critical section: noInterrupts() masks all interrupt sources; end critical section with interrupts()
    //~ interrupts();
    //
    // VERIFY: SPIwrite24bits print diagnostic information
    //cmdLine.serial().printf(" MOSI->"));
    //cmdLine.serial().printf(" 0x"));
    //Serial.print( (mosiData8_FF0000 & 0xFF), HEX);
    //cmdLine.serial().printf(" 0x"));
    //Serial.print( (mosiData16_00FF00 & 0xFF), HEX);
    //cmdLine.serial().printf(" 0x"));
    //Serial.print( (mosiData16_0000FF & 0xFF), HEX);
    // hex dump mosiData[0..byteCount-1]
#if 0 // HAS_MICROUSBSERIAL
    cmdLine_microUSBserial.serial().printf("\r\nSPI");
    if (byteCount > 7) {
        cmdLine_microUSBserial.serial().printf(" byteCount:%d", byteCount);
    }
    cmdLine_microUSBserial.serial().printf(" MOSI->");
    for (unsigned int byteIndex = 0; byteIndex < byteCount; byteIndex++)
    {
        cmdLine_microUSBserial.serial().printf(" 0x%2.2X", mosiData[byteIndex]);
    }
    // hex dump misoData[0..byteCount-1]
    cmdLine_microUSBserial.serial().printf("  MISO<-");
    for (unsigned int byteIndex = 0; byteIndex < numBytesTransferred; byteIndex++)
    {
        cmdLine_microUSBserial.serial().printf(" 0x%2.2X", misoData[byteIndex]);
    }
    cmdLine_microUSBserial.serial().printf(" ");
#endif
#if 0 // HAS_DAPLINK_SERIAL
    cmdLine_DAPLINKserial.serial().printf("\r\nSPI");
    if (byteCount > 7) {
        cmdLine_DAPLINKserial.serial().printf(" byteCount:%d", byteCount);
    }
    cmdLine_DAPLINKserial.serial().printf(" MOSI->");
    for (unsigned int byteIndex = 0; byteIndex < byteCount; byteIndex++)
    {
        cmdLine_DAPLINKserial.serial().printf(" 0x%2.2X", mosiData[byteIndex]);
    }
    // hex dump misoData[0..byteCount-1]
    cmdLine_DAPLINKserial.serial().printf("  MISO<-");
    for (unsigned int byteIndex = 0; byteIndex < numBytesTransferred; byteIndex++)
    {
        cmdLine_DAPLINKserial.serial().printf(" 0x%2.2X", misoData[byteIndex]);
    }
    cmdLine_DAPLINKserial.serial().printf(" ");
#endif
    // VERIFY: DIAGNOSTIC: print MAX5715 device register write
    // TODO: MAX5715_print_register_verbose(mosiData8_FF0000, mosiData16_00FFFF);
    //
    // int misoData16 = (misoData16_FF00 << 8) | misoData16_00FF;
    // return misoData16;
}

// CODE GENERATOR: extern function requirement MAX11131::SPIread16bits
// SPI read 16 bits while MOSI (MAX11131 DIN) is 0
// SPI interface to capture 16 bits miso data from MAX11131 DOUT
//
int16_t MAX11131::SPIread16bits()
{
    // CODE GENERATOR: extern function definition for function SPIread16bits
    // TODO1: CODE GENERATOR: extern function definition for standard SPI interface function int16_t SPIread16bits()
    int mosiData16 = 0;
    size_t byteCount = 2;
    static char mosiData[2];
    static char misoData[2];
    mosiData[0] = (char)((mosiData16 >> 8) & 0xFF); // MSByte
    mosiData[1] = (char)((mosiData16 >> 0) & 0xFF); // LSByte
    //
    // Arduino: begin critical section: noInterrupts() masks all interrupt sources; end critical section with interrupts()
    //~ noInterrupts();
    //
    //~ digitalWrite(Scope_Trigger_Pin, LOW); // diagnostic Scope_Trigger_Pin
    //
    unsigned int numBytesTransferred = m_spi.write(mosiData, byteCount, misoData, byteCount);
    //~ m_spi.transfer(mosiData8_FF0000);
    //~ m_spi.transfer(mosiData16_00FF00);
    //~ m_spi.transfer(mosiData16_0000FF);
    //
    //~ digitalWrite(Scope_Trigger_Pin, HIGH); // diagnostic Scope_Trigger_Pin
    //
    // Arduino: begin critical section: noInterrupts() masks all interrupt sources; end critical section with interrupts()
    //~ interrupts();
    //
    // VERIFY: SPIwrite24bits print diagnostic information
    //cmdLine.serial().printf(" MOSI->"));
    //cmdLine.serial().printf(" 0x"));
    //Serial.print( (mosiData8_FF0000 & 0xFF), HEX);
    //cmdLine.serial().printf(" 0x"));
    //Serial.print( (mosiData16_00FF00 & 0xFF), HEX);
    //cmdLine.serial().printf(" 0x"));
    //Serial.print( (mosiData16_0000FF & 0xFF), HEX);
    // hex dump mosiData[0..byteCount-1]
#if 0 // HAS_MICROUSBSERIAL
    cmdLine_microUSBserial.serial().printf("\r\nSPI");
    if (byteCount > 7) {
        cmdLine_microUSBserial.serial().printf(" byteCount:%d", byteCount);
    }
    cmdLine_microUSBserial.serial().printf(" MOSI->");
    for (unsigned int byteIndex = 0; byteIndex < byteCount; byteIndex++)
    {
        cmdLine_microUSBserial.serial().printf(" 0x%2.2X", mosiData[byteIndex]);
    }
    // hex dump misoData[0..byteCount-1]
    cmdLine_microUSBserial.serial().printf("  MISO<-");
    for (unsigned int byteIndex = 0; byteIndex < numBytesTransferred; byteIndex++)
    {
        cmdLine_microUSBserial.serial().printf(" 0x%2.2X", misoData[byteIndex]);
    }
    cmdLine_microUSBserial.serial().printf(" ");
#endif
#if 0 // HAS_DAPLINK_SERIAL
    cmdLine_DAPLINKserial.serial().printf("\r\nSPI");
    if (byteCount > 7) {
        cmdLine_DAPLINKserial.serial().printf(" byteCount:%d", byteCount);
    }
    cmdLine_DAPLINKserial.serial().printf(" MOSI->");
    for (unsigned int byteIndex = 0; byteIndex < byteCount; byteIndex++)
    {
        cmdLine_DAPLINKserial.serial().printf(" 0x%2.2X", mosiData[byteIndex]);
    }
    // hex dump misoData[0..byteCount-1]
    cmdLine_DAPLINKserial.serial().printf("  MISO<-");
    for (unsigned int byteIndex = 0; byteIndex < numBytesTransferred; byteIndex++)
    {
        cmdLine_DAPLINKserial.serial().printf(" 0x%2.2X", misoData[byteIndex]);
    }
    cmdLine_DAPLINKserial.serial().printf(" ");
#endif
    // VERIFY: DIAGNOSTIC: print MAX5715 device register write
    // TODO: MAX5715_print_register_verbose(mosiData8_FF0000, mosiData16_00FFFF);
    // TODO: print_verbose_SPI_diagnostic(mosiData16_FF00, mosiData16_00FF, misoData16_FF00, misoData16_00FF);
    //
    int misoData16 = (misoData[0] << 8) | misoData[1];
    return misoData16;
}

// CODE GENERATOR: extern function requirement MAX11131::CNVSToutputPulseLow
// Assert MAX11131 CNVST convert start.
// Required when using any of the InternalClock modes with SWCNV 0.
// Trigger measurement by driving CNVST/AIN14 pin low for a minimum active-low pulse duration of 5ns. (AIN14 is not available)
//
void MAX11131::CNVSToutputPulseLow()
{
    // CODE GENERATOR: extern function definition for function CNVSToutputPulseLow
    // TODO1: CODE GENERATOR: extern function definition for gpio interface function CNVSToutputPulseLow
    // TODO1: CODE GENERATOR: gpio pin CNVST assuming member function m_CNVST_pin
    // TODO1: CODE GENERATOR: gpio direction output
    // m_CNVST_pin.output(); // only applicable to DigitalInOut
    // TODO1: CODE GENERATOR: gpio function PulseLow
    m_CNVST_pin = 0; // output logic low
    wait(0.01); // pulse low delay time
    m_CNVST_pin = 1; // output logic high
}

// CODE GENERATOR: extern function requirement MAX11131::EOCinputWaitUntilLow
// Wait for MAX11131 EOC pin low, indicating end of conversion.
// Required when using any of the InternalClock modes.
//
void MAX11131::EOCinputWaitUntilLow()
{
    // CODE GENERATOR: extern function definition for function EOCinputWaitUntilLow
    // TODO1: CODE GENERATOR: extern function definition for gpio interface function EOCinputWaitUntilLow
    // TODO1: CODE GENERATOR: gpio pin EOC assuming member function m_EOC_pin
    // TODO1: CODE GENERATOR: gpio direction input
    // m_EOC_pin.input(); // only applicable to DigitalInOut
    // TODO1: CODE GENERATOR: gpio function WaitUntilLow
    while (m_EOC_pin != 0)
    {
        // spinlock waiting for logic low pin state
    }
}

// CODE GENERATOR: extern function requirement MAX11131::EOCinputValue
// Return the status of the MAX11131 EOC pin.
//
int MAX11131::EOCinputValue()
{
    // CODE GENERATOR: extern function definition for function EOCinputValue
    // TODO1: CODE GENERATOR: extern function definition for gpio interface function EOCinputValue
    // TODO1: CODE GENERATOR: gpio pin EOC assuming member function m_EOC_pin
    // TODO1: CODE GENERATOR: gpio direction input
    // m_EOC_pin.input(); // only applicable to DigitalInOut
    // TODO1: CODE GENERATOR: gpio function Value
    return m_EOC_pin.read();
}

// CODE GENERATOR: class member function definitions
//----------------------------------------
// Initialize device
void MAX11131::Init(void)
{
    
    //----------------------------------------
    // Nominal Full-Scale Voltage Reference
    VRef = 2.500;
    
    //----------------------------------------
    // define write-only register ADC_MODE_CONTROL
    ADC_MODE_CONTROL = 0;       //!< mosiData16 0x0000..0x7FFF format: 0 SCAN[3:0] CHSEL[3:0] RESET[1:0] PM[1:0] CHAN_ID SWCNV 0
    const int SCAN_LSB    = 11; const int SCAN_BITS    = 0x0F; //!< ADC_MODE_CONTROL.SCAN[3:0] ADC Scan Control (command)
    const int CHSEL_LSB   =  7; const int CHSEL_BITS   = 0x0F; //!< ADC_MODE_CONTROL.CHSEL[3:0] Analog Input Channel Select AIN0..AIN15
    const int RESET_LSB   =  5; const int RESET_BITS   = 0x03; //!< ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved
    const int PM_LSB      =  3; const int PM_BITS      = 0x03; //!< ADC_MODE_CONTROL.PM[1:0] Power Management 0=Normal, 1=AutoShutdown, 2=AutoStandby 3=reserved
    const int CHAN_ID_LSB =  2; const int CHAN_ID_BITS = 0x01; //!< ADC_MODE_CONTROL.CHAN_ID
    const int SWCNV_LSB   =  1; const int SWCNV_BITS   = 0x01; //!< ADC_MODE_CONTROL.SWCNV
    
    //----------------------------------------
    // define write-only register ADC_CONFIGURATION
    ADC_CONFIGURATION = 0x8000; //!< mosiData16 0x8000..0x87FF format: 1 0 0 0 0 REFSEL AVGON NAVG[1:0] NSCAN[1:0] SPM[1:0] ECHO 0 0
    const int REFSEL_LSB = 10; const int REFSEL_BITS = 0x01; // ADC_CONFIGURATION.REFSEL
    const int AVGON_LSB  =  9; const int AVGON_BITS  = 0x01; // ADC_CONFIGURATION.AVGON
    const int NAVG_LSB   =  7; const int NAVG_BITS   = 0x03; // ADC_CONFIGURATION.NAVG[1:0]
    const int NSCAN_LSB  =  5; const int NSCAN_BITS  = 0x03; // ADC_CONFIGURATION.NSCAN[1:0]
    const int SPM_LSB    =  3; const int SPM_BITS    = 0x03; // ADC_CONFIGURATION.SPM[1:0]
    const int ECHO_LSB   =  2; const int ECHO_BITS   = 0x01; // ADC_CONFIGURATION.ECHO
    
    //----------------------------------------
    // define write-only registers UNIPOLAR,BIPOLAR,RANGE
    UNIPOLAR = 0x8800;          //!< mosiData16 0x8800..0x8FFF format: 1 0 0 0 1 UCH0/1 UCH2/3 UCH4/5 UCH6/7 UCH8/9 UCH10/11 UCH12/13 UCH14/15 PDIFF_COM x x
    BIPOLAR = 0x9000;           //!< mosiData16 0x9000..0x97FF format: 1 0 0 1 0 BCH0/1 BCH2/3 BCH4/5 BCH6/7 BCH8/9 BCH10/11 BCH12/13 BCH14/15 x x x
    RANGE = 0x9800;             //!< mosiData16 0x9800..0x9FFF format: 1 0 0 1 1 RANGE0/1 RANGE2/3 RANGE4/5 RANGE6/7 RANGE8/9 RANGE10/11 RANGE12/13 RANGE14/15 x x x
    const int AIN_0_1_LSB   = 10; // UNIPOLAR.UCH0/1    BIPOLAR.BCH0/1    RANGE.RANGE0/1  
    const int AIN_2_3_LSB   =  9; // UNIPOLAR.UCH2/3    BIPOLAR.BCH2/3    RANGE.RANGE2/3  
    const int AIN_4_5_LSB   =  8; // UNIPOLAR.UCH4/5    BIPOLAR.BCH4/5    RANGE.RANGE4/5  
    const int AIN_6_7_LSB   =  7; // UNIPOLAR.UCH6/7    BIPOLAR.BCH6/7    RANGE.RANGE6/7  
    const int AIN_8_9_LSB   =  6; // UNIPOLAR.UCH8/9    BIPOLAR.BCH8/9    RANGE.RANGE8/9  
    const int AIN_10_11_LSB =  5; // UNIPOLAR.UCH10/11  BIPOLAR.BCH10/11  RANGE.RANGE10/11
    const int AIN_12_13_LSB =  4; // UNIPOLAR.UCH12/13  BIPOLAR.BCH12/13  RANGE.RANGE12/13
    const int AIN_14_15_LSB =  3; // UNIPOLAR.UCH14/15  BIPOLAR.BCH14/15  RANGE.RANGE14/15
    const int PDIFF_COMM_LSB =  2; const int PDIFF_COMM_BITS =  0x01; // UNIPOLAR.PDIFF_COM
    // Summary of Table 8:
    // UCH0/1=0, BCH0/1=0, RANGE0/1=0: AIN0/AIN1 two independent single-ended inputs, unipolar code (Full Scale = VREF, LSB = VREF/4096)
    // UCH0/1=1, BCH0/1=0, RANGE0/1=0: AIN0/AIN1 differential input pair, unipolar code (AIN0>AIN1) (Full Scale = VREF, LSB = VREF/4096)
    // UCH0/1=0, BCH0/1=1, RANGE0/1=0: AIN0/AIN1 differential input pair (+/-)(1/2)Vref, bipolar code (Full Scale = VREF, LSB = VREF/4096)
    // UCH0/1=1, BCH0/1=1, RANGE0/1=0: reserved do not use
    // UCH0/1=0, BCH0/1=0, RANGE0/1=1: reserved do not use
    // UCH0/1=1, BCH0/1=0, RANGE0/1=1: reserved do not use
    // UCH0/1=0, BCH0/1=1, RANGE0/1=1: AIN0/AIN1 differential input pair (+/-)Vref, bipolar code (Full Scale = 2VREF, LSB = VREF/2048)
    // UCH0/1=1, BCH0/1=1, RANGE0/1=1: reserved do not use
    // Both channels of a differential pair must be within Input Voltage Range (dynamic signal range) 0..VREF.
    
    //----------------------------------------
    // define write-only registers CSCAN0,CSCAN1
    CSCAN0 = 0xA000;            //!< mosiData16 0xA000..0xA7FF format: 1 0 1 0 0 CHSCAN15 CHSCAN14 CHSCAN13 CHSCAN12 CHSCAN11 CHSCAN10 CHSCAN9 CHSCAN8 x x x
    const int CHSCAN15_LSB = 10; // CSCAN0.CHSCAN15
    const int CHSCAN14_LSB =  9; // CSCAN0.CHSCAN14
    const int CHSCAN13_LSB =  8; // CSCAN0.CHSCAN13
    const int CHSCAN12_LSB =  7; // CSCAN0.CHSCAN12
    const int CHSCAN11_LSB =  6; // CSCAN0.CHSCAN11
    const int CHSCAN10_LSB =  5; // CSCAN0.CHSCAN10
    const int CHSCAN9_LSB  =  4; // CSCAN0.CHSCAN9
    const int CHSCAN8_LSB  =  3; // CSCAN0.CHSCAN8
    CSCAN1 = 0xA800;            //!< mosiData16 0xA800..0xAFFF format: 1 0 1 0 1 CHSCAN7 CHSCAN6 CHSCAN5 CHSCAN4 CHSCAN3 CHSCAN2 CHSCAN1 CHSCAN0 x x x
    const int CHSCAN7_LSB = 10; // CSCAN1.CHSCAN7
    const int CHSCAN6_LSB =  9; // CSCAN1.CHSCAN6
    const int CHSCAN5_LSB =  8; // CSCAN1.CHSCAN5
    const int CHSCAN4_LSB =  7; // CSCAN1.CHSCAN4
    const int CHSCAN3_LSB =  6; // CSCAN1.CHSCAN3
    const int CHSCAN2_LSB =  5; // CSCAN1.CHSCAN2
    const int CHSCAN1_LSB =  4; // CSCAN1.CHSCAN1
    const int CHSCAN0_LSB =  3; // CSCAN1.CHSCAN0
    
    //----------------------------------------
    // Initialize shadow of write-only register SAMPLESET.
    // Do not write to SAMPLESET at this time.
    // A write to SAMPLESET must be followed by specified number of pattern entry words.
    // See ScanSampleSetExternalClock function for details.
    SAMPLESET = 0xB000;         //!< mosiData16 0xB000..0xB7FF format: 1 0 1 1 0 SEQ_LENGTH[7:0] x x x
    const int SAMPLESET_LSB   =  3; const int SAMPLESET_BITS   = 0xFF; // SAMPLESET.SEQ_LENGTH[7:0]
    
    //----------------------------------------
    // Reset all registers: ADC_MODE_CONTROL.RESET[1:0] = 2
    ADC_MODE_CONTROL &= ~ ((    RESET_BITS) << RESET_LSB); // ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved
    ADC_MODE_CONTROL |=   ((2 & RESET_BITS) << RESET_LSB); // ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved
    
    //----------------------------------------
    // SPI write ADC MODE CONTROL register
    // Send SPI configuration to device
    SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern
    SPIoutputCS(0); // drive CS low
    SPIwrite16bits(ADC_MODE_CONTROL);
    SPIoutputCS(1); // drive CS high

#if REFSEL_0
    
    //----------------------------------------
    // Global setting for all channels: ADC_CONFIGURATION.REFSEL=0: external single-ended reference
    // SELECT REFERENCE SINGLE-ENDED OR DIFFERENTIAL
    // SELECT REFERENCE SINGLE-ENDED OR DIFFERENTIAL: EXTERNAL SINGLE-ENDED
    // SELECT ADC CONFIGURATION register set REFSEL BIT TO 0
    ADC_CONFIGURATION &= ~ ((    REFSEL_BITS) << REFSEL_LSB); // ADC_CONFIGURATION.REFSEL=0: external single-ended reference. (For the 16-channel chips: channel AIN15 is available.)
#endif // REFSEL_0

#if REFSEL_1
    
    //----------------------------------------
    // Global setting for all channels: ADC_CONFIGURATION.REFSEL=1: external differential reference (For the 16-channel chips: channel AIN15 is unavailable, the pin is assigned to REF-.)
    // SELECT REFERENCE SINGLE-ENDED OR DIFFERENTIAL
    // SELECT REFERENCE SINGLE-ENDED OR DIFFERENTIAL: EXTERNAL DIFFERENTIAL
    // SELECT ADC CONFIGURATION register set REFSEL BIT TO 1
    ADC_CONFIGURATION |=   ((1 & REFSEL_BITS) << REFSEL_LSB); // ADC_CONFIGURATION.REFSEL=1: external differential reference. (For the 16-channel chips: channel AIN15 is unavailable, the pin is assigned to REF-.)
#endif // REFSEL_1

#if PDIFF_COMM_0
    
    //----------------------------------------
    // Global setting for all channels: PDIFF_COMM
    UNIPOLAR &= ~ ((    PDIFF_COMM_BITS) << PDIFF_COMM_LSB); // UNIPOLAR.PDIFF_COMM=0: all single-ended channels use GND as common
#endif // PDIFF_COMM_0

#if PDIFF_COMM_1
    
    //----------------------------------------
    // Global setting for all channels: PDIFF_COMM
    // SELECT UNIPOLAR AND register set BIT PDIFF_COM TO 1 FOR PSEUDODIFFERENTIAL SELECTION
    UNIPOLAR |=   ((1 & PDIFF_COMM_BITS) << PDIFF_COMM_LSB); // UNIPOLAR.PDIFF_COMM=1: all single-ended channels are pseudo-differential with REF- as common
#endif // PDIFF_COMM_1

#if AIN_0_1_SingleEnded
    
    //----------------------------------------
    // ADC Channels AIN0, AIN1 = Both Single-Ended, Unipolar
    // Full Scale = VREF
    // Voltage per LSB count = VREF/4096
    // AIN0 is a Single-Ended input using Unipolar transfer function.
    // AIN1 is a Single-Ended input using Unipolar transfer function.
    // If PDIFF_COM_1, both are Pseudo-Differential with REF- as common.
    // AIN0 voltage must always be between 0 and VREF.
    // AIN1 voltage must always be between 0 and VREF.
    //
    // SELECT UNIPOLAR AND BIPOLAR register set PER CHANNEL UCH(X)/(X+1) AND BCH(X)/(X+1) TO 0 FOR SINGLE-ENDED SELECTION
    UNIPOLAR &= ~ (1 << AIN_0_1_LSB);
    BIPOLAR  &= ~ (1 << AIN_0_1_LSB);
    RANGE    &= ~ (1 << AIN_0_1_LSB);
    // UCH0/1=0, BCH0/1=0, RANGE0/1=0: AIN0/AIN1 two independent single-ended inputs, unipolar code (Full Scale = VREF, LSB = VREF/4096)
#endif // AIN_0_1_SingleEnded

#if AIN_0_1_DifferentialUnipolar
    
    //----------------------------------------
    // ADC Channels AIN0, AIN1 = Differential Unipolar (AIN0 > AIN1)
    // Full Scale = VREF
    // Voltage per LSB count = VREF/4096
    // AIN0, AIN1 are a Differential pair using Unipolar transfer function.
    // AIN0 voltage must always be between 0 and VREF.
    // AIN1 voltage must always be between 0 and VREF.
    //
    // SELECT UNIPOLAR register set PER CHANNEL UCH(X)/(X+1) TO 1 FOR UNIPOLAR
    UNIPOLAR |=   (1 << AIN_0_1_LSB);
    BIPOLAR  &= ~ (1 << AIN_0_1_LSB);
    RANGE    &= ~ (1 << AIN_0_1_LSB);
    // UCH0/1=1, BCH0/1=0, RANGE0/1=0: AIN0/AIN1 differential input pair, unipolar code (AIN0>AIN1) (Full Scale = VREF, LSB = VREF/4096)
#endif // AIN_0_1_DifferentialUnipolar

#if AIN_0_1_DifferentialBipolarFSVref
    
    //----------------------------------------
    // ADC Channels AIN0, AIN1 = Differential Bipolar
    // Full Scale = VREF
    // Voltage per LSB count = VREF/4096
    // AIN0, AIN1 are a Differential pair using Bipolar transfer function with range (+/-)(1/2)Vref
    // AIN0 voltage must always be between 0 and VREF.
    // AIN1 voltage must always be between 0 and VREF.
    //
    // SELECT BIPOLAR register set PER CHANNEL BCH(X)/(X+1) TO 1 FOR BIPOLAR FULLY DIFFERENTIAL
    // SELECT RANGE register set PER CHANNEL PAIR RANGE(X)/(X+1) TO 0 +/-VREF+/2
    UNIPOLAR &= ~ (1 << AIN_0_1_LSB);
    BIPOLAR  |=   (1 << AIN_0_1_LSB);
    RANGE    &= ~ (1 << AIN_0_1_LSB);
    // UCH0/1=0, BCH0/1=1, RANGE0/1=0: AIN0/AIN1 differential input pair (+/-)(1/2)Vref, bipolar code (Full Scale = VREF, LSB = VREF/4096)
#endif // AIN_0_1_DifferentialBipolarFSVref

#if AIN_0_1_DifferentialBipolarFS2Vref
    
    //----------------------------------------
    // ADC Channels AIN0, AIN1 = Differential Bipolar
    // Full Scale = 2 * VREF
    // Voltage per LSB count = VREF/2048
    // AIN0, AIN1 are a Differential pair using Bipolar transfer function with range (+/-)Vref
    // AIN0 voltage must always be between 0 and VREF.
    // AIN1 voltage must always be between 0 and VREF.
    //
    // SELECT BIPOLAR register set PER CHANNEL BCH(X)/(X+1) TO 1 FOR BIPOLAR FULLY DIFFERENTIAL
    // SELECT RANGE register set PER CHANNEL PAIR RANGE(X)/(X+1) TO 1 +/-VREF+
    UNIPOLAR &= ~ (1 << AIN_0_1_LSB);
    BIPOLAR  |=   (1 << AIN_0_1_LSB);
    RANGE    |=   (1 << AIN_0_1_LSB);
    // UCH0/1=0, BCH0/1=1, RANGE0/1=1: AIN0/AIN1 differential input pair (+/-)Vref, bipolar code (Full Scale = 2VREF, LSB = VREF/2048)
#endif // AIN_0_1_DifferentialBipolarFS2Vref

#if AIN_2_3_SingleEnded
    
    //----------------------------------------
    // ADC Channels AIN2, AIN3 = Both Single-Ended, Unipolar
    // Full Scale = VREF
    // Voltage per LSB count = VREF/4096
    // AIN2 is a Single-Ended input using Unipolar transfer function.
    // AIN3 is a Single-Ended input using Unipolar transfer function.
    // If PDIFF_COM_1, both are Pseudo-Differential with REF- as common.
    // AIN2 voltage must always be between 0 and VREF.
    // AIN3 voltage must always be between 0 and VREF.
    //
    // SELECT UNIPOLAR AND BIPOLAR register set PER CHANNEL UCH(X)/(X+1) AND BCH(X)/(X+1) TO 0 FOR SINGLE-ENDED SELECTION
    UNIPOLAR &= ~ (1 << AIN_2_3_LSB);
    BIPOLAR  &= ~ (1 << AIN_2_3_LSB);
    RANGE    &= ~ (1 << AIN_2_3_LSB);
    // UCH2/3=0, BCH2/3=0, RANGE2/3=0: AIN0/AIN1 two independent single-ended inputs, unipolar code (Full Scale = VREF, LSB = VREF/4096)
#endif // AIN_2_3_SingleEnded

#if AIN_2_3_DifferentialUnipolar
    
    //----------------------------------------
    // ADC Channels AIN2, AIN3 = Differential Unipolar (AIN2 > AIN3)
    // Full Scale = VREF
    // Voltage per LSB count = VREF/4096
    // AIN2, AIN3 are a Differential pair using Unipolar transfer function.
    // AIN2 voltage must always be between 0 and VREF.
    // AIN3 voltage must always be between 0 and VREF.
    //
    // SELECT UNIPOLAR register set PER CHANNEL UCH(X)/(X+1) TO 1 FOR UNIPOLAR
    UNIPOLAR |=   (1 << AIN_2_3_LSB);
    BIPOLAR  &= ~ (1 << AIN_2_3_LSB);
    RANGE    &= ~ (1 << AIN_2_3_LSB);
    // UCH2/3=1, BCH2/3=0, RANGE2/3=0: AIN0/AIN1 differential input pair, unipolar code (AIN0>AIN1) (Full Scale = VREF, LSB = VREF/4096)
#endif // AIN_2_3_DifferentialUnipolar

#if AIN_2_3_DifferentialBipolarFSVref
    
    //----------------------------------------
    // ADC Channels AIN2, AIN3 = Differential Bipolar
    // Full Scale = VREF
    // Voltage per LSB count = VREF/4096
    // AIN2, AIN3 are a Differential pair using Bipolar transfer function with range (+/-)(1/2)Vref
    // AIN2 voltage must always be between 0 and VREF.
    // AIN3 voltage must always be between 0 and VREF.
    //
    // SELECT BIPOLAR register set PER CHANNEL BCH(X)/(X+1) TO 1 FOR BIPOLAR FULLY DIFFERENTIAL
    // SELECT RANGE register set PER CHANNEL PAIR RANGE(X)/(X+1) TO 0 +/-VREF+/2
    UNIPOLAR &= ~ (1 << AIN_2_3_LSB);
    BIPOLAR  |=   (1 << AIN_2_3_LSB);
    RANGE    &= ~ (1 << AIN_2_3_LSB);
    // UCH2/3=0, BCH2/3=1, RANGE2/3=0: AIN0/AIN1 differential input pair (+/-)(1/2)Vref, bipolar code (Full Scale = VREF, LSB = VREF/4096)
#endif // AIN_2_3_DifferentialBipolarFSVref

#if AIN_2_3_DifferentialBipolarFS2Vref
    
    //----------------------------------------
    // ADC Channels AIN2, AIN3 = Differential Bipolar
    // Full Scale = 2 * VREF
    // Voltage per LSB count = VREF/2048
    // AIN2, AIN3 are a Differential pair using Bipolar transfer function with range (+/-)Vref
    // AIN2 voltage must always be between 0 and VREF.
    // AIN3 voltage must always be between 0 and VREF.
    //
    // SELECT BIPOLAR register set PER CHANNEL BCH(X)/(X+1) TO 1 FOR BIPOLAR FULLY DIFFERENTIAL
    // SELECT RANGE register set PER CHANNEL PAIR RANGE(X)/(X+1) TO 1 +/-VREF+
    UNIPOLAR &= ~ (1 << AIN_2_3_LSB);
    BIPOLAR  |=   (1 << AIN_2_3_LSB);
    RANGE    |=   (1 << AIN_2_3_LSB);
    // UCH2/3=0, BCH2/3=1, RANGE2/3=1: AIN0/AIN1 differential input pair (+/-)Vref, bipolar code (Full Scale = 2VREF, LSB = VREF/2048)
#endif // AIN_2_3_DifferentialBipolarFS2Vref

#if AIN_4_5_SingleEnded
    
    //----------------------------------------
    // ADC Channels AIN4, AIN5 = Both Single-Ended, Unipolar
    // Full Scale = VREF
    // Voltage per LSB count = VREF/4096
    // AIN4 is a Single-Ended input using Unipolar transfer function.
    // AIN5 is a Single-Ended input using Unipolar transfer function.
    // If PDIFF_COM_1, both are Pseudo-Differential with REF- as common.
    // AIN4 voltage must always be between 0 and VREF.
    // AIN5 voltage must always be between 0 and VREF.
    //
    // SELECT UNIPOLAR AND BIPOLAR register set PER CHANNEL UCH(X)/(X+1) AND BCH(X)/(X+1) TO 0 FOR SINGLE-ENDED SELECTION
    UNIPOLAR &= ~ (1 << AIN_4_5_LSB);
    BIPOLAR  &= ~ (1 << AIN_4_5_LSB);
    RANGE    &= ~ (1 << AIN_4_5_LSB);
    // UCH4/5=0, BCH4/5=0, RANGE4/5=0: AIN0/AIN1 two independent single-ended inputs, unipolar code (Full Scale = VREF, LSB = VREF/4096)
#endif // AIN_4_5_SingleEnded

#if AIN_4_5_DifferentialUnipolar
    
    //----------------------------------------
    // ADC Channels AIN4, AIN5 = Differential Unipolar (AIN4 > AIN5)
    // Full Scale = VREF
    // Voltage per LSB count = VREF/4096
    // AIN4, AIN5 are a Differential pair using Unipolar transfer function.
    // AIN4 voltage must always be between 0 and VREF.
    // AIN5 voltage must always be between 0 and VREF.
    //
    // SELECT UNIPOLAR register set PER CHANNEL UCH(X)/(X+1) TO 1 FOR UNIPOLAR
    UNIPOLAR |=   (1 << AIN_4_5_LSB);
    BIPOLAR  &= ~ (1 << AIN_4_5_LSB);
    RANGE    &= ~ (1 << AIN_4_5_LSB);
    // UCH4/5=1, BCH4/5=0, RANGE4/5=0: AIN0/AIN1 differential input pair, unipolar code (AIN0>AIN1) (Full Scale = VREF, LSB = VREF/4096)
#endif // AIN_4_5_DifferentialUnipolar

#if AIN_4_5_DifferentialBipolarFSVref
    
    //----------------------------------------
    // ADC Channels AIN4, AIN5 = Differential Bipolar
    // Full Scale = VREF
    // Voltage per LSB count = VREF/4096
    // AIN4, AIN5 are a Differential pair using Bipolar transfer function with range (+/-)(1/2)Vref
    // AIN4 voltage must always be between 0 and VREF.
    // AIN5 voltage must always be between 0 and VREF.
    //
    // SELECT BIPOLAR register set PER CHANNEL BCH(X)/(X+1) TO 1 FOR BIPOLAR FULLY DIFFERENTIAL
    // SELECT RANGE register set PER CHANNEL PAIR RANGE(X)/(X+1) TO 0 +/-VREF+/2
    UNIPOLAR &= ~ (1 << AIN_4_5_LSB);
    BIPOLAR  |=   (1 << AIN_4_5_LSB);
    RANGE    &= ~ (1 << AIN_4_5_LSB);
    // UCH4/5=0, BCH4/5=1, RANGE4/5=0: AIN0/AIN1 differential input pair (+/-)(1/2)Vref, bipolar code (Full Scale = VREF, LSB = VREF/4096)
#endif // AIN_4_5_DifferentialBipolarFSVref

#if AIN_4_5_DifferentialBipolarFS2Vref
    
    //----------------------------------------
    // ADC Channels AIN4, AIN5 = Differential Bipolar
    // Full Scale = 2 * VREF
    // Voltage per LSB count = VREF/2048
    // AIN4, AIN5 are a Differential pair using Bipolar transfer function with range (+/-)Vref
    // AIN4 voltage must always be between 0 and VREF.
    // AIN5 voltage must always be between 0 and VREF.
    //
    // SELECT BIPOLAR register set PER CHANNEL BCH(X)/(X+1) TO 1 FOR BIPOLAR FULLY DIFFERENTIAL
    // SELECT RANGE register set PER CHANNEL PAIR RANGE(X)/(X+1) TO 1 +/-VREF+
    UNIPOLAR &= ~ (1 << AIN_4_5_LSB);
    BIPOLAR  |=   (1 << AIN_4_5_LSB);
    RANGE    |=   (1 << AIN_4_5_LSB);
    // UCH4/5=0, BCH4/5=1, RANGE4/5=1: AIN0/AIN1 differential input pair (+/-)Vref, bipolar code (Full Scale = 2VREF, LSB = VREF/2048)
#endif // AIN_4_5_DifferentialBipolarFS2Vref

#if AIN_6_7_SingleEnded
    
    //----------------------------------------
    // ADC Channels AIN6, AIN7 = Both Single-Ended, Unipolar
    // Full Scale = VREF
    // Voltage per LSB count = VREF/4096
    // AIN6 is a Single-Ended input using Unipolar transfer function.
    // AIN7 is a Single-Ended input using Unipolar transfer function.
    // If PDIFF_COM_1, both are Pseudo-Differential with REF- as common.
    // AIN6 voltage must always be between 0 and VREF.
    // AIN7 voltage must always be between 0 and VREF.
    //
    // SELECT UNIPOLAR AND BIPOLAR register set PER CHANNEL UCH(X)/(X+1) AND BCH(X)/(X+1) TO 0 FOR SINGLE-ENDED SELECTION
    UNIPOLAR &= ~ (1 << AIN_6_7_LSB);
    BIPOLAR  &= ~ (1 << AIN_6_7_LSB);
    RANGE    &= ~ (1 << AIN_6_7_LSB);
    // UCH6/7=0, BCH6/7=0, RANGE6/7=0: AIN0/AIN1 two independent single-ended inputs, unipolar code (Full Scale = VREF, LSB = VREF/4096)
#endif // AIN_6_7_SingleEnded

#if AIN_6_7_DifferentialUnipolar
    
    //----------------------------------------
    // ADC Channels AIN6, AIN7 = Differential Unipolar (AIN6 > AIN7)
    // Full Scale = VREF
    // Voltage per LSB count = VREF/4096
    // AIN6, AIN7 are a Differential pair using Unipolar transfer function.
    // AIN6 voltage must always be between 0 and VREF.
    // AIN7 voltage must always be between 0 and VREF.
    //
    // SELECT UNIPOLAR register set PER CHANNEL UCH(X)/(X+1) TO 1 FOR UNIPOLAR
    UNIPOLAR |=   (1 << AIN_6_7_LSB);
    BIPOLAR  &= ~ (1 << AIN_6_7_LSB);
    RANGE    &= ~ (1 << AIN_6_7_LSB);
    // UCH6/7=1, BCH6/7=0, RANGE6/7=0: AIN0/AIN1 differential input pair, unipolar code (AIN0>AIN1) (Full Scale = VREF, LSB = VREF/4096)
#endif // AIN_6_7_DifferentialUnipolar

#if AIN_6_7_DifferentialBipolarFSVref
    
    //----------------------------------------
    // ADC Channels AIN6, AIN7 = Differential Bipolar
    // Full Scale = VREF
    // Voltage per LSB count = VREF/4096
    // AIN6, AIN7 are a Differential pair using Bipolar transfer function with range (+/-)(1/2)Vref
    // AIN6 voltage must always be between 0 and VREF.
    // AIN7 voltage must always be between 0 and VREF.
    //
    // SELECT BIPOLAR register set PER CHANNEL BCH(X)/(X+1) TO 1 FOR BIPOLAR FULLY DIFFERENTIAL
    // SELECT RANGE register set PER CHANNEL PAIR RANGE(X)/(X+1) TO 0 +/-VREF+/2
    UNIPOLAR &= ~ (1 << AIN_6_7_LSB);
    BIPOLAR  |=   (1 << AIN_6_7_LSB);
    RANGE    &= ~ (1 << AIN_6_7_LSB);
    // UCH6/7=0, BCH6/7=1, RANGE6/7=0: AIN0/AIN1 differential input pair (+/-)(1/2)Vref, bipolar code (Full Scale = VREF, LSB = VREF/4096)
#endif // AIN_6_7_DifferentialBipolarFSVref

#if AIN_6_7_DifferentialBipolarFS2Vref
    
    //----------------------------------------
    // ADC Channels AIN6, AIN7 = Differential Bipolar
    // Full Scale = 2 * VREF
    // Voltage per LSB count = VREF/2048
    // AIN6, AIN7 are a Differential pair using Bipolar transfer function with range (+/-)Vref
    // AIN6 voltage must always be between 0 and VREF.
    // AIN7 voltage must always be between 0 and VREF.
    //
    // SELECT BIPOLAR register set PER CHANNEL BCH(X)/(X+1) TO 1 FOR BIPOLAR FULLY DIFFERENTIAL
    // SELECT RANGE register set PER CHANNEL PAIR RANGE(X)/(X+1) TO 1 +/-VREF+
    UNIPOLAR &= ~ (1 << AIN_6_7_LSB);
    BIPOLAR  |=   (1 << AIN_6_7_LSB);
    RANGE    |=   (1 << AIN_6_7_LSB);
    // UCH6/7=0, BCH6/7=1, RANGE6/7=1: AIN0/AIN1 differential input pair (+/-)Vref, bipolar code (Full Scale = 2VREF, LSB = VREF/2048)
#endif // AIN_6_7_DifferentialBipolarFS2Vref

#if AIN_8_9_SingleEnded
    
    //----------------------------------------
    // ADC Channels AIN8, AIN9 = Both Single-Ended, Unipolar
    // Full Scale = VREF
    // Voltage per LSB count = VREF/4096
    // AIN8 is a Single-Ended input using Unipolar transfer function.
    // AIN9 is a Single-Ended input using Unipolar transfer function.
    // If PDIFF_COM_1, both are Pseudo-Differential with REF- as common.
    // AIN8 voltage must always be between 0 and VREF.
    // AIN9 voltage must always be between 0 and VREF.
    //
    // SELECT UNIPOLAR AND BIPOLAR register set PER CHANNEL UCH(X)/(X+1) AND BCH(X)/(X+1) TO 0 FOR SINGLE-ENDED SELECTION
    UNIPOLAR &= ~ (1 << AIN_8_9_LSB);
    BIPOLAR  &= ~ (1 << AIN_8_9_LSB);
    RANGE    &= ~ (1 << AIN_8_9_LSB);
    // UCH8/9=0, BCH8/9=0, RANGE8/9=0: AIN0/AIN1 two independent single-ended inputs, unipolar code (Full Scale = VREF, LSB = VREF/4096)
#endif // AIN_8_9_SingleEnded

#if AIN_8_9_DifferentialUnipolar
    
    //----------------------------------------
    // ADC Channels AIN8, AIN9 = Differential Unipolar (AIN8 > AIN9)
    // Full Scale = VREF
    // Voltage per LSB count = VREF/4096
    // AIN8, AIN9 are a Differential pair using Unipolar transfer function.
    // AIN8 voltage must always be between 0 and VREF.
    // AIN9 voltage must always be between 0 and VREF.
    //
    // SELECT UNIPOLAR register set PER CHANNEL UCH(X)/(X+1) TO 1 FOR UNIPOLAR
    UNIPOLAR |=   (1 << AIN_8_9_LSB);
    BIPOLAR  &= ~ (1 << AIN_8_9_LSB);
    RANGE    &= ~ (1 << AIN_8_9_LSB);
    // UCH8/9=1, BCH8/9=0, RANGE8/9=0: AIN0/AIN1 differential input pair, unipolar code (AIN0>AIN1) (Full Scale = VREF, LSB = VREF/4096)
#endif // AIN_8_9_DifferentialUnipolar

#if AIN_8_9_DifferentialBipolarFSVref
    
    //----------------------------------------
    // ADC Channels AIN8, AIN9 = Differential Bipolar
    // Full Scale = VREF
    // Voltage per LSB count = VREF/4096
    // AIN8, AIN9 are a Differential pair using Bipolar transfer function with range (+/-)(1/2)Vref
    // AIN8 voltage must always be between 0 and VREF.
    // AIN9 voltage must always be between 0 and VREF.
    //
    // SELECT BIPOLAR register set PER CHANNEL BCH(X)/(X+1) TO 1 FOR BIPOLAR FULLY DIFFERENTIAL
    // SELECT RANGE register set PER CHANNEL PAIR RANGE(X)/(X+1) TO 0 +/-VREF+/2
    UNIPOLAR &= ~ (1 << AIN_8_9_LSB);
    BIPOLAR  |=   (1 << AIN_8_9_LSB);
    RANGE    &= ~ (1 << AIN_8_9_LSB);
    // UCH8/9=0, BCH8/9=1, RANGE8/9=0: AIN0/AIN1 differential input pair (+/-)(1/2)Vref, bipolar code (Full Scale = VREF, LSB = VREF/4096)
#endif // AIN_8_9_DifferentialBipolarFSVref

#if AIN_8_9_DifferentialBipolarFS2Vref
    
    //----------------------------------------
    // ADC Channels AIN8, AIN9 = Differential Bipolar
    // Full Scale = 2 * VREF
    // Voltage per LSB count = VREF/2048
    // AIN8, AIN9 are a Differential pair using Bipolar transfer function with range (+/-)Vref
    // AIN8 voltage must always be between 0 and VREF.
    // AIN9 voltage must always be between 0 and VREF.
    //
    // SELECT BIPOLAR register set PER CHANNEL BCH(X)/(X+1) TO 1 FOR BIPOLAR FULLY DIFFERENTIAL
    // SELECT RANGE register set PER CHANNEL PAIR RANGE(X)/(X+1) TO 1 +/-VREF+
    UNIPOLAR &= ~ (1 << AIN_8_9_LSB);
    BIPOLAR  |=   (1 << AIN_8_9_LSB);
    RANGE    |=   (1 << AIN_8_9_LSB);
    // UCH8/9=0, BCH8/9=1, RANGE8/9=1: AIN0/AIN1 differential input pair (+/-)Vref, bipolar code (Full Scale = 2VREF, LSB = VREF/2048)
#endif // AIN_8_9_DifferentialBipolarFS2Vref

#if AIN_10_11_SingleEnded
    
    //----------------------------------------
    // ADC Channels AIN10, AIN11 = Both Single-Ended, Unipolar
    // Full Scale = VREF
    // Voltage per LSB count = VREF/4096
    // AIN10 is a Single-Ended input using Unipolar transfer function.
    // AIN11 is a Single-Ended input using Unipolar transfer function.
    // If PDIFF_COM_1, both are Pseudo-Differential with REF- as common.
    // AIN10 voltage must always be between 0 and VREF.
    // AIN11 voltage must always be between 0 and VREF.
    //
    // SELECT UNIPOLAR AND BIPOLAR register set PER CHANNEL UCH(X)/(X+1) AND BCH(X)/(X+1) TO 0 FOR SINGLE-ENDED SELECTION
    UNIPOLAR &= ~ (1 << AIN_10_11_LSB);
    BIPOLAR  &= ~ (1 << AIN_10_11_LSB);
    RANGE    &= ~ (1 << AIN_10_11_LSB);
    // UCH10/11=0, BCH10/11=0, RANGE10/11=0: AIN0/AIN1 two independent single-ended inputs, unipolar code (Full Scale = VREF, LSB = VREF/4096)
#endif // AIN_10_11_SingleEnded

#if AIN_10_11_DifferentialUnipolar
    
    //----------------------------------------
    // ADC Channels AIN10, AIN11 = Differential Unipolar (AIN10 > AIN11)
    // Full Scale = VREF
    // Voltage per LSB count = VREF/4096
    // AIN10, AIN11 are a Differential pair using Unipolar transfer function.
    // AIN10 voltage must always be between 0 and VREF.
    // AIN11 voltage must always be between 0 and VREF.
    //
    // SELECT UNIPOLAR register set PER CHANNEL UCH(X)/(X+1) TO 1 FOR UNIPOLAR
    UNIPOLAR |=   (1 << AIN_10_11_LSB);
    BIPOLAR  &= ~ (1 << AIN_10_11_LSB);
    RANGE    &= ~ (1 << AIN_10_11_LSB);
    // UCH10/11=1, BCH10/11=0, RANGE10/11=0: AIN0/AIN1 differential input pair, unipolar code (AIN0>AIN1) (Full Scale = VREF, LSB = VREF/4096)
#endif // AIN_10_11_DifferentialUnipolar

#if AIN_10_11_DifferentialBipolarFSVref
    
    //----------------------------------------
    // ADC Channels AIN10, AIN11 = Differential Bipolar
    // Full Scale = VREF
    // Voltage per LSB count = VREF/4096
    // AIN10, AIN11 are a Differential pair using Bipolar transfer function with range (+/-)(1/2)Vref
    // AIN10 voltage must always be between 0 and VREF.
    // AIN11 voltage must always be between 0 and VREF.
    //
    // SELECT BIPOLAR register set PER CHANNEL BCH(X)/(X+1) TO 1 FOR BIPOLAR FULLY DIFFERENTIAL
    // SELECT RANGE register set PER CHANNEL PAIR RANGE(X)/(X+1) TO 0 +/-VREF+/2
    UNIPOLAR &= ~ (1 << AIN_10_11_LSB);
    BIPOLAR  |=   (1 << AIN_10_11_LSB);
    RANGE    &= ~ (1 << AIN_10_11_LSB);
    // UCH10/11=0, BCH10/11=1, RANGE10/11=0: AIN0/AIN1 differential input pair (+/-)(1/2)Vref, bipolar code (Full Scale = VREF, LSB = VREF/4096)
#endif // AIN_10_11_DifferentialBipolarFSVref

#if AIN_10_11_DifferentialBipolarFS2Vref
    
    //----------------------------------------
    // ADC Channels AIN10, AIN11 = Differential Bipolar
    // Full Scale = 2 * VREF
    // Voltage per LSB count = VREF/2048
    // AIN10, AIN11 are a Differential pair using Bipolar transfer function with range (+/-)Vref
    // AIN10 voltage must always be between 0 and VREF.
    // AIN11 voltage must always be between 0 and VREF.
    //
    // SELECT BIPOLAR register set PER CHANNEL BCH(X)/(X+1) TO 1 FOR BIPOLAR FULLY DIFFERENTIAL
    // SELECT RANGE register set PER CHANNEL PAIR RANGE(X)/(X+1) TO 1 +/-VREF+
    UNIPOLAR &= ~ (1 << AIN_10_11_LSB);
    BIPOLAR  |=   (1 << AIN_10_11_LSB);
    RANGE    |=   (1 << AIN_10_11_LSB);
    // UCH10/11=0, BCH10/11=1, RANGE10/11=1: AIN0/AIN1 differential input pair (+/-)Vref, bipolar code (Full Scale = 2VREF, LSB = VREF/2048)
#endif // AIN_10_11_DifferentialBipolarFS2Vref

#if AIN_12_13_SingleEnded
    
    //----------------------------------------
    // ADC Channels AIN12, AIN13 = Both Single-Ended, Unipolar
    // Full Scale = VREF
    // Voltage per LSB count = VREF/4096
    // AIN12 is a Single-Ended input using Unipolar transfer function.
    // AIN13 is a Single-Ended input using Unipolar transfer function.
    // If PDIFF_COM_1, both are Pseudo-Differential with REF- as common.
    // AIN12 voltage must always be between 0 and VREF.
    // AIN13 voltage must always be between 0 and VREF.
    //
    // SELECT UNIPOLAR AND BIPOLAR register set PER CHANNEL UCH(X)/(X+1) AND BCH(X)/(X+1) TO 0 FOR SINGLE-ENDED SELECTION
    UNIPOLAR &= ~ (1 << AIN_12_13_LSB);
    BIPOLAR  &= ~ (1 << AIN_12_13_LSB);
    RANGE    &= ~ (1 << AIN_12_13_LSB);
    // UCH12/13=0, BCH12/13=0, RANGE12/13=0: AIN0/AIN1 two independent single-ended inputs, unipolar code (Full Scale = VREF, LSB = VREF/4096)
#endif // AIN_12_13_SingleEnded

#if AIN_12_13_DifferentialUnipolar
    
    //----------------------------------------
    // ADC Channels AIN12, AIN13 = Differential Unipolar (AIN12 > AIN13)
    // Full Scale = VREF
    // Voltage per LSB count = VREF/4096
    // AIN12, AIN13 are a Differential pair using Unipolar transfer function.
    // AIN12 voltage must always be between 0 and VREF.
    // AIN13 voltage must always be between 0 and VREF.
    //
    // SELECT UNIPOLAR register set PER CHANNEL UCH(X)/(X+1) TO 1 FOR UNIPOLAR
    UNIPOLAR |=   (1 << AIN_12_13_LSB);
    BIPOLAR  &= ~ (1 << AIN_12_13_LSB);
    RANGE    &= ~ (1 << AIN_12_13_LSB);
    // UCH12/13=1, BCH12/13=0, RANGE12/13=0: AIN0/AIN1 differential input pair, unipolar code (AIN0>AIN1) (Full Scale = VREF, LSB = VREF/4096)
#endif // AIN_12_13_DifferentialUnipolar

#if AIN_12_13_DifferentialBipolarFSVref
    
    //----------------------------------------
    // ADC Channels AIN12, AIN13 = Differential Bipolar
    // Full Scale = VREF
    // Voltage per LSB count = VREF/4096
    // AIN12, AIN13 are a Differential pair using Bipolar transfer function with range (+/-)(1/2)Vref
    // AIN12 voltage must always be between 0 and VREF.
    // AIN13 voltage must always be between 0 and VREF.
    //
    // SELECT BIPOLAR register set PER CHANNEL BCH(X)/(X+1) TO 1 FOR BIPOLAR FULLY DIFFERENTIAL
    // SELECT RANGE register set PER CHANNEL PAIR RANGE(X)/(X+1) TO 0 +/-VREF+/2
    UNIPOLAR &= ~ (1 << AIN_12_13_LSB);
    BIPOLAR  |=   (1 << AIN_12_13_LSB);
    RANGE    &= ~ (1 << AIN_12_13_LSB);
    // UCH12/13=0, BCH12/13=1, RANGE12/13=0: AIN0/AIN1 differential input pair (+/-)(1/2)Vref, bipolar code (Full Scale = VREF, LSB = VREF/4096)
#endif // AIN_12_13_DifferentialBipolarFSVref

#if AIN_12_13_DifferentialBipolarFS2Vref
    
    //----------------------------------------
    // ADC Channels AIN12, AIN13 = Differential Bipolar
    // Full Scale = 2 * VREF
    // Voltage per LSB count = VREF/2048
    // AIN12, AIN13 are a Differential pair using Bipolar transfer function with range (+/-)Vref
    // AIN12 voltage must always be between 0 and VREF.
    // AIN13 voltage must always be between 0 and VREF.
    //
    // SELECT BIPOLAR register set PER CHANNEL BCH(X)/(X+1) TO 1 FOR BIPOLAR FULLY DIFFERENTIAL
    // SELECT RANGE register set PER CHANNEL PAIR RANGE(X)/(X+1) TO 1 +/-VREF+
    UNIPOLAR &= ~ (1 << AIN_12_13_LSB);
    BIPOLAR  |=   (1 << AIN_12_13_LSB);
    RANGE    |=   (1 << AIN_12_13_LSB);
    // UCH12/13=0, BCH12/13=1, RANGE12/13=1: AIN0/AIN1 differential input pair (+/-)Vref, bipolar code (Full Scale = 2VREF, LSB = VREF/2048)
#endif // AIN_12_13_DifferentialBipolarFS2Vref

#if AIN_14_15_SingleEnded
    
    //----------------------------------------
    // ADC Channels AIN14, AIN15 = Both Single-Ended, Unipolar
    // Full Scale = VREF
    // Voltage per LSB count = VREF/4096
    // AIN14 is a Single-Ended input using Unipolar transfer function.
    // AIN15 is a Single-Ended input using Unipolar transfer function.
    // If PDIFF_COM_1, both are Pseudo-Differential with REF- as common.
    // AIN14 voltage must always be between 0 and VREF.
    // AIN15 voltage must always be between 0 and VREF.
    //
    // SELECT UNIPOLAR AND BIPOLAR register set PER CHANNEL UCH(X)/(X+1) AND BCH(X)/(X+1) TO 0 FOR SINGLE-ENDED SELECTION
    UNIPOLAR &= ~ (1 << AIN_14_15_LSB);
    BIPOLAR  &= ~ (1 << AIN_14_15_LSB);
    RANGE    &= ~ (1 << AIN_14_15_LSB);
    // UCH14/15=0, BCH14/15=0, RANGE14/15=0: AIN0/AIN1 two independent single-ended inputs, unipolar code (Full Scale = VREF, LSB = VREF/4096)
#endif // AIN_14_15_SingleEnded

#if AIN_14_15_DifferentialUnipolar
    
    //----------------------------------------
    // ADC Channels AIN14, AIN15 = Differential Unipolar (AIN14 > AIN15)
    // Full Scale = VREF
    // Voltage per LSB count = VREF/4096
    // AIN14, AIN15 are a Differential pair using Unipolar transfer function.
    // AIN14 voltage must always be between 0 and VREF.
    // AIN15 voltage must always be between 0 and VREF.
    //
    // SELECT UNIPOLAR register set PER CHANNEL UCH(X)/(X+1) TO 1 FOR UNIPOLAR
    UNIPOLAR |=   (1 << AIN_14_15_LSB);
    BIPOLAR  &= ~ (1 << AIN_14_15_LSB);
    RANGE    &= ~ (1 << AIN_14_15_LSB);
    // UCH14/15=1, BCH14/15=0, RANGE14/15=0: AIN0/AIN1 differential input pair, unipolar code (AIN0>AIN1) (Full Scale = VREF, LSB = VREF/4096)
#endif // AIN_14_15_DifferentialUnipolar

#if AIN_14_15_DifferentialBipolarFSVref
    
    //----------------------------------------
    // ADC Channels AIN14, AIN15 = Differential Bipolar
    // Full Scale = VREF
    // Voltage per LSB count = VREF/4096
    // AIN14, AIN15 are a Differential pair using Bipolar transfer function with range (+/-)(1/2)Vref
    // AIN14 voltage must always be between 0 and VREF.
    // AIN15 voltage must always be between 0 and VREF.
    //
    // SELECT BIPOLAR register set PER CHANNEL BCH(X)/(X+1) TO 1 FOR BIPOLAR FULLY DIFFERENTIAL
    // SELECT RANGE register set PER CHANNEL PAIR RANGE(X)/(X+1) TO 0 +/-VREF+/2
    UNIPOLAR &= ~ (1 << AIN_14_15_LSB);
    BIPOLAR  |=   (1 << AIN_14_15_LSB);
    RANGE    &= ~ (1 << AIN_14_15_LSB);
    // UCH14/15=0, BCH14/15=1, RANGE14/15=0: AIN0/AIN1 differential input pair (+/-)(1/2)Vref, bipolar code (Full Scale = VREF, LSB = VREF/4096)
#endif // AIN_14_15_DifferentialBipolarFSVref

#if AIN_14_15_DifferentialBipolarFS2Vref
    
    //----------------------------------------
    // ADC Channels AIN14, AIN15 = Differential Bipolar
    // Full Scale = 2 * VREF
    // Voltage per LSB count = VREF/2048
    // AIN14, AIN15 are a Differential pair using Bipolar transfer function with range (+/-)Vref
    // AIN14 voltage must always be between 0 and VREF.
    // AIN15 voltage must always be between 0 and VREF.
    //
    // SELECT BIPOLAR register set PER CHANNEL BCH(X)/(X+1) TO 1 FOR BIPOLAR FULLY DIFFERENTIAL
    // SELECT RANGE register set PER CHANNEL PAIR RANGE(X)/(X+1) TO 1 +/-VREF+
    UNIPOLAR &= ~ (1 << AIN_14_15_LSB);
    BIPOLAR  |=   (1 << AIN_14_15_LSB);
    RANGE    |=   (1 << AIN_14_15_LSB);
    // UCH14/15=0, BCH14/15=1, RANGE14/15=1: AIN0/AIN1 differential input pair (+/-)Vref, bipolar code (Full Scale = 2VREF, LSB = VREF/2048)
#endif // AIN_14_15_DifferentialBipolarFS2Vref
    
    //----------------------------------------
    // SPI write ADC CONFIGURATION register
    // Send SPI configuration to device
    SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern
    SPIoutputCS(0); // drive CS low
    SPIwrite16bits(ADC_CONFIGURATION);
    SPIoutputCS(1); // drive CS high
    
    //----------------------------------------
    // SPI write UNIPOLAR BIPOLAR RANGE registers
    SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern
    SPIoutputCS(0); // drive CS low
    SPIwrite16bits(UNIPOLAR);
    SPIoutputCS(1); // drive CS high
    SPIoutputCS(0); // drive CS low
    SPIwrite16bits(BIPOLAR);
    SPIoutputCS(1); // drive CS high
    SPIoutputCS(0); // drive CS low
    SPIwrite16bits(RANGE);
    SPIoutputCS(1); // drive CS high
    
    //----------------------------------------
    // SPI write CSCAN0 CSCAN1 registers
    SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern
    SPIoutputCS(0); // drive CS low
    SPIwrite16bits(CSCAN0);
    SPIoutputCS(1); // drive CS high
    SPIoutputCS(0); // drive CS low
    SPIwrite16bits(CSCAN1);
    SPIoutputCS(1); // drive CS high
}

//----------------------------------------
// ADC Channels AIN(channelId), AIN(channelId+1) = Both Single-Ended, Unipolar
// Full Scale = VREF
// Voltage per LSB count = VREF/4096
// AIN(channelId) is a Single-Ended input using Unipolar transfer function.
// AIN(channelId+1) is a Single-Ended input using Unipolar transfer function.
// If PDIFF_COM_1, both are Pseudo-Differential with REF- as common.
// AIN(channelId) voltage must always be between 0 and VREF.
// AIN(channelId+1) voltage must always be between 0 and VREF.
//
void MAX11131::Reconfigure_SingleEnded(int channelNumber_0_15)
{
    
    //----------------------------------------
    // UCH(ch)/(ch+1)=0, BCH(ch)/(ch+1)=0, RANGE(ch)/(ch+1)=0:
    // AIN(ch)/AIN(ch+1) two independent single-ended inputs,
    // unipolar code (Full Scale = VREF, LSB = VREF/4096)
    // 
    const int channelPairIndex = channelNumber_0_15 / 2;
    const int bitmask = (1 << (10 - channelPairIndex));
    UNIPOLAR &= ~ bitmask;
    BIPOLAR  &= ~ bitmask;
    RANGE    &= ~ bitmask;
    
    //----------------------------------------
    // SPI write UNIPOLAR BIPOLAR RANGE registers
    SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern
    SPIoutputCS(0); // drive CS low
    SPIwrite16bits(UNIPOLAR);
    SPIoutputCS(1); // drive CS high
    SPIoutputCS(0); // drive CS low
    SPIwrite16bits(BIPOLAR);
    SPIoutputCS(1); // drive CS high
    SPIoutputCS(0); // drive CS low
    SPIwrite16bits(RANGE);
    SPIoutputCS(1); // drive CS high
}

//----------------------------------------
// ADC Channels AIN(channelId), AIN(channelId+1) = Differential Unipolar (AIN(channelId) > AIN(channelId+1))
// Full Scale = VREF
// Voltage per LSB count = VREF/4096
// AIN(channelId), AIN(channelId+1) are a Differential pair using Unipolar transfer function.
// AIN(channelId) voltage must always be between 0 and VREF.
// AIN(channelId+1) voltage must always be between 0 and VREF.
//
void MAX11131::Reconfigure_DifferentialUnipolar(int channelNumber_0_15)
{
    
    //----------------------------------------
    // UCH(ch)/(ch+1)=1, BCH(ch)/(ch+1)=0, RANGE(ch)/(ch+1)=0:
    // AIN(ch)/AIN(ch+1) differential input pair,
    // unipolar code (AIN(ch)>AIN(ch+1)) (Full Scale = VREF, LSB = VREF/4096)
    // 
    const int channelPairIndex = channelNumber_0_15 / 2;
    const int bitmask = (1 << (10 - channelPairIndex));
    UNIPOLAR |=   bitmask;
    BIPOLAR  &= ~ bitmask;
    RANGE    &= ~ bitmask;
    // UCH0/1=1, BCH0/1=0, RANGE0/1=0: AIN0/AIN1 differential input pair, unipolar code (AIN0>AIN1) (Full Scale = VREF, LSB = VREF/4096)
    
    //----------------------------------------
    // SPI write UNIPOLAR BIPOLAR RANGE registers
    SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern
    SPIoutputCS(0); // drive CS low
    SPIwrite16bits(UNIPOLAR);
    SPIoutputCS(1); // drive CS high
    SPIoutputCS(0); // drive CS low
    SPIwrite16bits(BIPOLAR);
    SPIoutputCS(1); // drive CS high
    SPIoutputCS(0); // drive CS low
    SPIwrite16bits(RANGE);
    SPIoutputCS(1); // drive CS high
}

//----------------------------------------
// ADC Channels AIN(channelId), AIN(channelId+1) = Differential Bipolar
// Full Scale = VREF
// Voltage per LSB count = VREF/4096
// AIN(channelId), AIN(channelId+1) are a Differential pair using Bipolar transfer function with range (+/-)(1/2)Vref
// AIN(channelId) voltage must always be between 0 and VREF.
// AIN(channelId+1) voltage must always be between 0 and VREF.
//
void MAX11131::Reconfigure_DifferentialBipolarFSVref(int channelNumber_0_15)
{
    
    //----------------------------------------
    // UCH(ch)/(ch+1)=0, BCH(ch)/(ch+1)=1, RANGE(ch)/(ch+1)=0:
    // AIN(ch)/AIN(ch+1) differential input pair (+/-)(1/2)Vref,
    // bipolar code (Full Scale = VREF, LSB = VREF/4096)
    // 
    const int channelPairIndex = channelNumber_0_15 / 2;
    const int bitmask = (1 << (10 - channelPairIndex));
    UNIPOLAR &= ~ bitmask;
    BIPOLAR  |=   bitmask;
    RANGE    &= ~ bitmask;
    
    //----------------------------------------
    // SPI write UNIPOLAR BIPOLAR RANGE registers
    SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern
    SPIoutputCS(0); // drive CS low
    SPIwrite16bits(UNIPOLAR);
    SPIoutputCS(1); // drive CS high
    SPIoutputCS(0); // drive CS low
    SPIwrite16bits(BIPOLAR);
    SPIoutputCS(1); // drive CS high
    SPIoutputCS(0); // drive CS low
    SPIwrite16bits(RANGE);
    SPIoutputCS(1); // drive CS high
}

//----------------------------------------
// ADC Channels AIN(channelId), AIN(channelId+1) = Differential Bipolar
// Full Scale = 2 * VREF
// Voltage per LSB count = VREF/2048
// AIN(channelId), AIN(channelId+1) are a Differential pair using Bipolar transfer function with range (+/-)Vref
// AIN(channelId) voltage must always be between 0 and VREF.
// AIN(channelId+1) voltage must always be between 0 and VREF.
//
void MAX11131::Reconfigure_DifferentialBipolarFS2Vref(int channelNumber_0_15)
{
    
    //----------------------------------------
    // UCH(ch)/(ch+1)=0, BCH(ch)/(ch+1)=1, RANGE(ch)/(ch+1)=1:
    // AIN(ch)/AIN(ch+1) differential input pair (+/-)Vref,
    // bipolar code (Full Scale = 2VREF, LSB = VREF/2048)
    // 
    const int channelPairIndex = channelNumber_0_15 / 2;
    const int bitmask = (1 << (10 - channelPairIndex));
    UNIPOLAR &= ~ bitmask;
    BIPOLAR  |=   bitmask;
    RANGE    |=   bitmask;
    // UCH0/1=0, BCH0/1=1, RANGE0/1=1: AIN0/AIN1 differential input pair (+/-)Vref, bipolar code (Full Scale = 2VREF, LSB = VREF/2048)
    
    //----------------------------------------
    // SPI write UNIPOLAR BIPOLAR RANGE registers
    SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern
    SPIoutputCS(0); // drive CS low
    SPIwrite16bits(UNIPOLAR);
    SPIoutputCS(1); // drive CS high
    SPIoutputCS(0); // drive CS low
    SPIwrite16bits(BIPOLAR);
    SPIoutputCS(1); // drive CS high
    SPIoutputCS(0); // drive CS low
    SPIwrite16bits(RANGE);
    SPIoutputCS(1); // drive CS high
}

//----------------------------------------
// SCAN_0000_NOP
//
// Shift 16 bits out of ADC, without changing configuration.
// Note: @return data format depends on CHAN_ID bit:
//     "CH[3:0] DATA[11:0]" when CHAN_ID = 1, or
//     "0 DATA[11:0] x x x" when CHAN_ID = 0.
int16_t MAX11131::ScanRead(void)
{
    
    //----------------------------------------
    // Read SPI data from device while MOSI (Maxim DIN) is 0. Effectively ADC_MODE_CONTROL SCAN[3:0] = SCAN_0000_NOP = 0
    SPI_MOSI_Semantic = 0; // 0:Nothing 1:regWrite 2:sampleSetPattern
    SPIoutputCS(0); // drive CS low
    int16_t misoData16 = SPIread16bits();
    SPIoutputCS(1); // drive CS high
    // For external clock modes, the data format returned depends on the CHAN_ID bit.
    //     when CHAN_ID = 0: misoData16 = 0 DATA[11:0] x x x
    //     when CHAN_ID = 1: misoData16 = CH[3:0] DATA[11:0]
    // For internal clock modes, the data format always includes the channel address.
    //     misoData16 = CH[3:0] DATA[11:0]
    return misoData16;
}

//----------------------------------------
// SCAN_0000_NOP
//
// Read raw ADC codes from device into AINcode[] and RAW_misoData16[].
// If internal clock mode with SWCNV=0, measurements will be triggered using CNVST pin.
//
// @pre one of the Scan functions was called, setting NumWords
// @post RAW_misoData16[index] contains the raw SPI Master-In,Slave-Out data
// @post AINcode[NUM_CHANNELS] contains the latest readings in LSBs
//
void MAX11131::ReadAINcode(void)
{
    
    //----------------------------------------
    // loop index for RAW_misoData16[SAMPLESET_MAX_ENTRIES];
    int index;
    
    //----------------------------------------
    // If internal clock mode with SWCNV=0, trigger measurement using CNVST pin and wait for EOC pin.
      if (isExternalClock == 0)
      {
        if (swcnv_0_1 == 0)
        {
          // SWCNV=0: trigger measurement by driving CNVST/AIN14 pin low
          // for a minimum active-low pulse duration of 5ns. (AIN14 is not available)
          // One CNVST pulse scans all requested channels and stores the results in the FIFO.
          CNVSToutputPulseLow();
        }
        // wait for EOC low (internal clock mode end of conversion)
        EOCinputWaitUntilLow();
      }
    
    //----------------------------------------
    // Read raw ADC codes from device into AINcode[] and RAW_misoData16[].
      // For external clock modes, the data format returned depends on the CHAN_ID bit.
      //     when CHAN_ID = 0: misoData16 = 0 DATA[11:0] x x x
      //     when CHAN_ID = 1: misoData16 = CH[3:0] DATA[11:0]
      // For internal clock modes, the data format always includes the channel address.
      //     misoData16 = CH[3:0] DATA[11:0]
      switch(ScanMode)
      {
        //----------------------------------------
        // read data words
        // For internal clock modes, the data format always includes the channel address.
        //     misoData16 = CH[3:0] DATA[11:0]
      case SCAN_0000_NOP:
      case SCAN_0011_StandardInternalClock:
      case SCAN_0101_UpperInternalClock:
      case SCAN_0111_CustomInternalClock:
      default:
          for (index = 0; index < NumWords; index++) {
            RAW_misoData16[index] = ScanRead();
            // For internal clock modes, the data format always includes the channel address.
            //     misoData16 = CH[3:0] DATA[11:0]
            int16_t value_u12 = (RAW_misoData16[index] & 0x0FFF);
            int channelId = ((RAW_misoData16[index] >> 12) & 0x000F);
            AINcode[channelId] = value_u12;
          }
        break;
        //----------------------------------------
        // read data words
        // For external clock modes, the data format returned depends on the CHAN_ID bit.
        //     when CHAN_ID = 0: misoData16 = 0 DATA[11:0] x x x
        //     when CHAN_ID = 1: misoData16 = CH[3:0] DATA[11:0]
        // For internal clock modes, the data format always includes the channel address.
        //     misoData16 = CH[3:0] DATA[11:0]
      case SCAN_0001_Manual:
      case SCAN_0100_StandardExternalClock:
      case SCAN_0110_UpperExternalClock:
      case SCAN_1000_CustomExternalClock:
      case SCAN_1001_SampleSetExternalClock:
        if (chan_id_0_1 != 0) {
          for (index = 0; index < NumWords; index++) {
            RAW_misoData16[index] = ScanRead();
            // For internal clock modes, the data format always includes the channel address.
            //     misoData16 = CH[3:0] DATA[11:0]
            int16_t value_u12 = (RAW_misoData16[index] & 0x0FFF);
            int channelId = ((RAW_misoData16[index] >> 12) & 0x000F);
            AINcode[channelId] = value_u12;
          }
        } else {
          for (index = 0; index < NumWords; index++) {
            RAW_misoData16[index] = ScanRead();
            int16_t value_u12 = ((RAW_misoData16[index] >> 3) & 0x0FFF);
            int channelId = channelNumber_0_15;
            AINcode[channelId] = value_u12;
          }
        }
        break;
        //----------------------------------------
        // read data words and calculate mean, stddev
      case SCAN_0010_Repeat:
        // ScanRead_nWords_chanID_mean(NumWords); // TODO1: missing function
        // was this function AINcode_print_value_chanID_mean(int nWords) in main?
        // But this function prints to standard output so can't be inside the driver.
        for (index = 0; index < NumWords; index++) {
          RAW_misoData16[index] = ScanRead();
        }
        break;
      }
}

//----------------------------------------
// Sign-Extend a right-aligned MAX11131 code into a signed 2's complement value.
// Supports the bipolar transfer functions.
// @param[in] value_u12: raw 12-bit MAX11131 code (right justified).
// @return sign-extended 2's complement value.
//
int32_t MAX11131::TwosComplementValue(uint32_t regValue)
{
    const uint16_t SIGN_BIT_12BIT = 0x0800;
    const uint16_t FULL_SCALE_CODE_12BIT = 0x0fff;
    if (((regValue & SIGN_BIT_12BIT) != 0) && !((regValue & (SIGN_BIT_12BIT << 1)) != 0))
    {
        // (bSignBitNegative && !bExtendedSignBitNegative)
        // Twos_Complement negative value
        int32_t Offset_regValue = (int32_t)(regValue - (FULL_SCALE_CODE_12BIT + 1));
        return Offset_regValue;
    }
    // Twos_Complement positive value or zero
    return (int32_t)regValue;
}

//----------------------------------------
// Return the physical voltage corresponding to MAX11131 code.
// Does not perform any offset or gain correction.
// @pre VRef = Voltage of REF input, in Volts
// @param[in] value_u12: raw 12-bit MAX11131 code (right justified).
// @param[in] channelId: AIN channel number.
// @return physical voltage corresponding to MAX11131 code.
//
double MAX11131::VoltageOfCode(int16_t value_u12, int channelId)
{
    int channelPairIndex = channelId / 2;
    // format: 1 0 0 0 1 UCH0/1 UCH2/3 UCH4/5 UCH6/7 UCH8/9 UCH10/11 UCH12/13 UCH14/15 PDIFF_COM x x
    int UCHn = (UNIPOLAR >> (10 - channelPairIndex)) & 0x01;
    int BCHn = (BIPOLAR >> (10 - channelPairIndex)) & 0x01;
    int RANGEn = (RANGE >> (10 - channelPairIndex)) & 0x01;
    if (UCHn)
    {
        // UCH0/1=1, BCH0/1=0, RANGE0/1=0: AIN0/AIN1 differential input pair, unipolar code (AIN0>AIN1) (Full Scale = VREF, LSB = VREF/4096)
        return (value_u12 * VRef / 4096);
    }
    else
    {
        if (BCHn)
        {
            if (RANGEn)
            {
                // UCH0/1=0, BCH0/1=1, RANGE0/1=1: AIN0/AIN1 differential input pair (+/-)Vref, bipolar code (Full Scale = 2VREF, LSB = VREF/2048)
                return (TwosComplementValue(value_u12) * VRef / 2048);
            }
            else
            {
                // UCH0/1=0, BCH0/1=1, RANGE0/1=0: AIN0/AIN1 differential input pair (+/-)(1/2)Vref, bipolar code (Full Scale = VREF, LSB = VREF/4096)
                return (TwosComplementValue(value_u12) * VRef / 4096);
            }
        }
        else
        {
            // UCH0/1=0, BCH0/1=0, RANGE0/1=0: AIN0/AIN1 two independent single-ended inputs, unipolar code (Full Scale = VREF, LSB = VREF/4096)
            return (value_u12 * VRef / 4096);
        }
    }
}

//----------------------------------------
// SCAN_0001_Manual
//
// Measure ADC channel channelNumber_0_15 once.
// External clock mode.
// @param[in] channelNumber_0_15: AIN Channel Number
// @param[in] PowerManagement_0_2: 0=Normal, 1=AutoShutdown, 2=AutoStandby
// @param[in] chan_id_0_1: ADC_MODE_CONTROL.CHAN_ID
// @return number of ScanRead() words needed to retrieve the data.
// For external clock modes, the data format depends on CHAN_ID.
//     when CHAN_ID = 0: misoData16 = 0 DATA[11:0] x x x
//     when CHAN_ID = 1: misoData16 = CH[3:0] DATA[11:0]
//
int MAX11131::ScanManual(void)
{
    
    //----------------------------------------
    // define write-only register ADC_MODE_CONTROL
    ADC_MODE_CONTROL = 0;       //!< mosiData16 0x0000..0x7FFF format: 0 SCAN[3:0] CHSEL[3:0] RESET[1:0] PM[1:0] CHAN_ID SWCNV 0
    const int SCAN_LSB    = 11; const int SCAN_BITS    = 0x0F; //!< ADC_MODE_CONTROL.SCAN[3:0] ADC Scan Control (command)
    const int CHSEL_LSB   =  7; const int CHSEL_BITS   = 0x0F; //!< ADC_MODE_CONTROL.CHSEL[3:0] Analog Input Channel Select AIN0..AIN15
    const int RESET_LSB   =  5; const int RESET_BITS   = 0x03; //!< ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved
    const int PM_LSB      =  3; const int PM_BITS      = 0x03; //!< ADC_MODE_CONTROL.PM[1:0] Power Management 0=Normal, 1=AutoShutdown, 2=AutoStandby 3=reserved
    const int CHAN_ID_LSB =  2; const int CHAN_ID_BITS = 0x01; //!< ADC_MODE_CONTROL.CHAN_ID
    const int SWCNV_LSB   =  1; const int SWCNV_BITS   = 0x01; //!< ADC_MODE_CONTROL.SWCNV
    
    //----------------------------------------
    // Apply a soft reset when changing from internal to external clock mode.
    int needFIFOreset = (isExternalClock != 1);
    if (needFIFOreset) {
        // Apply a soft reset when changing from internal to external clock mode.
        ADC_MODE_CONTROL = ((1 & RESET_BITS) << RESET_LSB); // ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved
        // Send SPI configuration to device
        SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern
        SPIoutputCS(0); // drive CS low
        SPIwrite16bits(ADC_MODE_CONTROL);
        SPIoutputCS(1); // drive CS high
        ADC_MODE_CONTROL = 0;
    }
    
    //----------------------------------------
    // number of words to read
    NumWords = 1;
    
    //----------------------------------------
    // External Clock Mode
    isExternalClock = 1;
    
    //----------------------------------------
    // update device driver global variable
    ScanMode = SCAN_0001_Manual;
    
    //----------------------------------------
    // ADC MODE CONTROL register set SCAN[3:0] TO SCAN_0001_Manual = 1
    //~ const int SCAN_0001_Manual = 1; // replaced local const with enum
    ADC_MODE_CONTROL |=   ((SCAN_0001_Manual & SCAN_BITS) << SCAN_LSB);
    
    //----------------------------------------
    // ADC MODE CONTROL register set CHSEL[3:0] TO channel number
    ADC_MODE_CONTROL |=   ((channelNumber_0_15 & CHSEL_BITS) << CHSEL_LSB);
    
    //----------------------------------------
    // ADC MODE CONTROL REGISTER SELECT THE PM[1:0] BITS
    ADC_MODE_CONTROL |=   ((PowerManagement_0_2 & PM_BITS) << PM_LSB);
    
    //----------------------------------------
    // ADC MODE CONTROL REGISTER SELECT THE CHAN_ID BIT
    // (applicable to external clock mode only)
    // For external clock modes, the data format returned depends on the CHAN_ID bit.
    //     when CHAN_ID = 0: misoData16 = 0 DATA[11:0] x x x
    //     when CHAN_ID = 1: misoData16 = CH[3:0] DATA[11:0]
    // For internal clock modes, the data format always includes the channel address.
    //     misoData16 = CH[3:0] DATA[11:0]
    ADC_MODE_CONTROL |=   ((chan_id_0_1 & CHAN_ID_BITS) << CHAN_ID_LSB);
    
    //----------------------------------------
    // SPI write ADC MODE CONTROL register
    // Send SPI configuration to device
    SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern
    SPIoutputCS(0); // drive CS low
    SPIwrite16bits(ADC_MODE_CONTROL);
    SPIoutputCS(1); // drive CS high
    
    //----------------------------------------
    // return number of words to read
    return NumWords;
}

//----------------------------------------
// SCAN_0010_Repeat
//
// Measure ADC channel channelNumber_0_15 repeatedly with averaging.
// Internal clock mode.
// @param[in] channelNumber_0_15: AIN Channel Number
// @param[in] average_0_4_8_16_32: Number of samples averaged per ScanRead() word.
//     average_0_4_8_16_32=0 to disable averaging.
// @param[in] nscan_4_8_12_16: Number of ScanRead() words to report.
// @param[in] swcnv_0_1: ADC_MODE_CONTROL.SWCNV
//     SWCNV=0: trigger measurement by driving CNVST pin low.
//         Minimum active-low pulse duration of 5ns. (AIN14 is not available)
//     SWCNV=1: trigger measurement on SPI CS rising edge.
//         CS must be held low for minimum of 17 SCLK cycles.
//         CNVST pin is not used. (AIN14 is available)
// @param[in] PowerManagement_0_2: 0=Normal, 1=AutoShutdown, 2=AutoStandby
// @return number of ScanRead() words needed to retrieve the data.
// For internal clock modes, the data format always includes the channel address.
//     misoData16 = CH[3:0] DATA[11:0]
//
int MAX11131::ScanRepeat(void)
{
    
    //----------------------------------------
    // number of words to read
    NumWords = (nscan_4_8_12_16);
    
    //----------------------------------------
    // Internal Clock Mode
    isExternalClock = 0;
    
    //----------------------------------------
    // update device driver global variable
    ScanMode = SCAN_0010_Repeat;
    
    //----------------------------------------
    // define write-only register ADC_MODE_CONTROL
    ADC_MODE_CONTROL = 0;       //!< mosiData16 0x0000..0x7FFF format: 0 SCAN[3:0] CHSEL[3:0] RESET[1:0] PM[1:0] CHAN_ID SWCNV 0
    const int SCAN_LSB    = 11; const int SCAN_BITS    = 0x0F; //!< ADC_MODE_CONTROL.SCAN[3:0] ADC Scan Control (command)
    const int CHSEL_LSB   =  7; const int CHSEL_BITS   = 0x0F; //!< ADC_MODE_CONTROL.CHSEL[3:0] Analog Input Channel Select AIN0..AIN15
    const int RESET_LSB   =  5; const int RESET_BITS   = 0x03; //!< ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved
    const int PM_LSB      =  3; const int PM_BITS      = 0x03; //!< ADC_MODE_CONTROL.PM[1:0] Power Management 0=Normal, 1=AutoShutdown, 2=AutoStandby 3=reserved
    const int CHAN_ID_LSB =  2; const int CHAN_ID_BITS = 0x01; //!< ADC_MODE_CONTROL.CHAN_ID
    const int SWCNV_LSB   =  1; const int SWCNV_BITS   = 0x01; //!< ADC_MODE_CONTROL.SWCNV
    
    //----------------------------------------
    // define write-only register ADC_CONFIGURATION
    ADC_CONFIGURATION = 0x8000; //!< mosiData16 0x8000..0x87FF format: 1 0 0 0 0 REFSEL AVGON NAVG[1:0] NSCAN[1:0] SPM[1:0] ECHO 0 0
    const int REFSEL_LSB = 10; const int REFSEL_BITS = 0x01; // ADC_CONFIGURATION.REFSEL
    const int AVGON_LSB  =  9; const int AVGON_BITS  = 0x01; // ADC_CONFIGURATION.AVGON
    const int NAVG_LSB   =  7; const int NAVG_BITS   = 0x03; // ADC_CONFIGURATION.NAVG[1:0]
    const int NSCAN_LSB  =  5; const int NSCAN_BITS  = 0x03; // ADC_CONFIGURATION.NSCAN[1:0]
    const int SPM_LSB    =  3; const int SPM_BITS    = 0x03; // ADC_CONFIGURATION.SPM[1:0]
    const int ECHO_LSB   =  2; const int ECHO_BITS   = 0x01; // ADC_CONFIGURATION.ECHO
    
    //----------------------------------------
    // if average, ADC CONFIGURATION register set AVG and NAVG[1:0]
    // (applicable to internal clock mode only)
    // if average, ADC CONFIGURATION register set AVG ON BIT TO 1
    // if average, ADC CONFIGURATION register set NAVG[1:0] TO N
    if (average_0_4_8_16_32 == 4) {
        // Enable Averaging of 4 samples (AVGON=1, NAVG[1:0]=0)
        ADC_CONFIGURATION |=   ((1 & AVGON_BITS) << AVGON_LSB);
        ADC_CONFIGURATION &= ~ ((    NAVG_BITS) << NAVG_LSB);
        ADC_CONFIGURATION |=   ((0 & NAVG_BITS) << NAVG_LSB);
    } else if (average_0_4_8_16_32 == 8) {
        // Enable Averaging of 8 samples (AVGON=1, NAVG[1:0]=1)
        ADC_CONFIGURATION |=   ((1 & AVGON_BITS) << AVGON_LSB);
        ADC_CONFIGURATION &= ~ ((    NAVG_BITS) << NAVG_LSB);
        ADC_CONFIGURATION |=   ((1 & NAVG_BITS) << NAVG_LSB);
    } else if (average_0_4_8_16_32 == 16) {
        // Enable Averaging of 16 samples (AVGON=1, NAVG[1:0]=2)
        ADC_CONFIGURATION |=   ((1 & AVGON_BITS) << AVGON_LSB);
        ADC_CONFIGURATION &= ~ ((    NAVG_BITS) << NAVG_LSB);
        ADC_CONFIGURATION |=   ((2 & NAVG_BITS) << NAVG_LSB);
    } else if (average_0_4_8_16_32 == 32) {
        // Enable Averaging of 32 samples (AVGON=1, NAVG[1:0]=3)
        ADC_CONFIGURATION |=   ((1 & AVGON_BITS) << AVGON_LSB);
        ADC_CONFIGURATION &= ~ ((    NAVG_BITS) << NAVG_LSB);
        ADC_CONFIGURATION |=   ((3 & NAVG_BITS) << NAVG_LSB);
    } else {
        // Disable Averaging (AVGON=0, NAVG[1:0]=0)
        ADC_CONFIGURATION &= ~ ((    AVGON_BITS) << AVGON_LSB);
        ADC_CONFIGURATION &= ~ ((    NAVG_BITS) << NAVG_LSB);
    }
    
    //----------------------------------------
    // ADC CONFIGURATION register set NSCAN[1:0] for scan count
    // (applicable to SCAN_0010_Repeat only)
    if (nscan_4_8_12_16 == 4) {
        // Set scan count 4
        ADC_CONFIGURATION &= ~ ((    NSCAN_BITS) << NSCAN_LSB);
        ADC_CONFIGURATION |=   ((0 & NSCAN_BITS) << NSCAN_LSB);
    } else if (nscan_4_8_12_16 == 8) {
        // Set scan count 8
        ADC_CONFIGURATION &= ~ ((    NSCAN_BITS) << NSCAN_LSB);
        ADC_CONFIGURATION |=   ((1 & NSCAN_BITS) << NSCAN_LSB);
    } else if (nscan_4_8_12_16 == 12) {
        // Set scan count 12
        ADC_CONFIGURATION &= ~ ((    NSCAN_BITS) << NSCAN_LSB);
        ADC_CONFIGURATION |=   ((2 & NSCAN_BITS) << NSCAN_LSB);
    } else if (nscan_4_8_12_16 == 16) {
        // Set scan count 16
        ADC_CONFIGURATION &= ~ ((    NSCAN_BITS) << NSCAN_LSB);
        ADC_CONFIGURATION |=   ((3 & NSCAN_BITS) << NSCAN_LSB);
    }
    
    //----------------------------------------
    // SPI write ADC CONFIGURATION register
    // Send SPI configuration to device
    SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern
    SPIoutputCS(0); // drive CS low
    SPIwrite16bits(ADC_CONFIGURATION);
    SPIoutputCS(1); // drive CS high
    
    //----------------------------------------
    // Reset FIFO: ADC_MODE_CONTROL.RESET[1:0] = 1   Apply a soft reset when changing from internal to external clock mode.
    ADC_MODE_CONTROL &= ~ ((    RESET_BITS) << RESET_LSB); // ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved
    ADC_MODE_CONTROL |=   ((1 & RESET_BITS) << RESET_LSB); // ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved
    
    //----------------------------------------
    // ADC MODE CONTROL register set SCAN[3:0] TO SCAN_0010_Repeat = 2
    //~ const int SCAN_0010_Repeat = 2; // replaced local const with enum
    ADC_MODE_CONTROL |=   ((SCAN_0010_Repeat & SCAN_BITS) << SCAN_LSB);
    
    //----------------------------------------
    // ADC MODE CONTROL register set CHSEL[3:0] TO channel number
    ADC_MODE_CONTROL |=   ((channelNumber_0_15 & CHSEL_BITS) << CHSEL_LSB);
    
    //----------------------------------------
    // ADC MODE CONTROL REGISTER SELECT THE PM[1:0] BITS
    ADC_MODE_CONTROL |=   ((PowerManagement_0_2 & PM_BITS) << PM_LSB);
    
    //----------------------------------------
    // ADC MODE CONTROL register set SWCNV if CNVST pin is not used
    // ADC MODE CONTROL REGISTER SELECT THE RIGHT SWCNV BIT
    // (applicable to internal clock mode only)
    // SWCNV=1: trigger measurement on SPI CS rising edge; CNVST pin is not used. (AIN14 is available)
    // SWCNV=0: trigger measurement by driving CNVST pin low for a minimum active-low pulse duration of 5ns. (AIN14 is not available)
    if (swcnv_0_1) {
        ADC_MODE_CONTROL |=   ((swcnv_0_1 & SWCNV_BITS) << SWCNV_LSB);
    } else {
        ADC_MODE_CONTROL &= ~ ((            SWCNV_BITS) << SWCNV_LSB);
    }
    
    //----------------------------------------
    // SPI write ADC MODE CONTROL register
    // If SWCNV=1 then CS must be held low for at least 17 SCLK cycles.
    // Send SPI configuration to device
    SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern
    SPIoutputCS(0); // drive CS low
    if (swcnv_0_1) {
      // If SWCNV=1 then CS must be held low for at least 17 SCLK cycles.
      // NOTE: Figure 7 Internal Conversions with SWCNV=1 has an error, the 17th SCLK is mislabeled as "16" should be "17".
      SPIwrite24bits(ADC_MODE_CONTROL, 0);
    } else {
      SPIwrite16bits(ADC_MODE_CONTROL);
    }
    SPIoutputCS(1); // drive CS high
    
    //----------------------------------------
    // return number of words to read
    return NumWords;
}

//----------------------------------------
// SCAN_0011_StandardInternalClock
//
// Measure ADC channels in sequence from AIN0 to channelNumber_0_15.
// Internal clock mode.
// @param[in] channelNumber_0_15: AIN Channel Number
// @param[in] average_0_4_8_16_32: Number of samples averaged per ScanRead() word.
//     average_0_4_8_16_32=0 to disable averaging.
// @param[in] PowerManagement_0_2: 0=Normal, 1=AutoShutdown, 2=AutoStandby
// @param[in] swcnv_0_1: ADC_MODE_CONTROL.SWCNV
//     SWCNV=0: trigger measurement by driving CNVST pin low.
//         Minimum active-low pulse duration of 5ns. (AIN14 is not available)
//     SWCNV=1: trigger measurement on SPI CS rising edge.
//         CS must be held low for minimum of 17 SCLK cycles.
//         CNVST pin is not used. (AIN14 is available)
// @return number of ScanRead() words needed to retrieve the data.
// For internal clock modes, the data format always includes the channel address.
//     misoData16 = CH[3:0] DATA[11:0]
//
int MAX11131::ScanStandardInternalClock(void)
{
    
    //----------------------------------------
    // number of words to read
    NumWords = (1 + channelNumber_0_15);
    
    //----------------------------------------
    // Internal Clock Mode
    isExternalClock = 0;
    
    //----------------------------------------
    // update device driver global variable
    ScanMode = SCAN_0011_StandardInternalClock;
    
    //----------------------------------------
    // define write-only register ADC_MODE_CONTROL
    ADC_MODE_CONTROL = 0;       //!< mosiData16 0x0000..0x7FFF format: 0 SCAN[3:0] CHSEL[3:0] RESET[1:0] PM[1:0] CHAN_ID SWCNV 0
    const int SCAN_LSB    = 11; const int SCAN_BITS    = 0x0F; //!< ADC_MODE_CONTROL.SCAN[3:0] ADC Scan Control (command)
    const int CHSEL_LSB   =  7; const int CHSEL_BITS   = 0x0F; //!< ADC_MODE_CONTROL.CHSEL[3:0] Analog Input Channel Select AIN0..AIN15
    const int RESET_LSB   =  5; const int RESET_BITS   = 0x03; //!< ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved
    const int PM_LSB      =  3; const int PM_BITS      = 0x03; //!< ADC_MODE_CONTROL.PM[1:0] Power Management 0=Normal, 1=AutoShutdown, 2=AutoStandby 3=reserved
    const int CHAN_ID_LSB =  2; const int CHAN_ID_BITS = 0x01; //!< ADC_MODE_CONTROL.CHAN_ID
    const int SWCNV_LSB   =  1; const int SWCNV_BITS   = 0x01; //!< ADC_MODE_CONTROL.SWCNV
    
    //----------------------------------------
    // define write-only register ADC_CONFIGURATION
    ADC_CONFIGURATION = 0x8000; //!< mosiData16 0x8000..0x87FF format: 1 0 0 0 0 REFSEL AVGON NAVG[1:0] NSCAN[1:0] SPM[1:0] ECHO 0 0
    const int REFSEL_LSB = 10; const int REFSEL_BITS = 0x01; // ADC_CONFIGURATION.REFSEL
    const int AVGON_LSB  =  9; const int AVGON_BITS  = 0x01; // ADC_CONFIGURATION.AVGON
    const int NAVG_LSB   =  7; const int NAVG_BITS   = 0x03; // ADC_CONFIGURATION.NAVG[1:0]
    const int NSCAN_LSB  =  5; const int NSCAN_BITS  = 0x03; // ADC_CONFIGURATION.NSCAN[1:0]
    const int SPM_LSB    =  3; const int SPM_BITS    = 0x03; // ADC_CONFIGURATION.SPM[1:0]
    const int ECHO_LSB   =  2; const int ECHO_BITS   = 0x01; // ADC_CONFIGURATION.ECHO
    
    //----------------------------------------
    // if average, ADC CONFIGURATION register set AVG and NAVG[1:0]
    // (applicable to internal clock mode only)
    // if average, ADC CONFIGURATION register set AVG ON BIT TO 1
    // if average, ADC CONFIGURATION register set NAVG[1:0] TO N
    if (average_0_4_8_16_32 == 4) {
        // Enable Averaging of 4 samples (AVGON=1, NAVG[1:0]=0)
        ADC_CONFIGURATION |=   ((1 & AVGON_BITS) << AVGON_LSB);
        ADC_CONFIGURATION &= ~ ((    NAVG_BITS) << NAVG_LSB);
        ADC_CONFIGURATION |=   ((0 & NAVG_BITS) << NAVG_LSB);
    } else if (average_0_4_8_16_32 == 8) {
        // Enable Averaging of 8 samples (AVGON=1, NAVG[1:0]=1)
        ADC_CONFIGURATION |=   ((1 & AVGON_BITS) << AVGON_LSB);
        ADC_CONFIGURATION &= ~ ((    NAVG_BITS) << NAVG_LSB);
        ADC_CONFIGURATION |=   ((1 & NAVG_BITS) << NAVG_LSB);
    } else if (average_0_4_8_16_32 == 16) {
        // Enable Averaging of 16 samples (AVGON=1, NAVG[1:0]=2)
        ADC_CONFIGURATION |=   ((1 & AVGON_BITS) << AVGON_LSB);
        ADC_CONFIGURATION &= ~ ((    NAVG_BITS) << NAVG_LSB);
        ADC_CONFIGURATION |=   ((2 & NAVG_BITS) << NAVG_LSB);
    } else if (average_0_4_8_16_32 == 32) {
        // Enable Averaging of 32 samples (AVGON=1, NAVG[1:0]=3)
        ADC_CONFIGURATION |=   ((1 & AVGON_BITS) << AVGON_LSB);
        ADC_CONFIGURATION &= ~ ((    NAVG_BITS) << NAVG_LSB);
        ADC_CONFIGURATION |=   ((3 & NAVG_BITS) << NAVG_LSB);
    } else {
        // Disable Averaging (AVGON=0, NAVG[1:0]=0)
        ADC_CONFIGURATION &= ~ ((    AVGON_BITS) << AVGON_LSB);
        ADC_CONFIGURATION &= ~ ((    NAVG_BITS) << NAVG_LSB);
    }
    
    //----------------------------------------
    // SPI write ADC CONFIGURATION register
    // Send SPI configuration to device
    SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern
    SPIoutputCS(0); // drive CS low
    SPIwrite16bits(ADC_CONFIGURATION);
    SPIoutputCS(1); // drive CS high
    
    //----------------------------------------
    // Reset FIFO: ADC_MODE_CONTROL.RESET[1:0] = 1   Apply a soft reset when changing from internal to external clock mode.
    ADC_MODE_CONTROL &= ~ ((    RESET_BITS) << RESET_LSB); // ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved
    ADC_MODE_CONTROL |=   ((1 & RESET_BITS) << RESET_LSB); // ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved
    
    //----------------------------------------
    // ADC MODE CONTROL register set SCAN[3:0] TO SCAN_0011_StandardInternalClock = 3
    //~ const int SCAN_0011_StandardInternalClock = 3; // replaced local const with enum
    ADC_MODE_CONTROL |=   ((SCAN_0011_StandardInternalClock & SCAN_BITS) << SCAN_LSB);
    
    //----------------------------------------
    // ADC MODE CONTROL register set CHSEL[3:0] TO channel number
    ADC_MODE_CONTROL |=   ((channelNumber_0_15 & CHSEL_BITS) << CHSEL_LSB);
    
    //----------------------------------------
    // ADC MODE CONTROL REGISTER SELECT THE PM[1:0] BITS
    ADC_MODE_CONTROL |=   ((PowerManagement_0_2 & PM_BITS) << PM_LSB);
    
    //----------------------------------------
    // ADC MODE CONTROL register set SWCNV if CNVST pin is not used
    // ADC MODE CONTROL REGISTER SELECT THE RIGHT SWCNV BIT
    // (applicable to internal clock mode only)
    // SWCNV=1: trigger measurement on SPI CS rising edge; CNVST pin is not used. (AIN14 is available)
    // SWCNV=0: trigger measurement by driving CNVST pin low for a minimum active-low pulse duration of 5ns. (AIN14 is not available)
    if (swcnv_0_1) {
        ADC_MODE_CONTROL |=   ((swcnv_0_1 & SWCNV_BITS) << SWCNV_LSB);
    } else {
        ADC_MODE_CONTROL &= ~ ((            SWCNV_BITS) << SWCNV_LSB);
    }
    
    //----------------------------------------
    // SPI write ADC MODE CONTROL register
    // If SWCNV=1 then CS must be held low for at least 17 SCLK cycles.
    // Send SPI configuration to device
    SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern
    SPIoutputCS(0); // drive CS low
    if (swcnv_0_1) {
      // If SWCNV=1 then CS must be held low for at least 17 SCLK cycles.
      // NOTE: Figure 7 Internal Conversions with SWCNV=1 has an error, the 17th SCLK is mislabeled as "16" should be "17".
      SPIwrite24bits(ADC_MODE_CONTROL, 0);
    } else {
      SPIwrite16bits(ADC_MODE_CONTROL);
    }
    SPIoutputCS(1); // drive CS high
    
    //----------------------------------------
    // return number of words to read
    return NumWords;
}

//----------------------------------------
// SCAN_0100_StandardExternalClock
//
// Measure ADC channels in sequence from AIN0 to channelNumber_0_15.
// External clock mode.
// @param[in] channelNumber_0_15: AIN Channel Number
// @param[in] PowerManagement_0_2: 0=Normal, 1=AutoShutdown, 2=AutoStandby
// @param[in] chan_id_0_1: ADC_MODE_CONTROL.CHAN_ID
// @return number of ScanRead() words needed to retrieve the data.
// For external clock modes, the data format depends on CHAN_ID.
//     when CHAN_ID = 0: misoData16 = 0 DATA[11:0] x x x
//     when CHAN_ID = 1: misoData16 = CH[3:0] DATA[11:0]
//
int MAX11131::ScanStandardExternalClock(void)
{
    
    //----------------------------------------
    // define write-only register ADC_MODE_CONTROL
    ADC_MODE_CONTROL = 0;       //!< mosiData16 0x0000..0x7FFF format: 0 SCAN[3:0] CHSEL[3:0] RESET[1:0] PM[1:0] CHAN_ID SWCNV 0
    const int SCAN_LSB    = 11; const int SCAN_BITS    = 0x0F; //!< ADC_MODE_CONTROL.SCAN[3:0] ADC Scan Control (command)
    const int CHSEL_LSB   =  7; const int CHSEL_BITS   = 0x0F; //!< ADC_MODE_CONTROL.CHSEL[3:0] Analog Input Channel Select AIN0..AIN15
    const int RESET_LSB   =  5; const int RESET_BITS   = 0x03; //!< ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved
    const int PM_LSB      =  3; const int PM_BITS      = 0x03; //!< ADC_MODE_CONTROL.PM[1:0] Power Management 0=Normal, 1=AutoShutdown, 2=AutoStandby 3=reserved
    const int CHAN_ID_LSB =  2; const int CHAN_ID_BITS = 0x01; //!< ADC_MODE_CONTROL.CHAN_ID
    const int SWCNV_LSB   =  1; const int SWCNV_BITS   = 0x01; //!< ADC_MODE_CONTROL.SWCNV
    
    //----------------------------------------
    // Apply a soft reset when changing from internal to external clock mode.
    int needFIFOreset = (isExternalClock != 1);
    if (needFIFOreset) {
        // Apply a soft reset when changing from internal to external clock mode.
        ADC_MODE_CONTROL = ((1 & RESET_BITS) << RESET_LSB); // ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved
        // Send SPI configuration to device
        SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern
        SPIoutputCS(0); // drive CS low
        SPIwrite16bits(ADC_MODE_CONTROL);
        SPIoutputCS(1); // drive CS high
        ADC_MODE_CONTROL = 0;
    }
    
    //----------------------------------------
    // number of words to read
    NumWords = (1 + channelNumber_0_15);
    
    //----------------------------------------
    // External Clock Mode
    isExternalClock = 1;
    
    //----------------------------------------
    // update device driver global variable
    ScanMode = SCAN_0100_StandardExternalClock;
    
    //----------------------------------------
    // ADC MODE CONTROL register set SCAN[3:0] TO SCAN_0100_StandardExternalClock = 4
    //~ const int SCAN_0100_StandardExternalClock = 4; // replaced local const with enum
    ADC_MODE_CONTROL |=   ((SCAN_0100_StandardExternalClock & SCAN_BITS) << SCAN_LSB);
    
    //----------------------------------------
    // ADC MODE CONTROL register set CHSEL[3:0] TO channel number
    ADC_MODE_CONTROL |=   ((channelNumber_0_15 & CHSEL_BITS) << CHSEL_LSB);
    
    //----------------------------------------
    // ADC MODE CONTROL REGISTER SELECT THE PM[1:0] BITS
    ADC_MODE_CONTROL |=   ((PowerManagement_0_2 & PM_BITS) << PM_LSB);
    
    //----------------------------------------
    // ADC MODE CONTROL REGISTER SELECT THE CHAN_ID BIT
    // (applicable to external clock mode only)
    // For external clock modes, the data format returned depends on the CHAN_ID bit.
    //     when CHAN_ID = 0: misoData16 = 0 DATA[11:0] x x x
    //     when CHAN_ID = 1: misoData16 = CH[3:0] DATA[11:0]
    // For internal clock modes, the data format always includes the channel address.
    //     misoData16 = CH[3:0] DATA[11:0]
    ADC_MODE_CONTROL |=   ((chan_id_0_1 & CHAN_ID_BITS) << CHAN_ID_LSB);
    
    //----------------------------------------
    // SPI write ADC MODE CONTROL register
    // Send SPI configuration to device
    SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern
    SPIoutputCS(0); // drive CS low
    SPIwrite16bits(ADC_MODE_CONTROL);
    SPIoutputCS(1); // drive CS high
    
    //----------------------------------------
    // return number of words to read
    return NumWords;
}

//----------------------------------------
// SCAN_0101_UpperInternalClock
//
// Measure ADC channels in sequence from channelNumber_0_15 to AIN15.
// Internal clock mode.
// @param[in] channelNumber_0_15: AIN Channel Number
// @param[in] average_0_4_8_16_32: Number of samples averaged per ScanRead() word.
//     average_0_4_8_16_32=0 to disable averaging.
// @param[in] PowerManagement_0_2: 0=Normal, 1=AutoShutdown, 2=AutoStandby
// @param[in] swcnv_0_1: ADC_MODE_CONTROL.SWCNV
//     SWCNV=0: trigger measurement by driving CNVST pin low.
//         Minimum active-low pulse duration of 5ns. (AIN14 is not available)
//     SWCNV=1: trigger measurement on SPI CS rising edge.
//         CS must be held low for minimum of 17 SCLK cycles.
//         CNVST pin is not used. (AIN14 is available)
// @return number of ScanRead() words needed to retrieve the data.
// For internal clock modes, the data format always includes the channel address.
//     misoData16 = CH[3:0] DATA[11:0]
//
int MAX11131::ScanUpperInternalClock(void)
{
    
    //----------------------------------------
    // number of words to read
    NumWords = (16 - channelNumber_0_15);
    
    //----------------------------------------
    // Internal Clock Mode
    isExternalClock = 0;
    
    //----------------------------------------
    // update device driver global variable
    ScanMode = SCAN_0101_UpperInternalClock;
    
    //----------------------------------------
    // define write-only register ADC_MODE_CONTROL
    ADC_MODE_CONTROL = 0;       //!< mosiData16 0x0000..0x7FFF format: 0 SCAN[3:0] CHSEL[3:0] RESET[1:0] PM[1:0] CHAN_ID SWCNV 0
    const int SCAN_LSB    = 11; const int SCAN_BITS    = 0x0F; //!< ADC_MODE_CONTROL.SCAN[3:0] ADC Scan Control (command)
    const int CHSEL_LSB   =  7; const int CHSEL_BITS   = 0x0F; //!< ADC_MODE_CONTROL.CHSEL[3:0] Analog Input Channel Select AIN0..AIN15
    const int RESET_LSB   =  5; const int RESET_BITS   = 0x03; //!< ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved
    const int PM_LSB      =  3; const int PM_BITS      = 0x03; //!< ADC_MODE_CONTROL.PM[1:0] Power Management 0=Normal, 1=AutoShutdown, 2=AutoStandby 3=reserved
    const int CHAN_ID_LSB =  2; const int CHAN_ID_BITS = 0x01; //!< ADC_MODE_CONTROL.CHAN_ID
    const int SWCNV_LSB   =  1; const int SWCNV_BITS   = 0x01; //!< ADC_MODE_CONTROL.SWCNV
    
    //----------------------------------------
    // define write-only register ADC_CONFIGURATION
    ADC_CONFIGURATION = 0x8000; //!< mosiData16 0x8000..0x87FF format: 1 0 0 0 0 REFSEL AVGON NAVG[1:0] NSCAN[1:0] SPM[1:0] ECHO 0 0
    const int REFSEL_LSB = 10; const int REFSEL_BITS = 0x01; // ADC_CONFIGURATION.REFSEL
    const int AVGON_LSB  =  9; const int AVGON_BITS  = 0x01; // ADC_CONFIGURATION.AVGON
    const int NAVG_LSB   =  7; const int NAVG_BITS   = 0x03; // ADC_CONFIGURATION.NAVG[1:0]
    const int NSCAN_LSB  =  5; const int NSCAN_BITS  = 0x03; // ADC_CONFIGURATION.NSCAN[1:0]
    const int SPM_LSB    =  3; const int SPM_BITS    = 0x03; // ADC_CONFIGURATION.SPM[1:0]
    const int ECHO_LSB   =  2; const int ECHO_BITS   = 0x01; // ADC_CONFIGURATION.ECHO
    
    //----------------------------------------
    // if average, ADC CONFIGURATION register set AVG and NAVG[1:0]
    // (applicable to internal clock mode only)
    // if average, ADC CONFIGURATION register set AVG ON BIT TO 1
    // if average, ADC CONFIGURATION register set NAVG[1:0] TO N
    if (average_0_4_8_16_32 == 4) {
        // Enable Averaging of 4 samples (AVGON=1, NAVG[1:0]=0)
        ADC_CONFIGURATION |=   ((1 & AVGON_BITS) << AVGON_LSB);
        ADC_CONFIGURATION &= ~ ((    NAVG_BITS) << NAVG_LSB);
        ADC_CONFIGURATION |=   ((0 & NAVG_BITS) << NAVG_LSB);
    } else if (average_0_4_8_16_32 == 8) {
        // Enable Averaging of 8 samples (AVGON=1, NAVG[1:0]=1)
        ADC_CONFIGURATION |=   ((1 & AVGON_BITS) << AVGON_LSB);
        ADC_CONFIGURATION &= ~ ((    NAVG_BITS) << NAVG_LSB);
        ADC_CONFIGURATION |=   ((1 & NAVG_BITS) << NAVG_LSB);
    } else if (average_0_4_8_16_32 == 16) {
        // Enable Averaging of 16 samples (AVGON=1, NAVG[1:0]=2)
        ADC_CONFIGURATION |=   ((1 & AVGON_BITS) << AVGON_LSB);
        ADC_CONFIGURATION &= ~ ((    NAVG_BITS) << NAVG_LSB);
        ADC_CONFIGURATION |=   ((2 & NAVG_BITS) << NAVG_LSB);
    } else if (average_0_4_8_16_32 == 32) {
        // Enable Averaging of 32 samples (AVGON=1, NAVG[1:0]=3)
        ADC_CONFIGURATION |=   ((1 & AVGON_BITS) << AVGON_LSB);
        ADC_CONFIGURATION &= ~ ((    NAVG_BITS) << NAVG_LSB);
        ADC_CONFIGURATION |=   ((3 & NAVG_BITS) << NAVG_LSB);
    } else {
        // Disable Averaging (AVGON=0, NAVG[1:0]=0)
        ADC_CONFIGURATION &= ~ ((    AVGON_BITS) << AVGON_LSB);
        ADC_CONFIGURATION &= ~ ((    NAVG_BITS) << NAVG_LSB);
    }
    
    //----------------------------------------
    // SPI write ADC CONFIGURATION register
    // Send SPI configuration to device
    SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern
    SPIoutputCS(0); // drive CS low
    SPIwrite16bits(ADC_CONFIGURATION);
    SPIoutputCS(1); // drive CS high
    
    //----------------------------------------
    // Reset FIFO: ADC_MODE_CONTROL.RESET[1:0] = 1   Apply a soft reset when changing from internal to external clock mode.
    ADC_MODE_CONTROL &= ~ ((    RESET_BITS) << RESET_LSB); // ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved
    ADC_MODE_CONTROL |=   ((1 & RESET_BITS) << RESET_LSB); // ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved
    
    //----------------------------------------
    // ADC MODE CONTROL register set SCAN[3:0] TO SCAN_0101_UpperInternalClock = 5
    //~ const int SCAN_0101_UpperInternalClock = 5; // replaced local const with enum
    ADC_MODE_CONTROL |=   ((SCAN_0101_UpperInternalClock & SCAN_BITS) << SCAN_LSB);
    
    //----------------------------------------
    // ADC MODE CONTROL register set CHSEL[3:0] TO channel number
    ADC_MODE_CONTROL |=   ((channelNumber_0_15 & CHSEL_BITS) << CHSEL_LSB);
    
    //----------------------------------------
    // ADC MODE CONTROL REGISTER SELECT THE PM[1:0] BITS
    ADC_MODE_CONTROL |=   ((PowerManagement_0_2 & PM_BITS) << PM_LSB);
    
    //----------------------------------------
    // ADC MODE CONTROL register set SWCNV if CNVST pin is not used
    // ADC MODE CONTROL REGISTER SELECT THE RIGHT SWCNV BIT
    // (applicable to internal clock mode only)
    // SWCNV=1: trigger measurement on SPI CS rising edge; CNVST pin is not used. (AIN14 is available)
    // SWCNV=0: trigger measurement by driving CNVST pin low for a minimum active-low pulse duration of 5ns. (AIN14 is not available)
    if (swcnv_0_1) {
        ADC_MODE_CONTROL |=   ((swcnv_0_1 & SWCNV_BITS) << SWCNV_LSB);
    } else {
        ADC_MODE_CONTROL &= ~ ((            SWCNV_BITS) << SWCNV_LSB);
    }
    
    //----------------------------------------
    // SPI write ADC MODE CONTROL register
    // If SWCNV=1 then CS must be held low for at least 17 SCLK cycles.
    // Send SPI configuration to device
    SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern
    SPIoutputCS(0); // drive CS low
    if (swcnv_0_1) {
      // If SWCNV=1 then CS must be held low for at least 17 SCLK cycles.
      // NOTE: Figure 7 Internal Conversions with SWCNV=1 has an error, the 17th SCLK is mislabeled as "16" should be "17".
      SPIwrite24bits(ADC_MODE_CONTROL, 0);
    } else {
      SPIwrite16bits(ADC_MODE_CONTROL);
    }
    SPIoutputCS(1); // drive CS high
    
    //----------------------------------------
    // return number of words to read
    return NumWords;
}

//----------------------------------------
// SCAN_0110_UpperExternalClock
//
// Measure ADC channels in sequence from channelNumber_0_15 to AIN15.
// External clock mode.
// @param[in] channelNumber_0_15: AIN Channel Number
// @param[in] PowerManagement_0_2: 0=Normal, 1=AutoShutdown, 2=AutoStandby
// @param[in] chan_id_0_1: ADC_MODE_CONTROL.CHAN_ID
// @return number of ScanRead() words needed to retrieve the data.
// For external clock modes, the data format depends on CHAN_ID.
//     when CHAN_ID = 0: misoData16 = 0 DATA[11:0] x x x
//     when CHAN_ID = 1: misoData16 = CH[3:0] DATA[11:0]
//
int MAX11131::ScanUpperExternalClock(void)
{
    
    //----------------------------------------
    // define write-only register ADC_MODE_CONTROL
    ADC_MODE_CONTROL = 0;       //!< mosiData16 0x0000..0x7FFF format: 0 SCAN[3:0] CHSEL[3:0] RESET[1:0] PM[1:0] CHAN_ID SWCNV 0
    const int SCAN_LSB    = 11; const int SCAN_BITS    = 0x0F; //!< ADC_MODE_CONTROL.SCAN[3:0] ADC Scan Control (command)
    const int CHSEL_LSB   =  7; const int CHSEL_BITS   = 0x0F; //!< ADC_MODE_CONTROL.CHSEL[3:0] Analog Input Channel Select AIN0..AIN15
    const int RESET_LSB   =  5; const int RESET_BITS   = 0x03; //!< ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved
    const int PM_LSB      =  3; const int PM_BITS      = 0x03; //!< ADC_MODE_CONTROL.PM[1:0] Power Management 0=Normal, 1=AutoShutdown, 2=AutoStandby 3=reserved
    const int CHAN_ID_LSB =  2; const int CHAN_ID_BITS = 0x01; //!< ADC_MODE_CONTROL.CHAN_ID
    const int SWCNV_LSB   =  1; const int SWCNV_BITS   = 0x01; //!< ADC_MODE_CONTROL.SWCNV
    
    //----------------------------------------
    // Apply a soft reset when changing from internal to external clock mode.
    int needFIFOreset = (isExternalClock != 1);
    if (needFIFOreset) {
        // Apply a soft reset when changing from internal to external clock mode.
        ADC_MODE_CONTROL = ((1 & RESET_BITS) << RESET_LSB); // ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved
        // Send SPI configuration to device
        SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern
        SPIoutputCS(0); // drive CS low
        SPIwrite16bits(ADC_MODE_CONTROL);
        SPIoutputCS(1); // drive CS high
        ADC_MODE_CONTROL = 0;
    }
    
    //----------------------------------------
    // number of words to read
    NumWords = (16 - channelNumber_0_15);
    
    //----------------------------------------
    // External Clock Mode
    isExternalClock = 1;
    
    //----------------------------------------
    // update device driver global variable
    ScanMode = SCAN_0110_UpperExternalClock;
    
    //----------------------------------------
    // ADC MODE CONTROL register set SCAN[3:0] TO SCAN_0110_UpperExternalClock = 6
    //~ const int SCAN_0110_UpperExternalClock = 6; // replaced local const with enum
    ADC_MODE_CONTROL |=   ((SCAN_0110_UpperExternalClock & SCAN_BITS) << SCAN_LSB);
    
    //----------------------------------------
    // ADC MODE CONTROL register set CHSEL[3:0] TO channel number
    ADC_MODE_CONTROL |=   ((channelNumber_0_15 & CHSEL_BITS) << CHSEL_LSB);
    
    //----------------------------------------
    // ADC MODE CONTROL REGISTER SELECT THE PM[1:0] BITS
    ADC_MODE_CONTROL |=   ((PowerManagement_0_2 & PM_BITS) << PM_LSB);
    
    //----------------------------------------
    // ADC MODE CONTROL REGISTER SELECT THE CHAN_ID BIT
    // (applicable to external clock mode only)
    // For external clock modes, the data format returned depends on the CHAN_ID bit.
    //     when CHAN_ID = 0: misoData16 = 0 DATA[11:0] x x x
    //     when CHAN_ID = 1: misoData16 = CH[3:0] DATA[11:0]
    // For internal clock modes, the data format always includes the channel address.
    //     misoData16 = CH[3:0] DATA[11:0]
    ADC_MODE_CONTROL |=   ((chan_id_0_1 & CHAN_ID_BITS) << CHAN_ID_LSB);
    
    //----------------------------------------
    // SPI write ADC MODE CONTROL register
    // Send SPI configuration to device
    SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern
    SPIoutputCS(0); // drive CS low
    SPIwrite16bits(ADC_MODE_CONTROL);
    SPIoutputCS(1); // drive CS high
    
    //----------------------------------------
    // return number of words to read
    return NumWords;
}

//----------------------------------------
// SCAN_0111_CustomInternalClock
//
// Measure selected ADC channels in sequence from AIN0 to AIN15,
//     using only the channels enabled by enabledChannelsMask.
//     Bit 0x0001 enables AIN0.
//     Bit 0x0002 enables AIN1.
//     Bit 0x0004 enables AIN2.
//     Bit 0x0008 enables AIN3.
//     Bit 0x0010 enables AIN4.
//     Bit 0x0020 enables AIN5.
//     Bit 0x0040 enables AIN6.
//     Bit 0x0080 enables AIN7.
//     Bit 0x0100 enables AIN8.
//     Bit 0x0200 enables AIN9.
//     Bit 0x0400 enables AIN10.
//     Bit 0x0800 enables AIN11.
//     Bit 0x1000 enables AIN12.
//     Bit 0x2000 enables AIN13.
//     Bit 0x4000 enables AIN14.
//     Bit 0x8000 enables AIN15.
// Internal clock mode.
// @param[in] enabledChannelsMask: Bitmap of AIN Channels to scan.
// @param[in] average_0_4_8_16_32: Number of samples averaged per ScanRead() word.
//     average_0_4_8_16_32=0 to disable averaging.
// @param[in] PowerManagement_0_2: 0=Normal, 1=AutoShutdown, 2=AutoStandby
// @param[in] swcnv_0_1: ADC_MODE_CONTROL.SWCNV
//     SWCNV=0: trigger measurement by driving CNVST pin low.
//         Minimum active-low pulse duration of 5ns. (AIN14 is not available)
//     SWCNV=1: trigger measurement on SPI CS rising edge.
//         CS must be held low for minimum of 17 SCLK cycles.
//         CNVST pin is not used. (AIN14 is available)
// @return number of ScanRead() words needed to retrieve the data.
// For internal clock modes, the data format always includes the channel address.
//     misoData16 = CH[3:0] DATA[11:0]
//
int MAX11131::ScanCustomInternalClock(void)
{
    
    //----------------------------------------
    // count nWords = number of set bits in enabledChannelsMask
    uint16_t bitMask;
    int nWords = 0;
    for (bitMask = 0x8000; bitMask != 0; bitMask = bitMask / 2)
    {
        if (enabledChannelsMask & bitMask)
        {
            nWords++;
        }
    }
    
    //----------------------------------------
    // number of words to read
    NumWords = nWords;
    
    //----------------------------------------
    // Internal Clock Mode
    isExternalClock = 0;
    
    //----------------------------------------
    // update device driver global variable
    ScanMode = SCAN_0111_CustomInternalClock;
    
    //----------------------------------------
    // define write-only register ADC_MODE_CONTROL
    ADC_MODE_CONTROL = 0;       //!< mosiData16 0x0000..0x7FFF format: 0 SCAN[3:0] CHSEL[3:0] RESET[1:0] PM[1:0] CHAN_ID SWCNV 0
    const int SCAN_LSB    = 11; const int SCAN_BITS    = 0x0F; //!< ADC_MODE_CONTROL.SCAN[3:0] ADC Scan Control (command)
    const int CHSEL_LSB   =  7; const int CHSEL_BITS   = 0x0F; //!< ADC_MODE_CONTROL.CHSEL[3:0] Analog Input Channel Select AIN0..AIN15
    const int RESET_LSB   =  5; const int RESET_BITS   = 0x03; //!< ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved
    const int PM_LSB      =  3; const int PM_BITS      = 0x03; //!< ADC_MODE_CONTROL.PM[1:0] Power Management 0=Normal, 1=AutoShutdown, 2=AutoStandby 3=reserved
    const int CHAN_ID_LSB =  2; const int CHAN_ID_BITS = 0x01; //!< ADC_MODE_CONTROL.CHAN_ID
    const int SWCNV_LSB   =  1; const int SWCNV_BITS   = 0x01; //!< ADC_MODE_CONTROL.SWCNV
    
    //----------------------------------------
    // define write-only register ADC_CONFIGURATION
    ADC_CONFIGURATION = 0x8000; //!< mosiData16 0x8000..0x87FF format: 1 0 0 0 0 REFSEL AVGON NAVG[1:0] NSCAN[1:0] SPM[1:0] ECHO 0 0
    const int REFSEL_LSB = 10; const int REFSEL_BITS = 0x01; // ADC_CONFIGURATION.REFSEL
    const int AVGON_LSB  =  9; const int AVGON_BITS  = 0x01; // ADC_CONFIGURATION.AVGON
    const int NAVG_LSB   =  7; const int NAVG_BITS   = 0x03; // ADC_CONFIGURATION.NAVG[1:0]
    const int NSCAN_LSB  =  5; const int NSCAN_BITS  = 0x03; // ADC_CONFIGURATION.NSCAN[1:0]
    const int SPM_LSB    =  3; const int SPM_BITS    = 0x03; // ADC_CONFIGURATION.SPM[1:0]
    const int ECHO_LSB   =  2; const int ECHO_BITS   = 0x01; // ADC_CONFIGURATION.ECHO
    
    //----------------------------------------
    // define write-only registers CSCAN0,CSCAN1
    CSCAN0 = 0xA000;            //!< mosiData16 0xA000..0xA7FF format: 1 0 1 0 0 CHSCAN15 CHSCAN14 CHSCAN13 CHSCAN12 CHSCAN11 CHSCAN10 CHSCAN9 CHSCAN8 x x x
    const int CHSCAN15_LSB = 10; // CSCAN0.CHSCAN15
    const int CHSCAN14_LSB =  9; // CSCAN0.CHSCAN14
    const int CHSCAN13_LSB =  8; // CSCAN0.CHSCAN13
    const int CHSCAN12_LSB =  7; // CSCAN0.CHSCAN12
    const int CHSCAN11_LSB =  6; // CSCAN0.CHSCAN11
    const int CHSCAN10_LSB =  5; // CSCAN0.CHSCAN10
    const int CHSCAN9_LSB  =  4; // CSCAN0.CHSCAN9
    const int CHSCAN8_LSB  =  3; // CSCAN0.CHSCAN8
    CSCAN1 = 0xA800;            //!< mosiData16 0xA800..0xAFFF format: 1 0 1 0 1 CHSCAN7 CHSCAN6 CHSCAN5 CHSCAN4 CHSCAN3 CHSCAN2 CHSCAN1 CHSCAN0 x x x
    const int CHSCAN7_LSB = 10; // CSCAN1.CHSCAN7
    const int CHSCAN6_LSB =  9; // CSCAN1.CHSCAN6
    const int CHSCAN5_LSB =  8; // CSCAN1.CHSCAN5
    const int CHSCAN4_LSB =  7; // CSCAN1.CHSCAN4
    const int CHSCAN3_LSB =  6; // CSCAN1.CHSCAN3
    const int CHSCAN2_LSB =  5; // CSCAN1.CHSCAN2
    const int CHSCAN1_LSB =  4; // CSCAN1.CHSCAN1
    const int CHSCAN0_LSB =  3; // CSCAN1.CHSCAN0
    
    //----------------------------------------
    // if average, ADC CONFIGURATION register set AVG and NAVG[1:0]
    // (applicable to internal clock mode only)
    // if average, ADC CONFIGURATION register set AVG ON BIT TO 1
    // if average, ADC CONFIGURATION register set NAVG[1:0] TO N
    if (average_0_4_8_16_32 == 4) {
        // Enable Averaging of 4 samples (AVGON=1, NAVG[1:0]=0)
        ADC_CONFIGURATION |=   ((1 & AVGON_BITS) << AVGON_LSB);
        ADC_CONFIGURATION &= ~ ((    NAVG_BITS) << NAVG_LSB);
        ADC_CONFIGURATION |=   ((0 & NAVG_BITS) << NAVG_LSB);
    } else if (average_0_4_8_16_32 == 8) {
        // Enable Averaging of 8 samples (AVGON=1, NAVG[1:0]=1)
        ADC_CONFIGURATION |=   ((1 & AVGON_BITS) << AVGON_LSB);
        ADC_CONFIGURATION &= ~ ((    NAVG_BITS) << NAVG_LSB);
        ADC_CONFIGURATION |=   ((1 & NAVG_BITS) << NAVG_LSB);
    } else if (average_0_4_8_16_32 == 16) {
        // Enable Averaging of 16 samples (AVGON=1, NAVG[1:0]=2)
        ADC_CONFIGURATION |=   ((1 & AVGON_BITS) << AVGON_LSB);
        ADC_CONFIGURATION &= ~ ((    NAVG_BITS) << NAVG_LSB);
        ADC_CONFIGURATION |=   ((2 & NAVG_BITS) << NAVG_LSB);
    } else if (average_0_4_8_16_32 == 32) {
        // Enable Averaging of 32 samples (AVGON=1, NAVG[1:0]=3)
        ADC_CONFIGURATION |=   ((1 & AVGON_BITS) << AVGON_LSB);
        ADC_CONFIGURATION &= ~ ((    NAVG_BITS) << NAVG_LSB);
        ADC_CONFIGURATION |=   ((3 & NAVG_BITS) << NAVG_LSB);
    } else {
        // Disable Averaging (AVGON=0, NAVG[1:0]=0)
        ADC_CONFIGURATION &= ~ ((    AVGON_BITS) << AVGON_LSB);
        ADC_CONFIGURATION &= ~ ((    NAVG_BITS) << NAVG_LSB);
    }
    
    //----------------------------------------
    // SPI write ADC CONFIGURATION register
    // Send SPI configuration to device
    SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern
    SPIoutputCS(0); // drive CS low
    SPIwrite16bits(ADC_CONFIGURATION);
    SPIoutputCS(1); // drive CS high
    
    //----------------------------------------
    // SET CSCAN0 CSCAN1 REGISTERS from enabledChannelsMask
    CSCAN0 = 0xA000 | (((enabledChannelsMask >> 8) & 0xFF) << 3); // CSCAN0.CHSCAN[15:8]
    CSCAN1 = 0xA800 | (((enabledChannelsMask) & 0xFF) << 3); // CSCAN1.CHSCAN[7:0]
    SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern
    SPIoutputCS(0); // drive CS low
    SPIwrite16bits(CSCAN0);
    SPIoutputCS(1); // drive CS high
    SPIoutputCS(0); // drive CS low
    SPIwrite16bits(CSCAN1);
    SPIoutputCS(1); // drive CS high
    
    //----------------------------------------
    // Reset FIFO: ADC_MODE_CONTROL.RESET[1:0] = 1   Apply a soft reset when changing from internal to external clock mode.
    ADC_MODE_CONTROL &= ~ ((    RESET_BITS) << RESET_LSB); // ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved
    ADC_MODE_CONTROL |=   ((1 & RESET_BITS) << RESET_LSB); // ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved
    
    //----------------------------------------
    // ADC MODE CONTROL register set SCAN[3:0] TO SCAN_0111_CustomInternalClock = 7
    //~ const int SCAN_0111_CustomInternalClock = 7; // replaced local const with enum
    ADC_MODE_CONTROL |=   ((SCAN_0111_CustomInternalClock & SCAN_BITS) << SCAN_LSB);
    
    //----------------------------------------
    // ADC MODE CONTROL REGISTER SELECT THE PM[1:0] BITS
    ADC_MODE_CONTROL |=   ((PowerManagement_0_2 & PM_BITS) << PM_LSB);
    
    //----------------------------------------
    // ADC MODE CONTROL register set SWCNV if CNVST pin is not used
    // ADC MODE CONTROL REGISTER SELECT THE RIGHT SWCNV BIT
    // (applicable to internal clock mode only)
    // SWCNV=1: trigger measurement on SPI CS rising edge; CNVST pin is not used. (AIN14 is available)
    // SWCNV=0: trigger measurement by driving CNVST pin low for a minimum active-low pulse duration of 5ns. (AIN14 is not available)
    if (swcnv_0_1) {
        ADC_MODE_CONTROL |=   ((swcnv_0_1 & SWCNV_BITS) << SWCNV_LSB);
    } else {
        ADC_MODE_CONTROL &= ~ ((            SWCNV_BITS) << SWCNV_LSB);
    }
    
    //----------------------------------------
    // SPI write ADC MODE CONTROL register
    // If SWCNV=1 then CS must be held low for at least 17 SCLK cycles.
    // Send SPI configuration to device
    SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern
    SPIoutputCS(0); // drive CS low
    if (swcnv_0_1) {
      // If SWCNV=1 then CS must be held low for at least 17 SCLK cycles.
      // NOTE: Figure 7 Internal Conversions with SWCNV=1 has an error, the 17th SCLK is mislabeled as "16" should be "17".
      SPIwrite24bits(ADC_MODE_CONTROL, 0);
    } else {
      SPIwrite16bits(ADC_MODE_CONTROL);
    }
    SPIoutputCS(1); // drive CS high
    
    //----------------------------------------
    // return number of words to read
    return NumWords;
}

//----------------------------------------
// SCAN_1000_CustomExternalClock
//
// Measure selected ADC channels in sequence from AIN0 to AIN15,
//     using only the channels enabled by enabledChannelsMask.
//     Bit 0x0001 enables AIN0.
//     Bit 0x0002 enables AIN1.
//     Bit 0x0004 enables AIN2.
//     Bit 0x0008 enables AIN3.
//     Bit 0x0010 enables AIN4.
//     Bit 0x0020 enables AIN5.
//     Bit 0x0040 enables AIN6.
//     Bit 0x0080 enables AIN7.
//     Bit 0x0100 enables AIN8.
//     Bit 0x0200 enables AIN9.
//     Bit 0x0400 enables AIN10.
//     Bit 0x0800 enables AIN11.
//     Bit 0x1000 enables AIN12.
//     Bit 0x2000 enables AIN13.
//     Bit 0x4000 enables AIN14.
//     Bit 0x8000 enables AIN15.
// External clock mode.
// @param[in] enabledChannelsMask: Bitmap of AIN Channels to scan.
// @param[in] PowerManagement_0_2: 0=Normal, 1=AutoShutdown, 2=AutoStandby
// @param[in] chan_id_0_1: ADC_MODE_CONTROL.CHAN_ID
// @return number of ScanRead() words needed to retrieve the data.
// For external clock modes, the data format depends on CHAN_ID.
//     when CHAN_ID = 0: misoData16 = 0 DATA[11:0] x x x
//     when CHAN_ID = 1: misoData16 = CH[3:0] DATA[11:0]
//
int MAX11131::ScanCustomExternalClock(void)
{
    
    //----------------------------------------
    // count nWords = number of set bits in enabledChannelsMask
    uint16_t bitMask;
    int nWords = 0;
    for (bitMask = 0x8000; bitMask != 0; bitMask = bitMask / 2)
    {
        if (enabledChannelsMask & bitMask)
        {
            nWords++;
        }
    }
    
    //----------------------------------------
    // define write-only register ADC_MODE_CONTROL
    ADC_MODE_CONTROL = 0;       //!< mosiData16 0x0000..0x7FFF format: 0 SCAN[3:0] CHSEL[3:0] RESET[1:0] PM[1:0] CHAN_ID SWCNV 0
    const int SCAN_LSB    = 11; const int SCAN_BITS    = 0x0F; //!< ADC_MODE_CONTROL.SCAN[3:0] ADC Scan Control (command)
    const int CHSEL_LSB   =  7; const int CHSEL_BITS   = 0x0F; //!< ADC_MODE_CONTROL.CHSEL[3:0] Analog Input Channel Select AIN0..AIN15
    const int RESET_LSB   =  5; const int RESET_BITS   = 0x03; //!< ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved
    const int PM_LSB      =  3; const int PM_BITS      = 0x03; //!< ADC_MODE_CONTROL.PM[1:0] Power Management 0=Normal, 1=AutoShutdown, 2=AutoStandby 3=reserved
    const int CHAN_ID_LSB =  2; const int CHAN_ID_BITS = 0x01; //!< ADC_MODE_CONTROL.CHAN_ID
    const int SWCNV_LSB   =  1; const int SWCNV_BITS   = 0x01; //!< ADC_MODE_CONTROL.SWCNV
    
    //----------------------------------------
    // Apply a soft reset when changing from internal to external clock mode.
    int needFIFOreset = (isExternalClock != 1);
    if (needFIFOreset) {
        // Apply a soft reset when changing from internal to external clock mode.
        ADC_MODE_CONTROL = ((1 & RESET_BITS) << RESET_LSB); // ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved
        // Send SPI configuration to device
        SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern
        SPIoutputCS(0); // drive CS low
        SPIwrite16bits(ADC_MODE_CONTROL);
        SPIoutputCS(1); // drive CS high
        ADC_MODE_CONTROL = 0;
    }
    
    //----------------------------------------
    // number of words to read
    NumWords = nWords;
    
    //----------------------------------------
    // External Clock Mode
    isExternalClock = 1;
    
    //----------------------------------------
    // update device driver global variable
    ScanMode = SCAN_1000_CustomExternalClock;
    
    //----------------------------------------
    // define write-only registers CSCAN0,CSCAN1
    CSCAN0 = 0xA000;            //!< mosiData16 0xA000..0xA7FF format: 1 0 1 0 0 CHSCAN15 CHSCAN14 CHSCAN13 CHSCAN12 CHSCAN11 CHSCAN10 CHSCAN9 CHSCAN8 x x x
    const int CHSCAN15_LSB = 10; // CSCAN0.CHSCAN15
    const int CHSCAN14_LSB =  9; // CSCAN0.CHSCAN14
    const int CHSCAN13_LSB =  8; // CSCAN0.CHSCAN13
    const int CHSCAN12_LSB =  7; // CSCAN0.CHSCAN12
    const int CHSCAN11_LSB =  6; // CSCAN0.CHSCAN11
    const int CHSCAN10_LSB =  5; // CSCAN0.CHSCAN10
    const int CHSCAN9_LSB  =  4; // CSCAN0.CHSCAN9
    const int CHSCAN8_LSB  =  3; // CSCAN0.CHSCAN8
    CSCAN1 = 0xA800;            //!< mosiData16 0xA800..0xAFFF format: 1 0 1 0 1 CHSCAN7 CHSCAN6 CHSCAN5 CHSCAN4 CHSCAN3 CHSCAN2 CHSCAN1 CHSCAN0 x x x
    const int CHSCAN7_LSB = 10; // CSCAN1.CHSCAN7
    const int CHSCAN6_LSB =  9; // CSCAN1.CHSCAN6
    const int CHSCAN5_LSB =  8; // CSCAN1.CHSCAN5
    const int CHSCAN4_LSB =  7; // CSCAN1.CHSCAN4
    const int CHSCAN3_LSB =  6; // CSCAN1.CHSCAN3
    const int CHSCAN2_LSB =  5; // CSCAN1.CHSCAN2
    const int CHSCAN1_LSB =  4; // CSCAN1.CHSCAN1
    const int CHSCAN0_LSB =  3; // CSCAN1.CHSCAN0
    
    //----------------------------------------
    // SET CSCAN0 CSCAN1 REGISTERS from enabledChannelsMask
    CSCAN0 = 0xA000 | (((enabledChannelsMask >> 8) & 0xFF) << 3); // CSCAN0.CHSCAN[15:8]
    CSCAN1 = 0xA800 | (((enabledChannelsMask) & 0xFF) << 3); // CSCAN1.CHSCAN[7:0]
    SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern
    SPIoutputCS(0); // drive CS low
    SPIwrite16bits(CSCAN0);
    SPIoutputCS(1); // drive CS high
    SPIoutputCS(0); // drive CS low
    SPIwrite16bits(CSCAN1);
    SPIoutputCS(1); // drive CS high
    
    //----------------------------------------
    // ADC MODE CONTROL register set SCAN[3:0] TO SCAN_1000_CustomExternalClock = 8
    //~ const int SCAN_1000_CustomExternalClock = 8; // replaced local const with enum
    ADC_MODE_CONTROL |=   ((SCAN_1000_CustomExternalClock & SCAN_BITS) << SCAN_LSB);
    
    //----------------------------------------
    // ADC MODE CONTROL REGISTER SELECT THE PM[1:0] BITS
    ADC_MODE_CONTROL |=   ((PowerManagement_0_2 & PM_BITS) << PM_LSB);
    
    //----------------------------------------
    // ADC MODE CONTROL REGISTER SELECT THE CHAN_ID BIT
    // (applicable to external clock mode only)
    // For external clock modes, the data format returned depends on the CHAN_ID bit.
    //     when CHAN_ID = 0: misoData16 = 0 DATA[11:0] x x x
    //     when CHAN_ID = 1: misoData16 = CH[3:0] DATA[11:0]
    // For internal clock modes, the data format always includes the channel address.
    //     misoData16 = CH[3:0] DATA[11:0]
    ADC_MODE_CONTROL |=   ((chan_id_0_1 & CHAN_ID_BITS) << CHAN_ID_LSB);
    
    //----------------------------------------
    // SPI write ADC MODE CONTROL register
    // Send SPI configuration to device
    SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern
    SPIoutputCS(0); // drive CS low
    SPIwrite16bits(ADC_MODE_CONTROL);
    SPIoutputCS(1); // drive CS high
    
    //----------------------------------------
    // return number of words to read
    return NumWords;
}

//----------------------------------------
// SCAN_1001_SampleSetExternalClock
//
// Measure ADC channels in an arbitrary pattern.
//     Channels can be visited in any order, with repetition allowed.
// External clock mode.
// @pre enabledChannelsPatternLength_1_256: number of channel selections
// @pre enabledChannelsPattern: array containing channel selection pattern
//     In the array, one channel select per byte.
//     In the SPI interface, immediately after SAMPLESET register is written,
//     each byte encodes two channelNumber selections.
//     The high 4 bits encode the first channelNumber.
//     (((enabledChannelsPattern[0]) & 0x0F) << 4) | ((enabledChannelsPattern[1]) & 0x0F)
//     If it is an odd number of channels, additional nybbles will be ignored.
//     CS will be asserted low during the entire SAMPLESET pattern selection.
// @param[in] PowerManagement_0_2: 0=Normal, 1=AutoShutdown, 2=AutoStandby
// @param[in] chan_id_0_1: ADC_MODE_CONTROL.CHAN_ID
// @return number of ScanRead() words needed to retrieve the data.
// For external clock modes, the data format depends on CHAN_ID.
//     when CHAN_ID = 0: misoData16 = 0 DATA[11:0] x x x
//     when CHAN_ID = 1: misoData16 = CH[3:0] DATA[11:0]
//
int MAX11131::ScanSampleSetExternalClock(void)
{
    
    //----------------------------------------
    // define write-only register ADC_MODE_CONTROL
    ADC_MODE_CONTROL = 0;       //!< mosiData16 0x0000..0x7FFF format: 0 SCAN[3:0] CHSEL[3:0] RESET[1:0] PM[1:0] CHAN_ID SWCNV 0
    const int SCAN_LSB    = 11; const int SCAN_BITS    = 0x0F; //!< ADC_MODE_CONTROL.SCAN[3:0] ADC Scan Control (command)
    const int CHSEL_LSB   =  7; const int CHSEL_BITS   = 0x0F; //!< ADC_MODE_CONTROL.CHSEL[3:0] Analog Input Channel Select AIN0..AIN15
    const int RESET_LSB   =  5; const int RESET_BITS   = 0x03; //!< ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved
    const int PM_LSB      =  3; const int PM_BITS      = 0x03; //!< ADC_MODE_CONTROL.PM[1:0] Power Management 0=Normal, 1=AutoShutdown, 2=AutoStandby 3=reserved
    const int CHAN_ID_LSB =  2; const int CHAN_ID_BITS = 0x01; //!< ADC_MODE_CONTROL.CHAN_ID
    const int SWCNV_LSB   =  1; const int SWCNV_BITS   = 0x01; //!< ADC_MODE_CONTROL.SWCNV
    
    //----------------------------------------
    // Apply a soft reset when changing from internal to external clock mode.
    int needFIFOreset = (isExternalClock != 1);
    if (needFIFOreset) {
        // Apply a soft reset when changing from internal to external clock mode.
        ADC_MODE_CONTROL = ((1 & RESET_BITS) << RESET_LSB); // ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved
        // Send SPI configuration to device
        SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern
        SPIoutputCS(0); // drive CS low
        SPIwrite16bits(ADC_MODE_CONTROL);
        SPIoutputCS(1); // drive CS high
        ADC_MODE_CONTROL = 0;
    }
    
    //----------------------------------------
    // number of words to read
    NumWords = ((enabledChannelsPatternLength_1_256 != 0) ? enabledChannelsPatternLength_1_256 : 256 );
    
    //----------------------------------------
    // External Clock Mode
    isExternalClock = 1;
    
    //----------------------------------------
    // update device driver global variable
    ScanMode = SCAN_1001_SampleSetExternalClock;
    
    //----------------------------------------
    // Initialize shadow of write-only register SAMPLESET.
    // Do not write to SAMPLESET at this time.
    // A write to SAMPLESET must be followed by specified number of pattern entry words.
    // See ScanSampleSetExternalClock function for details.
    SAMPLESET = 0xB000;         //!< mosiData16 0xB000..0xB7FF format: 1 0 1 1 0 SEQ_LENGTH[7:0] x x x
    const int SAMPLESET_LSB   =  3; const int SAMPLESET_BITS   = 0xFF; // SAMPLESET.SEQ_LENGTH[7:0]
    
    //----------------------------------------
    // SampleSet register set SEQ_DEPTH[7:0] TO SET CHANNEL CAPTURE DEPTH; FOLLOW SampleSet REGISTER WITH CHANNEL PATTERN OF THE SAME SIZE AS SEQUENCE DEPTH
    // NOTE: SAMPLESET.SEQ_LENGTH[7:0] is the number of channel entries in the pattern.
    // NOTE: Each channel entry is 4 bits. The first 4 bits are the first channel in the sequence.
    // NOTE: Channels can be repeated in any arbitrary order.
    // NOTE: The channel entry pattern is sent immediately after writing SAMPLESET.
    // NOTE: Keep CS low during the entire SAMPLESET pattern entry.
    const int seq_length_minus_one_0_255 = enabledChannelsPatternLength_1_256 - 1;
    SAMPLESET = 0xB000;
    //SAMPLESET &= ~ ((                             SAMPLESET_BITS) << SAMPLESET_LSB);
    SAMPLESET |=   ((seq_length_minus_one_0_255 & SAMPLESET_BITS) << SAMPLESET_LSB);
    SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern
    SPIoutputCS(0); // drive CS low
    SPIwrite16bits(SAMPLESET); // SAMPLESET must be followed by several more bytes, length specified by SEQ_LENGTH[7:0]
    // pack enabledChannelsPattern[index] into nybbles
    SPIoutputCS(1); // drive CS high
    // NOTE: Send the sampleset pattern, with 4 entries packed into each 16-bit SPI word. Pad unused entries with 0.
    SPI_MOSI_Semantic = 2; // 0:Nothing 1:regWrite 2:sampleSetPattern
    SPIoutputCS(0); // drive CS low
    // NOTE: Keep CS low during the entire SAMPLESET pattern entry.
    int entryIndex;
    for (entryIndex = 0; entryIndex < enabledChannelsPatternLength_1_256; entryIndex += 4)
    {
        uint16_t pack4channels = 0;
        pack4channels |= (((enabledChannelsPattern[entryIndex + 0]) & 0x0F) << 12);
        if ((entryIndex + 1) < enabledChannelsPatternLength_1_256) {
            pack4channels |= (((enabledChannelsPattern[entryIndex + 1]) & 0x0F) << 8);
        }
        if ((entryIndex + 2) < enabledChannelsPatternLength_1_256) {
            pack4channels |= (((enabledChannelsPattern[entryIndex + 2]) & 0x0F) << 4);
        }
        if ((entryIndex + 3) < enabledChannelsPatternLength_1_256) {
            pack4channels |=   ((enabledChannelsPattern[entryIndex + 3]) & 0x0F);
        }
        SPIwrite16bits(pack4channels);
    }
    SPIoutputCS(1); // drive CS high
    
    //----------------------------------------
    // ADC MODE CONTROL register set SCAN[3:0] TO SCAN_1001_SampleSetExternalClock = 9
    //~ const int SCAN_1001_SampleSetExternalClock = 9; // replaced local const with enum
    ADC_MODE_CONTROL |=   ((SCAN_1001_SampleSetExternalClock & SCAN_BITS) << SCAN_LSB);
    
    //----------------------------------------
    // ADC MODE CONTROL register set CHSEL[3:0] TO channel number
    ADC_MODE_CONTROL |=   ((0 & CHSEL_BITS) << CHSEL_LSB);
    
    //----------------------------------------
    // ADC MODE CONTROL REGISTER SELECT THE PM[1:0] BITS
    ADC_MODE_CONTROL |=   ((PowerManagement_0_2 & PM_BITS) << PM_LSB);
    
    //----------------------------------------
    // ADC MODE CONTROL REGISTER SELECT THE CHAN_ID BIT
    // (applicable to external clock mode only)
    // For external clock modes, the data format returned depends on the CHAN_ID bit.
    //     when CHAN_ID = 0: misoData16 = 0 DATA[11:0] x x x
    //     when CHAN_ID = 1: misoData16 = CH[3:0] DATA[11:0]
    // For internal clock modes, the data format always includes the channel address.
    //     misoData16 = CH[3:0] DATA[11:0]
    ADC_MODE_CONTROL |=   ((chan_id_0_1 & CHAN_ID_BITS) << CHAN_ID_LSB);
    
    //----------------------------------------
    // SPI write ADC MODE CONTROL register
    // Send SPI configuration to device
    SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern
    SPIoutputCS(0); // drive CS low
    SPIwrite16bits(ADC_MODE_CONTROL);
    SPIoutputCS(1); // drive CS high
    
    //----------------------------------------
    // return number of words to read
    return NumWords;
}

//----------------------------------------
// Example configure and perform some measurements in ScanManual mode.
// @param[out] pd_mean = address for double mean (avearge)
// @param[out] pd_variance = address for double variance (variance)
// @param[out] pd_stddev = address for double stddev (standard deviation)
// @param[out] pd_Sx = address for double Sx (sum of all X)
// @param[out] pd_Sxx = address for double Sxx (sum of squares of each X)
void MAX11131::Example_ScanManual(int channelNumber_0_15, int nWords, 
  double* pd_mean, double* pd_variance, double* pd_stddev, 
  double* pd_Sx, double* pd_Sxx)
{
    
    //----------------------------------------
    // configure and perform some measurements in ScanManual mode
    Init();
    channelNumber_0_15 = channelNumber_0_15; // Analog Input Channel Select AIN0..
    PowerManagement_0_2 = 0; // Power Management 0=Normal, 1=AutoShutdown, 2=AutoStandby 3=reserved
    chan_id_0_1 = 1; // when CHAN_ID = 0: misoData16 = 0 DATA[11:0] x x x
    // const int nWords = 100;
    double Sx = 0;
    double Sxx = 0;
    int index;
    ScanManual();
    for (index = 0; index < nWords; index++)
    {
        int16_t misoData16 = ScanRead();
        // For internal clock modes, the data format always includes the channel address.
        //     misoData16 = CH[3:0] DATA[11:0]
        int16_t value_u12 = (misoData16 & 0x0FFF);
        int channelId = ((misoData16 >> 12) & 0x000F);
        Sx = Sx + value_u12;
        Sxx = Sxx + ((double)value_u12 * value_u12);
    }
    if (pd_Sx != 0) {
        *(pd_Sx) = Sx;
    }
    if (pd_Sxx != 0) {
        *(pd_Sxx) = Sxx;
    }
    if (pd_mean != 0) {
        *(pd_mean) = Sx / nWords;
    }
    if (nWords >= 2)
    {
        if (pd_variance != 0) {
            // TODO1: is this variance calculation too naive to work reliably?
            // see https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
            *(pd_variance) = (Sxx - ( Sx * Sx / nWords) ) / (nWords - 1);
        }
        if (pd_stddev != 0) {
            *(pd_stddev) = sqrt( *(pd_variance) );
        }
    }
}


// End of file