diff --git a/DCCRMT.cpp b/DCCRMT.cpp index cb28b10..ac97d0d 100644 --- a/DCCRMT.cpp +++ b/DCCRMT.cpp @@ -69,7 +69,7 @@ void IRAM_ATTR interrupt(rmt_channel_t channel, void *t) { if (tt) tt->RMTinterrupt(); } -RMTChannel::RMTChannel(byte pin, bool isMain) { +RMTChannel::RMTChannel(pinpair pins, bool isMain) { byte ch; byte plen; if (isMain) { @@ -119,13 +119,14 @@ RMTChannel::RMTChannel(byte pin, bool isMain) { config.rmt_mode = RMT_MODE_TX; config.channel = channel = (rmt_channel_t)ch; config.clk_div = RMT_CLOCK_DIVIDER; - config.gpio_num = (gpio_num_t)pin; + config.gpio_num = (gpio_num_t)pins.pin; config.mem_block_num = 2; // With longest DCC packet 11 inc checksum (future expansion) // number of bits needed is 22preamble + start + // 11*9 + extrazero + EOT = 124 // 2 mem block of 64 RMT items should be enough ESP_ERROR_CHECK(rmt_config(&config)); + addPin(pins.invpin, true); /* // test: config another gpio pin gpio_num_t gpioNum = (gpio_num_t)(pin-1); @@ -213,14 +214,19 @@ void IRAM_ATTR RMTChannel::RMTinterrupt() { dataRepeat--; } -bool RMTChannel::addPin(byte pin) { +bool RMTChannel::addPin(byte pin, bool inverted) { + if (pin == UNUSED_PIN) + return true; gpio_num_t gpioNum = (gpio_num_t)(pin); esp_err_t err; PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpioNum], PIN_FUNC_GPIO); err = gpio_set_direction(gpioNum, GPIO_MODE_OUTPUT); if (err != ESP_OK) return false; - gpio_matrix_out(gpioNum, RMT_SIG_OUT0_IDX+channel, 0, 0); + gpio_matrix_out(gpioNum, RMT_SIG_OUT0_IDX+channel, inverted, 0); if (err != ESP_OK) return false; return true; } +bool RMTChannel::addPin(pinpair pins) { + return addPin(pins.pin) && addPin(pins.invpin, true); +} #endif //ESP32 diff --git a/DCCRMT.h b/DCCRMT.h index ff790cd..33257a0 100644 --- a/DCCRMT.h +++ b/DCCRMT.h @@ -23,6 +23,7 @@ #include "driver/rmt.h" #include "soc/rmt_reg.h" #include "soc/rmt_struct.h" +#include "MotorDriver.h" // for class pinpair // make calculations easy and set up for microseconds #define RMT_CLOCK_DIVIDER 80 @@ -31,8 +32,9 @@ class RMTChannel { public: - RMTChannel(byte pin, bool isMain); - bool addPin(byte pin); + RMTChannel(pinpair pins, bool isMain); + bool addPin(byte pin, bool inverted=0); + bool addPin(pinpair pins); void IRAM_ATTR RMTinterrupt(); void RMTprefill(); //int RMTfillData(dccPacket packet); diff --git a/DCCWaveform.cpp b/DCCWaveform.cpp index 7140e91..5499b04 100644 --- a/DCCWaveform.cpp +++ b/DCCWaveform.cpp @@ -211,22 +211,24 @@ DCCWaveform::DCCWaveform(byte preambleBits, bool isMain) { } void DCCWaveform::begin() { for(const auto& md: TrackManager::getMainDrivers()) { + pinpair p = md->getSignalPin(); if(rmtMainChannel) { - DIAG(F("added pin %d to MAIN channel"), md->getSignalPin()); - rmtMainChannel->addPin(md->getSignalPin()); // add pin to existing main channel + DIAG(F("added pins %d %d to MAIN channel"), p.pin, p.invpin); + rmtMainChannel->addPin(p); // add pin to existing main channel } else { - DIAG(F("new MAIN channel with pin %d"), md->getSignalPin()); - rmtMainChannel = new RMTChannel(md->getSignalPin(), true); /* create new main channel */ + DIAG(F("new MAIN channel with pins %d %d"), p.pin, p.invpin); + rmtMainChannel = new RMTChannel(p, true); /* create new main channel */ } } MotorDriver *md = TrackManager::getProgDriver(); if (md) { + pinpair p = md->getSignalPin(); if (rmtProgChannel) { - DIAG(F("added pin %d to PROG channel"), md->getSignalPin()); - rmtProgChannel->addPin(md->getSignalPin()); // add pin to existing prog channel + DIAG(F("added pins %d %d to PROG channel"), p.pin, p.invpin); + rmtProgChannel->addPin(p); // add pin to existing prog channel } else { - DIAG(F("new PROGchannel with pin %d"), TrackManager::getProgDriver()->getSignalPin()); - rmtProgChannel = new RMTChannel(TrackManager::getProgDriver()->getSignalPin(), false); + DIAG(F("new PROGchannel with pins %d %d"), p.pin, p.invpin); + rmtProgChannel = new RMTChannel(p, false); } } } diff --git a/MotorDriver.h b/MotorDriver.h index 7a155ae..9e628eb 100644 --- a/MotorDriver.h +++ b/MotorDriver.h @@ -77,6 +77,16 @@ #define UNUSED_PIN 127 // inside int8_t #endif +class pinpair { +public: + pinpair(byte p1, byte p2) { + pin = p1; + invpin = p2; + }; + byte pin = UNUSED_PIN; + byte invpin = UNUSED_PIN; +}; + #if defined(__IMXRT1062__) || defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_STM32) typedef uint32_t portreg_t; #else @@ -134,7 +144,7 @@ class MotorDriver { else pinMode(signalPin, INPUT); }; - inline byte getSignalPin() { return signalPin; }; + inline pinpair getSignalPin() { return pinpair(signalPin,signalPin2); }; virtual void setDCSignal(byte speedByte); inline void detachDCSignal() { #ifndef ARDUINO_ARCH_ESP32 diff --git a/TrackManager.cpp b/TrackManager.cpp index 772ddc5..c082c95 100644 --- a/TrackManager.cpp +++ b/TrackManager.cpp @@ -140,8 +140,15 @@ bool TrackManager::setTrackMode(byte trackToSet, TRACK_MODE mode, int16_t dcAddr #ifdef ARDUINO_ARCH_ESP32 // remove pin from MUX matrix and turn it off - DIAG(F("Track=%c remove pin %d"),trackToSet+'A', track[trackToSet]->getSignalPin()); - gpio_reset_pin((gpio_num_t)track[trackToSet]->getSignalPin()); + pinpair p = track[trackToSet]->getSignalPin(); + DIAG(F("Track=%c remove pin %d"),trackToSet+'A', p.pin); + gpio_reset_pin((gpio_num_t)p.pin); + pinMode(p.pin, OUTPUT); // gpio_reset_pin may reset to input + if (p.invpin != UNUSED_PIN) { + DIAG(F("Track=%c remove ^pin %d"),trackToSet+'A', p.invpin); + gpio_reset_pin((gpio_num_t)p.invpin); + pinMode(p.invpin, OUTPUT); // gpio_reset_pin may reset to input + } #endif if (mode==TRACK_MODE_PROG) { // only allow 1 track to be prog