这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 【Zephyr|瑞萨RA6E2】7基于MCP41100的数字电位器

共1条 1/1 1 跳转至

【Zephyr|瑞萨RA6E2】7基于MCP41100的数字电位器

高工
2026-04-18 20:16:24     打赏

【前言】

准备做个可调电源,采用DCDC芯片,在原来的开发板上是用跳线来连接不同的电阻,决定电源的输出电压,因此我准备使用数字电位器来动态给出电阻,实现电压的输出。

【MCP41xxx简介】

MCP41xxx系列是由Microchip Technology(微芯科技)生产的一系列单通道数字电位器芯片。这些器件可以替代传统的机械式电位器,通过数字接口控制电阻值的变化,具有高精度、稳定性和可重复性等优点。

主要特性

基本电气特性

电阻值选择:提供10kΩ、50kΩ和100kΩ三种阻值选项

抽头数:256个等间距的抽头,提供精细的电阻调节能力

电源电压:单电源工作,电压范围2.7V - 5.5V

功耗:静态工作电流小于1μA,具有极低功耗特性

温度范围:工业级(-40°C至+85°C)和扩展级(-40°C至+125°C)

接口与控制

通信接口:标准SPI接口控制(支持模式0,0和1,1)

线性调节:电位器滑动端位置呈线性变化

精度指标:最大INL(积分非线性)和DNL(微分非线性)误差为±1LSB

功能特色

低功耗CMOS技术:采用先进的CMOS制造工艺

关断功能:软件关断功能可断开所有电阻电路,最大限度节省功耗

硬件复位:RS(复位)引脚实现硬件复位功能

非易失性存储:部分型号具有EEPROM特性,断电后保持设置值

上电复位:通电后滑动端自动重置到中间位置(第128抽头)

【工程创建】

我在zephyr的app目录下面创建app\mcp41100_ra6e2工程。

使用claude生成对应的文件目录。

image.png

【硬件连接】

由于Zephyr中FPB_RA6E2的spi0默认分配好,其连接接口如下:

image.png

由于我买到的模块只需要MOSI、SCK、CS,因此只需要连接三线即可。

【代码实现】

1、prj.conf

# MCP41100 Digital Potentiometer for FPB-RA6E2

# SPI (for MCP41100)
CONFIG_SPI=y

# Logging
CONFIG_LOG=y
CONFIG_LOG_DEFAULT_LEVEL=3

2、MCP41100.c

/*
 * Copyright (c) 2025
 * SPDX-License-Identifier: Apache-2.0
 */

#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/spi.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/logging/log.h>
#include "mcp41100.h"

LOG_MODULE_DECLARE(mcp41100, LOG_LEVEL_INF);

#define DT_DRV_COMPAT microchip_mcp41100

static int mcp41100_spi_transfer(const struct device *dev, uint8_t cmd, uint8_t data)
{
    const struct mcp41100_config *config = dev->config;
    uint8_t tx_buf[2] = { cmd, data };

    const struct spi_buf buf = {
        .buf = tx_buf,
        .len = sizeof(tx_buf)
    };
    const struct spi_buf_set tx = {
        .buffers = &buf,
        .count = 1
    };

    /* Assert CS */
    gpio_pin_set_dt(&config->cs_gpio, 0);

    int ret = spi_write(config->spi_dev, &config->spi_cfg, &tx);

    /* Release CS */
    gpio_pin_set_dt(&config->cs_gpio, 1);

    return ret;
}

int mcp41100_init(const struct device *dev)
{
    const struct mcp41100_config *config = dev->config;
    struct mcp41100_data *data = dev->data;

    if (!device_is_ready(config->spi_dev)) {
        LOG_ERR("SPI device not ready");
        return -ENODEV;
    }

    if (!device_is_ready(config->cs_gpio.port)) {
        LOG_ERR("CS GPIO device not ready");
        return -ENODEV;
    }

    /* Configure CS pin as output */
    int ret = gpio_pin_configure_dt(&config->cs_gpio, GPIO_OUTPUT);
    if (ret < 0) {
        LOG_ERR("CS pin configure failed: %d", ret);
        return ret;
    }

    /* CS inactive (high) */
    gpio_pin_set_dt(&config->cs_gpio, 1);

    data->wiper_pos = 0;

    LOG_INF("MCP41100 initialized");

    return 0;
}

