1、綜述
ESM335x 嵌入式主板的提供帶中斷的精簡(jiǎn)ISA擴(kuò)展總線,主要用于支持高速數(shù)據(jù)采集、多路串口擴(kuò)展以及其他的高級(jí)擴(kuò)展應(yīng)用。在這些應(yīng)用中,往往出現(xiàn)需要按一定的順序讀寫(xiě)一定量的數(shù)據(jù)的情況,如果用戶(hù)在應(yīng)用程序中一次一次的調(diào)用讀寫(xiě)操作將會(huì)很慢而且會(huì)占用較多系統(tǒng)資源。我們?cè)?a target="_blank">Linux-4.1.6 ISA總線驅(qū)動(dòng)增加了中斷時(shí)數(shù)據(jù)塊讀寫(xiě)操作的功能,當(dāng)有中斷發(fā)生時(shí),驅(qū)動(dòng)程序會(huì)按照用戶(hù)的設(shè)置讀寫(xiě)塊數(shù)據(jù),并將讀到的數(shù)據(jù)進(jìn)行緩存,讀寫(xiě)完之后驅(qū)動(dòng)程序會(huì)通知應(yīng)用程序,用戶(hù)在應(yīng)用程序中通過(guò)讀操作就能獲得需要讀取的塊數(shù)據(jù)。使用驅(qū)動(dòng)程序在中斷時(shí)自動(dòng)讀寫(xiě)能簡(jiǎn)化用戶(hù)應(yīng)用程序,減少塊讀寫(xiě)操作的延遲。具體的使用方法在下面介紹。
2、數(shù)據(jù)結(jié)構(gòu)及使用說(shuō)明
使用發(fā)生中斷時(shí)驅(qū)動(dòng)自動(dòng)讀寫(xiě)數(shù)據(jù)塊功能需要在應(yīng)用程序中使用em335x_drivers.h頭文件,使能功能需要使用struct isa_transfer結(jié)構(gòu)體,傳入此結(jié)構(gòu)體數(shù)組給驅(qū)動(dòng)以設(shè)置讀寫(xiě)操作的參數(shù):
structisa_transfer
{
constvoid *tx_buf; /* 寫(xiě)數(shù)據(jù)地址,不為NULL有效 */
void *rx_buf; /* 讀數(shù)據(jù)地址,不為NULL有效 */
unsigned len; /* 讀取長(zhǎng)度 */
unsigned offset; /* 總線地址 0x00 .. 0xFF */
unsigned inc; /* 每次讀寫(xiě)之后地址的增量 */
};
●tx_buf: 不為NULL時(shí), 表示寫(xiě)操作
●rx_buf: 不為NULL時(shí),表示讀操作,數(shù)據(jù)讀取存放地址
●tx_buf和rx_buf不能同時(shí)有效
●len:讀寫(xiě)長(zhǎng)度,以字節(jié)byte為單位,進(jìn)行塊讀寫(xiě)操作時(shí)必須為偶數(shù),也可以進(jìn)行單獨(dú)的1個(gè)byte的數(shù)據(jù)讀寫(xiě),即設(shè)置為1
●offset:讀寫(xiě)操作地址,塊數(shù)據(jù)讀寫(xiě)時(shí)offset必須為偶數(shù)
●inc:每次讀寫(xiě)操作后地址增加量,1或者0
總線塊數(shù)據(jù)讀寫(xiě)說(shuō)明
ESM335x精簡(jiǎn)ISA總線只有8位數(shù)據(jù)/地址線,但是硬件內(nèi)部可以進(jìn)行16bit的讀寫(xiě),并且會(huì)自動(dòng)將16bit的數(shù)據(jù)分為低8位和高8位兩次讀寫(xiě),低8位和高8位處在連續(xù)的地址處(即必須有兩個(gè)相鄰的地址),我們?cè)隍?qū)動(dòng)中為了加快讀寫(xiě)操作,在用戶(hù)進(jìn)行塊讀寫(xiě)(結(jié)構(gòu)體中的len為偶數(shù))時(shí)會(huì)使用16bit讀寫(xiě)的方式,具體讀寫(xiě)方式如下,請(qǐng)用戶(hù)注意讀寫(xiě)地址的變化:
●設(shè)置rx_buf有效,len=4, offset=0, inc=0時(shí),驅(qū)動(dòng)讀寫(xiě)地址及順序?yàn)椋?/p>
低8位—offset,高8位—offset+1;低8位—offset,高8位—offset+1。
●設(shè)置rx_buf有效,len=4, offset=0, inc=1時(shí),驅(qū)動(dòng)讀寫(xiě)地址及順序?yàn)椋?/p>
低8位—offset,高8位—offset+1;低8位—offset+2,高8位—offset+3。
寫(xiě)操作相同。
3、應(yīng)用程序示例
使用ISA總線需要先打開(kāi)相應(yīng)的設(shè)備文件:
intfd;
fd = open("/dev/em335x_isa", O_RDWR);
printf("open file = %d\n", fd);
if(fd < 0)
{
returnfd;
}
應(yīng)用程序需要先初始化要傳遞給驅(qū)動(dòng)的struct isa_transfer數(shù)組,讀寫(xiě)順序和數(shù)組中的順序相同,用戶(hù)可自行設(shè)定,要使用中斷自動(dòng)讀寫(xiě)功能數(shù)組第一個(gè)元素必須初始化為0,否則將直接進(jìn)行塊讀寫(xiě)操作,而不使用中斷:
#defineARRAY_SIZE(a) (sizeof(a)) //用于計(jì)算數(shù)組字節(jié)數(shù)
uint8_t tx[2] = { 0x5a, 0x55}; //第一次寫(xiě)入數(shù)據(jù)
uint8_t tx2[2] = { 0xaa, 0x1b}; //第二次寫(xiě)入數(shù)據(jù)
uint8_t rx[8]; //讀取數(shù)據(jù)存放處
structisa_transfer tr[4];
//第一個(gè)元素必須設(shè)置為0才會(huì)使能中斷自動(dòng)讀寫(xiě)功能
memset ( &tr[0], 0,sizeof(structisa_transfer) );
//第一次操作設(shè)置為寫(xiě)
tr[1].tx_buf = tx;
tr[1].rx_buf = NULL;
tr[1].len = ARRAY_SIZE(tx);
tr[1].offset = 0;
tr[1].inc = 1;
//第二次操作設(shè)置為讀,應(yīng)用程序中讀操作存放數(shù)據(jù)地址rx,總線起始地址為offset
tr[2].tx_buf = NULL;
tr[2].rx_buf = rx;
tr[2].len = ARRAY_SIZE(rx) ;
tr[2].offset = 4;
tr[2].inc = 0;
//第三次操作設(shè)置為寫(xiě)
tr[3].tx_buf = tx2;
tr[3].rx_buf = NULL;
tr[3].len = ARRAY_SIZE(tx2);
tr[3].offset = 0;
tr[3].inc = 1;
調(diào)用ioctl函數(shù)傳遞數(shù)組地址,使能中斷塊讀寫(xiě)操作:
ret = ioctl(fd, ISA_IOC_MESSAGE(4), tr );
設(shè)置過(guò)后的讀取地址必須保證在下次調(diào)用ioctl重新設(shè)置之前一直有效,用戶(hù)之后調(diào)用read函數(shù)時(shí)驅(qū)動(dòng)程序會(huì)自動(dòng)將數(shù)據(jù)寫(xiě)入設(shè)置的讀取地址(示例中的rx數(shù)組),而與用戶(hù)在read函數(shù)中輸入的地址無(wú)關(guān),這樣能夠簡(jiǎn)化用戶(hù)應(yīng)用程序中的設(shè)置,用戶(hù)只需要在每次read函數(shù)之后到ioctl傳遞的結(jié)構(gòu)體數(shù)組中的讀地址處(rx數(shù)組)獲得數(shù)據(jù),并在下次讀操作之前進(jìn)行拷貝或者其他操作以防止數(shù)據(jù)丟失。
停止中斷塊讀寫(xiě)操作,只傳入一個(gè)全為0的struct isa_transfer機(jī)構(gòu)體:
ret =ioctl(fd, ISA_IOC_MESSAGE(1), &tr[0] );
read函數(shù)讀取數(shù)據(jù)只需以sizeof(struct isa_transfer)為count參數(shù),地址為無(wú)關(guān)參數(shù),但是建議用戶(hù)傳入之前ioctl處的結(jié)構(gòu)體數(shù)組地址,如下所示,之后數(shù)據(jù)便會(huì)讀到之前設(shè)置的結(jié)構(gòu)體數(shù)組中指定的讀取數(shù)據(jù)存入地址處,即rx數(shù)組中:
nNum =read(fd, tr,sizeof(structisa_transfer));
需要重新設(shè)置讀寫(xiě)數(shù)據(jù)參數(shù)時(shí)需要重新設(shè)置結(jié)構(gòu)體數(shù)組,并重新調(diào)用ioctl函數(shù)。
設(shè)置完成后使用select函數(shù)查詢(xún)ISA總線狀態(tài),如有中斷發(fā)生,并且驅(qū)動(dòng)讀寫(xiě)完了設(shè)置的數(shù)據(jù)塊,select函數(shù)將會(huì)返回大于0的數(shù)值,并且設(shè)置相應(yīng)的讀文件標(biāo)志,應(yīng)用程序就可以調(diào)用read讀取數(shù)據(jù)了,select函數(shù)用法示例:
//線程函數(shù)中調(diào)用select函數(shù)查詢(xún)總線狀態(tài),如可讀,則調(diào)用read讀取數(shù)據(jù)到之前設(shè)置的地址
intISASelectThreadFunc(void* lparam)
{
intfd = * (int*)lparam;
printf( "fd %d\n", fd );
fd_set fdRead;
structtimeval aTime;
intret;
while(1)
{
FD_ZERO(&fdRead);
FD_SET(fd,&fdRead);
aTime.tv_sec = 2;
aTime.tv_usec = 0;
ret = select ( fd+1, &fdRead, NULL, NULL, &aTime );
if( ret<0 )
printf( "select, something wrong!\n " );
if( ret>0 )
{
if( FD_ISSET(fd, &fdRead) )
{
printf( "There is a IRQ!!! AND RW complete!\n" );
/********************在此調(diào)用read************************/
read(fd, &tx[0],sizeof(structisa_transfer));
//數(shù)據(jù)已經(jīng)讀到rx數(shù)組中了,用戶(hù)可在此進(jìn)行數(shù)據(jù)處理
}
}
//判斷程序運(yùn)行狀態(tài),跳出循環(huán)
//break;
}
pthread_exit( NULL );
return0;
}
//創(chuàng)建線程
intStartPulseThread(int*fd )
{
pthread_attr_t attr;
pthread_t m_thread;
int res;
res = pthread_attr_init(&attr);
if( res!=0 )
{
printf("Create attribute failed\n" );
}
res = pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM );
res += pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED );
if( res!=0 )
{
printf( "Setting attribute failed\n" );
}
res = pthread_create( &m_thread, &attr, (void*(*) (void*))&ISASelectThreadFunc, fd );
if( res!=0 )
{
return-1;
}
pthread_attr_destroy( &attr );
return0;
-
Linux
+關(guān)注
關(guān)注
87文章
11312瀏覽量
209701 -
嵌入式主板
+關(guān)注
關(guān)注
7文章
6085瀏覽量
35396
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論