I am working with CAN transmission on MM9Z1_638 with demo board RD9Z1_638_4Li Rev 1.2, We establish CAN communication between MM9Z1_638 and MICROCHIP CAN analyzer with demo code (RD9Z1_638_12VLA_CAN_demo). My aim is to work low power modes with CAN protocol, in this process i am setting MSCAN is in Sleep Mode and MCU in stop mode and according to the datasheet to wake the MCU from stop mode using PTB4 ( For Wake-up i am setting of the NWUE bit in the GPIO_IN4 register and with the Wake-up Enable Bit (WUPTB4) and the port configuration bit (PTWU) set) But i am unable wakeup the MCU with PTB4 interrupt.
Please help me to sort of this problem and I am attaching my code here
// --------------------------------------------------------------------
#include "drv638.h" // driver for MM9Z1-638
#include "nvm.h" // nvm driver
#include <stdio.h> // sprintf
#include "main.h"
#include "soc.h"
#include "rd9z1_638_12vc.h"
#include "ntc.h"
#include "service.h"
#include "usercan.h"
#include "msCANdrv.h"
// For CAN bit Timing see AN1798.pdf
extern u8 wak_int;
// --------------------------------------------------------------------
// This demo software is provided "AS-IS".
// For documentation please see the folder \docu\documentation.html
// --------------------------------------------------------------------
//---------------------------------------------------------------------
/*! \brief Structure for Clock configuration for CAN demo
- use external oscillator (16.000MHz) as reference clock (divide by 16)
- target VCO clock: 50.000MHz
- target core clock: 50.000MHz
- target bus clock : 25.000MHz
- target D2D clock : 25.000MHz
*/
TYPE_CPMU_CONF const ClockConf = {
ClockSrc_EXT,
VCO_RANGE,
SYNR(CLOCK_VCO, CLOCK_REF),
REFCLK_FREQ_1_2_MHZ_RANGE, // Ref is IRC = 1.000MHz
// REFDIV(4), // Refdivider div = 4 (4MHz quarz)
REFDIV(16), // Refdivider div = 16 (16MHz quarz)
POSTDIV(CLOCK_VCO, CLOCK_BUS),
PLL_FREQ_MOD_0_PERCENT,
PCRPRE(CLOCK_D2D), // PCR prescaler
D2DDIV(CLOCK_BUS, CLOCK_D2D)
};
// --------------------------------------------------------------------
//! \brief TSENSE list of channels to convert...
TYPE_TSENSE_LIST const tList[] = {
// ch , avg
CH_TSENSE_ITS , 1, 6, //!< measure internal chip temperature
TSENSE_EXT , 1, 6 //!< measure external temperature sensor (NTC)
};
const u8 tListEntries = sizeof(tList)/sizeof(TYPE_TSENSE_LIST); //!< number of entries in the list above
static u16 tValues[sizeof(tList)/sizeof(TYPE_TSENSE_LIST)]; //!< RAM buffer for the TSENSE module
// --------------------------------------------------------------------
//! \brief VSENSE list of channels to convert...
TYPE_VSENSE_LIST const vList[] = {
// ch , avg , latency
CH_VSENSE2 , 100, 12,
};
const u8 vListEntries = sizeof(vList)/sizeof(TYPE_VSENSE_LIST); //!< number of entries in the list above
static u16 vValues[sizeof(vList)/sizeof(TYPE_VSENSE_LIST)]; //!< RAM buffer for the VSENSE module
// --------------------------------------------------------------------
//! \brief CSENSE list of channels to convert...
TYPE_CSENSE_LIST const cList[] = {
// ch , avg , latency
CH_CSENSE , 100 , 0
};
const u8 cListEntries = sizeof(cList)/sizeof(TYPE_CSENSE_LIST); //!< number of entries in the list above
static s32 cValues[sizeof(cList)/sizeof(TYPE_CSENSE_LIST)]; //!< RAM buffer for the TSENSE module
/*
// --------------------------------------------------------------------
// PTA0 is connected to MC33901 STB pin
#define STANDBYMODE (1)
#define NORMALMODE (0)
#define CAN_STDBY(v) {DDRA_DDRA0 = 1; PTA_PTA0 = (v);}
*/
// --------------------------------------------------------------------
// PTA6 is connected to MC33901 STB pin
#define STANDBYMODE (1)
#define NORMALMODE (0)
#define CAN_STDBY(v) {DDRA_DDRA6 = 1; PTA_PTA6 = (v);}
// ---------------------------------------------------------------------
// private prototypes
void GPIOInit(void);
void LTCInit(void);
void asciitohexa(char* input, char* output); // Change by baji
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
void main(void) {
u16 TSensor[tListEntries];
u16 VSensor[vListEntries];
s32 CSensor[cListEntries];
TYPE_CAN_IBS_Data CAN_IBS_Data;
TYPE_CAN_IBS_Data_Ext CAN_IBS_Data_Ext;
u8 rec_data[9]={0},trans_arr[8],rec_flag;
TYPE_CAN_IBS_CONTROL CAN_IBS_Control;
MSCAN_TYPE_ERROR_CODE err_status; //To store the return value of the driver APIs.
MSCAN_TYPE_STATUS mbStat;
u8 CAN_status[3]; //CAN_status to store channel status,byte 0 store CANCTL0, byte 1 store CANCTL1, byte 2 store CANRFLG
u8 u8ModeTimer;
u32 u32Temp;
static TYPE_BATTERY Battery;
s16 s16Vdrop;
u8 u8WakeUpReason;
u8 u8ChipTemp;
u16 u16Result;
Bool WriteSystemCalibrationValues = FALSE; // do not change !!!
SYS_Init();
CPMUInit(&ClockConf);
D2DInit((TYPE_D2DCLKDIV) ClockConf.D2dDiv);
XirqEnable(); // enable XIRQ -> isrD2DErr() "write-once"
if (B_PCR_CTL_OPM & 2) { // Check if Wake Up from Sleep mode (see page RM3.0 110 Intermediate Mode)
u32Temp = B_ACQ_AHC;
B_PCR_CTL = OPM_SET_NORMAL; // set normal mode
while (!(B_PCR_SRH_WLPMF )) DO_NOTHING; // Wait for Clock Domain Change \! /todo where is this described?
}else{
if(!B_PCR_SR_HWRF) {
PCRReset(); // generate a HWR reset to ensure analog die is in defined state! E.g. debugging might cause strange effects in case bits are set from before //
}
}
B_WD_CTL = WD_OFF;
u8WakeUpReason = 0;
// evaluate wakeup reason
if(B_PCR_SR_WULINF) { // wakeup caused by LIN
u8WakeUpReason = 1;
}
if(B_PCR_SR_WUAHTHF) {
u8WakeUpReason = 2;
}
if(B_PCR_SR_WUCALF) {
u8WakeUpReason = 3;
}
if(B_PCR_SR_WUCTHF) { // current threshold
u8WakeUpReason = 4;
}
if(B_PCR_SR_WULTCF) {
u8WakeUpReason = 5;
}
B_PCR_SRH = 0xFF; // clear all flags
PCRInit(ClockConf.PCRprescaler);
SYSStartupTrimming();
//! \brief Set a breakpoint to this line and change the variable WriteSystemCalibrationValues to TRUE in the debugger to write values \ref CalibWrite
if(WriteSystemCalibrationValues) { // hook to manually write system calibration values to eeprom during sw development
CalibWriteManual();
}
if(CalibRead()==FALSE) { // reads system calibration data from EEPROM (if avaliable). needs to be before ADCInit()
CalibDefault(); // otherwise use default values
}
VsenseInit(&(vList[0]), &vListEntries, &(vValues[0]));
CsenseInit(&(cList[0]), &cListEntries, &(cValues[0]));
TsenseInit(&(tList[0]), &tListEntries, &(tValues[0]));
ADCInit();
GPIOInit();
LTCInit();
CAN_STDBY(NORMALMODE);
// IBS control frame
CAN_IBS_Control.u8Len = 2;
err_status = Init_CAN(CAN0, FAST); //Initialization msCAN channel 0, FAST means the reset won't wait until current transmit completed
do{
err_status = Check_CAN_Status(CAN0, CAN_status);
}while ((CAN_status[0] & SYNCH) == 0); //Wait for msCAN channel 0 synchronized to CAN Bus
err_status = Config_CAN_MB(CAN0, CANBUF1, TXDF, CAN_MO1); //configure the msCAN channel 0, buffer 1 to be TXDF mode (transmit dataframe) -> message object 1,see details in "MSCANID.h"
err_status = Config_CAN_MB(CAN0, CANBUF2, TXDF, CAN_MO2); //configure the msCAN channel 0, buffer 2 to be TXDF mode (transmit dataframe) -> message object 2
err_status = Config_CAN_MB(CAN0, CANBUF3, RXDF, CAN_MO3); //configure the msCAN channel 0, buffer 3 to be RXDF mode (receive dataframe) -> message object 3
Battery.tMode = BM_PARKING; // used to get an initial OCV based SoC
SoCInit();
RTIInit();
RTIEnable();
IrqEnable();
u8ModeTimer = 50; // timed mode change from parking -> driving (5*100ms)
for EVER {
switch(Battery.tMode) {
case BM_PARKING:
case BM_DRIVING:
// ----- measurements, voltage, current and temp ------
if(TsenseGetValue(CH_TSENSE_ITS, &TSensor[0])) { // request data
u8ChipTemp = (u8)(TSensor[0]/TSENSE_ITS_INVRES+K2C+40); // scale to deg C with offset 40
}
if(TsenseGetValue(TSENSE_EXT, &TSensor[1])) {
Battery.u16TempK = NTCRaw2Kelvin(NTCconvert, TSensor[1]);
}
if(CsenseGetValue(CH_CSENSE, &CSensor[0])) {
Battery.s32mAFilt = CSensor[0];
}
if(VsenseGetValue(CH_VSENSE2, &VSensor[0])) { // if 0 channel is converted then
#if (ISENSE_GND_REF==ISENSEL)
// ISENSEL is GND reference
s16Vdrop = (s16)(Battery.s32mAFilt/G_SHUNT); // calculated shunt drop voltage
Battery.u16mV = (VSensor[0]>>1) - s16Vdrop; // scale to mV and correct shunt drop voltage
#endif
#if (ISENSE_GND_REF==ISENSEH)
// ISENSEH is GND reference
Battery.u16mV = VSensor[0]>>1; // scale to mV and no correction
#endif
}
if(RTIEvery100ms()) {
SoCUpdate(&Battery);
TsenseHandler(); // temperature needs to be done polling (V,I interrupt driven)
if(u8ModeTimer>0) { // timed mode change from parking -> driving (5*100ms)
u8ModeTimer--;
}else{
Battery.tMode = BM_DRIVING;
}
CAN_IBS_Data.FrameLen = 8;
CAN_IBS_Data.BatVolt = u16Swap(Battery.u16mV); // scale to mV
CAN_IBS_Data.BatCurr = u32Swap(Battery.s32mAFilt);
CAN_IBS_Data.BatTemp = (u8)(Battery.u16TempK+K2C+40);
CAN_IBS_Data.BatMode = Battery.tMode;
err_status = Load_CAN_MB(CAN0, CANBUF1, CAN_IBS_Data.byte);
err_status = Transmit_CAN_MB(CAN0, CANBUF1);
}
if(RTIEvery1000ms()) {
CAN_IBS_Data_Ext.FrameLen = 6;
CAN_IBS_Data_Ext.ChipTemp = u8ChipTemp;
CAN_IBS_Data_Ext.SOC = Battery.u8SoC;
CAN_IBS_Data_Ext.Coulomb = u32Swap(Battery.u32CoulombCnt);
err_status = Load_CAN_MB(CAN0, CANBUF2, CAN_IBS_Data_Ext.byte);
err_status = Transmit_CAN_MB(CAN0, CANBUF2);
}
break;
case BM_CALIBRATION:
ServiceApp();
break;
default:
break;
}
// read message object .....
(void) Check_CAN_MB_Status(CAN0, CANBUF3, &mbStat);
if((mbStat.Status == NEWDATA) || (mbStat.Status == OVERRUN)) { //Wait for the Receive ISR to finish and change the buffer status, NEWDATA indicates that the buffer has receive a new data
if(wak_int == 10){
wak_int=1;
}
err_status = Read_CAN_MB_Data(CAN0, CANBUF3, CAN_IBS_Control.byte);//Copy the received data in msCAN channel 0 buffer 2 to data_rec;
CAN_IBS_Control.u16Var = u16Swap(CAN_IBS_Control.u16Var);
//Clear buffer_status[0]
//err_status = Read_CAN_MB_Data(CAN0, CANBUF3, rec_data);
err_status = Load_CAN_MB(CAN0, CANBUF1, CAN_IBS_Control.byte);
err_status = Transmit_CAN_MB(CAN0, CANBUF1);
mbStat.Status = NODATA;
if(CAN_IBS_Control.u16Var&0x8000) { // Goto Sleep Request
// goto sleep
err_status = Sleep_CAN(CAN0, CMPTX); // request CAN channel 0 go to sleep with completing transmission scheduled
do {
err_status = Check_CAN_Status(CAN0,CAN_status); // read the channel 0 status
}while (!(CAN_status[1]&SLPAK)); // wait till SLPAK bit set
B_PCR_WUEH_WUPTB4 = 1; // enable PTB4 wakeup
ADCDisable();
TsenseDisable();
B_GPIO_VSENSE = 0;
CAN_STDBY(STANDBYMODE);
PTA_PTA1 = 0;
PCREnterStopMode();
// .....zzzzzzzzzzz (stop mode)
// after wakeup the code continues to run here....
// but first the D2D Interrupt service routine will be run
B_WD_CTL = WD_OFF;
B_PCR_CTL = OPM_SET_NORMAL; /* set normal mode*/ // bb
VsenseInit(&(vList[0]), &vListEntries, &(vValues[0]));
CsenseInit(&(cList[0]), &cListEntries, &(cValues[0]));
TsenseInit(&(tList[0]), &tListEntries, &(tValues[0]));
ADCInit();
CAN_STDBY(NORMALMODE);
}
if(CAN_IBS_Control.u16Var&0x1000) { // Goto Calib mode
Battery.tMode = BM_CALIBRATION;
CAN_IBS_Data.BatMode = Battery.tMode;
err_status = Load_CAN_MB(CAN0, CANBUF1, CAN_IBS_Data.byte);
err_status = Transmit_CAN_MB(CAN0, CANBUF1);
err_status = Config_CAN_MB (CAN0, 8, RXDF, 8);
err_status = Config_CAN_MB (CAN0, 9, TXDF, 9);
}
if(CAN_IBS_Control.u16Var&0x2000) { // Goto normal mode
Battery.tMode = BM_DRIVING;
VsenseInit(&(vList[0]), &vListEntries, &(vValues[0]));
CsenseInit(&(cList[0]), &cListEntries, &(cValues[0]));
TsenseInit(&(tList[0]), &tListEntries, &(tValues[0]));
ADCInit();
}
}
} // for EVER
}
// ---------------------------------------------------------------------
/*! \brief Init GPIO
<b>Configuration used for the RD9Z1_638_12VLA_CAN_Demo:</b>
| Pin | Enabled | Direction | Routing | used for |
|:----------:|:--------:|:---------:|:-------:|------------------------------------|
| PTB0 | - | - | | analog input |
| PTB1 | disabled | n.a. | | not used |
| PTB2 | disabled | n.a. | | not used |
| PTB3 | disabled | n.a. | | not used |
| PTB4 | enabled | input | PTWU | CAN PHY wake up input |
| PTB5/GNDSW | - | - | - | GND switch for TSENSE_EXT |
*/
void GPIOInit(void) {
B_GPIO_CTL = GPIO_CTL_PTB1_DISABLE | GPIO_CTL_PTB1_INPUT;
B_GPIO_CTL = GPIO_CTL_PTB2_DISABLE | GPIO_CTL_PTB2_INPUT;
B_GPIO_CTL = GPIO_CTL_PTB3_DISABLE | GPIO_CTL_PTB3_INPUT;
B_GPIO_PUC_PDE4 = 1; // enable pull down (missing on KT9Z1638EVM)
B_GPIO_CTL = GPIO_CTL_PTB4_ENABLE; // PTB4 is used for CAN Wakeup
B_GPIO_IN4 = IN4_PTWU|IN4_NWUE; // enable WU in low power mode, negative edge
}
// ---------------------------------------------------------------------
/*! \brief
*
*/
void LTCInit(void) {
B_LTC_CTL = B_LTC_CTL_LTCEM_MASK | B_LTC_CTL_LTCE_MASK; // LTC enable, no interrupt
}
// --------------------------------------------------------------------
// --------------------------------------------------------------------
// --------------------------------------------------------------------
interrupt VectorNumber_Vcan0wkup void isrCANWakeup(void) {
CAN_Wakeup(CAN0);
}
// --------------------------------------------------------------------
interrupt VectorNumber_Vcan0err void isrCANErr(void) {
CAN_ERR(CAN0);
}
// --------------------------------------------------------------------
interrupt VectorNumber_Vcan0tx void isrCANTx(void) {
CAN_Transmit(CAN0);
}
// --------------------------------------------------------------------
interrupt VectorNumber_Vcan0rx void isrCANRx(void) {
CAN_Receive(CAN0);
}
Hi @vardhan,
This is under a discussion here:
https://community.nxp.com/t5/S12-MagniV-Microcontrollers/Low-Power-modes-in-MM9Z1638/td-p/1405922
Best regards,
Daniel