<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>
  • 精簡ISA總線Linux編程 – Part1

     2019-3-20     作者:Emtronix         

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


      對精簡ISA總線接口的應用編程,將通過3個部分分別加以介紹。本文是第一部分,主要介紹ISA總線的訪問模式,以及最基本的總線數據讀寫。第二部分介紹由應用程序啟動基于DMA的數據塊讀寫。采用DMA方式實現數據庫讀寫,可有效降低CPU的負載率。第三部分介紹ISA擴展硬件觸發DMA數據傳輸的方法,該方法主要面向工業控制領域的高速數據采集。由于采用硬件觸發的DMA傳輸機制,使得前端的高速AD單元不再采用昂貴的高速SRAM做數據緩沖,從而使采集單元的成本大幅度下降。該方法可實現高達5MB/s(每秒5兆字節)以上的數據采集率。


      ISA總線信號定義如下:


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


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


    ISA總線操作模式


      精簡ISA總線的寬度只有8-bit,因此它的地址尋址范圍也只有8-bit,即0x00 – 0xFF。ISA總線的驅動程序支持應用程序使用不同的地址范圍,來區別不同的訪問類型。根據ISA地址可有如下6種類型:


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


      ISA總線的異步總線周期是指每個總線周期讀寫一個字節,只需用到ISA最基本的12條信號線;而同步總線周期則需要使用總線時鐘信號(共13條信號線),可實現一個總線周期讀寫4個字節。在《在英創工控主板上實現高速工控數據采集》一文中有對異步總線周期時序和同步總線周期時序較詳細的介紹。


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


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


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


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


      采用DMA進行ISA總線數據傳送的目的,是為了降低高速傳送大量數據時的CPU開銷,使系統在進行高速數據采集的同時,還能進行其他的必要操作。MemCpy方式的DMA是指軟件線程啟動DMA,然后該線程掛起等待DMA操作完成。在多線程環境中,其他線程即可在DMA執行過程中得以并行運行。MemCpy方式DMA的具體情況將在《精簡ISA總線編程– Part 2》中介紹。硬件觸發DMA,為低成本實現高速數據采集提供了技術手段,將在《精簡ISA總線編程– Part 3》中介紹相關的采集時序和程序實現。


      表格中的offset項,是指在程序設計中使用的數據結構struct isa_transfer的成員,其結構如下:


    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 */
    };



      每一個總線周期的操作只能是讀或寫,因此在isa_transfer結構中只能有一個buffer指針不為NULL。


    ISA總線訪問API


      對ISA總線硬件端口的基本訪問方法,包含在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;
    }



      函數isa_open(..)和isa_close(..)是打開關閉ISA驅動的設備節點。為了提高應用程序訪問ISA硬件寄存器的速度,ISA驅動實現了mmap功能,使isa_read(..)、isa_write(..)、isa_read16(..)和isa_write16(..)這4個函數可在用戶空間直接操作ISA總線上的硬件寄存器,大大提高了代碼的執行速度。注意若在多個線程中均有調用isa_api_v3.cpp的函數時,需要加互斥鎖,保證對硬件資源操作的完整性。


    CPU字節/字讀寫


      函數isa_write(fd, 0x40, 0x55)是向地址為0x40的寄存器寫入單個字節0x55,對應的總線時序為:


    1.png


      時序圖顯示了8位總線的地址/數據復用,地址需利用ADV#信號鎖存。


      函數isa_read(fd, 0x40)是從地址為0x40的寄存器讀取單個字節,對應的總線時序為:


    2.png

     

      在上述時序中,ISA總線懸空,沒有接具體的外圍設備,因此由于分布電容的作用,在數據時段總線繼續保持前面輸出的地址0x40,讀取的數據也會是0x40。若此時有外圍設備輸出數據至總線上,該數據則會被系統讀取。


      函數isa_write16(fd, 0x40, 0xaa55)是向地址為0x40的字寄存器寫入16-bit字0xaa55,對應的總線時序為:


    3.png


      從時序圖可見,16-bit數據寫被分成兩個連續的總線周期,其中低位字節0x55寫入地址0x40寄存器,高位字節0xaa寫入地址0x41寄存器。為了盡可能縮短2個周期的間隔,要求地址必須是偶對齊。


      函數isa_read16(fd, 0x40)是從地址為0x40的字寄存器讀取16-bit字,對應的總線時序為:


    4.png


      同樣由于懸空總線的分布電容的作用,讀取的數據會是0x4140。


    CPU數據塊讀寫


      為了提高數據傳輸速度,對數據塊操作,推薦采用同步總線周期。在ESM7000 Linux版本中,每個同步總線周期可傳送4個字節。為了進一步加快數據塊的傳送,在驅動中使用了ARMv7的匯編塊指令來支持16字節以上的數據傳輸。因此強烈建議數據塊傳輸長度選擇為16字節的整倍數,其數據端口占用16個ISA地址,即只對高4位地址譯碼。


      進行數據塊讀寫需要用到structisa_transfer傳遞相關參數。以下是執行32字節數據塊寫的代碼,寫入地址為0x3040。順序的數據可方便時序的觀察。


    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);


      對應的總線時序說明如下:


    5.png


      上圖可見,32個字節分成了8個總線周期完成,大致的總線速率為13MB/s。展開上述時序可看到:


    6.png


    7.png


      總線上的數據0x55、0x59、…... 0x6D、0x71是每個總線周期CPU送出的第一個數據,保持3個時鐘節拍,所以可在示波器中顯示出來。進一步展開可看到:


    8.png


    9.png


    10.png


    11.png


    12.png


      ISA擴展單元可根據上述時序來支持高速的同步總線周期讀寫邏輯電路,其要點包括:

      ● 每個周期的第一個BCLK下降沿ADV#有效,標志同步周期的開始,之后連續7個BCLK下降沿后同步周期結束。

      ● 第一個總線周期地址為輸入地址,之后每個總線周期的地址+4,按16模循環。因此要求數據端口占用16個ISA地址。

      ● BCLK頻率30MHz,從第5個上升沿開始鎖存數據,連續4個數據。沒有BCLK時輸出的數據沒有意義,不影響正常的數據傳輸。


      以上是對精簡ISA總線基本讀寫的介紹,有興趣的客戶可與英創公司技術聯系,索取測試代碼源碼。技術支持郵箱:support@www.jsjflaw.com

    国产精品资源在线观看网站| 国产亚洲精品激情都市| 久久亚洲精品视频| 国产精品酒店视频免费看| 久久久一本精品99久久精品66| 国产A∨免费精品视频| 最新亚洲精品国偷自产在线| 国产AV午夜精品一区二区三区| 狼色精品人妻在线视频免费| 91精品福利一区二区| 久久国产精品鲁丝片| 亚洲精品国产自在久久| 久久精品亚洲日本波多野结衣| 亚洲精品福利视频| 国内精品国产成人国产三级| 国产成人无码精品一区不卡 | 久久精品国产亚洲沈樵| 青草午夜精品视频在线观看| 2021久久精品国产99国产精品| 日韩精品乱码AV一区二区| 99久久精品毛片免费播放| 亚洲А∨精品天堂在线| 自拍偷自拍亚洲精品偷一| 国产精品久久久久影院色| 无码日韩人妻精品久久蜜桃| 中文精品99久久国产 | 亚洲精品**中文毛片| 国产午夜精品无码| 精品无码一级毛片免费视频观看 | 亚洲国产婷婷综合在线精品| 精品精品国产自在97香蕉| 精品久久久久久中文字幕大豆网 | 国产伦精品一区二区三区不卡| 亚洲精品影院久久久久久| 色欲久久久天天天综合网精品| 最新国产精品精品视频| 精品久久久久久无码人妻蜜桃| 精品在线一区二区三区| 国产精品R级最新在线观看| 99久久精品国产第一页| 亚洲精品又粗又大又爽A片|