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

Protect port registers from change during interrupt code in differnet way

This commit is contained in:
Harald Barth 2022-08-09 13:12:04 +02:00
parent 84e44df47c
commit 76c5608181
3 changed files with 37 additions and 32 deletions

View File

@ -148,11 +148,17 @@ bool MotorDriver::isPWMCapable() {
void MotorDriver::setPower(POWERMODE mode) { void MotorDriver::setPower(POWERMODE mode) {
bool on=mode==POWERMODE::ON; bool on=mode==POWERMODE::ON;
if (on) { if (on) {
noInterrupts();
IODevice::write(powerPin,HIGH); IODevice::write(powerPin,HIGH);
interrupts();
if (isProgTrack) if (isProgTrack)
DCCWaveform::progTrack.clearResets(); DCCWaveform::progTrack.clearResets();
} }
else IODevice::write(powerPin,LOW); else {
noInterrupts();
IODevice::write(powerPin,LOW);
interrupts();
}
powerMode=mode; powerMode=mode;
} }
@ -164,10 +170,14 @@ void MotorDriver::setPower(POWERMODE mode) {
// (HIGH == release brake) and setBrake does // (HIGH == release brake) and setBrake does
// compensate for that. // compensate for that.
// //
void MotorDriver::setBrake(bool on) { void MotorDriver::setBrake(bool on, bool interruptContext) {
if (brakePin == UNUSED_PIN) return; if (brakePin == UNUSED_PIN) return;
if (on ^ invertBrake) setHIGH(fastBrakePin); if (!interruptContext) {noInterrupts();}
else setLOW(fastBrakePin); if (on ^ invertBrake)
setHIGH(fastBrakePin);
else
setLOW(fastBrakePin);
if (!interruptContext) {interrupts();}
} }
bool MotorDriver::canMeasureCurrent() { bool MotorDriver::canMeasureCurrent() {
@ -214,30 +224,18 @@ void MotorDriver::setDCSignal(byte speedcode) {
if (invertBrake) if (invertBrake)
brake=255-brake; brake=255-brake;
analogWrite(brakePin,brake); analogWrite(brakePin,brake);
// as the port registers can be shadowed to get syncronized DCC signals
// we need to take care of that and we have to turn off interrupts during
// that time as otherwise setDCCSignal() which is called from interrupt
// contect can undo whatever we do here.
if (fastSignalPin.shadowinout != NULL) {
if (HAVE_PORTA(fastSignalPin.shadowinout == &PORTA)) { if (HAVE_PORTA(fastSignalPin.shadowinout == &PORTA)) {
noInterrupts();
HAVE_PORTA(shadowPORTA=PORTA); HAVE_PORTA(shadowPORTA=PORTA);
setSignal(tDir); setSignal(tDir);
HAVE_PORTA(PORTA=shadowPORTA); HAVE_PORTA(PORTA=shadowPORTA);
interrupts();
} else if (HAVE_PORTB(fastSignalPin.shadowinout == &PORTB)) { } else if (HAVE_PORTB(fastSignalPin.shadowinout == &PORTB)) {
noInterrupts();
HAVE_PORTB(shadowPORTB=PORTB); HAVE_PORTB(shadowPORTB=PORTB);
setSignal(tDir); setSignal(tDir);
HAVE_PORTB(PORTB=shadowPORTB); HAVE_PORTB(PORTB=shadowPORTB);
interrupts();
} else if (HAVE_PORTC(fastSignalPin.shadowinout == &PORTC)) { } else if (HAVE_PORTC(fastSignalPin.shadowinout == &PORTC)) {
noInterrupts();
HAVE_PORTC(shadowPORTC=PORTC); HAVE_PORTC(shadowPORTC=PORTC);
setSignal(tDir); setSignal(tDir);
HAVE_PORTC(PORTC=shadowPORTC); HAVE_PORTC(PORTC=shadowPORTC);
interrupts();
}
} else { } else {
setSignal(tDir); setSignal(tDir);
} }

View File

@ -105,7 +105,14 @@ class MotorDriver {
byte current_pin, float senseFactor, unsigned int tripMilliamps, byte faultPin); byte current_pin, float senseFactor, unsigned int tripMilliamps, byte faultPin);
virtual void setPower( POWERMODE mode); virtual void setPower( POWERMODE mode);
virtual POWERMODE getPower() { return powerMode;} virtual POWERMODE getPower() { return powerMode;}
__attribute__((always_inline)) inline void setSignal( bool high) { // as the port registers can be shadowed to get syncronized DCC signals
// we need to take care of that and we have to turn off interrupts if
// we setSignal() or setBrake() or setPower() during that time as
// otherwise the call from interrupt context can undo whatever we do
// from outside interrupt
virtual void setBrake( bool on, bool interruptContext=false);
__attribute__((always_inline)) inline void setSignal( bool high, bool interruptContext=false) {
if (!interruptContext) {noInterrupts();}
if (trackPWM) { if (trackPWM) {
DCCTimer::setPWM(signalPin,high); DCCTimer::setPWM(signalPin,high);
} }
@ -119,6 +126,7 @@ class MotorDriver {
if (dualSignal) setHIGH(fastSignalPin2); if (dualSignal) setHIGH(fastSignalPin2);
} }
} }
if (!interruptContext) {interrupts();}
}; };
inline void enableSignal(bool on) { inline void enableSignal(bool on) {
if (on) if (on)
@ -127,7 +135,6 @@ class MotorDriver {
pinMode(signalPin, INPUT); pinMode(signalPin, INPUT);
}; };
inline byte getSignalPin() { return signalPin; }; inline byte getSignalPin() { return signalPin; };
virtual void setBrake( bool on);
virtual void setDCSignal(byte speedByte); virtual void setDCSignal(byte speedByte);
virtual int getCurrentRaw(); virtual int getCurrentRaw();
virtual int getCurrentRawInInterrupt(); virtual int getCurrentRawInInterrupt();

View File

@ -92,7 +92,7 @@ void TrackManager::setDCCSignal( bool on) {
HAVE_PORTA(shadowPORTA=PORTA); HAVE_PORTA(shadowPORTA=PORTA);
HAVE_PORTB(shadowPORTB=PORTB); HAVE_PORTB(shadowPORTB=PORTB);
HAVE_PORTC(shadowPORTC=PORTC); HAVE_PORTC(shadowPORTC=PORTC);
APPLY_BY_MODE(TRACK_MODE_MAIN,setSignal(on)); APPLY_BY_MODE(TRACK_MODE_MAIN,setSignal(on, true));
HAVE_PORTA(PORTA=shadowPORTA); HAVE_PORTA(PORTA=shadowPORTA);
HAVE_PORTB(PORTB=shadowPORTB); HAVE_PORTB(PORTB=shadowPORTB);
HAVE_PORTC(PORTC=shadowPORTC); HAVE_PORTC(PORTC=shadowPORTC);
@ -110,7 +110,7 @@ void TrackManager::setPROGSignal( bool on) {
HAVE_PORTA(shadowPORTA=PORTA); HAVE_PORTA(shadowPORTA=PORTA);
HAVE_PORTB(shadowPORTB=PORTB); HAVE_PORTB(shadowPORTB=PORTB);
HAVE_PORTC(shadowPORTC=PORTC); HAVE_PORTC(shadowPORTC=PORTC);
APPLY_BY_MODE(TRACK_MODE_PROG,setSignal(on)); APPLY_BY_MODE(TRACK_MODE_PROG,setSignal(on, true));
HAVE_PORTA(PORTA=shadowPORTA); HAVE_PORTA(PORTA=shadowPORTA);
HAVE_PORTB(PORTB=shadowPORTB); HAVE_PORTB(PORTB=shadowPORTB);
HAVE_PORTC(PORTC=shadowPORTC); HAVE_PORTC(PORTC=shadowPORTC);