Zephyr的GPIO头文件、驱动、应用的源码分析

本文深入解析Zephyr实时操作系统中的GPIO驱动,包括头文件`gpio.h`中定义的标志、数据类型、驱动API以及系统调用。此外,还分析了STM32 GPIO驱动的初始化和结构,展示了如何将系统调用映射到具体的驱动实现。内容涵盖了GPIO的配置、中断设置和回调处理等关键功能。

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

首先学习头文件:./zephyr/include/drivers/gpio.h。

该文件指导驱动中应该包含哪些接口,同时也提供了用户可以调用的系统调用。头文件的内容可以分为一下四个部分:

一、一些flags的定义区,这些flags在应用进程,驱动中均可以被使用。

/**
 * @name GPIO input/output configuration flags
 * @{
 */

/** Enables pin as input. */
#define GPIO_INPUT              (1U << 8)
/** Enables pin as output, no change to the output state. */
#define GPIO_OUTPUT             (1U << 9)
/** Disables pin for both input and output. */
#define GPIO_DISCONNECTED	0

/** @cond INTERNAL_HIDDEN */


/****************************/
/** so many other defines/
/****************************/


/** Default drive strength when GPIO pin output is high.
 */
#define GPIO_DS_DFLT_HIGH (0x0U << GPIO_DS_HIGH_POS)

/** Alternative drive strength when GPIO pin output is high.
 * For hardware that does not support configurable drive strengths
 * use the default drive strength.
 */
#define GPIO_DS_ALT_HIGH (0x1U << GPIO_DS_HIGH_POS)
/** @} */

/** @cond INTERNAL_HIDDEN */
#define GPIO_DIR_MASK		(GPIO_INPUT | GPIO_OUTPUT)
/** @endcond */

二、数据类型定义

/* 提供一个数据结构gpio_port_pins_t
    用于表示一个port中有哪些pin,每bit代表一个pin,通过(1 << n)来表示第n个pin
*/
typedef uint32_t gpio_port_pins_t;

/**
 * @brief Provides values for a set of pins associated with a port.
 *
 * The value for a pin with index n is high (physical mode) or active
 * (logical mode) if and only if the bit identified by (1U << n) is set.
 * Otherwise the value for the pin is low (physical mode) or inactive
 * (logical mode).
 *
 * Values of this type are often paired with a `gpio_port_pins_t` value
 * that specifies which encoded pin values are valid for the operation.
 */
/*
    提供一个数据结构,用于表示一个port的value,
    当port的n pin为高时(包含逻辑高、电平高),value的n bit置位,value |= 1<<n;
    当port的n pin为低时(包含逻辑低、电平低),value的n bit清零,value &= ~(1<<n);
*/
typedef uint32_t gpio_port_value_t;

/**
 * @brief Provides a type to hold a GPIO pin index.
 *
 * This reduced-size type is sufficient to record a pin number,
 * e.g. from a devicetree GPIOS property.
 */
/* 提供一个数据类型,记录pin的序号n*/
typedef uint8_t gpio_pin_t;

/**
 * @brief Provides a type to hold GPIO devicetree flags.
 *
 * All GPIO flags that can be expressed in devicetree fit in the low 8
 * bits of the full flags field, so use a reduced-size type to record
 * that part of a GPIOS property.
 */
typedef uint8_t gpio_dt_flags_t;

/**
 * @brief Provides a type to hold GPIO configuration flags.
 *
 * This type is sufficient to hold all flags used to control GPIO
 * configuration, whether pin or interrupt.
 */
typedef uint32_t gpio_flags_t;

/**
 * @brief Maximum number of pins that are supported by `gpio_port_pins_t`.
 */
#define GPIO_MAX_PINS_PER_PORT (sizeof(gpio_port_pins_t) * __CHAR_BIT__)

/**
 * This structure is common to all GPIO drivers and is expected to be
 * the first element in the object pointed to by the config field
 * in the device structure.
 */
