STM32给FPGA的外挂FLASH进行升级

STM32给FPGA的外挂FLASH进行升级

      • 一、电路方案设计
      • 二、软件写FLASH
      • 三、解决第一次烧录后FPGA无法启动的问题

前言:
一个复杂的嵌入式中,如果对某些实时性要求极高的情况下势必会使用到FPGA来保证,这里面牵扯到给FPGA的程序升级问题,一般采用负责逻辑处理的一个MCU来完成,实际就是对存储FPGA的这个flash进行读写操作。

一、电路方案设计

1、FLASH的(MOSI/MISO/CLK/CS)既要连接FPGA又要连接STM32,所以要设计一个单刀双置的开关。(注意:FLASH_D2和FLASH_D3是直接接入FPGA的,因为FPGA需要使用flash的四线模式)
在这里插入图片描述

二、软件写FLASH

1、mx25l.c

#include <stdio.h>
#include "mx25l.h"/******************************************************* @brief  SPI写数据* @param  data 要写入mx25l的数据 * @retval 返回一个字节
******************************************************/
uint8_t SPI1_WriteByte(uint8_t data)
{	//等待发送完成while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);//发送数据SPI_I2S_SendData(SPI1, data);//等待接收完成while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);return SPI_I2S_ReceiveData(SPI1);	
}/******************************************************* @brief  SPI读数据* @param  空* @retval 返回读取到的字节
******************************************************/
uint8_t SPI1_ReadByte(void)
{return(SPI1_WriteByte(0xff));
}/********************************* @brief  mx25l的写使能* @param  None* @retval None******************************/
void Write_enable(void)
{//CS=0, 选中芯片FLASH_CS_L();//MCU发送写使能命令0x06	SPI_SendbyteSPI1_WriteByte(0x06);//CS=1;//释放芯片FLASH_CS_H();
}/********************************* @brief  mx25l的写失能* @param  None* @retval None******************************/
void Write_disable(void)
{//CS=0, 选中芯片FLASH_CS_L();//MCU发送写失能命令0x04	SPI_SendbyteSPI1_WriteByte(0x04);//CS=1;//释放芯片FLASH_CS_H();
}/***************************************** @brief  读mx25l状态寄存器* @param  None* @retval None**************************************/
void Read_ststus(void)
{u8 sta=0;//接收状态寄存器的值//CS=0;//选中芯片FLASH_CS_L();//MCU发送读状态命令	0x05SPI1_WriteByte(0x05);do{sta = SPI1_ReadByte();}while((sta&(1<<0))==1);//CS=1;//释放芯片FLASH_CS_H();
}
#if 0
u8 SPI_Flash_ReadSR(void)   
{  u8 byte=0;   FLASH_CS_L();                          //使能器件   SPI1_WriteByte(0x05);              //发送读取状态寄存器命令    byte=SPI1_ReadByte();         //读取一个字节  FLASH_CS_H();                          //取消片选     return byte;   
} 
void SPI_Flash_Wait_Busy(void)  
{   while ((SPI_Flash_ReadSR()&0x01)==0x01);   // 等待WIP位清空
} 
#endif/************************************************************************** @brief  写mx25l状态寄存器QEbit,防止空板第一次下载程序FPGA无法启动现象* @param  None* @retval None************************************************************************/
void QEBit_Set(void)
{u8 sta=0; // 接收状态寄存器的值//写使能Write_enable();//CS=0;//选中芯片FLASH_CS_L();//MCU发送读状态命令	0x05SPI1_WriteByte(0x05);sta = SPI1_ReadByte();//CS=1;//释放芯片FLASH_CS_H();sta |= 0x40;//CS=0;//选中芯片FLASH_CS_L();//MCU发送写状态命令	0x01SPI1_WriteByte(0x01);SPI1_WriteByte(sta);//CS=1;//释放芯片FLASH_CS_H();Write_disable();
}/***************************************************** @brief  MCU 写数据到 mx25l* @param  addr 24位地址* @param  data 要写入的数据* @retval None* @attention 写数据之前一定要擦除芯片**************************************************/
void Mx25l_WriteByte(uint32_t addr, uint8_t data)
{	//打开写使能Write_enable();//CS=0;//选中芯片FLASH_CS_L();//MCU发送页编程命令  0x02SPI1_WriteByte(0x02);//发送24位地址SPI1_WriteByte((u8)(addr>>16));SPI1_WriteByte((u8)(addr>>8));SPI1_WriteByte((u8)(addr));//MCU发送写入的数据SPI1_WriteByte(data);//CS=1;//释放芯片FLASH_CS_H();//读状态Read_ststus();
}/***************************************************** @brief  MCU页写数据到 mx25l* @param  pBuffer  要写的数组* @param  addr     24位地址* @param  Nb_bytes 要写入的数据长度* @retval None* @attention       写数据之前一定要擦除芯片**************************************************/
void Mx25l_Write_Page(u8* pBuffer, u32 addr, u16 Nb_bytes)
{u16 i;  Write_enable(); //SET WEL FLASH_CS_L(); //使能器件   SPI1_WriteByte(0x02); //发送写页命令   SPI1_WriteByte((u8)(addr>>16)); //发送24bit地址    SPI1_WriteByte((u8)(addr>>8));   SPI1_WriteByte((u8)(addr));   for(i=0; i<Nb_bytes; i++){SPI1_WriteByte(pBuffer[i]); //循环写数  }FLASH_CS_H(); //取消片选 Read_ststus();	//等待写入结束
} /***************************************************** @brief  MCU 无校验写数据到 mx25l* @param  pBuffer  要写的数组* @param  addr     24位地址* @param  Nb_bytes 要写入的数据长度* @retval None* @attention       写数据之前一定要擦除芯片**************************************************/
void Mx25l_Write_NoCheck(u8* pBuffer,u32 addr,u16 Nb_bytes)   
{ 			 		 u16 PageRemain;	   PageRemain = 256 - addr%256; //单页剩余的字节数		if(Nb_bytes <= PageRemain) { //不大于256个字节Mx25l_Write_Page(pBuffer, addr, Nb_bytes); }else {Mx25l_Write_Page(pBuffer, addr, PageRemain);addr += PageRemain;Mx25l_Write_Page(pBuffer+PageRemain, addr, Nb_bytes-PageRemain);}	    
} /******************************************************** @brief  MCU从 mx25l 读数据* @param  addr 24位地址* @param  data 存放读出的数据* @param  size 要读的字节长度(不要太大,否则RAM承受不了)* @retval None*****************************************************/
void Mx25l_Read_data(u32 addr, u8 *data, u32 size)
{uint32_t i=0;//接收数据的循环变量//CS=0;//选中芯片FLASH_CS_L();//MCU发送读数据命令  0x03SPI1_WriteByte(0x03);//MCU发送开始读的地址SPI1_WriteByte((u8)(addr>>16));SPI1_WriteByte((u8)(addr>>8));SPI1_WriteByte((u8)(addr));//MCU接收数据for(i=0; i<size; i++){data[i] = SPI1_ReadByte();}//CS=1;//释放芯片FLASH_CS_H();  
}/******************************************************************* @brief  Sector Write* @param  nSector 第几个扇区* @param  pBuffer 数据* @retval None*****************************************************************/
void Mx25l_Write_Sector(uint32_t nSector, uint8_t* pBuffer)
{	int i,j;//扇区号转为地址nSector *= FLASH_SECTOR_SIZE;//一个扇区需要几个页for(j=0; j<FLASH_PAGES_PER_SECTOR; j++){Write_enable();                  //SET WELFLASH_CS_L();SPI1_WriteByte(0x02);SPI1_WriteByte((nSector >> 16) & 0xff);SPI1_WriteByte((nSector >> 8) & 0xff);SPI1_WriteByte(nSector & 0xff);for(i=0; i<FLASH_PAGE_SIZE; i++){		SPI1_WriteByte(pBuffer[i]);}pBuffer += FLASH_PAGE_SIZE;nSector += FLASH_PAGE_SIZE;FLASH_CS_L();Read_ststus();}
}/******************************************************************* @brief  Sector Read* @param  nSector 第几个扇区* @param  pBuffer 存放数据* @retval None*****************************************************************/
void Mx25l_Read_Sector(uint32_t nSector, u8* pBuffer)
{	uint16_t i;//扇区号转为地址nSector *= FLASH_SECTOR_SIZE;FLASH_CS_L();SPI1_WriteByte(0x03);SPI1_WriteByte((u8)(nSector >> 16));SPI1_WriteByte((u8)(nSector >> 8));SPI1_WriteByte((u8)(nSector));for(i=0;i<FLASH_SECTOR_SIZE;i++){	pBuffer[i] = SPI1_ReadByte();//usb_printf("%02x, ", pBuffer[i]);}FLASH_CS_L();Read_ststus();
}/******************************** @brief  擦除整个芯片* @param  None* @retval None*****************************/
void Chip_erase(void)
{//printf("chip erase starting...\r\n");Write_enable();//CS=0;//选中芯片FLASH_CS_L();//MCU发送芯片擦除命令  0x60SPI1_WriteByte(0x60);//CS=1;//释放芯片FLASH_CS_H();//读状态Read_ststus();//printf("chip erase complete...\r\n");
}

