計算機實驗室之樹莓派:課程 4 OK04
OK04 課程在 OK03 的基礎上進行構建,它教你如何使用定時器讓 OK 或 ACT LED 燈按精確的時間間隔來閃爍。假設你已經有了 課程 3:OK03 的作業系統,我們將以它為基礎來構建。
1、一個新裝置
定時器是樹莓派保持時間的唯一方法。大多數計算機都有一個電池供電的時鐘,這樣當計算機關機後仍然能保持時間。
到目前為止,我們僅看了樹莓派硬體的一小部分,即 GPIO 控制器。我只是簡單地告訴你做什麼,然後它會發生什麼事情。現在,我們繼續看定時器,並繼續帶你去了解它的工作原理。
和 GPIO 控制器一樣,定時器也有地址。在本案例中,定時器的基地址在 2000300016。閱讀手冊我們可以找到下面的表:
表 1.1 GPIO 控制器暫存器
地址 | 大小 / 位元組 | 名字 | 描述 | 讀或寫 |
---|---|---|---|---|
20003000 | 4 | Control / Status | 用於控制和清除定時器通道比較器匹配的暫存器 | RW |
20003004 | 8 | Counter | 按 1 MHz 的頻率遞增的計數器 | R |
2000300C | 4 | Compare 0 | 0 號比較器暫存器 | RW |
20003010 | 4 | Compare 1 | 1 號比較器暫存器 | RW |
20003014 | 4 | Compare 2 | 2 號比較器暫存器 | RW |
20003018 | 4 | Compare 3 | 3 號比較器暫存器 | RW |
這個表只告訴我們一部分內容,在手冊中描述了更多的欄位。手冊上解釋說,定時器本質上是按每微秒將計數器遞增 1 的方式來執行。每次它是這樣做的,它將計數器的低 32 位(4 位元組)與 4 個比較器暫存器進行比較,如果匹配它們中的任何一個,它更新 Control/Status
以反映出其中有一個是匹配的。
關於位、位元組、位欄位、以及資料大小的更多內容如下:
一個位是一個單個的二進位制數的名稱。你可能還記得,一個單個的二進位制數既可能是一個 1,也可能是一個 0。
一個位元組是一個 8 位集合的名稱。由於每個位可能是 1 或 0 這兩個值的其中之一,因此,一個位元組有 28 = 256 個不同的可能值。我們一般解釋一個位元組為一個介於 0 到 255(含)之間的二進位制數。
一個位欄位是解釋二進位制的另一種方式。二進位制可以解釋為許多不同的東西,而不僅僅是一個數字。一個位欄位可以將二進位制看做為一系列的 1(開) 或 0(關)的開關。對於每個小開關,我們都有一個意義,我們可以使用它們去控制一些東西。我們已經遇到了 GPIO 控制器使用的位欄位,使用它設定一個針腳的開或關。位為 1 時 GPIO 針腳將準確地開啟或關閉。有時我們需要更多的選項,而不僅僅是開或關,因此我們將幾個開關組合到一起,比如 GPIO 控制器的函式設定(如上圖),每 3 位為一組控制一個 GPIO 針腳的函式。
我們的目標是實現一個函式,這個函式能夠以一個時間數量為輸入來呼叫它,這個輸入的時間數量將作為等待的時間,然後返回。想一想如何去做,想想我們都擁有什麼。
我認為這將有兩個選擇:
- 從計數器中讀取一個值,然後保持分支返回到相同的程式碼,直到計數器的等待時間數量大於它。
- 從計數器中讀取一個值,加上要等待的時間數量,將它儲存到比較器暫存器,然後保持分支返回到相同的程式碼處,直到
Control / Status
暫存器更新。
這兩種策略都工作的很好,但在本教程中,我們將只實現第一個。原因是比較器暫存器更容易出錯,因為在增加等待時間並儲存它到比較器的暫存器期間,計數器可能已經增加了,並因此可能會不匹配。如果請求的是 1 微秒(或更糟糕的情況是 0 微秒)的等待,這樣可能導致非常長的意外延遲。
像這樣存在被稱為“併發問題”的問題,並且幾乎無法解決。
2、實現
我將把這個建立完美的等待方法的挑戰基本留給你。我建議你將所有與定時器相關的程式碼都放在一個名為 systemTimer.s
的檔案中(理由很明顯)。關於這個方法的複雜部分是,計數器是一個 8 位元組值,而每個暫存器僅能儲存 4 位元組。所以,計數器值將分到 2 個暫存器中。
大型的作業系統通常使用等待函式來抓住機會在後臺執行任務。
下列的程式碼塊是一個示例。
ldrd r0,r1,[r2,#4]
ldrd regLow,regHigh,[src,#val]
從src
中的數加上val
之和的地址載入 8 位元組到暫存器regLow
和regHigh
中。
上面的程式碼中你可以發現一個很有用的指令是 ldrd
。它載入 8 位元組的記憶體到兩個暫存器中。在本案例中,這 8 位元組記憶體從暫存器 r2
中的地址 + 4 開始,將被複制進暫存器 r0
和 r1
。這種安排的稍微複雜之處在於 r1
實際上只持有了高位 4 位元組。換句話說就是,如果如果計數器的值是 999,999,999,99910 = 11101000110101001010010100001111111111112 ,那麼暫存器 r1
中只有 111010002,而暫存器 r0
中則是 110101001010010100001111111111112。
實現它的更明智的方式應該是,去計算當前計數器值與來自方法啟動後的那一個值的差,然後將它與要求的等待時間數量進行比較。除非恰好你希望的等待時間是佔用 8 位元組的,否則上面示例中暫存器 r1
中的值將會丟棄,而計數器僅需要使用低位 4 位元組。
當等待開始時,你應該總是確保使用大於比較,而不是使用等於比較,因為如果你嘗試去等待一個時間,而這個時間正好等於方法開始的時間與結束的時間之差,那麼你就錯過這個值而永遠等待下去。
如果你不明白如何編寫等待函式的程式碼,可以參考下面的指南。
借鑑 GPIO 控制器的創意,第一個函式我們應該去寫如何取得系統定時器的地址。示例如下:
.globl GetSystemTimerBase GetSystemTimerBase: ldr r0,=0x20003000 mov pc,lr
另一個被證明非常有用的函式是返回在暫存器
r0
和r1
中的當前計數器值:.globl GetTimeStamp GetTimeStamp: push {lr} bl GetSystemTimerBase ldrd r0,r1,[r0,#4] pop {pc}
這個函式簡單地使用了
GetSystemTimerBase
函式,並像我們前面學過的那樣,使用ldrd
去載入當前計數器值。現在,我們可以去寫我們的等待方法的程式碼了。首先,在該方法啟動後,我們需要知道計數器值,我們可以使用
GetTimeStamp
來取得。delay .req r2 mov delay,r0 push {lr} bl GetTimeStamp start .req r3 mov start,r0
這個程式碼複製了我們的方法的輸入,將延遲時間的數量放到暫存器
r2
中,然後呼叫GetTimeStamp
,這個函式將會返回暫存器r0
和r1
中的當前計數器值。接著複製計數器值的低位 4 位元組到暫存器r3
中。接下來,我們需要計算當前計數器值與讀入的值的差,然後持續這樣做,直到它們的差至少是
delay
的大小為止。loop$: bl GetTimeStamp elapsed .req r1 sub elapsed,r0,start cmp elapsed,delay .unreq elapsed bls loop$
這個程式碼將一直等待,一直到等待到傳遞給它的時間數量為止。它從計數器中讀取數值,減去最初從計數器中讀取的值,然後與要求的延遲時間進行比較。如果過去的時間數量小於要求的延遲,它切換回
loop$
。.unreq delay .unreq start pop {pc}
程式碼完成後,函式返回。
3、另一個閃燈程式
你一旦明白了等待函式的工作原理,修改 main.s
去使用它。修改各處 r0
的等待設定值為某個很大的數量(記住它的單位是微秒),然後在樹莓派上測試。如果函式不能正常工作,請檢視我們的排錯頁面。
如果正常工作,恭喜你學會控制另一個裝置了,會使用它,則時間由你控制。在下一節課程中,我們將完成 OK 系列課程的最後一節 課程 5:OK05,我們將使用我們已經學習過的知識讓 LED 按我們的模式進行閃爍。
via: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/ok04.html
作者:Robert Mullins 選題:lujun9972 譯者:qhwdw 校對:wxy
相關文章
- 計算機實驗室之樹莓派:課程 11 輸入02計算機樹莓派
- 計算機實驗室之樹莓派:課程 8 螢幕03計算機樹莓派
- 計算機實驗室之樹莓派:課程 9 螢幕04計算機樹莓派
- 計算機實驗室之樹莓派:課程 7 螢幕02計算機樹莓派
- 計算機實驗室之樹莓派:課程 3 OK03計算機樹莓派
- 計算機實驗室之樹莓派:課程 5 OK05計算機樹莓派
- 計算機實驗室之樹莓派:課程 1 OK01計算機樹莓派
- 計算機實驗室之樹莓派:課程 2 OK02計算機樹莓派
- 計算機實驗室之樹莓派計算機樹莓派
- 樹莓派桌面體驗樹莓派
- 《計算機網路實驗課程》——Wireshark實驗計算機網路
- 樹莓派CM4(四):樹莓派映象替換核心樹莓派
- 樹莓派 4 開箱記樹莓派
- 樹莓派 4 來襲!樹莓派
- 第七天 樹莓派+計算棒配置過程樹莓派
- 用樹莓派計算模組搭建的工業單板計算機樹莓派計算機
- 樹莓派:開機使用樹莓派
- 樹莓派 - 實戰篇 [基於 websocket 實現手機遠端控制樹莓派小車]樹莓派Web
- 樹莓派基金會:截止2015年2月樹莓派微型計算機銷量超500萬臺樹莓派計算機
- 5、樹莓派3 Model B ——— 樹莓派PWM控制直流電機速度樹莓派
- 樹莓派 4 代-入門篇樹莓派
- 樹莓派使用入門:如何更新樹莓派樹莓派
- 樹莓派搭建下載機樹莓派
- 樹莓派是什麼 樹莓派能做什麼 樹莓派的功能用途樹莓派
- 樹莓派自建 NAS 雲盤之——樹莓派搭建網路儲存盤樹莓派
- 樹莓派GUI程式設計樹莓派GUI程式設計
- 樹莓派實戰:微信機器人(itchat實現)樹莓派機器人
- 樹莓派使用樹莓派
- 樹莓派 Zero WH 初使用體驗樹莓派
- 樹莓派4更換軟體源樹莓派
- 樹莓派之安裝webserver(LEMP)樹莓派WebServer
- 【.NET 與樹莓派】控制舵機樹莓派
- 從零做樹莓派挖掘機樹莓派
- 計算機課程程式設計經驗分享計算機程式設計
- 樹莓派4B-PCA9685驅動舵機樹莓派PCA
- 樹莓派使用入門:用樹莓派學 Linux樹莓派Linux
- 樹莓派的GPIO程式設計樹莓派程式設計
- 基於樹莓派的叢集實驗(一)--spark on yarn樹莓派SparkYarn