Test application for simplified access to the Microchip 1/4/8-Channels 12-Bit A/D Converters with SPI Serial Interface library

Dependencies:   DebugLibrary MCP320x_SPI MCP4xxxx_SPI mbed

Here is the schematic used to validate both libraries MCP320x_SPI and MCP4xxx_SPI.

/media/uploads/Yann/mbed.jpg

Files at this revision

API Documentation at this revision

Comitter:
Yann
Date:
Fri Apr 05 13:36:35 2013 +0000
Child:
1:643f3b45afd1
Commit message:
Add support of MCP3204/8

Changed in this revision

DebugLibrary.lib Show annotated file Show diff for this revision Revisions of this file
MCP320x_SPI/MCP320x_SPI.cpp Show annotated file Show diff for this revision Revisions of this file
MCP320x_SPI/MCP320x_SPI.h Show annotated file Show diff for this revision Revisions of this file
MCP4xxxx_SPI.lib Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DebugLibrary.lib	Fri Apr 05 13:36:35 2013 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/Yann/code/DebugLibrary/#a11adabe9ded
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MCP320x_SPI/MCP320x_SPI.cpp	Fri Apr 05 13:36:35 2013 +0000
@@ -0,0 +1,175 @@
+/* mbed simplified access to Microchip 12 bits ADC devices (SPI)
+ * Copyright (c) 2013 ygarcia, MIT License
+ *
+ * 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 THE AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+#include "MCP320x_SPI.h"
+
+namespace MCP320x_SPI {
+
+    unsigned char CMCP320x_SPI::SPIModuleRefCounter = 0;
+
+    CMCP320x_SPI::CMCP320x_SPI(const PinName p_mosi, const PinName p_miso, const PinName p_sclk, const PinName p_cs, const Mcp320xFamilly p_familly, const unsigned int p_frequency) : _internalId("") {
+        DEBUG_ENTER("CMCP320x_SPI")
+        
+        CMCP320x_SPI::SPIModuleRefCounter += 1;
+        if (CMCP320x_SPI::SPIModuleRefCounter > 1) {
+            //FIXME Check that SPI settings are identical. Otherwise it should failed
+            return;
+        }
+
+        _familly = p_familly;
+        switch (_familly) {
+            case _3201:
+                _channelsNum = 0;
+                break;
+            case _3204:
+                _channelsNum = 4;
+                break;
+            default: // _3208
+                _channelsNum = 8;
+        } // End of 'switch' statement
+        _settings = 0x02; // SGL/DIFF bit set to 1 = See DS21298E-page 19 TABLE 5-1: CONFIGURATION BITS FOR THE MCP3204/TABLE 5-2: CONFIGURATION BITS FOR THE MCP3208
+        DEBUG("CMCP320x_SPI: familly:%d - #channels:%d", _familly, _channelsNum)
+        _spiInstance = new SPI(p_mosi, p_miso, p_sclk);
+        _spiInstance->frequency(p_frequency); // Set the frequency of the SPI interface
+        _spiInstance->format(8, 3);
+        DEBUG_ENTER("CMCP320x_SPI: refCounter=%d", CMCP320x_SPI::SPIModuleRefCounter)
+
+        if (p_cs != NC) {
+            DEBUG("CMCP320x_SPI: /CS managed");
+            _cs = new DigitalOut(p_cs);
+            _cs->write(1); // Disable chip
+        } else {
+            DEBUG("CMCP320x_SPI: /CS not managed");
+            _cs = NULL; // Not used
+        }
+    
+   
+        DEBUG_LEAVE("CMCP320x_SPI")
+    }
+    
+    CMCP320x_SPI::~CMCP320x_SPI() {
+        DEBUG_ENTER("~CMCP320x_SPI")
+    
+        // Release I2C instance
+        DEBUG_ENTER("~CMCP320x_SPI: refCounter=%d", CMCP320x_SPI::SPIModuleRefCounter)
+        CMCP320x_SPI::SPIModuleRefCounter -= 1;
+        if (CMCP320x_SPI::SPIModuleRefCounter == 0) {
+            delete _spiInstance;
+            _spiInstance = NULL;
+        }
+        // Release _reset if required
+        if (_cs != NULL) {
+            _cs->write(1);
+            delete _cs;
+        }
+   
+        DEBUG_LEAVE("~CMCP320x_SPI")
+    }
+
+    float CMCP320x_SPI::Read(const Mcp320xChannels p_channels) {
+        DEBUG_ENTER("CMCP320x_SPI::Read: %d", (unsigned char)p_channels)
+        
+        // Read a sample
+        _sample.value = 0x00;
+        switch (_familly) {
+            case _3204:
+                // No break;
+            case _3208:
+                Read_320x(p_channels);
+                break;
+            default: // _3201
+                Read_3201();
+                break;
+        } // End of 'switch' statement 
+        DEBUG("CMCP320x_SPI::Read: 0x%02x - 0x%02x", _sample.bytes[0], _sample.bytes[1])
+        // Convert it
+        float temp;
+        _sample.value >>= 1; // Adjust composite integer for 12 valid bits
+        _sample.value &= 0x0FFF; // Mask out upper nibble of integer
+        temp = (_sample.value * 0.001225585);
+        
+        DEBUG_LEAVE("CMCP320x_SPI::Read: %f", temp)
+        return temp;        
+    }
+    
+    void CMCP320x_SPI::SetConfig(const bool p_settings) {
+        DEBUG_LEAVE("CMCP320x_SPI::SetConfig: %x", (unsigned char)p_settings)
+        
+        if (_settings) {
+            _settings = 0x02;
+        } else {
+            _settings = 0x00;
+        }
+    }
+    
+    bool CMCP320x_SPI::Shutdown(const bool p_shutdown) {
+        // Sanity check
+        if (_cs == NULL) {
+            return false;
+        }
+        
+        _cs->write(p_shutdown == false ? 0 : 1);
+        
+        return true;
+    }
+    
+    void CMCP320x_SPI::Read_3201() {
+        if (_cs != NULL) {
+            _cs->write(0);
+            wait_us(1);
+        }
+        _sample.bytes[1] = _spiInstance->write(0);
+        _sample.bytes[0] = _spiInstance->write(0);
+        if (_cs != NULL) {
+            _cs->write(1);
+        }    
+    }
+
+    void CMCP320x_SPI::Read_320x(const Mcp320xChannels p_channels) {
+        DEBUG_ENTER("CMCP320x_SPI::Read_320x: %d", (unsigned char)p_channels)
+        
+        unsigned char _channels = (unsigned char)p_channels % _channelsNum;
+        // Set start bit 
+        unsigned char mask = 0x04 | _settings; // Start bit set to 1 - See DS21298E-page 19 Clause 5.0 SERIAL COMMUNICATIONS
+        // Set channel address
+        unsigned char cmd0;
+        unsigned char cmd1;
+        if (_familly == _3204) {
+            cmd0 = mask;
+            cmd1 = _channels << 6; // MCP3204 has 4 channels in single-ended mode
+        } else { // MCP3208
+            cmd0 = mask | ((p_channels & 0x04) >> 2); // Extract D2 bit - See DS21298E-page 19 Clause 5.0 SERIAL COMMUNICATIONS
+            cmd1 = p_channels << 6; // MCP3204 has 8 channels in single-ended mode
+        }
+        DEBUG_ENTER("CMCP320x_SPI::Read_320x: comd0:%02x - cmd1:%02x", cmd0, cmd1)
+        if (_cs != NULL) {
+            _cs->write(0);
+            wait_us(1);
+        }
+        _spiInstance->write(cmd0); // Don't care of the result - See DS21298E-page 21 Clause 6.1 Using the MCP3204/3208 with Microcontroller (MCU) SPI Ports
+        _sample.bytes[1] = _spiInstance->write(cmd1); // DS21298E-page 21 See FIGURE 6-1: SPI Communication using 8-bit segments (Mode 0,0: SCLK idles low)
+        _sample.bytes[0] = _spiInstance->write(0);
+        if (_cs != NULL) {
+            _cs->write(1);
+        }
+            
+        DEBUG_LEAVE("CMCP320x_SPI::Read_320x")
+    }
+    
+} // End of namespace MCP320x_SPI
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MCP320x_SPI/MCP320x_SPI.h	Fri Apr 05 13:36:35 2013 +0000
@@ -0,0 +1,154 @@
+/* mbed simplified access to Microchip MCP320x 12 bits ADC devices (SPI)
+ * Copyright (c) 2013-2013 ygarcia, MIT License
+ *
+ * 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 THE AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+#if !defined(__MCP320x_SPI_H__)
+#define __MCP320x_SPI_H__
+
+#include <string>
+#include <vector>
+
+#include "Debug.h" // Include mbed header + debug primitives. See DebugLibrary
+
+namespace MCP320x_SPI {
+
+    /** This class provides simplified SPI access to a Microchip MCP320x 12-Bit A/D Converter with SPI Serial Interface device. V0.0.0.1
+     *
+     * Microchip MCP42xxx/MCP41xxx Serial EEPROM device reference: DS11195C
+     *
+     * Note that MCP3201 has no SI pin, only a SO output pin
+     * Note that for SPI details, please visit http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus
+     *
+     * @remark This class was validated with Tektronix TDS2014 oscilloscope in 3.3V
+     * @author Yann Garcia (Don't hesitate to contact me: garcia.yann@gmail.com)
+     */
+    class CMCP320x_SPI { 
+        /** Reference counter used to guarentee unicity of the instance of SPI class
+         */
+        static unsigned char SPIModuleRefCounter;
+        
+        /** ChipSelect (pin 1) see DS21290F-page 15 Clause 3.3 Chip Select/Shutdown (CS/SHDN)
+         */
+        DigitalOut *_cs;
+        
+        /** An unique instance of SPI class
+         */
+        SPI *_spiInstance;
+        
+        /** ADC sample structure
+         */
+        typedef union {
+            unsigned int value;
+            struct {
+                unsigned char bytes[2];
+            };
+        } ADCValue;
+        ADCValue _sample;
+        /** Number of channels according to the IC type 
+         */
+        unsigned char _channelsNum;
+        /** Set to true for single-ended inputs configuration, false for pseudo-differential inputs
+         * @see DS21298E-page 19 Clause 5.0 SERIAL COMMUNICATIONS
+         */
+        unsigned char _settings;
+   public:
+        /** MCP320x familly
+         */
+        enum Mcp320xFamilly {
+            _3201 = 0x00, /** See DS21290F */
+            _3204 = 0x01, /** See DS21298E */
+            _3208 = 0x03  /** See DS21298E */
+        };
+        Mcp320xFamilly _familly;
+        /** MCP320x channels to read
+         */
+        enum Mcp320xChannels {
+            CH0 = 0x00, /** See DS21290F/DS21290F */
+            CH1 = 0x01, /** See DS21298E */
+            CH2 = 0x02, /** See DS21298E */
+            CH3 = 0x03, /** See DS21298E */
+            CH4 = 0x04, /** See DS21298E */
+            CH5 = 0x05, /** See DS21298E */
+            CH6 = 0x06, /** See DS21298E */
+            CH7 = 0x07  /** See DS21298E */
+        };
+   public:
+        /** Constructor with Write Protect command pin wired.
+         *
+         * @param p_mosi: MBed pin for SDI
+         * @param p_miso: MBed pin for SDO
+         * @param p_sclk: MBed pin for CLK
+         * @param p_cs  : MBed pin for Chip Select. If NC, assumes that application manage /CS, default value is NC, not connected
+         * @param p_familly: MCP320x familly. Default: _3201
+         * @param p_frequency: Frequency of the SPI interface (SCK), default value is 1MHz
+         */
+        CMCP320x_SPI(const PinName p_mosi, const PinName p_miso, const PinName p_sclk, const PinName p_cs = NC, const Mcp320xFamilly p_familly = _3201, const unsigned int p_frequency = 1000000);
+    
+        /** Destructor
+         * If managed, the /CS pin is set to 1 before to release it
+         */
+        virtual ~CMCP320x_SPI();
+
+        /** Used to return the unique instance of SPI instance
+         */
+        inline const SPI * operator * () { return (const SPI *)_spiInstance; };
+
+        /** 
+         * @desc Launch an analog to digital conversion on the specified channel
+         * @param p_channel The channel to convert
+         * @return The converted value
+         */
+        float Read(const Mcp320xChannels p_channels = CH1);
+        
+        /** 
+         * @desc Change current configuration (only for MCP3204/8)
+         * @param p_setConfig Set to true for single-ended inputs configuration, false for pseudo-differential inputs
+         * @see DS21298E-page 17 Clause 4.1 Analog Inputs
+         */
+        void SetConfig(const bool p_settings);
+    
+         /** Shutdown the device
+         */
+        bool Shutdown(const bool p_shutdown);
+    
+   private:
+        /** Internal reference identifier
+         */
+        std::string _internalId;
+        
+    private:
+    
+        /** 
+         * @desc Launch an analog to digital conversion on the specified channel for MCP3201
+         * @see DS21290F-page 17 Clause 4.1 Analog Inputs
+         */
+        void Read_3201();
+        
+        /** 
+         * @desc Launch an analog to digital conversion on the specified channel for MCP3204/8
+         * @param p_setConfig Set to true for single-ended inputs configuration, false for pseudo-differential inputs
+         * @see DS21298E-page 17 Clause 4.1 Analog Inputs
+         */
+        void Read_320x(const Mcp320xChannels p_channels);    
+        
+    }; // End of class CMCP320x_SPI
+
+} // End of namespace MCP320x_SPI
+
+using namespace MCP320x_SPI;
+
+#endif // __MCP320x_SPI_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MCP4xxxx_SPI.lib	Fri Apr 05 13:36:35 2013 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/Yann/code/MCP4xxxx_SPI/#4f6133144e7e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Fri Apr 05 13:36:35 2013 +0000
@@ -0,0 +1,145 @@
+#include <string>
+#include <iostream>
+#include <iomanip>
+
+#include "MCP4xxxx_SPI.h" // Use SPI module #1 and /CS mapped on pin 8
+#include "MCP320x_SPI.h" // Use SPI module #1 and /CS mapped on pin 9
+
+struct UserChoice {
+    char choice;
+    unsigned char potId;
+    unsigned char adcId;
+};
+
+/*
+ * Declare functions
+ */
+void AvailableIndicator(); // LED1 flashing for program while program is alive
+UserChoice DisplayMenuAndGetChoice(); // Display and get the user choice
+
+/*
+ * Declare statics
+ */
+DigitalOut g_availableLed(LED1); // To verify if program in running
+Ticker g_available; // LED1 will flash with a period of 2s
+CMCP4xxxx_SPI g_digitalPot(p5, p6, p7);
+CMCP320x_SPI *g_adc = NULL;
+DigitalOut g_cs3201(p9);  // /CS mapped on pin 8 for MCP3201
+DigitalOut g_cs3208(p10); // /CS mapped on pin 10 for MCP3208
+DigitalOut g_cs42100(p8); // /CS mapped on pin 8 for MCP421pp
+DigitalOut g_cs41050(p11); // /CS mapped on pin 11 for MCP41050
+DigitalOut *g_csCurrentAdc = NULL;
+
+UserChoice g_userChoice; // Used to store user choice from displayed menu
+
+int main() {
+    // Deactivate all SPI devices
+    g_cs3201 = 1;
+    g_cs3208 = 1;
+    g_cs42100 = 1;
+    g_cs41050 = 1;
+
+    unsigned char potLevel = 0x80; // Initial digital potentiometer value
+    
+    // Launch available indicator
+    g_available.attach(&AvailableIndicator, 2.0);
+    
+    while (true) {
+        // Retrieve user choices 
+        g_userChoice = DisplayMenuAndGetChoice();
+        // Set the pot. value
+        //      1. Enable de right digipot
+        switch (g_userChoice.potId) {
+            case 'a':
+                g_cs42100 = 0;
+                break;
+            default:
+                g_cs41050 = 0;
+                break;
+        } // End of 'switch' statement
+        //      2. Apply user action
+        switch (g_userChoice.choice) {
+            case 'a':
+                potLevel += 1;
+                g_digitalPot.Write(CMCP4xxxx_SPI::WriteToPot1, potLevel);
+                break;
+            case 'b':
+                potLevel -= 1;
+                g_digitalPot.Write(CMCP4xxxx_SPI::WriteToPot1, potLevel);
+                break;
+            case 'c':
+                potLevel -= 1;
+                g_digitalPot.Write(CMCP4xxxx_SPI::ShutdownPot1);
+                break;
+            case 'd':
+                //g_digitalPot->Reset();
+                potLevel = 0x80;
+                break;
+            default:
+                std::cout << "Invalid user choice\r" << std::endl;
+                break;
+        } // End of 'switch' statement
+        //      3. Disable de right digipot
+        switch (g_userChoice.potId) {
+            case 'a':
+                g_cs42100 = 1;
+                break;
+            default:
+                g_cs41050 = 1;
+                break;
+        } // End of 'switch' statement
+        
+        // Set adc to use
+        switch (g_userChoice.adcId) {
+            case 'a': // MCP3201
+                g_adc = new CMCP320x_SPI(p5, p6, p7);
+                g_csCurrentAdc = &g_cs3201;
+                break;
+            case 'b': // MCP3208
+                g_adc = new CMCP320x_SPI(p5, p6, p7, NC, CMCP320x_SPI::_3208);
+                g_csCurrentAdc = &g_cs3208;
+                break;
+        } // End of 'switch' statement
+        g_csCurrentAdc->write(0);
+        float sample = g_adc->Read(CMCP320x_SPI::CH3);
+        g_csCurrentAdc->write(1);
+        std::cout << "Voltage at PW0: " << setprecision(5) << sample << "\r" << std::endl;
+        delete g_adc;
+        g_csCurrentAdc = NULL;
+    } // End of 'while' statement
+} // End of program - nerver reached
+
+void AvailableIndicator() {
+    g_availableLed = !g_availableLed;
+} // End of AvailableIndicator
+
+UserChoice DisplayMenuAndGetChoice() {
+    static UserChoice userChoice;
+
+    // Display the title
+    std::cout << "\r" << std::endl << "MCP320x_SPI v0.2\r" << std::endl;
+
+    // Display the pot selection menu
+    std::cout << "\tUse pot #1:\t\t\ta\r" << std::endl;
+    std::cout << "\tUse pot #2:\t\t\tb\r" << std::endl;
+    std::cout << "Enter your choice: " << std::flush;
+    userChoice.potId = getchar();
+    std::cout << "\r" << std::endl << std::flush;
+
+    // Display the adc selection menu
+    std::cout << "\tUse adc 3201:\t\t\ta\r" << std::endl;
+    std::cout << "\tUse adc 3208:\t\t\tb\r" << std::endl;
+    std::cout << "Enter your choice: " << std::flush;
+    userChoice.adcId = getchar();
+    std::cout << "\r" << std::endl << std::flush;
+    
+    // Display the menu
+    std::cout << "\tIncrease level of pot:\t\t\ta\r" << std::endl;
+    std::cout << "\tDecrease level of pot:\t\t\tb\r" << std::endl;
+    std::cout << "\tShutdown pot         :\t\t\tc\r" << std::endl;
+    std::cout << "\tReset pot            :\t\t\td\r" << std::endl;
+    std::cout << "Enter your choice: " << std::flush;
+    userChoice.choice = getchar();
+    std::cout << "\r" << std::endl << std::flush;
+    return userChoice;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Fri Apr 05 13:36:35 2013 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/0954ebd79f59
\ No newline at end of file