mirror of
https://github.com/RobTillaart/Arduino.git
synced 2024-10-03 18:09:02 -04:00
461 lines
8.4 KiB
C++
461 lines
8.4 KiB
C++
//
|
|
// FILE: MAX14661.cpp
|
|
// AUTHOR: Rob Tillaart
|
|
// DATE: 2021-01-29
|
|
// VERSION: 0.1.2
|
|
// PURPOSE: Arduino library for MAX14661 16 channel I2C multiplexer
|
|
// URL: https://github.com/RobTillaart/MAX14661
|
|
//
|
|
// HISTORY:
|
|
// 0.1.0 2021-01-29 initial version
|
|
// 0.1.1 2021-08-30 add shadow interface - experimental
|
|
// 0.1.2 2021-12-21 update library.json, license, minor edits
|
|
|
|
|
|
#include "MAX14661.h"
|
|
|
|
|
|
// registers
|
|
#define MAX14661_DIR0 0x00
|
|
#define MAX14661_DIR1 0x01
|
|
#define MAX14661_DIR2 0x02
|
|
#define MAX14661_DIR3 0x03
|
|
#define MAX14661_SHDW0 0x10
|
|
#define MAX14661_SHDW1 0x11
|
|
#define MAX14661_SHDW2 0x12
|
|
#define MAX14661_SHDW3 0x13
|
|
#define MAX14661_CMD_A 0x14
|
|
#define MAX14661_CMD_B 0x15
|
|
|
|
|
|
|
|
MAX14661::MAX14661(const uint8_t deviceAddress, TwoWire *wire)
|
|
{
|
|
_address = deviceAddress;
|
|
_wire = wire;
|
|
}
|
|
|
|
|
|
#if defined (ESP8266) || defined(ESP32)
|
|
bool MAX14661::begin(uint8_t dataPin, uint8_t clockPin)
|
|
{
|
|
_wire = &Wire;
|
|
if ((dataPin < 255) && (clockPin < 255))
|
|
{
|
|
_wire->begin(dataPin, clockPin);
|
|
} else {
|
|
_wire->begin();
|
|
}
|
|
_error = 0;
|
|
if (! isConnected()) return false;
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
|
|
bool MAX14661::begin()
|
|
{
|
|
_wire->begin();
|
|
_error = 0;
|
|
|
|
if (! isConnected()) return false;
|
|
return true;
|
|
}
|
|
|
|
|
|
bool MAX14661::isConnected()
|
|
{
|
|
_wire->beginTransmission(_address);
|
|
return ( _wire->endTransmission() == 0);
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////
|
|
//
|
|
// PAIR INTERFACE
|
|
//
|
|
bool MAX14661::openChannel(uint8_t channel)
|
|
{
|
|
if (channel > 15) return false;
|
|
uint8_t ch = channel;
|
|
uint8_t reg = MAX14661_DIR0;
|
|
if (ch > 7)
|
|
{
|
|
reg = MAX14661_DIR1;
|
|
ch -= 8;
|
|
}
|
|
uint8_t mask = readRegister(reg);
|
|
mask |= (1 << ch);
|
|
writeRegister(reg, mask);
|
|
reg += 2;
|
|
mask = readRegister(reg);
|
|
mask |= (1 << ch);
|
|
writeRegister(reg, mask);
|
|
return true;
|
|
}
|
|
|
|
|
|
bool MAX14661::closeChannel(uint8_t channel)
|
|
{
|
|
if (channel > 15) return false;
|
|
uint8_t ch = channel;
|
|
uint8_t reg = MAX14661_DIR0;
|
|
if (ch > 7)
|
|
{
|
|
reg = MAX14661_DIR1;
|
|
ch -= 8;
|
|
}
|
|
uint8_t mask = readRegister(reg);
|
|
mask &= ~(1 << ch);
|
|
writeRegister(reg, mask);
|
|
reg += 2;
|
|
mask = readRegister(reg);
|
|
mask &= ~(1 << ch);
|
|
writeRegister(reg, mask);
|
|
return true;
|
|
}
|
|
|
|
|
|
// assumption both A and B are in same state
|
|
bool MAX14661::isOpenChannel(uint8_t channel)
|
|
{
|
|
if (channel > 15) return false;
|
|
uint8_t ch = channel;
|
|
uint8_t reg = MAX14661_DIR0;
|
|
if (ch > 7)
|
|
{
|
|
reg = MAX14661_DIR1;
|
|
ch -= 8;
|
|
}
|
|
uint8_t mask = readRegister(reg);
|
|
return (mask & (1 << ch)) > 0;
|
|
}
|
|
|
|
|
|
void MAX14661::openAllChannels()
|
|
{
|
|
setChannels(0xFFFF);
|
|
}
|
|
|
|
|
|
void MAX14661::closeAllChannels()
|
|
{
|
|
setChannels(0);
|
|
}
|
|
|
|
void MAX14661::setChannels(uint16_t mask)
|
|
{
|
|
writeRegister(MAX14661_DIR0, mask & 0x00FF);
|
|
writeRegister(MAX14661_DIR1, (mask & 0xFF00) >> 8);
|
|
writeRegister(MAX14661_DIR2, mask & 0x00FF);
|
|
writeRegister(MAX14661_DIR3, (mask & 0xFF00) >> 8);
|
|
}
|
|
|
|
|
|
// assumption both A and B are in same state
|
|
uint16_t MAX14661::getChannels()
|
|
{
|
|
uint16_t channels = readRegister(MAX14661_DIR1) << 8;
|
|
channels |= readRegister(MAX14661_DIR0);
|
|
return channels;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////
|
|
//
|
|
// SHADOW INTERFACE
|
|
//
|
|
void MAX14661::shadowClear()
|
|
{
|
|
setShadowChannelMaskA(0x0000);
|
|
setShadowChannelMaskB(0x0000);
|
|
}
|
|
|
|
|
|
void MAX14661::activateShadow()
|
|
{
|
|
writeRegister(MAX14661_CMD_A, 0x11);
|
|
writeRegister(MAX14661_CMD_B, 0x11);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
void MAX14661::setShadowChannelMaskA(uint16_t mask)
|
|
{
|
|
writeRegister(MAX14661_SHDW0, mask & 0xFF);
|
|
writeRegister(MAX14661_SHDW1, mask >> 8);
|
|
}
|
|
|
|
|
|
uint16_t MAX14661::getShadowChannelMaskA()
|
|
{
|
|
uint16_t mask = readRegister(MAX14661_SHDW1) << 8;
|
|
mask |= readRegister(MAX14661_SHDW0);
|
|
return mask;
|
|
}
|
|
|
|
|
|
void MAX14661::setShadowChannelMaskB(uint16_t mask)
|
|
{
|
|
writeRegister(MAX14661_SHDW2, mask & 0xFF);
|
|
writeRegister(MAX14661_SHDW3, mask >> 8);
|
|
}
|
|
|
|
|
|
uint16_t MAX14661::getShadowChannelMaskB()
|
|
{
|
|
uint16_t mask = readRegister(MAX14661_SHDW3) << 8;
|
|
mask |= readRegister(MAX14661_SHDW2);
|
|
return mask;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
bool MAX14661::openShadowChannelA(uint8_t channel)
|
|
{
|
|
if (channel > 15) return false;
|
|
uint8_t ch = channel;
|
|
uint8_t reg = MAX14661_SHDW0;
|
|
if (ch > 7)
|
|
{
|
|
reg = MAX14661_SHDW1;
|
|
ch -= 8;
|
|
}
|
|
uint8_t mask = readRegister(reg);
|
|
mask |= (1 << ch);
|
|
writeRegister(reg, mask);
|
|
return true;
|
|
}
|
|
|
|
|
|
bool MAX14661::closeShadowChannelA(uint8_t channel)
|
|
{
|
|
if (channel > 15) return false;
|
|
uint8_t ch = channel;
|
|
uint8_t reg = MAX14661_SHDW0;
|
|
if (ch > 7)
|
|
{
|
|
reg = MAX14661_SHDW1;
|
|
ch -= 8;
|
|
}
|
|
uint8_t mask = readRegister(reg);
|
|
mask &= ~(1 << ch);
|
|
writeRegister(reg, mask);
|
|
return true;
|
|
}
|
|
|
|
|
|
bool MAX14661::isOpenShadowChannelA(uint8_t channel)
|
|
{
|
|
if (channel > 15) return false;
|
|
uint8_t ch = channel;
|
|
uint8_t reg = MAX14661_SHDW0;
|
|
if (ch > 7)
|
|
{
|
|
reg = MAX14661_SHDW1;
|
|
ch -= 8;
|
|
}
|
|
uint8_t mask = readRegister(reg);
|
|
return (mask & (1 << ch)) > 0;
|
|
}
|
|
|
|
|
|
bool MAX14661::openShadowChannelB(uint8_t channel)
|
|
{
|
|
if (channel > 15) return false;
|
|
uint8_t ch = channel;
|
|
uint8_t reg = MAX14661_SHDW0;
|
|
if (ch > 7)
|
|
{
|
|
reg = MAX14661_SHDW1;
|
|
ch -= 8;
|
|
}
|
|
uint8_t mask = readRegister(reg);
|
|
mask |= (1 << ch);
|
|
writeRegister(reg, mask);
|
|
return true;
|
|
}
|
|
|
|
|
|
bool MAX14661::closeShadowChannelB(uint8_t channel)
|
|
{
|
|
if (channel > 15) return false;
|
|
uint8_t ch = channel;
|
|
uint8_t reg = MAX14661_SHDW2;
|
|
if (ch > 7)
|
|
{
|
|
reg = MAX14661_SHDW3;
|
|
ch -= 8;
|
|
}
|
|
uint8_t mask = readRegister(reg);
|
|
mask &= ~(1 << ch);
|
|
writeRegister(reg, mask);
|
|
return true;
|
|
}
|
|
|
|
|
|
bool MAX14661::isOpenShadowChannelB(uint8_t channel)
|
|
{
|
|
if (channel > 15) return false;
|
|
uint8_t ch = channel;
|
|
uint8_t reg = MAX14661_SHDW2;
|
|
if (ch > 7)
|
|
{
|
|
reg = MAX14661_SHDW3;
|
|
ch -= 8;
|
|
}
|
|
uint8_t mask = readRegister(reg);
|
|
return (mask & (1 << ch)) > 0;
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////
|
|
//
|
|
// MUX INTERFACE
|
|
//
|
|
void MAX14661::MUXA(uint8_t channel)
|
|
{
|
|
uint8_t ch = channel;
|
|
if (channel > 15) ch = 0x10;
|
|
writeRegister(MAX14661_CMD_A, ch);
|
|
}
|
|
|
|
|
|
uint8_t MAX14661::getMUXA()
|
|
{
|
|
uint8_t ch = readRegister(MAX14661_CMD_A);
|
|
if ((ch & 0x10) == 0) return (ch & 0x0F);
|
|
return 255;
|
|
}
|
|
|
|
|
|
void MAX14661::MUXB(uint8_t channel)
|
|
{
|
|
uint8_t ch = channel;
|
|
if (channel > 15) ch = 0x10;
|
|
writeRegister(MAX14661_CMD_B, ch);
|
|
}
|
|
|
|
|
|
uint8_t MAX14661::getMUXB()
|
|
{
|
|
uint8_t ch = readRegister(MAX14661_CMD_B);
|
|
if ((ch & 0x10) == 0) return (ch & 0x0F);
|
|
return 255;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////
|
|
//
|
|
// FULL CONTROL
|
|
//
|
|
bool MAX14661::openA(uint8_t channel)
|
|
{
|
|
if (channel > 15) return false;
|
|
uint8_t ch = channel;
|
|
uint8_t reg = MAX14661_DIR0;
|
|
if (ch > 7)
|
|
{
|
|
reg = MAX14661_DIR1;
|
|
ch -= 8;
|
|
}
|
|
uint8_t mask = readRegister(reg);
|
|
mask |= (1 << ch);
|
|
writeRegister(reg, mask);
|
|
return true;
|
|
}
|
|
|
|
|
|
bool MAX14661::openB(uint8_t channel)
|
|
{
|
|
if (channel > 15) return false;
|
|
uint8_t ch = channel;
|
|
uint8_t reg = MAX14661_DIR2;
|
|
if (ch > 7)
|
|
{
|
|
reg = MAX14661_DIR3;
|
|
ch -= 8;
|
|
}
|
|
uint8_t mask = readRegister(reg);
|
|
mask |= (1 << ch);
|
|
writeRegister(reg, mask);
|
|
return true;
|
|
}
|
|
|
|
|
|
bool MAX14661::closeA(uint8_t channel)
|
|
{
|
|
if (channel > 15) return false;
|
|
uint8_t ch = channel;
|
|
uint8_t reg = MAX14661_DIR0;
|
|
if (ch > 7)
|
|
{
|
|
reg = MAX14661_DIR1;
|
|
ch -= 8;
|
|
}
|
|
uint8_t mask = readRegister(reg);
|
|
mask &= ~(1 << ch);
|
|
writeRegister(reg, mask);
|
|
return true;
|
|
}
|
|
|
|
|
|
bool MAX14661::closeB(uint8_t channel)
|
|
{
|
|
if (channel > 15) return false;
|
|
uint8_t ch = channel;
|
|
uint8_t reg = MAX14661_DIR2;
|
|
if (ch > 7)
|
|
{
|
|
reg = MAX14661_DIR3;
|
|
ch -= 8;
|
|
}
|
|
uint8_t mask = readRegister(reg);
|
|
mask &= ~(1 << ch);
|
|
writeRegister(reg, mask);
|
|
return true;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////
|
|
//
|
|
// LOW LEVEL CONTROL
|
|
//
|
|
uint8_t MAX14661::readRegister(uint8_t reg)
|
|
{
|
|
_wire->beginTransmission(_address);
|
|
_wire->write(reg);
|
|
_error = _wire->endTransmission();
|
|
if (_error != 0) return 0;
|
|
if (_wire->requestFrom(_address, (uint8_t)1) != 1)
|
|
{
|
|
_error = -1;
|
|
return 0;
|
|
}
|
|
return _wire->read();
|
|
}
|
|
|
|
|
|
int MAX14661::writeRegister(uint8_t reg, uint8_t value)
|
|
{
|
|
_wire->beginTransmission(_address);
|
|
_wire->write(reg);
|
|
_wire->write(value);
|
|
_error = _wire->endTransmission();
|
|
return _error;
|
|
}
|
|
|
|
|
|
int MAX14661::lastError()
|
|
{
|
|
int e = _error;
|
|
_error = 0;
|
|
return e;
|
|
}
|
|
|
|
|
|
|
|
|
|
// -- END OF FILE --
|