0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

【瑞萨RA × Zephyr评测】ADC、DAC和PWM

枫雪天 来源:枫雪天 2026-01-10 10:22 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

本文章旨在评估使用 Zephyr RTOS 在 Renesas FPB-RA6E2 开发板上实现 ADC模数转换器)、DAC数模转换器)和 PWM(脉宽调制)功能的应用。评估内容包括设备树配置、驱动初始化流程、主程序逻辑的详细解析,以及实验现象与数据分析。


1. 硬件连接与引脚定义

本实验涉及 ADC、DAC 和 PWM 的硬件资源,以下是关键引脚及其功能:

功能物理引脚 (Pin)信号定义接线说明
ADC 输入P013Analog In (AN011)连接至 DAC 输出或外部信号源
DAC 输出P014Analog Out (DA0)输出模拟电压
PWM 输出P408PWM Signal使用 GPT1 定时器通道 1

2. 软件环境配置

2.1 Device Tree Overlay (app.overlay)

设备树用于定义外设的物理引脚绑定和初始状态。以下是关键配置:

ADC 配置

&adc0 {
    status = "okay";
    pinctrl-0 = < &adc0_default >;
    pinctrl-names = "default";

    channel@0 {
        reg = < 0 >;
        zephyr,gain = "ADC_GAIN_1";
        zephyr,reference = "ADC_REF_INTERNAL";
        zephyr,acquisition-time = < ADC_ACQ_TIME_DEFAULT >;
        zephyr,resolution = < 12 >;
    };
};
};
};

};

#### DAC 配置

&dac0 {
    status = "okay";
    pinctrl-0 = < &dac0_default >;
    pinctrl-names = "default";
};

&pinctrl {
    dac0_default: dac0_default {
        group1 {
            psels = < RA_PSEL(RA_PSEL_DAC, 0, 14) >;
            renesas,analog-enable;
        };
    };
};
};
};

};

#### PWM 配置

&pwm1 {
    status = "okay";
};

pwmleds {
    compatible = "pwm-leds";
    pwm_led_p408: pwm_led_p408 {
        pwms = < &pwm1 1 PWM_MSEC(1) PWM_POLARITY_NORMAL >;
    };
};
};
};

};

### 2.2 Kconfig 配置 (prj.conf)

确保启用了 ADC、DAC 和 PWM 驱动支持:

CONFIG_ADC=y
CONFIG_DAC=y
CONFIG_PWM=y
CONFIG_LOG=y

3. 代码逻辑分析

3.1 核心流程

ADC 流程

/*
 * Copyright (c) 2020 Libre Solar Technologies GmbH
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include < inttypes.h >
#include < stddef.h >
#include < stdint.h >

#include < zephyr/device.h >
#include < zephyr/devicetree.h >
#include < zephyr/drivers/adc.h >
#include < zephyr/kernel.h >
#include < zephyr/sys/printk.h >
#include < zephyr/sys/util.h >

#if !DT_NODE_EXISTS(DT_PATH(zephyr_user)) || 
	!DT_NODE_HAS_PROP(DT_PATH(zephyr_user), io_channels)
#error "No suitable devicetree overlay specified"
#endif

#define DT_SPEC_AND_COMMA(node_id, prop, idx) 
	ADC_DT_SPEC_GET_BY_IDX(node_id, idx),

/* Data of ADC io-channels specified in devicetree. */
static const struct adc_dt_spec adc_channels[] = {
	DT_FOREACH_PROP_ELEM(DT_PATH(zephyr_user), io_channels,
			     DT_SPEC_AND_COMMA)
};

int main(void)
{
	int err;
	uint32_t count = 0;
	uint16_t buf;
	struct adc_sequence sequence = {
		.buffer = &buf,
		/* buffer size in bytes, not number of samples */
		.buffer_size = sizeof(buf),
	};

	/* Configure channels individually prior to sampling. */
	for (size_t i = 0U; i < ARRAY_SIZE(adc_channels); i++) {
		if (!adc_is_ready_dt(&adc_channels[i])) {
			printk("ADC controller device %s not readyn", adc_channels[i].dev- >name);
			return 0;
		}

		err = adc_channel_setup_dt(&adc_channels[i]);
		if (err < 0) {
			printk("Could not setup channel #%d (%d)n", i, err);
			return 0;
		}
	}

	while (1) {
		printk("ADC reading[%u]:n", count++);
		for (size_t i = 0U; i < ARRAY_SIZE(adc_channels); i++) {
			int32_t val_mv;

			printk("- %s, channel %d: ",
			       adc_channels[i].dev- >name,
			       adc_channels[i].channel_id);

			(void)adc_sequence_init_dt(&adc_channels[i], &sequence);

			err = adc_read_dt(&adc_channels[i], &sequence);
			if (err < 0) {
				printk("Could not read (%d)n", err);
				continue;
			}

			/*
			 * If using differential mode, the 16 bit value
			 * in the ADC sample buffer should be a signed 2's
			 * complement value.
			 */
			if (adc_channels[i].channel_cfg.differential) {
				val_mv = (int32_t)((int16_t)buf);
			} else {
				val_mv = (int32_t)buf;
			}
			printk("%"PRId32, val_mv);
			err = adc_raw_to_millivolts_dt(&adc_channels[i],
						       &val_mv);
			/* conversion to mV may not be supported, skip if not */
			if (err < 0) {
				printk(" (value in mV not available)n");
			} else {
				printk(" = %"PRId32" mVn", val_mv);
			}
		}

		k_msleep(1000);
	}
	return 0;
}
  1. 初始化 ADC 驱动并配置通道。
  2. 调用 adc_read 函数读取模拟输入值。
  3. 将读取的数字值转换为实际电压(基于参考电压和分辨率)。

