You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

树莓派4 ARM64汇编GPIO驱动问题:GPCLR0偏移无法清除引脚

问题分析与修复

你的代码存在几个关键问题,导致GPCLR0无法正确熄灭LED:

1. GPIO引脚位掩码错误

你要操作的是GPIO17,但在GPSET0和GPCLR0操作时,只写入了1(对应GPIO0的位),没有将掩码左移17位。这意味着你实际操作的是GPIO0,而非目标引脚GPIO17。

2. nanosleep系统调用的参数错误

nanosleep(syscall号0x65)要求传入的是struct timespec结构体指针,该结构体包含两个64位字段(tv_sec和tv_nsec),但你用.word定义了32位值,会导致内存访问错误,系统调用无法正常工作。

3. 寄存器被意外覆盖

调用nanosleep时,x1寄存器被用作剩余时间的指针,会覆盖之前设置的位掩码值,导致后续的GPCLR0操作使用错误的值。


修改后的代码片段

关键修改点:

  • 为GPIO17创建正确的位掩码,并在操作GPSET0/GPCLR0时使用
  • 修正timespec结构体的定义为64位字段
  • 保存位掩码到不会被系统调用覆盖的寄存器,避免值丢失
.global _start

.equ RDWR, 00000002
.equ SYNC, 00010000
.equ RESOLVE_IN_ROOT, 0x08
.equ MAP_SHARED, 0x01
.equ PROT_READ, 0x1
.equ PROT_WRITE, 0x2
.equ PAGELEN, 4096
.equ offset17, 21
.equ GPFSEL1, 0x04
.equ GPSET0, 0x1c
.equ GPCLR0, 0x28
.equ GPIO17_MASK, (1 << 17)  ; 新增:GPIO17的位掩码

_start:
    ldr x0, =RESOLVE_IN_ROOT
    ldr x1, =devmem
    mov x2, #(RDWR+SYNC)
    mov x8, #0x38
    svc 0
    adds x4, xzr, x0
    bpl Mmap
    mov x0, #1
    ldr x1, =errmessage
    ldr x2, =len
    mov x8, #0x40
    svc 0
    b exit
Mmap:
    ldr x0, =gpioBaseAddress
    mov x1, #PAGELEN
    mov x2, #(PROT_READ + PROT_WRITE)
    mov x3, #MAP_SHARED
    orr x5, x5, xzr
    mov x8, #0xde
    svc 0
    adds x9, xzr, x0
    bpl Select
    mov x0, #1
    ldr x1, =errmessage
    mov x2, #len
    mov x8, #0x40
    svc 0
Select:
    mov x1, #0b001
    lsl x1, x1, #offset17
    str w1, [x9, #GPFSEL1]

loop:
    add x10, x10, #1
    mov x1, #GPIO17_MASK  ; 使用GPIO17的正确掩码
    str w1, [x9, #GPSET0]
    ldr x0, =timeamount
    ldr x1, =timeremaining
    mov x8, #0x65
    svc 0
    mov x1, #GPIO17_MASK  ; 重新加载掩码,避免被nanosleep覆盖
    str w1, [x9, #GPCLR0]
    ldr x0, =timeamount
    ldr x1, =timeremaining
    mov x8, #0x65
    svc 0
    cmp x10, #10
    bne loop
    b exit
exit:
    mov x0, #0
    mov x8, #0x5d
    svc 0
.data
devmem:
    .asciz "/dev/gpiomem"
errmessage:
    .asciz "couldn't obtain file descriptor"
len = .-errmessage
gpioBaseAddress:
    .dword 0xfe200000  ; 改为64位定义,适配ARM64
timeamount:
    .dword 1           ; tv_sec = 1秒
    .dword 0           ; tv_nsec = 0
timeremaining:
    .dword 0
    .dword 0

额外说明

  • 树莓派4的GPIO基地址0xfe200000是正确的,无需修改
  • 所有GPIO寄存器操作必须使用32位指令(str w1而非str x1),你的这部分处理是正确的
  • 修改后,GPIO17会被正确设置为输出,循环执行点亮1秒、熄灭1秒的操作,重复10次后退出

内容的提问来源于stack exchange,提问作者Virtual Wizard

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 21:04:58