Rice我叫加饭? · 2021年09月03日

RT-Thread Nano如何适配I2C设备API,并在RT-Thread Nano使用软件包

本文介绍了如何在 RT-Thread Studio 上使用 RT-Thread Nano,并基于 BearPI-IOT STM32L431RCT6 的基础工程进行讲解如何使用 I2C 设备接口及相关软件包使用。

image.png
BearPI-IOT board

为什么需要设备接口

  1. RT-Thread 分为标准版本和 Nano 版本,其特点如下:
  • RT-Thread 标准版:拥有设备驱动框架,软件包等组件,软件包都是基于设备驱动接口来实现。
  • RT-Thread Nano:仅仅只是一个 RTOS 内核。没有任何组件。
  1. Nano 是无法直接使用 RT-Thread 丰富软件包功能。
  2. Nano 是一个面向低资源的 MCU 等芯片,不可能增加如同标准版的设备驱动框架。
  3. Nano 需要一套统一设备驱动 API,屏蔽不同芯片的 HAL 层的区别。方便移植工程到不同的平台。
  4. Nano 需要一套设备驱动 API,可以方便使用丰富软件包组件。

准备工作

  1. 使用 RT-Thread Studio 建立一个 STM32L431RCT6 的 RT-Thread Nano 基础工程。
  2. 基础工程创建可参考:在 RT-Thread Studio 上使用 RT-Thread Nano

I2C 设备接口

  1. 在 RT-Thread 标准版中,I2C设备驱动提供了一套设备管理接口来访问 I2C,用户程序可以直接使用该 API 操作 I2C 的功能,设备管理接口如下:

image.png

  1. 由于 RT-Thread Nano 不使用设备驱动框架,所以没有对应的 rt_device_find() 这个 API 获取设备对象。但 RT-Thread 标准版实际为用户层提供了另外一套 API 给用户层使用。设备管理接口如下:

image.png

  1. 对于 RT-Thread Nano,只需要适配如上这套 API,便可简单修改后使用 RT-Thread 丰富软件包功能。

适配 I2C 设备接口

  1. 复制 RT-Thread 完整版工程中的 i2c.h 文件(路径:rt-thread\components\drivers\include\drivers\i2c.h)到我们准备好的 STM32L431RCT6 的 RT-Thread Nano 基础工程中。
  2. 由于 RT-Thread Nano 没有设备驱动框架,所以我们要把 i2c.h 中有关完整版的内容去掉。整理完之后的 i2c.h 文件如下:

/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author        Notes
 * 2021-04-20     RiceChen      first version
 */

#ifndef __I2C_H__
#define __I2C_H__

#include <rtthread.h>

#ifdef __cplusplus
extern "C" {
#endif

#define RT_I2C_WR                0x0000
#define RT_I2C_RD               (1u << 0)
#define RT_I2C_ADDR_10BIT       (1u << 2)  /* this is a ten bit chip address */
#define RT_I2C_NO_START         (1u << 4)
#define RT_I2C_IGNORE_NACK      (1u << 5)
#define RT_I2C_NO_READ_ACK      (1u << 6)  /* when I2C reading, we do not ACK */
#define RT_I2C_NO_STOP          (1u << 7)

struct rt_i2c_config
{
    char *name;
    rt_uint8_t scl;
    rt_uint8_t sda;
};

struct rt_i2c_msg
{
    rt_uint16_t addr;
    rt_uint16_t flags;
    rt_uint16_t len;
    rt_uint8_t  *buf;
};

/*for i2c bus driver*/
struct rt_i2c_bus_device
{
    struct rt_i2c_config *config;
    rt_uint16_t  flags;
    rt_uint16_t  addr;
    struct rt_mutex lock;
    rt_uint32_t  timeout;
    rt_uint32_t  retries;
    void *priv;
};

struct rt_i2c_bus_device *rt_i2c_bus_device_find(const char *bus_name);
rt_size_t rt_i2c_transfer(struct rt_i2c_bus_device *bus,
                          struct rt_i2c_msg         msgs[],
                          rt_uint32_t               num);
rt_err_t rt_i2c_control(struct rt_i2c_bus_device *bus,
                        rt_uint32_t               cmd,
                        rt_uint32_t               arg);
rt_size_t rt_i2c_master_send(struct rt_i2c_bus_device *bus,
                             rt_uint16_t               addr,
                             rt_uint16_t               flags,
                             const rt_uint8_t         *buf,
                             rt_uint32_t               count);
rt_size_t rt_i2c_master_recv(struct rt_i2c_bus_device *bus,
                             rt_uint16_t               addr,
                             rt_uint16_t               flags,
                             rt_uint8_t               *buf,
                             rt_uint32_t               count);

rt_inline rt_err_t rt_i2c_bus_lock(struct rt_i2c_bus_device *bus, rt_tick_t timeout)
{
    return rt_mutex_take(&bus->lock, timeout);
}

rt_inline rt_err_t rt_i2c_bus_unlock(struct rt_i2c_bus_device *bus)
{
    return rt_mutex_release(&bus->lock);
}

int rt_i2c_core_init(void);

#ifdef __cplusplus
}
#endif