DAC 流程

/*
 * Copyright (c) 2020 Libre Solar Technologies GmbH
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include < zephyr/kernel.h >
#include < zephyr/sys/printk.h >
#include < zephyr/drivers/dac.h >

#define ZEPHYR_USER_NODE DT_PATH(zephyr_user)

#if (DT_NODE_HAS_PROP(ZEPHYR_USER_NODE, dac) && 
	DT_NODE_HAS_PROP(ZEPHYR_USER_NODE, dac_channel_id) && 
	DT_NODE_HAS_PROP(ZEPHYR_USER_NODE, dac_resolution))
#define DAC_NODE DT_PHANDLE(ZEPHYR_USER_NODE, dac)
#define DAC_CHANNEL_ID DT_PROP(ZEPHYR_USER_NODE, dac_channel_id)
#define DAC_RESOLUTION DT_PROP(ZEPHYR_USER_NODE, dac_resolution)
#else
#error "Unsupported board: see README and check /zephyr,user node"
#define DAC_NODE DT_INVALID_NODE
#define DAC_CHANNEL_ID 0
#define DAC_RESOLUTION 0
#endif

static const struct device *const dac_dev = DEVICE_DT_GET(DAC_NODE);

static const struct dac_channel_cfg dac_ch_cfg = {
	.channel_id  = DAC_CHANNEL_ID,
	.resolution  = DAC_RESOLUTION,
#if defined(CONFIG_DAC_BUFFER_NOT_SUPPORT)
	.buffered = false,
#else
	.buffered = true,
#endif /* CONFIG_DAC_BUFFER_NOT_SUPPORT */
};

int main(void)
{
	if (!device_is_ready(dac_dev)) {
		printk("DAC device %s is not readyn", dac_dev- >name);
		return 0;
	}

	int ret = dac_channel_setup(dac_dev, &dac_ch_cfg);

	if (ret != 0) {
		printk("Setting up of DAC channel failed with code %dn", ret);
		return 0;
	}

	printk("Generating sawtooth signal at DAC channel %d.n",
		DAC_CHANNEL_ID);
	while (1) {
		/* Number of valid DAC values, e.g. 4096 for 12-bit DAC */
		const int dac_values = 1U < < DAC_RESOLUTION;

		/*
		 * 1 msec sleep leads to about 4 sec signal period for 12-bit
		 * DACs. For DACs with lower resolution, sleep time needs to
		 * be increased.
		 * Make sure to sleep at least 1 msec even for future 16-bit
		 * DACs (lowering signal frequency).
		 */
		const int sleep_time = 4096 / dac_values > 0 ?
			4096 / dac_values : 1;

		for (int i = 0; i < dac_values; i++) {
			ret = dac_write_value(dac_dev, DAC_CHANNEL_ID, i);
			if (ret != 0) {
				printk("dac_write_value() failed with code %dn", ret);
				return 0;
			}
			k_sleep(K_MSEC(sleep_time));
		}
	}
	return 0;
}
  1. 初始化 DAC 驱动并设置通道分辨率。
  2. 调用 dac_write_value 函数输出模拟电压。
  3. 通过循环生成锯齿波或三角波。

PWM 流程

/*
 * Copyright (c) 2016 Intel Corporation
 * Copyright (c) 2020 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include < zephyr/kernel.h >
#include < zephyr/sys/printk.h >
#include < zephyr/device.h >
#include < zephyr/drivers/pwm.h >
 
/* 
 * 获取设备树中的 pwm-led0 别名
 * 注意:根据之前的 Overlay 配置,这对应 P408 引脚
 */
