这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 活动中心 » 板卡试用 » 【换取逻辑分析仪】rtthread添加RRH62000传感器驱动-基于野火启明6

共6条 1/1 1 跳转至

【换取逻辑分析仪】rtthread添加RRH62000传感器驱动-基于野火启明6M5

助工
2024-11-28 23:39:53   被打赏 48 分(兑奖)     打赏

背景

   9月份逛某论坛时,发现一个有意思的传感器RRH62000,此传感器号称可以监控室内大部分空气质量,瞬间就想到了多年前新家入住时特意买的甲醛监测仪,如果自己能做一个这样的设备,也是挺有意思的一件事。当时头脑一热,就申请了。到11月时,突然收到邮件说选中了,就赶紧拿回来把玩起来。

       RRH62000目前释放出来的资料不多,但是搜索github上发现,其实瑞萨的fsp5.6已经有上传RRH62000的代码了(具体可以在链接中搜索RRH62000:Releases · renesas/fsp),也就是说,如果要适配RRH62000,如果使用瑞萨主控,基于目前rtthread上瑞萨的代码逻辑,我们需要把板卡fsp升级到5.6,之后开启rrh62000,再将rrh62000对接到rtthread的传感器框架中,便能够实现适配。

       但是呢,通过查阅传感器部分的代码,我决定暂时放弃这一操作,原因是我并不认为目前fsp上的外围器件框架逻辑符合产品设计的需求。因为目前fsp上的rrh62000框架,I2C是独占式的,而实际项目设计中,I2C很少独占一路,而是多种器件共用一路I2C。

硬件配置

   由于RRH62000独特的架构设计(供电需要5V,但通信却使用3.3V),我手头上能直接供5V并操作3.3V的板子并不多,只有野火的启明6M5,因此就用启明6M5来做RRH6200的适配。

I2C通信接口

   启明6M5的typec端口上的串口可以配置成I2C1,如下图:

2.jpg      在调试时,仅仅需要将J35的跳冒拿开,并将RRH62000的I2C口接到此处即可。

供电部分

   启明6M5的J29座子上有引出VCC_5V和GND,因此可以将供电引至该口。

2.jpg

软件设置

   选定了硬件接口,那剩下的就是FSP的设置了,由于之前我已经把启明6M5大部分功能配好并合并到github主线仓库了,因此这里的配置,仅仅是通过FSP配置对应的硬件接口即可。

串口部分

FSP修改

     rtt主线上目前配置的串口和I2C1所使用的接口冲突,因此我将此路串口切换至JTAG上的串口,以便调试。具体配置如下:

     删除stacks中的uart4配置后,依次进行以下配置:

     这部分配置完毕后,点击Generate Project Content生成配置。

menuconfig配置

     fsp已经把uart4关闭,并打开了UART2,但是目前rtt默认的配置还是在uart4上,此时只需要进入menuconfig中,打开uart2,关闭uart4,并将调试口更换至uart2即可。具体修改如下:

     在emu中输入menuconfig并回车,进行以下配置:

     选择完毕后保存,并输入 scons --target=mdk5 生成新工程。此时编译运行,可发现finsh串口变成了uart2。

I2C1部分

FSP修改

     I2C1部分和配置类似,具体配置方法如下:

      之后点击Generate Project Content便可生成I2C1相关的配置。

menuconfig配置

     同样的,虽然FSP已经启用了I2C1,但是rtt目前并由没启用I2C1,此时需要在menuconfig中启用I2C1,启用方法同uart,但操作位置有细微差异,具体差异如下:

      选择完毕后保存,并输入 scons --target=mdk5 生成新工程。

      至此,I2C1也被添加至工程中。

传感器代码添加

文件添加

      所有驱动文件都按惯例,全部添加至bsp\renesas\libraries\HAL_Drivers\中,因为瑞萨所有的驱动看起来都是加在此处。

rrh62000.c

#include "rrh62000.h"

#define RRH62000_ADDR               0x69

/* Definitions of Timeout */
#define RM_RRH62000_TIMEOUT                       (100)

/* Definitions of Wait Time */
#define RM_RRH62000_WAIT_TIME_1000                (1000)

/* Definitions of Retry max counts */
#define RM_RRH62000_RETRY_MAX_COUNTS              (5)
#define RM_RRH62000_RETRY_ZMOD_CLEANING_COUNTS    (60 + 10) // ZMOD cleaning time (60s) + buffer (10s)