#endif

3.我们需要适配如上6个 I2C 设备 API ,参考实例:
image.png

  • drv_i2c.c
/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author            Notes
 * 2021-08-21     RiceChen     the first version
 */

#include <board.h>
#include "drv_i2c.h"

#ifdef RT_USING_I2C

enum
{
#ifdef RT_USING_I2C1
    I2C1_INDEX,
#endif
#ifdef RT_USING_I2C2
    I2C2_INDEX,
#endif
};

static struct rt_i2c_config i2c_config[] =
{
#ifdef RT_USING_I2C1
     RT_I2C1_CONFIG,
#endif
#ifdef RT_USING_I2C2
     RT_I2C1_CONFIG
#endif
};

static struct rt_i2c_bus_device i2c_bus[sizeof(i2c_config) / sizeof(i2c_config[0])] = {0};

static void rt_i2c_configure(struct rt_i2c_bus_device *bus)
{
    rt_uint8_t scl_pin = bus->config->scl;
    rt_uint8_t sda_pin = bus->config->sda;

    rt_pin_mode(scl_pin, PIN_MODE_OUTPUT_OD);
    rt_pin_mode(sda_pin, PIN_MODE_OUTPUT_OD);

    rt_pin_write(scl_pin, PIN_HIGH);
    rt_pin_write(sda_pin, PIN_HIGH);
}

static void rt_i2c_set_sda(struct rt_i2c_bus_device *bus, rt_uint32_t state)
{
    rt_uint8_t sda_pin = bus->config->sda;

    if (state)
    {
        rt_pin_write(sda_pin, PIN_HIGH);
    }
    else
    {
        rt_pin_write(sda_pin, PIN_LOW);
    }
}

static void rt_i2c_set_scl(struct rt_i2c_bus_device *bus, rt_uint32_t state)
{
    rt_uint8_t scl_pin = bus->config->scl;

    if (state)
    {
        rt_pin_write(scl_pin, PIN_HIGH);
    }
    else
    {
        rt_pin_write(scl_pin, PIN_LOW);
    }
}

static rt_uint32_t rt_i2c_get_sda(struct rt_i2c_bus_device *bus)
{
    rt_uint8_t sda_pin = bus->config->sda;

    return rt_pin_read(sda_pin);
}

static rt_uint32_t rt_i2c_get_scl(struct rt_i2c_bus_device *bus)
{
    rt_uint8_t scl_pin = bus->config->scl;

    return rt_pin_read(scl_pin);
}

static void rt_i2c_udelay(rt_uint32_t us)
{
    rt_hw_us_delay(us);
}

#define SET_SDA(bus, val)   rt_i2c_set_sda(bus, val)
#define SET_SCL(bus, val)   rt_i2c_set_scl(bus, val)
#define GET_SDA(bus)        rt_i2c_get_sda(bus)
#define GET_SCL(bus)        rt_i2c_get_scl(bus)

#define SDA_L(bus)          SET_SDA(bus, 0)
#define SDA_H(bus)          SET_SDA(bus, 1)
#define SCL_L(bus)          SET_SCL(bus, 0)

static rt_err_t SCL_H(struct rt_i2c_bus_device *bus)
{
    rt_tick_t start;

    SET_SCL(bus, 1);

    if(rt_i2c_get_scl(bus))
    {
        goto done;
    }

    start = rt_tick_get();
    while (!GET_SCL(bus))
    {
        if ((rt_tick_get() - start) > 100)
            return -RT_ETIMEOUT;
        rt_thread_delay(100);
    }
done:
    rt_i2c_udelay(1);

    return RT_EOK;
}