static const struct pwm_dt_spec pwm_dev = PWM_DT_SPEC_GET(DT_ALIAS(pwm_led0));
 
 
#define PERIOD PWM_MSEC(1)
 
/* 每次循环增加的占空比百分数 */
#define STEP   5
 
/* 每次速度变化的间隔时间 (毫秒) */
#define SLEEP_MS   500
 
int main(void)
{
	int ret;
	uint8_t duty_cycle = 0;   // 当前占空比 (0-100)
	uint32_t pulse_width = 0; // 实际脉宽时间
 
	if (!pwm_is_ready_dt(&pwm_dev)) {
		printk("Error: PWM device %s is not readyn",
		       pwm_dev.dev- >name);
		return 0;
	}
 
	printk("Starting pwm control on channel %d...n", pwm_dev.channel);
 
	ret = pwm_set_dt(&pwm_dev, PERIOD, 0);
	if (ret) {
		printk("Error: PWM device does not support period %lun", PERIOD);
		return 0;
	}
 
	while (1) {
		/* 计算脉宽: (周期 * 百分比) / 100 */
		pulse_width = (uint32_t)((uint64_t)PERIOD * duty_cycle / 100U);
 
		/* 设置 PWM: 周期固定,改变脉宽 */
		ret = pwm_set_dt(&pwm_dev, PERIOD, pulse_width);
		if (ret) {
			printk("Error %d: failed to set pulse widthn", ret);
			return 0;
		}
 
		/* 增加速度 */
		duty_cycle += STEP;
 
		/* 如果超过 100%,重置为 0 */
		if (duty_cycle > 100) {
			duty_cycle = 0; 
            printk(" > > Resetting cycle <
  1. 初始化 PWM 驱动并设置周期。
  2. 调用 pwm_set_dt 函数调整占空比。
  3. 通过循环实现占空比的动态变化。

3.2 关键 API 使用

以下是代码中使用的关键 API:

ADC

int adc_read(const struct device *dev, const struct adc_sequence *sequence);
  • dev: ADC 设备句柄。
  • sequence: 包含通道、缓冲区和采样时间的配置结构体。

DAC

int dac_write_value(const struct device *dev, uint8_t channel, uint32_t value);
  • dev: DAC 设备句柄。
  • channel: DAC 通道 ID。
  • value: 输出的数字值。

PWM

int pwm_set_dt(const struct pwm_dt_spec *spec, uint32_t period, uint32_t pulse);
  • spec: PWM 设备树绑定结构体。
  • period: PWM 周期(纳秒)。
  • pulse: PWM 脉宽(纳秒)。

4. 实验现象与数据分析

4.1 ADC 数据采集

终端应显示如下数据流:

ADC reading[0]:
* adc@40170000, channel 0: 0 = 0 mV

4.2 DAC 输出波形

  • 初始状态 : DAC 输出 0V。
  • 运行时 : 生成锯齿波或三角波,频率由延时控制。
  • 视觉效果 : 使用示波器观测 P014 引脚,应看到稳定的波形。
    DAC锯齿波.png

4.3 PWM 占空比变化

  • 初始状态 : PWM 输出低电平。
  • 运行时 : 占空比从 0% 到 100% 循环变化。
  • 视觉效果 : 使用 LED 或示波器观测 P408 引脚,亮度或波形应随占空比变化。

5. 测评总结

本程序成功演示了 Renesas RA6E2 在 Zephyr RTOS 下的 ADC、DAC 和 PWM 外设控制。通过闭环测试验证了数模转换的准确性,并展示了嵌入式系统中“数字-模拟-数字”的完整转换过程。代码结构清晰,适配了最新的驱动 API,适用于初学者学习和开发者快速验证硬件功能。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 单片机
    +关注

    关注

    6078

    文章

    45590

    浏览量

    673956
  • adc
    adc
    +关注

    关注

    100

    文章

    7950

    浏览量

    557002
  • 开发板
    +关注

    关注

    26

    文章

    6433

    浏览量

    121194
  • Zephyr
    +关注

    关注

    1

    文章

    62

    浏览量

    6637
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    如何搭建RA VS code开发环境

    在上一篇文章“当RA MCU遇见Zephyr,打通嵌入式开发任督二脉!”中,我们介绍了Zephyr极具前景的发展趋势以及开发板对
    的头像 发表于 11-05 14:41 4701次阅读
    如何搭建<b class='flag-5'>瑞</b><b class='flag-5'>萨</b><b class='flag-5'>RA</b> VS code开发环境

    RA6M3 HMI Board评测挑战】-RA6M3上的CAN实践

    RA6M3 HMI Board 评测大挑战】-RA6M3上的CAN实践
    的头像 发表于 10-17 14:55 3848次阅读
    【<b class='flag-5'>RA</b>6M3 HMI Board<b class='flag-5'>评测</b>挑战】-<b class='flag-5'>瑞</b><b class='flag-5'>萨</b><b class='flag-5'>RA</b>6M3上的CAN实践

    RA MCU遇见Zephyr系列(3)——在Vs code中配置Zephyr集成开发环境

    RA生态工作室关注我们上一篇文章介绍了如何在VScode中使用官方插件为RA芯片创建项目与项目调试,相信大家对RA在VScode中的开发
    的头像 发表于 01-01 10:04 5151次阅读
    当<b class='flag-5'>RA</b> MCU遇见<b class='flag-5'>Zephyr</b>系列(3)——在Vs  code中配置<b class='flag-5'>Zephyr</b>集成开发环境

    RA MCU众测宝典 | 串口之【RA-Eco-RA2L1】RTC日历及串口设置时间

    “RAMCU众测宝典”串口专题添硬核实操!开启宝典前言RAMCU众测宝典|串口之【RA2L1】开发板开箱及串口输出实现RAMCU众测宝典|PWM之【
    的头像 发表于 04-21 18:07 6523次阅读
    <b class='flag-5'>瑞</b><b class='flag-5'>萨</b><b class='flag-5'>RA</b> MCU众测宝典 | 串口之【<b class='flag-5'>RA-Eco-RA</b>2L1】RTC日历及串口设置时间

    RA4E2开发板评测ADC+DAC

    收到了发过来的RA4E2开发板,之前也测试过相关的ARM单片机,
    发表于 09-02 13:35

    RA6E2】ADCDAC 电压输入输出

    ); 代码中 dac 的值为 0 ~ 4095,对应 0 ~ 3.3v 电压 【ADC 电压输入】 RA6E2 支持 12 位
    发表于 11-10 01:29

    RA6E2地奇星开发板试用】DAC 输出指定电压、ADC 电压检测

    ); 代码中 dac 的值为 0 ~ 4095,对应 0 ~ 3.3v 电压 【ADC 电压输入】 RA6E2 支持 12 位
    发表于 12-19 18:30

    FPB-RA6E2试用】【原创】【RA × Zephyr开发板评测】+入门级任务测试1

    很荣幸获得了RA × ZephyrFPB-RA
    发表于 12-24 23:52

    FPB-RA6E2试用】【RA × Zephyr开发板评测】Linux环境配置和初步试用

    1. 前言 很荣幸获得了RA × ZephyrFPB-
    发表于 12-29 12:55

    FPB-RA6E2试用】基础功能使用2

    的基础功能模块。 PWM 呼吸灯 前言 硬件:Renesas FPB-RA6E2 开发板 系统 zephyr 4.2.0 目的:测评zephyr
    发表于 12-30 17:08

    FPB-RA6E2试用】【RA × Zephyr开发板评测ADCDAC、SPI、I2C 测试

    1. 前言 在上一篇评测中,我们完成了开发环境搭建和基础 GPIO 控制。作为一款高性能 MCU,RA6E2 的通信接口(SPI/I2C)和模拟外设(ADC/DAC)才是其核心竞争力的
    发表于 01-12 00:01

    RA × Zephyr开发板评测】基于PWM的电机转速控制

    项目使用的FPB-RAE62作为控制板,主要功能如下: ADC采集控制器数据来控制PWM波形的占空比 电机驱动板来控制的电机的转速 PWM
    发表于 01-16 01:19

    FPB-RA6E2试用】【FPB-RA6E2】 DAC-ADC 回环测试:基于 Zephyr RTOS 的模拟信号通路验证

    Zephyr ADC / DAC API 调试设备树 / pinctrl 校准 ADC / DAC 偏差 硬件 Bring-up 阶段测试
    发表于 01-16 15:22

    FPB-RA6E2试用】【RA × Zephyr开发板评测】基于PWM的电机转速控制

    项目使用的FPB-RAE62作为控制板,主要功能如下: ADC采集控制器数据来控制PWM波形的占空比 电机驱动板来控制的电机的转速 PWM
    发表于 01-17 16:18

    RA × Zephyr评测】SSD1306显示MPU6050加速度计读数

    本文介绍了在RA6E2单片机上基于Zephyr RTOS操作SPI与I2C总线的实验
    的头像 发表于 01-10 10:24 937次阅读
    【<b class='flag-5'>瑞</b><b class='flag-5'>萨</b><b class='flag-5'>RA</b> × <b class='flag-5'>Zephyr</b><b class='flag-5'>评测</b>】SSD1306显示MPU6050加速度计读数