Simplified access to a Microchip Digital Potentiometer (MCP41xxx/MCP42xxx) devices
Dependents: MCP41xxxApp MCP320xApp MCP41xxxApp
Revision 6:ded0d8a6729c, committed 2013-06-06
- 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;
Yann Garcia