Arm Processor Modes: What are they and Why are they

Simple processors used to have two modes. The first would handle the everyday processing tasks, whilst the second would kick in when an interrupt occurred. The interrupt would result in the processor saving its current state and then jumping to some predefined location to service the interrupt. Modern processors are required to do much more complicated things, servicing many tasks/programs at the same time. Keeping these tasks separate from each other and from the OS requires additional levels of privilege and hence a need for additional modes.

User Mode

This is the default, unprivileged mode under which most processes run.

System Mode

System Mode provides a means for the exception handler to execute subroutines without the potential for further exceptions over-writing the return address stored in R14.

Fast Interrupt Mode (FIQ)

Fast Interrupt Requests are essentially higher priority interrupts which operate in a dedicated mode. FIQ mode has seven dedicated registers (R8-R14) allowing a degree os persistence between interrupts. Under Linux, which only uses IRQs, the use of this system allows the software to implement a degree of real-time code. Writing the code does however require the use of assembler because of the register restrictions.

Normal Interrupt Mode (IRQ)

IRQ mode is entered when a regular, low priority interrupt is raised. As with all exceptions, when an IRQ occurs the processor copies the CPSR register to the mode appropriate SPSR and assigns the return address to the mode appropriate return address. The CPSR mode bits are modified as according to the new mode and the program counter is set according to an address taken from the exception vector table

Abort Mode

Abort mode is entered after a data or instruction prefetch is aborted. This occurs as a result of an application attempting to access an illegal memory location. It is usually possible to calculate the address of the instruction that caused the exception by looking at the value of the link register (R14) and subtraction 8.

Supervisor Mode (SVC)

When code executing in user mode requires access to privileged parts of the system this is typically achieved by an SVC call and a switch to Supervisor Mode.

Undefined Mode

If an unrecognised instruction is encountered the processor vectors off into undefined mode so that software emulation of co-processors or other extensions to the instruction set can be carried out.

Monitor Mode (MON)

Monitor Mode is there to facilitate the debugging of an application without stopping the core entirely. The continued servicing of critical interrupt routines can therefore continue whilst the core is being probed by the debugger.

Hypervisor Mode

Hypervisor Mode is there to facilitate virtualization. In the same way that user-space uses the SVC instruction to switch into kernel-space (SVC mode), the processor needs to be switched into Hypervisor mode in order to make use of the virtualization extensions.

How to connect and control an I2C device under Linux

An I2C bus can be searched to identity which addresses are in use using the i2cdetect command as shown below.

$ i2cdetect 1
WARNING! This program can confuse your I2C bus, cause data loss and worse!
I will probe file /dev/i2c-1.
I will probe address range 0x03-0x77.
Continue? [Y/n] Y
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- UU -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- 2d -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- 49 -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

The output in the above example indicates that there are three devices on bus 1. Devices were identified at addresses 2d and 49. The ‘–‘ symbol indicates that these address were probed but that no device responded, whilst the ‘UU’ at address 08 indicates that this address was not probed as it was being held by another driver.

Having identified that a device is present you can interact with the device using the i2ctranfser command. In the first example given below a value is 0x80 is written to address 0x503d on the device located at I2C address 0x3c. The second example reads two bytes of data from address 0x300a on the same device. In this case the device responds with the values 0x36 and 0x4c, the correct product ID for the queried OV3640 camera device.

$ i2ctransfer -f -y 1 w3@0x3c 0x50 0x3d 0x80
$ i2ctransfer -f -y 1 w2@0x3c 0x30 0x0a r2
0x36 0x4c

Alternatively, if a suitable driver exists within the kernel then you can connect it as shown below and interact with it using sysfs. In the example given I have connected a ds1621 digital thermometer located at I2C address 0x3c and read the temperature of 29.5 C

$ echo ds1621 0x3c > /sys/bus/i2c/devices/i2c-1/new_device
$ cat /sys/class/hwmon/hwmon1/temp1_input
29500