stm32外挂spiflash的烧录算法

1,目前做了spiflash的stm32f103芯片 可以进行flash的读写 使用STM32CubeProgrammer +stlink 来实现spiflash的读写 目前只支持st的芯片
2,打算做一个mdk的spiflash 读写算法
3,目前已经做好一个H750的spiflash和qspi的烧录算法 支持jlink的软件 j-flash的软件上进行读写外挂spiflash和qspiflash 也支持mdk软件烧录算法
stlink的H750的算法

#include "Dev_Inf.h"
/* This structure containes information used by ST-LINK Utility to program and erase the device */
#if defined (__ICCARM__)
__root struct StorageInfo const StorageInfo  =  {
#else
struct StorageInfo const StorageInfo  =  {
#endif
   "VT_CORE_W25Q256_H750", 	 					// Device Name + EVAL Borad name
   NOR_FLASH,                   					// Device Type
   QSPI_ADDR_BASE,                						// Device Start Address
   32*1024*1024,                 						// Device Size in Bytes (32MBytes)
   0x100,                    						// Programming Page Size 256Bytes
   0xFF,                       						// Initial Content of Erased Memory
// Specify Size and Address of Sectors (view example below)
   0x00002000, 0x00001000,     				 		// Sector Num : 8192 ,Sector Size: 4KBytes
   0x00000000, 0x00000000,
}; 
#include <stdint.h>
#include "sys.h"
#include "w25qxx.h"
#include "qspi.h"
#include "usart.h"
#include "string.h"
#include "Dev_Inf.h"
/*
*********************************************************************************************************

*********************************************************************************************************
*/
#define PAGE_SIZE            4096
/*
*********************************************************************************************************

*********************************************************************************************************
*/
#define DEBUG_BAUD_RATE      (921600)
/*
*********************************************************************************************************

*********************************************************************************************************
*/
// 
#if defined   (__GNUC__)        /* GNU Compiler */
    volatile uint8_t aux_buf[PAGE_SIZE] __attribute__ ((aligned (32)));
    volatile uint32_t base_adr __attribute__ ((aligned (32)));
    volatile uint32_t  write_flag __attribute__ ((aligned (32)));                               
#elif defined (__ICCARM__)    /* IAR Compiler */
	_Pragma("data_alignment=32") volatile uint8_t aux_buf[PAGE_SIZE];   
	_Pragma("data_alignment=32") volatile uint32_t base_adr;   
	_Pragma("data_alignment=32") volatile uint32_t  write_flag;   
#elif defined   (__CC_ARM)      /* ARM Compiler */
    volatile uint8_t aux_buf[PAGE_SIZE] __attribute__ ((aligned (32)));
    volatile uint32_t base_adr __attribute__ ((aligned (32)));
    volatile uint32_t  write_flag __attribute__ ((aligned (32)));
#endif
/*
*********************************************************************************************************

*********************************************************************************************************
*/
void qspi_sys_init(void)   
{
    Stm32_Clock_Init(5,160,2,2,2);//设置时钟,400Mhz
	//串口初始化
	uart_init(400,DEBUG_BAUD_RATE);
    //
    QSPI_W25QXX_Init();                 //初始化W25QXX
	//
    base_adr = QSPI_ADDR_BASE;
    //
}
/*******************************************************************************
 Description :																		
 System initialization										        
 Inputs 	:																        
 				 None 																		
 outputs 	:																				
 				"1" 		: Operation succeeded						
 				"0" 		: Operation failure							
********************************************************************************/
int Init (void)
{ 
    //
    qspi_sys_init();
    //
    debug_log("start qspi \r\n");
    //
    write_flag=0;
    //
  return 1;
}
/*******************************************************************************
 Description :																			         
 Write data to the device	 														       
 Inputs :																					           
 				Address 	: Write location  										     
 				Size 		: Length in bytes 										     
 				buffer 		: Address where to get the data to write	 
 outputs :																				           
 				"1" 	        : Operation succeeded								       
 Info :																						           
 Note : Mandatory for all types except SRAM and PSRAM			   
********************************************************************************/
int Write (uint32_t Address, uint32_t Size, uint8_t* buffer)
{
    uint32_t  result=0;
    uint32_t  size_shi=0;
    uint32_t  size_ge=0;
    uint32_t  i=0;
    uint8_t   *pbuf=(uint8_t *)buffer;
    //
    size_shi=Size/PAGE_SIZE;
    //
    size_ge =Size%PAGE_SIZE;
    //
    qspi_sys_init();
    //
    SCB_CleanInvalidateDCache();
    //
    SCB_CleanDCache();
    //
    usr_printf("ProgramPage  adr:0x%x ,sz: %d ,buf :0x%x \r\n",(uint32_t)Address,Size,(uint32_t)pbuf);
    //
    if(Address>=base_adr)
    {
        if(size_shi>0)
        {
            for(i=0;i<size_shi;i++)
            {
                QSPI_W25QXX_Write((pbuf+i*PAGE_SIZE),(Address-base_adr)+i*PAGE_SIZE,PAGE_SIZE);   
            }
        }
        //
        if(size_ge>0)
        {
            QSPI_W25QXX_Write((pbuf+size_shi*PAGE_SIZE), (Address-base_adr)+size_shi*PAGE_SIZE, size_ge); 
        }
        //
    }
	return 1;
}

/*******************************************************************************
 Description :																			
 Erase a full sector in the device 									
 Inputs :																					  
 				SectrorAddress	: Start of sector 					
 outputs :																				  
 				"1" : Operation succeeded										
 				"0" : Operation failure											
 Note : Not Mandatory for SRAM PSRAM and NOR_FLASH		
********************************************************************************/
int SectorErase (uint32_t EraseStartAddress ,uint32_t EraseEndAddress)
{     
	uint32_t SectorAddr;
    uint32_t Sector_start;
    //
    qspi_sys_init();
    //
    debug_log("ease:%x,ram:%x \r\n",EraseStartAddress,(uint32_t)EraseEndAddress);
    //
	Sector_start = (EraseStartAddress -  (EraseStartAddress % 0x1000));
	//
	while (EraseEndAddress>=Sector_start)
	{
		SectorAddr = Sector_start & 0x0FFFFFFF;
        //
		QSPI_W25QXX_Erase_Sector( SectorAddr);
        //
        Sector_start += 0x1000;
	}
 	return 1;	
}

/*******************************************************************************
 Description :																			
 Read data from the device	 														
 Inputs :																					
 				Address 	: Write location  										
 				Size 		: Length in bytes 										
 				buffer 		: Address where to get the data to write		
 outputs :																				
 				"1" 		: Operation succeeded								
 				"0" 		: Operation failure										
 Note : Not Mandatory                               
********************************************************************************/	
int Read (uint32_t Address, uint32_t Size, uint8_t* Buffer)
{     	
    //
    qspi_sys_init();
    //
    debug_log("read:%x,ram:%x,size:%d \r\n",Address,(uint32_t)Buffer,Size);
    //
    if(Address>=base_adr)
    {
        QSPI_W25QXX_Read((uint8_t*)Buffer, (Address-base_adr), Size);
    }
    //
	return 1;     
} 

/*******************************************************************************
 Description :																		
 Verify the data 	 														    
 Inputs :																					
 				MemoryAddr 	: Write location  					
 				RAMBufferAddr 	: RAM Address		          
 				Size 		: Length in bytes 								
 outputs :																				
 				"0" 		: Operation succeeded						
 Note : Not Mandatory                             	
********************************************************************************/
int Verify (uint32_t MemoryAddr, uint32_t RAMBufferAddr, uint32_t Size)
{ 
    volatile unsigned char *psrc=(volatile unsigned char *)RAMBufferAddr;
    volatile unsigned long i;
    uint32_t  size_shi=0;
    uint32_t  size_ge=0;
    uint32_t  j=0;
    uint8_t   *pbuf=(uint8_t *)aux_buf;
    //
    size_shi=Size/PAGE_SIZE;
    //
    size_ge =Size%PAGE_SIZE;
    //
    qspi_sys_init();
    //
    printf("start verify :0x%x ,0x%x,%d ,0x%x\r\n",(uint32_t)MemoryAddr,(uint32_t)Size,(uint32_t)Size,(uint32_t)RAMBufferAddr);
    //
    SCB_CleanInvalidateDCache();
    //
    SCB_CleanDCache();
    //
    if((Size> 0)&&(MemoryAddr>=base_adr))
    {
        //
        if(size_shi>0)
        {
            for(i=0;i<size_shi;i++)
            {
                //
                memset((uint8_t*)pbuf,0,PAGE_SIZE);
                //
                QSPI_W25QXX_Read((pbuf),(MemoryAddr-base_adr)+i*PAGE_SIZE,PAGE_SIZE);   
                //
                for(j = 0; j< PAGE_SIZE; j++)
                {
                    if(aux_buf[j] != psrc[j+i*PAGE_SIZE])
                    {
                        //
                        debug_log("erroffset:%d base addr:%x addr:%x data--read:%x  write:%x\r\n",
                        (uint32_t)(j+i*PAGE_SIZE),base_adr,MemoryAddr,aux_buf[j],psrc[j+i*PAGE_SIZE]);
                        //
                        return (MemoryAddr+j+i*PAGE_SIZE);                  
                    }
                }
            }
        }
        //
        if(size_ge>0)
        {
            //
            memset((uint8_t*)pbuf,0,PAGE_SIZE);
            //
            QSPI_W25QXX_Read((pbuf+size_shi*PAGE_SIZE), (MemoryAddr-base_adr)+size_shi*PAGE_SIZE, size_ge); 
            //
            for(j = 0; j< size_ge; j++)
            {
                if(aux_buf[j] != psrc[j+size_shi*PAGE_SIZE])
                {
                    //
                    debug_log("erroffset:%d base addr:%x addr:%x data--read:%x  write:%x\r\n",
                    (uint32_t)(j+size_shi*PAGE_SIZE),base_adr,MemoryAddr,aux_buf[j],psrc[j+size_shi*PAGE_SIZE]);
                    //
                    return (MemoryAddr+j+size_shi*PAGE_SIZE);                  
                }
            }
        }
        //
        return (MemoryAddr+Size);  
    }
    else
    {
        return (MemoryAddr);
    }  
}
#define 	MCU_FLASH 	1
#define 	NAND_FLASH  2
#define 	NOR_FLASH   3
#define 	SRAM        4
#define 	PSRAM       5
#define 	PC_CARD     6
#define 	SPI_FLASH   7
#define 	I2C_FLASH   8
#define 	SDRAM       9
#define 	I2C_EEPROM  10

//
#define QSPI_ADDR_BASE        (0x90000000)
//

#define SECTOR_NUM 10				// Max Number of Sector types

struct DeviceSectors  
{
  unsigned long		SectorNum;     // Number of Sectors
  unsigned long		SectorSize;    // Sector Size in Bytes
};

struct StorageInfo  
{
   char           DeviceName[100];			// Device Name and Description
   unsigned short DeviceType;			    // Device Type: ONCHIP, EXT8BIT, EXT16BIT, ...
   unsigned long  DeviceStartAddress;		// Default Device Start Address
   unsigned long  DeviceSize;				// Total Size of Device
   unsigned long  PageSize;					// Programming Page Size
   unsigned char  EraseValue;				// Content of Erased Memory
   struct 	  DeviceSectors	 sectors[SECTOR_NUM];
};

jlink的H750的算法

/**************************************************************************//**
 * @file     FlashOS.h
 * @brief    Data structures and entries Functions
 * @version  V1.0.0
 * @date     10. October 2018
 ******************************************************************************/
/*
 * Copyright (c) 2010-2018 Arm Limited. All rights reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the License); you may
 * not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#define  USE_SEGGER_LINK_EN    0//表示 jlink烧录器算法  0表示mdk 烧录算法
//
#define QSPI_ADDR_BASE        (0x90000000)
//
#if     (USE_SEGGER_LINK_EN>0)
//
#define U8  unsigned char
#define U16 unsigned short
#define U32 unsigned long

#define I8  signed char
#define I16 signed short
#define I32 signed long

#define ONCHIP     (1)             // On-chip Flash Memory

#define MAX_NUM_SECTORS (512)      // Max. number of sectors, must not be modified.
#define ALGO_VERSION    (0x0101)   // Algo version, must not be modified.

struct SECTOR_INFO  {
  U32 SectorSize;       // Sector Size in bytes
  U32 SectorStartAddr;  // Start address of the sector area (relative to the "BaseAddr" of the flash)
};

struct FlashDevice {
   U16 AlgoVer;       // Algo version number
   U8  Name[128];     // Flash device name
   U16 Type;          // Flash device type
   U32 BaseAddr;      // Flash base address
   U32 TotalSize;     // Total flash device size in Bytes (256 KB)
   U32 PageSize;      // Page Size (number of bytes that will be passed to ProgramPage(). MinAlig is 8 byte
   U32 Reserved;      // Reserved, should be 0
   U8  ErasedVal;     // Flash erased value
   U32 TimeoutProg;   // Program page timeout in ms; 0: use default timeout
   // el xxxx Multi Sector program: 
   U32 TimeoutErase;  // Erase sector timeout in ms 0: Use default timeout
   // el xxxx Multi Sector erase: 
   struct SECTOR_INFO SectorInfo[MAX_NUM_SECTORS]; // Flash sector layout definition
};
//
#define SECTOR_END 0xFFFFFFFF, 0xFFFFFFFF
//
// Flash module functions
//
extern int Init                (U32 Addr,       U32 Freq,         U32 Func       );
extern int UnInit              (U32 Func                                         );
extern int BlankCheck          (U32 Addr,       U32 NumBytes,     U8  BlankData  );
extern int EraseChip           (void                                             );
extern int EraseSector         (U32 SectorAddr                                   );
extern int ProgramPage         (U32 DestAddr,   U32 NumBytes,     U8  *pSrcBuff  );
extern U32 Verify              (U32 Addr,       U32 NumBytes,     U8  *pSrcBuff  );

//
// SEGGER defined functions
//
extern int SEGGER_OPEN_Read    (U32 Addr,       U32 NumBytes,     U8  *pDestBuff );
extern int SEGGER_OPEN_Program (U32 DestAddr,   U32 NumBytes,     U8  *pSrcBuff  );
extern int SEGGER_OPEN_Erase   (U32 SectorAddr, U32 SectorIndex,  U32 NumSectors );
//
#else
//                 
#define VERS       1           // Interface Version 1.01

#define UNKNOWN    0           // Unknown
#define ONCHIP     1           // On-chip Flash Memory
#define EXT8BIT    2           // External Flash Device on 8-bit  Bus
#define EXT16BIT   3           // External Flash Device on 16-bit Bus
#define EXT32BIT   4           // External Flash Device on 32-bit Bus
#define EXTSPI     5           // External Flash Device on SPI

#define SECTOR_NUM 512         // Max Number of Sector Items
#define PAGE_MAX   65536       // Max Page Size for Programming

struct FlashSectors  {
  unsigned long   szSector;    // Sector Size in Bytes
  unsigned long AddrSector;    // Address of Sector
};

#define SECTOR_END 0xFFFFFFFF, 0xFFFFFFFF

struct FlashDevice  {
   unsigned short     Vers;    // Version Number and Architecture
   char       DevName[128];    // Device Name and Description
   unsigned short  DevType;    // Device Type: ONCHIP, EXT8BIT, EXT16BIT, ...
   unsigned long    DevAdr;    // Default Device Start Address
   unsigned long     szDev;    // Total Size of Device
   unsigned long    szPage;    // Programming Page Size
   unsigned long       Res;    // Reserved for future Extension
   unsigned char  valEmpty;    // Content of Erased Memory

   unsigned long    toProg;    // Time Out of Program Page Function
   unsigned long   toErase;    // Time Out of Erase Sector Function

   struct FlashSectors sectors[SECTOR_NUM];
};

#define FLASH_DRV_VERS (0x0100+VERS)   // Driver Version, do not modify!

// Flash Programming Functions (Called by FlashOS)
extern          int  Init        (unsigned long adr,   // Initialize Flash
                                  unsigned long clk,
                                  unsigned long fnc);
extern          int  UnInit      (unsigned long fnc);  // De-initialize Flash
extern          int  BlankCheck  (unsigned long adr,   // Blank Check
                                  unsigned long sz,
                                  unsigned char pat);
extern          int  EraseChip   (void);               // Erase complete Device
extern          int  EraseSector (unsigned long adr);  // Erase Sector Function
extern          int  ProgramPage (unsigned long adr,   // Program Page Function
                                  unsigned long sz,
                                  unsigned char *buf);
extern unsigned long Verify      (unsigned long adr,   // Verify Function
                                  unsigned long sz,
                                  unsigned char *buf);
//
extern int SEGGER_OPEN_Read    (unsigned long Addr,       unsigned long NumBytes,     unsigned char  *pDestBuff );
extern int SEGGER_OPEN_Program (unsigned long DestAddr,   unsigned long NumBytes,     unsigned char  *pSrcBuff  );
extern int SEGGER_OPEN_Erase   (unsigned long SectorAddr, unsigned long SectorIndex,  unsigned long NumSectors );                                                       
//                                
#endif                            
/* -----------------------------------------------------------------------------
 * Copyright (c) 2016 ARM Ltd.
 *
 * This software is provided 'as-is', without any express or implied warranty.
 * In no event will the authors be held liable for any damages arising from
 * the use of this software. Permission is granted to anyone to use this
 * software for any purpose, including commercial applications, and to alter
 * it and redistribute it freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you must not
 *    claim that you wrote the original software. If you use this software in
 *    a product, an acknowledgment in the product documentation would be
 *    appreciated but is not required.
 *
 * 2. Altered source versions must be plainly marked as such, and must not be
 *    misrepresented as being the original software.
 *
 * 3. This notice may not be removed or altered from any source distribution.
 *
 *
 * $Date:        10. October 2018
 * $Revision:    V1.0.0
 *
 * Project:      Flash Device Description for
 *               STM32H750_FMC100 W25Q256 SPIFI Flash
 * --------------------------------------------------------------------------- */

#include "..\FlashOS.H"        // FlashOS Structures
//
#if     (USE_SEGGER_LINK_EN>0)
//
#ifdef W25Q64FV
//
struct FlashDevice const FlashDevice __attribute__ ((section ("DevDscr"))) =  {
  ALGO_VERSION,             // Algo version
  "VT_CORE_H7_V01_JLINK_W25Q64",    // Flash device name
  ONCHIP,                   // Flash device type
  QSPI_ADDR_BASE,               // Flash base address
  0x00800000,               // Total flash device size in Bytes (256 KB)
  4096,                     // Page Size (number of bytes that will be passed to ProgramPage(). MinAlig is 8 byte
  0,                        // Reserved, should be 0
  0xFF,                     // Flash erased value
  1000,                    // Program page timeout in ms
  6000,                    // Erase sector timeout in ms
  //
  // Flash sector layout definition
  0x001000, 0x000000,         // Sector Size 4kB (8192 Sectors)
  SECTOR_END
};
//
#endif
//
#else
//
#ifdef W25Q256FV
//
//4Kbytes为一个Sector
//16个扇区为1个Block
//W25Q256
//容量为32M字节,共有512个Block,8192个Sector
//
struct FlashDevice const FlashDevice  =
{
    FLASH_DRV_VERS,             // Driver Version, do not modify!
    "VT_CORE_H7_V01_W25Q256",              // Device Name
    EXTSPI,                     // Device Type
    QSPI_ADDR_BASE,                 // Device Start Address
    0x02000000,                 // Device Size (32MB)
    4096,                       // Programming Page Size
    0,                          // Reserved, must be 0
    0xFF,                       // Initial Content of Erased Memory
    10000,                       // Program Page Timeout 300 mSec
    30000,                       // Erase Sector Timeout 3000 mSec

// Specify Size and Address of Sectors
    0x001000, 0x000000,         // Sector Size 4kB (8192 Sectors)
    SECTOR_END
};
#endif

#ifdef W25Q128FV
struct FlashDevice const FlashDevice  =
{
    FLASH_DRV_VERS,             // Driver Version, do not modify!
    "VT_CORE_H7_V01_W25Q128",              // Device Name
    EXTSPI,                     // Device Type
    QSPI_ADDR_BASE,                 // Device Start Address
    0x01000000,                 // Device Size (16MB)
    4096,                       // Programming Page Size
    0,                          // Reserved, must be 0
    0xFF,                       // Initial Content of Erased Memory
    10000,                       // Program Page Timeout 300 mSec
    30000,                       // Erase Sector Timeout 3000 mSec

// Specify Size and Address of Sectors
    0x001000, 0x000000,         // Sector Size 4kB (8192 Sectors)
    SECTOR_END
};
#endif

#ifdef W25Q64FV
struct FlashDevice const FlashDevice  =
{
    FLASH_DRV_VERS,             // Driver Version, do not modify!
    "VT_CORE_H7_V01_W25Q64",               // Device Name
    EXTSPI,                     // Device Type
    QSPI_ADDR_BASE,                 // Device Start Address
    0x00800000,                 // Device Size (8MB)
    4096,                       // Programming Page Size
    0,                          // Reserved, must be 0
    0xFF,                       // Initial Content of Erased Memory
    10000,                       // Program Page Timeout 300 mSec
    30000,                       // Erase Sector Timeout 3000 mSec

// Specify Size and Address of Sectors
    0x001000, 0x000000,         // Sector Size 4kB (8192 Sectors)
    SECTOR_END
};
#endif
//
#endif
//
/* -----------------------------------------------------------------------------
 * Copyright (c) 2016 ARM Ltd.
 *
 * This software is provided 'as-is', without any express or implied warranty.
 * In no event will the authors be held liable for any damages arising from
 * the use of this software. Permission is granted to anyone to use this
 * software for any purpose, including commercial applications, and to alter
 * it and redistribute it freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you must not
 *    claim that you wrote the original software. If you use this software in
 *    a product, an acknowledgment in the product documentation would be
 *    appreciated but is not required.
 *
 * 2. Altered source versions must be plainly marked as such, and must not be
 *    misrepresented as being the original software.
 *
 * 3. This notice may not be removed or altered from any source distribution.
 *
 *
 * $Date:        10. October 2018
 * $Revision:    V1.0.0
 *
 * Project:      Flash Device Description for
 *               STM32H743 W25Q256 SPIFI Flash
 * --------------------------------------------------------------------------- */

#include "..\FlashOS.H"        // FlashOS Structures
#include "sys.h"
#include "w25qxx.h"
#include "qspi.h"
#include "usart.h"
#include "string.h"
/*
*********************************************************************************************************

*********************************************************************************************************
*/
#define EN_MDK_FLM_VERIFY    1//不开启校验
#define EN_MDK_FLM_MAP       0// 
#define BlankCheck_EN        0//
#define PROG_READ_WRITE_EN   0//
#define MDK_FLM_INIT_EN      1//保证稳定性每次都初始化
//
#define PAGE_SIZE            4096
//
#define DEBUG_BAUD_RATE      (921600)
//
#define FLM_VER_Main         (1)
//
#define FLM_VER_SUB1         (0)
//
#define FLM_VER_SUB2         (14)
/*
*********************************************************************************************************

*********************************************************************************************************
*/
#if     ((PROG_READ_WRITE_EN>0)||(EN_MDK_FLM_VERIFY>0))
__IO uint8_t aux_buf[PAGE_SIZE] __attribute__((aligned(32)));
#endif
__IO uint32_t base_adr __attribute__((aligned(32)));
__IO uint32_t  write_flag __attribute__((aligned(32)));
/*
*********************************************************************************************************

*********************************************************************************************************
*/
#if     (USE_SEGGER_LINK_EN>0)
/*
*********************************************************************************************************

*********************************************************************************************************
*/
int Init(U32 Addr,U32 Freq,U32 Func)
{
    uint32_t  result=0;
    //
	SystemInit();
    //
    Stm32_Clock_Init(5,160,2,2,2);//设置时钟,400Mhz
    //串口初始化
    uart_init(400,DEBUG_BAUD_RATE);
    //
    QSPI_W25QXX_Init();                 //初始化W25QXX
    //
    base_adr = Addr;
    //
    if(write_flag==0)
    {
        FLASH_Erase_APP_FLAG(APP_FLAG_Offset);
        FLASH_Write_APP_FLAG(APP_FLAG_Offset,0xA5A5);
    }
    //
    usr_printf("h750 flm ver: %d.%d.%d VERIFY:%d,MAP:%d,BLANK:%d,PROG_WR:%d,FLM_INIT:%d\r\n",
                FLM_VER_Main,FLM_VER_SUB1,FLM_VER_SUB2,
                EN_MDK_FLM_VERIFY,EN_MDK_FLM_MAP,
                BlankCheck_EN,PROG_READ_WRITE_EN,
                MDK_FLM_INIT_EN     );
    //
#if  (EN_MDK_FLM_MAP>0)
    // 内存映射
    result = QSPI_EnableMemoryMappedMode();
    if(result != 0)
    {
        //
        usr_printf("Init :%X\r\n",result);
        //
        return 1;
    }
#endif
    //
    write_flag=0;
    return (0);
}
/*
*********************************************************************************************************

*********************************************************************************************************
*/
int UnInit(U32 Func)
{
#if  (EN_MDK_FLM_MAP>0)
    uint32_t  result=0;
    //
#if  (EN_MDK_FLM_MAP>0)
    Stm32_Clock_Init(5,160,2,2,2);//设置时钟,400Mhz
    uart_init(400,DEBUG_BAUD_RATE);
    QSPI_W25QXX_Init();                 //初始化W25QXX
#elif (MDK_FLM_INIT_EN>0)
    Stm32_Clock_Init(5,160,2,2,2);//设置时钟,400Mhz
    uart_init(400,DEBUG_BAUD_RATE);
    QSPI_W25QXX_Init();                 //初始化W25QXX
#else
    QSPI_W25QXX_Init();                 //初始化W25QXX
#endif
    // 内存映射
    result = QSPI_EnableMemoryMappedMode();
    if(result != 0)
    {
        //
        usr_printf("UnInit :%X\r\n",result);
        //
        return 1;
    }
#endif
    //
    return (0);
}
/*
*********************************************************************************************************

*********************************************************************************************************
*/
#if  (BlankCheck_EN>0)
//
int BlankCheck(U32 Addr,U32 NumBytes,U8  BlankData)
{
    U8* pData;

    pData = (U8 *)Addr;
    do
    {
        if(*pData++ != BlankData)
        {
            return 1;
        }
    }
    while(--NumBytes);
    return 0;
}
#else
//
int BlankCheck(unsigned long adr, unsigned long sz, unsigned char pat)
{
    uint32_t  size_shi=0;
    uint32_t  size_ge=0;
    uint32_t  i=0;
    uint32_t  j=0;
    //
    usr_printf("BlankCheck adr:0x%x ,sz: 0x%x ,pat :0x%x \r\n",(uint32_t)adr,(uint32_t)sz,pat);
    //
    size_shi=sz/PAGE_SIZE;
    //
    size_ge =sz%PAGE_SIZE;
    //
    if(size_shi>0)
    {
        for(i=0;i<size_shi;i++)
        {
            QSPI_W25QXX_Read((uint8_t*)aux_buf, (adr-base_adr)+i*PAGE_SIZE, PAGE_SIZE);
            //
            for(j=0;j<PAGE_SIZE;j++)
            {
                if(aux_buf[j] != pat)
                {
                    return 1;
                }
            }   
        }
    }
    //
    if(size_ge>0)
    {
        QSPI_W25QXX_Read((uint8_t*)aux_buf, (adr-base_adr)+size_shi*PAGE_SIZE, size_ge);
        //
        for(j=0;j<size_ge;j++)
        {
            if(aux_buf[j] != pat)
            {
                return 1;
            }
        }   
    }
    return 0;                               
}
//
#endif
/*
*********************************************************************************************************

*********************************************************************************************************
*/
int EraseChip(void)
{
    uint32_t  result=0;
    //
#if  (EN_MDK_FLM_MAP>0)
    Stm32_Clock_Init(5,160,2,2,2);//设置时钟,400Mhz
    uart_init(400,DEBUG_BAUD_RATE);
    QSPI_W25QXX_Init();                 //初始化W25QXX
#elif (MDK_FLM_INIT_EN>0)
    Stm32_Clock_Init(5,160,2,2,2);//设置时钟,400Mhz
    uart_init(400,DEBUG_BAUD_RATE);
    QSPI_W25QXX_Init();                 //初始化W25QXX
#else
    QSPI_W25QXX_Init();                 //初始化W25QXX
#endif
    //
    QSPI_W25QXX_Erase_Chip();
    // 内存映射
#if  (EN_MDK_FLM_MAP>0)
    result = QSPI_EnableMemoryMappedMode();
    if(result != 0)
    {
        //
        usr_printf("EraseChip :%X\r\n",result);
        //
        return 1;
    }
#endif
    //
    return (0);     
}
/*
*********************************************************************************************************

*********************************************************************************************************
*/
int EraseSector(U32 SectorAddr)
{
    uint32_t  result=0;
    //
#if  (EN_MDK_FLM_MAP>0)
    Stm32_Clock_Init(5,160,2,2,2);//设置时钟,400Mhz
    uart_init(400,DEBUG_BAUD_RATE);
    QSPI_W25QXX_Init();                 //初始化W25QXX
#elif (MDK_FLM_INIT_EN>0)
    Stm32_Clock_Init(5,160,2,2,2);//设置时钟,400Mhz
    uart_init(400,DEBUG_BAUD_RATE);
    QSPI_W25QXX_Init();                 //初始化W25QXX
#else
    QSPI_W25QXX_Init();                 //初始化W25QXX
#endif
    //
    if(SectorAddr>=base_adr)
    {
        QSPI_W25QXX_Erase_Sector(SectorAddr-base_adr);
    }
    // 内存映射
#if  (EN_MDK_FLM_MAP>0)
    result = QSPI_EnableMemoryMappedMode();
    if(result != 0)
    {
        //
        usr_printf("EraseSector :%X\r\n",result);
        //
        return 1;
    }
#endif
    return (0);    
}
/*
*********************************************************************************************************

*********************************************************************************************************
*/
int ProgramPage(U32 DestAddr,   U32 NumBytes,     U8  *pSrcBuff)
{
    uint32_t  result=0;
    uint32_t  size_shi=0;
    uint32_t  size_ge=0;
    uint32_t  i=0;
    uint8_t   *pbuf=(uint8_t *)pSrcBuff;
    //
    size_shi=NumBytes/PAGE_SIZE;
    //
    size_ge =NumBytes%PAGE_SIZE;
    //
#if  (EN_MDK_FLM_MAP>0)
    Stm32_Clock_Init(5,160,2,2,2);//设置时钟,400Mhz
    uart_init(400,DEBUG_BAUD_RATE);
    QSPI_W25QXX_Init();                 //初始化W25QXX
#elif (MDK_FLM_INIT_EN>0)
    Stm32_Clock_Init(5,160,2,2,2);//设置时钟,400Mhz
    uart_init(400,DEBUG_BAUD_RATE);
    QSPI_W25QXX_Init();                 //初始化W25QXX
#else
    QSPI_W25QXX_Init();                 //初始化W25QXX
#endif
    //
    SCB_CleanInvalidateDCache();
    //
    SCB_CleanDCache();
    //
    usr_printf("ProgramPage  adr:0x%x ,sz: %ld ,buf :0x%x \r\n",(uint32_t)DestAddr,NumBytes,(uint32_t)pbuf);
    //
    if(DestAddr>=base_adr)
    {
        if(size_shi>0)
        {
            for(i=0;i<size_shi;i++)
            {
                QSPI_W25QXX_Write((pbuf+i*PAGE_SIZE),(DestAddr-base_adr)+i*PAGE_SIZE,PAGE_SIZE);   
            }
        }
        //
        if(size_ge>0)
        {
            QSPI_W25QXX_Write((pbuf+size_shi*PAGE_SIZE), (DestAddr-base_adr)+size_shi*PAGE_SIZE, size_ge); 
        }
        //
    }
    // 内存映射
#if  (EN_MDK_FLM_MAP>0)
    result = QSPI_EnableMemoryMappedMode();
    if(result != 0)
    {
        //
        usr_printf("ProgramPage :%X\r\n",result);
        //
        return 1;
    }
#endif
    return (0);      
}
/*
*********************************************************************************************************

*********************************************************************************************************
*/
#if   (EN_MDK_FLM_VERIFY>0)
//
U32 Verify(U32 Addr,       U32 NumBytes,     U8  *pSrcBuff)
{
    volatile unsigned char *psrc=pSrcBuff;
    volatile unsigned long i;
    uint32_t  result=0;
    uint32_t  size_shi=0;
    uint32_t  size_ge=0;
    uint32_t  j=0;
    uint8_t   *pbuf=(uint8_t *)aux_buf;
    //
    size_shi=NumBytes/PAGE_SIZE;
    //
    size_ge =NumBytes%PAGE_SIZE;
    //
#if  (EN_MDK_FLM_MAP>0)
    Stm32_Clock_Init(5,160,2,2,2);//设置时钟,400Mhz
    uart_init(400,DEBUG_BAUD_RATE);
    QSPI_W25QXX_Init();                 //初始化W25QXX
#elif (MDK_FLM_INIT_EN>0)
    Stm32_Clock_Init(5,160,2,2,2);//设置时钟,400Mhz
    uart_init(400,DEBUG_BAUD_RATE);
    QSPI_W25QXX_Init();                 //初始化W25QXX
#else
    QSPI_W25QXX_Init();                 //初始化W25QXX
#endif
    //
    printf("start verify :0x%x ,0x%x,%d ,0x%x\r\n",(uint32_t)Addr,(uint32_t)NumBytes,(uint32_t)NumBytes,(uint32_t)pbuf);
    //
    SCB_CleanInvalidateDCache();
    //
    SCB_CleanDCache();
    //
    if((NumBytes> 0)&&(Addr>=base_adr))
    {
        //
        if(size_shi>0)
        {
            for(i=0;i<size_shi;i++)
            {
                //
                memset((uint8_t*)pbuf,0,PAGE_SIZE);
                //
                QSPI_W25QXX_Read((pbuf),(Addr-base_adr)+i*PAGE_SIZE,PAGE_SIZE);   
                //
                for(j = 0; j< PAGE_SIZE; j++)
                {
                    if(aux_buf[j] != psrc[j+i*PAGE_SIZE])
                    {
                        //
                        debug_log("erroffset:%d base addr:%x addr:%lx data--read:%x  write:%x\r\n",
                        (uint32_t)(j+i*PAGE_SIZE),base_adr,Addr,aux_buf[j],psrc[j+i*PAGE_SIZE]);
                        //
                        return (Addr+j+i*PAGE_SIZE);                  
                    }
                }
            }
        }
        //
        if(size_ge>0)
        {
            //
            memset((uint8_t*)pbuf,0,PAGE_SIZE);
            //
            QSPI_W25QXX_Read((pbuf+size_shi*PAGE_SIZE), (Addr-base_adr)+size_shi*PAGE_SIZE, size_ge); 
            //
            for(j = 0; j< size_ge; j++)
            {
                if(aux_buf[j] != psrc[j+size_shi*PAGE_SIZE])
                {
                    //
                    debug_log("erroffset:%d base addr:%x addr:%lx data--read:%x  write:%x\r\n",
                    (uint32_t)(j+size_shi*PAGE_SIZE),base_adr,Addr,aux_buf[j],psrc[j+size_shi*PAGE_SIZE]);
                    //
                    return (Addr+j+size_shi*PAGE_SIZE);                  
                }
            }
        }
        //
        return (Addr+NumBytes);  
    }
    else
    {
        // 内存映射
#if  (EN_MDK_FLM_MAP>0)
        result = QSPI_EnableMemoryMappedMode();
        if(result != 0)
        {
            //
            usr_printf("Verify3 :%X\r\n",result);
            //
            return (Addr);
        }
#endif
        return (Addr);
    }
}
//
#endif
/*
*********************************************************************************************************

*********************************************************************************************************
*/
//
// SEGGER defined functions
//
int SEGGER_OPEN_Read(U32 Addr,       U32 NumBytes,     U8  *pDestBuff)
{
    uint32_t  result=0;
    //
#if  (EN_MDK_FLM_MAP>0)
    Stm32_Clock_Init(5,160,2,2,2);//设置时钟,400Mhz
    uart_init(400,DEBUG_BAUD_RATE);
    QSPI_W25QXX_Init();                 //初始化W25QXX
#elif (MDK_FLM_INIT_EN>0)
    Stm32_Clock_Init(5,160,2,2,2);//设置时钟,400Mhz
    uart_init(400,DEBUG_BAUD_RATE);
    QSPI_W25QXX_Init();                 //初始化W25QXX
#else
    QSPI_W25QXX_Init();                 //初始化W25QXX
#endif
    //
    SCB_CleanInvalidateDCache();
    //
    SCB_CleanDCache();
    //
    usr_printf("SEGGER_OPEN_Read  adr:0x%x ,sz: 0x%x ,buf :0x%x \r\n",(uint32_t)Addr,NumBytes,(uint32_t)pDestBuff);
    //
    if(Addr>=base_adr)
    {
        QSPI_W25QXX_Read(pDestBuff,(Addr-base_adr),NumBytes);
    }
    // 内存映射
#if  (EN_MDK_FLM_MAP>0)
    result = QSPI_EnableMemoryMappedMode();
    if(result != 0)
    {
        //
        usr_printf("SEGGER_OPEN_Read :%X\r\n",result);
        //
        return 0;
    }
#endif
    return NumBytes;
}
/*
*********************************************************************************************************

*********************************************************************************************************
*/
int SEGGER_OPEN_Program(U32 DestAddr,   U32 NumBytes,     U8  *pSrcBuff)
{
    uint32_t  result=0;
    uint32_t  size_shi=0;
    uint32_t  size_ge=0;
    uint32_t  i=0;
    uint8_t   *pbuf=(uint8_t *)pSrcBuff;
    //
    size_shi=NumBytes/PAGE_SIZE;
    //
    size_ge =NumBytes%PAGE_SIZE;
    //
#if  (EN_MDK_FLM_MAP>0)
    Stm32_Clock_Init(5,160,2,2,2);//设置时钟,400Mhz
    uart_init(400,DEBUG_BAUD_RATE);
    QSPI_W25QXX_Init();                 //初始化W25QXX
#elif (MDK_FLM_INIT_EN>0)
    Stm32_Clock_Init(5,160,2,2,2);//设置时钟,400Mhz
    uart_init(400,DEBUG_BAUD_RATE);
    QSPI_W25QXX_Init();                 //初始化W25QXX
#else
    QSPI_W25QXX_Init();                 //初始化W25QXX
#endif
    //
    SCB_CleanInvalidateDCache();
    //
    SCB_CleanDCache();
    //
    usr_printf("SEGGER_OPEN_Program  adr:0x%x ,sz: %ld ,buf :0x%x \r\n",(uint32_t)DestAddr,NumBytes,(uint32_t)pSrcBuff);
    //
    if(DestAddr>=base_adr)
    {
        if(size_shi>0)
        {
            for(i=0;i<size_shi;i++)
            {
                QSPI_W25QXX_Write((pbuf+i*PAGE_SIZE),(DestAddr-base_adr)+i*PAGE_SIZE,PAGE_SIZE);   
            }
        }
        //
        if(size_ge>0)
        {
            QSPI_W25QXX_Write((pbuf+size_shi*PAGE_SIZE), (DestAddr-base_adr)+size_shi*PAGE_SIZE, size_ge); 
        }
        //
    }
    // 内存映射
#if  (EN_MDK_FLM_MAP>0)
    result = QSPI_EnableMemoryMappedMode();
    if(result != 0)
    {
        //
        usr_printf("SEGGER_OPEN_Program :%X\r\n",result);
        //
        return 1;
    }
#endif
    return (0);  
}
/*
*********************************************************************************************************

*********************************************************************************************************
*/
int SEGGER_OPEN_Erase(U32 SectorAddr, U32 SectorIndex,  U32 NumSectors)
{
    uint32_t  result=0;
    //
#if  (EN_MDK_FLM_MAP>0)
    Stm32_Clock_Init(5,160,2,2,2);//设置时钟,400Mhz
    uart_init(400,DEBUG_BAUD_RATE);
    QSPI_W25QXX_Init();                 //初始化W25QXX
#elif (MDK_FLM_INIT_EN>0)
    Stm32_Clock_Init(5,160,2,2,2);//设置时钟,400Mhz
    uart_init(400,DEBUG_BAUD_RATE);
    QSPI_W25QXX_Init();                 //初始化W25QXX
#else
    QSPI_W25QXX_Init();                 //初始化W25QXX
#endif
    //
    usr_printf("SEGGER_OPEN_Erase  adr:0x%x ,SectorIndex: %ld ,NumSectors :%d \r\n",(uint32_t)SectorAddr,SectorIndex,(uint32_t)NumSectors);
    //
    do{
        //
        if(SectorAddr>=base_adr)
        {
            QSPI_W25QXX_Erase_Sector(SectorAddr-base_adr);
        }
        //
        SectorAddr += QSPI_SECTOR_SIZE;
        //
        SectorIndex++;
        //
    } while (--NumSectors);
    //
    // 内存映射
#if  (EN_MDK_FLM_MAP>0)
    result = QSPI_EnableMemoryMappedMode();
    if(result != 0)
    {
        //
        usr_printf("EraseSector :%X\r\n",result);
        //
        return 1;
    }
#endif
    return (0);   
}
/*
*********************************************************************************************************

*********************************************************************************************************
*/
#else
/*
*********************************************************************************************************

*********************************************************************************************************
*/
/*
 *  Initialize Flash Programming Functions
 *    Parameter:      adr:  Device Base Address
 *                    clk:  Clock Frequency (Hz)
 *                    fnc:  Function Code (1 - Erase, 2 - Program, 3 - Verify)
 *    Return Value:   0 - OK,  1 - Failed
 */
//这个函数在keil下载后,在擦除、编程都会重新调用一次此函数,而且在调用此函数之前keil会复位单片机,相当于单片机跑起来的初始化功能要在擦除、编程时都要初始化一遍
int Init(unsigned long adr, unsigned long clk, unsigned long fnc)
{
    uint32_t  result=0;
    //
	SystemInit();
    //
    Stm32_Clock_Init(5,160,2,2,2);//设置时钟,400Mhz
    //串口初始化
    uart_init(400,DEBUG_BAUD_RATE);
    //
    QSPI_W25QXX_Init();                 //初始化W25QXX
    //
    base_adr = QSPI_ADDR_BASE;
    //
    usr_printf("base addr:%x \r\n",base_adr);
    usr_printf("h750 flm ver: %d.%d.%d VERIFY:%d,MAP:%d,BLANK:%d,PROG_WR:%d,FLM_INIT:%d\r\n",
                FLM_VER_Main,FLM_VER_SUB1,FLM_VER_SUB2,
                EN_MDK_FLM_VERIFY,EN_MDK_FLM_MAP,
                BlankCheck_EN,PROG_READ_WRITE_EN,
                MDK_FLM_INIT_EN     );
    //
#if  (EN_MDK_FLM_MAP>0)
    // 内存映射
    result = QSPI_EnableMemoryMappedMode();
    if(result != 0)
    {
        //
        usr_printf("Init :%X\r\n",result);
        //
        return 1;
    }
#endif
    //
    write_flag=0;
    return (0);
}


/*
 *  De-Initialize Flash Programming Functions
 *    Parameter:      fnc:  Function Code (1 - Erase, 2 - Program, 3 - Verify)
 *    Return Value:   0 - OK,  1 - Failed
 */

int UnInit(unsigned long fnc)
{
#if  (EN_MDK_FLM_MAP>0)
    uint32_t  result=0;
    //
#if  (EN_MDK_FLM_MAP>0)
    Stm32_Clock_Init(5,160,2,2,2);//设置时钟,400Mhz
    uart_init(400,DEBUG_BAUD_RATE);
    QSPI_W25QXX_Init();                 //初始化W25QXX
#elif (MDK_FLM_INIT_EN>0)
    Stm32_Clock_Init(5,160,2,2,2);//设置时钟,400Mhz
    uart_init(400,DEBUG_BAUD_RATE);
    QSPI_W25QXX_Init();                 //初始化W25QXX
#else
    QSPI_W25QXX_Init();                 //初始化W25QXX
#endif
    // 内存映射
    result = QSPI_EnableMemoryMappedMode();
    if(result != 0)
    {
        //
        usr_printf("UnInit :%X\r\n",result);
        //
        return 1;
    }
#endif
    //
    return (0);
}


/*
 *  Erase complete Flash Memory
 *    Return Value:   0 - OK,  1 - Failed
 */

int EraseChip(void)
{
    uint32_t  result=0;
    //
#if  (EN_MDK_FLM_MAP>0)
    Stm32_Clock_Init(5,160,2,2,2);//设置时钟,400Mhz
    uart_init(400,DEBUG_BAUD_RATE);
    QSPI_W25QXX_Init();                 //初始化W25QXX
#elif (MDK_FLM_INIT_EN>0)
    Stm32_Clock_Init(5,160,2,2,2);//设置时钟,400Mhz
    uart_init(400,DEBUG_BAUD_RATE);
    QSPI_W25QXX_Init();                 //初始化W25QXX
#else
    QSPI_W25QXX_Init();                 //初始化W25QXX
#endif
    //
    QSPI_W25QXX_Erase_Chip();
    // 内存映射
#if  (EN_MDK_FLM_MAP>0)
    result = QSPI_EnableMemoryMappedMode();
    if(result != 0)
    {
        //
        usr_printf("EraseChip :%X\r\n",result);
        //
        return 1;
    }
#endif
    //
    return (0);                                        
}


/*
 *  Erase Sector in Flash Memory
 *    Parameter:      adr:  Sector Address
 *    Return Value:   0 - OK,  1 - Failed
 */

int EraseSector(unsigned long adr)
{
    uint32_t  result=0;
    //
#if  (EN_MDK_FLM_MAP>0)
    Stm32_Clock_Init(5,160,2,2,2);//设置时钟,400Mhz
    uart_init(400,DEBUG_BAUD_RATE);
    QSPI_W25QXX_Init();                 //初始化W25QXX
#elif (MDK_FLM_INIT_EN>0)
    Stm32_Clock_Init(5,160,2,2,2);//设置时钟,400Mhz
    uart_init(400,DEBUG_BAUD_RATE);
    QSPI_W25QXX_Init();                 //初始化W25QXX
#else
    QSPI_W25QXX_Init();                 //初始化W25QXX
#endif
    //
    if(adr>=base_adr)
    {
        QSPI_W25QXX_Erase_Sector(adr-base_adr);
    }
    // 内存映射
#if  (EN_MDK_FLM_MAP>0)
    result = QSPI_EnableMemoryMappedMode();
    if(result != 0)
    {
        //
        usr_printf("EraseSector :%X\r\n",result);
        //
        return 1;
    }
#endif
    return (0);                                        
}


/*
 *  Blank Check Checks if Memory is Blank
 *    Parameter:      adr:  Block Start Address
 *                    sz:   Block Size (in bytes)
 *                    pat:  Block Pattern
 *    Return Value:   0 - OK,  1 - Failed
 */
#if  (BlankCheck_EN>0)
int BlankCheck(unsigned long adr, unsigned long sz, unsigned char pat)
{
    uint8_t* pData;

    pData = (uint8_t *)adr;
    do
    {
        if(*pData++ != pat)
        {
            return 1;
        }
    }
    while(--sz);
    return 0;                               
}
#else
//
int BlankCheck(unsigned long adr, unsigned long sz, unsigned char pat)
{
    uint32_t  size_shi=0;
    uint32_t  size_ge=0;
    uint32_t  i=0;
    uint32_t  j=0;
    //
    usr_printf("BlankCheck adr:0x%x ,sz: 0x%x ,pat :0x%x \r\n",(uint32_t)adr,(uint32_t)sz,pat);
    //
    size_shi=sz/PAGE_SIZE;
    //
    size_ge =sz%PAGE_SIZE;
    //
    if(size_shi>0)
    {
        for(i=0;i<size_shi;i++)
        {
            QSPI_W25QXX_Read((uint8_t*)aux_buf, (adr-base_adr)+i*PAGE_SIZE, PAGE_SIZE);
            //
            for(j=0;j<PAGE_SIZE;j++)
            {
                if(aux_buf[j] != pat)
                {
                    return 1;
                }
            }   
        }
    }
    //
    if(size_ge>0)
    {
        QSPI_W25QXX_Read((uint8_t*)aux_buf, (adr-base_adr)+size_shi*PAGE_SIZE, size_ge);
        //
        for(j=0;j<size_ge;j++)
        {
            if(aux_buf[j] != pat)
            {
                return 1;
            }
        }   
    }
    return 0;                               
}
//
#endif

/*
 *  Program Page in Flash Memory
 *    Parameter:      adr:  Page Start Address
 *                    sz:   Page Size
 *                    buf:  Page Data
 *    Return Value:   0 - OK,  1 - Failed
 */

int ProgramPage(unsigned long adr, unsigned long sz, unsigned char *buf)
{
    uint32_t  result=0;
    uint32_t  size_shi=0;
    uint32_t  size_ge=0;
    uint32_t  i=0;
    uint8_t   *pbuf=(uint8_t *)buf;
    //
    size_shi=sz/PAGE_SIZE;
    //
    size_ge =sz%PAGE_SIZE;
    //
#if  (EN_MDK_FLM_MAP>0)
    Stm32_Clock_Init(5,160,2,2,2);//设置时钟,400Mhz
    uart_init(400,DEBUG_BAUD_RATE);
    QSPI_W25QXX_Init();                 //初始化W25QXX
#elif (MDK_FLM_INIT_EN>0)
    Stm32_Clock_Init(5,160,2,2,2);//设置时钟,400Mhz
    uart_init(400,DEBUG_BAUD_RATE);
    QSPI_W25QXX_Init();                 //初始化W25QXX
#else
    QSPI_W25QXX_Init();                 //初始化W25QXX
#endif
    //
    SCB_CleanInvalidateDCache();
    //
    SCB_CleanDCache();
    //
    usr_printf("ProgramPage  adr:0x%x ,sz: %ld ,buf :0x%x \r\n",(uint32_t)adr,sz,(uint32_t)pbuf);
    //
    if(adr>=base_adr)
    {
        if(size_shi>0)
        {
            for(i=0;i<size_shi;i++)
            {
                QSPI_W25QXX_Write((pbuf+i*PAGE_SIZE),(adr-base_adr)+i*PAGE_SIZE,PAGE_SIZE);   
            }
        }
        //
        if(size_ge>0)
        {
            QSPI_W25QXX_Write((pbuf+size_shi*PAGE_SIZE), (adr-base_adr)+size_shi*PAGE_SIZE, size_ge); 
        }
        //
    }
    // 内存映射
#if  (EN_MDK_FLM_MAP>0)
    result = QSPI_EnableMemoryMappedMode();
    if(result != 0)
    {
        //
        usr_printf("ProgramPage :%X\r\n",result);
        //
        return 1;
    }
#endif
    return (0);                                       
}


/*
 *  Verify Flash Contents
 *    Parameter:      adr:  Start Address
 *                    sz:   Size (in bytes)
 *                    buf:  Data
 *    Return Value:   (adr+sz) - OK, Failed Address
 */
#if   (EN_MDK_FLM_VERIFY>0)
//
unsigned long Verify(unsigned long adr, unsigned long sz, unsigned char *buf)
{
    volatile unsigned char *psrc=buf;
    volatile unsigned long i;
    uint32_t  result=0;
    uint32_t  size_shi=0;
    uint32_t  size_ge=0;
    uint32_t  j=0;
    uint8_t   *pbuf=(uint8_t *)aux_buf;
    //
    size_shi=sz/PAGE_SIZE;
    //
    size_ge =sz%PAGE_SIZE;
    //
#if  (EN_MDK_FLM_MAP>0)
    Stm32_Clock_Init(5,160,2,2,2);//设置时钟,400Mhz
    uart_init(400,DEBUG_BAUD_RATE);
    QSPI_W25QXX_Init();                 //初始化W25QXX
#elif (MDK_FLM_INIT_EN>0)
    Stm32_Clock_Init(5,160,2,2,2);//设置时钟,400Mhz
    uart_init(400,DEBUG_BAUD_RATE);
    QSPI_W25QXX_Init();                 //初始化W25QXX
#else
    QSPI_W25QXX_Init();                 //初始化W25QXX
#endif
    //
    printf("start verify :0x%x ,0x%x,%d ,0x%x\r\n",(uint32_t)adr,(uint32_t)sz,(uint32_t)sz,(uint32_t)buf);
    //
    SCB_CleanInvalidateDCache();
    //
    SCB_CleanDCache();
    //
    if((sz> 0)&&(adr>=base_adr))
    {
        //
        if(size_shi>0)
        {
            for(i=0;i<size_shi;i++)
            {
                //
                memset((uint8_t*)pbuf,0,PAGE_SIZE);
                //
                QSPI_W25QXX_Read((pbuf),(adr-base_adr)+i*PAGE_SIZE,PAGE_SIZE);   
                //
                for(j = 0; j< PAGE_SIZE; j++)
                {
                    if(aux_buf[j] != psrc[j+i*PAGE_SIZE])
                    {
                        //
                        debug_log("erroffset:%d base addr:%x addr:%lx data--read:%x  write:%x\r\n",
                        (uint32_t)(j+i*PAGE_SIZE),base_adr,adr,aux_buf[j],psrc[j+i*PAGE_SIZE]);
                        //
                        return (adr+j+i*PAGE_SIZE);                  
                    }
                }
            }
        }
        //
        if(size_ge>0)
        {
            //
            memset((uint8_t*)pbuf,0,PAGE_SIZE);
            //
            QSPI_W25QXX_Read((pbuf+size_shi*PAGE_SIZE), (adr-base_adr)+size_shi*PAGE_SIZE, size_ge); 
            //
            for(j = 0; j< size_ge; j++)
            {
                if(aux_buf[j] != psrc[j+size_shi*PAGE_SIZE])
                {
                    //
                    debug_log("erroffset:%d base addr:%x addr:%lx data--read:%x  write:%x\r\n",
                    (uint32_t)(j+size_shi*PAGE_SIZE),base_adr,adr,aux_buf[j],psrc[j+size_shi*PAGE_SIZE]);
                    //
                    return (adr+j+size_shi*PAGE_SIZE);                  
                }
            }
        }
        //
        return (adr+sz);  
    }
    else
    {
        // 内存映射
#if  (EN_MDK_FLM_MAP>0)
        result = QSPI_EnableMemoryMappedMode();
        if(result != 0)
        {
            //
            usr_printf("Verify3 :%X\r\n",result);
            //
            return (adr);
        }
#endif
        return (adr);
    }
}
//
#endif

/*
*********************************************************************************************************

*********************************************************************************************************
*/
//
// SEGGER defined functions
//
int SEGGER_OPEN_Read(unsigned long Addr,       unsigned long NumBytes,     unsigned char  *pDestBuff)
{
    uint32_t  result=0;
    //
#if  (EN_MDK_FLM_MAP>0)
    Stm32_Clock_Init(5,160,2,2,2);//设置时钟,400Mhz
    uart_init(400,DEBUG_BAUD_RATE);
    QSPI_W25QXX_Init();                 //初始化W25QXX
#elif (MDK_FLM_INIT_EN>0)
    Stm32_Clock_Init(5,160,2,2,2);//设置时钟,400Mhz
    uart_init(400,DEBUG_BAUD_RATE);
    QSPI_W25QXX_Init();                 //初始化W25QXX
#else
    QSPI_W25QXX_Init();                 //初始化W25QXX
#endif
    //
    SCB_CleanInvalidateDCache();
    //
    SCB_CleanDCache();
    //
    usr_printf("SEGGER_OPEN_Read  adr:0x%x ,sz: 0x%x ,buf :0x%x \r\n",(uint32_t)Addr,NumBytes,(uint32_t)pDestBuff);
    //
    if(Addr>=base_adr)
    {
        QSPI_W25QXX_Read(pDestBuff,(Addr-base_adr),NumBytes);
    }
    // 内存映射
#if  (EN_MDK_FLM_MAP>0)
    result = QSPI_EnableMemoryMappedMode();
    if(result != 0)
    {
        //
        usr_printf("SEGGER_OPEN_Read :%X\r\n",result);
        //
        return 0;
    }
#endif
    return NumBytes;
}
/*
*********************************************************************************************************

*********************************************************************************************************
*/
int SEGGER_OPEN_Program(unsigned long DestAddr,   unsigned long NumBytes,     unsigned char  *pSrcBuff)
{
    uint32_t  result=0;
    uint32_t  size_shi=0;
    uint32_t  size_ge=0;
    uint32_t  i=0;
    uint8_t   *pbuf=(uint8_t *)pSrcBuff;
    //
    size_shi=NumBytes/PAGE_SIZE;
    //
    size_ge =NumBytes%PAGE_SIZE;
    //
#if  (EN_MDK_FLM_MAP>0)
    Stm32_Clock_Init(5,160,2,2,2);//设置时钟,400Mhz
    uart_init(400,DEBUG_BAUD_RATE);
    QSPI_W25QXX_Init();                 //初始化W25QXX
#elif (MDK_FLM_INIT_EN>0)
    Stm32_Clock_Init(5,160,2,2,2);//设置时钟,400Mhz
    uart_init(400,DEBUG_BAUD_RATE);
    QSPI_W25QXX_Init();                 //初始化W25QXX
#else
    QSPI_W25QXX_Init();                 //初始化W25QXX
#endif
    //
    SCB_CleanInvalidateDCache();
    //
    SCB_CleanDCache();
    //
    usr_printf("SEGGER_OPEN_Program  adr:0x%x ,sz: %ld ,buf :0x%x \r\n",(uint32_t)DestAddr,NumBytes,(uint32_t)pbuf);
    //
    if(DestAddr>=base_adr)
    {
        if(size_shi>0)
        {
            for(i=0;i<size_shi;i++)
            {
                QSPI_W25QXX_Write((pbuf+i*PAGE_SIZE),(DestAddr-base_adr)+i*PAGE_SIZE,PAGE_SIZE);   
            }
        }
        //
        if(size_ge>0)
        {
            QSPI_W25QXX_Write((pbuf+size_shi*PAGE_SIZE), (DestAddr-base_adr)+size_shi*PAGE_SIZE, size_ge); 
        }
        //
    }
    //
    usr_printf("\r\nSEGGER_OPEN_Program  finish \r\n");
    //
    // 内存映射
#if  (EN_MDK_FLM_MAP>0)
    result = QSPI_EnableMemoryMappedMode();
    if(result != 0)
    {
        //
        usr_printf("SEGGER_OPEN_Program :%X\r\n",result);
        //
        return 1;
    }
#endif
    return (0);   
}
/*
*********************************************************************************************************

*********************************************************************************************************
*/
int SEGGER_OPEN_Erase(unsigned long SectorAddr, unsigned long SectorIndex,  unsigned long NumSectors)
{
    uint32_t  result=0;
    //
#if  (EN_MDK_FLM_MAP>0)
    Stm32_Clock_Init(5,160,2,2,2);//设置时钟,400Mhz
    uart_init(400,DEBUG_BAUD_RATE);
    QSPI_W25QXX_Init();                 //初始化W25QXX
#elif (MDK_FLM_INIT_EN>0)
    Stm32_Clock_Init(5,160,2,2,2);//设置时钟,400Mhz
    uart_init(400,DEBUG_BAUD_RATE);
    QSPI_W25QXX_Init();                 //初始化W25QXX
#else
    QSPI_W25QXX_Init();                 //初始化W25QXX
#endif
    //
    usr_printf("SEGGER_OPEN_Erase  adr:0x%x ,SectorIndex: %ld ,NumSectors :%d \r\n",(uint32_t)SectorAddr,SectorIndex,(uint32_t)NumSectors);
    //
    do{
        //
        if(SectorAddr>=base_adr)
        {
            QSPI_W25QXX_Erase_Sector(SectorAddr-base_adr);
        }
        //
        SectorAddr += QSPI_SECTOR_SIZE;
        //
        SectorIndex++;
        //
    } while (--NumSectors);
    //
    // 内存映射
#if  (EN_MDK_FLM_MAP>0)
    result = QSPI_EnableMemoryMappedMode();
    if(result != 0)
    {
        //
        usr_printf("EraseSector :%X\r\n",result);
        //
        return 1;
    }
#endif
    return (0);   
}
/*
*********************************************************************************************************

*********************************************************************************************************
*/
#endif
/*
*********************************************************************************************************

*********************************************************************************************************
*/
  • 4
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
STM32CubeMX是一个用于配置STM32微控制器的图形化工具,可以方便地配置和生成基于Cube库的应用程序代码。对于使用SPI Flash的应用,可以使用STM32CubeMX生成相应的初始化代码。 首先,打开STM32CubeMX,并选择相应的微控制器型号。 然后,在"Pinout & Configuration"选项卡中,找到SPI接口并启用它。选择相应的SPI引脚,并配置SPI的时钟速度、数据位长度等参数。 接下来,在"Configuration"选项卡中,找到"Middleware"部分,并选择"FatFS"文件系统。选择相应的SPI接口和对应的CS引脚。 然后,在"Project"窗口中,选择"Project Manager"选项卡。点击"Generate Code"按钮,生成初始化代码。 生成的初始化代码将包含有关SPI Flash的配置和操作。可以在生成的代码中找到相关的函数,如SPI_Init()用于初始化SPI接口,SPI_Transmit()用于发送数据,SPI_Receive()用于接收数据等。 使用这些函数,可以编写算法来实现SPI Flash的下载。通常的步骤如下: 1. 初始化SPI接口,设置SPI Flash的工作模式、时钟速度和数据位长度等参数。 2. 发送写入Enable Latch命令以启用写入操作。 3. 将待下载的数据写入SPI Flash的指定地址。可以使用循环来逐个字节地写入。 4. 发送写入Disable Latch命令以禁用写入操作,保护已写入的数据。 5. 可以使用SPI Flash的Read命令来验证写入的数据,以确保下载成功。 需要注意的是,不同的SPI Flash芯片可能有不同的指令集和操作模式。在编写算法时,应根据具体的SPI Flash型号和数据手册来进行相应的配置和操作。 总结来说,使用STM32CubeMX可以方便地配置和生成SPI Flash的初始化代码,通过编写相应的算法来实现SPI Flash的下载。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值