前不久在研究SYSTICK有關問題閱讀相關技術資料時,無意間產生了個小疑惑。
問題是這樣的,我們知道SYSTICK定時器是個24位向下計數器,每當發生從1記到0時會讓一個名為COUNTFLAG的標志位置1,如果此時SYSTICK的滴答中斷請求使能了的話,可以對CPU發起中斷請求。
根據我們平常STM32的開發經驗,通常各種外設事件發起中斷請求時,往往有相應的事件標志跟中斷響應關聯,在中斷服務程序里并將相關事件標志做清零操作,否則它會沒完沒了地發起中斷請求。基于這點,我想這個COUNTFLAG標志應該也是跟SYSTICK中斷密切相關,溢出時被置位,在SYSTICK中斷服務程序里將其清零。
可是,我們平常的SYSTICK的中斷服務程序里根本沒看到哪里有對COUNTFLAG標志做清零。ARM Cortex內核手冊針對COUNTFLAG標志的描述中涉及它可以清零的地方有兩處:
第一個地方是在SYSTICK控制寄存器【SYST_CSR】里有介紹,讀它可以清零。說實在的,這點我是通過咨詢ARM公司才理解到位的。第二個地方是在介紹SYSTCIK的當前計數器寄存器時提到,即對當前計數器寄存器進行寫操作時也會將COUNTFLAG標志清零。
問題是平常的SYSTICK的中斷服務程序里根本就沒有涉及到上面提到的可能對COUNTFLAG標志清零的操作啊?!既沒有讀SYSTICK控制寄存器,也沒有對計數器做寫操作。那這個標志啥時候被清零的呢?如果不清零的話,難道不會沒完沒了地申請中斷,可現在的實踐結果又不是這樣的!
后來,找同事咨詢、討論,有同事說他印象中計數器重裝時會將該標志清零。如果說重裝可以清COUNTFLAG的話,這樣可以很好地解釋目前的結果。因為既然每次重裝可以清零,自然用不著到中斷服務程序里再做清零,那么在中斷服務程序里見不到對COUNTFLAG的清零操作也就再正常不過了。也因此一時以為找到了答案。可后來一想,還是有些不對勁的地方。至少有2點說不通。
第一、如果是重裝時清零,該標志是溢出時被置1的,而溢出和重裝兩個動作可以看成同一時刻完成,即置位后馬上被清零。這樣的話,用戶永遠沒有機會見到該標志為1的時候。何時能被軟件用得上呢?定義這個標志意義何在呢?
第二、關于這個標志,在ARM 內核手冊里還說了下面一句話:
意思就是說用戶軟件可以通過查看COUNTFLAG標志來確認SYSTICK之前有發生過溢出。如果重裝可以清零的話,用戶軟件是不可能有機會讀到該標志為1的時候。也就是說重裝清零結論跟這句話是矛盾的。
經過與同事的來回討論,以及查找其它相關信息,后來認為這個標志可能跟中斷沒有必然關系。這個過程中我也意識到我提出這個標志哪里清零的問題,可能是先入為主的慣性思維在作怪。具體點說,我們認為這個COUNTFLAG標志在發生溢出時置位沒問題,前面提到的兩種情形下會被清零也沒問題。但是,SYSTICK的滴答中斷不跟這個標志位關聯,它只與計數器發生從1計到0的事件有關,即手冊中下面綠色方框框住的這句話。
說實在的,這句話我老早就看到了,只是覺得溢出做為中斷觸發條件沒錯,但一門心思老糾結著哪個地方對COUNTFLAG清零了。
如果說COUNTFLAG只是個溢出事件標志,滴答中斷不跟它關聯也是可以理解和接受的。首先,根據ARM手冊描述來理解這個結論沒有問題,沒有說不通的地方,然后,實現邏輯上也沒啥問題,反正溢出一次就申請一次中斷。
聊到這里,很多STM32用戶【包括本人在內】可能會覺得有點別扭或不習慣,這點我們下面繼續聊。我就我們針對COUNTFLAG標志跟SYSTICK中斷的關系的理解,說得直白點就是SYSTICK中斷跟COUNTFLAG有無關系、服務程序里要不要清零再次找ARM公司做了確認,他們完全認同我們的理解。即COUNTFLAG只是個溢出事件標志,SYSTICK中斷不跟它關聯,只與計數器溢出事件本身關聯,并不關心COUNTFLAG的值是0還是1。到此,關于COUNTFLAG要不要在服務程序里清零的疑惑算是塵埃落定。
但是------
用過STM32外設事件申請中斷的人應該很清晰地知道,要想各個外設事件中斷申請能得到響應的話,除了NVIC端接受響應、外設端允許申請中斷外,還得有相應的事件發生【包括軟件方式】以及對應的事件標志被置位【或者說應該有效】,中斷服務程序跟相應事件標志直接相關,即發生中斷響應時中斷事件標志必須有效,并需在中斷服務程序里對標志清零,否則會沒完沒了地申請中斷、響應中斷。顯然,這個過程跟前面SYSTICK中斷有點不一樣。SYSTICK中斷雖然設置了溢出事件標志,但其中斷并沒有跟該標志關聯起來。事實上這樣運行起來也沒有任何問題,那么ST設計的外設申請中斷怎么非要跟標志位關聯在一起呢?我們平常做STM32開發時,有時因為疏忽或原理不夠清晰,沒及時清零中斷請求標志讓CPU沒完沒了地進中斷而陷入異常。
why?
整體上,STM32微控制器是由ARM處理器和ST外設集成而來,ARM 處理器又包括內核、核外設【以示區別于ST公司設計的外設】。其中SYSTICK、FPU、MPU、NVIC等均屬于核外設。也就是說,SYSTICK是ARM的外設,不是ST設計的。既然這樣,難道只是設計思路上的差異?但是,SYSTICK中斷可以不跟事件標志關聯起來,可以行得通,為什么ST不也這樣設計呢?
一起來看看,嘗試找找原因。
原因在于SYSTICK外設就一個溢出事件可以申請中斷,在NVIC那邊獨立對應一個中斷請求號【IRQ#],所以CPU在響應SYSTICK中斷時根本無需關注那個溢出標志,有那個溢出事件就夠了,因為除了這個溢出事件沒別的事件來申請TICK中斷。
【下圖是來自STM32G4參考手冊里有關中斷矢量表的部分截圖】
而ST的外設申請中斷時就沒有SYSTICK那么好的福分了。往往是一個外設的多個事件共用1個中斷請求。比方以上面STM32G4系列ADC3的中斷來看,因為它只有1個中斷申請號,在CPU看來就一個中斷入口,即所有ADC3相關事件觸發的中斷共用一個中斷服務程序入口,但可以申請中斷的事件可多了,見下圖【我后面把能觸發同一中斷請求的事件稱之為兄弟事件】:
再以SPI3和LPTIM1的中斷為例,它倆也各只有一個中斷請求號,同樣可以申請中斷的事件也不少,分別見下面兩幅圖。
顯然,ST設計的外設不能照搬SYSTICK的玩法。如果中斷服務程序不跟觸發事件標志關聯起來,進了中斷就不知該基于哪個事件來運行程序;基于某個事件運行了中斷服務程序若不對它清零【包括讀清零、寫清零等】,等兄弟事件觸發再進來時如何分得清哪是過時事件、哪是新觸發的即時事件?
或許有人會說,為什么不給每個ST外設事件都安排一個中斷請求號呢?這要考慮到必要性和中斷請求號的有限性。不難理解必要性并不強,目前ST的設計其實沒有啥不合理的地方。另外,內核開放的中斷請求號數目是也有限的,視不同內核而定。
今天的話題就聊到這里,該問題屬于好奇型的,即使不知道問題原因,一般也不會影響到我們平常的STM32開發。探究下也就是滿足下好奇心,讓內心偶爾掀起一陣漣漪,給生活增添一抹色彩。
審核編輯:湯梓紅
-
cpu
+關注
關注
68文章
10854瀏覽量
211585 -
STM32
+關注
關注
2270文章
10895瀏覽量
355743 -
計數器
+關注
關注
32文章
2256瀏覽量
94478 -
中斷
+關注
關注
5文章
898瀏覽量
41471 -
Systick
+關注
關注
0文章
62瀏覽量
13072
原文標題:關于SYSTICK的COUNTFLAG標志的小疑惑
文章出處:【微信號:stmcu832,微信公眾號:茶話MCU】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論