美文网首页我爱编程
STM32F103RCT6 升级FPGA(EP2C8Q208)

STM32F103RCT6 升级FPGA(EP2C8Q208)

作者: wit_yuan | 来源:发表于2017-07-20 17:26 被阅读0次

    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的时间。

    相关文章

      网友评论

        本文标题:STM32F103RCT6 升级FPGA(EP2C8Q208)

        本文链接:https://www.haomeiwen.com/subject/getlkxtx.html