struct gpio_driver_config {
	/* Mask identifying pins supported by the controller.
	 *
	 * Initialization of this mask is the responsibility of device
	 * instance generation in the driver.
	 */
	gpio_port_pins_t port_pin_mask;
};

/**
 * This structure is common to all GPIO drivers and is expected to be the first
 * element in the driver's struct driver_data declaration.
 */
struct gpio_driver_data {
	/* Mask identifying pins that are configured as active low.
	 *
	 * Management of this mask is the responsibility of the
	 * wrapper functions in this header.
	 */
	gpio_port_pins_t invert;
};

struct gpio_callback;

/**
 * @typedef gpio_callback_handler_t
 * @brief Define the application callback handler function signature
 *
 * @param port Device struct for the GPIO device.
 * @param cb Original struct gpio_callback owning this handler
 * @param pins Mask of pins that triggers the callback handler
 *
 * Note: cb pointer can be used to retrieve private data through
 * CONTAINER_OF() if original struct gpio_callback is stored in
 * another private structure.
 */
typedef void (*gpio_callback_handler_t)(const struct device *port,
					struct gpio_callback *cb,
					gpio_port_pins_t pins);

/**
 * @brief GPIO callback structure
 *
 * Used to register a callback in the driver instance callback list.
 * As many callbacks as needed can be added as long as each of them
 * are unique pointers of struct gpio_callback.
 * Beware such structure should not be allocated on stack.
 *
 * Note: To help setting it, see gpio_init_callback() below
 */
struct gpio_callback {
	/** This is meant to be used in the driver and the user should not
	 * mess with it (see drivers/gpio/gpio_utils.h)
	 */
	sys_snode_t node;

	/** Actual callback function being called when relevant. */
	gpio_callback_handler_t handler;

	/** A mask of pins the callback is interested in, if 0 the callback
	 * will never be called. Such pin_mask can be modified whenever
	 * necessary by the owner, and thus will affect the handler being
	 * called or not. The selected pins must be configured to trigger
	 * an interrupt.
	 */
	gpio_port_pins_t pin_mask;
};

三、驱动中应当实现的API

__subsystem struct gpio_driver_api {
	int (*pin_configure)(const struct device *port, gpio_pin_t pin,
			     gpio_flags_t flags);
	int (*port_get_raw)(const struct device *port,
			    gpio_port_value_t *value);
	int (*port_set_masked_raw)(const struct device *port,
				   gpio_port_pins_t mask,
				   gpio_port_value_t value);
	int (*port_set_bits_raw)(const struct device *port,
				 gpio_port_pins_t pins);
	int (*port_clear_bits_raw)(const struct device *port,
				   gpio_port_pins_t pins);
	int (*port_toggle_bits)(const struct device *port,
				gpio_port_pins_t pins);
	int (*pin_interrupt_configure)(const struct device *port,
				       gpio_pin_t pin,
				       enum gpio_int_mode, enum gpio_int_trig);
	int (*manage_callback)(const struct device *port,
			       struct gpio_callback *cb,
			       bool set);
	uint32_t (*get_pending_int)(const struct device *dev);
};

四、相关的系统调用

/* GPIO口的常规配置,调用驱动,api->pin_configure*/
__syscall int gpio_config(const struct device *port, gpio_pin_t pin, gpio_flags_t flags);

/* GPIO口的中断配置,该接口也可用于复用管脚的中断配置,
   调用驱动,api->pin_interrupt_configure    */
__syscall int gpio_pin_interrupt_configure(const struct device *port,
					   gpio_pin_t pin,
					   gpio_flags_t flags);

/* 单个GPIO口的全部配置,会依据flags参数来调用常规配置、中断配置*/
static inline int gpio_pin_configure(const struct device *port,
				     gpio_pin_t pin,
				     gpio_flags_t flags)

/* 获取端口port的物理电平状态值,该值包含端口内所有pin的电平状态,
   调用驱动,api->port_get_raw    */
