基于外部处理器的FPGA加载应用程序的方法研究

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,重新加载。
采用的硬件连接如下图:
4、嵌入式 linux的驱动实现
本文以模块形式实现了运行于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的程序加载模式,加载速度快,灵活高效。


VR/AR头显和PS4相比还存在这些问题!
以STM32L431为例,解析LPUART唤醒STOP模式
开放原子开源基金会与Eclipse基金会正式签署协议,创造了两个第一
Solid Power:2022年初将开始测试用于汽车生产的固态电池
电线束线路故障的原因及检测
基于外部处理器的FPGA加载应用程序的方法研究
中方先后向阿富汗捐赠含音圈马达呼吸机在内的众多防疫物资
移远通信吴冰:携手合作伙伴加速5G技术在物联网领域的商用进程
iphone8上市多少钱?iphone8发布时间确定:史上最贵iPhone8价格确定,起步价就达到7000元敢买吗?
敦化联通打造“智慧助残扶贫”平台
罗永浩称锤子手机的用户学历最高、收入最高
Intel Rocket Lake 11代桌面酷睿性能曝光
BMS的构成、功能及智能充电机充电系统的设计与应用
ATR与北欧航空租赁签署了包含100余架飞机订单的意向书
凌华科技:全面开启数字化转型之旅
iPhone13发售_苹果13具体上线时间
PCB技术:Altium怎么安装导入导出插件
水泵控制箱变压器烧毁是什么原因
GAN新手必读:如何将将GAN应用于NLP(论文笔记)
基于ZYNQ的超低成本的开发板