Basic functionality for TM1637
[cortex-from-scratch] / ivt.c
1 /* (CC-BY-NC-SA) ROBIN KRENS - ROBIN @ ROBINKRENS.NL
2  * 
3  * $LOG$
4  * 2019/7/20 - ROBIN KRENS      
5  * Initial version 
6  * 
7  * $DESCRIPTION$
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.
13  *
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
18  * details.
19  * 
20  *
21  * */
22
23 #include <stdbool.h>
24 #include <stddef.h>
25 #include <stdint.h>
26
27 #include <sys/robsys.h>
28 #include <sys/mmap.h>
29
30 #include <lib/stdio.h>
31 #include <lib/string.h>
32 #include <lib/regfunc.h>
33
34 /* 
35  * These values are pushed on the stack just before
36  * entering the ISR. Normally, this would require
37  * assembly or inline assembly code. I use a so-called
38  * 'naked function' __attribute__ ((interrupt)) which
39  * gives me a little bit more control over the caller
40  *
41  * The following register are pushed to the stack
42  * in reverse order:
43  *
44  * */
45 struct interrupt_frame {
46
47         uint32_t r0; // N-32
48         uint32_t r1;
49         uint32_t r2;
50         uint32_t r3;
51         uint32_t r12;
52         uint32_t lr;
53         uint32_t pc;
54         uint32_t psr; // N-4
55 };
56
57 /* 
58  * Vector table, each entry contains an interrupt
59  * service routine: 
60  * interrupt vector 1-15: processor exceptions
61  * interrupt vector 16-92: irq0 - irq ..
62  * Vector table needs to be aligned in memory.
63  * */
64 uint32_t __attribute__((aligned(0x100))) ivt[92];
65
66 /* Each message corresponds to each and every exception. */
67 char * exception_message(uint8_t intnr) {
68
69 char * messages[] = {
70     "--",
71     "RESET",
72     "NMI",
73     "HARD FAULT",
74     "MEMMANAGE FAULT",
75     "BUS FAULT",
76     "USAGE FAULT",
77     "RESERVED",
78     "SVC",
79     "DEBUG MONITOR",
80     "RESERVED",
81     "RESERVED",
82     "RESERVED",
83     "RESERVED",
84     "PENDSV",
85     "SYSTICK",
86     "IRQ1",
87     "IRQ2",
88     "IRQ3",
89     "IRQ4",
90     // add more if needed
91 };
92
93 if (intnr < 20) // TODO: strlen
94         return messages[intnr];
95         return NULL;
96 }
97
98 void ivt_set_gate(unsigned char num, void * isr(), short pri) {
99
100         ivt[num] = (uint32_t) isr;
101         *NVIC_ISER0 = (1 << ((uint32_t)(num) & 0x1F));
102         /* TODO: Priorities */
103 }
104
105
106 /* Dummy interrupt: comment out the comment to use a naked
107  * function */
108
109 // __attribute__ ((interrupt)) 
110 void * dummy_isr(/* struct interrupt_frame * frame */) {
111
112         uint8_t nr = *SCB_VTOR_ST & 0xFF;
113         
114         cputs("EXCEPTION: ");
115         cputs(exception_message(nr));
116         cputs("\nSYSTEM HALTED\n");
117         
118         for(;;);
119 }
120
121 /* Initialize interrupt vector  */
122 void ivt_init() {
123
124         /* clear entire IVT location in memory  */
125         memset(&ivt, 0, (sizeof(uint32_t) * 92));
126
127         /* The reset, NMI and hardfault handlers are originally
128          * defined in the assembly start up and can be 
129          * reused or overwritten. 
130         *  */
131         extern void * reset,  * nmi, * hardfault;
132
133         // set dummy handlers 
134         for (int i = 1; i <= 64 ; i++) {
135                 ivt_set_gate(i, dummy_isr, 0);
136         }
137
138         /* The vector table is intially at 0x0. The vector table can be
139          * relocated to other memory locations. We can do this by setting 
140          * a register in the NVIC called the vector table offset register */
141
142         regw_u32(SCB_VTOR, (uint32_t) &ivt, 0, OWRITE);
143
144 }