Simplified access to a Microchip Digital Potentiometer (MCP41xxx/MCP42xxx) devices
Dependents: MCP41xxxApp MCP320xApp MCP41xxxApp
MCP4xxxx_SPI.cpp
- Committer:
- Yann
- Date:
- 2013-09-05
- Revision:
- 7:12a0d89aa72f
- Parent:
- 6:ded0d8a6729c
File content as of revision 7:12a0d89aa72f:
/* 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 * 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 "MCP4xxxx_SPI.h" namespace MCP4xxxx_SPI { 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 Mcp4xxxFamily p_family, const unsigned int p_frequency) : _internalId("") { DEBUG_ENTER("CMCP4xxxx_SPI") 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 CMCP4xxxx_SPI::SPIModuleRefCounter += 1; DEBUG_ENTER("CMCP4xxxx_SPI: refCounter=%d", CMCP4xxxx_SPI::SPIModuleRefCounter) if (p_cs != NC) { DEBUG("CMCP4xxxx_SPI: /CS managed"); _cs = new DigitalOut(p_cs); _cs->write(1); // Disable chip } else { DEBUG("CMCP4xxxx_SPI: /CS not managed"); _cs = NULL; // Not used } if (p_reset != NC) { DEBUG("CMCP4xxxx_SPI: /RESET managed"); _reset = new DigitalOut(p_reset); _reset->write(1); // Disable reset } else { DEBUG("CMCP4xxxx_SPI: /RESET not managed"); _reset = NULL; // Not used } if (p_shdn != NC) { DEBUG("CMCP4xxxx_SPI: /SHDN managed"); _shdn = new DigitalOut(p_shdn); _shdn->write(1); // Disable shutdown } else { DEBUG("CMCP4xxxx_SPI: /SHDN not managed"); _shdn = NULL; // Not used } _family = p_family; SetFamilly(p_family); _incStep = 0x80; // Set to middle step DEBUG_LEAVE("CMCP4xxxx_SPI") } CMCP4xxxx_SPI::~CMCP4xxxx_SPI() { DEBUG_ENTER("~CMCP4xxxx_SPI") // Release I2C instance DEBUG_ENTER("~CMCP4xxxx_SPI: refCounter=%d", CMCP4xxxx_SPI::SPIModuleRefCounter) CMCP4xxxx_SPI::SPIModuleRefCounter -= 1; if (CMCP4xxxx_SPI::SPIModuleRefCounter == 0) { delete _spiInstance; _spiInstance = NULL; } // Release _reset if required if (_cs != NULL) { _cs->write(0); delete _cs; } // Release _reset if required if (_reset != NULL) { _reset->write(0); delete _reset; } // Release _shdn if required if (_shdn != NULL) { _shdn->write(0); delete _shdn; } DEBUG_LEAVE("~CMCP4xxxx_SPI") } 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)_family) // Sanity check 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); 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", (unsigned char)p_address) 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::Increment(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)_family) // Sanity check if ((p_command != WriteToDigiPot1) && (p_command != WriteToDigiPot2) && (p_command != WriteToBoth)) { // Wrong parameters return (unsigned short) -1; } unsigned short command = 0; if ((_family == CMCP4xxxx_SPI::_41xxx) || (_family == 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::Write: Send command: 0x%04x", (unsigned char)command) if (_cs != NULL) { _cs->write(0); } unsigned short result = _spiInstance->write(command); if (_cs != NULL) { _cs->write(1); } DEBUG_LEAVE("CMCP4xxxx_SPI::Write: %d", result) return result; } 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)_family) // Sanity check if ((p_command != ShutdownDigiPot1) && (p_command != ShutdownDigiPot2) && (p_command != ShutdownBoth)) { // Wrong parameters return (unsigned short) -1; } unsigned short command = 0; if ((_family == CMCP4xxxx_SPI::_41xxx) || (_family == 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::Shutdown: Send command: 0x%04x", command) if (_cs != NULL) { _cs->write(0); } unsigned short result = _spiInstance->write(command); if (_cs != NULL) { _cs->write(1); } DEBUG_LEAVE("CMCP4xxxx_SPI::Shutdown: %d", result) return result; } //unsigned short CMCP4xxxx_SPI::Write() { // return _spiInstance->write(0); //} CMCP4xxxx_SPI::Mcp4xxxFamily CMCP4xxxx_SPI::SetFamilly(const CMCP4xxxx_SPI::Mcp4xxxFamily p_family) { DEBUG_ENTER("CMCP4xxxx_SPI::SetFamilly: 0x%02x", (unsigned char)p_family) Mcp4xxxFamily old = _family; _family = p_family; if ((_family != CMCP4xxxx_SPI::_41xxx) && (_family != CMCP4xxxx_SPI::_42xxx)) { // Setup TCON register DEBUG("CMCP4xxxx_SPI::SetFamilly: Setup TCON register") WriteRegister(CMCP4xxxx_SPI::TCon, 0xff); // See DS22060B-page 36 REGISTER 4-2: TCON BITS // TODO Use 'define' for command } 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 } } void CMCP4xxxx_SPI::Shutdown(const bool p_set) { if (_shdn != NULL) { _shdn->write(p_set == false ? 0 : 1); } } } // End of namespace MCP4xxxx_SPI