FuSa 8-Bit Libraries Safety Framework
Loading...
Searching...
No Matches
midware_watchdog_manager_diag.c
Go to the documentation of this file.
1
22
23// Standard Library Includes
24#include <stdbool.h>
25#include <stdint.h>
26
27// Framework Includes
28#include <define_error_flags.h>
29#include <driver_cpuctrl.h>
30#include <driver_errctrl.h>
31#include <driver_swdt.h>
32#include <driver_wdt.h>
35
36// Device-specific Includes
37#include <xc.h>
38
44#define UINT24_MAX 0x00FFFFFFUL
45
46// Variables for tracking internal state, must be written to atomically to avoid any race conditions
47static volatile bool isWdtCountOngoing = false;
48static volatile uint16_t beginWdtCount = 0U;
49
50// Private Function Prototypes
51static bool BackupDisableGlobalInterrupts(void);
52static void RestoreGlobalInterrupts(bool wasInterruptsEnabled);
53static void DisableSwdtChannel(void);
54static void RestoreSwdtChannelConfigs(uint8_t swdtChBackup);
55static bool InjectSwdtExpireError(void);
56
58{
59 // Disable and backup global interrupts configuration
61
62 // Sufficient to check the least significant byte when immediately reading it again
63 const uint8_t firstCountSample = SWDT_ReadCounterLsb();
64 const uint8_t secondCountSample = SWDT_ReadCounterLsb();
65
66 // Restore global interrupts configuration
68
69 errFlag_t diagResult = NO_ERROR;
70 if (firstCountSample == secondCountSample)
71 {
72 diagResult = ERROR;
73 }
74
75 return diagResult;
76}
77
78errFlag_t MW_DiagSwdtExpire(uint32_t newReset)
79{
80 bool invalidNewReset = ((newReset > UINT24_MAX) || (newReset == 0U));
81 if (invalidNewReset)
82 {
83 /* cppcheck-suppress misra-c2012-15.5 */
84 return ERROR;
85 }
86
87 const uint32_t swdtChMask = 1UL << ERRCTRL_ESF_13_bp;
88 const bool isConfigurable = IsErrChConfigurable(swdtChMask);
89 if (!isConfigurable)
90 {
91 /* cppcheck-suppress misra-c2012-15.5 */
92 return ERROR;
93 }
94
95 // Disable and backup global interrupts configuration
96 const bool wasInterruptsEnabled = BackupDisableGlobalInterrupts();
97
98 // Prevent error injection from triggering a real error response
99 uint8_t swdtChBackup = ERRCTRL_ReadConfigSwdt();
100 DisableSwdtChannel();
101
102 // Set the count value to be loaded after expiring
103 SWDT_WriteResetValue(newReset);
104
105 // Enable the SWDT if not already enabled
106 SWDT_SetControlA((uint8_t)SWDT_ENABLE_bm);
107
108 bool isDiagPassed = InjectSwdtExpireError();
109
110 RestoreSwdtChannelConfigs(swdtChBackup); // Restore Error Channel to previous state
111
112 // Restore global interrupts configuration
113 RestoreGlobalInterrupts(wasInterruptsEnabled);
114
115 errFlag_t diagResult = ERROR;
116 if (isDiagPassed)
117 {
118 diagResult = NO_ERROR;
119 }
120
121 return diagResult;
122}
123
125{
126 // Disable and backup global interrupts configuration
128
129 beginWdtCount = WDT_ReadCounter();
130 isWdtCountOngoing = true;
131
132 // Restore global interrupts configuration
134}
135
137{
138 return isWdtCountOngoing;
139}
140
142{
143 if (isWdtCountOngoing == false)
144 {
145 /* cppcheck-suppress misra-c2012-15.5 */
146 return ERROR;
147 }
148
149 // Disable and backup global interrupts configuration
151
152 const uint16_t endWdtCount = WDT_ReadCounter();
153 isWdtCountOngoing = false;
154
155 // Restore global interrupts configuration
157
158 errFlag_t diagResult = NO_ERROR;
159 if (beginWdtCount == endWdtCount)
160 {
161 diagResult = ERROR;
162 }
163
164 return diagResult;
165}
166
168{
169 // Set up Watchdog clock to shortest possible duration with window mode disabled
170 const uint8_t diagWindowConfig = (uint8_t)WDT_WINDOW_OFF_gc;
171 const uint8_t diagPeriodConfig = (uint8_t)WDT_PERIOD_8CLK_gc;
172 WDT_WriteControlA(diagWindowConfig | diagPeriodConfig);
173
174 bool waitForReset = true;
175 while (waitForReset)
176 {
177 // WDT will continue to count if it failed to reset the device after expiring
178 const uint16_t currentCount = WDT_ReadCounter();
179 const uint16_t expireCount = 8U;
180 if (currentCount > expireCount)
181 {
182 waitForReset = false;
183 }
184 }
185
186 return ERROR;
187}
188
189// Backs up and disables global interrupts
190static bool BackupDisableGlobalInterrupts(void)
191{
192 const uint8_t gieMask = (uint8_t)CPU_I_bm; // Global Interrupt Enable status bit
193 const uint8_t cpuStatusRegVal = CPUCTRL_ReadStatusRegister();
194 const bool wasInterruptsEnabled = ((cpuStatusRegVal & gieMask) == gieMask);
195
197
198 return wasInterruptsEnabled;
199}
200
201// Restores the Global Interrupt configuration
202static void RestoreGlobalInterrupts(bool wasInterruptsEnabled)
203{
204 if (wasInterruptsEnabled)
205 {
206 CPUCTRL_SetStatusRegister((uint8_t)CPU_I_bm);
207 }
208}
209
210// Sets the SWDT Error Channel to NOTIFICATION severity and disables I/O float
211static void DisableSwdtChannel(void)
212{
213 const uint8_t stateMask = (uint8_t)ERRCTRL_STATE_gm;
214 const uint8_t floatConfig = (uint8_t)(0U << ERRCTRL_FLOAT_bp);
215 const uint8_t severityConfig = (uint8_t)(ERRCTRL_ERRLVL_NOTIFICATION_gc);
216 const uint8_t disabledChConfig = (floatConfig | severityConfig);
217
218 ERRCTRL_ModifyControlA(stateMask, (uint8_t)ERRCTRL_STATE_CONFIG_gc);
219 ERRCTRL_WriteConfigSwdt(disabledChConfig);
220 ERRCTRL_ModifyControlA(stateMask, (uint8_t)ERRCTRL_STATE_NORMAL_gc);
221}
222
223// Restores the SWDT Error Channel configs to their backed up configurations
224static void RestoreSwdtChannelConfigs(uint8_t swdtChBackup)
225{
226 const uint8_t stateMask = (uint8_t)ERRCTRL_STATE_gm;
227 ERRCTRL_ModifyControlA(stateMask, (uint8_t)ERRCTRL_STATE_CONFIG_gc);
228 ERRCTRL_WriteConfigSwdt(swdtChBackup);
229 ERRCTRL_ModifyControlA(stateMask, (uint8_t)ERRCTRL_STATE_NORMAL_gc);
230}
231
232// Fast forwards the count register to expire before reading and clearing error flag and channel
233static bool InjectSwdtExpireError(void)
234{
235 // Start error injection
236 SWDT_WriteControlB((uint8_t)SWDT_TEST_bm); // Force SWDT counter to 1
237
238 volatile uint8_t waitCount = 0U;
239 waitCount++; // Ensure sufficient clock cycles has passed after injection on higher optimization
240
241 // Expire error flag should be set two cycles after injection
242 const uint8_t expFlagMask = (uint8_t)SWDT_EXP_bm;
243 const uint8_t intFlags = SWDT_ReadIntFlags();
244 const bool isExpFlagSet = ((intFlags & expFlagMask) == expFlagMask);
245
246 // SWDT Error Controller Channel should be set when expire error flag is set
247 const uint32_t swdtChMask = (1UL << ERRCTRL_ESF_13_bp);
248 const uint32_t chStatus = ERRCTRL_ReadChannelStatus();
249 const bool isSwdtChSet = ((chStatus & swdtChMask) == swdtChMask);
250
251 SWDT_WriteIntFlags((uint8_t)SWDT_ERROR_bm); // Clear expire error flag
252
253 ERRCTRL_WriteChannelStatus(swdtChMask); // Clear SWDT Error Channel after clearing source
254
255 bool isDiagPassed = (isExpFlagSet && isSwdtChSet);
256
257 return isDiagPassed;
258}
Defines error flag type for indicating detected errors in Middleware services.
errFlag_t
Defines the error flag used by Middleware services to indicate error detection.
@ NO_ERROR
uint8_t CPUCTRL_ReadStatusRegister(void)
Reads the SREG register value.
void CPUCTRL_ClearStatusRegister(uint8_t bitmask)
Clears specific bits in the SREG register.
void CPUCTRL_SetStatusRegister(uint8_t bitmask)
Sets specific bits in the SREG register.
uint8_t ERRCTRL_ReadConfigSwdt(void)
Reads the ESCSWDT register value.
uint32_t ERRCTRL_ReadChannelStatus(void)
Reads the ESF register value.
void ERRCTRL_WriteConfigSwdt(uint8_t value)
Overwrites the ESCSWDT register value.
void ERRCTRL_WriteChannelStatus(uint32_t value)
Overwrites the ESF register value.
void ERRCTRL_ModifyControlA(uint8_t groupMask, uint8_t groupConfig)
Modifies specific bit field(s) in the CTRLA register.
void AtomicSectionStart(void)
Backup and disable global interrupts.
void AtomicSectionEnd(void)
Restore global interrupts if previously enabled.
bool IsErrChConfigurable(uint32_t channelMask)
Check Error Controller state and error channels indicated by the channel mask input.
uint8_t SWDT_ReadIntFlags(void)
Reads the INTFLAGS register value.
Definition driver_swdt.c:52
void SWDT_WriteIntFlags(uint8_t value)
Overwrites the INTFLAGS register value.
Definition driver_swdt.c:57
void SWDT_WriteResetValue(uint32_t value)
Overwrites the RESET register value.
Definition driver_swdt.c:67
void SWDT_SetControlA(uint8_t bitmask)
Sets specific bits in the CTRLA register.
Definition driver_swdt.c:35
void SWDT_WriteControlB(uint8_t value)
Overwrites the CTRLB register value.
Definition driver_swdt.c:42
uint8_t SWDT_ReadCounterLsb(void)
Reads the CNT0 register value.
Definition driver_swdt.c:62
errFlag_t MW_DiagWdtExpire(void)
Performs error injection diagnostic to detect faults in the Watchdog Timer (WDT) Expire mechanism.
errFlag_t MW_DiagSwdtExpire(uint32_t newReset)
Performs error injection diagnostic to detect faults in the Synchronous Watchdog Timer (SWDT) Expire ...
#define UINT24_MAX
Defines max value for 24-bit registers.
void MW_DiagWdtCountBegin(void)
Begins diagnostic to detect faults in the Watchdog Timer (WDT) Counter mechanism.
errFlag_t MW_DiagSwdtCount(void)
Performs diagnostic to detect faults in the Synchronous Watchdog Timer (SWDT) Counter mechanism.
bool MW_IsDiagWdtCountOngoing(void)
Checks whether the Watchdog Timer (WDT) Count diagnostic is ongoing.
errFlag_t MW_DiagWdtCountEnd(void)
Completes diagnostic to detect faults in the Watchdog Timer (WDT) Counter mechanism.
uint16_t WDT_ReadCounter(void)
Reads the CNT register value.
Definition driver_wdt.c:43
void WDT_WriteControlA(uint8_t value)
Overwrites the CTRLA register value.
Definition driver_wdt.c:33
Contains API prototypes for the Watchdog Manager diagnostics.