1 /* (CC-BY-NC-SA) ROBIN KRENS - ROBIN @ ROBINKRENS.NL
4 * 2019/7/20 - ROBIN KRENS
8 * Set up of basic exceptions and interrupts. These interrupts
9 * don't do much, except for halting the system.
10 * ivt_set_gate(interrupt nr, function, priority) can be used
11 * later to define more appropriate handling. See timer (timer.c)
12 * or serial or (uart.c) handling for non-trivial examples.
14 * The actual code is not much, but there are a lot of details
15 * to consider. Besides that, in case more control is desired over
16 * entering and exiting interrupts (what is pushed on the stack)
17 * A so-called naked function can be used. See below for more
27 #include <sys/robsys.h>
30 #include <lib/stdio.h>
31 #include <lib/string.h>
32 #include <lib/regfunc.h>
33 #include <lib/tinyprintf.h>
36 * These values are pushed on the stack just before
37 * entering the ISR. I use a so-called
38 * 'naked function' __attribute__ ((naked)) which
39 * gives me a little bit more control over the caller
41 * The following register are pushed to the stack
45 struct interrupt_frame {
58 * Vector table, each entry contains an interrupt
60 * interrupt vector 1-15: processor exceptions
61 * interrupt vector 16-92: irq0 - irq ..
62 * Vector table needs to be aligned in memory.
64 uint32_t __attribute__((aligned(0x100))) ivt[92];
66 /* Each message corresponds to an exception in the vector table. */
67 char * exception_message(uint8_t intnr) {
96 if (intnr < 20) // TODO: strlen
97 return messages[intnr];
103 /* Function to set entries of the interrupt vector table
105 void ivt_set_gate(unsigned char num, void * isr(), short pri) {
107 ivt[num] = (uint32_t) isr;
109 //*NVIC_ISER0 = (1 << ((uint32_t)(num) & 0x1F));
110 /* TODO: Priorities */
114 /* Dummy interrupt: shows the saved stack registers and then
116 __attribute__ ((naked)) void * dummy_isr(void) {
118 uint32_t * current_sp;
120 /* Test whether system call was invoked from supervisor (use MSP) or
121 * user (use PSP) mode */
125 "mrseq %0, msp" "\n\t"
126 "mrsne %0, psp" : "=r" (current_sp));
128 memcpy(&frame, current_sp, sizeof(struct interrupt_frame));
130 uint8_t nr = *SCB_ICSR & 0xFF;
131 printf("EXCEPTION: %s\n", exception_message(nr));
132 printf("STACKFRAME:\n");
133 printf("R0:%p\n",frame.r0);
134 printf("R1:%p\n",frame.r1);
135 printf("R2:%p\n",frame.r2);
136 printf("R3:%p\n",frame.r3);
137 printf("R12:%p\n",frame.r12);
138 printf("LR:%p\n",frame.lr);
139 printf("PC:%p (<-- last function call)\n",frame.pc);
140 printf("PSR:%p\n",frame.psr);
142 printf("CPU STATUS:");
143 printf("%x\n", *SCB_CFSR);
147 /* Initialize interrupt vector */
150 /* clear entire IVT location in memory */
151 memset(&ivt, 0, (sizeof(uint32_t) * 92));
153 /* The reset, NMI and hardfault handlers are originally
154 * defined in the assembly start up and can be
155 * reused or overwritten.
157 extern void * reset, * nmi, * hardfault;
159 /* set dummy handlers */
160 for (int i = 1; i <= 64 ; i++) {
161 ivt_set_gate(i, dummy_isr, 0);
165 /* Enable memory management, bus and usage fault exceptions handlers
166 * If these are not enabled, the processor treats them as a hard
167 * faults. Unpriviliged access will cause a busfault in case no MPU */
168 rsetbit(SCB_SHCSR, 16); // MPU violation
169 rsetbit(SCB_SHCSR, 17); // Bus faults
170 rsetbit(SCB_SHCSR, 18); // Usage faults
172 /* Enable various other faults */
173 // rsetbit(SCB_CCR, 4); // division by zero, (needed if you write a lot
174 // of assembly, otherwise the compiler probably leave these divisions out
177 /* The vector table is intially at 0x0. The vector table can be
178 * relocated to other memory locations. We can do this by setting
179 * a register in the NVIC called the vector table offset register */
181 rwrite(SCB_VTOR, (uint32_t) &ivt);