2、mx25l.h

#ifndef  _MX25L_H_
#define  _MX25L_H_#include "stm32f10x.h"
#include "stm32f10x_spi.h"#define FLASH_PAGE_SIZE		256
#define FLASH_SECTOR_SIZE	4096
#define FLASH_SECTOR_COUNT	4096
#define FLASH_BLOCK_SIZE	65536
#define FLASH_PAGES_PER_SECTOR	FLASH_SECTOR_SIZE/FLASH_PAGE_SIZE
#define FLASH_CS_H()        GPIO_SetBits(GPIOA, GPIO_Pin_4)
#define FLASH_CS_L()        GPIO_ResetBits(GPIOA, GPIO_Pin_4)
uint8_t SPI1_WriteByte(uint8_t data);
uint8_t SPI1_ReadByte(void);
void Write_enable(void);
void Write_disable(void);
void Read_ststus(void);
void QEBit_Set(void);
void Mx25l_WriteByte(uint32_t addr,uint8_t data);
void Mx25l_Write_Page(u8* pBuffer, u32 addr, u16 Nb_bytes);
void Mx25l_Write_NoCheck(u8* pBuffer,u32 addr,u16 Nb_bytes);
void Mx25l_Read_data(uint32_t addr, uint8_t *data, uint32_t size);
void Mx25l_Write_Sector(uint32_t nSector, uint8_t* pBuffer);
void Mx25l_Read_Sector(uint32_t nSector, u8* pBuffer);
void Chip_erase(void);#endif

