diff --git a/DCCRMT.cpp b/DCCRMT.cpp new file mode 100644 index 0000000..5186ecf --- /dev/null +++ b/DCCRMT.cpp @@ -0,0 +1,138 @@ +/* + * © 2021, Harald Barth. + * + * This file is part of DCC-EX + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * It is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with CommandStation. If not, see . + */ + +#include "defines.h" +#include "DIAG.h" +#include "DCCRMT.h" +#include "soc/periph_defs.h" +#include "driver/periph_ctrl.h" + +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4,2,0) +#error wrong IDF version +#endif + +void setDCCBit1(rmt_item32_t* item) { + item->level0 = 1; + item->duration0 = DCC_1_HALFPERIOD; + item->level1 = 0; + item->duration1 = DCC_1_HALFPERIOD; +} + +void setDCCBit0(rmt_item32_t* item) { + item->level0 = 1; + item->duration0 = DCC_0_HALFPERIOD; + item->level1 = 0; + item->duration1 = DCC_0_HALFPERIOD; +} + +void IRAM_ATTR interrupt(rmt_channel_t channel, void *t) { + BaseType_t wtf = pdFALSE; + RMTPin *tt = (RMTPin *)t; + //DIAG(F("interrupt %d"), tt->idleLen); + tt->RMTinterrupt(channel,t); + rmt_tx_start(channel,true); + portYIELD_FROM_ISR(wtf); +} + +RMTPin::RMTPin(byte pin, byte ch, byte plen) { + + // preamble + preambleLen = plen+1; + preamble = (rmt_item32_t*)malloc(preambleLen*sizeof(rmt_item32_t)); + for (byte n=0; npreambleNext) { + rmt_fill_tx_items(channel, obj->preamble, obj->preambleLen, 0); + //obj->preambleNext = false; + } else { + if (obj->dataNext) { + rmt_fill_tx_items(channel, obj->packetBits, obj->packetLen, 0); + } else { + // here we should not get as now we need to send idle packet + rmt_fill_tx_items(channel, obj->idle, obj->idleLen, 0); + } + obj->preambleNext = true; + } + rmt_tx_start(channel,true); + DIAG(F("START")); + */ +} diff --git a/DCCRMT.h b/DCCRMT.h new file mode 100644 index 0000000..58f77de --- /dev/null +++ b/DCCRMT.h @@ -0,0 +1,51 @@ +/* + * © 2021, Harald Barth. + * + * This file is part of DCC-EX + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * It is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with CommandStation. If not, see . + */ + +#pragma once +#include +#include "driver/rmt.h" +#include "soc/rmt_reg.h" +#include "soc/rmt_struct.h" + +#define DCC_1_HALFPERIOD 4640 // 1 / 80000000 * 4640 = 58us +#define DCC_0_HALFPERIOD 8000 + +class RMTPin { + public: + RMTPin(byte pin, byte ch, byte plen); + void IRAM_ATTR RMTinterrupt(rmt_channel_t, void *t); + + static RMTPin mainRMTPin; + static RMTPin progRMTPin; + + // private: + + rmt_channel_t channel; + // 3 types of data to send, preamble and then idle or data + // if this is prog track, idle will contain reset instead + rmt_item32_t *idle; + byte idleLen; + rmt_item32_t *preamble; + byte preambleLen; + rmt_item32_t packetBits[64]; + byte packetLen; + // flags + volatile bool preambleNext = true; // alternate between preamble and content + volatile bool dataNext = false; // do we have real data available or send idle +}; diff --git a/DCCWaveform.cpp b/DCCWaveform.cpp index 94cd91d..505583f 100644 --- a/DCCWaveform.cpp +++ b/DCCWaveform.cpp @@ -25,6 +25,7 @@ #include "DCCTimer.h" #include "DIAG.h" #include "freeMemory.h" +#include "DCCRMT.h" DCCWaveform DCCWaveform::mainTrack(PREAMBLE_BITS_MAIN, true); DCCWaveform DCCWaveform::progTrack(PREAMBLE_BITS_PROG, false); @@ -37,6 +38,9 @@ volatile uint8_t DCCWaveform::numAckSamples=0; uint8_t DCCWaveform::trailingEdgeCounter=0; void DCCWaveform::begin(MotorDriver * mainDriver, MotorDriver * progDriver) { + + RMTPin *p = new RMTPin(21, 0, PREAMBLE_BITS_MAIN); + mainTrack.motorDriver=mainDriver; progTrack.motorDriver=progDriver; progTripValue = progDriver->mA2raw(TRIP_CURRENT_PROG); // need only calculate once hence static @@ -47,11 +51,14 @@ void DCCWaveform::begin(MotorDriver * mainDriver, MotorDriver * progDriver) { && (mainDriver->getFaultPin() != UNUSED_PIN)); // Only use PWM if both pins are PWM capable. Otherwise JOIN does not work MotorDriver::usePWM= mainDriver->isPWMCapable() && progDriver->isPWMCapable(); + /* if (MotorDriver::usePWM) DIAG(F("Signal pin config: high accuracy waveform")); else DIAG(F("Signal pin config: normal accuracy waveform")); DCCTimer::begin(DCCWaveform::interruptHandler); + */ + DIAG(F("No waveform")); } #ifdef SLOW_ANALOG_READ diff --git a/WifiESP32.cpp b/WifiESP32.cpp index 49b2116..48d40d6 100644 --- a/WifiESP32.cpp +++ b/WifiESP32.cpp @@ -17,6 +17,7 @@ along with CommandStation. If not, see . */ +#include #include "defines.h" #if defined(ARDUINO_ARCH_ESP32) #include @@ -231,7 +232,7 @@ void WifiESP::loop() { } } } //connected - yield(); + // when loop() is running on core0 we must // feed the core0 wdt ourselves as yield() // is not necessarily yielding to a low @@ -240,5 +241,6 @@ void WifiESP::loop() { // arduio IDE startup routines. if (xPortGetCoreID() == 0) feedTheDog0(); + yield(); } #endif //ESP32