《精簡(jiǎn)ISA總線編程接 – Part2》介紹了英創(chuàng)工控主板ESM7000在DMA驅(qū)動(dòng)的同步總線周期,在應(yīng)用層可獲得:
模式 | 傳輸速率 | CPU負(fù)載 |
MemCpy DMA同步總線讀 | 8.67MB/s | 6.01% |
MemCpy DMA同步總線寫 | 7.93MB/s | 5.71% |
本文在《精簡(jiǎn)ISA總線編程 – Part2》的基礎(chǔ)上,進(jìn)一步優(yōu)化總線參數(shù),總線同步時(shí)鐘BCLK從30MHz提高到40MHz,同時(shí)采用mmap存儲(chǔ)器映射方法在應(yīng)用層讀取ISA總線采集的數(shù)據(jù),使應(yīng)用層的讀取速度達(dá)到16MB/s。
為達(dá)到優(yōu)化目標(biāo),首先需要預(yù)留1MB的DDR空間,作mmap使用。對(duì)客戶來說,就是配置特別的DTB文件(imx7d-esm7000-isa-v2.dtb)。ISA讀取數(shù)據(jù)的流程很簡(jiǎn)單,基本是初始化mmap指針,把需要采集的長(zhǎng)度等參數(shù)填到struct isa_transfer結(jié)構(gòu)中,然后就是調(diào)用讀取函數(shù)。以下介紹核心的代碼。
Mmap指針初始化代碼如下:
void* mmap_base(unsigned long mem_phys, unsigned int size) { void *base = NULL; int fd; fd = open("/dev/mem", O_RDWR|O_SYNC); if(fd < 0) { printf("%s open failed %d\n", __func__, fd); goto cleanup; } /* mmap mem */ base = mmap( NULL, //Any adddress in our space will do size, //Map length PROT_READ|PROT_WRITE, //Enable reading & writting to mapped memory MAP_SHARED, //Shared with other processes fd, //File to map mem_phys //Offset to DMTimer peripheral ); close(fd); cleanup: return base; }
通過mmap驅(qū)動(dòng)ISA數(shù)據(jù)的核心函數(shù):
int mmap_dma_mem_read(int fd, struct isa_transfer *tp, void* mmapbuf, unsigned int mmapbuf_size) { int rc = 0; unsigned int rem_len, mmap_len, pack_len; u_int8_t *sbuf[2], *cbuf; unsigned int sbuf_len, sbuf_count, sbuf_idx; u_int8_t dbuf[256]; unsigned dbuf_len = sizeof(dbuf); struct pollfd fds[1]; rem_len = tp->len; if(!rem_len) { rc = -EINVAL; goto cleanup; } // init variables sbuf[0] = (u_int8_t*)mmapbuf; sbuf_len = mmapbuf_size / 2; sbuf[1] = sbuf[0] + sbuf_len; sbuf_count = 0; sbuf_idx = 0; cbuf = sbuf[sbuf_idx]; memset(fds, 0, sizeof(fds)); fds[0].fd = fd; fds[0].events = POLLIN; // start dma process rc = ioctl(fd, ISA_IOCTL_START, (unsigned long)tp); if(rc < 0) { printf("%s start dma-mmap failed %d\n", __func__, rc); goto cleanup; } while(rem_len) { // wait data ready with timeout rc = poll(fds, 1, POLL_TIMEOUT); if(rc == -1) { perror("poll failed!\n"); ioctl(fd, ISA_IOCTL_STOP, (unsigned long)tp); return rc; } else if(rc == 0) { // timeout continue; } // setup source buffer length mmap_len = sbuf_len; if(mmap_len > rem_len) { mmap_len = rem_len; } // get data from mmap buffer while(mmap_len) { pack_len = dbuf_len; if(pack_len > mmap_len) { pack_len = mmap_len; } memcpy(dbuf, sbuf[sbuf_idx] + sbuf_count, pack_len); sbuf_count += pack_len; mmap_len -= pack_len; if(INFINITE != rem_len) rem_len -= pack_len; } // switch to next mmap buffer sbuf_idx = (sbuf_idx + 1) % 2; sbuf_count = 0; } // well done rc = tp->len - rem_len; cleanup: return rc; }
上面的代碼中fd是打開設(shè)備/dev/em_isa的文件句柄。
應(yīng)用層調(diào)用:
#define MMAP_BASE_PHYS 0xBFF00000 #define MMAP_SIZE 0x80000 //512KB struct isa_transfer t; double elapsed, data_rate; unsigned int data_length; void *mmapbuf; unsigned int mmapbuf_size; //……… // get mmap buffer mmapbuf = mmap_base(MMAP_BASE_PHYS, MMAP_SIZE); if(!mmapbuf) { printf("failed to get mmap buffer\n"); break; } printf("mmap range(0x%08x, 0x%x) => %p\n", MMAP_BASE_PHYS, MMAP_SIZE, mmapbuf); memset(&t, 0, sizeof(struct isa_transfer)); t.rx_buf = (void*)MMAP_BASE_PHYS; t.offset = offset; t.len = count; rc = mmap_dma_mem_read(fd, &t, mmapbuf, MMAP_SIZE); if(rc < 0) { printf("mmap_dma_mem_read failed %d\n", rc); break; } data_length = rc;
采用64MB數(shù)據(jù)長(zhǎng)度,對(duì)上述代碼測(cè)試應(yīng)用層數(shù)據(jù):
模式 | 傳輸速率 | CPU負(fù)載 |
MemCpy DMA同步總線讀 | 16.06MB/s | 38.7% |
函數(shù)mmap_dma_mem_read是軟件啟動(dòng)DMA執(zhí)行同步總線讀周期,其基本的總線時(shí)序與《精簡(jiǎn)ISA總線編程 – Part2》的時(shí)序圖是一致的,不同之處僅僅是總線同步時(shí)鐘BCLK的周期從過去的33ns縮短到25ns。客戶的FPGA應(yīng)盡可能靠近主板CN2布局,以保證總線信號(hào)的完整性。
DMA-MEM同步總線讀時(shí)序
測(cè)試程序test_isa包括了完整的ISA總線的讀寫測(cè)試,其中執(zhí)行mmap dma-mem讀操作的命令為:
./test_isa D1000000 4000
命令中參數(shù)”D”表示mmap dma-mem讀操作,后續(xù)的是16進(jìn)制的讀取字節(jié)數(shù),0x1000000表示16MB,第二個(gè)參數(shù)是16進(jìn)制的ISA總線地址偏移量,0x4000用于告訴驅(qū)動(dòng)程序執(zhí)行dma-mem操作,有關(guān)地址偏移量的說明可參考《精簡(jiǎn)ISA總線編程 – Part1》。
對(duì)測(cè)試程序干興趣的客戶可來郵件(suppport@emtronix.com)索取test_isa的源代碼。目前在Linux平臺(tái)上的開發(fā)環(huán)境是多種多樣,推薦使用微軟開源的Visual Studio Code作為基本的IDE環(huán)境,通過簡(jiǎn)單的配置就可把ESM7000的SDK編譯工具加入環(huán)境,就可Build應(yīng)用程序。再通過NFS的掛載,就可直接在ESM7000目標(biāo)板上跑客戶的應(yīng)用程序了。
成都英創(chuàng)信息技術(shù)有限公司 028-8618 0660