Tool/software:
I'm testing a CAN bus node implemented via a TCAN1044AV-Q1 transceiver attached to the MCAN peripheral of a MSPM0G3507 MCU. The node is intended to operate as a receiver only. When configured in active mode, CAN packets are properly received. It is desired that during periods of inactivity:
- the MCAN peripheral be placed in power-down mode and the transceiver in standby mode by MCU firmware
- CAN Rx activity will automatically wake up the MCAN peripheral, and the corresponding wakeup interrupt will cause MCU firmware to put MCAN back into active mode and the transceiver into normal mode
Accordingly, MCU firmware was developed to implement this behavior per Section 20.4.10 of the MSPM0 G-Series Technical Reference Manual. I have verified that when in standby mode, the transceiver drives its RXD line low upon reception of a CAN packet. However, the MCU's MCAN (in power-down mode) is not raising a wakeup interrupt in this scenario; i.e., an XDS110 breakpoint set at the start of the MCAN interrupt handler is not being hit.
Relevant code snippets:
bool can_wakeup_event = false; int main(void) { SYSCFG_DL_init(); DL_MCAN_enableClockStopWakeupInterrupt(MCAN0_INST); NVIC_EnableIRQ(MCAN0_INST_INT_IRQN); while (1) { __WFI(); if (system_in_low_power) { if (can_wakeup_event) { can_wakeup_event = false; low_power_exit(); system_in_low_power = false; } } else if (inactivity_timer_expired) { inactivity_timer_expired = false; low_power_enter(); system_in_low_power = true; } } } void low_power_enter() { /* Put CAN transceiver in standby */ DL_GPIO_setPins(CAN_STB_PMIC_PORT, CAN_STB_PMIC_PIN); /* Ensure that CAN bus is idle, then put MCAN module into power down mode */ DL_MCAN_ProtocolStatus protStatus; do DL_MCAN_getProtocolStatus(MCAN0_INST, &protStatus); while (protStatus.act != DL_MCAN_COM_STATE_IDLE); DL_MCAN_addClockStopRequest(MCAN0_INST, true); while (!DL_MCAN_getClockStopAck(MCAN0_INST) && !can_wakeup_event) ; if (DL_MCAN_getClockStopAck(MCAN0_INST)) DL_MCAN_disableModuleClock(MCAN0_INST); } void low_power_exit() { /* Take CAN transceiver out of standby */ DL_GPIO_clearPins(CAN_STB_PMIC_PORT, CAN_STB_PMIC_PIN); /* Take MCAN module out of power down mode if applicable */ if (!DL_MCAN_isModuleClockEnabled(MCAN0_INST)) { DL_MCAN_enableModuleClock(MCAN0_INST); DL_MCAN_addClockStopRequest(MCAN0_INST, false); while (DL_MCAN_getClockStopAck(MCAN0_INST)) ; DL_MCAN_setOpMode(MCAN0_INST, DL_MCAN_OPERATION_MODE_NORMAL); } } void MCAN0_INST_IRQHandler(void) { switch (DL_MCAN_getPendingInterrupt(MCAN0_INST)) { case DL_MCAN_IIDX_WAKEUP: can_wakeup_event = true; break; case DL_MCAN_IIDX_LINE1: gInterruptLine1Status |= DL_MCAN_getIntrStatus(MCAN0_INST); DL_MCAN_clearIntrStatus(MCAN0_INST, gInterruptLine1Status, DL_MCAN_INTR_SRC_MCAN_LINE_1); break; default: break; } }
Relevant MCU register values (while in active/normal mode):
- CANFD0_MCANSS_CTRL 0x00000038
- CANFD0_MCANSS_CLKCTL 0x00000010
- CANFD0_IMASK 0x00000022
Note that the MCU's CANCLK is provided via 40MHz crystal (HFXT).
I was interested in using the MCAN_TEST register to read the actual value of the CAN receive pin when in power-down mode and CAN packets are received, but register access is not possible when MCAN clocks are gated. Consequently, I modified the MCU firmware to not disable the MCAN clocks when entering power-down mode. Then I caused the CAN node to enter power-down/standby mode and sent it a barrage of CAN packets. I used the XDS110 debugger on the MCU to manually suspend and resume firmware execution, and observed that the RX bit in MCAN_TEST was toggling between 1 and 0. So MCAN was seeing "dominants" but was not raising a wakeup interrupt.
Any ideas? Am I missing something?
Thanks, Dave L.