嵌入式開發筆記——MCU配置Altera-Cyclone系列FPGA(PS)

做者:zzssdd2ui

E-mail:zzssdd2@foxmail.com3d

一、需求描述

FPGA內部是SRAM儲存結構,掉電後程序就會丟失,故須要將FPGA程序保存在掉電不丟失的儲存介質中(好比FLASH、EMMC、SD卡等),在每次上電時讀取程序進行配置。code

二、功能分析

項目中使用的FPGA型號是Altera公司(現屬於Intel)的Cyclone系列。在Altera的文檔[Cyclone Device Handbook, Volume 1]:https://www.intel.com/content/dam/www/programmable/us/en/pdfs/literature/hb/cyc/cyc_c5v1.pdf 的第13章節講述了該系列FPGA的幾種配置方式。blog

FPGA'的三種配置模式文檔

模式 描述
AS(Active serial)模式 FPGA主動配置。該模式由FPGA主動從外部儲存器讀取配置數據
PS(Passive serial)模式 FPGA被動控制。該模式由外部控制器對FPGA進行配置
JTAG模式 經過外部下載器下載到FPGA內部SRAM中

FPGA選擇配置模式get

經過MSEL0MSEL1引腳不一樣的電平來選擇配置方式(若是使用JTAG配置則能夠忽略這些引腳配置)it

MSEL1 MSEL0 模式
0 0 AS
0 1 PS
x x JTAG

最終肯定的方案是使用PS模式經過MCU來升級、配置FPGA。下面主要講使用MCU對FPGA進行PS模式下的配置過程。table

PS模式配置引腳時序class

  • 發起配置請求
    • nCONFIG引腳拉低tCFG時間而後拉高,等待nSTATU拉低響應請求
  • 進行配置
    • FPGA在DCLK引腳的上升沿採集DATA引腳Bit數據,LSB在前傳輸方式
  • 配置完成
    • 等待CONF_DONE引腳迴應一個高電平表示配置完成

PS配置模式時序參數pdf

三、功能實現

配置FPGA用到的變量和標誌

static uint8_t fpga_cfg_buf[W25Q_SECTOR_SIZE]; //儲存從FLASH讀出數據
static __IO uint8_t fpga_cfg_sta = 0x00;       //記錄配置狀態
//配置過程用到的標識
enum
{
    FPGA_CFG_ENABLE	= 0x01,	
    FPGA_CFG_START	= 0x02,	
    FPGA_CFG_DONE	= 0x04,
    FPGA_CFG_OVER	= 0x08,
};

MCU與FPGA鏈接引腳配置

/*
**********************************************************************
*    函 數: fpga_config_init
*    功 能: 配置FPGA引腳
*    輸 入: 無
*    輸 出: 無
**********************************************************************
*/
void fpga_config_init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    /* 引腳時鐘使能 */
    FPGA_PIN_CLK_ENABLE();
    /* nCFG、DAT、CLK配置爲輸出 */
    GPIO_InitStruct.Pin 	= FPGA_nCFG_PIN;
    GPIO_InitStruct.Mode 	= GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull 	= GPIO_NOPULL;
    GPIO_InitStruct.Speed 	= GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(FPGA_nCFG_PORT, &GPIO_InitStruct);
    GPIO_InitStruct.Pin 	= FPGA_DAT_PIN;
    HAL_GPIO_Init(FPGA_DAT_PORT, &GPIO_InitStruct);
    GPIO_InitStruct.Pin 	= FPGA_CLK_PIN;
    HAL_GPIO_Init(FPGA_CLK_PORT, &GPIO_InitStruct);
    /* nSTA、CFG_DONE配置爲輸入 */
    GPIO_InitStruct.Pin 	= FPGA_nSTA_PIN;
    GPIO_InitStruct.Mode 	= GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull 	= GPIO_NOPULL;
    HAL_GPIO_Init(FPGA_nSTA_PORT, &GPIO_InitStruct);
    GPIO_InitStruct.Pin 	= FPGA_CFG_DONE_PIN;
    HAL_GPIO_Init(FPGA_CFG_DONE_PORT, &GPIO_InitStruct);
    /* 配置引腳默認狀態 */
    HAL_GPIO_WritePin(FPGA_nCFG_PORT, FPGA_nCFG_PIN, GPIO_PIN_SET);
    HAL_GPIO_WritePin(FPGA_DAT_PORT, FPGA_DAT_PIN, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(FPGA_CLK_PORT, FPGA_CLK_PIN, GPIO_PIN_RESET);
}

