1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
|
//go:build esp32c3
package interrupt
import (
"device/esp"
"device/riscv"
"errors"
"runtime/volatile"
"unsafe"
)
// Enable register CPU interrupt with interrupt.Interrupt.
// The ESP32-C3 has 31 CPU independent interrupts.
// The Interrupt.New(x, f) (x = [1..31]) attaches CPU interrupt to function f.
// Caller must map the selected interrupt using following sequence (for example using id 5):
//
// // map interrupt 5 to my XXXX module
// esp.INTERRUPT_CORE0.XXXX_INTERRUPT_PRO_MAP.Set( 5 )
// _ = Interrupt.New(5, func(interrupt.Interrupt) {
// ...
// }).Enable()
func (i Interrupt) Enable() error {
if i.num < 1 && i.num > 31 {
return errors.New("interrupt for ESP32-C3 must be in range of 1 through 31")
}
mask := riscv.DisableInterrupts()
defer riscv.EnableInterrupts(mask)
// enable CPU interrupt number i.num
esp.INTERRUPT_CORE0.CPU_INT_ENABLE.SetBits(1 << i.num)
// Set pulse interrupt type (rising edge detection)
esp.INTERRUPT_CORE0.CPU_INT_TYPE.SetBits(1 << i.num)
// Set default threshold to defaultThreshold
reg := (*volatile.Register32)(unsafe.Add(unsafe.Pointer(&esp.INTERRUPT_CORE0.CPU_INT_PRI_0), i.num*4))
reg.Set(defaultThreshold)
// Reset interrupt before reenabling
esp.INTERRUPT_CORE0.CPU_INT_CLEAR.SetBits(1 << i.num)
esp.INTERRUPT_CORE0.CPU_INT_CLEAR.ClearBits(1 << i.num)
// we must wait for any pending write operations to complete
riscv.Asm("fence")
return nil
}
// Adding pseudo function calls that is replaced by the compiler with the actual
// functions registered through interrupt.New.
//
//go:linkname callHandlers runtime/interrupt.callHandlers
func callHandlers(num int)
const (
IRQNUM_1 = 1 + iota
IRQNUM_2
IRQNUM_3
IRQNUM_4
IRQNUM_5
IRQNUM_6
IRQNUM_7
IRQNUM_8
IRQNUM_9
IRQNUM_10
IRQNUM_11
IRQNUM_12
IRQNUM_13
IRQNUM_14
IRQNUM_15
IRQNUM_16
IRQNUM_17
IRQNUM_18
IRQNUM_19
IRQNUM_20
IRQNUM_21
IRQNUM_22
IRQNUM_23
IRQNUM_24
IRQNUM_25
IRQNUM_26
IRQNUM_27
IRQNUM_28
IRQNUM_29
IRQNUM_30
IRQNUM_31
)
const (
defaultThreshold = 5
disableThreshold = 10
)
//go:inline
func callHandler(n int) {
switch n {
case IRQNUM_1:
callHandlers(IRQNUM_1)
case IRQNUM_2:
callHandlers(IRQNUM_2)
case IRQNUM_3:
callHandlers(IRQNUM_3)
case IRQNUM_4:
callHandlers(IRQNUM_4)
case IRQNUM_5:
callHandlers(IRQNUM_5)
case IRQNUM_6:
callHandlers(IRQNUM_6)
case IRQNUM_7:
callHandlers(IRQNUM_7)
case IRQNUM_8:
callHandlers(IRQNUM_8)
case IRQNUM_9:
callHandlers(IRQNUM_9)
case IRQNUM_10:
callHandlers(IRQNUM_10)
case IRQNUM_11:
callHandlers(IRQNUM_11)
case IRQNUM_12:
callHandlers(IRQNUM_12)
case IRQNUM_13:
callHandlers(IRQNUM_13)
case IRQNUM_14:
callHandlers(IRQNUM_14)
case IRQNUM_15:
callHandlers(IRQNUM_15)
case IRQNUM_16:
callHandlers(IRQNUM_16)
case IRQNUM_17:
callHandlers(IRQNUM_17)
case IRQNUM_18:
callHandlers(IRQNUM_18)
case IRQNUM_19:
callHandlers(IRQNUM_19)
case IRQNUM_20:
callHandlers(IRQNUM_20)
case IRQNUM_21:
callHandlers(IRQNUM_21)
case IRQNUM_22:
callHandlers(IRQNUM_22)
case IRQNUM_23:
callHandlers(IRQNUM_23)
case IRQNUM_24:
callHandlers(IRQNUM_24)
case IRQNUM_25:
callHandlers(IRQNUM_25)
case IRQNUM_26:
callHandlers(IRQNUM_26)
case IRQNUM_27:
callHandlers(IRQNUM_27)
case IRQNUM_28:
callHandlers(IRQNUM_28)
case IRQNUM_29:
callHandlers(IRQNUM_29)
case IRQNUM_30:
callHandlers(IRQNUM_30)
case IRQNUM_31:
callHandlers(IRQNUM_31)
}
}
//export handleInterrupt
func handleInterrupt() {
mcause := riscv.MCAUSE.Get()
exception := mcause&(1<<31) == 0
interruptNumber := uint32(mcause & 0x1f)
if !exception && interruptNumber > 0 {
// save MSTATUS & MEPC, which could be overwritten by another CPU interrupt
mstatus := riscv.MSTATUS.Get()
mepc := riscv.MEPC.Get()
// Using threshold to temporary disable this interrupts.
// FYI: using CPU interrupt enable bit make runtime to loose interrupts.
reg := (*volatile.Register32)(unsafe.Add(unsafe.Pointer(&esp.INTERRUPT_CORE0.CPU_INT_PRI_0), interruptNumber*4))
thresholdSave := reg.Get()
reg.Set(disableThreshold)
riscv.Asm("fence")
interruptBit := uint32(1 << interruptNumber)
// reset pending status interrupt
if esp.INTERRUPT_CORE0.CPU_INT_TYPE.Get()&interruptBit != 0 {
// this is edge type interrupt
esp.INTERRUPT_CORE0.CPU_INT_CLEAR.SetBits(interruptBit)
esp.INTERRUPT_CORE0.CPU_INT_CLEAR.ClearBits(interruptBit)
} else {
// this is level type interrupt
esp.INTERRUPT_CORE0.CPU_INT_CLEAR.ClearBits(interruptBit)
}
// enable CPU interrupts
riscv.MSTATUS.SetBits(1 << 3)
// Call registered interrupt handler(s)
callHandler(int(interruptNumber))
// disable CPU interrupts
riscv.MSTATUS.ClearBits(1 << 3)
// restore interrupt threshold to enable interrupt again
reg.Set(thresholdSave)
riscv.Asm("fence")
// restore MSTATUS & MEPC
riscv.MSTATUS.Set(mstatus)
riscv.MEPC.Set(mepc)
// do not enable CPU interrupts now
// the 'MRET' in src/device/riscv/handleinterrupt.S will copies the state of MPIE back into MIE, and subsequently clears MPIE.
// riscv.MSTATUS.SetBits(0x8)
} else {
// Topmost bit is clear, so it is an exception of some sort.
// We could implement support for unsupported instructions here (such as
// misaligned loads). However, for now we'll just print a fatal error.
handleException(mcause)
}
}
func handleException(mcause uintptr) {
println("*** Exception: pc:", riscv.MEPC.Get())
println("*** Exception: code:", uint32(mcause&0x1f))
println("*** Exception: mcause:", mcause)
switch uint32(mcause & 0x1f) {
case 1:
println("*** virtual addess:", riscv.MTVAL.Get())
case 2:
println("*** opcode:", riscv.MTVAL.Get())
case 5:
println("*** read address:", riscv.MTVAL.Get())
case 7:
println("*** write address:", riscv.MTVAL.Get())
}
for {
riscv.Asm("wfi")
}
}
|