1
Vos projets / Re : LaBox" : Une Centrale DCC polyvalente et abordable
« le: Aujourd'hui à 01:03:54 pm »
C est la méthode que je teste actuellement. (sur un ATTINY826) ( avec la partie "logic", "event" n cie)
Dans l'ISR du TIMER affecté au décodage des trames DCC:
fonction CUTOUT:
Comme tu le soulignes on a en fait une sortie cote ESP32 qui est une source DCC "universelle" ( voir non amplifiée) qui peut ensuite être distribuée à tous les CPU effectuant le CUTOUT qui pilotent eux les ponts en H. (L6203 pour mon cas)
On est alors aligné sur tous les segments.
Les sorties de l'ESP32 sont alors assimilables aux plots CD sur les centrales LENZ pour la synchro inter booster
Pour moi le Security Gap reste de mise pour écarter tout écart restant inter booster lorsqu'un véhicule reste à cheval puisque chaque électronique peut encore varier d'un pouillième...
Il y a donc bien une recomposition du signal entre l'émetteur (EP32) et tous les consommateurs (derrière le(s) pont(s) H) d'un un léger décalage mais qui est constant entre la source unique et tous les consommateurs.
Dans l'ISR du TIMER affecté au décodage des trames DCC:
Code: [Sélectionner]
//------------------------------------------- ISR ----------------------------------------------------
ISR(DCC_TIMER_INT_vect) {
DCC_TIMER.EVCTRL ^= TCB_EDGE_bm; // Change the event edge at which we trigger
uint16_t delta = DCC_TIMER.CCMP; // Delta holds the time since the previous interrupt
uint8_t DccBitVal;
if ((delta >= ONE_BIT_MIN) && (delta <= ONE_BIT_MAX)) {
if (dccHalfBit & EXPECT_ONE) { // This is the second part of the 1 bit
dccHalfBit = EXPECT_ANYTHING;
DccBitVal = 1;
}
else if (dccHalfBit & EXPECT_ANYTHING) { // This is the first part of the 1 bit
dccHalfBit = EXPECT_ONE;
return;
}
else { // We expected a 1, but received 0 => abort
DCC_TIMER.EVCTRL ^= TCB_EDGE_bm; // Likely J/K should be changed
dccHalfBit = EXPECT_ANYTHING;
dccrecState = WAIT_PREAMBLE;
dccrec.bitCount = 0;
return;
}
}
else if ((delta >= ZERO_BIT_MIN) && (delta <= ZERO_BIT_MAX)) {
if (dccHalfBit & EXPECT_ZERO) { // This is the second part of the 0 bit
dccHalfBit = EXPECT_ANYTHING;
DccBitVal = 0;
}
else if (dccHalfBit & EXPECT_ANYTHING) { // This is the first part of the 0 bit
dccHalfBit = EXPECT_ZERO;
return;
}
else { // We expected a 0, but received 1 => abort
dccHalfBit = EXPECT_ANYTHING;
dccrecState = WAIT_PREAMBLE;
dccrec.bitCount = 0;
return;
}
}
else {
// We ignore other halfbits, to avoid interference with orther protocols.
// In case railcom would be implemented, here we could detect the cutout start (26..32us)
return;
}
dccrec.bitCount++;
switch( dccrecState )
{
// According to NMRA standard S9.2, a packet consists of:
// - Preamble
// - Packet Start Bit
// - Address Data Byte:
// - Data Byte Start Bit + Data Byte [0 or more times]
// - Packet End Bit
case WAIT_PREAMBLE:
// The preamble to a packet consists of a sequence of "1" bits.
// A digital decoder must not accept as a valid, any preamble
// that has less then 10 complete one bits
if( DccBitVal ) // a "1" bit is received
{
if( dccrec.bitCount > 10 )
dccrecState = WAIT_START_BIT;
}
else
{
dccrec.bitCount = 0; // not a valid preamble.
}
break;
case WAIT_START_BIT:
// The packet start bit is the first bit with a value of "0"
// that follows a valid preamble. The packet start bit terminates the preamble
// and indicates that the next bits are an address data byte
if( !DccBitVal ) // a "0" bit is received
{
dccrecState = WAIT_DATA;
dccrec.tempMessageSize = 0;
// Initialise all fields
uint8_t i;
for(i = 0; i< MaxDccSize; i++ )
{
dccrec.tempMessage[i] = 0;
}
dccrec.bitCount = 0;
}
break;
case WAIT_DATA:
//==================
if( dccrec.bitCount == 8 ) // byte is complete
{
if(dccrec.tempMessageSize == MaxDccSize ) // Packet is too long - abort
{
dccrecState = WAIT_PREAMBLE;
dccrec.bitCount = 0;
}
else
{
dccrecState = WAIT_END_BIT; // Wait for next byte or end of packet
}
}
break;
case WAIT_END_BIT:
// The next bit is either a Data Byte Start Bit or a Packet End Bit
// Data Byte Start Bit: precedes a data byte and has the value of "0"
// Packet End Bit: marks the termination of the packet and has a value of "1"
if(DccBitVal) // End of packet?
{
// Complete packet received and no errors
// we are in a CUTOUT AREA NOW
noInterrupts();
//no new external event change the sequence actions queue above till queue is over,
//just add ~500ms latency on any AC0 notifications by interrupt
CUTOUT(bitRead(RAILCOM,0)); //proceed cutout till end of it
//cutout is over now, continue
dccrecState = WAIT_PREAMBLE; //next step will be at this state
interrupts();
}
else // Get next Byte
{
dccrecState = WAIT_DATA;
dccrec.bitCount = 0; // prepare for the next byte
}
break;
}
}
fonction CUTOUT:
Code: [Sélectionner]
void CUTOUT(bool RAILCOM_ACTIV_OR_NOT){
if(RAILCOM_ACTIV_OR_NOT == false) //NO RAILCOM CUTOUT TO INSERT
{
//BY PASS CUTOUT: FORCE SOME PINS STATE ON:
LOGIC_ENABLE_OUT_PIN_ON;
LOGIC_CUTOUT_OUT_PIN_ON;
return;
}
//RAILCOM ACTIV: NEED TO INSERT CUTOUT
//TIMER B IS ALREADY STARTED AND CNT GO UP
if(DCC_TIMER.CNT < ENABLE_STOP_TIME) //< 26us
{
//ENABLE ON
LOGIC_ENABLE_OUT_PIN_ON;
while(DCC_TIMER.CNT < ENABLE_STOP_TIME) {;}; //WAIT TILL IS OVER
}
else if((DCC_TIMER.CNT < CUTOUT_START_TIME) && (DCC_TIMER.CNT >= ENABLE_STOP_TIME)) // >=26us & <30us
{
//ENABLE OFF
LOGIC_ENABLE_OUT_PIN_OFF;
while(DCC_TIMER.CNT < CUTOUT_START_TIME) {;}; //WAIT TILL IS OVER
}
else if((DCC_TIMER.CNT < CUTOUT_STOP_TIME) && (DCC_TIMER.CNT >= CUTOUT_START_TIME)) // >=30us & <484us
{
//MAKE CUTOUT:
LOGIC_CUTOUT_OUT_PIN_ON;
while(DCC_TIMER.CNT < CUTOUT_STOP_TIME) {;}; //WAIT TILL IS OVER
}
else if((DCC_TIMER.CNT < ENABLE_START_TIME) && (DCC_TIMER.CNT >= CUTOUT_STOP_TIME)) // >=484 us & < 488us
{
//STOP CUTOUT
LOGIC_CUTOUT_OUT_PIN_OFF;
while(DCC_TIMER.CNT < ENABLE_START_TIME) {;}; //WAIT TILL IS OVER
}
else if ((DCC_TIMER.CNT >= ENABLE_START_TIME)) // >=488us
{
//ENABLE PIN ON:
LOGIC_ENABLE_OUT_PIN_ON;
//CUTOUT IS OVER
}
}
Comme tu le soulignes on a en fait une sortie cote ESP32 qui est une source DCC "universelle" ( voir non amplifiée) qui peut ensuite être distribuée à tous les CPU effectuant le CUTOUT qui pilotent eux les ponts en H. (L6203 pour mon cas)
On est alors aligné sur tous les segments.
Les sorties de l'ESP32 sont alors assimilables aux plots CD sur les centrales LENZ pour la synchro inter booster
Pour moi le Security Gap reste de mise pour écarter tout écart restant inter booster lorsqu'un véhicule reste à cheval puisque chaque électronique peut encore varier d'un pouillième...
Il y a donc bien une recomposition du signal entre l'émetteur (EP32) et tous les consommateurs (derrière le(s) pont(s) H) d'un un léger décalage mais qui est constant entre la source unique et tous les consommateurs.