當(dāng)前位置:首頁(yè) > 公眾號(hào)精選 > 技術(shù)讓夢(mèng)想更偉大
[導(dǎo)讀]【說(shuō)在前面的話】其實(shí)我很久之前就想寫這篇文章了,但彼時(shí)總覺得這是一個(gè)偽命題:既然已經(jīng)用了MDK,編譯出來(lái)的代碼,無(wú)論是體積還是性能都甩下armgcc好幾條街,誰(shuí)還會(huì)想用gcc來(lái)進(jìn)行Cortex-M開發(fā)呢?對(duì)那些只能使用armgcc、或者對(duì)gcc情有獨(dú)鐘的小伙伴來(lái)說(shuō),無(wú)論是配合ec...



【說(shuō)在前面的話】

其實(shí)我很久之前就想寫這篇文章了,但彼時(shí)總覺得這是一個(gè)偽命題:
  • 既然已經(jīng)用了MDK,編譯出來(lái)的代碼,無(wú)論是體積還是性能都甩下arm gcc好幾條街,誰(shuí)還會(huì)想用gcc來(lái)進(jìn)行Cortex-M開發(fā)呢?

  • 對(duì)那些只能使用arm gcc、或者對(duì)gcc情有獨(dú)鐘的小伙伴來(lái)說(shuō),無(wú)論是配合eclipse、vscode、Embedded Studio還是其它什么開發(fā)環(huán)境,哪個(gè)不比MDK香呢?


然而,既然你點(diǎn)開了這篇文章,無(wú)論是否真的有這樣的需求,至少說(shuō)明你對(duì)這樣的搭配還是“頗有些好奇”的。我就不去擔(dān)心背后的真正原因了,就讓我們速速切入正題,進(jìn)入實(shí)操環(huán)節(jié)吧。


先說(shuō)結(jié)論:
  • MDK原生支持GCC開發(fā),且不受License限制

  • MDK使用GCC開發(fā)時(shí)“可以做到”不寫一句匯編的程度

  • MDK使用GCC開發(fā)時(shí)可以享受來(lái)自Runtime Environment配置機(jī)制的福利——也就是你可以輕松的享用來(lái)自Pack Installer所引入的各類軟件包的支持——這同樣也是免費(fèi)的

  • MDK使用GCC開發(fā)時(shí)支持調(diào)試(所能調(diào)試的代碼尺寸受到License限制)


我們知道MDK是一個(gè)集成開發(fā)環(huán)境(Integrated Development Environment),它默認(rèn)原生支持Arm Compiler 5(armcc)、Arm Compiler 6(armclang)arm gcc。雖然這三個(gè)編譯器都是由Arm所維護(hù)和提供的,但前兩者算是彼此兼容的編譯器:

  • 使用共同的?armlink

  • 使用相同的方式來(lái)描述地址空間布局(分散加載腳本 scatter script)

  • 從Arm Compiler 6.14開始,armclang甚至開始支持armasm的匯編語(yǔ)法了


實(shí)際上可以認(rèn)為,armccarmclang是一對(duì)連體兄弟,身子是armlink,而兩個(gè)腦袋分別是 armccarmclang。大約是這種感覺,你體會(huì)下。



與親生的兩兄弟不同,牛頭人arm gccArm公司從GCC開源社區(qū)“抱回來(lái)的孩子”。它雖然語(yǔ)法上與armclang(clang)基本相同,但卻擁有自己獨(dú)立的編譯和連接環(huán)節(jié),用來(lái)描述地址空間布局的方式也完全不同——采用 linker script(*.ld)來(lái)進(jìn)行。


那么這些差異對(duì)我們?cè)?strong>MDK中使用gcc進(jìn)行開發(fā)有什么意義呢?我們需要做哪些工作準(zhǔn)備工作呢?總的來(lái)說(shuō),問題集中在以下幾個(gè)方面:
  1. 編譯器的獲取和集成

  2. 如何芯片的啟動(dòng)

  3. 如何描述目標(biāo)軟件的地址空間布局

  4. 如何對(duì)編譯選項(xiàng)進(jìn)行配置

  5. 如何進(jìn)行代碼的優(yōu)化


接下來(lái),我們就有針對(duì)性的為您解答這些問題。

【如何在將arm gcc集成到MDK環(huán)境中】


arm gcc 獲取并不困難,可以訪問arm的官方頁(yè)面直接下載:


https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm


下載后一路無(wú)腦安裝即可,這里就不再贅述。接下來(lái),我們打開MDK,通過菜單?project->New uVision Project... 新建一個(gè)工程:



為了方便,工程文件名不妨就叫 gcc_template好了:


單擊?"Save" 后,MDK會(huì)彈出窗口讓我們選擇工程的目標(biāo)芯片,實(shí)際上很多芯片公司都為MDK提供了面向gcc的工程模板,因此在這里直接選擇實(shí)際芯片型號(hào)往往就可以省略后面大部分步驟,但考慮到讓本教程擁有更強(qiáng)的通用性,這里我們選擇目標(biāo)芯片所使用的處理器


假設(shè),我們要使用的芯片是STM32F746,我們知道它的內(nèi)核是Cortex-M7,因此這里就選擇 Arm->ARM Cortex-M7->ARMCM7_SP(假設(shè)是單精度浮點(diǎn)運(yùn)算單元),單擊OK。
對(duì)這里選什么芯片比較糾結(jié)的小伙伴大可不必,因?yàn)楹竺骐S時(shí)可以回來(lái)改,不會(huì)存在那種“買定離手”而“無(wú)法反悔”的問題。
接下來(lái),MDK會(huì)彈出RTE的配置界面。RTE的配置我們將在后面介紹,此時(shí)直接單擊OK進(jìn)行跳過即可。


如果一切順利,你會(huì)看到如下的界面:



以上步驟只能算是準(zhǔn)備工作,接下來(lái)才是將arm gcc集成到MDK中的正題。依次通過菜單 Project -> Manage -> Project Items 打開配置窗體:


在新打開的對(duì)話框中選擇 "Folders/Extensions" 選項(xiàng)卡,并勾選“Use GCC Compiler (GNU)for ARM projects”(如下圖所示):

單擊 “...” 按鈕,選擇arm gcc工具鏈所在的安裝目錄。以最新的的arm gcc 2020-q4-major 版本為例,默認(rèn)情況下它會(huì)被安裝在?


“C:\Program Files (x86)\GNU Arm Embedded Toolchain”


目錄下。我們選中這里的 "10 2020-q4-major" 目錄,單擊 Select Folder 按鈕。


在回到上一級(jí)窗口時(shí),我們注意到,此時(shí)arm gcc的路徑已經(jīng)被正確配置了:


單擊“OK”就完成了 arm gcc 的添加工作。此時(shí),如果打開 Project ->?Options for Target 窗口,我們會(huì)看到編譯器配置界面變成了一個(gè)陌生的樣子:

如果你看到類似這樣的界面,恭喜您,您的MDK已經(jīng)和arm gcc“喜結(jié)連理”了。

【實(shí)現(xiàn)“無(wú)匯編化”的啟動(dòng)】

很多人可能都有錯(cuò)覺——以為使用gcc開發(fā)項(xiàng)目一定要用匯編的方式來(lái)處理啟動(dòng)文件——過去也許是這樣,但是,“大人時(shí)代變了”!。




借助 CMSIS的幫助,我們現(xiàn)在也可以優(yōu)雅的完全使用C語(yǔ)言來(lái)實(shí)現(xiàn)芯片的啟動(dòng)過程。首先,我們需要獲得最新的CMSIS,具體方法可以在這篇文章《CMSIS玩家的“陰間成就”指南》中獲得,這里就不在贅述。
無(wú)論是通過Pack安裝還是github導(dǎo)入,在確保最新的CMSIS被成功的安裝到MDK中以后,我們首先需要在工程中通過RTE窗口引入最新的CMSIS支持:在工具欄中,單擊下面的按鈕:
?
打開?Runtime Environment?配置窗口:


這里,我們展開CMSIS,并勾選?CORE(這里,請(qǐng)確保CORE的版本不低于?5.4.0),單擊OK確認(rèn)配置。
如果你對(duì)CMSIS的版本有所疑問,可以單擊 “Select Packs” 按鈕,確保窗體頂端的 “Use latest versions of all installed Software Packs” 被勾選,如果這樣做以后,CMSIS-CORE的版本仍然低于 5.4.0,請(qǐng)務(wù)必參考這篇文章CMSIS玩家的“陰間成就”指南來(lái)獲取最新的CMSIS。
單擊CMSIS-CORE后面的注釋文字:



會(huì)打開一個(gè)瀏覽器頁(yè)面,忽略其中的內(nèi)容,我們需要的是頁(yè)面網(wǎng)址中的路徑信息:


這里,我們找到了當(dāng)前CMSIS Pack在本地的路徑,利用這一路徑信息在瀏覽器中打開對(duì)應(yīng)文件夾,找到 Device目錄:



依次進(jìn)入目錄?“Device\ARM\ARMCM7\Source”:


將上圖選中的文件拷貝到我們的工程中來(lái):


MDK工程中,將startup_ARMCM7.csystem_ARMCM7.c加入到工程中參與編譯(這里我們新建了一個(gè)分組叫做 low_level):



先別著急去編譯,注意到這里的小鑰匙圖標(biāo)了么?這說(shuō)明這兩個(gè)文件自帶了“只讀屬性”。由于我們后面要修改這兩個(gè)文件,因此必須要通過Windows的文件屬性管理將只讀屬性去除(把下圖的勾選去掉后單擊OK):

此時(shí)再看MDK的工程管理器,小鑰匙標(biāo)志就已經(jīng)消失了:



接下來(lái),打開?“Option for Target...” 窗體,進(jìn)入Linker選項(xiàng)卡:


將這里的 "Do not use Standard System Startup Files" 選項(xiàng)去除。


注意,這一步驟非常重要,不可以省略,否則你會(huì)看到如下的編譯錯(cuò)誤:

linking...c:/program files (x86)/gnu arm embedded toolchain/10 2020-q4-major/bin/../lib/gcc/arm-none-eabi/10.2.1/../../../../arm-none-eabi/bin/ld.exe: warning: cannot find entry symbol _start; defaulting to 00008000c:/program files (x86)/gnu arm embedded toolchain/10 2020-q4-major/bin/../lib/gcc/arm-none-eabi/10.2.1/../../../../arm-none-eabi/bin/ld.exe: ./startup_armcm7.o: in function `__cmsis_start':C:/Users/gabriel/AppData/Local/Arm/Packs/ARM/CMSIS/5.8.0/CMSIS/Core/Include/cmsis_gcc.h:163: undefined reference to `_start'c:/program files (x86)/gnu arm embedded toolchain/10 2020-q4-major/bin/../lib/gcc/arm-none-eabi/10.2.1/../../../../arm-none-eabi/bin/ld.exe: C:/Users/gabriel/AppData/Local/Arm/Packs/ARM/CMSIS/5.8.0/CMSIS/Core/Include/cmsis_gcc.h:163: undefined reference to `__copy_table_start__'c:/program files (x86)/gnu arm embedded toolchain/10 2020-q4-major/bin/../lib/gcc/arm-none-eabi/10.2.1/../../../../arm-none-eabi/bin/ld.exe: C:/Users/gabriel/AppData/Local/Arm/Packs/ARM/CMSIS/5.8.0/CMSIS/Core/Include/cmsis_gcc.h:163: undefined reference to `__copy_table_end__'c:/program files (x86)/gnu arm embedded toolchain/10 2020-q4-major/bin/../lib/gcc/arm-none-eabi/10.2.1/../../../../arm-none-eabi/bin/ld.exe: C:/Users/gabriel/AppData/Local/Arm/Packs/ARM/CMSIS/5.8.0/CMSIS/Core/Include/cmsis_gcc.h:163: undefined reference to `__zero_table_start__'c:/program files (x86)/gnu arm embedded toolchain/10 2020-q4-major/bin/../lib/gcc/arm-none-eabi/10.2.1/../../../../arm-none-eabi/bin/ld.exe: C:/Users/gabriel/AppData/Local/Arm/Packs/ARM/CMSIS/5.8.0/CMSIS/Core/Include/cmsis_gcc.h:163: undefined reference to `__zero_table_end__'c:/program files (x86)/gnu arm embedded toolchain/10 2020-q4-major/bin/../lib/gcc/arm-none-eabi/10.2.1/../../../../arm-none-eabi/bin/ld.exe: ./startup_armcm7.o:E:\Temp Project\gcc_template/startup_ARMCM7.c:84: undefined reference to `__StackTop'collect2.exe: error: ld returned 1 exit status".\gcc_template.elf" - 1 Error(s), 0 Warning(s).正如錯(cuò)誤提示中指出的那樣,CMSIS會(huì)在一個(gè)叫做 __cmsis_start的函數(shù)中,調(diào)用 "_start"?函數(shù),而這一函數(shù)正是gcc標(biāo)準(zhǔn)啟動(dòng)文件的入口,當(dāng)你在MDK中選擇"Do not use Standard System Startup Files"?時(shí),linker自然就找不到這個(gè)“不存在”的入口函數(shù)啦。


接下來(lái),單擊如下圖所示的按鈕:



打開我們剛剛一起拷貝過來(lái)的GCC目錄,選中其中的連接腳本 gcc_arm.ld后,單擊Open:

最后的結(jié)果如下圖所示,單擊OK確認(rèn)我們的配置:


雖然不是必須,但推薦在Misc controls中添加如下的內(nèi)容:

--specs=nosys.specs?-Wl,--gc-sections-fshort-enums?-fshort-wchar即:

接下來(lái),為了初步檢驗(yàn)一下我們的成果,在工程中添加一個(gè)main.c(實(shí)現(xiàn)一個(gè)簡(jiǎn)單的main() 函數(shù)):



懷著忐忑的心理,按下編譯按鈕:




不用懷疑,我們已經(jīng)成功的實(shí)現(xiàn)了“零匯編”gcc工程建立。簡(jiǎn)單不?你可以把這個(gè)工程連同文件夾一起保存好,這就是未來(lái)的工程模板了。此外,關(guān)于main.c中的代碼,需要做一些簡(jiǎn)單的說(shuō)明:

#include #include #include #include "cmsis_compiler.h"
int main(void){ while(1) { }
return 0;}
__attribute__((noreturn))void exit(int err_code) { while(1) { __NOP(); }}
  • GCC要求main函數(shù)的返回值是 int 類型,而這里的返回值會(huì)被作為 exit() 函數(shù)的傳入?yún)?shù)——一般負(fù)數(shù)表示出錯(cuò),0表示平安。

  • 如果不實(shí)現(xiàn)一個(gè) exit()?函數(shù),鏈接器會(huì)報(bào)錯(cuò)。

  • __attribute__((noreturn)) 就是字面意思,告訴編譯器這個(gè)這個(gè)函數(shù)是有去無(wú)回的。

  • 為了使用類似 __NOP() 這樣的“固有函數(shù)(intrinsics)”,我們需要直接或者間接的包含頭文件? "cmsis_compiler.h"


此外,如果我們不做任何的設(shè)置,MDK會(huì)將所有生成的中間文件(比如 .o、.d之類)直接保存到工程文件夾下,產(chǎn)生“垃圾遍布”的感覺:

為了解決這一問題,我們可以在"Options for Target"窗口的Target選項(xiàng)卡中通過“Select Folder for Objects” 來(lái)選擇一個(gè)專門的文件夾放置這些中間文件:

完成基礎(chǔ)模板的制作后,接下來(lái)我們來(lái)一一介紹一些模板在使用過程中所需要處理的細(xì)節(jié)問題:


【簡(jiǎn)單的地址空間布局、Stack和Heap的配置】

在去掉 GCC/gcc_arm.ld 文件的只讀屬性后,我們就可以借助它根據(jù)目標(biāo)芯片的實(shí)際情況描述地址空間布局,打開gcc_arm.ld,可以看到如下的內(nèi)容:



如果你的目標(biāo)芯片較為簡(jiǎn)單,比如,F(xiàn)LASH是一片完整的地址區(qū)間,則可以通過修改__ROM_BASE的方式來(lái)設(shè)置目標(biāo)鏡像中FLASH的起始地址,通過修改修改__ROM_SIZE來(lái)設(shè)置FLASH的實(shí)際大小,比如,起始地址為0x0800-0000,大小為256K的Flash對(duì)應(yīng)的修改方式為:

/*---------------------- Flash Configuration ---------------------------------- Flash Configuration Flash Base Address <0x0-0xFFFFFFFF:8> Flash Size (in Bytes) <0x0-0xFFFFFFFF:8> -----------------------------------------------------------------------------*/__ROM_BASE = 0x08000000;__ROM_SIZE = 0x00040000;同理,SRAM的起始地址和大小可以通過__RAM_BASE__RAM_SIZE來(lái)設(shè)置,這里就不再贅述:

/*--------------------- Embedded RAM Configuration ---------------------------- RAM Configuration RAM Base Address <0x0-0xFFFFFFFF:8> RAM Size (in Bytes) <0x0-0xFFFFFFFF:8> -----------------------------------------------------------------------------*/__RAM_BASE = 0x20000000;__RAM_SIZE = 0x00020000;最后,關(guān)于StackHeap大小的設(shè)置可以借助__STACK_SIZE__HEAP_SIZE來(lái)設(shè)置:

/*--------------------- Stack / Heap Configuration ---------------------------- Stack / Heap Configuration Stack Size (in Bytes) <0x0-0xFFFFFFFF:8> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8> -----------------------------------------------------------------------------*/__STACK_SIZE = 0x00000800; /* 2K Byte */__HEAP_SIZE??=?0x00000200;???/* 256 Byte */

【如何配置中斷向量表】

不同的芯片擁有不同的中斷向量表,而此前我們所建立的gcc工程模板中,startup_ARMCM7.c 里定義的其實(shí)是一個(gè)默認(rèn)的中斷向量表:


可以看到,這一向量表完全采用的是C語(yǔ)言函數(shù)指針數(shù)組初始化的形式定義的。它不僅提供了默認(rèn)的各類系統(tǒng)異常的定義,還以Interruptn_Handler的形式為我們提供了定義的范例。

更新這一文件的步驟并不復(fù)雜。實(shí)際上一般芯片公司都會(huì)提供符合CMSIS規(guī)范的芯片頭文件,這一頭文件中會(huì)提供對(duì)應(yīng)的中斷向量定義,比如STM32F746就有一個(gè)對(duì)應(yīng)的頭文件 STM32F746xx.h。將其打開會(huì)看到專門的向量表定義:
/** * @brief STM32F7xx Interrupt Number Definition, according to the selected device * in @ref Library_configuration_section */typedef enum{/****** Cortex-M7 Processor Exceptions Numbers ****************************************************************/ NonMaskableInt_IRQn = -14, /*!< 2 Non Maskable Interrupt */ MemoryManagement_IRQn = -12, /*!< 4 Cortex-M7 Memory Management Interrupt */ BusFault_IRQn = -11, /*!< 5 Cortex-M7 Bus Fault Interrupt */ UsageFault_IRQn = -10, /*!< 6 Cortex-M7 Usage Fault Interrupt */ SVCall_IRQn = -5, /*!< 11 Cortex-M7 SV Call Interrupt */ DebugMonitor_IRQn = -4, /*!< 12 Cortex-M7 Debug Monitor Interrupt */ PendSV_IRQn = -2, /*!< 14 Cortex-M7 Pend SV Interrupt */ SysTick_IRQn = -1, /*!< 15 Cortex-M7 System Tick Interrupt *//****** STM32 specific Interrupt Numbers **********************************************************************/ WWDG_IRQn = 0, /*!< Window WatchDog Interrupt */??... SPDIF_RX_IRQn = 97, /*!< SPDIF-RX global Interrupt */} IRQn_Type;這里,WWDG_IRQnSPDIF_RX_IRQn之間的每一項(xiàng)都對(duì)應(yīng)一個(gè)外設(shè)中斷,可以將它們拷貝出來(lái),添加到我們的startup_ARMCM7.c的向量表中,并依樣畫葫蘆,修改成對(duì)應(yīng)的形式:

.../*---------------------------------------------------------------------------- Exception / Interrupt Handler *----------------------------------------------------------------------------*//* Exceptions */void NMI_Handler (void) __attribute__ ((weak, alias("Default_Handler")));void HardFault_Handler (void) __attribute__ ((weak));void MemManage_Handler (void) __attribute__ ((weak, alias("Default_Handler")));void BusFault_Handler (void) __attribute__ ((weak, alias("Default_Handler")));void UsageFault_Handler (void) __attribute__ ((weak, alias("Default_Handler")));void SVC_Handler (void) __attribute__ ((weak, alias("Default_Handler")));void DebugMon_Handler (void) __attribute__ ((weak, alias("Default_Handler")));void PendSV_Handler (void) __attribute__ ((weak, alias("Default_Handler")));void SysTick_Handler (void) __attribute__ ((weak, alias("Default_Handler")));/*void Interrupt0_Handler (void) __attribute__ ((weak, alias("Default_Handler")));...void Interrupt9_Handler (void) __attribute__ ((weak, alias("Default_Handler")));*/void WWDG_IRQn_Handler (void) __attribute__ ((weak, alias("Default_Handler")));...void?SPDIF_RX_IRQn_Handler??(void)?__attribute__?((weak,?alias("Default_Handler")));
...
extern const VECTOR_TABLE_Type __VECTOR_TABLE[240]; const VECTOR_TABLE_Type __VECTOR_TABLE[240] __VECTOR_TABLE_ATTRIBUTE = { (VECTOR_TABLE_Type)(
本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

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

關(guān)鍵字: 阿維塔 塞力斯 華為

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

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

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

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

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

關(guān)鍵字: 騰訊 編碼器 CPU

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

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

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

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

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

關(guān)鍵字: 通信 BSP 電信運(yùn)營(yíng)商 數(shù)字經(jīng)濟(jì)

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

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

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

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