Memory-mapped I/O ports on CX and Interrupts: Difference between pages

From Hackspire
(Difference between pages)
Jump to navigation Jump to search
(added a link to my new timers page)
 
 
Line 1: Line 1:
==00000000 - Boot1 ROM==
==General Processor-related Info==
128kB of on-chip ROM.


==10000000 - SDRAM==
On the ARM processor, there are two types of interrupts:


32 MiB SDRAM on CM or 64 MiB on CX. Managed by 0x8FFF0000.
===IRQ===


==8FFF0000 - SDRAM controller==
IRQ is the typical interrupt type (and is the one used by TI-Nspire OS). It can be disabled by setting bit I (0x80) in the CPSR register.


A DMC-340 r1p0.
When an IRQ is triggered, the following happens:


==8FFF1000 - NAND controller==
* The return address plus 4 is copied to the IRQ_LR register.
* The CPSR register is copied to the IRQ_SPSR register.
* The I bit of CPSR is set (disabling IRQ).
* The processor mode is set to IRQ (mode 0x12). This mode swaps the SP and LR registers for the IRQ_SP and IRQ_LR registers (so the IRQ handler can have its own stack and know the return address)
* The processor begins executing from 0x00000018.


A PL351 r1p2.
After the IRQ handler is executed, the following code can be used to return to the previously executing code and restore the CPSR:


==90000000 - General Purpose I/O (GPIO)==
* SUBS PC,LR,#4


See [[GPIO Pins]]
===FIQ===


==90010000 - Fast timer==
FIQ is designed for fast response time, and has priority over IRQ (note that FIQ is not automatically disabled upon entry to IRQ). It can be disabled by setting bit F (0x40) in the CPSR register.


The same interface as 900C0000/900D0000, but runs at the speed of the APB clock (22.5MHz) rather than 32kHz.
When an FIQ is triggered, the following happens:
<br>The speed of the timers seems to be configurable, see [[timers]].<br>
A [http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0271d/Babehiha.html SP804].


==90020000 - Serial UART==
* The return address plus 4 is copied to the FIQ_LR register.
* The CPSR register is copied to the FIQ_SPSR register.
* The I and F bits of CPSR are set (disabling IRQ and FIQ).
* The processor mode is set to FIQ (mode 0x11). This mode swaps the R8 - R12, SP, and LR registers for the FIQ_R8 - FIQ_R12, FIQ_SP, and FIQ_LR registers (so the FIQ handler can have its own stack, know the return address, and have multiple free registers to improve interrupt latency)
* The processor begins executing from 0x0000001C. This is at the end of the vector table, so it is possible to put the entire FIQ handler at this location rather than using a branch instruction.