static void rt_i2c_start(struct rt_i2c_bus_device *bus)
{
    SDA_L(bus);
    rt_i2c_udelay(1);
    SCL_L(bus);
}

static void rt_i2c_restart(struct rt_i2c_bus_device *bus)
{
    SDA_H(bus);
    SCL_H(bus);
    rt_i2c_udelay(1);

    SDA_L(bus);
    rt_i2c_udelay(1);
    SCL_L(bus);
}

static void rt_i2c_stop(struct rt_i2c_bus_device *bus)
{
    SDA_L(bus);
    rt_i2c_udelay(1);
    SCL_H(bus);
    rt_i2c_udelay(1);
    SDA_H(bus);
    rt_i2c_udelay(1);
}

rt_inline rt_bool_t rt_i2c_waitack(struct rt_i2c_bus_device *bus)
{
    rt_bool_t ack;

    SDA_H(bus);
    rt_i2c_udelay(1);

    if (SCL_H(bus) < 0)
    {
        return -RT_ETIMEOUT;
    }
    ack = !GET_SDA(bus);
    SCL_L(bus);

    return ack;
}

static rt_int32_t rt_i2c_writeb(struct rt_i2c_bus_device *bus, rt_uint8_t data)
{
    rt_int32_t i;
    rt_uint8_t bit;

    for (i = 7; i >= 0; i--)
    {
        SCL_L(bus);
        bit = (data >> i) & 1;
        SET_SDA(bus, bit);
        rt_i2c_udelay(1);
        if (SCL_H(bus) < 0)
        {
            return -RT_ETIMEOUT;
        }
    }
    SCL_L(bus);
    rt_i2c_udelay(1);

    return rt_i2c_waitack(bus);
}

static rt_int32_t rt_i2c_readb(struct rt_i2c_bus_device *bus)
{
    rt_uint8_t i;
    rt_uint8_t data = 0;

    SDA_H(bus);
    rt_i2c_udelay(1);
    for (i = 0; i < 8; i++)
    {
        data <<= 1;
        if (SCL_H(bus) < 0)
        {
            return -RT_ETIMEOUT;
        }
        if (GET_SDA(bus))
            data |= 1;
        SCL_L(bus);
        rt_i2c_udelay(1);
    }

    return data;
}

static rt_size_t rt_i2c_send_bytes(struct rt_i2c_bus_device *bus,
                                   struct rt_i2c_msg *msg)
{
    rt_int32_t ret;
    rt_size_t bytes = 0;
    const rt_uint8_t *ptr = msg->buf;
    rt_int32_t count = msg->len;
    rt_uint16_t ignore_nack = msg->flags & RT_I2C_IGNORE_NACK;

    while (count > 0)
    {
        ret = rt_i2c_writeb(bus, *ptr);

        if ((ret > 0) || (ignore_nack && (ret == 0)))
        {
            count --;
            ptr ++;
            bytes ++;
        }
        else if (ret == 0)
        {
            return 0;
        }
        else
        {
            return ret;
        }
    }

    return bytes;
}

static rt_err_t rt_i2c_send_ack_or_nack(struct rt_i2c_bus_device *bus, int ack)
{
    if (ack)
        SET_SDA(bus, 0);
    rt_i2c_udelay(1);
    if (SCL_H(bus) < 0)
    {
        return -RT_ETIMEOUT;
    }
    SCL_L(bus);

    return RT_EOK;
}

static rt_size_t rt_i2c_recv_bytes(struct rt_i2c_bus_device *bus,
                                   struct rt_i2c_msg *msg)
{
    rt_int32_t val;
    rt_int32_t bytes = 0;   /* actual bytes */
    rt_uint8_t *ptr = msg->buf;
    rt_int32_t count = msg->len;
    const rt_uint32_t flags = msg->flags;

    while (count > 0)
    {
        val = rt_i2c_readb(bus);
        if (val >= 0)
        {
            *ptr = val;
            bytes ++;
        }
        else
        {
            break;
        }

        ptr ++;
        count --;
        if (!(flags & RT_I2C_NO_READ_ACK))
        {
            val = rt_i2c_send_ack_or_nack(bus, count);
            if (val < 0)
                return val;
        }
    }

