1 基本说明
EP2C8Q208封装为208个引脚,也就是52*4的封装格式。
FPGA启动方式有三种:jtag,AS和PS。使用STM32F103RCT6启动FPGA,使用的是PS方式。
AS全称为active serial,DCLK可以运行在40MHz的频率上。
PS全称为passive serial,
JTAG全称为Joint Test Action Group。
FPGA启动,可以接受的文件有.rbf,.hex和.ttf格式。
使用PS启动方式,硬件连接图可以如下所示:
MSEL等硬件连接需要按照如下所示:
在开始传输时,要将nCONFIG引脚输出一个从低到高的电平。在nSTATUS为高电平的时候,单片机类控制芯片需要在DATA[0]上一直放置数据。
写一下每个引脚以及应有的含义:
引脚 | 输入输出 | 功能 |
---|---|---|
nCONFIG | 输出 | 开始配置 |
nSTATUS | 输入 | 升级响应标记位以及出错标志 |
CONFIG_DONE | 输入 | 升级完成标志位 |
DCLK | 输出 | 升级数据时钟 |
DATA[0] | 输出 | 升级数据 |
在黑金开发板上设置为PS模式的时候,需要做到:
引脚名称 | 引脚号 | FPGA接线 |
---|---|---|
MSEL1 | 125 | GND,已经为低电平 |
MSEL0 | 126 | 拉高,在第三面的22号脚上 |
nCONFIG | 26 | 可以接在R3上或者AS的J1的5号引脚上 |
nSTATUS | 121 | 接在R4上 |
CONFIG_DONE | 123 | 接在J1上的3号引脚上 |
DCLK | 21 | 接在J1上的1号引脚上 |
DATA[0] | 20 | 接在J1上的7号引脚上 |
INIT_DONE | 107 | 只能飞线接上去 |
2 数据组织格式
发送数据格式为LSB,也就是说首先发送低位。举个例子:
02 1B EE 01 FA
0100-0000 1101-1000 0111-0111 1000-0000 0101-1111
数据在DCLK的上升沿锁存。FPGA在CONFIG_DONE为高电平的时候进入初始化状态。
注意要将DCLK的速率设置在系统的运行频率以下。
如果FPGA接收了所有的数据,但是CONFIG_DONE或者INIT_DONE并没有变为高电平。单片机等控制类芯片需要重新配置FPGA。
控制时序图如下所示:
3 控制流程
下面说说使用PS方式给FPGA升级程序的流程:
1 . 在上电后,先将nCONFIG和DCLK设置为高电平,时间在100ms,然后将nCONFIG设置为低电平,时间在2us。
2 . 检测nSTATUS,如果为0,表示FPGA已经响应配置,可以进行配置了。否则就是报错了,正常情况下,在nCONFIG=0后1us之内,nSTATUS就会为0。
3 . nCONFIG为1,等待nSTATUS为高,如果超过5us,则说明有错误,跳出到步骤1。
4 . 发送数据,并且设置DCLK=1,然后延时。
5 . DCLK=0,检测nSTATUS,如果为0,则说明有错误,则需要重新开始传送数据。
6 . 再次发送数据,循环4,5两步步骤,一直等到数据发送完成。
7 . 数据发送完成之后,nCONFIG将会置1。若数据发送完成后,数据不为1,则说明数据发送有误,需要重新开始配置。
8 . 配置完成之后,需要等待40个DCLK周期,等待FPGA初始化完成。不过最好是检测状态,如果INIT_DONE不为高,说明有误,需要跳到步骤1。
具体可参考下面的图示:
上图要注意几点:
1.FPGA上电启动过程会持续100ms。
2.配置过程有三阶段:复位,配置和初始化。
3.nCONFIG或者nSTATUS引脚电平为低,FPGA会在复位的状态。
4.要判断CONFIG_DONE和INIT_DONE引脚电平,超时则表示错误。
4 出错处理
在配置的时候,如果出错,nSTATUS引脚会变低,形成内部自己复位。我们在做PS升级FPGA程序的时候,需要将Auto-restart configuration after error选项关闭,实现自己控制。
5 程序
实验可以这样做:STM32开发板上有ENC28J60网络芯片或者其他的网络芯片,使用TFTP下载FPGA生成了的实验性.rbf文件,将该文件下载到STM32的SPI FLASH上,然后,使用上面1~4部分说明的内容,给FPGA升级程序,现在贴出关于升级FPGA的实验性代码,注意,要多做出错处理。
#include "stm32_fpga.h"
#include
#define nSTATUS_rcc RCC_APB2Periph_GPIOA
#define nSTATUS_gpio GPIOA
#define nSTATUS_pin (GPIO_Pin_2)
#define CONFIG_DONE_rcc RCC_APB2Periph_GPIOA
#define CONFIG_DONE_gpio GPIOA
#define CONFIG_DONE_pin (GPIO_Pin_3)
#define nCONFIG_rcc RCC_APB2Periph_GPIOA
#define nCONFIG_gpio GPIOA
#define nCONFIG_pin (GPIO_Pin_1)
#define DCLK_rcc RCC_APB2Periph_GPIOB
#define DCLK_gpio GPIOB
#define DCLK_pin (GPIO_Pin_0)
#define DATA_rcc RCC_APB2Periph_GPIOB
#define DATA_gpio GPIOB
#define DATA_pin (GPIO_Pin_1)
#define FPGA_IO_SET 1
#define FPGA_IO_RESET 0
static void stm32_fpga_delay_us(unsigned int u_delay);
void set_nCONFIG_io_output(unsigned char val);
void set_DCLK_io_output(unsigned char val);
void set_DATA_io_output(unsigned char val);
/*
* copyright wit_yuan 2017-07-19
*
* PA1-----LED1----nCONFIG
* PA2-----LED2----nSTATUS
* PA3-----LED3----CONFIG_DONE
* PB0-----LED4----DCLK
* PB1-----LED5----DATA[0]
*/
void STM32_FPGA_IO_Init( void )
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(nSTATUS_rcc|CONFIG_DONE_rcc|nCONFIG_rcc|DCLK_rcc|DATA_rcc,ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = nSTATUS_pin;
GPIO_Init(nSTATUS_gpio, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = CONFIG_DONE_pin;
GPIO_Init(CONFIG_DONE_gpio, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = nCONFIG_pin;
GPIO_Init(nCONFIG_gpio, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = DCLK_pin;
GPIO_Init(DCLK_gpio, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = DATA_pin;
GPIO_Init(DATA_gpio, &GPIO_InitStructure);
set_nCONFIG_io_output(FPGA_IO_SET);
set_DCLK_io_output(FPGA_IO_RESET);
set_DATA_io_output(FPGA_IO_RESET);
}
/*
* copyright wit_yuan 2017-07-19
*
*/
void set_nCONFIG_io_output(unsigned char val){
switch(val){
case 0:
GPIO_ResetBits(nCONFIG_gpio, nCONFIG_pin);
break;
case 1:
GPIO_SetBits(nCONFIG_gpio, nCONFIG_pin);
break;
}
}
/*
* copyright wit_yuan 2017-07-19
*
*
*/
void set_DCLK_io_output(unsigned char val){
switch(val){
case 0:
GPIO_ResetBits(DCLK_gpio, DCLK_pin);
break;
case 1:
GPIO_SetBits(DCLK_gpio, DCLK_pin);
break;
}
}
/*
* copyright wit_yuan 2017-07-19
*
*/
void set_DATA_io_output(unsigned char val){
switch(val){
case 0:
GPIO_ResetBits(DATA_gpio, DATA_pin);
break;
case 1:
GPIO_SetBits(DATA_gpio, DATA_pin);
break;
}
}
unsigned char get_nSTATUS_io_input( void )
{
return GPIO_ReadInputDataBit(nSTATUS_gpio, nSTATUS_pin);
}
unsigned char get_CONFIG_DONE_io_input( void )
{
return GPIO_ReadInputDataBit(CONFIG_DONE_gpio, CONFIG_DONE_pin);
}
static void stm32_fpga_delay_us(unsigned int u_delay)
{
int i = 0,j=0;
for( i = 0 ; i < 3 ; i++){
for(j=0;j
提供给外部接口的有三个函数:
1.stm32_send_start_to_fpga(),作用是传输起始信号
2.stm32_send_byte_to_fpga(),作用是传输数据
3.stm32_get_fpga_config_done_flag(),作用是读取配置完成的标志,还需要加上INIT_DONE标志
这个程序,经过测算,一个74K的程序,需要6s的时间。