mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2024-12-23 21:01:25 +01:00
protect setSignal() changes in setDCSignal from being changed back during interrupt vis setDCCSignal
This commit is contained in:
parent
016bc37b53
commit
b24f6b27c6
@ -41,16 +41,20 @@ MotorDriver::MotorDriver(VPIN power_pin, byte signal_pin, byte signal_pin2, int8
|
||||
getFastPin(F("SIG"),signalPin,fastSignalPin);
|
||||
pinMode(signalPin, OUTPUT);
|
||||
|
||||
fastSignalPin.shadowinout = NULL;
|
||||
if (HAVE_PORTA(fastSignalPin.inout == &PORTA)) {
|
||||
DIAG(F("Found PORTA pin %d"),signalPin);
|
||||
fastSignalPin.shadowinout = fastSignalPin.inout;
|
||||
fastSignalPin.inout = &fakePORTA;
|
||||
}
|
||||
if (HAVE_PORTB(fastSignalPin.inout == &PORTB)) {
|
||||
DIAG(F("Found PORTB pin %d"),signalPin);
|
||||
fastSignalPin.shadowinout = fastSignalPin.inout;
|
||||
fastSignalPin.inout = &fakePORTB;
|
||||
}
|
||||
if (HAVE_PORTC(fastSignalPin.inout == &PORTC)) {
|
||||
DIAG(F("Found PORTC pin %d"),signalPin);
|
||||
fastSignalPin.shadowinout = fastSignalPin.inout;
|
||||
fastSignalPin.inout = &fakePORTC;
|
||||
}
|
||||
|
||||
@ -162,15 +166,39 @@ int MotorDriver::getCurrentRaw() {
|
||||
void MotorDriver::setDCSignal(byte speedcode) {
|
||||
if (brakePin == UNUSED_PIN)
|
||||
return;
|
||||
// spedcoode is a dcc speed /direction
|
||||
byte tSpeed=speedcode & 0x7F;
|
||||
// DCC Speed with 0,1 stop and speed steps 2 to 127
|
||||
// spedcoode is a dcc speed & direction
|
||||
byte tSpeed=speedcode & 0x7F; // DCC Speed with 0,1 stop and speed steps 2 to 127
|
||||
byte tDir=speedcode & 0x80;
|
||||
byte brake;
|
||||
if (tSpeed <= 1) brake = 255;
|
||||
else if (tSpeed >= 127) brake = 0;
|
||||
else brake = 2 * (128-tSpeed);
|
||||
analogWrite(brakePin,brake);
|
||||
setSignal(speedcode & 0x80);
|
||||
// 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)) {
|
||||
noInterrupts();
|
||||
fakePORTA=PORTA;
|
||||
setSignal(tDir);
|
||||
PORTA=fakePORTA;
|
||||
interrupts();
|
||||
} else if (HAVE_PORTB(fastSignalPin.shadowinout == &PORTB)) {
|
||||
noInterrupts();
|
||||
fakePORTB=PORTB;
|
||||
setSignal(tDir);
|
||||
PORTB=fakePORTB;
|
||||
interrupts();
|
||||
} else if (HAVE_PORTC(fastSignalPin.shadowinout == &PORTC)) {
|
||||
noInterrupts();
|
||||
fakePORTC=PORTC;
|
||||
setSignal(tDir);
|
||||
PORTC=fakePORTC;
|
||||
interrupts();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int MotorDriver::getCurrentRawInInterrupt() {
|
||||
|
@ -65,13 +65,15 @@
|
||||
struct FASTPIN {
|
||||
volatile uint32_t *inout;
|
||||
uint32_t maskHIGH;
|
||||
uint32_t maskLOW;
|
||||
uint32_t maskLOW;
|
||||
volatile uint32_t *shadowinout;
|
||||
};
|
||||
#else
|
||||
struct FASTPIN {
|
||||
volatile uint8_t *inout;
|
||||
uint8_t maskHIGH;
|
||||
uint8_t maskLOW;
|
||||
uint8_t maskLOW;
|
||||
volatile uint8_t *shadowinout;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -87,11 +87,15 @@ void TrackManager::addTrack(byte t, MotorDriver* driver) {
|
||||
}
|
||||
}
|
||||
|
||||
// The port registers that are shadowing
|
||||
// the real port registers. These are
|
||||
// defined in Motordriver.cpp
|
||||
extern byte fakePORTA;
|
||||
extern byte fakePORTB;
|
||||
extern byte fakePORTC;
|
||||
|
||||
// setDCCSignal(), called from interrupt context
|
||||
// does assume ports are shadowed if they can be
|
||||
void TrackManager::setDCCSignal( bool on) {
|
||||
HAVE_PORTA(fakePORTA=PORTA);
|
||||
HAVE_PORTB(fakePORTB=PORTB);
|
||||
@ -108,6 +112,8 @@ void TrackManager::setCutout( bool on) {
|
||||
// TODO APPLY_BY_MODE(TRACK_MODE_MAIN,setCutout(on));
|
||||
}
|
||||
|
||||
// setPROGSignal(), called from interrupt context
|
||||
// does assume ports are shadowed if they can be
|
||||
void TrackManager::setPROGSignal( bool on) {
|
||||
HAVE_PORTA(fakePORTA=PORTA);
|
||||
HAVE_PORTB(fakePORTB=PORTB);
|
||||
@ -118,18 +124,15 @@ void TrackManager::setPROGSignal( bool on) {
|
||||
HAVE_PORTC(PORTC=fakePORTC);
|
||||
}
|
||||
|
||||
// setDCSignal(), called from normal context
|
||||
// MotorDriver::setDCSignal handles shadowed IO port changes.
|
||||
// with interrupts turned off around the critical section
|
||||
void TrackManager::setDCSignal(int16_t cab, byte speedbyte) {
|
||||
HAVE_PORTA(fakePORTA=PORTA);
|
||||
HAVE_PORTB(fakePORTB=PORTB);
|
||||
HAVE_PORTC(fakePORTC=PORTC);
|
||||
FOR_EACH_TRACK(t) {
|
||||
if (trackDCAddr[t]!=cab) continue;
|
||||
if (trackMode[t]==TRACK_MODE_DC) track[t]->setDCSignal(speedbyte);
|
||||
else if (trackMode[t]==TRACK_MODE_DCX) track[t]->setDCSignal(speedbyte ^ 128);
|
||||
}
|
||||
HAVE_PORTA(PORTA=fakePORTA);
|
||||
HAVE_PORTB(PORTB=fakePORTB);
|
||||
HAVE_PORTC(PORTC=fakePORTC);
|
||||
}
|
||||
|
||||
|
||||
@ -193,10 +196,11 @@ bool TrackManager::setTrackMode(byte trackToSet, TRACK_MODE mode, int16_t dcAddr
|
||||
} else if (trackMode[t]==TRACK_MODE_MAIN || trackMode[t]==TRACK_MODE_PROG)
|
||||
canDo &= track[t]->isPWMCapable();
|
||||
}
|
||||
//DIAG(F("HAMode=%d"),canDo);
|
||||
if (!canDo) {
|
||||
DCCTimer::clearPWM();
|
||||
}
|
||||
//if (MotorDriver::usePWM != canDo)
|
||||
// DIAG(F("HA mode changed from %d to %d"), MotorDriver::usePWM, canDo);
|
||||
MotorDriver::usePWM=canDo;
|
||||
|
||||
|
||||
@ -211,7 +215,7 @@ bool TrackManager::setTrackMode(byte trackToSet, TRACK_MODE mode, int16_t dcAddr
|
||||
void TrackManager::applyDCSpeed(byte t) {
|
||||
uint8_t speedByte=DCC::getThrottleSpeedByte(trackDCAddr[t]);
|
||||
if (trackMode[t]==TRACK_MODE_DCX)
|
||||
speedByte = (speedByte & 0xF7) | ~(speedByte & 0x80); // Reverse highest bit
|
||||
speedByte = speedByte ^ 128; // reverse direction bit
|
||||
track[t]->setDCSignal(speedByte);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user