Maxim Integrated MAX11131 SPI 12-bit 16-channel ADC with SampleSet
Dependents: MAX11131BOB_Tester MAX11131BOB_12bit_16ch_SampleSet_SPI_ADC MAX11131BOB_Serial_Tester
Diff: MAX11131.cpp
- Revision:
- 0:f7d706d2904d
- Child:
- 1:77f1ee332e4a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MAX11131.cpp Wed Jun 05 02:16:46 2019 +0000 @@ -0,0 +1,2767 @@ +// /******************************************************************************* +// * 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 4000000 // 4MHz + //#define SPI_SCLK_Hz 2000000 // 2MHz + //#define SPI_SCLK_Hz 1000000 // 1MHz + m_SPI_SCLK_Hz = 12000000; // 12MHz; MAX11131 limit is 48MHz + 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 ±½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 ±½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 ±½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 ±½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 ±½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 ±½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 ±½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 ±½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 ±½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 ±½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 ±½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 ±½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 ±½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 ±½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 ±½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 ±½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 ±½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 ±½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 ±½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 ±½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) +{ + + //---------------------------------------- + // number of words to read + NumWords = 1; + + //---------------------------------------- + // External Clock Mode + isExternalClock = 1; + + //---------------------------------------- + // update device driver global variable + ScanMode = SCAN_0001_Manual; + + //---------------------------------------- + // 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 + + //---------------------------------------- + // 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_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) +{ + + //---------------------------------------- + // number of words to read + NumWords = (1 + channelNumber_0_15); + + //---------------------------------------- + // External Clock Mode + isExternalClock = 1; + + //---------------------------------------- + // update device driver global variable + ScanMode = SCAN_0100_StandardExternalClock; + + //---------------------------------------- + // 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 + + //---------------------------------------- + // 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_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) +{ + + //---------------------------------------- + // number of words to read + NumWords = (16 - channelNumber_0_15); + + //---------------------------------------- + // External Clock Mode + isExternalClock = 1; + + //---------------------------------------- + // update device driver global variable + ScanMode = SCAN_0110_UpperExternalClock; + + //---------------------------------------- + // 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 + + //---------------------------------------- + // 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_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++; + } + } + + //---------------------------------------- + // number of words to read + NumWords = nWords; + + //---------------------------------------- + // External Clock Mode + isExternalClock = 1; + + //---------------------------------------- + // update device driver global variable + ScanMode = SCAN_1000_CustomExternalClock; + + //---------------------------------------- + // 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 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 + + //---------------------------------------- + // 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_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) +{ + + //---------------------------------------- + // 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; + + //---------------------------------------- + // 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 + + //---------------------------------------- + // 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 + + //---------------------------------------- + // 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_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 +