[uboot] (番外篇)uboot dm-gpio使用方法以及工作流程

本文详细介绍了UBoot中的dm-gpio架构,包括其工作原理、使用示例、gpio uclass和gpio driver等内容。通过实例展示了如何在Tiny210平台上使用dm-gpio控制LED闪烁,阐述了在dtsi文件中的GPIO定义,以及在驱动中如何获取和操作GPIO。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[uboot] uboot流程系列
[project X] tiny210(s5pv210)上电启动流程(BL0-BL2)
[project X] tiny210(s5pv210)从存储设备加载代码到DDR
[uboot] (第一章)uboot流程——概述
[uboot] (第二章)uboot流程——uboot-spl编译流程
[uboot] (第三章)uboot流程——uboot-spl代码流程
[uboot] (第四章)uboot流程——uboot编译流程
[uboot] (第五章)uboot流程——uboot启动流程
[uboot] (番外篇)global_data介绍
[uboot] (番外篇)uboot relocation介绍
[uboot] (番外篇)uboot 驱动模型

建议先看《[uboot] (番外篇)uboot 驱动模型

=============================================================================================================

dm-gpio

一、dm-gpio架构

建议先参考《[uboot] (番外篇)uboot 驱动模型》搞懂uboot下的驱动模型。

1、dm-gpio架构图

如下:
这里写图片描述

2、说明

  • gpio core
    也在gpio uclass中实现,
    • 主要是为上层提供接口
    • 从dts中获取GPIO属性
    • 从gpio uclass的设备链表中获取到相应的udevice设备,并使用其操作集
  • gpio uclass

    • 链接属于该uclass的所有gpio udevice设备
    • 为gpio udevice的driver提供统一的操作集接口
  • bank和gpio

    • 有些平台上,将某些使用同一组寄存器的gpio构成一个bank,例如三星的s5pv210
    • 当然,并不是所有平台都有bank的概念,例如高通,高通的GPIO都有自己独立的寄存器,因此,可以将高通当成只有一个bank
  • gpio udevice

    • 一个bank对应一个gpio udevice,用bank中的偏移来表示具体的GPIO号
    • gpio udevice的driver就会根据bank以及offset对相应的寄存器上的相应的bit进行操作。

3、原理介绍

这里先简单介绍一下dm下gpio的工作原理

  • 一个bank对应一个udevice,udevice中私有数据中存放着该bank的信息,比如相应寄存器地址等等
  • 上层用gpio_desc描述符来描述一个GPIO,其中包括该GPIO所属的udevice、在bank内的偏移、以及标志位。
  • 上层通过调用gpio core的接口从dtsi获取到GPIO属性对应的gpio_desc描述符
  • 上层使用gpio_desc描述符来作为调用gpio core的操作接口的参数
  • gpio core从gpio_desc描述符提取udevice,并调用其driver中对应的操作集,以bank内的偏移作为其参数(这样driver就能判断出是哪个GPIO了)
  • driver中提取udevice的私有数据中的bank信息,并进行相应的操作

二、dm-gpio的使用示例

这里简单的以tiny210的led_1的闪烁为例子来介绍一下GPIO的使用。
虽然uboot中已经实现了led的uclass,但是我们这里先不使用这个uclass,只是简单的实现通过dm-gpio来控制一个led。

0、硬件简单说明(具体去参考原理图吧)

  • s5pv210的GPIO的地址空间
    参考《S5PV210_UM_REV1.1》2.1.2 SPECIAL FUNCTION REGISTER MAP,
    s5pv210的GPIO的地址空间为0xE020_0000开始的1000B的区域

  • 在tiny210上,有四个led,低电平为亮,高电平为灭

    • GPJ2_0 -> led_1
    • GPJ2_1 -> led_2
    • GPJ2_2 -> led_3
    • GPJ2_3 -> led_4
  • GPJ2这个bank的寄存器
    对应控制寄存器 0xE020_0280
    对应数据寄存器 0xE020_0284

1、dtsi中的定义

这里只说明GPIO引用的节点,不说明gpio控制器的节点,gpio控制器的节点在后面driver中进行说明
arch/arm/dts/s5pv210-tiny210.dts

    led_test {
        compatible = "dm-gpio,test";
        led1-gpio = <&gpj2 0 0>;      // 属性"led1-gpio",表示gpj2 bank的第0个gpio,0是值标志
        led2-gpio = <&gpj2 1 0>;    // gpj2 bank的第1个gpio,0是值标志
        led3-gpio = <&gpj2 2 0>;    // gpj2 bank的第2个gpio,0是值标志
        led4-gpio = <&gpj2 3 0>;    // gpj2 bank的第3个gpio,0是值标志
    };  

