08_GPIO点灯_从J41插针查到复用与寄存器

Jetson Nano GPIO 点灯:从 J41 插针查到寄存器

对象:你目前使用的 Jetson Nano / Tegra X1、J41 物理 12 脚 、板端内核 4.9.253-tegra。这是一份查资料与理解课程代码 的流程;实际板型、设备树版本和灯的亮灭仍须在你的板上核对。配套代码见 led.c 和 app.c。

先抓住与 STM32 相同、不同的地方

两者都要回答三件事:选哪个管脚功能、设输入还是输出、输出高还是低 。STM32 常从芯片封装脚直接查到 GPIO 端口和 MODER/ODR/BSRR;Jetson Nano 还隔着载板 J41、模组 SODIMM、SoC 管脚命名、可能的电平转换器,以及 Linux 已有的 pinctrl/GPIO 驱动。

你熟悉的 STM32 思路 此例在 Jetson Nano 上对应什么
开发板排针 → MCU 封装脚 J41-12 → 载板信号 I2S0_SCLK → 模组第 199 脚 → SoC 管脚 DAP4_SCLK
选 GPIO/复用功能 Pinmux 管脚设置 + GPIO 控制器的 CNF 位;这是两层
配置输出方向 Pinmux 的 TRISTATE 放行输出,再设 GPIO 的 OE
写高/低电平 GPIO 的 OUT 位 7
裸机直接写寄存器 课程的 led.ko 在内核 中 ioremap/readl/writel;用户程序只能经 /dev/led 的 ioctl 调用它

#mermaid-svg-Z0sERM13Ylu8QE7U{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Z0sERM13Ylu8QE7U .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Z0sERM13Ylu8QE7U .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Z0sERM13Ylu8QE7U .error-icon{fill:#552222;}#mermaid-svg-Z0sERM13Ylu8QE7U .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Z0sERM13Ylu8QE7U .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Z0sERM13Ylu8QE7U .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Z0sERM13Ylu8QE7U .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Z0sERM13Ylu8QE7U .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Z0sERM13Ylu8QE7U .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Z0sERM13Ylu8QE7U .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Z0sERM13Ylu8QE7U .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Z0sERM13Ylu8QE7U .marker.cross{stroke:#333333;}#mermaid-svg-Z0sERM13Ylu8QE7U svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Z0sERM13Ylu8QE7U p{margin:0;}#mermaid-svg-Z0sERM13Ylu8QE7U .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Z0sERM13Ylu8QE7U .cluster-label text{fill:#333;}#mermaid-svg-Z0sERM13Ylu8QE7U .cluster-label span{color:#333;}#mermaid-svg-Z0sERM13Ylu8QE7U .cluster-label span p{background-color:transparent;}#mermaid-svg-Z0sERM13Ylu8QE7U .label text,#mermaid-svg-Z0sERM13Ylu8QE7U span{fill:#333;color:#333;}#mermaid-svg-Z0sERM13Ylu8QE7U .node rect,#mermaid-svg-Z0sERM13Ylu8QE7U .node circle,#mermaid-svg-Z0sERM13Ylu8QE7U .node ellipse,#mermaid-svg-Z0sERM13Ylu8QE7U .node polygon,#mermaid-svg-Z0sERM13Ylu8QE7U .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Z0sERM13Ylu8QE7U .rough-node .label text,#mermaid-svg-Z0sERM13Ylu8QE7U .node .label text,#mermaid-svg-Z0sERM13Ylu8QE7U .image-shape .label,#mermaid-svg-Z0sERM13Ylu8QE7U .icon-shape .label{text-anchor:middle;}#mermaid-svg-Z0sERM13Ylu8QE7U .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Z0sERM13Ylu8QE7U .rough-node .label,#mermaid-svg-Z0sERM13Ylu8QE7U .node .label,#mermaid-svg-Z0sERM13Ylu8QE7U .image-shape .label,#mermaid-svg-Z0sERM13Ylu8QE7U .icon-shape .label{text-align:center;}#mermaid-svg-Z0sERM13Ylu8QE7U .node.clickable{cursor:pointer;}#mermaid-svg-Z0sERM13Ylu8QE7U .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Z0sERM13Ylu8QE7U .arrowheadPath{fill:#333333;}#mermaid-svg-Z0sERM13Ylu8QE7U .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Z0sERM13Ylu8QE7U .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Z0sERM13Ylu8QE7U .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Z0sERM13Ylu8QE7U .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Z0sERM13Ylu8QE7U .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Z0sERM13Ylu8QE7U .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Z0sERM13Ylu8QE7U .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Z0sERM13Ylu8QE7U .cluster text{fill:#333;}#mermaid-svg-Z0sERM13Ylu8QE7U .cluster span{color:#333;}#mermaid-svg-Z0sERM13Ylu8QE7U div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Z0sERM13Ylu8QE7U .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Z0sERM13Ylu8QE7U rect.text{fill:none;stroke-width:0;}#mermaid-svg-Z0sERM13Ylu8QE7U .icon-shape,#mermaid-svg-Z0sERM13Ylu8QE7U .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Z0sERM13Ylu8QE7U .icon-shape p,#mermaid-svg-Z0sERM13Ylu8QE7U .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Z0sERM13Ylu8QE7U .icon-shape .label rect,#mermaid-svg-Z0sERM13Ylu8QE7U .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Z0sERM13Ylu8QE7U .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Z0sERM13Ylu8QE7U .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Z0sERM13Ylu8QE7U :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} J41 物理 12 脚
载板 I2S0_SCLK
模组脚 199
SoC DAP4_SCLK
Pinmux 0x70003150
GPIO3_PJ.07
CNF / OE / OUT 的 bit 7
输出通路
LED 电路

