Raspberry Pi 4 bare metal GPIO set/clear issue
There are a few potential problems here. First and most importantly, when writing to GPIO registers, you should use str instead of ldr for the final GPIO_SET0 operation. You’re currently trying to read from the SET0 register rather than write to it. Here’s the corrected line:
str x1, [x0, #GPIO_SET0] // Use str to write to the register
The base address 0xFE200000 is correct for the Raspberry Pi 4’s peripheral base when using the ARM64 architecture, so that’s not the issue.
Your setup code for configuring GPIO 21 as an output looks correct, using GPIO_SEL2 register (GPFSEL2) and setting bits 3-5 for GPIO 21.
When running bare metal code, you need to ensure proper initialization. Here’s a more complete version of your code that might help:
.section ".text.boot"
.global _start
.equ GPIO_BASE, 0xFE200000
.equ GPIO_SET_21_OUT, 1 << 3
.equ GPIO_SEL2, 0x08
.equ GPIO_SET0, 0x1C
.equ GPIO_21, 1 << 21
_start:
// Ensure we're in EL1
mrs x0, currentel
lsr x0, x0, #2
cmp x0, #1
bne .
// Disable all interrupts
msr daifset, #0xf
// Initialize stack pointer
ldr x0, =_start
mov sp, x0
// GPIO initialization
ldr x0, =GPIO_BASE
ldr x1, =GPIO_SET_21_OUT
str x1, [x0, #GPIO_SEL2]
ldr x1, =GPIO_21
str x1, [x0, #GPIO_SET0] // Changed to str
loop:
nop
b loop
For your compilation, make sure you’re using the correct flags. Here’s a suggested compilation process:
aarch64-none-elf-as -c source.s -o source.o
aarch64-none-elf-ld -T linker.ld source.o -o kernel8.elf
aarch64-none-elf-objcopy -O binary kernel8.elf kernel8.img
And here’s a basic linker script (linker.ld):
SECTIONS
{
. = 0x80000;
.text : { *(.text.boot) *(.text*) }
.rodata : { *(.rodata*) }
.data : { *(.data*) }
.bss : { *(.bss*) }
}
The inconsistency in 32-bit mode might be related to the initialization state of the hardware. The Raspberry Pi’s boot process can leave the hardware in different states, which is why proper initialization is important.
Read more here: Source link
