做者: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; } }