<strike id="kiyse"></strike>
  • <tr id="kiyse"></tr>
  • <strike id="kiyse"></strike><samp id="kiyse"><tbody id="kiyse"></tbody></samp>
    <strike id="kiyse"><s id="kiyse"></s></strike>
    <tr id="kiyse"></tr>
    <noframes id="kiyse"><code id="kiyse"></code></noframes>
    <th id="kiyse"></th>
    <samp id="kiyse"></samp>
  • <th id="kiyse"><s id="kiyse"></s></th>
  • 精簡(jiǎn)ISA總線Linux編程 – Part1

     2019-3-20     作者:Emtronix         

      精簡(jiǎn)ISA總線接口是一種8-bit寬度的雙向并行擴(kuò)展總線,其特點(diǎn)是地址數(shù)據(jù)分時(shí)復(fù)用8-bit總線,加上4條總線控制信號(hào),即可實(shí)現(xiàn)對(duì)外部數(shù)據(jù)的快速讀寫(xiě)。若再使能一條總線時(shí)鐘信號(hào)(共13條信號(hào)),就可實(shí)現(xiàn)高達(dá)10MB/s的數(shù)據(jù)傳輸。精簡(jiǎn)ISA總線作為英創(chuàng)主板的特色功能之一,在ESM6802、ESM7000、ESM7100、ESM335x等多款型號(hào)中均有配置。


      對(duì)精簡(jiǎn)ISA總線接口的應(yīng)用編程,將通過(guò)3個(gè)部分分別加以介紹。本文是第一部分,主要介紹ISA總線的訪問(wèn)模式,以及最基本的總線數(shù)據(jù)讀寫(xiě)。第二部分介紹由應(yīng)用程序啟動(dòng)基于DMA的數(shù)據(jù)塊讀寫(xiě)。采用DMA方式實(shí)現(xiàn)數(shù)據(jù)庫(kù)讀寫(xiě),可有效降低CPU的負(fù)載率。第三部分介紹ISA擴(kuò)展硬件觸發(fā)DMA數(shù)據(jù)傳輸?shù)姆椒?,該方法主要面向工業(yè)控制領(lǐng)域的高速數(shù)據(jù)采集。由于采用硬件觸發(fā)的DMA傳輸機(jī)制,使得前端的高速AD單元不再采用昂貴的高速SRAM做數(shù)據(jù)緩沖,從而使采集單元的成本大幅度下降。該方法可實(shí)現(xiàn)高達(dá)5MB/s(每秒5兆字節(jié))以上的數(shù)據(jù)采集率。


      ISA總線信號(hào)定義如下:


    信號(hào)及說(shuō)明PIN#信號(hào)及說(shuō)明
    RESET_B,硬件復(fù)位12ISA_ADVn,地址鎖存控制信號(hào)
    ISA_AD0,地址數(shù)據(jù)總線,LSB34ISA_AD4,地址數(shù)據(jù)總線
    ISA_AD1,地址數(shù)據(jù)總線56ISA_AD5,地址數(shù)據(jù)總線
    ISA_AD2,地址數(shù)據(jù)總線78ISA_AD6,地址數(shù)據(jù)總線
    ISA_AD3,地址數(shù)據(jù)總線910ISA_AD7,地址數(shù)據(jù)總線,MSB
    MSLn,支持多模塊掛接總線1112ISA_WEn,數(shù)據(jù)寫(xiě)控制信號(hào)
    GPIO9,可選作為IRQ1314ISA_RDn,數(shù)據(jù)讀控制信號(hào)
    GPIO8,可選作為IRQ1516ISA_CSn,片選控制信號(hào)
    GPIO25,可選作為IRQ1718VDD_5V0,+5V供電
    GPIO24 / ISA_BCLK,同步時(shí)鐘ISA_BCLK1920GND,電源信號(hào)地


      本文以下部分,將以ESM7000 Linux平臺(tái)為例,介紹具體的編程方法。


    ISA總線操作模式


      精簡(jiǎn)ISA總線的寬度只有8-bit,因此它的地址尋址范圍也只有8-bit,即0x00 – 0xFF。ISA總線的驅(qū)動(dòng)程序支持應(yīng)用程序使用不同的地址范圍,來(lái)區(qū)別不同的訪問(wèn)類(lèi)型。根據(jù)ISA地址可有如下6種類(lèi)型:


    模式offsetISA總線操作
    00x0000 … 0x00FF異步總線周期,CPU操作
    10x1000 … 0x10FF異步總線周期,MemCpy方式DMA,固定端口地址
    20x2000 … 0x20FF異步總線周期,外部信號(hào)觸發(fā)方式DMA,固定端口地址
    30x3000 … 0x30FF同步總線周期,CPU操作,要求ISA端口地址16字節(jié)對(duì)齊
    40x4000 … 0x40FF同步總線周期,MemCpy方式DMA,同步譯碼端口
    50x5000 … 0x50FF同步總線周期,外部信號(hào)觸發(fā)方式DMA,同步譯碼端口


      ISA總線的異步總線周期是指每個(gè)總線周期讀寫(xiě)一個(gè)字節(jié),只需用到ISA最基本的12條信號(hào)線;而同步總線周期則需要使用總線時(shí)鐘信號(hào)(共13條信號(hào)線),可實(shí)現(xiàn)一個(gè)總線周期讀寫(xiě)4個(gè)字節(jié)。在《在英創(chuàng)工控主板上實(shí)現(xiàn)高速工控?cái)?shù)據(jù)采集》一文中有對(duì)異步總線周期時(shí)序和同步總線周期時(shí)序較詳細(xì)的介紹。


      由iMX7DSDMA(Smart DMA)控制器特性決定,ESM7000可支持的ISA總線操作類(lèi)型如下:


    模式offsetISA總線讀操作
    00x0000 … 0x00FF異步總線周期,CPU讀,inc僅對(duì)本模式有效
    30x3000 … 0x30FF同步總線周期,CPU讀,要求ISA端口地址16字節(jié)對(duì)齊
    40x4000 … 0x40FF同步總線周期,MemCpy方式DMA讀,同步譯碼端口
    50x5000 … 0x50FF同步總線周期,外部信號(hào)觸發(fā)方式DMA讀,同步譯碼端口


    模式offsetISA總線寫(xiě)操作
    00x0000 … 0x00FF異步總線周期,CPU寫(xiě),inc僅對(duì)本模式有效
    30x3000 … 0x30FF同步總線周期,CPU寫(xiě),要求ISA端口地址16字節(jié)對(duì)齊
    40x4000 … 0x40FF同步總線周期,MemCpy方式DMA寫(xiě),同步譯碼端口


      同步總線周期主要用于數(shù)據(jù)的高速傳送,因此采用固定數(shù)據(jù)端口。數(shù)據(jù)端口的譯碼則采用直接識(shí)別同步總線周期的方法,而不再采用對(duì)總線地址譯碼的方法。異步總線周期則主要用于擴(kuò)展電路單元內(nèi)各寄存器的控制。


      采用DMA進(jìn)行ISA總線數(shù)據(jù)傳送的目的,是為了降低高速傳送大量數(shù)據(jù)時(shí)的CPU開(kāi)銷(xiāo),使系統(tǒng)在進(jìn)行高速數(shù)據(jù)采集的同時(shí),還能進(jìn)行其他的必要操作。MemCpy方式的DMA是指軟件線程啟動(dòng)DMA,然后該線程掛起等待DMA操作完成。在多線程環(huán)境中,其他線程即可在DMA執(zhí)行過(guò)程中得以并行運(yùn)行。MemCpy方式DMA的具體情況將在《精簡(jiǎn)ISA總線編程– Part 2》中介紹。硬件觸發(fā)DMA,為低成本實(shí)現(xiàn)高速數(shù)據(jù)采集提供了技術(shù)手段,將在《精簡(jiǎn)ISA總線編程– Part 3》中介紹相關(guān)的采集時(shí)序和程序?qū)崿F(xiàn)。


      表格中的offset項(xiàng),是指在程序設(shè)計(jì)中使用的數(shù)據(jù)結(jié)構(gòu)struct isa_transfer的成員,其結(jié)構(gòu)如下:


    structisa_transfer
    {
           void              *rx_buf;                /* != NULL: buffer for bus read */
           void              *tx_buf;                /* != NULL: buffer for bus write */
           unsigned     len;                      /* buffer length in byte */
           unsigned     offset;                  /* offset,port address on isa bus */
           unsigned     inc;                      /* = 0: fixed offset, = 1: offset+1 after r/w */
    };



      每一個(gè)總線周期的操作只能是讀或?qū)懀虼嗽趇sa_transfer結(jié)構(gòu)中只能有一個(gè)buffer指針不為NULL。


    ISA總線訪問(wèn)API


      對(duì)ISA總線硬件端口的基本訪問(wèn)方法,包含在isa_api_v3.cpp文件中,如下所示:


    #include<fcntl.h>
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<sys/mman.h>
    #include<unistd.h>
    #include"em335x_drivers.h"
     
    unsignedchar *isa_base = NULL;
    unsignedintmap_size = 4096;
     
    // return >= 0: return file handle
    // return < 0: return failed code
    intisa_open()
    {
           intfd;
     
           fd = open("/dev/em_isa", O_RDWR);
           if(fd< 0)
           {
                  returnfd;
           }
     
           isa_base = (unsignedchar*)mmap(0,map_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
           if (isa_base == MAP_FAILED) {
                  printf("%s mmap failed\n", __func__);
                  isa_base = NULL;
                  close(fd);
                  return -1;
           }
     
           returnfd;
    }
     
    intisa_close(intfd)
    {
           if(isa_base != NULL) {
                  munmap(isa_base, map_size);
                  isa_base = NULL;
           }
     
           returnclose(fd);
    }
     
    // offset: port address in isa bus
    unsignedcharisa_read(intfd, unsignedint offset)
    {
           unsignedcharval_b;
           int          rc;
     
           offset&= 0xff;
           if(isa_base != NULL) {
                  unsignedshortintval_w;
     
                  val_w = *((unsignedshortint*)(isa_base + (offset << 1)));
                  val_b = (unsignedchar)(val_w& 0xff);
                  returnval_b;
           }
     
           val_b = offset;
           rc = read(fd, &val_b, sizeof(unsignedchar));
           if(rc< 0)
           {
                  // read error
                  printf("%s failed %d\n", __func__, rc);
           }
     
           returnval_b;
    }
     
    // offset: port address in isa bus
    voidisa_write(intfd, unsignedint offset, unsignedcharval_b)
    {
           unsignedshortintval_w;
           int                 rc;
     
           offset&= 0xff;
           if(isa_base != NULL) {
                  val_w = val_b;
                  *((unsignedshortint*)(isa_base + (offset << 1))) = val_w;
                  return;
           }
     
           val_w = ((offset & 0xff) << 8) | val_b;
           rc = write(fd, &val_w, sizeof(unsignedshortint));
           if(rc< 0)
           {
                  // read error
                  printf("%s failed %d\n", __func__, rc);
           }
    }
     
    // offset: port address in isa bus
    unsignedshortintisa_read16(intfd, unsignedint offset)
    {
           unsignedshortintval_w;
           int                 rc;
     
           // 2-byte alignment is required for offset
           offset&= 0xfe;
     
           if(isa_base != NULL) {
                  unsignedintval;
                  val = *((unsignedint*)(isa_base + (offset << 1)));
                  val_w = (unsignedshortint)((val>> 8) | (val& 0x00ff));
                  returnval_w;
           }
     
           val_w = (unsignedshortint)offset;
           rc = read(fd, &val_w, sizeof(unsignedshortint));
           if(rc< 0)
           {
                  // read error
                  printf("%s failed %d\n", __func__, rc);
           }
     
           returnval_w;
    }
     
    // offset: port address in isa bus
    voidisa_write16(intfd, unsignedint offset, unsignedshortintval_w)
    {
           unsignedintval;
           intrc;
     
           // 2-byte alignment is required for offset
           offset&= 0xfe;
     
           if(isa_base != NULL) {
                  val = val_w;
                  val = ((val<< 8) & 0x00ff0000) | (val& 0x000000ff);
                  *((unsignedint*)(isa_base + (offset << 1))) = val;
                  return;
           }
     
           val = (offset << 16) | val_w;
           rc = write(fd, &val, sizeof(unsignedint));
           if(rc< 0)
           {
                  // read error
                  printf("%s failed %d\n", __func__, rc);
           }
    }
     
    intisa_read_buf(intfd, structisa_transfer *tp)
    {
           int   rc;
     
           rc = read(fd, tp, sizeof(structisa_transfer));
           if(rc< 0)
           {
                  // read error
                  printf("%s failed %d\n", __func__, rc);
           }
           returnrc;
    }
     
    intisa_write_buf(intfd, structisa_transfer *tp)
    {
           int   rc;
     
           rc = write(fd, tp, sizeof(structisa_transfer));
           if(rc< 0)
           {
                  // read error
                  printf("%s failed %d\n", __func__, rc);
           }
     
           returnrc;
    }



      函數(shù)isa_open(..)和isa_close(..)是打開(kāi)關(guān)閉ISA驅(qū)動(dòng)的設(shè)備節(jié)點(diǎn)。為了提高應(yīng)用程序訪問(wèn)ISA硬件寄存器的速度,ISA驅(qū)動(dòng)實(shí)現(xiàn)了mmap功能,使isa_read(..)、isa_write(..)、isa_read16(..)和isa_write16(..)這4個(gè)函數(shù)可在用戶空間直接操作ISA總線上的硬件寄存器,大大提高了代碼的執(zhí)行速度。注意若在多個(gè)線程中均有調(diào)用isa_api_v3.cpp的函數(shù)時(shí),需要加互斥鎖,保證對(duì)硬件資源操作的完整性。


    CPU字節(jié)/字讀寫(xiě)


      函數(shù)isa_write(fd, 0x40, 0x55)是向地址為0x40的寄存器寫(xiě)入單個(gè)字節(jié)0x55,對(duì)應(yīng)的總線時(shí)序?yàn)椋?/p>


    1.png


      時(shí)序圖顯示了8位總線的地址/數(shù)據(jù)復(fù)用,地址需利用ADV#信號(hào)鎖存。


      函數(shù)isa_read(fd, 0x40)是從地址為0x40的寄存器讀取單個(gè)字節(jié),對(duì)應(yīng)的總線時(shí)序?yàn)椋?/p>


    2.png

     

      在上述時(shí)序中,ISA總線懸空,沒(méi)有接具體的外圍設(shè)備,因此由于分布電容的作用,在數(shù)據(jù)時(shí)段總線繼續(xù)保持前面輸出的地址0x40,讀取的數(shù)據(jù)也會(huì)是0x40。若此時(shí)有外圍設(shè)備輸出數(shù)據(jù)至總線上,該數(shù)據(jù)則會(huì)被系統(tǒng)讀取。


      函數(shù)isa_write16(fd, 0x40, 0xaa55)是向地址為0x40的字寄存器寫(xiě)入16-bit字0xaa55,對(duì)應(yīng)的總線時(shí)序?yàn)椋?/p>


    3.png


      從時(shí)序圖可見(jiàn),16-bit數(shù)據(jù)寫(xiě)被分成兩個(gè)連續(xù)的總線周期,其中低位字節(jié)0x55寫(xiě)入地址0x40寄存器,高位字節(jié)0xaa寫(xiě)入地址0x41寄存器。為了盡可能縮短2個(gè)周期的間隔,要求地址必須是偶對(duì)齊。


      函數(shù)isa_read16(fd, 0x40)是從地址為0x40的字寄存器讀取16-bit字,對(duì)應(yīng)的總線時(shí)序?yàn)椋?/p>


    4.png


      同樣由于懸空總線的分布電容的作用,讀取的數(shù)據(jù)會(huì)是0x4140。


    CPU數(shù)據(jù)塊讀寫(xiě)


      為了提高數(shù)據(jù)傳輸速度,對(duì)數(shù)據(jù)塊操作,推薦采用同步總線周期。在ESM7000 Linux版本中,每個(gè)同步總線周期可傳送4個(gè)字節(jié)。為了進(jìn)一步加快數(shù)據(jù)塊的傳送,在驅(qū)動(dòng)中使用了ARMv7的匯編塊指令來(lái)支持16字節(jié)以上的數(shù)據(jù)傳輸。因此強(qiáng)烈建議數(shù)據(jù)塊傳輸長(zhǎng)度選擇為16字節(jié)的整倍數(shù),其數(shù)據(jù)端口占用16個(gè)ISA地址,即只對(duì)高4位地址譯碼。


      進(jìn)行數(shù)據(jù)塊讀寫(xiě)需要用到structisa_transfer傳遞相關(guān)參數(shù)。以下是執(zhí)行32字節(jié)數(shù)據(jù)塊寫(xiě)的代碼,寫(xiě)入地址為0x3040。順序的數(shù)據(jù)可方便時(shí)序的觀察。


    unsignedchargbuf[64 * 1024];
    unsignedint i, value;
    structisa_transfer      t;
    unsignedchar   *pBuf8;
     
    // write data block
    memset(&t, 0, sizeof(structisa_transfer));
    t.offset = 0x3040;
    t.len = 32;
    t.tx_buf = gbuf;
    // fill data
    value = 0x55;             // initial value
    pBuf8 = (unsignedchar*)t.tx_buf;
    for(i = 0; i<t.len; i++){
           *pBuf8 = (unsignedchar)(value + i);
           pBuf8++;
    }
    isa_write_buf(fd, &t);


      對(duì)應(yīng)的總線時(shí)序說(shuō)明如下:


    5.png


      上圖可見(jiàn),32個(gè)字節(jié)分成了8個(gè)總線周期完成,大致的總線速率為13MB/s。展開(kāi)上述時(shí)序可看到:


    6.png


    7.png


      總線上的數(shù)據(jù)0x55、0x59、…... 0x6D、0x71是每個(gè)總線周期CPU送出的第一個(gè)數(shù)據(jù),保持3個(gè)時(shí)鐘節(jié)拍,所以可在示波器中顯示出來(lái)。進(jìn)一步展開(kāi)可看到:


    8.png


    9.png


    10.png


    11.png


    12.png


      ISA擴(kuò)展單元可根據(jù)上述時(shí)序來(lái)支持高速的同步總線周期讀寫(xiě)邏輯電路,其要點(diǎn)包括:

      ● 每個(gè)周期的第一個(gè)BCLK下降沿ADV#有效,標(biāo)志同步周期的開(kāi)始,之后連續(xù)7個(gè)BCLK下降沿后同步周期結(jié)束。

      ● 第一個(gè)總線周期地址為輸入地址,之后每個(gè)總線周期的地址+4,按16模循環(huán)。因此要求數(shù)據(jù)端口占用16個(gè)ISA地址。

      ● BCLK頻率30MHz,從第5個(gè)上升沿開(kāi)始鎖存數(shù)據(jù),連續(xù)4個(gè)數(shù)據(jù)。沒(méi)有BCLK時(shí)輸出的數(shù)據(jù)沒(méi)有意義,不影響正常的數(shù)據(jù)傳輸。


      以上是對(duì)精簡(jiǎn)ISA總線基本讀寫(xiě)的介紹,有興趣的客戶可與英創(chuàng)公司技術(shù)聯(lián)系,索取測(cè)試代碼源碼。技術(shù)支持郵箱:support@www.jsjflaw.com

    亚洲精品网站在线观看你懂的| 国产精品久久久久久久人人看 | 在线精品国产成人综合| 日韩精品无码一区二区三区AV| 99国产精品自在自在久久| 久久精品网站免费观看| 狠狠色伊人久久精品综合网| 热re99久久精品国99热| 探花国产精品三级在线播放| 久久精品国产99久久久香蕉| 精品国产一区二区三区不卡 | 国产美女在线精品观看| 国产精品自在线拍国产第一页| 人妻少妇精品中文字幕AV| 国产精品99久久久精品无码| 日韩精品一区二区午夜成人版| 久久精品中文闷骚内射| 亚洲国产精品嫩草影院久久| 亚洲熟妇无码久久精品| 精品精品国产国产| 国产三级国产精品| 日韩精品无码一区二区三区免费| 国语自产精品视频| 国产精品高潮露脸在线观看| 精品一区二区三区在线视频| 日韩精品午夜视频一区二区三区| 国产成人精品三级在线| 久久久久久久精品成人热色戒| 自拍中文精品无码| 国产精品无打码在线播放| 亚洲国产成人乱码精品女人久久久不卡 | 亚洲日韩国产精品乱| 国产精品久久久久一区二区| 78成人精品电影在线播放日韩精品电影一区亚洲| 国模和精品嫩模私拍视频| 精品一区二区三区免费观看 | 亚洲国产精品一区二区久久| 精品人妻伦九区久久AAA片69| 国产精品videossex白浆| 精品麻豆国产色欲色欲色欲www | 国产精品熟女福利久久AV|