Hi there,
I got the timed wakeup function working with PTB1. But it only would wake up once from PTB1. Everything seems fine after the first wakeup, LIN and application code running no problem.
The second time going to SLEEP mode, the uC seems to go to a different state that I can't understand
The only way to get out of this state is by power cycling.
One more observation is that if the wakeup is triggered by LIN, there seems no issue waking up multiple times. Only if the wake up is triggered the timed wakeup PTB1, the issue occurs.
Here's my SLEEP mode configuration
#define Wakeup_counter (unsigned int) 10*1000 // counter value in terms of ALFCLK (1ms by default)
char Wakeup_counter_hi = (char) ((Wakeup_counter & 0xFF00U) >> 8); // get the high byte
char Wakeup_counter_lo = (char) ((Wakeup_counter & 0x00FFU) >> 0); // get the low byte
void Handle_SleepRequest()
{
....... // save parameters to EEPROM
RTIDisable();
ADCDisable();
TsenseDisable();
B_GPIO_VSENSE = 0;
l_sys_irq_disable(BSC2_Node1); // only SCI!!!
B_TIE_C3I = 0; // LIN timer interrupt disabled
IrqDisable();
B_GPIO_IN1_TCAP1 = 0; // PTB1 input buffer disconnected from Timer channel 1 - input capture
B_GPIO_OUT1_TCOMP1 = 1; // Timer channel 1 - output compare connected to PTB1 output buffer OR gate (needs to be configured to allow OC to generate a system wakeup)
B_GPIO_CTL |= B_GPIO_CTL_DIR1_MASK | B_GPIO_CTL_DIR1M_MASK; // set PTB1 to output
B_GPIO_CTL |= 0|B_GPIO_CTL_PE1M_MASK; // PTB1 I/O to high impedance mode so that it's not connected to outside of MCU
// force internal PTB1 to low
B_TSCR1_TEN = 1;
B_TCTL1 = B_TCTL1_OM1_MASK; // clear on OC
B_CFORC_FOC1 = 1; // force OC to clear because TCTL1 set to clear on OC
B_TSCR1_TEN = 0; // disable the timer to setup timer
B_TCNT = 0x0000U; // reset counter
B_TIOS_IOS1 = 1; // Timer channel 1 acts as an output compare to allow TC1 write
/*Timer clock selection to be Timerclk/1 see table 647*/
B_TSCR2_PR0 = 0;
B_TSCR2_PR1 = 0;
B_TSCR2_PR2 = 0;
B_TSCR2_TCRE = 0; //Inhibits timer counter reset and couter continuews to run
// setup a rising edge on hitting the OC
B_TCTL1 = B_TCTL1_OM1_MASK | B_TCTL1_OL1_MASK; // configure to be set on OC
B_TC1Hi = Wakeup_counter_hi; // compare register needs to write the high byte before low byte
B_TC1Lo = Wakeup_counter_lo;
B_TFLG1_C1F = 1; // enable Timer channel 1 to cause a hardware interrupt
ADCLpEnable();
B_PCR_WUEH_WUPTB1 = 1; // enable PTB1 as the internal timed wake up source
PCREnterSleepMode();
while(1) DO_NOTHING; // should not reach here
}My wakeup handling function
void Wakeup_Process(void){
if (B_PCR_CTL_OPM & 2)
{ // Check if Wake Up from Sleep mode (see page RM3.0 110 Intermediate Mode)
B_PCR_CTL = OPM_SET_NORMAL; // set normal mode
while (!(B_PCR_SRH_WLPMF )) DO_NOTHING; // Wait for Clock Domain Change
}
else{
if(!B_PCR_SR_HWRF) {
PCRReset();
}
}
}main function
void main ()
{
SYS_Init();
CPMUInit(&ClockConf);
D2DInit((TYPE_D2DCLKDIV) ClockConf.D2dDiv);
XirqEnable(); // enable XIRQ -> isrD2DErr() "write-once"
Wakeup_Process(); // Process wakeup event to bring CPU to normal if it is waken up
B_WD_CTL = WD_OFF;
PCRInit(ClockConf.PCRprescaler);
SYSStartupTrimming();
ADCInit();
GPIOInit();
RTIInit();
RTIEnable();
IrqEnable();
EEPROM_Init(0x05);// 6.25MHz busclk
ReadEEPROM();
for EVER {
...... // main application loop
if (SleepRequested){Handle_SleepRequest();}
}
}Appreciate your help.
They are already cleared in PCREnterSleepMode() function.
void PCREnterSleepMode_SMP(void){
IrqDisable();
B_INT_MSK = 0xFF3F; // Mask Analog Interrupts
B_ACQ_SRH = 0xFF; // Clear pending Flags
B_INT_MSK = 0xFF00; // Enable Analog Int
B_PCR_SR = 0xFFFF; // Clear Flags
B_TFLG1 = 0xFF; // Clear timer interrupt flag1
B_PCR_CTL = OPM_SET_SLEEP; // Goto Sleep Mode
StopEnable();
StopEnter();
}But I think I found out the problem. I have a decondition function executed everytime the wakeup happens, that reverses the PTB1 configuration as the opposite of configuring PTB1 for wake-up source, like resetting counter OC, reversing GPIO configuration, etc. But the problem seems to be the resets don't register unless I put a while loop to check if the registers are updated. For example, if I don't put the while loop, the TC1 counter still holds the period I set up before going to sleep even though I am setting TC1 to 0x0000 in the deconditioning function.
Now that I added a while loop check to make sure the registers are reset, the wake-up functions normally and succeeds every time.
void PTB1_WU_Decondition(allow_Continue){
/* Configure port before enable it*/
B_GPIO_IN1_TCAP1 = 0; // PTB1 input buffer disconnected from Timer channel 1 - input capture
// B_GPIO_IN1_TCAP1 = 1; // PTB1 input buffer disconnected from Timer channel 1 - input capture
B_GPIO_OUT1_TCOMP1 = 0; // Timer channel 1 - output compare connected to PTB1 output buffer OR gate (needs to be configured to allow OC to generate a system wakeup)
B_GPIO_CTL |= 0 | B_GPIO_CTL_DIR1M_MASK; // set PTB1 to output
// B_GPIO_CTL |= 0 | B_GPIO_CTL_DIR1M_MASK; // set PTB1 to input
// B_GPIO_CTL |= B_GPIO_CTL_PE1_MASK|B_GPIO_CTL_PE1M_MASK; // PTB1 I/O enable mask enabled PTB1 enabled (not seem necessary due to figure 33.)
B_GPIO_CTL |= 0|B_GPIO_CTL_PE1M_MASK; // PTB1 I/O to high impedance mode so that it's not connected to outside of MCU
B_TIOS_IOS1 = 0; // Timer channel 1 disabled
/* Timer clock selection to be Timerclk/1 see table 647*/
B_TSCR2_PR0 = 0;
B_TSCR2_PR1 = 0;
B_TSCR2_PR2 = 0;
B_TSCR2_TCRE = 0; //Inhibits timer counter reset and couter continuews to run
// setup a rising edge on hitting the OC
B_TSCR1_TEN = 1; // enable the timer to reset TC1
B_TC1Hi = 0x00U; // compare register needs to write the high byte before low byte
B_TC1Lo = 0x00U;
B_TSCR1_TEN = 0; // disable the timer
B_TFLG1_C1F = 1; // clear timer 1 flag
while(B_TFLG1_C1F != 0 && B_TC1 != 0x0000U || allow_Continue){}; // MUST WAIT otherwise, the settings don't register
B_PCR_WUEH_WUPTB1 = 0; // disable PTB1 as the internal timed wake up source
}Hi @WWsmp,
The read-after-write sequence is a good practice.
Maybe you can rearrange the function, will it pass without the wait loop?
B_GPIO_OUT1_TCOMP1 = 0;// Detach OC from PTB1
B_GPIO_IN1_TCAP1= 0;// No capture routing
B_GPIO_CTL|= B_GPIO_CTL_DIR1M_MASK;// Internal buffer direction benign
B_GPIO_CTL|= B_GPIO_CTL_PE1M_MASK;// High impedance to outside
B_TSCR1_TEN= 0;// Stop counter
B_TIOS_IOS1= 1;// Channel 1 acts as Output Compare
B_TCTL1&= ~(B_TCTL1_OM1_MASK | B_TCTL1_OL1_MASK);// No OC action
B_TSCR2_PR0 = 0;
B_TSCR2_PR1 = 0;
B_TSCR2_PR2 = 0;
B_TFLG1_C1F= 1;// write-1-to-clear
B_TCNT= 0x0000U;// ensure counter starts from 0
B_TC1Hi= 0x00U;// high byte first
B_TC1Lo= 0x00U;
B_TSCR1_TEN= 1;
B_PCR_WUEH_WUPTB1 = 0;Hi @danielmartynek ,
I thought I fixed it but actually it is not 100% working. The issue still persists but in a different way now that I added the while loop. It looked like I was able to put the uC sleep and wake up consistently but the PCRReset() was somehow triggered but not from my application. The PCRReset() is triggered by isrD2DErr().
/*! \brief Interrupt Service Routine for D2D error interrupts.
*
* Interrupts are caused by errors detected by the D2D Initiator (uC side)
* during D2D transferes. This error is critical NMI and you need to have the
* CCR X-bit cleared
*/
interrupt VectorNumber_Vd2di_err void isrD2DErr(void) {
while(1) {
if(D2DSTAT0_ERRIF) {
D2DSTAT0_ERRIF = 1; // clear flag
}else{
PCRReset(); // issue an analog die reset
}
}
}How I realized it is that I have a variable saving the wakeup reason and reset reason. Normally, when it wakes up from PTB1, B_PCR_SRL_WUPTB1F is set to 1 and B_PCR_SRH_HVRF is set to 1. But after my "fix", I realized B_PCR_SRH_HVRF, B_PCR_SRH_WDRF and B_PCR_SRH_HWRF are all set to 1 and no WU bits are set. It is like the behavior I'd call PCRReset(). And I traced down to D2D error.
Is there a specific reason you would think of that can trigger this error?
Hi @WWsmp,
Let me trigger a discussion with the development team.
It may take some time.
Thank you,
Daniel
Hi @WWsmp,
No issue has been found in the code you posted.
Below is the possible source of isrD2Derr errors. The isrD2Derr indicates that an error was detected on the Die‑to‑Die (D2D) interface between the Analog Die and the MCU (S12Z) Die. The error can be caused by electrical, timing, power, mode‑control, or software issues.
BR, Daniel