MTK_SensorHub

目录

一、简介

二、架构介绍

三、sensor driver

一、重要结构体

二、宏定义介绍

三、i2c操作函数

四、重要组成部分

一、传感器初始化

二、注册广播消息

三、注册传感器设备

四、注册服务器

五、数据处理

四、sensor manger

一、重要结构体

二、调用流程

一、RTOS发送数据

二、RTOS接收数据

五、kernel


一、简介

        MTK Sensor Hub 框架是一个专门用于管理和处理智能手机中各类传感器数据的协处理器系统,旨在提高传感器数据处理效率和降低功耗。

        在现代智能手机中,传感器起着至关重要的作用,它们能够提供诸如加速度、陀螺仪、磁力、气压、湿度、压力、光照、近程和心率等多种物理数据的测量。然而,随着传感器数量和使用频率的增加,其对电能的消耗也相应增加。为了优化手机的电源使用效率,谷歌和联发科(MediaTek Inc., MTK)分别开发了CHRE(Context Hub Runtime Environment)和SCP(Sensor Control Processor),以实现更高效的传感器控制。

        MTK Sensor Hub框架的核心是SCP和CHRE。SCP是一种协处理器,专门用于处理与音频和传感器相关的功能以及其他客制化需求,它采用freeRTOS作为操作系统。而CHRE则是一种事件驱动的体系结构,可以视为一个轻量级、实时性的操作系统,其主要职能是处理传感器相关的操作。在这种架构下,CHRE的应用负责实现具体的传感器驱动程序,包括sensorInfo、sensorOps以及处理event的handler模块。

        那么freeRTOS系统怎么与Android系统进行通讯呢?首先,我们需要了解SCP和CHRE之间的关系。CHRE是一个中间件,负责管理SCP上的各种服务,包括传感器、音频等。CHRE通过IPC(进程间通信)与安卓系统进行通信。具体来说,CHRE提供了一组API,供安卓系统调用,以获取SCP上的服务。这些API包括打开/关闭服务、设置/获取服务参数等功能。接下来,我们来看freeRTOS如何与安卓系统通信。在SCP上运行的freeRTOS系统中,有一个名为“sensor hub driver”的驱动程序。这个驱动程序负责将SCP上的传感器数据传输到CHRE。当SCP上的传感器产生数据时,sensor hub driver会将这些数据封装成特定的格式,并通过SPI(串行外设接口)或I2C(两线式串行总线)等通信协议发送给CHRE。CHRE收到这些数据后,会对其进行解析和处理,然后将处理后的数据通过IPC发送给安卓系统。安卓系统收到这些数据后,会根据需要进行进一步的处理,例如更新UI界面、触发其他应用程序等。

二、架构介绍

  1. 应用层:开发者通过获取SensorManager服务并注册监听器来简单地调用传感器,此后传感器信息便会通过回调接口上报。
  2. Framework层:该层为开发者提供了与传感器交互的抽象接口,实际工作中会获取SystemSensorManager服务,这是专门为上层注册接口的类。
  3. JNI层:这一层提供了从Java到native代码的转换,使得java框架能与下层的HAL进行交互。
  4. HAL层:MTK的HAL层实现了对多个sensor的控制处理,其中HfManager扮演了重要角色,负责管理不同sensor的控制流程。
  5. 内核层:此层提供了sensor数据流的通道,并与硬件相关的驱动紧密相连。
  6. SCP/CHRE层:在这一层,所有的sensor driver实现都必须遵循CHRE app的设计框架,确保统一处理control和data flow

模块名称

功能

代码路径

hal层列表

hal层申明添加

vendor\mediatek\proprietary\hardware\sensor\2.0\hal\SensorListV2.cpp

sensor型号

对应sensor下选择sensor IC型号

vendor\mediatek\proprietary\tinysys\scp\project\RV55_A\chip>\项目>\inc\overlay_sensor.h

算法库

有些sensor标定需要算法支持如地磁

放置路径:vendor/mediatek/proprietary/tinysys/scp/middleware/sensorhub/algos/RV55_A/calibration

配置编译范围

配置编译范围

配置路径:vendor\mediatek\proprietary\tinysys\scp\project\RV55_A\chip>\platform\features\sensorhub.mk(chre.mk)

config配置

配置项目是否支持

编译配置:vendor\mediatek\proprietary\tinysys\scp\project\RV55_A\chip>\项目>\project.mk

sensor dts配置

配置sensor总线名称及地址信息

配置路径:vendor/mediatek/proprietary/tinysys/scp/project/RV55_A/chip>/项目>/sensordts.c

sensor driver

sensor 的驱动代码,被 sensor

hub manage 调用。

sensorhub3.0架构:vendor/mediatek/proprietary/tinysys/scp/middleware/sensorhub/drivers/physical

sensorhub2.0架构:

vendor/mediatek/proprietary/tinysys/scp/middleware/contexthub/MEMS_Driver

注:使用算法库时,需要将算法库路径添加至sensorhub.mk文件中的LIBFLAGS项。

三、sensor driver

一、重要结构体

struct i2c_regmap {
    uint8_t bus_id;
    uint8_t addr;
    uint8_t *tx_buf;
    uint8_t *rx_buf;
    size_t len;
    uint32_t speed_hz;
};


struct broadcast_receiver {
    struct broadcast_handle handle;    //操作句柄
    void (*receive)(void *, uint8_t, const void *);    //回调函数用于处理接收的广播内容
    void *private_data;
};

//确认传感器的ID
enum OVERLAY_WS {
    OVERLAY_WORK_00 = 0,
    OVERLAY_WORK_01,
    OVERLAY_WORK_02,
    OVERLAY_WORK_03,
    OVERLAY_WORK_04,
    OVERLAY_WORK_05,
    OVERLAY_WORK_06,
    OVERLAY_WORK_07,
    OVERLAY_WORK_08,
    OVERLAY_WORK_09,
    NUM_OVERLAY_WORK,

    /*for sensor start */
    /*acceleremter and gyroscope sensor */
    OVERLAY_ID_ACCGYRO = OVERLAY_WORK_00,
    /*magnetometer sensor */
    OVERLAY_ID_MAG = OVERLAY_WORK_01,
    /*light and proximity sensor */
    OVERLAY_ID_ALSPS = OVERLAY_WORK_02,
    /*barometer sensor */
    OVERLAY_ID_BARO = OVERLAY_WORK_03,
    /*light and proximity sensor secondary */
    OVERLAY_ID_ALSPS_SECONDARY = OVERLAY_WORK_04,
    /*sar sensor */
    OVERLAY_ID_SAR = OVERLAY_WORK_05,
    /*cali fusion lib*/
    OVERLAY_ID_CALIFUSION = OVERLAY_WORK_06,
    /*for sensor end */
};
//确认任务等级
enum broadcast_tasks {
    principal,
    deputy,
    vice,
    MAX_BROADCAST_TASK,
};

struct sensor_device {
    struct list_t list;    //记录传感器的信息vendor,唤醒模式,传感器类型,数据上报模式,等
    const struct broadcast_receiver *receiver;
    const struct sensor_info *support_list;
    unsigned int support_size;
    struct sensor_manager *manager;
    void *private_data;
    char *name;
};
//光距感eg:
    static const struct sensor_info stk3acx_list[] = 
{
    {
        .sensor_type = SENSOR_TYPE_LIGHT,
        .wakeup_mode = NON_WAKEUP_MODE,
        .report_mode = ONCHANGE_REPORT_MODE,
        .down_sample = NON_DOWN_SAMPLE_MODE,
        .name = ALS_NAME,
        .vendor = VENDOR_NAME,
    },
    {
        .sensor_type = SENSOR_TYPE_PROXIMITY,
        .wakeup_mode = WAKEUP_MODE,
        .report_mode = ONCHANGE_REPORT_MODE,
        .down_sample = NON_DOWN_SAMPLE_MODE,
        .name = PS_NAME,
        .vendor = VENDOR_NAME,
    },
};

二、宏定义介绍

//根据传感器中OVERLAY_DECLARE传入的参数分配一段内存,
#define OVERLAY_DECLARE_V2(ovl_name, ovl_section, ovl_data, ovl_func) \
    void overlay_construct_##ovl_name(void) __attribute__((section(".overlay_construct"))); \
    struct overlay_init_s overlay_init_##ovl_name __attribute__((section(".overlay_init"))) = { \
        .overlay_section = ovl_section, \
        .construct = overlay_construct_##ovl_name, \
        .data = (void *)ovl_data, \
        .func = (void *)ovl_func, \
    }; \
    void overlay_construct_##ovl_name(void) { \
        extern char __load_start_##ovl_name; \
        extern char __load_stop_##ovl_name; \
        extern struct overlay_init_s overlay_init_##ovl_name; \
        overlay_init_##ovl_name.name = #ovl_name; \
        overlay_init_##ovl_name.overlay_load_start = &__load_start_##ovl_name; \
        overlay_init_##ovl_name.overlay_load_end = &__load_stop_##ovl_name; \
    }

#define GET_OVERLAY_DECLARE_MACRO(_1, _2, _3, _4, NAME, ...) NAME
#define OVERLAY_DECLARE(...) GET_OVERLAY_DECLARE_MACRO(__VA_ARGS__, OVERLAY_DECLARE_V2, OVERLAY_DECLARE_V1)(__VA_ARGS__)

//eg:
    OVERLAY_DECLARE(mmc5603, OVERLAY_ID_MAG, deputy, init_mmc5603);

三、i2c操作函数

使用regmap机制来管理I2C\SPI,将I2C, SPI驱动做了一次重构,把I/O读写的重复逻辑在regmap中实现。

//根据设备树信息获取i2c设备地址,总线编号,传输速度等注册regmap
 
int i2c_regmap_request(struct i2c_regmap *regmap);    
 //regmap写操作
 int i2c_regmap_write(struct i2c_regmap *regmap, uint8_t reg, uint8_t data);
 //regmap读操作
 int i2c_regmap_read(struct i2c_regmap *regmap, uint8_t reg, size_t len, uint8_t **buf);

四、重要组成部分

一、传感器初始化
OVERLAY_DECLARE(****, OVERLAY_ID_MAG, deputy, init_****);    //注册传感器,参数:传感器名称,传感器类型,task等级,回调函数

int init_****(uint8_t task, uint8_t id);    //会穿task句柄,ID用于注册广播接收
二、注册广播消息
//注册广播接收,broadcast_receiver结构体中包含回调函数(用于处理sensor manger发送的消息),传感器初始化传入的task,ID,私有数据
int broadcast_receiver_register(const struct broadcast_receiver *br)    //注册广播接收
{
    broadcast_set_handle(&br->handle);
    return 0;
}
三、注册传感器设备
//注册传感器设备,sensor_device中包含设备信息,如:传感器类型,数据上传方式,是否唤醒cpu等,详见sensor_device->sensor_info数组
//并将传入broadcast_receiver放置sensor_device结构体中,关联在一起
int sensor_device_register(struct sensor_device *dev, const struct broadcast_receiver *receiver);
四、注册服务器
int sensor_client_register(struct sensor_client *client, const struct broadcast_receiver *receiver)
五、数据处理

在注册广播消息时,注册了回调函数,将接收到符合传感器类型的消息时,将会调用。根据不同的事件类型调用不同的函数,示例如下

tatic void mxc4005_receive(void *private_data, uint8_t event_type, const void *event_data)
{
    const struct sensor_control *control = event_data;
    const struct sensor_bytestream *bstr = event_data;
    struct mxc4005_device *dev = private_data;

    switch (event_type) {
    case EVENT_SAMPLE://193
        mxc4005_sample(dev);
        break;
    case EVENT_ENABLE://9
        mxc4005_enable(dev, control);
        break;
    case EVENT_DISABLE://8
        mxc4005_disable(dev);
        break;
    case EVENT_FLUSH://10
        mxc4005_flush(dev);
        break;
    case EVENT_ENABLE_RAW://15
        mxc4005_raw(dev, true);
        break;
    case EVENT_DISABLE_RAW://16
        mxc4005_raw(dev, false);
        break;
    case EVENT_CONFIG://12
        mxc4005_config(dev, bstr);
        break;
    case EVENT_CALI://11
        mxc4005_cali(dev);
        break;
    case EVENT_DEBUG:
        logi("debug\n");
        break;
    case EVENT_READY:
            logi("ready\n");
        break;
    }
}

在通过regmap读取到传感器详细信息后调用sensor_single_data_alloc申请地址,在将数据拷贝到这个地址中,最后调用sensor_broadcast函数。

struct sensor_single_data * sensor_single_data_alloc(uint8_t sensor_type);
//eg:  dbuf = sensor_single_data_alloc(SENSOR_TYPE_ACCELEROMETER);
//数据拷贝    memcpy(dbuf->data[0].ivalue, ivalue, len);
int sensor_broadcast(uint8_t event_type, void *event_data, void (*free_func)(uint8_t, void *));
//eg: sensor_broadcast(EVENT_CALI_DATA, dbuf, sensor_single_data_free);

四、sensor manger

一、重要结构体
struct sensor_core {
    spinlock_t client_lock;
    struct list_t client_list[MAX_BROADCAST_TASK];

    spinlock_t state_lock;
    struct sensor_state state[MAX_SENSOR_TYPE];

    spinlock_t manager_lock; // lock for another task find manager
    struct sensor_manager *manager_list[MAX_SENSOR_TYPE];
    struct list_t device_list;   //存放注册的设备信息
};

struct sensor_manager {
    const struct sensor_device *dev;
    struct sensor_core *core;
};

struct sensor_device {
    struct list_t list;
    const struct broadcast_receiver *receiver;    //调用sensor_device_register是放置receiver,存放操作句柄ID等
    const struct sensor_info *support_list;
    unsigned int support_size;
    struct sensor_manager *manager;    //调用sensor_device_register时,申请空间,manager->dev,指向sensor_device
    void *private_data;
    char *name;
};

struct sensor_client {
    struct list_t list;
    const struct broadcast_receiver *receiver;
    spinlock_t request_lock;
    struct sensor_state request[MAX_SENSOR_TYPE];
    struct sensor_core *core;
    char *name;
};
二、调用流程

mtk对sensor数据的采集采用freeRTOS作为操作系统。

文件路径:vendor\mediatek\proprietary\tinysys\scp\project\RV55_A\mt6789\platform\src\main.c

int main(void)
{
........
#ifdef CFG_SENSORHUB_SUPPORT
    sensorhub_init();
#endif
........
}

文件路径:vendor\mediatek\proprietary\tinysys\scp\middleware\sensorhub\core\init.c

void sensorhub_init(void)
{
    sensorhub_percluster_init();    //注册IPC接口用于freeRTOS与AP通信
    sensorhub_main_init();    //注册sensorhub相关
    sensorhub_secondary_init();    //
}

static void sensorhub_main_init(void)
{
    if (LOCAL_CLUSTER_ID() == 0) {
        if (LOCAL_CPU_ID() == 0) {
            sensor_comm_init();    //创建链表,创建任务,初始化锁,注册一些通知链
            scp_ready_init();    //创建通知链使用原子操作来通知管理
            sensor_list_init();    //注册一些链表的通知函数
            broadcast_init();   //注册广播
            sensor_manager_init();    //重点函数
            rpc_init();    
            dts_init();
            ipc_external_init();
            module_core_init();
            timesync_init();
            host_suspend_init();
            custom_cmd_init();
            power_manager_init();
        }
    }
}

文件路径:vendor\mediatek\proprietary\tinysys\scp\middleware\sensorhub\core\sensor_manager.c

void sensor_manager_init(void)
{
    fatal(MAX_SENSOR_EVENT <= EVENT_SENSOR_END);

    init_sensor_core(&sens_core);    //初始化队列,此队列用于传感器加载注册

    broadcast_dispatch_register(SENSOR_HANDLER, sensor_dispatch, NULL);    //注册发送广播回调函数
    broadcast_rescue_register(SENSOR_HANDLER, sensor_rescue, NULL);    //注册接收广播函数
    broadcast_notifier_register(&sensor_notifier);    //注册广播通知链

    sens_mgr_pool = MEM_POOL_INIT(sens_mgr_mem, struct sensor_manager, MAX_SENSOR_MANAGER_NUM);
    sens_ctrl_pool = MEM_POOL_INIT(sens_ctrl_mem, struct sensor_control, MAX_SENSOR_CONTROL_NUM);
    sens_single_pool = MEM_POOL_INIT(sens_single_mem, struct sensor_single_data, MAX_SENSOR_SINGLE_DATA_NUM);
    sens_multi_pool = MEM_POOL_INIT(sens_multi_mem, struct sensor_multi_data, MAX_SENSOR_MULTI_DATA_NUM);
    sens_super_single_pool = MEM_POOL_INIT(sens_super_single_mem, struct sensor_super_single_data,
        MAX_SENSOR_SUPER_DATA_NUM);

    down_sample_init();
    debug_file_init();
}

传感器注册广播接收



int broadcast_receiver_register(const struct broadcast_receiver *br)    //注册广播接收
{
    broadcast_set_handle(&br->handle);
    return 0;
}

void broadcast_set_handle(const struct broadcast_handle *handle)
{
    uint8_t task, id;

    fatal(handle);    //一个断言语句,用于检查变量,如果不成立,程序将抛出一个异常或终止执行。这通常用于调试和验证代码的正确性。
    task = handle->task;
    id = handle->id;
    if (task < MAX_BROADCAST_TASK && id < MAX_BROADCAST_HANDLE_NUM) {
        if (!bc_handle[task][id])
            bc_handle[task][id] = handle;
        fatal(bc_handle[task][id] == handle)
    }
}
//注册后会放置这个二维数组中bc_handle,用于存储指向broadcast_handle结构体的指针
static const struct broadcast_handle *bc_handle[MAX_BROADCAST_TASK][MAX_BROADCAST_HANDLE_NUM];

注册device

int sensor_device_register(struct sensor_device *dev, const struct broadcast_receiver *receiver)
{
    unsigned int i = 0;
    unsigned long flags = 0;
    const struct sensor_info *info = NULL;
    struct sensor_manager *manager = NULL;

    if (!atomic_read(&sens_register_permit) ||
            !dev || !receiver || !dev->name ||
            !dev->support_list || !dev->support_size)
        return -EINVAL;

    manager = mem_pool_alloc(sens_mgr_pool);
    fatal(manager);

    manager->dev = dev;    //此处关联了,client,manager,core结构体
    manager->core = &sens_core;    //static struct sensor_core sens_core;
    dev->receiver = receiver;
    dev->manager = manager;
    list_init(&dev->list);

    /* hold manager_lock for another task find manager */
    flags = spinlock_lock_irqsave(&manager->core->manager_lock);
    for (i = 0; i < dev->support_size; ++i) {
        info = &dev->support_list[i];
        fatal(info->sensor_type < MAX_SENSOR_TYPE);
        fatal(info->name);
        fatal(info->vendor);
        manager->core->manager_list[info->sensor_type] = manager;
    }
    list_add_tail(&manager->core->device_list, &dev->list);
    spinlock_unlock_irqrestore(&manager->core->manager_lock, flags);

    return 0;
}

注册服务器

int sensor_client_register(struct sensor_client *client, const struct broadcast_receiver *receiver)
{
    uint8_t task = 0;
    unsigned long flags = 0;

    if (!atomic_read(&sens_register_permit) ||
            !client || !receiver || !client->name)
        return -EINVAL;

    list_init(&client->list);
    client->receiver = receiver;

    spinlock_init(&client->request_lock);
    client->core = &sens_core;

    task = receiver->handle.task;
    fatal(task < ARRAY_SIZE(client->core->client_list));

    flags = spinlock_lock_irqsave(&client->core->client_lock);
    list_add_tail(&client->core->client_list[task], &client->list);    //讲服务添加至static struct sensor_core sens_core
    spinlock_unlock_irqrestore(&client->core->client_lock, flags);

    return 0;
}

传感器会调用此函数传递数据处理。

int sensor_broadcast(uint8_t event_type, void *event_data, void (*free_func)(uint8_t, void *))
{
    int ret = 0;
    unsigned int i = 0;
    unsigned long flags = 0;
    bool broadcast = false, has_request = false;
    struct sensor_header *header = (struct sensor_header *)event_data;
    uint8_t sensor_type = header->sensor_type;
    struct sensor_core *core = &sens_core;
    struct list_t *curr = NULL, *tmp = NULL;
    struct sensor_client *client = NULL;

    flags = spinlock_lock_irqsave(&core->client_lock);
    for (i = 0; i < ARRAY_SIZE(core->client_list); ++i) {
        list_for_each_entry_safe(&core->client_list[i], curr, tmp) {
            /*
             * NOTE: each loop must reset has_request to false
             * if don't reset swtich default branch will send invalid event
             */
            has_request = false;
            client = list_entry(curr, struct sensor_client, list);
            switch (event_type) {
            case EVENT_DATA:
                has_request = client->request[sensor_type].enable;
                break;
            case EVENT_FLUSH_DATA:
                has_request = client->request[sensor_type].flush > 0;
                break;
            case EVENT_CALI_DATA:
                has_request = client->request[sensor_type].cali;
                break;
            case EVENT_BIAS_DATA:
                has_request = client->request[sensor_type].bias;
                break;
            case EVENT_TEMP_CALI_DATA:
                has_request = client->request[sensor_type].temp;
                break;
            case EVENT_SELF_TEST_DATA:
                has_request = client->request[sensor_type].test;
                break;
            case EVENT_RAW_DATA:
                has_request = client->request[sensor_type].raw;
                break;
            default:
                fatal(NULL);
                break;
            }
            if (has_request) {
                /*
                 * NOTE: must first set and after broadcast_event failed clear.
                 * if not, event_data will be used after free and system crash.
                 * task0:               task1:                   task2:
                 * broadcast_event
                 *                      bit_clear_return(free)
                 *
                 * bit_set(task1, task2)
                 *                                               bit_clear_return(crash)
                 */
                bit_set(&header->task_map, client->receiver->handle.task);
                ret = broadcast_event(&client->receiver->handle,
                    SENSOR_HANDLER, event_type, event_data, free_func, false);    //传递数据
                /*
                 * NOTE: broadcast_event not use failed_auto_free,
                 * when broadcast_event failed return, we should clear task_map.
                 */
                if (ret < 0)
                    bit_clear(&header->task_map, client->receiver->handle.task);
                /*
                 * NOTE: when has_request of client is true in one task,
                 * we must break list_for_each_entry_safe for others clients in this task,
                 * if not, event_data will be used after free and system crash.
                 */
                break;
            }
        }
    }
    /* check bit to detect free or not in spinlock */
    broadcast = !!bit_read(&header->task_map);
    spinlock_unlock_irqrestore(&core->client_lock, flags);
    /* no task require data must free event data */
    if (!broadcast && free_func && event_data)
        free_func(FORCE_FREE, event_data);
    /* must return 0 due to multi dispatcher */
    return 0;
}
一、RTOS发送数据

sensor根据接收到书指令发送AP所需的数据,会调用以下函数

文件路径:vendor\mediatek\proprietary\tinysys\scp\middleware\sensorhub\core\broadcast.c

int broadcast_event(const struct broadcast_handle *handle,
        uint8_t user_type, uint8_t event_type, void *event_data,
        void (*free_func)(uint8_t, void *), bool failed_auto_free)
{
    unsigned long flags = 0;
    struct broadcast_message *bm = NULL;
    struct broadcast_task *bt = NULL;
    bool need_wakeup = false;

    fatal(handle->task < MAX_BROADCAST_TASK &&
        handle->id < MAX_BROADCAST_HANDLE_NUM);

    if (!atomic_read(&task_ready[handle->task])) {
        /* task not ready should free event data */
        if (user_type != DEFER_HANDLER &&
                failed_auto_free && free_func && event_data)
            free_func(handle->task, event_data);
        loge("%u %u to %u fail %d\n", user_type, event_type, handle->task, -ENODEV);
        return -ENODEV;
    }

    bm = mem_pool_alloc(msg_pool);
    if (!bm) {
        /* can't alloc should free event data */
        if (user_type != DEFER_HANDLER &&
                failed_auto_free && free_func && event_data)
            free_func(handle->task, event_data);
        loge("%u %u to %u fail %d\n", user_type, event_type, handle->task, -ENOMEM);
        return -ENOMEM;
    }

    list_init(&bm->list);
    bm->user_type = user_type;
    bm->event_type = event_type;
    bm->task = handle->task;
    bm->id = handle->id;
    bm->event_data = event_data;
    bm->free_func = free_func;
    if (is_in_isr())
        bm->task_wakeup = xTaskGetTickCountFromISR();
    else
        bm->task_wakeup = xTaskGetTickCount();

    bt = &bc_task[handle->task];

    flags = spinlock_lock_irqsave(&bt->lock);
    need_wakeup = !bt->event_running;
    list_add_tail(&bt->bm_head, &bm->list);    //它将事件信息封装成消息并将其添加到相应任务的消息队列中。
    spinlock_unlock_irqrestore(&bt->lock, flags);

    if (need_wakeup)    //如果任务当前没有运行事件,函数会唤醒任务以处理新的消息。
        broadcast_wakeup(handle->task);    //果需要唤醒任务,则调用 broadcast_wakeup
    return 0;
}


static inline void broadcast_wakeup(uint8_t task)
{
    BaseType_t xTaskWoken = pdFALSE;

    if (is_in_isr()) {    //检查当前是否处于中断服务程序(ISR)中。
        xTaskWoken = pdFALSE;
        vTaskNotifyGiveFromISR(bc_task_handle[task], &xTaskWoken);    //指定的任务发送通知
        portYIELD_FROM_ISR(xTaskWoken);    //让出CPU控制权,以便其他任务有机会运行。
    } else {
        if (xTaskNotifyGive(bc_task_handle[task]) == pdFAIL)
            loge("wakeup %u %s fail\n", task, pcTaskGetName(bc_task_handle[task]));
    }
}

文件路径:vendor/mediatek/proprietary/tinysys/freertos/source/kernel/FreeRTOS/Source/tasks.c

void vTaskNotifyGiveFromISR( TaskHandle_t xTaskToNotify, BaseType_t *pxHigherPriorityTaskWoken )
二、RTOS接收数据

以下函数用于接受IPC发送的数据

//broadcast_init初始化时会调用此函数,创建任务
static void deputy_init(void)
{
    fatal(xTaskCreate(deputy_task, "DEPUTY", 1024, NULL, DEPUTY_PRI, NULL));
}

static void deputy_task(void *pvParameters)
{
    task_run(deputy, deputy_task_run);
}

static void task_run(uint8_t task, void (*second_run)(uint8_t))
{
    fatal(task < MAX_BROADCAST_TASK);

    wait_host_ready(task);

    list_init(&bc_task[task].bm_head);
    list_init(&bc_task[task].br_head);
    spinlock_init(&bc_task[task].lock);
    bc_task_handle[task] = xTaskGetCurrentTaskHandle();

    module_level_init(task);

    second_run(task);
}

static void deputy_task_run(uint8_t local)
{
    set_task_ready(local);

    /* there overlay init and register to deputy_driver list */
    while (1) {
        receive_event(local);
        if (!ulTaskNotifyTake(pdTRUE, portMAX_DELAY))
            loge("task %u wait fail\n", local);
    }
}


static int receive_event(uint8_t task)
{
    unsigned long flags = 0;
    struct broadcast_task *bt = NULL;
    struct broadcast_message *bm = NULL;
    uint32_t event_exe = 0;

    fatal(task < MAX_BROADCAST_TASK);
    task_running[task] = xTaskGetTickCount();
    bt = &bc_task[task];
    flags = spinlock_lock_irqsave(&bt->lock);
    bt->event_running = true;
    while (!list_empty(&bt->bm_head)) {
        bm = list_first_entry(&bt->bm_head, struct broadcast_message, list);
        list_delete(&bm->list);
        spinlock_unlock_irqrestore(&bt->lock, flags);
        event_start[task] = xTaskGetTickCount();
        dispatch_to(task, bm);    //重点函数
        event_end[task] = xTaskGetTickCount();
        event_exe = event_end[task] - event_start[task];
        if (event_exe > 10 / portTICK_RATE_MS /* ms */) {
            logi("id %u user_type %u event_type %u execute %ums\n",
                bm->id, bm->user_type, bm->event_type, event_exe);
            //if (bm->event_type != EVENT_SELF_TEST)
                //fatal(event_exe < 200 / portTICK_RATE_MS /* ms */);
        }
        /* must first free event_data */
        if (bm->user_type != DEFER_HANDLER && bm->free_func && bm->event_data)
            bm->free_func(task, bm->event_data);
        /* free broadcast message */
        mem_pool_free(msg_pool, bm);
        flags = spinlock_lock_irqsave(&bt->lock);
    }
    bt->event_running = false;
    spinlock_unlock_irqrestore(&bt->lock, flags);
    task_idle[task] = xTaskGetTickCount();
    return 0;
}

static void dispatch_to(uint8_t task, struct broadcast_message *bm)
{
    uint8_t user_type = bm->user_type;
    struct broadcast_dispatch *bcd = NULL;

    fatal(task < MAX_BROADCAST_TASK);
    fatal(user_type < MAX_BROADCAST_USER);
    fatal(bm->task == task);
    fatal(bm->id < MAX_BROADCAST_HANDLE_NUM);

    bcd = &bc_dispatch[user_type];
    if (bcd->dispatch)
        bcd->dispatch(task, bm, bcd->private_data);   //调用这个函数指针
}


int broadcast_dispatch_register(uint8_t index,
        int (*f)(uint8_t, const struct broadcast_message *, void *), void *private_data)
{
    if (index >= MAX_BROADCAST_USER)
        return -EINVAL;

    bc_dispatch[index].private_data = private_data;
    bc_dispatch[index].dispatch = f;        //调用此函数对函数指针赋值
    return 0;
}

//在broadcast_init时调用broadcast_dispatch_register注册广播
void broadcast_init(void)
{
.........
    broadcast_dispatch_register(PUBLIC_HANDLER, public_dispatch, NULL);
    broadcast_dispatch_register(PRIVATE_HANDLER, private_dispatch, NULL);
    broadcast_dispatch_register(DEFER_HANDLER, defer_dispatch, NULL);
    broadcast_rescue_register(PUBLIC_HANDLER, public_rescue, NULL);
    broadcast_rescue_register(PRIVATE_HANDLER, private_rescue, NULL);
    broadcast_rescue_register(DEFER_HANDLER, defer_rescue, NULL);

  ...........
}

static int public_dispatch(uint8_t task, const struct broadcast_message *bm, void *private_data)
{
    uint8_t id = 0, i = 0;
    const struct broadcast_handle *handle = NULL;
    const struct broadcast_receiver *br = NULL;
    uint32_t modules = 0;

    fatal(bm->user_type == PUBLIC_HANDLER);
    fatal(bm->event_type > EVENT_PUBLIC && bm->event_type < EVENT_PRIVATE);

    modules = module_get_modules(task);
    for (id = 0, i = 0; id < MAX_BROADCAST_HANDLE_NUM && i < modules; ++id, ++i) {
        handle = bc_handle[task][id];     //bc_handle是broadcast_receiver_register函数注册用于存放的数组,根据task ID信息获得句柄
        if (!handle)
            continue;
        br = list_entry(handle, struct broadcast_receiver, handle);    //用于遍历链表并获取指向特定元素的指针
        br->receive(br->private_data, bm->event_type, bm->event_data);   //根据句柄信息找到broadcast_receiver_register注册时的回调函数。
    }
    return 0;
}

五、kernel

文件路径:alps\kernel-5.10\drivers\misc\mediatek\sensor\2.0\sensorhub\transceiver.c

注:当配置CONFIG_MTK_SENSOR_ARCHITECTURE=2.0时,mt8797 才能支持SCP侧的sensorhub

//入口函数
module_init(transceiver_init);
static int __init transceiver_init(void)
{
    int ret = 0;
    struct transceiver_device *dev = &transceiver_dev;
...................
    memset(&dev->hf_dev, 0, sizeof(dev->hf_dev));
    dev->hf_dev.dev_name = "transceiver";
    dev->hf_dev.device_poll = HF_DEVICE_IO_INTERRUPT;
    dev->hf_dev.device_bus = HF_DEVICE_IO_ASYNC;
    dev->hf_dev.support_list = dev->support_list;
    dev->hf_dev.support_size = dev->support_size;
    dev->hf_dev.enable = transceiver_enable;
    dev->hf_dev.batch = transceiver_batch;
    dev->hf_dev.flush = transceiver_flush;
    dev->hf_dev.calibration = transceiver_calibration;
    dev->hf_dev.config_cali = transceiver_config;
    dev->hf_dev.selftest = transceiver_selftest;
    dev->hf_dev.rawdata = transceiver_rawdata;
    dev->hf_dev.debug = transceiver_debug;
    dev->hf_dev.custom_cmd = transceiver_custom_cmd;
    dev->hf_dev.private_data = dev;
    ret = hf_device_register(&dev->hf_dev);    //重点函数,注册一个用于发送的数据的设备
 
 ..........
 }
 //传输原始数据
 static int transceiver_rawdata(struct hf_device *hf_dev,
        int sensor_type, int en)
{
    int ret = 0;

    if (en)
        ret = transceiver_comm_with(sensor_type,
            SENS_COMM_CTRL_ENABLE_RAW_CMD, NULL, 0);
    else
        ret = transceiver_comm_with(sensor_type,
            SENS_COMM_CTRL_DISABLE_RAW_CMD, NULL, 0);
    return ret;
}

static int transceiver_comm_with(int sensor_type, int cmd,
        void *data, uint8_t length)
{
    int ret = 0;
    struct sensor_comm_ctrl *ctrl = NULL;
    uint32_t ctrl_size = 0;

    ctrl_size = ipi_comm_size(sizeof(*ctrl) + length);    
    ctrl = kzalloc(ctrl_size, GFP_KERNEL);    //申请指定的空间用
    ctrl->sensor_type = sensor_type;
    ctrl->command = cmd;
    ctrl->length = length;
    if (length)
        memcpy(ctrl->data, data, length);
    ret = sensor_comm_ctrl_send(ctrl, ctrl_size);
    kfree(ctrl);
    return ret;
}

int sensor_comm_ctrl_send(struct sensor_comm_ctrl *ctrl, unsigned int size)
{
    int retry = 0, ret = 0;
    const int max_retry = 10;
    const int64_t timeout = 10000000000LL;
    int64_t start_time = 0, duration = 0;

    start_time = ktime_get_boottime_ns();
    if (!READ_ONCE(scp_status)) {
        pr_err_ratelimited("dropped comm %u %u\n",
            ctrl->sensor_type, ctrl->command);
        return 0;
    }

    do {
        ret = sensor_comm_ctrl_seq_send(ctrl, size);    //发送命令需要
    } while (retry++ < max_retry && ret < 0);

    duration = ktime_get_boottime_ns() - start_time;
    if (duration > timeout)
        pr_notice("running time %lld, type %u, cmd %u, retries %d\n",
            duration, ctrl->sensor_type, ctrl->command, retry);
    return ret;
}

  • 18
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MTK SensorHub 架构是指联发科技(MediaTek)在其芯片中采用的传感器集成解决方案。SensorHub 是一种低功耗、高性能的处理器,专门用于处理和管理各种传感器数据。下面是 MTK SensorHub 架构的一般概述: 1. 传感器集成:MTK SensorHub 包含了多个传感器,如加速度计、陀螺仪、磁力计、光传感器等。这些传感器可以用于检测设备的运动、环境亮度、方向等信息。 2. 低功耗设计:SensorHub 采用了低功耗设计,使其能够在后台持续运行而不会对设备电池寿命造成过大的影响。它通常会进入休眠状态,并在需要时通过中断或其他触发方式被唤醒。 3. 数据处理和算法:SensorHub 内部集成了处理器和存储器,可以进行传感器数据的实时处理和算法运算。它可以对传感器数据进行滤波、校准、姿态计算等操作,以提供更准确和可靠的传感器输出。 4. 与主处理器通信:SensorHub 与主处理器(如应用处理器)之间通过总线或其他通信接口进行通信。主处理器可以向 SensorHub 发送命令,配置传感器参数,并获取传感器数据。这种分离的架构可以减轻主处理器的负担,提高系统性能和能效。 5. 传感器数据融合:MTK SensorHub 支持传感器数据的融合,即将多个传感器的数据进行整合和处理,以获得更全面和准确的环境感知。例如,通过加速度计和陀螺仪的数据融合,可以实现更精确的运动检测和姿态跟踪。 总的来说,MTK SensorHub 架构提供了一种高效、低功耗的解决方案,用于管理和处理传感器数据。它可以为各种应用场景提供更好的用户体验,如智能手表、智能手机、智能家居等。具体的实现细节可能因不同的芯片型号和版本而有所不同。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值