一、打开哪份资料、查哪里

下列文件都在 I:\Linux内核驱动\嵌入式AI班资料\7.硬件控制资料。页码是 PDF 阅读器显示的页码;有印刷页码时也写出。

顺序 资料与位置 本例查到什么
1 2.1 载板标注说明,PDF 第 21--22 页、印刷第 17--18 页,Figure 3-1 / Table 3-3 找 J41 Header Pin #12 ;表格同一行给出模组信号 I2S0_SCLK、模组脚 199、Tegra 管脚 DAP4_SCLK、GPIO 口 PJ.07。J41-39 是 GND,J41-40 是信号。
2 2.3 载板电路图,PDF 第 19 页 用 J41、I2S0_SCLK 搜网名,并看到 J41 信号经过载板电平转换器;排针不是直接焊到 SoC 焊球。
3 4.1 名称指南,PDF 第 15 页、印刷第 11 页 复核模组第 199 脚:模组名 I2S0_SCLK,SoC 名 DAP4_SCLK。
4 4.2 开发板 40PIN 表,Jetson_Nano_DevKit 工作表第 145 行 一行同时看到 J41 脚位、SoC 名、GPIO 名、设备树 pin 名,以及当前用途/方向。
5 3.1 Tegra X1 TRM,第 9 章:PDF 第 331 页 §9.15.82;第 247--252 页 §9.13/Table 32 查 PINMUX_AUX_DAP4_SCLK_0、GPIO Controller 3 --- Port J、CNF/OE/OUT 的偏移和位定义。
6 4.4 NVIDIA 40-pin 配置说明,PDF 第 4--8 页 理解表格生成 pinmux 设备树文件、启动阶段应用配置的流程;这是持久配置路线,与老师的运行时直接写寄存器实验不同。

本例暂时用不到 ARM Cortex-A57/GIC 手册。查"J41 第几脚"先看载板资料 ;查"寄存器偏移和每个位"才进入 Tegra X1 TRM ,不要在 2977 页 TRM 中盲搜 12。

二、把五种名字串成同一个管脚

按 4.2 开发板表 → Jetson_Nano_DevKit → 第 7 行列标题 → 第 145 行读:

单元格 值 它是什么
C145 12 J41 物理插针号。
A145 / B145 I2S0_SCLK / 199 模组对外信号名 / 模组 SODIMM 脚号,199 不是 J41 脚号。
D145 DAP4_SCLK Tegra SoC 的管脚名称;用它去 TRM 搜 pinmux 寄存器。
H145 GPIO3_PJ.07 GPIO 控制器 3、J 口、口内第 7 位。用它去 GPIO 寄存器表查。
I145 I2S4B_SCLK 同一 SoC 管脚的一个 SFIO 复用功能 。载板写 I2S0_SCLK,SoC 功能表写 I2S4B_SCLK,编号体系不同。
W145 / AE145 dap4_sclk_pj7 / GPIO_PJ7 设备树 pinctrl 查找名 / GPIO pin group 名;拿 dap4_sclk_pj7 去 BSP 的 .dtsi 搜。
AS145 / AT145 GPIO3_PJ.07 / Input 这份表当前设为 GPIO 用途、输入方向;要在启动配置中设输出,方向也要改变。

**查找动作:**先在载板 PDF 搜 J41 并定位 12;然后在表格 C 列搜 12,找到第 145 行;接着用 DAP4_SCLK 搜 TRM 的 Pinmux 小节,用 GPIO3_PJ.07 找 Controller 3 / Port J。改查别的引脚时,重新走这条链,不复制 PJ.07 的地址。

4.3 模组表 的同一管脚也在第 145 行,但没有 4.2 的"40 Pin Header"列,所以相应字段整体左移:SoC 名在 C145、GPIO 名在 G145、设备树名在 V145、用途/方向在 AR145/AS145。NVIDIA 的 4.4 说明提到 AR/AS,与你手中 4.2 表的 AS/AT 不同。总以当前工作表第 7 行的列标题为准。

三、两处"复用"到底怎么配

**第一处:SoC 管脚的 Pinmux 寄存器。**在 TRM §9.15.82 搜 PINMUX_AUX_DAP4_SCLK_0:偏移 0x3150,本例物理地址 0x70003150。该寄存器至少要分清:

位 含义 对输出灯的关系
PM[1:0] 选择 SFIO 编码:0=I2S4B,1=RSVD1,2/3=RSVD2/3。 不能把 PM=1 翻译成"GPIO 编号 1" 。板级 GPIO 配置可能采用 rsvd1 来避开 I2S;最终 GPIO/SFIO 还要看下方 CNF。
TRISTATE[4] 1 为高阻,0 为允许输出通路。 老师代码清零 bit 4。只清这里还不会自动输出高电平。
PUPD[3:2] 无上下拉、下拉或上拉。 决定输入/空闲时的默认偏置;不是控制亮灭的 OUT。
E_INPUT[6]、PARK[5] 输入缓冲、深睡眠停放状态。 本例代码没有系统处理这些字段,不能说它完成了全部管脚配置。

老师代码为 (readl(gpio_pinmux) & ~(1 << 4)) | 1:它清 bit 4、置 bit 0 ,没有清 PM 的 bit 1,因此并不保证最终 PM[1:0]=01;而 01 在手册中标为 RSVD1。理解代码时应按位核对,后续正式配置应使用与当前 BSP 对应的 pinctrl/设备树方案,不把这句推广给其他管脚。

第二处:GPIO 控制器本身。 GPIO3_PJ.07 中的 J 决定寄存器位置,07 决定寄存器内的位:

  • CNF bit 7 = 1:选择 GPIO,而非 SFIO。
  • OE bit 7 = 1:GPIO 作为输出;0 是输入/高阻。
  • OUT bit 7 = 1/0:输出高/低。课程接线约定高电平亮、低电平灭。

所以Pinmux 放行输出 → CNF 选 GPIO → OE 选输出 → OUT 写电平,四个动作服务于同一根管脚,不能只做其中一个。TRM §9.13.1--9.13.3 分别说明了这三个 GPIO 寄存器的条件。

四、偏移怎么算:为什么是 0x04 / 0x14 / 0x24

先从 Linux 4.9 的 Tegra210 SoC 设备树看两块 MMIO 范围:GPIO 控制器为 0x6000D000 起,Pinmux 的 mux 寄存器范围为 0x70003000 起。这是核对地址来源的参考;你自己的 NVIDIA BSP 和板上实际设备树仍要再对照。

