精华内容
下载资源
问答
  • STM32用STLINK烧写外置FLASH遇到的问题

    千次阅读 2018-12-01 14:07:37
    由于项目需要大量的图片字库还有音频文件,所以外挂了NOR flash和...首先烧写用到PC端软件是STM32 STLINK Utility,在安装目录下附带了一些常用的flash的烧写算法,但没有我用到的那种,所以只能参考ST-LINK Utility...

    由于项目需要大量的图片字库还有音频文件,所以外挂了NOR flash和NAND flash,需要用到烧写算法STLDR(就是包含几段在SRAM里面运行的代码),调试的时候遇到了几个问题,都是大意造成的,所以写出来记录一下
    首先烧写用到PC端软件是STM32 STLINK Utility,在安装目录下附带了一些常用的flash的烧写算法,但没有我用到的那种,所以只能参考ST-LINK Utility UM手册在…\ST-LINK Utility\ExternalLoader目录下的工程模板上修改,修改需要用到对FLASH的初始化、读写、擦除函数,这个要提前调试好,填到对应的函数内就可以了,后面由上位机自己调用
    问题来了,主要是三方面的问题,第一个是编译出错,第二个是延时,第三个是地址
    1)编译出错:在修改完模板第一次编译的时候可能会报错.\xxx.axf: Error: L6265E: Non-PI Section loader_src.o(.data) cannot be assigned to PI Exec region PrgData.,这个问题需要修改target.sct文件,添加ABSOLUTE,这个是偶然在一个论坛上看到的,在此表示感谢
    在这里插入图片描述在这里插入图片描述
    2)延时问题:工程用的cubemx的HAL库开发,所有延时部分都是用的HAL_Delay()函数,但是在模板中并没有使用中断,一直卡死在延时函数里面出不来,所以最终改为常用的自减法来达到延时的目的
    3)地址问题:flash接在OSPI2接口上,起始基地址是0x70000000,但是OSPI的库函数使用的地址是不包括基地址的,而在模板中读写函数传入的地址参数是带着基地址的,所以需要与0x0FFFFFFF相与再使用
    这三个问题解决好就可以正常读写了,就是感觉速度不快,带校验也就50k/s,可能是HAL库函数注重稳定性和兼容性,代码冗余多,直接操作寄存器可能会快点

    展开全文
  • 15.1 FLASHFlash,全名叫做Flash EEPROM Memory,即平时所说的“闪存”,它结合了ROM和RAM的长处,不仅可以反复擦除,还可以快速读取数据,STM32运行的程序其实就是存放在Flash当中,但是由于STM32Flash一般1M左右...

    15.1 FLASH

    Flash,全名叫做Flash EEPROM Memory,即平时所说的“闪存”,它结合了ROM和RAM的长处,不仅可以反复擦除,还可以快速读取数据,STM32运行的程序其实就是存放在Flash当中,但是由于STM32的Flash一般1M左右,只能存储程序大小的数据,所以往往需要外扩Flash来存储数据,比如LCD界面当中的汉字字库,以及文件系统中读取的文件内容。

    但是一般Flash的擦除次数有限制,STM32F1系列最新的文档指出,片内的FLASH擦写次数大约在1W次左右,所以一般Flash用于擦除次数不多,但是数据量很大的场合。

    这个Flash读写实验我们用到的芯片是W25Q128,这是一款采用SPI协议进行读写的Flash芯片,存储容量为128Mbit,合计16Mbyte,工作电压2.7V~3.6V。这个实验我们采用STM32内置的SPI模块来进行对芯片的读写操作,STM32F1的SPI功能很强大,SPI时钟最高可以到18MHz,支持DMA,可以配置为SPI协议或者I2S协议。

    15.2 硬件SPI模块

    通过之前51单片机开发我们可以知道,SPI协议一共需要四根线来完成数据通信,即片选CS,总线时钟SCK,主机输入从机输出MISO和主机输出从机输入MOSI四根数据线。STM32的内部SPI模块结构框图如下图所示。

    c7abaf795300acad3f46992748777d7f.png

    从上面的结构框图我们可以发现,硬件SPI的优势就在于开发者不需要考虑SPI的详细参数以及时序,只需要配置内部的寄存器,设置速率,电平就可以实现SPI通信。

    15.3 相关寄存器

    15.3.1 SPI控制寄存器1:SPIx_CR1

    15

    14

    13

    12

    11

    10

    9

    8

    7

    6

    5

    4

    3

    2

    1

    0

    BIDI

    MODE

    BIDI

    OE

    CRC

    EN

    CRC

    NEXT

    DFF

    RX

    ONLY

    SSM

    SSI

    LSB

    FIRST

    SPE

    BR[2:0]

    MSTR

    CPOL

    CPHA

    Bit 15:双向数据模式使能

    0:选择双线双向模式

    1:选择单线双向模式

    Bit 14:双向模式下的输出使能

    0:输出禁止(只收模式)

    1:输出使能(只发模式)

    Bit 13:硬件CRC校验使能

    0:禁止CRC计算

    1:启动CRC计算

    Bit 12:下一个发送CRC

    0:下一个发送的值来自发送缓冲区

    1:下一个发送的值来自发送CRC寄存器

    Bit 11:数据帧格式

    0:使用8位数据帧格式进行发送/接收

    1:使用16位数据帧格式进行发送/接收

    Bit 10:只接收

    0:全双工(发送和接收)

    1:禁止输出(只接收模式)

    Bit 9:软件从设备管理

    0:禁止软件从设备管理

    1:启用软件从设备管理

    Bit 8:内部从设备选择

    注:该位只在SSM位为1时有意义。它决定了NSS上的电平,在NSS引脚上的I/O操作无效

    Bit 7:帧格式

    0:先发送MSB

    1:先发送LSB

    Bit 6:SPI使能

    0:禁止SPI设备

    1:开启SPI设备

    Bit 5~Bit 3:波特率控制

    000:fPCLK/2

    001:fPCLK/4

    010:fPCLK/8

    011:fPCLK/16

    100:fPCLK/32

    101:fPCLK/64

    110:fPCLK/128

    111:fPCLK/256

    Bit 2:主设备选择

    0:配置为从设备

    1:配置为主设备

    Bit 1:时钟极性

    0:空闲状态时,SCK保持低电平

    1:空闲状态时,SCK保持高电平

    Bit 0:时钟相位

    0:数据采样从第一个时钟边沿开始

    1:数据采样从第二个时钟边沿开始

    15.3.2 SPI状态寄存器:SPIx_SR

    15

    14

    13

    12

    11

    10

    9

    8

    7

    6

    5

    4

    3

    2

    1

    0

    -

    BSY

    OVR

    MODF

    CRC

    ERR

    UDR

    CHSI

    DE

    TXE

    RXNE

    Bit 7:忙标志

    0:SPI不忙

    1:SPI正忙于通信,或者发送缓冲非空

    Bit 6:溢出标志

    0:没有出现溢出错误

    1:出现溢出错误

    Bit 5:模式错误(在SPI模式下不使用)

    0:没有出现模式错误

    1:出现模式错误

    Bit 4:CRC错误标志(在SPI模式下不使用)

    0:收到的CRC值和SPI_RXCRCR寄存器中的值匹配

    1:收到的CRC值和SPI_RXCRCR寄存器中的值不匹配

    Bit 3:下溢标志位(在SPI模式下不使用)

    0:未发生下溢

    1:发生下溢

    Bit 2:声道(在SPI模式下不使用)

    0:需要传输或者接收左声道

    1:需要传输或者接收右声道

    Bit 1:发送缓冲为空

    0:发送缓冲非空

    1:发送缓冲为空

    Bit 0:接收缓冲非空

    0:接收缓冲为空

    1:接收缓冲非空

    15.4 实验例程

    功能:在Flash中写入一段字符串,而后读出来并显示在TFTLCD上。

    (1)创建w25q128.h并输入以下代码。

    /*********************************************************************************************************                FLASH    驱    动    文    件*********************************************************************************************************/#ifndef _W25Q128_H_#define _W25Q128_H_#include "sys.h"/*********************************************************************************************************                  端    口    定    义*********************************************************************************************************/#define  W25QXX_CS  PBout( 12 )                                      //W25QXX的片选信号/*********************************************************************************************************                  数    据    定    义*********************************************************************************************************///SPI总线速度设置#define SPI_SPEED_2       0#define SPI_SPEED_4       1#define SPI_SPEED_8       2#define SPI_SPEED_16      3#define SPI_SPEED_32     4#define SPI_SPEED_64     5#define SPI_SPEED_128     6#define SPI_SPEED_256     7//指令表#define W25X_WriteEnable    0x06#define W25X_WriteDisable    0x04#define W25X_ReadStatusReg    0x05#define W25X_WriteStatusReg    0x01#define W25X_ReadData      0x03#define W25X_FastReadData    0x0B#define W25X_FastReadDual    0x3B#define W25X_PageProgram    0x02#define W25X_BlockErase      0xD8#define W25X_SectorErase    0x20#define W25X_ChipErase      0xC7#define W25X_PowerDown      0xB9#define W25X_ReleasePowerDown  0xAB#define W25X_DeviceID      0xAB#define W25X_ManufactDeviceID  0x90#define W25X_JedecDeviceID    0x9F/*********************************************************************************************************                  函    数    列    表*********************************************************************************************************/void W25QXX_Init( void ) ;                                        //初始化Flashvoid W25QXX_Read( u8* pBuffer, u32 Address, u16 Len ) ;                          //读取Flashvoid W25QXX_Write( u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite ) ;                  //写入Flashvoid W25QXX_Erase_Chip( void ) ;                                    //整片擦除void W25QXX_Erase_Sector( u32 Dst_Addr ) ;                                //扇区擦除#endif

    (2)创建w25q128.c并输入以下代码。

    /*********************************************************************************************************                FLASH    驱    动    程    序*********************************************************************************************************/#include "w25q128.h" #include "delay.h"/***************************************************Name    :SPI2_SetSpeedFunction  :SPI2速度设置函数Paramater  :      SpeedSet:0~7Return    :None***************************************************/void SPI2_SetSpeed( u8 SpeedSet ){  SpeedSet &= 0x07 ;                                          //限制范围  SPI2->CR1 &= 0xFFC7 ;  SPI2->CR1 |= SpeedSet<<3 ;                                      //设置SPI2速度  SPI2->CR1 |= 1<<6 ;                                          //SPI设备使能}/***************************************************Name    :SPI2_ReadWriteByteFunction  :SPI2读写一个字节Paramater  :      TxData:要写入的字节Return    :读取到的字节***************************************************/u8 SPI2_ReadWriteByte( u8 TxData ){  u16 retry=0;  //等待发送区空  while( ( SPI2->SR&0x02 )==0 )  {    retry ++ ;    //超时退出    if( retry>=0xFFFE )      return 0 ;  }  SPI2->DR = TxData ;                                          //发送一个byte  //等待接收完一个byte  retry = 0 ;  while( ( SPI2->SR&0x01 )==0 )  {    retry ++ ;    //超时退出    if( retry>=0xFFFE )      return 0 ;  }  return SPI2->DR ;                                          //返回收到的数据}/***************************************************Name    :W25QXX_InitFunction  :初始化W25Q128芯片Paramater  :NoneReturn    :None***************************************************/void W25QXX_Init(){   RCC->APB2ENR |= 1<<3 ;                                        //PORTB时钟使能       GPIOB->CRH &= 0x0000FFFF ;  GPIOB->CRH |= 0xBBB30000 ;                                      //PB12推挽输出+PB13/14/15复用  GPIOB->ODR |= 0x7<<13 ;                                        //PB13/14/15上拉  W25QXX_CS = 1 ;                                            //SPI FLASH不选中  //初始化SPI  RCC->APB1ENR |= 1<<14 ;                                        //SPI2时钟使能  SPI2->CR1 |= 0<<10 ;                                        //全双工模式  SPI2->CR1 |= 1<<9 ;                                          //软件nss管理  SPI2->CR1 |= 1<<8 ;  SPI2->CR1 |= 1<<2 ;                                          //SPI主机  SPI2->CR1 |= 0<<11 ;                                        //8bit数据格式  SPI2->CR1 |= 1<<1 ;                                          //空闲模式下SCK1 CPOL=1  SPI2->CR1 |= 1<<0 ;                                          //数据采样从第二个时间边沿开始,CPHA=1  //对SPI2属于APB1的外设.时钟频率最大为36M  SPI2->CR1 |= 3<<3 ;                                          //Fsck=Fpclk1/256  SPI2->CR1 |= 0<<7 ;                                          //MSBfirst  SPI2->CR1 |= 1<<6 ;                                          //SPI设备使能  SPI2_ReadWriteByte( 0xFF ) ;                                    //启动传输  SPI2_SetSpeed( SPI_SPEED_2 ) ;                                    //设置为18M时钟,高速模式}/***************************************************Name    :W25QXX_Wait_BusyFunction  :等待空闲Paramater  :NoneReturn    :None***************************************************/void W25QXX_Wait_Busy()   {  u8 byte=0 ;  // 等待BUSY位清空  do  {    W25QXX_CS = 0 ;                                          //使能器件    SPI2_ReadWriteByte( W25X_ReadStatusReg ) ;                            //发送读取状态寄存器命令    byte = SPI2_ReadWriteByte( 0xFF ) ;                                //读取一个字节    W25QXX_CS = 1 ;                                          //取消片选  }while( ( byte&0x01 )==0x01 ) ;}/***************************************************Name    :W25QXX_Erase_ChipFunction  :擦除整个芯片Paramater  :NoneReturn    :None***************************************************/void W25QXX_Erase_Chip(){    W25QXX_CS = 0 ;                                            //使能器件    SPI2_ReadWriteByte( W25X_WriteEnable ) ;                              //发送写使能  W25QXX_CS = 1 ;                                            //取消片选    W25QXX_Wait_Busy() ;       W25QXX_CS=0 ;                                            //使能器件       SPI2_ReadWriteByte( W25X_ChipErase ) ;                                //发送片擦除命令    W25QXX_CS = 1 ;                                            //取消片选               W25QXX_Wait_Busy() ;                                        //等待芯片擦除结束}/***************************************************Name    :W25QXX_Erase_SectorFunction  :擦除一个扇区Paramater  :      Address:扇区地址Return    :None***************************************************/void W25QXX_Erase_Sector( u32 Address ){   Address *= 4096 ;    W25QXX_CS = 0 ;                                            //使能器件    SPI2_ReadWriteByte( W25X_WriteEnable ) ;                              //发送写使能  W25QXX_CS = 1 ;                                            //取消片选    W25QXX_Wait_Busy();       W25QXX_CS = 0 ;                                            //使能器件    SPI2_ReadWriteByte( W25X_SectorErase ) ;                              //发送扇区擦除指令    SPI2_ReadWriteByte( ( u8 )( Address>>16 ) ) ;                            //发送24bit地址    SPI2_ReadWriteByte( ( u8 )( Address>>8 ) ) ;    SPI2_ReadWriteByte( ( u8 )Address ) ;  W25QXX_CS = 1 ;                                            //取消片选    W25QXX_Wait_Busy() ;                                        //等待擦除完成}/***************************************************Name    :W25QXX_ReadFunction  :在指定地址开始读取指定长度的数据Paramater  :      pBuffer:数据存储区      Address:开始读取的地址      Len:要读取的字节数Return    :None***************************************************/void W25QXX_Read( u8 *pBuffer, u32 Address, u16 Len ){    u16 i ;                             W25QXX_CS = 0 ;                                            //使能器件    SPI2_ReadWriteByte( W25X_ReadData ) ;                                //发送读取命令    SPI2_ReadWriteByte( ( u8 )( Address>>16 ) ) ;                            //发送24bit地址    SPI2_ReadWriteByte( ( u8 )( Address>>8 ) ) ;    SPI2_ReadWriteByte( ( u8 )Address );    for( i=0; i        pBuffer[ i ] = SPI2_ReadWriteByte( 0xFF ) ;                            //循环读数  W25QXX_CS = 1 ;}/***************************************************Name    :W25QXX_Write_PageFunction  :在指定地址开始写入最大256字节的数据Paramater  :      pBuffer:数据存储区      Address:开始写入的地址      Len:要写入的字节数Return    :None***************************************************/void W25QXX_Write_Page( u8 *pBuffer, u32 Address, u8 Len ){   u16 i;    W25QXX_CS = 0 ;                                            //使能器件    SPI2_ReadWriteByte( W25X_WriteEnable ) ;                              //发送写使能    SPI2_ReadWriteByte( W25X_PageProgram ) ;                              //发送写页命令    SPI2_ReadWriteByte( ( u8 )( Address>>16 ) ) ;                            //发送24bit地址    SPI2_ReadWriteByte( ( u8 )( Address>>8 ) ) ;    SPI2_ReadWriteByte( ( u8 )Address ) ;    for( i=0; i    SPI2_ReadWriteByte( pBuffer[ i ] ) ;                              //循环写数  W25QXX_CS = 1 ;                                            //取消片选  W25QXX_Wait_Busy() ;                                        //等待写入结束}/***************************************************Name    :W25QXX_Write_NoCheckFunction  :无检验写数据Paramater  :      pBuffer:数据存储区      Address:开始写入的地址      Len:要写入的字节数Return    :None***************************************************/void W25QXX_Write_NoCheck( u8 *pBuffer, u32 Address, u16 Len ){  u16 pageremain ;  pageremain = 256-Address%256 ;                                    //单页剩余的字节数  //不大于256个字节  if( Len<=pageremain )    pageremain = Len ;  while( 1 )  {    W25QXX_Write_Page( pBuffer, Address, pageremain ) ;    //写入结束了    if( Len==pageremain )      break ;    //NumByteToWrite>pageremain     else    {      pBuffer += pageremain ;      Address += pageremain ;      Len -= pageremain ;                                      //减去已经写入了的字节数      //一次可以写入256个字节      if( Len>256 )        pageremain = 256 ;      //不够256个字节了      else        pageremain = Len ;    }  }}/***************************************************Name    :W25QXX_Write_NoCheckFunction  :在指定地址开始写入指定长度的数据Paramater  :      pBuffer:数据存储区      Address:开始写入的地址      Len:要写入的字节数Return    :None***************************************************/u8 W25QXX_BUFFER[ 4096 ] ;void W25QXX_Write( u8 *pBuffer, u32 Address, u16 Len ){  u32 secpos ;  u16 secoff ;  u16 secremain ;   u16 i ;  u8 *W25QXX_BUF ;     W25QXX_BUF = W25QXX_BUFFER ;   secpos = Address/4096 ;                                        //扇区地址  secoff = Address%4096 ;                                        //在扇区内的偏移  secremain = 4096-secoff ;                                      //扇区剩余空间大小  //不大于4096个字节   if( Len<=secremain )    secremain = Len ;  while( 1 )  {    W25QXX_Read( W25QXX_BUF, secpos*4096, 4096 ) ;                          //读出整个扇区的内容    //校验数据    for( i=0; i<secremain; i++ )    {      //需要擦除      if( W25QXX_BUF[ secoff+i ]!=0xFF )        break ;    }    //需要擦除    if( i<secremain )    {      W25QXX_Erase_Sector( secpos ) ;                                //擦除这个扇区      //复制      for( i=0; i<secremain; i++ )        W25QXX_BUF[ i+secoff ] = pBuffer[ i ] ;      W25QXX_Write_NoCheck( W25QXX_BUF, secpos*4096, 4096 ) ;                    //写入整个扇区    }    else      W25QXX_Write_NoCheck( pBuffer, Address, secremain ) ;                    //写已经擦除了的,直接写入扇区剩余区间    //写入结束了    if( Len==secremain )      break ;    //写入未结束    else    {      secpos ++ ;                                          //扇区地址增1      secoff = 0 ;                                        //偏移位置为0         pBuffer += secremain ;                                    //指针偏移      Address += secremain ;                                    //写地址偏移         Len -= secremain ;                                      //字节数递减      //下一个扇区还是写不完      if( Len>4096 )        secremain = 4096 ;      //下一个扇区可以写完了      else        secremain = Len ;    }  }}

    (3)在1.c文件中输入以下代码。

    #include "sys.h"#include "delay.h"#include "usart1.h"#include "lcd.h"#include "w25q128.h"const u8 TEXT_Buffer[] = { "WarShip STM32F1 SPI TEST" } ;#define SIZE sizeof( TEXT_Buffer )int main(){  u8 datatemp[ SIZE ] ;  u32 FLASH_SIZE ;  STM32_Clock_Init( 9 ) ;                                        //STM32时钟初始化  SysTick_Init( 72 ) ;                                        //SysTick初始化  USART1_Init( 72, 115200 ) ;                                      //初始化串口1波特率115200  LCD_Init() ;                                            //LCD初始化  W25QXX_Init() ;                                            //W25QXX初始化   POINT_COLOR = RED ;                                          //设置字体为红色  FLASH_SIZE = 128*1024*1024 ;                                    //FLASH 大小为16M字节  W25QXX_Write( (u8*)TEXT_Buffer, FLASH_SIZE-100, SIZE ) ;                      //从倒数第100个地址处开始,写入SIZE长度的数据  W25QXX_Read( datatemp, FLASH_SIZE-100, SIZE ) ;                            //从倒数第100个地址处开始,读出SIZE个字节  LCD_ShowString( 0, 0, datatemp ) ;                                  //显示读到的字符串  while( 1 )  {      }}
    展开全文
  •   这一张我们主要讲解一下STM32CUBEMX新版本 片外FLASH+FATFS文件系统。 一、准备工作 这里我们要想配置SPI和文件系统 并验证需要的准备工作如下: 1、MDK for ARM(KEIL5)或者IAR FOR ARM(这个是软件必备开发平台...

      这一张我们主要讲解一下STM32CUBEMX新版本 片外FLASH+FATFS文件系统。

    一、准备工作

    这里我们要想配置SPI和文件系统 并验证需要的准备工作如下:

    1、MDK for ARM(KEIL5)或者IAR FOR ARM(这个是软件必备开发平台) (必须)

    2、一块STM32最小系统开发板 (必须)

    3、一块片外FLASH可以在开发板上面或者是自己买的模块

    二、具体的操作

    1、工程建立

    1)、在Pinout&Configuration菜单栏下,配置硬件SPI的基本参数如图

    在这里插入图片描述
    在这里插入图片描述
    这里配置的是SPI2,还需要软件控制片选增加一个PB12作为输出的片选脚,这里SPI2就配置好了。

    2)、在Pinout&Configuration菜单栏下,配置FATFS基本信息

    在这里插入图片描述
    在MiddleWare下FATFS勾选User-define,在底下参数栏里面设置简体中文以及块大小,我们选取的是W25Q128,块的大小是4096。如果是SD卡就不需要更改大小为512。这里文件系统就配置好了。

    3)、生成工程配置如图

    在这里插入图片描述
    生成成功后打开工程。

    2、工程测试

    1)、SPI & FLASH测试

    在这里插入图片描述

    void MX_SPI2_Init(void)
    {
    
      hspi2.Instance = SPI2;
      hspi2.Init.Mode = SPI_MODE_MASTER;
      hspi2.Init.Direction = SPI_DIRECTION_2LINES;
      hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
      hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
      hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
      hspi2.Init.NSS = SPI_NSS_SOFT;
      hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
      hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
      hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
      hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
      hspi2.Init.CRCPolynomial = 10;
      if (HAL_SPI_Init(&hspi2) != HAL_OK)
      {
        Error_Handler();
      }
    	SPI2->CR1 |= SPI_CR1_SPE;
    }
    

    SPI2初始化代码添加SPI使能代码。
    FLASH.C

    #define W25Q80 	0XEF13 	
    #define W25Q16 	0XEF14
    #define W25Q32 	0XEF15
    #define W25Q64 	0XEF16
    #define W25Q128	0XEF17
    #define  M25P64_FLASH_ID        0x202017//C22017
    #define  M25P40_FLASH_ID        0x202013
    
    /* USER CODE BEGIN Includes */
    #define sFLASH_CMD_WRITE          0x02  /*!< Write to Memory instruction */
    #define sFLASH_CMD_WRSR           0x01  /*!< Write Status Register instruction */
    #define sFLASH_CMD_WREN           0x06  /*!< Write enable instruction */
    #define sFLASH_CMD_READ           0x03  /*!< Read from Memory instruction */
    #define sFLASH_CMD_RDSR           0x05  /*!< Read Status Register instruction  */
    #define sFLASH_CMD_RDID           0x9F  /*!< Read identification */
    #define sFLASH_CMD_SE             0x20  /*!< Sector Erase instruction (4k)*/
    #define sFLASH_CMD_BE             0xD8  /*!< Block Erase instruction (64k)*/
    #define sFLASH_CMD_CE             0xC7  /*!< Chip Erase instruction (Chip Erase)*/
    #define sFLASH_WIP_FLAG           0x01  /*!< Write In Progress (WIP) flag */
    #define sFLASH_CMD_RDID           0x9F  /*!< Read identification */
    #define sFLASH_CMD_DeviceID			    0xAB 
    #define sFLASH_CMD_ManufactDeviceID	    0x90 
    #define sFLASH_CMD_JedecDeviceID		0x9F 
    #define sFLASH_DUMMY_BYTE         0xFF
    
    uint8_t sFlashBuff[4096];
    
    //片选CS拉低
    void sFLASH_CS_LOW(void)
    {
        HAL_GPIO_WritePin(SPI2_CS_GPIO_Port,SPI2_CS_Pin,GPIO_PIN_RESET);
    }	
    //片选CS拉高
    void sFLASH_CS_HIGH(void)
    {
        HAL_GPIO_WritePin(SPI2_CS_GPIO_Port,SPI2_CS_Pin,GPIO_PIN_SET);
    }	
    //FLASH写使能
    void sFLASH_WriteEnable(void)
    {
      /*!< Select the FLASH: Chip Select low */
      sFLASH_CS_LOW();
      /*!< Send "Write Enable" instruction */
      sFLASH_SendByte(sFLASH_CMD_WREN);
    
      /*!< Deselect the FLASH: Chip Select high */
      sFLASH_CS_HIGH();
    }
    //FLASH 发送一个字节
    uint8_t sFLASH_SendByte(uint8_t byte)
    {
    	unsigned char dr;
      /*!< Loop while DR register in not emplty */
      //while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
    	while((SPI2->SR & SPI_SR_TXE) == 0);
    
      /*!< Send byte through the SPI1 peripheral */
      //SPI_I2S_SendData(SPI1, byte);
    	SPI2->DR = byte;
    
      /*!< Wait to receive a byte */
      //while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
    	while((SPI2->SR & SPI_SR_RXNE) == 0);
    
      /*!< Return the byte read from the SPI bus */
      //return SPI_I2S_ReceiveData(SPI1);
    	dr = SPI2->DR;
    	return dr;
    }
    //FLASH读取一个字节
    uint8_t sFLASH_ReadByte(void)
    {
      return (sFLASH_SendByte(sFLASH_DUMMY_BYTE));
    }
    //FLASH等待写完成
    void sFLASH_WaitForWriteEnd(void)
    {
        uint8_t flashstatus = 0;
        HAL_Delay(1);
        /*!< Select the FLASH: Chip Select low */
        sFLASH_CS_LOW();
        HAL_Delay(1);
        /*!< Send "Read Status Register" instruction */
        sFLASH_SendByte(sFLASH_CMD_RDSR);
    
        /*!< Loop as long as the memory is busy with a write cycle */
        do
        {
        /*!< Send a dummy byte to generate the clock needed by the FLASH
        and put the value of the status register in FLASH_Status variable */
        flashstatus = sFLASH_SendByte(sFLASH_DUMMY_BYTE);
    
        }
        while ((flashstatus & sFLASH_WIP_FLAG) == SET); /* Write in progress */
    
        /*!< Deselect the FLASH: Chip Select high */
        sFLASH_CS_HIGH();
    }
    
    //FLASH擦除一个扇区
    void sFLASH_EraseSector(uint32_t SectorAddr)
    {
      /*!< Send write enable instruction */
    	sFLASH_WriteEnable();
      /*!< Sector Erase */
      /*!< Select the FLASH: Chip Select low */
      sFLASH_CS_LOW();
      /*!< Send Sector Erase instruction */
    	sFLASH_SendByte(sFLASH_CMD_SE);
      /*!< Send SectorAddr high nibble address byte */
      sFLASH_SendByte((SectorAddr & 0xFF0000) >> 16);
      /*!< Send SectorAddr medium nibble address byte */
      sFLASH_SendByte((SectorAddr & 0xFF00) >> 8);
      /*!< Send SectorAddr low nibble address byte */
      sFLASH_SendByte(SectorAddr & 0xFF);
      /*!< Deselect the FLASH: Chip Select high */
      sFLASH_CS_HIGH();
    
      /*!< Wait the end of Flash writing */
      sFLASH_WaitForWriteEnd();
    }
    //FLASH擦除整个片
    void sFLASH_EraseChip(void)
    {
      /*!< Send write enable instruction */
      sFLASH_WriteEnable();
    
      /*!< Bulk Erase */
      /*!< Select the FLASH: Chip Select low */
      sFLASH_CS_LOW();
      /*!< Send Bulk Erase instruction  */
      sFLASH_SendByte(sFLASH_CMD_CE);
      /*!< Deselect the FLASH: Chip Select high */
      sFLASH_CS_HIGH();
    
      /*!< Wait the end of Flash writing */
      sFLASH_WaitForWriteEnd();
    }
    //FLASH写一个页
    void sFLASH_WritePage(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
    {
        sFLASH_WriteEnable();
        sFLASH_CS_LOW();
        sFLASH_SendByte(sFLASH_CMD_WRITE);
        sFLASH_SendByte((WriteAddr & 0xFF0000) >> 16);
        sFLASH_SendByte((WriteAddr & 0xFF00) >> 8);
        sFLASH_SendByte(WriteAddr & 0xFF);
    
        while (NumByteToWrite--)
        {
            sFLASH_SendByte(*pBuffer);
            pBuffer++;
        }
    
        sFLASH_CS_HIGH();
        sFLASH_WaitForWriteEnd();
    }
    //FLASH读取0-65536个
    void sFLASH_ReadBuffer(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead)
    {
        sFLASH_CS_LOW();
        sFLASH_SendByte(sFLASH_CMD_READ);
        sFLASH_SendByte((ReadAddr & 0xFF0000) >> 16);
        sFLASH_SendByte((ReadAddr& 0xFF00) >> 8);
        sFLASH_SendByte(ReadAddr & 0xFF);
    
        while (NumByteToRead--) /*!< while there is data to be read */
        {
            *pBuffer = sFLASH_SendByte(sFLASH_DUMMY_BYTE);
            pBuffer++;
        }
    
        sFLASH_CS_HIGH();
    }
    //读取FLASH ID
    uint32_t sFLASH_ReadID(void)
    {
        uint32_t Temp = 0, Temp0 = 0, Temp1 = 0, Temp2 = 0;
        sFLASH_CS_LOW();
        HAL_Delay(1);
        sFLASH_SendByte(sFLASH_CMD_RDID);
        Temp0 = sFLASH_SendByte(sFLASH_DUMMY_BYTE);
        Temp1 = sFLASH_SendByte(sFLASH_DUMMY_BYTE);
        Temp2 = sFLASH_SendByte(sFLASH_DUMMY_BYTE);
    
        sFLASH_CS_HIGH();
        Temp = (Temp0 << 16) | (Temp1 << 8) | Temp2;
    
        return Temp;
    }
    //无检验写SPI FLASH 
    void sFLASH_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)   
    { 			 		 
    	uint16_t pageremain;	   
    	pageremain=256-WriteAddr%256; //单页剩余的字节数		 	    
    	if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//不大于256个字节
    	while(1)
    	{	   
    		sFLASH_WritePage(pBuffer,WriteAddr,pageremain);
    		if(NumByteToWrite==pageremain)
            {
                break;//写入结束了
            }
    	 	else //NumByteToWrite>pageremain
    		{
    			pBuffer+=pageremain;
    			WriteAddr+=pageremain;	
    
    			NumByteToWrite-=pageremain;			  //减去已经写入了的字节数
    			if(NumByteToWrite>256)
                {
                    pageremain=256; //一次可以写入256个字节
                }
    			else
                {
                    pageremain=NumByteToWrite; 	  //不够256个字节了
                }
    		}
    	}
    }
    //带擦除的写0-65536个字节函数
    void sFLASH_WriteBuffer(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)   
    { 
    	uint32_t secpos;
    	uint16_t secoff;
    	uint16_t secremain;	   
     	uint16_t i;    
    	uint8_t * psFlashBuff;	  
      psFlashBuff=sFlashBuff;	     
     	secpos=WriteAddr/4096;//扇区地址  
    	secoff=WriteAddr%4096;//在扇区内的偏移
    	secremain=4096-secoff;//扇区剩余空间大小   
     	if(NumByteToWrite<=secremain)
        {
            secremain=NumByteToWrite;//不大于4096个字节
        }
        
    	while(1) 
    	{	
    		sFLASH_ReadBuffer(psFlashBuff,secpos*4096,4096);//读出整个扇区的内容      
    		sFLASH_EraseSector(secpos*4096);		//擦除这个扇区
    		for(i=0;i<secremain;i++)	   		//复制
    		{
    			psFlashBuff[i+secoff]=pBuffer[i];	  
    		}
    		sFLASH_Write_NoCheck(psFlashBuff,secpos*4096,4096);//写入整个扇区  
            
    		if(NumByteToWrite==secremain)
            {
                break;//写入结束了
            }
    		else//写入未结束
    		{
          secpos++;//扇区地址增1
          secoff=0;//偏移位置为0 	 
    
          pBuffer+=secremain;  				//指针偏移
          WriteAddr+=secremain;				//写地址偏移	   
          NumByteToWrite-=secremain;			//字节数递减
          if(NumByteToWrite>4096)
          {
            secremain=4096;//下一个扇区还是写不完
          }
          else 
          {
            secremain=NumByteToWrite;		//下一个扇区可以写完了
          }
    		}	 
    	}
    }
    
    

    FLASH.H

    #ifndef _H_SPIFLASH_H
    #define _H_SPIFLASH_H
    
    /**Includes************************************************************************************/
    #include "stm32f1xx_hal.h"
    #include "spi.h"
    
    /**Function declaration************************************************************************/
    
    
    void sFLASH_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite);
    void sFLASH_EraseChip(void);
    void sFLASH_WritePage(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite);
    void sFLASH_WriteBuffer(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite);
    void sFLASH_ReadBuffer(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead);
    uint32_t sFLASH_ReadID(void);
    #endif
    
    

    main.c
    检测FLASH_ID判断FLASH是否初始化成功

    uint32_t Flash_ID = 0;
    
    Flash_ID = sFLASH_ReadID();
    

    2)、文件系统代码添加及测试

    在这里插入图片描述
    在user_diskio.c增加如下代码

    #define PAGE_SIZE       256
    #define SECTOR_SIZE     4096
    #define SECTOR_COUNT	200
    #define BLOCK_SIZE	65536
    #define FLASH_PAGES_PER_SECTOR	SECTOR_SIZE/PAGE_SIZE
    
    FATFS fs;
    FIL file;						  /* 文件对象 */
    FRESULT f_res;                    /* 文件操作结果 */
    UINT fnum;            					  /* 文件成功读写数量 */
    BYTE ReadBuffer[1024]={0};        /* 读缓冲区 */
    BYTE WriteBuffer[]= "WH is the high hand\n";
    BYTE work[512];
     
    char USER_Path[4];
    
    void mount_disk(void)
    {
       f_res = f_mount(&fs, USER_Path, 0);
       return;
    
    }
    
    void format_disk(void)
    {
      uint8_t res = 0;
      //这里根据版本不同函数输入参数不一样
      f_res = f_mkfs(USER_Path, 1, 4096);
    }
    
     UINT bw;
    void create_file(void)
    {
      FIL file;
      FIL *pf = &file;
      uint8_t res;
      f_res = f_open(pf, "0:/test.txt", FA_OPEN_ALWAYS | FA_WRITE);
      f_res = f_write(&file, WriteBuffer, sizeof(WriteBuffer), &bw);
      f_res = f_close(pf);
    }
    
    void read_file(void)
    {
      FIL file;
      FRESULT res;
      uint8_t rbuf[100] = {0};
      f_res = f_open(&file, "0:/test.txt", FA_READ);
      f_res = f_read(&file, ReadBuffer, sizeof(WriteBuffer), &bw);
      f_res = f_close(&file);
    }
    
    void FileTest(void)
    {
    	mount_disk();
    	format_disk();
    	create_file();
    	read_file();
    }
    //初始化函数修改如下
    DSTATUS USER_initialize (
    	BYTE pdrv           /* Physical drive nmuber to identify the drive */
    )
    {
      /* USER CODE BEGIN INIT */
        Stat = STA_NOINIT;
    	if(sFLASH_ReadID() != 0){
        Stat &= ~STA_NOINIT;
      }	
    	
        return Stat;
      /* USER CODE END INIT */
    }
    //状态函修改如下
    DSTATUS USER_status (
    	BYTE pdrv       /* Physical drive number to identify the drive */
    )
    {
      /* USER CODE BEGIN STATUS */
        Stat &= ~STA_NOINIT;
        return Stat;
      /* USER CODE END STATUS */
    }
    //读取函数修改
    DRESULT USER_read (
    	BYTE pdrv,      /* Physical drive nmuber to identify the drive */
    	BYTE *buff,     /* Data buffer to store read data */
    	DWORD sector,   /* Sector address in LBA */
    	UINT count      /* Number of sectors to read */
    )
    {
      /* USER CODE BEGIN READ */
      DRESULT res = RES_ERROR;
      UINT i;
      
      for(i = 0;i < count;i++)
      {
    	  sFLASH_ReadBuffer(buff + i * 4096,sector * 4096 + i * 4096,4096 );
      }
    	
      res = RES_OK;
    
      return res;
      /* USER CODE END READ */
    }
    //写入函数修改
    DRESULT USER_write (
    	BYTE pdrv,          /* Physical drive nmuber to identify the drive */
    	const BYTE *buff,   /* Data to be written */
    	DWORD sector,       /* Sector address in LBA */
    	UINT count          /* Number of sectors to write */
    )
    { 
      /* USER CODE BEGIN WRITE */
      DRESULT res = RES_ERROR;
    	
      UINT i;
      
      for(i = 0;i < count;i++)
      {
    	  sFLASH_WriteBuffer((void *)(buff + i * 4096),sector * 4096 + i * 4096,4096 );
      }
    	
      res = RES_OK;	
      /* USER CODE HERE */
        return res;
      /* USER CODE END WRITE */
    }
    //枚举函数修改
    DRESULT USER_ioctl (
    	BYTE pdrv,      /* Physical drive nmuber (0..) */
    	BYTE cmd,       /* Control code */
    	void *buff      /* Buffer to send/receive control data */
    )
    {
      /* USER CODE BEGIN IOCTL */
    
      DRESULT res = RES_OK;
      
      switch(cmd)
      {
        case CTRL_SYNC :
            break;	
     
        case CTRL_TRIM:
            break;
    		
        case GET_BLOCK_SIZE:
    	*(DWORD*)buff = BLOCK_SIZE; 
    	break;
    		
        case GET_SECTOR_SIZE:
    	*(DWORD*)buff = SECTOR_SIZE;
            break;
    		
        case GET_SECTOR_COUNT:
    	*(DWORD*)buff = SECTOR_COUNT;
    	break;
    			
        default:
    	res = RES_PARERR;
    	break;
        }
      
      return res;
    
      /* USER CODE END IOCTL */
    }
    

    最后在main.c文件下
    调用测试代码

    FileTest();
    

    运行成功

    3、总结

    这样SPI FLASH+FATFS配置就完成了!~~~

    如有什么不懂联系加QQ群欢迎大家学习交流!
    在这里插入图片描述

    QQ:1320300083

    展开全文
  •   这一张我们主要讲解一下STM32CUBEMX新版本 片外FLASH(W25Q128)+FATFS文件系统+虚拟U盘。 一、准备工作 这里我们要想配置SPI和文件系统 并验证需要的准备工作如下: 1、MDK for ARM(KEIL5)或者IAR FOR ARM(这个...

      这一张我们主要讲解一下STM32CUBEMX新版本 片外FLASH(W25Q128)+FATFS文件系统+虚拟U盘。

    一、准备工作

    这里我们要想配置SPI和文件系统 并验证需要的准备工作如下:

    1、MDK for ARM(KEIL5)或者IAR FOR ARM(这个是软件必备开发平台) (必须)

    2、一块STM32最小系统开发板必须带USB (必须)

    3、一块片外FLASH可以在开发板上面或者是自己买的模块,这里我用的是W25Q128(16MB的片外flash) (必须)

    二、具体的操作

    1、工程建立

    1)、片外FLASH(W25Q128)+FATFS文件系统这一部分上一章节我已经讲解完了,大家可以去参考上一个章节去做。

    2)、在Pinout&Configuration菜单栏下,配置USB如图

    在这里插入图片描述

    3)、在Clock Configuration菜单栏下,配置USB主时钟必须是48M

    在这里插入图片描述

    3)、在Clock Configuration菜单栏下,配置USB模式为Mass Storage Class模式,在配置栏修改扇区大小为4096bytes,因为Flash的扇区是4096,SD卡扇区是512,这里要区分。

    在这里插入图片描述

    4)、生成工程配置如图

    在这里插入图片描述
    生成成功后打开工程。

    2、工程测试

    1)、虚拟U盘大小配置

    ![在这里插入图片描述](https://img-blog.csdnimg.cn/20201024105741215.png?x-oss-process=image/watermark,type_ZmFuZ3poZ在这里插入图片描述
    W5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzE1MTE3MTY3,size_16,color_FFFFFF,t_70#pic_center)
    U盘容量一个扇区4K=4096,我们这里设置扇区个数为 2048 = 8MB。

    2)、其他的函数配置如下

    最主要的配置是
    初始化函数
    int8_t STORAGE_Init_FS(uint8_t lun)
    读函数
    *int8_t STORAGE_Read_FS(uint8_t lun, uint8_t buf, uint32_t blk_addr, uint16_t blk_len)
    写函数
    *int8_t STORAGE_Write_FS(uint8_t lun, uint8_t buf, uint32_t blk_addr, uint16_t blk_len)

    /* Private functions ---------------------------------------------------------*/
    /**
      * @brief  Initializes over USB FS IP
      * @param  lun:
      * @retval USBD_OK if all operations are OK else USBD_FAIL
      */
    int8_t STORAGE_Init_FS(uint8_t lun)
    {
      /* USER CODE BEGIN 2 */
      return (USBD_OK);
      /* USER CODE END 2 */
    }
    
    /**
      * @brief  .
      * @param  lun: .
      * @param  block_num: .
      * @param  block_size: .
      * @retval USBD_OK if all operations are OK else USBD_FAIL
      */
    int8_t STORAGE_GetCapacity_FS(uint8_t lun, uint32_t *block_num, uint16_t *block_size)
    {
      /* USER CODE BEGIN 3 */
      *block_num  = STORAGE_BLK_NBR;
      *block_size = STORAGE_BLK_SIZ;
      return (USBD_OK);
      /* USER CODE END 3 */
    }
    
    /**
      * @brief  .
      * @param  lun: .
      * @retval USBD_OK if all operations are OK else USBD_FAIL
      */
    int8_t STORAGE_IsReady_FS(uint8_t lun)
    {
      /* USER CODE BEGIN 4 */
    	if(W25QXX_ReadID() != 0)
        return (USBD_OK);
    	else
    	return -1;
      /* USER CODE END 4 */
    }
    
    /**
      * @brief  .
      * @param  lun: .
      * @retval USBD_OK if all operations are OK else USBD_FAIL
      */
    int8_t STORAGE_IsWriteProtected_FS(uint8_t lun)
    {
      /* USER CODE BEGIN 5 */
    
      return (USBD_OK);
      /* USER CODE END 5 */
    }
    
    /**
      * @brief  .
      * @param  lun: .
      * @retval USBD_OK if all operations are OK else USBD_FAIL
      */
    int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
    {
      /* USER CODE BEGIN 6 */
    	uint32_t i = 0;
    	//W25QXX_Read(buf, blk_addr*STORAGE_BLK_SIZ, blk_len*STORAGE_BLK_SIZ);
    	
    	for(i = 0;i < blk_len;i++)
    	{
    	  W25QXX_Read(buf + i * STORAGE_BLK_SIZ,blk_addr * STORAGE_BLK_SIZ + i * STORAGE_BLK_SIZ,STORAGE_BLK_SIZ );
    	}
    	
    	return (USBD_OK);
      /* USER CODE END 6 */
    }
    
    /**
      * @brief  .
      * @param  lun: .
      * @retval USBD_OK if all operations are OK else USBD_FAIL
      */
    int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
    {
      /* USER CODE BEGIN 7 */
    //	W25QXX_Erase_Sector(blk_addr*STORAGE_BLK_SIZ);
    //	W25QXX_Page_Program(buf, blk_addr*STORAGE_BLK_SIZ,blk_len*STORAGE_BLK_SIZ);
    	uint32_t i = 0;
    
    	for(i = 0;i < blk_len;i++)
    	{
    //	  W25QXX_Erase_Sector(blk_addr + i);
    //	  W25QXX_Buffer_ProgramNoCheck((void *)(buf + i * STORAGE_BLK_SIZ),blk_addr * STORAGE_BLK_SIZ + i * STORAGE_BLK_SIZ,STORAGE_BLK_SIZ );
    	  W25QXX_Buffer_Program((void *)(buf + i * STORAGE_BLK_SIZ),blk_addr * STORAGE_BLK_SIZ + i * STORAGE_BLK_SIZ,STORAGE_BLK_SIZ );
    	  //W25QXX_Buffer_Program((void *)(buff + i * 4096),sector * 4096 + i * 4096,4096 );
    	}
    	
    	return (USBD_OK);
      /* USER CODE END 7 */
    }
    
    /**
      * @brief  .
      * @param  None
      * @retval .
      */
    int8_t STORAGE_GetMaxLun_FS(void)
    {
      /* USER CODE BEGIN 8 */
      return (STORAGE_LUN_NBR - 1);
      /* USER CODE END 8 */
    }
    

    3)、下载验证

    插上USB电脑会显示一个8M的硬盘,还有一个txt文件

    展开全文
  • STM32】读写stm32的内置Flash(附代码)

    千次阅读 2019-04-19 08:58:23
    stm32的flash之大,对于初学者的小打小闹完全不用担心不够用的情况。 因此,在需要保存一些芯片掉电之后依旧需要保存的数据(数据量不是特别大)时,运用内置flash的空闲部分可以为我们省去一颗eeprom或外置flash...
  • 使用cubemx配置BY25Q128AS时需要设置一些参数,其中包含数据帧参数、时钟参数等。 其中CPOL为时钟空闲电平状态,查看文档时序图可以看出来空闲电平为低电平, CPHA为采样电平,时序图可以看出是上升沿开始采集,所以...
  • 用正点原子的mini板子做EMWIN显示汉字需要把字库放在外置FLASH中,例程先将做好的字库放到SD卡中,然后使用FATFS把SD卡的字库拷贝到FLASH中,手上没有SD卡,考虑用串口+DMA传输将字库直接拷到FLASH中。 字库的制作...
  • 大家在使用中,有什么建议,欢迎反馈。脱机烧录视频效果展示:http://v.qq.com/x/page/p30628h2ou7.html多款STM8+STM32产品混合烧录展示:...h7_tool_app(V1.20).zip (480.91KB)H7-TOOL_STM32H7_App-master(V1.2
  • tid=86980 第71章 STM32H7的内部Flash应用之模拟EEPROM ...本章节为大家讲解STM32H7的内部Flash模拟EEPROM,主要应用到板子没有外置EERPOM的场合,而且H7的内部Flash比较大,可以开辟一个扇区用于模拟EEPROM。 目...
  • STM32GO中Flash充当EEPROM的操作 之前在学校的时候一直使用的是STM32F1的芯片,本月找了一份工作,安排下来的任务是写一个传感器的程序,程序比较简单,主要分为了两个部分: - 在Flash中找一片区域充当EEPROM的功能...
  • Flash先分块再分页,擦除是按块进行,这样的说法应该只是对外置Flash而言,对于片上Flash即可以按页擦除也可以整块擦除。 三、页面大小 STM32有4种Flash module organization,分别是:low-density devices(32KB,...
  • 说明:1、我们已经对STM32L0,STM32F0,STM32F1,STM32F4,STM32F7,STM32H7,STM8L,STM8S,外置QSPI Flash进行了适配。2、其它STM32型号的支持,大家可以看操作说明,做适配。后续会对市场上的其它厂家嵌入式芯片...
  • 第21章 ThreadX GUIX外置主题,字库和图库到外部SPI Flash 本章节为大家讲解GUIX外置主题,字库和图库到外部SPI Flash的方法。 目录 第21章 ThreadX GUIX外置主题,字库和图库到外部SPI Flash 21.1 初学者重要...
  • 第20章 ThreadX GUIX外置主题,字库和图库到外部SPI Flash 本章节为大家讲解GUIX外置主题,字库和图库到外部SPI Flash的方法。 目录 第20章 ThreadX GUIX外置主题,字库和图库到外部SPI Flash 20.1 初学者重要...
  • stm32h750/stm32h743原理图和pcb源文件

    千次阅读 2020-07-25 22:05:34
    stm32在目前使用非常广泛,但是目前很多人都还停留在stmf1/f4...功能:sd卡接口,24pin的cmos摄像头接口,rtc时钟,qspi接口的w25q64,支持程序从外置spi芯片启动,解决stm32h750的内存flash小的问题。 ad工程下载 ...
  • Nor Flash是通过FSMC总线可以直接读写的Flash存储器,掉电不丢失,相比NandFlash成本高,容量小,但可以作为程序存储器使用,即可以直接在NorFlash上执行代码,NandFlash虽然也可以执行代码,在至少在STM32中是不...
  • stm32h7_pcb.zip

    2020-07-25 22:00:48
    stm32h7板子支持100脚的stm32h743和h750这两款芯片,板子io口全引出来。...功能:sd卡接口,24pin的cmos摄像头接口,rtc时钟,qspi接口的w25q64,支持程序从外置spi芯片启动,解决stm32h750的内存flash小的问题。
  • 方式四:通过IAP升级,就是需要程序员将STM32flash分成两个区,主程序区和升级程序区,主程序将需要升级的固件下载到外置或者内置的flash上,然后通过IAP跳转到升级程序区,升级程序区将下载的估计通过flash写,写...
  • STM32f103C8T6 bootloader设计

    千次阅读 2018-09-08 22:53:37
    STM32 bootloader设计 ...在bootloader中判断一个单独的标志位看程序是否需要升级,如果需要升级,则复制外置flash处的内容到STM32的内置flash的指定地址处。 如: bootloader地址:0x08000000UL ...
  • 1.主控STM32F103RCT6+外置FlashW25Q64; 2.stm32USB口连接电脑,电脑识别为USB大容量设备; 3.将Bin文件拖入U盘,当存在多个Bin文件,默认第一个; 4.串口1会打印Flash内的Bin文件,按键1开始写入内部Flash; 5.按键...
  • 前面的博客描述了如何读写flash,可能还对读写flash思路还是不是那么的清晰,首先我们用的是外置flash,就要模拟跟外部硬件通讯的时序,这样外部硬件才能识别主控侧发出的信号是什么! SPI是全双工,同步的时钟...
  • stm32存储资源详解

    千次阅读 2019-09-22 22:38:30
    战舰STM32F103ZET6开发板 ZET6芯片 该芯片内部自带了64k字节的SRAM,以及512K的内部FLASH IROM1=0x80000=512K 和IRAM1=0X10000=64k的大小 同时开发板外置了1M字节外部SRAM芯片(IS62WV51216) 1M字节...

空空如也

空空如也

1 2 3
收藏数 44
精华内容 17
关键字:

stm32外置flash