-
Notifications
You must be signed in to change notification settings - Fork 3
Raspberry Pi Hardware
There are many versions of Raspberry Pi boards, each with each own characteristics, but many share a lot of similarities.
The main classification that can be done for the different models, is based on their Broadcom chip, their ARM Core, and their ARM Architecture.
- The Broadcom chip mainly determines the Peripherals of the boards, their addresses and their function.
-
BCM2835
,BCM2836
,BCM2837
have pretty much the same architecture and they share the same datasheet with some differences in the ARM-local peripherals, because of the different ARM Cores used. -
BCM2711
is a considerable on the previous ones and it has its own datasheet.
-
- The ARM Core mainly determines the ARM-local peripherals of each board, its speed and multicore support.
- The ARM Architecture determines the Instruction Set and as so the support for 32-bit or 64-bit architectures.
-
ARMv6
andARMv7-A
are 32-bit architectures with many similarities. -
ARMv8-A
is a newer architecture family that has support for both 32-bit or 64-bit instruction sets (AArch32
&AArch64
).
-
Here is a table that compares all the different characteristics of each model:
Specs / Pi Vers. | Pi Zero - Pi Zero W | Pi 2 | Pi 3 | Pi 4 |
---|---|---|---|---|
Broadcom Chip | BCM2835 | BCM2836 | BCM2837 | BCM2711 |
ARM Core | ARM1176JZF-S | Cortex-A7 | Cortex A53 | Cortex A72 |
ARM Core Family | ARM11 | Cortex-A | Cortex-A | Cortex-A |
ARM Architecture | ARMv6 | ARMv7-A | ARMv8-A | ARMv8-A |
Cores | Single core | Quad Core | Quad Core | Quad Core |
ISA Support Arch | - | AArch32 | AArch32 & AArch64 | AArch32 & AArch64 |
Instruction Set | 32 + 16 bit | 32 + 16 bit | 64 + 32 bit | 64 + 32 bit |
Thumb Support | Thumb2 (T32) | Thumb2 (T32) | - | - |
FPU | VFPv2 | VFPv4 | VFPv4 | VFPv4 |
NEON (SIMD) | - | 64-bit wide | 128-bit wide | 128-bit wide |
All peripherals communicate in memory with the CPU. Each has it's dedicated memory address starting from 0x7E000000
, but it's not in real RAM, it is what is called Memory Mapped IO.
The starting peripheral address for each board maps to different physical addresses based on the chip. So any reference at the datasheets for peripheral addresses that are advertised as 0x7Ennnnnn
bus addresses are:
- For Pi Zero - Pi Zero W:
- Mapped to
0x20nnnnnn
physical addresses (With starting address:0x20000000
).
- Mapped to
- For Pi 2, Pi 3:
- Mapped to
0x3Fnnnnnn
physical addresses (With starting address:0x3F000000
).
- Mapped to
- For Pi 4:
- Mapped to
0xFEnnnnnn
physical addresses (With starting address:0xFE000000
).
- Mapped to
The UART is a hardware device for asynchronous serial communication in which the data format and transmission speeds are configurable. It is a very useful interface for bare-metal applications or kernel development as it is the main form of input and output with the device, through serial communication, so it is usually the first thing that gets implemented in the kernel in order to send and receive messages to/from the application.
In order to have a sucessful UART connection, usually there are two connections needed:
- An Rx pin, that receives serial data.
- An Tx pin, that transmits serial data.
The two devices that want to communicate, connect each of their Rx, Tx pin to the opposite pin of the other device.
There are two types of UART available on the Raspberry Pi - PL011 and mini UART. The PL011 is a capable, broadly 16550-compatible UART, while the mini UART has a reduced feature set.
The Raspberry Pi Zero, 1, 2, and 3 each contain two UARTs as follows:
Name | Type |
---|---|
UART0 | PL011 |
UART1 | mini UART |
The Raspberry Pi 4 has four additional PL011s, which are disabled by default. The full list of UARTs on the Pi 4 is:
Name | Type |
---|---|
UART0 | PL011 |
UART1 | mini UART |
UART2 | PL011 |
UART3 | PL011 |
UART4 | PL011 |
UART5 | PL011 |
On the Raspberry Pi, one UART is selected to be present on GPIO 14
(transmit) and GPIO 15
(receive) - this is the primary UART. By default, this will also be the UART on which a Linux console may be present. Note that GPIO 14
is pin 8
on the GPIO header, while GPIO 15
is pin 10
.
The secondary UART is not normally present on the GPIO connector. By default, the secondary UART is connected to the Bluetooth side of the combined wireless LAN/Bluetooth controller, on models which contain this controller.
By default, only UART0 is enabled. The following table summarises the assignment of the first two UARTs:
Model | first PL011 (UART0) | mini UART |
---|---|---|
Raspberry Pi Zero | primary | secondary |
Raspberry Pi Zero W | secondary (Bluetooth) | primary |
Raspberry Pi 1 | primary | secondary |
Raspberry Pi 2 | primary | secondary |
Raspberry Pi 3 | secondary (Bluetooth) | primary |
Raspberry Pi 4 | secondary (Bluetooth) | primary |
Note: the mini UART is disabled by default, whether it is designated primary or secondary UART.
From the perspective of a Linux host, each UART device is shown differently in the /dev
directory:
Linux device | Description |
---|---|
/dev/ttyS0 |
mini UART |
/dev/ttyAMA0 |
first PL011 (UART0) |
/dev/serial0 |
primary UART |
/dev/serial1 |
secondary UART |
The mini UART
has smaller FIFOs. Combined with the lack of flow control, this makes it more prone to losing characters at higher baudrates. It is also generally less capable than a PL011
, mainly due to its baud rate link to the VPU clock speed.
The particular deficiencies of the mini UART
compared to a PL011
are:
- No break detection
- No framing errors detection
- No parity bit
- No receive timeout interrupt
- No DCD, DSR, DTR or RI signals
But the mini UART
is more easy to setup and configure, so it is the prefered choice as a first form of UART communication.
There are different configurations that need to be set up in order to use the mini UART for each Pi board. For the boards that have the mini UART as a secondary interface we need to set, we need to activate them and select the pin's alternative function 5
in order to make them work for UART 1
which is the mini UART
, the primary UART for the Raspberry Pi Zero W, Raspberry Pi 3, Raspberry Pi 4.
Also for the Raspberry Pi 3 and Pi 4, in order to use the mini UART, we need to configure the Raspberry Pi to use a fixed VPU core clock frequency. This is because the mini UART clock is linked to the VPU core clock, so that when the core clock frequency changes, the UART baud rate will also change.
The core_freq=500
setting can be added to config.txt
, in order to force the core clock to a fixed frequency of 500MHz, to change the behaviour of the mini UART.
Specifically for the UART the physical addresses for each board are the following:
Specs / Pi Vers. | Pi Zero - Pi Zero W | Pi 2 - Pi 3 | Pi 4 |
---|---|---|---|
MMIO_BASE | 0x20000000 |
0x3F000000 |
0xFE000000 |
GPIO_BASE | 0x20200000 |
0x3F200000 |
0xFE200000 |
UART_BASE | 0x20201000 |
0x3F201000 |
0xFE201000 |
We mentioned earlier a file called config.txt
. This file we can set the system configuration parameters, which would traditionally be edited and stored using a BIOS.
This is read by the GPU before the ARM CPU and the kernel are initialised. It must therefore be located on the first (boot
) partition of the SD card, alongside bootcode.bin
and start.elf
.
In the following sections, this file will be refernced in order to set some needed configurations.
Devices usually don't interrupt processor directly: instead, they rely on interrupt controller to do the job. Interrupt controller can be used to enable/disable interrupts sent by the hardware. We can also use interrupt controller to figure out which device generates an interrupt.
Raspberry PI has its own interrupt controller that is described on page 109 of BCM2835 ARM Peripherals manual and page 83 of BCM2711 ARM Peripherals manual.
The interrupt controllers for each chip are somewhat different, so we are going to examine each controller differently.
The base address for the ARM interrupt register is 0x7E00B000
.
Registers overview:
Address offset | Name |
---|---|
0x200 | IRQ basic pending |
0x204 | IRQ pending 1 |
0x208 | IRQ pending 2 |
0x20C | FIQ control |
0x210 | Enable IRQs 1 |
0x214 | Enable IRQs 2 |
0x218 | Enable Basic IRQs |
0x21C | Disable IRQs 1 |
0x220 | Disable IRQs 2 |
0x224 | Disable Basic IRQs |
The table in page 113, lists all interrupts which can come from the peripherals which can be handled by the ARM.
ARM peripherals interrupts table is broken into to banks:
- Bank 1:
0 - 31
- Bank 2:
32 - 63
In page 113,
IRQ 0-3
are system timer interrupts 0-3, and are missing from the table, source.
Raspberry Pi interrupt controller has 3 registers (1, 2, Basic
) that hold enabled/disabled status for all types of interrupts.
The Basic
IRQs are some common interrupts together with ARM local interrupts, and are defined from the ARM peripherals interrupts table:
# | ARM peripherals interrupts |
---|---|
0 | ARM Timer |
1 | ARM Mailbox |
2 | ARM Doorbell 0 |
3 | ARM Doorbell 1 |
4 | GPU0 halted (Or GPU1 halted if bit 10 of control register 1 is set) |
5 | GPU1 halted |
6 | Illegal access type 1 |
7 | Illegal access type 0 |
If we are interested in system timer interrupts, they are at lines 0 - 3 of the table in page 113, so they are in Bank 1.
We can enable system timer interrupts, by setting the bits 0-3 of IRQ enable 1 register at 0x210
according to the timer we want:
ENABLE_IRQS_1 = (1 << 0) // System Timer Compare 0
ENABLE_IRQS_1 = (1 << 1) // System Timer Compare 1
ENABLE_IRQS_1 = (1 << 2) // System Timer Compare 2
ENABLE_IRQS_1 = (1 << 3) // System Timer Compare 3
In the same maner we can disable the interrupts for system timers, by setting the bits 0-3 of IRQ disable 1 register at 0x21C
according to the timer we want:
DISABLE_IRQS_1 = (1 << 0) // System Timer Compare 0
DISABLE_IRQS_1 = (1 << 1) // System Timer Compare 1
DISABLE_IRQS_1 = (1 << 2) // System Timer Compare 2
DISABLE_IRQS_1 = (1 << 3) // System Timer Compare 3
The BCM2711 has a large number of interrupts from various sources, and a choice of two interrupt controllers. The GIC-400
interrupt controller is selected by default, but the legacy interrupt controller can be selected with a setting in config.txt
.
In the VideoCore interrupts table at page 85, we can see all the peripheral interrupts that we might be interested in:
# | IRQ 0-15 | # | IRQ 16-31 | # | IRQ 32-47 | # | IRQ 48-63 |
---|---|---|---|---|---|---|---|
0 | Timer 0 | 16 | DMA 0 | 32 | HDMI CEC | 48 | SMI |
1 | Timer 1 | 17 | DMA 1 | 33 | HVS | 49 | GPIO 0 |
2 | Timer 2 | 18 | DMA 2 | 34 | RPIVID | 50 | GPIO 1 |
3 | Timer 3 | 19 | DMA 3 | 35 | SDC | 51 | GPIO 2 |
4 | H264 0 | 20 | DMA 4 | 36 | DSI 0 | 52 | GPIO 3 |
5 | H264 1 | 21 | DMA 5 | 37 | Pixel Valve 2 | 53 | OR of all I2C |
6 | H264 2 | 22 | DMA 6 | 38 | Camera 0 | 54 | OR of all SPI |
7 | JPEG | 23 | DMA 7 & 8 | 39 | Camera 1 | 55 | PCM/I2S |
8 | ISP | 24 | DMA 9 & 10 | 40 | HDMI 0 | 56 | SDHOST |
9 | USB | 25 | DMA 11 | 41 | HDMI 1 | 57 | OR of all PL011 UART |
10 | V3D | 26 | DMA 12 | 42 | Pixel Valve 3 | 58 | OR of all ETH_PCIe L2 |
11 | Transposer | 27 | DMA 13 | 43 | SPI/BSC Slave | 59 | VEC |
12 | Multicore Sync 0 | 28 | DMA 14 | 44 | DSI 1 | 60 | CPG |
13 | MultiCore Sync 1 | 29 | AUX | 45 | Pixel Valve 0 | 61 | RNG |
14 | MultiCore Sync 2 | 30 | ARM | 46 | Pixel Valve 1 & 4 | 62 | EMMC & EMMC2 |
15 | MultiCore Sync 3 | 31 | DMA 15 | 47 | CPR | 63 | ETH_PCIe secure |
The ARMC
register base address is 0x7E00B000
(the same as the BCM2835).
There are 4 cores in the ARM processor (n = 0,1,2,3
), and there are 4 diferrent exceptions to be handled:
- IRQ
- FIQ
- SWIR
We have set and clear registers responsible for the masking and unmasking of the exceptions, for each core and interrupt:
IRQn_SET_EN_x
IRQn_CLR_EN_x
FIQn_SET_EN_x
FIQn_CLR_EN_x
SWIRQ_SET
SWIRQ_CLEAR
We are interested in the IRQ interrupts and only for one core (core 0
) so here is the table (page 98) that describes the function of each register and its offset from the ARMC
register base address:
Offset | Name | Description |
---|---|---|
0x200 |
IRQ0_PENDING0 |
ARM Core 0 IRQ Enabled Interrupt Pending bits [31:0]
|
0x204 |
IRQ0_PENDING1 |
ARM Core 0 IRQ Enabled Interrupt pending bits [63:32]
|
0x208 |
IRQ0_PENDING2 |
ARM Core 0 IRQ Enabled Interrupt pending bits [79:64]
|
0x210 |
IRQ0_SET_EN_0 |
Write to Set ARM Core 0 IRQ enable bits [31:0]
|
0x214 |
IRQ0_SET_EN_1 |
Write to Set ARM Core 0 IRQ enable bits [63:32]
|
0x218 |
IRQ0_SET_EN_2 |
Write to Set ARM Core 0 IRQ enable bits [79:64]
|
0x220 |
IRQ0_CLR_EN_0 |
Write to Clear ARM Core 0 IRQ enable bits [31:0]
|
0x224 |
IRQ0_CLR_EN_1 |
Write to Clear ARM Core 0 IRQ enable bits [63:32]
|
0x228 |
IRQ0_CLR_EN_2 |
Write to Clear ARM Core 0 IRQ enable bits [79:64]
|
If we are interested in system timer interrupts, they are at lines 0 - 3 of the table, so they are in Bank 0.
We can enable system timer interrupts, by setting the bits 0-3 of IRQ0_SET_EN_0
register at 0x210
according to the timer we want:
IRQ0_SET_EN_0 = (1 << 0) // System Timer Compare 0
IRQ0_SET_EN_0 = (1 << 1) // System Timer Compare 1
IRQ0_SET_EN_0 = (1 << 2) // System Timer Compare 2
IRQ0_SET_EN_0 = (1 << 3) // System Timer Compare 3
In the same maner we can disable the interrupts for system timers, by setting the bits 0-3 of IRQ0_CLR_EN_0
register at 0x220
according to the timer we want:
IRQ0_CLR_EN_0 = (1 << 0) // System Timer Compare 0
IRQ0_CLR_EN_0 = (1 << 1) // System Timer Compare 1
IRQ0_CLR_EN_0 = (1 << 2) // System Timer Compare 2
IRQ0_CLR_EN_0 = (1 << 3) // System Timer Compare 3
The System Timer on the Pi's uses a different clock frequence from the ARM cpu and it is 1MHz
.
The System Timer peripheral provides four 32-bit timer channels (n = 0,1,2,3
) and a single 64-bit free running counter. Each channel has an output compare register (Cn
), which is compared against the 32 least significant bits of the free running counter values.
The 4 output compare register for each channel:
- System Timer 0:
C0
- System Timer 1:
C1
- System Timer 2:
C2
- System Timer 3:
C3
System Timer 0 and 2 are not usable for us, because they are being used internally for the GPU (VideoCore device).
The 2 32-bit registers for the single 64-bit free running counter:
CLO
CHI
When the two values match (Cn
with CL0
), the system timer peripheral generates a signal to indicate a match for the appropriate channel. The match signal is then fed into the interrupt controller. Totally 4 different interrupts can be generated from the 4 channels.
The interrupt service routine then reads the output compare register and adds the appropriate offset for the next timer tick.
The free running counter is driven by the timer clock and stopped whenever the processor is stopped in debug mode.
The System Timer Registers are defined in page 172 of BCM2835 ARM Peripherals manual and page 140 of BCM2711 ARM Peripherals manual:
Offset | Name | Description |
---|---|---|
0x00 |
CS |
System Timer Control/Status |
0x04 |
CLO |
System Timer Counter Lower 32 bits |
0x08 |
CHI |
System Timer Counter Higher 32 bits |
0x0c |
C0 |
System Timer Compare 0 |
0x10 |
C1 |
System Timer Compare 1 |
0x14 |
C2 |
System Timer Compare 2 |
0x18 |
C3 |
System Timer Compare 3 |
The System Timer Control / Status CS
register, is used to record and clear timer channel comparator matches. The system timer match bits are routed to the interrupt controller where they can generate an interrupt.
The M0-3
fields contain the free-running counter match status.
We write a one to the relevant bit to clear the match detect status bit and the corresponding interrupt request line.
If we are using System Timer 1, in the interrupt handler we set the bit M1
to 1:
TIMER_CS = (1 << 1)
There are 54 general-purpose I/O (GPIO) lines split into two banks for thre BCM2835 chip and 57 for the BCM2711. All GPIO pins have at least two alternative functions within BCM. The alternate functions are usually peripheral IO and a single peripheral may appear in each bank to allow flexibility on the choice of IO voltage.
The GPIO pins have some dedicated registers, the main ones are responsible for doing the following:
- Setting pins High
- Clearing pins Low
- Defining the operation of the pin (Alternative Functions)
- Control the actuation of internal pull-downs resistors.
The registers responible for setting and clearing the pins are the following:
Name | Description |
---|---|
GPSET0 |
The GPSET0 register is used to set GPIO pins 0-31
|
GPSET1 |
The GPSET1 register is used to set GPIO pins 32-53
|
GPCLR0 |
The GPCLR0 register is used to clear GPIO pins 0-31
|
GPCLR1 |
The GPCLR1 register is used to clear GPIO pins 32-53
|
Most of the pins can be used with different devices, so before using a particular pin, we need to select the pin's alternative function. An alternative function is just a number from 0 to 5 that can be set for each pin and configures which device is connected to the pin.
All available GPIO alternative functions are the following:
-
000
= GPIO Pin 9 is an input -
001
= GPIO Pin 9 is an output -
100
= GPIO Pin 9 takes alternate function 0 -
101
= GPIO Pin 9 takes alternate function 1 -
110
= GPIO Pin 9 takes alternate function 2 -
111
= GPIO Pin 9 takes alternate function 3 -
011
= GPIO Pin 9 takes alternate function 4 -
010
= GPIO Pin 9 takes alternate function 5
Name | Description |
---|---|
GPFSEL0 |
GPIO Function Select 0,1,2,3,4,5 for pins 0-9
|
GPFSEL1 |
GPIO Function Select 0,1,2,3,4,5 for pins 10-19
|
GPFSEL2 |
GPIO Function Select 0,1,2,3,4,5 for pins 20-29
|
GPFSEL3 |
GPIO Function Select 0,1,2,3,4,5 for pins 30-39
|
GPFSEL4 |
GPIO Function Select 0,1,2,3,4,5 for pins 40-49
|
GPFSEL5 |
GPIO Function Select 0,1,2,3,4,5 for pins 50-59
|
These registers are used to control the pull-up/pull-down state of the pin. There are three available states: pull-up, pull-down, and neither (to remove the current pull-up or pull-down state).
The registers and their function have changed from the BCM2835 to the BCM2711 chip.
It has 3 registers:
Name | Description |
---|---|
GPPUD |
Controls actuation of pull up/down to ALL GPIO pins |
GPPUDCLK0 |
Controls actuation of pull up/down for GPIO pins 0-31
|
GPPUDCLK1 |
Controls actuation of pull up/down for GPIO pins 32-53
|
The GPPUD
who is responsible for controlling the pull-up/pull-down state of all pins, can take the following values:
-
00
= Off - disable pull-up/down -
01
= Enable Pull Down control -
10
= Enable Pull Up control -
11
= Reserved
The GPPUDCLK0-1
registers are used in conjunction with the GPPUD
register to effect GPIO Pull-up/down changes for each pin, and they can take the following values:
-
0
= No Effect -
1
= Assert Clock on line (n)
In this chip, we have the following 4 registers that control the actuation of the internal pull-up/down resistors for each pin:
Name | Description |
---|---|
GPIO_PUP_PDN_CNTRL_REG0 |
Controls actuation of pull up/down for GPIO pins 0-15
|
GPIO_PUP_PDN_CNTRL_REG1 |
Controls actuation of pull up/down for GPIO pins 16-31
|
GPIO_PUP_PDN_CNTRL_REG2 |
Controls actuation of pull up/down for GPIO pins 32-47
|
GPIO_PUP_PDN_CNTRL_REG3 |
Controls actuation of pull up/down for GPIO pins 48-57
|
Each can take the following values:
-
00
= No resistor is selected -
01
= Pull up resistor is selected -
10
= Pull down resistor is selected -
11
= Reserved
Blinking an LED for the Pi, is just a matter of manipulating the GPIO pins. In order to light an a LED we have to set a specific pin and in order to turn it off, we need to clear the pin. Also, we need to define that the pin is set as an output, by choosing the correct alternative function for the pin.
We can blink the following onboard LEDs for each model, using a GPIO PIN:
-
Pi 1 Models A and B
- The green activity LED (
GPIO 16
) may be written.
- The green activity LED (
-
Pi 1 Models A+ and B+
- The green activity LED (
GPIO 47
) may be written. - The red power LED (
GPIO 35
) may be written. - The high USB power mode (
GPIO 38
) may be written.
- The green activity LED (
-
Pi Zero and Pi Zero W
- The green activity LED (
GPIO 47
) may be written.
- The green activity LED (
-
Pi 2
- The green activity LED (
GPIO 47
) may be written. - The red power LED (
GPIO 35
) may be written. - The high USB power mode (
GPIO 38
) may be written.
- The green activity LED (
-
Pi 3
- The green activity LED writeable via mailbox .. as
GPIO 130
- The green activity LED writeable via mailbox .. as
-
Pi 3 B+
- The green activity LED (
GPIO 29
) may be written
- The green activity LED (
If we want ot move the function of ACT LED to other GPIO pin, we can set the following in config.txt
:
dtoverlay=act-led,gpio=17
On Raspberry Pi Zero the LED has inverted logic:
- We
CLR
its pin in order to turn it on. - We
SET
its pin in order to turn it off.
In order to invert that, we can set the following in config.txt
:
dtparam=act_led_trigger=none
dtparam=act_led_activelow=on
For Raspberry Pi 4 (and Pi 3), we can easily connect an external LED to a free GPIO PIN and control that. A full pinout for the Pi. From there select a GPIO PIN that preferably has not any other function. Such as GPIO PIN 17 (Physical PIN 11).
In order to connect it to the Pi, you need:
- 2 jumber wires
- An LED
- An 330 Ω resistor
The shorter leg (known as the ‘cathode’) is connected to the negative side of the power supply, known as ‘ground.
We have the following connections:
- Connect
GPIO PIN 17
(physical pin 11), to the anode of the LED (positive side - the longer leg). - Connect
GRND PIN
(physical pin 9), to the resistor - Connect the other end of the resistor to the cathode of the LED(negative side - the shorter leg).
Resistor 330Ω color band:
- If there are four colour bands, they will be:
- Orange, Orange, Brown, and then Gold.
- If there are five bands, then the colours will be:
- Orange, Orange, Black, Black, Brown.
Author: thanoskoutr
Wiki Documentation: https://github.com/thanoskoutr/armOS/wiki
Doxygen Documentation: https://thanoskoutr.github.io/armOS/