TRM Table 32 的 GPIO Controller 3 --- Port I J K L 一行里,J 是第二列:

目标 相对整个 GPIO 块 0x6000D000 相对老师取的 GPIO3 基址 0x6000D200 实际物理地址
J 口 CNF +0x204 +0x04 0x6000D204
J 口 OE +0x214 +0x14 0x6000D214
J 口 OUT +0x224 +0x24 0x6000D224
text 复制代码
GPIO 块 0x6000D000 + 控制器 3 的 0x200 + J 口 CNF 的 0x04
                    = 0x6000D204
GPIO3 基址 0x6000D200 + J 口 OUT 的 0x24
                    = 0x6000D224
目标位 = 1 << 7 = 0x80

0x04 是 J 口相对于 I 口的寄存器位置 ,7 是 J 口内的位号 ,二者不能相加。上表是 TRM 的 Lower / Read-Modify-Write 地址;右侧另有 0x284/0x294/0x2A4 等 Upper / Per-Pin Mask Write 地址。老师代码使用 readl → 改位 → writel 的 Lower 地址,没有使用 Mask Write。不要把两列混用。

Pinmux 的 0x70003150 也可写成 0x70003000 + 0x150;TRM 写的 Offset: 0x3150 可理解为相对 0x70000000。不能把 0x3150 再加到 0x70003000 上。这里的 Pinmux 地址与上面的 GPIO 地址属于不同 MMIO 区域。

五、对照你现在的 led.c 看执行顺序

  1. register_chrdev_region(MKDEV(500,0), ...) 占用字符设备号 。这里的 500:0 只负责把 /dev/led 关联到驱动,和 J41-12、模组脚 199、GPIO bit 7 没有数值关系。
  2. ioremap(0x70003150, 8) 获得 Pinmux MMIO 的内核映射地址;readl/writel 修改该管脚的复用/三态字段。
  3. ioremap(0x6000D200, 0xFF) 获得 GPIO3 寄存器窗口;用 +0x04 设置 J 口 CNF bit 7,用 +0x14 设置 OE bit 7,再用 +0x24 设置 OUT bit 7。
  4. cdev_init/cdev_add 把 file_operations 接入字符设备;板端 /dev/led 必须是字符节点 500,0。
  5. 用户态 open("/dev/led") → ioctl(LED_ON/LED_OFF);内核进入 led_ioctl() → led_on()/led_off(),最终只改 OUT 的 bit 7。用户态循环的 usleep(100000) 决定闪烁频率。
c 复制代码
/* 代码实际要找的三个地址:都在 GPIO3 的 J 口,只改第 7 位。 */
#define GPIO3 0x6000D200
#define CNF   0x04
#define OE    0x14
#define OUT   0x24
/* GPIO3 + OUT = 0x6000D224;bit 7 = 0x80。 */

ioremap 后的指针是内核虚拟地址,不是应用可直接解引用的物理地址;卸载时要 iounmap。同一 J 口还有其他位,读改写是为保留其他位,但它没有解决与 Linux GPIO/pinctrl 驱动并发使用同一寄存器的资源归属问题。课程直接写寄存器是理解硬件的实验。

六、表格配置与老师代码是两条不同时间线

  • **老师当前实验:运行时设置。**板子已经启动 Linux,insmod led.ko 才执行上述 MMIO 写入;模块卸载或重启后,这些运行时写入不等于持久的板级 Pinmux 配置。
  • NVIDIA 板级流程:启动时设置。在 4.2 表第 145 行按列标题确认 Customer Usage、Pin Direction、初始状态,再由表格生成 pinmux/gpio 的设备树文件,与匹配当前 L4T/BSP、板型版本 的启动配置一起部署。你这份 4.2 表目前显示 GPIO 用途、Input;若要上电就是输出,需要把方向及安全初始状态一同设计,并核对生成的配置。NVIDIA 的说明指出 CBoot 会应用这部分 pinmux 配置,Linux 不会自动重新应用 CBoot 那一份。NVIDIA Jetson Nano 适配文档