__syscall int gpio_port_get_raw(const struct device *port,
				gpio_port_value_t *value);

/* 获取端口port的逻辑电平状态值,在pin脚初始化时有的会配置flag GPIO_ACTIVE_LOW,
   这时物理状态与逻辑状态间,需要进行二次转换
   该接口会再次调用 gpio_port_get_raw */
static inline int gpio_port_get(const struct device *port,
				gpio_port_value_t *value)

/* 设置端口的多个pin脚的物理电平值(0/1),调用驱动,api->port_set_masked_raw*/
__syscall int gpio_port_set_masked_raw(const struct device *port,
				       gpio_port_pins_t mask,
				       gpio_port_value_t value);

/* 设置端口的多个pin脚的物理电平值,内部调用 gpio_port_set_masked_raw */
static inline int gpio_port_set_masked(const struct device *port,
				       gpio_port_pins_t mask,
				       gpio_port_value_t value)

/* 设置端口的多个pin脚的物理电平值为1,调用驱动 api->port_set_bits_raw*/
__syscall int gpio_port_set_bits_raw(const struct device *port,
				     gpio_port_pins_t pins);
/* 设置端口的多个pin脚的逻辑电平值为ACTIVE */
static inline int gpio_port_set_bits(const struct device *port,
				     gpio_port_pins_t pins)

/* 设置端口的多个pin脚的物理电平值为0,调用驱动 api->port_clear_bits_raw*/
__syscall int gpio_port_clear_bits_raw(const struct device *port,
				       gpio_port_pins_t pins);
/* 设置端口的多个pin脚的逻辑电平值为INACTIVE */
static inline int gpio_port_clear_bits(const struct device *port,
				       gpio_port_pins_t pins)

/* 端口翻转*/
__syscall int gpio_port_toggle_bits(const struct device *port,
				    gpio_port_pins_t pins);

/*********************************/
/* 还有一些其他的bit操作函数,*/
/*********************************/
重要的结构体
struct gpio_callback {
	/** This is meant to be used in the driver and the user should not
	 * mess with it (see drivers/gpio/gpio_utils.h)
	 */
    /* 系统使用,用户勿操作*/
	sys_snode_t node;    

	/** Actual callback function being called when relevant. */
    /* 用户回调函数*/
	gpio_callback_handler_t handler;

	/** A mask of pins the callback is interested in, if 0 the callback
	 * will never be called. Such pin_mask can be modified whenever
	 * necessary by the owner, and thus will affect the handler being
	 * called or not. The selected pins must be configured to trigger
	 * an interrupt.
	 */
    /* 回调适用于哪些引脚*/
	gpio_port_pins_t pin_mask;
};

/* 初始化callback结构,该结构体中保存有用户态回调函数的指针,以及回调函数适用于哪些引脚*/
tatic inline void gpio_init_callback(struct gpio_callback *callback,
				      gpio_callback_handler_t handler,
				      gpio_port_pins_t pin_mask)
/* 注册用户态回调函数,入参callback 来源于gpio_init_callback()的初始化*/
static inline int gpio_add_callback(const struct device *port,
				    struct gpio_callback *callback)
/* 移除回调*/
static inline int gpio_remove_callback(const struct device *port,
				       struct gpio_callback *callback)

/* 获取挂起中断,调用驱动,api->get_pending_int*/
__syscall int gpio_get_pending_int(const struct device *dev);

然后以stm32的GPIO驱动来简单分析下驱动的实现,仅分析驱动的实现过程,对接口的内部细节不做分析。文件:./zephyr/drivers/gpio/gpio_stm32.c;

一、驱动的定义及初始化

/*  数据类型定义 */
struct gpio_stm32_config {
	/* gpio_driver_config needs to be first */
	struct gpio_driver_config common;
	/* port base address */
	uint32_t *base;
	/* IO port */
	int port;
	struct stm32_pclken pclken;
};

