CODE PART2:
void INIT_SYSTEM_WITH_RAILCOM(){
//COMPARATOR:
//when inverting > non inverting ==> AC OUT = high
//measured current will be connected to inverting input (L6203 SENSE PIN trough a 10K resistor)
Comparator.input_p = comparator::in_p::in1; //inverting PIN_PB5
Comparator.input_n = comparator::in_n::in1; //non inverting PIN_PB4
Comparator.reference = comparator::ref::disable;
Comparator.hysteresis = comparator::hyst::disable;
Comparator.output = comparator::out::disable; // No output pin, signal not inverted internally
Comparator.init();
Comparator.start(); // Start comparator
//DEFINE CCL LUT3:
//NEED EVENT CHANNEL FIRST TO ROUTE INSIDE LUT3: USE EVENT CHANNEL 3
Event3.assign_generator_pin(gen3::pin_pa6); //PIN_PA6 AS EVENT CH3 SOURCE
Event3.set_user(user::ccl3_event_a); //EVENT A OF LUT3
Event3.start();
Logic3.enable; //ENABLE LUT3
Logic3.input0 = logic::in::ac; //AC0 level OUT
Logic3.input1 = logic::in::event_a; //EVENT_A from EVENT CH3
Logic3.input2 = logic::in::masked; //not used
Logic3.output = logic::out::disable; //NOT USED, use EVENT CH2 instead
Logic3.truth = 0x04;
Logic3.init();
Event2.assign_generator(gen::ccl3_out);
Event2.set_user(user::evouta_pin_pa7);
Event2.start();
//DEFINE CCL LUT0:
Logic0.enable; //ENABLE LUT0
Logic0.input0 = logic::in::masked; //UDPI NOT USED
Logic0.input1 = logic::in::pin; //PIN_PA1
Logic0.input2 = logic::in::pin; //PIN_PA2
Logic0.output = logic::out::disable; //NOT USED, use EVENT CH5 instead
Logic0.truth = 0x04; // Set truth table
Logic0.init();
Event5.assign_generator(gen::ccl0_out); //source LUT0 OUT
Event5.set_user(user::tcb0_capt); //route to TCB0
Event5.set_user(user::ccl1_event_a); //event A CCL1
Event5.set_user(user::ccl2_event_a); //event A CCL2
Event5.start();
Event1.assign_generator_pin(gen1::pin_pa3); //PA3 INPUT
Event1.set_user(user::ccl1_event_b); //event B CCL1
Event1.set_user(user::ccl2_event_b); //event B CCL2
Event1.start();
Logic1.enable; //ENABLE LUT1
Logic1.input0 = logic::in::event_a; //logic1 in0 event A
Logic1.input1 = logic::in::event_b; //logic1 in1 event B
Logic1.input2 = logic::in::masked; //not used
Logic1.output = logic::out::disable; //OUTPUT NOT USED, OUT STATE will go to EVENT CH0
Logic1.truth = 0x01; // Set truth table
Logic1.init();
Event0.assign_generator(gen::ccl1_out);
Event0.set_user(user::evoutb_pin_pb2);
Event0.start();
Logic2.enable; //ENABLE LUT2
Logic2.input0 = logic::in::event_a; //logic2 in0 event A
Logic2.input1 = logic::in::event_b; //logic2 in1 event B
Logic2.input2 = logic::in::masked; //not used
Logic2.output = logic::out::enable; //PIN_PB3 OUTPUT TO DRIVE L6203 IN
Logic2.truth = 0x02; // Set truth table
Logic2.init();
Event4.set_generator(gen::ac0_out); //source AC0 out
Event4.set_user(user::evoutc_pin_pc2); //manage LED_SHORCUT_OVERLOAD
Event4.start();
Logic0.start();
Logic1.start();
Logic2.start();
Logic3.start();
}
void INIT_SYSTEM_SIMPLE_AMPLIFICATOR(){
//COMPARATOR:
Comparator.input_p = comparator::in_p::in1;
Comparator.input_n = comparator::in_n::in1;
Comparator.reference = comparator::ref::disable;
Comparator.hysteresis = comparator::hyst::disable;
Comparator.output = comparator::out::disable_invert; // No output pin, signal inverted internally
Comparator.init();
Comparator.start(); // Start comparator
//EVENT CH1:
Event1.assign_generator_pin(gen1::pin_pa1); //PIN_PA1 AS EVENT CH1 SOURCE
Event1.set_user(user::ccl1_event_a); //EVENT A OF LUT0
Event1.set_user(user::ccl2_event_a); //EVENT B OF LUT2
Event1.start();
//EVENT CH2:
Event2.assign_generator_pin(gen2::pin_pa2); //PIN_PA2 AS EVENT CH2 SOURCE
Event2.set_user(user::ccl1_event_b); //EVENT A OF LUT0
Event2.set_user(user::ccl2_event_b); //EVENT B OF LUT2
Event2.start();
//LOGIC LUT1:
Logic1.enable; //ENABLE LUT3
Logic1.input0 = logic::in::event_a; //AC0 level OUT
Logic1.input1 = logic::in::event_b; //EVENT_A from EVENT CH3
Logic1.input2 = logic::in::masked; //not used
Logic1.output = logic::out::disable; //NOT USED, use EVENT CH0 instead
Logic1.truth = 0x04;
Logic1.init();
//EVENT CH0:
Event0.assign_generator(gen::ccl1_out);
Event0.set_user(user::evoutb_pin_pb2);
Event0.start();
//LOGIC LUT2:
Logic2.enable; //ENABLE LUT2
Logic2.input0 = logic::in::event_a; //logic1 in0 event A
Logic2.input1 = logic::in::event_b; //logic1 in1 event B
Logic2.input2 = logic::in::masked; //not used
Logic2.output = logic::out::enable; //OUTPUT PIN_PB3
Logic2.truth = 0x02; // Set truth table
Logic2.init();
//LOGIC LUT3:
Logic3.enable; //ENABLE LUT3
Logic3.input0 = logic::in::ac; //AC0 level OUT
Logic3.input1 = logic::in::masked; //not used
Logic3.input2 = logic::in::masked; //not used
Logic3.output = logic::out::disable; //NOT USED, use EVENT CH2 instead
Logic3.truth = 0x02;
Logic3.init();
//EVENT CH3:
Event3.assign_generator(gen::ccl3_out);
Event3.set_user(user::evouta_pin_pa7); //L6203_ENABLE_PIN
Event3.start();
//EVENT CH4:
Event4.assign_generator(gen::ac0_out);
Event4.set_user(user::evoutc_pin_pc2);
Event4.start();
//START LOGIC NODES:
Logic1.start();
Logic2.start();
Logic3.start();
}
CODE PART3:
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(TCB0.CNT < ENABLE_STOP_TIME) //< 26us
{
//ENABLE ON
LOGIC_ENABLE_OUT_PIN_ON;
while(TCB0.CNT < ENABLE_STOP_TIME) {;}; //WAIT TILL IS OVER
}
else if((TCB0.CNT < CUTOUT_START_TIME) && (TCB0.CNT >= ENABLE_STOP_TIME)) // >=26us & <30us
{
//ENABLE OFF
LOGIC_ENABLE_OUT_PIN_OFF;
while(TCB0.CNT < CUTOUT_START_TIME) {;}; //WAIT TILL IS OVER
}
else if((TCB0.CNT < CUTOUT_STOP_TIME) && (TCB0.CNT >= CUTOUT_START_TIME)) // >=30us & <484us
{
//MAKE CUTOUT:
LOGIC_CUTOUT_OUT_PIN_ON;
while(TCB0.CNT < CUTOUT_STOP_TIME) {;}; //WAIT TILL IS OVER
}
else if((TCB0.CNT < ENABLE_START_TIME) && (TCB0.CNT >= CUTOUT_STOP_TIME)) // >=484 us & < 488us
{
//STOP CUTOUT
LOGIC_CUTOUT_OUT_PIN_OFF;
while(TCB0.CNT < ENABLE_START_TIME) {;}; //WAIT TILL IS OVER
}
else if ((TCB0.CNT >= ENABLE_START_TIME)) // >=488us
{
//ENABLE PIN ON:
LOGIC_ENABLE_OUT_PIN_ON;
//CUTOUT IS OVER
}
}
//------------------------------------------ DCC Interrupt -------------------------------------------
//------------------------------------------- ISR Timers ----------------------------------------------------
ISR(TCB0_INT_vect) {
TCB0.EVCTRL ^= TCB_EDGE_bm; // Change the event edge at which we trigger
uint16_t delta = TCB0.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
TCB0.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 AC0 notifications
CUTOUT(RAILCOM); //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;
}
}
ISR(AC0_AC_vect) {
AC0.INTCTRL = 0;
}
Ltr