[http://infocenter.arm.com/help/topic/com.arm.doc.ddi0183f/DDI0183.pdf PL011].
After the FIQ handler is executed, the following code can be used to return to the previously executing code and restore the CPSR:


==90030000 - Unknown==
* SUBS PC,LR,#4


Probably some kind of hash/crypto thing.
==TI-Nspire Interrupt Controller==


==90040000 - SPI controller==
From here on, IRQ and FIQ can be used interchangeably, so for convenience' sake only IRQ will be mentioned. (An FIQ I/O register will be the IRQ register plus 0x100 unless otherwise mentioned.)


A PL022 for communicating with the LCD panel controller, which is probably an ILI9341 or ILI9340.
===IRQ Numbers===
Used on CX HW-W+ only.


==90050000 - I2C controller==
On the TI-Nspire, there can be up to 32 different interrupt sources, numbered 0-31. The following is a list of the currently known IRQ numbers:


The Touchpad on the CX is accessed through this controller. See [[Keypads#Touchpad I²C]] for protocol details. It seems to be a Synopsys Designware I2C adapter.
* IRQ 1 = [[Memory-mapped_I/O_ports#90020000 - Serial UART|Serial UART]]
* IRQ 3 = [[Memory-mapped_I/O_ports#90060000 - Watchdog timer|Watchdog timer]]
* IRQ 4 = [[Memory-mapped_I/O_ports#90090000 - Real-Time Clock (RTC)|RTC]]
* IRQ 7 = [[Memory-mapped_I/O_ports#90000000 - General Purpose I/O (GPIO)|GPIO]]
* IRQ 8 = [[Memory-mapped_I/O_ports#B0000000 - USB OTG controller|USB OTG]]
* IRQ 9 = [[Memory-mapped_I/O_ports#B4000000 - USB HOST controller|USB HOST]]
* IRQ 11 = [[Memory-mapped_I/O_ports#C4000000 - Analog-to-Digital Converter (ADC)|ADC]]
* IRQ 13 = [[Memory-mapped_I/O_ports#AC000000 - SD Host Controller|SD Host Controller]]
* IRQ 14 = [[Memory-mapped_I/O_ports#900F0000 - HDQ/1-Wire and LCD contrast|HDQ/1-Wire]]
* IRQ 15 = [[Memory-mapped_I/O_ports#900B0000 - Power management|Power management]]
* IRQ 16 = [[Memory-mapped_I/O_ports_on_CX#900E0000_-_Keypad_controller|Keypad]]
* IRQ 17 = [[Memory-mapped_I/O_ports#90010000 - Fast timer|Fast timer]]
* IRQ 18 = [[Memory-mapped_I/O_ports#900C0000 - First timer|First timer]]
* IRQ 19 = [[Memory-mapped_I/O_ports#900D0000 - Second timer|Second timer]]
* IRQ 20 = [[Memory-mapped_I/O_ports#90050000_-_I2C_controller|I2C]]
* IRQ 21 = [[Memory-mapped_I/O_ports#C0000000 - LCD controller|LCD controller]]
* IRQ 22 = [[Memory-mapped_I/O_ports#90100000 - TI-84 Plus link port|TI-84 Plus link port]] (?)


* 90050000 (R/W): Control register?
The following documentation is for TI-Nspire classic. The CX has a [http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0181e/index.html PL190] interrupt controller.
* 90050004 (?): ?
* 90050010 (R/W): Data/command register
* 90050014 (R/W): Speed divider for high period (standard speed) OS: 0x9c
* 90050018 (R/W): Speed divider for low period (standard speed) OS: 0xea
* 9005001c (R/W): Speed divider for high period (high speed) OS: 0x3b
* 90050020 (R/W): Speed divider for low period (high speed) OS: 0x2b
* 9005002c (R/W?): Interrupt status
* 90050030 (R/W): Interrupt mask
* 90050040 (R/W): Interrupt clear. Write 1 bits to clear
* 9005006c (R/W): Enable register
* 90050070 (R): Status register
* 90050074 (R?/W): TX FIFO?
* 90050078 (R?/W): RX FIFO?
* 900500f4 (?): ?
* 90050080 (?): ?


==90060000 - Watchdog timer==
===IRQ Priority===


Possibly an [http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0270b/index.html ARM SP805] or compatible. Runs at the APB clock frequency.
Each of the 32 IRQ sources can be assigned a priority number from 0-7. Lower numbers indicate higher priority. The array of priority values is located at 0xDC000300-0xDC00037F. This array is used by both IRQ and FIQ.


==90090000 - Real-Time Clock (RTC)==
===IRQ Raw Status===


Similar to the [http://infocenter.arm.com/help/topic/com.arm.doc.ddi0224b/index.html ARM PrimeCell PL031], but interrupt registers are different.
The register at 0xDC000004 reads the raw interrupt status, which is a bitfield where each bit corresponds to an interrupt source. Each bit will be set if the source is requesting an interrupt (regardless of whether that IRQ number is enabled or disabled) or reset if not.


At least on HW-AA it's a standard PL031 with no registers changed.
===IRQ Sticky Status===


* 90090000 (R): Current time, increments by 1 every second.
The register at 0xDC000004 can also be configured bit-by-bit to read a "sticky interrupt" status instead of the raw interrupt status. When an interrupt source's raw status changes from 0 to 1, the sticky status becomes set. Writing a 1 to the corresponding bit in the 0xDC000004 register will reset the sticky interrupt. The register at 0xDC000204 controls whether each bit in 0xDC000004 reads the raw status (bit=0) or the sticky status (bit=1). This register is shared by IRQ and FIQ.
* 90090004 (R/W): Alarm value. When the time passes this, interrupt becomes active.
* 90090008 (R/W): Sets the value of 90090000 (clock will not read new time until a couple seconds later). Reads last value written.
* 9009000C (R/W): Interrupt mask (1-bit)
* 90090010 (R/W): Masked interrupt status, reads 1 if interrupt active and mask bit is set. Write 1 to acknowledge.
* 90090014 (R): Status
** Bit 0: Time setting in progress
** Bit 1: Alarm setting in progress
** Bit 2: Interrupt acknowledgment in progress
** Bit 3: Interrupt mask setting in progress


==900A0000 - Miscellaneous==
===IRQ Mask===


* 900A0000 (R): ? 0x101
A bitmask is used to enable or disable each interrupt source. If a bit in the mask is 1, the corresponding IRQ will be enabled. If the bit is 0, the IRQ will be disabled. Writing to register 0xDC000008 will set the bits in the mask that are set in the written value (thus enabling IRQ sources), and writing to 0xDC00000C will reset the bits in the mask that are set in the written value (disabling IRQ sources). Reading either of these registers will return the IRQ mask.
* 900A0004 (R/W): Set bit 0x20 to enable TI-84+ keypad link port. Other bits likely control functions of peripherals as well.
* 900A0008 (W): Write a 2 to cause a hardware reset
* 900A0028-900A002C (R): These registers together give a 64-bit number (28 is low, 2C is high) which comprises 56 data bits and 8 parity checking bits, allowing any single-bit error in it to be detected and corrected.
** Parity bit 0: Check of all data bits
** Parity bits 1, 2, 4, 8, 16, and 32: Checks of the data bits whose positions, expressed in binary, have that respective bit set.
** Data bits 3, 5-7, 9-15, 17-31, and 33-55: Serial number (middle part of the calculator's Product ID)
** Data bits 56-57: Unknown
** Data bits 58-62: "ASIC user flags"; must match the 80E0 field in an OS image. 01 = CAS, 00 = non-CAS, 03 = CM CAS, 02 = CM non-CAS.
** Parity bit 63: Check of parity bits 1, 2, 4, 8, 16, and 32.
* 900A0F04 (R/W): Unknown; Boot1 sets this to 0x1D


==900B0000 - Power management==
===IRQ Masked Status===


* 900B0000 (R/W): [[Clock speed]] load value
The register at 0xDC000000 reads the masked interrupt status, where each bit is set if the corresponding bit in 0xDC000004 is set and the IRQ is "masked in" (aka enabled). In this case, the IRQ is known as "active". But simply having bits set in this register will not necessarily cause an IRQ to be triggered, as shown below.
* 900B0004 (R/W): 25-bit mask of which events may wake the hardware up from low-power mode.
** Bit 10: Unknown, probably the [[#90100000 - TI-84 Plus link port|TI-84 Plus link port]]
** Bit 12: [[#90090000 - Real-Time Clock (RTC)|RTC]] interrupt
** Bit 13: Unknown, probably ON key or USB activity
** Bit 17: Battery door open/close?
** Bit 23: Keypad remove/replace?
* 900B0008 (R/W): Reason for waking up from low-power mode. Write "1" bits to acknowledge.
* 900B000C (R/W): Clock speed control. Write 4 to set the clock speed according to the value in 900B0000. If interrupts are disabled the new clock speed will only become effective after exiting the program. Write 3A to enter low-power mode; this requires various peripherals to be prepared and probably works by stopping the clock.
* 900B0010 (R/W): ON interrupt mask (1-bit). 1 if ON interrupt should be serviced or 0 if not.
* 900B0014 (R/W): Bit 0 is set if ON interrupt is requested. Bit 1 also causes an interrupt, but the cause is unknown (and it is not masked by [900B0010]) - it is set after writing 4 to 900B000C. Write "1" bits to reset the requests.
* 900B0018 (R/W): Disable bus access to peripherals. Reads will just return the last word read from anywhere in the address range, and writes will be ignored.
** Bit 4: [[#C4000000 - Analog-to-Digital Converter (ADC)]]
** Bit 5: [[#B0000000 - USB OTG controller]]
** Bit 6: [[#B4000000 - USB HOST controller]]
** Bit 7: [[#B8010000 - SRAM Controller]]
** Bit 10: [[#CC000000 - SHA-256 hash generator]]
** Bit 11: [[#900C0000 - First timer]]
** Bit 12: [[#900D0000 - Second timer]]
** Bit 13: [[#90060000 - Watchdog timer]]
** Bit 17: [[#90020000 - Serial UART]]
** Bit 22: [[#90110000_-_LED]]?
* 900B0020 (R/W): ? - Possibly another peripheral bus access disable register.
* 900B0024 (R): Reads current clock speed value (see 900B0000 for details)
* 900B0028 (R): Bit 4 (0x10) clear when ON key pressed


==900C0000 - First timer==
===IRQ Max Priority===


A [http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0271d/Babehiha.html SP804].
The register at 0xDC00002C controls which priority level IRQs can be triggered. Only IRQs with priority number less than the value in this register can trigger an interrupt.
<br>The speed of the timers seems to be configurable, see [[timers]].


==900D0000 - Second timer==
===IRQ Current Number===


A [http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0271d/Babehiha.html SP804].
The register at 0xDC000020 reads the current IRQ number. This number is the active IRQ of highest priority (i.e. lowest priority value). If there are multiple active IRQs of the same priority, the lowest IRQ number is chosen. If there are no active IRQs, this value will be 0. The IRQ Current Number is what really forces IRQ priority, because it tells the interrupt handler which IRQ to handle.
<br>The speed of the timers seems to be configurable, see [[timers]].


==900E0000 - Keypad controller==
===Triggering IRQs===


See also [[Keypads]] for information about the keypads themselves.
When an IRQ is triggered (which only happens if there is an active IRQ with priority number less than IRQ Max Priority), imagine an internal flag that is set to 1. The only way to reset this flag is by reading the register at 0xDC000028 when there are no IRQs triggering the flag. The flag will be set regardless of the status of the I bit in CPSR. The interrupt will actually be taken once the I bit is reset (IRQ is enabled again). But this internal flag will continue to be set even if you mask out the IRQ source that caused it. Thus, it is possible that an interrupt can be taken even if there are no active IRQs! Thus, it is recommended to read register 0xDC000028 after disabling any IRQ types.


* 900E0000 (R/W):
==Handling Interrupts==
** Bits 0-1: Scan mode
*** Mode 0: Idle.
*** Mode 1: Indiscriminate key detection. Data registers are not updated, but whenever any key is pressed, interrupt bit 2 is set (and cannot be cleared until the key is released).
*** Mode 2: Single scan. The keypad is scanned once, and then the mode returns to 0.
*** Mode 3: Continuous scan. When scanning completes, it just starts over again after a delay.
** Bits 2-15: Number of APB cycles to wait before scanning each row
** Bits 16-31: Number of APB cycles to wait between scans
* 900E0004 (R/W):
** Bits 0-7: Number of rows to read (later rows are not updated in 900E0010-900E002F, and just read as whatever they were before being disabled)
** Bits 8-15: Number of columns to read (later column bits in a row are set to 1 when it is updated)
* 900E0008 (R/W): Keypad interrupt status/acknowledge (3-bit). Write "1" bits to acknowledge.
** Bit 0: Keypad scan complete
** Bit 1: Keypad data register changed
** Bit 2: Key pressed in mode 1
* 900E000C (R/W): Keypad interrupt mask (3-bit). Set each bit to 1 if the corresponding event in [900E0008] should cause an interrupt.
* 900E0010-900E002F (R): Keypad data, one halfword per row.
* 900E0030-900E003F (R/W): Keypad GPIOs. Each register is 20 bits, with one bit per GPIO. The role of each register is unknown.
* 900E0040 (R/W): Interrupt enable. Bits unknown but seems to be related to touchpad. Causes interrupt on touchpad touched.
* 900E0044 (R/W): Interrupt status. Bits unknown. Write 1s to acknowledge.
* 900E0048 (R/W): Unknown


==900F0000 - HDQ/1-Wire and LCD contrast==
* Save clobbered registers to the IRQ stack.
 
* Read 0xDC000024.
The HDQ/1-Wire registers resemble those on the TI OMAP processors, and are possibly used to communicate with the wireless cradle. There is no conceivable reason for the LCD contrast register to be part of the same module, but here it is. :-(
** The value read will be the IRQ Current Number.
 
** As a side effect, the value of IRQ Max Priority is copied to 0xDC000028 and the priority of IRQ Current Number is copied to IRQ Max Priority.
* 900F0004 (W): Transmitted data
* If using sticky interrupts, write (1 << IRQ Current Number) to 0xDC000004.
* 900F0008 (R): Received data
* Read 0xDC000028.
* 900F000C (R/W): Control/status
** This will reset the interrupt trigger flag if there are no other active interrupts.
* 900F0010 (R): Interrupt status (automatically acknowledged when read)
** Since IRQ Max Priority is now equal to the priority of IRQ Current Number, the current IRQ cannot re-trigger the interrupt flag.
* 900F0020 (R/W): LCD contrast/backlight. Valid range for contrast: 0x11a to 0x1ce; normal value is 0x174. However, it can range from 0x100 (backlight off) to about 0x1d0 (about max brightness).
** The value read is the previous value of IRQ Max Priority. This can be used later.
 
* Use the IRQ Current Number to decide which IRQ source to handle.
==90110000 - LED==
* Acknowledge the interrupt at the source, which should reset the IRQ Raw Status bit.
 
* Do anything else needed for this interrupt.
* 90110B00 (R/W): Control register
* Update the IRQ Max Priority. Either write the value read from 0xDC000028 to restore the previous value, or write 8 to allow interrupts of any priority.
** Bit 0: Set this bit to enable green light blink data. If green blink data iteration is not on, the green light state is read from bit 0 of green blink data.
* Restore clobbered registers from the stack and exit the interrupt handler.
** Bit 1: Set this bit and bit 6 to enable green blink data iteration.
** Bit 2: Set this bit to force green light off. Overrides bit 4.
** Bit 3: Set this bit to force red light off. Overrides bits 5 and 13.
** Bit 4: Set this bit to force green light on.
** Bit 5: Set this bit to force red light on.
** Bit 6: See this bit and bit 1 to enable green blink data iteration. Reset before modifying green blink data or delay.
** Bit 9: Set this bit to enable red light blink data. If red blink data iteration is not on, the red light state is read from bit 0 of red blink data.
** Bit 10: Set this bit and bit 12 to enable red blink data iteration.
** Bit 12: Set this bit and bit 10 to enable red blink data iteration. Reset before modifying red blink data or delay.
** Bit 13: Forces red light on if bit 4 is 0, or red light off if bit 4 is 1. (?)
* 90110B04 (R/W): Green blink data. 32 bits of on and off state, represented by 1 and 0. Iteration is done from bit 31 to bit 0 repeatedly.
* 90110B08 (R/W): Green blink delay (negative). OS sets this to -2048.
* 90110B0C (R/W): Red blink data. 32 bits of on and off state, represented by 1 and 0. Iteration is done from bit 31 to bit 0 repeatedly.
* 90110B10 (R/W): Red blink delay (negative). OS sets this to -2048.
 
Note: If red and green lights are on at the same time, the color becomes yellow.
 
==A4000000 - Internal SRAM==
 
0x20000 bytes SRAM, managed by the controller at 0xB8000000.
 
==B0000000 - USB OTG controller==
 
The OTG controller on all models is a ChipIdea-based dual-role USB controller. It only supports full speed communications so the PFSC bit (bit 24) must be set in the PORTSC register when in host mode. Otherwise, it'll attempt to connect at high speed for devices that support it and will never succeed in enumerating them.
 
Documentation can be found in the [http://www.freescale.com/files/dsp/doc/ref_manual/IMX23RM.pdf IMX233 reference manual].
The host interface is, again, based on EHCI; but the register defaults are different. The addresses have been adjusted from the ones contained in the IMX233 reference manual.
 
* Module identification registers
** B0000000: HW_USBCTRL_ID - default 0xE241FA05
** B0000004: HW_USBCTRL_HWGENERAL - default 0x00000015
** B0000008: HW_USBCTRL_HWHOST - default 0x10020001
** B000000C: HW_USBCTRL_HWDEVICE - default 0x0000000B
** B0000010: HW_USBCTRL_HWTXBUF - default 0x40060910
** B0000014: HW_USBCTRL_HWRXBUF - default 0x00000710
* Capability registers
** B0000100: HW_USBCTRL_CAPLENGTH - default 0x01000040
** B0000104: HW_USBCTRL_HCSPARAMS - default 0x00010011
** B0000108: HW_USBCTRL_HCCPARAMS - default 0x00000006
** B0000120: HW_USBCTRL_DCIVERSION - default 0x00000001
** B0000124: HW_USBCTRL_DCCPARAMS - default 0x00000185 (host-capable, device-capable, 5 endpoints)
* Operational registers
** B0000140: HW_USBCTRL_USBCMD - default 0x00080B00 in host mode, 0x00080000 in device mode
** B0000144: HW_USBCTRL_USBSTS - default 0x00001000 in host mode, 0x00000000 in device mode
** B0000148: HW_USBCTRL_USBINTR - default 0x00000000
** B000014C: HW_USBCTRL_FRINDEX - default 0x00000000
** B0000154: (in host mode) HW_USBCTRL_PERIODICLISTBASE - default 0x00000000
** B0000154: (in device mode) HW_USBCTRL_DEVICEADDR - default 0x00000000
** B0000158: (in host mode) HW_USBCTRL_ASYNCLISTADDR - default 0x00000000
** B0000158: (in device mode) HW_USBCTRL_ENDPOINTLISTADDR - default 0x00000000
** B000015C: HW_USBCTRL_TTCTRL - default 0x00000000
** B0000160: HW_USBCTRL_BURSTSIZE - default 0x00001010
** B0000164: HW_USBCTRL_TXFILLTUNING - default 0x000000000
** B000016C: HW_USBCTRL_IC_USB - default 0x00000000
** B0000170: HW_USBCTRL_ULPI - default 0x00000000
** B0000178: HW_USBCTRL_ENDPTNAK - default 0x00000000
** B000017C: HW_USBCTRL_ENDPTNAKEN - default 0x00000000
** B0000184: HW_USBCTRL_PORTSC1 - default 0x10000000
** B00001A4: HW_USBCTRL_OTGSC - default 0x00000120
** B00001A8: HW_USBCTRL_USBMODE - default 0x00000000
** B00001AC: HW_USBCTRL_ENDPTSETUPSTAT - default 0x00000000
** B00001B0: HW_USBCTRL_ENDPTPRIME - default 0x00000000
** B00001B4: HW_USBCTRL_ENDPTFLUSH - default 0x00000000
** B00001B8: HW_USBCTRL_ENDPTSTAT - default 0x00000000
** B00001BC: HW_USBCTRL_ENDPTCOMPLETE - default 0x00000000
** B00001C0: HW_USBCTRL_ENDPTCTRL0 - default 0x00100010
** B00001C4: HW_USBCTRL_ENDPTCTRL1 - default 0x00000000
** B00001C8: HW_USBCTRL_ENDPTCTRL2 - default 0x00000000
** B00001CC: HW_USBCTRL_ENDPTCTRL3 - default 0x00000000
** B00001D0: HW_USBCTRL_ENDPTCTRL4 - default 0x00000000
 
===Role switching===
 
During role switching some GPIO output registers are modified.
 
* GPIO2:
** Active low.
** Controls VBUS/pull-up (drives VBUS to 5v for host mode)
 
* USB-B: GPIO6
** Active low.
** Probably controls charging from USB
 
==B4000000 - USB HOST controller==
 
Same port structure as B0000000.
 
==B8001000 - SRAM Controller==
 
A [http://infocenter.arm.com/help/topic/com.arm.doc.ddi0380g/DDI0380G_smc_pl350_series_r2p1_trm.pdf PL352] r1p2.
 
==C0000000 - LCD controller==
 
A [http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0293c/index.html PL111].
 
==C4000000 - Analog-to-Digital Converter (ADC)==
 
Used to check various voltages. Channels 1 ("VBATT"), 2 ("VSYS"), and 4 ("B12") are used to check the battery status; channel 3 is used to determine which keypad is in use.
 
* C4000000 (R): Masked interrupt status (4 bits per channel: bits 0-3 are for channel 0, etc)
* C4000004 (R/W): Raw interrupt status, write 1 bits to acknowledge
* C4000008 (R/W): Interrupt enable register
* C4000100-C40001DF: Per-channel registers (channel 0 starts at C4000100, channel 1 at C4000120, etc.)
** +00 (R/W): Set bit 0 to start measurement; interrupt status bits 0 and 1 will be set when complete and the value will be stored in +10 register. Other commands do exist, including some that write to memory.
** +04 (R/W): Unknown (28 bits)
** +08 (R/W): Number of halfwords to write (25 bits)
** +0C (R/W): Base address (word-aligned)
** +10 (R): Read measured voltage. Scale for channels 1 and 2 is 155 units = 1 volt; scale for other channels is 310 units = 1 volt
** +14 (R/W): Speed (10 bits, set to AHB clock speed / 40000)
 
==C8010000 - Triple DES encryption==
 
Implements the [http://en.wikipedia.org/wiki/Triple_DES Triple DES encryption algorithm].
 
* C8010000 (R/W): Right half of block
* C8010004 (R/W): Left half of block. Writing this causes the block to be encrypted/decrypted.
* C8010008 (R/W): Right 32 bits of key 1
* C801000C (R/W):
** Bits 0-23: Left 24 bits of key 1
** Bit 30: Set to 0 to encrypt, 1 to decrypt
* C8010010 (R/W): Right 32 bits of key 2
* C8010014 (R/W): Left 24 bits of key 2
* C8010018 (R/W): Right 32 bits of key 3
* C801001C (R/W): Left 24 bits of key 3
 
==CC000000 - SHA-256 hash generator==
 
Implements the [http://en.wikipedia.org/wiki/SHA_hash_functions SHA-256 hash algorithm], which is used in cryptographic signatures.
 
* CC000000 (R): Busy if bit 0 set
* CC000000 (W): Write 0x10 and then 0x0 to initialize. Write 0xA to process first block, 0xE to process subsequent blocks
* CC000008 (R/W): Some sort of bus write-allow register? If a bit is set, it allows R/W access to the registers of the peripheral, if clear, R/O access only. Don't know what it's doing here, but it's here anyway.
** Bit 8: [[#CC000000 - SHA-256 hash generator]]
** Bit 10: ?
* CC000010-CC00004F (R/W): 512-bit block
* CC000060-CC00007F (R): 256-bit state
 
==DC000000 - Interrupt controller==
See [[Interrupts]]. The controller is a [http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0181e/index.html PL190].

Revision as of 20:58, 4 August 2020

General Processor-related Info

On the ARM processor, there are two types of interrupts:

IRQ

IRQ is the typical interrupt type (and is the one used by TI-Nspire OS). It can be disabled by setting bit I (0x80) in the CPSR register.

When an IRQ is triggered, the following happens:

  • The return address plus 4 is copied to the IRQ_LR register.
  • The CPSR register is copied to the IRQ_SPSR register.
  • The I bit of CPSR is set (disabling IRQ).
  • The processor mode is set to IRQ (mode 0x12). This mode swaps the SP and LR registers for the IRQ_SP and IRQ_LR registers (so the IRQ handler can have its own stack and know the return address)
  • The processor begins executing from 0x00000018.

After the IRQ handler is executed, the following code can be used to return to the previously executing code and restore the CPSR:

  • SUBS PC,LR,#4

FIQ

FIQ is designed for fast response time, and has priority over IRQ (note that FIQ is not automatically disabled upon entry to IRQ). It can be disabled by setting bit F (0x40) in the CPSR register.

When an FIQ is triggered, the following happens:

  • The return address plus 4 is copied to the FIQ_LR register.
  • The CPSR register is copied to the FIQ_SPSR register.
  • The I and F bits of CPSR are set (disabling IRQ and FIQ).
  • The processor mode is set to FIQ (mode 0x11). This mode swaps the R8 - R12, SP, and LR registers for the FIQ_R8 - FIQ_R12, FIQ_SP, and FIQ_LR registers (so the FIQ handler can have its own stack, know the return address, and have multiple free registers to improve interrupt latency)
  • The processor begins executing from 0x0000001C. This is at the end of the vector table, so it is possible to put the entire FIQ handler at this location rather than using a branch instruction.

After the FIQ handler is executed, the following code can be used to return to the previously executing code and restore the CPSR:

  • SUBS PC,LR,#4

TI-Nspire Interrupt Controller

From here on, IRQ and FIQ can be used interchangeably, so for convenience' sake only IRQ will be mentioned. (An FIQ I/O register will be the IRQ register plus 0x100 unless otherwise mentioned.)

IRQ Numbers

On the TI-Nspire, there can be up to 32 different interrupt sources, numbered 0-31. The following is a list of the currently known IRQ numbers:

The following documentation is for TI-Nspire classic. The CX has a PL190 interrupt controller.

IRQ Priority

Each of the 32 IRQ sources can be assigned a priority number from 0-7. Lower numbers indicate higher priority. The array of priority values is located at 0xDC000300-0xDC00037F. This array is used by both IRQ and FIQ.

IRQ Raw Status

The register at 0xDC000004 reads the raw interrupt status, which is a bitfield where each bit corresponds to an interrupt source. Each bit will be set if the source is requesting an interrupt (regardless of whether that IRQ number is enabled or disabled) or reset if not.

IRQ Sticky Status

The register at 0xDC000004 can also be configured bit-by-bit to read a "sticky interrupt" status instead of the raw interrupt status. When an interrupt source's raw status changes from 0 to 1, the sticky status becomes set. Writing a 1 to the corresponding bit in the 0xDC000004 register will reset the sticky interrupt. The register at 0xDC000204 controls whether each bit in 0xDC000004 reads the raw status (bit=0) or the sticky status (bit=1). This register is shared by IRQ and FIQ.

IRQ Mask

A bitmask is used to enable or disable each interrupt source. If a bit in the mask is 1, the corresponding IRQ will be enabled. If the bit is 0, the IRQ will be disabled. Writing to register 0xDC000008 will set the bits in the mask that are set in the written value (thus enabling IRQ sources), and writing to 0xDC00000C will reset the bits in the mask that are set in the written value (disabling IRQ sources). Reading either of these registers will return the IRQ mask.

IRQ Masked Status

The register at 0xDC000000 reads the masked interrupt status, where each bit is set if the corresponding bit in 0xDC000004 is set and the IRQ is "masked in" (aka enabled). In this case, the IRQ is known as "active". But simply having bits set in this register will not necessarily cause an IRQ to be triggered, as shown below.

IRQ Max Priority

The register at 0xDC00002C controls which priority level IRQs can be triggered. Only IRQs with priority number less than the value in this register can trigger an interrupt.

IRQ Current Number

The register at 0xDC000020 reads the current IRQ number. This number is the active IRQ of highest priority (i.e. lowest priority value). If there are multiple active IRQs of the same priority, the lowest IRQ number is chosen. If there are no active IRQs, this value will be 0. The IRQ Current Number is what really forces IRQ priority, because it tells the interrupt handler which IRQ to handle.

Triggering IRQs

When an IRQ is triggered (which only happens if there is an active IRQ with priority number less than IRQ Max Priority), imagine an internal flag that is set to 1. The only way to reset this flag is by reading the register at 0xDC000028 when there are no IRQs triggering the flag. The flag will be set regardless of the status of the I bit in CPSR. The interrupt will actually be taken once the I bit is reset (IRQ is enabled again). But this internal flag will continue to be set even if you mask out the IRQ source that caused it. Thus, it is possible that an interrupt can be taken even if there are no active IRQs! Thus, it is recommended to read register 0xDC000028 after disabling any IRQ types.

Handling Interrupts

  • Save clobbered registers to the IRQ stack.
  • Read 0xDC000024.
    • The value read will be the IRQ Current Number.
    • As a side effect, the value of IRQ Max Priority is copied to 0xDC000028 and the priority of IRQ Current Number is copied to IRQ Max Priority.
  • If using sticky interrupts, write (1 << IRQ Current Number) to 0xDC000004.
  • Read 0xDC000028.
    • This will reset the interrupt trigger flag if there are no other active interrupts.
    • Since IRQ Max Priority is now equal to the priority of IRQ Current Number, the current IRQ cannot re-trigger the interrupt flag.
    • The value read is the previous value of IRQ Max Priority. This can be used later.
  • Use the IRQ Current Number to decide which IRQ source to handle.
  • Acknowledge the interrupt at the source, which should reset the IRQ Raw Status bit.
  • Do anything else needed for this interrupt.
  • Update the IRQ Max Priority. Either write the value read from 0xDC000028 to restore the previous value, or write 8 to allow interrupts of any priority.
  • Restore clobbered registers from the stack and exit the interrupt handler.