/**
 * @brief driver data
 */
struct gpio_stm32_data {
	/* gpio_driver_data needs to be first */
	struct gpio_driver_data common;
	/* device's owner of this data */
	const struct device *dev;
	/* user ISR cb */
	sys_slist_t cb;
};

/*  驱动定义及初始化相关的宏定义 */
#define GPIO_DEVICE_INIT(__node, __suffix, __base_addr, __port, __cenr, __bus) \
	static const struct gpio_stm32_config gpio_stm32_cfg_## __suffix = {   \
		.common = {						       \
			 .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_NGPIOS(16U), \
		},							       \
		.base = (uint32_t *)__base_addr,				       \
		.port = __port,						       \
		.pclken = { .bus = __bus, .enr = __cenr }		       \
	};								       \
	static struct gpio_stm32_data gpio_stm32_data_## __suffix;	       \
	DEVICE_DT_DEFINE(__node,					       \
			    gpio_stm32_init,				       \
			    device_pm_control_nop,			       \
			    &gpio_stm32_data_## __suffix,		       \
			    &gpio_stm32_cfg_## __suffix,		       \
			    POST_KERNEL,				       \
			    CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,	       \
			    &gpio_stm32_driver)

#define GPIO_DEVICE_INIT_STM32(__suffix, __SUFFIX)			\
	GPIO_DEVICE_INIT(DT_NODELABEL(gpio##__suffix),	\
			 __suffix,					\
			 DT_REG_ADDR(DT_NODELABEL(gpio##__suffix)),	\
			 STM32_PORT##__SUFFIX,				\
			 DT_CLOCKS_CELL(DT_NODELABEL(gpio##__suffix), bits),\
			 DT_CLOCKS_CELL(DT_NODELABEL(gpio##__suffix), bus))

/*  驱动定义 */
#if DT_NODE_HAS_STATUS(DT_NODELABEL(gpioa), okay)
GPIO_DEVICE_INIT_STM32(a, A);
#endif /* DT_NODE_HAS_STATUS(DT_NODELABEL(gpioa), okay) */

/* 驱动定义*/

如果设备设备树中存在标签:gpioa,则利用驱动宏定义驱动

GPIO_DEVICE_INIT_STM32(a, A);

在上述宏中,会对驱动进行定义:

DEVICE_DT_DEFINE(__node,                 //节点
                gpio_stm32_init,               //初始化函数,会根据初始化等级,在驱动初始化阶段被调用
                device_pm_control_nop,            //电源管理相关
                &gpio_stm32_data_## __suffix,          //驱动实例的数据部分,可变
                &gpio_stm32_cfg_## __suffix,             //驱动实例的配置部分,不可变
                POST_KERNEL,                       //初始化等级,
                CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,       //同等级内的优先级
                &gpio_stm32_driver)          //通用API

static int gpio_stm32_init(const struct device *device):在初始化接口中,主要完成时钟相关的配置,配置时钟后,GPIO模块变可以进行后续配置及使用。

GPIO引脚的输入输出、中断配置及中断回调的注册,则是在应用程序中通过系统调用完成。

static const struct gpio_driver_api gpio_stm32_driver = {
    .pin_configure = gpio_stm32_config,
    .port_get_raw = gpio_stm32_port_get_raw,
    .port_set_masked_raw = gpio_stm32_port_set_masked_raw,
    .port_set_bits_raw = gpio_stm32_port_set_bits_raw,
    .port_clear_bits_raw = gpio_stm32_port_clear_bits_raw,
    .port_toggle_bits = gpio_stm32_port_toggle_bits,
    .pin_interrupt_configure = gpio_stm32_pin_interrupt_configure,
    .manage_callback = gpio_stm32_manage_callback,
};

在gpio_stm32_driver 结构体的定义中则完成了系统调用与其实现的映射。在gpio.h文件中的系统调用都能够在这里找到具体实现。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值