Hello,
I want to use the WWDT at the controller MSPM0L1105.
For testing the setup, I configured the watchdog for a period of 1 second and to call the NMI instead of the BOOT reset. Within the NMI a counter is increased.
In the main loop, there is timeout checked for every 0.75 second. When the timeout occurs, it is restarted and the "DL_WWDT_restart(WWDT0_INST);" is called. Additionally the counter from the NMI is transmitted over UART.
- First, the watchdog without windowed mode (closed window = 0%) works fine and the NMI counter is not increasing.
- Second, the watchdog with windowed mode (closed window = 50%) does not work as expected. The NMI counter increases. It seems, there is no periodic scheme, when the counter increases. There are phases, when the counter is constant and there are a point, where the counter is increased by value 1, 2 or 3.
Question:
- Is there a synchronization problem?
- How can I synchronize?
- Are there other issues known?
Code snippets:
void NMI_Handler(void) { DL_SYSCTL_NMI_IIDX eIdx = DL_SYSCTL_getPendingNonMaskableInterrupt(); switch(eIdx) { case DL_SYSCTL_NMI_IIDX_WWDT0_FAULT: m_u32Test_NVM++; m_u32Test_TimeNVM = SysTimer_Getms(); break; default: // ignore it break; } }
For the configuration, I use the syscfg within the Code Composer Studio Version: 12.4.0.00007:
/* * Copyright (c) 2021, Texas Instruments Incorporated * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * ============ ti_msp_dl_config.c ============= * Configured MSPM0 DriverLib module definitions * * DO NOT EDIT - This file is generated for the MSPM0L110X * by the SysConfig tool. */ #include "ti_msp_dl_config.h" /* * ======== SYSCFG_DL_init ======== * Perform any initialization needed before using any board APIs */ SYSCONFIG_WEAK void SYSCFG_DL_init(void) { SYSCFG_DL_initPower(); SYSCFG_DL_GPIO_init(); /* Module-Specific Initializations*/ SYSCFG_DL_SYSCTL_init(); SYSCFG_DL_PWM_H_Bridge_init(); SYSCFG_DL_PWM_MEAS_init(); SYSCFG_DL_TIMER_SysTime_init(); SYSCFG_DL_UART_0_Debug_init(); SYSCFG_DL_ADC12_0_init(); SYSCFG_DL_VREF_init(); SYSCFG_DL_WWDT0_init(); } SYSCONFIG_WEAK void SYSCFG_DL_initPower(void) { DL_GPIO_reset(GPIOA); DL_TimerG_reset(PWM_H_Bridge_INST); DL_TimerG_reset(PWM_MEAS_INST); DL_TimerG_reset(TIMER_SysTime_INST); DL_UART_Main_reset(UART_0_Debug_INST); DL_ADC12_reset(ADC12_0_INST); DL_VREF_reset(VREF); DL_WWDT_reset(WWDT0_INST); DL_GPIO_enablePower(GPIOA); DL_TimerG_enablePower(PWM_H_Bridge_INST); DL_TimerG_enablePower(PWM_MEAS_INST); DL_TimerG_enablePower(TIMER_SysTime_INST); DL_UART_Main_enablePower(UART_0_Debug_INST); DL_ADC12_enablePower(ADC12_0_INST); DL_VREF_enablePower(VREF); DL_WWDT_enablePower(WWDT0_INST); delay_cycles(POWER_STARTUP_DELAY); } SYSCONFIG_WEAK void SYSCFG_DL_GPIO_init(void) { DL_GPIO_initPeripheralAnalogFunction(GPIO_ROSC_IOMUX); DL_GPIO_initPeripheralOutputFunction(GPIO_PWM_H_Bridge_C1_IOMUX,GPIO_PWM_H_Bridge_C1_IOMUX_FUNC); DL_GPIO_enableOutput(GPIO_PWM_H_Bridge_C1_PORT, GPIO_PWM_H_Bridge_C1_PIN); DL_GPIO_initPeripheralInputFunction(GPIO_PWM_MEAS_C0_IOMUX,GPIO_PWM_MEAS_C0_IOMUX_FUNC); DL_GPIO_initPeripheralOutputFunction( GPIO_UART_0_Debug_IOMUX_TX, GPIO_UART_0_Debug_IOMUX_TX_FUNC); DL_GPIO_initDigitalOutput(GPIO_GRP_0_PIN_WAKE_UC_IOMUX); DL_GPIO_initDigitalInputFeatures(GPIO_GRP_0_PIN_KL15UC_IOMUX, DL_GPIO_INVERSION_ENABLE, DL_GPIO_RESISTOR_NONE, DL_GPIO_HYSTERESIS_DISABLE, DL_GPIO_WAKEUP_DISABLE); DL_GPIO_setPins(GPIO_GRP_0_PORT, GPIO_GRP_0_PIN_WAKE_UC_PIN); DL_GPIO_enableOutput(GPIO_GRP_0_PORT, GPIO_GRP_0_PIN_WAKE_UC_PIN); } SYSCONFIG_WEAK void SYSCFG_DL_SYSCTL_init(void) { DL_SYSCTL_setSYSOSCFreq(DL_SYSCTL_SYSOSC_FREQ_BASE); DL_SYSCTL_enableSYSOSCFCL(); DL_SYSCTL_setMCLKDivider(DL_SYSCTL_MCLK_DIVIDER_DISABLE); //Low Power Mode is configured to be SLEEP0 DL_SYSCTL_setBORThreshold(DL_SYSCTL_BOR_THRESHOLD_LEVEL_3); DL_SYSCTL_setWWDT0ErrorBehavior(DL_SYSCTL_ERROR_BEHAVIOR_NMI); } /* * Timer clock configuration to be sourced by / 1 (32000000 Hz) * timerClkFreq = (timerClkSrc / (timerClkDivRatio * (timerClkPrescale + 1))) * 32000000 Hz = 32000000 Hz / (1 * (0 + 1)) */ static const DL_TimerG_ClockConfig gPWM_H_BridgeClockConfig = { .clockSel = DL_TIMER_CLOCK_BUSCLK, .divideRatio = DL_TIMER_CLOCK_DIVIDE_1, .prescale = 0U }; static const DL_TimerG_PWMConfig gPWM_H_BridgeConfig = { .pwmMode = DL_TIMER_PWM_MODE_EDGE_ALIGN, .period = 1600, .startTimer = DL_TIMER_STOP, }; SYSCONFIG_WEAK void SYSCFG_DL_PWM_H_Bridge_init(void) { DL_TimerG_setClockConfig( PWM_H_Bridge_INST, (DL_TimerG_ClockConfig *) &gPWM_H_BridgeClockConfig); DL_TimerG_initPWMMode( PWM_H_Bridge_INST, (DL_TimerG_PWMConfig *) &gPWM_H_BridgeConfig); DL_TimerG_setCaptureCompareValue(PWM_H_Bridge_INST, 1600, DL_TIMER_CC_1_INDEX); DL_TimerG_setCaptureCompareOutCtl(PWM_H_Bridge_INST, DL_TIMER_CC_OCTL_INIT_VAL_LOW, DL_TIMER_CC_OCTL_INV_OUT_ENABLED, DL_TIMER_CC_OCTL_SRC_FUNCVAL, DL_TIMERG_CAPTURE_COMPARE_1_INDEX); DL_TimerG_setCaptCompUpdateMethod(PWM_H_Bridge_INST, DL_TIMER_CC_UPDATE_METHOD_ZERO_EVT, DL_TIMERG_CAPTURE_COMPARE_1_INDEX); DL_TimerG_enableClock(PWM_H_Bridge_INST); DL_TimerG_setCCPDirection(PWM_H_Bridge_INST , DL_TIMER_CC1_OUTPUT ); } /* * Timer clock configuration to be sourced by BUSCLK / (4000000 Hz) * timerClkFreq = (timerClkSrc / (timerClkDivRatio * (timerClkPrescale + 1))) * 4000000 Hz = 4000000 Hz / (8 * (0 + 1)) */ static const DL_TimerG_ClockConfig gPWM_MEASClockConfig = { .clockSel = DL_TIMER_CLOCK_BUSCLK, .divideRatio = DL_TIMER_CLOCK_DIVIDE_8, .prescale = 0U }; /* * Timer load value (where the counter starts from) is calculated as (timerPeriod * timerClockFreq) - 1 * PWM_MEAS_INST_LOAD_VALUE = (10 ms * 4000000 Hz) - 1 */ static const DL_TimerG_CaptureCombinedConfig gPWM_MEASCaptureConfig = { .captureMode = DL_TIMER_CAPTURE_COMBINED_MODE_PULSE_WIDTH_AND_PERIOD, .period = PWM_MEAS_INST_LOAD_VALUE, .startTimer = DL_TIMER_STOP, .inputChan = DL_TIMER_INPUT_CHAN_0, .inputInvMode = DL_TIMER_CC_INPUT_INV_INVERT, }; SYSCONFIG_WEAK void SYSCFG_DL_PWM_MEAS_init(void) { DL_TimerG_setClockConfig(PWM_MEAS_INST, (DL_TimerG_ClockConfig *) &gPWM_MEASClockConfig); DL_TimerG_initCaptureCombinedMode(PWM_MEAS_INST, (DL_TimerG_CaptureCombinedConfig *) &gPWM_MEASCaptureConfig); DL_TimerG_enableInterrupt(PWM_MEAS_INST , DL_TIMERG_INTERRUPT_CC0_DN_EVENT | DL_TIMERG_INTERRUPT_CC1_DN_EVENT | DL_TIMERG_INTERRUPT_ZERO_EVENT); DL_TimerG_enableClock(PWM_MEAS_INST); } /* * Timer clock configuration to be sourced by BUSCLK / (4000000 Hz) * timerClkFreq = (timerClkSrc / (timerClkDivRatio * (timerClkPrescale + 1))) * 20000 Hz = 4000000 Hz / (8 * (199 + 1)) */ static const DL_TimerG_ClockConfig gTIMER_SysTimeClockConfig = { .clockSel = DL_TIMER_CLOCK_BUSCLK, .divideRatio = DL_TIMER_CLOCK_DIVIDE_8, .prescale = 199U, }; /* * Timer load value (where the counter starts from) is calculated as (timerPeriod * timerClockFreq) - 1 * TIMER_SysTime_INST_LOAD_VALUE = (1000 ms * 20000 Hz) - 1 */ static const DL_TimerG_TimerConfig gTIMER_SysTimeTimerConfig = { .period = TIMER_SysTime_INST_LOAD_VALUE, .timerMode = DL_TIMER_TIMER_MODE_PERIODIC_UP, .startTimer = DL_TIMER_STOP, }; SYSCONFIG_WEAK void SYSCFG_DL_TIMER_SysTime_init(void) { DL_TimerG_setClockConfig(TIMER_SysTime_INST, (DL_TimerG_ClockConfig *) &gTIMER_SysTimeClockConfig); DL_TimerG_initTimerMode(TIMER_SysTime_INST, (DL_TimerG_TimerConfig *) &gTIMER_SysTimeTimerConfig); DL_TimerG_enableInterrupt(TIMER_SysTime_INST , DL_TIMERG_INTERRUPT_ZERO_EVENT); DL_TimerG_enableClock(TIMER_SysTime_INST); } static const DL_UART_Main_ClockConfig gUART_0_DebugClockConfig = { .clockSel = DL_UART_MAIN_CLOCK_BUSCLK, .divideRatio = DL_UART_MAIN_CLOCK_DIVIDE_RATIO_1 }; static const DL_UART_Main_Config gUART_0_DebugConfig = { .mode = DL_UART_MAIN_MODE_NORMAL, .direction = DL_UART_MAIN_DIRECTION_TX, .flowControl = DL_UART_MAIN_FLOW_CONTROL_NONE, .parity = DL_UART_MAIN_PARITY_NONE, .wordLength = DL_UART_MAIN_WORD_LENGTH_8_BITS, .stopBits = DL_UART_MAIN_STOP_BITS_ONE }; SYSCONFIG_WEAK void SYSCFG_DL_UART_0_Debug_init(void) { DL_UART_Main_setClockConfig(UART_0_Debug_INST, (DL_UART_Main_ClockConfig *) &gUART_0_DebugClockConfig); DL_UART_Main_init(UART_0_Debug_INST, (DL_UART_Main_Config *) &gUART_0_DebugConfig); /* * Configure baud rate by setting oversampling and baud rate divisors. * Target baud rate: 115200 * Actual baud rate: 115211.52 */ DL_UART_Main_setOversampling(UART_0_Debug_INST, DL_UART_OVERSAMPLING_RATE_16X); DL_UART_Main_setBaudRateDivisor(UART_0_Debug_INST, UART_0_Debug_IBRD_32_MHZ_115200_BAUD, UART_0_Debug_FBRD_32_MHZ_115200_BAUD); /* Configure Interrupts */ DL_UART_Main_enableInterrupt(UART_0_Debug_INST, DL_UART_MAIN_INTERRUPT_TX); DL_UART_Main_enable(UART_0_Debug_INST); } /* ADC12_0 Initialization */ static const DL_ADC12_ClockConfig gADC12_0ClockConfig = { .clockSel = DL_ADC12_CLOCK_SYSOSC, .divideRatio = DL_ADC12_CLOCK_DIVIDE_32, .freqRange = DL_ADC12_CLOCK_FREQ_RANGE_24_TO_32, }; SYSCONFIG_WEAK void SYSCFG_DL_ADC12_0_init(void) { DL_ADC12_setClockConfig(ADC12_0_INST, (DL_ADC12_ClockConfig *) &gADC12_0ClockConfig); DL_ADC12_initSeqSample(ADC12_0_INST, DL_ADC12_REPEAT_MODE_DISABLED, DL_ADC12_SAMPLING_SOURCE_AUTO, DL_ADC12_TRIG_SRC_SOFTWARE, DL_ADC12_SEQ_START_ADDR_00, DL_ADC12_SEQ_END_ADDR_02, DL_ADC12_SAMP_CONV_RES_12_BIT, DL_ADC12_SAMP_CONV_DATA_FORMAT_UNSIGNED); DL_ADC12_configConversionMem(ADC12_0_INST, ADC12_0_ADCMEM_Temperature, DL_ADC12_INPUT_CHAN_11, DL_ADC12_REFERENCE_VOLTAGE_INTREF, DL_ADC12_SAMPLE_TIMER_SOURCE_SCOMP0, DL_ADC12_AVERAGING_MODE_DISABLED, DL_ADC12_BURN_OUT_SOURCE_DISABLED, DL_ADC12_TRIGGER_MODE_AUTO_NEXT, DL_ADC12_WINDOWS_COMP_MODE_DISABLED); DL_ADC12_configConversionMem(ADC12_0_INST, ADC12_0_ADCMEM_CURRENTMEAS, DL_ADC12_INPUT_CHAN_1, DL_ADC12_REFERENCE_VOLTAGE_INTREF, DL_ADC12_SAMPLE_TIMER_SOURCE_SCOMP0, DL_ADC12_AVERAGING_MODE_DISABLED, DL_ADC12_BURN_OUT_SOURCE_DISABLED, DL_ADC12_TRIGGER_MODE_AUTO_NEXT, DL_ADC12_WINDOWS_COMP_MODE_DISABLED); DL_ADC12_configConversionMem(ADC12_0_INST, ADC12_0_ADCMEM_KL30MEAS, DL_ADC12_INPUT_CHAN_3, DL_ADC12_REFERENCE_VOLTAGE_INTREF, DL_ADC12_SAMPLE_TIMER_SOURCE_SCOMP0, DL_ADC12_AVERAGING_MODE_DISABLED, DL_ADC12_BURN_OUT_SOURCE_DISABLED, DL_ADC12_TRIGGER_MODE_AUTO_NEXT, DL_ADC12_WINDOWS_COMP_MODE_DISABLED); DL_ADC12_setPowerDownMode(ADC12_0_INST,DL_ADC12_POWER_DOWN_MODE_MANUAL); DL_ADC12_setSampleTime0(ADC12_0_INST,300); DL_ADC12_setSampleTime1(ADC12_0_INST,10000); DL_ADC12_enableConversions(ADC12_0_INST); } static const DL_VREF_ClockConfig gVREFClockConfig = { .clockSel = DL_VREF_CLOCK_LFCLK, .divideRatio = DL_VREF_CLOCK_DIVIDE_1, }; static const DL_VREF_Config gVREFConfig = { .vrefEnable = DL_VREF_ENABLE_ENABLE, .bufConfig = DL_VREF_BUFCONFIG_OUTPUT_2_5V, .shModeEnable = DL_VREF_SHMODE_DISABLE, .holdCycleCount = DL_VREF_HOLD_MIN, .shCycleCount = DL_VREF_SH_MIN, }; SYSCONFIG_WEAK void SYSCFG_DL_VREF_init(void) { DL_VREF_setClockConfig(VREF, (DL_VREF_ClockConfig *) &gVREFClockConfig); DL_VREF_configReference(VREF, (DL_VREF_Config *) &gVREFConfig); delay_cycles(VREF_READY_DELAY); } SYSCONFIG_WEAK void SYSCFG_DL_WWDT0_init(void) { /* * Initialize WWDT0 in Watchdog mode with following settings * Watchdog Source Clock = (LFCLK Freq) / (WWDT Clock Divider) * = 32768Hz / 8 = 4.10 kHz * Watchdog Period = (WWDT Clock Divider) ∗ (WWDT Period Count) / 32768Hz * = 8 * 2^12 / 32768Hz = 1.00 s * Window0 Closed Period = (WWDT Period) * (Window0 Closed Percent) * = 1.00 s * 50% = 500.00 ms * Window1 Closed Period = (WWDT Period) * (Window1 Closed Percent) * = 1.00 s * 0% = 0.00 s */ DL_WWDT_initWatchdogMode(WWDT0_INST, DL_WWDT_CLOCK_DIVIDE_8, DL_WWDT_TIMER_PERIOD_12_BITS, DL_WWDT_STOP_IN_SLEEP, DL_WWDT_WINDOW_PERIOD_50, DL_WWDT_WINDOW_PERIOD_0); /* Set Window0 as active window */ DL_WWDT_setActiveWindow(WWDT0_INST, DL_WWDT_WINDOW0); }