|
| 1 | +@ Amanda Falke 2015 |
| 2 | +@ Sitara ARM GPIO LED Pulse Train |
| 3 | +@ Using ARM Assembly, this program implements GPIO button interrupts, |
| 4 | +@ timer interrupts (a sort of pre-emption), for an LED pulse train. |
| 5 | +@ |
| 6 | +@ Engin-nerds beware: This program goes over 80 cols. |
| 7 | + |
| 8 | + |
| 9 | +.text |
| 10 | +.global _start |
| 11 | +.global INT_DIRECTOR |
| 12 | +_start: |
| 13 | + |
| 14 | +@ MAPPING of GPIO2_1 to PIN 18 via gpmc_clk register mapping: |
| 15 | +LDR R6, =0x44E1088C |
| 16 | +MOV R7, #0x00000027@ copy word to set bits 5, and 0-2 to mode7 |
| 17 | +LDR R8,[R6]@ READ from it, |
| 18 | +ORR R8, R7, R8@ MODIFY Control Module Reg with mode 7, |
| 19 | +STR R8, [R6]@ WRITE to Control Module register. |
| 20 | + |
| 21 | + |
| 22 | +@ Note: Interrupt vector table redirects IRQ to INT_DIRECTOR via hook and chain method. |
| 23 | +
|
| 24 | + |
| 25 | +LDR R13,=STACK1 @ Point to base of STACK for SVC mode |
| 26 | +ADD R13, R13, #0x1000@ point to top of stack |
| 27 | +CPS #0x12@ Switch to IRQ mode |
| 28 | +LDR R13,=STACK2 @ Point to IRQ Stack |
| 29 | +ADD R13, R13, #0x1000@ Point to top of Stack |
| 30 | +CPS #0x13@ back to SVC mode |
| 31 | + |
| 32 | + |
| 33 | +LDR R0,=0x4804C000@GPIO1 Base Address |
| 34 | +LDR R1,=0x481AC000@GPIO2 Base Address |
| 35 | + |
| 36 | + |
| 37 | +INT_CLEAR: |
| 38 | +ADD R4, R0, #0x190@ GPIO1_CLEARDATAOUT register, |
| 39 | +MOV R7, #0x01E00000@ LOAD VALUE TO TURN OFF ALL LED'S, |
| 40 | +STR R7, [R4]@ TURN OFF ALL LED'S, |
| 41 | +ADD R2, R0, #0x134@ MAKE GPIO1_OE REGISTER ADDRESS, |
| 42 | +LDR R6, [R2]@ READ CURRENT GPIO1 ENABLE REGISTER, |
| 43 | +LDR R7,=0xFE1FFFFF@ WORD TO ENABLE GPIO1 ALL LED'S AS OUTPUT, |
| 44 | +AND R6, R7, R6 @ CLEAR BITS 21, 22, 23, 24 USR0-USR3, |
| 45 | +STR R6, [R2]@ WRITE TO GPIO1_CLEARDATAOUT REGISTER. |
| 46 | +
|
| 47 | +@ Detect falling edge on GPIO2_1 and enable to assert POINTERPEND1 |
| 48 | +@ Write 0x0000 0002 to 0x481AC14C to program GPIO2, pin 1, to detect falling edge. RMW. |
| 49 | +ADD R2, R1, #0x14C@ R2 = address of GPIO2_FALLINGDETECT reg |
| 50 | +MOV R3, #0x00000002@ load value for bit 1 |
| 51 | +LDR R4, [R2]@ READ GPIO2_FALLINGDETECT reg |
| 52 | +ORR R4, R4, R3 @ MODIFY (set bit 1) |
| 53 | +STR R4, [R2]@ WRITE |
| 54 | + |
| 55 | +@ Enable GPIO module to send interrupt request to INTC: |
| 56 | +@ Write 0x00000002 to 0x481AC034 |
| 57 | +ADD R2, R1, #0x34@ Address of GPIO2_IRQSTATUS_SET_0 reg |
| 58 | +STR R3, [R2]@ enable GPIO2_1 request on POINTERPEND1 |
| 59 | + |
| 60 | +
|
| 61 | +
|
| 62 | +@ Initialize INTC : |
| 63 | +@ Enable INTC to respond to an interrupt request: |
| 64 | +LDR R2,=0x48200000@ Address of INTC base register, |
| 65 | +
|
| 66 | +@ TIMER4: CONFIG: Write 0x2 to INTC_SYSCONFIG at 0x4820 0010 to reset INTC: |
| 67 | +MOV R3, #0x2@ Value to reset INTC |
| 68 | +STR R3, [R2, #0x10]@ Write to INTC Sys CONFIG register. |
| 69 | +
|
| 70 | +@ TIMER4: INTERRUPT: Write 0x1000 0000 to 0x482000C8 enable INTC #92 Timer4: |
| 71 | +MOV R3, #0x10000000@ unmask INTC #92, MIR2 bit 28, hence IRQ2. |
| 72 | +STR R3, [R2, #0xC8]@ INTC base 4820 + offset 0xC8 INTC_MIR_CLEAR2 |
| 73 | + |
| 74 | +@ BUTTON: Write 0x0000 0001 to INTC_MIR_SET1 register at address 0x4820 00A8. |
| 75 | +MOV R3, #0x00000001@ value to unmask INTC INT 32. GPIOINT2A |
| 76 | +STR R3, [R2, #0xA8]@ WRITE to INTC_MIR_CLEAR1 register. |
| 77 | +
|
| 78 | +
|
| 79 | +
|
| 80 | +@ Turn on Timer4 clock: |
| 81 | +@ Write 0x02 to Base Address of CM_PER 0x44E0 0000 base |
| 82 | +@ + offset 0x88 for CM_PER_TIMER4_CLKCTRL = Write 0x2 to 0x 44E0 0088 : |
| 83 | +MOV R3, #0x2@ Value to enable TIMER4 CLK |
| 84 | +LDR R1,=0x44E00088@ Address CM_PER_TIMER4 CLK |
| 85 | +STR R3, [R1]@ Turn on CLK |
| 86 | +@Set Timer clock frequency MUX for 32K Hz: |
| 87 | +@Write 0x2 to PRCM CLKSEL_TIMER4 register at address 0x44E0 0510 : |
| 88 | +LDR R1,=0x44E00510@ Address of PRCM CLKSEL_TIMER4 register |
| 89 | +STR R3, [R1]@ Select 32K CLK for timer 4, by writing 0x2. |
| 90 | + |
| 91 | + |
| 92 | +
|
| 93 | +@ Initialize Timer 4 registers, with count, overflow interrupt generation |
| 94 | +@7a. Write 0x1 to Timer4 CFG register at 0x4804 4010 to reset Timer4 |
| 95 | +LDR R1,=0x48044000@ Base address TIMER4 registers |
| 96 | +MOV R3, #0x1@ value to reset TIMER4 |
| 97 | +STR R3, [R1, #0x10]@ Write to TIMER4 CONFIG register |
| 98 | +@7b. Write 0x2 to Timer4 IRQ_ENABLE_SET register at 0x 4804 402C |
| 99 | +MOV R3, #0x2@ Value to enable Overflow interrupt |
| 100 | +STR R3, [R1, #0x2C]@ Write to TIMER4 IRQENABLE_SET |
| 101 | +@7c. Write 0x FFFF 8000 to Timer4 TLDR TimerLoad reg at 0x4804 4040 to get 1sec |
| 102 | +LDR R3,=0xFFFF8000@ Count value for 1 second |
| 103 | +STR R3, [R1, #0x40]@Timer4 TLDR load reg (reload value) |
| 104 | +@7d. Write 0x FFFF 8000 to Timer4 TCRR TimerCounter reg at 0x 4804 403C to get 1sec |
| 105 | +STR R3, [R1, #0x3C]@ Write to Timer4 TCRR count register |
| 106 | +
|
| 107 | +
|
| 108 | + |
| 109 | + |
| 110 | +@ Make sure processor IRQ enabled in CPSR |
| 111 | +MRS R3, CPSR @ Copy CPSR to R3 |
| 112 | +BIC R3, #0x80@ Clear bit 7 |
| 113 | +MSR CPSR_c, R3 @ Write back to CPSR |
| 114 | + |
| 115 | +MOV R8, #0x0@ set LEDFLAG to zero so it falls through the first time. |
| 116 | + |
| 117 | +@ wait for interrupt |
| 118 | +LOOP: NOP |
| 119 | +
|
| 120 | +B LOOP |
| 121 | + |
| 122 | +INT_DIRECTOR: |
| 123 | + |
| 124 | +STMFD SP!, {R0-R3, LR} @ push registers on stack |
| 125 | +LDR R0,=0x482000B8@ Address of INTC_PENDING_IRQ1 reg, text p. 236 |
| 126 | +LDR R1, [R0]@ Read INTC_PENDING_IRQ1 register |
| 127 | +TST R1, #0x00000001@ test bit ZERO of IRQ 1 !!! |
| 128 | +
|
| 129 | +@ IS TIMER?? If bit 0 = 0 then not BUTTON |
| 130 | +BEQ TIMERCHECK @ if not from button push, Check if Timer 2, else |
| 131 | +
|
| 132 | +@ IS BUTTON?? If bit 0 = 1 then check if button: |
| 133 | +LDR R0,=0x481AC02C@ Load GPIO2_IRQSTATUS_0 register address, text p. 131 |
| 134 | +LDR R1, [R0]@ READ status register, to see if button, |
| 135 | +TST R1, #0x00000002@ Check if bit 1 = 1 |
| 136 | +BNE BUTTON_PUSHED @ If bit 1 = 1, then button pushed! |
| 137 | +
|
| 138 | +@ program control moves to PASS_ON here if it's NEITHER button NOR TIMER4: |
| 139 | +
|
| 140 | +@ "if bit 1 = 0, then enable new IRQ response in INTC by |
| 141 | +@ writing 0x1 to INTC_CONTROL register at 4820 0048 to allow new IRQ. |
| 142 | + |
| 143 | +@BEQ PASS_ON @ if bit 1 = 0, then : |
| 144 | +LDR R0,=0x48200048@ Else, go back. Address of INTC_PENDING_IRQ2 reg TIMER4 |
| 145 | +MOV R3, #01@ value to clear bit 0 per sitara manual |
| 146 | +STR R3, [R0]@ Write to INTC_CONTROL register. |
| 147 | +LDMFD SP!, {R0-R3, LR} @ Restore registers = POP |
| 148 | +SUBS PC, LR, #4@ Pass execution on to wait LOOP for now |
| 149 | + |
| 150 | + |
| 151 | + |
| 152 | + |
| 153 | +
|
| 154 | +TIMERCHECK: |
| 155 | +LDR R3,=0x482000D8@ Address of INTC PENDING IRQ2 register |
| 156 | +LDR R0, [R3]@ Read value |
| 157 | +TST R0, #0x10000000@ Check if interrupt from TIMER4 |
| 158 | +BEQ PASS_ON @ if not TIMER4 interrupt, return; if YES, check overflow |
| 159 | +@ if yes, aka IS TIMER4 interrupt, check for overflow: |
| 160 | +LDR R3,=0x48044028@ Address of TIMER4 IRQSTATUS register |
| 161 | +LDR R0, [R3]@ read value |
| 162 | +TST R0, #0x2@ check bit 1. Sitara manual p 4341, IRQSTATUS OVERFLOW bit. |
| 163 | +BNE LEDZ @ if overflow, then go to toggle LEDs |
| 164 | +@ else go back to wait loop |
| 165 | +PASS_ON: |
| 166 | +LDR R0,=0x48200048@ Else, go back. Address of INTC_PENDING_IRQ2 reg TIMER4 |
| 167 | +MOV R3, #01@ value to clear bit 0 |
| 168 | +STR R3, [R0]@ Write to INTC_CONTROL register. |
| 169 | +LDMFD SP!, {R0-R3, LR} @ Restore registers = POP |
| 170 | +SUBS PC, LR, #4@ Pass execution on to wait LOOP for now |
| 171 | + |
| 172 | + |
| 173 | + |
| 174 | + |
| 175 | +
|
| 176 | +BUTTON_PUSHED: |
| 177 | +LDR R0,=0x481AC02C@ Load GPIO2_IRQSTATUS_0 register address, text p. 131 |
| 178 | +MOV R1, #0x00000002@ Value turns off GPIO2_1 interrupt request |
| 179 | +@ also INTC interrupt request |
| 180 | +STR R1, [R0]@ Write to GPIO2_IRQSTATUS_0 register |
| 181 | + |
| 182 | + |
| 183 | +@ Start Timer4, and set for auto reload by writing 0x03 to TCLR at 0x 4804 4038: |
| 184 | +MOV R3, #0x03@ load value of auto reload timer and start |
| 185 | +LDR R1,=0x48044038 |
| 186 | +STR R3, [R1] |
| 187 | + |
| 188 | +@ turn off NEWIRQA bit in INTC_CONTROL, so |
| 189 | +@ processor can respond to new IRQ: |
| 190 | +LDR R0,=0x48200048@ Address of INTC_CONTROL reg p.236 |
| 191 | +MOV R1, #01@ Clear Bit 0 |
| 192 | +STR R1, [R0]@ Write to INTC_CONTROL register |
| 193 | + |
| 194 | + |
| 195 | +LDR R0,=0x4804C000@ LOAD ADDRESS OF GPIO1 REGISTER for LED's. |
| 196 | + |
| 197 | +
|
| 198 | +@ if LED's are off, fall through to flash LED's. Else, stop it! |
| 199 | +TST R8, #0x1@ Check if bit 1 = 1 |
| 200 | +BNE STOPIT @ If bit LEDFLAG = 1, then button pushed! |
| 201 | +@ if bit LEDFLAG = 0, then FALL THROUGH |
| 202 | +
|
| 203 | +/* IF LED'S ARE ON, THEN FALL THROUGH TO LEDZ AND THE PARITY CHECK. */ |
| 204 | +
|
| 205 | + |
| 206 | + |
| 207 | +
|
| 208 | +LEDZ: |
| 209 | +MOV R8, #0x1@ set LEDFLAG to 1, therefore "LEDs on." |
| 210 | +
|
| 211 | +LDR R0,=0x4804C000@ LOAD ADDRESS OF GPIO1 REGISTER for LED's. |
| 212 | + |
| 213 | +@ Turn off Timer4 Overflow Interrupt request: |
| 214 | +@ Write 0x2 to IRQSTATUS register at 0x4804 4028 : |
| 215 | +LDR R1,=0x48044028@ load address of Timer4 IRQSTATUS register |
| 216 | +MOV R2, #0x2@ value to reset timer4 overflow IRQ request (bit1) |
| 217 | +STR R2, [R1]@ write. |
| 218 | + |
| 219 | +
|
| 220 | +/* when hitting the button to START the LEDs, we MUST RESET/ENABLE timer overflow IRQ's. |
| 221 | +TO DO SO, WE USE IRQENABLE_SET REGISTERS IN SITARA MANUAL (TIMER). |
| 222 | + */ |
| 223 | +LDR R1,=0x48044000@ BASE ADDRESS OF TIMER4, |
| 224 | +MOV R3, #0x2@ WRITE A 1 TO BIT 1 OF BOTH SET AND CLR REGISTERS, |
| 225 | +STR R3, [R1, #0x2C]@ IRQENABLE_SET |
| 226 | +
|
| 227 | +
|
| 228 | +
|
| 229 | +TOGGLEPARITY: |
| 230 | + |
| 231 | +@ TEST PARITY : EVEN OR ODD. IF 0, GOTO ODDS. IF 1, GOTO EVEN. |
| 232 | + |
| 233 | +TST R9, #0x1@ Check if bit 1 = 1 |
| 234 | +BNE EVENS |
| 235 | + |
| 236 | +ODDS: |
| 237 | +MOV R9, #0x1@ SET PARITY TO ODD |
| 238 | +@ clear evens: |
| 239 | +MOV R11, #0x00A00000@ COPY MASK: EVENS, |
| 240 | +ADD R2, R0, #0x190@ CLEARDATAOUT ADDRESS, |
| 241 | +STR R11, [R2]@ WRITE MASK. CLEAR EVENS. |
| 242 | + |
| 243 | +@ Set odds: |
| 244 | +MOV R11, #0x01400000@ COPY MASK: ODDS, |
| 245 | +ADD R2, R0, #0x194@ SETDATAOUT ADDRESS, |
| 246 | +STR R11, [R2]@ WRITE MASK. LIGHT ODDS. |
| 247 | +B PASS_ON_TEMP |
| 248 | +
|
| 249 | +EVENS: |
| 250 | +MOV R9, #0x0@ SET PARITY TO EVEN |
| 251 | +@ Clear odds: |
| 252 | +MOV R11, #0x01400000@ COPY MASK: ODDS |
| 253 | +ADD R2, R0, #0x190@ CLEARDATAOUT ADDRESS |
| 254 | +STR R11, [R2]@ WRITE MASK. CLEAR ODDS. |
| 255 | +
|
| 256 | +MOV R11, #0x00A00000@ COPY MASK: EVENS. |
| 257 | +ADD R2, R0, #0x194@ SETDATAOUT address, |
| 258 | +STR R11, [R2]@ WRITE MASK, LIGHT EVENS. |
| 259 | +B PASS_ON_TEMP |
| 260 | +
|
| 261 | +
|
| 262 | +STOPIT: |
| 263 | +@ CLEAR LED'S |
| 264 | +MOV R8, #0x0@ set LEDFLAG to zero |
| 265 | +
|
| 266 | +ADD R4, R0, #0x190@ GPIO1_CLEARDATAOUT register, |
| 267 | +MOV R7, #0x01E00000@ LOAD VALUE TO TURN OFF ALL LED'S, |
| 268 | +STR R7, [R4]@ TURN OFF ALL LED'S. |
| 269 | +
|
| 270 | +/* when hitting the button to stop the LEDs, we MUST disable timer overflow IRQ's. |
| 271 | +TO DO SO, WE USE IRQENABLE_SET AND IRQENABLE_CLR REGISTERS IN SITARA MANUAL (TIMER). |
| 272 | + */ |
| 273 | +LDR R1,=0x48044000@ BASE ADDRESS OF TIMER4, |
| 274 | +MOV R3, #0x2@ WRITE A 1 TO BIT 1 OF BOTH SET AND CLR REGISTERS, |
| 275 | +STR R3, [R1, #0x2C]@ IRQENABLE_SET |
| 276 | +STR R3, [R1, #0X30]@ IRQENABLE_CLR |
| 277 | +
|
| 278 | +PASS_ON_TEMP: |
| 279 | +@ INTC : RESET FOR NEW IRQ'S! |
| 280 | +LDR R1,=0x48200048@ address of INTC control register |
| 281 | +MOV R3, #0x01 |
| 282 | +STR R3, [R1]@ Write to INTC_CONTROL register |
| 283 | +
|
| 284 | +@return to wait loop |
| 285 | +LDMFD SP!, {R0-R3, LR} @ Restore registers |
| 286 | +SUBS PC, LR, #4@ Pass execution on to wait LOOP for now |
| 287 | +
|
| 288 | +@LDR R1,=0x481AC02C@ Load GPIO2_IRQSTATUS_0 register address, text p. 131 |
| 289 | +@LDR R2, [R1]@ READ status register, |
| 290 | +@TST R2, #0x00000002@ Check if bit 1 = 1 |
| 291 | +@BNE STOPIT @ If bit 1 = 1, then button pushed again, so go back to WAIT! |
| 292 | +
|
| 293 | + |
| 294 | +.align 2 |
| 295 | +SYS_IRQ: .WORD 0@location to store systems IRQ address! |
| 296 | + |
| 297 | +.data |
| 298 | + |
| 299 | +.align 2 |
| 300 | + |
| 301 | +STACK1: .rept 1024 |
| 302 | +.word 0x0000 |
| 303 | +.endr |
| 304 | +STACK2: .rept 1024 |
| 305 | +.word 0x0000 |
| 306 | +.endr |
| 307 | +
|
| 308 | +.END |
| 309 | + |
| 310 | + |
| 311 | + |
0 commit comments