/* Definitions of Command */
#define RM_RRH62000_COMMAND_READ                  (0x00)
#define RM_RRH62000_COMMAND_DATA                  (0x40)
#define RM_RRH62000_COMMAND_RESET                 (0x52)
#define RM_RRH62000_COMMAND_MAVE                  (0x53)
#define RM_RRH62000_COMMAND_SPEEDFAN              (0x63)
#define RM_RRH62000_COMMAND_ARGVER                (0x73)
#define RM_RRH62000_COMMAND_CSTATUS               (0x74)
#define RM_RRH62000_COMMAND_FWVAR                 (0x75)

/* Definitions of Reset */
#define RM_RRH62000_RESET_VALUE                   (0x81)

/* Definitions of Cleaning Status */
#define RM_RRH62000_ZMOD_CLEAN_NOT_COMPLETE       (0x00)
#define RM_RRH62000_ZMOD_CLEAN_COMPLETE           (0x01)

/* Definitions of data size */
#define RM_RRH62000_LEN_MEASUREMENT_DATA          (37)

/* Definitions of Mask */
#define RM_RRH62000_STATUS_MASK                   (0x01)
#define RM_RRH62000_HIGH_CONCENTRATION_MASK       (0x01)
#define RM_RRH62000_DUST_ACCUMULATION_MASK        (0x02)
#define RM_RRH62000_FAN_SPEED_MASK                (0x04)
#define RM_RRH62000_FAN_MASK                      (0x08)

/* Definitions of Position */
#define RM_RRH62000_POSITION_STATUS               (0)
#define RM_RRH62000_POSITION_NC_0P3               (2)
#define RM_RRH62000_POSITION_TEMPERATURE          (24)
#define RM_RRH62000_POSITION_ECO2                 (30)
#define RM_RRH62000_POSITION_IAQ                  (32)

/* Definitions of Calculation */
#define RM_RRH62000_CALC_CRC_INITIAL_VALUE        (0xFF)
#define RM_RRH62000_CALC_CRC_DATA_LENGTH          (36)
#define RM_RRH62000_CALC_DATA_STEP                (2)
#define RM_RRH62000_CALC_CRC_8BITS_LENGTH         (8)
#define RM_RRH62000_CACL_CRC_0X80                 (0x80)
#define RM_RRH62000_CACL_CRC_MASK_MSB             (0x80)
#define RM_RRH62000_CALC_CRC_POLYNOMIAL           (0x31)
#define RM_RRH62000_CALC_CRC_FINAL_XOR            (0x00)
#define RM_RRH62000_CALC_DECIMAL_VALUE_100        (100)
#define RM_RRH62000_CALC_DECIMAL_VALUE_10         (10)

/* Definitions of Shift */
#define RM_RRH62000_SHIFT_24                      (24)
#define RM_RRH62000_SHIFT_16                      (16)
#define RM_RRH62000_SHIFT_8                       (8)


static rt_err_t rrh62000_read(struct rt_i2c_bus_device *bus, uint8_t reg, uint8_t *data, uint16_t len)
{
    rt_uint8_t        tmp = reg;
    struct rt_i2c_msg msgs[2];

    msgs[0].addr  = RRH62000_ADDR;      /* Slave address */
    msgs[0].flags = RT_I2C_WR; /* Write flag */
    msgs[0].buf   = &tmp;      /* Slave register address */
    msgs[0].len   = 1;         /* Number of bytes sent */

    msgs[1].addr  = RRH62000_ADDR;      /* Slave address */
    msgs[1].flags = RT_I2C_RD; /* Read flag */
    msgs[1].buf   = data;      /* Read data pointer */
    msgs[1].len   = len;       /* Number of bytes read */

    if (rt_i2c_transfer(bus, msgs, 2) != 2)
    {
        return -RT_ERROR;
    }

    return RT_EOK;
}

static rt_err_t rrh62000_write(struct rt_i2c_bus_device *bus, uint8_t reg, uint8_t *data, uint16_t len)
{
    struct rt_i2c_msg msgs[2];
    uint8_t           data1[5];
    uint16_t          i;

    data1[0] = reg;
    for (i = 0; i < len; i++)
    {
        data1[i + 1] = data[i];
    }

    msgs[0].addr  = RRH62000_ADDR;      /* Slave address */
    msgs[0].flags = RT_I2C_WR; /* Write flag */
    msgs[0].buf   = data1;     /* Slave register address */
    msgs[0].len   = len + 1;   /* Number of bytes sent */

    if (rt_i2c_transfer(bus, msgs, 1) != 1)
    {
        return -RT_ERROR;
    }

    return RT_EOK;
}

