Skip to content

Commit

Permalink
Revision 1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
jmalloc committed Jul 21, 2012
0 parents commit d339ff4
Show file tree
Hide file tree
Showing 2 changed files with 305 additions and 0 deletions.
119 changes: 119 additions & 0 deletions mcp4xxx.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
#include "mcp4xxx.h"

namespace icecave {
namespace arduino {

MCP4XXX::MCP4XXX(byte select_pin, Pot pot, MemorySize memory_size, WiperConfiguration config)
: m_select_pin(select_pin)
, m_pot_address(static_cast<Address>(pot))
, m_max_value(memory_size + config) // Potentiometer configurations allow "memory_size + 1" values, for setting the "full-scale" wiper position.
{
SPI.begin();
pinMode(m_select_pin, OUTPUT);
deselect();
}


word MCP4XXX::max_value(void) const
{
return m_max_value;
}

bool MCP4XXX::increment(void)
{
return transfer(m_pot_address, command_increment);
}

bool MCP4XXX::decrement(void)
{
return transfer(m_pot_address, command_decrement);
}

bool MCP4XXX::set(word value)
{
return transfer(m_pot_address, command_write, min(value, m_max_value));
}

bool MCP4XXX::get(word& value) const
{
return transfer(m_pot_address, command_read, data_mask_word, value);
}

word MCP4XXX::get(void) const
{
word result = 0xFFFF;
get(result);
return result;
}

void MCP4XXX::select(void) const
{
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE0);
SPI.setClockDivider(SPI_CLOCK_DIV128);
digitalWrite(m_select_pin, LOW);
}

void MCP4XXX::deselect(void) const
{
digitalWrite(m_select_pin, HIGH);
}

byte MCP4XXX::build_command(Address address, Command command) const
{
return ((address << 4) & address_mask)
| ((command << 2) & command_mask)
| cmderr_mask;
}

word MCP4XXX::build_command(Address address, Command command, word data) const
{
return (build_command(address, command) << 8)
| (data & data_mask_word);
}

bool MCP4XXX::transfer(Address address, Command command) const
{
select();
byte result = SPI.transfer(build_command(address, command));
deselect();
return result & cmderr_mask;
}

bool MCP4XXX::transfer(Address address, Command command, word data) const
{
select();

word cmd = build_command(address, command, data);
bool valid = SPI.transfer(highByte(cmd)) & cmderr_mask;

if (valid)
{
SPI.transfer(lowByte(cmd));
}

deselect();
return valid;
}

bool MCP4XXX::transfer(Address address, Command command, word data, word& result) const
{
select();

word cmd = build_command(address, command, data);
byte high_byte = SPI.transfer(highByte(cmd));
bool valid = high_byte & cmderr_mask;

if (valid)
{
result = ((high_byte & data_mask) << 8)
| SPI.transfer(lowByte(cmd));
}

deselect();
return valid;
}

} // end namespace arduino
} // end namespace icecave

186 changes: 186 additions & 0 deletions mcp4xxx.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
#ifndef __ICECAVE_ARDUINO_MCP4XXX
#define __ICECAVE_ARDUINO_MCP4XXX

#include <Arduino.h>
#include <SPI.h>

