Maxim Integrated MAX11131 SPI 12-bit 16-channel ADC with SampleSet
Dependents: MAX11131BOB_Tester MAX11131BOB_12bit_16ch_SampleSet_SPI_ADC MAX11131BOB_Serial_Tester
MAX11131.cpp
- Committer:
- whismanoid
- Date:
- 2019-08-04
- Revision:
- 4:8a0ae95546fa
- Parent:
- 3:621191a7e3fd
- Child:
- 5:6ef046dbe77e
File content as of revision 4:8a0ae95546fa:
// /******************************************************************************* // * Copyright (C) 2019 Maxim Integrated Products, Inc., All Rights Reserved. // * // * Permission is hereby granted, free of charge, to any person obtaining a // * copy of this software and associated documentation files (the "Software"), // * to deal in the Software without restriction, including without limitation // * the rights to use, copy, modify, merge, publish, distribute, sublicense, // * and/or sell copies of the Software, and to permit persons to whom the // * Software is furnished to do so, subject to the following conditions: // * // * The above copyright notice and this permission notice shall be included // * in all copies or substantial portions of the Software. // * // * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES // * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // * OTHER DEALINGS IN THE SOFTWARE. // * // * Except as contained in this notice, the name of Maxim Integrated // * Products, Inc. shall not be used except as stated in the Maxim Integrated // * Products, Inc. Branding Policy. // * // * The mere transfer of this software does not imply any licenses // * of trade secrets, proprietary technology, copyrights, patents, // * trademarks, maskwork rights, or any other form of intellectual // * property whatsoever. Maxim Integrated Products, Inc. retains all // * ownership rights. // ******************************************************************************* // */ // ********************************************************************* // @file MAX11131.cpp // ********************************************************************* // Device Driver file // DO NOT EDIT; except areas designated "CUSTOMIZE". Automatically generated file. // generated by XMLSystemOfDevicesToMBED.py // System Name = ExampleSystem // System Description = Device driver example #include "MAX11131.h" // Device Name = MAX11131 // Device Description = 3Msps, Low-Power, Serial SPI 12-Bit, 16-Channel, Differential/Single-Ended Input, SAR ADC // Device Manufacturer = Maxim Integrated // Device PartNumber = MAX11131ATI+ // Device RegValue_Width = DataWidth16bit_HL // // ADC MaxOutputDataRate = 3Msps // ADC NumChannels = 16 // ADC ResolutionBits = 12 // // SPI CS = ActiveLow // SPI FrameStart = CS // SPI CPOL = 1 // SPI CPHA = 1 // SPI MOSI and MISO Data are both stable on Rising edge of SCLK // SPI SCLK Idle High // SPI SCLKMaxMHz = 48 // SPI SCLKMinMHz = 0.48 // // InputPin Name = CNVST // InputPin Description = Active-Low Conversion Start Input/Analog Input 14 // InputPin Function = Trigger // // InputPin Name = REF+ // InputPin Description = External Positive Reference Input. Apply a reference voltage at REF+. Bypass to GND with a 0.47uF capacitor. // InputPin Function = Reference // // InputPin Name = REF-/AIN15 // InputPin Description = External Differential Reference Negative Input/Analog Input 15 // InputPin Function = Reference // // OutputPin Name = EOC // OutputPin Description = End of Conversion Output. Data is valid after EOC pulls low (Internal clock mode only). // OutputPin Function = Event // // SupplyPin Name = VDD // SupplyPin Description = Power-Supply Input. Bypass to GND with a 10uF in parallel with a 0.1uF capacitors. // SupplyPin VinMax = 3.6 // SupplyPin VinMin = 2.35 // SupplyPin Function = Analog // // SupplyPin Name = OVDD // SupplyPin Description = Interface Digital Power-Supply Input. Bypass to GND with a 10uF in parallel with a 0.1uF capacitors. // SupplyPin VinMax = 3.6 // SupplyPin VinMin = 1.5 // SupplyPin Function = Digital // // CODE GENERATOR: class constructor definition MAX11131::MAX11131(SPI &spi, DigitalOut &cs_pin, // SPI interface // CODE GENERATOR: class constructor definition gpio InputPin pins DigitalOut &CNVST_pin, // Digital Trigger Input to MAX11131 device // AnalogOut &REF__pin, // Reference Input to MAX11131 device // AnalogOut &REF__AIN15_pin, // Reference Input to MAX11131 device // CODE GENERATOR: class constructor definition gpio OutputPin pins DigitalIn &EOC_pin, // Digital Event Output from MAX11131 device // CODE GENERATOR: class constructor definition ic_variant MAX11131_ic_t ic_variant) // CODE GENERATOR: class constructor initializer list : m_spi(spi), m_cs_pin(cs_pin), // SPI interface // CODE GENERATOR: class constructor initializer list gpio InputPin pins m_CNVST_pin(CNVST_pin), // Digital Trigger Input to MAX11131 device // m_REF__pin(REF__pin), // Reference Input to MAX11131 device // m_REF__AIN15_pin(REF__AIN15_pin), // Reference Input to MAX11131 device // CODE GENERATOR: class constructor initializer list gpio OutputPin pins m_EOC_pin(EOC_pin), // Digital Event Output from MAX11131 device // CODE GENERATOR: class constructor initializer list ic_variant m_ic_variant(ic_variant) { // CODE GENERATOR: class constructor definition SPI interface initialization // // SPI CS = ActiveLow // SPI FrameStart = CS m_SPI_cs_state = 1; m_cs_pin = m_SPI_cs_state; // SPI CPOL = 1 // SPI CPHA = 1 // SPI MOSI and MISO Data are both stable on Rising edge of SCLK // SPI SCLK Idle High m_SPI_dataMode = 3; //SPI_MODE3 // CPOL=1,CPHA=1: Rising Edge stable; SCLK idle High m_spi.format(8,m_SPI_dataMode); // int bits_must_be_8, int mode=0_3 CPOL=0,CPHA=0 // SPI SCLKMaxMHz = 48 // SPI SCLKMinMHz = 0.48 //#define SPI_SCLK_Hz 48000000 // 48MHz //#define SPI_SCLK_Hz 24000000 // 24MHz //#define SPI_SCLK_Hz 12000000 // 12MHz //#define SPI_SCLK_Hz 6000000 // 6MHz //#define SPI_SCLK_Hz 4000000 // 4MHz //#define SPI_SCLK_Hz 2000000 // 2MHz //#define SPI_SCLK_Hz 1000000 // 1MHz #if defined(TARGET_MAX32600) // MAX11131BOB_Serial_Tester on MAX32600MBED limit SCLK=6MHz m_SPI_SCLK_Hz = 6000000; // 6MHz; MAX11131 limit is 48MHz #else // all other platforms m_SPI_SCLK_Hz = 12000000; // 12MHz; MAX11131 limit is 48MHz #endif m_spi.frequency(m_SPI_SCLK_Hz); // TODO1: CODE GENERATOR: class constructor definition gpio InputPin (Input to device) initialization // m_CNVST_pin = 1; // output logic high -- initial value in constructor } // CODE GENERATOR: class destructor definition MAX11131::~MAX11131() { // do nothing } // CODE GENERATOR: spi_frequency setter definition // set SPI SCLK frequency void MAX11131::spi_frequency(int spi_sclk_Hz) { m_SPI_SCLK_Hz = spi_sclk_Hz; m_spi.frequency(m_SPI_SCLK_Hz); } // CODE GENERATOR: omit global g_MAX11131_device // CODE GENERATOR: extern function declarations // CODE GENERATOR: extern function requirement MAX11131::SPIoutputCS // Assert SPI Chip Select // SPI chip-select for MAX11131 // void MAX11131::SPIoutputCS(int isLogicHigh) { // CODE GENERATOR: extern function definition for function SPIoutputCS // CODE GENERATOR: extern function definition for standard SPI interface function SPIoutputCS(int isLogicHigh) m_SPI_cs_state = isLogicHigh; m_cs_pin = m_SPI_cs_state; } // CODE GENERATOR: extern function requirement MAX11131::SPIwrite16bits // SPI write 16 bits // SPI interface to MAX11131 shift 16 bits mosiData16 into MAX11131 DIN // ignoring MAX11131 DOUT // void MAX11131::SPIwrite16bits(int16_t mosiData16) { // CODE GENERATOR: extern function definition for function SPIwrite16bits // TODO1: CODE GENERATOR: extern function definition for standard SPI interface function SPIwrite16bits(int16_t mosiData16) size_t byteCount = 2; static char mosiData[2]; static char misoData[2]; mosiData[0] = (char)((mosiData16 >> 8) & 0xFF); // MSByte mosiData[1] = (char)((mosiData16 >> 0) & 0xFF); // LSByte // // Arduino: begin critical section: noInterrupts() masks all interrupt sources; end critical section with interrupts() //~ noInterrupts(); // //~ digitalWrite(Scope_Trigger_Pin, LOW); // diagnostic Scope_Trigger_Pin // unsigned int numBytesTransferred = m_spi.write(mosiData, byteCount, misoData, byteCount); //~ m_spi.transfer(mosiData8_FF0000); //~ m_spi.transfer(mosiData16_00FF00); //~ m_spi.transfer(mosiData16_0000FF); // //~ digitalWrite(Scope_Trigger_Pin, HIGH); // diagnostic Scope_Trigger_Pin // // Arduino: begin critical section: noInterrupts() masks all interrupt sources; end critical section with interrupts() //~ interrupts(); // // VERIFY: SPIwrite24bits print diagnostic information //cmdLine.serial().printf(" MOSI->")); //cmdLine.serial().printf(" 0x")); //Serial.print( (mosiData8_FF0000 & 0xFF), HEX); //cmdLine.serial().printf(" 0x")); //Serial.print( (mosiData16_00FF00 & 0xFF), HEX); //cmdLine.serial().printf(" 0x")); //Serial.print( (mosiData16_0000FF & 0xFF), HEX); // hex dump mosiData[0..byteCount-1] #if 0 // HAS_MICROUSBSERIAL cmdLine_microUSBserial.serial().printf("\r\nSPI"); if (byteCount > 7) { cmdLine_microUSBserial.serial().printf(" byteCount:%d", byteCount); } cmdLine_microUSBserial.serial().printf(" MOSI->"); for (unsigned int byteIndex = 0; byteIndex < byteCount; byteIndex++) { cmdLine_microUSBserial.serial().printf(" 0x%2.2X", mosiData[byteIndex]); } // hex dump misoData[0..byteCount-1] cmdLine_microUSBserial.serial().printf(" MISO<-"); for (unsigned int byteIndex = 0; byteIndex < numBytesTransferred; byteIndex++) { cmdLine_microUSBserial.serial().printf(" 0x%2.2X", misoData[byteIndex]); } cmdLine_microUSBserial.serial().printf(" "); #endif #if 0 // HAS_DAPLINK_SERIAL cmdLine_DAPLINKserial.serial().printf("\r\nSPI"); if (byteCount > 7) { cmdLine_DAPLINKserial.serial().printf(" byteCount:%d", byteCount); } cmdLine_DAPLINKserial.serial().printf(" MOSI->"); for (unsigned int byteIndex = 0; byteIndex < byteCount; byteIndex++) { cmdLine_DAPLINKserial.serial().printf(" 0x%2.2X", mosiData[byteIndex]); } // hex dump misoData[0..byteCount-1] cmdLine_DAPLINKserial.serial().printf(" MISO<-"); for (unsigned int byteIndex = 0; byteIndex < numBytesTransferred; byteIndex++) { cmdLine_DAPLINKserial.serial().printf(" 0x%2.2X", misoData[byteIndex]); } cmdLine_DAPLINKserial.serial().printf(" "); #endif // VERIFY: DIAGNOSTIC: print MAX5715 device register write // TODO: MAX5715_print_register_verbose(mosiData8_FF0000, mosiData16_00FFFF); // TODO: print_verbose_SPI_diagnostic(mosiData16_FF00, mosiData16_00FF, misoData16_FF00, misoData16_00FF); // // int misoData16 = (misoData16_FF00 << 8) | misoData16_00FF; // return misoData16; } // CODE GENERATOR: extern function requirement MAX11131::SPIwrite24bits // SPI write 17-24 bits // SPI interface to MAX11131 shift 16 bits mosiData16 into MAX11131 DIN // followed by one additional SCLK byte. // ignoring MAX11131 DOUT // void MAX11131::SPIwrite24bits(int16_t mosiData16_FFFF00, int8_t mosiData8_0000FF) { // CODE GENERATOR: extern function definition for function SPIwrite24bits // TODO1: CODE GENERATOR: extern function definition for standard SPI interface function SPIwrite24bits(int16_t mosiData16_FFFF00, int8_t mosiData8_0000FF) // TODO: implement SPIwrite24bits(int16_t mosiData16_FFFF00, int8_t mosiData8_0000FF) size_t byteCount = 3; static char mosiData[3]; static char misoData[3]; mosiData[0] = (char)((mosiData16_FFFF00 >> 8) & 0xFF); // MSByte mosiData[1] = (char)((mosiData16_FFFF00 >> 0) & 0xFF); // LSByte mosiData[2] = mosiData8_0000FF; // // Arduino: begin critical section: noInterrupts() masks all interrupt sources; end critical section with interrupts() //~ noInterrupts(); // //~ digitalWrite(Scope_Trigger_Pin, LOW); // diagnostic Scope_Trigger_Pin // unsigned int numBytesTransferred = m_spi.write(mosiData, byteCount, misoData, byteCount); //~ m_spi.transfer(mosiData8_FF0000); //~ m_spi.transfer(mosiData16_00FF00); //~ m_spi.transfer(mosiData16_0000FF); // //~ digitalWrite(Scope_Trigger_Pin, HIGH); // diagnostic Scope_Trigger_Pin // // Arduino: begin critical section: noInterrupts() masks all interrupt sources; end critical section with interrupts() //~ interrupts(); // // VERIFY: SPIwrite24bits print diagnostic information //cmdLine.serial().printf(" MOSI->")); //cmdLine.serial().printf(" 0x")); //Serial.print( (mosiData8_FF0000 & 0xFF), HEX); //cmdLine.serial().printf(" 0x")); //Serial.print( (mosiData16_00FF00 & 0xFF), HEX); //cmdLine.serial().printf(" 0x")); //Serial.print( (mosiData16_0000FF & 0xFF), HEX); // hex dump mosiData[0..byteCount-1] #if 0 // HAS_MICROUSBSERIAL cmdLine_microUSBserial.serial().printf("\r\nSPI"); if (byteCount > 7) { cmdLine_microUSBserial.serial().printf(" byteCount:%d", byteCount); } cmdLine_microUSBserial.serial().printf(" MOSI->"); for (unsigned int byteIndex = 0; byteIndex < byteCount; byteIndex++) { cmdLine_microUSBserial.serial().printf(" 0x%2.2X", mosiData[byteIndex]); } // hex dump misoData[0..byteCount-1] cmdLine_microUSBserial.serial().printf(" MISO<-"); for (unsigned int byteIndex = 0; byteIndex < numBytesTransferred; byteIndex++) { cmdLine_microUSBserial.serial().printf(" 0x%2.2X", misoData[byteIndex]); } cmdLine_microUSBserial.serial().printf(" "); #endif #if 0 // HAS_DAPLINK_SERIAL cmdLine_DAPLINKserial.serial().printf("\r\nSPI"); if (byteCount > 7) { cmdLine_DAPLINKserial.serial().printf(" byteCount:%d", byteCount); } cmdLine_DAPLINKserial.serial().printf(" MOSI->"); for (unsigned int byteIndex = 0; byteIndex < byteCount; byteIndex++) { cmdLine_DAPLINKserial.serial().printf(" 0x%2.2X", mosiData[byteIndex]); } // hex dump misoData[0..byteCount-1] cmdLine_DAPLINKserial.serial().printf(" MISO<-"); for (unsigned int byteIndex = 0; byteIndex < numBytesTransferred; byteIndex++) { cmdLine_DAPLINKserial.serial().printf(" 0x%2.2X", misoData[byteIndex]); } cmdLine_DAPLINKserial.serial().printf(" "); #endif // VERIFY: DIAGNOSTIC: print MAX5715 device register write // TODO: MAX5715_print_register_verbose(mosiData8_FF0000, mosiData16_00FFFF); // // int misoData16 = (misoData16_FF00 << 8) | misoData16_00FF; // return misoData16; } // CODE GENERATOR: extern function requirement MAX11131::SPIread16bits // SPI read 16 bits while MOSI (MAX11131 DIN) is 0 // SPI interface to capture 16 bits miso data from MAX11131 DOUT // int16_t MAX11131::SPIread16bits() { // CODE GENERATOR: extern function definition for function SPIread16bits // TODO1: CODE GENERATOR: extern function definition for standard SPI interface function int16_t SPIread16bits() int mosiData16 = 0; size_t byteCount = 2; static char mosiData[2]; static char misoData[2]; mosiData[0] = (char)((mosiData16 >> 8) & 0xFF); // MSByte mosiData[1] = (char)((mosiData16 >> 0) & 0xFF); // LSByte // // Arduino: begin critical section: noInterrupts() masks all interrupt sources; end critical section with interrupts() //~ noInterrupts(); // //~ digitalWrite(Scope_Trigger_Pin, LOW); // diagnostic Scope_Trigger_Pin // unsigned int numBytesTransferred = m_spi.write(mosiData, byteCount, misoData, byteCount); //~ m_spi.transfer(mosiData8_FF0000); //~ m_spi.transfer(mosiData16_00FF00); //~ m_spi.transfer(mosiData16_0000FF); // //~ digitalWrite(Scope_Trigger_Pin, HIGH); // diagnostic Scope_Trigger_Pin // // Arduino: begin critical section: noInterrupts() masks all interrupt sources; end critical section with interrupts() //~ interrupts(); // // VERIFY: SPIwrite24bits print diagnostic information //cmdLine.serial().printf(" MOSI->")); //cmdLine.serial().printf(" 0x")); //Serial.print( (mosiData8_FF0000 & 0xFF), HEX); //cmdLine.serial().printf(" 0x")); //Serial.print( (mosiData16_00FF00 & 0xFF), HEX); //cmdLine.serial().printf(" 0x")); //Serial.print( (mosiData16_0000FF & 0xFF), HEX); // hex dump mosiData[0..byteCount-1] #if 0 // HAS_MICROUSBSERIAL cmdLine_microUSBserial.serial().printf("\r\nSPI"); if (byteCount > 7) { cmdLine_microUSBserial.serial().printf(" byteCount:%d", byteCount); } cmdLine_microUSBserial.serial().printf(" MOSI->"); for (unsigned int byteIndex = 0; byteIndex < byteCount; byteIndex++) { cmdLine_microUSBserial.serial().printf(" 0x%2.2X", mosiData[byteIndex]); } // hex dump misoData[0..byteCount-1] cmdLine_microUSBserial.serial().printf(" MISO<-"); for (unsigned int byteIndex = 0; byteIndex < numBytesTransferred; byteIndex++) { cmdLine_microUSBserial.serial().printf(" 0x%2.2X", misoData[byteIndex]); } cmdLine_microUSBserial.serial().printf(" "); #endif #if 0 // HAS_DAPLINK_SERIAL cmdLine_DAPLINKserial.serial().printf("\r\nSPI"); if (byteCount > 7) { cmdLine_DAPLINKserial.serial().printf(" byteCount:%d", byteCount); } cmdLine_DAPLINKserial.serial().printf(" MOSI->"); for (unsigned int byteIndex = 0; byteIndex < byteCount; byteIndex++) { cmdLine_DAPLINKserial.serial().printf(" 0x%2.2X", mosiData[byteIndex]); } // hex dump misoData[0..byteCount-1] cmdLine_DAPLINKserial.serial().printf(" MISO<-"); for (unsigned int byteIndex = 0; byteIndex < numBytesTransferred; byteIndex++) { cmdLine_DAPLINKserial.serial().printf(" 0x%2.2X", misoData[byteIndex]); } cmdLine_DAPLINKserial.serial().printf(" "); #endif // VERIFY: DIAGNOSTIC: print MAX5715 device register write // TODO: MAX5715_print_register_verbose(mosiData8_FF0000, mosiData16_00FFFF); // TODO: print_verbose_SPI_diagnostic(mosiData16_FF00, mosiData16_00FF, misoData16_FF00, misoData16_00FF); // int misoData16 = (misoData[0] << 8) | misoData[1]; return misoData16; } // CODE GENERATOR: extern function requirement MAX11131::CNVSToutputPulseLow // Assert MAX11131 CNVST convert start. // Required when using any of the InternalClock modes with SWCNV 0. // Trigger measurement by driving CNVST/AIN14 pin low for a minimum active-low pulse duration of 5ns. (AIN14 is not available) // void MAX11131::CNVSToutputPulseLow() { // CODE GENERATOR: extern function definition for function CNVSToutputPulseLow // TODO1: CODE GENERATOR: extern function definition for gpio interface function CNVSToutputPulseLow // TODO1: CODE GENERATOR: gpio pin CNVST assuming member function m_CNVST_pin // TODO1: CODE GENERATOR: gpio direction output // m_CNVST_pin.output(); // only applicable to DigitalInOut // TODO1: CODE GENERATOR: gpio function PulseLow m_CNVST_pin = 0; // output logic low wait(0.01); // pulse low delay time m_CNVST_pin = 1; // output logic high } // CODE GENERATOR: extern function requirement MAX11131::EOCinputWaitUntilLow // Wait for MAX11131 EOC pin low, indicating end of conversion. // Required when using any of the InternalClock modes. // void MAX11131::EOCinputWaitUntilLow() { // CODE GENERATOR: extern function definition for function EOCinputWaitUntilLow // TODO1: CODE GENERATOR: extern function definition for gpio interface function EOCinputWaitUntilLow // TODO1: CODE GENERATOR: gpio pin EOC assuming member function m_EOC_pin // TODO1: CODE GENERATOR: gpio direction input // m_EOC_pin.input(); // only applicable to DigitalInOut // TODO1: CODE GENERATOR: gpio function WaitUntilLow while (m_EOC_pin != 0) { // spinlock waiting for logic low pin state } } // CODE GENERATOR: extern function requirement MAX11131::EOCinputValue // Return the status of the MAX11131 EOC pin. // int MAX11131::EOCinputValue() { // CODE GENERATOR: extern function definition for function EOCinputValue // TODO1: CODE GENERATOR: extern function definition for gpio interface function EOCinputValue // TODO1: CODE GENERATOR: gpio pin EOC assuming member function m_EOC_pin // TODO1: CODE GENERATOR: gpio direction input // m_EOC_pin.input(); // only applicable to DigitalInOut // TODO1: CODE GENERATOR: gpio function Value return m_EOC_pin.read(); } // CODE GENERATOR: class member function definitions //---------------------------------------- // Initialize device void MAX11131::Init(void) { //---------------------------------------- // Nominal Full-Scale Voltage Reference VRef = 2.500; //---------------------------------------- // define write-only register ADC_MODE_CONTROL ADC_MODE_CONTROL = 0; //!< mosiData16 0x0000..0x7FFF format: 0 SCAN[3:0] CHSEL[3:0] RESET[1:0] PM[1:0] CHAN_ID SWCNV 0 const int SCAN_LSB = 11; const int SCAN_BITS = 0x0F; //!< ADC_MODE_CONTROL.SCAN[3:0] ADC Scan Control (command) const int CHSEL_LSB = 7; const int CHSEL_BITS = 0x0F; //!< ADC_MODE_CONTROL.CHSEL[3:0] Analog Input Channel Select AIN0..AIN15 const int RESET_LSB = 5; const int RESET_BITS = 0x03; //!< ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved const int PM_LSB = 3; const int PM_BITS = 0x03; //!< ADC_MODE_CONTROL.PM[1:0] Power Management 0=Normal, 1=AutoShutdown, 2=AutoStandby 3=reserved const int CHAN_ID_LSB = 2; const int CHAN_ID_BITS = 0x01; //!< ADC_MODE_CONTROL.CHAN_ID const int SWCNV_LSB = 1; const int SWCNV_BITS = 0x01; //!< ADC_MODE_CONTROL.SWCNV //---------------------------------------- // define write-only register ADC_CONFIGURATION ADC_CONFIGURATION = 0x8000; //!< mosiData16 0x8000..0x87FF format: 1 0 0 0 0 REFSEL AVGON NAVG[1:0] NSCAN[1:0] SPM[1:0] ECHO 0 0 const int REFSEL_LSB = 10; const int REFSEL_BITS = 0x01; // ADC_CONFIGURATION.REFSEL const int AVGON_LSB = 9; const int AVGON_BITS = 0x01; // ADC_CONFIGURATION.AVGON const int NAVG_LSB = 7; const int NAVG_BITS = 0x03; // ADC_CONFIGURATION.NAVG[1:0] const int NSCAN_LSB = 5; const int NSCAN_BITS = 0x03; // ADC_CONFIGURATION.NSCAN[1:0] const int SPM_LSB = 3; const int SPM_BITS = 0x03; // ADC_CONFIGURATION.SPM[1:0] const int ECHO_LSB = 2; const int ECHO_BITS = 0x01; // ADC_CONFIGURATION.ECHO //---------------------------------------- // define write-only registers UNIPOLAR,BIPOLAR,RANGE UNIPOLAR = 0x8800; //!< mosiData16 0x8800..0x8FFF format: 1 0 0 0 1 UCH0/1 UCH2/3 UCH4/5 UCH6/7 UCH8/9 UCH10/11 UCH12/13 UCH14/15 PDIFF_COM x x BIPOLAR = 0x9000; //!< mosiData16 0x9000..0x97FF format: 1 0 0 1 0 BCH0/1 BCH2/3 BCH4/5 BCH6/7 BCH8/9 BCH10/11 BCH12/13 BCH14/15 x x x RANGE = 0x9800; //!< mosiData16 0x9800..0x9FFF format: 1 0 0 1 1 RANGE0/1 RANGE2/3 RANGE4/5 RANGE6/7 RANGE8/9 RANGE10/11 RANGE12/13 RANGE14/15 x x x const int AIN_0_1_LSB = 10; // UNIPOLAR.UCH0/1 BIPOLAR.BCH0/1 RANGE.RANGE0/1 const int AIN_2_3_LSB = 9; // UNIPOLAR.UCH2/3 BIPOLAR.BCH2/3 RANGE.RANGE2/3 const int AIN_4_5_LSB = 8; // UNIPOLAR.UCH4/5 BIPOLAR.BCH4/5 RANGE.RANGE4/5 const int AIN_6_7_LSB = 7; // UNIPOLAR.UCH6/7 BIPOLAR.BCH6/7 RANGE.RANGE6/7 const int AIN_8_9_LSB = 6; // UNIPOLAR.UCH8/9 BIPOLAR.BCH8/9 RANGE.RANGE8/9 const int AIN_10_11_LSB = 5; // UNIPOLAR.UCH10/11 BIPOLAR.BCH10/11 RANGE.RANGE10/11 const int AIN_12_13_LSB = 4; // UNIPOLAR.UCH12/13 BIPOLAR.BCH12/13 RANGE.RANGE12/13 const int AIN_14_15_LSB = 3; // UNIPOLAR.UCH14/15 BIPOLAR.BCH14/15 RANGE.RANGE14/15 const int PDIFF_COMM_LSB = 2; const int PDIFF_COMM_BITS = 0x01; // UNIPOLAR.PDIFF_COM // Summary of Table 8: // UCH0/1=0, BCH0/1=0, RANGE0/1=0: AIN0/AIN1 two independent single-ended inputs, unipolar code (Full Scale = VREF, LSB = VREF/4096) // UCH0/1=1, BCH0/1=0, RANGE0/1=0: AIN0/AIN1 differential input pair, unipolar code (AIN0>AIN1) (Full Scale = VREF, LSB = VREF/4096) // UCH0/1=0, BCH0/1=1, RANGE0/1=0: AIN0/AIN1 differential input pair (+/-)(1/2)Vref, bipolar code (Full Scale = VREF, LSB = VREF/4096) // UCH0/1=1, BCH0/1=1, RANGE0/1=0: reserved do not use // UCH0/1=0, BCH0/1=0, RANGE0/1=1: reserved do not use // UCH0/1=1, BCH0/1=0, RANGE0/1=1: reserved do not use // UCH0/1=0, BCH0/1=1, RANGE0/1=1: AIN0/AIN1 differential input pair (+/-)Vref, bipolar code (Full Scale = 2VREF, LSB = VREF/2048) // UCH0/1=1, BCH0/1=1, RANGE0/1=1: reserved do not use // Both channels of a differential pair must be within Input Voltage Range (dynamic signal range) 0..VREF. //---------------------------------------- // define write-only registers CSCAN0,CSCAN1 CSCAN0 = 0xA000; //!< mosiData16 0xA000..0xA7FF format: 1 0 1 0 0 CHSCAN15 CHSCAN14 CHSCAN13 CHSCAN12 CHSCAN11 CHSCAN10 CHSCAN9 CHSCAN8 x x x const int CHSCAN15_LSB = 10; // CSCAN0.CHSCAN15 const int CHSCAN14_LSB = 9; // CSCAN0.CHSCAN14 const int CHSCAN13_LSB = 8; // CSCAN0.CHSCAN13 const int CHSCAN12_LSB = 7; // CSCAN0.CHSCAN12 const int CHSCAN11_LSB = 6; // CSCAN0.CHSCAN11 const int CHSCAN10_LSB = 5; // CSCAN0.CHSCAN10 const int CHSCAN9_LSB = 4; // CSCAN0.CHSCAN9 const int CHSCAN8_LSB = 3; // CSCAN0.CHSCAN8 CSCAN1 = 0xA800; //!< mosiData16 0xA800..0xAFFF format: 1 0 1 0 1 CHSCAN7 CHSCAN6 CHSCAN5 CHSCAN4 CHSCAN3 CHSCAN2 CHSCAN1 CHSCAN0 x x x const int CHSCAN7_LSB = 10; // CSCAN1.CHSCAN7 const int CHSCAN6_LSB = 9; // CSCAN1.CHSCAN6 const int CHSCAN5_LSB = 8; // CSCAN1.CHSCAN5 const int CHSCAN4_LSB = 7; // CSCAN1.CHSCAN4 const int CHSCAN3_LSB = 6; // CSCAN1.CHSCAN3 const int CHSCAN2_LSB = 5; // CSCAN1.CHSCAN2 const int CHSCAN1_LSB = 4; // CSCAN1.CHSCAN1 const int CHSCAN0_LSB = 3; // CSCAN1.CHSCAN0 //---------------------------------------- // Initialize shadow of write-only register SAMPLESET. // Do not write to SAMPLESET at this time. // A write to SAMPLESET must be followed by specified number of pattern entry words. // See ScanSampleSetExternalClock function for details. SAMPLESET = 0xB000; //!< mosiData16 0xB000..0xB7FF format: 1 0 1 1 0 SEQ_LENGTH[7:0] x x x const int SAMPLESET_LSB = 3; const int SAMPLESET_BITS = 0xFF; // SAMPLESET.SEQ_LENGTH[7:0] //---------------------------------------- // Reset all registers: ADC_MODE_CONTROL.RESET[1:0] = 2 ADC_MODE_CONTROL &= ~ (( RESET_BITS) << RESET_LSB); // ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved ADC_MODE_CONTROL |= ((2 & RESET_BITS) << RESET_LSB); // ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved //---------------------------------------- // SPI write ADC MODE CONTROL register // Send SPI configuration to device SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern SPIoutputCS(0); // drive CS low SPIwrite16bits(ADC_MODE_CONTROL); SPIoutputCS(1); // drive CS high #if REFSEL_0 //---------------------------------------- // Global setting for all channels: ADC_CONFIGURATION.REFSEL=0: external single-ended reference // SELECT REFERENCE SINGLE-ENDED OR DIFFERENTIAL // SELECT REFERENCE SINGLE-ENDED OR DIFFERENTIAL: EXTERNAL SINGLE-ENDED // SELECT ADC CONFIGURATION register set REFSEL BIT TO 0 ADC_CONFIGURATION &= ~ (( REFSEL_BITS) << REFSEL_LSB); // ADC_CONFIGURATION.REFSEL=0: external single-ended reference. (For the 16-channel chips: channel AIN15 is available.) #endif // REFSEL_0 #if REFSEL_1 //---------------------------------------- // Global setting for all channels: ADC_CONFIGURATION.REFSEL=1: external differential reference (For the 16-channel chips: channel AIN15 is unavailable, the pin is assigned to REF-.) // SELECT REFERENCE SINGLE-ENDED OR DIFFERENTIAL // SELECT REFERENCE SINGLE-ENDED OR DIFFERENTIAL: EXTERNAL DIFFERENTIAL // SELECT ADC CONFIGURATION register set REFSEL BIT TO 1 ADC_CONFIGURATION |= ((1 & REFSEL_BITS) << REFSEL_LSB); // ADC_CONFIGURATION.REFSEL=1: external differential reference. (For the 16-channel chips: channel AIN15 is unavailable, the pin is assigned to REF-.) #endif // REFSEL_1 #if PDIFF_COMM_0 //---------------------------------------- // Global setting for all channels: PDIFF_COMM UNIPOLAR &= ~ (( PDIFF_COMM_BITS) << PDIFF_COMM_LSB); // UNIPOLAR.PDIFF_COMM=0: all single-ended channels use GND as common #endif // PDIFF_COMM_0 #if PDIFF_COMM_1 //---------------------------------------- // Global setting for all channels: PDIFF_COMM // SELECT UNIPOLAR AND register set BIT PDIFF_COM TO 1 FOR PSEUDODIFFERENTIAL SELECTION UNIPOLAR |= ((1 & PDIFF_COMM_BITS) << PDIFF_COMM_LSB); // UNIPOLAR.PDIFF_COMM=1: all single-ended channels are pseudo-differential with REF- as common #endif // PDIFF_COMM_1 #if AIN_0_1_SingleEnded //---------------------------------------- // ADC Channels AIN0, AIN1 = Both Single-Ended, Unipolar // Full Scale = VREF // Voltage per LSB count = VREF/4096 // AIN0 is a Single-Ended input using Unipolar transfer function. // AIN1 is a Single-Ended input using Unipolar transfer function. // If PDIFF_COM_1, both are Pseudo-Differential with REF- as common. // AIN0 voltage must always be between 0 and VREF. // AIN1 voltage must always be between 0 and VREF. // // SELECT UNIPOLAR AND BIPOLAR register set PER CHANNEL UCH(X)/(X+1) AND BCH(X)/(X+1) TO 0 FOR SINGLE-ENDED SELECTION UNIPOLAR &= ~ (1 << AIN_0_1_LSB); BIPOLAR &= ~ (1 << AIN_0_1_LSB); RANGE &= ~ (1 << AIN_0_1_LSB); // UCH0/1=0, BCH0/1=0, RANGE0/1=0: AIN0/AIN1 two independent single-ended inputs, unipolar code (Full Scale = VREF, LSB = VREF/4096) #endif // AIN_0_1_SingleEnded #if AIN_0_1_DifferentialUnipolar //---------------------------------------- // ADC Channels AIN0, AIN1 = Differential Unipolar (AIN0 > AIN1) // Full Scale = VREF // Voltage per LSB count = VREF/4096 // AIN0, AIN1 are a Differential pair using Unipolar transfer function. // AIN0 voltage must always be between 0 and VREF. // AIN1 voltage must always be between 0 and VREF. // // SELECT UNIPOLAR register set PER CHANNEL UCH(X)/(X+1) TO 1 FOR UNIPOLAR UNIPOLAR |= (1 << AIN_0_1_LSB); BIPOLAR &= ~ (1 << AIN_0_1_LSB); RANGE &= ~ (1 << AIN_0_1_LSB); // UCH0/1=1, BCH0/1=0, RANGE0/1=0: AIN0/AIN1 differential input pair, unipolar code (AIN0>AIN1) (Full Scale = VREF, LSB = VREF/4096) #endif // AIN_0_1_DifferentialUnipolar #if AIN_0_1_DifferentialBipolarFSVref //---------------------------------------- // ADC Channels AIN0, AIN1 = Differential Bipolar // Full Scale = VREF // Voltage per LSB count = VREF/4096 // AIN0, AIN1 are a Differential pair using Bipolar transfer function with range (+/-)(1/2)Vref // AIN0 voltage must always be between 0 and VREF. // AIN1 voltage must always be between 0 and VREF. // // SELECT BIPOLAR register set PER CHANNEL BCH(X)/(X+1) TO 1 FOR BIPOLAR FULLY DIFFERENTIAL // SELECT RANGE register set PER CHANNEL PAIR RANGE(X)/(X+1) TO 0 +/-VREF+/2 UNIPOLAR &= ~ (1 << AIN_0_1_LSB); BIPOLAR |= (1 << AIN_0_1_LSB); RANGE &= ~ (1 << AIN_0_1_LSB); // UCH0/1=0, BCH0/1=1, RANGE0/1=0: AIN0/AIN1 differential input pair (+/-)(1/2)Vref, bipolar code (Full Scale = VREF, LSB = VREF/4096) #endif // AIN_0_1_DifferentialBipolarFSVref #if AIN_0_1_DifferentialBipolarFS2Vref //---------------------------------------- // ADC Channels AIN0, AIN1 = Differential Bipolar // Full Scale = 2 * VREF // Voltage per LSB count = VREF/2048 // AIN0, AIN1 are a Differential pair using Bipolar transfer function with range (+/-)Vref // AIN0 voltage must always be between 0 and VREF. // AIN1 voltage must always be between 0 and VREF. // // SELECT BIPOLAR register set PER CHANNEL BCH(X)/(X+1) TO 1 FOR BIPOLAR FULLY DIFFERENTIAL // SELECT RANGE register set PER CHANNEL PAIR RANGE(X)/(X+1) TO 1 +/-VREF+ UNIPOLAR &= ~ (1 << AIN_0_1_LSB); BIPOLAR |= (1 << AIN_0_1_LSB); RANGE |= (1 << AIN_0_1_LSB); // UCH0/1=0, BCH0/1=1, RANGE0/1=1: AIN0/AIN1 differential input pair (+/-)Vref, bipolar code (Full Scale = 2VREF, LSB = VREF/2048) #endif // AIN_0_1_DifferentialBipolarFS2Vref #if AIN_2_3_SingleEnded //---------------------------------------- // ADC Channels AIN2, AIN3 = Both Single-Ended, Unipolar // Full Scale = VREF // Voltage per LSB count = VREF/4096 // AIN2 is a Single-Ended input using Unipolar transfer function. // AIN3 is a Single-Ended input using Unipolar transfer function. // If PDIFF_COM_1, both are Pseudo-Differential with REF- as common. // AIN2 voltage must always be between 0 and VREF. // AIN3 voltage must always be between 0 and VREF. // // SELECT UNIPOLAR AND BIPOLAR register set PER CHANNEL UCH(X)/(X+1) AND BCH(X)/(X+1) TO 0 FOR SINGLE-ENDED SELECTION UNIPOLAR &= ~ (1 << AIN_2_3_LSB); BIPOLAR &= ~ (1 << AIN_2_3_LSB); RANGE &= ~ (1 << AIN_2_3_LSB); // UCH2/3=0, BCH2/3=0, RANGE2/3=0: AIN0/AIN1 two independent single-ended inputs, unipolar code (Full Scale = VREF, LSB = VREF/4096) #endif // AIN_2_3_SingleEnded #if AIN_2_3_DifferentialUnipolar //---------------------------------------- // ADC Channels AIN2, AIN3 = Differential Unipolar (AIN2 > AIN3) // Full Scale = VREF // Voltage per LSB count = VREF/4096 // AIN2, AIN3 are a Differential pair using Unipolar transfer function. // AIN2 voltage must always be between 0 and VREF. // AIN3 voltage must always be between 0 and VREF. // // SELECT UNIPOLAR register set PER CHANNEL UCH(X)/(X+1) TO 1 FOR UNIPOLAR UNIPOLAR |= (1 << AIN_2_3_LSB); BIPOLAR &= ~ (1 << AIN_2_3_LSB); RANGE &= ~ (1 << AIN_2_3_LSB); // UCH2/3=1, BCH2/3=0, RANGE2/3=0: AIN0/AIN1 differential input pair, unipolar code (AIN0>AIN1) (Full Scale = VREF, LSB = VREF/4096) #endif // AIN_2_3_DifferentialUnipolar #if AIN_2_3_DifferentialBipolarFSVref //---------------------------------------- // ADC Channels AIN2, AIN3 = Differential Bipolar // Full Scale = VREF // Voltage per LSB count = VREF/4096 // AIN2, AIN3 are a Differential pair using Bipolar transfer function with range (+/-)(1/2)Vref // AIN2 voltage must always be between 0 and VREF. // AIN3 voltage must always be between 0 and VREF. // // SELECT BIPOLAR register set PER CHANNEL BCH(X)/(X+1) TO 1 FOR BIPOLAR FULLY DIFFERENTIAL // SELECT RANGE register set PER CHANNEL PAIR RANGE(X)/(X+1) TO 0 +/-VREF+/2 UNIPOLAR &= ~ (1 << AIN_2_3_LSB); BIPOLAR |= (1 << AIN_2_3_LSB); RANGE &= ~ (1 << AIN_2_3_LSB); // UCH2/3=0, BCH2/3=1, RANGE2/3=0: AIN0/AIN1 differential input pair (+/-)(1/2)Vref, bipolar code (Full Scale = VREF, LSB = VREF/4096) #endif // AIN_2_3_DifferentialBipolarFSVref #if AIN_2_3_DifferentialBipolarFS2Vref //---------------------------------------- // ADC Channels AIN2, AIN3 = Differential Bipolar // Full Scale = 2 * VREF // Voltage per LSB count = VREF/2048 // AIN2, AIN3 are a Differential pair using Bipolar transfer function with range (+/-)Vref // AIN2 voltage must always be between 0 and VREF. // AIN3 voltage must always be between 0 and VREF. // // SELECT BIPOLAR register set PER CHANNEL BCH(X)/(X+1) TO 1 FOR BIPOLAR FULLY DIFFERENTIAL // SELECT RANGE register set PER CHANNEL PAIR RANGE(X)/(X+1) TO 1 +/-VREF+ UNIPOLAR &= ~ (1 << AIN_2_3_LSB); BIPOLAR |= (1 << AIN_2_3_LSB); RANGE |= (1 << AIN_2_3_LSB); // UCH2/3=0, BCH2/3=1, RANGE2/3=1: AIN0/AIN1 differential input pair (+/-)Vref, bipolar code (Full Scale = 2VREF, LSB = VREF/2048) #endif // AIN_2_3_DifferentialBipolarFS2Vref #if AIN_4_5_SingleEnded //---------------------------------------- // ADC Channels AIN4, AIN5 = Both Single-Ended, Unipolar // Full Scale = VREF // Voltage per LSB count = VREF/4096 // AIN4 is a Single-Ended input using Unipolar transfer function. // AIN5 is a Single-Ended input using Unipolar transfer function. // If PDIFF_COM_1, both are Pseudo-Differential with REF- as common. // AIN4 voltage must always be between 0 and VREF. // AIN5 voltage must always be between 0 and VREF. // // SELECT UNIPOLAR AND BIPOLAR register set PER CHANNEL UCH(X)/(X+1) AND BCH(X)/(X+1) TO 0 FOR SINGLE-ENDED SELECTION UNIPOLAR &= ~ (1 << AIN_4_5_LSB); BIPOLAR &= ~ (1 << AIN_4_5_LSB); RANGE &= ~ (1 << AIN_4_5_LSB); // UCH4/5=0, BCH4/5=0, RANGE4/5=0: AIN0/AIN1 two independent single-ended inputs, unipolar code (Full Scale = VREF, LSB = VREF/4096) #endif // AIN_4_5_SingleEnded #if AIN_4_5_DifferentialUnipolar //---------------------------------------- // ADC Channels AIN4, AIN5 = Differential Unipolar (AIN4 > AIN5) // Full Scale = VREF // Voltage per LSB count = VREF/4096 // AIN4, AIN5 are a Differential pair using Unipolar transfer function. // AIN4 voltage must always be between 0 and VREF. // AIN5 voltage must always be between 0 and VREF. // // SELECT UNIPOLAR register set PER CHANNEL UCH(X)/(X+1) TO 1 FOR UNIPOLAR UNIPOLAR |= (1 << AIN_4_5_LSB); BIPOLAR &= ~ (1 << AIN_4_5_LSB); RANGE &= ~ (1 << AIN_4_5_LSB); // UCH4/5=1, BCH4/5=0, RANGE4/5=0: AIN0/AIN1 differential input pair, unipolar code (AIN0>AIN1) (Full Scale = VREF, LSB = VREF/4096) #endif // AIN_4_5_DifferentialUnipolar #if AIN_4_5_DifferentialBipolarFSVref //---------------------------------------- // ADC Channels AIN4, AIN5 = Differential Bipolar // Full Scale = VREF // Voltage per LSB count = VREF/4096 // AIN4, AIN5 are a Differential pair using Bipolar transfer function with range (+/-)(1/2)Vref // AIN4 voltage must always be between 0 and VREF. // AIN5 voltage must always be between 0 and VREF. // // SELECT BIPOLAR register set PER CHANNEL BCH(X)/(X+1) TO 1 FOR BIPOLAR FULLY DIFFERENTIAL // SELECT RANGE register set PER CHANNEL PAIR RANGE(X)/(X+1) TO 0 +/-VREF+/2 UNIPOLAR &= ~ (1 << AIN_4_5_LSB); BIPOLAR |= (1 << AIN_4_5_LSB); RANGE &= ~ (1 << AIN_4_5_LSB); // UCH4/5=0, BCH4/5=1, RANGE4/5=0: AIN0/AIN1 differential input pair (+/-)(1/2)Vref, bipolar code (Full Scale = VREF, LSB = VREF/4096) #endif // AIN_4_5_DifferentialBipolarFSVref #if AIN_4_5_DifferentialBipolarFS2Vref //---------------------------------------- // ADC Channels AIN4, AIN5 = Differential Bipolar // Full Scale = 2 * VREF // Voltage per LSB count = VREF/2048 // AIN4, AIN5 are a Differential pair using Bipolar transfer function with range (+/-)Vref // AIN4 voltage must always be between 0 and VREF. // AIN5 voltage must always be between 0 and VREF. // // SELECT BIPOLAR register set PER CHANNEL BCH(X)/(X+1) TO 1 FOR BIPOLAR FULLY DIFFERENTIAL // SELECT RANGE register set PER CHANNEL PAIR RANGE(X)/(X+1) TO 1 +/-VREF+ UNIPOLAR &= ~ (1 << AIN_4_5_LSB); BIPOLAR |= (1 << AIN_4_5_LSB); RANGE |= (1 << AIN_4_5_LSB); // UCH4/5=0, BCH4/5=1, RANGE4/5=1: AIN0/AIN1 differential input pair (+/-)Vref, bipolar code (Full Scale = 2VREF, LSB = VREF/2048) #endif // AIN_4_5_DifferentialBipolarFS2Vref #if AIN_6_7_SingleEnded //---------------------------------------- // ADC Channels AIN6, AIN7 = Both Single-Ended, Unipolar // Full Scale = VREF // Voltage per LSB count = VREF/4096 // AIN6 is a Single-Ended input using Unipolar transfer function. // AIN7 is a Single-Ended input using Unipolar transfer function. // If PDIFF_COM_1, both are Pseudo-Differential with REF- as common. // AIN6 voltage must always be between 0 and VREF. // AIN7 voltage must always be between 0 and VREF. // // SELECT UNIPOLAR AND BIPOLAR register set PER CHANNEL UCH(X)/(X+1) AND BCH(X)/(X+1) TO 0 FOR SINGLE-ENDED SELECTION UNIPOLAR &= ~ (1 << AIN_6_7_LSB); BIPOLAR &= ~ (1 << AIN_6_7_LSB); RANGE &= ~ (1 << AIN_6_7_LSB); // UCH6/7=0, BCH6/7=0, RANGE6/7=0: AIN0/AIN1 two independent single-ended inputs, unipolar code (Full Scale = VREF, LSB = VREF/4096) #endif // AIN_6_7_SingleEnded #if AIN_6_7_DifferentialUnipolar //---------------------------------------- // ADC Channels AIN6, AIN7 = Differential Unipolar (AIN6 > AIN7) // Full Scale = VREF // Voltage per LSB count = VREF/4096 // AIN6, AIN7 are a Differential pair using Unipolar transfer function. // AIN6 voltage must always be between 0 and VREF. // AIN7 voltage must always be between 0 and VREF. // // SELECT UNIPOLAR register set PER CHANNEL UCH(X)/(X+1) TO 1 FOR UNIPOLAR UNIPOLAR |= (1 << AIN_6_7_LSB); BIPOLAR &= ~ (1 << AIN_6_7_LSB); RANGE &= ~ (1 << AIN_6_7_LSB); // UCH6/7=1, BCH6/7=0, RANGE6/7=0: AIN0/AIN1 differential input pair, unipolar code (AIN0>AIN1) (Full Scale = VREF, LSB = VREF/4096) #endif // AIN_6_7_DifferentialUnipolar #if AIN_6_7_DifferentialBipolarFSVref //---------------------------------------- // ADC Channels AIN6, AIN7 = Differential Bipolar // Full Scale = VREF // Voltage per LSB count = VREF/4096 // AIN6, AIN7 are a Differential pair using Bipolar transfer function with range (+/-)(1/2)Vref // AIN6 voltage must always be between 0 and VREF. // AIN7 voltage must always be between 0 and VREF. // // SELECT BIPOLAR register set PER CHANNEL BCH(X)/(X+1) TO 1 FOR BIPOLAR FULLY DIFFERENTIAL // SELECT RANGE register set PER CHANNEL PAIR RANGE(X)/(X+1) TO 0 +/-VREF+/2 UNIPOLAR &= ~ (1 << AIN_6_7_LSB); BIPOLAR |= (1 << AIN_6_7_LSB); RANGE &= ~ (1 << AIN_6_7_LSB); // UCH6/7=0, BCH6/7=1, RANGE6/7=0: AIN0/AIN1 differential input pair (+/-)(1/2)Vref, bipolar code (Full Scale = VREF, LSB = VREF/4096) #endif // AIN_6_7_DifferentialBipolarFSVref #if AIN_6_7_DifferentialBipolarFS2Vref //---------------------------------------- // ADC Channels AIN6, AIN7 = Differential Bipolar // Full Scale = 2 * VREF // Voltage per LSB count = VREF/2048 // AIN6, AIN7 are a Differential pair using Bipolar transfer function with range (+/-)Vref // AIN6 voltage must always be between 0 and VREF. // AIN7 voltage must always be between 0 and VREF. // // SELECT BIPOLAR register set PER CHANNEL BCH(X)/(X+1) TO 1 FOR BIPOLAR FULLY DIFFERENTIAL // SELECT RANGE register set PER CHANNEL PAIR RANGE(X)/(X+1) TO 1 +/-VREF+ UNIPOLAR &= ~ (1 << AIN_6_7_LSB); BIPOLAR |= (1 << AIN_6_7_LSB); RANGE |= (1 << AIN_6_7_LSB); // UCH6/7=0, BCH6/7=1, RANGE6/7=1: AIN0/AIN1 differential input pair (+/-)Vref, bipolar code (Full Scale = 2VREF, LSB = VREF/2048) #endif // AIN_6_7_DifferentialBipolarFS2Vref #if AIN_8_9_SingleEnded //---------------------------------------- // ADC Channels AIN8, AIN9 = Both Single-Ended, Unipolar // Full Scale = VREF // Voltage per LSB count = VREF/4096 // AIN8 is a Single-Ended input using Unipolar transfer function. // AIN9 is a Single-Ended input using Unipolar transfer function. // If PDIFF_COM_1, both are Pseudo-Differential with REF- as common. // AIN8 voltage must always be between 0 and VREF. // AIN9 voltage must always be between 0 and VREF. // // SELECT UNIPOLAR AND BIPOLAR register set PER CHANNEL UCH(X)/(X+1) AND BCH(X)/(X+1) TO 0 FOR SINGLE-ENDED SELECTION UNIPOLAR &= ~ (1 << AIN_8_9_LSB); BIPOLAR &= ~ (1 << AIN_8_9_LSB); RANGE &= ~ (1 << AIN_8_9_LSB); // UCH8/9=0, BCH8/9=0, RANGE8/9=0: AIN0/AIN1 two independent single-ended inputs, unipolar code (Full Scale = VREF, LSB = VREF/4096) #endif // AIN_8_9_SingleEnded #if AIN_8_9_DifferentialUnipolar //---------------------------------------- // ADC Channels AIN8, AIN9 = Differential Unipolar (AIN8 > AIN9) // Full Scale = VREF // Voltage per LSB count = VREF/4096 // AIN8, AIN9 are a Differential pair using Unipolar transfer function. // AIN8 voltage must always be between 0 and VREF. // AIN9 voltage must always be between 0 and VREF. // // SELECT UNIPOLAR register set PER CHANNEL UCH(X)/(X+1) TO 1 FOR UNIPOLAR UNIPOLAR |= (1 << AIN_8_9_LSB); BIPOLAR &= ~ (1 << AIN_8_9_LSB); RANGE &= ~ (1 << AIN_8_9_LSB); // UCH8/9=1, BCH8/9=0, RANGE8/9=0: AIN0/AIN1 differential input pair, unipolar code (AIN0>AIN1) (Full Scale = VREF, LSB = VREF/4096) #endif // AIN_8_9_DifferentialUnipolar #if AIN_8_9_DifferentialBipolarFSVref //---------------------------------------- // ADC Channels AIN8, AIN9 = Differential Bipolar // Full Scale = VREF // Voltage per LSB count = VREF/4096 // AIN8, AIN9 are a Differential pair using Bipolar transfer function with range (+/-)(1/2)Vref // AIN8 voltage must always be between 0 and VREF. // AIN9 voltage must always be between 0 and VREF. // // SELECT BIPOLAR register set PER CHANNEL BCH(X)/(X+1) TO 1 FOR BIPOLAR FULLY DIFFERENTIAL // SELECT RANGE register set PER CHANNEL PAIR RANGE(X)/(X+1) TO 0 +/-VREF+/2 UNIPOLAR &= ~ (1 << AIN_8_9_LSB); BIPOLAR |= (1 << AIN_8_9_LSB); RANGE &= ~ (1 << AIN_8_9_LSB); // UCH8/9=0, BCH8/9=1, RANGE8/9=0: AIN0/AIN1 differential input pair (+/-)(1/2)Vref, bipolar code (Full Scale = VREF, LSB = VREF/4096) #endif // AIN_8_9_DifferentialBipolarFSVref #if AIN_8_9_DifferentialBipolarFS2Vref //---------------------------------------- // ADC Channels AIN8, AIN9 = Differential Bipolar // Full Scale = 2 * VREF // Voltage per LSB count = VREF/2048 // AIN8, AIN9 are a Differential pair using Bipolar transfer function with range (+/-)Vref // AIN8 voltage must always be between 0 and VREF. // AIN9 voltage must always be between 0 and VREF. // // SELECT BIPOLAR register set PER CHANNEL BCH(X)/(X+1) TO 1 FOR BIPOLAR FULLY DIFFERENTIAL // SELECT RANGE register set PER CHANNEL PAIR RANGE(X)/(X+1) TO 1 +/-VREF+ UNIPOLAR &= ~ (1 << AIN_8_9_LSB); BIPOLAR |= (1 << AIN_8_9_LSB); RANGE |= (1 << AIN_8_9_LSB); // UCH8/9=0, BCH8/9=1, RANGE8/9=1: AIN0/AIN1 differential input pair (+/-)Vref, bipolar code (Full Scale = 2VREF, LSB = VREF/2048) #endif // AIN_8_9_DifferentialBipolarFS2Vref #if AIN_10_11_SingleEnded //---------------------------------------- // ADC Channels AIN10, AIN11 = Both Single-Ended, Unipolar // Full Scale = VREF // Voltage per LSB count = VREF/4096 // AIN10 is a Single-Ended input using Unipolar transfer function. // AIN11 is a Single-Ended input using Unipolar transfer function. // If PDIFF_COM_1, both are Pseudo-Differential with REF- as common. // AIN10 voltage must always be between 0 and VREF. // AIN11 voltage must always be between 0 and VREF. // // SELECT UNIPOLAR AND BIPOLAR register set PER CHANNEL UCH(X)/(X+1) AND BCH(X)/(X+1) TO 0 FOR SINGLE-ENDED SELECTION UNIPOLAR &= ~ (1 << AIN_10_11_LSB); BIPOLAR &= ~ (1 << AIN_10_11_LSB); RANGE &= ~ (1 << AIN_10_11_LSB); // UCH10/11=0, BCH10/11=0, RANGE10/11=0: AIN0/AIN1 two independent single-ended inputs, unipolar code (Full Scale = VREF, LSB = VREF/4096) #endif // AIN_10_11_SingleEnded #if AIN_10_11_DifferentialUnipolar //---------------------------------------- // ADC Channels AIN10, AIN11 = Differential Unipolar (AIN10 > AIN11) // Full Scale = VREF // Voltage per LSB count = VREF/4096 // AIN10, AIN11 are a Differential pair using Unipolar transfer function. // AIN10 voltage must always be between 0 and VREF. // AIN11 voltage must always be between 0 and VREF. // // SELECT UNIPOLAR register set PER CHANNEL UCH(X)/(X+1) TO 1 FOR UNIPOLAR UNIPOLAR |= (1 << AIN_10_11_LSB); BIPOLAR &= ~ (1 << AIN_10_11_LSB); RANGE &= ~ (1 << AIN_10_11_LSB); // UCH10/11=1, BCH10/11=0, RANGE10/11=0: AIN0/AIN1 differential input pair, unipolar code (AIN0>AIN1) (Full Scale = VREF, LSB = VREF/4096) #endif // AIN_10_11_DifferentialUnipolar #if AIN_10_11_DifferentialBipolarFSVref //---------------------------------------- // ADC Channels AIN10, AIN11 = Differential Bipolar // Full Scale = VREF // Voltage per LSB count = VREF/4096 // AIN10, AIN11 are a Differential pair using Bipolar transfer function with range (+/-)(1/2)Vref // AIN10 voltage must always be between 0 and VREF. // AIN11 voltage must always be between 0 and VREF. // // SELECT BIPOLAR register set PER CHANNEL BCH(X)/(X+1) TO 1 FOR BIPOLAR FULLY DIFFERENTIAL // SELECT RANGE register set PER CHANNEL PAIR RANGE(X)/(X+1) TO 0 +/-VREF+/2 UNIPOLAR &= ~ (1 << AIN_10_11_LSB); BIPOLAR |= (1 << AIN_10_11_LSB); RANGE &= ~ (1 << AIN_10_11_LSB); // UCH10/11=0, BCH10/11=1, RANGE10/11=0: AIN0/AIN1 differential input pair (+/-)(1/2)Vref, bipolar code (Full Scale = VREF, LSB = VREF/4096) #endif // AIN_10_11_DifferentialBipolarFSVref #if AIN_10_11_DifferentialBipolarFS2Vref //---------------------------------------- // ADC Channels AIN10, AIN11 = Differential Bipolar // Full Scale = 2 * VREF // Voltage per LSB count = VREF/2048 // AIN10, AIN11 are a Differential pair using Bipolar transfer function with range (+/-)Vref // AIN10 voltage must always be between 0 and VREF. // AIN11 voltage must always be between 0 and VREF. // // SELECT BIPOLAR register set PER CHANNEL BCH(X)/(X+1) TO 1 FOR BIPOLAR FULLY DIFFERENTIAL // SELECT RANGE register set PER CHANNEL PAIR RANGE(X)/(X+1) TO 1 +/-VREF+ UNIPOLAR &= ~ (1 << AIN_10_11_LSB); BIPOLAR |= (1 << AIN_10_11_LSB); RANGE |= (1 << AIN_10_11_LSB); // UCH10/11=0, BCH10/11=1, RANGE10/11=1: AIN0/AIN1 differential input pair (+/-)Vref, bipolar code (Full Scale = 2VREF, LSB = VREF/2048) #endif // AIN_10_11_DifferentialBipolarFS2Vref #if AIN_12_13_SingleEnded //---------------------------------------- // ADC Channels AIN12, AIN13 = Both Single-Ended, Unipolar // Full Scale = VREF // Voltage per LSB count = VREF/4096 // AIN12 is a Single-Ended input using Unipolar transfer function. // AIN13 is a Single-Ended input using Unipolar transfer function. // If PDIFF_COM_1, both are Pseudo-Differential with REF- as common. // AIN12 voltage must always be between 0 and VREF. // AIN13 voltage must always be between 0 and VREF. // // SELECT UNIPOLAR AND BIPOLAR register set PER CHANNEL UCH(X)/(X+1) AND BCH(X)/(X+1) TO 0 FOR SINGLE-ENDED SELECTION UNIPOLAR &= ~ (1 << AIN_12_13_LSB); BIPOLAR &= ~ (1 << AIN_12_13_LSB); RANGE &= ~ (1 << AIN_12_13_LSB); // UCH12/13=0, BCH12/13=0, RANGE12/13=0: AIN0/AIN1 two independent single-ended inputs, unipolar code (Full Scale = VREF, LSB = VREF/4096) #endif // AIN_12_13_SingleEnded #if AIN_12_13_DifferentialUnipolar //---------------------------------------- // ADC Channels AIN12, AIN13 = Differential Unipolar (AIN12 > AIN13) // Full Scale = VREF // Voltage per LSB count = VREF/4096 // AIN12, AIN13 are a Differential pair using Unipolar transfer function. // AIN12 voltage must always be between 0 and VREF. // AIN13 voltage must always be between 0 and VREF. // // SELECT UNIPOLAR register set PER CHANNEL UCH(X)/(X+1) TO 1 FOR UNIPOLAR UNIPOLAR |= (1 << AIN_12_13_LSB); BIPOLAR &= ~ (1 << AIN_12_13_LSB); RANGE &= ~ (1 << AIN_12_13_LSB); // UCH12/13=1, BCH12/13=0, RANGE12/13=0: AIN0/AIN1 differential input pair, unipolar code (AIN0>AIN1) (Full Scale = VREF, LSB = VREF/4096) #endif // AIN_12_13_DifferentialUnipolar #if AIN_12_13_DifferentialBipolarFSVref //---------------------------------------- // ADC Channels AIN12, AIN13 = Differential Bipolar // Full Scale = VREF // Voltage per LSB count = VREF/4096 // AIN12, AIN13 are a Differential pair using Bipolar transfer function with range (+/-)(1/2)Vref // AIN12 voltage must always be between 0 and VREF. // AIN13 voltage must always be between 0 and VREF. // // SELECT BIPOLAR register set PER CHANNEL BCH(X)/(X+1) TO 1 FOR BIPOLAR FULLY DIFFERENTIAL // SELECT RANGE register set PER CHANNEL PAIR RANGE(X)/(X+1) TO 0 +/-VREF+/2 UNIPOLAR &= ~ (1 << AIN_12_13_LSB); BIPOLAR |= (1 << AIN_12_13_LSB); RANGE &= ~ (1 << AIN_12_13_LSB); // UCH12/13=0, BCH12/13=1, RANGE12/13=0: AIN0/AIN1 differential input pair (+/-)(1/2)Vref, bipolar code (Full Scale = VREF, LSB = VREF/4096) #endif // AIN_12_13_DifferentialBipolarFSVref #if AIN_12_13_DifferentialBipolarFS2Vref //---------------------------------------- // ADC Channels AIN12, AIN13 = Differential Bipolar // Full Scale = 2 * VREF // Voltage per LSB count = VREF/2048 // AIN12, AIN13 are a Differential pair using Bipolar transfer function with range (+/-)Vref // AIN12 voltage must always be between 0 and VREF. // AIN13 voltage must always be between 0 and VREF. // // SELECT BIPOLAR register set PER CHANNEL BCH(X)/(X+1) TO 1 FOR BIPOLAR FULLY DIFFERENTIAL // SELECT RANGE register set PER CHANNEL PAIR RANGE(X)/(X+1) TO 1 +/-VREF+ UNIPOLAR &= ~ (1 << AIN_12_13_LSB); BIPOLAR |= (1 << AIN_12_13_LSB); RANGE |= (1 << AIN_12_13_LSB); // UCH12/13=0, BCH12/13=1, RANGE12/13=1: AIN0/AIN1 differential input pair (+/-)Vref, bipolar code (Full Scale = 2VREF, LSB = VREF/2048) #endif // AIN_12_13_DifferentialBipolarFS2Vref #if AIN_14_15_SingleEnded //---------------------------------------- // ADC Channels AIN14, AIN15 = Both Single-Ended, Unipolar // Full Scale = VREF // Voltage per LSB count = VREF/4096 // AIN14 is a Single-Ended input using Unipolar transfer function. // AIN15 is a Single-Ended input using Unipolar transfer function. // If PDIFF_COM_1, both are Pseudo-Differential with REF- as common. // AIN14 voltage must always be between 0 and VREF. // AIN15 voltage must always be between 0 and VREF. // // SELECT UNIPOLAR AND BIPOLAR register set PER CHANNEL UCH(X)/(X+1) AND BCH(X)/(X+1) TO 0 FOR SINGLE-ENDED SELECTION UNIPOLAR &= ~ (1 << AIN_14_15_LSB); BIPOLAR &= ~ (1 << AIN_14_15_LSB); RANGE &= ~ (1 << AIN_14_15_LSB); // UCH14/15=0, BCH14/15=0, RANGE14/15=0: AIN0/AIN1 two independent single-ended inputs, unipolar code (Full Scale = VREF, LSB = VREF/4096) #endif // AIN_14_15_SingleEnded #if AIN_14_15_DifferentialUnipolar //---------------------------------------- // ADC Channels AIN14, AIN15 = Differential Unipolar (AIN14 > AIN15) // Full Scale = VREF // Voltage per LSB count = VREF/4096 // AIN14, AIN15 are a Differential pair using Unipolar transfer function. // AIN14 voltage must always be between 0 and VREF. // AIN15 voltage must always be between 0 and VREF. // // SELECT UNIPOLAR register set PER CHANNEL UCH(X)/(X+1) TO 1 FOR UNIPOLAR UNIPOLAR |= (1 << AIN_14_15_LSB); BIPOLAR &= ~ (1 << AIN_14_15_LSB); RANGE &= ~ (1 << AIN_14_15_LSB); // UCH14/15=1, BCH14/15=0, RANGE14/15=0: AIN0/AIN1 differential input pair, unipolar code (AIN0>AIN1) (Full Scale = VREF, LSB = VREF/4096) #endif // AIN_14_15_DifferentialUnipolar #if AIN_14_15_DifferentialBipolarFSVref //---------------------------------------- // ADC Channels AIN14, AIN15 = Differential Bipolar // Full Scale = VREF // Voltage per LSB count = VREF/4096 // AIN14, AIN15 are a Differential pair using Bipolar transfer function with range (+/-)(1/2)Vref // AIN14 voltage must always be between 0 and VREF. // AIN15 voltage must always be between 0 and VREF. // // SELECT BIPOLAR register set PER CHANNEL BCH(X)/(X+1) TO 1 FOR BIPOLAR FULLY DIFFERENTIAL // SELECT RANGE register set PER CHANNEL PAIR RANGE(X)/(X+1) TO 0 +/-VREF+/2 UNIPOLAR &= ~ (1 << AIN_14_15_LSB); BIPOLAR |= (1 << AIN_14_15_LSB); RANGE &= ~ (1 << AIN_14_15_LSB); // UCH14/15=0, BCH14/15=1, RANGE14/15=0: AIN0/AIN1 differential input pair (+/-)(1/2)Vref, bipolar code (Full Scale = VREF, LSB = VREF/4096) #endif // AIN_14_15_DifferentialBipolarFSVref #if AIN_14_15_DifferentialBipolarFS2Vref //---------------------------------------- // ADC Channels AIN14, AIN15 = Differential Bipolar // Full Scale = 2 * VREF // Voltage per LSB count = VREF/2048 // AIN14, AIN15 are a Differential pair using Bipolar transfer function with range (+/-)Vref // AIN14 voltage must always be between 0 and VREF. // AIN15 voltage must always be between 0 and VREF. // // SELECT BIPOLAR register set PER CHANNEL BCH(X)/(X+1) TO 1 FOR BIPOLAR FULLY DIFFERENTIAL // SELECT RANGE register set PER CHANNEL PAIR RANGE(X)/(X+1) TO 1 +/-VREF+ UNIPOLAR &= ~ (1 << AIN_14_15_LSB); BIPOLAR |= (1 << AIN_14_15_LSB); RANGE |= (1 << AIN_14_15_LSB); // UCH14/15=0, BCH14/15=1, RANGE14/15=1: AIN0/AIN1 differential input pair (+/-)Vref, bipolar code (Full Scale = 2VREF, LSB = VREF/2048) #endif // AIN_14_15_DifferentialBipolarFS2Vref //---------------------------------------- // SPI write ADC CONFIGURATION register // Send SPI configuration to device SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern SPIoutputCS(0); // drive CS low SPIwrite16bits(ADC_CONFIGURATION); SPIoutputCS(1); // drive CS high //---------------------------------------- // SPI write UNIPOLAR BIPOLAR RANGE registers SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern SPIoutputCS(0); // drive CS low SPIwrite16bits(UNIPOLAR); SPIoutputCS(1); // drive CS high SPIoutputCS(0); // drive CS low SPIwrite16bits(BIPOLAR); SPIoutputCS(1); // drive CS high SPIoutputCS(0); // drive CS low SPIwrite16bits(RANGE); SPIoutputCS(1); // drive CS high //---------------------------------------- // SPI write CSCAN0 CSCAN1 registers SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern SPIoutputCS(0); // drive CS low SPIwrite16bits(CSCAN0); SPIoutputCS(1); // drive CS high SPIoutputCS(0); // drive CS low SPIwrite16bits(CSCAN1); SPIoutputCS(1); // drive CS high } //---------------------------------------- // ADC Channels AIN(channelId), AIN(channelId+1) = Both Single-Ended, Unipolar // Full Scale = VREF // Voltage per LSB count = VREF/4096 // AIN(channelId) is a Single-Ended input using Unipolar transfer function. // AIN(channelId+1) is a Single-Ended input using Unipolar transfer function. // If PDIFF_COM_1, both are Pseudo-Differential with REF- as common. // AIN(channelId) voltage must always be between 0 and VREF. // AIN(channelId+1) voltage must always be between 0 and VREF. // void MAX11131::Reconfigure_SingleEnded(int channelNumber_0_15) { //---------------------------------------- // UCH(ch)/(ch+1)=0, BCH(ch)/(ch+1)=0, RANGE(ch)/(ch+1)=0: // AIN(ch)/AIN(ch+1) two independent single-ended inputs, // unipolar code (Full Scale = VREF, LSB = VREF/4096) // const int channelPairIndex = channelNumber_0_15 / 2; const int bitmask = (1 << (10 - channelPairIndex)); UNIPOLAR &= ~ bitmask; BIPOLAR &= ~ bitmask; RANGE &= ~ bitmask; //---------------------------------------- // SPI write UNIPOLAR BIPOLAR RANGE registers SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern SPIoutputCS(0); // drive CS low SPIwrite16bits(UNIPOLAR); SPIoutputCS(1); // drive CS high SPIoutputCS(0); // drive CS low SPIwrite16bits(BIPOLAR); SPIoutputCS(1); // drive CS high SPIoutputCS(0); // drive CS low SPIwrite16bits(RANGE); SPIoutputCS(1); // drive CS high } //---------------------------------------- // ADC Channels AIN(channelId), AIN(channelId+1) = Differential Unipolar (AIN(channelId) > AIN(channelId+1)) // Full Scale = VREF // Voltage per LSB count = VREF/4096 // AIN(channelId), AIN(channelId+1) are a Differential pair using Unipolar transfer function. // AIN(channelId) voltage must always be between 0 and VREF. // AIN(channelId+1) voltage must always be between 0 and VREF. // void MAX11131::Reconfigure_DifferentialUnipolar(int channelNumber_0_15) { //---------------------------------------- // UCH(ch)/(ch+1)=1, BCH(ch)/(ch+1)=0, RANGE(ch)/(ch+1)=0: // AIN(ch)/AIN(ch+1) differential input pair, // unipolar code (AIN(ch)>AIN(ch+1)) (Full Scale = VREF, LSB = VREF/4096) // const int channelPairIndex = channelNumber_0_15 / 2; const int bitmask = (1 << (10 - channelPairIndex)); UNIPOLAR |= bitmask; BIPOLAR &= ~ bitmask; RANGE &= ~ bitmask; // UCH0/1=1, BCH0/1=0, RANGE0/1=0: AIN0/AIN1 differential input pair, unipolar code (AIN0>AIN1) (Full Scale = VREF, LSB = VREF/4096) //---------------------------------------- // SPI write UNIPOLAR BIPOLAR RANGE registers SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern SPIoutputCS(0); // drive CS low SPIwrite16bits(UNIPOLAR); SPIoutputCS(1); // drive CS high SPIoutputCS(0); // drive CS low SPIwrite16bits(BIPOLAR); SPIoutputCS(1); // drive CS high SPIoutputCS(0); // drive CS low SPIwrite16bits(RANGE); SPIoutputCS(1); // drive CS high } //---------------------------------------- // ADC Channels AIN(channelId), AIN(channelId+1) = Differential Bipolar // Full Scale = VREF // Voltage per LSB count = VREF/4096 // AIN(channelId), AIN(channelId+1) are a Differential pair using Bipolar transfer function with range (+/-)(1/2)Vref // AIN(channelId) voltage must always be between 0 and VREF. // AIN(channelId+1) voltage must always be between 0 and VREF. // void MAX11131::Reconfigure_DifferentialBipolarFSVref(int channelNumber_0_15) { //---------------------------------------- // UCH(ch)/(ch+1)=0, BCH(ch)/(ch+1)=1, RANGE(ch)/(ch+1)=0: // AIN(ch)/AIN(ch+1) differential input pair (+/-)(1/2)Vref, // bipolar code (Full Scale = VREF, LSB = VREF/4096) // const int channelPairIndex = channelNumber_0_15 / 2; const int bitmask = (1 << (10 - channelPairIndex)); UNIPOLAR &= ~ bitmask; BIPOLAR |= bitmask; RANGE &= ~ bitmask; //---------------------------------------- // SPI write UNIPOLAR BIPOLAR RANGE registers SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern SPIoutputCS(0); // drive CS low SPIwrite16bits(UNIPOLAR); SPIoutputCS(1); // drive CS high SPIoutputCS(0); // drive CS low SPIwrite16bits(BIPOLAR); SPIoutputCS(1); // drive CS high SPIoutputCS(0); // drive CS low SPIwrite16bits(RANGE); SPIoutputCS(1); // drive CS high } //---------------------------------------- // ADC Channels AIN(channelId), AIN(channelId+1) = Differential Bipolar // Full Scale = 2 * VREF // Voltage per LSB count = VREF/2048 // AIN(channelId), AIN(channelId+1) are a Differential pair using Bipolar transfer function with range (+/-)Vref // AIN(channelId) voltage must always be between 0 and VREF. // AIN(channelId+1) voltage must always be between 0 and VREF. // void MAX11131::Reconfigure_DifferentialBipolarFS2Vref(int channelNumber_0_15) { //---------------------------------------- // UCH(ch)/(ch+1)=0, BCH(ch)/(ch+1)=1, RANGE(ch)/(ch+1)=1: // AIN(ch)/AIN(ch+1) differential input pair (+/-)Vref, // bipolar code (Full Scale = 2VREF, LSB = VREF/2048) // const int channelPairIndex = channelNumber_0_15 / 2; const int bitmask = (1 << (10 - channelPairIndex)); UNIPOLAR &= ~ bitmask; BIPOLAR |= bitmask; RANGE |= bitmask; // UCH0/1=0, BCH0/1=1, RANGE0/1=1: AIN0/AIN1 differential input pair (+/-)Vref, bipolar code (Full Scale = 2VREF, LSB = VREF/2048) //---------------------------------------- // SPI write UNIPOLAR BIPOLAR RANGE registers SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern SPIoutputCS(0); // drive CS low SPIwrite16bits(UNIPOLAR); SPIoutputCS(1); // drive CS high SPIoutputCS(0); // drive CS low SPIwrite16bits(BIPOLAR); SPIoutputCS(1); // drive CS high SPIoutputCS(0); // drive CS low SPIwrite16bits(RANGE); SPIoutputCS(1); // drive CS high } //---------------------------------------- // SCAN_0000_NOP // // Shift 16 bits out of ADC, without changing configuration. // Note: @return data format depends on CHAN_ID bit: // "CH[3:0] DATA[11:0]" when CHAN_ID = 1, or // "0 DATA[11:0] x x x" when CHAN_ID = 0. int16_t MAX11131::ScanRead(void) { //---------------------------------------- // Read SPI data from device while MOSI (Maxim DIN) is 0. Effectively ADC_MODE_CONTROL SCAN[3:0] = SCAN_0000_NOP = 0 SPI_MOSI_Semantic = 0; // 0:Nothing 1:regWrite 2:sampleSetPattern SPIoutputCS(0); // drive CS low int16_t misoData16 = SPIread16bits(); SPIoutputCS(1); // drive CS high // For external clock modes, the data format returned depends on the CHAN_ID bit. // when CHAN_ID = 0: misoData16 = 0 DATA[11:0] x x x // when CHAN_ID = 1: misoData16 = CH[3:0] DATA[11:0] // For internal clock modes, the data format always includes the channel address. // misoData16 = CH[3:0] DATA[11:0] return misoData16; } //---------------------------------------- // SCAN_0000_NOP // // Read raw ADC codes from device into AINcode[] and RAW_misoData16[]. // If internal clock mode with SWCNV=0, measurements will be triggered using CNVST pin. // // @pre one of the Scan functions was called, setting NumWords // @post RAW_misoData16[index] contains the raw SPI Master-In,Slave-Out data // @post AINcode[NUM_CHANNELS] contains the latest readings in LSBs // void MAX11131::ReadAINcode(void) { //---------------------------------------- // loop index for RAW_misoData16[SAMPLESET_MAX_ENTRIES]; int index; //---------------------------------------- // If internal clock mode with SWCNV=0, trigger measurement using CNVST pin and wait for EOC pin. if (isExternalClock == 0) { if (swcnv_0_1 == 0) { // SWCNV=0: trigger measurement by driving CNVST/AIN14 pin low // for a minimum active-low pulse duration of 5ns. (AIN14 is not available) // One CNVST pulse scans all requested channels and stores the results in the FIFO. CNVSToutputPulseLow(); } // wait for EOC low (internal clock mode end of conversion) EOCinputWaitUntilLow(); } //---------------------------------------- // Read raw ADC codes from device into AINcode[] and RAW_misoData16[]. // For external clock modes, the data format returned depends on the CHAN_ID bit. // when CHAN_ID = 0: misoData16 = 0 DATA[11:0] x x x // when CHAN_ID = 1: misoData16 = CH[3:0] DATA[11:0] // For internal clock modes, the data format always includes the channel address. // misoData16 = CH[3:0] DATA[11:0] switch(ScanMode) { //---------------------------------------- // read data words // For internal clock modes, the data format always includes the channel address. // misoData16 = CH[3:0] DATA[11:0] case SCAN_0000_NOP: case SCAN_0011_StandardInternalClock: case SCAN_0101_UpperInternalClock: case SCAN_0111_CustomInternalClock: default: for (index = 0; index < NumWords; index++) { RAW_misoData16[index] = ScanRead(); // For internal clock modes, the data format always includes the channel address. // misoData16 = CH[3:0] DATA[11:0] int16_t value_u12 = (RAW_misoData16[index] & 0x0FFF); int channelId = ((RAW_misoData16[index] >> 12) & 0x000F); AINcode[channelId] = value_u12; } break; //---------------------------------------- // read data words // For external clock modes, the data format returned depends on the CHAN_ID bit. // when CHAN_ID = 0: misoData16 = 0 DATA[11:0] x x x // when CHAN_ID = 1: misoData16 = CH[3:0] DATA[11:0] // For internal clock modes, the data format always includes the channel address. // misoData16 = CH[3:0] DATA[11:0] case SCAN_0001_Manual: case SCAN_0100_StandardExternalClock: case SCAN_0110_UpperExternalClock: case SCAN_1000_CustomExternalClock: case SCAN_1001_SampleSetExternalClock: if (chan_id_0_1 != 0) { for (index = 0; index < NumWords; index++) { RAW_misoData16[index] = ScanRead(); // For internal clock modes, the data format always includes the channel address. // misoData16 = CH[3:0] DATA[11:0] int16_t value_u12 = (RAW_misoData16[index] & 0x0FFF); int channelId = ((RAW_misoData16[index] >> 12) & 0x000F); AINcode[channelId] = value_u12; } } else { for (index = 0; index < NumWords; index++) { RAW_misoData16[index] = ScanRead(); int16_t value_u12 = ((RAW_misoData16[index] >> 3) & 0x0FFF); int channelId = channelNumber_0_15; AINcode[channelId] = value_u12; } } break; //---------------------------------------- // read data words and calculate mean, stddev case SCAN_0010_Repeat: // ScanRead_nWords_chanID_mean(NumWords); // TODO1: missing function // was this function AINcode_print_value_chanID_mean(int nWords) in main? // But this function prints to standard output so can't be inside the driver. for (index = 0; index < NumWords; index++) { RAW_misoData16[index] = ScanRead(); } break; } } //---------------------------------------- // Sign-Extend a right-aligned MAX11131 code into a signed 2's complement value. // Supports the bipolar transfer functions. // @param[in] value_u12: raw 12-bit MAX11131 code (right justified). // @return sign-extended 2's complement value. // int32_t MAX11131::TwosComplementValue(uint32_t regValue) { const uint16_t SIGN_BIT_12BIT = 0x0800; const uint16_t FULL_SCALE_CODE_12BIT = 0x0fff; if (((regValue & SIGN_BIT_12BIT) != 0) && !((regValue & (SIGN_BIT_12BIT << 1)) != 0)) { // (bSignBitNegative && !bExtendedSignBitNegative) // Twos_Complement negative value int32_t Offset_regValue = (int32_t)(regValue - (FULL_SCALE_CODE_12BIT + 1)); return Offset_regValue; } // Twos_Complement positive value or zero return (int32_t)regValue; } //---------------------------------------- // Return the physical voltage corresponding to MAX11131 code. // Does not perform any offset or gain correction. // @pre VRef = Voltage of REF input, in Volts // @param[in] value_u12: raw 12-bit MAX11131 code (right justified). // @param[in] channelId: AIN channel number. // @return physical voltage corresponding to MAX11131 code. // double MAX11131::VoltageOfCode(int16_t value_u12, int channelId) { int channelPairIndex = channelId / 2; // format: 1 0 0 0 1 UCH0/1 UCH2/3 UCH4/5 UCH6/7 UCH8/9 UCH10/11 UCH12/13 UCH14/15 PDIFF_COM x x int UCHn = (UNIPOLAR >> (10 - channelPairIndex)) & 0x01; int BCHn = (BIPOLAR >> (10 - channelPairIndex)) & 0x01; int RANGEn = (RANGE >> (10 - channelPairIndex)) & 0x01; if (UCHn) { // UCH0/1=1, BCH0/1=0, RANGE0/1=0: AIN0/AIN1 differential input pair, unipolar code (AIN0>AIN1) (Full Scale = VREF, LSB = VREF/4096) return (value_u12 * VRef / 4096); } else { if (BCHn) { if (RANGEn) { // UCH0/1=0, BCH0/1=1, RANGE0/1=1: AIN0/AIN1 differential input pair (+/-)Vref, bipolar code (Full Scale = 2VREF, LSB = VREF/2048) return (TwosComplementValue(value_u12) * VRef / 2048); } else { // UCH0/1=0, BCH0/1=1, RANGE0/1=0: AIN0/AIN1 differential input pair (+/-)(1/2)Vref, bipolar code (Full Scale = VREF, LSB = VREF/4096) return (TwosComplementValue(value_u12) * VRef / 4096); } } else { // UCH0/1=0, BCH0/1=0, RANGE0/1=0: AIN0/AIN1 two independent single-ended inputs, unipolar code (Full Scale = VREF, LSB = VREF/4096) return (value_u12 * VRef / 4096); } } } //---------------------------------------- // SCAN_0001_Manual // // Measure ADC channel channelNumber_0_15 once. // External clock mode. // @param[in] channelNumber_0_15: AIN Channel Number // @param[in] PowerManagement_0_2: 0=Normal, 1=AutoShutdown, 2=AutoStandby // @param[in] chan_id_0_1: ADC_MODE_CONTROL.CHAN_ID // @return number of ScanRead() words needed to retrieve the data. // For external clock modes, the data format depends on CHAN_ID. // when CHAN_ID = 0: misoData16 = 0 DATA[11:0] x x x // when CHAN_ID = 1: misoData16 = CH[3:0] DATA[11:0] // int MAX11131::ScanManual(void) { //---------------------------------------- // define write-only register ADC_MODE_CONTROL ADC_MODE_CONTROL = 0; //!< mosiData16 0x0000..0x7FFF format: 0 SCAN[3:0] CHSEL[3:0] RESET[1:0] PM[1:0] CHAN_ID SWCNV 0 const int SCAN_LSB = 11; const int SCAN_BITS = 0x0F; //!< ADC_MODE_CONTROL.SCAN[3:0] ADC Scan Control (command) const int CHSEL_LSB = 7; const int CHSEL_BITS = 0x0F; //!< ADC_MODE_CONTROL.CHSEL[3:0] Analog Input Channel Select AIN0..AIN15 const int RESET_LSB = 5; const int RESET_BITS = 0x03; //!< ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved const int PM_LSB = 3; const int PM_BITS = 0x03; //!< ADC_MODE_CONTROL.PM[1:0] Power Management 0=Normal, 1=AutoShutdown, 2=AutoStandby 3=reserved const int CHAN_ID_LSB = 2; const int CHAN_ID_BITS = 0x01; //!< ADC_MODE_CONTROL.CHAN_ID const int SWCNV_LSB = 1; const int SWCNV_BITS = 0x01; //!< ADC_MODE_CONTROL.SWCNV //---------------------------------------- // Apply a soft reset when changing from internal to external clock mode. int needFIFOreset = (isExternalClock != 1); if (needFIFOreset) { // Apply a soft reset when changing from internal to external clock mode. ADC_MODE_CONTROL = ((1 & RESET_BITS) << RESET_LSB); // ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved // Send SPI configuration to device SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern SPIoutputCS(0); // drive CS low SPIwrite16bits(ADC_MODE_CONTROL); SPIoutputCS(1); // drive CS high ADC_MODE_CONTROL = 0; } //---------------------------------------- // number of words to read NumWords = 1; //---------------------------------------- // External Clock Mode isExternalClock = 1; //---------------------------------------- // update device driver global variable ScanMode = SCAN_0001_Manual; //---------------------------------------- // ADC MODE CONTROL register set SCAN[3:0] TO SCAN_0001_Manual = 1 //~ const int SCAN_0001_Manual = 1; // replaced local const with enum ADC_MODE_CONTROL |= ((SCAN_0001_Manual & SCAN_BITS) << SCAN_LSB); //---------------------------------------- // ADC MODE CONTROL register set CHSEL[3:0] TO channel number ADC_MODE_CONTROL |= ((channelNumber_0_15 & CHSEL_BITS) << CHSEL_LSB); //---------------------------------------- // ADC MODE CONTROL REGISTER SELECT THE PM[1:0] BITS ADC_MODE_CONTROL |= ((PowerManagement_0_2 & PM_BITS) << PM_LSB); //---------------------------------------- // ADC MODE CONTROL REGISTER SELECT THE CHAN_ID BIT // (applicable to external clock mode only) // For external clock modes, the data format returned depends on the CHAN_ID bit. // when CHAN_ID = 0: misoData16 = 0 DATA[11:0] x x x // when CHAN_ID = 1: misoData16 = CH[3:0] DATA[11:0] // For internal clock modes, the data format always includes the channel address. // misoData16 = CH[3:0] DATA[11:0] ADC_MODE_CONTROL |= ((chan_id_0_1 & CHAN_ID_BITS) << CHAN_ID_LSB); //---------------------------------------- // SPI write ADC MODE CONTROL register // Send SPI configuration to device SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern SPIoutputCS(0); // drive CS low SPIwrite16bits(ADC_MODE_CONTROL); SPIoutputCS(1); // drive CS high //---------------------------------------- // return number of words to read return NumWords; } //---------------------------------------- // SCAN_0010_Repeat // // Measure ADC channel channelNumber_0_15 repeatedly with averaging. // Internal clock mode. // @param[in] channelNumber_0_15: AIN Channel Number // @param[in] average_0_4_8_16_32: Number of samples averaged per ScanRead() word. // average_0_4_8_16_32=0 to disable averaging. // @param[in] nscan_4_8_12_16: Number of ScanRead() words to report. // @param[in] swcnv_0_1: ADC_MODE_CONTROL.SWCNV // SWCNV=0: trigger measurement by driving CNVST pin low. // Minimum active-low pulse duration of 5ns. (AIN14 is not available) // SWCNV=1: trigger measurement on SPI CS rising edge. // CS must be held low for minimum of 17 SCLK cycles. // CNVST pin is not used. (AIN14 is available) // @param[in] PowerManagement_0_2: 0=Normal, 1=AutoShutdown, 2=AutoStandby // @return number of ScanRead() words needed to retrieve the data. // For internal clock modes, the data format always includes the channel address. // misoData16 = CH[3:0] DATA[11:0] // int MAX11131::ScanRepeat(void) { //---------------------------------------- // number of words to read NumWords = (nscan_4_8_12_16); //---------------------------------------- // Internal Clock Mode isExternalClock = 0; //---------------------------------------- // update device driver global variable ScanMode = SCAN_0010_Repeat; //---------------------------------------- // define write-only register ADC_MODE_CONTROL ADC_MODE_CONTROL = 0; //!< mosiData16 0x0000..0x7FFF format: 0 SCAN[3:0] CHSEL[3:0] RESET[1:0] PM[1:0] CHAN_ID SWCNV 0 const int SCAN_LSB = 11; const int SCAN_BITS = 0x0F; //!< ADC_MODE_CONTROL.SCAN[3:0] ADC Scan Control (command) const int CHSEL_LSB = 7; const int CHSEL_BITS = 0x0F; //!< ADC_MODE_CONTROL.CHSEL[3:0] Analog Input Channel Select AIN0..AIN15 const int RESET_LSB = 5; const int RESET_BITS = 0x03; //!< ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved const int PM_LSB = 3; const int PM_BITS = 0x03; //!< ADC_MODE_CONTROL.PM[1:0] Power Management 0=Normal, 1=AutoShutdown, 2=AutoStandby 3=reserved const int CHAN_ID_LSB = 2; const int CHAN_ID_BITS = 0x01; //!< ADC_MODE_CONTROL.CHAN_ID const int SWCNV_LSB = 1; const int SWCNV_BITS = 0x01; //!< ADC_MODE_CONTROL.SWCNV //---------------------------------------- // define write-only register ADC_CONFIGURATION ADC_CONFIGURATION = 0x8000; //!< mosiData16 0x8000..0x87FF format: 1 0 0 0 0 REFSEL AVGON NAVG[1:0] NSCAN[1:0] SPM[1:0] ECHO 0 0 const int REFSEL_LSB = 10; const int REFSEL_BITS = 0x01; // ADC_CONFIGURATION.REFSEL const int AVGON_LSB = 9; const int AVGON_BITS = 0x01; // ADC_CONFIGURATION.AVGON const int NAVG_LSB = 7; const int NAVG_BITS = 0x03; // ADC_CONFIGURATION.NAVG[1:0] const int NSCAN_LSB = 5; const int NSCAN_BITS = 0x03; // ADC_CONFIGURATION.NSCAN[1:0] const int SPM_LSB = 3; const int SPM_BITS = 0x03; // ADC_CONFIGURATION.SPM[1:0] const int ECHO_LSB = 2; const int ECHO_BITS = 0x01; // ADC_CONFIGURATION.ECHO //---------------------------------------- // if average, ADC CONFIGURATION register set AVG and NAVG[1:0] // (applicable to internal clock mode only) // if average, ADC CONFIGURATION register set AVG ON BIT TO 1 // if average, ADC CONFIGURATION register set NAVG[1:0] TO N if (average_0_4_8_16_32 == 4) { // Enable Averaging of 4 samples (AVGON=1, NAVG[1:0]=0) ADC_CONFIGURATION |= ((1 & AVGON_BITS) << AVGON_LSB); ADC_CONFIGURATION &= ~ (( NAVG_BITS) << NAVG_LSB); ADC_CONFIGURATION |= ((0 & NAVG_BITS) << NAVG_LSB); } else if (average_0_4_8_16_32 == 8) { // Enable Averaging of 8 samples (AVGON=1, NAVG[1:0]=1) ADC_CONFIGURATION |= ((1 & AVGON_BITS) << AVGON_LSB); ADC_CONFIGURATION &= ~ (( NAVG_BITS) << NAVG_LSB); ADC_CONFIGURATION |= ((1 & NAVG_BITS) << NAVG_LSB); } else if (average_0_4_8_16_32 == 16) { // Enable Averaging of 16 samples (AVGON=1, NAVG[1:0]=2) ADC_CONFIGURATION |= ((1 & AVGON_BITS) << AVGON_LSB); ADC_CONFIGURATION &= ~ (( NAVG_BITS) << NAVG_LSB); ADC_CONFIGURATION |= ((2 & NAVG_BITS) << NAVG_LSB); } else if (average_0_4_8_16_32 == 32) { // Enable Averaging of 32 samples (AVGON=1, NAVG[1:0]=3) ADC_CONFIGURATION |= ((1 & AVGON_BITS) << AVGON_LSB); ADC_CONFIGURATION &= ~ (( NAVG_BITS) << NAVG_LSB); ADC_CONFIGURATION |= ((3 & NAVG_BITS) << NAVG_LSB); } else { // Disable Averaging (AVGON=0, NAVG[1:0]=0) ADC_CONFIGURATION &= ~ (( AVGON_BITS) << AVGON_LSB); ADC_CONFIGURATION &= ~ (( NAVG_BITS) << NAVG_LSB); } //---------------------------------------- // ADC CONFIGURATION register set NSCAN[1:0] for scan count // (applicable to SCAN_0010_Repeat only) if (nscan_4_8_12_16 == 4) { // Set scan count 4 ADC_CONFIGURATION &= ~ (( NSCAN_BITS) << NSCAN_LSB); ADC_CONFIGURATION |= ((0 & NSCAN_BITS) << NSCAN_LSB); } else if (nscan_4_8_12_16 == 8) { // Set scan count 8 ADC_CONFIGURATION &= ~ (( NSCAN_BITS) << NSCAN_LSB); ADC_CONFIGURATION |= ((1 & NSCAN_BITS) << NSCAN_LSB); } else if (nscan_4_8_12_16 == 12) { // Set scan count 12 ADC_CONFIGURATION &= ~ (( NSCAN_BITS) << NSCAN_LSB); ADC_CONFIGURATION |= ((2 & NSCAN_BITS) << NSCAN_LSB); } else if (nscan_4_8_12_16 == 16) { // Set scan count 16 ADC_CONFIGURATION &= ~ (( NSCAN_BITS) << NSCAN_LSB); ADC_CONFIGURATION |= ((3 & NSCAN_BITS) << NSCAN_LSB); } //---------------------------------------- // SPI write ADC CONFIGURATION register // Send SPI configuration to device SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern SPIoutputCS(0); // drive CS low SPIwrite16bits(ADC_CONFIGURATION); SPIoutputCS(1); // drive CS high //---------------------------------------- // Reset FIFO: ADC_MODE_CONTROL.RESET[1:0] = 1 Apply a soft reset when changing from internal to external clock mode. ADC_MODE_CONTROL &= ~ (( RESET_BITS) << RESET_LSB); // ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved ADC_MODE_CONTROL |= ((1 & RESET_BITS) << RESET_LSB); // ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved //---------------------------------------- // ADC MODE CONTROL register set SCAN[3:0] TO SCAN_0010_Repeat = 2 //~ const int SCAN_0010_Repeat = 2; // replaced local const with enum ADC_MODE_CONTROL |= ((SCAN_0010_Repeat & SCAN_BITS) << SCAN_LSB); //---------------------------------------- // ADC MODE CONTROL register set CHSEL[3:0] TO channel number ADC_MODE_CONTROL |= ((channelNumber_0_15 & CHSEL_BITS) << CHSEL_LSB); //---------------------------------------- // ADC MODE CONTROL REGISTER SELECT THE PM[1:0] BITS ADC_MODE_CONTROL |= ((PowerManagement_0_2 & PM_BITS) << PM_LSB); //---------------------------------------- // ADC MODE CONTROL register set SWCNV if CNVST pin is not used // ADC MODE CONTROL REGISTER SELECT THE RIGHT SWCNV BIT // (applicable to internal clock mode only) // SWCNV=1: trigger measurement on SPI CS rising edge; CNVST pin is not used. (AIN14 is available) // SWCNV=0: trigger measurement by driving CNVST pin low for a minimum active-low pulse duration of 5ns. (AIN14 is not available) if (swcnv_0_1) { ADC_MODE_CONTROL |= ((swcnv_0_1 & SWCNV_BITS) << SWCNV_LSB); } else { ADC_MODE_CONTROL &= ~ (( SWCNV_BITS) << SWCNV_LSB); } //---------------------------------------- // SPI write ADC MODE CONTROL register // If SWCNV=1 then CS must be held low for at least 17 SCLK cycles. // Send SPI configuration to device SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern SPIoutputCS(0); // drive CS low if (swcnv_0_1) { // If SWCNV=1 then CS must be held low for at least 17 SCLK cycles. // NOTE: Figure 7 Internal Conversions with SWCNV=1 has an error, the 17th SCLK is mislabeled as "16" should be "17". SPIwrite24bits(ADC_MODE_CONTROL, 0); } else { SPIwrite16bits(ADC_MODE_CONTROL); } SPIoutputCS(1); // drive CS high //---------------------------------------- // return number of words to read return NumWords; } //---------------------------------------- // SCAN_0011_StandardInternalClock // // Measure ADC channels in sequence from AIN0 to channelNumber_0_15. // Internal clock mode. // @param[in] channelNumber_0_15: AIN Channel Number // @param[in] average_0_4_8_16_32: Number of samples averaged per ScanRead() word. // average_0_4_8_16_32=0 to disable averaging. // @param[in] PowerManagement_0_2: 0=Normal, 1=AutoShutdown, 2=AutoStandby // @param[in] swcnv_0_1: ADC_MODE_CONTROL.SWCNV // SWCNV=0: trigger measurement by driving CNVST pin low. // Minimum active-low pulse duration of 5ns. (AIN14 is not available) // SWCNV=1: trigger measurement on SPI CS rising edge. // CS must be held low for minimum of 17 SCLK cycles. // CNVST pin is not used. (AIN14 is available) // @return number of ScanRead() words needed to retrieve the data. // For internal clock modes, the data format always includes the channel address. // misoData16 = CH[3:0] DATA[11:0] // int MAX11131::ScanStandardInternalClock(void) { //---------------------------------------- // number of words to read NumWords = (1 + channelNumber_0_15); //---------------------------------------- // Internal Clock Mode isExternalClock = 0; //---------------------------------------- // update device driver global variable ScanMode = SCAN_0011_StandardInternalClock; //---------------------------------------- // define write-only register ADC_MODE_CONTROL ADC_MODE_CONTROL = 0; //!< mosiData16 0x0000..0x7FFF format: 0 SCAN[3:0] CHSEL[3:0] RESET[1:0] PM[1:0] CHAN_ID SWCNV 0 const int SCAN_LSB = 11; const int SCAN_BITS = 0x0F; //!< ADC_MODE_CONTROL.SCAN[3:0] ADC Scan Control (command) const int CHSEL_LSB = 7; const int CHSEL_BITS = 0x0F; //!< ADC_MODE_CONTROL.CHSEL[3:0] Analog Input Channel Select AIN0..AIN15 const int RESET_LSB = 5; const int RESET_BITS = 0x03; //!< ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved const int PM_LSB = 3; const int PM_BITS = 0x03; //!< ADC_MODE_CONTROL.PM[1:0] Power Management 0=Normal, 1=AutoShutdown, 2=AutoStandby 3=reserved const int CHAN_ID_LSB = 2; const int CHAN_ID_BITS = 0x01; //!< ADC_MODE_CONTROL.CHAN_ID const int SWCNV_LSB = 1; const int SWCNV_BITS = 0x01; //!< ADC_MODE_CONTROL.SWCNV //---------------------------------------- // define write-only register ADC_CONFIGURATION ADC_CONFIGURATION = 0x8000; //!< mosiData16 0x8000..0x87FF format: 1 0 0 0 0 REFSEL AVGON NAVG[1:0] NSCAN[1:0] SPM[1:0] ECHO 0 0 const int REFSEL_LSB = 10; const int REFSEL_BITS = 0x01; // ADC_CONFIGURATION.REFSEL const int AVGON_LSB = 9; const int AVGON_BITS = 0x01; // ADC_CONFIGURATION.AVGON const int NAVG_LSB = 7; const int NAVG_BITS = 0x03; // ADC_CONFIGURATION.NAVG[1:0] const int NSCAN_LSB = 5; const int NSCAN_BITS = 0x03; // ADC_CONFIGURATION.NSCAN[1:0] const int SPM_LSB = 3; const int SPM_BITS = 0x03; // ADC_CONFIGURATION.SPM[1:0] const int ECHO_LSB = 2; const int ECHO_BITS = 0x01; // ADC_CONFIGURATION.ECHO //---------------------------------------- // if average, ADC CONFIGURATION register set AVG and NAVG[1:0] // (applicable to internal clock mode only) // if average, ADC CONFIGURATION register set AVG ON BIT TO 1 // if average, ADC CONFIGURATION register set NAVG[1:0] TO N if (average_0_4_8_16_32 == 4) { // Enable Averaging of 4 samples (AVGON=1, NAVG[1:0]=0) ADC_CONFIGURATION |= ((1 & AVGON_BITS) << AVGON_LSB); ADC_CONFIGURATION &= ~ (( NAVG_BITS) << NAVG_LSB); ADC_CONFIGURATION |= ((0 & NAVG_BITS) << NAVG_LSB); } else if (average_0_4_8_16_32 == 8) { // Enable Averaging of 8 samples (AVGON=1, NAVG[1:0]=1) ADC_CONFIGURATION |= ((1 & AVGON_BITS) << AVGON_LSB); ADC_CONFIGURATION &= ~ (( NAVG_BITS) << NAVG_LSB); ADC_CONFIGURATION |= ((1 & NAVG_BITS) << NAVG_LSB); } else if (average_0_4_8_16_32 == 16) { // Enable Averaging of 16 samples (AVGON=1, NAVG[1:0]=2) ADC_CONFIGURATION |= ((1 & AVGON_BITS) << AVGON_LSB); ADC_CONFIGURATION &= ~ (( NAVG_BITS) << NAVG_LSB); ADC_CONFIGURATION |= ((2 & NAVG_BITS) << NAVG_LSB); } else if (average_0_4_8_16_32 == 32) { // Enable Averaging of 32 samples (AVGON=1, NAVG[1:0]=3) ADC_CONFIGURATION |= ((1 & AVGON_BITS) << AVGON_LSB); ADC_CONFIGURATION &= ~ (( NAVG_BITS) << NAVG_LSB); ADC_CONFIGURATION |= ((3 & NAVG_BITS) << NAVG_LSB); } else { // Disable Averaging (AVGON=0, NAVG[1:0]=0) ADC_CONFIGURATION &= ~ (( AVGON_BITS) << AVGON_LSB); ADC_CONFIGURATION &= ~ (( NAVG_BITS) << NAVG_LSB); } //---------------------------------------- // SPI write ADC CONFIGURATION register // Send SPI configuration to device SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern SPIoutputCS(0); // drive CS low SPIwrite16bits(ADC_CONFIGURATION); SPIoutputCS(1); // drive CS high //---------------------------------------- // Reset FIFO: ADC_MODE_CONTROL.RESET[1:0] = 1 Apply a soft reset when changing from internal to external clock mode. ADC_MODE_CONTROL &= ~ (( RESET_BITS) << RESET_LSB); // ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved ADC_MODE_CONTROL |= ((1 & RESET_BITS) << RESET_LSB); // ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved //---------------------------------------- // ADC MODE CONTROL register set SCAN[3:0] TO SCAN_0011_StandardInternalClock = 3 //~ const int SCAN_0011_StandardInternalClock = 3; // replaced local const with enum ADC_MODE_CONTROL |= ((SCAN_0011_StandardInternalClock & SCAN_BITS) << SCAN_LSB); //---------------------------------------- // ADC MODE CONTROL register set CHSEL[3:0] TO channel number ADC_MODE_CONTROL |= ((channelNumber_0_15 & CHSEL_BITS) << CHSEL_LSB); //---------------------------------------- // ADC MODE CONTROL REGISTER SELECT THE PM[1:0] BITS ADC_MODE_CONTROL |= ((PowerManagement_0_2 & PM_BITS) << PM_LSB); //---------------------------------------- // ADC MODE CONTROL register set SWCNV if CNVST pin is not used // ADC MODE CONTROL REGISTER SELECT THE RIGHT SWCNV BIT // (applicable to internal clock mode only) // SWCNV=1: trigger measurement on SPI CS rising edge; CNVST pin is not used. (AIN14 is available) // SWCNV=0: trigger measurement by driving CNVST pin low for a minimum active-low pulse duration of 5ns. (AIN14 is not available) if (swcnv_0_1) { ADC_MODE_CONTROL |= ((swcnv_0_1 & SWCNV_BITS) << SWCNV_LSB); } else { ADC_MODE_CONTROL &= ~ (( SWCNV_BITS) << SWCNV_LSB); } //---------------------------------------- // SPI write ADC MODE CONTROL register // If SWCNV=1 then CS must be held low for at least 17 SCLK cycles. // Send SPI configuration to device SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern SPIoutputCS(0); // drive CS low if (swcnv_0_1) { // If SWCNV=1 then CS must be held low for at least 17 SCLK cycles. // NOTE: Figure 7 Internal Conversions with SWCNV=1 has an error, the 17th SCLK is mislabeled as "16" should be "17". SPIwrite24bits(ADC_MODE_CONTROL, 0); } else { SPIwrite16bits(ADC_MODE_CONTROL); } SPIoutputCS(1); // drive CS high //---------------------------------------- // return number of words to read return NumWords; } //---------------------------------------- // SCAN_0100_StandardExternalClock // // Measure ADC channels in sequence from AIN0 to channelNumber_0_15. // External clock mode. // @param[in] channelNumber_0_15: AIN Channel Number // @param[in] PowerManagement_0_2: 0=Normal, 1=AutoShutdown, 2=AutoStandby // @param[in] chan_id_0_1: ADC_MODE_CONTROL.CHAN_ID // @return number of ScanRead() words needed to retrieve the data. // For external clock modes, the data format depends on CHAN_ID. // when CHAN_ID = 0: misoData16 = 0 DATA[11:0] x x x // when CHAN_ID = 1: misoData16 = CH[3:0] DATA[11:0] // int MAX11131::ScanStandardExternalClock(void) { //---------------------------------------- // define write-only register ADC_MODE_CONTROL ADC_MODE_CONTROL = 0; //!< mosiData16 0x0000..0x7FFF format: 0 SCAN[3:0] CHSEL[3:0] RESET[1:0] PM[1:0] CHAN_ID SWCNV 0 const int SCAN_LSB = 11; const int SCAN_BITS = 0x0F; //!< ADC_MODE_CONTROL.SCAN[3:0] ADC Scan Control (command) const int CHSEL_LSB = 7; const int CHSEL_BITS = 0x0F; //!< ADC_MODE_CONTROL.CHSEL[3:0] Analog Input Channel Select AIN0..AIN15 const int RESET_LSB = 5; const int RESET_BITS = 0x03; //!< ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved const int PM_LSB = 3; const int PM_BITS = 0x03; //!< ADC_MODE_CONTROL.PM[1:0] Power Management 0=Normal, 1=AutoShutdown, 2=AutoStandby 3=reserved const int CHAN_ID_LSB = 2; const int CHAN_ID_BITS = 0x01; //!< ADC_MODE_CONTROL.CHAN_ID const int SWCNV_LSB = 1; const int SWCNV_BITS = 0x01; //!< ADC_MODE_CONTROL.SWCNV //---------------------------------------- // Apply a soft reset when changing from internal to external clock mode. int needFIFOreset = (isExternalClock != 1); if (needFIFOreset) { // Apply a soft reset when changing from internal to external clock mode. ADC_MODE_CONTROL = ((1 & RESET_BITS) << RESET_LSB); // ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved // Send SPI configuration to device SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern SPIoutputCS(0); // drive CS low SPIwrite16bits(ADC_MODE_CONTROL); SPIoutputCS(1); // drive CS high ADC_MODE_CONTROL = 0; } //---------------------------------------- // number of words to read NumWords = (1 + channelNumber_0_15); //---------------------------------------- // External Clock Mode isExternalClock = 1; //---------------------------------------- // update device driver global variable ScanMode = SCAN_0100_StandardExternalClock; //---------------------------------------- // ADC MODE CONTROL register set SCAN[3:0] TO SCAN_0100_StandardExternalClock = 4 //~ const int SCAN_0100_StandardExternalClock = 4; // replaced local const with enum ADC_MODE_CONTROL |= ((SCAN_0100_StandardExternalClock & SCAN_BITS) << SCAN_LSB); //---------------------------------------- // ADC MODE CONTROL register set CHSEL[3:0] TO channel number ADC_MODE_CONTROL |= ((channelNumber_0_15 & CHSEL_BITS) << CHSEL_LSB); //---------------------------------------- // ADC MODE CONTROL REGISTER SELECT THE PM[1:0] BITS ADC_MODE_CONTROL |= ((PowerManagement_0_2 & PM_BITS) << PM_LSB); //---------------------------------------- // ADC MODE CONTROL REGISTER SELECT THE CHAN_ID BIT // (applicable to external clock mode only) // For external clock modes, the data format returned depends on the CHAN_ID bit. // when CHAN_ID = 0: misoData16 = 0 DATA[11:0] x x x // when CHAN_ID = 1: misoData16 = CH[3:0] DATA[11:0] // For internal clock modes, the data format always includes the channel address. // misoData16 = CH[3:0] DATA[11:0] ADC_MODE_CONTROL |= ((chan_id_0_1 & CHAN_ID_BITS) << CHAN_ID_LSB); //---------------------------------------- // SPI write ADC MODE CONTROL register // Send SPI configuration to device SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern SPIoutputCS(0); // drive CS low SPIwrite16bits(ADC_MODE_CONTROL); SPIoutputCS(1); // drive CS high //---------------------------------------- // return number of words to read return NumWords; } //---------------------------------------- // SCAN_0101_UpperInternalClock // // Measure ADC channels in sequence from channelNumber_0_15 to AIN15. // Internal clock mode. // @param[in] channelNumber_0_15: AIN Channel Number // @param[in] average_0_4_8_16_32: Number of samples averaged per ScanRead() word. // average_0_4_8_16_32=0 to disable averaging. // @param[in] PowerManagement_0_2: 0=Normal, 1=AutoShutdown, 2=AutoStandby // @param[in] swcnv_0_1: ADC_MODE_CONTROL.SWCNV // SWCNV=0: trigger measurement by driving CNVST pin low. // Minimum active-low pulse duration of 5ns. (AIN14 is not available) // SWCNV=1: trigger measurement on SPI CS rising edge. // CS must be held low for minimum of 17 SCLK cycles. // CNVST pin is not used. (AIN14 is available) // @return number of ScanRead() words needed to retrieve the data. // For internal clock modes, the data format always includes the channel address. // misoData16 = CH[3:0] DATA[11:0] // int MAX11131::ScanUpperInternalClock(void) { //---------------------------------------- // number of words to read NumWords = (16 - channelNumber_0_15); //---------------------------------------- // Internal Clock Mode isExternalClock = 0; //---------------------------------------- // update device driver global variable ScanMode = SCAN_0101_UpperInternalClock; //---------------------------------------- // define write-only register ADC_MODE_CONTROL ADC_MODE_CONTROL = 0; //!< mosiData16 0x0000..0x7FFF format: 0 SCAN[3:0] CHSEL[3:0] RESET[1:0] PM[1:0] CHAN_ID SWCNV 0 const int SCAN_LSB = 11; const int SCAN_BITS = 0x0F; //!< ADC_MODE_CONTROL.SCAN[3:0] ADC Scan Control (command) const int CHSEL_LSB = 7; const int CHSEL_BITS = 0x0F; //!< ADC_MODE_CONTROL.CHSEL[3:0] Analog Input Channel Select AIN0..AIN15 const int RESET_LSB = 5; const int RESET_BITS = 0x03; //!< ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved const int PM_LSB = 3; const int PM_BITS = 0x03; //!< ADC_MODE_CONTROL.PM[1:0] Power Management 0=Normal, 1=AutoShutdown, 2=AutoStandby 3=reserved const int CHAN_ID_LSB = 2; const int CHAN_ID_BITS = 0x01; //!< ADC_MODE_CONTROL.CHAN_ID const int SWCNV_LSB = 1; const int SWCNV_BITS = 0x01; //!< ADC_MODE_CONTROL.SWCNV //---------------------------------------- // define write-only register ADC_CONFIGURATION ADC_CONFIGURATION = 0x8000; //!< mosiData16 0x8000..0x87FF format: 1 0 0 0 0 REFSEL AVGON NAVG[1:0] NSCAN[1:0] SPM[1:0] ECHO 0 0 const int REFSEL_LSB = 10; const int REFSEL_BITS = 0x01; // ADC_CONFIGURATION.REFSEL const int AVGON_LSB = 9; const int AVGON_BITS = 0x01; // ADC_CONFIGURATION.AVGON const int NAVG_LSB = 7; const int NAVG_BITS = 0x03; // ADC_CONFIGURATION.NAVG[1:0] const int NSCAN_LSB = 5; const int NSCAN_BITS = 0x03; // ADC_CONFIGURATION.NSCAN[1:0] const int SPM_LSB = 3; const int SPM_BITS = 0x03; // ADC_CONFIGURATION.SPM[1:0] const int ECHO_LSB = 2; const int ECHO_BITS = 0x01; // ADC_CONFIGURATION.ECHO //---------------------------------------- // if average, ADC CONFIGURATION register set AVG and NAVG[1:0] // (applicable to internal clock mode only) // if average, ADC CONFIGURATION register set AVG ON BIT TO 1 // if average, ADC CONFIGURATION register set NAVG[1:0] TO N if (average_0_4_8_16_32 == 4) { // Enable Averaging of 4 samples (AVGON=1, NAVG[1:0]=0) ADC_CONFIGURATION |= ((1 & AVGON_BITS) << AVGON_LSB); ADC_CONFIGURATION &= ~ (( NAVG_BITS) << NAVG_LSB); ADC_CONFIGURATION |= ((0 & NAVG_BITS) << NAVG_LSB); } else if (average_0_4_8_16_32 == 8) { // Enable Averaging of 8 samples (AVGON=1, NAVG[1:0]=1) ADC_CONFIGURATION |= ((1 & AVGON_BITS) << AVGON_LSB); ADC_CONFIGURATION &= ~ (( NAVG_BITS) << NAVG_LSB); ADC_CONFIGURATION |= ((1 & NAVG_BITS) << NAVG_LSB); } else if (average_0_4_8_16_32 == 16) { // Enable Averaging of 16 samples (AVGON=1, NAVG[1:0]=2) ADC_CONFIGURATION |= ((1 & AVGON_BITS) << AVGON_LSB); ADC_CONFIGURATION &= ~ (( NAVG_BITS) << NAVG_LSB); ADC_CONFIGURATION |= ((2 & NAVG_BITS) << NAVG_LSB); } else if (average_0_4_8_16_32 == 32) { // Enable Averaging of 32 samples (AVGON=1, NAVG[1:0]=3) ADC_CONFIGURATION |= ((1 & AVGON_BITS) << AVGON_LSB); ADC_CONFIGURATION &= ~ (( NAVG_BITS) << NAVG_LSB); ADC_CONFIGURATION |= ((3 & NAVG_BITS) << NAVG_LSB); } else { // Disable Averaging (AVGON=0, NAVG[1:0]=0) ADC_CONFIGURATION &= ~ (( AVGON_BITS) << AVGON_LSB); ADC_CONFIGURATION &= ~ (( NAVG_BITS) << NAVG_LSB); } //---------------------------------------- // SPI write ADC CONFIGURATION register // Send SPI configuration to device SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern SPIoutputCS(0); // drive CS low SPIwrite16bits(ADC_CONFIGURATION); SPIoutputCS(1); // drive CS high //---------------------------------------- // Reset FIFO: ADC_MODE_CONTROL.RESET[1:0] = 1 Apply a soft reset when changing from internal to external clock mode. ADC_MODE_CONTROL &= ~ (( RESET_BITS) << RESET_LSB); // ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved ADC_MODE_CONTROL |= ((1 & RESET_BITS) << RESET_LSB); // ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved //---------------------------------------- // ADC MODE CONTROL register set SCAN[3:0] TO SCAN_0101_UpperInternalClock = 5 //~ const int SCAN_0101_UpperInternalClock = 5; // replaced local const with enum ADC_MODE_CONTROL |= ((SCAN_0101_UpperInternalClock & SCAN_BITS) << SCAN_LSB); //---------------------------------------- // ADC MODE CONTROL register set CHSEL[3:0] TO channel number ADC_MODE_CONTROL |= ((channelNumber_0_15 & CHSEL_BITS) << CHSEL_LSB); //---------------------------------------- // ADC MODE CONTROL REGISTER SELECT THE PM[1:0] BITS ADC_MODE_CONTROL |= ((PowerManagement_0_2 & PM_BITS) << PM_LSB); //---------------------------------------- // ADC MODE CONTROL register set SWCNV if CNVST pin is not used // ADC MODE CONTROL REGISTER SELECT THE RIGHT SWCNV BIT // (applicable to internal clock mode only) // SWCNV=1: trigger measurement on SPI CS rising edge; CNVST pin is not used. (AIN14 is available) // SWCNV=0: trigger measurement by driving CNVST pin low for a minimum active-low pulse duration of 5ns. (AIN14 is not available) if (swcnv_0_1) { ADC_MODE_CONTROL |= ((swcnv_0_1 & SWCNV_BITS) << SWCNV_LSB); } else { ADC_MODE_CONTROL &= ~ (( SWCNV_BITS) << SWCNV_LSB); } //---------------------------------------- // SPI write ADC MODE CONTROL register // If SWCNV=1 then CS must be held low for at least 17 SCLK cycles. // Send SPI configuration to device SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern SPIoutputCS(0); // drive CS low if (swcnv_0_1) { // If SWCNV=1 then CS must be held low for at least 17 SCLK cycles. // NOTE: Figure 7 Internal Conversions with SWCNV=1 has an error, the 17th SCLK is mislabeled as "16" should be "17". SPIwrite24bits(ADC_MODE_CONTROL, 0); } else { SPIwrite16bits(ADC_MODE_CONTROL); } SPIoutputCS(1); // drive CS high //---------------------------------------- // return number of words to read return NumWords; } //---------------------------------------- // SCAN_0110_UpperExternalClock // // Measure ADC channels in sequence from channelNumber_0_15 to AIN15. // External clock mode. // @param[in] channelNumber_0_15: AIN Channel Number // @param[in] PowerManagement_0_2: 0=Normal, 1=AutoShutdown, 2=AutoStandby // @param[in] chan_id_0_1: ADC_MODE_CONTROL.CHAN_ID // @return number of ScanRead() words needed to retrieve the data. // For external clock modes, the data format depends on CHAN_ID. // when CHAN_ID = 0: misoData16 = 0 DATA[11:0] x x x // when CHAN_ID = 1: misoData16 = CH[3:0] DATA[11:0] // int MAX11131::ScanUpperExternalClock(void) { //---------------------------------------- // define write-only register ADC_MODE_CONTROL ADC_MODE_CONTROL = 0; //!< mosiData16 0x0000..0x7FFF format: 0 SCAN[3:0] CHSEL[3:0] RESET[1:0] PM[1:0] CHAN_ID SWCNV 0 const int SCAN_LSB = 11; const int SCAN_BITS = 0x0F; //!< ADC_MODE_CONTROL.SCAN[3:0] ADC Scan Control (command) const int CHSEL_LSB = 7; const int CHSEL_BITS = 0x0F; //!< ADC_MODE_CONTROL.CHSEL[3:0] Analog Input Channel Select AIN0..AIN15 const int RESET_LSB = 5; const int RESET_BITS = 0x03; //!< ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved const int PM_LSB = 3; const int PM_BITS = 0x03; //!< ADC_MODE_CONTROL.PM[1:0] Power Management 0=Normal, 1=AutoShutdown, 2=AutoStandby 3=reserved const int CHAN_ID_LSB = 2; const int CHAN_ID_BITS = 0x01; //!< ADC_MODE_CONTROL.CHAN_ID const int SWCNV_LSB = 1; const int SWCNV_BITS = 0x01; //!< ADC_MODE_CONTROL.SWCNV //---------------------------------------- // Apply a soft reset when changing from internal to external clock mode. int needFIFOreset = (isExternalClock != 1); if (needFIFOreset) { // Apply a soft reset when changing from internal to external clock mode. ADC_MODE_CONTROL = ((1 & RESET_BITS) << RESET_LSB); // ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved // Send SPI configuration to device SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern SPIoutputCS(0); // drive CS low SPIwrite16bits(ADC_MODE_CONTROL); SPIoutputCS(1); // drive CS high ADC_MODE_CONTROL = 0; } //---------------------------------------- // number of words to read NumWords = (16 - channelNumber_0_15); //---------------------------------------- // External Clock Mode isExternalClock = 1; //---------------------------------------- // update device driver global variable ScanMode = SCAN_0110_UpperExternalClock; //---------------------------------------- // ADC MODE CONTROL register set SCAN[3:0] TO SCAN_0110_UpperExternalClock = 6 //~ const int SCAN_0110_UpperExternalClock = 6; // replaced local const with enum ADC_MODE_CONTROL |= ((SCAN_0110_UpperExternalClock & SCAN_BITS) << SCAN_LSB); //---------------------------------------- // ADC MODE CONTROL register set CHSEL[3:0] TO channel number ADC_MODE_CONTROL |= ((channelNumber_0_15 & CHSEL_BITS) << CHSEL_LSB); //---------------------------------------- // ADC MODE CONTROL REGISTER SELECT THE PM[1:0] BITS ADC_MODE_CONTROL |= ((PowerManagement_0_2 & PM_BITS) << PM_LSB); //---------------------------------------- // ADC MODE CONTROL REGISTER SELECT THE CHAN_ID BIT // (applicable to external clock mode only) // For external clock modes, the data format returned depends on the CHAN_ID bit. // when CHAN_ID = 0: misoData16 = 0 DATA[11:0] x x x // when CHAN_ID = 1: misoData16 = CH[3:0] DATA[11:0] // For internal clock modes, the data format always includes the channel address. // misoData16 = CH[3:0] DATA[11:0] ADC_MODE_CONTROL |= ((chan_id_0_1 & CHAN_ID_BITS) << CHAN_ID_LSB); //---------------------------------------- // SPI write ADC MODE CONTROL register // Send SPI configuration to device SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern SPIoutputCS(0); // drive CS low SPIwrite16bits(ADC_MODE_CONTROL); SPIoutputCS(1); // drive CS high //---------------------------------------- // return number of words to read return NumWords; } //---------------------------------------- // SCAN_0111_CustomInternalClock // // Measure selected ADC channels in sequence from AIN0 to AIN15, // using only the channels enabled by enabledChannelsMask. // Bit 0x0001 enables AIN0. // Bit 0x0002 enables AIN1. // Bit 0x0004 enables AIN2. // Bit 0x0008 enables AIN3. // Bit 0x0010 enables AIN4. // Bit 0x0020 enables AIN5. // Bit 0x0040 enables AIN6. // Bit 0x0080 enables AIN7. // Bit 0x0100 enables AIN8. // Bit 0x0200 enables AIN9. // Bit 0x0400 enables AIN10. // Bit 0x0800 enables AIN11. // Bit 0x1000 enables AIN12. // Bit 0x2000 enables AIN13. // Bit 0x4000 enables AIN14. // Bit 0x8000 enables AIN15. // Internal clock mode. // @param[in] enabledChannelsMask: Bitmap of AIN Channels to scan. // @param[in] average_0_4_8_16_32: Number of samples averaged per ScanRead() word. // average_0_4_8_16_32=0 to disable averaging. // @param[in] PowerManagement_0_2: 0=Normal, 1=AutoShutdown, 2=AutoStandby // @param[in] swcnv_0_1: ADC_MODE_CONTROL.SWCNV // SWCNV=0: trigger measurement by driving CNVST pin low. // Minimum active-low pulse duration of 5ns. (AIN14 is not available) // SWCNV=1: trigger measurement on SPI CS rising edge. // CS must be held low for minimum of 17 SCLK cycles. // CNVST pin is not used. (AIN14 is available) // @return number of ScanRead() words needed to retrieve the data. // For internal clock modes, the data format always includes the channel address. // misoData16 = CH[3:0] DATA[11:0] // int MAX11131::ScanCustomInternalClock(void) { //---------------------------------------- // count nWords = number of set bits in enabledChannelsMask uint16_t bitMask; int nWords = 0; for (bitMask = 0x8000; bitMask != 0; bitMask = bitMask / 2) { if (enabledChannelsMask & bitMask) { nWords++; } } //---------------------------------------- // number of words to read NumWords = nWords; //---------------------------------------- // Internal Clock Mode isExternalClock = 0; //---------------------------------------- // update device driver global variable ScanMode = SCAN_0111_CustomInternalClock; //---------------------------------------- // define write-only register ADC_MODE_CONTROL ADC_MODE_CONTROL = 0; //!< mosiData16 0x0000..0x7FFF format: 0 SCAN[3:0] CHSEL[3:0] RESET[1:0] PM[1:0] CHAN_ID SWCNV 0 const int SCAN_LSB = 11; const int SCAN_BITS = 0x0F; //!< ADC_MODE_CONTROL.SCAN[3:0] ADC Scan Control (command) const int CHSEL_LSB = 7; const int CHSEL_BITS = 0x0F; //!< ADC_MODE_CONTROL.CHSEL[3:0] Analog Input Channel Select AIN0..AIN15 const int RESET_LSB = 5; const int RESET_BITS = 0x03; //!< ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved const int PM_LSB = 3; const int PM_BITS = 0x03; //!< ADC_MODE_CONTROL.PM[1:0] Power Management 0=Normal, 1=AutoShutdown, 2=AutoStandby 3=reserved const int CHAN_ID_LSB = 2; const int CHAN_ID_BITS = 0x01; //!< ADC_MODE_CONTROL.CHAN_ID const int SWCNV_LSB = 1; const int SWCNV_BITS = 0x01; //!< ADC_MODE_CONTROL.SWCNV //---------------------------------------- // define write-only register ADC_CONFIGURATION ADC_CONFIGURATION = 0x8000; //!< mosiData16 0x8000..0x87FF format: 1 0 0 0 0 REFSEL AVGON NAVG[1:0] NSCAN[1:0] SPM[1:0] ECHO 0 0 const int REFSEL_LSB = 10; const int REFSEL_BITS = 0x01; // ADC_CONFIGURATION.REFSEL const int AVGON_LSB = 9; const int AVGON_BITS = 0x01; // ADC_CONFIGURATION.AVGON const int NAVG_LSB = 7; const int NAVG_BITS = 0x03; // ADC_CONFIGURATION.NAVG[1:0] const int NSCAN_LSB = 5; const int NSCAN_BITS = 0x03; // ADC_CONFIGURATION.NSCAN[1:0] const int SPM_LSB = 3; const int SPM_BITS = 0x03; // ADC_CONFIGURATION.SPM[1:0] const int ECHO_LSB = 2; const int ECHO_BITS = 0x01; // ADC_CONFIGURATION.ECHO //---------------------------------------- // define write-only registers CSCAN0,CSCAN1 CSCAN0 = 0xA000; //!< mosiData16 0xA000..0xA7FF format: 1 0 1 0 0 CHSCAN15 CHSCAN14 CHSCAN13 CHSCAN12 CHSCAN11 CHSCAN10 CHSCAN9 CHSCAN8 x x x const int CHSCAN15_LSB = 10; // CSCAN0.CHSCAN15 const int CHSCAN14_LSB = 9; // CSCAN0.CHSCAN14 const int CHSCAN13_LSB = 8; // CSCAN0.CHSCAN13 const int CHSCAN12_LSB = 7; // CSCAN0.CHSCAN12 const int CHSCAN11_LSB = 6; // CSCAN0.CHSCAN11 const int CHSCAN10_LSB = 5; // CSCAN0.CHSCAN10 const int CHSCAN9_LSB = 4; // CSCAN0.CHSCAN9 const int CHSCAN8_LSB = 3; // CSCAN0.CHSCAN8 CSCAN1 = 0xA800; //!< mosiData16 0xA800..0xAFFF format: 1 0 1 0 1 CHSCAN7 CHSCAN6 CHSCAN5 CHSCAN4 CHSCAN3 CHSCAN2 CHSCAN1 CHSCAN0 x x x const int CHSCAN7_LSB = 10; // CSCAN1.CHSCAN7 const int CHSCAN6_LSB = 9; // CSCAN1.CHSCAN6 const int CHSCAN5_LSB = 8; // CSCAN1.CHSCAN5 const int CHSCAN4_LSB = 7; // CSCAN1.CHSCAN4 const int CHSCAN3_LSB = 6; // CSCAN1.CHSCAN3 const int CHSCAN2_LSB = 5; // CSCAN1.CHSCAN2 const int CHSCAN1_LSB = 4; // CSCAN1.CHSCAN1 const int CHSCAN0_LSB = 3; // CSCAN1.CHSCAN0 //---------------------------------------- // if average, ADC CONFIGURATION register set AVG and NAVG[1:0] // (applicable to internal clock mode only) // if average, ADC CONFIGURATION register set AVG ON BIT TO 1 // if average, ADC CONFIGURATION register set NAVG[1:0] TO N if (average_0_4_8_16_32 == 4) { // Enable Averaging of 4 samples (AVGON=1, NAVG[1:0]=0) ADC_CONFIGURATION |= ((1 & AVGON_BITS) << AVGON_LSB); ADC_CONFIGURATION &= ~ (( NAVG_BITS) << NAVG_LSB); ADC_CONFIGURATION |= ((0 & NAVG_BITS) << NAVG_LSB); } else if (average_0_4_8_16_32 == 8) { // Enable Averaging of 8 samples (AVGON=1, NAVG[1:0]=1) ADC_CONFIGURATION |= ((1 & AVGON_BITS) << AVGON_LSB); ADC_CONFIGURATION &= ~ (( NAVG_BITS) << NAVG_LSB); ADC_CONFIGURATION |= ((1 & NAVG_BITS) << NAVG_LSB); } else if (average_0_4_8_16_32 == 16) { // Enable Averaging of 16 samples (AVGON=1, NAVG[1:0]=2) ADC_CONFIGURATION |= ((1 & AVGON_BITS) << AVGON_LSB); ADC_CONFIGURATION &= ~ (( NAVG_BITS) << NAVG_LSB); ADC_CONFIGURATION |= ((2 & NAVG_BITS) << NAVG_LSB); } else if (average_0_4_8_16_32 == 32) { // Enable Averaging of 32 samples (AVGON=1, NAVG[1:0]=3) ADC_CONFIGURATION |= ((1 & AVGON_BITS) << AVGON_LSB); ADC_CONFIGURATION &= ~ (( NAVG_BITS) << NAVG_LSB); ADC_CONFIGURATION |= ((3 & NAVG_BITS) << NAVG_LSB); } else { // Disable Averaging (AVGON=0, NAVG[1:0]=0) ADC_CONFIGURATION &= ~ (( AVGON_BITS) << AVGON_LSB); ADC_CONFIGURATION &= ~ (( NAVG_BITS) << NAVG_LSB); } //---------------------------------------- // SPI write ADC CONFIGURATION register // Send SPI configuration to device SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern SPIoutputCS(0); // drive CS low SPIwrite16bits(ADC_CONFIGURATION); SPIoutputCS(1); // drive CS high //---------------------------------------- // SET CSCAN0 CSCAN1 REGISTERS from enabledChannelsMask CSCAN0 = 0xA000 | (((enabledChannelsMask >> 8) & 0xFF) << 3); // CSCAN0.CHSCAN[15:8] CSCAN1 = 0xA800 | (((enabledChannelsMask) & 0xFF) << 3); // CSCAN1.CHSCAN[7:0] SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern SPIoutputCS(0); // drive CS low SPIwrite16bits(CSCAN0); SPIoutputCS(1); // drive CS high SPIoutputCS(0); // drive CS low SPIwrite16bits(CSCAN1); SPIoutputCS(1); // drive CS high //---------------------------------------- // Reset FIFO: ADC_MODE_CONTROL.RESET[1:0] = 1 Apply a soft reset when changing from internal to external clock mode. ADC_MODE_CONTROL &= ~ (( RESET_BITS) << RESET_LSB); // ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved ADC_MODE_CONTROL |= ((1 & RESET_BITS) << RESET_LSB); // ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved //---------------------------------------- // ADC MODE CONTROL register set SCAN[3:0] TO SCAN_0111_CustomInternalClock = 7 //~ const int SCAN_0111_CustomInternalClock = 7; // replaced local const with enum ADC_MODE_CONTROL |= ((SCAN_0111_CustomInternalClock & SCAN_BITS) << SCAN_LSB); //---------------------------------------- // ADC MODE CONTROL REGISTER SELECT THE PM[1:0] BITS ADC_MODE_CONTROL |= ((PowerManagement_0_2 & PM_BITS) << PM_LSB); //---------------------------------------- // ADC MODE CONTROL register set SWCNV if CNVST pin is not used // ADC MODE CONTROL REGISTER SELECT THE RIGHT SWCNV BIT // (applicable to internal clock mode only) // SWCNV=1: trigger measurement on SPI CS rising edge; CNVST pin is not used. (AIN14 is available) // SWCNV=0: trigger measurement by driving CNVST pin low for a minimum active-low pulse duration of 5ns. (AIN14 is not available) if (swcnv_0_1) { ADC_MODE_CONTROL |= ((swcnv_0_1 & SWCNV_BITS) << SWCNV_LSB); } else { ADC_MODE_CONTROL &= ~ (( SWCNV_BITS) << SWCNV_LSB); } //---------------------------------------- // SPI write ADC MODE CONTROL register // If SWCNV=1 then CS must be held low for at least 17 SCLK cycles. // Send SPI configuration to device SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern SPIoutputCS(0); // drive CS low if (swcnv_0_1) { // If SWCNV=1 then CS must be held low for at least 17 SCLK cycles. // NOTE: Figure 7 Internal Conversions with SWCNV=1 has an error, the 17th SCLK is mislabeled as "16" should be "17". SPIwrite24bits(ADC_MODE_CONTROL, 0); } else { SPIwrite16bits(ADC_MODE_CONTROL); } SPIoutputCS(1); // drive CS high //---------------------------------------- // return number of words to read return NumWords; } //---------------------------------------- // SCAN_1000_CustomExternalClock // // Measure selected ADC channels in sequence from AIN0 to AIN15, // using only the channels enabled by enabledChannelsMask. // Bit 0x0001 enables AIN0. // Bit 0x0002 enables AIN1. // Bit 0x0004 enables AIN2. // Bit 0x0008 enables AIN3. // Bit 0x0010 enables AIN4. // Bit 0x0020 enables AIN5. // Bit 0x0040 enables AIN6. // Bit 0x0080 enables AIN7. // Bit 0x0100 enables AIN8. // Bit 0x0200 enables AIN9. // Bit 0x0400 enables AIN10. // Bit 0x0800 enables AIN11. // Bit 0x1000 enables AIN12. // Bit 0x2000 enables AIN13. // Bit 0x4000 enables AIN14. // Bit 0x8000 enables AIN15. // External clock mode. // @param[in] enabledChannelsMask: Bitmap of AIN Channels to scan. // @param[in] PowerManagement_0_2: 0=Normal, 1=AutoShutdown, 2=AutoStandby // @param[in] chan_id_0_1: ADC_MODE_CONTROL.CHAN_ID // @return number of ScanRead() words needed to retrieve the data. // For external clock modes, the data format depends on CHAN_ID. // when CHAN_ID = 0: misoData16 = 0 DATA[11:0] x x x // when CHAN_ID = 1: misoData16 = CH[3:0] DATA[11:0] // int MAX11131::ScanCustomExternalClock(void) { //---------------------------------------- // count nWords = number of set bits in enabledChannelsMask uint16_t bitMask; int nWords = 0; for (bitMask = 0x8000; bitMask != 0; bitMask = bitMask / 2) { if (enabledChannelsMask & bitMask) { nWords++; } } //---------------------------------------- // define write-only register ADC_MODE_CONTROL ADC_MODE_CONTROL = 0; //!< mosiData16 0x0000..0x7FFF format: 0 SCAN[3:0] CHSEL[3:0] RESET[1:0] PM[1:0] CHAN_ID SWCNV 0 const int SCAN_LSB = 11; const int SCAN_BITS = 0x0F; //!< ADC_MODE_CONTROL.SCAN[3:0] ADC Scan Control (command) const int CHSEL_LSB = 7; const int CHSEL_BITS = 0x0F; //!< ADC_MODE_CONTROL.CHSEL[3:0] Analog Input Channel Select AIN0..AIN15 const int RESET_LSB = 5; const int RESET_BITS = 0x03; //!< ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved const int PM_LSB = 3; const int PM_BITS = 0x03; //!< ADC_MODE_CONTROL.PM[1:0] Power Management 0=Normal, 1=AutoShutdown, 2=AutoStandby 3=reserved const int CHAN_ID_LSB = 2; const int CHAN_ID_BITS = 0x01; //!< ADC_MODE_CONTROL.CHAN_ID const int SWCNV_LSB = 1; const int SWCNV_BITS = 0x01; //!< ADC_MODE_CONTROL.SWCNV //---------------------------------------- // Apply a soft reset when changing from internal to external clock mode. int needFIFOreset = (isExternalClock != 1); if (needFIFOreset) { // Apply a soft reset when changing from internal to external clock mode. ADC_MODE_CONTROL = ((1 & RESET_BITS) << RESET_LSB); // ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved // Send SPI configuration to device SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern SPIoutputCS(0); // drive CS low SPIwrite16bits(ADC_MODE_CONTROL); SPIoutputCS(1); // drive CS high ADC_MODE_CONTROL = 0; } //---------------------------------------- // number of words to read NumWords = nWords; //---------------------------------------- // External Clock Mode isExternalClock = 1; //---------------------------------------- // update device driver global variable ScanMode = SCAN_1000_CustomExternalClock; //---------------------------------------- // define write-only registers CSCAN0,CSCAN1 CSCAN0 = 0xA000; //!< mosiData16 0xA000..0xA7FF format: 1 0 1 0 0 CHSCAN15 CHSCAN14 CHSCAN13 CHSCAN12 CHSCAN11 CHSCAN10 CHSCAN9 CHSCAN8 x x x const int CHSCAN15_LSB = 10; // CSCAN0.CHSCAN15 const int CHSCAN14_LSB = 9; // CSCAN0.CHSCAN14 const int CHSCAN13_LSB = 8; // CSCAN0.CHSCAN13 const int CHSCAN12_LSB = 7; // CSCAN0.CHSCAN12 const int CHSCAN11_LSB = 6; // CSCAN0.CHSCAN11 const int CHSCAN10_LSB = 5; // CSCAN0.CHSCAN10 const int CHSCAN9_LSB = 4; // CSCAN0.CHSCAN9 const int CHSCAN8_LSB = 3; // CSCAN0.CHSCAN8 CSCAN1 = 0xA800; //!< mosiData16 0xA800..0xAFFF format: 1 0 1 0 1 CHSCAN7 CHSCAN6 CHSCAN5 CHSCAN4 CHSCAN3 CHSCAN2 CHSCAN1 CHSCAN0 x x x const int CHSCAN7_LSB = 10; // CSCAN1.CHSCAN7 const int CHSCAN6_LSB = 9; // CSCAN1.CHSCAN6 const int CHSCAN5_LSB = 8; // CSCAN1.CHSCAN5 const int CHSCAN4_LSB = 7; // CSCAN1.CHSCAN4 const int CHSCAN3_LSB = 6; // CSCAN1.CHSCAN3 const int CHSCAN2_LSB = 5; // CSCAN1.CHSCAN2 const int CHSCAN1_LSB = 4; // CSCAN1.CHSCAN1 const int CHSCAN0_LSB = 3; // CSCAN1.CHSCAN0 //---------------------------------------- // SET CSCAN0 CSCAN1 REGISTERS from enabledChannelsMask CSCAN0 = 0xA000 | (((enabledChannelsMask >> 8) & 0xFF) << 3); // CSCAN0.CHSCAN[15:8] CSCAN1 = 0xA800 | (((enabledChannelsMask) & 0xFF) << 3); // CSCAN1.CHSCAN[7:0] SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern SPIoutputCS(0); // drive CS low SPIwrite16bits(CSCAN0); SPIoutputCS(1); // drive CS high SPIoutputCS(0); // drive CS low SPIwrite16bits(CSCAN1); SPIoutputCS(1); // drive CS high //---------------------------------------- // ADC MODE CONTROL register set SCAN[3:0] TO SCAN_1000_CustomExternalClock = 8 //~ const int SCAN_1000_CustomExternalClock = 8; // replaced local const with enum ADC_MODE_CONTROL |= ((SCAN_1000_CustomExternalClock & SCAN_BITS) << SCAN_LSB); //---------------------------------------- // ADC MODE CONTROL REGISTER SELECT THE PM[1:0] BITS ADC_MODE_CONTROL |= ((PowerManagement_0_2 & PM_BITS) << PM_LSB); //---------------------------------------- // ADC MODE CONTROL REGISTER SELECT THE CHAN_ID BIT // (applicable to external clock mode only) // For external clock modes, the data format returned depends on the CHAN_ID bit. // when CHAN_ID = 0: misoData16 = 0 DATA[11:0] x x x // when CHAN_ID = 1: misoData16 = CH[3:0] DATA[11:0] // For internal clock modes, the data format always includes the channel address. // misoData16 = CH[3:0] DATA[11:0] ADC_MODE_CONTROL |= ((chan_id_0_1 & CHAN_ID_BITS) << CHAN_ID_LSB); //---------------------------------------- // SPI write ADC MODE CONTROL register // Send SPI configuration to device SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern SPIoutputCS(0); // drive CS low SPIwrite16bits(ADC_MODE_CONTROL); SPIoutputCS(1); // drive CS high //---------------------------------------- // return number of words to read return NumWords; } //---------------------------------------- // SCAN_1001_SampleSetExternalClock // // Measure ADC channels in an arbitrary pattern. // Channels can be visited in any order, with repetition allowed. // External clock mode. // @pre enabledChannelsPatternLength_1_256: number of channel selections // @pre enabledChannelsPattern: array containing channel selection pattern // In the array, one channel select per byte. // In the SPI interface, immediately after SAMPLESET register is written, // each byte encodes two channelNumber selections. // The high 4 bits encode the first channelNumber. // (((enabledChannelsPattern[0]) & 0x0F) << 4) | ((enabledChannelsPattern[1]) & 0x0F) // If it is an odd number of channels, additional nybbles will be ignored. // CS will be asserted low during the entire SAMPLESET pattern selection. // @param[in] PowerManagement_0_2: 0=Normal, 1=AutoShutdown, 2=AutoStandby // @param[in] chan_id_0_1: ADC_MODE_CONTROL.CHAN_ID // @return number of ScanRead() words needed to retrieve the data. // For external clock modes, the data format depends on CHAN_ID. // when CHAN_ID = 0: misoData16 = 0 DATA[11:0] x x x // when CHAN_ID = 1: misoData16 = CH[3:0] DATA[11:0] // int MAX11131::ScanSampleSetExternalClock(void) { //---------------------------------------- // define write-only register ADC_MODE_CONTROL ADC_MODE_CONTROL = 0; //!< mosiData16 0x0000..0x7FFF format: 0 SCAN[3:0] CHSEL[3:0] RESET[1:0] PM[1:0] CHAN_ID SWCNV 0 const int SCAN_LSB = 11; const int SCAN_BITS = 0x0F; //!< ADC_MODE_CONTROL.SCAN[3:0] ADC Scan Control (command) const int CHSEL_LSB = 7; const int CHSEL_BITS = 0x0F; //!< ADC_MODE_CONTROL.CHSEL[3:0] Analog Input Channel Select AIN0..AIN15 const int RESET_LSB = 5; const int RESET_BITS = 0x03; //!< ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved const int PM_LSB = 3; const int PM_BITS = 0x03; //!< ADC_MODE_CONTROL.PM[1:0] Power Management 0=Normal, 1=AutoShutdown, 2=AutoStandby 3=reserved const int CHAN_ID_LSB = 2; const int CHAN_ID_BITS = 0x01; //!< ADC_MODE_CONTROL.CHAN_ID const int SWCNV_LSB = 1; const int SWCNV_BITS = 0x01; //!< ADC_MODE_CONTROL.SWCNV //---------------------------------------- // Apply a soft reset when changing from internal to external clock mode. int needFIFOreset = (isExternalClock != 1); if (needFIFOreset) { // Apply a soft reset when changing from internal to external clock mode. ADC_MODE_CONTROL = ((1 & RESET_BITS) << RESET_LSB); // ADC_MODE_CONTROL.RESET[1:0] Reset 0=Normal 1=ResetFIFO 2=ResetAllRegisters 3=reserved // Send SPI configuration to device SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern SPIoutputCS(0); // drive CS low SPIwrite16bits(ADC_MODE_CONTROL); SPIoutputCS(1); // drive CS high ADC_MODE_CONTROL = 0; } //---------------------------------------- // number of words to read NumWords = ((enabledChannelsPatternLength_1_256 != 0) ? enabledChannelsPatternLength_1_256 : 256 ); //---------------------------------------- // External Clock Mode isExternalClock = 1; //---------------------------------------- // update device driver global variable ScanMode = SCAN_1001_SampleSetExternalClock; //---------------------------------------- // Initialize shadow of write-only register SAMPLESET. // Do not write to SAMPLESET at this time. // A write to SAMPLESET must be followed by specified number of pattern entry words. // See ScanSampleSetExternalClock function for details. SAMPLESET = 0xB000; //!< mosiData16 0xB000..0xB7FF format: 1 0 1 1 0 SEQ_LENGTH[7:0] x x x const int SAMPLESET_LSB = 3; const int SAMPLESET_BITS = 0xFF; // SAMPLESET.SEQ_LENGTH[7:0] //---------------------------------------- // SampleSet register set SEQ_DEPTH[7:0] TO SET CHANNEL CAPTURE DEPTH; FOLLOW SampleSet REGISTER WITH CHANNEL PATTERN OF THE SAME SIZE AS SEQUENCE DEPTH // NOTE: SAMPLESET.SEQ_LENGTH[7:0] is the number of channel entries in the pattern. // NOTE: Each channel entry is 4 bits. The first 4 bits are the first channel in the sequence. // NOTE: Channels can be repeated in any arbitrary order. // NOTE: The channel entry pattern is sent immediately after writing SAMPLESET. // NOTE: Keep CS low during the entire SAMPLESET pattern entry. const int seq_length_minus_one_0_255 = enabledChannelsPatternLength_1_256 - 1; SAMPLESET = 0xB000; //SAMPLESET &= ~ (( SAMPLESET_BITS) << SAMPLESET_LSB); SAMPLESET |= ((seq_length_minus_one_0_255 & SAMPLESET_BITS) << SAMPLESET_LSB); SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern SPIoutputCS(0); // drive CS low SPIwrite16bits(SAMPLESET); // SAMPLESET must be followed by several more bytes, length specified by SEQ_LENGTH[7:0] // pack enabledChannelsPattern[index] into nybbles SPIoutputCS(1); // drive CS high // NOTE: Send the sampleset pattern, with 4 entries packed into each 16-bit SPI word. Pad unused entries with 0. SPI_MOSI_Semantic = 2; // 0:Nothing 1:regWrite 2:sampleSetPattern SPIoutputCS(0); // drive CS low // NOTE: Keep CS low during the entire SAMPLESET pattern entry. int entryIndex; for (entryIndex = 0; entryIndex < enabledChannelsPatternLength_1_256; entryIndex += 4) { uint16_t pack4channels = 0; pack4channels |= (((enabledChannelsPattern[entryIndex + 0]) & 0x0F) << 12); if ((entryIndex + 1) < enabledChannelsPatternLength_1_256) { pack4channels |= (((enabledChannelsPattern[entryIndex + 1]) & 0x0F) << 8); } if ((entryIndex + 2) < enabledChannelsPatternLength_1_256) { pack4channels |= (((enabledChannelsPattern[entryIndex + 2]) & 0x0F) << 4); } if ((entryIndex + 3) < enabledChannelsPatternLength_1_256) { pack4channels |= ((enabledChannelsPattern[entryIndex + 3]) & 0x0F); } SPIwrite16bits(pack4channels); } SPIoutputCS(1); // drive CS high //---------------------------------------- // ADC MODE CONTROL register set SCAN[3:0] TO SCAN_1001_SampleSetExternalClock = 9 //~ const int SCAN_1001_SampleSetExternalClock = 9; // replaced local const with enum ADC_MODE_CONTROL |= ((SCAN_1001_SampleSetExternalClock & SCAN_BITS) << SCAN_LSB); //---------------------------------------- // ADC MODE CONTROL register set CHSEL[3:0] TO channel number ADC_MODE_CONTROL |= ((0 & CHSEL_BITS) << CHSEL_LSB); //---------------------------------------- // ADC MODE CONTROL REGISTER SELECT THE PM[1:0] BITS ADC_MODE_CONTROL |= ((PowerManagement_0_2 & PM_BITS) << PM_LSB); //---------------------------------------- // ADC MODE CONTROL REGISTER SELECT THE CHAN_ID BIT // (applicable to external clock mode only) // For external clock modes, the data format returned depends on the CHAN_ID bit. // when CHAN_ID = 0: misoData16 = 0 DATA[11:0] x x x // when CHAN_ID = 1: misoData16 = CH[3:0] DATA[11:0] // For internal clock modes, the data format always includes the channel address. // misoData16 = CH[3:0] DATA[11:0] ADC_MODE_CONTROL |= ((chan_id_0_1 & CHAN_ID_BITS) << CHAN_ID_LSB); //---------------------------------------- // SPI write ADC MODE CONTROL register // Send SPI configuration to device SPI_MOSI_Semantic = 1; // 0:Nothing 1:regWrite 2:sampleSetPattern SPIoutputCS(0); // drive CS low SPIwrite16bits(ADC_MODE_CONTROL); SPIoutputCS(1); // drive CS high //---------------------------------------- // return number of words to read return NumWords; } //---------------------------------------- // Example configure and perform some measurements in ScanManual mode. // @param[out] pd_mean = address for double mean (avearge) // @param[out] pd_variance = address for double variance (variance) // @param[out] pd_stddev = address for double stddev (standard deviation) // @param[out] pd_Sx = address for double Sx (sum of all X) // @param[out] pd_Sxx = address for double Sxx (sum of squares of each X) void MAX11131::Example_ScanManual(int channelNumber_0_15, int nWords, double* pd_mean, double* pd_variance, double* pd_stddev, double* pd_Sx, double* pd_Sxx) { //---------------------------------------- // configure and perform some measurements in ScanManual mode Init(); channelNumber_0_15 = channelNumber_0_15; // Analog Input Channel Select AIN0.. PowerManagement_0_2 = 0; // Power Management 0=Normal, 1=AutoShutdown, 2=AutoStandby 3=reserved chan_id_0_1 = 1; // when CHAN_ID = 0: misoData16 = 0 DATA[11:0] x x x // const int nWords = 100; double Sx = 0; double Sxx = 0; int index; ScanManual(); for (index = 0; index < nWords; index++) { int16_t misoData16 = ScanRead(); // For internal clock modes, the data format always includes the channel address. // misoData16 = CH[3:0] DATA[11:0] int16_t value_u12 = (misoData16 & 0x0FFF); int channelId = ((misoData16 >> 12) & 0x000F); Sx = Sx + value_u12; Sxx = Sxx + ((double)value_u12 * value_u12); } if (pd_Sx != 0) { *(pd_Sx) = Sx; } if (pd_Sxx != 0) { *(pd_Sxx) = Sxx; } if (pd_mean != 0) { *(pd_mean) = Sx / nWords; } if (nWords >= 2) { if (pd_variance != 0) { // TODO1: is this variance calculation too naive to work reliably? // see https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance *(pd_variance) = (Sxx - ( Sx * Sx / nWords) ) / (nWords - 1); } if (pd_stddev != 0) { *(pd_stddev) = sqrt( *(pd_variance) ); } } } // End of file