static rt_err_t rm_rrh62000_crc_execute (const uint8_t * const p_raw_data)
{
    uint8_t         crc;
    const uint8_t * p_input_data;
    uint8_t         i;
    uint8_t         j;

    /* Set pointer to input data */
    p_input_data = &p_raw_data[0];

    /* Set initial value */
    crc = RM_RRH62000_CALC_CRC_INITIAL_VALUE;

    /* Execute CRC */
    for (i = 0; i < RM_RRH62000_CALC_CRC_DATA_LENGTH; i++)
    {
        /* Calculate XOR with input value */
        crc ^= *p_input_data;

        for (j = 0; j < RM_RRH62000_CALC_CRC_8BITS_LENGTH; j++)
        {
            if (RM_RRH62000_CACL_CRC_0X80 == (crc & RM_RRH62000_CACL_CRC_MASK_MSB))
            {
                /* If MSB is 1, calculate XOR with the polynomial. */
                crc = (uint8_t) (crc << 1) ^ RM_RRH62000_CALC_CRC_POLYNOMIAL;
            }
            else
            {
                crc <<= 1;
            }
        }

        p_input_data++;
    }

    /* Final XOR */
    crc ^= RM_RRH62000_CALC_CRC_FINAL_XOR;
    if(p_raw_data[RM_RRH62000_CALC_CRC_DATA_LENGTH] == crc)
    {
        return RT_EOK;    
    }
    else
    {
        return -RT_ERROR;    
    }
}

static rt_err_t RM_RRH62000_DataCalculate (uint8_t * p_raw_data, struct rrh62000_data *p_rrh62000_data)
{
    rt_err_t err = RT_EOK;
    rt_uint32_t tmp_u32;
    rm_air_sensor_single_data_t * p_sensor_data;
    rt_uint32_t position;

    /* Execute CRC */
    err = rm_rrh62000_crc_execute(p_raw_data);
    if(err != RT_EOK)
    {
        return err;    
    }

    /* Set status data */
    p_rrh62000_data->status =
        (uint32_t) (((uint32_t) p_raw_data[1] << RM_RRH62000_SHIFT_8) | (uint32_t) p_raw_data[0]);

    /* Set measurement results */
    p_sensor_data = &p_rrh62000_data->nc_0p3;
    for (position = RM_RRH62000_POSITION_NC_0P3;
         position < RM_RRH62000_LEN_MEASUREMENT_DATA;
         position += RM_RRH62000_CALC_DATA_STEP)
    {
        /* Calculate sensor data from measurement results (big-endian). */
        tmp_u32 = (uint32_t) (((uint32_t) p_raw_data[position] << RM_RRH62000_SHIFT_8) |
                              (uint32_t) p_raw_data[position + 1]);
        if (RM_RRH62000_POSITION_TEMPERATURE > position)
        {
            /* NC_x and PMx_x data. One decimal place. */
            p_sensor_data->integer_part = tmp_u32 / RM_RRH62000_CALC_DECIMAL_VALUE_10;
            p_sensor_data->decimal_part = tmp_u32 % RM_RRH62000_CALC_DECIMAL_VALUE_10;
        }
        else if ((RM_RRH62000_POSITION_ECO2 > position) || (RM_RRH62000_POSITION_IAQ == position))
        {
            /* Temperature, humidity, TVOC and IAQ data. Two decimal places. */
            p_sensor_data->integer_part = tmp_u32 / RM_RRH62000_CALC_DECIMAL_VALUE_100;
            p_sensor_data->decimal_part = tmp_u32 % RM_RRH62000_CALC_DECIMAL_VALUE_100;
        }
        else
        {
            /* eCO2 and Relative IAQ data. These data does not have a decimal part. */
            p_sensor_data->integer_part = tmp_u32;
            p_sensor_data->decimal_part = 0;
        }

        p_sensor_data++;
    }

    return RT_EOK;
}

rt_err_t rrh62000_read_measured_value(struct rt_i2c_bus_device *bus, struct rrh62000_data *data)
{
    rt_uint8_t buf[37];
    rt_uint32_t len = 37;

    if(rrh62000_read(bus, RM_RRH62000_COMMAND_READ, buf, len) != RT_EOK) {
        return -RT_ERROR;
    }

    return RM_RRH62000_DataCalculate(buf, data);
}

rt_err_t rrh62000_read_data_status(struct rt_i2c_bus_device *bus, rt_bool_t *isDataReady)
{
    rt_uint8_t buf[1];
    if(rrh62000_read(bus, RM_RRH62000_COMMAND_DATA, buf, 1) != RT_EOK) {
        return -RT_ERROR;
    }

    *isDataReady = buf[0];

    return RT_EOK;
}

rt_err_t rrh62000_sleep_set(struct rt_i2c_bus_device *bus, rt_bool_t isSleep)
{
    rt_uint8_t buf[1];

    if(isSleep)
    {
        buf[0] = 0x00;
    }
    else
    {
        buf[0] = 0x80;
    }

    if(rrh62000_write(bus, 0x50, buf, 1) != RT_EOK) {
        return -RT_ERROR;
    }

    return RT_EOK;
}

