做者: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
經過MSEL0
和MSEL1
引腳不一樣的電平來選擇配置方式(若是使用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; } }