三、解决第一次烧录后FPGA无法启动的问题

1、这个问题的原因是因为FPGA编译使用的flash是4线模式,而flash默认是1线模式,所以升级完之后调用QEBit_Set();配饰flash为4线模式。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/86952.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/86952.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python 数据分析与可视化 Day 9 - 缺失值与异常值处理技巧

✅ 今日目标 熟练处理数据中的缺失值&#xff08;NaN、None&#xff09;学会识别和处理异常值&#xff08;outliers&#xff09;掌握常用的处理方法&#xff1a;填充、删除、替换、标准差法、箱型图法等为后续机器学习建模打好数据清洗基础 &#x1f4da; 一、缺失值处理&…

概述-1-数据库的相关概念

数据库的相关概念 用户通过SQL操作数据库管理系统&#xff0c;再通过数据库管理系统操作数据库以及数据库中的数据。 数据库 数据库是存储数据的仓库, 数据是有组织的进行存储, DataBase简称&#xff08;DB&#xff09; 数据库管理系统 操纵和管理数据库的大型软件, DataB…

可视化大屏展示

可视化大屏是一种将大量数据进行整合、分析&#xff0c;并以直观、形象的可视化方式展示在大屏幕上的信息展示系统。主要组成部分分为2个&#xff1a;硬件设备、软件系统。 一、大屏价值 1、数据可视化&#xff1a;将复杂的数据转化为直观的图形、图表和地图等&#xff0c;使数…

