/* * Tis code should run on Teensy 4.0 * It is bi directional forwarding and displaying status of ERR pin to see * behaviour of TJA1055 when bus goes to sleep. * Dusan Koszeghy * * 13.07.2020 ForwareTJA1055test2 * Nothing on ERR pin changes as bus gets to sleep. * Adding Snooze example of deepSleep * * 13.07.2020 ForwardTJA1055test4 * after startup Teensy go to sleep after PresetRXtimeout milliseconds * All three TJAs are put to Goto sleep and then sleep mode. * Current consumption during sleep is around 5,7 mA @ 12V. * This includes around 900 uA for 12/5V switching regulator. * Then waits for change on TJA_MASTER_ERR pin indicating remote wakeup. * Teensy properly wake up only if can.reset() on all three can interfaces is called * before put to sleep. * As such, can.begin has to be called upon wakeup. * * 13.07.2020 PSA_GW_NAC_01 * Copy of previous Forward code * * 14.07.2020 PS_GW_NAC_02 * HW: tied WAKE pins on all TJA1045 to BAT * SW: removed pinMode for those WAKE pins * * 14.07.2020 PS_GW_NAC_04 * Added engine run detection with CAN id 0xB6. * * 18.07.2020 PS_GW_NAC_06 * Added FRAM * * 19.07.2020 PS_GW_NAC_06 * sometimes Teensy hangs when wake up event occur and is connected to PC using USB cable. * * 20.07.2020 PS_GW_NAC_07 * still issues with freezing even with MsTimer2 * * 20.07.2020 PS_GW_NAC_08 * still issues with freezing* * * */ #include #include #include #include #include #include #define TJA_MASTER_ERR 2 #define TJA_MASTER_STB 11 #define TJA_MASTER_EN 10 #define TJA_SUBNET_STB 8 #define TJA_SUBNET_EN 7 #define TJA_SUBNET2_STB 5 #define TJA_SUBNET2_EN 4 #define LED_HEARTBEAT 13 #define LED_DEBUG1 12 #define LED_DEBUG2 14 #define LED_DEBUG3 15 #define LED_MASTER 20 // indicating received data on "car" side #define LED_SUBNET 16 // indicates received data on subnet side 1 #define LED_SUBNET2 17 // detto #define LED_MASTER_ERR 21 // indicates error output on "car" tja #define IN_DEBUG 3 // button #define oneMsInterval 1000 // micros fpr one millisecond generation #define oneSInterval 1000 // milliseconds #define ERR_test 100 // how often is checked TJA_MASTER_ERR in ms #define PresetRXtimeout 5000 // 5000 ms #define PresetDebug 20000 // 20 s #define PresetDelayTelegrams 50 // how many 0x1A9 messages must come from NAC after engineRun flag has been risen to simulate button press #define PresetDelayTelegrams2 5 // how many 0x1A9 messages will we simulate button press #define EE_StartStop_deactivate 0 #define PresetFlagStartStop 750 // 250 ms for canceling start stop enabled flag #define PresetEngineRun 100 // enngine run flag delay in ms #define PresetEngineStopped 1100 // 1100 ms for displaying engine stopped flag struct timers { uint32_t wrk_master_rx_timeout = PresetRXtimeout; // will be preset to PresetRXtimeout after successfull receive on can_master of after wakeup uint32_t wrk_master_err_test = 0; uint32_t wrk_led_master_subnet = 0; uint32_t wrk_led_subnet_master = 0; uint32_t wrk_led_subnet2_master = 0; uint32_t wrk_debug_timer = PresetDebug; uint32_t wrk_one_sec = oneSInterval; uint32_t wrk_led_debug1 = 0; uint32_t wrk_led_debug2 = 0; uint32_t wrk_flag_start_stop = 0; uint32_t wrk_engine_run = 0; uint32_t wrk_engine_stopped = 0; uint32_t wrk_start_stop_deact = 0; uint32_t wrk_state_start_stop = PresetFlagStartStop; } timers; #define StateStartStopDeactivated 4 #define StateStartStopHItemp 8 struct can_messages { CAN_message_t msg; uint32_t wrk_start_stop_telegrams = PresetDelayTelegrams; uint32_t wrk_start_stop = 0; uint32_t state_start_stop = 0; } can_messages; struct flags { bool doSnooze = false; bool debug = false; bool oneSecond = false; bool engineRun = false; bool engineStopped = false; bool StartStop_helper = false; bool StartStop_feedback = false; bool StartStop_deactivate = false; } flags; SnoozeDigital digital; SnoozeUSBSerial usb; SnoozeBlock config_teensy40(digital, usb); //SnoozeBlock config_teensy40(usb); FlexCAN_T4 can_master; FlexCAN_T4 can_subnet; FlexCAN_T4 can_subnet2; elapsedMicros oneMs; //Metro millisec = Metro(1); /*******************************************************************************************************************************************************/ /*******************************************************************************************************************************************************/ /*******************************************************************************************************************************************************/ void setup(void) { pinMode(TJA_MASTER_ERR, INPUT); pinMode(TJA_MASTER_EN, OUTPUT); pinMode(TJA_MASTER_STB, OUTPUT); pinMode(TJA_SUBNET_STB, OUTPUT); pinMode(TJA_SUBNET_EN, OUTPUT); pinMode(TJA_SUBNET2_STB, OUTPUT); pinMode(TJA_SUBNET2_EN, OUTPUT); pinMode(LED_MASTER, OUTPUT); pinMode(LED_DEBUG1, OUTPUT); pinMode(LED_DEBUG2, OUTPUT); pinMode(LED_DEBUG3, OUTPUT); pinMode(IN_DEBUG, INPUT_PULLUP); pinMode(LED_SUBNET, OUTPUT); pinMode(LED_SUBNET2, OUTPUT); pinMode(LED_MASTER_ERR, OUTPUT); pinMode(LED_HEARTBEAT, OUTPUT); pinMode(LED_BUILTIN, OUTPUT); digitalWrite(TJA_MASTER_EN, HIGH); digitalWrite(TJA_MASTER_STB, HIGH); digitalWrite(TJA_SUBNET_STB, HIGH); digitalWrite(TJA_SUBNET_EN, HIGH); digitalWrite(TJA_SUBNET2_STB, HIGH); digitalWrite(TJA_SUBNET2_EN, HIGH); delay(100); can_begin(); digital.pinMode(TJA_MASTER_ERR, INPUT, FALLING); //TJA_MASTER_ERR, mode, type digital.pinMode(IN_DEBUG, INPUT_PULLUP, FALLING); //TJA_MASTER_ERR, mode, type MsTimer2::set(500, flash); // 500ms period MsTimer2::start(); } /*******************************************************************************************************************************************************/ /*******************************************************************************************************************************************************/ /*******************************************************************************************************************************************************/ void loop() { if (oneMs > oneMsInterval) { oneMs = 0; digitalWrite(LED_DEBUG3, !digitalRead(LED_DEBUG3)); // show me 1 ms if (timers.wrk_master_rx_timeout) { snoozeStages(); timers.wrk_master_rx_timeout--; } // start stop status canceler if (timers.wrk_state_start_stop) { timers.wrk_state_start_stop--; } else { can_messages.state_start_stop = 0; } // helping timeout for indicating engine stop if (timers.wrk_engine_run) { timers.wrk_engine_run--; flags.engineRun = true; } else { flags.engineRun = false; } if (timers.wrk_engine_stopped) { timers.wrk_engine_stopped--; // digitalWriteFast(LED_DEBUG1, HIGH); flags.engineStopped = true; } else { // digitalWriteFast(LED_DEBUG1, LOW); flags.engineStopped = false; } if (timers.wrk_one_sec) { timers.wrk_one_sec--; } else { timers.wrk_one_sec = oneSInterval; flags.oneSecond = true; } if (flags.StartStop_deactivate) { // digitalWriteFast(LED_DEBUG1, HIGH); timers.wrk_start_stop_deact = 1000; } else { if (timers.wrk_start_stop_deact) { timers.wrk_start_stop_deact--; } else { // digitalWriteFast(LED_DEBUG1, LOW); } } // unused // 20s generator if (timers.wrk_debug_timer == (PresetDebug - 500)) { // 19,5s flags.debug = true; } if (timers.wrk_debug_timer == 1) { // 20s timers.wrk_debug_timer = PresetDebug; flags.debug = false; } timers.wrk_debug_timer--; // check for TJA_MASTER ERR input every 100 ms / flash LED_BUILTIN if (timers.wrk_master_err_test < ERR_test) { timers.wrk_master_err_test++; } else { timers.wrk_master_err_test = 0; digitalWrite(LED_MASTER_ERR, !digitalRead(TJA_MASTER_ERR)); digitalWrite(LED_HEARTBEAT, !digitalRead(LED_HEARTBEAT)); /* if (flags.engineRun) { digitalWrite(LED_DEBUG3, HIGH); } else { digitalWrite(LED_DEBUG3, LOW); } if (flags.StartStop_feedback) { digitalWrite(LED_DEBUG2, LOW); } else { digitalWrite(LED_DEBUG2, HIGH); } */ } // timeout routines for LED indicating comm if (digitalRead(LED_MASTER)) { if (timers.wrk_led_master_subnet) { timers.wrk_led_master_subnet--; } else { digitalWrite(LED_MASTER, LOW); } } if (digitalRead(LED_SUBNET)) { if (timers.wrk_led_subnet_master) { timers.wrk_led_subnet_master--; } else { digitalWrite(LED_SUBNET, LOW); } } if (digitalRead(LED_SUBNET2)) { if (timers.wrk_led_subnet2_master) { timers.wrk_led_subnet2_master--; } else { digitalWrite(LED_SUBNET2, LOW); } } } can_forwarding(); // b_can flags.oneSecond = false; } /*******************************************************************************************************************************************************/ void snoozeStages() { switch (timers.wrk_master_rx_timeout) { case 175: { digitalWrite(LED_DEBUG1, HIGH); can_reset(); } break; case 150: { digitalWrite(TJA_SUBNET_STB, LOW); digitalWrite(TJA_SUBNET2_STB, LOW); digitalWrite(TJA_MASTER_STB, LOW); } break; case 125: { digitalWrite(TJA_SUBNET_EN, LOW); digitalWrite(TJA_SUBNET2_EN, LOW); digitalWrite(TJA_MASTER_EN, LOW); } break; case 100: { digitalWrite(LED_HEARTBEAT, LOW); digitalWrite(LED_SUBNET, LOW); digitalWrite(LED_MASTER, LOW); digitalWrite(LED_DEBUG1, LOW); digitalWrite(LED_DEBUG3, LOW); digitalWrite(LED_DEBUG2, LOW); Snooze.deepSleep(config_teensy40); // return module that woke processor } break; case 95: { can_begin(); } break; case 94: { digitalWrite(LED_DEBUG3, HIGH); digitalWrite(TJA_MASTER_STB, HIGH); digitalWrite(TJA_MASTER_EN, HIGH); digitalWrite(TJA_SUBNET_STB, HIGH); digitalWrite(TJA_SUBNET_EN, HIGH); digitalWrite(TJA_SUBNET2_STB, HIGH); digitalWrite(TJA_SUBNET2_EN, HIGH); timers.wrk_master_rx_timeout = PresetRXtimeout; } break; } } /*******************************************************************************************************************************************************/ void can_reset() { can_master.reset(); can_subnet.reset(); can_subnet2.reset(); } /*******************************************************************************************************************************************************/ void can_begin() { can_master.begin(); can_master.setBaudRate(125000); can_subnet.begin(); can_subnet.setBaudRate(125000); can_subnet2.begin(); can_subnet2.setBaudRate(125000); can_messages.wrk_start_stop = 0; } /*******************************************************************************************************************************************************/ void can_forwarding() { // data that come from car if (can_master.read(can_messages.msg)) { timers.wrk_master_rx_timeout = PresetRXtimeout; // preset timer to skip going to deep sleep digitalWriteFast(LED_MASTER, HIGH); timers.wrk_led_master_subnet = 2; can_check_engine_run(can_messages.msg); // sets or clears flags.engineRun boolean // can_check_start_stop(can_messages.msg); can_check_start_stop2(can_messages.msg); can_subnet.write(can_messages.msg); can_subnet2.write(can_messages.msg); // data that come from NAC } else if ( can_subnet.read(can_messages.msg) ) { digitalWriteFast(LED_SUBNET, HIGH); timers.wrk_led_subnet_master = 4; can_start_stop(can_messages.msg); // can_simulate_button_press(); can_master.write(can_messages.msg); can_subnet2.write(can_messages.msg); // data that come from keypad and visual ecu } else if ( can_subnet2.read(can_messages.msg) ) { digitalWriteFast(LED_SUBNET2, HIGH); timers.wrk_led_subnet_master = 4; can_master.write(can_messages.msg); can_subnet.write(can_messages.msg); } } /*******************************************************************************************************************************************************/ /* CAN ID 0xB6 50 ms frame.buf[0] and frame.buf[1] are engine RPM int, need to divide by 10 frame.buf[6] counts up every 500 ms and roll over frame.buf[7] holds 0xD0, but when start stop button is pressed, briefly changes to 0x28 */ void can_check_engine_run(CAN_message_t &frame) { if (frame.id == 0xB6) { if (frame.buf[0] || frame.buf[1]) { timers.wrk_engine_run = PresetEngineRun; timers.wrk_engine_stopped = 0; } else { if (timers.wrk_engine_run) { timers.wrk_engine_stopped = PresetEngineStopped; } } } } /*******************************************************************************************************************************************************/ /* Does not work yet */ void can_start_stop(CAN_message_t &frame) { if (frame.id == 0x1A9) { if (flags.engineRun) { if (can_messages.wrk_start_stop < 1060) { can_messages.wrk_start_stop++; } else if (can_messages.wrk_start_stop > 1000 && can_messages.wrk_start_stop < 1050) { if (flags.StartStop_feedback && flags.StartStop_deactivate) { can_messages.msg.buf[6] = can_messages.msg.buf[6] | 0b10000000; } } } if (can_messages.msg.buf[6] & 0b10000000) { // check, if we pressed on screen button for activation/deactivation if (!flags.StartStop_helper) { // once we checked and changed flags.StartStop_deactivate, we dont want to run there again, so flags.StartStop_helper = true; // set there the helper flag to skip next time if (flags.StartStop_feedback) { // if StartStop_feedback is true, start stop has not been deactivated, see can_check_start_stop() flags.StartStop_deactivate = false; // change the boolean and EEPROM } else { flags.StartStop_deactivate = true; } // EEPROM.put(EE_StartStop_deactivate, flags.StartStop_deactivate); } } else { if (flags.StartStop_helper) { flags.StartStop_helper = false; } } } } /*******************************************************************************************************************************************************/ // simulate start stop button press every 20 s // unused void can_simulate_button_press() { if (flags.debug && can_messages.msg.id == 0x1A9) { can_messages.msg.buf[6] = can_messages.msg.buf[6] | 0b10000000; } } /*******************************************************************************************************************************************************/ // shows feedback of start stop activation or deactivation void can_check_start_stop(CAN_message_t &frame) { if (frame.id == 0x227) { if (frame.buf[3] & 0b00000100) { // if true, Start Stop is deactivated timers.wrk_flag_start_stop = PresetFlagStartStop; // so preload working register } } } /*******************************************************************************************************************************************************/ /* CAN ID 0x227 250 ms shows feedback of start stop activation or deactivation by setting of can_messages.state_start_stop to: 00 - start stop activated 04 - deactivated start stop 08 - when deactivated and pressed start stop button on display this value displays message on instrument cluster that temperature is high and makes touch button flashing on radio too */ void can_check_start_stop2(CAN_message_t &frame) { if (frame.id == 0x227) { can_messages.state_start_stop = frame.buf[3] & 0b00001100; // mask off other bits, just in case timers.wrk_state_start_stop = PresetFlagStartStop; } } /*******************************************************************************************************************************************************/ // test with MsTimer2 void flash() { static boolean output = HIGH; digitalWrite(LED_DEBUG2, output); output = !output; }