int mcp41100_set_wiper(const struct device *dev, uint8_t pos)
{
    struct mcp41100_data *data = dev->data;

    if (pos > MCP41100_WIPER_MAX) {
        pos = MCP41100_WIPER_MAX;
    }

    int ret = mcp41100_spi_transfer(dev, MCP41100_CMD_WRITE, pos);
    if (ret < 0) {
        LOG_ERR("Failed to set wiper: %d", ret);
        return ret;
    }

    data->wiper_pos = pos;

    return 0;
}

uint8_t mcp41100_get_wiper(const struct device *dev)
{
    struct mcp41100_data *data = dev->data;
    return data->wiper_pos;
}

int mcp41100_set_resistance(const struct device *dev, uint32_t total_ohm, uint32_t target_ohm)
{
    uint8_t pos = mcp41100_calc_position(total_ohm, target_ohm);
    return mcp41100_set_wiper(dev, pos);
}

int mcp41100_sleep(const struct device *dev)
{
    return mcp41100_spi_transfer(dev, MCP41100_CMD_SLEEP, 0);
}

int mcp41100_wake(const struct device *dev)
{
    return mcp41100_spi_transfer(dev, MCP41100_CMD_WAKE, 0);
}

3、MCP4110.h

/*
 * Copyright (c) 2025
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @file
 * @brief MCP41100 Digital Potentiometer Driver
 *
 * MCP41100 is a 100K ohm digital potentiometer with 256 wiper positions.
 * Communicates via SPI (3-wire).
 */

#ifndef MCP41100_H__
#define MCP41100_H__

#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/spi.h>

/** MCP41100 SPI commands */
#define MCP41100_CMD_WRITE    0x11  /* Write to wiper (potentiometer mode) */
#define MCP41100_CMD_SLEEP   0x21  /* Shutdown pot */
#define MCP41100_CMD_WAKE    0x20  /* Wake from shutdown */

/** MCP41100 wiper positions */
#define MCP41100_WIPER_MIN   0
#define MCP41100_WIPER_MAX   255

/**
 * @brief MCP41100 device configuration
 */
struct mcp41100_config {
    /** SPI device */
    const struct device *spi_dev;
    /** SPI bus configuration */
    struct spi_config spi_cfg;
    /** CS GPIO specification */
    struct gpio_dt_spec cs_gpio;
};

/**
 * @brief MCP41100 device data
 */
struct mcp41100_data {
    /** Current wiper position */
    uint8_t wiper_pos;
};

/**
 * @brief Initialize MCP41100 device
 *
 * @param dev MCP41100 device pointer
 * @return 0 on success, negative errno on failure
 */
int mcp41100_init(const struct device *dev);

/**
 * @brief Set wiper position
 *
 * @param dev MCP41100 device pointer
 * @param pos Wiper position (0-255)
 * @return 0 on success, negative errno on failure
 */
int mcp41100_set_wiper(const struct device *dev, uint8_t pos);

/**
 * @brief Get current wiper position
 *
 * @param dev MCP41100 device pointer
 * @return Current wiper position (0-255)
 */
uint8_t mcp41100_get_wiper(const struct device *dev);

/**
 * @brief Calculate wiper position for target resistance
 *
 * @param total_ohm Total potentiometer resistance in ohms
 * @param target_ohm Target resistance in ohms
 * @return Wiper position (0-255)
 */
static inline uint8_t mcp41100_calc_position(uint32_t total_ohm, uint32_t target_ohm)
{
    if (target_ohm >= total_ohm) {
        return MCP41100_WIPER_MAX;
    }
    return (uint8_t)((target_ohm * MCP41100_WIPER_MAX) / total_ohm);
}

/**
 * @brief Set resistance (convenience function)
 *
 * @param dev MCP41100 device pointer
 * @param total_ohm Total potentiometer resistance in ohms
 * @param target_ohm Target resistance in ohms
 * @return 0 on success, negative errno on failure
 */
int mcp41100_set_resistance(const struct device *dev, uint32_t total_ohm, uint32_t target_ohm);

