Developing a Generic Hard Fault handler for ARM Cortex-M3/Cortex-M4

Slides:



Advertisements
Similar presentations
Cortex-M3 Implementation Overview. Chapter 6 in the reference book.
Advertisements

ECE 353 Introduction to Microprocessor Systems
Exceptions. Exception Types Exception Handling Vectoring Interrupts Interrupt Handlers Interrupt Priorities Interrupt applications 6-2.
Cortex-M3 Memory Systems
Cortex-M3 Exceptions and Interrupts
Exceptional Control Flow Processes Today. Control Flow Processors do only one thing: From startup to shutdown, a CPU simply reads and executes (interprets)
Interrupts Chapter 8 – pp Chapter 10 – pp Appendix A – pp 537 &
9/20/6Lecture 3 - Instruction Set - Al1 Exception Handling (2)
Computertechniek Hogeschool van Utrecht / Institute for Computer, Communication and Media Technology 1.
I/O Unit.
68HC11 Polling and Interrupts
ECE 372 – Microcontroller Design Parallel IO Ports - Interrupts
LOGO Chapter 1 Interrupt handling. hardware interrupt Under x86, hardware interrupts are called IRQ's. When the CPU receives an interrupt, it stops whatever.
OS Fall ’ 02 Introduction Operating Systems Fall 2002.
7/23 Coldfire Exceptions and Interrupts Computer Science & Engineering Department Arizona State University Tempe, AZ Dr. Yann-Hang Lee
1 Interrupts INPUT/OUTPUT ORGANIZATION: Interrupts CS 147 JOKO SUTOMO.
Introduction to Interrupts
Getting Started with a Cortex-M3 Board
Dr. Kimberly E. Newman Hybrid Embedded wk3 Fall 2009.
MSP432™ MCUs Training Part 9: Porting between MSP430 and MSP432
Cortex-M3 Debugging System
Exception and Interrupt Handling
Introduction to Embedded Systems
Exceptions and Interrupts 2
Interrupts. What Are Interrupts? Interrupts alter a program’s flow of control  Behavior is similar to a procedure call »Some significant differences.
CORTEX-M0 Structure Discussion 2 – Core Peripherals
1 Computer System Overview Chapter 1. 2 n An Operating System makes the computing power available to users by controlling the hardware n Let us review.
MICROPROCESSOR INPUT/OUTPUT
Copyright 2001 Oxford Consulting, Ltd1 January Storage Classes, Scope and Linkage Overview Focus is on the structure of a C++ program with –Multiple.
Microcontroller based system design Asst. Prof. Dr. Alper ŞİŞMAN.
UBI >> Contents Chapter 2 Software Development tools Code Composer Essentials v3: Code Debugging Texas Instruments Incorporated University of Beira Interior.
© 2008, Renesas Technology America, Inc., All Rights Reserved 1 Course Introduction Purpose  This training course provides an overview of the CPU architecture.
CSNB374: Microprocessor Systems Chapter 5: Procedures and Interrupts.
ARM Cortex-M0 August 23, 2012 Paul Nickelsberg Orchid Technologies Engineering and Consulting, Inc. CORTEX-M0 Structure Discussion.
Z80 Overview internal architecture and major elements of the Z80 CPU.
Virtual 8086 Mode  The supports execution of one or more 8086, 8088, 80186, or programs in an protected-mode environment.  An 8086.
1 Interrupts, Resets Today: First Hour: Interrupts –Section 5.2 of Huang’s Textbook –In-class Activity #1 Second Hour: More Interrupts Section 5.2 of Huang’s.
Exceptional Control Flow Topics Exceptions except1.ppt CS 105 “Tour of the Black Holes of Computing”
6-1 Infineon 167 Interrupts The C167CS provides 56 separate interrupt sources that may be assigned to 16 priority levels. The C167CS uses a vectored interrupt.
CE Operating Systems Lecture 2 Low level hardware support for operating systems.
AT91 C-startup. 2 For reasons of modularity and portability most application code for an embedded application is written in C The application entry point.
Execution Architecture MTT CPU08 Core M CPU08 INTRODUCTION.
بسم الله الرحمن الرحيم MEMORY AND I/O.
Interrupt-Driven I/O There are different types of interrupts –Hardware Generated by the 8259 PIC – signals the CPU to suspend execution of the current.
© 2008, Renesas Technology America, Inc., All Rights Reserved 1 Introduction Purpose  This training course demonstrates the Project Generator function.
BIOS and DOS Interrupts Basic Input /Outpu System Disk Operating System.
Memory system Kang Min Ju. 01 Memory map NVIC : Nested Vector Interrupt Controller MPU : Memory Protection Unit * This arrangement allows:
Introduction to Exceptions 1 Introduction to Exceptions ARM Advanced RISC Machines.
DATE S. S.. Sandstone The sandstone carries out the following tasks: 1. Set up target platform environment, 2. Load a bootable image into memory, 3. Relinquish.
Cortex-M3 Exceptions RTLAB. Hyeonggon Jo.  Exceptions Exception types & priority Abort model SVC and PendSV  Interrupt operation Pre-emption & Exit.
Interrupt 마이크로 프로세서 (Micro Processor) 2015년 2학기 충북대학교 전자공학과 박 찬식
-Low Power and System Control Features
ARM Cortex M3 & M4 Chapter 4 - Architecture
An Interrupt is either a Hardware generated CALL (externally derived from a hardware signal) OR A Software-generated CALL (internally derived from.
Interrupt and Exception Programming
Microprocessor Systems Design I
Refer to Chapter 7, 8, 9 in the reference book
Timer and Interrupts.
Anton Burtsev February, 2017
ARM Cortex-M3 RTLAB 박 유 진.
Interrupts In 8085 and 8086.
Overview of today’s lecture
Interrupt and Exception Programming
Interrupt and Exception Programming
Interrupt and Exception Programming
Subject Name: Microprocessors Subject Code:10EC46 Department: Electronics and Communication Date: /20/2018.
Interrupt and Exception Programming
CNET 315 Microprocessor & Assembly Language
Interrupt and Exception Programming
CORTEX-M0 Structure Discussion 1
Presentation transcript:

Developing a Generic Hard Fault handler for ARM Cortex-M3/Cortex-M4 4/11/2017 Developing a Generic Hard Fault handler for ARM Cortex-M3/Cortex-M4 Niall Cooling Feabhas Limited www.feabhas.com Place company logo here. Recommend a white transparent GIF logo which cannot be larger than the ARM TechCon logo at right.

Divide by zero error int div(int lho, int rho) { return lho/rho; } int main(void) { int a = 10; int b = 0; int c; … c = div(a, b); Copyright (c) Feabhas Ltd. 1995-2013

Enabling hardware reporting of div0 errors To enable hardware reporting of div0 errors we need to configure the Configuration and Control Register (CCR). The CCR is part of the Cortex-M's System Control Block (SCB) and controls entry trapping of divide by zero and unaligned accesses among other things. The CCR bit assignment for div0 is: [4] DIV_0_TRP Enables faulting or halting when the processor executes an SDIV or UDIV instruction with a divisor of 0: 0 = do not trap divide by 0 1 = trap divide by 0. When this bit is set to 0, a divide by zero returns a quotient of 0. SCB->CCR |= 0x10; Copyright (c) Feabhas Ltd. 1995-2013

ARMv7-M Vector Table Address Vector 0x00 Initial Main SP 0x04 Reset NMI 0x0c Hard Fault 0x10 Memory Manage 0x14 Bus Fault 0x18 Usage Fault 0x1c-0x28 Reserved 0x2c SVCall 0x30 Debug Monitor 0x34 0x38 PendSV 0x3c SysTick 0x40 IRQ0 …. More IRQs Initial Stack Pointer Initial Program Counter Minimal Set Non-Maskable Interrupt Non-privilege access MPU generated Instruction prefetch abort or data access error Invalid instructions System Service Call (SVC) – used for RTOS entry calls Pended System Call – used for RTOS context switching First Device Specific IRQ (0-239)

CMSIS-Core Cortex™-M3 & Cortex™-M0 Core Peripheral Access Layer Cortex-M Core Register Access Cortex-M Instruction Access NVIC Access Functions SysTick Configuration Function Instrumented Trace Macrocell (ITM) Cortex ™ -M3 ITM Debug Access ITM_SendChar Cortex ™ -M3 additional Debug Access ITM_ReceiveChar Copyright (c) Feabhas Ltd. 1995-2013

CMSIS v3.0 - Device Copyright (c) Feabhas Ltd. 1995-2013 CMSIS_V3P01 Silicon vendor Device compiler Source Include _Template_Vendor Device ARMArch.h system_ARMArch.h e.g. ARMCM3.h e.g. system_ARMCM3.h Include ARM ARM Arch e.g. ARMCM3 Source compiler startup_ARMArch.s system_ARMArch.c e.g. system_ARMCM3.c e.g. ARM, IAR, GCC, G++ startup_ARMCM3.s Copyright (c) Feabhas Ltd. 1995-2013

CMSIS ARM/Keil Application startup_Device.s ; Vector Table Mapped to Address 0 at Reset AREA RESET, DATA, READONLY EXPORT __Vectors __Vectors DCD __initial_sp ; Top of Stack DCD Reset_Handler ; Reset Handler DCD NMI_Handler ; NMI Handler DCD HardFault_Handler ; Hard Fault Handler DCD MemManage_Handler ; MPU Fault Handler DCD BusFault_Handler ; Bus Fault Handler … ; Dummy Exception Handlers (infinite loops which can be modified) NMI_Handler PROC EXPORT NMI_Handler [WEAK] B . ENDP HardFault_Handler\ PROC EXPORT HardFault_Handler [WEAK] MemManage_Handler\ Copyright (c) Feabhas Ltd. 1995-2013

ARM/Keil uVision Execution Need to halt execution yourself Execution will stop here: Need to replace the default HardFault_Handler with our own code Normally need to modify the asm file Weak linkage to the rescue! Copyright (c) Feabhas Ltd. 1995-2013

Weak linkage void simple(void) __attribute__((weak)) ; int main (void) { simple(); } void __attribute__((weak)) simple(void) printf("In WEAK simple\n"); This function attribute is a GNU compiler extension that is supported by the ARM compiler. Copyright (c) Feabhas Ltd. 1995-2013

Overriding weak linkage void simple(void) __attribute__((weak)) ; int main(void) { simple(); } void __attribute__((weak)) simple(void) printf("In WEAK simple\n"); void simple(void) { printf("overridden in: %s\n", __FILE__); } Copyright (c) Feabhas Ltd. 1995-2013

Override The Default Hard Fault_Handler void HardFault_Handler(void) { while(1); } Copyright (c) Feabhas Ltd. 1995-2013

Enter debug state automatically Rather than having to enter breakpoints via your IDE, we want to force the processor to enter debug state automatically if a certain instruction is reached (a sort of debug based assert). Inserting the BKPT (breakpoint) ARM instruction in our code will cause the processor to enter debug state. The “immediate” following the opcode normally doesn't matter (but always check) except it shouldn't be 0xAB (which is used for semihosting). #include "ARMCM3.h" void HardFault_Handler(void) { __ASM volatile("BKPT #01"); while(1); } Copyright (c) Feabhas Ltd. 1995-2013

Run and Break Now when we run the execution will halt when the BKPT instruction is executed Copyright (c) Feabhas Ltd. 1995-2013

Error Message Output The next step in developing the fault handler is the ability to report the fault. One option is, of course, to use stdio (stderr) and semihosting. However, as the support for semihosting can vary from compiler to compiler The "better" alternative is to use Instrumented Trace Macrocell (ITM) utilizing the CMSIS wrapper function ITM_SendChar Copyright (c) Feabhas Ltd. 1995-2013

ARM Cortex-M3 Processor ETM Instruction Trace NVIC 1-240 Interrupts 8-256 Priorities Cortex-M3 CPU Core (5-pins) Trace Port SYSTICK TPIU Trace Port Serial-Wire Viewer (1-pin) DAP JTAG/SWD Memory Protection Unit ITM Instrumentation Trace FPB BKPT DWT Data Trace Bus Matrix Code Buses to Flash to Code SRAM System Bus to Stack SRAM to Peripherals © Feabhas Ltd. 1995-2012

Instrumentation Trace Macrocell (ITM) Generates several types of Trace Packets Software trace Software can write directly to ITM, causing packets to be emitted Similar to using printf() to debug a C program Hardware trace Packets are generated by the DWT and emitted by the ITM Timestamps Cortex-M3 CPU Core ETM Instruction Trace NVIC 1-240 Interrupts 8-256 Priorities (5-pins) Trace Port SYSTICK TPIU Trace Port Instr. Data Serial-Wire Viewer (1-pin) DAP JTAG/SWD Memory Protection Unit ITM Instrumentation Trace External Private Peripheral Bus ROM tables FPB BKPT DWT Data Trace APB i/f Internal Private Peripheral Bus Bus Matrix Code Buses to Flash to Code SRAM System Bus to Stack SRAM to Peripherals © Feabhas Ltd. 1995-2012

ITM Based Error Message Output void printErrorMsg(const char * errMsg) { while(*errMsg != '\0'){ ITM_SendChar(*errMsg); ++errMsg; } Copyright (c) Feabhas Ltd. 1995-2013

Error Message Output Copyright (c) Feabhas Ltd. 1995-2013

Hard Fault Status Register (HFSR) Within the Cortex-M3's System Control Block (SCB) is the HardFault Status Register (HFSR). CMSIS defines symbols giving access these register (SCB->HFSR) void HardFault_Handler(void) { static char msg[80]; printErrorMsg("In Hard Fault Handler\n"); sprintf(msg, "SCB->HFSR = 0x%08x\n", SCB->HFSR); printErrorMsg(msg); __ASM volatile("BKPT #01"); while(1); } Copyright (c) Feabhas Ltd. 1995-2013

Hard Fault Status Register (HFSR) By examining the HFSR bit configuration, we can see that the FORCED bit is set. 1 When this bit is set to 1, the HardFault handler must read the other fault status registers to find the cause of the fault. Copyright (c) Feabhas Ltd. 1995-2013

Configurable Fault Status Register (SCB->CFSR) A forced hard fault may be caused by a bus fault, a memory fault, or as in our case, a usage fault. For brevity, here we're only going to focus on the Usage Fault Copyright (c) Feabhas Ltd. 1995-2013

Updated Fault Handler for FORCED flag So given what we know to date, our basic Fault Handler can be updated to: check if the FORCED bit is set ( if ((SCB->HFSR & (1 << 30)) != 0) ) and if so, print out the contents of the CFSR void HardFault_Handler(void) { static char msg[80]; printErrorMsg("In Hard Fault Handler\n"); sprintf(msg, "SCB->HFSR = 0x%08x\n", SCB->HFSR); printErrorMsg(msg); if ((SCB->HFSR & (1 << 30)) != 0) { printErrorMsg("Forced Hard Fault\n"); sprintf(msg, "SCB->CFSR = 0x%08x\n", SCB->CFSR ); } __ASM volatile("BKPT #01"); while(1); Copyright (c) Feabhas Ltd. 1995-2013

CFSR Output Copyright (c) Feabhas Ltd. 1995-2013

Usage Fault Status Register (UFSR) The bit configuration of the UFSR is shown below, and unsurprisingly the output shows that bit 9 (DIVBYZERO) is set. 1 We can now extend the HardFault handler to mask the top half of the CFSR, and if not zero then further report on those flags, as in: Copyright (c) Feabhas Ltd. 1995-2013

UFSR Fault Message void HardFault_Handler(void) { static char msg[80]; printErrorMsg("In Hard Fault Handler\n"); sprintf(msg, "SCB->HFSR = 0x%08x\n", SCB->HFSR); printErrorMsg(msg); if ((SCB->HFSR & (1 << 30)) != 0) { printErrorMsg("Forced Hard Fault\n"); sprintf(msg, "SCB->CFSR = 0x%08x\n", SCB->CFSR ); if((SCB->CFSR & 0x030F0000) != 0) { printUsageErrorMsg(SCB->CFSR); } __ASM volatile("BKPT #01"); while(1); void printUsageErrorMsg(uint32_t CFSRValue) printErrorMsg("Usage fault: "); CFSRValue >>= 16; // right shift to lsb if((CFSRValue & (1<<9)) != 0) { printErrorMsg("Divide by zero\n"); Copyright (c) Feabhas Ltd. 1995-2013

Usage Fault Output Copyright (c) Feabhas Ltd. 1995-2013

Register dump One final thing we can do as part of any fault handler is to dump out known register contents as they were at the time of the exception. One really useful feature of the Cortex-M architecture is that a core set of registers are automatically stacked (by the hardware) as part of the exception handling mechanism. Copyright (c) Feabhas Ltd. 1995-2013

Interrupt Register Usage ISR functions do not require compiler specific directives All managed in hardware Upon receiving an interrupt, the processor will finish current instruction Some opcodes may be interrupted for better interrupt latency Then, processor state automatically saved to the stack over the data bus {PC, R0-R3, R12, R14, xPSR} On Cortex-M3/M4, in parallel, the ISR address is prefetched on the instruction bus ISR ready to start executing as soon as stack push is complete r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13/sp r14/lr r15/pc xPSR Copyright (c) Feabhas Ltd. 1995-2013

Set of stacked registers Copyright (c) Feabhas Ltd. 1995-2013

Procedure Call Standard for the ARM Architecture ARM have defined a set of rules for function entry/exit This is part of ARM’s ABI and is referred to as the ARM Architecture Procedure Call Standard (AAPCS), e.g. Register Synonym Role R0 a1 Argument 1 / word result R1 a2 Argument 2 / double-word result R2 a3 Argument 3 R3 a4 Argument 4 More complex returns are passed via an address stored in a1 Sub-word sized arguments will still use a whole register char and short double-word arguments will be passed in multiple registers double and long long © Feabhas Ltd. 1995-2012

AAPCS Register Usage Result(s) from function Arguments into function otherwise usable as scratch r1 r2 r3 r4 r5 r6 Register variables Must be preserved r7 r8 r9 r10 r11 Scratch register (corruptible) r12 Stack Pointer Link Register Program Counter r13/SP r14/LR r15/PC © Feabhas Ltd. 1995-2012

Parameter Passing (4 Parameters or fewer) int callerP4(void) { return funcP4(1,2,3,4); } callerP4 PROC ;;;1 int callerP4(void) ;;;2 { ;;;3 return funcP4(1,2,3,4); 000000 2304 MOVS r3,#4 000002 2203 MOVS r2,#3 000004 2102 MOVS r1,#2 000006 2001 MOVS r0,#1 000008 f7ffbffe B.W funcP4 ;;;4 } ;;;5 ENDP R0 a R1 b R2 c R3 d int funcP4(int a, int b, int c, int d) { return a+b+c+d; } **ANIMATED** The PUSH in caller2 looks like it stores too many registers (no need to preserve r0-r3 on entry to a function). However the compiler only moves the stack pointer once per function – the extra stores are to make space for the later store of arguments 5 and 6. This accounts for r2 and r3. r4 is stored simply to maintain 8 byte stack alignment. The 6 parameter version is (a) longer in terms of code size and (b) involves stack accesses to external memory which will be slow (especially with stack in slow and/or narrow memory). Note the tail-call optimisation in the first case. This cannot be done in the second case since the stack is in used to pass parameters. See how func2 doesn’t need to preserve 8 byte stack alignment because it is a leaf function. If caller2 is compiled with v5TE & later architectures, the STM of two registers will be replaced by STRD instruction. Taking one step further, if compiled with v7 the LDMIB in func2 will be replaced by LDRD too.

Using the AAPCS Using this knowledge in conjunction with AAPCS we can get access to these register values. First we modify our original HardFault handler by: modifying it's name to “Hard_Fault_Handler” (no weak linkage) adding a parameter declared as an array of 32–bit unsigned integers. void Hard_Fault_Handler(uint32_t stack[]) Based on AAPCS rules, we know that the parameter label (stack) will map onto register r0. Copyright (c) Feabhas Ltd. 1995-2013

New HardFault_Handler We now implement the actual HardFault_Handler. This function simply copies the current Main Stack Pointer (MSP) into r0 and then branches to our renamed Hard_Fault_Handler (this is based on ARM/Keil syntax): __asm void HardFault_Handler(void) { MRS r0, MSP; B __cpp(Hard_Fault_Handler) } Copyright (c) Feabhas Ltd. 1995-2013

StackDump function stack[0] Finally we implement a function to dump the stack values based on their relative offset enum { r0, r1, r2, r3, r12, lr, pc, psr}; void stackDump(uint32_t stack[]) { static char msg[80]; sprintf(msg, "r0 = 0x%08x\n", stack[r0]); printErrorMsg(msg); sprintf(msg, "r1 = 0x%08x\n", stack[r1]); sprintf(msg, "r2 = 0x%08x\n", stack[r2]); sprintf(msg, "r3 = 0x%08x\n", stack[r3]); sprintf(msg, "r12 = 0x%08x\n", stack[r12]); sprintf(msg, "lr = 0x%08x\n", stack[lr]); sprintf(msg, "pc = 0x%08x\n", stack[pc]); sprintf(msg, "psr = 0x%08x\n", stack[psr]); } stack[0] Copyright (c) Feabhas Ltd. 1995-2013

Stack Dump Output This function can then be called from the Fault handler, passing through the stack argument. Running the program should result is the following output: Examining the output, we can see that the program counter (pc) is reported as being the value 0x00000272, giving us the opcode generating the fault. Copyright (c) Feabhas Ltd. 1995-2013

Tracing the PC If we disassemble the image using the command: fromelf -c CM3_Fault_Handler.axf —output listing.txt By trawling through the listing (listing.txt) we can see the SDIV instruction at offending line (note also r2 contains 10 and r1 the offending 0). .text div 0x00000270: 4602 MOV r2,r0 0x00000272: fb92f0f1 SDIV r0,r2,r1 0x00000276: 4770 BX lr Copyright (c) Feabhas Ltd. 1995-2013

Dealing with the Cortex-M Operational modes Privileged Execution Exception Power-up/ Reset Thread Mode Handler Mode Exception exit Exception exit CONTROL[0] = 1 User Thread Mode Exception Copyright (c) Feabhas Ltd. 1995-2013

Operational modes – No RTOS Privileged Execution Exception Power-up/ Reset Thread Mode Handler Mode Exception exit Privileged execution has full access to all processor, NVIC and MPU registers Copyright (c) Feabhas Ltd. 1995-2013

Operational modes - RTOS Privileged Execution SVC Power-up/ Reset Thread Mode Handler Mode Exception exit Exception To change between Privileged mode and User Thread mode when returning from an exception by modify the EXC_RETURN value in the link register (R14). User Thread Mode User Thread Mode cannot access certain registers with generating a Hard Fault exception Stack Pointer Link Register Program Counter r13/SP Process SP Main SP r14/LR r15/PC Copyright (c) Feabhas Ltd. 1995-2013

Thread / Handler mode __asm void HardFault_Handler(void) { Finally, if you're going to use the privilege/non–privilege model, you'll need to modify the HardFault_Handler to detect whether the exception happened in Thread mode or Handler mode. This can be achieved by checking bit 3 of the HardFault_Handler's Link Register (lr) value. Bit 3 determines whether on return from the exception, the Main Stack Pointer (MSP) or Process Stack Pointer (PSP) is used. __asm void HardFault_Handler(void) { TST lr, #4 // Test for MSP or PSP ITE EQ MRSEQ r0, MSP MRSNE r0, PSP B __cpp(Hard_Fault_Handler) } Copyright (c) Feabhas Ltd. 1995-2013

Final Notes The initial model for fault handling can be found in Joseph Yiu's excellent book “The Definitive Guide to the ARM Cortex-M3” The code shown was built using the ARM/Keil MDK-ARM Version 4.60 development environment (a 32Kb size limited evaluation is available from the Keil website) The code, deliberately, has not been refactored to remove the hard-coded (magic) values. Code available on GitHub at git://github.com/feabhas/CM3_Fault_Handler Copyright (c) Feabhas Ltd. 1995-2013

Thank You Niall Cooling Feabhas Limited 5 Lowesden Works Lambourn Woodlands Hungerford Berks. RG17 7RY UK +44 1488 73050 www.feabhas.com niall.cooling(at)feabhas.com @feabhas blog.feabhas.com uk.linkedin.com/in/nscooling Copyright (c) Feabhas Ltd. 1995-2013