rt_err_t rrh62000_sleep_get(struct rt_i2c_bus_device *bus, rt_bool_t *isSleep)
{
    rt_uint8_t buf[1];

    if(rrh62000_read(bus, 0x50, buf, 1) != RT_EOK) {
        return -RT_ERROR;
    }

    if(buf[0])
    {
        *isSleep = 0;
    }
    else
    {
        *isSleep = 1;
    }

    return RT_EOK;
}

rt_err_t rrh62000_start_dust_cleaning(struct rt_i2c_bus_device *bus)
{
    rt_uint8_t buf[1] = {0x01};
    if(rrh62000_write(bus, 0x51, buf, 1) != RT_EOK) {
        return -RT_ERROR;
    }

    return RT_EOK;
}

rt_err_t rrh62000_reset(struct rt_i2c_bus_device *bus)
{
    rt_uint8_t buf[1] = {0x81};
    if(rrh62000_write(bus, RM_RRH62000_COMMAND_RESET, buf, 1) != RT_EOK) {
        return -RT_ERROR;
    }

    return RT_EOK;
}

rt_err_t rrh62000_moving_average_set(struct rt_i2c_bus_device *bus, uint8_t time)
{
    rt_uint8_t buf[1];

    if(time > 60)
    {
        time = 60;
    }
    else if(time < 1)
    {
        time = 1;
    }
    buf[0] = time;

    if(rrh62000_write(bus, RM_RRH62000_COMMAND_MAVE, buf, 1) != RT_EOK) {
        return -RT_ERROR;
    }

    return RT_EOK;
}

rt_err_t rrh62000_moving_average_get(struct rt_i2c_bus_device *bus, uint8_t *time)
{
    rt_uint8_t buf[1];

    if(rrh62000_read(bus, RM_RRH62000_COMMAND_MAVE, buf, 1) != RT_EOK) {
        return -RT_ERROR;
    }

    *time = buf[0];

    return RT_EOK;
}

rt_err_t rrh62000_clean_interval_time_set(struct rt_i2c_bus_device *bus, uint16_t time)
{
    rt_uint8_t buf[1];

    if(time > 60480)
    {
        time = 60480;
    }
    buf[0] = (time >> 8);
    if(rrh62000_write(bus, 0x5A, buf, 1) != RT_EOK) {
        return -RT_ERROR;
    }

    buf[0] = (time & 0x00FF);
    if(rrh62000_write(bus, 0x5B, buf, 1) != RT_EOK) {
        return -RT_ERROR;
    }
    return RT_EOK;
}

rt_err_t rrh62000_clean_interval_time_get(struct rt_i2c_bus_device *bus, uint16_t *time)
{
    rt_uint8_t buf[2];

    if(rrh62000_read(bus, 0x5A, buf, 1) != RT_EOK) {
        return -RT_ERROR;
    }

    if(rrh62000_read(bus, 0x5B, buf + 1, 1) != RT_EOK) {
        return -RT_ERROR;
    }

    *time = ((uint16_t)buf[0] << 8) + buf[1];

    return RT_EOK;
}

rt_err_t rrh62000_auto_clean_time_set(struct rt_i2c_bus_device *bus, uint8_t time)
{
    rt_uint8_t buf[1];

    if(time > 60)
    {
        time = 60;
    }
    buf[0] = time;

    if(rrh62000_write(bus, 0x5C, buf, 1) != RT_EOK) {
        return -RT_ERROR;
    }

    return RT_EOK;
}

rt_err_t rrh62000_auto_clean_time_get(struct rt_i2c_bus_device *bus, uint8_t *time)
{
    rt_uint8_t buf[1];

    if(rrh62000_read(bus, 0x5C, buf, 1) != RT_EOK) {
        return -RT_ERROR;
    }

    *time = buf[0];

    return RT_EOK;
}

rt_err_t rrh62000_fan_speed_set(struct rt_i2c_bus_device *bus, uint8_t speed)
{
    rt_uint8_t buf[1];

    if(speed > 100)
    {
        speed = 100;
    }
    else if(speed < 60)
    {
        speed = 60;
    }
    buf[0] = speed;

    if(rrh62000_write(bus, RM_RRH62000_COMMAND_SPEEDFAN, buf, 1) != RT_EOK) {
        return -RT_ERROR;
    }

    return RT_EOK;
}

rt_err_t rrh62000_fan_speed_get(struct rt_i2c_bus_device *bus, uint8_t *speed)
{
    rt_uint8_t buf[1];

    if(rrh62000_read(bus, RM_RRH62000_COMMAND_SPEEDFAN, buf, 1) != RT_EOK) {
        return -RT_ERROR;
    }

    *speed = buf[0];

    return RT_EOK;
}