/**
 * @brief Put MCP41100 to sleep (shutdown mode)
 *
 * @param dev MCP41100 device pointer
 * @return 0 on success, negative errno on failure
 */
int mcp41100_sleep(const struct device *dev);

/**
 * @brief Wake MCP41100 from sleep
 *
 * @param dev MCP41100 device pointer
 * @return 0 on success, negative errno on failure
 */
int mcp41100_wake(const struct device *dev);

#endif /* MCP41100_H__ */

3、\boards\fpb_ra6e2.overlay

&spi0 {
    status = "okay";
};

/* SPI0 CS controlled via GPIO (P3_01) - software control only, don't use hw cs */
&spi0 {
    cs-gpios = <&ioport3 1 GPIO_ACTIVE_HIGH>;  /* 1=high=inactive, 0=low=active */
};

在这里使能spi0, 以及定义0为使能CS,即低电平选中。

4、main.c

/*
 * MCP41100 Digital Potentiometer Control
 * FPB-RA6E2 + SPI0 -> MCP41100 (100K ohm, 实测89K)
 *
 * Output: 50K resistance (校准后)
 *   - 校准: 89K实测 → 50K目标 → 位置=143 (0x8F)
 */

#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/spi.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/logging/log.h>
#include "mcp41100.h"

LOG_MODULE_REGISTER(mcp41100, LOG_LEVEL_INF);

/* SPI device */
#define SPI_DEV   DEVICE_DT_GET(DT_NODELABEL(spi0))

/* MCP41100 配置 - 使用设备树中的 cs-gpios */
static const struct gpio_dt_spec cs_gpio = GPIO_DT_SPEC_GET(DT_NODELABEL(spi0), cs_gpios);

/* SPI config - Mode 0 (CPOL=0, CPHA=0), 1MHz */
static struct spi_config spi_cfg = {
    .frequency = 1000000,
    .operation = SPI_OP_MODE_MASTER | SPI_WORD_SET(8),
    .slave = 0,
};

/* MCP41100 设备配置 */
static const struct mcp41100_config mcp41100_config = {
    .spi_dev = SPI_DEV,
    .spi_cfg = {
        .frequency = 1000000,
        .operation = SPI_OP_MODE_MASTER | SPI_WORD_SET(8),
        .slave = 0,
    },
    .cs_gpio = GPIO_DT_SPEC_GET(DT_NODELABEL(spi0), cs_gpios),
};

/* MCP41100 设备数据 */
static struct mcp41100_data mcp41100_data;

/* MCP41100 设备定义 */
DEVICE_DEFINE(mcp41100, "MCP41100", mcp41100_init, NULL,
          &mcp41100_data, &mcp41100_config, POST_KERNEL,
          CONFIG_KERNEL_INIT_PRIORITY_DEVICE, NULL);

int main(void)
{
    const struct device *dev;

    LOG_INF("MCP41100 Digital Pot Control Demo");

    dev = device_get_binding("MCP41100");
    if (dev == NULL) {
        LOG_ERR("Failed to get MCP41100 device");
        return -ENODEV;
    }

    /* 校准参数: 实测90.5K → 目标50K */
    uint32_t total_ohm = 90500;
    uint32_t target_ohm = 50000;
    uint8_t pos = mcp41100_calc_position(total_ohm, target_ohm);

    LOG_INF("Target: %d ohm, Wiper pos: %d (0x%02x)", target_ohm, pos, pos);

    int ret = mcp41100_set_resistance(dev, total_ohm, target_ohm);
    if (ret < 0) {
        LOG_ERR("Failed to set resistance: %d", ret);
        return ret;
    }

    LOG_INF("Resistance set to ~%d ohm", target_ohm);

    while (1) {
        k_sleep(K_SECONDS(10));
    }
    return 0;
}

【编译与下载】

执行west build -b fpb_ra6e2即可以编译生成工程。

由于开发板板载了jlink-ob因此可以直接使用west下载,执行:west flash --runner jlink即可以实现工程下载到开发板。

【验证】

下载好工程后,连接好开发板,可以测到正确的电阻值为50K





关键词: Zephyr     RA6E2     MCP41100    

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]