那曲檬骨新材料有限公司

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Liteos-a內核工作隊列的實現原理分析及經驗總結——芯海科技PPG芯片CS1262接入OpenHarmony實戰

芯海科技(深圳)股份有限公司 ? 2022-04-26 09:26 ? 次閱讀

摘要

OpenHarmony系統中使用了liteos-m、liteos-a、linux三種內核,工作隊列是linux內核引入的一種異步處理機制。本文對liteos-a內核下工作隊列的實現原理進行分析,并對芯海科技的PPG芯片CS1262接入OpenHarmony過程中對工作隊列的使用方法進行總結分享。

工作隊列工作隊列(Workqueue)是linux內核引入的一種異步進程調用的機制,允許內核代碼請求在將來某個時間調用一個函數。在內核源碼的documentation中也有對workqueue的說明,路徑為Documentation/core-api/workqueue.rst。網絡上也有很多對工作隊列機制的總結文章可以學習,《Linux workqueue工作原理》講解的就比較詳細。簡單理解就是先創建一個隊列用于存放work,并創建一個處理線程叫worker;用戶進程通過調用接口往隊列里面添加work驅動著worker來處理,如下:


fa12291e-c4bc-11ec-8521-dac502259ad0.png

而OpenHarmony系統根據不同的使用場景使用了liteos-m/liteos-a/linux三種內核。

這里通過CS1262驅動的實現,對liteos-a內核中工作隊列的使用及實現做一下分析。


工作隊列的使用方法

Sensor設備作為外接設備重要組成模塊,Sensor驅動模型為上層Sensor服務系統提供穩定的Sensor基礎能力接口,包括Sensor列表查詢、Sensor啟停、Sensor訂閱及去訂閱,Sensor參數配置等功能。傳感器驅動模型總體框架如圖1所示。

OpenHarmony系統對workqueue提供了幾個接口,以方便用戶的使用。

1. 調用HdfWorkQueueInit,傳入queue名稱,創建并初始化一個workqueue

2. 調用HdfWorkInit,可以理解為初始化一個work的模板,主要記錄處理這個queue里面work的回調函數func以及參數para信息,類似于linux的work_struct

3. 通過調用HdfAddWork往workqueue中添加work,觸發調用與此queue關聯的回調函數func


步驟1~2可以在CS1262驅動HdfDriverEntry對象的Init接口中看到

int32_t InitPpgDriver(struct HdfDeviceObject *device)
{
    CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM);
    struct PpgDrvData *drvData = (struct PpgDrvData *)device->service;
    CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);

    if (HdfWorkQueueInit(&drvData->ppgWorkQueue, HDF_PPG_WORK_QUEUE) != HDF_SUCCESS) {
        HDF_LOGE("%s: Ppg init work queue failed", __func__);
        return HDF_FAILURE;
    }

    if (HdfWorkInit(&drvData->ppgWork, PpgDataWorkEntry, drvData) != HDF_SUCCESS) {
        HDF_LOGE("%s: Ppg create thread failed", __func__);
        return HDF_FAILURE;
    }

    drvData->initStatus = true;
    drvData->enable = false;
    drvData->detectFlag = false;

    HDF_LOGI("%s: init Ppg driver success", __func__);
    return HDF_SUCCESS;
}

步驟3在CS1262的中斷處理函數中,有數據需要上報時會產生一個中斷,中斷處理中添加一個work通過工作隊列機制來實現數據的上報。

static int32_t PpgReadInt(uint16_t gpio, void *data)
{
    struct PpgDrvData *drvData = PpgGetDrvData();
    CHECK_PPG_INIT_RETURN_VALUE(drvData, HDF_ERR_NOT_SUPPORT);

    if (!drvData->enable) {
        HDF_LOGE("%s: ppg not enabled", __func__);
        return HDF_SUCCESS;
    }

    if (!HdfAddWork(&drvData->ppgWorkQueue, &drvData->ppgWork)) {
        HDF_LOGE("%s: Ppg add work queue failed", __func__);
        return HDF_FAILURE;
    }

    return HDF_SUCCESS;
}

CS1262工作對列中work的回調接口實現,兩個主要功能:獲取數據,數據上報。

static void PpgDataWorkEntry(void *arg)
{
    int32_t ret;
    struct PpgDrvData *drvData = (struct PpgDrvData *)arg;
    uint16_t readLen = 0;

    CHECK_NULL_PTR_RETURN(drvData);
    CHECK_NULL_PTR_RETURN(drvData->chipData.opsCall.ReadData);

    ret = drvData->chipData.opsCall.ReadData(g_fifoBuf, sizeof(g_fifoBuf), &readLen);
    if ((ret != HDF_SUCCESS) || (readLen > sizeof(g_fifoBuf))) {
        HDF_LOGE("%s: Ppg read data failed", __func__);
        return;
    }

    if (PpgReportInt(g_fifoBuf, readLen) != HDF_SUCCESS) {
        HDF_LOGE("%s: Cs1262ReportInt fail", __func__);
    }
}

