├── .gitignore ├── ARMCM0plus.mk ├── ARMCM3.mk ├── ARMCM4.mk ├── LICENSE.txt ├── Makefile ├── README.md ├── SiliconLabs ├── efm32gg.mk ├── efm32zg.mk ├── segger.mk ├── silabs.mk ├── stk3200 │ ├── Makefile │ └── ozone.jdebug.in └── stk3700 │ ├── Makefile │ └── ozone.jdebug.in ├── cm0plus.mk ├── cm3.mk ├── cm4.mk ├── pom.xml ├── src ├── main │ ├── asm │ │ ├── faultHandling_cm0.S │ │ └── faultHandling_cm3.S │ ├── c │ │ └── faultHandling.c │ └── include │ │ └── faultHandling.h └── test │ └── c │ ├── branchZero.c │ ├── busFault.c │ ├── faultGuru.c │ ├── iaccviol.c │ ├── invstate.c │ ├── mpuFault.c │ ├── noopProcessor.c │ ├── stackSmashing.c │ ├── stk3200.c │ └── stk3700.c └── toolchain.mk /.gitignore: -------------------------------------------------------------------------------- 1 | *.a 2 | *.o 3 | *.i 4 | 5 | *.axf 6 | *.bin 7 | *.map 8 | *.lst 9 | *.jlink 10 | *.jdebug 11 | *.jdebug.user 12 | -------------------------------------------------------------------------------- /ARMCM0plus.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright © 2022 Stuart Maclean 3 | # 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are 8 | # met: 9 | # 10 | # * Redistributions of source code must retain the above copyright 11 | # notice, this list of conditions and the following disclaimer. 12 | # 13 | # * Redistributions in binary form must reproduce the above 14 | # copyright notice, this list of conditions and the following 15 | # disclaimer in the documentation and/or other materials provided 16 | # with the distribution. 17 | # 18 | # * Neither the name of the copyright holder nor the names of its 19 | # contributors may be used to endorse or promote products derived 20 | # from this software without specific prior written permission. 21 | # 22 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | # HOLDER NOR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 29 | # OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 31 | # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 32 | # USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 33 | # DAMAGE. 34 | # 35 | 36 | CMSIS_device_header = ARMCM0plus.h 37 | 38 | DEVICE = $(CMSIS_HOME)/Device/ARM/ARMCM0plus 39 | 40 | CPPFLAGS += -I$(DEVICE)/Include -DARMCM0P 41 | 42 | VPATH += $(DEVICE)/Source $(DEVICE)/Source/GCC 43 | 44 | DEVICE_SRCS = system_ARMCM0plus.c startup_ARMCM0plus.c 45 | 46 | LDSCRIPT = $(DEVICE)/Source/GCC/gcc_arm.ld 47 | 48 | CPPFLAGS += -I$(CMSIS_HOME)/CMSIS/Core/Include 49 | 50 | # eof 51 | -------------------------------------------------------------------------------- /ARMCM3.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright © 2022 Stuart Maclean 3 | # 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are 8 | # met: 9 | # 10 | # * Redistributions of source code must retain the above copyright 11 | # notice, this list of conditions and the following disclaimer. 12 | # 13 | # * Redistributions in binary form must reproduce the above 14 | # copyright notice, this list of conditions and the following 15 | # disclaimer in the documentation and/or other materials provided 16 | # with the distribution. 17 | # 18 | # * Neither the name of the copyright holder nor the names of its 19 | # contributors may be used to endorse or promote products derived 20 | # from this software without specific prior written permission. 21 | # 22 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | # HOLDER NOR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 29 | # OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 31 | # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 32 | # USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 33 | # DAMAGE. 34 | # 35 | 36 | CMSIS_device_header = ARMCM3.h 37 | 38 | DEVICE = $(CMSIS_HOME)/Device/ARM/ARMCM3 39 | 40 | CPPFLAGS += -I$(DEVICE)/Include -DARMCM3 41 | 42 | VPATH += $(DEVICE)/Source $(DEVICE)/Source/GCC 43 | 44 | DEVICE_SRCS = system_ARMCM3.c startup_ARMCM3.c 45 | 46 | LDSCRIPT = $(DEVICE)/Source/GCC/gcc_arm.ld 47 | 48 | CPPFLAGS += -I$(CMSIS_HOME)/CMSIS/Core/Include 49 | 50 | # eof 51 | -------------------------------------------------------------------------------- /ARMCM4.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright © 2022 Stuart Maclean 3 | # 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are 8 | # met: 9 | # 10 | # * Redistributions of source code must retain the above copyright 11 | # notice, this list of conditions and the following disclaimer. 12 | # 13 | # * Redistributions in binary form must reproduce the above 14 | # copyright notice, this list of conditions and the following 15 | # disclaimer in the documentation and/or other materials provided 16 | # with the distribution. 17 | # 18 | # * Neither the name of the copyright holder nor the names of its 19 | # contributors may be used to endorse or promote products derived 20 | # from this software without specific prior written permission. 21 | # 22 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | # HOLDER NOR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 29 | # OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 31 | # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 32 | # USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 33 | # DAMAGE. 34 | # 35 | 36 | CMSIS_device_header = ARMCM4.h 37 | 38 | DEVICE = $(CMSIS_HOME)/Device/ARM/ARMCM4 39 | 40 | CPPFLAGS += -I$(DEVICE)/Include -DARMCM4 41 | 42 | VPATH += $(DEVICE)/Source $(DEVICE)/Source/GCC 43 | 44 | DEVICE_SRCS = system_ARMCM4.c startup_ARMCM4.c 45 | 46 | LDSCRIPT = $(DEVICE)/Source/GCC/gcc_arm.ld 47 | 48 | CPPFLAGS += -I$(CMSIS_HOME)/CMSIS/Core/Include 49 | 50 | # eof 51 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright © 2022 Stuart Maclean 2 | 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are 7 | met: 8 | 9 | * Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above 13 | copyright notice, this list of conditions and the following 14 | disclaimer in the documentation and/or other materials provided 15 | with the distribution. 16 | 17 | * Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived 19 | from this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 | HOLDER NOR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 28 | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 29 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 30 | TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 31 | USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 32 | DAMAGE. 33 | 34 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright © 2022 Stuart Maclean 3 | # 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are 8 | # met: 9 | # 10 | # * Redistributions of source code must retain the above copyright 11 | # notice, this list of conditions and the following disclaimer. 12 | # 13 | # * Redistributions in binary form must reproduce the above 14 | # copyright notice, this list of conditions and the following 15 | # disclaimer in the documentation and/or other materials provided 16 | # with the distribution. 17 | # 18 | # * Neither the name of the copyright holder nor the names of its 19 | # contributors may be used to endorse or promote products derived 20 | # from this software without specific prior written permission. 21 | # 22 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | # HOLDER NOR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 29 | # OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 31 | # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 32 | # USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 33 | # DAMAGE. 34 | # 35 | 36 | # Stuart Maclean, 2021. See ./LICENSE.txt and ./README.md 37 | 38 | BASEDIR ?= $(abspath .) 39 | 40 | ## Infrastructure, just to ensure this Makefile is leaner 41 | 42 | include $(BASEDIR)/toolchain.mk 43 | 44 | ########################### CMSIS BUNDLE FROM ARM ############################ 45 | 46 | # ARM Software's CMSIS_5 repo at github cloned to some local directory. 47 | # Replace the CMSIS_HOME path with your local equivalent. 48 | 49 | CMSIS_HOME = $(BASEDIR)/../CMSIS_5 50 | 51 | ################################### CPU ################################# 52 | 53 | # We're building here for M3 by default, you could switch in e.g. M0, M4 54 | # (make CM4=1 or edit below). 55 | 56 | ifdef CM0 57 | include $(BASEDIR)/cm0plus.mk 58 | else ifdef CM4 59 | include $(BASEDIR)/cm4.mk 60 | else 61 | include $(BASEDIR)/cm3.mk 62 | endif 63 | 64 | # A VENDOR-specific build (see e.g. ./SiliconLabs/*) will define its 65 | # own DEVICE files. If no VENDOR, use ARM defaults, which describe a 66 | # generic CPU only (no peripherals). 67 | 68 | ifndef CMSIS_device_header 69 | 70 | ifdef CM0 71 | include $(BASEDIR)/ARMCM0plus.mk 72 | else ifdef CM4 73 | include $(BASEDIR)/ARMCM4.mk 74 | else 75 | include $(BASEDIR)/ARMCM3.mk 76 | endif 77 | 78 | endif 79 | 80 | ########################## FAULT HANDLING LIB, TESTS ###################### 81 | 82 | LIB_C_SRCS = faultHandling.c 83 | 84 | LIB_OBJS = $(LIB_ASM_SRCS:.S=.o) $(LIB_C_SRCS:.c=.o) 85 | 86 | DEVICE_OBJS = $(DEVICE_SRCS:.c=.o) 87 | 88 | # LIB itself was defined in cmX.mk 89 | 90 | # Some tests that use the faultHandling api, currently just one. 91 | # Vendor-specific test cases will define others, see 92 | # e.g. SiliconLabs/stk3700/Makefile. 93 | 94 | ifndef VENDOR 95 | TESTS += noopProcessor 96 | endif 97 | 98 | ############################ Derived File Names ############################# 99 | 100 | # Buildable artifacts derivable from our TESTS names 101 | 102 | AXFS = $(addsuffix .axf, $(TESTS)) 103 | 104 | BINS = $(addsuffix .bin, $(TESTS)) 105 | 106 | 107 | #################### Build Settings: VPATH, CPPFLAGS ############## 108 | 109 | # run 'make flags' to inspect these 110 | 111 | # Locates our lib sources 112 | VPATH += $(BASEDIR)/src/main/c $(BASEDIR)/src/main/asm 113 | 114 | # Locates our test sources 115 | VPATH += $(BASEDIR)/src/test/c 116 | 117 | # Locates our lib headers 118 | CPPFLAGS += -I$(BASEDIR)/src/main/include 119 | 120 | # Needed by faultHandling.h 121 | CPPFLAGS += -DCMSIS_device_header=\"$(CMSIS_device_header)\" 122 | 123 | LDLIBS += -lc -lnosys 124 | 125 | ############################### Build Targets ################################ 126 | 127 | # Print out recipes only if V set (make V=1), else quiet to avoid clutter 128 | ifndef V 129 | ECHO=@ 130 | endif 131 | 132 | default: lib 133 | 134 | lib: $(LIB) 135 | 136 | $(LIB): $(LIB_OBJS) 137 | @echo AR $(@F) 138 | $(ECHO)$(AR) cr $@ $^ 139 | 140 | tests: $(BINS) 141 | 142 | clean: 143 | $(RM) *.bin *.axf *.map *.lst *.a *.o *.i 144 | 145 | 146 | ############################## Pattern Rules ################################ 147 | 148 | # Overriding default patterns for inclusion of CPU_OPTIONS, which are 149 | # a must. The arm-none-eabi toolchain can compile for a wide variety of 150 | # cpus, and we have to tell it what we have. 151 | 152 | %.o : %.c 153 | @echo CC $( $@ || $(RM) $@ 164 | 165 | %.bin: %.axf 166 | @echo OBJCOPY $( $*.lst 177 | 178 | ################################### MISC ############################## 179 | 180 | # Inspect VPATH, CPPFLAGS, useful when things won't build 181 | flags: 182 | @echo 183 | @echo VPATH $(VPATH) | tr ' ' '\n' 184 | @echo 185 | @echo CPPFLAGS $(CPPFLAGS) | tr ' ' '\n' 186 | @echo 187 | @echo LIB $(LIB) 188 | @echo 189 | @echo LIB_OBJS $(LIB_OBJS) 190 | 191 | # Build ALL configurations 192 | sweep: 193 | $(MAKE) clean lib tests CM3=1 194 | $(MAKE) clean lib tests CM4=1 195 | $(MAKE) clean lib tests CM0=1 196 | $(MAKE) -C SiliconLabs/stk3700 clean lib tests 197 | $(MAKE) -C SiliconLabs/stk3200 clean lib tests 198 | 199 | .PHONY: default lib clean distclean flags tests sweep 200 | 201 | # eof 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Structured Fault Handling on ARM Cortex M Processors 2 | 3 | + Fault Dumps 4 | 5 | + Fault Dump API 6 | 7 | + Building The Library 8 | 9 | + Running Test Applications 10 | 11 | + Quiz - Match Faulting Code Against Dump 12 | 13 | ## Fault Dumps 14 | 15 | For programs running on ARM Cortex-M series microcontrollers, given a 16 | CPU fault resulting from code such as this 17 | 18 | ``` 19 | void (*p)(void) = (void(*)(void))0; 20 | ... 21 | p(); 22 | ``` 23 | this 'fault handling' library produces a 'fault dump' like this: 24 | 25 | ``` 26 | r7 2001BEC8 27 | sp 2001BEA0 28 | excrt FFFFFFFD 29 | psr 20000004 30 | hfsr 00000000 31 | cfsr 00000082 32 | mmfar 00000000 33 | bfar 00000000 34 | shcsr 00010001 35 | s.r0 00000000 36 | s.r1 0004BCF8 37 | s.r2 00000000 38 | s.r3 0004BCF8 39 | s.r12 01010101 40 | s.lr 0001D053 41 | s.pc 0003B9CC 42 | s.psr 21000000 43 | 2001FFD8 00002001 44 | 2001FFE4 00001801 45 | 2001FFE8 00000101 46 | 2001FFFC 0000016B 47 | 48 | ``` 49 | 50 | The fault dump is just a multi-line string. It is prepared at program 51 | start, and the register value *holes* filled in at fault time to 52 | complete the string. This minimizes string processing after fault 53 | occurrence. 54 | 55 | The dump above is from a faulting Cortex M3/4. On a Cortex-M0/M0+, the 56 | hfsr through bfar registers would be missing. 57 | 58 | The dump includes 17 register values followed by four 'possible pushed 59 | LR' values. Each is a pair: stack location where the possible LR was 60 | found, and the value itself. From this sequence the call stack leading 61 | to the fault might be identified. 62 | 63 | A register dump like the one above is routinely created by your 64 | IDE/debugger when some program you are working with keels over and 65 | crashes. But what to do when your application has deployed, and there 66 | *is* no IDE/debugger? If you need to solve that problem, this library 67 | could be for you. 68 | 69 | Our approach is this: 70 | 71 | * Application uses an API to plan for a fault. 72 | 73 | * A fault produces a fault dump, as above. 74 | 75 | * Application somehow exports the dump. 76 | 77 | * Developer gets copy and does analysis. 78 | 79 | The code presented here *is* that API. 80 | 81 | The dump string is thus exported from the microcontroller for fault 82 | dump analysis. The library described here just creates the fault dump 83 | string. The export step is environment-specific, so is added by the 84 | application developer, via a callback in the API. 85 | 86 | The simplest export might be *printf* (whatever that means on a 87 | microcontroller!): 88 | 89 | ``` 90 | void printfDumpProcessor(void) { 91 | printf( "%s\n", faultDump ); 92 | } 93 | ``` 94 | 95 | I work in oceanographic instrumentation, 96 | including underwater [profiling floats](https://en.wikipedia.org/wiki/Float_(oceanography)). If my system faults, 2000m down 97 | somewhere in the Pacific Ocean, there ain't anyone there watching, so 98 | console printf is of limited utility. And the JTAG cable doesn't quite 99 | reach. And the wi-fi is spotty. And I have no hard disk. 100 | 101 | My export strategy therefore is to declare the faultDump buffer in a 102 | .noInit section of RAM, re-boot after the fault, wait until I am back 103 | at the surface, then beam the fault dump home via [Iridium sat comms](https://en.wikipedia.org/wiki/Iridium_satellite_constellation). 104 | Only then can the fault analysis begin, and in my (painful) 105 | experience, each and every register in the dump can contribute to 106 | solving the error cause. 107 | 108 | Analysis is essentially a case of matching register values from the 109 | fault dump against your .map and .lst files for the .bin file 110 | installed on the faulting system. You do *have* the .map and .lst 111 | files? If no, stop reading now, go fix your build process, then 112 | proceed. The Makefile included here shows how I derive the .map and 113 | .lst files for any application, adapt as necessary. 114 | 115 | ## Fault Dump API 116 | 117 | A minimal working example of this api would be an application like: 118 | 119 | ``` 120 | #include "faultHandling.h" 121 | 122 | static char faultDumpBuffer[FAULT_HANDLING_DUMP_SIZE]; 123 | 124 | static void noopDumpProcessor(void) { 125 | // Wot, no peripherals to send the faultDump to, not even a serial port! 126 | } 127 | 128 | int main(void) { 129 | faultHandlingSetDumpProcessor( faultDumpBuffer, noopDumpProcessor ); 130 | faultHandlingSetPostFaultAction( POSTHANDLER_LOOP ); 131 | 132 | rest of application, will fault somewhere... 133 | } 134 | 135 | // Override the (weak) HFH to vector to our library 136 | __attribute__((naked)) 137 | void HardFault_Handler(void) { 138 | __asm__( "B FaultHandler\n" ); 139 | } 140 | ``` 141 | 142 | In additional to the core CPU register values, the fault dump can 143 | include an inferred function call stack, i.e. which function call 144 | sequence led to the fault. To do this, the library needs some help on 145 | memory layout from the user: 146 | 147 | ``` 148 | extern const tVectorEntry __Vectors[]; 149 | extern uint32_t __etext; 150 | extern uint32_t __StackTop; 151 | 152 | /* params: text.min, text.max, msp.max, psp.max/0 */ 153 | faultHandlingSetCallStackParameters( &__Vectors, &__etext, &__StackTop, 0 ); 154 | ``` 155 | 156 | You just supply lower and upper bounds for the .text section, and 157 | upper bounds for Main Stack and Process Stack (latter optional). The 158 | vector table `__Vectors` will be declared in `startup_device.c`. I get 159 | `__etext` and `__StackTop` declared by my linker, via the .ld 160 | file. Your build will have similar. 161 | 162 | Exact accuracy for the values is not critical, it will just reduce false 163 | positive identification of pushed LR values (and thus call stack 164 | composition). See the [code](src/main/c/faultHandling.c) for more details. 165 | 166 | ## Building The Library 167 | 168 | ### Prerequisites 169 | 170 | My preferred build system uses gcc tools, woven together with a 171 | Makefile. I normally work on Linux, so my setup would be 172 | 173 | ``` 174 | $ sudo apt install gcc-arm-none-eabi make 175 | ``` 176 | 177 | The code here is being built by make. Adapt to your build 178 | system as needed. 179 | 180 | ### For Generic ARM Processors 181 | 182 | We can build this library against a generic ARM Cortex M processor, 183 | i.e. one with no peripherals defined. To do so, we need some ARM 184 | header files relating to a generic ARM device, plus the CMSIS Core 185 | headers, i.e: 186 | 187 | ``` 188 | CMSIS_5/Device/ARM/ARMCM0/Include/*.h 189 | CMSIS_5/Device/ARM/ARMCM3/Include/*.h 190 | ... 191 | CMSIS_5/CMSIS/Core/Include/*.h 192 | ``` 193 | 194 | To build any test cases that use the library, we can also make use of ARM 195 | system and startup files, e.g. 196 | 197 | ``` 198 | CMSIS_5/Device/ARM/ARMCM3/Source/*.c 199 | CMSIS_5/Device/ARM/ARMCM3/Source/GCC/*.S, *.ld 200 | ``` 201 | 202 | Assuming that the source tree above is not already on your development 203 | system, grab it from ARM-software's GitHub repo, into some local 204 | directory C: 205 | 206 | ``` 207 | $ cd C 208 | $ git clone https://github.com/ARM-software/CMSIS_5.git 209 | 210 | ``` 211 | 212 | We have verified that tagged releases 5.8.0 and 5.9.0 are good to go 213 | for our purposes. Other releases are untested. So, you could checkout 214 | a particular commit, via e.g. 215 | 216 | ``` 217 | $ git checkout 5.8.0 ; git checkout 5.9.0 218 | ``` 219 | 220 | or just skip this step and go with the HEAD of master/main. 221 | 222 | Next, clone the fault-handler repo (the one whose README you are now 223 | reading), if not done so already, into some local location F: 224 | 225 | ``` 226 | $ cd F 227 | $ git clone https://github.com/tobermory/faultHandling-cortex-m.git 228 | ``` 229 | 230 | Next, edit the Makefile, setting the CMSIS_HOME variable to point to 231 | your ARM-software CMSIS_5 repo clone, e.g: 232 | 233 | ``` 234 | $ cd faultHandling-cortex-m 235 | $ ed Makefile 236 | 237 | CMSIS_HOME = /path/to/C/CMSIS_5 238 | ``` 239 | 240 | With all the prep work done, it should now be a case of just: 241 | 242 | ``` 243 | $ make 244 | ``` 245 | 246 | to go from this: 247 | 248 | ``` 249 | src/main 250 | ├── asm 251 | │   └── faultHandling_cm3.S 252 | ├── c 253 | │   ├── faultHandling.c 254 | └── include 255 | ├── faultHandling.h 256 | ``` 257 | 258 | to this: 259 | 260 | ``` 261 | libfaultHandling_CM3.a 262 | ``` 263 | 264 | 265 | By default, the build output is terse (uncluttered!). To see a bit more: 266 | 267 | ``` 268 | $ make clean 269 | $ make V=1 270 | ``` 271 | 272 | We include a make target that just prints important variables 273 | (VPATH, CPPFLAGS, etc): 274 | 275 | ``` 276 | $ make flags 277 | ``` 278 | 279 | A simple test case [noopProcessor.c](src/test/c/noopProcessor.c) is 280 | provided for a generic ARM Cortex-M processor. To build it: 281 | 282 | ``` 283 | $ make tests 284 | ``` 285 | 286 | should produce `noopProcessor.axf, noopProcessor.bin, noopProcessor.map, noopProcessor.lst`. 287 | 288 | ### Other Cortex M Variants 289 | 290 | Default build is for Cortex M3, my usual target. To build for other CPUs: 291 | 292 | ``` 293 | $ make clean 294 | $ make CM4=1 295 | $ make CM4=1 tests 296 | 297 | $ make clean 298 | $ make CM0=1 299 | $ make CM0=1 tests 300 | ``` 301 | 302 | ### For Vendor-Specific Micro-controllers 303 | 304 | I work with Cortex M micro-controllers from Silicon Labs, and below 305 | detail how to test this faultHandling api on those controllers. Adapt 306 | as necessary for other vendors, e.g. STM32, etc. 307 | 308 | I have two SiliconLabs starter kits upon which I can test this fault 309 | handling library: 310 | 311 | + The [EFM32GG-STK3700](https://www.silabs.com/development-tools/mcu/32-bit/efm32gg-starter-kit), which has a Cortex M3 Giant Gecko, with 1MB flash and 128kb RAM. 312 | 313 | + The [EFM32ZG-STK3200](https://www.silabs.com/development-tools/mcu/32-bit/efm32zg-starter-kit), which has a Cortex M0+ Zero Gecko, 32kb flash and just 4kb RAM. 314 | 315 | These boards have real peripherals, so we can truly export our fault 316 | dumps to e.g. a serial console. To make use of such peripherals, we 317 | just need SiliconLabs' hardware access layer (HAL), which they call 318 | *emlib*. We also want/need their Device files, which replace the ARM 319 | ones we built against in the previous section. 320 | 321 | SiliconLabs bundle their HAL layer (emlib), plus Device headers and 322 | CMSIS headers, in a GitHub repository called `gecko_sdk`. Decide on 323 | some local directory in which to clone it, we'll call it G: 324 | 325 | ``` 326 | $ cd G 327 | $ git clone https://github.com/SiliconLabs/gecko_sdk 328 | $ cd gecko_sdk 329 | ``` 330 | 331 | At time of writing (Mar 2024), the latest tag is v4.4.1. We have used 332 | that tag to build against, so 333 | 334 | ``` 335 | $ git checkout v4.4.1 336 | ``` 337 | 338 | or just use the HEAD of the gsdk_4.4 branch. 339 | 340 | The relevant gecko_sdk files we use here are 341 | 342 | ``` 343 | // for emlib 344 | platform/emlib/inc/*.h 345 | platform/emlib/src/*.c 346 | platform/common/inc/*.h 347 | 348 | // for the stk3700 (efm32gg) 349 | platform/Device/SiliconLabs/EFM32GG/Include/*.h 350 | platform/Device/SiliconLabs/EFM32GG/Source/*.c 351 | platform/Device/SiliconLabs/EFM32GG/Source/GCC/*.c, efm32gg.ld 352 | 353 | // for the stk3200 (efm32zg) 354 | platform/Device/SiliconLabs/EFM32ZG/Include/*.h 355 | platform/Device/SiliconLabs/EFM32ZG/Source/*.c 356 | platform/Device/SiliconLabs/EFM32ZG/Source/GCC/*.c, efm32zg.ld 357 | 358 | // for the CMSIS Core 359 | platform/CMSIS/Core/Include/*.h 360 | ``` 361 | 362 | With such a file layout, we can build our fault handling library AND 363 | some test cases that would run on those boards and produce real fault 364 | dumps exported via a serial console. 365 | 366 | Switch back to the clone of THIS repository, and proceed thus: 367 | 368 | ``` 369 | $ cd SiliconLabs 370 | 371 | $ ed silabs.mk 372 | GECKO_SDK = /path/to/G/gecko_sdk 373 | ``` 374 | i.e. the `GECKO_SDK` makefile variable matches the location of your 375 | SiliconLabs gecko_sdk clone. 376 | 377 | Then, to build the library and some test applications 378 | for the STK3700 starter board, so we can turn this: 379 | 380 | ``` 381 | src/test/c/*.c 382 | ``` 383 | 384 | to this: 385 | 386 | ``` 387 | SiliconLabs/stk3700/*.bin 388 | ``` 389 | 390 | we do this: 391 | 392 | ``` 393 | $ cd stk3700 394 | $ make flags 395 | $ make lib tests 396 | $ ls *.bin 397 | busFault.bin iaccviol.bin invstate.bin mpuFault.bin stackSmashing.bin 398 | ``` 399 | 400 | As well as the .bin file, we of course want the corresponding listing 401 | and map file, for these are what we cross-reference when analyzing a 402 | fault dump. These are built automatically: 403 | 404 | ``` 405 | $ ls busFault.* 406 | busFault.axf busFault.bin busFault.lst busFault.map 407 | ``` 408 | 409 | Similarly, we can build some test applications for the STK3200: 410 | 411 | ``` 412 | $ cd ../stk3200 413 | $ make lib tests 414 | $ ls *.bin 415 | iaccviol.bin invstate.bin stackSmashing.bin 416 | ``` 417 | 418 | See [stk3700.c](src/test/c/stk3700.c) and 419 | [stk3200.c](src/test/c/stk3200.c) for instructions on making use of a 420 | uart peripheral on each board (via the Expansion Header) to export our 421 | fault dumps to a host machine via serial/usb. 422 | 423 | The STK3700 and STK3200 boards have a Segger JLink debugger interface 424 | built in. So, you just need Segger's 'JLink Commander' tool (called 425 | JLinkExe on Linux) to flash these binaries to the boards and 426 | run them. Our Makefiles provide targets to do this, e.g: 427 | 428 | ``` 429 | $ cd SiliconLabs/stk3700/ 430 | 431 | $ make busFault.run 432 | ``` 433 | 434 | will invoke JLinkExe to flash `busFault.bin` to the STK3700 and run 435 | it. If your serial uart on the STK3700 is hooked up to a host machine, 436 | you can capture the exported-via-serial fault dump via something as 437 | simple as `cat`: 438 | 439 | ``` 440 | $ stty -F /dev/ttyUSB0 115200 -echo 441 | $ cat /dev/ttyUSB0 442 | 443 | $ make busFault.run 444 | ``` 445 | 446 | Should you ever need to actually (single-step) debug these test 447 | applications, and you have Segger's Ozone debugger installed, that too 448 | can be invoked via make, e.g. 449 | 450 | ``` 451 | $ make busFault.ozone 452 | ``` 453 | 454 | See [segger.mk](SiliconLabs/segger.mk) for details. 455 | 456 | 457 | ## Quiz - Match Faulting Code Against Dump 458 | 459 | Can you identify five faulting programs from their fault dumps? 460 | 461 | When built via the Makefiles included here and run on my SiliconLabs 462 | STK3700 starter board, the test applications make these 463 | mistakes (i.e. fault): 464 | 465 | + Access Violation - [iaccviol.c](src/test/c/iaccviol.c) 466 | 467 | + Invalid State - [invstate.c](src/test/c/invstate.c) 468 | 469 | + MPU Violation - [mpuFault.c](src/test/c/mpuFault.c) 470 | 471 | + Bus Fault - [busFault.c](src/test/c/busFault.c) 472 | 473 | + Stack Corruption - [stackSmashing.c](src/test/c/stackSmashing.c) 474 | 475 | 476 | Here are relevant code snippets, i.e. the source of the faults, in no particular order: 477 | 478 | ``` 479 | 1 480 | 481 | void (*p)(void) = (void(*)(void))((1LL << 32) - 1); 482 | p(); 483 | 484 | 2 485 | 486 | void (*p)(void) = (void(*)(void))0; 487 | p(); 488 | 489 | 3 490 | 491 | static void bar(void) { 492 | } 493 | 494 | static void foo(void) { 495 | uint32_t a[1]; 496 | bar(); 497 | a[0] = 0xCAFEBABE; 498 | a[1] = 0xDEADBEEF; 499 | a[2] = 0xCAFEBABE; 500 | a[3] = 0xDEADBEEF; 501 | } 502 | 503 | 4 504 | 505 | void (*p)(void) = (void(*)(void)) 0x20202020; 506 | p(); 507 | 508 | 5 509 | 510 | uint32_t rbar = ARM_MPU_RBAR( 0, 0 ); 511 | uint32_t rsar = ARM_MPU_RASR_EX( 0, ARM_MPU_AP_NONE, 512 | ARM_MPU_ACCESS_(0,0,1,0), 513 | 0, ARM_MPU_REGION_SIZE_32B ); 514 | ARM_MPU_SetRegion( rbar, rsar ); 515 | ARM_MPU_Enable( MPU_CTRL_PRIVDEFENA_Msk ); 516 | ... 517 | int* p = (int*)NULL; 518 | int i = *p; 519 | ``` 520 | 521 | which produce, in no particular order, these fault dump strings: 522 | 523 | ``` 524 | A 525 | 526 | r7 DEADBEEF 527 | sp 2001FFD8 528 | excrt FFFFFFF9 529 | psr 20000003 530 | hfsr 40000000 531 | cfsr 00000001 532 | mmfar E000ED34 533 | bfar E000ED38 534 | shcsr 00000000 535 | s.r0 4000C400 536 | s.r1 0000000A 537 | s.r2 0000000A 538 | s.r3 DEADBEEF 539 | s.r12 2000056A 540 | s.lr 00000267 541 | s.pc CAFEBABE 542 | s.psr 00000000 543 | 2001FFFC 0000016B 544 | 00000000 00000000 545 | 00000000 00000000 546 | 00000000 00000000 547 | 548 | B 549 | 550 | r7 2001FFF0 551 | sp 2001FFD0 552 | excrt FFFFFFF9 553 | psr 20000003 554 | hfsr 40000000 555 | cfsr 00000100 556 | mmfar E000ED34 557 | bfar E000ED38 558 | shcsr 00000000 559 | s.r0 00000000 560 | s.r1 00003588 561 | s.r2 200005D4 562 | s.r3 20202020 563 | s.r12 2000056A 564 | s.lr 0000022F 565 | s.pc 20202020 566 | s.psr 00000000 567 | 2001FFFC 0000016B 568 | 00000000 00000000 569 | 00000000 00000000 570 | 00000000 00000000 571 | 572 | C 573 | 574 | r7 2001FFD8 575 | sp 2001FFB8 576 | excrt FFFFFFF9 577 | psr 20000004 578 | hfsr 00000000 579 | cfsr 00000082 580 | mmfar 00000000 581 | bfar 00000000 582 | shcsr 00010001 583 | s.r0 00000004 584 | s.r1 00000000 585 | s.r2 E000ED00 586 | s.r3 00000000 587 | s.r12 2000056A 588 | s.lr 00000275 589 | s.pc 0000027A 590 | s.psr 41000000 591 | 2001FFD8 00000001 592 | 2001FFE4 00000001 593 | 2001FFE8 00000101 594 | 2001FFFC 0000016B 595 | 596 | D 597 | 598 | r7 2001FFF0 599 | sp 2001FFD0 600 | excrt FFFFFFF9 601 | psr 20000003 602 | hfsr 40000000 603 | cfsr 00000001 604 | mmfar E000ED34 605 | bfar E000ED38 606 | shcsr 00000000 607 | s.r0 00000000 608 | s.r1 00003698 609 | s.r2 200005DC 610 | s.r3 FFFFFFFF 611 | s.r12 20000572 612 | s.lr 00000303 613 | s.pc FFFFFFFE 614 | s.psr 01000000 615 | 2001FFFC 0000016B 616 | 00000000 00000000 617 | 00000000 00000000 618 | 00000000 00000000 619 | 620 | E 621 | 622 | r7 2001FFF0 623 | sp 2001FFD0 624 | excrt FFFFFFF9 625 | psr 20000003 626 | hfsr 40000000 627 | cfsr 00020000 628 | mmfar E000ED34 629 | bfar E000ED38 630 | shcsr 00000000 631 | s.r0 00000000 632 | s.r1 00003588 633 | s.r2 200005D4 634 | s.r3 00000000 635 | s.r12 2000056A 636 | s.lr 0000022D 637 | s.pc 00000000 638 | s.psr 40000000 639 | 2001FFFC 0000016B 640 | 00000000 00000000 641 | 00000000 00000000 642 | 00000000 00000000 643 | ``` 644 | 645 | Which is which? Answers on a postcard... 646 | 647 | ## Fault Guru 648 | 649 | Joking aside, we could collect all the heuristics we use when 650 | identifying faulting source code from its register dump and create 651 | some kind of 'fault guru' program. You feed the guru a fault dump and 652 | it tells you what happened, and perhaps even suggests a code fix. 653 | Something along the lines of 654 | 655 | ``` 656 | $ faultGuru myFaultDumpString.txt 657 | 658 | 1: lr[3] = 1 : Fault occurred in Thread Mode 659 | 2: lr[2] = 1 : Fault occurred on Process Stack - RTOS likely present 660 | 3: hfsr[30] = 1 : Fault escalated from Usage/Bus/MemManage 661 | 4: etc etc 662 | ``` 663 | 664 | My own guru, a work-in-progress, is [here](src/test/c/faultGuru.c). 665 | 666 | ## Related Work 667 | 668 | * Fault analysis by the folks at [memfault](https://interrupt.memfault.com/blog/cortex-m-fault-debug) 669 | 670 | * Fault exceptions app note by [keil](https://www.keil.com/appnotes/files/apnt209.pdf) 671 | 672 | --- 673 | 674 | For other work of mine, see [here](https://github.com/tobermory). 675 | 676 | sdmaclean AT jeemale 677 | 678 | 679 | -------------------------------------------------------------------------------- /SiliconLabs/efm32gg.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright © 2022 Stuart Maclean 3 | # 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are 8 | # met: 9 | # 10 | # * Redistributions of source code must retain the above copyright 11 | # notice, this list of conditions and the following disclaimer. 12 | # 13 | # * Redistributions in binary form must reproduce the above 14 | # copyright notice, this list of conditions and the following 15 | # disclaimer in the documentation and/or other materials provided 16 | # with the distribution. 17 | # 18 | # * Neither the name of the copyright holder nor the names of its 19 | # contributors may be used to endorse or promote products derived 20 | # from this software without specific prior written permission. 21 | # 22 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | # HOLDER NOR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 29 | # OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 31 | # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 32 | # USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 33 | # DAMAGE. 34 | # 35 | 36 | # GECKO_SDK defined in ./silabs.mk 37 | 38 | CMSIS_device_header = em_device.h 39 | 40 | DEVICE = $(GECKO_SDK)/platform/Device/SiliconLabs/EFM32GG 41 | 42 | CPPFLAGS += -I$(DEVICE)/Include 43 | 44 | VPATH += $(DEVICE)/Source $(DEVICE)/Source/GCC 45 | 46 | DEVICE_SRCS = system_efm32gg.c startup_efm32gg.c 47 | 48 | LDSCRIPT = $(DEVICE)/Source/GCC/efm32gg.ld 49 | 50 | CPPFLAGS += -I$(GECKO_SDK)/platform/CMSIS/Core/Include 51 | 52 | # eof 53 | -------------------------------------------------------------------------------- /SiliconLabs/efm32zg.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright © 2022 Stuart Maclean 3 | # 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are 8 | # met: 9 | # 10 | # * Redistributions of source code must retain the above copyright 11 | # notice, this list of conditions and the following disclaimer. 12 | # 13 | # * Redistributions in binary form must reproduce the above 14 | # copyright notice, this list of conditions and the following 15 | # disclaimer in the documentation and/or other materials provided 16 | # with the distribution. 17 | # 18 | # * Neither the name of the copyright holder nor the names of its 19 | # contributors may be used to endorse or promote products derived 20 | # from this software without specific prior written permission. 21 | # 22 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | # HOLDER NOR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 29 | # OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 31 | # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 32 | # USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 33 | # DAMAGE. 34 | # 35 | 36 | # GECKO_SDK_SUITE defined in ./silabs.mk 37 | 38 | CMSIS_device_header = em_device.h 39 | 40 | DEVICE = $(GECKO_SDK)/platform/Device/SiliconLabs/EFM32ZG 41 | 42 | CPPFLAGS += -I$(DEVICE)/Include 43 | 44 | VPATH += $(DEVICE)/Source $(DEVICE)/Source/GCC 45 | 46 | DEVICE_SRCS = system_efm32zg.c startup_efm32zg.c 47 | 48 | LDSCRIPT = $(DEVICE)/Source/GCC/efm32zg.ld 49 | 50 | CPPFLAGS += -I$(GECKO_SDK)/platform/CMSIS/Core/Include 51 | 52 | # eof 53 | 54 | -------------------------------------------------------------------------------- /SiliconLabs/segger.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright © 2022 Stuart Maclean 3 | # 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are 8 | # met: 9 | # 10 | # * Redistributions of source code must retain the above copyright 11 | # notice, this list of conditions and the following disclaimer. 12 | # 13 | # * Redistributions in binary form must reproduce the above 14 | # copyright notice, this list of conditions and the following 15 | # disclaimer in the documentation and/or other materials provided 16 | # with the distribution. 17 | # 18 | # * Neither the name of the copyright holder nor the names of its 19 | # contributors may be used to endorse or promote products derived 20 | # from this software without specific prior written permission. 21 | # 22 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | # HOLDER NOR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 29 | # OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 31 | # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 32 | # USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 33 | # DAMAGE. 34 | # 35 | 36 | # make targets to invoke SEGGER tools JLinkExe (flashing) 37 | # and ozone (debugging). 38 | 39 | # To flash and run a program called foo (i.e. its binary is foo.bin): 40 | 41 | # make foo.run 42 | 43 | # To debug a program called foo (i.e. its binary is foo.bin): 44 | 45 | # make foo.ozone 46 | 47 | JLINK = JLinkExe 48 | 49 | RUNS = $(addsuffix .run, $(TESTS)) 50 | 51 | $(RUNS) : %.run : %.jlink %.bin 52 | $(JLINK) $< 53 | 54 | %.jlink: 55 | -$(RM) $@ 56 | @echo if SWD >> $@ 57 | @echo device $(PART_NUMBER) >> $@ 58 | @echo speed 1000 >> $@ 59 | @echo loadfile $*.bin >> $@ 60 | @echo rnh >> $@ 61 | @echo q >> $@ 62 | 63 | .PHONY: $(RUNS) 64 | 65 | OZONE = ozone 66 | 67 | OZONES = $(addsuffix .ozone, $(TESTS)) 68 | 69 | %.jdebug : ozone.jdebug.in 70 | @echo SED $(@F) 71 | @cp $< $@ 72 | $(ECHO)sed -i 's/DEVICE/$(PART_NUMBER)/g' $@ 73 | $(ECHO)sed -i 's/PROGRAM/$*.axf/g' $@ 74 | 75 | $(OZONES) : %.ozone: %.axf %.jdebug 76 | $(OZONE) $*.jdebug 77 | 78 | %.ozone: CFLAGS += -g -gdwarf-2 -O0 79 | 80 | .PHONY: $(OZONES) 81 | -------------------------------------------------------------------------------- /SiliconLabs/silabs.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright © 2022 Stuart Maclean 3 | # 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are 8 | # met: 9 | # 10 | # * Redistributions of source code must retain the above copyright 11 | # notice, this list of conditions and the following disclaimer. 12 | # 13 | # * Redistributions in binary form must reproduce the above 14 | # copyright notice, this list of conditions and the following 15 | # disclaimer in the documentation and/or other materials provided 16 | # with the distribution. 17 | # 18 | # * Neither the name of the copyright holder nor the names of its 19 | # contributors may be used to endorse or promote products derived 20 | # from this software without specific prior written permission. 21 | # 22 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | # HOLDER NOR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 29 | # OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 31 | # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 32 | # USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 33 | # DAMAGE. 34 | # 35 | 36 | # Replace this with where you cloned the SiliconLabs gecko_sdk repo to... 37 | GECKO_SDK ?= $(HOME)/projects/github-tobermory/gecko_sdk 38 | 39 | VENDOR = SiliconLabs 40 | 41 | EMLIB = $(GECKO_SDK)/platform/emlib 42 | 43 | COMMON = $(GECKO_SDK)/platform/common 44 | 45 | CPPFLAGS += -I$(EMLIB)/inc -I$(COMMON)/inc 46 | 47 | VPATH += $(EMLIB)/src 48 | 49 | # eof 50 | -------------------------------------------------------------------------------- /SiliconLabs/stk3200/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright © 2022 Stuart Maclean 3 | # 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are 8 | # met: 9 | # 10 | # * Redistributions of source code must retain the above copyright 11 | # notice, this list of conditions and the following disclaimer. 12 | # 13 | # * Redistributions in binary form must reproduce the above 14 | # copyright notice, this list of conditions and the following 15 | # disclaimer in the documentation and/or other materials provided 16 | # with the distribution. 17 | # 18 | # * Neither the name of the copyright holder nor the names of its 19 | # contributors may be used to endorse or promote products derived 20 | # from this software without specific prior written permission. 21 | # 22 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | # HOLDER NOR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 29 | # OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 31 | # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 32 | # USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 33 | # DAMAGE. 34 | # 35 | 36 | BASEDIR = $(abspath ../..) 37 | 38 | TESTS = invstate 39 | 40 | TESTS += iaccviol 41 | 42 | TESTS += stackSmashing 43 | 44 | PART_NUMBER = EFM32ZG222F32 45 | 46 | CPPFLAGS += -D$(PART_NUMBER) 47 | 48 | CM0=1 49 | 50 | include $(BASEDIR)/SiliconLabs/silabs.mk 51 | include $(BASEDIR)/SiliconLabs/efm32zg.mk 52 | include $(BASEDIR)/Makefile 53 | 54 | include $(BASEDIR)/SiliconLabs/segger.mk 55 | 56 | $(AXFS) : stk3200.o em_core.o em_cmu.o em_gpio.o em_system.o em_usart.o 57 | 58 | # eof 59 | -------------------------------------------------------------------------------- /SiliconLabs/stk3200/ozone.jdebug.in: -------------------------------------------------------------------------------- 1 | 2 | /********************************************************************* 3 | * 4 | * OnProjectLoad 5 | * 6 | * Function description 7 | * Project load routine. Required. 8 | * 9 | ********************************************************************** 10 | */ 11 | void OnProjectLoad (void) { 12 | // 13 | // Dialog-generated settings 14 | // 15 | Project.SetDevice ("DEVICE"); 16 | Project.SetHostIF ("USB", ""); 17 | Project.SetTargetIF ("SWD"); 18 | Project.SetTIFSpeed ("1 MHz"); 19 | Project.AddSvdFile ("$(ConfigDir)/CPU/Cortex-M3.svd"); 20 | Project.AddSvdFile ("$(ConfigDir)/Peripherals/DEVICE.svd"); 21 | // 22 | // User settings 23 | // 24 | File.Open ("PROGRAM"); 25 | } 26 | 27 | /********************************************************************* 28 | * 29 | * TargetReset 30 | * 31 | * Function description 32 | * Replaces the default target device reset routine. Optional. 33 | * 34 | * Notes 35 | * This example demonstrates the usage when 36 | * debugging a RAM program on a Cortex-M target device 37 | * 38 | ********************************************************************** 39 | */ 40 | //void TargetReset (void) { 41 | // 42 | // unsigned int SP; 43 | // unsigned int PC; 44 | // unsigned int VectorTableAddr; 45 | // 46 | // Exec.Reset(); 47 | // 48 | // VectorTableAddr = Elf.GetBaseAddr(); 49 | // 50 | // if (VectorTableAddr != 0xFFFFFFFF) { 51 | // 52 | // Util.Log("Resetting Program."); 53 | // 54 | // SP = Target.ReadU32(VectorTableAddr); 55 | // Target.SetReg("SP", SP); 56 | // 57 | // PC = Target.ReadU32(VectorTableAddr + 4); 58 | // Target.SetReg("PC", PC); 59 | // } 60 | //} 61 | 62 | /********************************************************************* 63 | * 64 | * BeforeTargetReset 65 | * 66 | * Function description 67 | * Event handler routine. Optional. 68 | * 69 | ********************************************************************** 70 | */ 71 | //void BeforeTargetReset (void) { 72 | //} 73 | 74 | /********************************************************************* 75 | * 76 | * AfterTargetReset 77 | * 78 | * Function description 79 | * Event handler routine. 80 | * - Sets the PC register to program reset value. 81 | * - Sets the SP register to program reset value on Cortex-M. 82 | * 83 | ********************************************************************** 84 | */ 85 | void AfterTargetReset (void) { 86 | unsigned int SP; 87 | unsigned int PC; 88 | unsigned int VectorTableAddr; 89 | 90 | VectorTableAddr = Elf.GetBaseAddr(); 91 | 92 | if (VectorTableAddr == 0xFFFFFFFF) { 93 | Util.Log("Project file error: failed to get program base"); 94 | } else { 95 | SP = Target.ReadU32(VectorTableAddr); 96 | Target.SetReg("SP", SP); 97 | 98 | PC = Target.ReadU32(VectorTableAddr + 4); 99 | Target.SetReg("PC", PC); 100 | } 101 | } 102 | 103 | /********************************************************************* 104 | * 105 | * DebugStart 106 | * 107 | * Function description 108 | * Replaces the default debug session startup routine. Optional. 109 | * 110 | ********************************************************************** 111 | */ 112 | //void DebugStart (void) { 113 | //} 114 | 115 | /********************************************************************* 116 | * 117 | * TargetConnect 118 | * 119 | * Function description 120 | * Replaces the default target IF connection routine. Optional. 121 | * 122 | ********************************************************************** 123 | */ 124 | //void TargetConnect (void) { 125 | //} 126 | 127 | /********************************************************************* 128 | * 129 | * BeforeTargetConnect 130 | * 131 | * Function description 132 | * Event handler routine. Optional. 133 | * 134 | ********************************************************************** 135 | */ 136 | //void BeforeTargetConnect (void) { 137 | //} 138 | 139 | /********************************************************************* 140 | * 141 | * AfterTargetConnect 142 | * 143 | * Function description 144 | * Event handler routine. Optional. 145 | * 146 | ********************************************************************** 147 | */ 148 | //void AfterTargetConnect (void) { 149 | //} 150 | 151 | /********************************************************************* 152 | * 153 | * TargetDownload 154 | * 155 | * Function description 156 | * Replaces the default program download routine. Optional. 157 | * 158 | ********************************************************************** 159 | */ 160 | //void TargetDownload (void) { 161 | //} 162 | 163 | /********************************************************************* 164 | * 165 | * BeforeTargetDownload 166 | * 167 | * Function description 168 | * Event handler routine. Optional. 169 | * 170 | ********************************************************************** 171 | */ 172 | //void BeforeTargetDownload (void) { 173 | //} 174 | 175 | /********************************************************************* 176 | * 177 | * AfterTargetDownload 178 | * 179 | * Function description 180 | * Event handler routine. 181 | * - Sets the PC register to program reset value. 182 | * - Sets the SP register to program reset value on Cortex-M. 183 | * 184 | ********************************************************************** 185 | */ 186 | void AfterTargetDownload (void) { 187 | unsigned int SP; 188 | unsigned int PC; 189 | unsigned int VectorTableAddr; 190 | 191 | VectorTableAddr = Elf.GetBaseAddr(); 192 | 193 | if (VectorTableAddr == 0xFFFFFFFF) { 194 | Util.Log("Project file error: failed to get program base"); 195 | } else { 196 | SP = Target.ReadU32(VectorTableAddr); 197 | Target.SetReg("SP", SP); 198 | 199 | PC = Target.ReadU32(VectorTableAddr + 4); 200 | Target.SetReg("PC", PC); 201 | } 202 | } 203 | 204 | /********************************************************************* 205 | * 206 | * BeforeTargetDisconnect 207 | * 208 | * Function description 209 | * Event handler routine. Optional. 210 | * 211 | ********************************************************************** 212 | */ 213 | //void BeforeTargetDisconnect (void) { 214 | //} 215 | 216 | /********************************************************************* 217 | * 218 | * AfterTargetDisconnect 219 | * 220 | * Function description 221 | * Event handler routine. Optional. 222 | * 223 | ********************************************************************** 224 | */ 225 | //void AfterTargetDisconnect (void) { 226 | //} 227 | 228 | /********************************************************************* 229 | * 230 | * AfterTargetHalt 231 | * 232 | * Function description 233 | * Event handler routine. Optional. 234 | * 235 | ********************************************************************** 236 | */ 237 | //void AfterTargetHalt (void) { 238 | //} 239 | -------------------------------------------------------------------------------- /SiliconLabs/stk3700/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright © 2022 Stuart Maclean 3 | # 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are 8 | # met: 9 | # 10 | # * Redistributions of source code must retain the above copyright 11 | # notice, this list of conditions and the following disclaimer. 12 | # 13 | # * Redistributions in binary form must reproduce the above 14 | # copyright notice, this list of conditions and the following 15 | # disclaimer in the documentation and/or other materials provided 16 | # with the distribution. 17 | # 18 | # * Neither the name of the copyright holder nor the names of its 19 | # contributors may be used to endorse or promote products derived 20 | # from this software without specific prior written permission. 21 | # 22 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | # HOLDER NOR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 29 | # OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 31 | # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 32 | # USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 33 | # DAMAGE. 34 | # 35 | 36 | BASEDIR = $(abspath ../..) 37 | 38 | TESTS = busFault invstate iaccviol stackSmashing mpuFault 39 | 40 | PART_NUMBER = EFM32GG990F1024 41 | 42 | CPPFLAGS += -D$(PART_NUMBER) 43 | 44 | CM3=1 45 | 46 | include $(BASEDIR)/SiliconLabs/silabs.mk 47 | include $(BASEDIR)/SiliconLabs/efm32gg.mk 48 | include $(BASEDIR)/Makefile 49 | 50 | include $(BASEDIR)/SiliconLabs/segger.mk 51 | 52 | $(AXFS) : stk3700.o em_core.o em_cmu.o em_gpio.o em_system.o em_usart.o 53 | 54 | #mpuFault.axf: em_mpu.o 55 | 56 | # eof 57 | 58 | -------------------------------------------------------------------------------- /SiliconLabs/stk3700/ozone.jdebug.in: -------------------------------------------------------------------------------- 1 | 2 | /********************************************************************* 3 | * 4 | * OnProjectLoad 5 | * 6 | * Function description 7 | * Project load routine. Required. 8 | * 9 | ********************************************************************** 10 | */ 11 | void OnProjectLoad (void) { 12 | // 13 | // Dialog-generated settings 14 | // 15 | Project.SetDevice ("DEVICE"); 16 | Project.SetHostIF ("USB", ""); 17 | Project.SetTargetIF ("SWD"); 18 | Project.SetTIFSpeed ("1 MHz"); 19 | Project.AddSvdFile ("$(ConfigDir)/CPU/Cortex-M3.svd"); 20 | Project.AddSvdFile ("$(ConfigDir)/Peripherals/DEVICE.svd"); 21 | // 22 | // User settings 23 | // 24 | File.Open ("PROGRAM"); 25 | } 26 | 27 | /********************************************************************* 28 | * 29 | * TargetReset 30 | * 31 | * Function description 32 | * Replaces the default target device reset routine. Optional. 33 | * 34 | * Notes 35 | * This example demonstrates the usage when 36 | * debugging a RAM program on a Cortex-M target device 37 | * 38 | ********************************************************************** 39 | */ 40 | //void TargetReset (void) { 41 | // 42 | // unsigned int SP; 43 | // unsigned int PC; 44 | // unsigned int VectorTableAddr; 45 | // 46 | // Exec.Reset(); 47 | // 48 | // VectorTableAddr = Elf.GetBaseAddr(); 49 | // 50 | // if (VectorTableAddr != 0xFFFFFFFF) { 51 | // 52 | // Util.Log("Resetting Program."); 53 | // 54 | // SP = Target.ReadU32(VectorTableAddr); 55 | // Target.SetReg("SP", SP); 56 | // 57 | // PC = Target.ReadU32(VectorTableAddr + 4); 58 | // Target.SetReg("PC", PC); 59 | // } 60 | //} 61 | 62 | /********************************************************************* 63 | * 64 | * BeforeTargetReset 65 | * 66 | * Function description 67 | * Event handler routine. Optional. 68 | * 69 | ********************************************************************** 70 | */ 71 | //void BeforeTargetReset (void) { 72 | //} 73 | 74 | /********************************************************************* 75 | * 76 | * AfterTargetReset 77 | * 78 | * Function description 79 | * Event handler routine. 80 | * - Sets the PC register to program reset value. 81 | * - Sets the SP register to program reset value on Cortex-M. 82 | * 83 | ********************************************************************** 84 | */ 85 | void AfterTargetReset (void) { 86 | unsigned int SP; 87 | unsigned int PC; 88 | unsigned int VectorTableAddr; 89 | 90 | VectorTableAddr = Elf.GetBaseAddr(); 91 | 92 | if (VectorTableAddr == 0xFFFFFFFF) { 93 | Util.Log("Project file error: failed to get program base"); 94 | } else { 95 | SP = Target.ReadU32(VectorTableAddr); 96 | Target.SetReg("SP", SP); 97 | 98 | PC = Target.ReadU32(VectorTableAddr + 4); 99 | Target.SetReg("PC", PC); 100 | } 101 | } 102 | 103 | /********************************************************************* 104 | * 105 | * DebugStart 106 | * 107 | * Function description 108 | * Replaces the default debug session startup routine. Optional. 109 | * 110 | ********************************************************************** 111 | */ 112 | //void DebugStart (void) { 113 | //} 114 | 115 | /********************************************************************* 116 | * 117 | * TargetConnect 118 | * 119 | * Function description 120 | * Replaces the default target IF connection routine. Optional. 121 | * 122 | ********************************************************************** 123 | */ 124 | //void TargetConnect (void) { 125 | //} 126 | 127 | /********************************************************************* 128 | * 129 | * BeforeTargetConnect 130 | * 131 | * Function description 132 | * Event handler routine. Optional. 133 | * 134 | ********************************************************************** 135 | */ 136 | //void BeforeTargetConnect (void) { 137 | //} 138 | 139 | /********************************************************************* 140 | * 141 | * AfterTargetConnect 142 | * 143 | * Function description 144 | * Event handler routine. Optional. 145 | * 146 | ********************************************************************** 147 | */ 148 | //void AfterTargetConnect (void) { 149 | //} 150 | 151 | /********************************************************************* 152 | * 153 | * TargetDownload 154 | * 155 | * Function description 156 | * Replaces the default program download routine. Optional. 157 | * 158 | ********************************************************************** 159 | */ 160 | //void TargetDownload (void) { 161 | //} 162 | 163 | /********************************************************************* 164 | * 165 | * BeforeTargetDownload 166 | * 167 | * Function description 168 | * Event handler routine. Optional. 169 | * 170 | ********************************************************************** 171 | */ 172 | //void BeforeTargetDownload (void) { 173 | //} 174 | 175 | /********************************************************************* 176 | * 177 | * AfterTargetDownload 178 | * 179 | * Function description 180 | * Event handler routine. 181 | * - Sets the PC register to program reset value. 182 | * - Sets the SP register to program reset value on Cortex-M. 183 | * 184 | ********************************************************************** 185 | */ 186 | void AfterTargetDownload (void) { 187 | unsigned int SP; 188 | unsigned int PC; 189 | unsigned int VectorTableAddr; 190 | 191 | VectorTableAddr = Elf.GetBaseAddr(); 192 | 193 | if (VectorTableAddr == 0xFFFFFFFF) { 194 | Util.Log("Project file error: failed to get program base"); 195 | } else { 196 | SP = Target.ReadU32(VectorTableAddr); 197 | Target.SetReg("SP", SP); 198 | 199 | PC = Target.ReadU32(VectorTableAddr + 4); 200 | Target.SetReg("PC", PC); 201 | } 202 | } 203 | 204 | /********************************************************************* 205 | * 206 | * BeforeTargetDisconnect 207 | * 208 | * Function description 209 | * Event handler routine. Optional. 210 | * 211 | ********************************************************************** 212 | */ 213 | //void BeforeTargetDisconnect (void) { 214 | //} 215 | 216 | /********************************************************************* 217 | * 218 | * AfterTargetDisconnect 219 | * 220 | * Function description 221 | * Event handler routine. Optional. 222 | * 223 | ********************************************************************** 224 | */ 225 | //void AfterTargetDisconnect (void) { 226 | //} 227 | 228 | /********************************************************************* 229 | * 230 | * AfterTargetHalt 231 | * 232 | * Function description 233 | * Event handler routine. Optional. 234 | * 235 | ********************************************************************** 236 | */ 237 | //void AfterTargetHalt (void) { 238 | //} 239 | -------------------------------------------------------------------------------- /cm0plus.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright © 2022 Stuart Maclean 3 | # 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are 8 | # met: 9 | # 10 | # * Redistributions of source code must retain the above copyright 11 | # notice, this list of conditions and the following disclaimer. 12 | # 13 | # * Redistributions in binary form must reproduce the above 14 | # copyright notice, this list of conditions and the following 15 | # disclaimer in the documentation and/or other materials provided 16 | # with the distribution. 17 | # 18 | # * Neither the name of the copyright holder nor the names of its 19 | # contributors may be used to endorse or promote products derived 20 | # from this software without specific prior written permission. 21 | # 22 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | # HOLDER NOR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 29 | # OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 31 | # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 32 | # USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 33 | # DAMAGE. 34 | # 35 | 36 | LIB = libfaultHandling_CM0.a 37 | 38 | LIB_ASM_SRCS = faultHandling_cm0.S 39 | 40 | # Set this mandatory CC setting here, NOT in CFLAGS, which the user 41 | # likes to control (warnings,debug,etc). 42 | CPU_OPTIONS += -mcpu=cortex-m0plus 43 | 44 | # eof 45 | -------------------------------------------------------------------------------- /cm3.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright © 2022 Stuart Maclean 3 | # 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are 8 | # met: 9 | # 10 | # * Redistributions of source code must retain the above copyright 11 | # notice, this list of conditions and the following disclaimer. 12 | # 13 | # * Redistributions in binary form must reproduce the above 14 | # copyright notice, this list of conditions and the following 15 | # disclaimer in the documentation and/or other materials provided 16 | # with the distribution. 17 | # 18 | # * Neither the name of the copyright holder nor the names of its 19 | # contributors may be used to endorse or promote products derived 20 | # from this software without specific prior written permission. 21 | # 22 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | # HOLDER NOR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 29 | # OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 31 | # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 32 | # USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 33 | # DAMAGE. 34 | # 35 | 36 | LIB = libfaultHandling_CM3.a 37 | 38 | LIB_ASM_SRCS = faultHandling_cm3.S 39 | 40 | # Set this mandatory CC setting here, NOT in CFLAGS, which the user 41 | # likes to control (warnings,debug,etc). 42 | CPU_OPTIONS += -mcpu=cortex-m3 43 | 44 | # eof 45 | -------------------------------------------------------------------------------- /cm4.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright © 2022 Stuart Maclean 3 | # 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are 8 | # met: 9 | # 10 | # * Redistributions of source code must retain the above copyright 11 | # notice, this list of conditions and the following disclaimer. 12 | # 13 | # * Redistributions in binary form must reproduce the above 14 | # copyright notice, this list of conditions and the following 15 | # disclaimer in the documentation and/or other materials provided 16 | # with the distribution. 17 | # 18 | # * Neither the name of the copyright holder nor the names of its 19 | # contributors may be used to endorse or promote products derived 20 | # from this software without specific prior written permission. 21 | # 22 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | # HOLDER NOR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 29 | # OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 31 | # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 32 | # USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 33 | # DAMAGE. 34 | # 35 | 36 | LIB = libfaultHandling_CM4.a 37 | 38 | # For purpose of CPU fault handling, CM4 equivalent to CM3 ?? 39 | LIB_ASM_SRCS = faultHandling_cm3.S 40 | 41 | # Set this mandatory CC setting here, NOT in CFLAGS, which the user 42 | # likes to control (warnings,debug,etc). 43 | CPU_OPTIONS += -mcpu=cortex-m4 44 | 45 | # eof 46 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 35 | 36 | 40 | 4.0.0 41 | 42 | 48 | 49 | tobermory 50 | CortexM-FaultHandling 51 | 1.0.0 52 | pom 53 | 54 | Structured Fault Handling for ARM Cortex-M Processors 55 | https://github.com/tobermory 56 | 57 | 58 | 59 | 60 | 2022 61 | 62 | 63 | 64 | 65 | 66 | 67 | tobermory 68 | Stuart Maclean 69 | sdmaclean@gmail.com 70 | 71 | 72 | 73 | 74 | 75 | BSD 3-Clause 76 | http://opensource.org/licenses/BSD-3-Clause 77 | See LICENSE.txt 78 | manual 79 | 80 | 81 | 82 | 83 | process-sources 84 | 85 | 86 | com.mycila 87 | license-maven-plugin 88 | 2.11 89 | 90 |
LICENSE.txt
91 | false 92 | true 93 |
94 | 95 | 96 | main 97 | process-sources 98 | 99 | format 100 | 101 | 102 | 103 | src/main/c/*.c 104 | src/main/include/*.h 105 | src/main/asm/*.S 106 | src/test/c/*.c 107 | **/Makefile 108 | **/*.mk 109 | 110 | 111 | SLASHSTAR_STYLE 112 | SCRIPT_STYLE 113 | SCRIPT_STYLE 114 | 115 | 116 | 117 | 118 |
119 |
120 |
121 |
122 | -------------------------------------------------------------------------------- /src/main/asm/faultHandling_cm0.S: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2022 Stuart Maclean 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are 8 | * met: 9 | * 10 | * * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above 14 | * copyright notice, this list of conditions and the following 15 | * disclaimer in the documentation and/or other materials provided 16 | * with the distribution. 17 | * 18 | * * Neither the name of the copyright holder nor the names of its 19 | * contributors may be used to endorse or promote products derived 20 | * from this software without specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | * HOLDER NOR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 29 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 31 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 32 | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 33 | * DAMAGE. 34 | */ 35 | // Called by HardFault_Handler, on CM0/CM0+ platforms, when 36 | // our 'structured fault handler' api is in use. 37 | 38 | .file "faultHandling_cm0.S" 39 | .syntax unified 40 | 41 | .thumb 42 | .section ".text" 43 | .align 2 44 | 45 | .thumb_func 46 | .type FaultHandler, %function 47 | .global FaultHandler 48 | .fnstart 49 | .cantunwind 50 | FaultHandler: 51 | 52 | // In order to call FaultHandler_C with r7, r13 (sp) and r14 (lr) 53 | // as parameters, in that order, we have to get those values 54 | // into r0, r1 and r2 respectively. sp may be MSP or PSP, which 55 | // is revealed by bit 2 of LR (EXC_RETURN). 56 | 57 | // Unlike the cm3 version, cm0/0+ doesn't have IT instruction, 58 | // so everything a bit more manual here. 59 | MOV R0,LR 60 | LSRS R0,R0,#3 61 | BCC MRS_MSP 62 | MRS R1, PSP 63 | B POST_MRS 64 | MRS_MSP: 65 | MRS R1, MSP 66 | POST_MRS: 67 | MOV R2, LR 68 | MOV R0, R7 69 | 70 | // Is it safe to just 'B FaultHandler_C'? The B range on CM0 is 71 | // only +-2046 bytes. If this fails, the LDR+BX will work. 72 | 73 | // Will it 'fail' at build/link time, or runtime? 74 | 75 | // The validity of the B must depend on WHERE FaultHandler_C sits 76 | // relative to this code, in the final binary?? 77 | // Since the two are built into the SAME .a file, with FaultHandler 78 | // preceding FaultHandler_C, the gap between 79 | // the two is only the handful of instructions above. 80 | 81 | // LDR R3,=FaultHandler_C 82 | // BX R3 83 | B FaultHandler_C 84 | 85 | .fnend 86 | .size FaultHandler, .-FaultHandler 87 | 88 | .end 89 | 90 | -------------------------------------------------------------------------------- /src/main/asm/faultHandling_cm3.S: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2022 Stuart Maclean 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are 8 | * met: 9 | * 10 | * * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above 14 | * copyright notice, this list of conditions and the following 15 | * disclaimer in the documentation and/or other materials provided 16 | * with the distribution. 17 | * 18 | * * Neither the name of the copyright holder nor the names of its 19 | * contributors may be used to endorse or promote products derived 20 | * from this software without specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | * HOLDER NOR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 29 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 31 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 32 | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 33 | * DAMAGE. 34 | */ 35 | // Called by HardFault_Handler, on CM3/4 platforms, when 36 | // our 'structured fault handler' api is in use. 37 | 38 | .file "faultHandling_cm3.S" 39 | .syntax unified 40 | 41 | .thumb 42 | .section ".text" 43 | .align 2 44 | 45 | .thumb_func 46 | .type FaultHandler, %function 47 | .global FaultHandler 48 | .fnstart 49 | .cantunwind 50 | FaultHandler: 51 | 52 | // In order to call FaultHandler_C with r7, r13 (sp) and r14 (lr) 53 | // as parameters, in that order, we have to get those values 54 | // into r0, r1 and r2 respectively. sp may be MSP or PSP, which 55 | // is revealed by bit 2 of LR (EXC_RETURN). 56 | 57 | TST LR, #4 58 | ITE EQ 59 | MRSEQ R1, MSP 60 | MRSNE R1, PSP 61 | MOV R2, LR 62 | MOV R0, R7 63 | B FaultHandler_C 64 | 65 | .fnend 66 | .size FaultHandler, .-FaultHandler 67 | 68 | .end 69 | 70 | -------------------------------------------------------------------------------- /src/main/c/faultHandling.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright © 2022 Stuart Maclean 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are 8 | * met: 9 | * 10 | * * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above 14 | * copyright notice, this list of conditions and the following 15 | * disclaimer in the documentation and/or other materials provided 16 | * with the distribution. 17 | * 18 | * * Neither the name of the copyright holder nor the names of its 19 | * contributors may be used to endorse or promote products derived 20 | * from this software without specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | * HOLDER NOR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 29 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 31 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 32 | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 33 | * DAMAGE. 34 | */ 35 | #include 36 | #include 37 | 38 | /** 39 | * @author Stuart Maclean 40 | 41 | Project-local headers we snarfed from 42 | CMSIS_5/Device/ARM/ARMCMX/Include/*.h. We need this for the 43 | definition of the SCB_Type struct and the SCB pointer, 44 | e.g. SCB->HFSR, etc. Contents of SCB vary by cm0, cm3, cm4. 45 | 46 | Each of these files includes the respective core_cmN.h. In each of 47 | those headers, __CORTEX_M is defined to be 0, 3, 4, etc. We'll use 48 | that define below, it's more standard than our own build process 49 | defines: __CORTEX_M3, etc. But our build process, e.g. make, must 50 | supply e.g. __CORTEX_M3, __CORTEX_M0PLUS, etc. 51 | */ 52 | 53 | 54 | #include "faultHandling.h" 55 | 56 | /** 57 | * @author Stuart Maclean 58 | * 59 | * Structured fault handling on the Cortex-M processor. 60 | * 61 | * When a fault occurs (HardFault or any of MemManage, BusFault, 62 | * UsageFault), our fault handler collects processor state, formats 63 | * that state into a 'fault dump table' in a human readable format, 64 | * then offers it to a pre-registered 'dump processor' function. 65 | 66 | * The formatted 'fault dump table' looks thus. First N lines are each 67 | * label+space+hexvalue, for N lines each holding one CPU 68 | * register. Following those is an optional call stack inference. On 69 | * CM3, a dump table looks like this: 70 | 71 | r7 2001FFF0 72 | sp 2001FFD0 73 | excrt FFFFFFF9 74 | psr 20000003 75 | hfsr 40000000 76 | cfsr 00020000 77 | mmfar E000ED34 78 | bfar E000ED38 79 | shcsr 00000000 80 | s.r0 00000002 81 | s.r1 0000000A 82 | s.r2 20000A3C 83 | s.r3 00000000 84 | s.r12 20000B38 85 | s.lr 000001AF 86 | s.pc 00000000 87 | s.psr 40000000 88 | 20000FE4 00000317 89 | 20000FEC 000002ED 90 | 20000FF4 000002AF 91 | 20000FFC 00000127 92 | 93 | * The call-stack pairs, of which there are 4 above, indicate where in 94 | * the ram the pushed LR was found, and the LR value itself. Combine 95 | * these values with the .map file for your faulting program (you do 96 | * HAVE the .map file right?) to derive the function call stack. 97 | 98 | * Some of the registers above are missing on CM0/0+ (no hfsr, etc). 99 | 100 | * The dump table is passed to the processor. The processor's job is 101 | * to decide what to DO with the dump: 102 | 103 | * Print to a 'console' 104 | * Saved to 'disk' 105 | * Stream to an overhead satellite (welcome to MY world) 106 | 107 | * After the processor is done, we take a course of action according 108 | * to caller's setup: return, loop, reset/reboot or 109 | * set-debug-breakpoint. 110 | * 111 | * To use this faultHandling api in an application, be sure to include 112 | * at LEAST the HardFault_Handler (given below) and optionally any 113 | * desired combo of MemManage, BusFault and UsageFault handlers (CM3/4). 114 | * These functions go in the program's Vector table, and override weak 115 | * versions supplied by the startup code. 116 | * 117 | * Then, to use this api, just call 3 routines early in main: 118 | * 119 | * 1 reserve a buffer and set a dump processor: 120 | * 121 | * char buf[FAULT_HANDLING_DUMP_SIZE]; 122 | * faultHandlingSetDumpProcessor( buf, myProcessor ); 123 | * 124 | * 2 (optional), if you want the fault handler to infer a call stack 125 | * leading up to the fault, supply .text section boundaries, an upper 126 | * limit on MSP (likely top-of-ram) and an upper limit of PSP 127 | * (if using rtos, if not, pass 0): 128 | 129 | * faultHandlingSetCallStackParameters( &Vectors, &__etext, &__StackTop, 0 ); 130 | * 131 | * The symbols Vectors, __etext, __StackTop are likely defined by your linker 132 | * script, and can be used in code. 133 | * 134 | * 3 finally, state what you want to occur at fault time: spin, reboot, return: 135 | * 136 | * faultHandlingSetPostFaultAction( REBOOT ); 137 | * 138 | * Now just wait for your program to blow up! 139 | 140 | * The dump processor is passed the 'fault table' at time of fault. 141 | * Processor might write to serial console, swo, to disk (?) or even 142 | * to RAM. In my apps, I have to beam the fault dump over Iridium SBD 143 | * from a remotely-deployed instrument! 144 | * 145 | * For examples, see swoTest.c, consoleTest.c, others in src/test/c 146 | * 147 | * We draw HEAVILY on Chap 12 of Yiu's 3rd ed of Cortex M3/M4 148 | * Definitive Guide, which should be considered a MUST-READ ;) 149 | * 150 | * Why include r7 in the dump? Well, the usual C function prolog (on 151 | * function entry) is 'push {r7,lr}', so that the function can itself 152 | * update these two regs and still get back to caller, via the usual 153 | * epilogs: 'pop {r7, lr}; bx lr' or the shorter 'pop {r7, pc}'. 154 | 155 | * If our fault is a bad PC, it may be due to the epilog encountering 156 | * a trashed stack location for the pushed lr. If we trashed the 157 | * pushed lr, we may have also trashed the adjacent pushed r7. If 158 | * fault dump values for r7, pc are same/related, it lends weight to 159 | * the notion that the fault is indeed due to stack smashing: 160 | 161 | int stackLocalVar[2]; 162 | 163 | stackLocalVar[2] = X; 164 | stackLocalVar[3] = Y; 165 | 166 | The two erroneous array accesses above may trash the prolog-pushed 167 | r7, lr, causing the fault to occur at function return (epilog). If r7 168 | shows X and pc (loaded from lr) shows Y, good bet stack corruption 169 | occurred. 170 | 171 | @see faultGuru.c for a tool that attempts to make sense of the fault 172 | table output. 173 | */ 174 | 175 | /* Total RAM space needed by fault handler api */ 176 | static char* dumpBuffer = NULL; 177 | static faultHandlingDumpProcessor dumpProcessor = NULL; 178 | static uint32_t startText, endText, mspTop, pspTop; 179 | static faultHandlingPostFaultAction postFaultAction = POSTHANDLER_LOOP; 180 | 181 | static void faultDumpPrepare(void); 182 | static void formatRegValue( faultHandlingRegIndex index, uint32_t value ); 183 | static void formatCallStackPair( int index, uint32_t addr, uint32_t val ); 184 | 185 | /* 186 | Our formatted 'fault dump table' of the N registers we are dumping 187 | is made up of 'label plus value', for each cpu register, plus some 188 | line-endings for pretty-printing purposes. 189 | 190 | Here we set up the entire multi-line string, with blanks for the reg 191 | values. Then, at fault time, we just 'fill in the holes' with 192 | what-went-wrong. A short header and footer markup the formatted 193 | text. 194 | */ 195 | 196 | void faultHandlingSetDumpProcessor( char* buf, faultHandlingDumpProcessor p ) { 197 | dumpBuffer = buf; 198 | dumpProcessor = p; 199 | faultDumpPrepare(); 200 | } 201 | 202 | /** 203 | * @param mspTop - Top of main stack, likely top of RAM. 204 | * 205 | * @param pspTop - only needed if running threads in an RTOS. 206 | * Otherwise, set to 0. 207 | */ 208 | void faultHandlingSetCallStackParameters( uint32_t* textLo, 209 | uint32_t* textHi, 210 | uint32_t* mspTop_, 211 | uint32_t* pspTop_ ) { 212 | startText = (uint32_t)textLo; 213 | endText = (uint32_t)textHi; 214 | mspTop = (uint32_t)mspTop_; 215 | pspTop = pspTop_ == 0 ? mspTop : (uint32_t)pspTop_; 216 | } 217 | 218 | void faultHandlingSetPostFaultAction( faultHandlingPostFaultAction pfa ) { 219 | postFaultAction = pfa; 220 | } 221 | 222 | /** 223 | * As per Yiu 3rd Ed, p 401. Other page numbers below refer to same text. 224 | * 225 | * @param r7 - frame pointer at time of fault (useful for 'pop 226 | * {r7,pc}' diagnosis, see above commentary?) 227 | * 228 | * @param stack - where the 8 stacked regs are found (is sp). 229 | * 230 | * @param excrt - exception return value in LR at time of fault. 231 | * 232 | * We've chosen to order the parameters passed by increasing reg 233 | * number: r7, r13 (sp), r14 (lr, which is excRet upon fault). This 234 | * ordering is arbitrary, but accommodates should we ever want to add 235 | * more regs. 236 | */ 237 | void FaultHandler_C( uint32_t r7, uint32_t* stack, uint32_t excRet ) { 238 | 239 | // NOT set up correctly if we have no processor! 240 | if( !dumpProcessor ) 241 | return; 242 | 243 | /* 244 | Vital SCB registers, give clues to the fault cause. SCB 245 | contents differ across CM platforms. 246 | */ 247 | 248 | #if (__CORTEX_M > 0) 249 | uint32_t hfsr = SCB->HFSR; 250 | uint32_t cfsr = SCB->CFSR; 251 | uint32_t bfar = SCB->BFAR; 252 | uint32_t mmfar = SCB->MMFAR; 253 | #endif 254 | 255 | // see p 264, indicates enabled handlers at time of fault 256 | uint32_t shcsr = SCB->SHCSR; 257 | 258 | /* 259 | On Cortex M (0,3,4), eight regs are stacked, see p 394. This is 260 | the (partial) state of the running program when the fault occured. 261 | */ 262 | uint32_t sp = (uint32_t)stack; 263 | uint32_t r0 = stack[0]; 264 | uint32_t r1 = stack[1]; 265 | uint32_t r2 = stack[2]; 266 | uint32_t r3 = stack[3]; 267 | uint32_t r12 = stack[4]; 268 | uint32_t lr = stack[5]; 269 | uint32_t pc = stack[6]; 270 | uint32_t psr = stack[7]; 271 | 272 | /* 273 | Current psr, contains IPSR [8..0] which tells us the active fault 274 | handler(hard, usage, etc). Always 3=HardFault on CM0/0+. 275 | */ 276 | uint32_t psrNow = __get_xPSR(); 277 | 278 | // For EXC_RETURN decoding, see p 278, and below 279 | formatRegValue( R7, r7 ); 280 | formatRegValue( SP, sp ); 281 | formatRegValue( EXCRT, excRet ); 282 | formatRegValue( PSR, psrNow ); 283 | 284 | #if (__CORTEX_M > 0) 285 | formatRegValue( HFSR, hfsr ); 286 | formatRegValue( CFSR, cfsr ); 287 | /* 288 | It is up to dump analyzer (e.g. our faultGuru.c) to determine, via 289 | cfsr bit masks, whether mmfar, bfar reg are valid. Our job is 290 | just to make them available! 291 | */ 292 | formatRegValue( MMFAR, mmfar ); 293 | formatRegValue( BFAR, bfar ); 294 | #endif 295 | 296 | formatRegValue( SHCSR, shcsr ); 297 | 298 | formatRegValue( STKR0, r0 ); 299 | formatRegValue( STKR1, r1 ); 300 | formatRegValue( STKR2, r2 ); 301 | formatRegValue( STKR3, r3 ); 302 | formatRegValue( STKR12, r12 ); 303 | formatRegValue( STKLR, lr ); 304 | formatRegValue( STKPC, pc ); 305 | formatRegValue( STKPSR, psr ); 306 | 307 | 308 | 309 | /* 310 | Heuristics to locate the function call stack leading up to the 311 | fault. We basically search the stack (starting at the addr above 312 | the stacked regs) until we've found N values that may be pushed LR 313 | regs, or until we reach some TopOfStack limit. 314 | 315 | In an application w RTOS, we'd likely have threads that use their 316 | own Process stack. In that case, would be better to terminate the 317 | search when see an LR = osThreadExit, rather than when hitting 318 | __StackTop (which would likely be a LONG way from a Process 319 | Stack). IDEA: can test LR to see if Process Stack is the one we are 320 | searching, same way that asm code did to LOCATE that stack. 321 | */ 322 | if( endText > 0 ) { 323 | int found = 0; 324 | 325 | /* 326 | 8 regs are stacked prior to fault handler entry, so start 327 | the 'pushed LR's search above those. 328 | 329 | Depending on the stack in use at time of fault, we use 330 | the mspTop or pspTop sentinel to bound the stack search. 331 | */ 332 | uint32_t TOS = excRet & 4 ? pspTop : mspTop; 333 | 334 | for( uint32_t* fp = stack + 8; fp < (uint32_t*)TOS; fp++ ) { 335 | 336 | uint32_t val = *fp; 337 | 338 | /* 339 | Code section is bounded by these two addresses. Any LR would 340 | be within that range. 341 | */ 342 | if( val < (uint32_t)startText || val > (uint32_t)endText ) 343 | continue; 344 | 345 | // On M3, pc[0] == 1, so any LR must have this property too. 346 | if( (val & 1) == 0 ) 347 | continue; 348 | 349 | // Deem that this word is indeed a 'pushed LR'. 350 | formatCallStackPair( found, (uint32_t)fp, val ); 351 | 352 | // Found as many as we want, or have ROOM for in the dump table ? 353 | found++; 354 | if( found == FAULT_HANDLING_CALLSTACK_ENTRIES ) 355 | break; 356 | } 357 | } 358 | 359 | // The fault table is now complete, ship it out the door! 360 | dumpProcessor(); 361 | 362 | // Once the fault packaged up and offered to processor, what do we do next? 363 | switch( postFaultAction ) { 364 | 365 | case POSTHANDLER_LOOP: 366 | while(2) 367 | ; 368 | break; 369 | 370 | case POSTHANDLER_RESET: 371 | NVIC_SystemReset(); 372 | break; 373 | 374 | case POSTHANDLER_DEBUG: 375 | #define DEBUG_BREAK __asm__("BKPT #0") 376 | DEBUG_BREAK; 377 | break; 378 | 379 | case POSTHANDLER_RETURN: 380 | break; 381 | 382 | default: 383 | ; 384 | } 385 | } 386 | 387 | 388 | 389 | /************************ STATICS, PRIVATE IMPLEMENTATION *****************/ 390 | 391 | static const char* const cpuRegLabels[] = 392 | { "r7 ", 393 | "sp ", 394 | "excrt", 395 | "psr ", 396 | #if (__CORTEX_M > 0) 397 | "hfsr ", 398 | "cfsr ", 399 | "mmfar", 400 | "bfar ", 401 | #endif 402 | "shcsr", 403 | "s.r0 ", 404 | "s.r1 ", 405 | "s.r2 ", 406 | "s.r3 ", 407 | "s.r12", 408 | "s.lr ", 409 | "s.pc ", 410 | "s.psr" 411 | }; 412 | 413 | static void faultDumpPrepare(void) { 414 | 415 | int cursor = 0; 416 | 417 | // N cpu registers 418 | for( int i = 0; i < FAULT_HANDLING_CPUREG_COUNT; i++ ) { 419 | // Each line of output is '5-char-LABEL 8-char-VALUE\r\n' = 16 chars 420 | 421 | // The label and space char: 0..5 422 | strcpy( dumpBuffer + cursor, cpuRegLabels[i] ); 423 | dumpBuffer[cursor+5] = ' '; 424 | 425 | // The hole for hex-formatted reg value is [6]..[13] 426 | 427 | // The eol 428 | dumpBuffer[cursor+14] = '\n'; 429 | // faultTable[cursor+15] = '\n'; 430 | 431 | // next 'row' 432 | cursor += FAULT_HANDLING_CPUREG_ROWSIZE; 433 | } 434 | 435 | /* 436 | Call stack leading to the fault. Each line is '8-char-ADDR 437 | 8-char-VALUE\n' = 18 chars, 4 lines total. 438 | */ 439 | for( int i = 0; i < FAULT_HANDLING_CALLSTACK_ENTRIES; i++ ) { 440 | dumpBuffer[cursor+8] = ' '; 441 | dumpBuffer[cursor+17] = '\n'; 442 | formatCallStackPair( i, 0, 0 ); 443 | cursor += FAULT_HANDLING_CALLSTACK_ROWSIZE; 444 | } 445 | 446 | // Trailing NULL, final byte in the fault dump. 447 | dumpBuffer[cursor] = 0; 448 | } 449 | 450 | 451 | 452 | /* 453 | Overkill to call sprintf when we have ONE value we know we want 454 | HEX formatted, so do it locally, a nibble at a time ;) 455 | */ 456 | static char hex[16] = { '0', '1', '2', '3', 457 | '4', '5', '6', '7', 458 | '8', '9', 'A', 'B', 459 | 'C', 'D', 'E', 'F' }; 460 | 461 | /** 462 | * Format one register value into the fault table string 463 | */ 464 | static void formatRegValue( faultHandlingRegIndex index, uint32_t value ) { 465 | 466 | /* 467 | Locate the 8-char hole for this reg value in the fault dump 468 | string, index identifies the 'row'. 469 | */ 470 | int cursor = 15*index + 6; 471 | 472 | /* and fill it in with hex-encoded reg value */ 473 | for( int i = 0; i < 8; i++ ) { 474 | uint32_t nibble = (value >> (28-4*i)) & 0xf; 475 | dumpBuffer[cursor+i] = hex[nibble]; 476 | } 477 | } 478 | 479 | static void formatCallStackPair( int index, uint32_t addr, uint32_t val ) { 480 | 481 | /* 482 | Locate the 2 8-char holes in the fault table string part reserved for 483 | call stack info, index identifies the 'row'. 484 | */ 485 | int cursor = FAULT_HANDLING_CPUREG_ROWSIZE*FAULT_HANDLING_CPUREG_COUNT + 486 | FAULT_HANDLING_CALLSTACK_ROWSIZE*index; 487 | 488 | /* and fill it in with hex-encoded reg values */ 489 | for( int i = 0; i < 8; i++ ) { 490 | uint32_t nibbleA = (addr >> (28-4*i)) & 0xf; 491 | uint32_t nibbleV = (val >> (28-4*i)) & 0xf; 492 | dumpBuffer[cursor+i] = hex[nibbleA]; 493 | dumpBuffer[cursor+9+i] = hex[nibbleV]; 494 | } 495 | } 496 | 497 | /************************ END PRIVATE IMPLEMENTATION *****************/ 498 | 499 | /** 500 | * We include FOUR fault handlers for reference here. ALL vector to 501 | * our asm FaultHandler above. 502 | 503 | * The HardFault_Handler MUST be copied to an application source file. 504 | * It will NOT be picked up by the linker if ONLY located in here in 505 | * libfaultHandling.a! 506 | * 507 | * The other three handlers are useful if you want to know the EXACT 508 | * fault type. Without these, the fault dump will show psr[8..0] = 3 509 | * (HardFault) and show 'escalated' fault (hfsr[30] = 1) but you won't 510 | * know WHICH fault was escalated. All three handlers vector 511 | * immediately to our FaultHandler. 512 | * 513 | * To enable these faults also require application set-up: 514 | * 515 | * SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk; // MemManage faults 516 | * 517 | * SCB->SHCSR |= SCB_SHCSR_BUSFAULTENA_Msk; // BusFault faults 518 | * 519 | * SCB->SHCSR |= SCB_SHCSR_USGFAULTENA_Msk; // UsageFault faults 520 | * 521 | * If you enable any of the three faults as above, you MUST copy in to 522 | * your application the corresponding handler below. Otherwise, 523 | * you'll get the startup code's DefaultHandler, which is often 524 | * while-1, and none of the above fault handling will occur. 525 | */ 526 | 527 | #if 0 528 | 529 | __attribute__((naked)) 530 | void HardFault_Handler(void) { 531 | __asm__( "B FaultHandler\n" ); 532 | } 533 | 534 | __attribute__((naked)) 535 | void MemManage_Handler(void) { 536 | __asm__( "B FaultHandler\n" ); 537 | } 538 | 539 | __attribute__((naked)) 540 | void BusFault_Handler(void) { 541 | __asm__( "B FaultHandler\n" ); 542 | } 543 | 544 | __attribute__((naked)) 545 | void UsageFault_Handler(void) { 546 | __asm__( "B FaultHandler\n" ); 547 | } 548 | 549 | #endif 550 | 551 | // eof 552 | -------------------------------------------------------------------------------- /src/main/include/faultHandling.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright © 2022 Stuart Maclean 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are 8 | * met: 9 | * 10 | * * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above 14 | * copyright notice, this list of conditions and the following 15 | * disclaimer in the documentation and/or other materials provided 16 | * with the distribution. 17 | * 18 | * * Neither the name of the copyright holder nor the names of its 19 | * contributors may be used to endorse or promote products derived 20 | * from this software without specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | * HOLDER NOR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 29 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 31 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 32 | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 33 | * DAMAGE. 34 | */ 35 | #ifndef CORTEXM_FAULT_HANDLING_H 36 | #define CORTEXM_FAULT_HANDLING_H 37 | 38 | #include 39 | 40 | /** 41 | Define CMSIS_device_header in your build tool/IDE. For example, 42 | in a Makefile, you'd do e.g. 43 | 44 | CPPFLAGS += -DCMSIS_device_header = \"myDevice.h\" 45 | 46 | We did not invent this approach. ARM use it for their RTOS2/RTX 47 | builds. 48 | */ 49 | #include CMSIS_device_header 50 | 51 | /** 52 | * @author Stuart Maclean 53 | * 54 | * Structured fault handling on the Cortex-M processor. See 55 | * faultHandling.c for more details. 56 | * 57 | * @see faultHandling.c 58 | */ 59 | 60 | /** 61 | * What to do after the fault dump is populated and sent to the dump 62 | * processor. 63 | */ 64 | typedef enum { POSTHANDLER_LOOP, 65 | POSTHANDLER_RESET, 66 | POSTHANDLER_DEBUG, 67 | POSTHANDLER_RETURN } faultHandlingPostFaultAction; 68 | 69 | 70 | /** 71 | * This next typedef for documentation purposes only. Currently, we 72 | * have no use for this type. It lists the registers included in 73 | * the dump, for CM0, CM3/4. 74 | */ 75 | typedef struct { 76 | uint32_t r7; // aka frame-pointer fp 77 | uint32_t sp; 78 | uint32_t excrt; 79 | #if (__CORTEX_M > 0) 80 | uint32_t hfsr; 81 | uint32_t cfsr; 82 | uint32_t mmfar; 83 | uint32_t bfar; 84 | #endif 85 | uint32_t shcsr; 86 | 87 | // The 8 stacked registers, always pushed to MSP/PSP on fault. 88 | uint32_t stkr0; 89 | uint32_t stkr1; 90 | uint32_t stkr2; 91 | uint32_t stkr3; 92 | uint32_t stkr12; 93 | uint32_t stklr; 94 | uint32_t stkpc; 95 | uint32_t stkpsr; 96 | 97 | } faultHandlingRegSet; 98 | 99 | /* 100 | An enum of the registers we are dumping. Note how the final element, 101 | FAULTHANDLING_CPUREG_COUNT, gives us the count we need in the processing. 102 | */ 103 | typedef enum { R7=0, 104 | SP, 105 | EXCRT, 106 | PSR, 107 | #if (__CORTEX_M > 0) 108 | HFSR, 109 | CFSR, 110 | MMFAR, 111 | BFAR, 112 | #endif 113 | SHCSR, 114 | STKR0, 115 | STKR1, 116 | STKR2, 117 | STKR3, 118 | STKR12, 119 | STKLR, 120 | STKPC, 121 | STKPSR, 122 | FAULT_HANDLING_CPUREG_COUNT } faultHandlingRegIndex; 123 | 124 | #define FAULT_HANDLING_CALLSTACK_ENTRIES (4) 125 | 126 | /* 127 | The formatted fault dump (see faultHandling.c) has N 15-byte 128 | records, for the N regs above, then 4 18-byte records for call stack 129 | info, and a final NULL byte at end. Total size 328 bytes (CM3), which 130 | just fits in an Iridium SBD message! 131 | 132 | We define the size, 'FAULT_HANDLING_DUMP_SIZE', here so that 133 | application 'dump processors' can allocate a char[] of correct 134 | length to hold such a dump, e.g. 135 | 136 | char dumpBuffer[FAULT_HANDLING_DUMP_SIZE]; 137 | */ 138 | 139 | /* 140 | A formatted CPU reg value 'row' is 141 | 142 | label/5 + space/1 + value/8 + eol/1 143 | */ 144 | #define FAULT_HANDLING_CPUREG_ROWSIZE (15) 145 | 146 | /* 147 | A formatted 'pushed LR' value 'row' is 148 | 149 | addr/8 + space/1 + value/8 + eol/1 150 | */ 151 | #define FAULT_HANDLING_CALLSTACK_ROWSIZE (18) 152 | 153 | /* 154 | The complete fault dump is then the cpu reg rows and the pushed LR 155 | rows, plus a trailing NULL byte (making the dump a valid C string). 156 | */ 157 | #define FAULT_HANDLING_DUMP_SIZE (FAULT_HANDLING_CPUREG_COUNT*\ 158 | FAULT_HANDLING_CPUREG_ROWSIZE+\ 159 | FAULT_HANDLING_CALLSTACK_ENTRIES*\ 160 | FAULT_HANDLING_CALLSTACK_ROWSIZE+1) 161 | 162 | typedef void(*faultHandlingDumpProcessor)(void); 163 | 164 | /** 165 | * Install the fault dump processor. It is called if/when a fault occurs. 166 | */ 167 | void faultHandlingSetDumpProcessor( char* dumpBuffer, 168 | faultHandlingDumpProcessor dumpProcessor ); 169 | 170 | /** 171 | * Set the bounds for the 'pushed LR' search, i.e. the 'function call 172 | * stack'. 173 | * 174 | * Any pushed LR will lie in the bounds of 'text_start' to 'text_end', 175 | * use these if your linker script defines them. If no text_start 176 | * symbol, approximate that with __Vectors_End or even __Vectors.. If 177 | * that not available either, just use 4, or the offset for which the 178 | * application was built (non-zero if bootloader present). Do NOT use 179 | * 0. 180 | * 181 | * These bounds for text (code) will be incorrect if you have 182 | * RAMFUNCS, and the search will miss (not identify) pushed LRs in 183 | * this case. 184 | * 185 | * @param textLo - lowest address that could contain code, must be > 0. 186 | * 187 | * @param textHi - highest address that could contain code. 188 | * 189 | * @param mspTop - top of main stack. Likely there is a 190 | * linker-script-defined variable that the application can use for 191 | * this parameter, for GNU .ld files this is typically '__StackTop'. 192 | * 193 | * @param pspTop - top of process stack. Application should pass 0 if 194 | * not using the process stack. 0 can be passed also if the 195 | * application just doesn't know a good value for top of process 196 | * stack. We will just use mspTop. 197 | * 198 | * Only threads, under an RTOS, would use the process stack. Not 199 | * trivial to locate the top of this 'thread stacks' area. Address of 200 | * '__bss_end__' (GNU linker scripts) is a pessimistic approximation, 201 | * but still better (i.e. lower address) than mspTop. 202 | */ 203 | 204 | void faultHandlingSetCallStackParameters( uint32_t* textLo, 205 | uint32_t* textHi, 206 | uint32_t* mspTop, 207 | uint32_t* pspTop ); 208 | 209 | /** 210 | * Set what to do after the fault dump is delivered to the dump processor. 211 | */ 212 | void faultHandlingSetPostFaultAction( faultHandlingPostFaultAction ); 213 | 214 | /** 215 | Needed by application fault handlers (asm), e.g. 216 | 217 | __attribute__((naked)) 218 | void HardFault_Handler(void) { 219 | __asm__( "B FaultHandler\n" ); 220 | } 221 | 222 | It MUST be a simple branch (B), i.e. a jump, and NOT a branch+link 223 | (BL), i.e. NOT a call. 224 | */ 225 | 226 | void FaultHandler(void); 227 | 228 | #endif 229 | 230 | // eof 231 | -------------------------------------------------------------------------------- /src/test/c/branchZero.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright © 2022 Stuart Maclean 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are 8 | * met: 9 | * 10 | * * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above 14 | * copyright notice, this list of conditions and the following 15 | * disclaimer in the documentation and/or other materials provided 16 | * with the distribution. 17 | * 18 | * * Neither the name of the copyright holder nor the names of its 19 | * contributors may be used to endorse or promote products derived 20 | * from this software without specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | * HOLDER NOR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 29 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 31 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 32 | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 33 | * DAMAGE. 34 | */ 35 | #include 36 | 37 | #include "faultHandling.h" 38 | 39 | #include "em_chip.h" 40 | #include "em_cmu.h" 41 | #include "em_gpio.h" 42 | #include "em_usart.h" 43 | 44 | /** 45 | * @author Stuart Maclean 46 | * 47 | * Fault capture using the faultHandling api, where the processing of 48 | * the fault is to 'export the fault dump' by writing it to a uart on 49 | * the SiliconLabs STK3700 starter kit. The STK3700 uses an 50 | * EFM32GG990F1024 cpu. 51 | * 52 | * We are viewing that uart as the 'serial console' of that board, so 53 | * the dump export is as close to a 'printf' as such a board can 54 | * mimic. 55 | 56 | * On the STK3700, Expansion Header pin 4 (USART1 Tx) is PD0 while pin 57 | * 6 (USART1 Rx) is PD1. These pins are route/location 1 for that 58 | * USART. See the STK3700 data sheet. 59 | 60 | * Hook up a ttl-usb cable to your host, and open e.g. minicom (or 61 | * just cat!) at 115200 and see the fault dump appear as the stk3700 62 | * end keels over with a fault! 63 | */ 64 | 65 | /** 66 | * Prepare the stk3700's cmu, gpio and usart peripherals so that we 67 | * have a 'serial console' to which we can write a fault dump when one 68 | * occurs. This is all typical emlib stuff. 69 | */ 70 | static void initConsole(void) { 71 | 72 | CMU_OscillatorEnable( cmuOsc_HFXO, true, true ); 73 | CMU_ClockSelectSet( cmuClock_HF, cmuSelect_HFXO ); 74 | 75 | // needed? 76 | CMU_ClockEnable( cmuClock_HFPER, true ); 77 | 78 | CMU_ClockEnable( cmuClock_GPIO, true ); 79 | GPIO_PinModeSet( gpioPortD, 0, gpioModePushPull, 1 ); 80 | GPIO_PinModeSet( gpioPortD, 1, gpioModeInput, 0 ); 81 | 82 | CMU_ClockEnable( cmuClock_USART1, true ); 83 | 84 | // At 48MHz (HFXO), oversampling of 6 gives lowest baud rate error for 115200 85 | USART_InitAsync_TypeDef init = USART_INITASYNC_DEFAULT; 86 | init.oversampling = usartOVS6; 87 | init.enable = usartDisable; 88 | 89 | /* 90 | USART_InitAsync calls USART_Reset, which resets the ROUTE reg. 91 | So, do the ROUTE setup AFTER the Init call. 92 | */ 93 | USART_InitAsync( USART1, &init ); 94 | USART1->ROUTE = USART_ROUTE_RXPEN | USART_ROUTE_TXPEN | 95 | USART_ROUTE_LOCATION_LOC1; 96 | 97 | USART_Enable( USART1, usartEnable ); 98 | } 99 | 100 | /** 101 | * Write string @p s to the stk3700 serial console (defined to be USART1) 102 | */ 103 | static void consoleWrite( char* s ) { 104 | char* cp = s; 105 | while( *cp ) { 106 | USART_Tx( USART1, *cp ); 107 | cp++; 108 | } 109 | } 110 | 111 | // A place to hold the formatted fault dump, of correct size. 112 | static char faultDumpBuffer[FAULT_HANDLING_DUMP_SIZE]; 113 | 114 | /** 115 | * Dump the fault to the serial console, so a user can 'see' what went wrong. 116 | */ 117 | void consoleDumpProcessor(void) { 118 | consoleWrite( faultDumpBuffer ); 119 | } 120 | 121 | int main(void) { 122 | 123 | CHIP_Init(); 124 | 125 | initConsole(); 126 | 127 | // Use of the faultHandling api itself... 128 | 129 | // 1: a buffer to hold the dump and the function to be called to process it 130 | faultHandlingSetDumpProcessor( faultDumpBuffer, consoleDumpProcessor ); 131 | 132 | // 2: stack search parameters 133 | extern uint32_t __etext; 134 | extern uint32_t __StackTop; 135 | 136 | faultHandlingSetCallStackParameters( 0, &__etext, &__StackTop, 0 ); 137 | 138 | // 3: what to do once the fauly has occurred: loop, reboot, etc 139 | faultHandlingSetPostFaultAction( POSTHANDLER_LOOP ); 140 | 141 | /* 142 | Force a invState fault by calling through a zeroed func pointer. 143 | */ 144 | 145 | // The set up... 146 | void (*p)(void) = (void(*)(void))0; 147 | 148 | // ... and the failure 149 | p(); 150 | 151 | return 0; 152 | } 153 | 154 | /* 155 | We MUST define a HardFault_Handler. It just vectors to 156 | faultHandling's provided FaultHandler. This overrides the weak 157 | version in startup_efm32gg.c. 158 | 159 | The 'naked' attribute ensures that this function has no 160 | prolog/epilog that affect the stack (e.g. push r7,lr). 161 | */ 162 | __attribute__((naked)) 163 | void HardFault_Handler(void) { 164 | __asm__( "B FaultHandler\n" ); 165 | } 166 | 167 | // eof 168 | -------------------------------------------------------------------------------- /src/test/c/busFault.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright © 2022 Stuart Maclean 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are 8 | * met: 9 | * 10 | * * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above 14 | * copyright notice, this list of conditions and the following 15 | * disclaimer in the documentation and/or other materials provided 16 | * with the distribution. 17 | * 18 | * * Neither the name of the copyright holder nor the names of its 19 | * contributors may be used to endorse or promote products derived 20 | * from this software without specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | * HOLDER NOR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 29 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 31 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 32 | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 33 | * DAMAGE. 34 | */ 35 | #include 36 | 37 | #include "faultHandling.h" 38 | 39 | #include "em_chip.h" 40 | #include "em_cmu.h" 41 | #include "em_gpio.h" 42 | #include "em_usart.h" 43 | 44 | /** 45 | * @author Stuart Maclean 46 | * 47 | * Fault capture using the faultHandling api, where the processing of 48 | * the fault is to 'export the fault dump' by writing it to a uart on 49 | * the SiliconLabs STK3700 starter kit. The STK3700 uses an 50 | * EFM32GG990F1024 cpu. 51 | * 52 | * We are viewing that uart as the 'serial console' of that board, so 53 | * the dump export is as close to a 'printf' as such a board can 54 | * mimic. 55 | 56 | * On the STK3700, Expansion Header pin 4 (USART1 Tx) is PD0 while pin 57 | * 6 (USART1 Rx) is PD1. These pins are route/location 1 for that 58 | * USART. See the STK3700 data sheet. 59 | 60 | * Hook up a ttl-usb cable to your host, and open e.g. minicom (or 61 | * just cat!) at 115200 and see the fault dump appear as the stk3700 62 | * end keels over with a fault! 63 | */ 64 | 65 | void initConsole(void); 66 | void consoleWrite( char* s ); 67 | 68 | // A place to hold the formatted fault dump, of correct size. 69 | static char faultDumpBuffer[FAULT_HANDLING_DUMP_SIZE]; 70 | 71 | /** 72 | * Dump the fault to the serial console, so a user can 'see' what went wrong. 73 | */ 74 | void consoleDumpProcessor(void) { 75 | consoleWrite( faultDumpBuffer ); 76 | } 77 | 78 | int main(void) { 79 | 80 | CHIP_Init(); 81 | 82 | initConsole(); 83 | 84 | // Use of the faultHandling api itself... 85 | 86 | // 1: a buffer to hold the dump and the function to be called to process it 87 | faultHandlingSetDumpProcessor( faultDumpBuffer, consoleDumpProcessor ); 88 | 89 | // 2: stack search parameters 90 | extern uint32_t __etext; 91 | extern uint32_t __StackTop; 92 | 93 | faultHandlingSetCallStackParameters( 0, &__etext, &__StackTop, 0 ); 94 | 95 | // 3: what to do once the fauly has occurred: loop, reboot, etc 96 | faultHandlingSetPostFaultAction( POSTHANDLER_LOOP ); 97 | 98 | /* 99 | Force a invState fault by calling through a zeroed func pointer. 100 | */ 101 | 102 | // The set up... 103 | void (*p)(void) = (void(*)(void)) 0x20202020; 104 | 105 | // ... and the failure 106 | p(); 107 | 108 | return 0; 109 | } 110 | 111 | /* 112 | We MUST define a HardFault_Handler. It just vectors to 113 | faultHandling's provided FaultHandler. This overrides the weak 114 | version in startup_efm32gg.c. 115 | 116 | The 'naked' attribute ensures that this function has no 117 | prolog/epilog that affect the stack (e.g. push r7,lr). 118 | */ 119 | __attribute__((naked)) 120 | void HardFault_Handler(void) { 121 | __asm__( "B FaultHandler\n" ); 122 | } 123 | 124 | // eof 125 | -------------------------------------------------------------------------------- /src/test/c/faultGuru.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(void) { 4 | 5 | printf( "Your program crashed, oh how disappointing.\n" ); 6 | 7 | return 0; 8 | } 9 | 10 | // eof 11 | -------------------------------------------------------------------------------- /src/test/c/iaccviol.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright © 2022 Stuart Maclean 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are 8 | * met: 9 | * 10 | * * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above 14 | * copyright notice, this list of conditions and the following 15 | * disclaimer in the documentation and/or other materials provided 16 | * with the distribution. 17 | * 18 | * * Neither the name of the copyright holder nor the names of its 19 | * contributors may be used to endorse or promote products derived 20 | * from this software without specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | * HOLDER NOR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 29 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 31 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 32 | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 33 | * DAMAGE. 34 | */ 35 | #include 36 | 37 | #include "faultHandling.h" 38 | 39 | #include "em_chip.h" 40 | #include "em_cmu.h" 41 | #include "em_gpio.h" 42 | #include "em_usart.h" 43 | 44 | /** 45 | * @author Stuart Maclean 46 | * 47 | * Fault capture using the faultHandling api, where the processing of 48 | * the fault is to 'export the fault dump' by writing it to a uart on 49 | * the SiliconLabs STK3700 starter kit. The STK3700 uses an 50 | * EFM32GG990F1024 cpu. 51 | * 52 | * We are viewing that uart as the 'serial console' of that board, so 53 | * the dump export is as close to a 'printf' as such a board can 54 | * mimic. 55 | 56 | * On the STK3700, Expansion Header pin 4 (USART1 Tx) is PD0 while pin 57 | * 6 (USART1 Rx) is PD1. These pins are route/location 1 for that 58 | * USART. See the STK3700 data sheet. 59 | 60 | * Hook up a ttl-usb cable to your host, and open e.g. minicom (or 61 | * just cat!) at 115200 and see the fault dump appear as the stk3700 62 | * end keels over with a fault! 63 | */ 64 | 65 | void initConsole(void); 66 | void consoleWrite( char* s ); 67 | 68 | 69 | // A place to hold the formatted fault dump, of correct size. 70 | static char faultDumpBuffer[FAULT_HANDLING_DUMP_SIZE]; 71 | 72 | /** 73 | * Dump the fault to the serial console, so a user can 'see' what went wrong. 74 | */ 75 | void consoleDumpProcessor(void) { 76 | consoleWrite( faultDumpBuffer ); 77 | } 78 | 79 | int main(void) { 80 | 81 | CHIP_Init(); 82 | 83 | initConsole(); 84 | 85 | // Use of the faultHandling api itself... 86 | 87 | // 1: a buffer to hold the dump and the function to be called to process it 88 | faultHandlingSetDumpProcessor( faultDumpBuffer, consoleDumpProcessor ); 89 | 90 | // 2: stack search parameters 91 | extern uint32_t __etext; 92 | extern uint32_t __StackTop; 93 | 94 | faultHandlingSetCallStackParameters( 0, &__etext, &__StackTop, 0 ); 95 | 96 | // 3: what to do once the fauly has occurred: loop, reboot, etc 97 | faultHandlingSetPostFaultAction( POSTHANDLER_LOOP ); 98 | 99 | /* 100 | Force a busFault by calling through a func pointer to a non-mapped address. 101 | */ 102 | 103 | // The set up... 104 | void (*p)(void) = (void(*)(void))((1LL << 32) - 1); 105 | 106 | // ... and the failure 107 | p(); 108 | 109 | return 0; 110 | } 111 | 112 | /* 113 | We MUST define a HardFault_Handler. It just vectors to 114 | faultHandling's provided FaultHandler. This overrides the weak 115 | version in startup_efm32gg.c. 116 | 117 | The 'naked' attribute ensures that this function has no 118 | prolog/epilog that affect the stack (e.g. push r7,lr). 119 | */ 120 | __attribute__((naked)) 121 | void HardFault_Handler(void) { 122 | __asm__( "B FaultHandler\n" ); 123 | } 124 | 125 | // eof 126 | -------------------------------------------------------------------------------- /src/test/c/invstate.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright © 2022 Stuart Maclean 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are 8 | * met: 9 | * 10 | * * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above 14 | * copyright notice, this list of conditions and the following 15 | * disclaimer in the documentation and/or other materials provided 16 | * with the distribution. 17 | * 18 | * * Neither the name of the copyright holder nor the names of its 19 | * contributors may be used to endorse or promote products derived 20 | * from this software without specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | * HOLDER NOR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 29 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 31 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 32 | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 33 | * DAMAGE. 34 | */ 35 | #include 36 | 37 | #include "faultHandling.h" 38 | 39 | #include "em_chip.h" 40 | #include "em_cmu.h" 41 | #include "em_gpio.h" 42 | #include "em_usart.h" 43 | 44 | /** 45 | * @author Stuart Maclean 46 | * 47 | * Fault capture using the faultHandling api, where the processing of 48 | * the fault is to 'export the fault dump' by writing it to a uart on 49 | * the SiliconLabs STK3700 starter kit. The STK3700 uses an 50 | * EFM32GG990F1024 cpu. 51 | * 52 | * We are viewing that uart as the 'serial console' of that board, so 53 | * the dump export is as close to a 'printf' as such a board can 54 | * mimic. 55 | 56 | * On the STK3700, Expansion Header pin 4 (USART1 Tx) is PD0 while pin 57 | * 6 (USART1 Rx) is PD1. These pins are route/location 1 for that 58 | * USART. See the STK3700 data sheet. 59 | 60 | * Hook up a ttl-usb cable to your host, and open e.g. minicom (or 61 | * just cat!) at 115200 and see the fault dump appear as the stk3700 62 | * end keels over with a fault! 63 | */ 64 | 65 | void initConsole(void); 66 | void consoleWrite( char* s ); 67 | 68 | 69 | // A place to hold the formatted fault dump, of correct size. 70 | static char faultDumpBuffer[FAULT_HANDLING_DUMP_SIZE]; 71 | 72 | /** 73 | * Dump the fault to the serial console, so a user can 'see' what went wrong. 74 | */ 75 | void consoleDumpProcessor(void) { 76 | consoleWrite( faultDumpBuffer ); 77 | } 78 | 79 | int main(void) { 80 | 81 | CHIP_Init(); 82 | 83 | initConsole(); 84 | 85 | // Use of the faultHandling api itself... 86 | 87 | // 1: a buffer to hold the dump and the function to be called to process it 88 | faultHandlingSetDumpProcessor( faultDumpBuffer, consoleDumpProcessor ); 89 | 90 | // 2: stack search parameters 91 | extern uint32_t __etext; 92 | extern uint32_t __StackTop; 93 | 94 | faultHandlingSetCallStackParameters( 0, &__etext, &__StackTop, 0 ); 95 | 96 | // 3: what to do once the fauly has occurred: loop, reboot, etc 97 | faultHandlingSetPostFaultAction( POSTHANDLER_LOOP ); 98 | 99 | /* 100 | Force a busFault by calling through a func pointer to a non-mapped address. 101 | */ 102 | 103 | // The set up... 104 | void (*p)(void) = (void(*)(void))0; 105 | 106 | // ... and the failure 107 | p(); 108 | 109 | return 0; 110 | } 111 | 112 | /* 113 | We MUST define a HardFault_Handler. It just vectors to 114 | faultHandling's provided FaultHandler. This overrides the weak 115 | version in startup_efm32gg.c. 116 | 117 | The 'naked' attribute ensures that this function has no 118 | prolog/epilog that affect the stack (e.g. push r7,lr). 119 | */ 120 | __attribute__((naked)) 121 | void HardFault_Handler(void) { 122 | __asm__( "B FaultHandler\n" ); 123 | } 124 | 125 | // eof 126 | -------------------------------------------------------------------------------- /src/test/c/mpuFault.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright © 2022 Stuart Maclean 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are 8 | * met: 9 | * 10 | * * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above 14 | * copyright notice, this list of conditions and the following 15 | * disclaimer in the documentation and/or other materials provided 16 | * with the distribution. 17 | * 18 | * * Neither the name of the copyright holder nor the names of its 19 | * contributors may be used to endorse or promote products derived 20 | * from this software without specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | * HOLDER NOR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 29 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 31 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 32 | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 33 | * DAMAGE. 34 | */ 35 | #include 36 | 37 | #include "faultHandling.h" 38 | 39 | #include "em_chip.h" 40 | #include "em_cmu.h" 41 | #include "em_gpio.h" 42 | #include "em_usart.h" 43 | 44 | #include "mpu_armv7.h" 45 | 46 | /** 47 | * @author Stuart Maclean 48 | * 49 | * Fault capture using the faultHandling api, where the processing of 50 | * the fault is to 'export the fault dump' by writing it to a uart on 51 | * the SiliconLabs STK3700 starter kit. The STK3700 uses an 52 | * EFM32GG990F1024 cpu. 53 | * 54 | * We are viewing that uart as the 'serial console' of that board, so 55 | * the dump export is as close to a 'printf' as such a board can 56 | * mimic. 57 | 58 | * On the STK3700, Expansion Header pin 4 (USART1 Tx) is PD0 while pin 59 | * 6 (USART1 Rx) is PD1. These pins are route/location 1 for that 60 | * USART. See the STK3700 data sheet. 61 | 62 | * Hook up a ttl-usb cable to your host, and open e.g. minicom (or 63 | * just cat!) at 115200 and see the fault dump appear as the stk3700 64 | * end keels over with a fault! 65 | */ 66 | 67 | void initConsole(void); 68 | void consoleWrite( char* s ); 69 | 70 | // A place to hold the formatted fault dump, of correct size. 71 | static char faultDumpBuffer[FAULT_HANDLING_DUMP_SIZE]; 72 | 73 | /** 74 | * Dump the fault to the serial console, so a user can 'see' what went wrong. 75 | */ 76 | void consoleDumpProcessor(void) { 77 | consoleWrite( faultDumpBuffer ); 78 | } 79 | 80 | int main(void) { 81 | 82 | CHIP_Init(); 83 | 84 | initConsole(); 85 | 86 | // Use of the faultHandling api itself... 87 | 88 | // 1: a buffer to hold the dump and the function to be called to process it 89 | faultHandlingSetDumpProcessor( faultDumpBuffer, consoleDumpProcessor ); 90 | 91 | // 2: stack search parameters 92 | extern uint32_t __etext; 93 | extern uint32_t __StackTop; 94 | 95 | faultHandlingSetCallStackParameters( 0, &__etext, &__StackTop, 0 ); 96 | 97 | // 3: what to do once the fauly has occurred: loop, reboot, etc 98 | faultHandlingSetPostFaultAction( POSTHANDLER_LOOP ); 99 | 100 | 101 | /* The set up: Define a no-access region to bottom 32 bytes of flash... */ 102 | uint32_t rbar = ARM_MPU_RBAR( 0, FLASH_MEM_BASE ); 103 | 104 | // Mimics attributes of (older) em_mpu.h's MPU_INIT_FLASH_DEFAULT 105 | uint32_t accessAttributes = ARM_MPU_ACCESS_(0,0,1,0); 106 | 107 | uint32_t rsar = ARM_MPU_RASR_EX( 0, ARM_MPU_AP_NONE, accessAttributes, 108 | 0, ARM_MPU_REGION_SIZE_32B ); 109 | ARM_MPU_SetRegion( rbar, rsar ); 110 | ARM_MPU_Enable( MPU_CTRL_PRIVDEFENA_Msk ); 111 | 112 | // ... and the failure: a 'null pointer' attempts to read from that region 113 | int* p = (int*)NULL; 114 | int i = *p; 115 | 116 | return 0; 117 | } 118 | 119 | __attribute__((naked)) 120 | void MemManage_Handler(void) { 121 | __asm__( "B FaultHandler\n" ); 122 | } 123 | 124 | // eof 125 | -------------------------------------------------------------------------------- /src/test/c/noopProcessor.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright © 2022 Stuart Maclean 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are 8 | * met: 9 | * 10 | * * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above 14 | * copyright notice, this list of conditions and the following 15 | * disclaimer in the documentation and/or other materials provided 16 | * with the distribution. 17 | * 18 | * * Neither the name of the copyright holder nor the names of its 19 | * contributors may be used to endorse or promote products derived 20 | * from this software without specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | * HOLDER NOR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 29 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 31 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 32 | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 33 | * DAMAGE. 34 | */ 35 | #include "faultHandling.h" 36 | 37 | /** 38 | * @author Stuart Maclean 39 | * 40 | * A program that uses the faultHandling api, so that if/when a fault occurs, 41 | * we are supplied a dump of the CPU state at fault time. 42 | * 43 | * Because this program is buildable for the generic 'ARM Cortex M' cpu, 44 | * with NO peripherals defined, we cannot actually export the fault dump 45 | * in any way (SD card, console uart, etc). 46 | * 47 | * See e.g. SiliconLabs test cases for fault dump processors that CAN 48 | * actually export the fault dump. 49 | */ 50 | 51 | /* We define the memory for the faultHandling api to write the dump to */ 52 | static char faultDumpBuffer[FAULT_HANDLING_DUMP_SIZE]; 53 | 54 | /* We define what to DO with the fault dump, in this case, nothing */ 55 | static void noopDumpProcessor(void) { 56 | 57 | // Wot, no periperhals to send the faultDump to, not even a serial port! 58 | 59 | } 60 | 61 | int main(void) { 62 | 63 | /* The faultHandling api */ 64 | faultHandlingSetDumpProcessor( faultDumpBuffer, noopDumpProcessor ); 65 | faultHandlingSetPostFaultAction( POSTHANDLER_LOOP ); 66 | 67 | /* 68 | Force a fault by calling through a func pointer to a non-mapped address. 69 | */ 70 | 71 | // step 1: The set up... 72 | void (*p)(void) = (void(*)(void))0x87654321; 73 | 74 | /* 75 | ... and step 2, the failure. This will cause our faultHandler to 76 | compose a fault dump in the app-supplied char[], followed by a call to 77 | the app-supplied dump processor. 78 | */ 79 | p(); 80 | 81 | return 0; 82 | } 83 | 84 | /* 85 | We MUST define a HardFault_Handler. It just vectors to faultHandling's 86 | provided FaultHandler. 87 | 88 | The 'naked' attribute ensures that this function has no 89 | prolog/epilog that affect the stack (e.g. push r7,lr). 90 | */ 91 | __attribute__((naked)) 92 | void HardFault_Handler(void) { 93 | __asm__( "B FaultHandler\n" ); 94 | } 95 | 96 | #if 0 97 | /* 98 | If we wanted to catch more-specific faults, e.g. MemManage faults, 99 | we would define this also: 100 | */ 101 | 102 | __attribute__((naked)) 103 | void MemManageFault_Handler(void) { 104 | __asm__( "B FaultHandler\n" ); 105 | } 106 | 107 | /* 108 | Such a program would need this too, to enable the MemManageFault_Handler: 109 | */ 110 | 111 | SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk; 112 | 113 | #endif 114 | 115 | // eof 116 | -------------------------------------------------------------------------------- /src/test/c/stackSmashing.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright © 2022 Stuart Maclean 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are 8 | * met: 9 | * 10 | * * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above 14 | * copyright notice, this list of conditions and the following 15 | * disclaimer in the documentation and/or other materials provided 16 | * with the distribution. 17 | * 18 | * * Neither the name of the copyright holder nor the names of its 19 | * contributors may be used to endorse or promote products derived 20 | * from this software without specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | * HOLDER NOR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 29 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 31 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 32 | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 33 | * DAMAGE. 34 | */ 35 | #include 36 | 37 | #include "faultHandling.h" 38 | 39 | #include "em_chip.h" 40 | #include "em_cmu.h" 41 | #include "em_gpio.h" 42 | #include "em_usart.h" 43 | 44 | /** 45 | * @author Stuart Maclean 46 | * 47 | * As per ./stk3700.c in terms of console printf setup. 48 | 49 | * The fault generation here is via stack smashing. A called function 50 | * declares local variables, but then writes past them, into slots in 51 | * the stack from which r7 and lr will be popped by function epilog. 52 | */ 53 | 54 | void initConsole(void); 55 | void consoleWrite( char* s ); 56 | 57 | // A place to hold the formatted fault dump, of correct size. 58 | static char faultDumpBuffer[FAULT_HANDLING_DUMP_SIZE]; 59 | 60 | /** 61 | * Dump the fault to the serial console, so a user can 'see' what went wrong. 62 | */ 63 | void consoleDumpProcessor(void) { 64 | // consoleWrite( "foo\r\n" ); 65 | consoleWrite( faultDumpBuffer ); 66 | } 67 | 68 | static void foo(void); 69 | 70 | int main(void) { 71 | 72 | CHIP_Init(); 73 | 74 | initConsole(); 75 | 76 | // Use of the faultHandling api itself... 77 | 78 | // 1: a buffer to hold the dump and the function to be called to process it 79 | faultHandlingSetDumpProcessor( faultDumpBuffer, consoleDumpProcessor ); 80 | 81 | // 2: stack search parameters 82 | extern uint32_t __etext; 83 | extern uint32_t __StackTop; 84 | 85 | faultHandlingSetCallStackParameters( 0, &__etext, &__StackTop, 0 ); 86 | 87 | // 3: what to do once the fauly has occurred: loop, reboot, etc 88 | faultHandlingSetPostFaultAction( POSTHANDLER_LOOP ); 89 | 90 | consoleWrite( "Foo\r\n" ); 91 | 92 | foo(); 93 | 94 | consoleWrite( "Done\r\n" ); 95 | 96 | return 0; 97 | } 98 | 99 | static void bar(void) { 100 | } 101 | 102 | 103 | static void foo(void) { 104 | 105 | /* 106 | By having local variables AND being a non-leaf function, we 107 | ensure that our prolog pushes caller's r7 and lr, since we have 108 | our own use for them. 109 | */ 110 | uint32_t a[1]; 111 | 112 | bar(); 113 | 114 | /* 115 | Since stack frames are 8 byte aligned, then local vars, such as 116 | 'a' here, can have padding. Such padding will widen the gap 117 | between valid array indices and the prolog-pushed values of r7, lr 118 | (if both pushed). 119 | 120 | Register pushes are from HIGHEST-NUMBERED to LOWEST-NUMBERED, so 121 | lr (r14) would be pushed FIRST, and r7 pushed SECOND. In terms of 122 | accessing outside an array, if a[i] trashes r7, then a[i+1] will 123 | trash lr. The actual value of i is not well-defined (depends on 124 | stack frame alignment). 125 | */ 126 | 127 | a[0] = 0xCAFEBABE; 128 | a[1] = 0xDEADBEEF; 129 | a[2] = 0xCAFEBABE; 130 | a[3] = 0xDEADBEEF; 131 | 132 | } 133 | 134 | /* 135 | We MUST define a HardFault_Handler. It just vectors to 136 | faultHandling's provided FaultHandler. This overrides the weak 137 | version in startup_efm32gg.c. 138 | 139 | The 'naked' attribute ensures that this function has no 140 | prolog/epilog that affect the stack (e.g. push r7,lr). 141 | */ 142 | __attribute__((naked)) 143 | void HardFault_Handler(void) { 144 | __asm__( "B FaultHandler\n" ); 145 | } 146 | 147 | // eof 148 | -------------------------------------------------------------------------------- /src/test/c/stk3200.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright © 2022 Stuart Maclean 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are 8 | * met: 9 | * 10 | * * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above 14 | * copyright notice, this list of conditions and the following 15 | * disclaimer in the documentation and/or other materials provided 16 | * with the distribution. 17 | * 18 | * * Neither the name of the copyright holder nor the names of its 19 | * contributors may be used to endorse or promote products derived 20 | * from this software without specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | * HOLDER NOR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 29 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 31 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 32 | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 33 | * DAMAGE. 34 | */ 35 | #include 36 | 37 | #include "em_cmu.h" 38 | #include "em_gpio.h" 39 | #include "em_usart.h" 40 | 41 | /** 42 | * @author Stuart Maclean 43 | * 44 | * Helper for fault handling api test cases that run on a SiliconLabs 45 | * stk3200 starter kit board. That board contains a ZeroGecko CPU, a 46 | * CM0plus. 47 | 48 | * https://www.silabs.com/development-tools/mcu/32-bit/efm32zg-starter-kit?tab=overview 49 | 50 | * Here we provide TWO routines for test cases: 51 | 52 | * initConsole() - set up the CMU, GPIO and USART peripherals such 53 | * that USART1 is pinned out to the stk3200's Expansion Header on pins 54 | * 4 (Tx) and 6 (Rx). We are viewing that uart as the 'serial console' 55 | * of that board. 56 | 57 | * consoleWrite( char* s ) - write a supplied string to the serial console. 58 | * 59 | * Hook up a ttl-usb cable to your host, and open 60 | * e.g. minicom/teraterm (or just cat!) at 115200 baud, 8N1, and see 61 | * any output written by the stk3200's consoleWrite routine. 62 | * 63 | * $ stty -F /dev/ttyXXX 115200 -echo 64 | * $ cat /dev/ttyXXX 65 | */ 66 | 67 | /** 68 | * Prepare the stk3200's cmu, gpio and usart peripherals so that we 69 | * have a 'serial console' to which we can write a fault dump when one 70 | * occurs. This is all typical emlib stuff. 71 | */ 72 | void initConsole(void) { 73 | 74 | CMU_OscillatorEnable( cmuOsc_HFXO, true, true ); 75 | CMU_ClockSelectSet( cmuClock_HF, cmuSelect_HFXO ); 76 | 77 | // USART1#2 = Tx - D7, Rx - D6 78 | CMU_ClockEnable( cmuClock_GPIO, true ); 79 | GPIO_PinModeSet( gpioPortD, 7, gpioModePushPull, 1 ); 80 | GPIO_PinModeSet( gpioPortD, 6, gpioModeInput, 0 ); 81 | 82 | CMU_ClockEnable( cmuClock_USART1, true ); 83 | 84 | // At 24MHz (HFXO), oversampling of 6 gives lowest baud rate error for 115200 85 | USART_InitAsync_TypeDef init = USART_INITASYNC_DEFAULT; 86 | init.oversampling = usartOVS6; 87 | init.enable = usartDisable; 88 | 89 | /* 90 | USART_InitAsync calls USART_Reset, which resets the ROUTE register. 91 | So, do the ROUTE setup AFTER the Init call. 92 | */ 93 | USART_InitAsync( USART1, &init ); 94 | USART1->ROUTE = USART_ROUTE_RXPEN | USART_ROUTE_TXPEN | 95 | USART_ROUTE_LOCATION_LOC2; 96 | 97 | USART_Enable( USART1, usartEnable ); 98 | } 99 | 100 | /** 101 | * Write null-terminated string @p s to the stk3700 'serial console', 102 | * defined by us to be USART1. 103 | */ 104 | void consoleWrite( char* s ) { 105 | char* cp = s; 106 | while( *cp ) { 107 | USART_Tx( USART1, *cp ); 108 | cp++; 109 | } 110 | } 111 | 112 | // eof 113 | -------------------------------------------------------------------------------- /src/test/c/stk3700.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright © 2022 Stuart Maclean 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are 8 | * met: 9 | * 10 | * * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above 14 | * copyright notice, this list of conditions and the following 15 | * disclaimer in the documentation and/or other materials provided 16 | * with the distribution. 17 | * 18 | * * Neither the name of the copyright holder nor the names of its 19 | * contributors may be used to endorse or promote products derived 20 | * from this software without specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | * HOLDER NOR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 29 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 31 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 32 | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 33 | * DAMAGE. 34 | */ 35 | #include 36 | 37 | #include "em_cmu.h" 38 | #include "em_gpio.h" 39 | #include "em_usart.h" 40 | 41 | /** 42 | * @author Stuart Maclean 43 | * 44 | * Helper for fault handling api test cases that run on a SiliconLabs 45 | * stk3700 starter kit board. That board contains a GiantGecko CPU, a 46 | * CM3. 47 | * 48 | * https://www.silabs.com/development-tools/mcu/32-bit/efm32gg-starter-kit?tab=overview 49 | 50 | * Here we provide TWO routines for test cases: 51 | 52 | * initConsole() - set up the CMU, GPIO and USART peripherals such 53 | * that USART1 is pinned out to the stk3700's Expansion Header on pins 54 | * 4 (Tx) and 6 (Rx). We are viewing that uart as the 'serial console' 55 | * of that board. 56 | * 57 | * On the STK3700, Expansion Header pin 4 (USART1 Tx) is PD0 while pin 58 | * 6 (USART1 Rx) is PD1. These pins are route/location 1 for that 59 | * USART. See the STK3700 data sheet. 60 | * 61 | * consoleWrite( char* s ) - write a supplied string to the serial console. 62 | * 63 | * Hook up a ttl-usb cable to your host, and open 64 | * e.g. minicom/teraterm (or just cat!) at 115200 baud, 8N1, and see 65 | * any output written by the stk3700's consoleWrite routine. 66 | * 67 | * $ stty -F /dev/ttyXXX 115200 -echo 68 | * $ cat /dev/ttyXXX 69 | */ 70 | 71 | /** 72 | * Prepare the stk3700's cmu, gpio and usart peripherals so that we 73 | * have a 'serial console' to which we can write a fault dump when one 74 | * occurs. This is all typical emlib stuff. 75 | */ 76 | void initConsole(void) { 77 | 78 | CMU_OscillatorEnable( cmuOsc_HFXO, true, true ); 79 | CMU_ClockSelectSet( cmuClock_HF, cmuSelect_HFXO ); 80 | 81 | // USART1#1 = Tx - D1, Rx - D0 82 | CMU_ClockEnable( cmuClock_GPIO, true ); 83 | GPIO_PinModeSet( gpioPortD, 0, gpioModePushPull, 1 ); 84 | GPIO_PinModeSet( gpioPortD, 1, gpioModeInput, 0 ); 85 | 86 | CMU_ClockEnable( cmuClock_USART1, true ); 87 | 88 | // At 48MHz (HFXO), oversampling of 6 gives lowest baud rate error for 115200 89 | USART_InitAsync_TypeDef init = USART_INITASYNC_DEFAULT; 90 | init.oversampling = usartOVS6; 91 | init.enable = usartDisable; 92 | 93 | /* 94 | USART_InitAsync calls USART_Reset, which resets the ROUTE register. 95 | So, do the ROUTE setup AFTER the Init call. 96 | */ 97 | USART_InitAsync( USART1, &init ); 98 | USART1->ROUTE = USART_ROUTE_RXPEN | USART_ROUTE_TXPEN | 99 | USART_ROUTE_LOCATION_LOC1; 100 | 101 | USART_Enable( USART1, usartEnable ); 102 | } 103 | 104 | /** 105 | * Write null-terminated string @p s to the stk3700 'serial console', 106 | * defined by us to be USART1. 107 | */ 108 | void consoleWrite( char* s ) { 109 | char* cp = s; 110 | while( *cp ) { 111 | USART_Tx( USART1, *cp ); 112 | cp++; 113 | } 114 | } 115 | 116 | // eof 117 | -------------------------------------------------------------------------------- /toolchain.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright © 2022 Stuart Maclean 3 | # 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are 8 | # met: 9 | # 10 | # * Redistributions of source code must retain the above copyright 11 | # notice, this list of conditions and the following disclaimer. 12 | # 13 | # * Redistributions in binary form must reproduce the above 14 | # copyright notice, this list of conditions and the following 15 | # disclaimer in the documentation and/or other materials provided 16 | # with the distribution. 17 | # 18 | # * Neither the name of the copyright holder nor the names of its 19 | # contributors may be used to endorse or promote products derived 20 | # from this software without specific prior written permission. 21 | # 22 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | # HOLDER NOR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 29 | # OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 31 | # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 32 | # USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 33 | # DAMAGE. 34 | # 35 | 36 | 37 | # $ sudo apt install gcc-arm-none-eabi 38 | 39 | # $ sudo apt install binutils-arm-none-eabi (??) 40 | 41 | # $ sudo apt install libnewlib-arm-none-eabi (??) 42 | 43 | PREFIX = arm-none-eabi 44 | 45 | AR = $(PREFIX)-ar 46 | AS = $(PREFIX)-as 47 | CC = $(PREFIX)-gcc 48 | LD = $(PREFIX)-ld 49 | NM = $(PREFIX)-nm 50 | OBJCOPY = $(PREFIX)-objcopy 51 | OBJDUMP = $(PREFIX)-objdump 52 | RANLIB = $(PREFIX)-ranlib 53 | READELF = $(PREFIX)-readelf 54 | SIZE = $(PREFIX)-size 55 | STRIP = $(PREFIX)-strip 56 | 57 | --------------------------------------------------------------------------------