    return bytes;
}

static rt_int32_t rt_i2c_send_address(struct rt_i2c_bus_device *bus,
                                      rt_uint8_t addr, rt_int32_t retries)
{
    rt_int32_t i;
    rt_err_t ret = 0;

    for (i = 0; i <= retries; i++)
    {
        ret = rt_i2c_writeb(bus, addr);
        if (ret == 1 || i == retries)
            break;
        rt_i2c_stop(bus);
        rt_i2c_udelay(1);
        rt_i2c_start(bus);
    }

    return ret;
}

static rt_err_t rt_i2c_bit_send_address(struct rt_i2c_bus_device *bus,
                                        struct rt_i2c_msg *msg)
{
    rt_uint16_t flags = msg->flags;
    rt_uint16_t ignore_nack = msg->flags & RT_I2C_IGNORE_NACK;

    rt_uint8_t addr1, addr2;
    rt_int32_t retries;
    rt_err_t ret;

    retries = ignore_nack ? 0 : bus->retries;

    if (flags & RT_I2C_ADDR_10BIT)
    {
        addr1 = 0xf0 | ((msg->addr >> 7) & 0x06);
        addr2 = msg->addr & 0xff;

        ret = rt_i2c_send_address(bus, addr1, retries);
        if ((ret != 1) && !ignore_nack)
        {
            return -RT_EIO;
        }

        ret = rt_i2c_writeb(bus, addr2);
        if ((ret != 1) && !ignore_nack)
        {
            return -RT_EIO;
        }
        if (flags & RT_I2C_RD)
        {
            rt_i2c_restart(bus);
            addr1 |= 0x01;
            ret = rt_i2c_send_address(bus, addr1, retries);
            if ((ret != 1) && !ignore_nack)
            {
                return -RT_EIO;
            }
        }
    }
    else
    {
        addr1 = msg->addr << 1;
        if (flags & RT_I2C_RD)
            addr1 |= 1;
        ret = rt_i2c_send_address(bus, addr1, retries);
        if ((ret != 1) && !ignore_nack)
            return -RT_EIO;
    }

    return RT_EOK;
}

rt_err_t rt_i2c_control(struct rt_i2c_bus_device *bus,
                        rt_uint32_t               cmd,
                        rt_uint32_t               arg)
{
    return RT_EOK;
}

rt_size_t rt_i2c_transfer(struct rt_i2c_bus_device *bus,
                          struct rt_i2c_msg         msgs[],
                          rt_uint32_t               num)
{
    struct rt_i2c_msg *msg;
    rt_int32_t i, ret;
    rt_uint16_t ignore_nack;

    rt_i2c_start(bus);
    for (i = 0; i < num; i++)
    {
        msg = &msgs[i];
        ignore_nack = msg->flags & RT_I2C_IGNORE_NACK;
        if (!(msg->flags & RT_I2C_NO_START))
        {
            if (i)
            {
                rt_i2c_restart(bus);
            }
            ret = rt_i2c_bit_send_address(bus, msg);
            if ((ret != RT_EOK) && !ignore_nack)
            {
                goto out;
            }
        }
        if (msg->flags & RT_I2C_RD)
        {
            ret = rt_i2c_recv_bytes(bus, msg);
            if (ret >= 1)
                ;
            if (ret < msg->len)
            {
                if (ret >= 0)
                    ret = -RT_EIO;
                goto out;
            }
        }
        else
        {
            ret = rt_i2c_send_bytes(bus, msg);
            if (ret >= 1)
                ;
            if (ret < msg->len)
            {
                if (ret >= 0)
                    ret = -RT_ERROR;
                goto out;
            }
        }
    }
    ret = i;

out:
    rt_i2c_stop(bus);

    return ret;
}

rt_size_t rt_i2c_master_send(struct rt_i2c_bus_device *bus,
                             rt_uint16_t               addr,
                             rt_uint16_t               flags,
                             const rt_uint8_t         *buf,
                             rt_uint32_t               count)
{
    rt_err_t ret;
    struct rt_i2c_msg msg;

    msg.addr  = addr;
    msg.flags = flags;
    msg.len   = count;
    msg.buf   = (rt_uint8_t *)buf;

    ret = rt_i2c_transfer(bus, &msg, 1);

    return (ret > 0) ? count : ret;
}

