Zephyr下控制ESP32S3的GPIO口

1.关于esp32s3脚的定义

下面以GPIO38为例介绍esp32s3下GPIO口的控制,参考ESP32S3-wroom-1规格书,关于GPIO38接口的定义如下:


由上表可知GPIO38与SPI复用引脚

2.查看esp32s3_devkitm对应的设备树定义

这里我选用的是esp32s3_devkitm/esp32s3/procpu,因此我查找关于这个board的dts定义,如下所示

进入文件,查看关于GPIO38和SPI的定义,没有关于GPIO38的定义,SPI的定义如下,对应的SPI功能默认全部打开,需要将其禁用,让gpio功能开启:

继续查找关于GPIO的定义

关于"esp32s3_mini_n8.dtsi"里面定义了Flash和RAM的大小

关于"esp32s3_devkitm-pinctrl.dtsi",里面定义各个功能对应的PIN脚;

GPIO38用于SPI3的CS脚。

3.控制GPIO38对应的设备树

需要进一步获取系统关于GPIO的定义,由上可知,esp32s3_devkitm更底层,引用了esp32s3_common.dtsi,进一步查看:

gpio0寄存器控制GPIO0-31这32个GPIO;

gpio1寄存器控制GPIO32-53这22个GPIO;

因此,选用gpio1寄存器,具体设备树定义,如下所示:

复制代码
#include <zephyr/dt-bindings/gpio/gpio.h>

/ {
    aliases {
        led0 = &user_led; // 别名正确指向LED节点
    };
    leds {
        compatible = "gpio-leds";
        user_led: led_0 {
            gpios = <&gpio1 38 GPIO_ACTIVE_LOW>;
            status = "okay";
        };
    };
};

&spi3 {
	status = "disabled"; //禁用spi3,释放对应io脚
};

&gpio1 {
    status = "okay"; // gpio1控制器必须启用
};

4.控制GPIO38

下面控制GPIO38,使其对应的LED灯亮1s,灭1s,如下所示

复制代码
#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>

#define LED0_NODE DT_ALIAS(led0)
static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios);

int main(void)
{
    int ret;
    bool current_state;

    if (!gpio_is_ready_dt(&led)) {
        printk("LED GPIO not ready\n");
        return 0;
    }
    
    // 配置为输出,初始高电平(灭,因GPIO_ACTIVE_LOW)
    ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT | GPIO_PUSH_PULL);
    if (ret != 0) {
        printk("Configure failed: %d\n", ret);
        return 0;
    }
    
    while (1) {
        ret = gpio_pin_set_dt(&led, 1); // 1对应高电平(因ACTIVE_LOW,此时LED应灭)
        if (ret != 0) {
            printk("Set high failed: %d\n", ret);
        }
        int level = gpio_pin_get_dt(&led);
        printk("After set high, level = %d\n", level); // 预期应为1
        k_msleep(1000);

        printk("Testing set low...\n");
        ret = gpio_pin_set_dt(&led, 0); // 0对应低电平(LED应亮)
        if (ret != 0) {
            printk("Set low failed: %d\n", ret);
        }
        level = gpio_pin_get_dt(&led);
        printk("After set low, level = %d\n", level); // 预期应为0
        k_msleep(1000);
    }
    return 0;
}

ESP32-S3 的部分 GPIO(尤其是 34~39 号引脚)默认配置为输入专用模式(无内部上拉 / 下拉电阻)。如果你的 LED 连接在这类引脚上,即使配置为输出,读取电平(输入操作)时可能无法正确获取输出状态,导致gpio_pin_get_dt始终返回 0。

5.控制 GP IO0做按键



代码如下:

复制代码
#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>

#define KEY_NODE DT_ALIAS(sw0)
static const struct gpio_dt_spec key = GPIO_DT_SPEC_GET (KEY_NODE, gpios);

static int64_t last_mode_change;
volatile uint8_t pwm_mode = 1;

static void change_mode(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
{
        (void) dev;
        (void) cb;
        (void) pins;

        int64_t now = k_uptime_get();

        if (now - last_mode_change > 300) {
		pwm_mode = (pwm_mode)?0:1;
                last_mode_change = now;
        }
}

int main(void)
{
	struct gpio_callback button_cb_data;
	int ret;

	if(!gpio_is_ready_dt(&key)) {
		printf("Error: GPIO device not ready!\n");
		return -1;
	}
	ret = gpio_pin_configure_dt(&key, GPIO_INPUT);
	if(ret != 0) {
		printf("Failed to configure.key (ret = %d)\n", ret);
		return -1;
	}
	gpio_pin_interrupt_configure_dt(&key, GPIO_INT_EDGE_RISING);
	gpio_init_callback(&button_cb_data, change_mode, BIT(key.pin));
	gpio_add_callback(key.port, &button_cb_data);

	while(1) {
		printk("pwm_mode = %d\n", pwm_mode);
	}
	return 0;
}

运行后,执行结果如下:

相关推荐
零K沁雪4 分钟前
Linux 内核中网络地址快速打印符
linux·内核
十年编程老舅32 分钟前
窥探内核心脏:深入解析 proc 虚拟文件系统
linux·服务器·数据库·c++·linux内核·文件系统·读写锁
hoiii18740 分钟前
STM32 RS232串口通讯实验
stm32·单片机·嵌入式硬件
可乐鸡翅好好吃44 分钟前
Keil更改RAM地址
网络·单片机·嵌入式硬件
江公望1 小时前
Linux kernel completion(完成量)10分钟讲清楚
linux
惶了个恐1 小时前
嵌入式硬件第七弹——ARM(4)
arm开发·stm32·单片机·嵌入式硬件·arm·硬件工程
Sakuyu434681 小时前
sed和awk
linux
码农多耕地呗1 小时前
VMware创建虚拟机
linux·运维·服务器
wggmrlee1 小时前
性能压测-单机
linux
youyudexiaowangzi2 小时前
ubuntu 1604安装组件报错
linux·运维·ubuntu