**现在学习这份 MD 时只读资料、核对当前板子即可。**4.4 文档中的 U-Boot/CBoot、刷机命令和文件名针对其发布版本,不应直接复制到你现在的 4.9.253-tegra 系统。以后进入 Platform/设备树/GPIO 子系统,再做匹配 BSP 的持久配置和驱动资源管理。

七、板上只读核对与常见误认

在 Jetson Linux 中查看板型和实际加载的设备树信息,不写寄存器:

sh 复制代码
uname -r
uname -m
cat /proc/device-tree/model
tr '\0' '\n' < /proc/device-tree/compatible
test -r /proc/device-tree/nvidia,dtsfilename && tr -d '\0' < /proc/device-tree/nvidia,dtsfilename

在 Ubuntu 虚拟机 的 NVIDIA BSP 中用上一步的板型/文件名找相应 .dts/.dtsi,再搜索 dap4_sclk_pj7、GPIO_PJ7、gpio@6000d000。看到名字和配置后,才判断当前板实际由谁占用这根脚。没有板端结果之前,本笔记的地址链是手册与课程代码的静态核对。

常见误认 正确区分
"12、199、7 是同一个 GPIO 编号。" 12=J41 物理插针;199=模组 SODIMM 脚;7=PJ 口内位号。
"GPIO3_PJ.07 的 3 是高电平 3V。" 3 指第 3 组 GPIO 控制器;J 指端口,07 指位号。排针电平由载板规格确认。
"PM=1 就是 GPIO。" TRM 把 1 标为 RSVD1;GPIO_CNF 决定 GPIO/SFIO。
"设置 OUT=1 灯就一定亮。" 还要 Pinmux 放行、CNF=GPIO、OE=输出、设备节点/驱动正常,外接电路也要正确。
"J41-40 是地。" J41-39 是 GND;40 是 I2S0_DOUT 信号。

**接灯留意载板能力:**2.1 的 J41 表为 12 脚标出很弱的 20 µA / -20 µA 驱动,并注明这类信号经过 TXB0108 电平转换器。课程"串电阻直连 LED"的思路适合解释高低电平,但不保证裸 LED 能明显发光;做可见亮灭测试宜让 12 脚驱动高阻缓冲/晶体管,LED 电流由合适电源与限流电阻提供。J41-12 到 J41-39 的信号/地关系先确认,不要把 40 脚当地线。

最后给自己做一个闭卷追踪:任选 J41 的另一个可用 GPIO,能否从载板 Table 3-3 找到模组/SoC 名,在 4.2 表找到设备树名,在 TRM 找到 Controller/Port/位,再分别算出 Pinmux 与 GPIO 的地址?能走通这一遍,就真正掌握了老师找 PJ.07 的方法。

相关推荐
SuperByteMaster14 小时前
allegro 布线规则管理器
嵌入式硬件
女神下凡15 小时前
芯参谋(41):DDR2_电路设计指南
arm开发·单片机·嵌入式硬件·设计规范
Zhao1368245539117 小时前
国产替代DPE5500百兆以太网控制芯片兼容W5500
嵌入式硬件·物联网
yuehuaxin0117 小时前
LP20R100FN 同步整流|3C 认证适配器 CCM 工况倒灌、温升超标样机避坑解析
嵌入式硬件·智能家居·适配器模式·智能硬件
国科安芯18 小时前
商业立方星平台中高集成度抗辐射MCU的功耗优化与批量化应用可行性探讨
单片机·嵌入式硬件·架构·risc-v·抗辐射·as32x601
女神下凡18 小时前
芯参谋(40):UFS 电路设计指南
arm开发·单片机·嵌入式硬件·设计规范
iCxhust19 小时前
CAN信号电平与485信号电平实测
单片机·can·通讯·rs485
深圳市恒锐丰科技杨生20 小时前
EG1125 准谐振原边反馈 CC‑CV 功率开关|屹晶 EGmicro
嵌入式硬件·硬件工程
iCxhust20 小时前
51单片机电力载波应用开发(七)广播通讯
c语言·开发语言·单片机·嵌入式硬件·51单片机