rt_size_t rt_i2c_master_recv(struct rt_i2c_bus_device *bus,
                             rt_uint16_t               addr,
                             rt_uint16_t               flags,
                             rt_uint8_t               *buf,
                             rt_uint32_t               count)
{
    rt_err_t ret;
    struct rt_i2c_msg msg;
    RT_ASSERT(bus != RT_NULL);

    msg.addr   = addr;
    msg.flags  = flags | RT_I2C_RD;
    msg.len    = count;
    msg.buf    = buf;

    ret = rt_i2c_transfer(bus, &msg, 1);

    return (ret > 0) ? count : ret;
}

struct rt_i2c_bus_device *rt_i2c_bus_device_find(const char *bus_name)
{
    rt_size_t bus_num = sizeof(i2c_bus) / sizeof(i2c_bus[0]);

    for(int i = 0; i < bus_num; i++)
    {
        if(rt_strncmp(i2c_bus[i].config->name, bus_name, RT_NAME_MAX) == 0)
        {
            return &i2c_bus[i];
        }
    }
    return RT_NULL;
}

int rt_i2c_core_init(void)
{
    rt_size_t bus_num = sizeof(i2c_bus) / sizeof(i2c_bus[0]);

    for(int i = 0; i < bus_num; i++)
    {
        i2c_bus[i].config = &i2c_config[i];
        rt_i2c_configure(&i2c_bus[i]);
    }

    return RT_EOK;
}
INIT_COMPONENT_EXPORT(rt_i2c_core_init);

#endif /* RT_USING_I2C */
  • drv_i2c.h
/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author            Notes
 * 2021-04-20     RiceChen      first version
 */

#ifndef __DRV_I2C_H__
#define __DRV_I2C_H__

#include <drv_common.h>
#include <board.h>
#include "pin.h"
#include "i2c.h"

#ifdef __cplusplus
extern "C" {
#endif

#ifdef RT_USING_I2C1
#define RT_I2C1_SCL_PIN            GET_PIN(B, 6)
#define RT_I2C1_SDA_PIN            GET_PIN(B, 7)

#define RT_I2C1_CONFIG                                         \
    {                                                          \
        .name = "i2c1",                                        \
        .scl = RT_I2C1_SCL_PIN,                                \
        .sda = RT_I2C1_SDA_PIN,                                \
    }
#endif

#ifdef RT_USING_I2C2
#define RT_I2C2_SCL_PIN            GET_PIN(B, 8)
#define RT_I2C2_SDA_PIN            GET_PIN(B, 9)

#define RT_I2C2_CONFIG                                         \
    {                                                          \
        .name = "i2c2",                                        \
        .scl = RT_I2C2_SCL_PIN,                                \
        .sda = RT_I2C2_SDA_PIN,                                \
    }
#endif

#ifdef __cplusplus
}
#endif

#endif /* __DRV_GPIO_H__ */

编写 I2C 设备使用示例

#include <rtthread.h>
#include <rtdevice.h>

#define AHT10_I2C_BUS_NAME          "i2c1"  /* 传感器连接的I2C总线设备名称 */
#define AHT10_ADDR                  0x38    /* 从机地址 */
#define AHT10_CALIBRATION_CMD       0xE1    /* 校准命令 */
#define AHT10_NORMAL_CMD            0xA8    /* 一般命令 */
#define AHT10_GET_DATA              0xAC    /* 获取数据命令 */

static struct rt_i2c_bus_device *i2c_bus = RT_NULL;     /* I2C总线设备句柄 */
static rt_bool_t initialized = RT_FALSE;                /* 传感器初始化状态 */

/* 写传感器寄存器 */
static rt_err_t write_reg(struct rt_i2c_bus_device *bus, rt_uint8_t reg, rt_uint8_t *data)
{
    rt_uint8_t buf[3];
    struct rt_i2c_msg msgs;
    rt_uint32_t buf_size = 1;

    buf[0] = reg; //cmd
    if (data != RT_NULL)
    {
        buf[1] = data[0];
        buf[2] = data[1];
        buf_size = 3;
    }

    msgs.addr = AHT10_ADDR;
    msgs.flags = RT_I2C_WR;
    msgs.buf = buf;
    msgs.len = buf_size;

    /* 调用I2C设备接口传输数据 */
    if (rt_i2c_transfer(bus, &msgs, 1) == 1)
    {
        return RT_EOK;
    }
    else
    {
        return -RT_ERROR;
    }
}

