STM32F103RCT6 升级FPGA(EP2C8Q208)


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启动方式,硬件连接图可以如下所示:

PS启动

MSEL等硬件连接需要按照如下所示:

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。

控制时序图如下所示:

PS模式时序图
PS模式时间参数1
PS模式时间参数2

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。

具体可参考下面的图示:

FPGA程序升级步骤

上图要注意几点:
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 <stm32f10x.h>

#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<u_delay;j++){
            ;
        }
    }
}

unsigned char stm32_send_start_to_fpga( void )
{
        stm32_fpga_delay_us(1000000);
    
        if(get_nSTATUS_io_input() == 0)
        {
            rt_kprintf(" status first low \r\n");
        }           
    
        set_nCONFIG_io_output(FPGA_IO_SET);
        set_DCLK_io_output(FPGA_IO_RESET);  
        set_DATA_io_output(FPGA_IO_RESET);
    
        stm32_fpga_delay_us(10);
    
        /*nCONFIG=0*/
        set_nCONFIG_io_output(FPGA_IO_RESET);
        set_DCLK_io_output(FPGA_IO_RESET);
    
        stm32_fpga_delay_us(2);
        
        set_nCONFIG_io_output(FPGA_IO_SET);
    
        if(get_nSTATUS_io_input() == 0)
        {
            
            rt_kprintf(" fpga reacked \r\n");
            stm32_fpga_delay_us(1000);
            if(get_nSTATUS_io_input()==0)
            {
                
            }
            else
            {
                    rt_kprintf(" status high is right \r\n");   
            }
        }
        else
        {   
            return 1;
        }
        
        rt_kprintf(" fpga config start \r\n");
        
        stm32_fpga_delay_us(5); 

        return 0;
}

/*
*       copyright wit_yuan 2017-07-19 
*
*
*/
unsigned char stm32_send_byte_to_fpga( unsigned char data )
{
    int i = 0;
    unsigned char tmp;
    
    tmp = data;
    for(i = 0 ; i < 8 ; i ++){
        if(tmp & (1<<i)){
                set_DATA_io_output(FPGA_IO_SET);    
        }
        else
        {
                set_DATA_io_output(FPGA_IO_RESET);  
        }
        
        stm32_fpga_delay_us(1);
        
        set_DCLK_io_output(FPGA_IO_SET);
        
        stm32_fpga_delay_us(1);
        set_DCLK_io_output(FPGA_IO_RESET);
        
        /*¼ì²ânSTATUS£¬Èç¹ûΪ0£¬±íʾÓдíÎó*/
        if(get_nSTATUS_io_input()==0){
            return 1;
        }
        
        stm32_fpga_delay_us(1);
    }
    return 0;
}

unsigned char stm32_get_fpga_config_done_flag(   )
{
        if(get_CONFIG_DONE_io_input()==1){
                rt_kprintf(" config done \r\n");
        }
        return get_CONFIG_DONE_io_input();
        //stm32_fpga_delay_us(100000);
}

提供给外部接口的有三个函数:

1.stm32_send_start_to_fpga(),作用是传输起始信号
2.stm32_send_byte_to_fpga(),作用是传输数据
3.stm32_get_fpga_config_done_flag(),作用是读取配置完成的标志,还需要加上INIT_DONE标志

这个程序,经过测算,一个74K的程序,需要6s的时间。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容