說明:當前CS1262驅動已提交PR,還未正式上庫


Liteos-a內核中工作隊列的實現

1.HdfWorkQueueInit接口

(1)在liteos-a系統源碼中搜索,接口定義如下:

源文件:drivers/adapter/khdf/liteos/osal/src/osal_workqueue.c
代碼如下:
int32_t HdfWorkQueueInit(HdfWorkQueue *queue, char *name)
{
......

    queue->realWorkQueue = create_singlethread_workqueue(name);

......

    return HDF_SUCCESS;
}

(2)create_singlethread_workqueue接口實現如下

源文件:kernel/liteos_a/bsd/compat/linuxkpi/include/linux/workqueue.h

宏定義:
#define create_singlethread_workqueue(name) \
    linux_create_singlethread_workqueue(name)


源文件:kernel/liteos_a/bsd/compat/linuxkpi/src/linux_workqueue.c
代碼如下:
struct workqueue_struct *linux_create_singlethread_workqueue(char *name)
{
    return __create_workqueue_key(name, 1, 0, 0, NULL, NULL);
}

(3)__create_workqueue_key中初始化化了一個event后面會用;創建一個workqueueThread線程用來處理這個workqueue里的所有work

源文件:kernel/liteos_a/bsd/compat/linuxkpi/src/linux_workqueue.c
代碼如下:
struct workqueue_struct *__create_workqueue_key(char *name,
                                                int singleThread,
                                                int freezeable,
                                                int rt,
                                                struct lock_class_key *key,
                                                const char *lockName)
{
......

    (VOID)LOS_EventInit(&wq->wq_event);

    if (singleThread) {
        cwq = InitCpuWorkqueue(wq, singleThread);
        ret = CreateWorkqueueThread(cwq, singleThread);
    } else {
        LOS_MemFree(m_aucSysMem0, wq->cpu_wq);
        LOS_MemFree(m_aucSysMem0, wq);
        return NULL;
    }

    if (ret) {
        destroy_workqueue(wq);
        wq = NULL;
    }

    return wq;
}

(4)LOS_EventInit就是liteos系統的task之間通信的事件機制實現

(5)CreateWorkqueueThread就是調用的liteos的LOS_TaskCreate來創建一個Task(也即thread),處理函數為WorkerThread,如下

源文件:kernel/liteos_a/bsd/compat/linuxkpi/src/linux_workqueue.c
代碼如下:
STATIC UINT32 CreateWorkqueueThread(cpu_workqueue_struct *cwq, INT32 cpu)
{
    ......

    taskInitParam.pfnTaskEntry = (TSK_ENTRY_FUNC)WorkerThread;

    ......

    ret = LOS_TaskCreate(&cwq->wq->wq_id, &taskInitParam);

    ......

    return LOS_OK;
}

STATIC VOID WorkerThread(cpu_workqueue_struct *cwqParam)
{
    cpu_workqueue_struct *cwq = cwqParam;

    for (;;) {
        if (WorkqueueIsEmpty(cwq)) {
(VOID)LOS_EventRead(&(cwq->wq->wq_event),0x01,LOS_WAITMODE_OR|LOS_WAITMODE_CLR,LOS_WAIT_FOREVER);
        }
        RunWorkqueue(cwq);
    }
}

線程處理函數里面就是一個死循環,當workqueue中為空時,代碼會阻塞在LOS_EventRead處,讀一個還未發生的事件時,代碼就會在此處一直阻塞,直到事件發生;

(6)在事件發生(有work可以處理)時,就會調用真正的處理接口RunWorkqueue,對work調用回調函數(例如上面CS1262中的PpgDataWorkEntry)

源文件:kernel/liteos_a/bsd/compat/linuxkpi/src/linux_workqueue.c
代碼如下:
STATIC VOID RunWorkqueue(cpu_workqueue_struct *cwq)
{
    ......
    if (!WorkqueueIsEmpty(cwq)) {
        ......
        func = work->func;
        func(work);
        ......
    }
    LOS_SpinUnlockRestore(&g_workqueueSpin, intSave);
}

2.HdfWorkInit接口

(1)接口實現如下