服务器被入侵的常见迹象有哪些?

&#x1f6a8; 服务器被入侵的常见迹象 &#x1f7e2; 一、系统和资源异常 CPU、内存或网络流量异常飙高 即使没有业务负载&#xff0c;资源长期占满。 磁盘空间突然被写满 可疑大文件或日志暴涨。 系统负载显著升高 uptime、top 显示 load average 异常。 &#x1f7e1;…

日本生活:日语语言学校-日语作文-沟通无国界(5)-题目:我的一天

日本生活&#xff1a;日语语言学校-日语作文-沟通无国界&#xff08;5&#xff09;-题目&#xff1a;我的一天 1-前言2-作文原稿3-作文日语和译本&#xff08;1&#xff09;日文原文&#xff08;2&#xff09;对应中文&#xff08;3&#xff09;对应英文 4-老师评语5-自我感想&…

前端领域的技术热点与深度解析

&#x1f525; 一、框架革新&#xff1a;React、Vue、Svelte 的进化方向 React 19 实验版 Server Components 深化&#xff1a;支持流式渲染与异步状态管理&#xff0c;SSR 性能提升40%。 并发模式优化&#xff1a;减少渲染阻塞&#xff0c;复杂交互场景延迟降低35%。 Vue 3…

【unity游戏开发——网络】网络游戏通信方案——强联网游戏(Socket长连接)、 弱联网游戏(HTTP短连接)

注意&#xff1a;考虑到热更新的内容比较多&#xff0c;我将热更新的内容分开&#xff0c;并全部整合放在【unity游戏开发——网络】专栏里&#xff0c;感兴趣的小伙伴可以前往逐一查看学习。 文章目录 一、联网游戏类型划分二、核心通信协议对比三、开发选择指南专栏推荐完结 …

Java-60 深入浅出 分布式服务Paxos 算法优化 如何保证Paxos算法的活性

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月16日更新到&#xff1a; AI炼丹日志-29 - 字节…

一阶线性双曲型偏微分方程组的特征值与通解分析