/* 读传感器寄存器数据 */
static rt_err_t read_regs(struct rt_i2c_bus_device *bus, rt_uint8_t len, rt_uint8_t *buf)
{
    struct rt_i2c_msg msgs;

    msgs.addr = AHT10_ADDR;
    msgs.flags = RT_I2C_RD;
    msgs.buf = buf;
    msgs.len = len;

    /* 调用I2C设备接口传输数据 */
    if (rt_i2c_transfer(bus, &msgs, 1) == 1)
    {
        return RT_EOK;
    }
    else
    {
        return -RT_ERROR;
    }
}

static void read_temp_humi(float *cur_temp, float *cur_humi)
{
    rt_uint8_t temp[6];

    write_reg(i2c_bus, AHT10_GET_DATA, RT_NULL);      /* 发送命令 */
    rt_thread_mdelay(400);
    read_regs(i2c_bus, 6, temp);                /* 获取传感器数据 */

    /* 湿度数据转换 */
    *cur_humi = (temp[1] << 12 | temp[2] << 4 | (temp[3] & 0xf0) >> 4) * 100.0 / (1 << 20);
    /* 温度数据转换 */
    *cur_temp = ((temp[3] & 0xf) << 16 | temp[4] << 8 | temp[5]) * 200.0 / (1 << 20) - 50;
}

static void aht10_init(const char *name)
{
    rt_uint8_t temp[2] = {0, 0};

    /* 查找I2C总线设备,获取I2C总线设备句柄 */
    i2c_bus = rt_i2c_bus_device_find(name);

    if (i2c_bus == RT_NULL)
    {
        rt_kprintf("can't find %s device!\n", name);
    }
    else
    {
        write_reg(i2c_bus, AHT10_NORMAL_CMD, temp);
        rt_thread_mdelay(400);

        temp[0] = 0x08;
        temp[1] = 0x00;
        write_reg(i2c_bus, AHT10_CALIBRATION_CMD, temp);
        rt_thread_mdelay(400);
        initialized = RT_TRUE;
    }
}

