FuSa 8-Bit Libraries Safety Framework
Loading...
Searching...
No Matches
midware_power_manager_diag.c
1
22
23// Standard Library Includes
24#include <stdbool.h>
25#include <stdint.h>
26
27// Framework Includes
28#include <driver_cpuctrl.h>
29#include <driver_errctrl.h>
30#include <driver_slpctrl.h>
33
34// Device-specific Includes
35#include <xc.h>
36
42#define CRITICAL_CH_CONFIG ((uint8_t)ERRCTRL_FLOAT_bm | (uint8_t)ERRCTRL_ERRLVL_CRITICAL_gc)
43
44/*
45 * Variables used for tracking internal state and restoring error channel configs after diagnostics
46 * are complete. Must be written to atomically to avoid any race conditions.
47 */
48static volatile bool isDiagOngoing = false;
49static volatile uint8_t vregfailChBackup = CRITICAL_CH_CONFIG;
50static volatile uint8_t vregwarnChBackup = CRITICAL_CH_CONFIG;
51
52// Error Controller masks
53static const uint32_t vregfailChMask = 1UL << ERRCTRL_ESF_0_bp;
54static const uint32_t vregwarnChMask = 1UL << ERRCTRL_ESF_8_bp;
55
56// Private function prototypes
57static errFlag_t DiagVmonBegin(bool isOver);
58static bool IsDiagVmonDone(bool isOver);
59static errFlag_t DiagVmonEnd(bool isOver);
60static errFlag_t VerifyDiagStartFlags(void);
61static errFlag_t VerifyDiagEndFlags(bool isOver);
62static void BackupVregChConfigs(void);
63static void DisableVregChannels(void);
64static void RestoreVregChConfigs(void);
65
67{
68 const bool isOver = true;
69 const errFlag_t flag = DiagVmonBegin(isOver);
70 return flag;
71}
72
74{
75 const bool isOver = true;
76 const bool isDone = IsDiagVmonDone(isOver);
77 return isDone;
78}
79
81{
82 const bool isOver = true;
83 const errFlag_t flag = DiagVmonEnd(isOver);
84 return flag;
85}
86
88{
89 const bool isOver = false;
90 const errFlag_t flag = DiagVmonBegin(isOver);
91 return flag;
92}
93
95{
96 const bool isOver = false;
97 const bool isDone = IsDiagVmonDone(isOver);
98 return isDone;
99}
100
102{
103 const bool isOver = false;
104 const errFlag_t flag = DiagVmonEnd(isOver);
105 return flag;
106}
107
108static errFlag_t DiagVmonBegin(bool isOver)
109{
110 const uint32_t errorChMask = vregwarnChMask | vregfailChMask;
111 const bool isConfigurable = IsErrChConfigurable(errorChMask);
112 if (isDiagOngoing || !isConfigurable)
113 {
114 /* cppcheck-suppress misra-c2012-15.5 */
115 return ERROR;
116 }
117
118 // Disable and backup global interrupts configuration
120
121 // Prevent error injection from triggering a real error response
122 BackupVregChConfigs();
123 DisableVregChannels();
124
125 uint8_t dmodeVal = (uint8_t)SLPCTRL_DMODE_UNDER_gc; // Starts undervoltage diagnostic by default
126 if (isOver)
127 {
128 dmodeVal = (uint8_t)SLPCTRL_DMODE_OVER_gc;
129 }
130 SLPCTRL_WriteControlB(dmodeVal); // Start error injection
131
132 const errFlag_t flag = VerifyDiagStartFlags();
133
134 isDiagOngoing = true;
135
136 // Restore global interrupts configuration
138
139 return flag;
140}
141
142static bool IsDiagVmonDone(bool isOver)
143{
144 bool isErrInjectionDone = false;
145
146 if (isDiagOngoing)
147 {
148 const uint8_t intFlagVal = SLPCTRL_ReadIntFlags();
149 const uint8_t vdexitFlagMask = (uint8_t)SLPCTRL_VDEXIT_bm;
150
151 uint8_t flagMask = (uint8_t)SLPCTRL_VUV_bm;
152 if (isOver)
153 {
154 flagMask = (uint8_t)SLPCTRL_VOV_bm;
155 }
156
157 bool isFlagSet = (intFlagVal & flagMask) == flagMask;
158 bool isVdexitFlagSet = (intFlagVal & vdexitFlagMask) == vdexitFlagMask;
159 if (isFlagSet || isVdexitFlagSet)
160 {
161 isErrInjectionDone = true;
162 }
163 }
164
165 return isErrInjectionDone;
166}
167
168static errFlag_t DiagVmonEnd(bool isOver)
169{
170 if (isDiagOngoing == false)
171 {
172 /* cppcheck-suppress misra-c2012-15.5 */
173 return ERROR;
174 }
175
176 // Disable and backup global interrupts configuration
178
179 // Take VMON out of diagnostic mode
180 SLPCTRL_WriteControlB((uint8_t)SLPCTRL_DMODE_NO_gc); // If already timed out, this has no effect
181
182 const errFlag_t diagResult = VerifyDiagEndFlags(isOver);
183
184 RestoreVregChConfigs();
185
186 isDiagOngoing = false;
187
188 // Restore global interrupts configuration
190
191 return diagResult;
192}
193
194// Verifies that the expected flags are set after starting a diagnostic and clears them
195static errFlag_t VerifyDiagStartFlags(void)
196{
197 errFlag_t flag = ERROR;
198
199 /*
200 * When entering diagnostic mode, the VDENTER flag should be set, indicating that the error
201 * injection has successfully started. This flag will also set the VREGWARN Error Channel. Both
202 * of these are cleared here since they are not symptoms of errors in this case.
203 */
204 const uint8_t intFlagVal = SLPCTRL_ReadIntFlags();
205 const uint8_t vdenterFlagMask = (uint8_t)SLPCTRL_VDENTER_bm;
206 bool isVdenterSet = (intFlagVal & vdenterFlagMask) == vdenterFlagMask;
207 if (isVdenterSet)
208 {
209 SLPCTRL_WriteIntFlags(vdenterFlagMask); // Clear VDENTER interrupt flag
210 ERRCTRL_WriteChannelStatus(vregwarnChMask); // Clear VREGWARN channel flag
211 flag = NO_ERROR; // If VDENTER is set, the diagnostic was successfully initiated
212 }
213
214 return flag;
215}
216
217// Verifies that the expected flags are set when ending a diagnostic and clears them
218static errFlag_t VerifyDiagEndFlags(bool isOver)
219{
220 errFlag_t diagResultFlag = ERROR;
221 uint8_t flagMask = (uint8_t)SLPCTRL_VUV_bm; // Checks undervoltage flag by default
222 if (isOver)
223 {
224 flagMask = (uint8_t)SLPCTRL_VOV_bm;
225 }
226
227 const uint8_t intFlagVal = SLPCTRL_ReadIntFlags();
228 const bool isFlagSet = (intFlagVal & flagMask) == flagMask;
229
230 const uint32_t chStatus = ERRCTRL_ReadChannelStatus();
231 const bool isVregwarnChSet = ((chStatus & vregwarnChMask) == vregwarnChMask);
232 const bool isVregfailChSet = ((chStatus & vregfailChMask) == vregfailChMask);
233
234 if ((isFlagSet && isVregfailChSet && isVregwarnChSet))
235 {
236 /*
237 * If the VOV/VUV interrupt flag was set, that means that the VMON successfully detected and
238 * reported the injected error. In addition, the VREGFAIL channel should have been set by
239 * the VOV/VUV flag. The VREGWARN channel should also have been set once the VMON goes out
240 * of diagnostic mode and sets VDEXIT, either through a timeout or manually exiting
241 * diagnostic mode. All of these conditions need to be met for the diagnostic to be
242 * considered successful.
243 */
244 diagResultFlag = NO_ERROR;
245 }
246
247 const uint8_t vdexitFlagMask = (uint8_t)SLPCTRL_VDEXIT_bm;
248 SLPCTRL_WriteIntFlags(flagMask | vdexitFlagMask); // Clear diagnostic interrupt flags
249 ERRCTRL_WriteChannelStatus(vregfailChMask | vregwarnChMask); // Clear diagnosed Error Channels
250
251 return diagResultFlag;
252}
253
254// Saves the VREG Error Channel configurations so they can be restored after the diagnostic is done
255static void BackupVregChConfigs(void)
256{
257 vregfailChBackup = ERRCTRL_ReadConfigVregfail();
258 vregwarnChBackup = ERRCTRL_ReadConfigVregwarn();
259}
260
261// Sets the VREG Error Channels to NOTIFICATION severity and disables I/O float
262static void DisableVregChannels(void)
263{
264 const uint8_t stateMask = (uint8_t)ERRCTRL_STATE_gm;
265 const uint8_t floatConfig = 0U << ERRCTRL_FLOAT_bp; // Disable I/O float
266 const uint8_t severityConfig = (uint8_t)(ERRCTRL_ERRLVL_NOTIFICATION_gc);
267 const uint8_t disabledChConfig = (floatConfig | severityConfig);
268
269 ERRCTRL_ModifyControlA(stateMask, (uint8_t)ERRCTRL_STATE_CONFIG_gc);
270 ERRCTRL_WriteConfigVregfail(disabledChConfig);
271 ERRCTRL_WriteConfigVregwarn(disabledChConfig);
272 ERRCTRL_ModifyControlA(stateMask, (uint8_t)ERRCTRL_STATE_NORMAL_gc);
273}
274
275// Restores the VREG Error Channel configs to their backed up configurations
276static void RestoreVregChConfigs(void)
277{
278 const uint8_t stateMask = (uint8_t)ERRCTRL_STATE_gm;
279 ERRCTRL_ModifyControlA(stateMask, (uint8_t)ERRCTRL_STATE_CONFIG_gc);
280 ERRCTRL_WriteConfigVregfail(vregfailChBackup);
281 ERRCTRL_WriteConfigVregwarn(vregwarnChBackup);
282 ERRCTRL_ModifyControlA(stateMask, (uint8_t)ERRCTRL_STATE_NORMAL_gc);
283}
errFlag_t
Defines the error flag used by Middleware services to indicate error detection.
@ NO_ERROR
uint8_t ERRCTRL_ReadConfigVregfail(void)
Reads the ESCVREGFAIL register value.
uint32_t ERRCTRL_ReadChannelStatus(void)
Reads the ESF register value.
void ERRCTRL_WriteConfigVregfail(uint8_t value)
Overwrites the ESCVREGFAIL register value.
void ERRCTRL_WriteConfigVregwarn(uint8_t value)
Overwrites the ESCVREGWARN 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.
uint8_t ERRCTRL_ReadConfigVregwarn(void)
Reads the ESCVREGWARN register value.
errFlag_t MW_DiagVmonUnderBegin(void)
Starts error injection diagnostic to detect faults in the VMON undervoltage detector.
errFlag_t MW_DiagVmonOverEnd(void)
Completes error injection diagnostic to detect faults in the VMON overvoltage detector.
errFlag_t MW_DiagVmonUnderEnd(void)
Completes error injection diagnostic to detect faults in the VMON undervoltage detector.
bool MW_IsDiagVmonOverDone(void)
Checks if the VMON overvoltage error injection has been completed.
errFlag_t MW_DiagVmonOverBegin(void)
Starts error injection diagnostic to detect faults in the VMON overvoltage detector.
bool MW_IsDiagVmonUnderDone(void)
Checks if the VMON undervoltage error injection has been completed.
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.
void SLPCTRL_WriteIntFlags(uint8_t value)
Overwrites the INTFLAGS register value.
void SLPCTRL_WriteControlB(uint8_t value)
Overwrites the CTRLB register value.
uint8_t SLPCTRL_ReadIntFlags(void)
Reads the INTFLAGS register value.
#define CRITICAL_CH_CONFIG
Default to maximum criticality and float I/O in case of erroneously restoring with default backup val...
Implements APIs for the Power Manager Diagnostics.