rt_err_t rrh62000_read_mox_resistance(struct rt_i2c_bus_device *bus, uint32_t *data)
{
    rt_uint8_t buf[4];
    if(rrh62000_read(bus, 0x71, buf, 4) != RT_EOK) {
        return -RT_ERROR;
    }

    *data  = (uint32_t)buf[0] << 24;
    *data += (uint32_t)buf[1] << 16;
    *data += (uint32_t)buf[2] << 8;
    *data += (uint32_t)buf[3] << 0;

    return RT_EOK;
}

rt_err_t rrh62000_read_uid(struct rt_i2c_bus_device *bus, struct rrh62000_uid *data)
{
    rt_uint8_t buf[6];
    if(rrh62000_read(bus, 0x72, buf, 6) != RT_EOK) {
        return -RT_ERROR;
    }

    rt_memcpy(&data->uid, buf, 6);

    return RT_EOK;
}

rt_err_t rrh62000_read_algoritm_verison(struct rt_i2c_bus_device *bus, struct rrh62000_algoversion *data)
{
    rt_uint8_t buf[3];
    if(rrh62000_read(bus, RM_RRH62000_COMMAND_ARGVER, buf, 3) != RT_EOK) {
        return -RT_ERROR;
    }

    data->major = buf[0];
    data->minor = buf[1];
    data->patch = buf[2];

    return RT_EOK;
}

rt_err_t rrh62000_read_TVOC_sensor_clean_status(struct rt_i2c_bus_device *bus, rt_bool_t *isComplete)
{
    rt_uint8_t buf[1];
    if(rrh62000_read(bus, RM_RRH62000_COMMAND_CSTATUS, buf, 1) != RT_EOK) {
        return -RT_ERROR;
    }

    *isComplete = buf[0];

    return RT_EOK;
}

rt_err_t rrh62000_read_firmware_verison(struct rt_i2c_bus_device *bus, struct rrh62000_firmwareversion *data)
{
    rt_uint8_t buf[2];
    if(rrh62000_read(bus, RM_RRH62000_COMMAND_FWVAR, buf, 2) != RT_EOK) {
        return -RT_ERROR;
    }

    data->major = buf[0];
    data->minor = buf[1];

    return RT_EOK;
}

rrh_62000.h

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

typedef struct st_rm_air_sensor_single_data
{
    uint32_t integer_part;             ///< Integer part of sensor data.
    uint32_t decimal_part;             ///< Decimal part of sensor data.
} rm_air_sensor_single_data_t;

/** AIR SENSOR data block */
struct rrh62000_data
{
    uint32_t status;
    rm_air_sensor_single_data_t nc_0p3;      ///< Number concentration of particle size 0.3 um - 10 um [1/cm3]
    rm_air_sensor_single_data_t nc_0p5;      ///< Number concentration of particle size 0.5 um - 10 um [1/cm3]
    rm_air_sensor_single_data_t nc_1;        ///< Number concentration of particle size 1 um - 10 um [1/cm3]
    rm_air_sensor_single_data_t nc_2p5;      ///< Number concentration of particle size 2.5 um - 10 um [1/cm3]
    rm_air_sensor_single_data_t nc_4;        ///< Number concentration of particle size 4 um - 10 um [1/cm3]
    rm_air_sensor_single_data_t pm1_1;       ///< Mass concentration of particle size 0.3 um - 1 um with reference to KCl particle [um/cm3]
    rm_air_sensor_single_data_t pm2p5_1;     ///< Mass concentration of particle size 0.3 um - 2.5 um with reference to KCl particle [um/cm3]
    rm_air_sensor_single_data_t pm10_1;      ///< Mass concentration of particle size 0.3 um - 10 um with reference to KCl particle [um/cm3]
    rm_air_sensor_single_data_t pm1_2;       ///< Mass concentration of particle size 0.3 um - 1 um with reference to cigarette smoke [um/cm3]
    rm_air_sensor_single_data_t pm2p5_2;     ///< Mass concentration of particle size 0.3 um - 2.5 um with reference to cigarette smoke [um/cm3]
    rm_air_sensor_single_data_t pm10_2;      ///< Mass concentration of particle size 0.3 um - 10 um with reference to cigarette smoke [um/cm3]
    rm_air_sensor_single_data_t temperature; ///< Temperature [Celsius]
    rm_air_sensor_single_data_t humidity;    ///< Humidity [%RH]
    rm_air_sensor_single_data_t tvoc;        ///< Total volatile organic compounds (TVOC) concentrations [mg/m3]
    rm_air_sensor_single_data_t eco2;        ///< Estimated carbon dioxide (eCO2) level [ppm]
    rm_air_sensor_single_data_t iaq;         ///< Indoor Air Quality level according to UBA
    rm_air_sensor_single_data_t rel_iaq;     ///< Relative IAQ
};

