FuSa 8-Bit Libraries Safety Framework
Loading...
Searching...
No Matches
midware_clock_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 <driver_clkctrl.h>
29#include <driver_errctrl.h>
32
33// Device-specific Includes
34#include <xc.h>
35
41#define CRITICAL_CH_CONFIG ((uint8_t)ERRCTRL_FLOAT_bm | (uint8_t)ERRCTRL_ERRLVL_CRITICAL_gc)
42
48#define CFD_RESET_CONFIG 0U
49
55typedef struct
56{
57 uint16_t windowLow;
58 uint16_t windowHigh;
59 uint16_t windowRef;
60 uint8_t ctrlA;
61 uint8_t ctrlB;
62 uint8_t errChBackup;
63} cfmConfig_t;
64
70typedef struct
71{
72 bool isDiagOngoing;
73 bool wasIntEnabled;
74 uint8_t errChBackup;
75 uint8_t ctrlABackup;
76} cfdState_t;
77
78// Error Controller bitmasks used when reading the error channel register
79static const uint32_t cfd0ChMask = 1UL << ERRCTRL_ESF_9_bp;
80static const uint32_t cfd1ChMask = 1UL << ERRCTRL_ESF_10_bp;
81static const uint32_t cfm0ChMask = 1UL << ERRCTRL_ESF_11_bp;
82static const uint32_t cfm1ChMask = 1UL << ERRCTRL_ESF_12_bp;
83
84/*
85 * Variables used for tracking internal state and restoring error channel configs after diagnostics
86 * are complete. Must be written to atomically to avoid any race conditions.
87 */
88static volatile cfdState_t cfd0State = {
89 .isDiagOngoing = false,
90 .wasIntEnabled = false,
91 .errChBackup = CRITICAL_CH_CONFIG,
92 .ctrlABackup = CFD_RESET_CONFIG,
93};
94
95static volatile cfdState_t cfd1State = {
96 .isDiagOngoing = false,
97 .wasIntEnabled = false,
98 .errChBackup = CRITICAL_CH_CONFIG,
99 .ctrlABackup = CFD_RESET_CONFIG,
100};
101
102// Private function prototypes
103static void SetupCfd(bool isCfd0Diag);
104static void BackupDisableCfdInterrupts(bool isCfd0Diag);
105static void BackupDisableErrorChConfig(bool isCfd0Diag);
106static void BackupConfigureCfd(bool isCfd0Diag);
107static void DisableCfdChannel(bool isCfd0Diag);
108
109static bool IsCfdDiagPassed(uint8_t cfmMask, uint32_t cfmChMask);
110
111static void RestoreCfd(bool isCfd0Diag);
112static void RestoreCfdChannel(bool isCfd0Diag);
113static void RestoreCfdInterrupts(bool isCfd0Diag);
114
115static cfmConfig_t SetupCfm(bool isCfm0Diag);
116static cfmConfig_t BackupCfmConfig(bool isCfm0Diag);
117static cfmConfig_t BackupCfm0Config(void);
118static cfmConfig_t BackupCfm1Config(void);
119static void DisableCfmChannel(bool isCfm0Diag);
120static void ConfigureCfmRefOsc(bool isCfm0Diag);
121
122static bool IsCfmDiagPassed(bool isCfm0Diag);
123static bool IsCfm0TestPassed(uint16_t windowLow, uint16_t windowHigh, bool expectErr);
124static bool IsCfm1TestPassed(uint16_t windowLow, uint16_t windowHigh, bool expectErr);
125static bool CheckCfmTest(uint8_t cfmMask, uint8_t cfmDoneMask, uint32_t cfmChMask, bool expectErr);
126static bool IsCfmFlagSet(uint8_t cfmMask, uint8_t cfmDoneMask);
127
128static void RestoreCfmConfig(bool isCfm0Diag, cfmConfig_t config);
129static void RestoreCfm0Config(cfmConfig_t config);
130static void RestoreCfm1Config(cfmConfig_t config);
131static void RestoreCfmChannel(bool isCfm0Diag, uint8_t chConfig);
132
134{
135 // Check if there are any unhandled errors and ensure the Error Controller is in NORMAL state
136 const bool isConfigurable = IsErrChConfigurable(cfd0ChMask);
137 if (cfd0State.isDiagOngoing || !isConfigurable)
138 {
139 /* cppcheck-suppress misra-c2012-15.5 */
140 return ERROR;
141 }
142
143 AtomicSectionStart(); // Disable and backup global interrupts configuration
144
145 bool isCfd0Diag = true; // CFD0 diagnostics
146 // Backup, disable and configure hardware for diagnostic
147 SetupCfd(isCfd0Diag);
148
149 // Begin diagnostics
150 const uint8_t cfd0Mask = (uint8_t)CLKCTRL_CFD0_bm;
151 CLKCTRL_SetMainControlC(cfd0Mask);
152
153 cfd0State.isDiagOngoing = true; // Set CFD0 diag to in progress
154
155 AtomicSectionEnd(); // Restore global interrupts configuration
156
157 return NO_ERROR;
158}
159
161{
162 if (cfd0State.isDiagOngoing == false)
163 {
164 // cppcheck-suppress misra-c2012-15.5
165 return ERROR;
166 }
167
168 AtomicSectionStart(); // Disable and backup global interrupts configuration
169
170 // End diagnostics
171 const uint8_t cfd0Mask = (uint8_t)CLKCTRL_CFD0_bm;
172 const bool isDiagPassed = IsCfdDiagPassed(cfd0Mask, cfd0ChMask);
173
174 cfd0State.isDiagOngoing = false; // Set CFD0 diag to done
175
176 // Clear interrupt flags and error channels
177 CLKCTRL_WriteIntFlags(cfd0Mask);
178 ERRCTRL_WriteChannelStatus(cfd0ChMask);
179
180 bool isCfd0Diag = true; // CFD0 diagnostics
181 // Restore registers used in diagnostic
182 RestoreCfd(isCfd0Diag);
183
184 AtomicSectionEnd(); // Restore global interrupts configuration
185
186 errFlag_t diagResults = ERROR;
187 if (isDiagPassed)
188 {
189 diagResults = NO_ERROR;
190 }
191 return diagResults;
192}
193
195{
196 return cfd0State.isDiagOngoing;
197}
198
200{
201 // Check if there are any unhandled errors and ensure the Error Controller is in NORMAL state
202 const bool isConfigurable = IsErrChConfigurable(cfd1ChMask);
203 if (cfd1State.isDiagOngoing || !isConfigurable)
204 {
205 /* cppcheck-suppress misra-c2012-15.5 */
206 return ERROR;
207 }
208
209 AtomicSectionStart(); // Disable and backup global interrupts configuration
210
211 bool isCfd0Diag = false; // CFD1 diagnostics
212 // Backup, disable and configure hardware for diagnostic
213 SetupCfd(isCfd0Diag);
214
215 // Begin diagnostics
216 const uint8_t cfd1Mask = (uint8_t)CLKCTRL_CFD1_bm;
217 CLKCTRL_SetMainControlC(cfd1Mask);
218 cfd1State.isDiagOngoing = true; // Set CFD1 diag to in progress
219
220 AtomicSectionEnd(); // Restore global interrupts configuration
221
222 return NO_ERROR;
223}
224
226{
227 if (cfd1State.isDiagOngoing == false)
228 {
229 // cppcheck-suppress misra-c2012-15.5
230 return ERROR;
231 }
232
233 AtomicSectionStart(); // Disable and backup global interrupts configuration
234
235 // End diagnostics
236 const uint8_t cfd1Mask = (uint8_t)CLKCTRL_CFD1_bm;
237 const bool isDiagPassed = IsCfdDiagPassed(cfd1Mask, cfd1ChMask);
238
239 cfd1State.isDiagOngoing = false; // Set CFD1 diag to done
240
241 // Clear interrupt flags and error channels
242 CLKCTRL_WriteIntFlags(cfd1Mask);
243 ERRCTRL_WriteChannelStatus(cfd1ChMask);
244
245 // Restore registers used in diagnostic
246 bool isCfd0Diag = false; // CFD1 diagnostics
247 RestoreCfd(isCfd0Diag);
248
249 AtomicSectionEnd(); // Restore global interrupts configuration
250
251 errFlag_t diagResults = ERROR;
252 if (isDiagPassed)
253 {
254 diagResults = NO_ERROR;
255 }
256 return diagResults;
257}
258
260{
261 return cfd1State.isDiagOngoing;
262}
263
265{
266 // Check if there are any unhandled errors and ensure the Error Controller is in NORMAL state
267 const bool isConfigurable = IsErrChConfigurable(cfm0ChMask);
268 if (!isConfigurable)
269 {
270 /* cppcheck-suppress misra-c2012-15.5 */
271 return ERROR;
272 }
273
274 AtomicSectionStart(); // Disable and backup global interrupts configuration
275
276 bool isCfm0Diag = true; // CFM0 diagnostics
277 // Backup registers used in diagnostic
278 cfmConfig_t cfm0Backup = SetupCfm(isCfm0Diag);
279
280 // Run tests for measurement within, above and below window
281 const bool isDiagPassed = IsCfmDiagPassed(isCfm0Diag);
282
283 uint8_t monitorEnableMask = (uint8_t)CLKCTRL_MEN_bm;
284 CLKCTRL_ClearCfm0ControlA(monitorEnableMask); // Disable CFM0 to do config
285
286 RestoreCfmConfig(isCfm0Diag, cfm0Backup); // Restore CFM configuration
287
288 AtomicSectionEnd(); // Restore global interrupts configuration
289
290 errFlag_t diagResults = ERROR;
291 if (isDiagPassed)
292 {
293 diagResults = NO_ERROR;
294 }
295 return diagResults;
296}
297
299{
300 // Check if there are any unhandled errors and ensure the Error Controller is in NORMAL state
301 const bool isConfigurable = IsErrChConfigurable(cfm1ChMask);
302 if (!isConfigurable)
303 {
304 /* cppcheck-suppress misra-c2012-15.5 */
305 return ERROR;
306 }
307
308 AtomicSectionStart(); // Disable and backup global interrupts configuration
309
310 bool isCfm0Diag = false; // CFM1 diagnostics
311 // Backup registers used in diagnostic
312 cfmConfig_t cfm1Backup = SetupCfm(isCfm0Diag);
313
314 // Run tests for measurement within, above and below window
315 const bool isDiagPassed = IsCfmDiagPassed(isCfm0Diag);
316
317 uint8_t monitorEnableMask = (uint8_t)CLKCTRL_MEN_bm;
318 CLKCTRL_ClearCfm1ControlA(monitorEnableMask); // Disable CFM1 to do config
319
320 // Restore registers used in diagnostic
321 RestoreCfmConfig(isCfm0Diag, cfm1Backup); // Restore CFM configuration
322
323 AtomicSectionEnd(); // Restore global interrupts configuration
324
325 errFlag_t diagResults = ERROR;
326 if (isDiagPassed)
327 {
328 diagResults = NO_ERROR;
329 }
330 return diagResults;
331}
332
333// Backup, disable and configure hardware for diagnostic
334static void SetupCfd(bool isCfd0Diag)
335{
336 // Store and disable CFD interrupts between begin and end diagnostic
337 BackupDisableCfdInterrupts(isCfd0Diag);
338
339 // Store error channel config to global state variable and set to NOTIFICATION
340 BackupDisableErrorChConfig(isCfd0Diag);
341
342 // Store current CFD config and set it to diagnostic config
343 BackupConfigureCfd(isCfd0Diag);
344}
345
346// Backup and disable CFD interrupts, stays of during diag
347static void BackupDisableCfdInterrupts(bool isCfd0Diag)
348{
349 const uint8_t intControl = CLKCTRL_ReadIntControl();
350 uint8_t intMask;
351 if (isCfd0Diag)
352 {
353 intMask = (uint8_t)CLKCTRL_CFD0_bm;
354 cfd0State.wasIntEnabled = ((intControl & intMask) == intMask);
355 }
356 else
357 {
358 intMask = (uint8_t)CLKCTRL_CFD1_bm;
359 cfd1State.wasIntEnabled = ((intControl & intMask) == intMask);
360 }
362}
363
364// Backup and disable CFD error channel
365static void BackupDisableErrorChConfig(bool isCfd0Diag)
366{
367 if (isCfd0Diag)
368 {
369 cfd0State.errChBackup = ERRCTRL_ReadConfigCfd0();
370 DisableCfdChannel(isCfd0Diag); // Disables float and sets channel to NOTIFICATION
371 }
372 else
373 {
374 cfd1State.errChBackup = ERRCTRL_ReadConfigCfd1();
375 DisableCfdChannel(isCfd0Diag); // Disables float and sets channel to NOTIFICATION
376 }
377}
378
379// Backup and configure CFD for diagnostic
380static void BackupConfigureCfd(bool isCfd0Diag)
381{
382 const uint8_t cfdEnableMask = (uint8_t)CLKCTRL_CFDEN_bm;
383 const uint8_t srcOscHfConfig = (uint8_t)CLKCTRL_CFDSRC_OSCHF_gc;
384 const uint8_t refOsc32kConfig = (uint8_t)CLKCTRL_CFDREF_OSC32K_gc;
385
386 if (isCfd0Diag)
387 {
388 cfd0State.ctrlABackup = CLKCTRL_ReadCfd0ControlA();
389 CLKCTRL_WriteCfd0ControlA(srcOscHfConfig | refOsc32kConfig | cfdEnableMask);
390 }
391 else
392 {
393 cfd1State.ctrlABackup = CLKCTRL_ReadCfd1ControlA();
394 CLKCTRL_WriteCfd1ControlA(srcOscHfConfig | refOsc32kConfig | cfdEnableMask);
395 }
396}
397
398// Sets the specified CFD Error Channel to NOTIFICATION severity and disables I/O float
399static void DisableCfdChannel(bool isCfd0Diag)
400{
401 const uint8_t stateMask = (uint8_t)ERRCTRL_STATE_gm;
402 const uint8_t floatConfig = 0U << ERRCTRL_FLOAT_bp; // Disable I/O float
403 const uint8_t severityConfig = (uint8_t)(ERRCTRL_ERRLVL_NOTIFICATION_gc);
404 const uint8_t disabledChConfig = (floatConfig | severityConfig);
405
406 ERRCTRL_ModifyControlA(stateMask, (uint8_t)ERRCTRL_STATE_CONFIG_gc);
407 if (isCfd0Diag)
408 {
409 ERRCTRL_WriteConfigCfd0(disabledChConfig);
410 }
411 else
412 {
413 ERRCTRL_WriteConfigCfd1(disabledChConfig);
414 }
415
416 ERRCTRL_ModifyControlA(stateMask, (uint8_t)ERRCTRL_STATE_NORMAL_gc);
417}
418
419// Read interrupt flag and error controller to determine if diag passed
420static bool IsCfdDiagPassed(uint8_t cfmMask, uint32_t cfmChMask)
421{
422 const uint8_t intFlags = CLKCTRL_ReadIntFlags();
423 const bool isCfdFlagSet = ((intFlags & cfmMask) == cfmMask);
424
425 const uint32_t chStatus = ERRCTRL_ReadChannelStatus();
426 const bool isErrorChSet = ((chStatus & cfmChMask) == cfmChMask);
427
428 return (isCfdFlagSet && isErrorChSet);
429}
430
431// Restore CFD config from backup
432static void RestoreCfd(bool isCfd0Diag)
433{
434 // Restore CFD CTRLA register
435 if (isCfd0Diag)
436 {
437 CLKCTRL_WriteCfd0ControlA(cfd0State.ctrlABackup);
438 }
439 else
440 {
441 CLKCTRL_WriteCfd1ControlA(cfd1State.ctrlABackup);
442 }
443
444 // Restore error channel config
445 RestoreCfdChannel(isCfd0Diag);
446
447 // Restore global and CFD0 interrupts configuration
448 RestoreCfdInterrupts(isCfd0Diag);
449}
450
451// Restores the specified CFD Error Channel configs to their backed up configurations
452static void RestoreCfdChannel(bool isCfd0Diag)
453{
454 const uint8_t stateMask = (uint8_t)ERRCTRL_STATE_gm;
455 ERRCTRL_ModifyControlA(stateMask, (uint8_t)ERRCTRL_STATE_CONFIG_gc);
456 if (isCfd0Diag)
457 {
458 ERRCTRL_WriteConfigCfd0(cfd0State.errChBackup);
459 }
460 else
461 {
462 ERRCTRL_WriteConfigCfd1(cfd1State.errChBackup);
463 }
464 ERRCTRL_ModifyControlA(stateMask, (uint8_t)ERRCTRL_STATE_NORMAL_gc);
465}
466
467// Restore CFD interrupts
468static void RestoreCfdInterrupts(bool isCfd0Diag)
469{
470 if (isCfd0Diag)
471 {
472 if (cfd0State.wasIntEnabled)
473 {
474 uint8_t intMask = (uint8_t)CLKCTRL_CFD0_bm;
475 CLKCTRL_SetIntControl((uint8_t)intMask);
476 }
477 }
478 else
479 {
480 if (cfd1State.wasIntEnabled)
481 {
482 uint8_t intMask = (uint8_t)CLKCTRL_CFD1_bm;
483 CLKCTRL_SetIntControl((uint8_t)intMask);
484 }
485 }
486}
487
488// Configures the CFM and Error Controller for diagnostics
489static cfmConfig_t SetupCfm(bool isCfm0Diag)
490{
491 // Backup registers used in diagnostic
492 cfmConfig_t cfmBackup = BackupCfmConfig(isCfm0Diag);
493
494 DisableCfmChannel(isCfm0Diag); // Disables float and sets channel to NOTIFICATION
495
496 // Set reference clock to fastest internal clock and enable
497 ConfigureCfmRefOsc(isCfm0Diag);
498
499 return cfmBackup;
500}
501
502// Backs up CFM configuration before diagnostic
503static cfmConfig_t BackupCfmConfig(bool isCfm0Diag)
504{
505 cfmConfig_t cfmConfig;
506 if (isCfm0Diag)
507 {
508 cfmConfig = BackupCfm0Config();
509 }
510 else
511 {
512 cfmConfig = BackupCfm1Config();
513 }
514 return cfmConfig;
515}
516
517// Backs up CFM0 configuration before diagnostic
518static cfmConfig_t BackupCfm0Config(void)
519{
520 cfmConfig_t cfmConfig;
521 cfmConfig.errChBackup = ERRCTRL_ReadConfigCfm0();
522 cfmConfig.windowLow = CLKCTRL_ReadCfm0WindowLow();
523 cfmConfig.windowHigh = CLKCTRL_ReadCfm0WindowHigh();
524 cfmConfig.windowRef = CLKCTRL_ReadCfm0RefNum();
525 cfmConfig.ctrlA = CLKCTRL_ReadCfm0ControlA();
526 cfmConfig.ctrlB = CLKCTRL_ReadCfm0ControlB();
527 return cfmConfig;
528}
529
530// Backs up CFM1 configuration before diagnostic
531static cfmConfig_t BackupCfm1Config(void)
532{
533 cfmConfig_t cfmConfig;
534 cfmConfig.errChBackup = ERRCTRL_ReadConfigCfm1();
535 cfmConfig.windowLow = CLKCTRL_ReadCfm1WindowLow();
536 cfmConfig.windowHigh = CLKCTRL_ReadCfm1WindowHigh();
537 cfmConfig.windowRef = CLKCTRL_ReadCfm1RefNum();
538 cfmConfig.ctrlA = CLKCTRL_ReadCfm1ControlA();
539 cfmConfig.ctrlB = CLKCTRL_ReadCfm1ControlB();
540 return cfmConfig;
541}
542
543// Sets the specified CFM Error Channel to NOTIFICATION severity and disables I/O float
544static void DisableCfmChannel(bool isCfm0Diag)
545{
546 const uint8_t stateMask = (uint8_t)ERRCTRL_STATE_gm;
547 const uint8_t floatConfig = 0U << ERRCTRL_FLOAT_bp; // Disable I/O float
548 const uint8_t severityConfig = (uint8_t)(ERRCTRL_ERRLVL_NOTIFICATION_gc);
549 const uint8_t disabledChConfig = (floatConfig | severityConfig);
550
551 ERRCTRL_ModifyControlA(stateMask, (uint8_t)ERRCTRL_STATE_CONFIG_gc);
552 if (isCfm0Diag)
553 {
554 ERRCTRL_WriteConfigCfm0(disabledChConfig);
555 }
556 else
557 {
558 ERRCTRL_WriteConfigCfm1(disabledChConfig);
559 }
560
561 ERRCTRL_ModifyControlA(stateMask, (uint8_t)ERRCTRL_STATE_NORMAL_gc);
562}
563
564// Configures the CFM reference clock and the number of cycles to monitor
565static void ConfigureCfmRefOsc(bool isCfm0Diag)
566{
567 uint8_t monitorEnableMask = (uint8_t)CLKCTRL_MEN_bm;
568 // Set high frequency oscillator as reference and enable ref
569 uint8_t cfmCtrlBConfig = (uint8_t)CLKCTRL_CFMREF_OSCHF_gc | (uint8_t)CLKCTRL_CFMREF_gm;
570
571 if (isCfm0Diag)
572 {
573 CLKCTRL_ClearCfm0ControlA(monitorEnableMask); // Disable CFM0
574 CLKCTRL_WriteCfm0RefNum(8U); // Set number of reference clock cycles to monitor
575 CLKCTRL_WriteCfm0ControlB(cfmCtrlBConfig);
576 }
577 else
578 {
579 CLKCTRL_ClearCfm1ControlA(monitorEnableMask); // Disable CFM1
580 CLKCTRL_WriteCfm1RefNum(8U); // Set number of reference clock cycles to monitor
581 CLKCTRL_WriteCfm1ControlB(cfmCtrlBConfig);
582 }
583}
584
585/*
586 * Runs all 3 CFM diagnostic tests and returns the result
587 *
588 * The number of reference clock cycles to measure the source clock is set in ConfigureCfmRefOsc
589 * to 8. Due to hardware synchronization the measurement might count between 6 and 10 cycles.
590 * The window must then be configures so that the expected measurement of 6-10 is inside, above
591 * or below depending on which part is tested.
592 */
593static bool IsCfmDiagPassed(bool isCfm0Diag)
594{
595 bool (*cfmTest)(uint16_t windowLow, uint16_t windowHigh, bool expectErr);
596 if (isCfm0Diag)
597 {
598 cfmTest = &IsCfm0TestPassed;
599 }
600 else
601 {
602 cfmTest = &IsCfm1TestPassed;
603 }
604
605 // Reports no error if inside window
606 uint16_t windowLow = 5U;
607 uint16_t windowHigh = 11U;
608 bool expectErr = false;
609 const bool isDiagInsidePassed = cfmTest(windowLow, windowHigh, expectErr);
610
611 // Reports error if above window
612 windowLow = 2U;
613 windowHigh = 5U;
614 expectErr = true;
615 const bool isDiagOverPassed = cfmTest(windowLow, windowHigh, expectErr);
616
617 // Reports error if below window
618 windowLow = 12U;
619 windowHigh = 15U;
620 expectErr = true;
621 const bool isDiagUnderPassed = cfmTest(windowLow, windowHigh, expectErr);
622
623 return (isDiagInsidePassed && isDiagOverPassed && isDiagUnderPassed);
624}
625
626// Runs one CFM0 test based on input and returns the results
627static bool IsCfm0TestPassed(uint16_t windowLow, uint16_t windowHigh, bool expectErr)
628{
629 // Bitmasks used for this diagnostic
630 const uint8_t monitorEnableMask = (uint8_t)CLKCTRL_MEN_bm;
631 const uint8_t srcOscHfMask = (uint8_t)CLKCTRL_CFMSRC_OSCHF_gc;
632 const uint8_t oneShotMask = (uint8_t)CLKCTRL_TYPE_ONESHOT_gc;
633 const uint8_t cfmMask = (uint8_t)CLKCTRL_CFM0_bm;
634 const uint8_t cfmDoneMask = (uint8_t)CLKCTRL_CFMD0_bm;
635
636 CLKCTRL_ClearCfm0ControlA(monitorEnableMask); // Disable CFM0
638 CLKCTRL_WriteCfm0WindowHigh(windowHigh);
639
640 CLKCTRL_WriteCfm0ControlA(monitorEnableMask | srcOscHfMask | oneShotMask);
641
642 const bool isDiagPassed = CheckCfmTest(cfmMask, cfmDoneMask, cfm0ChMask, expectErr);
643
644 // Clear interrupt flags and error channels
645 CLKCTRL_WriteIntFlags(cfmMask | cfmDoneMask);
646 ERRCTRL_WriteChannelStatus(cfm0ChMask);
647
648 return isDiagPassed; // Return true if flag set (Diag passed)
649}
650
651// Runs one CFM1 test based on input and returns the results
652static bool IsCfm1TestPassed(uint16_t windowLow, uint16_t windowHigh, bool expectErr)
653{
654 // Bitmasks used for this diagnostic
655 const uint8_t monitorEnableMask = (uint8_t)CLKCTRL_MEN_bm;
656 const uint8_t srcOscHfMask = (uint8_t)CLKCTRL_CFMSRC_OSCHF_gc;
657 const uint8_t oneShotMask = (uint8_t)CLKCTRL_TYPE_ONESHOT_gc;
658 const uint8_t cfmMask = (uint8_t)CLKCTRL_CFM1_bm;
659 const uint8_t cfmDoneMask = (uint8_t)CLKCTRL_CFMD1_bm;
660
661 CLKCTRL_ClearCfm1ControlA(monitorEnableMask); // Disable CFM1
662
664 CLKCTRL_WriteCfm1WindowHigh(windowHigh);
665
666 CLKCTRL_WriteCfm1ControlA(monitorEnableMask | srcOscHfMask | oneShotMask);
667
668 const bool isDiagPassed = CheckCfmTest(cfmMask, cfmDoneMask, cfm1ChMask, expectErr);
669
670 // Clear interrupt flags and error channels
671 CLKCTRL_WriteIntFlags(cfmMask | cfmDoneMask);
672 ERRCTRL_WriteChannelStatus(cfm1ChMask);
673
674 return isDiagPassed; // Return true if flag set (Diag passed)
675}
676
677// Reads the CFM interrupt flags and error channel and returns if triggered correctly
678static bool CheckCfmTest(uint8_t cfmMask, uint8_t cfmDoneMask, uint32_t cfmChMask, bool expectErr)
679{
680 bool isIntFlagSet = IsCfmFlagSet(cfmMask, cfmDoneMask);
681
682 const uint32_t chStatus = ERRCTRL_ReadChannelStatus();
683 bool isErrorChSet = ((chStatus & cfmChMask) == cfmChMask);
684
685 bool isDiagPassed = false;
686 if (expectErr)
687 {
688 // Interrupt flag and error channel set, diagnostic passed
689 isDiagPassed = (isIntFlagSet && isErrorChSet);
690 }
691 else
692 {
693 // Interrupt flag and/or error channel not set, diagnostic failed
694 isDiagPassed = !(isIntFlagSet || isErrorChSet);
695 }
696
697 return isDiagPassed;
698}
699
700// Reads CFM flag and returns state
701static bool IsCfmFlagSet(uint8_t cfmMask, uint8_t cfmDoneMask)
702{
703 uint8_t intFlags;
704 bool isCfmDone = false;
705 while (!isCfmDone) // Wait until measurement is done
706 {
707 intFlags = CLKCTRL_ReadIntFlags();
708 isCfmDone = ((intFlags & cfmDoneMask) == cfmDoneMask);
709 }
710
711 return ((intFlags & cfmMask) == cfmMask);
712}
713
714// Restores the CFM registers and error channel used in the diagnostics
715static void RestoreCfmConfig(bool isCfm0Diag, cfmConfig_t config)
716{
717 if (isCfm0Diag)
718 {
719 RestoreCfm0Config(config);
720 }
721 else
722 {
723 RestoreCfm1Config(config);
724 }
725 RestoreCfmChannel(isCfm0Diag, config.errChBackup);
726}
727
728// Restores the CFM0 registers used in the diagnostics
729static void RestoreCfm0Config(cfmConfig_t config)
730{
731 CLKCTRL_WriteCfm0WindowLow(config.windowLow);
732 CLKCTRL_WriteCfm0WindowHigh(config.windowHigh);
733 CLKCTRL_WriteCfm0RefNum(config.windowRef);
734 CLKCTRL_WriteCfm0ControlB(config.ctrlB);
735 CLKCTRL_WriteCfm0ControlA(config.ctrlA); // Restored last to avoid monitor enabled in config
736}
737
738// Restores the CFM1 registers used in the diagnostics
739static void RestoreCfm1Config(cfmConfig_t config)
740{
741 CLKCTRL_WriteCfm1WindowLow(config.windowLow);
742 CLKCTRL_WriteCfm1WindowHigh(config.windowHigh);
743 CLKCTRL_WriteCfm1RefNum(config.windowRef);
744 CLKCTRL_WriteCfm1ControlB(config.ctrlB);
745 CLKCTRL_WriteCfm1ControlA(config.ctrlA); // Restored last to avoid monitor enabled in config
746}
747
748// Restores the specified CFM Error Channel configs to their backed up configurations
749static void RestoreCfmChannel(bool isCfm0Diag, uint8_t chConfig)
750{
751 const uint8_t stateMask = (uint8_t)ERRCTRL_STATE_gm;
752 ERRCTRL_ModifyControlA(stateMask, (uint8_t)ERRCTRL_STATE_CONFIG_gc);
753 if (isCfm0Diag)
754 {
755 ERRCTRL_WriteConfigCfm0(chConfig);
756 }
757 else
758 {
759 ERRCTRL_WriteConfigCfm1(chConfig);
760 }
761 ERRCTRL_ModifyControlA(stateMask, (uint8_t)ERRCTRL_STATE_NORMAL_gc);
762}
errFlag_t
Defines the error flag used by Middleware services to indicate error detection.
@ NO_ERROR
void CLKCTRL_WriteCfm1ControlA(uint8_t value)
Overwrites the MCLKCFM1CTRLA register value.
void CLKCTRL_ClearCfm0ControlA(uint8_t bitmask)
Clears specific bits in the MCLKCFM0CTRLA register.
void CLKCTRL_WriteCfd0ControlA(uint8_t value)
Overwrites the MCLKCFD0CTRLA register value.
uint16_t CLKCTRL_ReadCfm0WindowLow(void)
Reads the MCLKCFM0WINLT register value.
uint8_t CLKCTRL_ReadCfm1ControlA(void)
Reads the MCLKCFM1CTRLA register value.
void CLKCTRL_WriteCfm1WindowHigh(uint16_t value)
Overwrites the MCLKCFM1WINHT register value.
void CLKCTRL_WriteCfm0ControlB(uint8_t value)
Overwrites the MCLKCFM0CTRLB register value.
uint16_t CLKCTRL_ReadCfm1WindowLow(void)
Reads the MCLKCFM1WINLT register value.
void CLKCTRL_ClearCfm1ControlA(uint8_t bitmask)
Clears specific bits in the MCLKCFM1CTRLA register.
uint8_t CLKCTRL_ReadCfd1ControlA(void)
Reads the MCLKCFD1CTRLA register value.
void CLKCTRL_WriteCfm1WindowLow(uint16_t value)
Overwrites the MCLKCFM1WINLT register value.
void CLKCTRL_WriteCfm1RefNum(uint16_t value)
Overwrites the MCLKCFM1REFNUM register value.
uint16_t CLKCTRL_ReadCfm1WindowHigh(void)
Reads the MCLKCFM1WINHT register value.
void CLKCTRL_WriteCfd1ControlA(uint8_t value)
Overwrites the MCLKCFD1CTRLA register value.
uint16_t CLKCTRL_ReadCfm0WindowHigh(void)
Reads the MCLKCFM0WINHT register value.
void CLKCTRL_WriteCfm0RefNum(uint16_t value)
Overwrites the MCLKCFM0REFNUM register value.
uint8_t CLKCTRL_ReadCfd0ControlA(void)
Reads the MCLKCFD0CTRLA register value.
uint16_t CLKCTRL_ReadCfm0RefNum(void)
Reads the MCLKCFM0REFNUM register value.
void CLKCTRL_WriteCfm0WindowHigh(uint16_t value)
Overwrites the MCLKCFM0WINHT register value.
uint8_t CLKCTRL_ReadCfm0ControlB(void)
Reads the MCLKCFM0CTRLB register value.
void CLKCTRL_WriteCfm1ControlB(uint8_t value)
Overwrites the MCLKCFM1CTRLB register value.
uint8_t CLKCTRL_ReadIntFlags(void)
Reads the MCLKINTFLAGS register value.
void CLKCTRL_ClearIntControl(uint8_t bitmask)
Clears specific bits in the MCLKINTCTRL register.
uint8_t CLKCTRL_ReadIntControl(void)
Reads the MCLKINTCTRL register value.
uint8_t CLKCTRL_ReadCfm1ControlB(void)
Reads the MCLKCFM1CTRLB register value.
void CLKCTRL_SetMainControlC(uint8_t bitmask)
Sets specific bits in the MCLKCTRLC register.
void CLKCTRL_WriteCfm0WindowLow(uint16_t value)
Overwrites the MCLKCFM0WINLT register value.
void CLKCTRL_SetIntControl(uint8_t bitmask)
Sets specific bits in the MCLKINTCTRL register.
uint16_t CLKCTRL_ReadCfm1RefNum(void)
Reads the MCLKCFM1REFNUM register value.
void CLKCTRL_WriteCfm0ControlA(uint8_t value)
Overwrites the MCLKCFM0CTRLA register value.
uint8_t CLKCTRL_ReadCfm0ControlA(void)
Reads the MCLKCFM0CTRLA register value.
void CLKCTRL_WriteIntFlags(uint8_t value)
Overwrites the MCLKINTFLAGS register value.
errFlag_t MW_DiagClockCfd0Begin(void)
Starts error injection diagnostic to detect faults in the Clock Failure Detection 0 (CFD0) monitor.
errFlag_t MW_DiagClockCfd1End(void)
Completes error injection diagnostic to detect faults in the CFD1 monitor.
bool MW_IsDiagCfd1Ongoing(void)
Checks if the CFD1 error injection is ongoing.
errFlag_t MW_DiagClockCfd0End(void)
Completes error injection diagnostic to detect faults in the CFD0 monitor.
errFlag_t MW_DiagClockCfm1(void)
Performs error injection diagnostic to detect faults in the Clock Frequency Measure 1 (CFM1) monitor.
errFlag_t MW_DiagClockCfm0(void)
Performs error injection diagnostic to detect faults in the Clock Frequency Measure 0 (CFM0) monitor.
errFlag_t MW_DiagClockCfd1Begin(void)
Starts error injection diagnostic to detect faults in the Clock Failure Detection 1 (CFD1) monitor.
bool MW_IsDiagCfd0Ongoing(void)
Checks if the CFD0 error injection is ongoing.
uint8_t ERRCTRL_ReadConfigCfd1(void)
Reads the ESCCFD1 register value.
void ERRCTRL_WriteConfigCfd0(uint8_t value)
Overwrites the ESCCFD0 register value.
void ERRCTRL_WriteConfigCfd1(uint8_t value)
Overwrites the ESCCFD1 register value.
uint32_t ERRCTRL_ReadChannelStatus(void)
Reads the ESF register value.
uint8_t ERRCTRL_ReadConfigCfd0(void)
Reads the ESCCFD0 register value.
void ERRCTRL_WriteConfigCfm1(uint8_t value)
Overwrites the ESCCFM1 register value.
uint8_t ERRCTRL_ReadConfigCfm0(void)
Reads the ESCCFM0 register value.
uint8_t ERRCTRL_ReadConfigCfm1(void)
Reads the ESCCFM1 register value.
void ERRCTRL_WriteConfigCfm0(uint8_t value)
Overwrites the ESCCFM0 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.
#define CFD_RESET_CONFIG
Default reset value of CFD CTRLA register in case of erroneously restoring with default backup values...
#define CRITICAL_CH_CONFIG
Default to maximum criticality and float I/O in case of erroneously restoring with default backup val...
Contains API prototypes for the Clock Manager Diagnostics.