1、引言
FPGA在系統上電時,需要從外部載入所要運行的程序,此過程被稱為程序加載。多數情況下,FPGA從外部專用的 EPROM讀入程序。這種方式速度慢,而且只能加載固定的程序。顯然,當系統需要容量大而且 FPGA要加載的程序可以根據需要有選擇的加載時不能采用這種方法。本文實現了一種基于外部處理器的加載方法,速度快,而且可以根據設置給FPGA加載相應的程序。
對于 Xilinx公司的 FPGA芯片,有五種加載方式:JTAG模式,串行從模式,串行主模式,并行從模式和并行主模式。JTAG模式常用于調試時,將主機綜合好的程序加載到FPGA,優先級高于其他幾種模式。其他加載模式取決于 FPGA上加載模式管腳(M0,M1,M2)的設置。
用外部處理器給 FPGA加載程序時,可以采用串行從模式、并行從模式,甚至于 JTAG模式。本文選擇并行從模式,原因在于更高的配置速率。 2、 FPGA程序數據的產生
FGPA的程序加載即是要把綜合好的程序文件按一定的時序寫入FPGA。而 Xilinx的開發環境可以根據用戶的選擇產生多種文件格式,以不同的后綴名區分。不同的文件格式包含了不同的信息,有不同的用途。
本文選擇了.bin格式的文件。此文件是只包含有程序數據的二進制文件。產生此文件,要在bitgen 參數里增加-g Binary:yes 選項。
此外,需要說明的是,通常的微處理器 D0位是最低有效位,而 Xilinx的 FPGA在接收程序數據時,D0位是最高有效位。因此,在按字節讀取.bin格式的文件之后,需要有一個轉換的過程。如從文件讀到一個字節,0x7D,即二進制的 0111 1101,需轉換為:1011 1110。
加載過程開始時,就要從.bin文件中順序按字節讀出數據,然后在 CCLK的上升沿寫入 FPGA。在.bin文件中的數據都被寫入 FPGA后,CCLK需要多出四個時鐘周期,以使得 FPGA完成啟動過程。 3、硬件設計
在FPGA上,與配置有關的管腳分為兩類:專用管腳,包括PROG_B,HSWAP_EN,TDI, TMS,,TCK,TDO,CCLK,DONE,和M0-M2。還有一類是可復用管腳,這類管腳在配置階段作為配置管腳,配置結束后可以配置為通用普通的IO管腳,也可以繼續作為配置管腳。在并行從模式下,涉及到的配置管腳和功能如下:
CS_B:片選信號,低有效; RDWR_B:寫信號,低有效; BUSY:FPGA忙指示,高有效,一般只有在并行加載時鐘速率大于50M時才有可能用到;D0-D7:數據線; INIT_B:芯片被復位后,此管腳為輸出信號,輸出低電平指示FPGA正在自行復位內部
寄存器。復位結束后,此管腳浮空,處于輸入狀態。因此需要上拉電阻,指示復位結束。內部寄存器復位結束后,此管腳若被拉低,則會推遲FPGA的程序加載過程。在程序加載過程中,此管腳又變回輸入狀態,對外輸出低電平指示加載的程序數據存在CRC校驗錯誤。
PROG_B:異步復位信號,下降沿有效,此信號為低電平時復位FPGA,復位后,FPGA芯片處于內部寄存器自行復位過程,INIT_B被FPGA芯片拉低,此過程結束后,FPGA不再驅動INIT_B管腳,INIT_B管腳處于浮空狀態,此時,INIT_B有上拉電阻時,INIT_B呈現高電平,依次可以指示FPGA的內部寄存器自行復位結束。程序加載狀態。
DONE:加載成功指示。 CCLK:程序加載時,數據在此信號的上升沿被寫入FPGA。在本設計中,ARM芯片采用的是 SUMSUN公司的S3C2410,與 FPGA配置管腳相連的是
此芯片的通用 IO管腳 D組。硬件連接如圖所示。在 ARM的程序中,ARM管腳在程序加載的各階段的輸入輸出設置如下:首先,設置 GPD(與 FPGA的 INIT_B相連)、GPD(與 FPGA的 BUSY相連)為輸入管腳,以監視 FPGA內部寄存器自行復位結束和忙閑狀態。其次,設置GPD(與 FPGA的 PROG_B相連)為輸出狀態,并使其輸出低脈沖,使 FPGA復位。然后依次設置 GPD(與 FPGA的 CS_B相連)、GPD(與 FPGA的 RDWR_B相連)、GPD(與 FPGA的 CCLK相連)為輸出管腳,并使其輸出低電平,使 FPGA處于被選可接受數據狀態;接著設置D[0..7]為輸出狀態。至此,ARM中的程序開始輪詢GPD的狀態,檢測到此信號為高時,有兩種選擇,其一是因為需要而推遲 FPGA的程序加載,可以通過設置 GPD為輸出,并使其輸出為低電平直至程序加載開始。其二是開始給 FPGA加載程序,FPGA在 CCLK的上升沿接收數據,在給 FPGA加載程序的過程中,程序需要監視GPD管腳的狀態,一旦為低,FPGA指示程序數據加載 CRC校驗出錯。此時需要復位FPGA,重新加載。
采用的硬件連接如下圖:
本文以模塊形式實現了運行于S3C2410上的linux驅動程序,源文件如下(有關寄存器
的設置參考S3C2410的數據手冊,以下源代碼未包含頭文件):
#define GPIO_va_base 0x0F6000000
//基于S3C2410 上的Linux內核IO控制寄存器首地址映射后的虛擬地址
#define ARM_GPDCON PIO_va_base+0x30);
#define ARM_GPDUP PIO_va_base+0x38);
#define ARM_port_wr(addr,value) *(volatile unsigned int*)(addr)=value)
//定義輸出
#define FPGA_CS 8
#define FPGA_RW 9
#define FPGA_PROG 12
#define FPGA_CCLK 14
//定義操作
#define ARM_GPDDAT (*(volatile u32 *)(GPIO_va_base+0x34))
#define set_register_bit(x) ARM_GPDDAT=(1《《x)|ARM_GPDDAT
#define clear_register_bit(x) ARM_GPDDAT=(~(1《《x))&ARM_GPDDAT
//定義輸入
#define FPGA_INIT ((ARM_GPDDAT》》10)&1)
#define FPGA_BUSY ((ARM_GPDDAT》》11)&1)
#define FPGA_DONE ((ARM_GPDDAT》》13)&1)
#define FPGA 211
//定義主設備號,和mknod /dev/fpga c 211 0匹配
typedef char fpga_device_t;
static fpga_device_t fpga_devices[257];
char buf[1000000];
int fpga_open(struct inode *, struct file *);
ssize_t fpga_write(struct file *,const char *,size_t ,loff_t *);
int fpga_release(struct inode*, struct file *);
//初始化ARM的D組通用IO管腳
void init_fpga(void){
ARM_port_wr(GPIO_va_base+0x30,0x55555555);
//FPGA_BUSY FPGA_DONE FPGA_INIT be set input
ARM_port_wr(GPIO_va_base+0x34,0xFFFF);
ARM_port_wr(GPIO_va_base+0x30,0x51055555);
ARM_port_wr(GPIO_va_base+0x38,0);// put up
set_register_bit(FPGA_CCLK);//set GCLK
}
static struct file_operations fpga_ctl_fops= {
open: fpga_open,
write: fpga_write,
release: fpga_release,};
int init_module(void) {
printk(“Hello,word,Now preparing FPGA.。..。.\n”);
printk(“register FPGA.。..。.\n”);
register_chrdev(FPGA, “fpga”, &fpga_ctl_fops);
printk(“Done!\n”);
printk(“Hello,word,success!\n”);
return 0;
}
int fpga_open(struct inode *inode, struct file *filp){
int minor;
minor = MINOR(inode-》i_rdev);
init_fpga();
fpga_devices[minor]++;
printk(“FPGA is ready.\n”);
return 0;
}
ssize_t fpga_write(struct file *flip,const char *buffer,size_t count,loff_t
*ppos){
int i;
if(copy_from_user(buf,buffer,count)){
printk(“error \n”);
return -EFAULT;
}
printk(“%d numbers have been received!\n”,count);
printk(“The number is:%d\n”,count);
for(i=0;i《count;i++){
ARM_GPDDAT=(ARM_GPDDAT&0x3F00)|buf[i];
set_register_bit(FPGA_CCLK);
}
printk(“data write finished\n”);
for(i=0;i《4;i++){
set_register_bit(FPGA_CCLK);
clear_register_bit(FPGA_CCLK);
}
return count;
}
int fpga_release(struct inode *inode, struct file *filp){
int minor;
minor = MINOR(inode-》i_rdev);
if (fpga_devices[minor])
fpga_devices[minor]--;
printk(“Goodbye cruel world\n”);
return 0;
}
void cleanup_module(void){
printk(“Goodbye cruel world\n”);
}
5、結束語
本文的創新點:基于ARM-Linux平臺,實現了一種FPGA的程序加載模式,加載速度快,靈活高效。
責任編輯:gt
評論
查看更多