| **银杏科技有限公司旗下技术文档发布平台** |||| |技术支持电话|**0379-69926675-801**||| |技术支持邮件|Gingko@vip.163.com||| ^ 版本 ^ 日期 ^ 作者 ^ 修改内容 ^ | V1.0 | 2020-03-03 | gingko | 初次建立 | \\ \\ \\ ===== STM32CubeMX教程十九——SD_IAP_FPGA实验 ===== \\ 1.在主界面选择File-->New Project 或者直接点击ACCEE TO MCU SELECTOR。 {{ :icore4t:icore4t_cube_19_1.png?direct |}} 2.出现芯片型号选择,搜索自己芯片的型号,双击型号,或者点击Start Project进入配置。 在搜索栏的下面,提供的各 种查找方式,可以选择芯片内核,型号,等等,可以帮助你查找芯片。本实验选取的芯片型号为:STM32H750IBKx。 {{ :icore4t:icore4t_cube_19_2.png?direct |}} 3.配置RCC,使用外部时钟源。 {{ :icore4t:icore4t_cube_19_3.png?direct |}} 4.时基源选择SysTick。 {{ :icore4t:icore4t_cube_19_4.png?direct |}} 5.将PA10,PB7,PB8设置为GPIO_Output。 {{ :icore4t:icore4t_cube_19_5.png?direct |}} 6.引脚模式配置。 {{ :icore4t:icore4t_cube_19_6.png?direct |}} {{ :icore4t:icore4t_cube_19_7.png?direct |}} 7.设置串口。 {{ :icore4t:icore4t_cube_19_8.png?direct |}} 8.在NVIC Settings一栏使能接收中断。 {{ :icore4t:icore4t_cube_19_9.png?direct |}} 9.配置SDMMC1。 {{ :icore4t:icore4t_cube_19_10.png?direct |}} 10.配置FATFS。 {{ :icore4t:icore4t_cube_19_11.png?direct |}} {{ :icore4t:icore4t_cube_19_12.png?direct |}} 11.时钟源设置,选择外部高速时钟源,配置为最大主频。 {{ :icore4t:icore4t_cube_19_13.png?direct |}} {{ :icore4t:icore4t_cube_19_14.png?direct |}} 12.工程文件的设置, 这里就是工程的各种配置 我们只用到有限几个,其他的默认即可 IDE我们使用的是 MDK V5.27。 {{ :icore4t:icore4t_cube_19_15.png?direct |}} 13.点击Code Generator,进行进一步配置。 {{ :icore4t:icore4t_cube_19_16.png?direct |}} * **Copy all used libraries into the project folder** * **将HAL库的所有.C和.H都复制到所建工程中** * 优点:这样如果后续需要新增其他外设又可能不再用STM32CubeMX的时候便会很方便。 * 缺点:体积大,编译时间很长。 * **Copy only the necessary library files** * **只复制所需要的.C和.H(推荐)** * 优点:体积相对小,编译时间短,并且工程可复制拷贝。 * 缺点:新增外设时需要重新用STM32CubeMX导入。 * **Add necessary library files as reference in the toolchain project configuration file** * **不复制文件,直接从软件包存放位置导入.C和.H** * 优点:体积小,比较节约硬盘空间。 * 缺点:复制到其他电脑上或者软件包位置改变,就需要修改相对应的路径。 * 自行选择方式即可。 14.然后点击GENERATE CODE 创建工程。 {{ :icore4t:icore4t_cube_19_17.png?direct |}} 创建成功,打开工程。 \\ \\ ===== 实验十九:SD_IAP_FPGA实验——更新升级FPGA ===== ==== 一、 实验目的与意义 ==== - 了解FPGA PS配置方式。 - 掌握SD卡使用方法。 - 掌握FATFS使用方法。 - 掌握KEILMDK 集成开发环境使用方法。 ==== 二、 实验设备及平台 ==== - iCore4T 双核心板。[[https://item.taobao.com/item.htm?spm=a1z10.1-c.w137644-251734891.3.5923532fDrMDOe&id=610595120319|点击购买]] - JLINK(或相同功能)仿真器。[[https://item.taobao.com/item.htm?id=554869837940|点击购买]] - Micro USB线缆。 - SD卡。 - Keil MDK 开发平台。 - STM32CubeMX开发平台。 - 装有WIN XP(及更高版本)系统的计算机。 ==== 三、 实验原理 ==== === 1.IAP简介 === * IAP是In Application Programming的首字母缩写,IAP是用户自己的程序在运行过程中对User Flash的部分区域进行烧写,目的是为了在产品发布后可以方便地通过预留的通信口对产品中的固件程序进行更新升级。 * 在应用编程IAP(In-Application Programming)是应用在Flash程序存储器的一种编程模式。它可以在应用程序正常运行的情况下,通过调用特定的IAP程序对另外一段程序Flash空间进行读/写操作,甚至可以控制对某段、某页甚至某个字节的读/写操作,这为数据存储和固件的现场升级带来了更大的灵活性。 * 通常在用户需要实现IAP功能时,即用户程序运行中作自身的更新操作,需要在设计固件程序时编写两个项目代码,第一个项目程序不执行正常的功能操作,而只是通过某种通信管道(如USB、USART)接收程序或数据,执行对第二部分代码的更新;第二个项目代码才是真正的功能代码。这两部分项目代码都同时烧录在User Flash中,当芯片上电后,首先是第一个项目代码开始运行,它作如下操作: * 1.检查是否需要对第二部分代码进行更新; * 2.如果不需要更新则转到4; * 3.执行更新操作; * 4.跳转到第二部分代码执行 * 第一部分代码必须通过其它手段,如JTAG或ISP烧入;第二部分代码可以使用第一部分代码IAP功能烧入,也可以和第一部分代码一道烧入,以后需要程序更新是再通过第一部分IAP代码更新。 === 2.FPGA PS配置方式介绍 === * FPGA器件有三类配置下载方式:主动配置方式(AS)和被动配置方式(PS)和最常用的(JTAG)配置方式。 * AS模式(active serial configuration mode):FPGA器件每次上电时作为控制器,由FPGA器件引导配置操作过程,它控制着外部存储器和初始化过程,从配置器件EPCS主动发出读取数据信号,从而把EPCS的数据读入FPGA中,实现对FPGA的编程配置数据通过DATA0引脚送入 FPGA,配置数据被同步在DCLK输入上,1个时钟周期传送1位数据。 * PS模式(passive serial configuration mode):则由外部计算机或控制器控制配置过程。通过加强型配置器件(EPC16,EPC8,EPC4)等配置器件来完成,EPCS作为控制器件,把FPGA当作存储器,把数据写人到FPGA中,实现对FPGA的编程。该模式可以实现对FPGA在线可编程。对于FPGA器件来说,在下载配置的时候,不同的下载配置对应不同的文件格式;JTAG下载方式对应.sof,AS下载方式对应.jic。 * JTAG下载方式:JTAG是直接将编译文件烧录到FPGA里面的 由于是SRAM,断电后要重新烧录,AS是将文件下载到FPGA的配置芯片里保存的,每次上电就写到FPGA里。 * 在PS方式下,FPGA处于完全被动的地位。FPGA接收配置时钟、配置命令和配置数据,给出配置的状态信号以及配置完成指示信号等。PS配置可以使用altera的配置器件(EPC1、EPC4等),可以使用系统中的微处理器,也可以使用单板上的CPLD,或者altera的下载电缆,不管配置的数据源从哪里来,只要可以模拟出FPGA需要的配置时序来,将配置数据写入FPGA就可以。 * 在上电以后,FPGA会在nCONFIG管脚上检测到一个从低到高的跳变沿,因此可以自动启动配置过程。 === 3.FPGA PS具体配置 === * **时序图:** {{ :icore4t:icore4t_arm_hal_19_1.png?direct |}} * 首先CPU需要利用5个I/O脚与FPGA相连,从而实现了PS模式的硬件连接。 {{ :icore4t:icore4t_arm_hal_19_2.png?direct |}} * CPU按下列步骤操作I/O口线,即可完成对FPGA的配置: * 1:nCONFIG="0"、DCLK="0",保持2μS以上。 * 2:检测nSTATUS,如果为"0",表明FPGA已响应配置要求,可开始进行配置。否则报错。正常情况下,nCONFIG="0"后1μS内nSTATUS将为"0"。 * 3:nCONFIG="1",并等待5μS。 * 4:Data0上放置数据(LSB first),DCLK="1",延时。 * 5:DCLK="0",并检测nSTATUS,若为"0",则报错并重新开始。 * 6:准备下一位数据,并重复执行步骤4、5,直到所有数据送出为止。 * 7:此时Conf_done应变成"1",表明FPGA的配置已完成。如果所有数据送出后,Conf_done不为"1",必须重新配置(从步骤1开始) * 8:配置完成后,再送出40个周期的DCLK,以使FPGA完成初始化。 * 在本实验中,因FPGA具有远程升级功能(PS 模式),STM32程序在运行的过程中可以实现对 FPGA 进行程序烧写,以此实现对产品中的固件进行更新升级。实验中SD 卡实现虚拟 U 盘,用来存放升级 FPGA 的文件。 {{ :icore4t:icore4t_arm_hal_19_3.png?direct |}} ==== 四、 实验程序 ==== === 1.主函数 === int main(void) { FATFS fatfs; static FRESULT res; HAL_Init(); SystemClock_Config(); i2c.initialize(); axp152.initialize(); axp152.set_dcdc1(3500);//[ARM & FPGA BK1/2/6 &OTHER] axp152.set_dcdc2(1200);//[FPGA INT & PLL D] axp152.set_aldo1(2500);//[FPGA PLL A] axp152.set_dcdc4(3300);//[POWER_OUTPUT] axp152.set_dcdc3(3300);//[FPGA BK4][Adjustable] axp152.set_aldo2(3300);//[FPGA BK3][Adjustable] axp152.set_dldo1(3300);//[FPGA BK7][Adjustable] axp152.set_dldo2(3300);//[FPGA BK5][Adjustable] MX_GPIO_Init(); MX_USART2_UART_Init(); MX_SDMMC1_SD_Init(); MX_FATFS_Init(); usart2.initialize(115200); //串口波特率设置 usart2.printf("\x0c"); //清屏 usart2.printf("\033[1;32;40m"); //设置终端字体为绿色 usart2.printf("Hello,I am iCore4T!\r\n\r\n"); //串口信息输出 LED_ON; //FPGA PS fpga_ps.initialize();//FPGA PS模式初始化 usart2.printf("\033[1;32;40m"); //显示绿色 usart2.printf("*Try config fpga from TF Card......\r\n"); if(BSP_SD_Init() != MSD_OK){//判断SD卡是否初始化 usart2.printf("*TF Card error!\r\n"); while (1){ } }else{ usart2.printf("*FPGA Is Updating......\r\n"); } HAL_Delay(500); res = f_mount(&fatfs,"0",1);//挂载SD卡 if(res != RES_OK){ usart2.printf("*f_mount error!\r\n");//挂载失败 } if(fpga_ps.from_tf() == 0){//通过from_tf函数返回值0,判断升级是否成功 usart2.printf("*Update Completed!\r\n"); } while (1) { } } === 2.FPGA PS模式初始化函数,配置各引脚 === static int initialize(void) { GPIO_InitTypeDef GPIO_InitStruct; //初始化PS配置引脚 __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOD_CLK_ENABLE(); __HAL_RCC_GPIOI_CLK_ENABLE(); //PS_DATA0<--->PI8 //PS_DCLK<--->PI4 GPIO_InitStruct.Pin = GPIO_PIN_4 | GPIO_PIN_8; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; HAL_GPIO_Init(GPIOI, &GPIO_InitStruct); //PS_NCONFIG<--->PC6 GPIO_InitStruct.Pin = GPIO_PIN_6; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); //nSTATUS<--->PD4 //CONFDONE<--->PC13 GPIO_InitStruct.Pin = GPIO_PIN_13; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_4; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); return 0; } === 3.PS模式下传输文件,完成固件更新 === static int ps(FIL *f) { int i; int k; unsigned int counter; unsigned long int ncounter = 0; unsigned char buffer[1024]; FRESULT res; FILINFO finfo; //进入PS模式 NCONFIG_OFF; DCLK_OFF; for(i = 0; i < 5000; i++); if(NSTATUS == 1){//判断FPGA是否已响应配置要求 usart2.printf("\r\n*fpga error!\r\n"); return -1; } for(i = 0;i < 40;i++); NCONFIG_ON; for(i = 0; i < 40; i++); f_stat ("0:/spi.rbf",&finfo); //获取文件状态 while(ncounter < finfo.fsize) { res = f_read(f,buffer,1024,&counter); //读取文件 if(res != RES_OK){ usart2.printf("\r\n*f_read error!\r\n"); return -1; } for(k = 0; k < counter; k++) { for(i = 0; i < 8; i++) { if(buffer[k]&0x01)DATA0_ON; else DATA0_OFF; DCLK_ON; buffer[k] >>= 1; DCLK_OFF; } ncounter++; } } if(CONFIG_DONE == 0){ usart2.printf("\r\n*config error!\r\n"); return -1; } for(i = 0; i < 40; i++) { DCLK_ON; for(i = 0; i < 800; i++);//delay 100us DCLK_OFF; for(i = 0; i < 800; i++);//delay 100us } return 0;//返回成功标志 } === 4.FATFS函数介绍 === FRESULT f_mount ( //挂载/卸载逻辑驱动器 FATFS* fs, /* 指向文件系统对象的指针*/ const TCHAR* path, /* 要安装/卸载的逻辑驱动器号 */ BYTE opt /* 模式选项0:不安装(延迟安装),1:立即安装*/ ) FRESULT f_open ( //打开或创建文件 FIL* fp, /* 指向空白文件对象的指针 */ const TCHAR* path, /* 指向文件名的指针 */ BYTE mode /* 访问模式和文件打开模式标志 */ ) FRESULT f_write ( //写文件 FIL* fp, /* 指向文件对象的指针 */ const void* buff, /* 指向要写入的数据的指针 */ UINT btw, /* 要写入的字节数 */ UINT* bw /* 指向写入字节数的指针 */ ) FRESULT f_sync ( //冲洗一个写文件的缓存信息 FIL* fp /* 指向文件对象的指针 */ ) FRESULT f_close ( //关闭一个文件 FIL* fp /* 指向要关闭的文件对象的指针 */ ) FRESULT f_lseek ( //移动文件读/写指针 FIL* fp, /* 指向文件对象的指针 */ FSIZE_t ofs /* 指向文件头的指针 */ ) FRESULT f_opendir ( //创建目录对象 DIR* dp, /* 指向要创建的目录对象的指针 */ const TCHAR* path /* 指向目录路径的指针 */ ) FRESULT f_closedir ( // 关闭目录 DIR *dp /* 指向要关闭的目录对象的指针 */ ) FRESULT f_readdir ( //顺序读取目录条目 DIR* dp, /* 指向打开目录对象的指针 */ FILINFO* fno /* 指向要返回的文件信息的指针 */ ) FRESULT f_stat ( //获取文件状态 const TCHAR* path, /* 指向文件路径的指针 */ FILINFO* fno /* 指向要返回的文件信息的指针 */ ) FRESULT f_getfree ( //获取空闲簇数 const TCHAR* path, /* 逻辑驱动器号的路径名 */ DWORD* nclst, /* 指向变量的指针以返回空闲簇的数量*/ FATFS** fatfs /* 返回指向相应文件系统对象的指针的指针 */ ) FRESULT f_truncate ( //截断文件 FIL* fp /* 指向文件对象的指针 */ ) FRESULT f_unlink ( //删除一个文件或目录 const TCHAR* path /* 指向文件或目录路径的指针 */ ) FRESULT f_mkdir ( //创建一个目录 const TCHAR* path /* 指向目录路径的指针 */ ) FRESULT f_rename ( //重命名文件/目录 const TCHAR* path_old, /* 指向要重命名的对象名称的指针 */ const TCHAR* path_new /* 指向新名称的指针 */ ) ==== 五、 实验步骤 ==== - 将升级文件拷贝到SD卡system文件夹下; - 把仿真器与iCore4T的SWD调试口相连(直接相连或者通过转接器相连); - 把iCore4T通过Micro USB线与计算机相连,为iCore4T供电; - 打开PuTTY串口终端; - 打开Keil MDK 开发环境,并打开本实验工程; - 烧写程序到iCore4T上; - 也可以进入Debug 模式,单步运行或设置断点验证程序逻辑。 ==== 六、 实验现象 ==== * FPGA升级成功,则终端显示“Update Completed!”,如果升级失败,将会显示“error!”。