當前位置:首頁 > 嵌入式 > 嵌入式軟件
[導讀]uClinux下中斷驅(qū)動的I/O方式

摘要 在開發(fā)數(shù)據(jù)流設備的驅(qū)動程序時,采用中斷驅(qū)動的I/O方式結(jié)合緩沖區(qū)的使用,可以將數(shù)據(jù)的接收和系統(tǒng)調(diào)用read隔離開來,提高設備在系統(tǒng)中的運行效率。本文在討論uClinux下中斷處理程序和底半部分的開發(fā)的基礎上,以一種電信E1線路和以太網(wǎng)互聯(lián)設備上數(shù)據(jù)流設備為例,講述中斷驅(qū)動的I/O方式的驅(qū)動程序開發(fā)。主要過程是在中斷期間填充數(shù)據(jù)到緩沖塊,并用鏈表將緩沖塊串接起來;在系統(tǒng)調(diào)用read期間從緩沖塊取走數(shù)據(jù),再將緩沖塊放到自由鏈表中備用。涉及驅(qū)動程序中常用的阻塞式I/O和自旋鎖等技術應用。通過使用上述多種技術開發(fā)的數(shù)據(jù)流設備驅(qū)動程序,確保系統(tǒng)穩(wěn)定高效的動作。
關鍵詞 uClinux 中斷驅(qū)動 I/O方式

引 言
    在32位微處理器逐漸成為嵌入式系統(tǒng)主流的同時,嵌入式應用也變得越來越復雜。許多嵌入式系統(tǒng)都不得不借助于專用的操作系統(tǒng)來支撐自己的應用。uClinux作為類Unix操作系統(tǒng),繼承了Linux的各種優(yōu)秀的品質(zhì),成為首選的嵌入式系統(tǒng)的操作系統(tǒng)。

    為自己的設備在操作系統(tǒng)下添加驅(qū)動程序,是嵌入式設計必不可少的部分。針對不同的設備類型,選擇合適的驅(qū)動程序的模式,同樣也是十分重要的。通常的設備驅(qū)動采用直接I/O的方式,如存儲器、看門狗等;而對于象網(wǎng)絡這樣的數(shù)據(jù)流設備的驅(qū)動,則應該用到中斷機制。

    本文以uClinux為背景,以一種數(shù)據(jù)流設備為目標,介紹中斷驅(qū)動的I/O設備驅(qū)動的開發(fā)。

1 應用背景
1.1 硬件描述

    本文介紹的驅(qū)動程序是應用在一種電信E1線路和以太網(wǎng)互聯(lián)設備上的。它是旁路接收E1數(shù)據(jù)并將其發(fā)送到以太網(wǎng)的某一臺服務器上,在服務器上對E1的話路和信令時隙分析。

    該設備中的處理器是采用三星公司出品的網(wǎng)絡型ARM處理器S3C4510B。E1線路接口采用Dallas半導體公司的專用El接口單元(LIU)芯片DS2148,它完成波形整理、時鐘恢復和HDB3解碼。DS2148將整理后的E1數(shù)據(jù)流送給一片Altera公司的Cyclone系列的FPGA(EPlC3T144C8),它將串行的E1數(shù)據(jù)流存入到FIFO,再通過ARM的32位外部總線將數(shù)據(jù)傳送給ARM。ARM將數(shù)據(jù)打包通過以太網(wǎng)發(fā)送到服務器上。圖l所示是本系統(tǒng)的硬件框圖。本文主要介紹接在ARM的外部總線上的FPGA,在uClinux下的驅(qū)動程序中斷機制的設計。

1.2硬件連接
     
S3C4510B處理器和FPGA的連接電路如圖2所示。

 

1.3 FPGA內(nèi)FIFO的結(jié)構(gòu)
    在FPGA內(nèi)部設置了兩個FIFO。為了防止ARM和FPGA操作的沖突,ARM和FPGA對兩個FIFO操作采用乒乓方式,這樣ARM和FPGA就可以同時操作不同的FIFO,而不需要等待。FIFO的大小是4096位,能容納一個E1復幀的數(shù)據(jù)量。當FPGA將一個FIFO填滿后,會用中斷的方式通知ARM來讀FIFO,同時FPGA會置內(nèi)部的F1FO狀態(tài)寄存器。FIFO)狀態(tài)寄存器命名為fpga_imf,是一個32位的寄存器,用其中某幾位置“l(fā)”,表示對應的FIFO需要讀取。

2 軟件設計
    中斷驅(qū)動的I/O是指,輸人數(shù)據(jù)在中斷期間被填充到緩沖區(qū)內(nèi),并由讀取該設備的進程取走緩沖區(qū)內(nèi)的數(shù)據(jù);輸出緩沖區(qū)由寫設備的進程填充,并在中斷期間取走數(shù)據(jù)。數(shù)據(jù)緩沖可以將數(shù)據(jù)的發(fā)送和接收與write及read系統(tǒng)調(diào)用分離開來,提高系統(tǒng)的整體性能。下面是uCllnux下的中斷程序的設計。

2.1 uClinux下的中斷程序

    在uClinux系統(tǒng)中,通過調(diào)用下面這個函數(shù)向系統(tǒng)申請一個中斷通道(或中斷請求IRQ),并在處理完以后釋放掉它。
    mt reqLIest_irq(unsigned int irq,void(*handler)(int,vold*,
    struct pt_regs*),unsigned 10ng flags,const chat*device,
    vold*dev_id);
    void free_irq(unstgned int lrq,VOid*dev_id);

    其中,irq是中斷號。在本系統(tǒng)中它對應于S3C4510B的21個中斷源。這里用的是中斷源O。handler指向要安裝的中斷處理函數(shù)的指針。flags是一個與中斷管理有關的各種選項的字節(jié)掩碼。device傳遞給request_irq的字符串,在/proc/interrupts中用于顯示中斷的擁有者。dev_id指針用于共享的中斷信號線。函數(shù)的返回值為O時表示成功,或者返回一個負的錯誤碼。函數(shù)返回一EBUJSY通知另一個設備驅(qū)動程序已經(jīng)使用了要申請的中斷信號線。下面是FPGA的設備中斷申請函數(shù)。這個函數(shù)是在驅(qū)動中的fpga_open函數(shù)中被調(diào)用的。
    int fpga_open(struct inode*inocle,stuct_file*file){
    int result;
    result=request_irq(FPGA_IRQ,δfpga_isr,SA_INTER-RUPT,″fpga″,NULL);
    if(resuIt!=O){
    printk(KERN_INFO”Can not register FPGA ISR!\n”);}else{
    printk(KERN_INFO″FPGA ISR Register successfully!\n”);
  }
}

    在申請了中斷通道后,系統(tǒng)會響應外部中斷0,而進入中斷處理程序。中斷處理程序的第一步是要先清除S3C4510B的中斷懸掛寄存器的外部中斷O位。這是為了讓FPGA可以產(chǎn)生新的中斷。在uClinux系統(tǒng)中是調(diào)用下面的宏來實現(xiàn)的。
    #deflne CLEAR_PEND_INT(n) IntPend=(1<<(n))

    中斷處理程序功能就是將有關中斷接收的信息反饋給設備,并根據(jù)要服務的中斷的不同含義相應地對數(shù)據(jù)進行讀寫。所以FPGA的中斷處理的主要任務是,讀取FPGA中FIFO狀態(tài)寄存器的值,獲取需要讀取的FIFO的信息并安排接收數(shù)據(jù)。在程序中用到了系統(tǒng)提供的inl函數(shù)。
    unmgned mt status
    status=inl(FPGA_IMF);

    中斷處理程序的執(zhí)行應盡可能的短,而從FPGA中接收數(shù)據(jù),一次必須讀完一個FIFO及128字。這是一個需要較長時間的外部I/O操作,所以把這個操作放到中斷處理的底半部(bottom-haIf)來完成。下面介紹中斷處理的底半部的設計。

