Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Support for 2 SX1509B I/O Expanders #379

Open
wants to merge 9 commits into
base: v3.01-dev
Choose a base branch
from
79 changes: 70 additions & 9 deletions src/DuetNG/DueXn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,16 @@ namespace DuetExpansion
static ExpansionBoardType dueXnBoardType = ExpansionBoardType::none;

const uint8_t AdditionalIoExpanderAddress = 0x71; // address of the SX1509B we allow for general I/O expansion
const uint8_t AdditionalIoExpanderAddress2 = 0x3F;

static SX1509 additionalIoExpander;
static bool additionalIoExpanderPresent = false;
static uint16_t additionalIoInputBits = 0;

static SX1509 additionalIoExpander2;
static bool additionalIoExpanderPresent2 = false;
static uint16_t additionalIoInputBits2 = 0;

static volatile bool taskWaiting = false;
static volatile bool inputsChanged = false;

Expand Down Expand Up @@ -161,6 +166,7 @@ namespace DuetExpansion
void AdditionalOutputInit()
{
I2C::Init(); // initialise I2C
delay(200); // the SX1509B has an independent power on reset, so give it some time

bool ret;
unsigned int attempts = 0;
Expand All @@ -178,6 +184,24 @@ namespace DuetExpansion
additionalIoInputBits = additionalIoExpander.digitalReadAll();
additionalIoExpanderPresent = true;
}

bool ret2;
unsigned int attempts2 = 0;
do
{
++attempts2;
delay(50);
ret2 = additionalIoExpander2.begin(AdditionalIoExpanderAddress2);
} while (!ret2 && attempts2 < 5);
(void)I2C_IFACE.GetErrorCounts(true); // clear the error counts in case there wasn't a device there or we didn't find it first time

if (ret2)
{
additionalIoExpander2.pinModeMultiple((1u << 16) - 1, INPUT_PULLDOWN);
additionalIoInputBits2 = additionalIoExpander2.digitalReadAll();
additionalIoExpanderPresent2 = true;
}

}

// Return the name of the expansion board, or nullptr if no expansion board
Expand All @@ -199,7 +223,21 @@ namespace DuetExpansion
// Return the name of the additional expansion board, or nullptr if no expansion board
const char* _ecv_array null GetAdditionalExpansionBoardName()
{
return (additionalIoExpanderPresent) ? "SX1509B expander" : nullptr;
if (additionalIoExpanderPresent && additionalIoExpanderPresent2)
{
return "SX1509B expander (0x71 & 0x3F)";
}
else if (additionalIoExpanderPresent)
{
return "SX1509B expander (0x71)";
}
else if (additionalIoExpanderPresent2)
{
return "SX1509B expander (0x3F)";
} else
{
return nullptr;
}
}

// Set the I/O mode of a pin
Expand Down Expand Up @@ -236,12 +274,16 @@ namespace DuetExpansion
dueXnExpander.pinMode(pin, mode);
}
}
else if (pin >= AdditionalIoExpansionStart && pin < AdditionalIoExpansionStart + 16)
else if (pin >= AdditionalIoExpansionStart && pin < AdditionalIoExpansionStart + 32)
{
if (additionalIoExpanderPresent)
if (additionalIoExpanderPresent && pin < AdditionalIoExpansionStart + 16)
{
additionalIoExpander.pinMode(pin - AdditionalIoExpansionStart, mode);
}
else if (additionalIoExpanderPresent2 && pin >= AdditionalIoExpansionStart + 16)
{
additionalIoExpander2.pinMode(pin - (AdditionalIoExpansionStart + 16), mode);
}
}
}

Expand All @@ -262,9 +304,9 @@ namespace DuetExpansion
return (dueXnInputBits & (1u << (pin - DueXnExpansionStart))) != 0;
}
}
else if (pin >= AdditionalIoExpansionStart && pin < AdditionalIoExpansionStart + 16)
else if (pin >= AdditionalIoExpansionStart && pin < AdditionalIoExpansionStart + 32)
{
if (additionalIoExpanderPresent)
if (additionalIoExpanderPresent && pin < AdditionalIoExpansionStart + 16)
{
// We don't have an interrupt from the additional I/O expander, so always read fresh data.
// If this is called from inside an ISR, we will get stale data.
Expand All @@ -275,6 +317,17 @@ namespace DuetExpansion

return (additionalIoInputBits & (1u << (pin - AdditionalIoExpansionStart))) != 0;
}
else if (additionalIoExpanderPresent2 && pin >= AdditionalIoExpansionStart + 16)
{
// We don't have an interrupt from the additional I/O expander, so always read fresh data.
// If this is called from inside an ISR, we will get stale data.
if (!inInterrupt() && __get_BASEPRI() == 0) // we must not call expander.digitalRead() from within an ISR
{
additionalIoInputBits2 = additionalIoExpander2.digitalReadAll();
}

return (additionalIoInputBits2 & (1u << (pin - (AdditionalIoExpansionStart + 16)))) != 0;
}
}

