こんにちは、
PTB1 で時間指定ウェイクアップ機能を動作させることができました。しかし、PTB1 から起動するのは 1 回だけです。最初のウェイクアップ後はすべて正常に動作しているようで、LIN とアプリケーション コードは問題なく実行されています。
2回目にスリープモードに入ると、MCUは理解できない別の状態になるようです
この状態から抜け出す唯一の方法は、電源を入れ直すことです。
もう 1 つの観察結果は、ウェイクアップが LIN によってトリガーされる場合、複数回ウェイクアップしても問題はないと思われることです。ウェイクアップが時間指定ウェイクアップ PTB1 によってトリガーされた場合にのみ、問題が発生します。
これが私のスリープモードの設定です
#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
}私のウェイクアップ処理関数
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();
}
}
}メイン関数
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();}
}
}ご協力に感謝します。
これらはPCREnterSleepMode()関数ですでにクリアされています。
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();
}しかし、問題点は分かったと思います。ウェイクアップが発生するたびに実行されるデコンディショニング関数があり、カウンター OC をリセットしたり、GPIO 構成を逆にするなど、ウェイクアップ ソースの PTB1 を構成するのとは逆に PTB1 構成を逆にします。しかし、問題は、レジスタが更新されたかどうかを確認するための while ループを配置しない限り、リセットが登録されないということのようです。たとえば、while ループを配置しないと、デコンディショニング関数で TC1 を 0x0000 に設定しているにもかかわらず、TC1 カウンターはスリープ状態になる前に設定した期間を保持し続けます。
レジスタがリセットされていることを確認するための while ループ チェックを追加したので、ウェイクアップは正常に機能し、毎回成功します。
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
}こんにちは@WWsmp 、
書き込み後の読み取りシーケンスは良い方法です。
関数を再配置すれば、待機ループなしでも成功するでしょうか?
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;こんにちは@danielmartynek 、
修正したと思いましたが、実際には 100% 機能していません。問題はまだ解決していませんが、while ループを追加したため、状況が変わりました。MCU を一貫してスリープ状態にして起動することができているように見えましたが、PCRReset() は何らかの理由でトリガーされましたが、それはアプリケーションからではありませんでした。PCRReset() は 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
}
}
}私がそれをどのように実現したかというと、ウェイクアップ理由とリセット理由を保存する変数があるということです。通常、PTB1 から起動すると、B_PCR_SRL_WUPTB1F が 1 に設定され、B_PCR_SRH_HVRF が 1 に設定されます。しかし、「修正」後、B_PCR_SRH_HVRF、B_PCR_SRH_WDRF、および B_PCR_SRH_HWRF がすべて 1 に設定され、WU ビットが設定されていないことに気付きました。これは PCRReset() と呼ぶ動作に似ています。そして、D2D エラーまで追跡しました。
このエラーを引き起こす可能性がある具体的な理由はありますか?
こんにちは@WWsmp 、
開発チームとの議論を開始させてください。
少し時間がかかるかもしれません。
ありがとうございました。
ダニエル
こんにちは@WWsmp 、
投稿したコードには問題は見つかりませんでした。
以下は、isrD2Derr エラーの考えられる原因です。isrD2Derr は、アナログ ダイと MCU (S12Z) ダイ間のダイ間 (D2D) インターフェースでエラーが検出されたことを示します。エラーは、電気、タイミング、電源、モード制御、またはソフトウェアの問題によって発生する可能性があります。
BR、ダニエル