2.2 BH機制

    底半部處理程序和上半部最大的不同就在于,在執(zhí)行BH時所有的中斷都是打開的,所以說它是在“更安全”時間內(nèi)運行。2.4版本的uClinux內(nèi)核有三種機制來實現(xiàn)底半部的處理:軟中斷、tasklet和BH。在這里選用了較為簡單的BH機制。

    BH機制實際上是一個任務隊列,中斷處理程序?qū)⒁幚淼娜蝿詹宓教囟ǖ娜蝿贞犃兄械却齼?nèi)核執(zhí)行。內(nèi)核維護著多個任務隊列,但驅(qū)動程序只能用前三種:
    ①tq_scheduler隊列。當調(diào)度器被運行時,該隊列就會被處理。因為此時調(diào)度器在被調(diào)度出的進程的上下文中運行,所以該隊列中的任務幾乎可以做任何事。它們不會在中斷時運行。
    ②tq_timer隊列。該隊列由定時器隊列處理程序(timertick)運行,因為該處理程序是在中斷時問運行的。該隊列中的所有任務就也是在中斷時間內(nèi)運行的。
    ③tu_lmmediate隊列。立即隊列在系統(tǒng)調(diào)用返回時或調(diào)度器運行時盡快得到處理的(不管兩種情況誰先發(fā)生了)。該隊列是在中斷時間內(nèi)得到處理的。
    隊列元素由下面的結(jié)構(gòu)來描述:
    structtq_struct 
    structq_struct*mext       /*激活的BH的鏈接表*/
    unsigned 1ong sync;      /*必須初始化為零*/
    void(*outine)(vold*);    /*調(diào)用的函數(shù)*/
    void*data;                /*傳遞給函數(shù)的參數(shù)*/
 };

    上面的數(shù)據(jù)結(jié)構(gòu)中最重要的字段是rotltine和data。將要延遲的任務插入隊列,必須先設置好結(jié)構(gòu)的這些字段,并把next和sync兩個字段清零。結(jié)構(gòu)中的sync標志位用于避免同一任務被插人多次,這會破壞next指針。一旦任務被排人隊列,該數(shù)據(jù)結(jié)構(gòu)就被認為是內(nèi)核“擁有”了,不能再被修改。

    在FPGA的驅(qū)動中,定義了一個任務隊列元素用于完成底半部分:
    struct tq_struct el_task;
    unsigned int el_line;
    el_line數(shù)組用來保存?zhèn)鬟f給任務的參數(shù)。在打開FPGA時要對任務隊列結(jié)構(gòu)賦值:
    el_task.routine=fpga_bh;
    e1 task.data=&e1_line:

    上面的fpga_bh是底半部分處理函數(shù)void fpga_bh(unsigned int*line)的函數(shù)名,el_line是傳遞給fpga_bh函數(shù)的實參。

    與任務隊列有關的還有下面的函數(shù):
    void queue_task(struct tq_struet*task,task_queue*List);

    正如該函數(shù)的名字,本函數(shù)用于將任務排進隊列中。它關閉了中斷,避免了競爭,因此可以被模塊中任一函數(shù)調(diào)用。FPGA的任務被插入到tq_immediate隊列中,所以,list被賦值為&tq_immediate。

    當某段代碼需要調(diào)度運行下半部處理時,只要調(diào)用mark_bh即可:
    void mark_bh(int nr);

    這里,nr是激活的BH的類型。這個數(shù)是在頭文件<linux/interupth>中定義的一個符號常數(shù)。每個下半部BH相應的處理函數(shù)由擁有它的那個驅(qū)動程序提供。

    完成任務隊列元素設置后,中斷處理函數(shù)中就可以啟用BH機制。在讀得fpga_imf的值后將其賦給el_line,然后調(diào)用queue_task將任務插入到tq_immediate隊列中,再調(diào)用mark_bh(IMMEDIATE_BH),啟動底半部分處理。到此,中斷處理程序就可以退出了。

2.3底半部分處理程序和緩沖區(qū)

    uClinux操作系統(tǒng)退出中斷處理程序后,會立即將tq_immediate隊列中任務投入運行,其中也有fpga_bh函數(shù)。在進入fpga_bh同時,系統(tǒng)會將el_line的地址作為實參傳遞給形參line。也就是將FIFO狀態(tài)寄存器(fpga_imf)的值間接傳給了底半部處理程序。底半部分程序中會檢查這個值的每一位,據(jù)此決定需要讀的FIFO。

    從FIFO中讀上來的數(shù)據(jù)都是存放在內(nèi)核的緩沖區(qū)中的。因為每一個FIFO的容量是一個E1的復幀,所以內(nèi)核的緩沖也是以E1復幀的大小為一個緩沖塊。緩沖塊用鏈表串連起來。緩沖單元的數(shù)據(jù)結(jié)構(gòu)如下:
    struct buf_struct{
    struct list_head list;   /*鏈表頭*/
    unsigned int buf_size;   /*數(shù)據(jù)塊的大小*/
    unsigned int*buLhead;    /*緩沖塊的指針*/
    unsigned int*buL_curl     /*緩沖塊當前指針*/
};
    buf_size說明了數(shù)據(jù)塊的大小。這是一個以“字”為單位的數(shù)值。緩沖塊在內(nèi)核堆區(qū)開辟,buf_head指向?qū)嶋H的緩沖塊的首地址,而buf_cur指向緩沖塊中正在操作的單元。為了使用鏈表機制,驅(qū)動必須包含頭文件<linux/list.h>。其中定義了list_head類型結(jié)構(gòu):
    struct list_head{
    struct list_head*next.*prev;

    為了訪問緩沖塊鏈表,還要建立一個鏈表頭,在驅(qū)動 中定義全局變量: 
    struct list_head read_list;

    鏈表頭必須是一個獨立的list_head結(jié)構(gòu)。在使用之前,必須用INIT_LIST_HEAD宏來初始化鏈表頭:
    INIT_LIST_HEAD(&readlist); I
    Linux系統(tǒng)提供了鏈表的操作函數(shù),在頭文件<linux/list.h>中: 
    list_add(struet list_head*new,struct list_head*head);     /*在鏈表頭后插入一個新項*/ 
    list_add_tail(stuot list_head*new,struet list_head*head); /*在鏈表尾部添加一個新項*/ 
    list_del(struet_list_head*entry);                           /*將給定項從鏈表中刪除*/ 
    list_empty(struct list_head*head)                            /*判斷鏈表是否為空*/ 
    list_entry(struct list_head。ptr,type_of_struet,field_ name); /*訪問包含鏈表頭的結(jié)構(gòu)*/ 
 
   其中l(wèi)ist_entry的作用是一個1ist_head結(jié)構(gòu)指針映射回一個指向包含它的大結(jié)構(gòu)的指針。ptr是指向structlist_head結(jié)構(gòu)的指針,type_of_struct是包含ptr的結(jié)構(gòu)類型,field_name是結(jié)構(gòu)中鏈表字段的名字。如可以用這個宏將指向數(shù)據(jù)緩沖塊的鏈表指針(readl)映射為緩沖塊結(jié)構(gòu)指針(buf): 
    struet buf_strcut*buf=list_entry(real,struct buf_struct,list); 

    底半部分處理程序中,內(nèi)核緩沖塊是動態(tài)分配的。因為驅(qū)動程序是內(nèi)核的一部分,所以在內(nèi)核堆區(qū)開辟緩沖區(qū)就要用專用的函數(shù),在頭文件<linux/malloc.h>定義了如下函數(shù):
    void*kmalloc(size t size,int flags);/*在內(nèi)核堆中分配size大小的空問*/
    void kfree(void*obi/*釋放kmalloc分配的空間*/

    kmalloc函數(shù)的第1個參數(shù)是size(大小),第2個參數(shù)是優(yōu)先權。最常用的優(yōu)先權是GFP_KERNEL,它的意思是該內(nèi)存分配是由運行在內(nèi)核態(tài)的進程調(diào)用的。有時kmalloc是在進程上下文之外調(diào)用的,比如在中斷處理、任務隊列處理和內(nèi)核定時器處理時發(fā)生。這些情況下,current進程就不應該進入睡眠狀態(tài),這時應該就使用優(yōu)先權GFP_ATOMIC。

    不要過于頻繁地用kmalloc在內(nèi)核堆中分配空間,因為在分配空間時可能有中斷到來,這樣是不安全的。在驅(qū)動中建立另一個鏈表用于回收使用過的緩沖塊。在驅(qū)動中用free_1ist作為回收緩沖塊的鏈表頭:
    struct list_head free_list;

    這樣就存在兩個鏈表:一個是裝載著數(shù)據(jù)的鏈表,一個是已經(jīng)使用過的緩沖塊的鏈表(稱為自由鏈表)。那么只要自由鏈表中還有表項,在需要緩沖塊時就可以直接從自由鏈表中取出一個使用,而不用kmalloc再去分配。

2.4 阻塞型I/O和自旋鎖的使用

    在驅(qū)動程序中,read的工作是將內(nèi)核緩沖區(qū)中拷貝到用戶空間。在進行這種操作時有兩種情況是應該注意的:
    ①當read時發(fā)現(xiàn)讀鏈表是空,也就是還沒有數(shù)據(jù)可讀。

    這種情況下,可以讓read立即返回一EAGAIN,告知用戶進程沒有讀到數(shù)據(jù);另一個辦法就是實現(xiàn)阻塞型I/O,在沒有數(shù)據(jù)可讀時讓用戶進程進入睡眠狀態(tài)并等待數(shù)據(jù)。

    有幾種處理和喚醒的方法,都要處理同一個基本的數(shù)據(jù)類型——等待隊列(walt_queue_head_t),就是由正在等待某事件發(fā)生的進程組成的一個隊列。使用之前必須聲明和初始化,在驅(qū)動程序中是如下聲明的:
    wait_queue_head_t read_Jqueue;
    init_waitqueue_head(&read_queue);

    可以調(diào)用如下函數(shù)之一讓進程進入睡眠狀態(tài):
    void wait_evet(wait_queue_head_ queue,int condition);
    int wait_evem_interruptible(Walt_queue_hean_t queue,int condition);

    這兩個函數(shù)把等待事件和測試事件是否發(fā)生合并起來。調(diào)用之后,進程會一直睡眠到C布爾表達式condition為真時為止。在驅(qū)動中的read函數(shù)中,判斷讀鏈表為空,就調(diào)用它進入睡眠:
    while(1ist_efnpty(&read_list)){
    If(filp一>f_flags δO_NoNBLOCK)/*如果設置成非阻塞I/o*/
    return—EAGAIN;
    if(wait_evert_interruptible(read_queue,!list_empty(δread_list))) return—ERESTARTSYS;

}

    對應上面的函數(shù),要喚醒進程可以調(diào)用下面的函數(shù):
    wake_up(wait_queue_gead_t*queue);
    wake_up_jnterruptlbk(wait_queue_head_t*queue);

    驅(qū)動程序應該在數(shù)據(jù)到來后及時喚醒進程,也就是從FIFO讀取數(shù)據(jù)后,在退出底半部處理程序前執(zhí)行:
    wake_up_mterIuptible(&read_queue);

    要指出的是被喚醒并不保證等待的事件發(fā)生了,所以從睡眠態(tài)返回后,應該循環(huán)測試condition。

    ②當read操作正在訪問某一個鏈表時,底半程序也要訪問同一個鏈表。這樣是比較危險的,應該避免。

    為了避免這種情況的發(fā)生,這里使用自旋鎖。在read操作訪問鏈表前獲得鎖,訪問結(jié)束時解鎖。底半部要訪問鏈表時先要檢查自旋鎖是否已上鎖,如果有,則等待到鎖可用。

    自旋鎖使用類型spinlock_t來描述。自旋鎖被聲明和初始化為不加鎖狀態(tài)方式如下:
    spinlock_t1ist_10ck=SPIN_LoCK_UNLOCKED;

    處理自旋鎖的函數(shù)如下:
    spill_1ock_bh(Spllalock-t*1ock);
    spin_unloek_bh(splnlock_t*lock);

    這里使用獲得自旋鎖并且阻止底半部執(zhí)行的函數(shù),就可以完全保證底半部程序不會在read操作訪問鏈表時來訪問鏈表。程序中如下實現(xiàn):
    spln_lock_bh(&list_lock);
    list_del(readl); /*將使用后的緩沖塊從讀鏈表中刪除*/
    list_add_tail(readI,&free_list);/*將使用后的緩沖塊插入自由鏈表中*/
    spin_unlock_bh(&list_lock);

2.5中斷驅(qū)動的I/O

    至此,可以完整地描述ARM與FPGA之間數(shù)據(jù)流動的過程:當FPGA的一個FIFO滿后,向ARM發(fā)出中斷,ARM進入中斷處理程序后,讀取FPGA中的FlFO狀態(tài)寄存器(fpga_imf)的值,然后把一個任務插到立即隊列(tq_imrnediate)中,啟動底半部分(BH),同時將FIFO)狀態(tài)寄存器的值傳遞給底半部分處理程序(fpga_bh),完成這些工作后退出中斷處理程序。進入底半部分處理程序后,根據(jù)FIFO狀態(tài)寄存器的值確定要處理的F1F0。從FIFO中將數(shù)據(jù)讀出存人到內(nèi)核緩沖塊中,這個緩沖塊可能是從自由隊列(free_list)中取出來的一個。如果自由隊列中是空的,就新分配一個緩沖塊。接下來將填好的緩沖塊加到讀隊列(read-list)中,并喚醒睡眠的進程,這樣底半部分的工作也完成了。當用戶進程對FPGA設備進行讀操作時,驅(qū)動中的read函數(shù)檢查讀鏈表。如果讀鏈表為空,則進入睡眠并等待數(shù)據(jù)到來。有數(shù)據(jù)后將從讀隊列中取出的緩沖塊的數(shù)據(jù)拷貝到用戶空間,然后將使用過的緩沖塊插到自由隊列中,等待以后再次使用。內(nèi)核緩沖區(qū)的操作過程如圖3所示。圖3上半部分是在底半部分程序中,下半部分是在read函數(shù)中。

結(jié)語
    連續(xù)數(shù)據(jù)流設備在uClinux下的驅(qū)動,通常會用到中斷機制。本文討論的中斷驅(qū)動的I/O式為這種應用提供了一種實用的方法。文中所涉及的鏈表、阻塞型I/O、自旋鎖等技術在驅(qū)動程序的開發(fā)中也經(jīng)常得到使用。

本站聲明: 本文章由作者或相關機構(gòu)授權發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫毥谦F公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉(zhuǎn)型技術解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時1.5...

關鍵字: 汽車 人工智能 智能驅(qū)動 BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務能7×24不間斷運行,同時企業(yè)卻面臨越來越多業(yè)務中斷的風險,如企業(yè)系統(tǒng)復雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務連續(xù)性,提升韌性,成...

關鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關鍵字: 華為 12nm EDA 半導體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會上,華為常務董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權最終是由生態(tài)的繁榮決定的。

關鍵字: 華為 12nm 手機 衛(wèi)星通信

要點: 有效應對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務引領增長 以科技創(chuàng)新為引領,提升企業(yè)核心競爭力 堅持高質(zhì)量發(fā)展策略,塑強核心競爭優(yōu)勢...

關鍵字: 通信 BSP 電信運營商 數(shù)字經(jīng)濟

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術學會聯(lián)合牽頭組建的NVI技術創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會上宣布正式成立。 活動現(xiàn)場 NVI技術創(chuàng)新聯(lián)...

關鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會上,軟通動力信息技術(集團)股份有限公司(以下簡稱"軟通動力")與長三角投資(上海)有限...

關鍵字: BSP 信息技術
關閉
關閉