內容提要
1.1 基於ARM CoreSight調試技術AHB-AP實現SEGGER J-LINK上位機軟體與目標MCU的 RTT高速通信1.2 基於目標MCU內存中RTT控制塊結構體實現實時數據讀寫管理1.5 RTT支持的內核和與上位機軟體通信連接以及文本顏色輸出2. GEGGER RTT在S32K1xx系列MCU平臺上的移植2.1 創建一個S32K144的S32DS IDE應用工程(配置NO I/O support,NewLib,選擇Segger Debugging Interface作為Debugger)2.3 為編譯目標添加C編譯器Includes路徑和編譯配置(Build Configurations)2.6 連接J-LINK上位軟體顯示RTT上行數據和發送下行數據傳統的重定向實現方式為調試器半主機模式( debugger semi-host mode)和MCU串行通信外設(比如UART或者USB等)兩種,前者會佔用調試通信帶寬,且脫離調試器連接無法工作,後者雖然可以離線(斷開調試器)運行,但需要佔用寶貴的MCU串行通信外設資源,因此實現效果都不理想。最近,我無意間發現SEGGER公司(就是大名鼎鼎的ARM內核處理器和微控制器(CPU/MPU/MCU)調試器--JLINK的設計和生產廠家,PS:由於價廉物美的山寨J-LINK調試器在國內某寶上鋪天蓋地的銷售,使其成為國內基於ARM內核嵌入式MCU開發者的必備神器)提供了一個名為實時傳輸(RTT--Real Time Transfer)技術,很好地解決了以上傳統方案的不足--功能強大,性能卓越,令人印象深刻。本文就給大家詳細介紹一下SEGGER RTT的實現原理和應用以及其在NXP S32K1xx MCU平臺(以S32K144為例)上的移植方法和過程,希望對大家有所幫助和啟發。SEGGER的實時傳輸(RTT)是一種用於嵌入式應用程式中的交互式用戶I / O的技術。它以很高的性能結合了SWO和半主機的優點。使用RTT,可以從目標微控制器輸出信息,以及以很高的速度將輸入發送到應用程式,而不會影響目標的實時性。SEGGER RTT可與任何J-Link模型和支持後臺內存訪問的任何受支持的目標處理器一起使用,這些處理器是Cortex-M和RX目標。RTT在雙向上都支持多個通道,直至主機和目標,都可以用於不同目的,並為用戶提供最大的自由度。默認實現是每個方向使用一個通道,該通道用於可列印的終端輸入和輸出。使用J-Link RTT Viewer,此通道可用於多個「虛擬」終端,從而僅使用一個目標緩衝區即可列印到多個窗口(例如,一個用於標準輸出,一個用於錯誤輸出,一個用於調試輸出)。例如,可以使用一個附加的(主機)通道來發送概要分析或事件跟蹤數據(例如SEGGER SystemView)。1.1 基於ARM CoreSight調試技術AHB-AP實現SEGGER J-LINK上位機軟體與目標MCU的 RTT高速通信在ARM Cortex M系列MCU內核中,使用CoreSight調試技術,通過集成的眾多片上調試和跟蹤組件(包括FPB、DWT、ITM、SWV、ETM、TPIU、CTI、MTB等) 支持傳統的IEEE-1149.1標準四線邊界掃描(JTAG)和兩線串行線調試(SWD)接口協議:在具體實現時,CorrSight技術使用不同的DP(Debug Port,調試埠)實現對JTAG和SWD接口的支持,使用不同的AP(Access Port,訪問接口)對目標MCU的內核和外設以及存儲器資源的訪問:上圖中,AHB-AP通過AHB總線連接到MCU內部的系統AHB總線矩陣,從而可以對MCU片上高速外設(比如ENET,DMA)和存儲器(SRAM 和 Flash)進行高速讀寫訪問;而APB-AP連接到MCU的APB總線,因此可以對MCU片上外設模塊寄存器進行實時讀寫訪問。由於MCU片上外設和儲存器都是統一內存地址映射(Memry Map)的,所以AHB-AP和APB-AP通常也被稱作存儲器訪問接口(MEM-AP),因此,在ARM內核的一些文檔中也會看到如下的ARM調試接口框圖:Tips:ARM Cortex M系列內核使用的Armv6-M、Armv7-M和Armv8-M以及Armv7-A/R和Armv8-A/R內核架構對CoreSight規範的ARM調試接口(ADI--ARM Debug Interface)支持情況如下表:Tips:具體ARM Cortex M系列內核支持的調試和跟蹤功能對比如下表:從以上介紹可知,外部調試器(比如SEGGER的J-LINK)通過ARM內核的集成的AHB-AP能夠對目標MCU片內的存儲器進行高速訪問,而不影響MCU實時性。SEGGER的RTT正是通過ARM CoreSight調試技術AHB-AP實現PC主機與目標MCU之間的RTT通信的。在實際應用中,可以使用不同的應用程式與目標MCU上的RTT進行通信。該功能甚至可以使用J-Link SDK集成到自定義應用程式中。在目標應用程式中使用RTT非常容易。實施代碼可免費下載,並可集成到任何現有應用程式中。要通過RTT進行通信,可以使用任何J-Link。通過終端(通道0)進行通信的簡單方法是,當與J-Link的連接(例如通過調試會話)處於活動狀態時,使用Telnet客戶端或類似客戶端創建與localhost:19021的連接。J-Link軟體包隨附了一些用於不同目的的更高級的應用程式。1.2 基於目標MCU內存中RTT控制塊結構體實現實時數據讀寫管理實時傳輸使用如下圖實現在目標MCU內存(SRAM)中的SEGGER RTT控制塊結構來管理數據讀取和寫入。該控制塊包含一個ID,以使其可以通過連接的J-Link在內存中找到;每個可用通道的環形緩衝區結構(ring buffer structure)均描述了該通道緩衝區及其狀態。可用通道的最大數量可以在編譯時配置,每個緩衝區可以在運行時由應用程式配置和添加。上行(Up, 目標MCU => J-LINK調試器PC端軟體)和下行(Down, J-LINK調試器PC端軟體 => 目標MCU)緩衝區可以分別處理。(該圖顯示了目標中的簡化結構。可以有任意數量的「下緩衝區描述符」(目標->主機),也可以有任意數量的「下緩衝區描述符」(主機->目標)。每個緩衝區大小可以單獨配置。緩衝區中的灰色區域是包含有效數據的區域。對於Up緩衝區,寫指針由目標寫入,讀指針由調試探針(J-Link,主機)寫入。當讀寫指針指向同一元素時,緩衝區為空。這確保了永遠不會出現競爭狀況。)可以將每個通道配置為阻塞(blocking)或非阻塞(non-blocking)模式。在阻塞模式下,應用程式將在緩衝區已滿時等待,直到可以寫入所有內存為止,從而導致應用程式處於阻塞狀態,但可以防止數據丟失。在非阻塞模式下,只會寫入適合緩衝區的數據,或完全不寫入緩衝區的數據,其餘的將被丟棄。即使沒有連接調試器,也可以實時運行。開發人員不必創建特殊的調試版本,並且代碼可以保留在發布應用程式中。當RTT在主機上處於活動狀態時,通過直接通過RTT Viewer之類的應用程式使用RTT或通過Telnet連接到使用J-Link的應用程式(如調試器),J-Link會自動搜索SEGGER RTT控制塊 在目標的已知RAM區域中。RAM區域或控制塊的特定地址也可以通過主機應用程式設置,以加快檢測速度,或者在無法自動找到該塊的情況下。SEGGER RTT的性能明顯高於用於將數據輸出到主機PC的任何其他技術。平均文本行可以在1微秒或更短的時間內輸出。基本上只有一次執行一次memcopy()的時間。(*上圖中速度比較是在168 MHz的STM32F407 Cortex-M4上完成的。printf()調用的開銷已刪除)SEGGER RTT將輸出數據發送到主機的最大速度取決於目標緩衝區大小和目標接口速度。即使使用較小的512位元組目標緩衝區,在高接口速度的情況下,RTT速度也可能高達1 MB/s,而在常規J-Link模型中,RTT速度可能達到0.5 MB/s。使用不同版本(速度)J-LINK調試器和不同的RTT緩存大小配置, RTT能夠實現的最大傳輸速率如下表:② 傳輸緩存大小(Transfer Buffer Size)RTT上行通道的緩衝區可能相對較小。所需的最小緩衝區大小可以通過一毫秒內寫入的數據量和一次寫入操作中寫入的最大值來近似。如果數據發送頻率較低,則緩衝區應有足夠的空間容納一次寫入發送的數據。如果更頻繁地發送數據,則緩衝區大小應足以在一毫秒內寫入最大數據量。下圖顯示了每100 us和每1 ms發送一次均勻分布的不同數量的數據時所需的最小緩衝區大小。(使用J-Link PRO V4 @ 36 MHz JTAG速度測得的值。目標:運行頻率為168 MHz的SEGGER emPower評估板(MCU為NXP K66))
RTT實現代碼在RAM中的控制塊上每通道使用〜500位元組的ROM和24位元組的ID + 24位元組。每個通道都需要一些內存用於緩衝區(RAM)。根據輸入/輸出的負載,建議的大小對於上行通道為1 kByte,對於下行通道為16至32 Byte。Memory
Usage
ROM Usage
~500 Bytes
RAM Usage
24 Bytes fixed + (24 + SizeofBuffer) Bytes / channel
SEGGER RTT實現是用ANSI C編寫的,並且可以使用該代碼集成到任何嵌入式應用程式中,這些代碼可從SEGGER官網下載。可以通過簡單易用的API使用RTT。甚至可以重寫標準的printf()函數以使用RTT。使用RTT可將printf()所需的時間減至最少,並允許在應用程式執行時間緊迫的實時任務時將調試信息列印到主機PC。SEGGER RTT實現包括printf()的簡單實現,可用於通過RTT寫入格式化的字符串。SEGGER_RTT_Printf()比大多數標準庫printf實現要小,並且不需要堆,只需要可配置數量的堆棧。SEGGER RTT實施完全可以使用預處理程序定義進行配置。可以使用Lock()和Unlock()例程使讀取和寫入任務安全,可以輕鬆設置緩衝區的數量以及終端緩衝區的大小。RTT目標代碼作為J-Link軟體和文檔包的一部分提供,可以從SEGGER官網(https://www.segger.com)下載安裝。可以在J-LLINK軟體包的以下位置找到RTT原始碼:Samples / RTT。下圖為J-LINK軟體安裝後RTT所在的目錄:Root Directory - Examples - Main_RTT_InputEchoApp.c - Sample application which echoes input on Channel 0. - Main_RTT_MenuApp.c - Sample application to demonstrate RTT bi-directional functionality. - Main_RTT_PrintfTest.c - Sample application to test RTT small printf implementation. - Main_RTT_SpeedTestApp.c - Sample application for measuring RTT performance. embOS needed. - RTT - SEGGER_RTT.c - The RTT implementation. - SEGGER_RTT.h - Header for RTT implementation. - SEGGER_RTT_Conf.h - Pre-processor configuration for the RTT implementation. - SEGGER_RTT_Printf.c - Simple implementation of printf to write formatted strings via RTT. - Syscalls - RTT_Syscalls_GCC.c - Low-level syscalls to retarget printf() to RTT with GCC / Newlib. - RTT_Syscalls_IAR.c - Low-level syscalls to retarget printf() to RTT with IAR compiler. - RTT_Syscalls_KEIL.c - Low-level syscalls to retarget printf() to RTT with KEIL/uVision compiler. - RTT_Syscalls_SES.c - Low-level syscalls to retarget printf() to RTT with SEGGER Embedded Studio.RTT為用戶提供了以下RTT初始化和讀寫操作的API函數:Tips:RTT中用於printf()的底層函數通常很容易被覆蓋,以提供自己的輸出函數。SEGGER RTT實現包包括GCC/Newlib,IAR和KEIL MDK所需的代碼,這些代碼可以簡單地包含在實際應用工程中,從而將printf()重定向到通過RTT輸出數據。另外,SEGGER RTT實現包包括printf()的簡化版本SEGGER_RTT_printf(),可用於直接通過RTT列印格式化的字符串,而無需使用標準庫,從而節省空間,減少Flash存儲器佔用。1.5 RTT支持的內核和與上位機軟體通信連接以及文本顏色輸出RTT能夠被用於J-LINK調試器支持的任意允許運行時後臺內存訪問(background memory access)的MCU,包括基於以下CPU內核的MCU:除了運行外部Telnet客戶端,RTT也可以通過以下兩種方式中的任何一種直接集成到任何PC應用程式中,例如調試軟體。① 通過RTT Telnet伺服器的套接字連接(在localhost:19021上監聽);② 使用J-Link SDK的一部分J-Link RTT API直接配置RTT並獲取/發送數據。通過RTT讀取的所有數據的刷新都和從目標讀取的一樣無任何修改。從而,允許應用程式處理ANSI控制序列列印以粗體顯示RTT數據或更改其顏色。Linux控制臺原生支持在終端應用程式中處理ANSI控制序列。在Windows上,需要一個包裝程序如ANSICON(http://adoxa.altervista.org/ansicon),然後在調用RTT客戶端。當然,某些Telnet應用程式(如PuTTY)也支持Windows上的ANSI控制序列。2. GEGGER RTT在S32K1xx系列MCU平臺上的移植有了以上對SEGGER RTT的了解,接下來,我們將其移植到NXP的S32K1xx系列MCU上,並對其進行配置和測試。 2.1 創建一個S32K144的S32DS IDE應用工程(配置NO I/O support,NewLib,選擇Segger Debugging Interface作為Debugger)為了支持SEGGER RTT,在新建S32DS應用工程時,需要選擇使用NewLib庫,No I/O support,且選擇Segger Debugging Interface作為調試器(Debugger):將JLINK軟體安裝目錄下的RTT原始碼解壓,並將其中的以下5個文件添加到應用工程中(新建一個RTT目錄):在RTT的Syscalls目錄下,提供了4個不同的RTC_Syscalls_XXX.c文件實現工具鏈底層庫的系統調用(system call),以實現對GNU, IAR和Keil/uVision以及SEGGER Embedded Studio等不同工具鏈的printf()重定向支持:RTT_Syscalls_GCC.c - Low-level syscalls to retarget printf() to RTT with GCC / Newlib.RTT_Syscalls_IAR.c - Low-level syscalls to retarget printf() to RTT with IAR compiler.RTT_Syscalls_KEIL.c - Low-level syscalls to retarget printf() to RTT with KEIL/uVision compiler.RTT_Syscalls_SES.c - Low-level syscalls to retarget printf() to RTT with SEGGER Embedded Studio.這裡,由於S32DS IDE使用的是GCC編譯器,所以選擇添加RTC_Syscalls_GCC.c即可。2.3 為編譯目標添加C編譯器Includes路徑和編譯配置(Build Configurations)
首先,需要在應用工程的工程屬性配置中,將上一步添加的RTT原始碼文件夾路徑添加所使用編譯目標的C編譯器Includes中:然後,再選中應用工程,右鍵 --> 選擇Build Configurations Explorer:在彈出的Build configuration窗口中,將RTT源文件添加到編譯目標的編譯列表中:在SEGGER_RTT_Conf.h中提供了RTT的配置選項,包括:SEGGER_RTT_MAX_NUM_UP_BUFFERS:最大上行緩存數量,默認為3;
SEGGER_RTT_MAX_NUM_DOWN_BUFFERS:最大下行緩存數量,默認為3;
BUFFER_SIZE_UP:上行緩存大小,默認為1024位元組
BUFFER_SIZE_DOWN:下行緩存大小,默認為16位元組
SEGGER_RTT_PRINTF_BUFFER_SIZE:RTT printf()緩存大小,默認為64位元組
SEGGER_RTT_MODE_DEFAULT:RTT內存塊工作模式;默認為SEGGER_RTT_MODE_NO_BLOCK_SKIP(非阻塞跳過);
用戶可以根據自己的實際需求,對這些參數進行配置,也可以使用其默認配置工作。其中,RTT內存塊工作模式工作模式可以配置為以下三種之一:#define SEGGER_RTT_MODE_NO_BLOCK_SKIP (0) // Skip. Do not block, output nothing. (Default)#define SEGGER_RTT_MODE_NO_BLOCK_TRIM (1) // Trim: Do not block, output as much as fits.#define SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL (2) // Block: Wait until there is space in the buffer.前面兩種都是非阻塞方式,差別是寫入數據長度大於當前buffer中可用空間時,是跳過不寫入任何數據(SKIP),還是寫入儘量多的數據(TRIM, 比如要寫入5個字節「Hello」,而當前buffer只剩2個字節空間了,則將「He」寫入,而「llo」則被忽略);若選擇SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL ,在寫入數據長度大於當前buffer中可用空間時,RTT將阻塞CPU內核,等待buffer中的數據為J-LINK上位機取走,再寫入。這種方式雖然可以避免數據丟失,但是在脫機運行(不連接J-LINK上位機軟體)時,將會阻塞CPU運行,因此,需要特別小心。在main()函數中,首先調用SEGGER_RTT_ConfigUpBuffer() API完成對上行數據傳輸所用buffer的初始化(若使用SEGGER_RTT_Conf.h中提供的默認配置,則無需調用此API函數),然後就可以調用SEGGER_RTT_WriteString() API列印輸出純字符串信息或者SEGGER_RTT_printf() API格式化輸出用戶想要列印的任意調試信息了:/* Initialize and configure clocks */ CLOCK_SYS_Init(g_clockManConfigsArr, CLOCK_MANAGER_CONFIG_CNT, g_clockManCallbacksArr, CLOCK_MANAGER_CALLBACK_CNT); CLOCK_SYS_UpdateConfiguration(0U, CLOCK_MANAGER_POLICY_AGREEMENT);
/* Initialize pins */ PINS_DRV_Init(NUM_OF_CONFIGURED_PINS, g_pin_mux_InitConfigArr);
ADC_Init(&adc_pal1_instance, &adc_pal1_InitConfig0);
/* initialize the RTT buffer with buffer index */ SEGGER_RTT_ConfigUpBuffer(0, NULL, NULL, 0, SEGGER_RTT_MODE_NO_BLOCK_SKIP);
/* send the command prompt information at first */ SEGGER_RTT_WriteString(0, USR_CMD_STR);
while(1) { PINS_DRV_TogglePins(PTD, 1<<RGB_BLUE_LED_PIN); /* toggle the blue RGB LED*/
OSIF_TimeDelay(50);/* delay 10ms */
/* call SEGGER_RTT_printf() API to print any debug information you need */ SEGGER_RTT_printf(0, "\r\nThe SEGGER RTT is running, and main looped %d times!\r\n", cnt++);
/* start the ADC conversion */ ADC_StartGroupConversion(&adc_pal1_instance, 0);
/* wait for ADC conversion complete */ while(false == ADC_Conversion_Finish_Flag);
/* call SEGGER_RTT_printf() API to print any debug information you need */ SEGGER_RTT_printf(0, "The ADC conversion finished, and the voltage is 0x%x .\r\n", adc_pal1_Results00[0]);
ADC_Conversion_Finish_Flag = false;/* clean the flag */
/* get the user input */ SEGGER_RTT_Read(0, &get_user_input, 1); if(0 != get_user_input) { /* ACK the received command */ SEGGER_RTT_printf(0, "char '%c' received.\r\n\r\n", get_user_input);
/* toggle RGB LED on S32K144-EVB according to the user input */ switch(get_user_input) { case 'R': PINS_DRV_TogglePins(RGB_LED_GPIO, 1<<RGB_RED_LED_PIN); break; case 'G': PINS_DRV_TogglePins(RGB_LED_GPIO, 1<<RGB_GREEN_LED_PIN); break; case 'B': PINS_DRV_TogglePins(RGB_LED_GPIO, 1<<RGB_BLUE_LED_PIN); break; defualt: break; } } }Tips:在調用RTT API函數的C文件中需要包含其聲明頭文件--SEGGER_RTT.h:2.6 連接J-LINK上位軟體顯示RTT上行數據和發送下行數據完成以上配置後,用J-LINK調試器將應用工程編譯連結生成的elf文件下載到S32K144-EVB,RTT即可開始工作。在Win10桌面的右下角,雙擊J-LINK進程圖標,即可打開J-LINK狀態和控制界面(J-Link - Web control panel:http://localhost:19080/general.htm):J-Link - Web control panel默認頁面如下:選擇打開RTT顯示和控制界面,選擇正確的Target -> Host channel(Show data for channel),並點擊「Start」啟動與目標MCU的RTT通信連接:Tips:以上J-LINK進程圖標會在J-LINK與目標MCU連接時出現,比如S32DS下載在線調試時或者通過JLINK軟體單獨啟動J-LINK時。若已經斷開S32DS的J-LINK調試連接,大家還可以使用J-LINK提供的J-LINK Commander連接目標MCU,從而打開RTT顯示和控制界面,其步驟如下:① 在Windows開始菜單中選擇打開SEGGER J-LINK Commander:② 在 J-LINK Commander窗口中,輸入命令「connect」,並輸入正確的目標MCU part number(S32K144),調試接口(S: SWD)和通信速度(4000 Kbbit/s),即可建立與目標MCU的通信連接:③ 以上連接會復位目標MCU並暫停其運行,此時輸入命令「g」運行MCU,輸入命令「h」暫停MCU運行:MCU運行後,即可打開J-LINK RTT顯示和控制界面。若在MCU運行時,停止J-LINK RTT連接(點擊下圖中的Stop按鍵),則會錯過這段時間內目標MCU輸出的上行數據。Tips:當然,大家也可以參考1.5 RTT支持的內核和與上位機軟體通信連接以及文本顏色輸出小節,使用其他串行終端軟體,建立與目標MCU上運行RTT的通信連接,從而實現上行數據顯示和下行命令發送。本文詳細介紹了SEGGER RTT的實現原理和應用以及其在NXP S32K1xx MCU平臺(以S32K144為例)上的移植方法和過程,希望對大家有所幫助和啟發。為了幫助大家更好地掌握本文介紹的知識和內容,我已將文中介紹的S32K144 RTT移植S32DS IDE(S32DS for ARM v2.2 + S32K1xx SDK RTM 3.0)應用工程分享到如下NXP community,供大家參考學習:https://community.nxp.com/t5/S32K-Knowledge-Base/SEGGER-Real-Time-Transfer-RTT-porting-on-S32K144-S32DS-for-ARM/ta-p/1185287;https://www.segger.com/products/debug-probes/j-link/technology/about-real-time-transfer/
https://wiki.segger.com/RTT#SEGGER_RTT_TerminalOut.28.29;
Using Segger Real Time Terminal (RTT) with Eclipse:https://mcuoneclipse.com/2015/07/07/using-segger-real-time-terminal-rtt-with-eclipse/
本公眾號近期文章精選推薦(點擊文章標題即可直接跳轉閱讀):
1. 深入淺出談嵌入式MCU 內核之ARM Cortex-M系列CPU內核功能特性概述與對比(強烈推薦!!!);
2. 深入淺出談嵌入式MCU 內核之ARM Cortex-M系列CPU內核特權模式定義與切換方法詳解;
3. 淺談嵌入式MCU軟體開發之MCU在線調試功能正常而離線工作異常原因探究(以NXP汽車MCU為例);
4. S32K1xx ECU bootloader開發之RAM NVM驅動(S19文件)生成與集成調用和測試詳解;
5. 汽車電子ECU bootloader開發之S32K1xx系列MCU NVM驅動獨立安全bootloader開發詳解;
6. S32K1xx系列MCU應用指南之FlexCAN模塊功能與應用詳解;
7. S32K SDK使用詳解之can_pal組件和flexcan組件使用詳解(含RxFIFO DMA和ID濾波器以及總線關閉恢復等);
8. 淺談嵌入式MCU軟體開發之S32K1xx系列MCU的啟動過程和啟動時間優化方法詳細;
更多精彩文章,請進入本公眾號主頁,通過分類菜單訪問或者點擊以下歷史文章分類列表目錄獲取閱讀連結:
《歷史文章分類列表目錄(點擊文章標題即可直接跳轉閱讀,截止2020年11月15日)》;
原創寫作不易, 如果大家覺得本文對你的工作和學習有幫助,也歡迎大家讚賞鼓勵----我將堅持寫作,給大家帶來更多精彩的原創文章。
Tips:點擊本文文末的「喜歡作者」對本文進行讚賞或者「在看」進行分享,並留言提問,我將第一時間回復大家的關切!
歡迎在此與我一起學習/探討汽車電子和嵌入式系統軟硬體設計相關的技術。若對本公眾號或者分享的文章觀點有任何意見和建議也歡迎留言指出。您的點讚/關注/轉發分享是對我辛勤寫作的最大支持和肯定!
本公眾號已開通關鍵詞回復功能,請在公眾號主頁回復如下關鍵詞以獲取更多信息和精彩文章:
關於作者,請回復關鍵詞「作者簡介」;
聯繫作者,請回復關鍵詞「聯繫作者」;
獲取高清PDF版本公眾號文章,請回復關鍵詞「獲取文章」;
獲取專業及時的技術支持服務,請回復關鍵詞「專業服務」;
下載2017~2018年度原創技術文章集合高清PDF,請回復關鍵詞「文章全集」;
CodeWarrior IDE license購買及安裝使用問題諮詢,請回復關鍵詞「CW License」;
汽車乙太網轉工業乙太網轉換器購買,請回復關鍵詞「乙太網轉換器購買」;
獲取最新最全的公眾號原創技術分享文章目錄,請回復關鍵詞「文章目錄」;
鄭重聲明:本公眾號所有原創技術文章免費閱讀,文中所有觀點/結論均為個人觀點,不代表任何公司官方觀點意見;所有demo代碼/程序,僅作參考學習,不保證質量,若用於商業用途,責任自負;所有本公眾號文章,版權歸本人所有智慧財產權,一切未經本人同意的轉載均屬違法,盜版必究~!如果你喜歡本公眾號的文章,請點擊文章最開始的公眾號關注或微信直接長按掃描識別下方二維碼關注,你也可以在微信添加朋友-->公眾號-->輸入"汽車電子expert成長之路"搜索-->點擊關注。若對本文觀點有任何意見和建議也歡迎留言指出。
您的關注、點讚、轉發分享是對我辛勤寫作的最大肯定!
另外,我在這裡也鄭重推薦大家掃描下方二維碼(長按掃描識別下方二維碼關注),下載專注於汽車電子技術分享和知識學習服務的「涅槃汽車APP」,同步閱讀我的汽車電子與嵌入式MCU軟硬體系統開發原創技術分享系列文章專輯(我後期的所有原創技術分享文章都將同步更新到此APP,在這裡能夠找到眾多汽車電子從業同行和業界專家大咖,大家一起交流學習!)Enwei Hu(胡恩偉)
2020年11月18日於山城·重慶