FPGA烧录基础知识

JTAG下载方式:即生成sof文件或者转换的.jic可以通过JTAG方式下载。是直接将程序文件下载到FPGA里面,由于FPGA是SRAM结构,掉电后程序消失。

AS下载方式:   即生成pof文件,通过Activeserial programming方式下载。是将程序下载到配置芯片里面(一般使用EPCS4/EPCS16/EPCS64,我们EP4CE6开发板使用的是EPCS4,我们EP4CE10开发板使用的是EPCS16),然后配置芯片自动加载到FPGA里面,掉电后程序不消失。一般使用JTAG做调试和下载。另外AS下载完成后,需要掉电,然后拔掉AS下载器,然后重新上电,程序才能执行。

EPCS:串行存储器,NiosII 不能直接从EPCS中执行程序,它实际上是执行EPCS控制器的片内ROM中的代码(即Bootloader),把EPCS中的程序搬到RAM中执行。FPGA配置数据和NiosII程序都存放在EPCS器件中。FPGA配置数据放在最前面,程序放在后面,程序可能有多个段,每个段前面都插有一个“程序记录”。一个“程序记录”由2个32位的数据构成,一个是32位的整数,另一个是32位的地址,分别用于表示程序段本身的长度和程序段的运行时地址。这个“程序记录”用于帮助Bootloader把各个程序段搬到程序执行时真正的位置。

Nios II Cache

经常有人反映说自己写的代码无法正常工作,然后晒出自己的代码来。经过对用户代码的分析可以知道,他们都是参考了网络上流传的比较系统的两份资料的方式,采用直接地址映射,即用指针的方式来直接操作外设里面的寄存器。这样操作在不带Cache的NIOS II版本中能够很好的奏效,例如NIOS II的e版本和s版本,但是在f版本中,为了增强NIOS II处理器的性能,加入了数据cache和指令cache。如果用户使用带cache的CPU,却还是像之前那样,直接使用指针映射寄存器地址的方式,就会出现很多时候,我们希望写入的数据并没有直接写入到外设IP的寄存器中,而是写入到了cache中,即外设IP中并未立即写入我们希望写入的值,也就不会执行相应的操作了。(关于CACHE是个啥东西,这里不做专门讲解,有兴趣的请自行查阅相关资料)。那么为什么明明是要写入到外设IP寄存器中的数据,却写入到了cache中呢?这是因为,NIOS II e和s版有31位的地址线,f版本有32位地址线,但是这第32位地址线恰恰就是用来选择cache的,当地32位地址线为0的时候,选择cache,当第32位地址线为1的时候,就旁路/屏蔽cache,也就是说,当我们还是继续使用指针映射的方式操作外设寄存器,假设寄存器的地址为0x00000001,那么在带有cache的系统中,该地址实际是映射到了cache中,而真正的寄存器地址应该是0x10000001,因为要想寻址到实际的寄存器地址,必须屏蔽cache,即需要地址的最高位为1。所以,如果我们还是用指针直接操作0x00000001这个地址,当然数据不会传入实际的寄存器中,所以无法生效。那么怎么解决呢,个人观点还是使用Altera 官方提供的HAL库,如io.h这个文件里,提供了很多读写函数:

IORD_32DIRECT(BASE, OFFSET)       //从某地址读出32位的数据

IORD_16DIRECT(BASE, OFFSET)       //从某地址读出16位的数据

IORD_8DIRECT(BASE, OFFSET)         //从某地址读出8位的数据

 

IOWR_32DIRECT(BASE, OFFSET, DATA)   //向某地址写入32位的数据

扫描二维码关注公众号,回复: 4038229 查看本文章

IOWR_16DIRECT(BASE, OFFSET, DATA)   //向某地址写入16位的数据

IOWR_8DIRECT(BASE, OFFSET, DATA)      //向某地址写入8位的数据

 

IORD(BASE, REGNUM)                        //从某地址按照CPU数据位宽(32)读出数据

IOWR(BASE, REGNUM, DATA) //向某地址按照CPU数据位宽(32)写入的数据

 

这些函数在使用的时候,会自动屏蔽CACHE,另外,针对每个特定的IP,Altera也都提供了相应的驱动文件,如PIO核,提供的驱动头文件名叫“altera_avalon_pio_regs.h”,在这里面定义了对PIO外设IP进行读写和控制的所有驱动函数,这些函数也都是自动屏蔽了CACHE的。而且,使用这个函数,能够方便的在各种NIOS II 版本的CPU之间移植,而不用担心CACHE的问题。所以,个人强烈推荐使用官方库进行IP核的使用。如果用户执意要坚持自己的观点,使用指针直接映射,那么请在定义指针的时候,将地址最高位置为1,例如, PIO_LED的地址为0x00000001,那么用户定义该地址指针时,请用#define PIO_LED (0x00000001 | 0x80000000),或者#define PIO_LED (PIO_LED_BASE | 0x80000000),其中PIO_LED_BASE在system.h头文件中定义。这样再操作就不会有问题了。

猜你喜欢

转载自blog.csdn.net/asd892776222/article/details/83794886