In the Fault Handler the Fault Module routine needs to be changed to a Main routine.
The Fault Handler does not require a Fault routine. Only a Main routine is needed here. The Fault Handler executes automatically when there is a controller fault due to loss of communications with a required I/O module.
If there is also a Program Fault routine (Fault_1 in your example) then the Program Fault routine would execute
if the fault occurred within that program. If that routine fails to clear the fault, then the Fault Handler would execute. In this way, each program could be setup with a unique fault routine with the Fault Handler managing any faults not addressed by the unique program fault routines.
A failed "required" I/O module would not be considered a Program fault so the Program fault routine would not execute. Instead, the Fault Handler would execute.
EDIT #1: OK, there is a lot going on here....
In the Controller Fault Handler, the timer isn't going to work. Timing should never be done in a fault routine/handler. The scan does not sit on rung #0 and wait for the timer to finish before moving to rung #1. It starts the timer and then moves on.
When the fault occurs, it jumps to the handler, starts the timer and then moves to the next rung, the timer isn't done yet, so the GSV does not execute. Then it reaches the END and faults the system. There is no SSV here to clear the fault.
In your Program Fault Routine, I would guess that the CPU_SCANNING is preventing the SSV from executing. I would remove that so you only have the CLR and the SSV.
EDIT #2:
Personally, I do three things in a fault routine.
- Turn on an internal bit.
- Capture the fault information
- Clear the fault
Turn on an internal bit. I simply have an OTE on a rung by itself with a unique tag name assigned to it. No inputs ahead of it. I can use that bit in my normal logic to turn on an output (horn/light). I can have my HMI monitor it to identify if there has been a fault. I never turn on an actual output within my fault routines.
Capture the fault information. Pretty straightforward. Use the GSV to capture this data. Like your example I might call this Fault_Log or Program_Fault. I now have the fault type and code captured.
Clear the fault. I do this with the SSV a little differently than how Rockwell suggests. I create a new tag for the SSV. I might call this Program_Fault_Clear. The default value in all data fields would be 0, so the CLR isn't necessary. When the SSV executes it sends all zeroes clearing the fault. But I still have my fault information captured from the GSV.
OG