Advertisement
Guest User

Untitled

a guest
Nov 20th, 2019
126
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 26.92 KB | None | 0 0
  1. ; This code is based upon InputOutput's from the book:
  2. ; "Embedded Systems: Introduction to ARM Cortex M Microcontrollers"
  3. ; ISBN: 978-1469998749, Jonathan Valvano, copyright (c) 2014
  4. ;
  5. ; The code provided initializes all 3 ports (A,B,E) with the ECE Shield plugged into the Tiva board
  6. ; Port F with the Tiva 3 LEDs (Red, Green, Blue) and two buttons is also initialized
  7. ; Then the LEDs on each port are turned off and on with time delays - while the Tiva board R, G, B LEDs are turned on and off
  8. ;
  9. ; Dec 2017
  10.  
  11. AREA |.text|, CODE, READONLY, ALIGN=2
  12. THUMB
  13. EXPORT Start
  14. EXPORT GPIOPortF_Handler
  15.  
  16. ; These equates allow one to associate a name with a value to make the code more readable
  17.  
  18. RED EQU 0x02 ; These are the values (bit locations) for various LEDs on the Tiva (Port F)
  19. BLUE EQU 0x04
  20. GREEN EQU 0x08
  21. SW1 EQU 0x10 ; on the left side of the Tiva board
  22. SW2 EQU 0x01 ; on the right side of the Tiva board
  23.  
  24. Start
  25. BL Port_Init ; initialize input and output pins of Ports A to F
  26.  
  27. BL Interrupt_Init ; initialize an interrupt for the button
  28.  
  29. MOV R11, #0xe1f0 ; seed the pseudo random number generator
  30.  
  31. ; each of the Tiva ports is 8 bits wide and connect to wires which can be inputs or outputs
  32.  
  33. ; to read the buttons on port F use the address GPIO_PORTF_DATA_R EQU 0x400253FC
  34.  
  35. ; feel free to reuse code from Lab #3 to drive the 7-segment display, speaker, ....
  36.  
  37. keep_flashing
  38. MOV R6, #0 ; initialize R6 to zero to detect an interrupt / button press
  39.  
  40. ; turn off 7 port B LEDs on the shield - the last LED is on Port E
  41. LDR R3, =GPIO_PORTB + (PORT_B_MASK << 2) ; generate the base address for port B
  42. LDR R1, [R3, #GPIO_DATA_OFFSET]
  43. EOR R1, #0xFD ; write out a 0 to turn off the 7 LEDs on port B
  44. STR R1, [R3, #GPIO_DATA_OFFSET] ; GPIO_DATA_OFFSET is the address offset to get to the DATA part of the port
  45.  
  46. ; The last LED is on port E - so read the value, modify bit 1 as it drives the LED and write it back out - this is called read-modify-write
  47. LDR R3, =GPIO_PORTE + (PORT_E_MASK << 2) ; generate the base address for port B
  48. LDR R1, [R3, #GPIO_DATA_OFFSET] ; GPIO_DATA_OFFSET is the address offset to get to the DATA part of the port
  49. EOR R1, #0x02
  50. STR R1, [R3, #GPIO_DATA_OFFSET] ; write the data back out
  51.  
  52. MOV R1, #5000 ;according to lab manual - this is on
  53. BL Delay
  54.  
  55. ;be sure that the RandomNum routine is called in the time delay routine
  56. ;okay we did
  57.  
  58. TEQ R6, #0
  59. BNE count_down
  60. ; check for R6 being non-zero as an exit condition
  61.  
  62. B keep_flashing
  63.  
  64. count_down
  65.  
  66. ; display the number in R6 on the eight LEDs and optionally on the 7-segment displays
  67. MOV R5, R6
  68. BL display_right_7seg
  69.  
  70. ;ADD LEDS LATER
  71. ;MOV R1, #1
  72. MOV R1, #10000
  73. BL Delay
  74. ; be sure that the RandomNum routine is called in the time delay routine
  75. ; if R6 will go negative go back to flashing
  76. ; subtract 10 from R6
  77. SUBS R6, R6, #10
  78. BLS keep_flashing
  79.  
  80.  
  81. B count_down
  82.  
  83.  
  84. ; This ISR is called when any interrupt associated with a wire on Port F is generated
  85. ; A careful programmer would verify which of the 8 possible interrupt sources (pins) generated the input
  86. ; If there is only one interrupt and the program is simple then one doesn't have to be so paranoid
  87. ;
  88. ; On ARM processors R0 .. R3 are automatically saved - you must preserve all other registers you change
  89.  
  90. GPIOPortF_Handler ; an interrupt due to any pin on Port F calls this interrupt handler
  91.  
  92. STMFD R13!,{R14} ; I'm paranoid - save R1 and R3 since I'm using them
  93.  
  94. ; some code to toggle an LED so I know I made it in here - or use a break point ...
  95.  
  96. LDR R1, =GPIO_PORTF_DATA_R ; pointer to Port F data register where the LEDs are
  97. LDR R2, [R1, #GPIO_DATA_OFFSET]
  98. EOR R2, #RED ; toggle the RED LED
  99. STR R2, [R1, #GPIO_DATA_OFFSET] ; read-modify-write opertion complete
  100.  
  101. ; scale the random number in R11 to generate a number in R6 between 50 and 250
  102.  
  103. MOV R10, #327
  104. UDIV R11, R11, R10
  105. ADD R11, R11, #50
  106. MOV R6, R11
  107.  
  108. ; Before exiting, the interrupt must be acknowledged by clearing the appropiate bit in the Port F ICR register
  109. ; If this is not done all future interrupts from this Port will be blocked
  110. ; There is no harm in clearing extra interrupt sources (ie using either button to generate an interrupt)
  111.  
  112. LDR R1, =GPIO_PORTF + GPIO_ICR_OFFSET
  113. MOV R0, #SW1 ; clear the interrupt by having a one match the correct bit where the switch is
  114. STR R0, [R1] ; acknowledge the interrupt
  115.  
  116. LDMFD R13!,{R15} ; restore the saved registers and return
  117.  
  118. GPIO_IS_OFFSET EQU 0x404 ;GPIOIS - Interrupt Sense : 0 = edge, 1 = level interrupt
  119. GPIO_IBE_OFFSET EQU 0x408 ;GPIOIBE - Interrupt Both Edges : 0 = single edge, 1 = both edges
  120. GPIO_IEV_OFFSET EQU 0x40c ;GPIOIEV - Interrupt Event : 0 = low level or falling edge, 1= high level or rising edge
  121. GPIO_IM_OFFSET EQU 0x410 ;GPIOIM - Interrupt Mask : 0 = masked, 1 = unmasked
  122. GPIO_RIS_OFFSET EQU 0x414 ; Raw Interrupt Status - READ ONLY
  123. GPIO_MIS_OFFSET EQU 0x418 ; Masked Interrupt Status - READ ONLY
  124. GPIO_ICR_OFFSET EQU 0x41c ; Interrupt Clear - writing a 1 clears the RIS and MIS registers
  125.  
  126. ;Program the GPIOIS, GPIOIBE, GPIOEV, and GPIOIM registers to configure the type, event,
  127. ;and mask of the interrupts for each port.
  128. ;Note: To prevent false interrupts, the following steps should be taken when re-configuring
  129. ;GPIO edge and interrupt sense registers:
  130. Interrupt_Init
  131. STMFD R13!,{R14} ; push the LR or return address
  132.  
  133. ;a. Mask the corresponding port by clearing the IME field in the GPIOIM register.
  134.  
  135. LDR R1, =GPIO_PORTF
  136. MOV R0, #0x00 ; 0 means mask or block interrupts
  137. STR R0, [R1, #GPIO_IM_OFFSET] ; mask interrupts from happening
  138.  
  139. ; b. Configure the IS field in the GPIOIS register and the IBE field in the GPIOIBE register.
  140.  
  141. MOV R0, #0x00 ; 0 means edge detecting interrupt
  142. STR R0, [R1, #GPIO_IS_OFFSET] ;
  143.  
  144. MOV R0, #0x00 ; 0 means falling edge detecting
  145. STR R0, [R1, #GPIO_IEV_OFFSET] ;
  146.  
  147. MOV R0, #0x00 ; 0 means single edge detection
  148. STR R0, [R1, #GPIO_IBE_OFFSET] ;
  149.  
  150. ;c. Clear the GPIORIS register using the ICR register to clear any pending interrupts.
  151. ; The switches are bits 0 and 4 on Port F and a 1 must be written to the bit / switch used.
  152. MOV R0, #0x00000011 ; 0 means mask or block interrupts
  153. STR R0, [R1, #GPIO_ICR_OFFSET] ; clear any interrupts recieved
  154.  
  155. ;d. Unmask the port by setting the IME field in the GPIOIM register.
  156. ; Set the appropiate bit to 1 to enable interrupts for only the one switch required
  157. ; This register only uses the lowest 8 bits - one for each wire on the port.
  158. MOV R0, #0x000000FF ; 0 means mask or block interrupts
  159. STR R0, [R1, #GPIO_IM_OFFSET] ; mask interrupts from happening
  160.  
  161. ;Looking in the Startup.s file one will find an EXPORT of the address for interrupt handlers, one for each GPIO port
  162.  
  163. ; Interrupt Enable Registers
  164. CORE_PERIPHERALS EQU 0xe000e000
  165. INTERRUPT_EN0_OFFSET EQU 0x100
  166.  
  167. ; The Interrupt Number (Bit in Interrupt Registers) value written to the EN0 register to enable port F interrupts can be found in Table 2-9 (page 104)
  168. MOV R0,# 0x40000000 ; this 32-bit value enables GPIO Port F Interrupts - by setting only the appropiate single bit to one
  169.  
  170. LDR R1, =CORE_PERIPHERALS
  171. STR R0, [R1, #INTERRUPT_EN0_OFFSET] ; GPIO Interrupts require this enable
  172.  
  173. LDMFD R13!,{R15} ; push the LR or return address
  174.  
  175.  
  176. ; Driving the 7-segment outputs is harder because they're spread over multiple ports
  177. ; Naming of the 7-segment segments is clockwise from the top: A, B, C, D, E, F, G, DP (decimal point) as per Appendix H
  178. ; DO NOT USE THE DP (decimal point) - they are not included below
  179.  
  180. ; left 7-segment bits are: F2, F3, D2, D3, D6, D7, E0 [ports F, D, E are used]
  181. ; right 7-segment bits are: A2, A3, E2, A5, A6, A7, A4 [ ports A, E are used]
  182.  
  183. ; Display numbers to the right 7-segment as an example of read-modify-write data manipulation on I/O ports
  184. ;
  185. ; INPUT: R5 - The 4 LSB of R5 will be displayed
  186. ; OUTPUT: none
  187. ;
  188. display_right_7seg STMFD R13!,{R0, R1, R2, R3, R4, R5, R14}
  189.  
  190. PUSH {R5} ; save R5 so that it can be used for the other 7-segment display
  191. ; First take the 4 LSB and display that to HEX #2
  192. ; Convert the binary number to the bit pattern required by the 7-segment display
  193.  
  194. LDR R3, =Seven_Seg_Table ; get the base address of the 7-segment pattern table
  195. AND R5, #0xf ; mask the number to display to the range 0 to 0xf
  196. LSL R5, #1 ; multiply by two, to get an address offset in bytes, as the lookup table holds an array of 16-bit data
  197. LDRH R0, [R3, R5] ; read the 7-segment pattern - table base address + offset in R5
  198. ; DP is Bit 0, then A, B, C, D, E, F, G (bit 7)
  199.  
  200. ; brute force data manipulation - read bit by bit and conditionally set the appropiate bit in a register which gets written to the port
  201. ; use right shift - the LSB that falls off goes into the Carry flag and is used to conditionally set
  202.  
  203. MOV R1, #0 ; R1 will hold the data written to port A
  204. MOV R2, #0 ; R1 will hold the data written to port E
  205.  
  206. ; right 7-segment bits are: A2, A3, E2, A5, A6, A7, A4 [ ports A, E are used]
  207. ; NOTE: a "1" in the 7-seg pattern should write a 0 because the 7-seg display is active low - so the code below inverts
  208.  
  209. LSRS R0, #1 ; shift LSB into Carry flag - this goes to dp (decimal point) - but is not used
  210. LSRS R0, #1 ; shift next LSB - this is segment "G" and goes to port A bit 2 (A2)
  211. ORRCC R1, #0x04 ; conditionally set A2 if Carry is Equal to 0
  212.  
  213. LSRS R0, #1
  214. ORRCC R1, #0x08 ; conditionally set A3 if Carry is Equal to 0
  215.  
  216. LSRS R0, #1
  217. ORRCC R2, #0x04 ; conditionally set E2 if Carry is Equal to 0
  218.  
  219. LSRS R0, #1
  220. ORRCC R1, #0x20 ; conditionally set A5 if Carry is Equal to 0
  221.  
  222. LSRS R0, #1
  223. ORRCC R1, #0x40 ; conditionally set A6 if Carry is Equal to 0
  224.  
  225. LSRS R0, #1
  226. ORRCC R1, #0x80 ; conditionally set A7 - bit 7 if Carry is Equal to 0
  227.  
  228. LSRS R0, #1
  229. ORRCC R1, #0x10 ; conditionally set A4 - bit 4 if Carry is Equal to 0
  230.  
  231. ; now read-modify-write port A
  232. LDR R0, =GPIO_PORTA + (PORT_A_MASK << 2)
  233. LDR R4, [R0, #GPIO_DATA_OFFSET] ; read port A
  234. AND R4, #0x03 ; clear all bits being overwritten from the data manipulation above
  235. ORR R4, R1 ; ORR in the data manipulation done - R1 which is port A data
  236. STR R4, [R0, #GPIO_DATA_OFFSET] ; write port A back out
  237.  
  238. ; now read-modify-write port E
  239. LDR R0, =GPIO_PORTE + (PORT_E_MASK << 2)
  240. LDR R4, [R0, #GPIO_DATA_OFFSET] ; read port A
  241. AND R4, #0xfb ; clear all bits being overwritten from the data manipulation above
  242. ORR R4, R2 ; ORR in the data manipulation done - R2 which is port E data
  243. STR R4, [R0, #GPIO_DATA_OFFSET] ; write port A back out
  244.  
  245. ; In order to drive the Left 7-segment:
  246. ; Ports D, E and F are used - so a register is needed to read-modify-write each of those
  247.  
  248. POP {R5} ; retrieve the original value passed in
  249. LSR R5, #4 ; shift right to access the upper 4 bits of the provided # which will be displayed to the 7-seg
  250. AND R5, #0xf ; mask the number to display to the range 0 to 0xf - this is unnecessary
  251. LSL R5, #1 ; multiply by two, to get an address offset in bytes, as the lookup table holds an array of 16-bit data
  252. LDR R3, =Seven_Seg_Table ; get the base address of the 7-segment pattern table
  253. LDRH R0, [R3, R5] ; read the 7-segment pattern - table base address + offset in R5
  254. ; DP is Bit 0, then A, B, C, D, E, F, G (bit 7)
  255.  
  256. MOV R1, #0 ; R1 will hold the data written to port D
  257. MOV R2, #0 ; R1 will hold the data written to port E
  258. MOV R3, #0 ; R1 will hold the data written to port F
  259.  
  260. ; right 7-segment bits are: A2, A3, E2, A5, A6, A7, A4 [ ports A, E are used]
  261. ; NOTE: a "1" in the 7-seg pattern should write a 0 because the 7-seg display is active low - so the code below inverts
  262.  
  263. LSRS R0, #1 ; shift LSB into Carry flag - this goes to dp (decimal point) - but is not used
  264.  
  265. LSRS R0, #1 ; shift next LSB - this is segment "G" and goes to port F2
  266. ORRCC R3, #0x04 ; conditionally set F2 if Carry is Equal to 0
  267.  
  268. LSRS R0, #1
  269. ORRCC R3, #0x08 ; conditionally set F3 if Carry is Equal to 0
  270.  
  271. LSRS R0, #1
  272. ORRCC R1, #0x04 ; conditionally set D2 if Carry is Equal to 0
  273.  
  274. LSRS R0, #1
  275. ORRCC R1, #0x08 ; conditionally set D3 if Carry is Equal to 0
  276.  
  277. LSRS R0, #1
  278. ORRCC R1, #0x40 ; conditionally set D6 if Carry is Equal to 0
  279.  
  280. LSRS R0, #1
  281. ORRCC R1, #0x80 ; conditionally set D7 if Carry is Equal to 0
  282.  
  283. LSRS R0, #1
  284. ORRCC R2, #0x01 ; conditionally set E0 if Carry is Equal to 0
  285.  
  286. ; now read-modify-write port D
  287. LDR R0, =GPIO_PORTD + (PORT_D_MASK << 2)
  288. LDR R4, [R0, #GPIO_DATA_OFFSET] ; read port A
  289. AND R4, #0x33 ; clear all bits being overwritten from the data manipulation above
  290. ORR R4, R1 ; ORR in the data manipulation done - R1 which is port A data
  291. STR R4, [R0, #GPIO_DATA_OFFSET] ; write port A back out
  292.  
  293. ; now read-modify-write port E
  294. LDR R0, =GPIO_PORTE + (PORT_E_MASK << 2)
  295. LDR R4, [R0, #GPIO_DATA_OFFSET] ; read port A
  296. AND R4, #0xFE ; clear all bits being overwritten from the data manipulation above
  297. ORR R4, R2 ; ORR in the data manipulation done - R2 which is port E data
  298. STR R4, [R0, #GPIO_DATA_OFFSET] ; write port A back out
  299.  
  300. ; now read-modify-write port F
  301. LDR R0, =GPIO_PORTF + (PORT_F_MASK << 2)
  302. LDR R4, [R0, #GPIO_DATA_OFFSET] ; read port A
  303. AND R4, #0xF3 ; clear all bits being overwritten from the data manipulation above
  304. ORR R4, R3 ; ORR in the data manipulation done - R1 which is port A data
  305. STR R4, [R0, #GPIO_DATA_OFFSET] ; write port A back out
  306.  
  307.  
  308. LDMFD R13!,{R0, R1, R2, R3, R4, R5, R15}
  309.  
  310. ALIGN
  311. ; This table is the binary pattern of 8 bits required to drive the 7 LEDs of a 7-segment display to display a hex. number
  312. ; The LSB is the lowest bit and is not to be used
  313. ;
  314. Seven_Seg_Table
  315. DCW 0x7e, 0x0c, 0xb6, 0x9e, 0xcc, 0xda, 0xfa, 0x0e, 0xfe, 0xce ; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
  316. DCW 0xee, 0xf8, 0xb0, 0xbc, 0xf2, 0xe2 ; A, B, C, D, E, F with LSB being 0 for the DP
  317. ALIGN
  318.  
  319.  
  320. ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  321. ; DO NOT EDIT CODE BELOW THIS LINE
  322. ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  323.  
  324. ;------------RandomNum------------
  325. ; R11 holds a 16-bit "random" number via a pseudo-random sequence as per the Linear feedback shift register (Fibonacci) on WikiPedia
  326. ; R11 holds a non-zero 16-bit number. If a zero is fed in, as the seed, the pseudo-random sequence will stay stuck at 0
  327. ; Take as many bits of R11 as you need. If you take the lowest 4 bits then you get a number between 0 and 15 while 16 bits gives you a value between 1 and 0xffff.
  328. ;
  329. ; R11 can be read anywhere in the user code but must only be written to by this subroutine
  330. ;
  331. ; INPUT: R11 - before calling this for the FIRST time R11 must be initialized to a large 16-bit non-zero value or else it will stay stuck at 0
  332. ; OUTPUT: R11 - random number is the lowest 16 bits of R11, the upper 16 bits are cleared
  333. ;
  334. RandomNum STMFD R13!,{R1, R2, R3, R14}
  335.  
  336. AND R1, R11, #0x8000
  337. AND R2, R11, #0x2000
  338. LSL R2, #2
  339. EOR R3, R1, R2
  340. AND R1, R11, #0x1000
  341. LSL R1, #3
  342. EOR R3, R3, R1
  343. AND R1, R11, #0x0400
  344. LSL R1, #5
  345. EOR R3, R3, R1 ; the new bit to go into the LSB is present
  346. LSR R3, #15
  347. LSL R11, #1
  348. ORR R11, R11, R3
  349. MOV R1, #0xFFFF
  350. AND R11, R1 ; zero all bits above the pseudorandom 16 bits
  351. LDMFD R13!,{R1, R2, R3, R15}
  352.  
  353.  
  354. ; Tons of initialization to be done in order to use the I/O ports as they're off by default.
  355. ;
  356. ; Define the addresses and provide functions to initialize everything.
  357.  
  358. GPIO_PORTF_DIR_R EQU 0x40025400 ; Port F Data Direction Register setting pins as input or output
  359. GPIO_PORTF_DATA_R EQU 0x400253FC ; address for reading button inputs and writing to LEDs
  360. GPIO_PORTF_AFSEL_R EQU 0x40025420
  361. GPIO_PORTF_PUR_R EQU 0x40025510
  362. GPIO_PORTF_DEN_R EQU 0x4002551C
  363. GPIO_PORTF_LOCK_R EQU 0x40025520
  364. GPIO_PORTF_CR_R EQU 0x40025524
  365. GPIO_PORTF_AMSEL_R EQU 0x40025528
  366. GPIO_PORTF_PCTL_R EQU 0x4002552C
  367.  
  368. ;Section 3.1.2 Nested Vector Interrupt Controller
  369.  
  370. ;The Cortex-M4F processor supports interrupts and system exceptions. The processor and the
  371. ;Nested Vectored Interrupt Controller (NVIC) prioritize and handle all exceptions. An exception
  372. ;changes the normal flow of software control. The processor uses Handler mode to handle all
  373. ;exceptions except for reset. See Exception Entry and Return on page 108 for more information.
  374. ;The NVIC registers control interrupt handling. See Nested Vectored Interrupt Controller
  375. ;(NVIC) on page 124 for more information.
  376.  
  377. ;Table 3-8 on page 134 details interrupt Set / Clear
  378. ; they allow one to enable individual interrupts and DIS? lets one disable individual interrupt numbers
  379.  
  380. ; Table 2-9 Interrupts on page 104 details interrupt number / bit assignments
  381. ; Port F - Bit 30
  382. ; Timer 0A Bit 19
  383. ; Timer 0B Bit 20
  384.  
  385. ;For edge-triggered interrupts, software must clear the interrupt to enable any further interrupts.
  386.  
  387. ; NOTE: The NMI (non-maskable interrupt) is on PF0. That means that
  388. ; the Alternate Function Select, Pull-Up Resistor, Pull-Down Resistor,
  389. ; and Digital Enable are all locked for PF0 until a value of 0x4C4F434B
  390. ; is written to the Port F GPIO Lock Register. After Port F is
  391. ; unlocked, bit 0 of the Port F GPIO Commit Register must be set to
  392. ; allow access to PF0's control registers. On the LM4F120, the other
  393. ; bits of the Port F GPIO Commit Register are hard-wired to 1, meaning
  394. ; that the rest of Port F can always be freely re-configured at any
  395. ; time. Requiring this procedure makes it unlikely to accidentally
  396. ; re-configure the JTAG and NMI pins as GPIO, which can lock the
  397. ; debugger out of the processor and make it permanently unable to be
  398. ; debugged or re-programmed.
  399.  
  400. ; These are the configuration registers which should not be touched
  401. ; Port Base addresses for the legacy (not high-performance) interface to I/O ports
  402. GPIO_PORTA EQU 0x40004000
  403. GPIO_PORTB EQU 0x40005000
  404. GPIO_PORTC EQU 0x40006000
  405. GPIO_PORTD EQU 0x40007000
  406. GPIO_PORTE EQU 0x40024000
  407. GPIO_PORTF EQU 0x40025000
  408.  
  409. ; These are the masks for pins which are outputs
  410. PORT_A_MASK EQU 0xfc ;0xE0 ; PA7,6,5 are outputs for LEDs
  411. PORT_B_MASK EQU 0xff ;3f ; exclude B2:3 0xff ;33 ; PB5,4,1,0 are outputs %0011 0011
  412. PORT_C_MASK EQU 0x30 ; this hangs the CPU 0xf0
  413. PORT_D_MASK EQU 0xcc ;exclude d7 0xcf Disable D0, D1 due to short with B6, B7
  414. PORT_E_MASK EQU 0x3f ;0x30 ; PE5,4 are outputs %0011 0000
  415. PORT_F_MASK EQU 0x0e ; PF has LEDs on PF 1,2,3 and buttons PF0, PF4 (don't enable buttons as outputs)
  416.  
  417. ; Offsets are from table 10-6 on page 660
  418. GPIO_DATA_OFFSET EQU 0x000 ; Data address is the base address - YOU HAVE TO ADD AN ADDRESS MASK TOO to read or write this!!
  419. GPIO_DIR_OFFSET EQU 0x400 ; Direction register
  420. GPIO_AFSEL_OFFSET EQU 0x420 ; Alternate Function SELection
  421. GPIO_PUR_OFFSET EQU 0x510 ; Pull Up Resistors
  422. GPIO_DEN_OFFSET EQU 0x51C ; Digital ENable
  423. GPIO_LOCK_OFFSET EQU 0x520
  424. GPIO_CR_OFFSET EQU 0x524
  425. GPIO_AMSEL_OFFSET EQU 0x528 ; Analog Mode SELect
  426. GPIO_PCTL_OFFSET EQU 0x52C
  427.  
  428. SYSCTL_HBCTL EQU 0x400FE06C ; high performance bus control for ports A to F
  429.  
  430. GPIO_LOCK_KEY EQU 0x4C4F434B ; Unlocks the GPIO_CR register
  431. SYSCTL_RCGCGPIO_R EQU 0x400FE608 ; Register to enable clocks to the I/O port hardware
  432.  
  433. ;------------Port_Init------------
  434. ; Initialize GPIO Port F for negative logic switches on PF0 and
  435. ; PF4 as the Launchpad is wired. Weak internal pull-up
  436. ; resistors are enabled, and the NMI functionality on PF0 is
  437. ; disabled. Make the RGB LED's pins outputs.
  438. ; Input: none
  439. ; Output: none
  440. ; Modifies: R0, R1, R2, R3
  441. Port_Init
  442. STMFD R13!,{R14} ; push the LR or return address
  443.  
  444. ; First enable the clock to the I/O ports, by default the clocks are off to save power
  445. ; If a clock is not enabled to a port and you access it - then the processor hard faults
  446. LDR R1, =SYSCTL_RCGCGPIO_R ; activate clock for Ports (see page 340)
  447. LDR R0, [R1]
  448. ORR R0, R0, #0x3F ; turn on clock to all 6 ports (A to F, bits 0 to 5)
  449. STR R0, [R1]
  450. NOP
  451. NOP ; allow time for clock to finish
  452.  
  453. ; Set all ports to APB bus instead of AHB - this should be unnecessary
  454. ; LDR R1, =SYSCTL_HBCTL
  455. ; LDR R0, [R1]
  456. ; AND R0, #0xFFFFFFE0 ; set Ports A thru F to APB (0) and leave the rest at their default
  457. ; STR R0, [R1]
  458.  
  459. ; Page 650, Table 10-1 GPIO Pins with Special Considerations.
  460. ; These pins must be left as configured after reset:
  461. ; PA[5:0] (UART0 and SSIO), PB[3:2] (I2C), PC[3:0] (JTAG)
  462.  
  463. ; Initialize the I/O ports A, B, E, F via a common subroutine Port_Init_Individual
  464. ; Call Port_Init_Individual with the following paramaters passed:
  465. ; R1 is the base port address
  466. ; R2 is the output pin mask (which bits are outputs)
  467. ; R3 is the input pin mask (which bits get configured as inputs)
  468.  
  469. MOV R3, #0x00 ; Select no pins as input (unless it's changed as for port F)
  470.  
  471. ; Init Port A, B, E are by default GPIO - set all output pins used to a 1 to enable them
  472. ; and leave all of the other pins as previously configured!
  473. LDR R1, =GPIO_PORTA
  474. MOV R2, #PORT_A_MASK ; enable commit for Port, 1 means allow access
  475. BL Port_Init_Individual
  476.  
  477. ; Init Port B
  478. LDR R1, =GPIO_PORTB
  479. MOV R2, #PORT_B_MASK ; enable commit for Port, 1 means allow access
  480. BL Port_Init_Individual
  481.  
  482. ; Init Port C
  483. LDR R1, =GPIO_PORTC
  484. MOV R2, #PORT_C_MASK
  485. ;BL Port_Init_Individual ; Do not initialize Port C as it renders the Tiva board unprogramable !
  486.  
  487. ; Init Port D
  488. LDR R1, =GPIO_PORTD
  489. MOV R2, #PORT_D_MASK
  490. BL Port_Init_Individual
  491.  
  492. ; Init Port E
  493. LDR R1, =GPIO_PORTE
  494. MOV R2, #PORT_E_MASK ; enable commit for Port, 1 means allow access
  495. BL Port_Init_Individual
  496.  
  497. ; Init Port F
  498. LDR R1, =GPIO_PORTF
  499. MOV R2, #PORT_F_MASK ; enable commit for Port, 1 means allow access
  500. MOV R3, #0x11 ; enable weak pull-up on PF0 and PF4 (buttons)
  501. BL Port_Init_Individual
  502.  
  503. LDMFD R13!,{R15} ; pull the LR or return address from the stack and return
  504.  
  505.  
  506. ;------------Port_Init_Individual------------
  507. ; Initialize one GPIO Port with select bits as inputs and outputs
  508. ; Output: none
  509. ; Input: R1, R2, R3
  510. ; R1 has to be the port address
  511. ; R2 has to hold the mask for output pins
  512. ; R3 has to be the mask for input pins
  513. ; Modifies: R0
  514.  
  515. Port_Init_Individual
  516. STMFD R13!,{R14} ; push the LR or return address
  517. LDR R0, =0x4C4F434B ; unlock GPIO Port F Commit Register
  518. STR R0, [R1, #GPIO_LOCK_OFFSET] ; 2) unlock the lock register
  519. ORR R0, R2, R3 ; all access to inputs and outputs as masked in R2 and R3
  520. STR R0, [R1, #GPIO_CR_OFFSET] ; enable commit for Port F
  521. MOV R0, #0 ; 0 means analog is off
  522. STR R0, [R1, #GPIO_AMSEL_OFFSET] ; 3) disable analog functionality
  523. MOV R0, #0x00000000 ; 0 means configure Port F as GPIO
  524. STR R0, [R1, #GPIO_PCTL_OFFSET] ; 4) configure as GPIO
  525. LDR R0, [R1, #GPIO_DIR_OFFSET] ; 5) read default direction register configuration
  526. ORR R0, R2 ; ORR in only the bits we want as outputs
  527. STR R0, [R1, #GPIO_DIR_OFFSET] ; 5) set direction register
  528. MOV R0, #0 ; 0 means disable alternate function
  529. STR R0, [R1, #GPIO_AFSEL_OFFSET] ; 6) regular port function
  530. STR R3, [R1, #GPIO_PUR_OFFSET] ; pull-up resistors for PF4,PF0
  531. MOV R0, #0xFF ; 1 means enable digital I/O
  532. STR R0, [R1, #GPIO_DEN_OFFSET]
  533. LDMFD R13!,{R15} ; pull the LR or return address and return
  534.  
  535.  
  536. ; Beep the speaker on the ECE Shield using port E4 and E5
  537. ; The speaker is connected to two pins - toggle each end for more volume than a singled ended drive
  538. ; before exiting ensure that both wires to the speaker are 0 to prevent it from being heated up
  539. ; Ensure that each beep is about the same length - 0x300 loops of delay loop
  540. ;
  541. ; Input: R1 sets the tone - 2 is a high pitch, and pitch 0 is NO SOUND with the time delay of a beep
  542. ; Output: none
  543.  
  544. SpeakerBeep
  545. STMFD R13!,{R1-R4, R11, R14} ; push the LR or return address
  546.  
  547. MOV R4, #0x30 ; a value of 0x30 will toggle the voltage to the speaker
  548. TEQ R1, #0 ; if the user inputs R1 = 0 then keep the speaker silent and just delay for how long a beep would last
  549. BNE make_beeps
  550. MOV R1, #1 ; define a reasonable value so that the UDIV instruction does not divide by 0
  551. MOV R4, #0x0 ; a value of 0x0 will keep the speaker silent
  552.  
  553. make_beeps
  554. MOV R3, #0x300
  555. UDIV R3, R1 ; loop the tone R1 / R3 times to ensure a total of 0x100 delays for all tones
  556.  
  557. LDR R2, =GPIO_PORTE + (PORT_E_MASK << 2)
  558. LDR R11, [R2, #GPIO_DATA_OFFSET] ; get the initial value of the port E outputs - read-modify-write to only change 2 bits going to the speaker
  559. AND R11, #0xcf ; clear two bits that the speaker is on %1100 1111
  560. ORR R11, #0x10 ; initial speaker output (one side high 0x10, the other low 0x20)
  561. buzz_loop
  562. BL ShortDelay ; delay
  563. EOR R11, R4 ; toggle the voltage to the speaker if R4 ix 0x30 or not if it is 0x0
  564. STR R11, [R2, #GPIO_DATA_OFFSET]
  565. SUBS R3, #1
  566. BNE buzz_loop
  567.  
  568. AND R11, #0xcf ; before exiting power down the speaker by having 0 on both of it's wires
  569. STR R11, [R2, #GPIO_DATA_OFFSET] ; this doesn't work perfectly - there is a bit of sound created
  570.  
  571. LDMFD R13!,{R1-R4, R11, R15} ; pull the LR or return address and return
  572.  
  573. ; ShortDelay subroutine - delay for a fixed amount of time
  574. ;
  575. ; This is a bad piece of code - only use it as an example for what never to do!!
  576. ;
  577. ; Input: R1 - how many times do we loop (multiply) the fixed delay - If R1 = 0 then there is no time delay
  578. ; Output: none
  579.  
  580. SHORTDELAYCOUNT EQU 400 ; faction of a second delay. this is 0.1 milliseconds
  581.  
  582. Delay ; alternate name for this subroutine
  583. ShortDelay
  584. STMFD R13!,{R0, R1, R14} ; push the LR or return address
  585.  
  586. delay_outer_loop
  587. BL RandomNum
  588. TEQ R1, #0
  589. BNE not_done_delay
  590. B done_delay
  591. not_done_delay
  592. SUB R1, #1
  593. LDR R0, =SHORTDELAYCOUNT ; R0 = a value to get about a second delay
  594. delay_loop
  595. SUBS R0, R0, #1 ; R0 = R0 - 1 (count = count - 1) and set N, Z, C status bits
  596. ; Note: For SUBs the "s" suffix means to set the status bits, without this the loops would not exit
  597. CBNZ R0, delay_back ; compare if not zero then keep counting down
  598. B delay_outer_loop
  599. delay_back
  600. B delay_loop
  601. done_delay
  602. LDMFD R13!,{R0, R1, R15} ; pull the LR or return address and return
  603.  
  604. ALIGN
  605.  
  606. Port_Table
  607. DCD GPIO_PORTA + (PORT_A_MASK << 2) ; DCD - Define Constant Double Word (32-bits)
  608. DCD GPIO_PORTB + (PORT_B_MASK << 2), GPIO_PORTC + (PORT_C_MASK << 2)
  609. DCD GPIO_PORTD + (PORT_D_MASK << 2), GPIO_PORTE + (PORT_E_MASK << 2)
  610. DCD GPIO_PORTF + (PORT_F_MASK << 2), 0
  611.  
  612. ALIGN ; make sure the end of this section is aligned
  613. END ; end of file - nothing after this is assembled
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement