碎碎念:好久不見,甚是想念!本期帶來的是有關ZYNQ7020的內容,我們知道ZYNQ作為一款具有硬核的SOC,PS端很強大,可以更加便捷地實現(xiàn)一些算法驗證。本文具體講解一下里面的TTC定時器,之后發(fā)布的Part2將基于具體項目出發(fā),實現(xiàn)PS端單核進行六路不等長占空比的PWM輸出~
雖然最后對我自己畢業(yè)好像沒有什么幫助QAQ,但是畢竟花費了一些時間閱讀手冊等內容,還是打算記錄一下供大家參考。
目錄
1 TTC原理分析
1.1 主要特點
1.2 結構框圖
1.3 功能描述
1.3.1 操作模式
1.3.2 事件定時器/脈寬計數(shù)器(Event Timer)操作
1.4 寄存器概述
1.5 編程模型
1.5.1 計數(shù)器使能的步驟
1.5.2 計數(shù)器停止的步驟
1.5.3 計數(shù)器重啟的步驟
1.5.4 事件計數(shù)器(脈寬計數(shù)器)使能的步驟
1.5.5 清除中斷和確認的步驟
1.6 計數(shù)器時鐘輸入的選擇
2 SDK分析
2.1 工程建立
2.2 案例分析
1.設置中斷系統(tǒng):SetupInterruptSystem()
2.設置Ticker定時器:SetupTicker()?
3.設置PWM定時器:SetupPWM()
4.逐漸修改占空比:WaitForDutyCycleFull()
5.停止計數(shù)器:XTtcPs_Stop()
1 TTC原理分析
這一部分我們直接按照UG585的思路,進行分析和介紹,由于原文的內容本身是英文理解起來還是需要一些經驗(盡管更推薦去閱讀原文部分)。
TTC包含了三個獨立的定時器,分別是上圖中的Timer/Clock 0、Timer/Clock 1、Timer/Clock 2。從左下角可以看到在PS端包含兩個TTC,分別是TTC0和TTC1,因此兩個TTC共包含6個獨立的定時器。TTC控制器可以通過修改nic301_addr_region_ctrl_registers.security_apb [ttc1_apb]這個寄存器的位,來實現(xiàn)對于安全模式(secure mode)和非安全模式(non-secure mode)的切換。對于這兩種模式的內容可以參考下面:
傳送門
Secure mode and Non-secure mode:
這兩種模式來源于ARM TrustZone技術,ARM在CPU的常規(guī)模式之外引入了一種稱為“安全模式”的特殊CPU模式,建立了“安全世界”和“正常世界”之間的的概念。默認情況下,安全世界訪問正常世界的所有狀態(tài),反之則不然。由于ARM基本使用的都是基于存儲映射的結構,我的理解是通過這兩種模式的分隔,來實現(xiàn)對于重要寄存器的保護。
1.1 主要特點
每個TTC有如下特點:
1.三個獨立16位預分頻器和16位的向上/向下計數(shù)器。(向上:0,1,2,3,4...? 向下:9,8,7,6...)
2.可選的時鐘源輸入(內部PS總線時鐘:CPU_1x,內部時鐘:PL,外部時鐘:MIO)
3.對于TTC內部每一個counter,都各自有一個中斷
4.在一定間隔內的溢出中斷,或者計數(shù)匹配到設定的值時會發(fā)出中斷
5.產生波形輸出,可以通過MIO或者PL(EMIO)
1.2 結構框圖
通過上面的結構框圖,對于TTC中第一個計數(shù)器Timer/Clock 0的時鐘輸入、波形輸出信號的多路控制是通過slcr.MIO_PIN_xx寄存器實現(xiàn)的,默認情況下使用EMIO接口。
1.3 功能描述
每個預分頻模塊(Pre-scaler)都可以獨立設置為使用PS內部總線時鐘或者外部時鐘(來自MIO或者PL)。對于外部時鐘輸入,通過使用SLCR寄存器來選擇具體的信號輸入。預分頻模塊可以將輸入時鐘在/2和/65536之間進行分頻,當如分頻寄存器為0的時候,會對時鐘進行二分頻,之后輸出給后面的計數(shù)器。
計時器可以設置為增計數(shù)、減計數(shù),并且通過設置間隔寄存器的值,可以控制計數(shù)的范圍。同時可以比較三個匹配寄存器的值和計數(shù)器(一個TTC包含3個計數(shù)器Counter和3組匹配寄存器)的值,產生中斷信號。
中斷模塊組合了各種類型的中斷:計數(shù)器間隔中斷(Interval Interrupt)、計數(shù)器匹配中斷(Match Interrupt)、計數(shù)器溢出中斷(Overflow Interrupt)、事件計時器溢出。每種類型都可以單獨啟用。
1.3.1 操作模式
一個TTC中的每個計數(shù)器模塊,都可以獨立編程,并以以下兩種模式中的任何一種運行。
間隔模式(Interval mode):
通過修改計數(shù)器控制寄存器(Counter Control register)的DEC位,可以控制計數(shù)器的計數(shù)方向是+1還是-1。通過修改間隔計數(shù)器(Interval mode)的值可以控制計數(shù)的范圍是0到間隔計數(shù)器的值。當計數(shù)值經過0的時候,會產生一個計數(shù)器間隔中斷(Interval Interrupt)。當計數(shù)器的值等于匹配計數(shù)器(Match register)值的時候,會產生一個匹配中斷(Match Interrupt)。
溢出模式(Overflow mode):
計數(shù)器在0x0000和0xFFFF之間連續(xù)的+1或者-1變化,并通過修改計數(shù)器控制寄存器的DEC位來控制計數(shù)的方向。當計數(shù)值經過0的時候,會產生一個溢出中斷(Overflow Interrupt)。當計數(shù)器的值等于匹配計數(shù)器值的時候,會產生一個匹配中斷。
1.3.2 事件定時器/脈寬計數(shù)器(Event Timer)操作
從名字脈寬計數(shù)器,可以推斷出其功能是對外部輸入信號的脈寬進行測量,原理有一些類似電機差分編碼器的M法測速。
事件定時器內部有一個對用戶不可見的16位內部計數(shù)器(Internal Counter),該計數(shù)器被CPU_1x的時鐘控制,其滿足如下兩個條件:
1.當外部脈沖的非計數(shù)階段,被重置為0
2.在外部脈沖的計數(shù)階段,開始增加
修改事件定時器控制內部計數(shù)器的行為,主要通過三個位來控制:
1 E_En bit 使能位,等于0時,將內部計數(shù)器復位到0,并停止計數(shù)
2 E_Lo bit 指定外部脈沖的計數(shù)相位
3 E_Ov bit 指定如何處理當內部計數(shù)器溢出時,如何處理。
???? 當為0的時候,溢出導致E_En置為0;
當為1的時候,溢出導致內部計數(shù)器繼續(xù)循環(huán)計數(shù);
在另一個寄存器的控制下,可以決定溢出時是否產生中斷(而與E_Ov bit本身的值無關)。
當外部計數(shù)脈沖的計數(shù)相位結束的時候,會使用內部計數(shù)器的非零計數(shù)值對事件寄存器(Event Register)的值進行更新。因此,這個值展示了外部脈沖的寬度。由于內部計數(shù)器被CPU_1x的時鐘控制,因此脈沖寬度是由CPU_1x的時鐘周期數(shù)來衡量的。
當外部計數(shù)脈沖的計數(shù)相位階段,如果內部計數(shù)器由于溢出被重置為0,那么事件寄存器將不會被更新,并保持上次非溢出計數(shù)操作的舊值。
1.4 寄存器概述
功能 |
名稱 |
概述 |
時鐘控制 |
時鐘控制寄存器 |
控制預分頻器,選擇時鐘輸入,選擇邊沿 |
計數(shù)器控制寄存器 |
使能計數(shù)器,設置操作模式,設置計數(shù)方向,使能匹配,使能波形輸出 |
|
狀態(tài) |
計數(shù)器數(shù)值寄存器 |
返回計數(shù)器的當前值 |
計數(shù)器控制 |
間隔寄存器 |
設置間隔值 |
匹配寄存器1 匹配寄存器2 匹配寄存器3 |
設置匹配值,一共有3組,對應了一個TTC內部的3個Counter(這種說法不準確,其實每個Counter都有自己的一組三個匹配寄存器) |
|
中斷 |
中斷寄存器 |
顯示當前中斷狀態(tài) |
中斷使能寄存器 |
使能中斷 |
|
事件 |
事件控制計時器寄存器 |
使能事件計時器,停止計時器,設置計數(shù)相位 |
事件寄存器 |
顯示外部脈沖的寬度(即內部計數(shù)器的計數(shù)值) |
1.5 編程模型
1.5.1 計數(shù)器使能的步驟
- 選擇時鐘輸入源,設置預分頻值(slcr.MIO_MUX_SEL registers, TTC Clock Control register),進行這一步前需要保證TTC處于不使能狀態(tài)(slcr.MIO_MUX_SEL registers, TTC Clock Control register)
- 設置間隔值(Interval register),這一步驟是可選的,僅在間隔模式進行
- 設置匹配值(Match registers),這一步是可選的,如果匹配是使能狀態(tài)則需要設置
- 使能中斷(Interrupt Enable register),這一步是可選的,如果需要中斷則需要使能
- 設置波形輸出的使能狀態(tài),設置匹配的使能狀態(tài),設置計數(shù)的方向,設置模式,使能計數(shù)器 (TTC Counter Control register),這一步開啟計數(shù)器
1.5.2 計數(shù)器停止的步驟
- 讀取當前計數(shù)器控制器的值
- 設置DIS位為1,保持其他位不變
- 將上面修改了DIS位的數(shù)值寫回計數(shù)器控制器
1.5.3 計數(shù)器重啟的步驟
- 讀取計數(shù)器控制器的值
- 設置RST位為1,保持其他位不變
- 將上面修改了DIS位的數(shù)值寫回計數(shù)器控制器
1.5.4 事件計數(shù)器(脈寬計數(shù)器)使能的步驟
- 選擇外部脈沖源(slcr.MIO_MUX_SEL registers),所選擇的外部脈沖的脈寬將會被時鐘CPU_1x的周期所衡量
- 設置計數(shù)溢出時的處理,選擇外部脈沖的電平,使能事件計數(shù)器(select external pulse level),這一步開始測量選擇的外部脈沖的脈寬(高電平或者低電平)
- 使能中斷(Interrupt Enable register),這一步是可選的,如果需要中斷則需要使能
- 讀取測量到的脈沖寬度(Event register),注意當計數(shù)溢出發(fā)生的時候,返回來的脈寬計數(shù)值是不準確的。具體可以看前文對事件計數(shù)器的敘述
1.5.5 清除中斷和確認的步驟
- 讀取中斷寄存器,將會自動讀取并清除中斷寄存器中的所有位
1.6 計數(shù)器時鐘輸入的選擇
下面展示了如何設置SoC選擇對于TTC0中Counter/timer 0 的時鐘源,使用的是一組if else 語句來實現(xiàn)。
if slcr.MIO_PIN_19[6:0] is 1100000, use MIO pin 19
else if slcr.MIO_PIN_31[6:0] is 1100000, use MIO pin 31
else if slcr.MIO_PIN_43[6:0] is 1100000, use MIO pin 43
else use EMIOTTC0CLKI0
TTC0 的 Counter/timer 1只能使用EMIOTTC0CLKI1
TTC0 的 Counter/timer 2只能使用EMIOTTC0CLKI2
下面展示了如何設置SoC選擇對于TTC1中Counter/timer 0 的時鐘源,使用的是一組if else 語句來實現(xiàn)。
if slcr.MIO_PIN_17[6:0] is 1100000, use MIO pin 17
else if slcr.MIO_PIN_29[6:0] is 1100000, use MIO pin 29
else if slcr.MIO_PIN_41[6:0] is 1100000, use MIO pin 41
else use EMIOTTC1CLKI0
TTC1 的 Counter/timer 1只能使用EMIOTTC1CLKI1
TTC1 的 Counter/timer 2只能使用EMIOTTC1CLKI2
IMPORTANT:當選擇MIO引腳或EMIOTTCxCLKIx作為時鐘源時,如果時鐘停止運行,相應的計數(shù)值寄存器將保留舊值,而不管時鐘已經停止的事實。在這種情況下必須謹慎。這句話理解為,時鐘停止運行這件事可能是很容易被忽略的。
2 SDK分析
2.1 工程建立
在任意一個ZYNQ工程中進行如下配置:
這里對TTC0和TTC1都打上對勾,在Block Design就會多出6個Pin腳。(為下一期的6占空比PWM輸出做準備~)
右鍵每一個Pin腳,設置Make External:
之后在xdc文件中對輸出的引腳進行綁定即可。
同時可以在Clock Configuration看到時鐘的頻率,這里顯示TTC1和TTC2的時鐘源都是來自CPU_1x的內部時鐘,頻率是133.333333MHz
至此,Block Design部分就設置完畢了。
首先修改完Block Design之后,需要先點F6,進行Validate Design操作,驗證Block Design的正確性。
之后點擊Generate Output Products生成輸出。
下一步點擊左側的Generate Bitstream輸出比特流文件。
之后點擊File-Export-Export Hardware,將硬件信息導出。
之后點擊File-Lauch SDK,新建一個空的工程。(這一步的流程可以參考正點原子的領航者ZYNQ系列視頻的嵌入式開發(fā)系列)
打開Vivado工程對應的SDK文件后,我們可以在左側找到所提供的一些ttc參考文件:
我們只需要關注xttcps.h這個頭文件即可,他是PS中TTC模塊驅動頭文件,給出了比較詳細的函數(shù)定義
同時也可以找到一些示例文件:
這里主要對第一個案例進行代碼的講解。
2.2 案例分析
這里需要讀者自行打開上述的案例文件~由于不需要額外硬件設置,可以直接在SDK中看到上述內容。
這里我們針對這一文件簡單介紹一下ttc的設置流程。
這個文件內部給出了利用TTC產生中斷的案例,共分成了幾個步驟。
1.設置中斷系統(tǒng):SetupInterruptSystem()
Line547+552:初始化中斷控制器
Line562:注冊中斷處理
Line569:使能中斷
2.設置Ticker定時器:SetupTicker()?
需要注意的是SetupTicker里面包含了信息的初始化,對單個定時器的設置,中斷的設置。相當于將這幾部分結合在了一起。
該函數(shù)從Line257開始,這里引用了一個數(shù)據(jù)結構TmrCntrSetup,定義在Line100
typedef struct {
?? ?u32 OutputHz;?? ?/* Output frequency */
?? ?XInterval Interval;?? ?/* Interval value */
?? ?u8 Prescaler;?? ?/* Prescaler value */
?? ?u16 Options;?? ?/* Option settings */
} TmrCntrSetup;
并且Line261調用了Line131定義的數(shù)組:?
static TmrCntrSetup SettingsTable[2] = {
?? ?{100, 0, 0, 0},?? ?/* Ticker timer counter initial setup, only output freq */
?? ?{200, 0, 0, 0}, /* PWM timer counter initial setup, only output freq */
};?
可以看到這個數(shù)組分別用來設置Ticker timer和PWM timer的狀態(tài),分別包括:輸出頻率;間隔值;預分頻系數(shù);輸出選項設置。
對于輸出選項的設置,是在Line267通過或操作來實現(xiàn),具體的可選參數(shù)可以看xttcps.h中的定義:
回到xttcps_intr_example中,Line267定義當前模式為間隔模式,同時設置了不輸出波形。(如果這里設置輸出波形,那么當計數(shù)器值等于匹配值的時候,會將輸出進行翻轉,實現(xiàn)波形輸出)。
之后在Line275調用了SetupTimer函數(shù),實現(xiàn)對單個定時器的具體設置。這一函數(shù)定義在Line469。注意信息的傳遞是通過TTC_TICK_DEVICE_ID來實現(xiàn)的。
主要實現(xiàn)的功能就是初始化設備(XTtcPs_LookupConfig、XTtcPs_CfgInitialize),將SetupTicker中的設置傳遞過來,分別包括(設置選項模式XTtcPs_SetOptions、計算間隔值XTtcPs_CalcIntervalFromFreq、設置間隔值XTtcPs_SetInterval、設置預分頻系數(shù)XTtcPs_SetPrescaler)
設置完成后,就獲得了設置好的設備TtcPsTick。
回到SetupTicker中,Line285實現(xiàn)對中斷控制器的設置,將設備以及中斷處理函數(shù)進行定義。
中斷處理函數(shù)TickHandler定義在Line592,首先在Line599獲取中斷的類型,之后在Line600清除中斷。在Line602對中斷的類型進行判斷,這里檢測的是XTTCPS_IXR_INTERVAL_MASK,其定義以及其他類型的中斷,我們可以在xttcps_hw.h找到,這里面定義了六種中斷類型:
當檢測到對應類型的中斷,我們就利用TickCount對間隔終端出現(xiàn)的次數(shù)進行累加處理。
回到SetupTicker中,在Line294和Line300進行了中斷的使能操作,之后在Line305設置開啟定時器。
3.設置PWM定時器:SetupPWM()
這個相信也是很多人比較關注的部分。
Line328實現(xiàn)一些設置信息,主要是將前面的數(shù)組第二個元素存儲過來。
Line334設置間隔模式、匹配模式、并使能wave的輸出,這里就保證了當計數(shù)值與匹配值相同的時候,輸出信號就會發(fā)生翻轉。從而可以利用間隔值設置PWM的周期,利用匹配值設置PWM的占空比。
Line342同樣調用SetupTimer來實現(xiàn)對單個定時器的具體設置,具體說明可以看上面的部分。這一函數(shù)定義在Line469。注意信息的傳遞是通過TTC_PWM_DEVICE_ID來實現(xiàn)的。
主要實現(xiàn)的功能就是初始化設備(XTtcPs_LookupConfig、XTtcPs_CfgInitialize),將SetupPWM中的設置傳遞過來,分別包括(設置選項模式XTtcPs_SetOptions、計算間隔值XTtcPs_CalcIntervalFromFreq、設置間隔值XTtcPs_SetInterval、設置預分頻系數(shù)XTtcPs_SetPrescaler)
設置完成后,就獲得了設置好的設備TtcPsPWM
Line352通過調用XScuGic_Connect實現(xiàn)對中斷控制器,設備ID,中斷處理函數(shù)以及匹配值指針的設置。
中斷處理函數(shù)PWMHandler定義在Line637,當檢測到中斷信號是間隔中斷(也就是表示輸出了一個周期),就會在Line653調用XTtcPs_SetMatchValue進行匹配值的設置,在代碼注釋中提到,匹配寄存器0是特殊的,如果輸出被使能,當匹配值與計數(shù)值相等時,會修改輸出的極性。
但是這個地方的注釋是容易被誤解的,TTC定時器的三個匹配寄存器功能是不一致的,并不是都可以用于波形的輸出,在ZYNQ官方實例中,register0被指定為Special,也就是當計數(shù)器與register0的匹配值相等時,會觸發(fā)特殊中斷事件并翻轉輸出電平。經試驗表明,對于同一個Counter來說,register1和register2并不會影響PWM輸出的翻轉,但是由于每個TTC中有三個Counter,其實可以設置三個register0的值來實現(xiàn)三個不同占空比PWM的輸出。
回到SetupPWM中,在Line361和Line367進行了中斷的使能操作,之后在Line372設置開啟定時器。
4.逐漸修改占空比:WaitForDutyCycleFull()
這個函數(shù)定義在Line397,主要是通過當每一次循環(huán)輸出一次PWM波之后,TickHandler函數(shù)會在Line607將PWM_UpdateFlag更新為TRUE,之后會在WaitForDutyCycleFull中滿足if的條件,從而修改全局變量MatchValue的值。通過中斷處理函數(shù)PWMHandler中的Line643,就實現(xiàn)了MatchValue對MatchReg的賦值,從而在Line653可以修改MatchReg的值,進而就修改了占空比。
整體邏輯只要抓住下面三點:1.間隔模式中斷:在PWM周期結束更新flag;2.修改占空比:檢測flag修改全局變量,改變占空比;3.PWM輸出中斷處理函數(shù)(也是間隔模式中斷)將匹配值設置進去。
5.停止計數(shù)器:XTtcPs_Stop()
這里直接在Line236和Line238調用了XTtcPs_Stop實現(xiàn)了計數(shù)器的停止。文章來源:http://www.zghlxwxcb.cn/news/detail-545766.html
這就是本期的全部內容啦,如果你喜歡我的文章,不要忘了點贊+收藏+關注,分享給身邊的朋友哇~文章來源地址http://www.zghlxwxcb.cn/news/detail-545766.html
到了這里,關于ZYNQ:【1】深入理解PS端的TTC定時器(Part1:原理+官方案例講解)的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!