
前言:想要對(duì)OSD下手已經(jīng)不是頭一次了,前幾次都淺嘗輒止。一個(gè)是能力不夠,BetaFlight的代碼體系太龐大了,看不懂也摘不出來。
這次要做一款帶osd功能的接收機(jī)(用在遙控車上),所以又來打飛控程序主意。
參考代碼:betaflight-3.3.1
OSD疊加芯片:AT7456E 【可以在立創(chuàng)商城中搜索PDF的文檔】
Betaflight中有關(guān)于常用飛控型號(hào)的圖片,經(jīng)過查看可以知道大多數(shù)飛控使用的OSD芯片為AT7456E。

飛控板子一般不會(huì)留下SWD接口給予調(diào)試。所以想要拿飛控板進(jìn)行開發(fā)AT7456的話可以我之前發(fā)布的一篇文章進(jìn)行燒錄。
下面是AT7456部分的電路圖??梢钥吹绞褂肧PI與之通訊不需要額外的控制引腳。

MAX7456和AT7456的不同之處:


AT7456預(yù)裝512的字符, AT7456E有兩頁。MAX只有一頁。
AT通過CA【8】來翻頁,MAX用不到CA【8】。所以后面可以通過CA【8】寄存器來區(qū)分AT和MAX7456


解析過程:
=======================================
新版本的bf源代碼看起來不夠直觀,因?yàn)橐m配很多平臺(tái)所以,看起來有點(diǎn)繞。
下面分析使用的版本為betaflight-3.3.1??梢缘絞ithub-bf下載歷史版本。

上述文件是OSD框架文件。這里沒有具體的硬件層操作,是將底層操作函數(shù)封裝成一個(gè)結(jié)構(gòu)體。然后通過對(duì)結(jié)構(gòu)體的調(diào)用,來實(shí)現(xiàn)對(duì)OSD芯片的操作。
【記住這里的幾個(gè)結(jié)構(gòu)體的名字】等下會(huì)看到。

struct displayPortVTable_s;
typedef struct displayPort_s {
const struct displayPortVTable_s *vTable;
xxxxx...
} displayPort_t;
typedef struct displayPortVTable_s {
xxxxx...
} displayPortVTable_t;
typedef struct displayPortProfile_s {
xxxxx...
} displayPortProfile_t;這里可以把結(jié)構(gòu)體理解為一個(gè)類,這個(gè)類擁有描述自己參數(shù),以及操作OSD的函數(shù)可以調(diào)用。像是Python中的Class。后面的程序會(huì)將結(jié)構(gòu)體作為參數(shù)來傳遞。
========================================================================

通過上述文件:OSD顯示程序的調(diào)用是這里實(shí)現(xiàn)的,以60Hz的頻率調(diào)用 osdSlaveUpdate函數(shù),相當(dāng)于在后臺(tái)loop這個(gè)函數(shù),以實(shí)現(xiàn)osd刷新功能。
進(jìn)入【osdSlaveUpdate】函數(shù) 來到下面文件【osd_slave.c】

可以看到實(shí)際是調(diào)用的【displayDrawScreen(osdDisplayPort);】函數(shù)。
然后看一下這個(gè)文件主要做什么:

主要就三個(gè)函數(shù):
一、Init初始化函數(shù),osd初始化階段要做的事情。
displayWrite(osdDisplayPort, 13, 6, "OSD");
可以看出主要是通過displayWrite函數(shù)進(jìn)行顯示。
二、check函數(shù)、暫時(shí)不關(guān)心
三、osdSlaveUpdate就是之前說的后臺(tái)Loop函數(shù)。用于程序運(yùn)行過程中的刷新
從這個(gè)文件中就可以看出,所有的操作都是對(duì)displayPort_t結(jié)構(gòu)體的實(shí)例化的操作。
接下來我們看看,初始化函數(shù)中傳入的實(shí)際參數(shù)是誰。
void osdSlaveInit(displayPort_t *osdDisplayPortToUse)
通過全局搜索:

是下面函數(shù)的返回值 給了init初始化函數(shù)。繼續(xù)進(jìn)入函數(shù)內(nèi)部查看
osdDisplayPort = max7456DisplayPortInit(vcdProfile());
【displayport_max7456.c】

【max7456.c】再進(jìn)入max7456Init函數(shù)看一下:

可以看出這里是對(duì)硬件進(jìn)行配置。很多操作都是針對(duì)硬件的了。框起來的程序中有一部分是對(duì)芯片進(jìn)行區(qū)分。
// Detect device type by writing and reading CA[8] bit at CMAL[6].
// Do this at half the speed for safety.
spiSetDivisor(MAX7456_SPI_INSTANCE, MAX7456_SPI_CLK * 2);
max7456Send(MAX7456ADD_CMAL, (1 << 6)); // CA[8] bit
if (max7456Send(MAX7456ADD_CMAL|MAX7456ADD_READ, 0xff) & (1 << 6)) {
max7456DeviceType = MAX7456_DEVICE_TYPE_AT;
} else {
max7456DeviceType = MAX7456_DEVICE_TYPE_MAX;
}通過對(duì)CA8寄存器的讀寫來判斷當(dāng)前使用的那款芯片。
先對(duì)上述的幾個(gè)文件進(jìn)行整理分析:

到此,對(duì)bf固件中osd部分代碼應(yīng)該有一點(diǎn)點(diǎn)了解了。其實(shí)其他部分應(yīng)該也是這樣看的。還剩下具體的硬件操作函數(shù),我還沒有看完,正好篇幅挺長(zhǎng)了,主要是截圖多??赐杲又鴮懀赐甏m(xù).....
電源轉(zhuǎn)換: 升壓芯片、 降壓芯片、 LDO、 背光驅(qū)動(dòng)
電源管理: 鋰電池充電管理、 鋰電池保護(hù)、 QC快充協(xié)議、 OVP/OCP、 電壓檢測(cè)、 復(fù)位芯片、 PMU、 顯示屏電源芯片、 MOSFET、 ESD
馬達(dá)驅(qū)動(dòng): 步進(jìn)電機(jī)/無刷&有刷
其它芯片: 運(yùn)算放大器、 OSD