问题3 求系统 U u + A U x = 0 U_u + A U_x = 0 Uu​+AUx​=0 的特征并写出通解,其中矩阵 A A A 如下: A 1 = ( 3 2 1 0 2 1 0 0 1 ) , A 2 = ( 3 2 1 0 2 1 0 0 − 1 ) , A_1 = \begin{pmatrix} 3 & 2 & 1 \\ 0 & 2 & 1 \\ 0 & 0 & 1 \end{pmatr…

解锁AI无限潜能!景联文科技数据产品矩阵再升级:多语言题库、海量语料、垂域代码库,全面赋能大模型训练

景联文科技持续聚焦AI数据需求前沿&#xff0c;全新发布包含中文题库数据集、英文题库数据集、算法代码数据库、英文语料、中文语料、垂直领域数据、小语种数据在内的七大高质量数据集产品系列。 此次发布的数据集覆盖广泛的应用场景&#xff0c;通过严格的清洗与结构化处理&am…

OSPF(开放最短路径优先)

一、ospf简介 OSPF是基于链路状态的内部网关协议&#xff0c;与距离矢量协议不同&#xff0c;链路状态协议通告的是链路状态而不是路由表。OSPF是用于自治系统&#xff08;AS&#xff09;内部的路由决策,特点有&#xff0c;收敛速度快&#xff0c;安全性好&#xff0c;避免环路…

全面拥抱vue3

Vue 3 性能全面解析&#xff1a;为何性能飞跃提升 Vue 3 在性能方面实现了质的飞跃&#xff0c;相比 Vue 2 在多个维度都有显著提升。以下是 Vue 3 性能优化的全面解析&#xff1a; 一、核心架构优化 1. 响应式系统重写&#xff08;Proxy 替代 defineProperty&#xff09; …

C#最佳实践:考虑为类重写ToString()方法

C#最佳实践:考虑为类重写ToString()方法 在 C# 编程的日常开发中,ToString()方法是一个既基础又容易被忽视的重要成员。它是System.Object类的虚方法,所有类都继承自System.Object,这意味着每个类都拥有ToString()方法。然而,默认的ToString()方法往往无法满足实际需求,…

从0开始学习计算机视觉--Day05--优化

除了得到最小的W之外&#xff0c;如何节省这个探索最优W的过程&#xff0c;也是很重要的一点。假如把这个过程比作从山上的顶点开始下山&#xff0c;把图中必定游玩的经典比作最优权重&#xff0c;那么节省的过程&#xff0c;就是找到下山的最短路径的过程。而在下山的过程中&a…

OpenCV计算机视觉实战(14)——直方图均衡化

OpenCV计算机视觉实战&#xff08;14&#xff09;——直方图均衡化 0. 前言1. CLAHE 自适应均衡1.1 应用场景1.2 实现过程 2. 直方图反向投影2.1 应用场景2.2 实现过程 3. 基于颜色的目标追踪小结系列链接 0. 前言 在图像处理与计算机视觉领域&#xff0c;直方图技术是最直观且…

基于uniapp的老年皮肤健康管理微信小程序平台(源码+论文+部署+安装+售后)

感兴趣的可以先收藏起来&#xff0c;还有大家在毕设选题&#xff0c;项目以及论文编写等相关问题都可以给我留言咨询&#xff0c;我会一一回复&#xff0c;希望帮助更多的人。 系统背景 近年来&#xff0c;我国人口老龄化进程不断加快&#xff0c;据国家统计局数据显示&#…

MySQL(106)如何设计分片键?

设计分片键&#xff08;Sharding Key&#xff09;是数据库分片的核心&#xff0c;它决定了将数据分配到不同分片的方式。一个好的分片键应该能够均衡地分布数据&#xff0c;避免热点问题&#xff0c;提高查询性能。下面将详细介绍如何设计分片键&#xff0c;并结合代码进行说明…

汽车一键启动升级手机控车

汽车一键启动升级手机控车实现手机远程启动&#xff0c;不改变原车任何功能且全部免接线。升级后原车遥控器能在有效范围内启动车辆。移动管家手机控车一键启动系统用手机远程控制&#xff0c;完美兼容原车遥控器。支持长安、别克、宝马、奥迪等众多系列车型&#xff0c;市场99…

【开源项目】「安卓原生3D开源渲染引擎」:Sceneform‑EQR

「安卓原生3D开源渲染引擎」&#xff1a;Sceneform‑EQR 渲染引擎 “那一夜凌晨3点&#xff0c;第一次提交 PR 的手在抖……”——我深刻体会这种忐忑与激动。 仓库地址&#xff1a;(https://github.com/eqgis/Sceneform-EQR)。 一、前言&#xff1a;开源对我意味着什么 DIY 的…

建造者模式 - Flutter中的乐高大师,优雅组装复杂UI组件!

痛点场景&#xff1a;复杂的对话框配置 假设你需要创建一个多功能对话框&#xff1a; CustomDialog(title: 警告,content: 确定要删除吗&#xff1f;,titleStyle: TextStyle(fontSize: 20, color: Colors.red),contentStyle: TextStyle(fontSize: 16),backgroundColor: Color…