創建字符設備
1 創建設備號
alloc_chrdev_region
2.創建cdev
cdev_init
3.添加一個 cdev,完成字符設備注冊到內核
cdev_add
4.創建類
class_create
5.創建設備
device_create
1.內核空間與用戶空間數據
copy_from_use
r 和copy_to_use
r 倆個函數來完成。
copy_from_use
r 函數是將用戶空間的數據拷貝到內核空間。
copy_to_user
函數是將內核空間的數據拷貝到用戶空間
2.container_of 函數
通過結構體變量中某個成員的首地址進而獲得整個結構體變量的首地址
container_of(ptr,type,member)
參數含義:
ptr 是結構體變量中某個成員的地址。
type 是結構體的類型
member 是該結構體變量的具體名字
3.并發與競爭
3.1什么是競爭?
多個程序同時訪問一個共享資源產生的問題就叫做競爭。競爭產生的根本原因就是 Linux 系統的并發訪問
競爭產生的原因如下所示:
(1)多線程的并發訪問
(2)中斷程序的并發訪問
(3)搶占式并發訪問
3.2什么是并發?
所謂并發,就是通過算法將 CPU 資源合理地分配給多個任務,當一個任務執行 I/O 操作
時,CPU 可以轉而執行其它的任務,等到 I/O 操作完成以后,或者新的任務遇到 I/O 操作時,CPU 再回到原來的任務繼續執行
3.3解決競爭問題
原子操作、自旋鎖、信號量、互斥體
原子操作
只能對整形變量或者位進行保護,而對于結構體或者其他類型的共享資源,原子操作就力不從心了
自旋鎖
是為了保護共享資源提出的一種鎖機制。自旋鎖(spin lock)是一種非阻塞鎖,也就是說,如果某線程需要獲取鎖,但該鎖已經被其他線程占用時,該線程不會被掛起,而是在不斷的消耗 CPU 的時間,不停的試圖獲取鎖
自旋鎖死鎖發生存在兩種情況
:
進程 A 擁有自旋鎖,中斷到來,CPU 執行中斷函數,中斷處理函數,中斷處理函數需要獲得自旋鎖,訪問共享資源,此時無法獲得鎖,只能自旋,從而產生死鎖
對于中斷引發的死鎖,最好的解決方法就是在獲取鎖之前關閉本地中斷,Linux 內核在
“/include/linux/spinlock.h”
文件中提供了相應的 API 函數
信號量
也是解決競爭的一種常用方法,與自旋鎖不同的是,信號量會使等待的線程進入休眠狀態,適用于那些占用資源比較久的場合
互斥鎖
會導致休眠,所以在中斷里面不能用互斥鎖。同一時刻只能有一個線程持有互斥鎖,并且只有持有者才可以解鎖,并且不允許遞歸上鎖和解鎖
4.Linux 定期器
硬件為內核提供了一個系統定時器來計算流逝的時間(即基于未來時間點的計時方式,以當前時刻為計時開始的起點,以未來的某一時刻為計時的終點),內核只有在系統定時器的幫助下才能計算和管理時間,但是內核定時器的精度并不高,所以不能作為高精度定時器使用。并且內核定時器的運行沒有周期性,到達計時終點后會自動關閉。如果要實現周期性定時,就要在定時處理函數中重新開啟定時器
補充:高級定時器
5.Linux 內核打印
dmseg 命令
查看 kmsg 文件,cat /proc/kmsg
調整內核打印等級cat /proc/sys/kernel/printk
6.驅動調試方法
printk 函數打印
dump_stack 函數
WARN_ON(condition)函數
7.中斷
中斷是指在 CPU 正常運行期間,由外部或內部事件引起的一種機制。當中斷發生時,CPU會停止當前正在執行的程序,并轉而執行觸發該中斷的中斷處理程序。處理完中斷處理程序后,CPU 會返回到中斷發生的地方,繼續執行被中斷的程序。中斷機制允許 CPU 在實時響應外部或內部事件的同時,保持對其他任務的處理能力
7.1中斷的上下半部
中斷上文
是中斷服務程序的第一部分
它主要處理一些緊急且需要快速響應的任務,包括保存寄存器狀態、更新計數器等,以便在中斷處理完成后能夠正確地返回到中斷前的執行位置
中斷下文
是中斷服務程序的第二部分
中斷下文負責處理那些不能立即完成的、需要更多時間的任務。這些任務可
能包括復雜的計算、訪問外部設備或進行長時間的數據處理等
中斷下文的一種實現方式——tasklet
Tasklet 綁定的函數在同一時間只能在一個 CPU 上運行,因此不會出現并發沖突,tasklet 綁定的函數中不能調用可能導致休眠的函數,否則可能引起內核異常
一般步驟:
首先定義了 my_tasklet_handler 作為 tasklet 的處理函數。
然后,聲明了一個名為 my_tasklet 的 tasklet 結構體,
并使用 tasklet_init 函數對其進行初始化。調用 tasklet_schedule 函數,我們調度(觸發)了 my_tasklet 的執行。調度 tasklet 只是將 tasklet 標記為需要執行,并不會立即執行 tasklet 的處理函數。實際的執行時間取決于內核的調度和處理機制
7.2中斷子系統框架
由上到下分別為用戶層、通用層、硬件相關層和硬件層
7.3中斷控制器 GIC
中斷控制器 GIC(Generic Interrupt Controller)是中斷子系統框架硬件層中的一個關鍵組件,用于管理和控制中斷,接收來自各種中斷源的中斷請求,并根據預先配置的中斷優先級、屏蔽和路由規則,將中斷請求分發給適當的處理器核心或中斷服務例程
7.4中斷線程化
將中斷處理程序從主線程中獨立出來,創建一個專門的線程來處理這些中斷事件。
這樣,主線程就不再受到中斷的干擾,可以專注于自己的工作,不再頻繁地被打斷。
中斷線程化的核心思想是將中斷處理和主線程的工作分開,讓它們可以并行執行。中斷線程負責處理中斷事件,而主線程負責執行主要的工作任務。這樣一來,不僅可以減少切換的開銷,還可以提高整個程序的響應速度和性能
中斷線程化的處理仍然可以看作是將原來的中斷上半部分和中斷下半部分。上半部分還是用來處理緊急的事情,下半部分也是出路比較耗時的操作,但是下半部分會交給一個專門的內核線程來處理。這個內核線程只用于這個中斷。當發生中斷的時候,會喚醒這個內核線程,然后由這個內核線程來執行中斷下半部分的函數
request_threaded_irq
是 Linux 內核中用于請求并注冊一個線程化的中斷處理函數的函數
int request_threaded_irq(unsigned int irq, irq_handler_t handler,
irq_handler_t thread_fn, unsigned long irqflags, const char *devname, void *dev_id);
handle
r:是在發生中斷時首先要執行的處理程序,非常類似于頂半部,該函數最后會返回 IRQ_WAKE_THREAD 來喚醒中斷,一般 handler 設為 NULL,用系統提供的默認處理
thread_fn
:線程化的中斷處理函數,非常類似于底半部。如果此處設置為 NULL 則表示沒有使用中斷線程化
8平臺總線模型
平臺總線(Platform bus)是 Linux 內核中提供的一種虛擬總線,用于管理和組織與特定硬件平臺相關的設備和驅動。它充當了平臺設備(platform device)和平臺驅(platform driver)之間的橋梁,負責將它們進行匹配和綁定。
平臺總線優勢如下所示:
(1)設備與驅動的分離
設備代碼放在device.c 文件中(或者設備樹),驅動代碼放在 driver.c 文件中
(2)提高代碼的重用性:平臺總線模型使得相同類型的設備可以共享相同的驅動代碼
(3)減少重復性代碼:在傳統的設備驅動模型中,如果有多個相同類型的設備存在,就
需要為每個設備編寫獨立的驅動代碼
9.虛擬文件系統 ConfigFS
9.1常用的虛擬文件系統
虛擬文件系統提供了一個內核抽象層,使得應用程序可以通過統一的文件訪問接口操作不同類型的文件和設備
procfs
是一個虛擬文件系統,提供了對系統內核運行時狀態的訪問接口。它以文件和目錄的形式表示內核中的進程,設備,驅動程序和其他系統信息。通過讀取和寫入 procfs 中的文件,可以獲取和修改有關系統狀態的信息
sysfs
是一個虛擬文件系統,用于表示系統中的設備,驅動程序和其他內核對象
configfs
是一個虛擬文件系統,用于動態配置和管理內核對象,允許用戶在運行時添加,修改和刪除內核對象,而無需重新編譯內核或重新啟動系統
10.設備模型基本框架-kobject 和 kset
11.pinctrl子系統
12.GPIO 子系統
13.輸入子系統
在 Linux 中,input 子系統是專門為處理輸入類設備而設計的一個子系統或框架
Input 子系統可以分為事件處理層、設備驅動層、核心層三層
固定輸入設備的設備節點:
不同廠家和型號的外設在內核啟動時加載的順序可能會不同。例如,觸摸板和 USB 轉串口等設備,這會導致在/dev/input 目錄下創建的 evdevx 節點(其中 x=0,1,2,3…)不同
解決思路如下:通過分析 evdev.c 驅動程序,我們確定設備節點是在 evdev_connect 函數中創建的。因此,只需要在 evdev_connect 函數中針對需要固定設備節點的設備單獨創建一個設備節點即可
14.調節LCD
- 查看外設Datasheet,了解電子特性、啟動時序、屏幕參數
- 查看原理圖,確定相關IO引腳
- 修改DTS
- 編譯&運行&調試
屏幕參數:
常見問題
- 在點亮屏后剛開始有開機 logo 閃爍,向右偏移了近半個屏幕的長度,等問題。
重新確認 clock-frequence 后發現少打了一個 0 ,修改后解決了閃爍大偏移的問題。 - 畫面偏移
稍微降低 hs_clk ,由 504 降低到 496 解決。 - 垂直方向會顯示多一點內容。
調整 VFP 后解決,將 VFP 增大為 15 。 - 有黑邊
稍微增大 VBP 后解決,將 VBP 增大為 15。 - 開機 android 最左邊會被裁剪一部分
增大 HBP 后解決,將 HBP 由 10 增加到 30。 - 顯示偏移、圖像位置偏差
timing 中的參數設置有誤。優先確認。
看著圖像調節前掃、回掃進行左右上下移動 - 白屏
隨機出現白屏有可能是靜電問題,把LCD拿到頭發上擦幾下,如果很容易出現白屏那肯定就是靜電問題了。另外一個在有Backend IC的情況下,也有可能bypass沒處理好。
結束開機logo至android動畫出現之間出現閃屏或者閃白光的情況。原因:在這個時間點kernel會會對屏再次初始化,我們可以軟件上屏蔽第一次初始化動作從而解決。 - 屏在進出睡眠或者顯示過程中白屏
喚醒屏幕閃白光問題,說白了是背光早亮了,很有可能是下序列mdelay太久,改小點就沒有這個問題了。根本原因屏幕初始化序列下慢了。
sleep out(0x11)和 display on(0x29)之間需要 mdelay(120ms)左右。 - 花屏
說明 lcd 初始化成功,但是沒有 rgb 刷過來。
timing 中的參數設置有誤。優先確認 pclk。
花屏 還可能是總線速度有問題。
開機就花屏最簡單的解決方式是,在 Init 結束的地方加一個刷黑屏的功能。也可以在睡眠函數里加延時函數。 - 屏幕閃爍
pclk 有問題
在最開始的時候,我的 pclk 漏了一個 0 ,為之前的 1/10 此時就有圖像閃爍問題。
proch 有問題
在調試完后,我嘗試將 proch 增加到極限,發現會出現圖像閃爍的問題。 - 屏幕抖動
測時序,延時不足 - 屏幕閃動
通過調節電壓來穩定,一般調節的電壓為VRL、VRH、VDV和VCM - 喚醒閃屏問題
這是由於每次重新RST下序列過程delay久了導致,適當減少delay時間 - 屏幕喚醒顯示灰色底面
寄存器沒有使能外部升壓電路 - 水波紋
通常都是rgb interface polarity導致,需要調整pclk hsync vsync de極性使之符合平臺極性 - 調節對比度
VRL、VRH、VDV和VCM,這些電壓也可以用來調節亮暗(對比度)
也可以通過調節Gamma值來實現,要調節的對象為 PRP、PRN、VRP、VRN 等 - 確認有沒有 framebuffer 輸出
要是改動了display這塊的clk很有可能沒有buffer輸出的,可以通過cat /dev/graphyics/fb0 查看有沒有輸出字符
如果有說明是 mipi 還沒有調通,如果沒有說明是 fb 有問題
15.調節TP
TP驅動主要是通過IIC和IC通,通過輸入子系統上報觸摸事件
tp調試時的問題排查
1.當我們調試出現問題時,首先檢查電壓;
2.在porbe 函數里面加一句打印,確認驅動已經正常注冊進系統了;
3.確認中斷是否注冊上了,可以adb shell cat /proc/interrupters
,
getevent
工具可以監聽中斷事件,如果沒有就查下打印,一般申請中斷失敗,都是IO 口被其他驅動或虛擬設備占用;
4.如果注冊上了,但是觸摸沒中斷.就用示波器勾下中斷腳是否有波形,如果沒有就代表觸摸屏本身有問題,換一個試一下;
5.如果有波形,但是adb shell cat /proc/interrupters,中斷號對應的中斷數沒有增加,一般都是中斷腳被復用為其他作用,比如PWM;
6.一般這時候上層都會有點出來,大致分為三種情況:
- 出現鼠標,或者只有一個圓圈出來,這個是屬于input 創建時候的有問題,可以參考正常的驅動;
- 出現上下或左右反了,這個是要改驅動里面的上報函數;
- 如果上下左右正常了,但是會出現無法畫到四個邊的情況,這個是屬于TP 里面的軟件問題,需要聯系TP 廠的FAE,進行修改;
16.調節WIFI
STA 模式 和 AP 模式
Sta模式: Station, 類似于無線終端,sta本身并不接受無線的接入,它可以連接到AP,一般無線網卡即工作在該模式。
AP模式: Access Point,提供無線接入服務,允許其它無線設備接入,提供數據訪問,一般的無線路由/網橋工作在該模式下。AP和AP之間允許相互連接
在使用的過程主要是wpa_suplicant和hostapd兩個命令去設置為STA和AP模式
如果需要在設置為AP模式下還需要該熱點能上網的話,就還需要橋接網口或者4G讓該熱點能上網
SDIO 接口的 WiFi,首先,它是一個 SDIO卡 設備,然后具備了 WiFi 的功能,所以 SDIO 接口的 WiFi 驅動就是在 WiFi 驅動外面套上了一個 SDIO 驅動 的外殼
mmc 子系統
設備驅動層(WiFi 設備):
|
核心層(向上向下提供接口) 注冊mmc總線,SDIO總線
|
主機驅動層(實現 SDIO 驅動)主要是針對不同的芯片使用的host的控制器,在這里面當和設備樹匹配之后,會創建一個host,把這個host添加到mmc總線上,會檢測卡是否插入(中斷檢測某個GPIO,輪詢檢測),檢測到卡之后,會注冊SDIO驅動到添加到host
WiFi驅動移植流程
- BSP已支持WiFi
- BSP未支持WiFi
WiFi驅動放到kernel里面
將供應商提供rtl8821CU WiFi驅動復制到kernel/drivers/net/wireless/rockchip_wlan/這個目錄下面,同時修改當前目錄下的Kconfig文件和Makefile文件
常見排查問題:
檢查DTS
關注時鐘、IO、WiFi_chip_type
&sdio0 {clock-frequency = <100000000>; /*時鐘修改的地方 如果SDIO讀寫識別,可調整時鐘*/clock-freq-min-max = <200000 100000000>; /*時鐘修改的地方*/supports-sdio; /*SDIO功能*/bus-width = <4>; /*4線模式,調試可改為1線測試*/disable-wp;cap-sd-highspeed; /*highspeed的SDIO外設*/cap-sdio-irq; /*SDIO中斷*/keep-power-in-suspend; /*睡眠不斷電*/mmc-pwrseq = <&sdio_pwrseq>; /*電源控制*/non-removable;num-slots = <1>;pinctrl-names = "default";pinctrl-0 = <&sdio0_bus4 &sdio0_cmd &sdio0_clk>;sd-uhs-sdr104; /* SDIO3.0 模式*/status = "okay";
};sdio_pwrseq: sdio-pwrseq {compatible = "mmc-pwrseq-simple";clocks = <&rk808 1>; /*提供32.768 LPO*/clock-names = "ext_clock"; /*外部時鐘源*/pinctrl-names = "default";pinctrl-0 = <&WiFi_enable_h>;/** On the module itself this is one of these (depending* on the actual card populated):* - SDIO_RESET_L_WL_REG_ON* - PDN (power down when low)*///控制WiFi電源的GPIOreset-gpios = <&gpio0 10 GPIO_ACTIVE_LOW>; /* GPIO0_B2 */
};wireless-wlan {compatible = "wlan-platdata";rockchip,grf = <&grf>;WiFi_chip_type = "ap6255";sdio_vref = <1800>;//控制WiFi中斷的GPIOWiFi,host_wake_irq = <&gpio0 3 GPIO_ACTIVE_HIGH>; /* GPIO0_a3 */status = "okay";
};wireless-bluetooth {compatible = "bluetooth-platdata";clocks = <&rk808 1>;clock-names = "ext_clock";//WiFi-bt-power-toggle;uart_rts_gpios = <&gpio2 19 GPIO_ACTIVE_LOW>; /* GPIO2_C3 */pinctrl-names = "default", "rts_gpio";pinctrl-0 = <&uart0_rts>;pinctrl-1 = <&uart0_gpios>;//BT,power_gpio = <&gpio3 19 GPIO_ACTIVE_HIGH>; /* GPIOx_xx */BT,reset_gpio = <&gpio0 9 GPIO_ACTIVE_HIGH>; /* GPIO0_B1 */BT,wake_gpio = <&gpio2 26 GPIO_ACTIVE_HIGH>; /* GPIO2_D2 */BT,wake_host_irq = <&gpio0 4 GPIO_ACTIVE_HIGH>; /* GPIO0_A4 */status = "okay";
};
- 排查DTS對應的GPIO設置
確定復用引腳已配置、方向配置、測試高低電平
使用io命令shell
io -4 -w 0xFF77e008 0x0fff0000
sysfs使用echo命令shell
echo xxx > /sys/class/gpio/export
echo out > /sys/class/gpio/gpioxxx/direction
echo 0 > /sys/class/gpio/gpioxxx/value
echo 1 > /sys/class/gpio/gpioxxx/value
使用debugfs查看
- 檢查電壓電平
電源電壓,VDDIO、VBAT的電壓,WiFi_REG_ON上電及復位控制信號
電源控制:
echo 0 > /sys/class/rkWiFi/power //對WiFi模塊掉電
echo 1 > /sys/class/rkWiFi/power //對WiFi模塊上電
echo 1 > /sys/class/rkWiFi/driver //命令會調用模塊的驅動的初始化操作,初始化成功后
看到wlan0 節點;
如果執行上面命令對模塊進行上下電,而實際測量對應管腳不受控,可以通過io 命令讀取對應的寄存器,確認是否寫入,如果正確寫入但是實際測量不受控請檢查硬件部分;
對于sdio接口的模塊,執行” echo 1 > /sys/class/rkWiFi/driver”命令 ,正常情況下 sdio_clk 和sdio_cmd 能夠測量到相關波形,內核打印上能夠看到如下打印,如果沒有測量到波形也沒有看到如下打印,根據配置文檔檢查是否正確配置sdio;
WL_REG_ON
主要用于上電,休眠的時候,請保持該GPIO上電,否則會丟失WiFi內部的狀態,導致WiFi喚醒失敗;
WL_HOST_WAKE
主要用于WiFi設備有數據的時候,喚醒CPU,進入中斷,關于中斷流程上面已經說過。
-
檢查時鐘
32.768K的LPO, 37.4M晶振主時鐘,SDIO_CLK、SDIO_CMD 的波形
同時測量執行echo 1 > /sys/class/rkWiFi/driver 時 外部晶體是否有起振,如果掃描時沒有起振檢查下硬件;同時建議測量外部晶體頻偏,頻偏比較大情況下,會出現能掃描到模塊但是初始化失敗;除檢查晶振外,正基系列還需要外部32k,測量32k的峰峰值(峰峰值>=0.7VDDIO && 峰峰值 <= 1VDDIO);【注:頻偏和峰峰值一定要測量檢查,頻偏過大峰峰值不對會影響WiFi(掃描連接熱點)和藍牙(掃描連接設備))】 -
嘗試單線模式
如果降低clk依然不行,考慮使用sdio單線模式方法如下
&sdio {
…
bus-width = <1>;
使用 sdio 單線模式。如果單線模式可以而使用4線模式不行,檢查硬件sdio_data0~sdio_data3 四根線的線序是否弄錯;
如果降低clk,使用單線模式均不可以檢查下是否是使用最新的sdk代碼和最新的WiFi驅動(ftp服務器上有相關patch);
上述檢查均無結果,check 圖紙 是否周圍器件有貼錯器件;
-
檢查模塊能否處于工作狀態
netcfg wlan0 up 或busybox ifconfig wlan0 up //執行完成后檢查 wlan0 是否處于up狀態;如果沒有處于up狀態;做如下檢查確認
1 確認相關固件是否存在(正基系列,通過看內核日志可以看到),固件不存在考慮到ftp下載固件;此時如果還報其他錯誤從兩個方面排查1 上電時序,2檢查sdio部分走線;
2 嘗試使用原始最新的sdk代碼做測試;(有客戶出現過,上層做了相關修改導致WiFi初始化成功,但是執行netcfg wlan0 up 報告無法識別 ioctl 命令等奇怪錯誤,原生sdk生成的sysytem.img 沒有問題)
執行iwlist wlan0 scanning ,測試掃描熱點是否正常(3368平臺下執行iwlist 命令有問題,忽略此步驟) -
確認Android層是否能夠打開
述檢查各個步驟可以工作,而通過上層settings界面打開失敗;以下幾個方面排查
1 dts中的WiFi_type配置是否正確;cat /sys/class/rkWiFi/chip 確認 下 打印的結果和你的模塊是否匹配
2 確認 wpa_supplicant 相關服務是否生成,libhardware_leacy 啟動的wpa服務是否正確;
3 抓取logcat 日志上傳readmine
其他問題
無法連接熱點
1.無法連接熱點,正基系列模塊檢查確認晶振頻偏和32k峰峰值;
rtl模塊考慮驅動配置是否正確,是否匹配;
2.檢查確認p2p wlan0 的mac地址是否一致如果檢查是否有調用rockchip_WiFi_mac_addr讀取mac地址,如果有考慮直接在該函數中return -1;
3.檢查確認是否有做RF指標測試以及天線匹配測試
4.上述檢查沒有問題,做如下測試 (首先用給手機連接所測試的熱點做確認)
1 連接無加密熱點
2 連接加密熱點 測試能否連接成功,并記錄對應的logcat 日志與內核日志(開機到打開WiFi以及連接熱點的整個過程)
softap 無法打開(正基系列的)
1.查看打開熱點時的內核日志,確認下 下載固件是否正確 ,正基系列的模塊 softap 下載的固件一般是帶ap后綴結尾的;
2.固件下載沒有問題 ,考慮使用原始的sdk代碼做測試
P2P 問題
P2p 無法打開:確認是否有p2p節點,有p2p節點的檢查確認mac地址是否與wlan0 一樣,如果一樣按照熱點問題中的step 2 處理;
第一次開機能夠打開,重啟后無法打開:考慮檢查上電時序,目前遇到都是rtl的模塊出現過,問題在于chipen 腳不受控,建議做成受控,在重啟時對chipen腳下電;可以通過如下方法實現net/rfkill-wlan.c中的rfkill_wlan_driver 中增加shutdown函數 在該函數中對chip_en 下電;
休眠喚醒出現WiFi無法打開:
1 對比檢查休眠喚醒前后 sdio 的iomux 是否發生變更
2 對比 休眠前后以及休眠中 WiFi的外圍供電是否發生變更吞吐率問題
8. pcb檢查,一定要讓模塊原廠檢查確認 pcb是否存在問題
9. RF指標確認是否ok
10. 天線是否做過匹配
11. Sdio 接口的可以考慮 提到sdio的clk 啟用sdio3.0【前提 平臺支持 sdio3.0 ,模塊支持sdio3.0】
12.常用指令
-
打開和關閉WiFi
打開WiFi指令
svc WiFi enable
關閉WiFi指令
svc WiFi disable
查看wpa_supplicant是不是已經起來了
ps | grep WiFi -
打開和關閉藍牙BT:
關閉:adb shell settings put global bluetooth_on 0
打開:adb shell settings put global bluetooth_on 1
查詢:adb shell settings get global bluetooth_on -
查詢藍牙開啟狀態:
adb shell settings get global bluetooth_on
=》0: 未開啟 1: 已開啟 -
獲取mac地址:
17.調節藍牙
藍牙一般是使用串口接口
常見問題是無法打開藍牙,可以手動拉bluez
比如使用hci命令去手動up一個hci節點,加載藍牙固件,如果能正常掃描到藍牙,基本可以確認硬件沒什么問題;其次就是要注意時鐘問題,也可能導致打不開藍牙
18.調節4G
4G按照供應商提供的文檔操作,像更新最新的代碼,添加VID,PID到USB里面,設置PPPD撥號的VPN,在Linux系統的話基本可以搞定,不需要加載ridl庫,這個是在Android中需要添加的,也是比較麻煩的。
19.調節網口
網口用的是MDIO,和RMII接口
內部 MAC 通過 MII/RMII 接口來與外部的 PHY 芯片連接,完成網絡數據傳輸
MDIO 和MDC 這兩根線訪問 PHY 芯片的任意一個寄存器
一般內核中可以使用通用的網口驅動就可以使能以太網,不過芯片商一般都會做一些針對自己家的主控的修改
一般來說主要是針對網口的燈做一些定制,這部分就要通過查看PHY芯片的手冊,修改對應的寄存器的值,phy_register_fixup_for_uid 函數,這是一個linux 中的通用函數,用于修正設置指定uid的PHY,比如:
topeet@ubuntu:~/RK_android11/rk_android11.0_sdk_211130/kernel$ git diff drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index cff46c49b72f..b08899e69dea 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -58,6 +58,13 @@#define STMMAC_ALIGN(x) ALIGN(ALIGN(x, SMP_CACHE_BYTES), 16)#define TSO_MAX_BUFF_SIZE (SZ_16K - 1)+
+#define RTL_8211F_PHY_ID 0x001cc916
+#define RTL_8211F_PHY_ID_MASK 0x001fffff
+#define RTL_8211F_PAGE_SELECT 0x1f
+#define RTL_8211F_LCR_ADDR 0x10
+#define RTL_8211F_EEELCR_ADDR 0x11
+/* Module parameters */#define TX_TIMEO 5000static int watchdog = TX_TIMEO;
@@ -4260,6 +4267,30 @@ static int stmmac_hw_init(struct stmmac_priv *priv)return 0;}+static int phy_rtl8211f_led_fixup(struct phy_device *phydev)
+{
+ u32 val, val2;
+ pr_info("terry in : %s\n", __func__);
+ /*switch to page0xd04*/
+ phy_write(phydev, RTL_8211F_PAGE_SELECT, 0xd04);
+ /*set led1(green) Link 10/100/1000M, and set led2(yellow) Link
+ 10/100/1000M+Active*/
+ val = phy_read(phydev, RTL_8211F_LCR_ADDR);
+ val |= (1<<5);
+ val |= (1<<8);
+ val &= (~(1<<9));
+ val |= (1<<10);
+ val |= (1<<11);
+ phy_write(phydev, RTL_8211F_LCR_ADDR, val);
+ /*set led1(green) EEE LED function disabled so it can keep on when linked*/
+ val2 = phy_read(phydev, RTL_8211F_EEELCR_ADDR);
+ val2 &= (~(1<<2));
+ phy_write(phydev, RTL_8211F_EEELCR_ADDR, val2);
+ /*switch back to page0*/
+ phy_write(phydev,RTL_8211F_PAGE_SELECT, 0xa42);
+ return 0;
+}
+/*** stmmac_dvr_probe* @device: device pointer
@@ -4452,6 +4483,11 @@ int stmmac_dvr_probe(struct device *device,netdev_warn(priv->dev, "%s: failed debugFS registration\n",__func__);#endif
+ /* register the PHY board fixup */
+ ret = phy_register_fixup_for_uid(RTL_8211F_PHY_ID, RTL_8211F_PHY_ID_MASK, phy_rtl8211f_led_fixup);
+ if (ret) {
+ dev_warn(priv->device, "Cannot register PHY board fixup, terry in :%s.\n", __func__);
+ }return ret;
另外還可以使用ethtool工具去修改
20.調節紅外遙控
21.emmc
22.nfc
23.串口
異步全雙工,低–>高
通用異步收發器即通用的串行、異步通信總線,該總線有兩條數據線,實現全雙工的發送和接收
說明:一次只能發送一個字節,檢驗位可以有可以無,每次發送都是這樣的格式
串口通信存在的問題:
1)串口只是規定了協議,即幀格式,用高電平表示1,低電平表示0,但是在不同的處理器中這個定義是不一樣的機電氣特性不一樣,所以這兩個處理器是不能直接連
2)抗干擾能力差,使用的是 TTL 信號表示0和1,
3)通信距離短,只能用于一個電路板上的兩個不同芯片之間的通信
由于串口通信存在的問題就出現了RS232、RS485協議,但是軟件編程還是串口那樣編程,因為改的只是硬件上的電性
24.IIC
串行同步半雙工 高---->低
起始:在SCL為高電平時,SDA由高變低
停止:在SCL為高電平時,SDA由低變高
時序
25.SPI
全雙工、同步串行,高—>低