Simplified access to a Microchip Digital Potentiometer (MCP41xxx/MCP42xxx) devices

Dependents:   MCP41xxxApp MCP320xApp MCP41xxxApp

Files at this revision

API Documentation at this revision

Comitter:
Yann
Date:
Thu Jun 06 07:59:16 2013 +0000
Parent:
5:4f6133144e7e
Child:
7:12a0d89aa72f
Commit message:
Validate support of _42xx familly

Changed in this revision

MCP4xxxx_SPI.cpp Show annotated file Show diff for this revision Revisions of this file
MCP4xxxx_SPI.h Show annotated file Show diff for this revision Revisions of this file
--- a/MCP4xxxx_SPI.cpp	Fri Apr 05 13:36:29 2013 +0000
+++ b/MCP4xxxx_SPI.cpp	Thu Jun 06 07:59:16 2013 +0000
@@ -1,4 +1,4 @@
-/* mbed simplified access to Microchip MCP42xxx/MCP41xxx Digital Potentiometer devices (SPI)
+/* mbed simplified access to Microchip 24LCxx Serial EEPROM devices (SPI)
  * Copyright (c) 2013 ygarcia, MIT License
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
@@ -23,19 +23,18 @@
 
     unsigned char CMCP4xxxx_SPI::SPIModuleRefCounter = 0;
 
-    CMCP4xxxx_SPI::CMCP4xxxx_SPI(const PinName p_mosi, const PinName p_miso, const PinName p_sclk, const PinName p_cs, const PinName p_reset, const PinName p_shdn, const unsigned int p_frequency) : _internalId("") {
+    CMCP4xxxx_SPI::CMCP4xxxx_SPI(const PinName p_mosi, const PinName p_miso, const PinName p_sclk, const PinName p_cs, const PinName p_reset, const PinName p_shdn, const Mcp4xxxFamilly p_familly, const unsigned int p_frequency) : _internalId("") {
         DEBUG_ENTER("CMCP4xxxx_SPI")
 
-        CMCP4xxxx_SPI::SPIModuleRefCounter += 1;
-        if (CMCP4xxxx_SPI::SPIModuleRefCounter > 1) {
-            //FIXME Check that SPI settings are identical. Otherwise it should failed
-            return;
+        if (CMCP4xxxx_SPI::SPIModuleRefCounter != 0) {
+            error("CMCP4xxxx_SPI: Wrong params");
         }
 
         _spiInstance = new SPI(p_mosi, p_miso, p_sclk);
         _spiInstance->frequency(p_frequency); // Set the frequency of the SPI interface
         _spiInstance->format(16, 0); // See http://mbed.org/users/mbed_official/code/mbed/docs/0954ebd79f59//classmbed_1_1SPI.html
-        DEBUG("CMCP4xxxx_SPI: refCounter=%d", CMCP4xxxx_SPI::SPIModuleRefCounter)
+        CMCP4xxxx_SPI::SPIModuleRefCounter += 1;
+        DEBUG_ENTER("CMCP4xxxx_SPI: refCounter=%d", CMCP4xxxx_SPI::SPIModuleRefCounter)
 
         if (p_cs != NC) {
             DEBUG("CMCP4xxxx_SPI: /CS managed");
@@ -63,7 +62,12 @@
             DEBUG("CMCP4xxxx_SPI: /SHDN not managed");
             _shdn = NULL; // Not used
         }
-    
+        
+        _familly = p_familly;
+        SetFamilly(p_familly);
+        
+        _incStep = 0x80; // Set to middle step
+        
         DEBUG_LEAVE("CMCP4xxxx_SPI")
     }
 
@@ -79,7 +83,7 @@
         }
         // Release _reset if required
         if (_cs != NULL) {
-            _cs->write(1);
+            _cs->write(0);
             delete _cs;
         }
         // Release _reset if required
@@ -96,28 +100,100 @@
         DEBUG_LEAVE("~CMCP4xxxx_SPI")
     }
     
-    unsigned short CMCP4xxxx_SPI::Write(const Commands p_command, const unsigned char p_value) {
-        DEBUG_ENTER("CMCP4xxxx_SPI::Write: 0x%02x - 0x%02x", (unsigned char)p_command, p_value)
+    unsigned short CMCP4xxxx_SPI::WriteRegister(const Addresses p_address, const unsigned char p_value) {
+        DEBUG_ENTER("CMCP4xxxx_SPI::WriteRegister: 0x%02x - 0x%02x - 0x%02x", (unsigned char)p_address, p_value, (unsigned char)_familly)
         
         // Sanity check
-        if ((p_command != WriteToPot1) && (p_command != WriteToPot2) && (p_command != WriteToBoth)) {
+        if (p_address == CMCP4xxxx_SPI::Status) {
+            // Wrong parameters
+            return (unsigned short) -1;
+        }
+        
+        unsigned short command = ((p_address & 0x0f) << 4 | 0x00/*TODO Use 'define' for Write command*/) << 8;
+        command |= p_value;
+        
+        DEBUG("CMCP4xxxx_SPI::WriteRegister: Send command: 0x%04x", command)
+        if (_cs != NULL) {
+            _cs->write(0);
+        }
+        unsigned short result = _spiInstance->write(command);
+        DEBUG("CMCP4xxxx_SPI::WriteRegister: returned value=%d", result)
+        if (_cs != NULL) {
+            _cs->write(1);
+        }
+        
+        DEBUG_LEAVE("CMCP4xxxx_SPI::WriteRegister: %d", result & 0x00ff)
+        return result & 0x00ff;
+    }
+    
+    unsigned short CMCP4xxxx_SPI::ReadRegister(const Addresses p_address) {
+        DEBUG_ENTER("CMCP4xxxx_SPI::ReadRegister: 0x%02x - 0x%02x", (unsigned char)p_address, (unsigned char)_familly)
+        
+        unsigned short command = ((p_address & 0x0f) << 4 | (0x03/*TODO Use 'define' for Read command*/ << 2)) << 8;
+        
+        DEBUG("CMCP4xxxx_SPI::ReadRegister: Send command: 0x%04x", command)
+        if (_cs != NULL) {
+            _cs->write(0);
+        }
+        unsigned short result = _spiInstance->write(command);
+        DEBUG("CMCP4xxxx_SPI::ReadRegister: full result=0x%04x", result)
+        if (_cs != NULL) {
+            _cs->write(1);
+        }
+        
+        DEBUG_LEAVE("CMCP4xxxx_SPI::ReadRegister: 0x%02x", result & 0x00ff)
+        return result & 0x00ff;
+    }
+    
+    unsigned short CMCP4xxxx_SPI::Incrememt(const Commands p_command) { 
+        // Sanity check
+        if (_incStep != 0xff) { 
+            _incStep += 1; // TODO Change increment 1 by a parametrized increment step
+        }
+        return Write(p_command, _incStep);
+    }
+    
+    unsigned short CMCP4xxxx_SPI::Decrement(const Commands p_command) { 
+        // Sanity check
+        if (_incStep != 0x00) { 
+            _incStep -= 1; // TODO Change increment 1 by a parametrized increment step
+        }
+        return Write(p_command, _incStep);
+    }
+
+    
+    unsigned short CMCP4xxxx_SPI::Write(const Commands p_command, const unsigned char p_value) {
+        DEBUG_ENTER("CMCP4xxxx_SPI::Write: 0x%02x - 0x%02x - 0x%02x", (unsigned char)p_command, p_value, (unsigned char)_familly)
+        
+        // Sanity check
+        if ((p_command != WriteToDigiPot1) && (p_command != WriteToDigiPot2) && (p_command != WriteToBoth)) {
             // Wrong parameters
             return (unsigned short) -1;
         }
         
         unsigned short command = 0;
-        switch (p_command) {
-            case WriteToPot1: 
-                command = (0x11 << 8 | p_value);
-                break;
-            case WriteToPot2:
-                command = (0x12 << 8 | p_value);
-                break;
-            default:
-                command = (0x13 << 8 | p_value);
-        } // End of 'switch' statement
+        if ((_familly == CMCP4xxxx_SPI::_41xxx) || (_familly == CMCP4xxxx_SPI::_42xxx)) {  // See DS11195C
+            switch (p_command) {
+                case WriteToDigiPot1: 
+                    command = (0x11 << 8 | p_value);
+                    break;
+                case WriteToDigiPot2:
+                    command = (0x12 << 8 | p_value);
+                    break;
+                default:
+                    command = (0x13 << 8 | p_value);
+            } // End of 'switch' statement
+        } else { // See DS22060B
+            switch (p_command) {
+                case WriteToDigiPot2:  // Wiper1: adress=0x01, WriteCmd=00
+                    command = (0x01 << 5 | p_value);
+                    break;
+                default:
+                    command = p_value;  // Wiper1: adress=0x00, WriteCmd=00
+            } // End of 'switch' statement
+        }
         
-        DEBUG("CMCP4xxxx_SPI: Send command: 0x%04x", command)
+        DEBUG("CMCP4xxxx_SPI::Write: Send command: 0x%04x", (unsigned char)command, (unsigned char)_familly)
         if (_cs != NULL) {
             _cs->write(0);
         }
@@ -130,28 +206,55 @@
         return result;
     }
 
