1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2024-12-23 21:01:25 +01:00

ESP32 rewrite PWM LEDC to use pin mux

This commit is contained in:
Harald Barth 2024-04-05 01:02:49 +02:00
parent 02bf50b909
commit fdc956576b
5 changed files with 79 additions and 11 deletions

View File

@ -66,7 +66,9 @@ class DCCTimer {
static void ackRailcomTimer();
static void DCCEXanalogWriteFrequency(uint8_t pin, uint32_t frequency);
static void DCCEXanalogWrite(uint8_t pin, int value);
static void DCCEXledcDetachPin(uint8_t pin);
static void DCCEXanalogCopyChannel(uint8_t frompin, uint8_t topin);
static void DCCEXInrushControlOn(uint8_t pin);
// Update low ram level. Allow for extra bytes to be specified
// by estimation or inspection, that may be used by other
// called subroutines. Must be called with interrupts disabled.

View File

@ -78,6 +78,7 @@ int DCCTimer::freeMemory() {
////////////////////////////////////////////////////////////////////////
#ifdef ARDUINO_ARCH_ESP32
#include "DIAG.h"
#include <driver/adc.h>
#include <soc/sens_reg.h>
#include <soc/sens_struct.h>
@ -154,8 +155,10 @@ void DCCTimer::reset() {
void DCCTimer::DCCEXanalogWriteFrequency(uint8_t pin, uint32_t f) {
if (f >= 16)
DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, f);
else if (f == 7)
/*
else if (f == 7) // not used on ESP32
DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, 62500);
*/
else if (f >= 4)
DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, 32000);
else if (f >= 3)
@ -188,22 +191,65 @@ void DCCTimer::DCCEXanalogWriteFrequencyInternal(uint8_t pin, uint32_t frequency
}
}
void DCCTimer::DCCEXledcDetachPin(uint8_t pin) {
DIAG(F("Clear pin %d channel"), pin);
pin_to_channel[pin] = 0;
pinMatrixOutDetach(pin, false, false);
}
void DCCTimer::DCCEXanalogCopyChannel(uint8_t frompin, uint8_t topin) {
DIAG(F("Pin %d copied to %d channel %d"), frompin, topin, pin_to_channel[frompin]);
pin_to_channel[topin] = pin_to_channel[frompin];
ledcAttachPin(topin, pin_to_channel[topin]);
}
void DCCTimer::DCCEXanalogWrite(uint8_t pin, int value) {
// This allocates channels 15, 13, 11, ....
// so each channel gets its own timer.
if (pin < SOC_GPIO_PIN_COUNT) {
if (pin_to_channel[pin] == 0) {
int search_channel;
int n;
if (!cnt_channel) {
log_e("No more PWM channels available! All %u already used", LEDC_CHANNELS);
return;
}
pin_to_channel[pin] = --cnt_channel;
ledcSetup(cnt_channel, 1000, 8);
ledcAttachPin(pin, cnt_channel);
// search for free channels top down
for (search_channel=LEDC_CHANNELS-1; search_channel >=cnt_channel; search_channel -= 2) {
bool chanused = false;
for (n=0; n < SOC_GPIO_PIN_COUNT; n++) {
if (pin_to_channel[n] == search_channel) { // current search_channel used
chanused = true;
break;
}
}
if (chanused)
continue;
if (n == SOC_GPIO_PIN_COUNT) // current search_channel unused
break;
}
if (search_channel >= cnt_channel) {
pin_to_channel[pin] = search_channel;
DIAG(F("Pin %d assigned to search channel %d"), pin, search_channel);
} else {
pin_to_channel[pin] = --cnt_channel; // This sets 15, 13, ...
DIAG(F("Pin %d assigned to new channel %d"), pin, cnt_channel);
--cnt_channel; // Now we are at 14, 12, ...
}
ledcSetup(pin_to_channel[pin], 1000, 8);
ledcAttachPin(pin, pin_to_channel[pin]);
} else {
//DIAG(F("Pin %d assigned to old channel %d"), pin, pin_to_channel[pin]);
ledcAttachPin(pin, pin_to_channel[pin]);
}
ledcWrite(pin_to_channel[pin], value);
}
}
void DCCTimer::DCCEXInrushControlOn(uint8_t pin) {
ledcSetup(0, 62500, 8);
ledcAttachPin(pin, 0);
ledcWrite(0, 207);
}
int ADCee::init(uint8_t pin) {
pinMode(pin, ANALOG);

View File

@ -411,10 +411,10 @@ void MotorDriver::throttleInrush(bool on) {
duty = 255-duty;
#if defined(ARDUINO_ARCH_ESP32)
if(on) {
DCCTimer::DCCEXanalogWrite(brakePin,duty);
DCCTimer::DCCEXanalogWriteFrequency(brakePin, 7); // 7 means max
DCCTimer::DCCEXInrushControlOn(brakePin);
} else {
ledcDetachPin(brakePin);
ledcDetachPin(brakePin); // not DCCTimer::DCCEXledcDetachPin() as we have not
// registered the pin in the pin to channel array
}
#elif defined(ARDUINO_ARCH_STM32)
if(on) {

View File

@ -193,13 +193,14 @@ class MotorDriver {
}
};
inline pinpair getSignalPin() { return pinpair(signalPin,signalPin2); };
inline byte getBrakePin() { return brakePin; };
void setDCSignal(byte speedByte, uint8_t frequency=0);
void throttleInrush(bool on);
inline void detachDCSignal() {
#if defined(__arm__)
pinMode(brakePin, OUTPUT);
#elif defined(ARDUINO_ARCH_ESP32)
ledcDetachPin(brakePin);
DCCTimer::DCCEXledcDetachPin(brakePin);
#else
setDCSignal(128);
#endif

View File

@ -252,13 +252,32 @@ bool TrackManager::setTrackMode(byte trackToSet, TRACK_MODE mode, int16_t dcAddr
track[trackToSet]->makeProgTrack(false); // only the prog track knows it's type
}
track[trackToSet]->setMode(mode);
trackDCAddr[trackToSet]=dcAddr;
// When a track is switched, we must clear any side effects of its previous
// state, otherwise trains run away or just dont move.
// This can be done BEFORE the PWM-Timer evaluation (methinks)
if (!(mode & TRACK_MODE_DC)) {
if (mode & TRACK_MODE_DC) {
if (trackDCAddr[trackToSet] != dcAddr) {
// if we change dcAddr, detach first old signal
track[trackToSet]->detachDCSignal();
#ifdef ARDUINO_ARCH_ESP32
int trackfound = -1;
FOR_EACH_TRACK(t) {
if ((track[t]->getMode() & TRACK_MODE_DC) && trackDCAddr[t] == dcAddr) {
trackfound = t;
break;
}
}
if (trackfound > -1) {
DCCTimer::DCCEXanalogCopyChannel(track[trackfound]->getBrakePin(),
track[trackToSet]->getBrakePin());
}
#endif
}
// set future DC Addr;
trackDCAddr[trackToSet]=dcAddr;
} else {
// DCC tracks need to have set the PWM to zero or they will not work.
track[trackToSet]->detachDCSignal();
track[trackToSet]->setBrake(false);