源文件:drivers/adapter/khdf/liteos/osal/src/osal_workqueue.c
代碼如下:
int32_t HdfWorkInit(HdfWork *work, HdfWorkFunc func, void *para)
{
    ......

    wrapper = (struct WorkWrapper *)OsalMemCalloc(sizeof(*wrapper));
    if (wrapper == NULL) {
        HDF_LOGE("%s malloc fail", __func__);
        return HDF_ERR_MALLOC_FAIL;
    }
    realWork = &(wrapper->work.work);
    wrapper->workFunc = func;
    wrapper->para = para;

    INIT_WORK(realWork, WorkEntry);
    work->realWork = wrapper;

    return HDF_SUCCESS;
}

(2)從這里看這個處理函數func賦值給了wrapper->workFunc,而在INIT_WORK中將WorkEntry接口賦值給了work的func

源文件:drivers/adapter/khdf/liteos/osal/src/osal_workqueue.c
代碼如下:
#ifdef WORKQUEUE_SUPPORT_PRIORITY
#define INIT_WORK(work, callbackFunc)  do {      \
    INIT_LIST_HEAD(&((work)->entry));            \
    (work)->func = (callbackFunc);               \
    (work)->data = (atomic_long_t)(0);           \
    (work)->work_status = 0;                     \
    (work)->work_pri = OS_WORK_PRIORITY_DEFAULT; \
} while (0)
#else
#define INIT_WORK(work, callbackFunc)  do { \
    INIT_LIST_HEAD(&((work)->entry));       \
    (work)->func = (callbackFunc);          \
    (work)->data = (atomic_long_t)(0);      \
    (work)->work_status = 0;                \
} while (0)
#endif

(3)從前面分析,有work需要處理時調用的就是這個(work)->func;而這里看這個接口的值是WorkEntry,怎么跟驅動側輸入的處理接口聯系的呢?就是這個WorkEntry實現的

源文件:drivers/adapter/khdf/liteos/osal/src/osal_workqueue.c
代碼如下:
static void WorkEntry(struct work_struct *work)
{
    struct WorkWrapper *wrapper = NULL;
    if (work != NULL) {
        wrapper = (struct WorkWrapper *)work;
        if (wrapper->workFunc != NULL) {
            wrapper->workFunc(wrapper->para);
        } else {
            HDF_LOGE("%s routine null", __func__);
        }
    } else {
        HDF_LOGE("%s work null", __func__);
    }
}

從這里看就是調用的wrapper->workFunc,也即HdfWorkInit接口傳入的回調函數。

3.HdfAddWork接口

(1)接口定義如下

源文件:drivers/adapter/khdf/liteos/osal/src/osal_workqueue.c
代碼如下:
bool HdfAddWork(HdfWorkQueue *queue, HdfWork *work)
{
    ......

    return queue_work(queue->realWorkQueue, &((struct WorkWrapper *)work->realWork)->work.work);
}

(2)queue_work接口是一個宏,定義如下

源文件:drivers/adapter/khdf/liteos/osal/src/osal_workqueue.c
代碼如下:
#define queue_work(wq, work) \
    linux_queue_work(wq, work)

源文件:kernel/liteos_a/bsd/compat/linuxkpi/src/linux_workqueue.c

linux_queue_work最終調用的接口是InsertWork,中間的調用如下

linux_queue_work()
   |--> QueueWorkOn()
           |--> QueueWork()
                  |-->InsertWork()

接口實現:
STATIC VOID InsertWork(cpu_workqueue_struct *cwq, struct work_struct *work, 
struct list_head *head, UINT32 *intSave)
{
#ifdef WORKQUEUE_SUPPORT_PRIORITY
    WorkListAdd(&work->entry, head, work->work_pri);
#else
    WorkListAddTail(&work->entry, head);
#endif
    LOS_SpinUnlockRestore(&g_workqueueSpin, *intSave);
    (VOID)LOS_EventWrite(&(cwq->wq->wq_event), 0x01);
    LOS_SpinLockSave(&g_workqueueSpin, intSave);
}

從實現上看這里就是寫了一個Event,還記得前面在init里面一個阻塞在讀Event的嗎?這里的LOS_EventWrite就代表了事件發生,然后就可以正常處理work了


總結

OpenHarmony的liteos-a內核中工作隊列的實現就是參照linux內核的實現,只是底層使用的是嵌入式系統中事件處理機制。

OpenHarmony在內核上層做了一層封裝(OSAL),在使用linux和liteos-a內核時工作隊列的使用方式統一,驅動開發時無感知。