MCU對FPGA配置過程

/*
**********************************************************************
*    函 數: fpga_config_process
*    功 能: FPGA程序配置
*    輸 入: _uiDataSize:FPGA配置文件大小
*          _uiStartAddr:FLASH儲存FPGA配置文件地址
*    輸 出: 失敗:< 0; 成功:0
**********************************************************************
*/
int fpga_config_process(uint32_t _uiDataSize, uint32_t _uiStartAddr)
{
    UINT interrupt_save;
    uint16_t i, j;
    uint32_t uiTout, uiRdAddr, uiCnt = 0;
	
    fpga_cfg_sta = 0;
    uiRdAddr = _uiStartAddr; 
    
    /*############## 第一階段:發起配置請求 ########################*/
    FPGA_PinWrite(FPGA_nCFG_PORT,FPGA_nCFG_PIN,GPIO_PIN_RESET);
    dwt_delay_us(100);
    FPGA_PinWrite(FPGA_nCFG_PORT,FPGA_nCFG_PIN,GPIO_PIN_SET);
    dwt_delay_us(40);
    /* 等待FPGA迴應:100ms超時 */
    for (uiTout = 0; uiTout < 10000; uiTout++)
    {
        if (GPIO_PIN_RESET == FPGA_PinRead(FPGA_nSTA_PORT,FPGA_nSTA_PIN))
        {
            SET_BIT(fpga_cfg_sta, FPGA_CFG_START);
            break;
        }
        dwt_delay_us(10);
    }
    /* 是否響應? */
    if (!READ_BIT(fpga_cfg_sta, FPGA_CFG_START))
    {
        return -1;
    }
    
    /*############## 第二階段:進行配置 ########################*/
    do{
        W25Q_ReadBuffer(fpga_cfg_buf, uiRdAddr, W25Q_SECTOR_SIZE);
        uiRdAddr += W25Q_SECTOR_SIZE;
        for (i = 0; i < W25Q_SECTOR_SIZE; i++)
        {
            /* 按bit寫入,LSB在前 */
            DISABLE_IRQ();
            for (j = 0; j < 8; j++)
            {
                if (fpga_cfg_buf[i] & 0x01) 
                {
                    FPGA_PinWrite(FPGA_DAT_PORT,FPGA_DAT_PIN,GPIO_PIN_SET);
                } 
                else 
                {
                    FPGA_PinWrite(FPGA_DAT_PORT,FPGA_DAT_PIN,GPIO_PIN_RESET);
                }
                FPGA_PinWrite(FPGA_CLK_PORT,FPGA_CLK_PIN,GPIO_PIN_RESET); Delay(2);
                FPGA_PinWrite(FPGA_CLK_PORT,FPGA_CLK_PIN,GPIO_PIN_SET);	  Delay(2);
                FPGA_PinWrite(FPGA_CLK_PORT,FPGA_CLK_PIN,GPIO_PIN_RESET); Delay(2);

                fpga_cfg_buf[i] >>= 1;
            }
            ENABLE_IRQ();

            /* 數據寫入完畢退出 */
            if (++uiCnt >= _uiDataSize) 
            {
                SET_BIT(fpga_cfg_sta, FPGA_CFG_OVER);
                break;
            }
        }
    }while(RESET == READ_BIT(fpga_cfg_sta, FPGA_CFG_OVER));
	
    /*############## 第三階段:等待配置完成迴應 ########################*/
    for (i = 0, uiTout = 0; uiTout < 20000; uiTout++)
    {
        dwt_delay_us(100);
        if (GPIO_PIN_SET == FPGA_PinRead(FPGA_CFG_DONE_PORT,FPGA_CFG_DONE_PIN))
        {
            if (++i >= 10)
            {
                SET_BIT(fpga_cfg_sta, FPGA_CFG_DONE);
                break;
            }
        }
        else
        {
            i = 0;
        }
    }

    if (READ_BIT(fpga_cfg_sta, FPGA_CFG_DONE))
    {
        return 0;
    }
    else
    {
        return -1;
    }
}
相關文章
相關標籤/搜索