rt_err_t rrh62000_read_measured_value(struct rt_i2c_bus_device *bus, struct rrh62000_data *data);
rt_err_t rrh62000_read_data_status(struct rt_i2c_bus_device *bus, rt_bool_t *isDataReady);
rt_err_t rrh62000_sleep_set(struct rt_i2c_bus_device *bus, rt_bool_t isSleep);
rt_err_t rrh62000_sleep_get(struct rt_i2c_bus_device *bus, rt_bool_t *isSleep);
rt_err_t rrh62000_start_dust_cleaning(struct rt_i2c_bus_device *bus);
rt_err_t rrh62000_reset(struct rt_i2c_bus_device *bus);
rt_err_t rrh62000_moving_average_set(struct rt_i2c_bus_device *bus, uint8_t time);
rt_err_t rrh62000_moving_average_get(struct rt_i2c_bus_device *bus, uint8_t *time);
rt_err_t rrh62000_clean_interval_time_set(struct rt_i2c_bus_device *bus, uint16_t time);
rt_err_t rrh62000_clean_interval_time_get(struct rt_i2c_bus_device *bus, uint16_t *time);
rt_err_t rrh62000_auto_clean_time_set(struct rt_i2c_bus_device *bus, uint8_t time);
rt_err_t rrh62000_auto_clean_time_get(struct rt_i2c_bus_device *bus, uint8_t *time);
rt_err_t rrh62000_fan_speed_set(struct rt_i2c_bus_device *bus, uint8_t speed);
rt_err_t rrh62000_fan_speed_get(struct rt_i2c_bus_device *bus, uint8_t *speed);
rt_err_t rrh62000_read_mox_resistance(struct rt_i2c_bus_device *bus, uint32_t *data);

struct rrh62000_uid{
    char uid[6];
};

rt_err_t rrh62000_read_uid(struct rt_i2c_bus_device *bus, struct rrh62000_uid *data);

struct rrh62000_algoversion{
    char major;
    char minor;
    char patch;
};

rt_err_t rrh62000_read_algoritm_verison(struct rt_i2c_bus_device *bus, struct rrh62000_algoversion *data);
rt_err_t rrh62000_read_TVOC_sensor_clean_status(struct rt_i2c_bus_device *bus, rt_bool_t *isComplete);

struct rrh62000_firmwareversion{
    char major;
    char minor;
};

rt_err_t rrh62000_read_firmware_verison(struct rt_i2c_bus_device *bus, struct rrh62000_firmwareversion *data);

drv_rrh62000.c

#include <drivers/sensor.h>
#include "hal_data.h"
#include "rrh62000.h"

struct sensor_device {
    rt_bool_t openCount;
    struct rt_i2c_bus_device * dev;
    struct rrh62000_data data;
};

static rt_ssize_t _get_data(rt_sensor_t sensor, struct rt_sensor_data *data)
{
    struct sensor_device *dev = sensor->parent.user_data;
    rt_bool_t isDataReady = RT_FALSE;

    if (sensor->info.type == RT_SENSOR_CLASS_TEMP)
    {
        if((rrh62000_read_data_status(dev->dev, &isDataReady) == RT_EOK) && (isDataReady))
        {
            rrh62000_read_measured_value(dev->dev, &dev->data);
        }

    }

    if (sensor->info.type == RT_SENSOR_CLASS_TEMP)
    {
        data->data.temp = (dev->data.temperature.integer_part << 16) + dev->data.temperature.decimal_part;
        data->timestamp = rt_sensor_get_ts();
        return 1;
    }
    
    return 0;
}

static rt_ssize_t fetch_data(struct rt_sensor_device *sensor, void *buf, rt_size_t len)
{
    RT_ASSERT(buf);

    if (sensor->config.mode == RT_SENSOR_MODE_POLLING)
        return _get_data(sensor, buf);
    else
        return 0;
}

