攝像頭驅(qū)動(dòng)
一些概念:
攝像接口的主時(shí)鐘信號(hào)由USB PLL產(chǎn)生,它的頻率為96MHz,再經(jīng)過分頻處理后輸出給攝像頭,攝像頭再根據(jù)該時(shí)鐘信號(hào)產(chǎn)生三個(gè)同步時(shí)鐘信號(hào)(像素時(shí)鐘、幀同步時(shí)鐘和行同步時(shí)鐘),反過來再輸入回s3c2440。
OV9650內(nèi)部有大量的寄存器需要配置,這就需要另外的數(shù)據(jù)接口。
OV9650的數(shù)據(jù)接口稱為SCCB(串行攝像控制總線),它由兩條數(shù)據(jù)線組成:一個(gè)是用于傳輸時(shí)鐘信號(hào)的SIO_C,另一個(gè)是用于傳輸數(shù)據(jù)信號(hào)的SIO_D。SCCB的傳輸協(xié)議與IIC的極其相似,只不過IIC在每傳輸完一個(gè)字節(jié)后,接收數(shù)據(jù)的一方要發(fā)送一位的確認(rèn)數(shù)據(jù),而SCCB一次要傳輸9位數(shù)據(jù),前8位為有用數(shù)據(jù),而第9位數(shù)據(jù)在寫周期中是Don’t-Care位(即不必關(guān)心位),在讀周期中是NA位。SCCB定義數(shù)據(jù)傳輸?shù)幕締卧獮橄啵?/span>phase),即一個(gè)相傳輸一個(gè)字節(jié)數(shù)據(jù)。
SCCB只包括三種傳輸周期,即3相寫傳輸周期(三個(gè)相依次為設(shè)備從地址,內(nèi)存地址,所寫數(shù)據(jù)),2相寫傳輸周期(兩個(gè)相依次為設(shè)備從地址,內(nèi)存地址)和2相讀傳輸周期(兩個(gè)相依次為設(shè)備從地址,所讀數(shù)據(jù))。當(dāng)需要寫操作時(shí),應(yīng)用3相寫傳輸周期,當(dāng)需要讀操作時(shí),依次應(yīng)用2相寫傳輸周期和2相讀傳輸周期。(這些讀寫和IIC一樣~)
OV9650有兩個(gè)只讀寄存器——0x1C和0x1D,用于存放廠家ID,數(shù)據(jù)分別為0x7F和0xA2,我們可以通過讀取它們來判斷s3c2440是否連接了OV9650。當(dāng)確認(rèn)連接了OV9650后,我們就可以把VGA(640×480)模式下YUV彩色空間的配置數(shù)組寫入OV9650內(nèi) (二維數(shù)組:第一個(gè)表示寄存器地址,第二個(gè)表示要寫入的數(shù)據(jù))
注意比較三個(gè)變量的含義:
Width = 640 //源寬度
PrDstWidth =480 //目標(biāo)寬度
SrcWidth =640 - WinHorOffset*2; //偏移后寬度
驅(qū)動(dòng)函數(shù)編寫步驟:
外圍基礎(chǔ)準(zhǔn)備硬件初始化
IIC初始化, LCD初始化, UPLL時(shí)鐘初始化(96M, 0V9650系統(tǒng)時(shí)鐘) ,
GPIO初始化(GPJ),硬件和軟件復(fù)位攝像頭(GPJ12為CAMERARESET,rCIGCTRL)
0V9650寄存器配置
A、讀取OV9650廠商ID,驗(yàn)證是否工作
B、復(fù)位所有OV9650寄存器
C、配置OV9650寄存器(用規(guī)定的二維數(shù)組直接配)
攝像頭接口初始化
攝像頭接口的一些寄存器初始化:rCIGCTRL,rCIWDOFST rCISRCFMT
rCIPRTRGFMT,rCIPRTAREA
B、設(shè)置內(nèi)存首地址為LCD緩存數(shù)組首地址 :rCIPRCLRSA1~4
C、計(jì)算水平和垂直縮放比率和位移量,以及主水平、垂直比率
放入以下三個(gè)寄存器中rCIPRSCPRERATIO,rCIPRSCPREDST rCIPRSCCTRL
中斷函數(shù)開啟和指向
控制臺(tái)菜單的編寫與實(shí)現(xiàn)
顯示視頻
rCIPRSCCTRL|=(1<<15); //預(yù)覽縮放開啟
rCIIMGCPT =(1<<31)|(1<<29); //預(yù)覽縮放捕捉使能
截圖,定格
rCIPRSCCTRL &=~(1<<15); //預(yù)覽縮放關(guān)閉
rCIIMGCPT &=~((1<<31)|(1<<29)); //預(yù)覽縮放捕捉不使能
視頻定格后,LCD_BUFFER數(shù)組就是圖像數(shù)據(jù)
放大,縮小
調(diào)節(jié)偏移量HOffset ,VOffset,每次改變后重新初始化攝像頭接口
四個(gè)額外寫出需注意的函數(shù):
1、計(jì)算主突發(fā)長(zhǎng)度和剩余突發(fā)長(zhǎng)度 CalculateBurstSize
2、/計(jì)算預(yù)縮放比率及移位量 CalculatePrescalerRatioShift
3、中斷函數(shù)(只清中斷,不干別的) camera_interrupt
4、SCCB總線函數(shù)的讀寫(像IIC) Rd_SCCB,Wr_SCCB
網(wǎng)卡驅(qū)動(dòng)
DM9000的一些基本概念:
DM9000對(duì)外來說只有兩個(gè)端口——地址口和數(shù)據(jù)口,地址口用于輸入內(nèi)部寄存器的地址,而數(shù)據(jù)口則完成對(duì)某一寄存器的讀寫。DM9000的CMD引腳用來區(qū)分這兩個(gè)端口,當(dāng)CMD引腳為0時(shí),DM9000的數(shù)據(jù)線上傳輸?shù)氖羌拇嫫?/span>地址,當(dāng)CMD引腳為1時(shí),傳輸?shù)氖亲x寫數(shù)據(jù)。
我們把DM9000的A8和A9接為高電平,把A4~A7接為低電平,并且把DM9000的AEN接到s3c2440的nGCS4引腳上,則DM9000的端口基址為0x20000300,如果再把DM9000的CMD引腳接到s3c2440的ADDR2引腳上0x20000304(怎么計(jì)算?)
查了一下書,是和存儲(chǔ)控制器有關(guān)系,每個(gè)nGCSx對(duì)應(yīng)128M地址空間,8個(gè)nGCSx對(duì)應(yīng)1G地址。
nGCS4剛好對(duì)應(yīng)0x20000000開始的地址,但為什么是0x20000300?
再加上IObase:300
如果將 DM9000的CMD引腳接到s3c2440的ADDR2,由于CMD引腳的高低電平?jīng)Q定地址口和數(shù)據(jù)口,那么,ADDR2為0時(shí),訪問的
就是地址口,所以地址口的起始地址為 ARRD2為0的情況,即0x20000000 ;ADDR2為1時(shí),(LADDR3~LADDR0 = 0100)訪問的就是數(shù)
據(jù)口,所以數(shù)據(jù)口的地址即 0x20000004。
如果要寫入DM9000中的某個(gè)寄存器,則先把該寄存器的地址賦予DM_ADDR_PORT,然后再把要寫入的數(shù)據(jù)賦予DM_DATA_PORT即可。讀取DM9000中的某個(gè)寄存器也類似。
DM9000寄存器介紹在數(shù)據(jù)手冊(cè)11頁(yè)開始:
DM9000內(nèi)部有0x3FF大小的SRAM用于接受和發(fā)送數(shù)據(jù)緩存。在發(fā)送或接收數(shù)據(jù)包之前,數(shù)據(jù)是暫存在這個(gè)SRAM中的。當(dāng)需要連續(xù)發(fā)送或接收數(shù)據(jù)時(shí),我們需要分別把DM9000寄存器MWCMD或MRCMD賦予數(shù)據(jù)端口,這樣就指定了SRAM中的某個(gè)地址,并且在傳輸完一個(gè)數(shù)據(jù)后,指針會(huì)指向SRAM中的下一個(gè)地址,從而完成了連續(xù)訪問數(shù)據(jù)的目的。
基于ARP協(xié)議的DM9000編寫步驟:
初始化EINT7中斷,設(shè)置中斷函數(shù)入口
因?yàn)?/span>DM9000的數(shù)據(jù)中斷引腳INT是連接到s3c2440的外部中斷7引腳上的
編寫好讀和寫DM9000寄存器函數(shù),用其配置DM9000的寄存器
并使其用中斷方式接收網(wǎng)卡數(shù)據(jù),查詢方式發(fā)送數(shù)據(jù)
(這步挺難的,很多寄存器要配置,對(duì)照著Datasheet和別人的程序)
注:DM9000內(nèi)的寄存器的地址宏定義時(shí),不用管基址,直接按OFFSET定義
編寫好DM9000發(fā)送和接受函數(shù)(位寬為16)
分別把DM9000寄存器MWCMD或MRCMD賦予數(shù)據(jù)端口
接受數(shù)據(jù)時(shí)要注意,按照規(guī)定的格式來編寫
定義一個(gè)符合ARP協(xié)議格式的數(shù)組,用于數(shù)據(jù)傳輸
將該數(shù)組作為發(fā)送函數(shù)形參發(fā)給PC機(jī)請(qǐng)求包
編寫中斷函數(shù),清屏蔽
將接收函數(shù)中的數(shù)組內(nèi)容,用串口打印出控制臺(tái)
SD卡驅(qū)動(dòng)
SD(全名為Secure Digital Memory Card,安全數(shù)碼卡)
s3c2440集成了SD控制器,可以方便地讀寫SD、MMC和對(duì)SDIO進(jìn)行操作。
可以用SDIO控制器來編,也可用SPI總線來編
SDIO的應(yīng)用是未來嵌入式系統(tǒng)最重要的接口技術(shù)之一,會(huì)取代目前GPIO式的SPI接口
具體的CMD 命令和協(xié)議內(nèi)容自己看回資料了。
我使用的SD卡為手機(jī)的內(nèi)存卡(不是MMC),型號(hào)為SDHC_V20_CARD,支持 PLV2.0協(xié)議
主要講 編寫簡(jiǎn)單的SD讀寫步驟:
準(zhǔn)備工作,編寫要使用到一堆東西:
檢查SDIO命令發(fā)送,接收是否結(jié)束函數(shù)Chk_CMD_End(int cmd, int be_resp)
使用到的 CMD 和ACMD 函數(shù)(這部分要配置寄存器,要查值,比較難,參考別人的吧)
編寫一個(gè)要用的結(jié)構(gòu)體SD_STRUCT,用于記錄cCardType和iCardRCA等
SD卡識(shí)別模式:
初始化:時(shí)鐘400K,Type B, clk enable,SD卡模式,FIFO reset
CMD 0 ——》reset指令
CMD 8——》工作電壓范圍,初始化SDHC卡,看是否支持PLV2.0,返回類型
CMD 55——》RCA為0x0,使用ACMD41前必須使用
ACMD 41——》識(shí)別卡能否在給定的VDD下工作
CMD 2——》查卡的CID 信息
CMD 3——》要求系統(tǒng)給SD卡發(fā)送一個(gè)新相對(duì)地址 RCA
改時(shí)鐘頻率:25M,準(zhǔn)備進(jìn)入transfer狀態(tài)
CMD 7——》進(jìn)入 transfer狀態(tài)
ACMD 6——》設(shè)置總線寬度為 4bit
數(shù)據(jù)傳輸模式:
若需要擦除:
{
CMD 32——》start address
CMD 33——》end address
CMD 38 ——》erase
}注意:擦除后必須要進(jìn)行復(fù)位,即重新初始化前面步驟,不然不能進(jìn)行讀寫
單塊寫 或多塊寫
CMD 7——》transfer模式
單塊讀或多塊讀
拓展:
將攝像頭捕捉的圖像,寫進(jìn)SD卡中,然后再還原顯示出來
注意一個(gè)點(diǎn):
就是要將LCD_BUFFER[480][272]的二維數(shù)組轉(zhuǎn)化為LCD_BUFFER_SD[480*272]一維
一個(gè)疑問?好像只需 51200就可將整幅圖像都顯示出來,而不需要480*272那么多
附加部分(有空研究):
文件系統(tǒng)的構(gòu)建:
12、NORFLASH 操作
norflash為EN29LV160AB
對(duì)norflash的操作主要就是讀、寫、擦除和識(shí)別
EN29LV160AB的數(shù)據(jù)寬度可以是8位字節(jié)型,也可以是16位的字型,它由某一引腳配置實(shí)現(xiàn)的。在這里我們選擇字型
BYTE#位置硬件接地,直接默認(rèn)為Word Mode(16位)
寫操作只能使“1”變?yōu)?ldquo;0”,而只有擦除才能使“0”變?yōu)?ldquo;1”。因此在寫之前一定要先擦除
對(duì)norflash另一個(gè)比較常用的操作是讀取芯片的ID
NorFlash啟動(dòng),nGCS0接NorFlash,起始地址為0x0。0x0000 0000 –0x0800 0000為NorFlash
注意幾個(gè)地方:
1、#define CMD_ADDR0 *((volatile U16 *)(0x555<<1+flash_base))
之所以又把norflash中的地址向左移一位(即乘以2),是因?yàn)槲覀兪前?/span>s3c2440的ADDR1連接到了norflash的A0上的緣故,(自己看原理圖),容易理解,等于本來最低位的數(shù)被推后沒了,要左移拉回來。
2、check_toggle函數(shù)(校驗(yàn)函數(shù))中
oldtoggle = *((volatile U16 *)0x0); newtoggle = *((volatile U16 *)0x0);
表示兩次讀值
if((oldtoggle & 0x40)==(newtoggle & 0x40)) //表示兩次的DQ6是否相同
if(newtoggle & 0x20) //DQ5是否為1
幾個(gè)常用的函數(shù):
讀函數(shù): read_en29lv160ab(U32 addr)
return *((volatile U16 *)(addr));// 數(shù)據(jù)要轉(zhuǎn)為16位
寫函數(shù): en29lv160ab_program(U32 addr, U16 dat)
第一個(gè)周期是把命令0xAA寫入地址為0x555的命令寄存器中,
第二個(gè)周期是把命令0x55寫入地址為0x2AA命令寄存器中,
第三個(gè)周期是把命令0xA0再寫入地址為0x555命令寄存器中,
第四個(gè)周期為真正地把要寫入的數(shù)據(jù)寫入到norflash的地址中。
復(fù)位函數(shù): reset_en29lv160ab(void)
是向任一地址寫入復(fù)位命令0xF0
擦除函數(shù): en29lv160ab_sector_erase(U32 section_addr)
第一個(gè)周期是把命令0xAA寫入地址為0x555的命令寄存器中,
第二個(gè)周期是把命令0x55寫入地址為0x2AA命令寄存器中,
第三個(gè)周期是把命令0x80再寫入地址為0x555命令寄存器中,
第四個(gè)周期是把命令0xAA寫入地址為0x555的命令寄存器中,
第五個(gè)周期是把命令0x55再寫入地址為0x2AA命令寄存器中,
第六個(gè)周期是把命令0x30寫入要擦除塊的首地址內(nèi)
驗(yàn)證函數(shù): check_toggle()
連續(xù)兩次讀取數(shù)據(jù)總線上的數(shù)據(jù),判斷數(shù)據(jù)總線上的第6位數(shù)值(DQ6)是否翻轉(zhuǎn),如果沒有翻轉(zhuǎn)則正確,否則還要判斷第5位(DQ5),以確定是否是因?yàn)槌瑫r(shí)而引起的翻轉(zhuǎn)。
讀ID函數(shù): get_en29lv160ab_id()
第一個(gè)周期是把命令0xAA寫入地址為0x555的命令寄存器中,
第二個(gè)周期是把命令0x55寫入地址為0x2AA命令寄存器中,
第三個(gè)周期是把命令0x90再寫入地址為0x555命令寄存器中,
第四個(gè)周期為讀取地址為0x100中的內(nèi)容,即廠商ID(0x1C)。
讀取設(shè)備ID的過程的前三個(gè)周期與讀取廠商ID相同,第四個(gè)周期是讀取地址為0x01中的內(nèi)容,即設(shè)備ID(0x2249)
問題1:
原來真的是寫得塊地址問題,寫到前面的0x400就行,寫后一點(diǎn)如0xf0000就讀不出來了,0x0000 0000 –0x0800 0000為NorFlash,為什么后面的不行呢?
問題2:
本來擦除后寫完能讀出寫的內(nèi)容,但再?gòu)?fù)位后不寫,只讀回上次地址,發(fā)現(xiàn)讀出不同的數(shù)據(jù)
而且好像擦除后就算返回return 1也沒用,擦后讀回那地址,也不是全部數(shù)據(jù)為0的,也是有值的
13、NANDFLASH操作
nandflash為K9F2G08U0A,它是8位的nandflash
一個(gè)劣勢(shì)是很容易產(chǎn)生壞塊,因此在使用nandflash時(shí),往往要利用校驗(yàn)算法發(fā)現(xiàn)壞塊并標(biāo)注出來
K9F2G08U0A的一頁(yè)為(2K+64)字節(jié)(加號(hào)前面的2K表示的是main區(qū)容量,加號(hào)后面的64表示的是spare區(qū)容量),它的一塊為64頁(yè),而整個(gè)設(shè)備包括了2048個(gè)塊
內(nèi)存容量大小計(jì)算:
要實(shí)現(xiàn)用8個(gè)IO口來要訪問這么大的容量,K9F2G08U0A規(guī)定了用5個(gè)周期來實(shí)現(xiàn)。
列地址是用于尋址頁(yè)內(nèi)空間,行地址用于尋址頁(yè),如果要直接訪問塊,則需要從地址A18開始。
CMD_STATUS讀狀態(tài)命令可以實(shí)現(xiàn)讀取設(shè)備內(nèi)的狀態(tài)寄存器,通過該命令可以獲知寫操作或擦除操作是否完成(判斷第6位),以及是否成功完成(判斷第0位)。
自己編寫NANDFLASH的步驟:(進(jìn)行塊擦除,頁(yè)寫,頁(yè)讀)
1、在頭文件中列出相關(guān)的固量 和 函數(shù) 宏
常用的各種命令集;一些基于NANDFLASH控制器的基本函數(shù)
ECC應(yīng)用和使能nandflash片選;NFSTAT寄存器
一些返回判斷值的宏定義
2、寫出幾個(gè)基本的初始化函數(shù):
管腳,寄存器初始化函數(shù) ; 復(fù)位函數(shù) ; 讀NAND ID號(hào)函數(shù)
3、相關(guān)的檢測(cè)判斷函數(shù):
A、檢測(cè)是否寫擦除成功函數(shù)NF_toggle:通過NF_CMD(CMD_STATUS)狀態(tài)位
B、測(cè)試是否壞塊函數(shù)NF_testBadBlock:讀取2054處壞塊標(biāo)志位
C、寫壞塊標(biāo)志函數(shù)NF_MarkBadBlock:寫標(biāo)志到 2054處
4、讀、寫、擦除函數(shù):
具體自己看代碼了,有兩點(diǎn)要注意了:
A、讀操作 檢測(cè)正確性是通過ECC檢驗(yàn)碼,而寫和擦除是通過toggle函數(shù)
B、隨機(jī)讀寫 是 在讀頁(yè),寫頁(yè)的基礎(chǔ)上 加上列的部分
注意區(qū)別兩個(gè)東西:
1、ECC檢驗(yàn)碼的判斷
讀操作來說,我們還要繼續(xù)讀取spare區(qū)的相應(yīng)地址內(nèi)容,已得到上次寫操作時(shí)所存儲(chǔ)的main區(qū)和spare區(qū)的ECC,并把這些數(shù)據(jù)分別放入NFMECCD0/1和NFSECCD的相應(yīng)位置中。最后我們就可以通過讀取NFESTAT0/1(因?yàn)?/span>K9F2G08U0A是8位IO口,因此這里只用到了NFESTAT0)中的低4位來判斷讀取的數(shù)據(jù)是否正確,其中第0位和第1位為main區(qū)指示錯(cuò)誤,第2位和第3位為spare區(qū)指示錯(cuò)誤。
2、壞塊的判斷
對(duì)于寫頁(yè)和擦除操作來說,通過toggle函數(shù)檢測(cè):
NF_CMD(CMD_STATUS); //讀狀態(tài)命令
//判斷狀態(tài)值的第6位是否為1,即是否在忙
//判斷狀態(tài)值的第0位是否為0,為0則寫操作正確,否則錯(cuò)誤
若第0位操作錯(cuò)誤,則該塊為 壞塊
3、main區(qū)和spare區(qū)的解鎖只為了產(chǎn)生ECC碼,一旦產(chǎn)生后,就要鎖上,打開另外區(qū)的,不要影響互相順序的ECC碼產(chǎn)生
擴(kuò)展:從NANDFLASH啟動(dòng)程序
當(dāng)檢測(cè)到是由nandflash啟動(dòng)時(shí),系統(tǒng)會(huì)自動(dòng)把nandflash中的前4k字節(jié)的數(shù)據(jù)加載到Steppingstone中,然后把該Steppingstone映射為Bank0,因此系統(tǒng)會(huì)從Steppingstone開始運(yùn)行程序,從而實(shí)現(xiàn)了s3c2440的nandflash自啟動(dòng)的功能
通過在Steppingstone中,把程序的其余部分復(fù)制到RAM中,程序運(yùn)行時(shí)由Steppingstone轉(zhuǎn)移到該RAM中,SRAM起始地址0x30000000
RdNF2SDRAM是C語(yǔ)言編寫的一段把nandflash中的數(shù)據(jù)復(fù)制到SRAM的程序
看看這函數(shù),了解一下就行了
附加:nandflash、norflash、SDRAM的區(qū)別:
ROM在系統(tǒng)停止供電的時(shí)候仍然可以保持?jǐn)?shù)據(jù),
RAM通常都是在掉電之后就丟失數(shù)據(jù),典型的RAM就是計(jì)算機(jī)的內(nèi)存。
SRAM速度非常快,是目前讀寫最快的存儲(chǔ)設(shè)備了,但是它也非常昂貴,所以只在要求很苛刻的地方使用,譬如CPU的一級(jí)緩沖,二級(jí)緩沖
動(dòng)態(tài)RAM(Dynamic RAM/DRAM),DRAM保留數(shù)據(jù)的時(shí)間很短,速度也比SRAM慢,不過它還是比任何的ROM都要快,但從價(jià)格上來說DRAM相比SRAM要便宜很多,計(jì)算機(jī)內(nèi)存就是DRAM的。
RAM
|
SRAM
|
DRAM
|
SDRAM,DDR RAM等
|
ROM
|
EROM,E2PROM等
|
NANDFLASH、NORFALSH等
|
NOR和NAND是現(xiàn)在市場(chǎng)上兩種主要的非易失閃存技術(shù)。Intel于1988年首先開發(fā)出NOR flash技術(shù),徹底改變了原先由EPROM和EEPROM一統(tǒng)天下的局面。
NOR比較好操作,因?yàn)榧闪讼到y(tǒng)地址線和數(shù)據(jù)線在芯片內(nèi),而NAND只有8個(gè)I/O,要操作,還需要結(jié)合相應(yīng)硬件,如2440里有的 NAND控制器。
14、基于OHCI的USB主機(jī)(僅做了枚舉)
發(fā)現(xiàn)了一個(gè)很好的博客講這個(gè)的:http://lancelot.blog.51cto.com/393579/328233
部分經(jīng)典內(nèi)容摘要:
在OHCI規(guī)范中,最重要的幾個(gè)概念是端點(diǎn)(EndPoint - ED)、傳輸描述符(Transport Descriptor - TD)、主機(jī)控制器通信區(qū)(HCCA)。其中ED負(fù)責(zé)確定傳輸類型(控制傳輸、批量傳輸、同步傳輸和中斷傳輸)。TD確定傳輸參數(shù)。HCCA用于確定數(shù)據(jù)傳輸是否完畢。
OHCI(基本流程)
進(jìn)行控制/批量傳輸?shù)闹饕幚砹鞒倘缦拢?/span>
1、創(chuàng)建控制/批量傳輸?shù)腅D列表;
2、創(chuàng)建ED下的TD列表;
3、設(shè)置命令到相應(yīng)寄存器開始數(shù)據(jù)傳輸;
4、在中斷處理程序中判斷數(shù)據(jù)傳輸是否結(jié)束;
在OHCI層,主要完成如下功能:
l 通過控制端口讀寫數(shù)據(jù)(包含SETUP、DATA、STATUS等3個(gè)TD);
l 通過控制端口發(fā)送設(shè)置命令(沒有DATA的TD);
l 通過批量端口讀數(shù)據(jù);
l 通過批量端口寫數(shù)據(jù);
l 中斷處理程序;
在OHCI的體系下,判斷數(shù)據(jù)是否傳輸完畢是需要通過中斷程序來判斷的,當(dāng)USB主機(jī)設(shè)置了HcControl和HcCommandStatus寄存器開始傳輸數(shù)據(jù)后,AM9200 自動(dòng)開始數(shù)據(jù)傳輸,并且定期的檢查HcDoneHead寄存器的內(nèi)容,并且將其轉(zhuǎn)移到HCCA.DoneHead。然后產(chǎn)生中斷,觸發(fā)中斷處理程序。
在中斷處理程序中需要判斷當(dāng)前結(jié)束的TD是否是當(dāng)前命令的最后一個(gè)TD,這樣才能確保整個(gè)ED處理完畢。
進(jìn)行U盤的數(shù)據(jù)傳輸時(shí)需要通過批量傳輸端口收發(fā)數(shù)據(jù),所使用的協(xié)議為Mass Storage協(xié)議
要學(xué)習(xí)的一種數(shù)據(jù)結(jié)構(gòu)與結(jié)構(gòu)體結(jié)合應(yīng)用的模式:
聲明時(shí):
typedef struct _ED {
…………
} ED, *P_ED;
__inline void CreateEd( unsigned int EDAddr , ………….)
{
P_ED pED = (P_ED) EDAddr; //這個(gè)在函數(shù)中創(chuàng)建結(jié)構(gòu)體pED來初始化
pED->Control =…………………….
}
調(diào)用時(shí),因16字節(jié)對(duì)齊:
__align(16) ED ed; (聲明)
CreateEd(
(unsigned int) &ed, // ED Address
………….
);
簡(jiǎn)單的USB設(shè)備枚舉,讀取描述符:(控制傳輸步驟)
搞好最重要的3個(gè)數(shù)據(jù)結(jié)構(gòu):
端點(diǎn)描述符ED,傳輸描述符TD和共享數(shù)據(jù)域HCCA
由于HCCA只是創(chuàng)建一個(gè)空間域,不需要初始化
而ED和TD在設(shè)備枚舉時(shí)需要不同初始化,故還要?jiǎng)?chuàng)建兩個(gè)
初始化結(jié)構(gòu)體函數(shù):CreateEd 和CreateGenTd
初始化OCHI寄存器(僅限枚舉部分,不涉及中斷)
復(fù)位,設(shè)置幀間隔,初始化HcDoneHead,設(shè)置HC為運(yùn)行狀態(tài)
寫HCCA(開拓一片域)
檢測(cè)是否有USB設(shè)備
設(shè)一定的時(shí)間檢測(cè),如 for(i=0;i<100000;i++)
設(shè)備枚舉的5個(gè)過程:第一步,主機(jī)得到設(shè)備描述符
第二步 為設(shè)備分配地址
第三步,主機(jī)用新的地址再次獲取設(shè)備描述符
第四步,主機(jī)讀取設(shè)備全部配置描述符
第五步,主機(jī)發(fā)送SETUP數(shù)據(jù)包,用以設(shè)置配置,允許所有端點(diǎn)進(jìn)入工作狀態(tài)。
注意:控制寫傳輸需要3個(gè)TD:第一個(gè)發(fā)送Setup包,第二個(gè)用于接收握手或零長(zhǎng)度的數(shù)據(jù)包,第三個(gè)用于發(fā)送狀態(tài);
控制讀傳輸需要4個(gè)TD:第一個(gè)發(fā)送Setup包,第二個(gè)用于接收數(shù)據(jù),第三個(gè)用于發(fā)送一個(gè)零長(zhǎng)度的數(shù)據(jù)包,,第四個(gè)用于接收狀態(tài)
具體有兩種方法判斷TD是否傳送完成:
中斷法
初始化好中斷寄存器rHcInterruptEnable |= (1<<1)|(1<<31);
rHcInterruptStatus |= (1<<1);
pISR_USBH = (int)USBH_interrupt;
rINTMSK = ~BIT_USBH;
當(dāng)有TD完成時(shí),便進(jìn)入中斷。
如何判斷枚舉過程中每一步是否最后一個(gè)TD完成呢?
可以通過TD創(chuàng)造函數(shù)中DelayInterrupt即DI變量設(shè)置來巧妙解決
當(dāng)DI=0x7時(shí),即使TD完成也不會(huì)進(jìn)入中斷的,故可以只在每一階段最后的TD設(shè)為非0x7,其余的設(shè)為0x7,這樣進(jìn)入中斷就代表是最后數(shù)據(jù)發(fā)送完成了
2、狀態(tài)檢測(cè)法:
可以通過rHcCommandStatus寄存器中第二位是否1來判斷Controllistfilled。
當(dāng)其為1時(shí),表示還有TD在隊(duì)列,沒發(fā)送完成
為 0時(shí),表示無TD在隊(duì)列,全部發(fā)送完
可以這樣檢測(cè):while(rHcCommandStatus&&0x02)
{
Delay(50);
}
具體的UFI讀寫設(shè)備參考網(wǎng)上的吧(弄了很久,還沒弄成功)
1、查詢
2、讀余量
3、讀寫扇區(qū)
好啦,到這里,算是結(jié)束了,開始帶LINUX系統(tǒng)的真正學(xué)習(xí)啦,GO
一切都會(huì)有新的開始。。。。。。。。。。