-    unsigned short CMCP4xxxx_SPI::Write(const Commands p_command) {
-        DEBUG_ENTER("CMCP4xxxx_SPI::Write: 0x%02x", (unsigned char)p_command)
+    unsigned short CMCP4xxxx_SPI::Shutdown(const Commands p_command, const bool p_set) {
+        DEBUG_ENTER("CMCP4xxxx_SPI::Shutdown: 0x%02x - 0x%02x", (unsigned char)p_command, (unsigned char)_familly)
         
         // Sanity check
-        if ((p_command != ShutdownPot1) && (p_command != ShutdownPot2) && (p_command != ShutdownBoth)) {
+        if ((p_command != ShutdownDigiPot1) && (p_command != ShutdownDigiPot2) && (p_command != ShutdownBoth)) {
             // Wrong parameters
             return (unsigned short) -1;
         }
         
        unsigned short command = 0;
-        switch (p_command) {
-            case ShutdownPot1:
-                command = (0x21 << 8);
-                break;
-            case ShutdownPot2:
-                command = (0x21 << 8);
-                break;
-            default: //<! Shutdown both digital potentiometers
-                command = (0x23 << 8);                
-        } // End of 'switch' statement
+       if ((_familly == CMCP4xxxx_SPI::_41xxx) || (_familly == CMCP4xxxx_SPI::_42xxx)) { // See DS11195C
+           switch (p_command) {
+                case ShutdownDigiPot1:
+                    command = (0x21 << 8);
+                    break;
+                case ShutdownDigiPot2:
+                    command = (0x21 << 8);
+                    break;
+                default: //<! Shutdown both digital potentiometers
+                    command = (0x23 << 8);                
+            } // End of 'switch' statement
+        } else { // See DS22060B
+            unsigned short tcon = ReadRegister(TCon); // Read TCon register 
+            if (p_set == true) {
+               switch (p_command) {
+                    case ShutdownDigiPot1:
+                        command = 0x4000 | (tcon & 0xf8);
+                        break;
+                    case ShutdownDigiPot2:
+                        command = 0x4000 | (tcon & 0x8f);
+                        break;
+                    default: //<! Shutdown both digital potentiometers
+                        command = 0x4000;                
+                } // End of 'switch' statement
+            } else {
+                switch (p_command) {
+                    case ShutdownDigiPot1:
+                        command = 0x4000 | (tcon | 0x000f);
+                        break;
+                    case ShutdownDigiPot2:
+                        command = 0x4000 | (tcon | 0x00f0);
+                        break;
+                    default: //<! Shutdown both digital potentiometers
+                        command = 0x40ff;                
+                } // End of 'switch' statement
+            }
+        }
         
-        DEBUG("CMCP4xxxx_SPI: Send command: 0x%04x", command)
+        DEBUG("CMCP4xxxx_SPI::Shutdown: Send command: 0x%04x", command)
         if (_cs != NULL) {
             _cs->write(0);
         }
@@ -160,35 +263,43 @@
             _cs->write(1);
         }
         
-        DEBUG_LEAVE("CMCP4xxxx_SPI::Write: %d", result)
+        DEBUG_LEAVE("CMCP4xxxx_SPI::Shutdown: %d", result)
         return result;
     }
     unsigned short CMCP4xxxx_SPI::Write() {
         return _spiInstance->write(0);
     }
-
-    bool CMCP4xxxx_SPI::Reset() {
-        // Sanity check
-        if (_reset == NULL) {
-            return false;
+    
+    CMCP4xxxx_SPI::Mcp4xxxFamilly CMCP4xxxx_SPI::SetFamilly(const CMCP4xxxx_SPI::Mcp4xxxFamilly p_familly) { 
+        DEBUG_ENTER("CMCP4xxxx_SPI::SetFamilly: 0x%02x", (unsigned char)p_familly)
+        
+        Mcp4xxxFamilly old = _familly;
+        _familly = p_familly;
+        if ((_familly != CMCP4xxxx_SPI::_41xxx) && (_familly != CMCP4xxxx_SPI::_42xxx)) {
+            // Setup TCON register 
+            DEBUG("CMCP4xxxx_SPI::SetFamilly: Setup TCON register")
+            WriteRegister(CMCP4xxxx_SPI::TCon, 0x7f); // See DS22060B-page 36 REGISTER 4-2: TCON BITS
+                                                      // TODO Use 'define' for command
         }
         
-        _reset->write(0); // Set level low to activate reset 
-        wait_us(1); // Wait for 1us
-        _reset->write(1); // Set level low to de-activate reset 
-       
-        return true;
+       DEBUG_LEAVE("CMCP4xxxx_SPI::SetFamilly: 0x%02x", (unsigned char)old)
+       return old;
+    }
+
+    void CMCP4xxxx_SPI::Reset() {
+        _incStep = 0x80; // Set to middle step
+        // Sanity check
+        if (_reset != NULL) {
+            _reset->write(0); // Set level low to activate reset 
+            wait_us(1); // Wait for 1us
+            _reset->write(1); // Set level low to de-activate reset 
+        }       
     }
     
-    bool CMCP4xxxx_SPI::Shutdown(const bool p_set) {
-        // Sanity check
-        if (_shdn == NULL) {
-            return false;
+    void CMCP4xxxx_SPI::Shutdown(const bool p_set) {
+        if (_shdn != NULL) {
+            _shdn->write(p_set == false ? 0 : 1);
         }
-        
-        _shdn->write(p_set == false ? 0 : 1);
-        
-        return true;
     }
 
 } // End of namespace MCP4xxxx_SPI
--- a/MCP4xxxx_SPI.h	Fri Apr 05 13:36:29 2013 +0000
+++ b/MCP4xxxx_SPI.h	Thu Jun 06 07:59:16 2013 +0000
@@ -26,13 +26,19 @@
 
 namespace MCP4xxxx_SPI {
 
-    /** This class provides simplified SPI access to a Microchip MCP42xxx/MCP41xxx Digital Potentiometer device. V0.0.0.1
+    /** This class provides simplified SPI access to a Microchip MCP42xxx/MCP41xxx Digital Potentiometer device. V0.0.0.2
+     * The SPI static settings are: 16bits, mode (0,0)
+     * This class manages ONLY ONE /CS pin. If more than one SPI devices are used, ALL /CS pins shall be done by the application itself
      *
      * Microchip MCP42xxx/MCP41xxx Serial EEPROM device reference: DS11195C
+     * Microchip MCP41xx/MCP42xx Serial EEPROM device reference: DS122060B
      *
+     * Note that MCP41xxx has no SO pin, only a SOI input pin
+     * Note that MCP42xxx has a SO pin reserved for daisy-chain configuration
+     * Note that MCP41xx/MCP42xx increment/decrement operations are not supported due to the 16 bits SPI setting
      * 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
+     * @remark This class was validated with Tektronix TDS2014 oscilloscope in 3.3V and in mixte power mode 3.3V for mbed and 5V for the Microchip 24LCxx Serial EEPROM device
      * @author Yann Garcia (Don't hesitate to contact me: garcia.yann@gmail.com)
      */
     class CMCP4xxxx_SPI { 
@@ -55,17 +61,37 @@
         /** An unique instance of SPI class
          */
         SPI *_spiInstance;
+        /** Increment step value used for inc/dec methods, when inc/dec commands are not supported (such as _4xxxx famillies)
+         */
+        unsigned char _incStep;
+     public:
+        /** MCP32xx familly
+         */
+        enum Mcp4xxxFamilly {
+            _41xxx = 0x00,  //<! 41xxx familly such as MCP41010 - See DS11195C
+            _42xxx = 0x01,  //<! 42xxx familly such as MCP42010 - See DS11195C
+            _41xx = 0x02,   //<! 41xx familly such as MCP4251 - Single Potentiometer/Rheostat
+            _42xx = 0x03    //<! 42x2 familly such as MCP42x2 - Dual Potentiometer/Rheostat
+       };
+        Mcp4xxxFamilly _familly;     
      public:
         /** Authorized commands
          * See DS11195C-page 18
          */
         enum Commands {
-            WriteToPot1, //<! Write to digital potentiometer #1
-            WriteToPot2, //<! Write to digital potentiometer #2
-            WriteToBoth, //<! Write to both digital potentiometers
-            ShutdownPot1, //<! Shutdown digital potentiometer #1
-            ShutdownPot2, //<! Shutdown digital potentiometer #2
-            ShutdownBoth, //<! Shutdown both digital potentiometers
+            WriteToDigiPot1,    //<! Write to digital potentiometer #1
+            WriteToDigiPot2,    //<! Write to digital potentiometer #2
+            WriteToBoth,        //<! Write to both digital potentiometers
+            ShutdownDigiPot1,   //<! Shutdown digital potentiometer #1
+            ShutdownDigiPot2,   //<! Shutdown digital potentiometer #2
+            ShutdownBoth,       //<! Shutdown both digital potentiometers
+        };
+        /** Register adresses
+         * See DS22060B-page 33 Clause 4.0 FUNCTIONAL OVERVIEW 
+         */
+        enum Addresses {
+            TCon = 0x04,
+            Status = 0x05
         };
    public:
         /** Constructor with Write Protect command pin wired.
@@ -78,10 +104,9 @@
          * @param p_shdn: MBed pin to manage /SHDN input. If NC, /SHDN is not managed, default value is NC, not connected
          * @param p_frequency: Frequency of the SPI interface (SCK), default value is 1MHz
          */
-        CMCP4xxxx_SPI(const PinName p_mosi, const PinName p_miso, const PinName p_sclk, const PinName p_cs = NC, const PinName p_reset = NC, const PinName p_shdn = NC, const unsigned int p_frequency = 1000000);
+        CMCP4xxxx_SPI(const PinName p_mosi, const PinName p_miso, const PinName p_sclk, const PinName p_cs = NC, const PinName p_reset = NC, const PinName p_shdn = NC, const Mcp4xxxFamilly familly = _41xxx, const unsigned int p_frequency = 1000000);
     
         /** Destructor
-         * /CS pin is set to 1 before to release it
          */
         virtual ~CMCP4xxxx_SPI();
 
@@ -89,9 +114,34 @@
          */
         inline const SPI * operator * () { return (const SPI *)_spiInstance; };
 
+        /** Write a value to the specified register. Only for _41xx/_42xx famillies
+         * @param p_address The register to be written
+         * @param p_value The value to write
+         * @return 0x0000 on success, any value otherwise
+         */
+        unsigned short WriteRegister(const Addresses p_address, const unsigned char p_value);
+        
+        /** Read the content of the specified register. Only for _41xx/_42xx famillies
+         * @param p_address The register to be written
+         * @return The register value 
+         */
+        unsigned short ReadRegister(const Addresses p_address);
+        
+        /** Increment the specified digital potentiometer
+         * @param p_command The digital potentiometer to increment. Default: WriteToDigiPot1
+         * @return 0x0000 on success, any value otherwise
+         */
+        unsigned short Incrememt(const Commands p_command = WriteToDigiPot1);
+        
+        /** Decrement the specified digital potentiometer
+         * @param p_command The digital potentiometer to decrement. Default: WriteToDigiPot1
+         * @return 0x0000 on success, any value otherwise
+         */
+        unsigned short Decrement(const Commands p_command = WriteToDigiPot1);
+
         /** Send a write a command (WriteToPot1, WriteToPot2 or WriteBoth)
          *
-         * @param p_command The command to execute: Write or Shutdown (See DS11195C-page 18)
+         * @param p_command The command to execute (See DS11195C-page 18)
          * @param p_value The potentiometer selection bits (See DS11195C-page 14 Clause 4.1 Modes of Operation)
          * @return 0x0000 on success, 0Xffff otherwise
          * Exemple:
@@ -108,42 +158,48 @@
     
         /** Send a shutdown a command (ShutdownPot1, ShutdownPot2 or ShutdownBoth)
          *
-         * @param p_command The command to execute: Write or Shutdown (See DS11195C-page 18)
-         * @param p_value The potentiometer selection bits (See DS11195C-page 14 Clause 4.1 Modes of Operation)
+         * @param p_command The command to execute (See DS11195C-page 18)
+         * @param p_set Set to true to shutdown, false to set up. Only used for _41xx/_42xx famillies (See DS22060B-page 36 REGISTER 4-2: TCON BITS)
          * @return 0x0000 on success, 0Xffff otherwise
          * Exemple:
          * @code
          * ...
          * g_chipSelect.write(0);
-         * g_digitalPot.Write(CMCP4xxxx_SPI::ShutdownPot1);
+         * g_digitalPot.Shutdown(CMCP4xxxx_SPI::ShutdownPot1);
          * g_chipSelect.write(1);
          * ...
          * @endcode
          */
-        unsigned short Write(const Commands p_command);
+        unsigned short Shutdown(const Commands p_command, const bool p_set = true);
     
          /** Write a NOP command
-         */
+          */
         unsigned short Write();
     
+         /** Change the current familly 
+          * @param familly The new type of ICs 
+          * @return the previous type of ICs 
+          */
+        Mcp4xxxFamilly SetFamilly(const Mcp4xxxFamilly familly);
+    
        /** Reset the device
-         * @code
-         * unsigned char potLevel;
-         * ...
-         * g_chipSelect.write(0);
-         * g_digitalPot.Reset();
-         * g_chipSelect.write(1);
-         * ...
-         * @endcode
-         */
-        bool Reset();
+        * @code
+        * unsigned char potLevel;
+        * ...
+        * g_digitalPot.Reset();
+        * ...
+        * @endcode
+        */
+        void Reset();
     
         /** Shutdown the device
          */
-        bool Shutdown(const bool p_set);
+        void Shutdown(const bool p_set);
     
     private:
-        /** Internal reference identifier
+        /** Internal reference identifier. Only used when /RS in is available
+         *
+         * @param p_set Set to true to shutdown, false to set up
          */
         std::string _internalId;