注意,这里<&gpj2 0 0>取决于driver是如何对这个属性进行转化的。并不是所有平台都是一样的。

2、驱动中从节点中获取一个GPIO

我们在board_late_init中来实现GPIO闪烁的功能
board/samsung/tiny210/board.c

int board_late_init(void)
{
    struct gpio_desc led1_gpio;
    int node;
    node = fdt_node_offset_by_compatible(gd->fdt_blob, 0, "dm-gpio,test");   
   // 注意,我们并没有使用dm模型的driver来匹配compatible = "dm-gpio,test"的节点,所
<think>好的,我现在需要解决用户在Visual C++中使用sprintf时遇到的C4996错误。首先,我得回忆一下这个错误的常见原因和解决方法。根据之前的经验,C4996通常是因为微软认为某些函数不安全,推荐使用更安全的版本,比如sprintf_s。不过用户可能不想修改代码,所以需要其他解决方案。 首先,我应该确认用户的具体情况。用户提到的是C4996错误,这通常与安全性警告相关。微软在较新的VC版本中将一些传统函数如sprintf标记为不安全,因为它们容易导致缓冲区溢出。因此,编译器会抛出这个错误,提示开发者使用更安全的替代函数。 接下来,我需要考虑可能的解决方案。根据引用[1]中的信息,VC++ 2015对printf和scanf系列函数进行了inline处理,导致链接错误,但这里的问题是不同的,属于编译时警告而非链接错误。不过,解决方案可能有相似之处,比如添加预处理指令来禁用特定警告,或者改用安全函数。 可能的解决方法包括: 1. 使用_sprintf_s代替sprintf,这是微软推荐的安全替代函数。 2. 在代码中添加宏定义来禁止编译器产生这个警告,比如使用#define _CRT_SECURE_NO_WARNINGS。 3. 在项目属性中禁用特定警告C4996。 4. 使用#pragma指令局部禁用警告。 用户可能希望保持原有代码不变,所以方法2、3、4可能更适用。需要注意的是,禁用警告可能会导致潜在的安全风险,因此需要评估代码的安全性。 另外,引用[1]中提到可以通过包含头文件或链接特定库来解决链接错误,但C4996是编译警告,可能需要不同的处理方式。因此,正确的解决步骤应该是优先使用安全函数,或者在确保安全的情况下禁用警告。 现在需要将这些思路整理成清晰的步骤,并引用相关的参考资料。例如,引用[1]提到的处理方式虽然针对链接错误,但说明微软在VC++中对传统函数进行了调整,这可能与编译器设置有关,因此可以类比处理。 最后,生成相关问题,帮助用户进一步理解相关的问题,比如其他编译错误或安全函数的替代方案。</think>在Visual C++中使用`sprintf`时出现C4996错误,是由于该函数被微软标记为“不安全”,可能导致缓冲区溢出。以下是逐步解决方案: ### 方法1:使用安全版本函数 将`sprintf`替换为微软提供的安全函数`sprintf_s`,并调整参数: ```cpp char buffer[100]; int num = 123; sprintf_s(buffer, sizeof(buffer), "%d", num); // 添加缓冲区大小参数[^1] ``` ### 方法2:添加宏定义禁止警告 在代码文件顶部添加宏定义(需在所有头文件包含之前): ```cpp #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> // 后续代码... ``` ### 方法3:项目属性设置 1. 右键项目 → **属性** → **C/C++** → **预处理器** 2. 在**预处理器定义**中添加:`_CRT_SECURE_NO_WARNINGS` ### 方法4:局部禁用警告 在调用`sprintf`的代码段前后添加: ```cpp #pragma warning(disable:4996) sprintf(buffer, "%d", num); #pragma warning(default:4996) ``` ### 方法5:改用标准库函数 对于C++代码,建议使用`std::ostringstream`避免安全问题: ```cpp #include <sstream> std::ostringstream oss; oss << num; std::string str = oss.str(); ``` --- **选择建议**: - 若需兼容性和安全性 → 优先用方法1或方法5 - 若需快速修复旧代码 → 用方法2或方法3 - 临时调试 → 用方法4 ---
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值