Skip to content

Commit

Permalink
SPI: added support for MCP3002 A/D converter
Browse files Browse the repository at this point in the history
  • Loading branch information
plan44 committed Jul 12, 2018
1 parent 88784c9 commit 9ac3750
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 1 deletion.
71 changes: 70 additions & 1 deletion spi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ SPIDevicePtr SPIManager::getDevice(int aBusNumber, const char *aDeviceID)
dev = SPIDevicePtr(new MCP23S17(deviceAddress, bus.get(), deviceOptions.c_str()));
else if (typeString=="MCP3008")
dev = SPIDevicePtr(new MCP3008(deviceAddress, bus.get(), deviceOptions.c_str()));
else if (typeString=="MCP3002")
dev = SPIDevicePtr(new MCP3002(deviceAddress, bus.get(), deviceOptions.c_str()));
else if (typeString=="generic")
dev = SPIDevicePtr(new SPIDevice(deviceAddress, bus.get(), deviceOptions.c_str()));
// TODO: add more device types
Expand Down Expand Up @@ -711,7 +713,7 @@ double MCP3008::getPinValue(int aPinNo)
uint8_t out[3];
uint8_t in[3];
uint16_t raw = 0;
// - first byte is 7 zero dummy bits plus MSB==1==start bit
// - first byte is 7 zero dummy bits plus LSB==1==start bit
out[0] = 0x01;
// - second byte is 4 bit channel selection/differential vs single, plus 4 bit dummy
// Bit 7 Bit 6 Bit 5 Bit 4
Expand Down Expand Up @@ -742,6 +744,73 @@ bool MCP3008::getPinRange(int aPinNo, double &aMin, double &aMax, double &aResol
}


// MARK: ===== MCP3002

MCP3008::MCP3002(uint8_t aDeviceAddress, SPIBus *aBusP, const char *aDeviceOptions) :
inherited(aDeviceAddress, aBusP, aDeviceOptions)
{
// currently no device options
// int b = atoi(aDeviceOptions);
}


bool MCP3002::isKindOf(const char *aDeviceType)
{
if (strcmp(deviceType(),aDeviceType)==0)
return true;
else
return inherited::isKindOf(aDeviceType);
}


double MCP3002::getPinValue(int aPinNo)
{
// MCP3002 needs to transfer 3 bytes in and out for one conversion
// Note: with a correctly working SPI (not the case in MT7688),
// 2 bytes would be sufficient. But as the first returned byte
// is flawed in MT7688 (see @wdu's comment in Onion forum:
// "In full duplex, I have observed errors in the second bit (always
// 1 or 0, don't remember exactly), depending on the state of the
// first bit. This makes the first transmitted byte unreliable."),
// this implementation shifts the bit such that first returned byte
// can be discarded entirely.
uint8_t out[3];
uint8_t in[3];
uint16_t raw = 0;
// - first byte is 4 zero dummy bits, then 1==start bit, then:
// Bit 2 Bit 1 Bit 0
// D/S CHSEL MSBFirst
// - we invert the D/S bit to have 1:1 PinNo->Single ended channel assignments (0,1).
// PinNo 2,3 then represent the differential modes, see data sheet.
out[0] =
0x08 | // start bit
((aPinNo^0x02)<<1) | // channel and mode selection
0x01; // MSB first
// - second and third byte is dummy
out[1] = 0;
out[2] = 0;
if (spibus->SPIRawWriteRead(this, 3, out, 3, in, true)) {
// first byte returned is broken anyway on MT7688, no data there
// second byte contains a 0 in Bit7, Bit6..0 = Bit9..3 of result
// third byte contains Bit7..5 = Bit2..0 of result, rest is dummy
raw = ((uint16_t)(in[1] & 0x7F)<<3) + (in[2]>>5);
}
// return raw value (no physical unit at this level known, and no scaling or offset either)
return raw;
}


bool MCP3002::getPinRange(int aPinNo, double &aMin, double &aMax, double &aResolution)
{
// as we don't know what will be connected to the inputs, we return raw A/D value.
aMin = 0;
aMax = 1024;
aResolution = 1;
return true;
}





// MARK: ===== AnalogSPIpin
Expand Down
25 changes: 25 additions & 0 deletions spi.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,31 @@ namespace p44 {



class MCP3002 : public SPIAnalogPortDevice
{
typedef SPIAnalogPortDevice inherited;

public:

/// create device
/// @param aDeviceAddress slave address of the device
/// @param aBusP I2CBus object
/// @param aDeviceOptions optional device-level options
MCP3002(uint8_t aDeviceAddress, SPIBus *aBusP, const char *aDeviceOptions);

/// @return device type identifier
virtual const char *deviceType() P44_OVERRIDE { return "MCP3002"; };

/// @return true if this device or one of it's ancestors is of the given type
virtual bool isKindOf(const char *aDeviceType) P44_OVERRIDE;

virtual double getPinValue(int aPinNo) P44_OVERRIDE;
virtual void setPinValue(int aPinNo, double aValue) P44_OVERRIDE { /* dummy */ };
virtual bool getPinRange(int aPinNo, double &aMin, double &aMax, double &aResolution) P44_OVERRIDE;

};



/// wrapper class for analog I/O pin
class AnalogSPIPin : public AnalogIOPin
Expand Down

0 comments on commit 9ac3750

Please sign in to comment.