-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit d339ff4
Showing
2 changed files
with
305 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |