MTK_SensorHub
零星,思索 2024-08-28 13:01:06 阅读 88
目录
一、简介
二、架构介绍
三、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界面、触发其他应用程序等。
二、架构介绍
应用层:开发者通过获取SensorManager服务并注册监听器来简单地调用传感器,此后传感器信息便会通过回调接口上报。Framework层:该层为开发者提供了与传感器交互的抽象接口,实际工作中会获取SystemSensorManager服务,这是专门为上层注册接口的类。JNI层:这一层提供了从Java到native代码的转换,使得java框架能与下层的HAL进行交互。HAL层:MTK的HAL层实现了对多个sensor的控制处理,其中HfManager扮演了重要角色,负责管理不同sensor的控制流程。内核层:此层提供了sensor数据流的通道,并与硬件相关的驱动紧密相连。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
一、重要结构体
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;
}
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。