芯海科技作為OpenHarmony項目群B類捐贈人,已加入DriverFramework SIG和DevBoard SIG。在DriverFramework SIG中負責心率傳感器PPG驅動模型和HDI的實現。CS1262是芯海科技最新推出的一款用于光電血管容積圖(PPG)信號采集的高端模擬前端(AFE),通過SPI總線與主控通信。關鍵性能指標達到業界一流水平:

高精度測量:最高PPG SNR高達110dB

◆ 超強抗干擾:PSRR ≥ 90dB(0.5Hz~10MHz 范圍內的Boost噪聲)

◆ 低功耗:83uA@100Hz@4Ch@2階環境光

◆ 全膚色支持:單路LED Driver最大電流可達125mA,兩路合并后支持250mA

◆ 高可靠:支持過溫保護/關鍵寄存器保護/LED過流保護/SPI通訊可靠性check

◆ 易用性:支持1/2階環境光消減/硬件佩戴檢測/自動調光/動態配置刷新


聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 芯片
    +關注

    關注

    456

    文章

    51166

    瀏覽量

    427206
  • OpenHarmony
    +關注

    關注

    25

    文章

    3744

    瀏覽量

    16573
收藏 人收藏

    評論

    相關推薦

    科技CS8M321/326系列經濟型MCU全新上市

    近期,科技(股票代碼:688595)全新推出了CS8M321(簡稱M321)、CS8M326(簡稱M326)系列ADC模塊經濟型MCU。該系列MCU集成了12位單端ADC、低溫漂基
    的頭像 發表于 01-10 18:05 ?146次閱讀
    <b class='flag-5'>芯</b><b class='flag-5'>海</b>科技<b class='flag-5'>CS</b>8M321/326系列經濟型MCU全新上市

    科技CS1262:高精度全場景PPG AFE

    科技CS1262作為一款高精度全場景PPG AFE芯片,以其卓越的性能指標、全面的功能特性和低功耗特性,為用戶提供了高效、可靠的生命體征
    的頭像 發表于 12-17 17:32 ?291次閱讀
    <b class='flag-5'>芯</b><b class='flag-5'>海</b>科技<b class='flag-5'>CS1262</b>:高精度全場景<b class='flag-5'>PPG</b> AFE

    科技可穿戴設備PPG方案:結構、工藝與高精度設計探索

    CS1262芯片以其卓越的性能指標,如高配置、高精度測量、超強抗干擾、低功耗、全膚色支持、高可靠性和易用性等,贏得了業界的廣泛認可。未來,隨著科技在健康測量領域的持續投入和創新,
    的頭像 發表于 12-17 17:27 ?246次閱讀
    <b class='flag-5'>芯</b><b class='flag-5'>海</b>科技可穿戴設備<b class='flag-5'>PPG</b>方案:結構、工藝與高精度設計探索

    科技系列OpenHarmony3.1芯片支持智慧生態構建

    隨著OpenHarmony3.1的正式發布,科技作為OpenHarmony生態的重要參與者,及時推出了兩款與系統適配的新品:健康測量CS1262
    的頭像 發表于 12-17 17:25 ?231次閱讀
    <b class='flag-5'>芯</b><b class='flag-5'>海</b>科技系列<b class='flag-5'>OpenHarmony</b>3.1<b class='flag-5'>芯片</b>支持智慧生態構建

    科技深化穿戴健康測量產品布局,CS1262CS1253芯片引領創新

    隨著全球健康意識的提升,健康測量設備需求激增,特別是智能手表和手環等腕帶設備,年均復合增長率超過15%。科技自2007年起便布局健康測量領域,從基礎的體重秤、體脂秤到復雜的PPG、BIA等智能
    的頭像 發表于 12-17 17:23 ?249次閱讀
    <b class='flag-5'>芯</b><b class='flag-5'>海</b>科技深化穿戴健康測量產品布局,<b class='flag-5'>CS1262</b>與<b class='flag-5'>CS</b>1253<b class='flag-5'>芯片</b>引領創新

    科技CS32A01X系列芯片閃耀第七屆集創賽,助力半導體人才培育

    科技的SmartAnalog芯片CS32A01X系列產品,憑借其卓越的綜合性能,被“曾益慧創杯”選定為數模混合信號賽題的測試芯片,為
    的頭像 發表于 11-28 09:15 ?311次閱讀
    <b class='flag-5'>芯</b><b class='flag-5'>海</b>科技<b class='flag-5'>CS32A</b>01X系列<b class='flag-5'>芯片</b>閃耀第七屆集創賽,助力半導體人才培育

    科技車規級SAR ADC新品CS1795X榮獲“中國

    11月7日,2024中國微電子產業促進大會暨第十九屆“中國”優秀產品征集結果發布儀式在珠海橫琴粵澳深度合作區隆重舉行。科技旗下集成高精度基準的低功耗汽車級SARADC芯片
    的頭像 發表于 11-09 01:06 ?405次閱讀
    <b class='flag-5'>芯</b><b class='flag-5'>海</b>科技車規級SAR ADC新品<b class='flag-5'>CS</b>1795X榮獲“中國<b class='flag-5'>芯</b>”

    CS1262資料

    求一波CS1262芯片的例程代碼、寄存器配置、完整數據手冊等,郵箱24181214463@stu.xidian.edu.cn。謝謝大家啦
    發表于 10-22 11:22

    ADC 芯片 CS1237 為例,簡述國產 ADC 芯片的優勢

    科技的 ADC 芯片 CS1237 便是國產 ADC 芯片中的佼佼者,通過對其的分析,我們可以一窺國產 ADC
    的頭像 發表于 07-23 15:25 ?1484次閱讀

    科技 PD 應用筆記: 基于 CS32G02X 的 PD3.1-EPR 系統設計

    本文檔介紹和說明科技旗下 CS32G02X 芯片的 PD3.1-EPR 系統系統設計,包括 PD3.1-EPR 協議介紹、PD3.1-EPR 硬件設計要求、PD3.1-EPR 軟件
    發表于 05-16 14:18

    應用筆記:通用 MCU 基于 IAR 芯片包 IAR9 開發指南

    科技與 IAR Systems 達成合作,IAR Embedded Workbench for Arm 已全面支持科技CS32F10
    發表于 05-16 11:52

    科技通用 MCU 應用筆記: CS32F103 FOC 電機評估板使用指南

    本文檔描述了基于 CS32F103 系列芯片的矢量控制電機開發板 V1.00 的設計理念、結構和使用說明,以幫助用戶快速使用此開發板,評估 CS
    發表于 05-16 11:35

    OpenHarmony內核編程實戰

    編程入門[Hello,OpenHarmony]在正式開始之前,對于剛接觸OpenHarmony的伙伴們,面對大篇幅的源碼可能無從下手,不知道怎么去編碼寫程序,下面用一個簡單的例子帶伙伴們入門。▍任務
    的頭像 發表于 03-27 08:31 ?941次閱讀
    <b class='flag-5'>OpenHarmony</b><b class='flag-5'>內核</b>編程<b class='flag-5'>實戰</b>

    Linux 6.9-rc1發布,加入定時器、工作隊列及AMD P-State優化

    內核方面,6.9版本進行了定時器的大幅重構,增加了每個CPU核心的時間輪支持,以提升定時器運效率,尤其在網絡應用中表現出色。此外,工作隊列子系統新增BH工作隊列支持,摒棄了老舊的tasklet機制。
    的頭像 發表于 03-25 13:49 ?499次閱讀

    【鴻蒙】小型系統LiteOS-A內核

    LiteOS-A 內核 移植概述 移植場景 LiteOS-A 當前支持 ARMv7-a 指令集架構,如果三方芯片為 ARMv7-
    的頭像 發表于 02-29 16:16 ?1312次閱讀
    【鴻蒙】小型系統<b class='flag-5'>LiteOS-A</b><b class='flag-5'>內核</b>
    大发888免费娱乐| 闲和庄百家乐赌场娱乐网规则| 时时博百家乐官网的玩法技巧和规则| 真人百家乐官网赌法| 至尊百家乐官网qvod| 澳门百家乐官网游戏说明书| 专业百家乐官网筹码| 澳门百家乐官网海星王娱乐城 | 百家乐游戏规则介绍| 百家乐21点游戏| 百家乐如何看| 威尼斯人娱乐场55556| 大发888注册 大发888官网| 博彩网站排名| 百家乐详解| 百家乐官网游戏运营| 百家乐官网ho168平台| 百家乐官网智能软件| 欧凯百家乐官网的玩法技巧和规则 | 百家乐官网顺序| 钱隆百家乐官网智能| 百家乐庄闲和概率| 百家乐技巧-百家乐开户指定代理网址| 百家乐注码技术打法| 全讯网123| 网上博彩娱乐| 百家乐官网怎么赢博彩正网| 中原百家乐官网的玩法技巧和规则 | 百家乐游戏论坛| 宝马会百家乐的玩法技巧和规则| 大发888真人娱乐场| 阿荣旗| 百家乐官网秘| 百家乐线上真人游戏| 百家乐有没有单机版的| 大发888赌场是干什么的| 密云县| 百家乐官网翻天| 芝加哥百家乐的玩法技巧和规则 | 澳门百家乐官网上下限| 百家乐官网赌场|