static rt_err_t _set_power(struct rt_sensor_device *sensor, void *args)
{
    struct sensor_device *dev = sensor->parent.user_data;
    rt_uint8_t power = *(uint8_t *)args;
    //fsp_err_t ret;
    rt_err_t ret;
    rt_bool_t isTVOCCLean = RT_FALSE;
    int count = 70; // 70s

    if(power == RT_SENSOR_POWER_DOWN)
    {
        if(dev->openCount != 0)
        {
            dev->openCount--;
        }
    }
    else
    {
        if(dev->openCount == 0)
        {
            do
            {
                if(rrh62000_read_TVOC_sensor_clean_status(dev->dev, &isTVOCCLean) == RT_EOK)
                {
                    if(isTVOCCLean == RT_FALSE)
                    {
                        rt_thread_mdelay(1000);
                        count--;
                    }
                }
            }while((isTVOCCLean == RT_FALSE) && (count--));

            if(count == 0)
            {
                goto RET;
            }

            ret = rrh62000_reset(dev->dev);
            if(ret != RT_EOK)
            {
                rt_kprintf("open failed %d\n\r",ret);
                goto RET;
            }
            

            rt_thread_mdelay(1000);

            ret = rrh62000_moving_average_set(dev->dev, 1);
            ret = rrh62000_fan_speed_set(dev->dev, 60);
        }
        dev->openCount++;
    }

    return RT_EOK;

RET:
    return -RT_ERROR;
}

static rt_err_t control(struct rt_sensor_device *sensor, int cmd, void *args)
{
    rt_err_t result = RT_EOK;
    
    switch (cmd)
    {
        case RT_SENSOR_CTRL_GET_ID:
            // TODO:  get device id
            // result = xxxx(sensor, args);
            break;
        case RT_SENSOR_CTRL_GET_INFO:
            // TODO:  get info
            // result = xxxx(sensor, args);
            break;
        case RT_SENSOR_CTRL_SET_RANGE:
            // TODO: set test range
            // result = xxxx(sensor, args);
            break;
        case RT_SENSOR_CTRL_SET_ODR:
            // TODO: set frequency
            // result = xxxx(sensor, args);
            break;
        case RT_SENSOR_CTRL_SET_MODE:
            // TODO: set work mode
            // result = xxxx(sensor, args);
            break;
        case RT_SENSOR_CTRL_SET_POWER:
            // TODO: set power mode
            result = _set_power(sensor, args);
            break;

        case RT_SENSOR_CTRL_SELF_TEST:
            // TODO: process self test
            // result = xxxx(sensor);
            break;
        default:
            return -RT_ERROR;
    }
    
    return result;
}

static struct rt_sensor_ops sensor_ops =
{
    fetch_data,
    control
};

struct sensor_device * rrh62000_param_init(void)
{
    struct sensor_device *dev;
    struct rrh62000_firmwareversion fwVersion;
    struct rrh62000_algoversion algoVersion;

    dev = rt_calloc(1, sizeof(struct sensor_device));
    if(!dev)
    {
        goto exit;
    }
    rt_memset(dev, 0x00, sizeof(struct sensor_device));
    dev->dev = (struct rt_i2c_bus_device *)rt_device_find("i2c1");
    if(dev->dev == RT_NULL)
    {
        goto exit;
    }


    if(rrh62000_read_firmware_verison(dev->dev, &fwVersion) != RT_EOK)
    {
        goto exit;
    }

    if(rrh62000_read_algoritm_verison(dev->dev, &algoVersion) != RT_EOK)
    {
        goto exit;
    }

    rt_kprintf("rrh62000 firmware version %d.%d\n\r", fwVersion.major, fwVersion.minor);
    rt_kprintf("rrh62000 algoritm version %d.%d.%d\n\r", algoVersion.major, algoVersion.minor, algoVersion.patch);

    return dev;

exit:
    if(dev)
        rt_free(dev);
    return RT_NULL;
}

int rt_hw_init(const char *name, struct rt_sensor_config *cfg)
{
    rt_int8_t result;
    rt_sensor_t sensor = RT_NULL; 
    struct sensor_device *dev;

    dev = rrh62000_param_init();
    if(dev == RT_NULL)
    {
        goto __exit;
    }
    
    /* sensor register */
    sensor = rt_calloc(1, sizeof(struct rt_sensor_device));
    if (sensor == RT_NULL)
        goto __exit;
    
    sensor->info.type       = RT_SENSOR_CLASS_TEMP; // Set real type
    sensor->info.vendor     = RT_SENSOR_VENDOR_UNKNOWN; // Set real vendor
    sensor->info.model      = name;  // set real model name
    sensor->info.unit       = RT_SENSOR_UNIT_DCELSIUS; // set to real unit flag
    sensor->info.intf_type  = RT_SENSOR_INTF_I2C; // Set interface type
    sensor->info.range_max  = 0xFFFF; // Set to range max
    sensor->info.range_min  = 0x0000; // Set to range min
    sensor->info.period_min = 50; // Set frequency

    rt_memcpy(&sensor->config, cfg, sizeof(struct rt_sensor_config));
    sensor->ops = &sensor_ops;

    result = rt_hw_sensor_register(sensor, name, RT_DEVICE_FLAG_RDONLY, dev);
    if (result != RT_EOK)
    {
        goto __exit;
    }

    return RT_EOK;

__exit:
    if (sensor)
        rt_free(sensor);
    if(dev)
        rt_free(dev);
    return -RT_ERROR;
}

