openharmony南向研究(5)-linux驅(qū)動(dòng)框架-PWM
??想了解更多關(guān)于開(kāi)源的內(nèi)容,請(qǐng)?jiān)L問(wèn):??
??51CTO 開(kāi)源基礎(chǔ)軟件社區(qū)??
本文簡(jiǎn)要介紹對(duì)比基于linux內(nèi)核開(kāi)發(fā)PWM平臺(tái)驅(qū)動(dòng)的方案,在平臺(tái)驅(qū)動(dòng)開(kāi)發(fā)完成后可以合入HDF框架作為Openharmony底層驅(qū)動(dòng)方案,之前寫(xiě)完驅(qū)動(dòng)GPIO方案LINUX驅(qū)動(dòng)基礎(chǔ)以及合入openharmony的文章后有同學(xué)問(wèn)其他的外設(shè)怎么合入,有沒(méi)有更簡(jiǎn)單易用的方法開(kāi)發(fā)陌生的linux開(kāi)發(fā)板和系統(tǒng),本章接著介紹PWM接口技術(shù),以及設(shè)備樹(shù)構(gòu)造技術(shù)來(lái)進(jìn)行簡(jiǎn)單解析。
本次實(shí)踐部分使用九聯(lián)UnionPi開(kāi)發(fā)板演示。
PWM技術(shù)基礎(chǔ)
PWM全稱(chēng)Pulse Width Modulation:脈沖寬度調(diào)制(簡(jiǎn)稱(chēng)脈寬調(diào)制,通俗的講就是調(diào)節(jié)脈沖的寬度),是電子電力應(yīng)用中非常重要的一種控制技術(shù)。
通過(guò)PWM可以控制實(shí)現(xiàn)原本閾值電壓范圍內(nèi)電壓值的控制.PWM有非常廣泛的應(yīng)用,比如直流電機(jī)的無(wú)極調(diào)速,開(kāi)關(guān)電源、逆變器等等。
上述公式可以帶來(lái)的效果包括但不限于希望一個(gè)點(diǎn)燈以50%亮度點(diǎn)亮?xí)r可以使用該方法完成,設(shè)置一個(gè)占空比為50%的PWM波輸出即可,而在用PWM控制電機(jī)轉(zhuǎn)速時(shí),占空比的降低可以使得電機(jī)轉(zhuǎn)速降低,而占空比的增加會(huì)使得電機(jī)轉(zhuǎn)速的增加。
PWM技術(shù)中需要關(guān)注的參數(shù)包括:
- PWM周期:PWM周期是指載波信號(hào)重復(fù)的時(shí)間。它的值取決于系統(tǒng)中使用的計(jì)時(shí)器和計(jì)數(shù)器的設(shè)置,可以根據(jù)需求進(jìn)行調(diào)整。通常情況下,PWM周期越短,電機(jī)或LED的響應(yīng)速度越快。
- 占空比:占空比是指PWM信號(hào)中高電平的時(shí)間與周期時(shí)間的比例。例如,50%的占空比意味著高電平時(shí)間等于周期時(shí)間的一半。占空比越高,電機(jī)或LED的亮度或速度越高。
- 分辨率:分辨率是指PWM信號(hào)能夠表達(dá)的離散級(jí)別數(shù)量。它取決于系統(tǒng)的計(jì)時(shí)器和計(jì)數(shù)器分辨率,以及PWM周期的長(zhǎng)度。較高的分辨率意味著我們可以更精細(xì)地控制PWM信號(hào)的占空比和輸出精度。
在通常使用的芯片中通過(guò)對(duì)以下幾個(gè)寄存器的配置可以實(shí)現(xiàn)PWM的控制。
- TMR(計(jì)時(shí)器)寄存器:TMR寄存器用于設(shè)置PWM信號(hào)的載波周期。通過(guò)設(shè)置TMR寄存器的計(jì)數(shù)值和預(yù)置值,可以確定PWM信號(hào)的頻率。TMR寄存器的計(jì)數(shù)值決定了PWM周期的長(zhǎng)度,預(yù)置值決定了載波信號(hào)周期的長(zhǎng)度。通過(guò)調(diào)整計(jì)數(shù)值和預(yù)置值,可以調(diào)整PWM周期和頻率。
- PR(預(yù)置器)寄存器:PR寄存器用于設(shè)置PWM信號(hào)的載波周期的預(yù)置值。預(yù)置值決定了載波信號(hào)周期的長(zhǎng)度,它是TMR寄存器計(jì)數(shù)值的上限。當(dāng)TMR寄存器的計(jì)數(shù)值達(dá)到預(yù)置值時(shí),計(jì)數(shù)器會(huì)重新計(jì)數(shù)并產(chǎn)生一個(gè)新的PWM周期。
- PWM占空比寄存器:PWM占空比寄存器用于設(shè)置PWM信號(hào)的占空比。在PWM周期內(nèi)的高電平時(shí)間和低電平時(shí)間是由PWM占空比寄存器的值決定的。通過(guò)改變PWM占空比寄存器的值,可以調(diào)整PWM信號(hào)的占空比,從而控制輸出的電壓或電流大小。
- IO控制寄存器:IO控制寄存器用于設(shè)置PWM輸出引腳的模式和狀態(tài)。通過(guò)IO控制寄存器,可以選擇PWM輸出引腳的功能和輸出模式,例如單極性輸出或雙極性輸出。還可以設(shè)置引腳的電平、電流和電壓等參數(shù)。
- 中斷寄存器:中斷寄存器用于設(shè)置PWM中斷功能。當(dāng)PWM周期結(jié)束時(shí),可以通過(guò)中斷寄存器來(lái)觸發(fā)中斷事件,并在中斷服務(wù)程序中執(zhí)行一些操作。
下圖為PR寄存器值為8,TMR寄存器值為4,最終輸出信號(hào)位OCXREF,占空比為44.4%。
在常用的芯片中對(duì)應(yīng)不同的寄存器,但是核心邏輯還是在于TMR寄存器和PR寄存器,例如在STM32中預(yù)置器寄存器又叫做TIMx_ARR定時(shí)器重載控制器,需要讀者仔細(xì)甄別。
寄存器具體作用方式如下:
首先在定時(shí)器以PWM模式工作時(shí)會(huì)將計(jì)數(shù)器計(jì)數(shù)模式設(shè)置為向上計(jì)數(shù)模式,并使能計(jì)時(shí)器。(此處為示意代碼)。
再配置定時(shí)器相關(guān)參數(shù),設(shè)定定時(shí)器的分頻值,PWM的周期長(zhǎng)度和PWM的占空比。
prescaler_value為定時(shí)器的時(shí)鐘分頻系數(shù),用于設(shè)置定時(shí)器的時(shí)鐘頻率,period_value為PWM周期的長(zhǎng)度,即PR寄存器的值,pulse_value為PWM波形的占空比,即TMR寄存器的值。
最后啟動(dòng)PWM輸出。
按照基本寄存器操作邏輯整體計(jì)算占空比的公式如下:
頻率計(jì)算公式為:
如果使用文中的九聯(lián)UnionPi開(kāi)發(fā)板,將會(huì)用到Amlogic A311D芯片,以下例程可以單獨(dú)通過(guò)寄存器實(shí)現(xiàn)占空比為50%,頻率為4000Hz的PWM輸出。
其中,PWM_BASE表示PWM控制器的基地址;PWM_CHANNEL表示要使用的PWM輸出通道,取值為0、1、2或3;period_value和pulse_value分別表示PWM周期和占空比的值,根據(jù)占空比為50%、頻率為4000Hz可以計(jì)算出period_value=PWM_CLOCK_RATE/4000-1,pulse_value=period_value/2。
另外,需要注意的是,在Amlogic A311D芯片中,PWM波形的占空比是由hi_time和lo_time寄存器的值決定的。在上面的代碼中,我們通過(guò)修改pwm_dev->hi_time[PWM_CHANNEL]和pwm_dev->lo_time[PWM_CHANNEL]參數(shù)來(lái)設(shè)置占空比的值,實(shí)際上是將該值寫(xiě)入hi_time和lo_time寄存器中。因此,在不同的通道上設(shè)置占空比時(shí),需要根據(jù)具體的寄存器名和通道號(hào)來(lái)設(shè)置pwm_dev->hi_time和pwm_dev->lo_time參數(shù)。
LINUX驅(qū)動(dòng)中配置PWM
- 通過(guò)閱讀開(kāi)發(fā)板原理圖和開(kāi)發(fā)板手冊(cè)了解PWM口物理連接接口
- 創(chuàng)建PWM設(shè)備節(jié)點(diǎn): 創(chuàng)建一個(gè)新的PWM設(shè)備節(jié)點(diǎn),可以使用misc設(shè)備驅(qū)動(dòng)程序或platform_device框架。在創(chuàng)建設(shè)備節(jié)點(diǎn)時(shí),需要指定設(shè)備ID、名稱(chēng)和相關(guān)的設(shè)備數(shù)據(jù)。
- 初始化PWM設(shè)備: 在PWM設(shè)備初始化期間,需要設(shè)置PWM時(shí)鐘、周期、占空比和極性等參數(shù)。可以通過(guò)PWM子系統(tǒng)提供的函數(shù)進(jìn)行操作。
- 實(shí)現(xiàn)PWM設(shè)備控制函數(shù): 這些函數(shù)提供了PWM設(shè)備的讀寫(xiě)訪問(wèn)。可以使用sysfs接口或misc設(shè)備驅(qū)動(dòng)程序提供的ioctl函數(shù)進(jìn)行實(shí)現(xiàn)。
- 注冊(cè)PWM設(shè)備: 注冊(cè)PWM設(shè)備以啟用設(shè)備。可以使用misc設(shè)備驅(qū)動(dòng)程序或platform_device框架提供的函數(shù)進(jìn)行操作。
在編寫(xiě)PWM驅(qū)動(dòng)程序時(shí),需要配置PWM控制器的寄存器以實(shí)現(xiàn)PWM輸出。PWM控制器的寄存器地址和控制位的具體定義因芯片而異,因此需要根據(jù)具體的硬件平臺(tái)進(jìn)行編寫(xiě)。
在Linux內(nèi)核中,通常使用PWM子系統(tǒng)提供的接口來(lái)訪問(wèn)PWM控制器的寄存器。PWM子系統(tǒng)提供了一組API函數(shù),用于初始化PWM、設(shè)置PWM周期和占空比、開(kāi)啟/關(guān)閉PWM輸出等操作,這些API函數(shù)會(huì)自動(dòng)設(shè)置PWM控制器的寄存器。
例如,在上面的PWM驅(qū)動(dòng)程序示例中,使用了PWM子系統(tǒng)提供的函數(shù)pwm_request()、pwm_init()、pwm_enable()等,這些函數(shù)會(huì)自動(dòng)配置PWM控制器的寄存器以實(shí)現(xiàn)PWM輸出。因此,可以通過(guò)使用PWM子系統(tǒng)提供的接口,避免手動(dòng)配置PWM控制器的寄存器,從而簡(jiǎn)化驅(qū)動(dòng)程序的編寫(xiě)。
PWM子系統(tǒng)中的具體接口函數(shù)屬性如下:
- struct pwm_device:表示一個(gè)PWM通道,定義在include/linux/pwm.h文件中。
- struct pwm_state:表示一個(gè)PWM通道的狀態(tài),包括周期、占空比等參數(shù),定義在include/linux/pwm.h文件中。
- struct pwm_ops:表示PWM驅(qū)動(dòng)程序的操作函數(shù),包括配置PWM通道、使能/禁用PWM輸出等,定義在include/linux/pwm.h文件中。
- struct platform_device:表示一個(gè)平臺(tái)設(shè)備,包含設(shè)備名、設(shè)備資源等信息,定義在include/linux/platform_device.h文件中。
- pwm_get:獲取一個(gè)PWM通道,定義在drivers/pwm/core.c文件中。
- pwm_request:申請(qǐng)一個(gè)PWM通道,定義在drivers/pwm/core.c文件中。
- pwm_free:釋放一個(gè)PWM通道,定義在drivers/pwm/core.c文件中。
- pwm_config:配置PWM通道的參數(shù),包括周期、占空比等,定義在drivers/pwm/core.c文件中。
- pwm_enable:使能PWM輸出,定義在drivers/pwm/core.c文件中。
- pwm_disable:禁用PWM輸出,定義在drivers/pwm/core.c文件中。
- pwm_apply_state:將PWM通道的配置應(yīng)用到硬件上,定義在drivers/pwm/core.c文件中。
這些函數(shù)和結(jié)構(gòu)體的實(shí)現(xiàn)可能會(huì)因?yàn)長(zhǎng)inux內(nèi)核版本不同而有所變化,因此在編寫(xiě)設(shè)備驅(qū)動(dòng)程序時(shí)需要仔細(xì)閱讀對(duì)應(yīng)內(nèi)核版本的源代碼和文檔。
在上述代碼中我們已經(jīng)完成了標(biāo)注的PWM驅(qū)動(dòng)編寫(xiě),接下來(lái)要對(duì)其進(jìn)行調(diào)用。
對(duì)其進(jìn)行編譯合并入內(nèi)核。
常規(guī)在LINUX內(nèi)核環(huán)境中進(jìn)行驅(qū)動(dòng)調(diào)用的方式有兩種,一種是重寫(xiě)底層硬件配置調(diào)用platform_device_register()函數(shù)來(lái)完成注冊(cè)操作,以及可以使用文件系統(tǒng)調(diào)用內(nèi)核中已經(jīng)寫(xiě)好的驅(qū)動(dòng),如GPIO章節(jié)描述的方法類(lèi)似,另一種是通過(guò)設(shè)備樹(shù)來(lái)完成底層硬件和內(nèi)核態(tài)程序間的隔離和連接。
如果想調(diào)用剛剛寫(xiě)好的驅(qū)動(dòng),通過(guò)設(shè)備樹(shù)的方式可以將節(jié)點(diǎn)注冊(cè)到設(shè)備樹(shù)中。
設(shè)備樹(shù)的參數(shù)屬性詳細(xì)解釋如下所示。
我們需要將設(shè)備樹(shù)寫(xiě)入到dtsi文件當(dāng)中,該文件目錄位于 kernel/linux/linux-5.10/arch/arm/boot/dts/meson8.dtsi。同時(shí)通過(guò)搜索PWM,PINCTRL可以查看到廠商以及合入的內(nèi)核設(shè)備樹(shù),我們可以在此處添加或修改新的硬件對(duì)于amlogic a311d芯片而言。
重啟系統(tǒng)剛剛注冊(cè)的設(shè)備和驅(qū)動(dòng)可以在前臺(tái)通過(guò)讀寫(xiě)文件的方式進(jìn)行控制
第二種不通過(guò)設(shè)備樹(shù)的驅(qū)動(dòng)編寫(xiě)方案如下,其核心思路是注冊(cè)該設(shè)備,即將該設(shè)備添加到Linux內(nèi)核中的設(shè)備列表中,可以使用platform_device_register()函數(shù)來(lái)完成注冊(cè)操作。
目前可以在.dtsi文件中查找到A311D開(kāi)發(fā)板設(shè)備樹(shù)中已經(jīng)配置完成具備兩個(gè)硬件PWM引腳,分別對(duì)應(yīng)在:
PWM1 /sys/class/pwm/pwmchip0/pwm0
PWM2/sys/class/pwm/pwmchip2/pwm0
案例實(shí)戰(zhàn)
接下來(lái)通過(guò)一個(gè)實(shí)際案例演示PWM操作呼吸燈。//代碼和工程文件加在附件中。
通過(guò)文件系統(tǒng)和終端操作已經(jīng)完成驅(qū)動(dòng)配置的PWM引腳
以上兩行指令在pwmchip0和pwmchip2中生成引腳目錄pwm0。
也可以進(jìn)入pwm0目錄查看內(nèi)涵屬性。
打開(kāi)pwm和關(guān)閉pwm。
設(shè)置周期值。
設(shè)置高電平時(shí)間。
此時(shí)占空比=duty_cycle/period=50%。
設(shè)置PWM極性。
呼吸燈實(shí)現(xiàn)原理:
更改脈沖電平寬度,不斷連續(xù)減小。
(代碼為邏輯示意代碼,STM32版本,具體參見(jiàn)附件)。
該方法不適用精準(zhǔn)定時(shí)器,只做PWM口演示使用。
??想了解更多關(guān)于開(kāi)源的內(nèi)容,請(qǐng)?jiān)L問(wèn):??