目 錄
0. 前述
0.1 文例
1. 主結構概述
1.1 模組區塊圖
2. 特殊演算法
2.1 物理特性計算
2.2 三維轉二維演算法
2.3 貼圖遮蔽演算法
2.4 二維繪圖
3. 程式說明
3.1物理特性模組(PHYSICS.v)
3.2加速度計模組(acc_SPI.v)
3.3雙暫存緩衝模組(DOUBLE_BUFFER.v)
3.4 SDRAM初始化模組(SDRAM_init.v)
3.5 LTM模組(LTM_process.v)
3.6 SDRAM繪圖模組(DRAW_TO_SDRAM.v)
3.7貼圖遮蔽模控制組(threeDTotwoD_control.v)
3.8三維轉二維模組(threeDTotwoD.v)
3.9靜態隨機存取記憶體模組(ssram.v)
3.10快閃記憶體寫入靜態隨機存取記憶體模組(flashtossram.v)
3.11靜態隨機存取記憶體讀取模組(ssram_re.v)
3.12靜態隨機存取記憶體寫入模組(ssram_wr.v)
3.13簡易除法模組(divide.v)
0. 前述
本技術手冊內容為數位電路實驗期末專題,以中文來進行撰寫。唯少數無常用中文譯名的專有名詞和程式碼檔名及其內容部份,為求閱讀上的方便,將會直接以英文來表示。至於其他中文翻譯為確定的專有名詞,將會在其後以小括號註解其原文。
0.1 文例
{0,1} :大括號內名詞通常代表數字序列。
[reset] :中引號名詞通常代表該名詞意味著變數名稱。
「初始化」:引號名詞通常代表該名詞意味特殊意義,集合或事件,或是其他段落標題。
註:以下說明裡的變數名稱皆指其在所屬檔案裡的變數名稱,故可能會出現重複的現象
1. 主結構概述
1.1 模組區塊圖
2. 特殊演算法
2.1 物理特性計算
反彈演算法與牛頓運動定律演算法
以下以pseudo code概念描述之
while(1){
//X,_fY_f,Z_f代表球心空間位置
//vx,vy,vz代表球體移動速度
//
//n0[k],n1[k],n2[k]代表球心到第k個偵測點的單位方向向量
//sx[k],sy[k],sz[k]代表第k個偵測點在空間中的位置
for( i=0 ; I < 60 ; ++i){
sx[i] = X_f + 19 * n0[i];
sy[i] = Y_f + 19 * n1[i];
sz[i] = Z_f + 19 * n2[i];
if( sx[i],sy[i],sz[i]組成的座標在反彈執行區域內 ) {
beep[i]=1;
have_beep = 1;}
else{
beep[i]=0;
}
//N0,N1,N2代表概念上的反射面的方向資訊
N0 = N1 = N2 = 0;
for( i = 0 ; i<60; ++i){
N0 +=n0[i]*beep[i];
N1 +=n1[i]*beep[i];
N2 +=n2[i]*beep[i];
}
///////////////////////////////
//v_norm_x,v_norm_y,v_norm_z代表球體速度在(N0,N1,N2)上且方向一//致的正投影,即球體速度與概念上的反射面垂直的分量。
//v_para_x,v_para_y,v_para_z代表球體速度與概念上的反射面平行的分//向。
v_norm_x =abs( ((vx*N0+vy*N1+vz*N2)/(N0*N0+N1*N1+N2*N2))) *N0;
v_norm_y =abs( ((vx*N0+vy*N1+vz*N2)/(N0*N0+N1*N1+N2*N2)))*N1;
v_norm_z = abs( ((vx*N0+vy*N1+vz*N2)/(N0*N0+N1*N1+N2*N2)))*N2;
v_para_x = vx + (-v_norm_x);
v_para_y = vy + (-v_norm_y);
v_para_z = vz + (-v_norm_z);
//new_vx,new_vy,new_vz 充當球體考慮反彈後的速度
new_vx = v_para_x * friction_ratio + (- v_norm_x * reflection_ratio);
new_vy = v_para_y * friction_ratio + (- v_norm_y * reflection_ratio);
new_vz = v_para_z * friction_ratio + (- v_norm_z * reflection_ratio);
//new_x,new_y,new_z 充當球體考慮反彈後的位置
new_x =X_f+(-v_norm_x*2);
new_y =Y_f+(-v_norm_x*2);
new_z =Z_f+(-v_norm_x*2);
//意思是果斷地將球直接移出反射區域。系數”2”為一個保險用比例
X =( have_beep)?new_x : (X + vx);
Y =( have_beep)?new_x : (Y + vy);
Z =( have_beep)?new_x : (Z + vz);
vx =( have_beep)?new_vx : limitation(vx + ax*ascale);
vy =( have_beep)?new_vy : limitation(vy+ ay*ascale);
vz =( have_beep)?new_vz : limitation(vz + az*ascale);
//limitation表示各方向速限,最大值為+1,最小值為-1,單位為像素
//ax為來自加速度儀晶片的加速度資訊ascale為虛擬空間與實體空間加
//速度比例校正參數
}
}
2.2 三維轉二維演算法
在計算球運動的方式之後,需要把它轉到螢幕上去顯示,故要將其三維座標轉換成相對應的二維座標。
三維轉二維的做法大致上分成兩種:(1)正交投影(Orthographic projection ) (2)透視投影(Perspective projection)。此次顯示採用的是透視投影法,如下圖所示。將視點(perspective)和想要投影的點連線,再找到和投影平面的交點就是投影的結果。例如:圖中A點投影在Z = k的平面上的點就是B點。
規格設定是X軸:800、Y軸:480、Z軸:240(單位:像素),視點選在(400,240,1200),投影到Z = 240(單位:像素)的平面,所算出的投影公式:
其中下標代表示三維、二維,X、Y、Z為對應的座標。
此一投影實踐於” 3.8 三維轉二維模組(threeDTotwoD)模組”。
2.3 貼圖遮蔽演算法
在整個長方體(座標和三維轉二維演算法相同)內將其切割成三邊大小為的立方體區塊,故總共有個,目的是將其當作最小單位,來建構障礙物,並將每一個立方體區塊的八個頂點依照下圖編號,上色時以四個頂點決定一個面,一面塗一個顏色,由於一次最多只會看到三個面,所以完全沒有邊相連的兩個面塗相同顏色。各面的編號如下表所示,在傳送每個面時,會將四頂點的X、Y座標分開傳。
平面編號
|
頂點
|
face1
|
3478
|
face2
|
1234或5678
|
face3
|
2468或1357
|
由於此小立方體在轉成二維座標去上色的時候,會有互相遮蔽的問題,如下面左右兩圖所示,其中的數字代表區塊(block)上色的順序,左邊的上色順序造成不合理的結果,因為中間多了一塊不可能看得到的顏色,要像右邊的作法,所做出來的圖才是正確的的,因此,不可以就照座標順序一直畫下去,須想方法讓它們的遮蔽關係是合理的。
最簡單的解決方法就是從距離視點最遠的區塊塗到距離最近的區塊,由於在不同Z值上的區塊直接照順序就剛好是從遠排到近,故不必特別去排序。而不同X、Y得排序法會因為所處的區域不同,造成須有不同的順序,因此把其分成四大區域(1,2,3,4),如下圖所示。在各區域只要依照箭頭所示的方向依序上色,所畫出的結果就是合理的,可以由下圖看出先畫X還是Y是沒有影響的,不過,實踐上是先畫X再畫Y再畫Z,比較符合一般的直覺。
此一演算法實踐於” 3.7 貼圖遮蔽模控制組(threeDTotwoD_control)模組”,其中每一個區塊是以最靠近原點的頂點(以三維座標而言)為代表。
2.4 二維繪圖
此演算法為將一完整立體圖形在特定視角下可見的三個面,其四個座標點的資料分別轉為一整面的離散座標點,並將其寫入靜態隨機存取記憶體(ssram,以下簡稱為記憶體)中。首先見下圖:
此圖表示了原始四點的資料分佈位置,其預定形成的面共有三種情況,在圖中以三種不同的顏色來表示,輸入的順序皆為圖上標示數字的由小而大。此三種情況分別為正方形和兩個分別在X方向以及Y方向平行的梯形。由於記憶體的寫入一次只能寫入一個單位(cell)的資訊,故此處形成面的每一座標點皆需一個一個依序寫入。
此處採用的是逐行分別寫入的方式,此處行代表與四邊形平行邊平行的方向。首先須先將原始四點座標分類為起始邊和結束邊,每當其中一行寫入完成後便沿起始邊和結束邊跟新此次行輸入的起始和結束位置,跟新方式為列座標加一、行座標加斜率值,並重新寫入下一行,直到完成整個四邊形的寫入。逐行移動的方向為上圖標示編號的由小到大,當三個方向的面皆完成後便可得到一立方體的平面視圖。
但是需注意輸入的點順序和其所形成的面的位置關係會因為原本的立方體所在的位置而不同,共會有以下四種情況:
因此當每一行的起始點在作列方向移動時,需考慮行方向的座標值移動方向,此部份可透過計算斜率時帶有正負號來完成。以下為簡易流程圖:
此演算法可以透過有限狀態機(finite state machine)來達成。
3. 程式說明
3.1物理特性模組(PHYSICS.v)
介面:
變數名
|
類型
|
大小(bits)
|
說明
|
clk
|
輸入
|
1
|
時序資訊,用以驅動本模組。本次實作本模組的操作頻率為10MHz
|
reset
|
輸入
|
1
|
初始化命令參數,邏輯值為{0}時及執行本模組的初始化動作。
|
ax,ay,az
|
輸入
|
8
|
來自acc_SPI模組的加速度儀晶片所偵測到的三方向加速度資訊,格式為8位元的2補數。
|
X,Y,Z
|
輸出
|
32
|
當前球體空間位置,格式為2補數,但本次實作理論實際數字範圍皆為0~800的正數。
|
cube_x_cnt,
cube_y_cnt,
cube_z_cnt
|
輸入
|
5
4
3
|
threeDTotwoD_control模組在此模組中查詢空間資訊的相關參數,供空間資訊繪圖參考
|
fill
|
輸出
|
1
|
回應threeDTotwoD_control模組在此模組中查詢空間資訊的相關參數
|
<以下均為測試用參數,對外沒有實質應用功能>
|
user_X_f,
user_Y_f,
user_Z_f
|
輸入
|
32
|
用以測試偵測點計算模組(SENSOR_OPERATION)正確性的測資輸入,一開始作用是由測試者決定球心座標。
|
count_wire
|
輸出
|
11
|
用以觀測相態
|
N0,N1,N2
|
輸出
|
32
|
內部線路,用以溝通計算出的反射方向,格式為IEEE-754 Floating Point
|
id0, ids0
|
輸出
|
7
|
內部傳遞參數,與cube_x_cnt功能相同。
|
n0,ns0
|
輸出
|
32
|
內部傳遞參數,與fill功能相同
|
have_beep
|
輸出
|
1
|
內部傳遞參數,是偵測點計算模組(SENSOR_OPERATION)用以告知移動計算模組(CAL_MOVE)球體是否該發生碰撞行為。
|
out_test
|
輸出
|
1
|
輸出時序信號供測試參考。
|
重要資料流向示意
說明:
如上圖,本模組包含若干子模組,SENSOR_OPERATION, CAL_MOVE, NORMAL_VECTOR,AREA_MAP四個主要子模組。對外的溝通行為包含傳送球體空間座標給DRAW_TO_SDRAM、傳送空間障礙物資訊給ThreeDTotwoD_control、以及接收acc_SPI處理的加速度偵測儀資訊。
本模組主要功能就是計算球體的運動行為,包含位置、速度、加速度、碰撞模型,關於物理模型的詳細資訊,” 2.1 物理特性計算”。
資料演算流程:
SENSOR_OPERATION首先先以球體目前所在位置,以及NORMAL_VECTOR所提供的偵測點相對於球體位置的方向向量,推算出60個碰撞偵測點在空間中的所在位置,之後參考AREA_MAP所提供的空間資訊去判斷這六十個偵測點是否進入碰撞執行區域,進而推算出反射方向資訊。
CAL_MOVE接著根據反射方向計算球體在下一步在空間中可能的所在位置。
其中每一個步驟會動用到大量的浮點數運算,我們在模組內因此安排了若干個FPGA板所提供的mega function形式的浮點數整數轉換器、加法器、乘法器……等。
以下將以圖示表示詳細資料流以及各單位所占用的運算資源與運算時間。
圖 總共具有三個浮點數家法器、三個浮點數乘法器、以及三個浮點數轉整數轉換器
SENSOR_OPERATION中,第一部分都是在處理碰撞偵測點的位置以及是否有碰撞事件發生。
之後就是把具有碰撞事件的偵測點向量全部加總。我們善用加法器可連續指定的特性,兩兩一組連續送入,以減少每一次運算需要7個cycle time在時間上耗費。最後得到的就是代表碰撞面的方向資訊向量。
這個向量之後會送入CAL_MOVE中,繼續計算碰撞、牛頓運動定律以求出球體位置。
CAL_MOVE中,具有三個浮點數乘法器、一個浮點數加法器、一個浮點數倒數器、一個浮點數轉整數轉換器(用來將浮點數座標轉至整數以傳送到DRAW_TO_SDRAM模組繪出球體)、一個整數轉浮點數轉換器(用在處理來自acc_SPI加速度資訊)以及一個浮點數大小比較器。
計算的排程概念同上,詳細演算流程請參閱物理特性計算相關章節。整個CAL_MOVE計算從開始到完成需要約110個cycle time,加上前面SENSOR_OPERATION所需要的180個cycle time,整個物理模組計算所花的時間就約花費290個cycle time。在10MHz的clk的驅動下,整個運算所花實體時間約為0.03ms。
在外部,只要所設定的物理運算週期大於290個cycle time都是在可調整的範圍內。我們目前設定一次物理運算週期為1000個10MHz,也就是說,物理模組的計算周期為0.1ms。
3.2加速度計模組(acc_SPI.v)
介面:
名稱
|
類型
|
位元數
|
功能
|
reset
|
input
|
1
|
重置訊號,用以重設加速度計。
|
clk
|
input
|
1
|
模組所需的時脈,需為4MHz。
|
ready
|
output
|
1
|
讀值改變訊號。1時為正在改變。
|
Xa
|
output
|
8
|
X方向加速度讀值。
|
Ya
|
output
|
8
|
Y方向加速度讀值。
|
Za
|
output
|
8
|
Z方向加速度讀值。
|
cs_o
|
output
|
1
|
加速度計的晶片選擇訊號。
|
spclk_o
|
output
|
1
|
加速度計SPI介面時脈。
|
sdio_io
|
inout
|
1
|
加速度計SPI介面資料。
|
drdy
|
input
|
1
|
加速度計測量完成訊號。
|
功能說明:
此模組的功能是用來和外界的加速度計模組做溝通,並將其量測到的加速度值分別以X、Y、Z三方向各8位元,二進位補數法來表示之。再設定上是用SPI介面和加速度計做聯繫,其波形如下:
http://www.parallax.com/Portals/0/Downloads/docs/prod/sens/FreescaleMMA7455LDeviceDocumentation.pdf (figure 11&12)
其每次動作共有16個時脈週期,並以[cs]為低電位時做為一週期,其中第一個時脈送出寫入讀取訊號,後接6位元的暫存器位址,並在隔一時脈後讀入或輸出其值(8位元)。
程式說明:
整體構成為兩個有限狀態機(finite state machine),其中一個用來「重設」加速度模組的設定,另一為用來讀取加速度值,兩者以一個控制用位元[mode]來決定哪一有限狀態機的輸出訊號將外連至加速度計。
重設部份
「重設」的部份其以[reset]為零作為起始訊號,將其狀態[step]回覆到開始狀態(0),並開始動作。
控制用特殊參數
名稱
|
功 能
|
ini_pattern
|
記錄此週期所要輸出的資料流。
|
ini_sel
|
選擇所要使用的[ini_pattern]。有關[ini_pattern]所代表的意義,請參見(http://www.parallax.com/Portals/0/Downloads/docs/prod/sens/FreescaleMMA7455LDeviceDocumentation.pdf)
|
各狀態功能及動作如下:
狀態
|
動作
|
0
|
起始狀態,所有控制參數回復初始值。
|
1~16
|
依序輸出[ini_pattern]的值。
|
17
|
用[reg_sel]檢查是否還有需要輸入的[ini_pattern],若有則回到狀態1重新輸入。若無則進入閒置狀態。
|
18
|
閒置狀態,此時[mode]轉為1,連至實體加速度的介面轉至讀取部份。
|
讀取部份
讀取部份則是依據由加速度計傳來的[drdy]訊號來開始動作,此訊號為加速度計量測完成的訊號,約以60Hz的頻率來變化。此外位了減少輸出值[Xa]、[Ya]、[Za]的變化時間。此處是先將讀值存取到加速度讀值緩衝[Xa_in]、[Ya_in]、[Za_in]後再一次改變。
控制用特殊參數:
名稱
|
功 能
|
read_pattern
|
記錄要讀取的暫存器位置。
|
reg_sel
|
選擇此次要讀取的暫存器。
|
w_counter
|
用來決定目前[read_pattern]的輸出位元。
|
r_counter
|
用來決定目前從[sdio_io]的讀值要寫入哪一位元。
|
rw
|
目前[sdio_io]的運作模式。(1:write、0:read)
|
各狀態功能及動作如下:
狀態
|
動作
|
0
|
起始狀態,所有控制參數回復初始值。
|
1~8
|
依序輸出[read_pattern]的值。
|
9~16
|
讀入[sdio_io]的值,並將其依序寫入加速度讀值緩衝。
|
17
|
用[reg_sel]檢查是否X、Y、Z方向加速度值都以讀取完畢,若無則回到狀態1。
|
18
|
將[Xa_in]、[Ya_in]、[Za_in]寫入[Xa]、[Ya]、[Za]。
|
19
|
閒置狀態。等下次[drdy]為高電位時再回到狀態0。
|
3.3雙暫存緩衝模組(DOUBLE_BUFFER.v)
介面:
變數名
|
類型
|
大小(bits)
|
說明
|
clk_50M
|
時序輸入
|
1
|
50MHz的時序信號輸入,之後會通過一個PLL變頻器產生出40MHz的時序信號供SDRAM記憶體寫入功能使用
|
clk_40Mo
|
時序輸出
|
1
|
向外送出的時序信號,目的是讓外界需要顯示功能的模組藉此達到時序同步
|
reset
|
重設
|
1
|
重至訊號,在其為邏輯0時執行重置
|
write_done
|
輸入
|
1
|
外界模組在寫入動作完成時,需藉由將write_done持續設為邏輯{1}(至少直到偵測到[turn_sign]信號變為邏輯{1}為止)告訴本模組外界寫入動作已完成,可以允許兩個記憶體讀寫角色交換
|
turn_sign
|
輸出
|
1
|
在記憶體讀寫角色交換後,本模組會對外界,以約33MHz的頻率產生一個邏輯{1}的突波告知記憶體讀寫角色已成功交換,可以進行下一回合的顯示寫入動作。
|
switch
|
輸入
|
1
|
測試期間遺留的變數,對目前功能沒有重要作用
|
mask
|
輸入
|
1
|
SDRAM記憶體寫入資料遮罩。若為邏輯{1}則表示命令SDRAM無視當前的待寫入資料:[writer_data]。
|
|
|
|
|
writer_syq
|
輸出
|
1
|
本模組執行SDRAM的寫入動作時是以12個[clk_40o]個時間長度為一個大回合。當writer_syq為邏輯{1}時,表示內部寫入程序正在一個大回合的最終階段,告知外界準備開始下一回合的寫入動作。關於本模組寫入回合的設計,請參照後續說明
|
writer_col
|
輸入
|
13
|
資料待寫入SDRAM的目標行位址
|
writer_row
|
輸入
|
13
|
資料待寫入SDRAM的目標列位址
|
writer_data
|
輸入
|
16
|
待寫入資料
|
|
|
|
|
HD
|
直接與LTM硬體溝通的參數,請參閱LTM_process相關章節。
|
VD
|
DEN
|
R
|
G
|
B
|
NCLK
|
reset_o
|
<以下區域為直接與兩個SDRAM硬體溝通的相關參數>
|
DRAM_A0
|
輸出
|
13
|
用以告知SDRAM寫入/讀取資料的位址資訊。
|
DRAM_D0
|
輸出/輸入
|
16
|
用以與SDRAM溝通寫入/讀取的資料內容
|
CLK0
|
輸出
|
1
|
送入控制SDRAM的時序資訊。向SDRAM寫入資料時須送入[clk_40o]的時序資訊;從SDRAM讀取資料時須送入[clk_33M]的時序資訊(與LTM模組顯示頻率同步)
|
CKE0
|
輸出
|
1
|
時序開關。在本次設計為永遠設為邏輯{0},意指要求晶片永遠對時序有反應。
|
LDQM0
|
輸出
|
1
|
下八位資料讀寫遮罩,本次設計為向SDRAM寫入資料時參考[mask]信號;從SDRAM讀取資料時則永遠為邏輯{0}(意指不遮蔽)
|
UDQM0
|
輸出
|
1
|
上八位資料讀寫遮罩。在本次設計中其邏輯值與[LDQM0]邏輯一致。
|
WE0
|
輸出
|
1
|
控制SDRAM的功能參數。與[CAS0]、[RAS0]以一定型式互相配合方有作用,欲知本次被使用到的功能,請參照本章「說明」相關小節;欲知SDRAM對此參數的完整功能支援,請參照SDRAM說明文件。
|
CAS0
|
輸出
|
1
|
RAS0
|
輸出
|
1
|
CS0
|
輸出
|
1
|
「chip select」的縮寫,邏輯{1}時代表晶片不動作
|
BA0
|
輸出
|
2
|
|
|
|
|
|
DRAM_A1
|
輸出
|
13
|
功能概念與上述同名參數相同,只是專門掌管另一個實體SDRAM。
|
DRAM_D1
|
輸出
|
16
|
CLK1
|
輸出
|
1
|
CKE1
|
輸出
|
1
|
LDQM1
|
輸出
|
1
|
UDQM1
|
輸出
|
1
|
WE1
|
輸出
|
1
|
CAS
|
輸出
|
1
|
RAS1
|
輸出
|
1
|
CS1
|
輸出
|
1
|
BA1
|
輸出
|
2
|
說明:
「DOUBLE_BUFFER」模組由兩個「SDRAM_init」、一個寫入程序管理區塊、一個讀取程序管理區塊、以及一個「LTM_process」所組成,主要的功能是作為從顯示資訊到「LTM」顯示器之間的記憶體緩衝區。兩個「SDRAM_init」除了初始化命令出現的同時執行對SDRAM硬體的初始化外,其餘時間控制權是由「DOUBLE_BUFFER」模組內部的寫入程序管理區塊以及讀取程序管理區塊直接掌管。
模組黑盒子使用方式:
由於所有需要顯示的資料在本次架構中是規定全部必須經過「DOUBLE_BUFFER」的管理,因此,從顯示資料開始,往LTM顯示器的方向看去,這可以視為一個專門管理顯示功能的模組。所有需要利用顯示功能的其他模組,只要遵守本次架構對DOUBLE_BUFFER的使用規則,便可達到顯示目的
以下說明我們對每一幀畫面資料的假設與輸入要求方式
i. 顯示解析度為800(col)*480(row)。每個像素為16bit的RGB565分配方式。
ii. 輸入方式規定一個回合必須「連續輸入八個同列像素」的資料(但這8個為一組的資料,位址彼此之間沒有規定關係)。倘若其中某個像素想要跳過不覆蓋任何值可利用[mask]功能跳過。[mask]是提供資料遮罩。倘若不想要因強制的規定形式而被迫必須對顯示畫面的像素作任何更改,可將[mask]邏輯值送入邏輯{1}。
iii. 這八個同列的像素,起始像素位址的行位址必須是八的倍數才會有正常顯示功能。
iv. 記憶體內部資料除了經過關機狀態以外都不會消失,因此若要顯示黑屏請自行對顯示畫面所有像素送入資料{16’h0000}。
v. 每一幀畫面的所有像素都輸入完畢後,可以回合為時間單位,須將[writer_done]改為邏輯{1},且將[mask]設為邏輯{1}或隨便指定列與行位址為畫面外範圍,直到收到[turn_page]的回應,以通知讀取程序管理區塊可以讀取本幀畫面。當讀取程序管理區塊開始切換讀取本幀畫面時,[turn_page]會出現一定長時間(1個33MHz頻率的時序週期)的突波回應已換頁,之後可以將[writer_done]暫時改回為邏輯{0},繼續輸入下一幀畫面資料。請注意[turn_page]信號出現的位址並不以回合為單位
vi. 目前的版本,外部模組尚無法從「DOUBLE_BUFFER」查看最新寫入的資料。故資料方向為單方向。請應用者注意。
D1. D2. D3 D4 ..D5 D6 D7 .D8
|
請在輸入最後一個像素以後,才將[writer_done]設為{1}
可能須等待若干回合直至[turn_page]出現
|
模組內部運作形式:
[writer_data],[writer_col],[writer_row],[mask]
|
內部,wrcmd和rdcmd是本模組中兩個概念上的控制區域,是為寫入程序管理區塊與讀取程序管理區塊。圖中線條代表資料流的概念走向。由於兩個實體SDRAM的資料排線各自只有一套IO,因此SDRAM是無法作到同時讀取資料又同時寫入資料的。而且SDRAM的寫入讀取都需要透過一定複雜的命令來執行,在須同時兼顧顯示速率、命令正確性以及與LTM硬體可正常溝通的情況下,就必須有這兩個管理區塊來專門執行讀取寫入的動作。
圖中的MUX、開關概念的方向,是由程式內部的[RW_state]參數值決定。當值為邏輯{0}時,表示資料寫入至SDRAM1且LTM讀取SDRAM0內部的資料;當值為邏輯{1}時,表示資料寫入至SDRAM0且LTM讀取SDRAM1內部存放的資料。[RW_state]的參數,只有在[writer_done]為邏輯{1}且LTM掃描至其概念頁的結尾時,才會翻轉,進而影響整個內部的讀取/寫入模式。
寫入程序管理區塊
寫入程序管理區塊,基本上就是連續性不間斷第對外部輸出SDRAM的寫入命令,而他目前是否有實際管理到任何記憶體也不在乎。他可以視為是一個具有12個state的有限相態機器(finite state machine) 因為一個穩定、具有可隨時換列、換頁的寫入程序最穩定狀態,經過本組研究發現需要12個命令相態,因此就如此體現。我們所設計的命令如下表所示:
相態
|
[WRCMD_addr]
|
[WRCMD_ras]
|
[WRCMD_cas]
|
[WRCMD_we]
|
[WRCMD_ba]
|
命令,及動作說明
|
0
|
{2'b0,1'b1,10'b0}
|
0
|
1
|
0
|
在[writer_col]的值大於或等於400時為{01},其他時候為{00}
|
precharge all bank
|
1
|
13'b0
|
1
|
1
|
1
|
NOP
|
2
|
[writer_row]的值
|
0
|
1
|
1
|
Activate a bank and a row
|
3
|
13’b0
|
1
|
1
|
1
|
NOP
|
4
|
[writer_col]對應至記憶體位址的值
|
1
|
0
|
0
|
輸入第一個行位址/寫入D1
|
5
|
13’b0
|
1
|
1
|
1
|
寫入D2
|
6
|
13’b0
|
1
|
1
|
1
|
寫入D3
|
7
|
13’b0
|
1
|
1
|
1
|
寫入D4
|
8
|
13’b0
|
1
|
1
|
1
|
寫入D5
|
9
|
13’b0
|
1
|
1
|
1
|
寫入D6
|
10
|
13’b0
|
1
|
1
|
1
|
寫入D7
|
11
|
13’b0
|
1
|
1
|
1
|
寫入D8
|
所有像態變化時機均為負緣觸發
本次所使用的SDRAM型號為IS42S16160B,結構上含有4個bank,每個bank含有13bits(4096個)的row,以及9bits(512個)的column,每個位址記憶16bits。但本次所需要用到的顯示解析度為 800 * 480 ,而且LTM的掃描方向又是以水平方向為優先,因此若只是直接讓512處理column對應到800個像素上是不夠用的,勢必要有其他記憶體對應方式。
本次處理的對應方式是讓0~399的顯示像素資訊儲存於bank0的0~399的column內,讓400~799的顯示像素資訊儲存於bank1的0~399的column內,如此的好處是記憶體換算公式比較簡單。
從使用介面到這一層的命令,可知需要在某些資料上應用若干個延遲機器。比方說[writer_data]到真正寫入D1之間相差了4個時序週期(clk),這就需要對[writer_data]作4個時序週期的延遲。
其他詳細的命令資訊請參閱SDRAM使用手冊。
讀取程序管理區塊
讀取程序管理區塊主要功能是建立LTM和SDRAM之間資訊能夠正常溝通的管道。
若要SDRAM與LTM配合使用,那SDRAM就要支援LTM的「連續不斷地」讀取動作。因此,讀取程序管理區塊就必須設計為具有八個像態的有限相態機器。
各相態功能如下:
相態(第n回合)[RDCMD_phase]
|
[RDCMD_addr]
|
[WRCMD_ras]
|
[WRCMD_cas]
|
[WRCMD_we]
|
[WRCMD_ba]
|
命令,及動作說明
|
0
|
讀取的列位址
|
0
|
1
|
1
|
在[writer_col]的值大於或等於400時為{01},其他時候為{00}
|
Activate a bank and a row/讀取Dn-15
|
1
|
13’b0
|
1
|
1
|
1
|
NOP/讀取Dn-16
|
2
|
讀取的行位址(A0~A8),且A10必須設為1,其餘填{0}
|
1
|
0
|
1
|
Read with auto precharge/讀取Dn-17
|
3
|
13’b0
|
1
|
1
|
1
|
NOP/讀取Dn-18
|
4
|
13’b0
|
1
|
1
|
1
|
讀取Dn1
|
5
|
13’b0
|
1
|
1
|
1
|
讀取Dn2
|
6
|
13’b0
|
1
|
1
|
1
|
讀取Dn3
|
7
|
13’b0
|
1
|
1
|
1
|
讀取Dn4
|
所有像態變化時機均為負緣觸發
可以發現,讀取回合與命令回合中間相差了四個時序週期,因此,要讓LTM與SDRAM順利溝通,同樣也是需要若干個延遲機器。
另外,讀取程序管理區塊與寫入程序管理區塊內部所使用的所有flip-flop的變化順間都是使用時序資訊的負緣觸發,但在LTM不然,因此就要處理正負緣觸發之間的溝通問題。
以下舉SDRAM與LTM溝通的時間表一例。
[RDCMD_phase]會根據[projector_x]的值除以8的餘數來調整自己的值
|
若[projector_x]的值大於等於611則數值為1,其餘為0,意思是可見螢幕範圍的左半邊儲存於bank0,右半邊儲存於bank1,故讀取時也要讀取對應的bank
|
由LTM_process模組提供的像素的掃描位置,216為螢幕可見的最左端位址,1016為最右端
|
SDRAM硬體恰好會在rdclk的正緣觸發時改變送出的值。
|
3.4 SDRAM初始化模組(SDRAM_init.v)
介面:
變數名
|
類型
|
大小(bits)
|
說明
|
clk_reset
|
時序輸入
|
1
|
用來驅動執行SDRAM初始化的時序信號
|
clk_in
|
時序輸入
|
1
|
用來送入SDRAM硬體的時序信號,只有在SDRAM初始化程序完成以後其信號才會導入SDRAM內。其邏輯值可以與[clk_reset]無關係
|
addr
|
|
|
讓其他模組控制SDRAM的參數,只有在SDRAM初始化程序完成以後其信號才會導入SDRAM內。
|
data_in
|
|
|
data_out
|
|
|
we
|
|
|
cas
|
|
|
ras
|
|
|
ba
|
|
|
mask
|
|
|
reset
|
|
|
用以命令SDRAM初始化程序開始的參數
|
operating
|
|
|
邏輯值為{1}表示告訴外界初始化程序執行中,記憶體暫由此模組接管;{0}表示初始化程序完成,記憶體交由外部模組接管。
|
sel
|
|
|
用以管理,處理inout線路的高阻抗狀態參數。因SDRAM的we的邏輯值並不完全表示SDRAM當前是讀取或寫入的狀態,因此inout的線路就要另闢此參數作管理。
|
<以下區域為直接SDRAM硬體溝通的相關參數>
|
DRAM_A
|
輸出
|
13
|
用以告知SDRAM寫入/讀取資料的位址資訊。
|
DRAM_D
|
輸出/輸入
|
16
|
用以與SDRAM溝通寫入/讀取的資料內容
|
CLK
|
輸出
|
1
|
送入控制SDRAM的時序資訊。向SDRAM寫入資料時須送入[clk_40o]的時序資訊;從SDRAM讀取資料時須送入[clk_33M]的時序資訊(與LTM模組顯示頻率同步)
|
CKE
|
輸出
|
1
|
時序開關。在本次設計為永遠設為邏輯{0},意指要求晶片永遠對時序有反應。
|
LDQM
|
輸出
|
1
|
下八位資料讀寫遮罩,本次設計為向SDRAM寫入資料時參考[mask]信號;從SDRAM讀取資料時則永遠為邏輯{0}(意指不遮蔽)
|
UDQM
|
輸出
|
1
|
上八位資料讀寫遮罩。在本次設計中其邏輯值與[LDQM0]邏輯一致。
|
WE
|
輸出
|
1
|
控制SDRAM的功能參數。與[CAS0]、[RAS0]以一定型式互相配合方有作用,欲知本次被使用到的功能,請參照本章「說明」相關小節;欲知SDRAM對此參數的完整功能支援,請參照SDRAM說明文件。
|
CAS
|
輸出
|
1
|
RAS
|
輸出
|
1
|
CS
|
輸出
|
1
|
「chip select」的縮寫,邏輯{1}時代表晶片不動作
|
BA
|
輸出
|
2
|
bank
|
|
|
|
|
說明:
由於SDRAM的初始化程序相對複雜,故本模組目的只是在於為SDRAM的初始化程序提供一個包裝。讓使用SDRAM的使用者透過簡單輸入一個觸發信號[reset]來對SDRAM作初始化。
本模組內部在初始化所作的程序完全遵照SDRAM IS42S16160B說明文件中的指示(如下圖),詳情請參閱IS42S16160B晶片相關說明文件。
在初始化程序執行時,[operating]的邏輯值為{1},本模組擁有該實體SDRAM的管理權限;在初始化程序執行完畢後,則SDRAM的權限則全部交由外部模組控制,包含命令、時序資訊、以及資料流。
另外必須注意的是,本模組對控管SDRAM的輸入輸出腳位事先作了區分,分別以[data_in]以及[data_out]來配合SDRAM的DRAM_D腳位輸入輸出的資料流。控制DRAM_D腳位輸入輸出的角色依據是[sel]的邏輯值。當[sel]邏輯值為{1}時,表示DRAM_D腳位在本模組當作信號輸入,本模組內相應對策是將其接至高阻抗以讀取資料;反之則當其為信號輸出,由[data_in]負責提供輸出信號。
也就是說,外部模組可直接控制[sel]的邏輯值,並以[data_in]來決定輸入實體SDRAM的資料,並以[data_out]接收來自於實體SDRAM的資料,藉此免除後續輸入輸出應用的衍生問題。
3.5 LTM模組(LTM_process.v)
介面:
變數名
|
類型
|
大小(bits)
|
說明
|
reset
|
輸入
|
1
|
重設訊號
|
clk50M
|
輸入
|
1
|
33.3M的時序
|
pattern_R
|
輸入
|
8
|
雙暫存緩衝模組要送給LTM紅色的資訊
|
pattern_G
|
輸入
|
8
|
雙暫存緩衝模組要送給LTM綠色的資訊
|
pattern_B
|
輸入
|
8
|
雙暫存緩衝模組要送給LTM藍色的資訊
|
NCLK
|
輸出
|
1
|
送給LTM 的33.3M時序
|
HD
|
輸出
|
1
|
送給LTM 的水平同步訊號
|
VD
|
輸出
|
1
|
送給LTM 的垂直同步訊號
|
DEN
|
輸出
|
1
|
送給LTM 的資料有效化訊號(data enable signal)
|
R
|
輸出
|
8
|
送給LTM紅色的資訊
|
G
|
輸出
|
8
|
送給LTM綠色的資訊
|
B
|
輸出
|
8
|
送給LTM藍色的資訊
|
reset_o
|
輸出
|
1
|
送給LTM的GRESET訊號(global reset)
|
projector_x
|
輸出
|
11
|
送給雙暫存緩衝模組目前掃到的X座標
|
projector_y
|
輸出
|
10
|
送給雙暫存緩衝模組目前掃到的Y座標
|
說明:
閱讀儀器所附的資料冊(TRDB_LTM_UserGuide_v1.23.pdf),可知顯示的格式(3-2章),唯一須要注意的是要將訊號改成和NCLK的正緣觸發對齊才能正常運作。此本模組是依照的解析度實踐,掃完一整頁的波形如下圖二所示。
圖一:每一行的波形
圖二:每一頁的波形
將螢幕(即每一頁)想像成如下圖所示可以方便理解。先掃完一行X再掃下一行,到最後一個像素,會在回到原點從頭掃一次。需要注意的是X軸的時間單位是一個NCLK,但Y軸的單位是1056個NCLK,所要求的值都在寫在資料冊(datasheet)中。原始碼中會有用來記錄目前掃到的像素座標(x_cnt, y_cnt),而顏色的資訊只有在掃到紅色的區塊的時候才需要送出,故會有用來記錄的變數[display_area],其餘的變數皆和上兩圖的相同。
重要變數:
變數名稱
|
功能
|
宣告形式
|
x_cnt
|
記錄目前掃到的像素X座標
|
reg [10:0] x_cnt
|
y_cnt
|
記錄目前掃到的像素Y座標
|
reg [9:0] y_cnt
|
display_area
|
記錄是否到需要送出顏色資訊的位元
|
reg display_area;
|
3.6 SDRAM繪圖模組(DRAW_TO_SDRAM.v)
介面:
變數名
|
類型
|
大小(bits)
|
說明
|
clk_50M
|
輸入
|
1
|
時序資訊,用以驅動本模組。本次實作本模組的操作頻率為40MHz,與DOUBLE_BUFFER的寫入程序管理模組的驅動時序完全相同。
|
reset
|
輸入
|
1
|
初始化命令參數,邏輯值為{0}時及執行本模組的初始化動作。
|
<以下為直接與DOUBLE_BUFFER模組溝通的參數>
|
turn_sign
|
輸入
|
1
|
來自DOUBLE_BUFFER模組的換頁提醒。詳情請參照DOUBLE_BUFFER模組說明章節。
|
writer_syq
|
輸入
|
1
|
來自DOUBLE_BUFFER模組的寫入程序同步化信號,詳情請參照DOUBLE_BUFFER模組說明章節
|
mask_i
|
輸出
|
1
|
直接與DOUBLE_BUFFER模組溝通,詳情請參照DOUBLE_BUFFER模組說明章節
|
writer_col
|
輸出
|
13
|
writer_row
|
輸出
|
13
|
writer_data
|
輸出
|
16
|
write_done_i
|
輸出
|
1
|
<以下參數為來自PHYSICS模組的資訊>
|
X_in,Y_in,Z_in
|
輸入
|
13
|
為來自PHYSICS模組所計算出的球體位置資訊
|
<以下參數為直接與ssram模組溝通的參數>
|
writer_col_bg_pseudo
|
輸出
|
13
|
對ssram要求讀取記憶體的行位址
|
writer_row_bg_pseudo
|
輸出
|
13
|
對ssram要求讀取記憶體的列位址
|
ssdata
|
輸入
|
16
|
ssram回應的記憶體內容
|
<以下為測試用參數,無實質應用功能>
|
*switch
|
輸入
|
1
|
來自開關,用以測試DOUBLE_BUFFER功能的正確性
|
*mask
|
輸入
|
1
|
來自開關,用以測試DOUBLE_BUFFER功能的正確性
|
說明:
DRAW_TO_SDRAM的主要功能就是作為顯示畫面貼圖的排程,包含背景資訊與球體。
每一幀的貼圖順序都是由一個繪圖排程區塊先將背景資訊由ssram寫入到DOUBLE_BUFFER,之後再將球體繪至畫面的目標位置。
繪圖排程區塊作用說明如下表
相態
|
命令參數
|
監視參數
|
描述
|
0
|
[call_bg] = 1’b0;
[call_ball] = 1’b0;
[write_done_i]=1’b1
|
[turn_sign]
|
閒置狀態,持續發送繪圖完成信號並等待DOUBLE_BUFFER的換頁信號出現,才跳至相態1
|
1
|
[call_bg] = 1’b1;
[call_ball] = 1’b0;
[write_done_i]=1’b0
|
[writer_bg_done]
|
觸發背景繪圖區塊開始作用,並將DOUBLE_BUFFER繪圖權限交由背景繪圖區塊。其後就等待背景繪圖權限回應繪圖動作完成,跳至相態2
|
2
|
[call_bg] = 1’b0;
[call_ball] = 1’b1;
[write_done_i]=1’b0
|
[writer_ball_done]
|
觸發球體繪圖區塊開始作用,並將DOUBLE_BUFFER繪圖權限交由球體繪圖區塊。其後就等待背景繪圖權限回應繪圖動作完成,跳回像態0
|
如此,若要增加其他繪圖物件,只要考慮相互遮蔽問題後,在繪圖排程區塊內加入排程,只要適當管理好直接與DOUBLE_BUFFER模組溝通的參數如前表<直接與DOUBLE_BUFFER模組溝通的參數>一區內所有參數,並遵守相關寫入規則(包含與繪圖排程區塊的溝通以及DOUBLE_BUFFER寫入程序管理區塊要求原則)即可。
背景繪圖區塊
背景資訊在經過ThreeDTotwoD之後相關模組編譯後的結果是儲存在ssram內部,因此,DRAW_TO_SDRAM就必須具有與ssram溝通的能力。ssram內部也存在一個ssram_re模組專門服務DRAW_TO_SDRAM的讀取工作。
首先,已知的事實是,在DOUBLE_BUFFER內部,已經將寫入程序管理區塊設計為十二個cycle time為一個寫入週期的形式(詳細內容請見DOUBLE_BUFFER說明相關章節。),因此,ssram_re也是設計為十二個cycle time為一個讀取週期的形式,只是這兩者之間對同步化信號校正的位置有些不同,我們舉圖例說明。
[writer_col]與[writer_row]分別為[writer_col_pseudo]與[writer_row_pseudo]的一個寫入回合延遲
|
球體繪圖模組(DRAW_BALL)
介面
變數名
|
類型
|
大小(bits)
|
說明
|
clk_50M
|
輸入
|
1
|
時序資訊,用以驅動本模組。本次實作本模組的操作頻率為40MHz,與DOUBLE_BUFFER的寫入程序管理模組的驅動時序完全相同。
|
<以下為直接與DOUBLE_BUFFER模組溝通的參數>
|
turn_sign_wire
|
輸入
|
1
|
來自DOUBLE_BUFFER模組的換頁提醒。詳情請參照DOUBLE_BUFFER模組說明章節。
|
writer_syq
|
輸入
|
1
|
來自DOUBLE_BUFFER模組的寫入程序同步化信號,詳情請參照DOUBLE_BUFFER模組說明章節
|
mask_ball
|
輸出
|
1
|
直接與DOUBLE_BUFFER模組溝通,詳情請參照DOUBLE_BUFFER模組說明章節
|
writer_col_ball
|
輸出
|
13
|
writer_row_ball
|
輸出
|
13
|
writer_ball_done
|
輸出
|
16
|
write_done_i
|
輸出
|
1
|
<以下參數為來自PHYSICS模組的資訊>
|
X_in,Y_in,Z_in
|
輸入
|
13
|
為來自PHYSICS模組所計算出的球體位置資訊
|
說明:
本模組專門負責讀取一球心在空間中的位置以後,並考慮深淺對球體半徑造成的影響以後,在二維顯視器上顯示的動作。
在目前的版本,球體在深淺不同的位置時,球體顯示的顏色也有所不同,目的是方便區別深淺位置;另外,我們透過對[draw_ball_mask]的控制,繪製球體時以棋盤式地方式繪上,便造成球體的半透明效果,如此可簡單避免場景遮蔽的不自然感。
要繪出圓形的球體,我們使用了畢氏定理計算繪圖像素與球心位置的距離與半徑的比較,來決定[draw_ball_mask]的開關,如此可輕鬆繪出圓形的球體。
3.7貼圖遮蔽模控制組(threeDTotwoD_control.v)
介面:
變數名
|
類型
|
大小(bits)
|
說明
|
reset
|
輸入
|
1
|
重設訊號
|
clk
|
輸入
|
1
|
輸入時序
|
call
|
輸入
|
1
|
啟動此模組訊號
|
fill
|
輸入
|
1
|
目前區塊(cube)是否需要上色,邏輯1代表要上色,邏輯0代表不需要,接到物理特性模組
|
map_done
|
輸入
|
1
|
目前區塊是否上色完畢訊號,邏輯1代表要上色完畢,接到靜態隨機存取記憶體模組
|
cube_x_cnt
|
輸出
|
5
|
目前區塊的X座標
|
cube_y_cnt
|
輸出
|
4
|
目前區塊的Y座標
|
cube_z_cnt
|
輸出
|
3
|
目前區塊的Z座標
|
face1_x
|
輸出
|
40
|
|
face1_y
|
輸出
|
36
|
編號face1的面四頂點Y座標匯流排(bus)
|
face2_x
|
輸出
|
40
|
編號face2的面四頂點X座標匯流排(bus)
|
face2_y
|
輸出
|
36
|
編號face2的面四頂點Y座標匯流排(bus)
|
face3_x
|
輸出
|
40
|
編號face3的面四頂點X座標匯流排(bus)
|
face3_y
|
輸出
|
36
|
編號face3的面四頂點Y座標匯流排(bus)
|
map_start
|
輸出
|
1
|
開始將目前區塊的三個面上色的訊號,靜態隨機存取記憶體寫入模組
|
done
|
輸出
|
1
|
所有區塊上色完畢訊號,邏輯1代表完成
|
註:所有的輸出訊號都是跟著clk的正緣觸發。
說明:
詳細的演算法見「貼圖遮蔽演算法」章節,須要注意的是區塊(cube)的編號,就是以每一個區塊是以最靠近原點的頂點(以三維座標而言)為代表,除以40,例如:(40, 80, 120) à (1,2,3)。原始碼中運用到三維轉二維模組(threeDTotwoD)組合電路的編號就是「貼圖遮蔽演算法」章節中頂點的編號。
與靜態隨機存取記憶體寫入模組間的溝通方式如上圖所示,當需要上色時,[map_start]的訊號會成為邏輯1的時候,靜態隨機存取記憶體寫入模組開始動作,當靜態隨機存取記憶體寫入模組完成動作後,會把[map_done]訊號變成邏輯1,接著[map_start]的訊號會成為邏輯0。
下圖為此模組中的狀態圖(state diagram),當start的訊號為邏輯0時,會一直停在狀態零,start的訊號為邏輯1時變成狀態一,之後藉由判斷目前區塊是否需要上色,決定是要跳到狀態二去上色(依照上一段所提到的溝通方式去下指令),還是在狀態一繼續判斷下一個區塊,當所有區塊都上色完畢之後,會從狀態一或二跳到狀態三,並將[done]訊號變成邏輯1,等待[call]訊號變成邏輯0就跳回狀態零。
狀態
|
功能
|
state0
|
閒置狀態
|
state1
|
決定是否要上色或繼續判斷下一個區塊
|
state2
|
對SSRAM模組下開始上色指令
|
state3
|
等待start信號變成邏輯0
|
重要變數說明:
變數名
|
功能
|
宣告形式
|
state
|
顯示現在所在的狀態(state)
|
reg [1:0] state;
|
section
|
顯示現在所在的區域
|
reg [1:0] section;
|
註:區域的編號方法見「貼圖遮蔽演算法」章節
NextCube模組:
在原始碼當中用到的NextCube這個模組,功能是由目前區塊(cube)的編號計算出下一個區塊(cube)的編號(順序見「貼圖遮蔽演算法」章節),而當目前是最後一個區塊時,會傳回此區塊座標,並將last訊號改成邏輯1。
3.8三維轉二維模組(threeDTotwoD.v)
介面:
變數名
|
類型
|
大小(bits)
|
說明
|
reset
|
輸入
|
1
|
重設訊號
|
X_3D
|
輸入
|
10
|
像素的三維X座標
|
Y_3D
|
輸入
|
9
|
像素的三維Y座標
|
Z_3D
|
輸入
|
8
|
像素的三維Z座標
|
X_2D_o
|
輸出
|
10
|
像素的二維X座標
|
Y_2D_o
|
輸出
|
9
|
像素的二維Y座標
|
說明:
實踐「三維轉二維演算法」中的公式,原始碼中須要注意的有兩點,
(1) 分成四種情況判斷的目的是不要讓相減的結果變成負的,造成溢位的現象。
(2) 為了讓相除的結果不是純小數(因為可能會被四捨五入變成0),故先將相乘項做出來再做除法。公式中重複的項也沒有獨立出來做,也是因為會出現純小數。
本實踐事實上是用近似的方法,因為實際須轉換的點距離最短也有40像素,故使用座標只取到整數的做法的話,並不會因此把兩個不同的三維點投影到相同的二維點,但要精確的去做的話也沒有關係,只是可能需要用到magafuction,不過,此應用並沒有此必要。
3.9靜態隨機存取記憶體模組(ssram.v)
介面:
名稱
|
類型
|
位元數
|
功能
|
clk
|
input
|
1
|
模組運作用時脈。(40Mhz)
|
X
|
input
|
10
|
讀取起始X位置。
|
Y
|
input
|
9
|
讀取起始Y位置。
|
sig
|
input
|
1
|
讀取回復起始訊號。
|
data
|
output
|
16
|
輸出從“ssram”讀得之訊號。
|
s_addr
|
output
|
19
|
“ssram”位址線。
|
s_data
|
input
|
32
|
“ssram”資料輸入線。
|
adsc
|
output
|
1
|
“ssram” 位址移動控制訊號,新位址讀入。
|
adsp
|
output
|
1
|
“ssram” 位址移動控制訊號,起始位置讀入。
|
adv
|
output
|
1
|
“ssram” 位址移動控制訊號,位址移動。
|
ce1
|
output
|
1
|
“ssram” 晶片啟動訊號1。
|
ce3
|
output
|
1
|
“ssram” 晶片啟動訊號3。
|
oe
|
output
|
1
|
“ssram” 輸出允許訊號。
|
功能說明:
此模組的功能是用於將“ssram”中的資料讀出,運作方式為當[sig]為高電位時將狀態[step]回復到0,重新開始讀取。否則便以12個時脈唯一週期的方式來連續運作。一週期讀取出來的資料為{[Y]、[X]}值到{[Y]、[X]+7}共八單位(每單位16位元)依序讀出。有關於讀取時和所需要的靜態隨機存取記憶體相關波形,請見下圖:
其中各參數的輸出是依據[step]的值來改變。有關於波形代表的涵義,請見靜態隨機存取記憶體之datasheet: “ 61VPS_LPS-51236A_102418A.pdf”。
程式說明:
此處是以有限狀態機的方式來實現上述動作,其各狀態功能如下:
狀態
|
動作
|
0
|
週期起始。
|
1
|
“ssram”初始位址寫入。
|
2~9
|
“ssram”資料輸出。
|
10~11
|
閒置狀態,並於最後回到狀態0。
|
3.10快閃記憶體寫入靜態隨機存取記憶體模組(flashtossram.v)
1.介面
名稱
|
類型
|
位元數
|
功能
|
clk
|
input
|
1
|
模組運作用時脈。(2.5Mhz)
|
start
|
input
|
1
|
開始訊號。
|
finish
|
output
|
1
|
完成訊號。
|
s_addr
|
output
|
19
|
“ssram”位址排線。
|
s_data
|
output
|
32
|
“ssram”資料排線。
|
adsc
|
output
|
1
|
“ssram”位址移動控制訊號,新位址讀入。
|
adsp
|
output
|
1
|
“ssram”位址移動控制訊號,起始位置讀入。
|
adv
|
output
|
1
|
“ssram”位址移動控制訊號,位址移動。
|
ce1
|
output
|
1
|
“ssram”晶片啟動訊號1。
|
ce3
|
output
|
1
|
“ssram”晶片啟動訊號3。
|
we
|
output
|
1
|
“ssram” 寫入允許訊號。
|
f_reset
|
output
|
1
|
“flash” 內部狀態重設。
|
f_addr
|
output
|
22
|
“flash” 位址排線。
|
f_data
|
input
|
16
|
“flash” 資料排線。
|
2.功能說明
此模組主要是要將存取於快閃記憶體裡800*480大小的背景圖片依序寫入靜態隨機存取記憶體裡。下圖為快閃記憶體讀取時的波形圖:
在開始進行讀取前會先將[f_reset]拉至低電位確保其內部的狀態機回到讀取狀態,且須注意雖然其不需要時脈控制,但其位址改變後其資料是在一小段延遲後才會出現的,不過由於我們使用的時脈為2.5MHz,故可視為即時出現。
關於靜態隨機存取記憶體的波形,請見靜態隨機存取記憶體寫入模組,寫入方式為逐行依序寫入。
3.程式說明
此處使用有限狀態機(finite state machine)實現所需的波形輸出,由[start]作為開始訊號,並在回到閒置狀態時將[finish]拉為高電位。其中各種對記憶體的控制用訊號皆是以狀態[step]為依據來做變換。
各狀態功能及動作如下:
狀態
|
動作
|
0
|
開始狀態,並在此時「重設」快閃記憶體。
|
1
|
等待快閃記憶體。
|
2
|
靜態隨機存取記憶體開始讀入位址。
|
3
|
等待靜態隨機存取記憶體。
|
4
|
[Y]值不變下改變[X]值依序寫入整行。
|
5
|
檢查[Y]值是否為結束位置,若否更改[Y]值後回到狀態4。
|
6
|
閒置狀態。此時[finish]轉為高電位。
|
3.11靜態隨機存取記憶體讀取模組(ssram_re.v)
介面:
名稱
|
類型
|
位元數
|
功能
|
clk
|
input
|
1
|
模組運作用時脈。(40Mhz)
|
X
|
input
|
10
|
讀取起始X位置。
|
Y
|
input
|
9
|
讀取起始Y位置。
|
sig
|
input
|
1
|
讀取回復起始訊號。
|
data
|
output
|
16
|
輸出從“ssram”讀得之訊號。
|
s_addr
|
output
|
19
|
“ssram”位址線。
|
s_data
|
input
|
32
|
“ssram”資料輸入線。
|
adsc
|
output
|
1
|
“ssram” 位址移動控制訊號,新位址讀入。
|
adsp
|
output
|
1
|
“ssram” 位址移動控制訊號,起始位置讀入。
|
adv
|
output
|
1
|
“ssram” 位址移動控制訊號,位址移動。
|
ce1
|
output
|
1
|
“ssram” 晶片啟動訊號1。
|
ce3
|
output
|
1
|
“ssram” 晶片啟動訊號3。
|
oe
|
output
|
1
|
“ssram” 輸出允許訊號。
|
功能說明:
此模組的功能是用於將“ssram”中的資料讀出,運作方式為當[sig]為高電位時將狀態[step]回復到0,重新開始讀取。否則便以12個時脈唯一週期的方式來連續運作。一週期讀取出來的資料為{[Y]、[X]}值到{[Y]、[X]+7}共八單位(每單位16位元)依序讀出。有關於讀取時和所需要的靜態隨機存取記憶體相關波形,請見下圖:
其中各參數的輸出是依據[step]的值來改變。有關於波形代表的涵義,請見靜態隨機存取記憶體之datasheet: “ 61VPS_LPS-51236A_102418A.pdf”。
程式說明:
此處是以有限狀態機的方式來實現上述動作,其各狀態功能如下:
狀態
|
動作
|
0
|
週期起始。
|
1
|
“ssram”初始位址寫入。
|
2~9
|
“ssram”資料輸出。
|
10~11
|
閒置狀態,並於最後回到狀態0。
|
3.12靜態隨機存取記憶體寫入模組(ssram_wr.v)
介面:
名稱
|
類型
|
位元數
|
功能
|
clk
|
input
|
1
|
模組運作時脈。(2.5Mhz)
|
call
|
input
|
1
|
模組開始訊號。
|
done
|
output
|
1
|
模組結束訊號。
|
face1_X
|
input
|
40
|
X座標組1。
|
face1_Y
|
input
|
36
|
Y座標組1。
|
face2_X
|
input
|
40
|
X座標組1。
|
face2_Y
|
input
|
36
|
Y座標組1。
|
face3_X
|
input
|
40
|
X座標組1。
|
face3_Y
|
input
|
36
|
Y座標組1。
|
s_addr
|
output
|
19
|
位址排線。
|
s_data
|
output
|
32
|
資料排線。
|
adsc
|
output
|
1
|
位址移動控制訊號,新位址讀入。
|
adsp
|
output
|
1
|
位址移動控制訊號,起始位置讀入。
|
adv
|
output
|
1
|
位址移動控制訊號,位址移動。
|
ce1
|
output
|
1
|
晶片啟動訊號1。
|
ce3
|
output
|
1
|
晶片啟動訊號3。
|
we
|
output
|
1
|
寫入允許訊號。
|
功能說明:
本模組主要是用於將外界傳來的座標點資料,轉為一整個四邊形的平面並寫入靜態隨機存取記憶體中。其中傳進來的資料為四個點,實際寫入方法為由每面的邊12逐行寫到邊34,由有限狀態機完成。
其中傳進來的座標其相對位置會依其原始立方體在螢幕中的位置而有所不同(如圖),因此在實作程式時將會依據此部分而特別進行處理。
關於靜態隨機存取記憶體的輸出波形,依據其“datasheet”所言,開始後其輸出波形因如下圖(黑線部分),但此處爲了減化有限狀態機的狀態,我們在開始寫入後便將[adsc]持續以低電位輸出(紅線部分),如此便不用在寫入暫停後重新輸出位址起始波形。
程式說明:
程式共分為三部份,第一部份為座標點的重分類,第二部份為座標點相對位置資訊的處理,第三部份為實際對靜態隨機存取記憶體進行波形輸出的有限狀態機。其中第一部份為優先進行,第二、三部份為同時進行。
第一部份: 座標點的重分
原始座標點組[face1_X]等,為一由四個10位元X座標組成之40位元排線,分別代表四邊型的四個點其順序為原立方體編號的由小到大。此處要將其轉為如右圖三個四邊型的編號順序。相對應如下:
原變數名稱
|
新變數名稱
|
原變數名稱
|
新變數名稱
|
f1_X1
|
face1_X[39:30]
|
f2_Y1
|
face2_Y[35:27]
|
f1_X2
|
face1_X[29:20]
|
f2_Y2
|
face2_Y[26:18]
|
f1_X3
|
face1_X[19:10]
|
f2_Y3
|
face2_Y[17:9]
|
f1_X4
|
face1_X[9:0]
|
f2_Y4
|
face2_Y[8:0]
|
f1_Y1
|
face1_Y[35:27]
|
f3_X1
|
face3_X[29:20]
|
f1_Y2
|
face1_Y[26:18]
|
f3_X2
|
face3_X[9:0]
|
f1_Y3
|
face1_Y[17:9]
|
f3_X3
|
face3_X[39:30]
|
f1_Y4
|
face1_Y[8:0]
|
f3_X4
|
face3_X[19:10]
|
f2_X1
|
face2_X[39:30]
|
f3_Y1
|
face3_Y[26:18]
|
f2_X2
|
face2_X[29:20]
|
f3_Y2
|
face3_Y[8:0]
|
f2_X3
|
face2_X[19:10]
|
f3_Y3
|
face3_Y[35:27]
|
f2_X4
|
face2_X[9:0]
|
f3_Y4
|
face3_Y[17:9]
|
第二部份:起始結束點邊資訊
黑色&藍色四邊形,非平行邊斜率的計算。此部份為透過子模組“divide.v”來達成,詳見簡易除法模組。
第三部份:有限狀態機
此部份在每次[call]為高電位時將狀態回復到零,開始動作,並在最後一個狀態前將[done]輸出一週期的高電位表寫入完成。
控制用特殊參數:
名稱
|
功 能
|
addr_x
|
此次輸出X位址,為一20位元參數,取其整數部分輸出,後10位為小數。
|
addr_y
|
此次輸出Y位址,為一19位元參數,取其整數部分輸出,後10位為小數。
|
addr_x_start
|
輸入邊起始X值。
|
addr_y_start
|
輸入邊起始Y值。
|
addr_x_end
|
輸入邊結束X值。
|
addr_y_end
|
輸入邊結束Y值。
|
各狀態功能及動作如下:
寫入面
|
狀態
|
動作
|
紅色面
|
0
|
起始狀態,輸入起始、結束值。
|
1
|
“ssram”初次位址寫入。
|
2
|
等待“ssram”。
|
3
|
“ssram”資料連續寫入,並在[addr_x]到達[addr_x_end]結束點時至狀態4。
|
4
|
檢查[addr_y]是否到達結束點,若否跟新輸入邊起始結束X方向的值後回到狀態3。
|
黑色面
|
5
|
輸入起始、結束值。
|
6
|
“ssram”初次位址寫入。
|
7
|
等待“ssram”。
|
8
|
“ssram”資料連續寫入,並在[addr_x]到達[addr_x_end]結束點時至狀態9。
|
9
|
檢查[addr_y]是否到達結束點,若否跟新輸入邊起始結束X方向的值後回到狀態8。
|
藍色面
|
10
|
輸入起始、結束值。
|
11
|
“ssram”初次位址寫入。
|
12
|
等待“ssram”。
|
13
|
“ssram”資料連續寫入,並在[addr_y]到達[addr_y_end]結束點時至狀態14。
|
14
|
檢查[addr_x]是否到達結束點,若否跟新輸入邊起始結束Y方向的值後回到狀態13。
|
無
|
15
|
閒置狀態。
|
16
|
閒置狀態,輸出完成訊號。
|
3.13簡易除法模組(divide.v)
介面:
名稱
|
類型
|
位元數
|
功能
|
A1
|
input
|
10
|
輸入被除數1。
|
A2
|
input
|
10
|
輸入被除數2。
|
B1
|
input
|
10
|
輸入除數1。
|
B2
|
input
|
10
|
輸入除數2。
|
ans
|
output
|
20
|
輸出答案。
|
minusA
|
output
|
1
|
[A1]、[A2]大小關係表示。1表示A1>A2。
|
minusB
|
output
|
1
|
[B1]、[B2]大小關係表示。1表示B1>B2。
|
功能說明:
此模組是進行的計算,並將[A1]、[A2],[B1]、[B2]間的大小關係以[minusA]和[minusB]來記錄,以方便之後判斷使用。並使[ans]轉為20位元(後面10位元表示小數)同時爲了使用上的方便和計算述速度上的考量,最後是以移位的方式(只除以)來做一個近似解。
程式說明:
整體流程如下圖:
其中dA/dB是透過以dB為依據,選擇將dA寫入[ans]的第幾位元來得到的。整個組合電路大約需2μs便可得正確答案。
設計方法:
演算法概念 :
1 物理特性計算
反彈演算法與牛頓運動定律演算法
以下以 pseudo code 概念描述之
while(1){
//X,_fY_f,Z_f 代表球心空間位置
//vx,vy,vz 代表球體移動速度
//
//n0[k],n1[k],n2[k]代表球心到第 k 個偵測點的單位方向向量
//sx[k],sy[k],sz[k]代表第 k 個偵測點在空間中的位置
for( i=0 ; I < 60 ; ++i){
sx[i] = X_f + 19 * n0[i];
sy[i] = Y_f + 19 * n1[i];
sz[i] = Z_f + 19 * n2[i];
if( sx[i],sy[i],sz[i]組成的座標在反彈執行區域內 ) {
beep[i]=1;
have_beep = 1;}
else{
beep[i]=0;
}
//N0,N1,N2 代表概念上的反射面的方向資訊
N0 = N1 = N2 = 0;
for( i = 0 ; i<60; ++i){
N0 +=n0[i]*beep[i];
N1 +=n1[i]*beep[i];
N2 +=n2[i]*beep[i];
}
///////////////////////////////
//v_norm_x,v_norm_y,v_norm_z 代表球體速度在(N0,N1,N2)上且方向一
//致的正投影,即球體速度與概念上的反射面垂直的分量。
//v_para_x,v_para_y,v_para_z 代表球體速度與概念上的反射面平行的分
//向。
v_norm_x =abs( ((vx*N0+vy*N1+vz*N2)/(N0*N0+N1*N1+N2*N2))) *N0;
v_norm_y =abs( ((vx*N0+vy*N1+vz*N2)/(N0*N0+N1*N1+N2*N2)))*N1;
v_norm_z = abs( ((vx*N0+vy*N1+vz*N2)/(N0*N0+N1*N1+N2*N2)))*N2;
v_para_x = vx + (-v_norm_x);
v_para_y = vy + (-v_norm_y);
v_para_z = vz + (-v_norm_z);
//new_vx,new_vy,new_vz 充當球體考慮反彈後的速度
new_vx = v_para_x * friction_ratio + (- v_norm_x * reflection_ratio);
new_vy = v_para_y * friction_ratio + (- v_norm_y * reflection_ratio);
new_vz = v_para_z * friction_ratio + (- v_norm_z * reflection_ratio);
//new_x,new_y,new_z 充當球體考慮反彈後的位置
new_x =X_f+(-v_norm_x*2);
new_y =Y_f+(-v_norm_x*2);
new_z =Z_f+(-v_norm_x*2);
//意思是果斷地將球直接移出反射區域。系數”2”為一個保險用比例
X =( have_beep)?new_x : (X + vx);
Y =( have_beep)?new_x : (Y + vy);
Z =( have_beep)?new_x : (Z + vz);
vx =( have_beep)?new_vx : limitation(vx + ax*ascale);
vy =( have_beep)?new_vy : limitation(vy+ ay*ascale);
vz =( have_beep)?new_vz : limitation(vz + az*ascale);
//limitation 表示各方向速限,最大值為+1,最小值為-1,單位為像素
//ax 為來自加速度儀晶片的加速度資訊 ascale 為虛擬空間與實體空間加
//速度比例校正參數
}
}
2.
6
v_norm_y =abs( ((vx*N0+vy*N1+vz*N2)/(N0*N0+N1*N1+N2*N2)))*N1;
v_norm_z = abs( ((vx*N0+vy*N1+vz*N2)/(N0*N0+N1*N1+N2*N2)))*N2;
v_para_x = vx + (-v_norm_x);
v_para_y = vy + (-v_norm_y);
v_para_z = vz + (-v_norm_z);
//new_vx,new_vy,new_vz 充當球體考慮反彈後的速度
new_vx = v_para_x * friction_ratio + (- v_norm_x * reflection_ratio);
new_vy = v_para_y * friction_ratio + (- v_norm_y * reflection_ratio);
new_vz = v_para_z * friction_ratio + (- v_norm_z * reflection_ratio);
//new_x,new_y,new_z 充當球體考慮反彈後的位置
new_x =X_f+(-v_norm_x*2);
new_y =Y_f+(-v_norm_x*2);
new_z =Z_f+(-v_norm_x*2);
//意思是果斷地將球直接移出反射區域。系數”2”為一個保險用比例
X =( have_beep)?new_x : (X + vx);
Y =( have_beep)?new_x : (Y + vy);
Z =( have_beep)?new_x : (Z + vz);
vx =( have_beep)?new_vx : limitation(vx + ax*ascale);
vy =( have_beep)?new_vy : limitation(vy+ ay*ascale);
vz =( have_beep)?new_vz : limitation(vz + az*ascale);
//limitation 表示各方向速限,最大值為+1,最小值為-1,單位為像素
//ax 為來自加速度儀晶片的加速度資訊 ascale 為虛擬空間與實體空間加
//速度比例校正參數
}
}
2.2 三維轉二維演算法
在計算球運動的方式之後,需要把它轉到螢幕上去顯示,故要將其三維座標轉換
成相對應的二維座標。
三維轉二維的做法大致上分成兩種:(1)正交投影(Orthographic projection ) (2)
透視投影(Perspective projection)。此次顯示採用的是透視投影法,如下圖所示。
將視點(perspective)和想要投影的點連線,再找到和投影平面的交點就是投影的
結果。例如:圖中 A 點投影在 Z = k 的平面上的點就是 B 點。
程式體現 :
根據設計架構,我們目前完成了硬體設計模擬方塊圖中除了CENTRAL_CONTROL以外的所有部分。也就是所有晶片的控制子單元已全部完成。
設計架構已大致清楚描述了我們程式撰寫的大略架構。包含 :
1.物理特性模組(PHYSICS)
2.加速度計模組(acc_SPI)
3.雙暫存緩衝模組(DOUBLE_BUFFER)
4. SDRAM 初始化模組(SDRAM_init)
5.LTM模組(LTM_process)(觸控面板的部分尚未納入主架構內)
6.SDRAM繪圖模組(DRAW_TO_SDRAM)
7.貼圖遮蔽控制模組(threeDTotwoD_control)
8.三為轉二維模組(threeDTotwoD)
9.靜態隨機存取記憶體模組(ssram)
10.快閃記憶體寫入靜態隨機存取記憶體模組(flashtossram)
11.靜態隨機存取記憶體讀取模組(ssram_re)
12.靜態隨機存取記憶體寫入模組(ssram_wr)
13.簡易除法模組(divide)
以上所有13個模組皆為verilog語法所撰寫,所體現出來的功能主要是讓LCD顯示幕上出現3D的簡單場景與一個具有物體碰撞力學特性的虛擬球體。
(Revision: 5 / 2010-09-17 23:38:12)