-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathgpio_mode6_interrupts.asm
380 lines (270 loc) · 9.24 KB
/
gpio_mode6_interrupts.asm
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
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
; AGON GPIO INTERRUPTS
; Richard Turnnidge 2025
; Mode 6 example
; ---------------------------------------------
;
; MACROS
;
; ---------------------------------------------
macro MOSCALL function
ld a, function
rst.lil $08
endmacro
; ---------------------------------------------
macro TABTO x, y
ld a, 31
rst.lil $10
ld a, x
rst.lil $10
ld a, y
rst.lil $10
endmacro
; ---------------------------------------------
macro CLS
ld a, 12
rst.lil $10
endmacro
; ---------------------------------------------
macro SETCURSOR value ; to set cursor visible or not [0 or 1]
push af
ld a, 23
rst.lil $10
ld a, 1
rst.lil $10
ld a, value
rst.lil $10 ; VDU 23,1,value [0 off, 1 on]
pop af
endmacro
; ---------------------------------------------
;
; CONSTANTS
;
; ---------------------------------------------
; GPIO port IDs
PC_DR: equ $9E
PC_DDR: equ $9F
PC_ALT1: equ $A0
PC_ALT2: equ $A1
; ---------------------------------------------
;
; INITIALISE AGON
;
; ---------------------------------------------
.assume adl=1 ; big memory mode
.org $40000 ; load code here
jp start_here ; jump to start of code
.align 64 ; MOS header
.db "MOS",0,1
; ---------------------------------------------
;
; INITIAL SETUP CODE HERE
;
; ---------------------------------------------
start_here:
push af ; store everything as good practice
push bc ; pop back when we return from code later
push de
push ix
push iy
im 2 ; make sure running in interrupt mode 2
CLS ; clear screen before we start
SETCURSOR 0 ; hide the cursor
TABTO 2,8 ; TAB to title position
ld hl, msg_title ; put address of message into HL
call printString ; print the demo title
call setup_GPIO_ports ; configure the GPIO pin settings
call start_GPIO_interrupts ; start the interrupt listener
; ---------------------------------------------
;
; MAIN LOOP
;
; ---------------------------------------------
MAIN_LOOP:
get_key_input:
MOSCALL $08 ; get IX pointer to sysvars
ld a, (ix + 05h) ; ix+5h is 'last key pressed'
cp 27 ; is it ESC key?
jp z, exit_here ; if so exit cleanly
jp MAIN_LOOP ; loop around until ESC is pressed
; ---------------------------------------------
;
; EXIT CODE CLEANLY
;
; ---------------------------------------------
exit_here:
call reset_GPIO ; reset GPIO port C to defaults
CLS ; clear the screen
SETCURSOR 1 ; show cursor
pop iy
pop ix
pop de
pop bc
pop af
ld hl,0 ; reset all values before returning to MOS
ret ; return to MOS here
; ---------------------------------------------
;
; IO PORT INIT
;
; ---------------------------------------------
;
; This example uses GPIO Interrupt mode 6 - level-sensitive interrupts
;
; For each pin used, we set:-
; Data Register (DR) 1
; Data Direction Register (DDR) 0
; Alt1 register (ALT1) 0
; Alt2 register (ALT2) 1
;
; We are only working with interrupts on GPIO pins PC0 and PC1 in this example
; It defines pins 0 & 1 as interrupt driven input, and pins 2-7 as outputs
setup_GPIO_ports:
di ; stop any interrupts whle we configure
ld a, 00000011b
out0 (PC_DR), a ; set DR of PC0 and PC1 to 1
ld a, 00000000b
out0 (PC_DDR), a ; set DDR of register to 0
ld a, 00000000b
out0 (PC_ALT1), a ; set ALT1 of register to 0
ld a, 00000011b
out0 (PC_ALT2), a ; set ALT2 of PC0 and PC1 to 1
ei ; re-enable the interrupts
ret
; ---------------------------------------------
start_GPIO_interrupts:
ld hl, isr_gpio_PC0_event ; address of service routine to call
ld e, $40 ; interrupt vector (GPIO Port PC0)
MOSCALL $14 ; mos_api_setintvector
ld hl, isr_gpio_PC1_event ; address of service routine to call
ld e, $42 ; interrupt vector (GPIO Port PC1)
MOSCALL $14 ; mos_api_setintvector
ret
; ---------------------------------------------
; reset all of GPIO port C to default values
; ie. standard inputs
reset_GPIO:
di ; stop any interrupts whle we configure
ld a, $00
out0 (PC_DR), a ; set DR of all port C to 0
ld a, $FF
out0 (PC_DDR), a ; set DDR of all port C to 0
ld a, $00
out0 (PC_ALT1), a ; set ALT1 of all port C to 0
ld a, $00
out0 (PC_ALT2), a ; set ALT2 of all port C to 0
ei ; re-enable the interrupts
ret
; ---------------------------------------------
;
; INTERRUPT SERVICE ROUTINES
;
; GPIO interrupt service routine for pins PC 0 & 1
; Triggered when status changes from high to low, or vice versa
;
; ---------------------------------------------
isr_gpio_PC0_event:
di ; stop any other interrupts while we do this
push hl
push af ; store any registers we are going to use
in0 a, (PC_DR) ; read the current status of the GPIO PC pins
ld (lastPortC), a ; store latest port data
bit 0, a ; check status of the the GPIO pin we want (pin PC0)
jr nz, @released ; decide if pressed or released
@pressed:
ld hl, msg_PC0_pressed ; put address of message into HL
jr @end ; jump ahead
@released:
ld hl, msg_PC0_released ; put address of message into HL
@end:
or 00000011b ; only change bits 1 & 0, leave others as they are
out0 (PC_DR), a ; set DR of port C to acknowledge interrupt
TABTO 2,12 ; TAB to print text
call printString ; print the message
call displayPortC ; display purely for info, in binary format
pop af
pop hl ; retrieve registers we have used
ei ; re-enable interrupts for next time
reti.l ; return from interrupt routine
; ---------------------------------------------
isr_gpio_PC1_event:
di ; stop any other interrupts while we do this
push hl
push af ; store any registers we are going to use
in0 a, (PC_DR) ; read the current status of the GPIO PC pins
ld (lastPortC), a ; store latest port data
bit 1, a ; check status of the the GPIO pin we want (pin PC1)
jr nz, @released ; decide if pressed or released
@pressed:
ld hl, msg_PC1_pressed ; put address of message into HL
jr @end ; jump ahead
@released:
ld hl, msg_PC1_released ; put address of message into HL
@end:
or 00000011b ; only change bits 1 & 0, leave others as they are
out0 (PC_DR), a ; set DR of port C to acknowledge interrupt
TABTO 2,14 ; TAB to print text
call printString ; print the message
call displayPortC ; display purely for info, in binary format
pop af
pop hl ; retrieve registers we have used
ei ; re-enable interrupts for next time
reti.l ; return from interrupt routine
; ---------------------------------------------
displayPortC:
TABTO 2,17 ; TAB to print text
ld a, (lastPortC) ; retrieve the latest port value (need original value)
call printBin ; display purely for info, in binary format
ret
lastPortC: .db 0
; ---------------------------------------------
;
; OTHER ROUTINES
;
; ---------------------------------------------
; print zero terminated string
; Any char apart from zero will be sent to VDP
printString:
ld a,(hl) ; put char byte into A
or a ; check if zero
ret z ; return if it is, as we are at the end of the zero terminated string
rst.lil $10 ; send byte A to VDP
inc hl ; move to next byte in the string
jr printString ; loop around and test next byte
; ---------------------------------------------
; take A as number and print out as binary
; will destroy HL, BC
printBin:
push bc ; store BC for later
ld b, 8 ; number of bits to do
ld hl, binString
@rpt:
ld (hl), 48 ; set our byte to '0' as default
bit 7, a ; check if bit is set
jr z, @nxt ; if not, move on to next bit
ld (hl), 49 ; set our byte to '1'
@nxt:
inc hl ; set next position in output 'binString'
rla ; rotate byte A so that bit 7 is next bit
djnz @rpt ; loop round until done 8 times
ld hl, binString ; HL is address of the 'binary' string of 8 bytes
call printString ; print the string at HL
pop bc ; restore BC
ret
binString: .asciz "00000000" ; 8 chars plus a zero
; ---------------------------------------------
;
; text data
;
; ---------------------------------------------
; the title printed first
msg_title: .asciz "GPIO Interrupt Handler "
; some messages with coloured text
msg_PC0_pressed: .asciz 17, 15, "Pin PC0 ", 17, 13, "LOW (PRESSED) ", 17, 15
msg_PC0_released: .asciz 17, 15, "Pin PC0 ", 17, 9, "HIGH (RELEASED) ", 17, 15
msg_PC1_pressed: .asciz 17, 15, "Pin PC1 ", 17, 14, "LOW (PRESSED) ", 17, 15
msg_PC1_released: .asciz 17, 15, "Pin PC1 ", 17, 12, "HIGH (RELEASED) ", 17, 15
; ---------------------------------------------
;
; END
;
; ---------------------------------------------