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

Wave-state machine ( part 11)

This commit is contained in:
Asbelos 2021-01-27 09:46:08 +00:00
parent b8d61fb839
commit 4e6f79589a
4 changed files with 47 additions and 36 deletions

View File

@ -56,6 +56,10 @@ void DCCWaveform::interruptHandler() {
// after the rising edge of the signal // after the rising edge of the signal
if (mainCall2) mainTrack.interrupt2(); if (mainCall2) mainTrack.interrupt2();
if (progCall2) progTrack.interrupt2(); if (progCall2) progTrack.interrupt2();
// Read current if in high middle of zero wave (state is set for NEXT interrupt!)
if (mainTrack.state==WAVE_MID_0) mainTrack.lastCurrent=mainTrack.motorDriver->getCurrentRaw();
if (progTrack.state==WAVE_MID_0) progTrack.lastCurrent=progTrack.motorDriver->getCurrentRaw();
} }
@ -74,7 +78,7 @@ DCCWaveform::DCCWaveform( byte preambleBits, bool isMain) {
isMainTrack = isMain; isMainTrack = isMain;
packetPending = false; packetPending = false;
memcpy(transmitPacket, idlePacket, sizeof(idlePacket)); memcpy(transmitPacket, idlePacket, sizeof(idlePacket));
state = 0; state = WAVE_START;
// The +1 below is to allow the preamble generator to create the stop bit // The +1 below is to allow the preamble generator to create the stop bit
// fpr the previous packet. // fpr the previous packet.
requiredPreambles = preambleBits+1; requiredPreambles = preambleBits+1;
@ -112,7 +116,6 @@ void DCCWaveform::checkPowerOverload() {
break; break;
case POWERMODE::ON: case POWERMODE::ON:
// Check current // Check current
lastCurrent = motorDriver->getCurrentRaw();
if (lastCurrent <= tripValue) { if (lastCurrent <= tripValue) {
sampleDelay = POWER_SAMPLE_ON_WAIT; sampleDelay = POWER_SAMPLE_ON_WAIT;
if(power_good_counter<100) if(power_good_counter<100)
@ -144,41 +147,49 @@ void DCCWaveform::checkPowerOverload() {
// process time-edge sensitive part of interrupt // process time-edge sensitive part of interrupt
// return true if second level required // return true if second level required
bool DCCWaveform::interrupt1() { bool DCCWaveform::interrupt1() {
// NOTE: this must consume transmission buffers even if the power is off // NOTE: this must consume transmission buffers even if the power is off
// otherwise can cause hangs in main loop waiting for the pendingBuffer. // otherwise can cause hangs in main loop waiting for the pendingBuffer.
byte sigwave;
switch (state) { switch (state) {
case 0: // start of bit transmission // Each section of this case is designed to run as near as possible in the same cpu time
setSignal(HIGH); // hence some unnecessary duplication and pin setting.
state = 1; // Breaking this causes jitter in the prog track waveform.
return true; // must call interrupt2 to set currentBit
case 1: // 58us after case 0 case WAVE_START: // start of bit transmission
if (currentBit) { sigwave=HIGH;
setSignal(LOW); state = WAVE_PENDING;
state = 0; break; // must call interrupt2 to set next state
}
else { case WAVE_MID_1: // 58us after case 0 with currentbit=1
setSignal(HIGH); // jitter prevention sigwave=LOW;
state = 2; state = WAVE_START;
}
break; break;
case 2: // 116us after case 0
setSignal(LOW); case WAVE_HIGH_0: // 58us after case 0 with currentbit=0
state = 3; sigwave=HIGH;
state = WAVE_MID_0;
break; break;
case 3: // finished sending zero bit
setSignal(LOW); // jitter prevention case WAVE_MID_0: // 116us after case 0 with currentbit=0
state = 0; sigwave=LOW;
state = WAVE_LOW_0;
break;
case WAVE_LOW_0: // half way through zero-low
sigwave=LOW; // jitter prevention
state = WAVE_START;
break; break;
} }
setSignal(sigwave);
// ACK check is prog track only and will only be checked if // ACK check is prog track only and will only be checked if
// this is not case(0) which needs relatively expensive packet change code to be called. // this is not case(0) which needs relatively expensive packet change code to be called.
if (ackPending) checkAck(); if (ackPending && state!=WAVE_PENDING) checkAck();
return false;
return state==WAVE_PENDING; // true, caller must call Interrupt2
} }
void DCCWaveform::setSignal(bool high) { void DCCWaveform::setSignal(bool high) {
@ -193,16 +204,16 @@ void DCCWaveform::setSignal(bool high) {
} }
void DCCWaveform::interrupt2() { void DCCWaveform::interrupt2() {
// set currentBit to be the next bit to be sent. // calculate the next bit to be sent.
if (remainingPreambles > 0 ) { if (remainingPreambles > 0 ) {
currentBit = true; state=WAVE_MID_1; // switch state to trigger LOW on next interrupt
remainingPreambles--; remainingPreambles--;
return; return;
} }
// beware OF 9-BIT MASK generating a zero to start each byte // beware OF 9-BIT MASK generating a zero to start each byte
currentBit = transmitPacket[bytes_sent] & bitMask[bits_sent]; state=(transmitPacket[bytes_sent] & bitMask[bits_sent])? WAVE_MID_1 : WAVE_HIGH_0;
bits_sent++; bits_sent++;
// If this is the last bit of a byte, prepare for the next byte // If this is the last bit of a byte, prepare for the next byte
@ -267,7 +278,7 @@ int DCCWaveform::getLastCurrent() {
void DCCWaveform::setAckBaseline() { void DCCWaveform::setAckBaseline() {
if (isMainTrack) return; if (isMainTrack) return;
int baseline = motorDriver->getCurrentRaw(); int baseline = lastCurrent;
ackThreshold= baseline + motorDriver->mA2raw(ackLimitmA); ackThreshold= baseline + motorDriver->mA2raw(ackLimitmA);
if (Diag::ACK) DIAG(F("\nACK baseline=%d/%dmA Threshold=%d/%dmA Duration: %dus <= pulse <= %dus"), if (Diag::ACK) DIAG(F("\nACK baseline=%d/%dmA Threshold=%d/%dmA Duration: %dus <= pulse <= %dus"),
baseline,motorDriver->raw2mA(baseline), baseline,motorDriver->raw2mA(baseline),
@ -302,7 +313,6 @@ void DCCWaveform::checkAck() {
return; return;
} }
lastCurrent=motorDriver->getCurrentRaw();
if (lastCurrent > ackMaxCurrent) ackMaxCurrent=lastCurrent; if (lastCurrent > ackMaxCurrent) ackMaxCurrent=lastCurrent;
// An ACK is a pulse lasting between minAckPulseDuration and maxAckPulseDuration uSecs (refer @haba) // An ACK is a pulse lasting between minAckPulseDuration and maxAckPulseDuration uSecs (refer @haba)

View File

@ -38,6 +38,7 @@ const byte MAX_PACKET_SIZE = 12;
enum class POWERMODE { OFF, ON, OVERLOAD }; enum class POWERMODE { OFF, ON, OVERLOAD };
enum WAVE_STATE {WAVE_START,WAVE_MID_1,WAVE_HIGH_0,WAVE_MID_0,WAVE_LOW_0,WAVE_PENDING};
const byte idlePacket[] = {0xFF, 0x00, 0xFF}; const byte idlePacket[] = {0xFF, 0x00, 0xFF};
const byte resetPacket[] = {0x00, 0x00, 0x00}; const byte resetPacket[] = {0x00, 0x00, 0x00};
@ -118,11 +119,9 @@ class DCCWaveform {
byte transmitRepeats; // remaining repeats of transmission byte transmitRepeats; // remaining repeats of transmission
byte remainingPreambles; byte remainingPreambles;
byte requiredPreambles; byte requiredPreambles;
bool currentBit; // bit to be transmitted
byte bits_sent; // 0-8 (yes 9 bits) sent for current byte byte bits_sent; // 0-8 (yes 9 bits) sent for current byte
byte bytes_sent; // number of bytes sent from transmitPacket byte bytes_sent; // number of bytes sent from transmitPacket
byte state; // wave generator state machine WAVE_STATE state; // wave generator state machine
byte pendingPacket[MAX_PACKET_SIZE]; byte pendingPacket[MAX_PACKET_SIZE];
byte pendingLength; byte pendingLength;
byte pendingRepeats; byte pendingRepeats;

View File

@ -45,6 +45,7 @@ MotorDriver::MotorDriver(byte power_pin, byte signal_pin, byte signal_pin2, int8
faultPin=fault_pin; faultPin=fault_pin;
tripMilliamps=trip_milliamps; tripMilliamps=trip_milliamps;
rawCurrentTripValue=(int)(trip_milliamps / sense_factor); rawCurrentTripValue=(int)(trip_milliamps / sense_factor);
simulatedOverload=(int)(32000/senseFactor);
pinMode(powerPin, OUTPUT); pinMode(powerPin, OUTPUT);
pinMode(brakePin < 0 ? -brakePin : brakePin, OUTPUT); pinMode(brakePin < 0 ? -brakePin : brakePin, OUTPUT);
setBrake(false); setBrake(false);
@ -91,7 +92,7 @@ void MotorDriver::setSignal( bool high) {
int MotorDriver::getCurrentRaw() { int MotorDriver::getCurrentRaw() {
if (faultPin != UNUSED_PIN && ReadPin(faultPin) == LOW && ReadPin(powerPin) == HIGH) if (faultPin != UNUSED_PIN && ReadPin(faultPin) == LOW && ReadPin(powerPin) == HIGH)
return (int)(32000/senseFactor); return simulatedOverload;
// IMPORTANT: This function can be called in Interrupt() time within the 56uS timer // IMPORTANT: This function can be called in Interrupt() time within the 56uS timer
// The default analogRead takes ~100uS which is catastrphic // The default analogRead takes ~100uS which is catastrphic

View File

@ -43,5 +43,6 @@ class MotorDriver {
float senseFactor; float senseFactor;
unsigned int tripMilliamps; unsigned int tripMilliamps;
int rawCurrentTripValue; int rawCurrentTripValue;
int simulatedOverload;
}; };
#endif #endif