static int rrh62000_device_register(void)
{
    struct rt_sensor_config      cfg = {
        .mode = RT_SENSOR_MODE_POLLING,
        .power = RT_SENSOR_POWER_DOWN,
    };

    rt_hw_init("rrh62000", &cfg);

    return RT_EOK;

}
INIT_DEVICE_EXPORT(rrh62000_device_register);

#if 1
#define RRH_TEMP_DEVICE_NAME "temp_rrh"
void rrh6200_temp_read(void)
{
    rt_device_t dev = rt_device_find(RRH_TEMP_DEVICE_NAME);
    rt_err_t result;
    rt_uint32_t len;
    struct rt_sensor_data data;

    if(!dev)
    {
        rt_kprintf("No device name %s\n\r", RRH_TEMP_DEVICE_NAME);
        return;
    }
    result = rt_device_open(dev,RT_DEVICE_FLAG_RDONLY);
    if(result != RT_EOK)
    {
        rt_kprintf("Open %s Fail\n\r", RRH_TEMP_DEVICE_NAME);
        return;

    }
    
    len = rt_device_read(dev, 0 ,&data,1);
    if(len)
    {
        rt_kprintf("Temp %d.%d \n\r", data.data.temp >> 16, data.data.temp & 0x0000FFFF);
    }

    result = rt_device_close(dev);
    if(result != RT_EOK)
    {
        rt_kprintf("Close %s Fail\n\r", RRH_TEMP_DEVICE_NAME);
        return;

    }

}
MSH_CMD_EXPORT(rrh6200_temp_read, rrh62000 temprate sample);
#endif

编译选项修改

      虽然代码已经添加到目录里了,但是工程并不会编译,此时需要我们手动修改脚本,让工程自动将这些文件导入工程,具体修改如下:

bsp\renesas\ebf_qi_min_6m5\board\Kconfig

2.jpgbsp\renesas\libraries\HAL_Drivers\SConscript

2.jpg

menuconfig配置

     上面添加完毕后,我们还需要去menuconfig中将此传感器启用,具体修改方法如下:

2.jpg

     配置完毕后保存,并输入 scons --target=mdk5生成新工程并编译

运行结果

\ | /
- RT -     Thread Operating System
 / | \     5.2.0 build Nov 28 2024 22:19:37
 2006 - 2024 Copyright by RT-Thread team
[I/I2C] I2C bus [i2c1] registered
rrh62000 firmware version 1.0
rrh62000 algoritm version 3.2.0
[I/sensor] rt_sensor[temp_rrh62000] init success

Hello RT-Thread!
msh >r
reboot
rrh6200_temp_read
msh >rr
rrh6200_temp_read
msh >rrh6200_temp_read
Temp 0.0
msh >rrh6200_temp_read
Temp 0.0
msh >rrh6200_temp_read
Temp 0.0
msh >rrh6200_temp_read
Temp 22.17
msh >rrh6200_temp_read
Temp 22.17
msh >rrh6200_temp_read
Temp 22.17
msh >rrh6200_temp_read
Temp 22.12
msh >rrh6200_temp_read
Temp 22.12
msh >rrh6200_temp_read
Temp 22.12
msh >rrh6200_temp_read
Temp 22.12
msh >rrh6200_temp_read
Temp 22.7
msh >rrh6200_temp_read
Temp 22.7
msh >rrh6200_temp_read
Temp 22.7
msh >rrh6200_temp_read
Temp 22.7
msh >rrh6200_temp_read
Temp 22.3
msh >rrh6200_temp_read
Temp 22.3

后续计划

   目前仅仅是初步把温度传感器部分打通了,后续将陆续把剩余的RTT支持的传感器类型全打通。另外,由于搞得比较匆忙,其实代码封装很多地方都不太合适,还需要进一步完善,完善后看怎么推到rtt的软件包里面去。






关键词: rrh6200     换取     逻辑     分析仪     启明     驱动     S    

专家
2024-11-29 00:11:03     打赏
2楼

感谢楼主分享


专家
2024-11-29 08:10:51     打赏
3楼

感谢分享


工程师
2024-11-29 08:40:13     打赏
4楼

学习了。


工程师
2024-11-29 09:51:24     打赏
5楼

666666


高工
2024-11-29 17:03:00     打赏
6楼

这经验分享真棒!

我怎么感觉还是自己写驱动实现得快呢


共6条 1/1 1 跳转至

回复

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