static void i2c_aht10_sample(int argc, char *argv[])
{
    float humidity, temperature;
    char name[RT_NAME_MAX];

    humidity = 0.0;
    temperature = 0.0;

    if (argc == 2)
    {
        rt_strncpy(name, argv[1], RT_NAME_MAX);
    }
    else
    {
        rt_strncpy(name, AHT10_I2C_BUS_NAME, RT_NAME_MAX);
    }

    if (!initialized)
    {
        /* 传感器初始化 */
        aht10_init(name);
    }
    if (initialized)
    {
        /* 读取温湿度数据 */
        read_temp_humi(&temperature, &humidity);

        rt_kprintf("read aht10 sensor humidity   : %d.%d %%\n", (int)humidity, (int)(humidity * 10) % 10);
        if( temperature >= 0 )
        {
            rt_kprintf("read aht10 sensor temperature: %d.%d°C\n", (int)temperature, (int)(temperature * 10) % 10);
        }
        else
        {
            rt_kprintf("read aht10 sensor temperature: %d.%d°C\n", (int)temperature, (int)(-temperature * 10) % 10);
        }
    }
    else
    {
        rt_kprintf("initialize sensor failed!\n");
    }
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(i2c_aht10_sample, i2c aht10 sample);

实例代码运行现象:
 C
msh >i2c_aht10_sample i2c1
read aht10 sensor humidity   : 90.0 %
read aht10 sensor temperature: 25.33°C
msh >

I2C 设备相关软件包使用

  1. 我们使用as7341软件包来验证 I2C 设备 API。
  2. 首先克隆 as7341 软件包到 STM32L431RCT6 的 RT-Thread Nano 工程。as7341 软件包链接:https://github.com/RiceChen/a...
  3. 由于没有了 RT-Thread 标准版本的设备驱动框架,所以对软件包进行简单的修改:
  • 在 as7341.h 中包含 drv_i2c.h 头文件。
  • 修改 as7341.c 中的测试用例。代码如下:
static void as7341(int argc, char *argv[])
{
    static as7341_device_t dev = RT_NULL;
    
    if (argc > 1)
    {
        if (!strcmp(argv[1], "probe"))
        {
            if (argc >= 3)
            {
                /* initialize the sensor when first probe */
                if (!dev || strcmp(dev->i2c->config->name, argv[2])) // 修改点1
                {
                    /* deinit the old device */
                    if(dev)
                    {
      rt_kprintf("Deinit as7341\n");
                        as7341_deinit(dev);
                    }

                    dev = as7341_init(argv[2], eSpm);
                    if(!dev)
                    {
                        rt_kprintf("as7341 probe failed, check input args\n");
                    }else
     {
      rt_kprintf("as7341 probed, addr:0x%x\n", AS7341_ADDR) ;
     }
                }
            }
            else
            {
                as7341_usage();
            }
        }
        else if (!strcmp(argv[1], "read"))
        {
            if (dev)
            {
                if(!strcmp(argv[2], "spectral"))
                {
                    MODE_ONE_DATA_t data1;
                    MODE_TOW_DATA_t data2;

                    as7341_start_measure(dev, eF1F4ClearNIR);
                    data1 = as7341_read_spectral_data_one(dev);
                    rt_kprintf("F1(405-425nm): %d\n", data1.ADF1);
                    rt_kprintf("F2(435-455nm): %d\n", data1.ADF2);
                    rt_kprintf("F3(470-490nm): %d\n", data1.ADF3);
                    rt_kprintf("F4(505-525nm): %d\n", data1.ADF4);

                    as7341_start_measure(dev, eF5F8ClearNIR);
                    data2 = as7341_read_spectral_data_tow(dev);
                    rt_kprintf("F5(545-565nm): %d\n", data2.ADF5);
                    rt_kprintf("F6(580-600nm): %d\n", data2.ADF6);
                    rt_kprintf("F7(620-640nm): %d\n", data2.ADF7);
                    rt_kprintf("F8(670-690nm): %d\n", data2.ADF8);

                    rt_kprintf("Clear: %d\n", data2.ADCLEAR);
                    rt_kprintf("NIR: %d\n", data2.ADNIR);
                }
                else if(!strcmp(argv[2], "flicker"))
                {
                    rt_uint8_t freq = 0;
                    freq = as7341_read_flicker_data(dev);
                    if(freq == 1)
                    {
                        rt_kprintf("Unknown frequency\n");
                    }
                    else if(freq == 0)
                    {
                        rt_kprintf("No flicker\n");
                    }
                    else
                    {
                        rt_kprintf("freq: %dHz\n", freq);
                    }
                }
                else
                {
                    as7341_usage();
                }
                
            }
            else
            {
                rt_kprintf("Please using 'as7341 probe <i2c dev name>' first\n");
            }
        }
        else
        {
            as7341_usage();
        }
    }
    else
    {
        as7341_usage();   
    }
}
  1. 使用 as7341 软件包实例,编译烧录便可以在终端输入测试命令:
msh >as7341 probe i2c1
as7341 id: 0x24
as7341 probed, addr:0x39
msh >
msh >as7341 read spectral
F1(405-425nm): 1
F2(435-455nm): 3
F3(470-490nm): 4
F4(505-525nm): 5
F5(545-565nm): 7
F6(580-600nm): 6
F7(620-640nm): 7
F8(670-690nm): 4
Clear: 22
NIR: 2
msh >

总结

  • 通过适配I2C设备接口,我们可以无缝对接到软件包的使用。
  • 对于低资源的芯片使用 Nano 并且能够使用 RT-THREAD 丰富的软件,无疑是一个非常完美的做法。也没有庞大的驱动框架。
  • 通过这样的方式,学习完 RT-THREAD Nano 在转移到 RT-THREAD 标准版的学习,更加简单方便。
首发:Rice 嵌入式开发技术分享
作者:RiceDIY

推荐阅读

更多嵌入式技术干货请关注Rice 嵌入式开发技术分享
推荐阅读
关注数
1761
内容数
51
一个周末很无聊的嵌入式软件工程师,写写经验,写写总结。
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息