namespace icecave {
namespace arduino {

/**
* This class controls Microchip's MCP4XXX range of digital potentiometers.
* http://ww1.microchip.com/downloads/en/DeviceDoc/22060b.pdf
*
* The supported chips are configured as follows:
*
* MCP 4 X Y Z
* | | |
* | | +- Z = Wiper Configuration (1 = Potentiometer, 2 = Rheostat).
* | |
* | +--- Y = Memory Type (3 = 7-bit RAM, 4 = 7-bit EEPROM, 5 = 8-bit RAM, 6 = 8-bit EEPROM).
* |
* +----- X = Number of pots (1 or 2).
*
* Note that the MCP41X1 chips multiplex the SDI and SDO on a single pin.
* To use these chips with a standard SPI interface as on the Arduino you will need to
* connect the SDI/SDO pin on the pot to the Arduino's MISO pin, then bridge the MISO pin to the MOSI pin
* with a resistor (3k9 resistor seems to work well).
*
* This class has only been tested with the MCP4151.
*/
class MCP4XXX
{
public:
enum Pot
{
pot_0 = B00,
pot_1 = B01
};

enum MemorySize
{
memory_7bit = 127,
memory_8bit = 255
};

enum WiperConfiguration
{
rheostat = 0,
potentiometer = 1
};

/**
* select_pin - The pin to use for the SPI slave select signal, defaults to the main slave select pin on your Arduino.
* pot - For the 2-pot variants (MCP42XX), the potentiometer to control. Must be pot_0 for MCP41XX chips.
* memory_size - memory_7bit for MCP4X3X and MCP4X4X, memory_8bit for MCP4X5X and MCP4X6X.
*/
MCP4XXX(byte select_pin = SS, Pot pot = pot_0, MemorySize memory_size = memory_8bit, WiperConfiguration config = potentiometer);

/**
* Retrieve the maximum value allowed for the wiper position.
*
* The maximum value depends on the device's memory type and wiper configuration.
*
* 7-bit devices have a maximum value of 127 for rheostats and 128 for potentiometers.
* 8-bit devices have a maximum value of 255 for rheostats and 256 for potentiometers.
*
* The higher value on potentiometers (MCP4XX1) facilitates direct connection of the wiper to the "A" terminal (also known as "full-scale").
* Confusingly the rheostat devices (MCP4XX2) have only a wiper pin and "B" terminal pin, (not "A").
*/
word max_value(void) const;

/**
* Increase the wiper position by 1.
*
* Returns TRUE on success; otherwise, FALSE.
*/
bool increment(void);

/**
* Decrease the wiper position by 1.
*
* Returns TRUE on success; otherwise, FALSE.
*/
bool decrement(void);

/**
* Set the wiper position.
*
* value - The new wiper position (must be between 0 and max_value()).
*
* Returns TRUE on success; otherwise, FALSE.
*/
bool set(word value);

/**
* Get the wiper position.
*
* value - Assigned the value of the current wiper position when retrieved successfully.
*
* Returns TRUE on success; otherwise, FALSE.
*/
bool get(word& value) const;

/**
* Get the wiper position.
*
* Returns the current wiper position, a value of 0xFFFF indicates a failure.
*/
word get(void) const;

private:
const static byte address_mask = B11110000;
const static byte command_mask = B00001100;
const static byte cmderr_mask = B00000010;
const static byte data_mask = B00000001;
const static word data_mask_word = 0x01FF;

enum Address
{
address_pot0_wiper = B0000
, address_pot1_wiper = B0001
, address_tcon = B0100
, address_status = B0101
};

enum Command
{
command_write = B00
, command_read = B11
, command_increment = B01
, command_decrement = B10
};

/**
* Select this device for SPI communication
*
* Configures SPI for communication with MCP devices, and sends slave-select pin LOW.
*/
void select(void) const;

/**
* Cease SPI communications with this device.
*
* Sends the slave-select pin HIGH.
*/
void deselect(void) const;

/**
* Build an 8-bit command.
*/
byte build_command(Address address, Command command) const;

/**
* Build a 16-bit command.
*/
word build_command(Address address, Command command, word data) const;

/**
* Transfer an 8-bit command.
*/
bool transfer(Address address, Command command) const;

/**
* Transfer a 16-bit command.
*
* Result is TRUE if address/command combination is valid; otherwise, FALSE.
*/
bool transfer(Address address, Command command, word data) const;

/**
* Transfer a 16-bit command, and read the response.
*
* Result is TRUE if address/command combination is valid; otherwise, FALSE.
*
* The result argument is populated with the 9-bit response only if return value is TRUE.
*/
bool transfer(Address address, Command command, word data, word& result) const;

byte m_select_pin;
Address m_pot_address;
word m_max_value;
};

} // end namespace arduino
} // end namespace icecave
#endif // __ICECAVE_ARDUINO_MCP4XXX

0 comments on commit d339ff4

Please sign in to comment.