return false;
Expand All @@ -290,12 +343,16 @@ namespace DuetExpansion
dueXnExpander.digitalWrite(pin - DueXnExpansionStart, high);
}
}
else if (pin >= AdditionalIoExpansionStart && pin < AdditionalIoExpansionStart + 16)
else if (pin >= AdditionalIoExpansionStart && pin < AdditionalIoExpansionStart + 32)
{
if (additionalIoExpanderPresent)
if (additionalIoExpanderPresent && pin < AdditionalIoExpansionStart + 16)
{
additionalIoExpander.digitalWrite(pin - AdditionalIoExpansionStart, high);
}
else if (additionalIoExpanderPresent2 && pin >= AdditionalIoExpansionStart + 16)
{
additionalIoExpander2.digitalWrite(pin - (AdditionalIoExpansionStart + 16), high);
}
}
}

Expand All @@ -309,12 +366,16 @@ namespace DuetExpansion
dueXnExpander.analogWrite(pin - DueXnExpansionStart, (uint8_t)(constrain<float>(pwm, 0.0, 1.0) * 255));
}
}
else if (pin >= AdditionalIoExpansionStart && pin < AdditionalIoExpansionStart + 16)
else if (pin >= AdditionalIoExpansionStart && pin < AdditionalIoExpansionStart + 32)
{
if (additionalIoExpanderPresent)
if (additionalIoExpanderPresent && pin < AdditionalIoExpansionStart + 16)
{
additionalIoExpander.analogWrite(pin - AdditionalIoExpansionStart, (uint8_t)(constrain<float>(pwm, 0.0, 1.0) * 255));
}
else if (additionalIoExpanderPresent2 && pin >= AdditionalIoExpansionStart + 16)
{
additionalIoExpander2.analogWrite(pin - (AdditionalIoExpansionStart + 16), (uint8_t)(constrain<float>(pwm, 0.0, 1.0) * 255));
}
}
}

Expand Down
50 changes: 33 additions & 17 deletions src/DuetNG/Pins_DuetNG.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ constexpr Pin UsbVBusPin = PortCPin(22); // Pin used to monitor VBUS on USB po
#define I2C_IRQn WIRE_ISR_ID // The interrupt number it uses

constexpr Pin DueXnExpansionStart = 200; // Pin numbers 200-215 are on the I/O expander
constexpr Pin AdditionalIoExpansionStart = 220; // Pin numbers 220-235 are on the additional I/O expander
constexpr Pin AdditionalIoExpansionStart = 220; // Pin numbers 220-251 are on the additional I/O expander

// The numbers of entries in each array must correspond with the values of DRIVES, AXES, or HEATERS. Set values to NoPin to flag unavailability.

