11import subprocess
22import struct
3- import re
43import os
54from dataclasses import dataclass
65from typing import List , Optional
6+
77HF_FLASH_ADDR = 0x080C0000
88HF_FLASH_ADDR_STRING = "0x080C000"
99ELF_FILE = "out/build/latest.elf"
1010
1111CALL_TRACE_MAX_DEPTH = 16
12+
13+
1214@dataclass
1315class HardFaultFrame :
1416 flag : int
@@ -24,12 +26,17 @@ class HardFaultFrame:
2426 fault_addr : int
2527 calltrace_depth : int
2628 calltrace_pcs : List [int ]
29+
30+
2731def read_flash ():
2832 try :
2933 cmd = [
3034 "STM32_Programmer_CLI" ,
31- "-c" , "port=SWD" ,
32- "-r32" , hex (HF_FLASH_ADDR ), "112"
35+ "-c" ,
36+ "port=SWD" ,
37+ "-r32" ,
38+ hex (HF_FLASH_ADDR ),
39+ "112" ,
3340 ]
3441 out = subprocess .check_output (cmd , text = True )
3542 return out
@@ -40,8 +47,8 @@ def read_flash():
4047 except FileNotFoundError :
4148 print ("STM32_Programmer_CLI not found. Make sure it is installed and in PATH." )
4249 return None
43-
44-
50+
51+
4552def decode_cfsr_memory (cfsr , fault_addr ):
4653 memory_fault = cfsr & 0xFF
4754 if memory_fault == 0 :
@@ -66,6 +73,7 @@ def decode_cfsr_memory(cfsr, fault_addr):
6673 print (" IACCVIOL : Instruction access violation" )
6774 return 1
6875
76+
6977# --------------------------
7078# Decode Bus Fault (BFSR)
7179# --------------------------
@@ -75,10 +83,10 @@ def decode_cfsr_bus(cfsr, fault_addr):
7583 return 0
7684 print ("\n Bus Fault (BFSR):" )
7785 if bus_fault & 0b10000000 :
78- if ( bus_fault & 0b00000001 ) :
86+ if bus_fault & 0b00000001 :
7987 print (f" BFARVALID : Bus fault address valid -> 0x{ fault_addr :08X} " )
8088 if bus_fault & 0b00000100 :
81- print (f "\033 [91m Bus fault address imprecise\033 [0m (DON'T LOOK CALL STACK)" )
89+ print ("\033 [91m Bus fault address imprecise\033 [0m (DON'T LOOK CALL STACK)" )
8290
8391 if bus_fault & 0b00100000 :
8492 print (" LSPERR : Floating Point Unit lazy state preservation error" )
@@ -88,6 +96,7 @@ def decode_cfsr_bus(cfsr, fault_addr):
8896 print (" UNSTKERR : Stack error on return from exception" )
8997 return 2
9098
99+
91100# --------------------------
92101# Decode Usage Fault (UFSR)
93102# --------------------------
@@ -110,6 +119,7 @@ def decode_cfsr_usage(cfsr):
110119 print (" UNDEFINSTR : Undefined instruction" )
111120 return 4
112121
122+
113123def decode_cfsr (cfsr , fault_addr ):
114124 error = 0
115125 error = decode_cfsr_memory (cfsr , fault_addr ) + error
@@ -128,25 +138,25 @@ def addr2line(addr):
128138
129139
130140def print_code_context (lines , context = 2 ):
131- #addr2line
132- #line 0: function name
133- #line 1 : file : line
141+ # addr2line
142+ # line 0: function name
143+ # line 1 : file : line
134144 line_list = lines .splitlines ()
135145 if len (line_list ) < 2 :
136146 print ("Invalid addr2line output" )
137147 return
138-
148+
139149 file_line = line_list [1 ].strip ()
140- split = file_line .rfind (':' )
150+ split = file_line .rfind (":" )
141151
142152 if split == - 1 :
143153 print ("Invalid file:line format" )
144154 return
145-
155+
146156 file_path = file_line [:split ]
147157
148158 try :
149- line_no = int (file_line [split + 1 :]) - 1
159+ line_no = int (file_line [split + 1 :]) - 1
150160 except ValueError :
151161 print ("Couldn't parse line number" )
152162 return
@@ -171,7 +181,6 @@ def print_code_context(lines, context=2):
171181 print (f"{ i + 1 :>4} : { code } " )
172182
173183
174-
175184def parse_hardfault (memory_string : str ) -> Optional [HardFaultFrame ]:
176185 try :
177186 raw_bytes = bytes .fromhex (memory_string )
@@ -196,18 +205,17 @@ def parse_hardfault(memory_string: str) -> Optional[HardFaultFrame]:
196205 cfsr = raw [9 ],
197206 fault_addr = raw [10 ],
198207 calltrace_depth = raw [11 ],
199- calltrace_pcs = list (raw [12 :28 ])
208+ calltrace_pcs = list (raw [12 :28 ]),
200209 )
201210
202211 except Exception as e :
203212 print (f"Error parsing hardfault frame: { e } " )
204213 return None
205-
206-
207- def analyze_call_stack (calltrace_depth : int ,
208- calltrace_pcs : List [int ],
209- context : int = 1 ):
210214
215+
216+ def analyze_call_stack (
217+ calltrace_depth : int , calltrace_pcs : List [int ], context : int = 1
218+ ):
211219 print ("\n ==== Call Stack Trace ====" )
212220
213221 try :
@@ -226,7 +234,6 @@ def analyze_call_stack(calltrace_depth: int,
226234 depth = min (calltrace_depth , len (calltrace_pcs ), CALL_TRACE_MAX_DEPTH )
227235
228236 for i in range (depth ):
229-
230237 pc = calltrace_pcs [i ]
231238
232239 # Validación básica de PC
@@ -258,54 +265,65 @@ def analyze_call_stack(calltrace_depth: int,
258265 print (f"Unexpected error in analyze_call_stack: { e } " )
259266
260267 print ("===============================================" )
261- def hard_fault_analysis (hf ,context ):
262-
263- if (hf .flag != 0xFF00FF00 ):
264- print ("There was no hardfault in your Microcontroller, Kudos for you, I hope..." )
268+
269+
270+ def hard_fault_analysis (hf , context ):
271+ if hf .flag != 0xFF00FF00 :
272+ print (
273+ "There was no hardfault in your Microcontroller, Kudos for you, I hope..."
274+ )
265275 return
266-
276+
267277 print ("================HARDFAULT DETECTED ===========" )
268278 print ("Registers:" )
269279
270- for r in ['r0' , 'r1' , 'r2' , 'r3' , ' r12' , 'lr' , 'pc' , ' psr' ]:
280+ for r in ["r0" , "r1" , "r2" , "r3" , " r12" , "lr" , "pc" , " psr" ]:
271281 value = getattr (hf , r )
272- print (f" { r .upper ():<4} : 0x{ value :08X} " )
282+ print (f" { r .upper ():<4} : 0x{ value :08X} " )
273283 print ("\n " )
274284 print ("Register that contains the info about the HardFault" )
275285 print (f" CFSR: 0x{ hf .cfsr :08X} " )
276- #get the cause of the error
286+ # get the cause of the error
277287 print ("------HardFault Fail------" )
278- error = decode_cfsr (hf .cfsr , hf .fault_addr )
288+ decode_cfsr (hf .cfsr , hf .fault_addr )
279289 print ("---------------------------" )
280-
290+
281291 pc_loc = addr2line (hf .pc )
282292 lr_loc = addr2line (hf .lr )
283-
293+
284294 print ("\n =======Source Location: ===========\n " )
285295 print (f" --> Linker Register : 0x{ hf .lr :08X} \n -> { lr_loc } " )
286- print_code_context (lr_loc ,context )
296+ print_code_context (lr_loc , context )
287297 print ("\n " )
288298 print (f" -->Program Counter : 0x{ hf .pc :08X} \n -> { pc_loc } " )
289- print_code_context (pc_loc ,context )
299+ print_code_context (pc_loc , context )
290300 print ("=============================" )
291- analyze_call_stack (hf .calltrace_depth ,hf .calltrace_pcs ,context )
301+ analyze_call_stack (hf .calltrace_depth , hf .calltrace_pcs , context )
292302
293303 print ("======================================================" )
294304
295-
296- print ("Note: In Release builds (-O2/-O3) the PC may not point exactly to the failing instruction." )
297- print (" During interrupts, bus faults, or stack corruption, the PC can be imprecise." )
298- print ("\n In case of Imprecise error is dificult to find due to is asynchronous fault" )
305+ print (
306+ "Note: In Release builds (-O2/-O3) the PC may not point exactly to the failing instruction."
307+ )
308+ print (
309+ " During interrupts, bus faults, or stack corruption, the PC can be imprecise."
310+ )
311+ print (
312+ "\n In case of Imprecise error is dificult to find due to is asynchronous fault"
313+ )
299314 print ("The error has to be before PC. But not possible to know exactly when." )
300- print ("Check this link to know more : https://interrupt.memfault.com/blog/cortex-m-hardfault-debug#fn:8" )
315+ print (
316+ "Check this link to know more : https://interrupt.memfault.com/blog/cortex-m-hardfault-debug#fn:8"
317+ )
301318
302- #get the memory with the address of HardFault
319+
320+ # get the memory with the address of HardFault
303321def extract_memory_dump (cli_output : str ) -> Optional [str ]:
304322 pos = cli_output .rfind (HF_FLASH_ADDR_STRING )
305323 if pos == - 1 :
306324 print ("The address was not found in CLI output" )
307325 return None
308-
326+
309327 flash = cli_output [pos :]
310328
311329 memory_string = ""
@@ -318,9 +336,8 @@ def extract_memory_dump(cli_output: str) -> Optional[str]:
318336 return memory_string .replace (" " , "" )
319337
320338
321-
322- if __name__ == '__main__' :
323- #First get all the information from the flash Memory
339+ if __name__ == "__main__" :
340+ # First get all the information from the flash Memory
324341 out = read_flash ()
325342 if out is None :
326343 exit (1 )
@@ -331,12 +348,12 @@ def extract_memory_dump(cli_output: str) -> Optional[str]:
331348 hf = parse_hardfault (memory_string )
332349 if not hf :
333350 exit (1 )
334- print ("Lines of context to watch (max 10):" ,end = "" )
351+ print ("Lines of context to watch (max 10):" , end = "" )
335352 try :
336353 context = int (input ())
337354 except ValueError :
338355 context = 2
339356 if context < 0 or context > 10 :
340357 context = 10
341358 print ("\n " )
342- hard_fault_analysis (hf ,context )
359+ hard_fault_analysis (hf , context )
0 commit comments