修改main.s的內容如下:
.section .init
.globl _start
_start:
ldr r0,=0x20200000
mov r1,#1
lsl r1,#18
str r1,[r0,#4]
/* <#1> */
loop$:
mov r1,#1
lsl r1,#16
str r1,[r0,#40]
/* <#2> */
mov r2,#0x3f0000
wait$:
sub r2,#1
cmp r2,#0
bne wait
/* <#3> */
mov r1,#1
lsl r1,#16
str r1,[r0,#28]
/* <#4> */
mov r2,#0x3f0000
wait2$:
sub r2,#1
cmp r2,#0
bne wait2
b loop$
說明:
<#1>
在這段之前的程式碼不變,而這一段落也只加了loop$,這個區段的tag。
<#2>
打開16th pin的開關後,維持一小段時間,再把16th pin的開關關掉,再等待一段時間再打開,如此反覆即可達到閃爍的效果。這一段程式碼的目的就是等待,但是目前還沒用到計數器,只是很單純的暴力解法,設定一個值,然後一直減1減1直到變成0等待結束,這樣的寫法非常直觀,但是不能保證每次的時間間隔是固定的。
使用mov在r2中填入0x3f0000的值,接著設定一個wait$的tag,用sub將r2的值減去1,然後用cmp比較目前r2的值跟0之間的大小,最後用bne反覆執行wait$的內容。bne是指令b的變形,b可以想成是執行,而bne則是有條件的執行,代表當上一次比較結果不一致時則執行,b + not equal = bne。所以在r2的值不為0的時候會一直反覆減1,直到r2 = 0為止才會跳脫wait$這個區段。
<#3>
這個區段的程式碼跟<#1>相似,差別只在於最後將直寫入的記憶體位址不同,這裡是寫到r0 + 28 bytes的地方,而不是r0 + 40 bytes。目的是要將16th pin的Output Set值設定為1,藉此將ACT燈關掉。
<#4>
這個區段跟<#2>意義相同,差別只在於tag不同,因為tag的名稱不能重複,如此而已。這種寫法看起來很蠢,程式碼重複但不能重用,在此先牛刀小試一番,之後再改成聰明的寫法。最後再回到loop$的開頭重新執行,這樣就能使ACT燈一明一滅,非常有趣,當然也可以讓明滅等待的時間不同。
同樣回到Template目錄,執行make編譯,將編譯產生的kernel.img複製到SD卡上取代原本的kernel.img。