Expand Down Expand Up @@ -298,22 +298,38 @@ constexpr PinEntry PinTable[] =
{ 210, PinCapability::rwpwm, "duex.gp2" },
{ 209, PinCapability::rwpwm, "duex.gp3" },
{ 208, PinCapability::rwpwm, "duex.gp4" },
{ 220, PinCapability::rwpwm, "sx1509b.0" },
{ 221, PinCapability::rwpwm, "sx1509b.1" },
{ 222, PinCapability::rwpwm, "sx1509b.2" },
{ 223, PinCapability::rwpwm, "sx1509b.3" },
{ 224, PinCapability::rwpwm, "sx1509b.4" },
{ 225, PinCapability::rwpwm, "sx1509b.5" },
{ 226, PinCapability::rwpwm, "sx1509b.6" },
{ 227, PinCapability::rwpwm, "sx1509b.7" },
{ 228, PinCapability::rwpwm, "sx1509b.8" },
{ 229, PinCapability::rwpwm, "sx1509b.9" },
{ 230, PinCapability::rwpwm, "sx1509b.10" },
{ 231, PinCapability::rwpwm, "sx1509b.11" },
{ 232, PinCapability::rwpwm, "sx1509b.12" },
{ 233, PinCapability::rwpwm, "sx1509b.13" },
{ 234, PinCapability::rwpwm, "sx1509b.14" },
{ 235, PinCapability::rwpwm, "sx1509b.15" }
{ 220, PinCapability::rwpwm, "sx1509b.0,0x71.0" },
{ 221, PinCapability::rwpwm, "sx1509b.1,0x71.1" },
{ 222, PinCapability::rwpwm, "sx1509b.2,0x71.2" },
{ 223, PinCapability::rwpwm, "sx1509b.3,0x71.3" },
{ 224, PinCapability::rwpwm, "sx1509b.4,0x71.4" },
{ 225, PinCapability::rwpwm, "sx1509b.5,0x71.5" },
{ 226, PinCapability::rwpwm, "sx1509b.6,0x71.6" },
{ 227, PinCapability::rwpwm, "sx1509b.7,0x71.7" },
{ 228, PinCapability::rwpwm, "sx1509b.8,0x71.8" },
{ 229, PinCapability::rwpwm, "sx1509b.9,0x71.9" },
{ 230, PinCapability::rwpwm, "sx1509b.10,0x71.10" },
{ 231, PinCapability::rwpwm, "sx1509b.11,0x71.11" },
{ 232, PinCapability::rwpwm, "sx1509b.12,0x71.12" },
{ 233, PinCapability::rwpwm, "sx1509b.13,0x71.13" },
{ 234, PinCapability::rwpwm, "sx1509b.14,0x71.14" },
{ 235, PinCapability::rwpwm, "sx1509b.15,0x71.15" },
{ 236, PinCapability::rwpwm, "sx1509b2.0,0x3f.0" },
{ 237, PinCapability::rwpwm, "sx1509b2.1,0x3f.1" },
{ 238, PinCapability::rwpwm, "sx1509b2.2,0x3f.2" },
{ 239, PinCapability::rwpwm, "sx1509b2.3,0x3f.3" },
{ 240, PinCapability::rwpwm, "sx1509b2.4,0x3f.4" },
{ 241, PinCapability::rwpwm, "sx1509b2.5,0x3f.5" },
{ 242, PinCapability::rwpwm, "sx1509b2.6,0x3f.6" },
{ 243, PinCapability::rwpwm, "sx1509b2.7,0x3f.7" },
{ 244, PinCapability::rwpwm, "sx1509b2.8,0x3f.8" },
{ 245, PinCapability::rwpwm, "sx1509b2.9,0x3f.9" },
{ 246, PinCapability::rwpwm, "sx1509b2.10,0x3f.10" },
{ 247, PinCapability::rwpwm, "sx1509b2.11,0x3f.11" },
{ 248, PinCapability::rwpwm, "sx1509b2.12,0x3f.12" },
{ 249, PinCapability::rwpwm, "sx1509b2.13,0x3f.13" },
{ 250, PinCapability::rwpwm, "sx1509b2.14,0x3f.14" },
{ 251, PinCapability::rwpwm, "sx1509b2.15,0x3f.15" }
};

constexpr unsigned int NumNamedPins = ARRAY_SIZE(PinTable);
Expand Down
2 changes: 2 additions & 0 deletions src/RepRap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,8 @@ void RepRap::Diagnostics(MessageType mtype) noexcept
platform->MessageF(mtype, "%s version %s running on %s", FIRMWARE_NAME, VERSION, platform->GetElectronicsString());
const char* const expansionName = DuetExpansion::GetExpansionBoardName();
platform->MessageF(mtype, (expansionName == nullptr) ? "\n" : " + %s\n", expansionName);
const char* additionalExpansionName = DuetExpansion::GetAdditionalExpansionBoardName();
platform->MessageF(mtype, (additionalExpansionName == nullptr) ? "\n" : " + %s\n", additionalExpansionName);
#elif defined(__LPC17xx__)
platform->MessageF(mtype, "%s (%s) version %s running on %s at %dMhz\n", FIRMWARE_NAME, lpcBoardName, VERSION, platform->GetElectronicsString(), (int)SystemCoreClock/1000000);
#else
Expand Down