【STM32H7教程】第85章 STM32H7的SPI 總線應用之SPI Flash的STM32CubeProg下載算法制作


完整教程下載地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980

第85章       STM32H7的SPI 總線應用之SPI Flash的STM32CubeProg下載算法制作

本章節為大家講解STM32CubeProg下載算法制作方法。

85.1 初學者重要提示

85.2 STM32CubeProg簡介

85.3 STM32CubeProg下載算法基礎知識

85.4 創建STM32CubeProg下載算法通用流程

85.4 SPI Flash的STM32CubeProg下載算法制作

85.5 SPI Flash的STM32CubeProg下載算法使用方法

85.6 實驗例程說明

85.7 總結

 

 

 

85.1 初學者重要提示

  1.   QSPI Flash的相關知識點可以看第78章和79章。
  2.   QSPI Flash下載算法文件直接采用HAL庫制作,方便大家自己修改。
  3.   STM32CubeProg下載算法制作和MDK下載算法制作基本是一樣
  4.   本教程的第68章USB DFU和第69章串口IAP章節為大家介紹過STM32CubeProg的用法。STM32CubeProg下載http://www.armbbs.cn/forum.php?mod=viewthread&tid=97370

85.2 STM32CubeProg簡介

STM32CubeProg,此軟件實現了之前的 DfuSe,STLINK 小軟件和 Flashloader 三合一,並且支持外部 EEPROM,NOR Flash,SPI Flash,NAND Flash 等燒寫,也支持 OTA 編程。

 

85.3 STM32CubeProg下載算法基礎知識

STM32CubeProg下載算法是一種用於擦除應用程序或將應用程序下載到Flash的程序代碼。ST自家的芯片都自帶下載算法,存放在STM32CubeProg安裝目錄里面,但不支持的需要我們自己制作,本章教程為此而生。

85.3.1 程序能夠通過下載算法下載到芯片的核心思想

認識到這點很重要:通過IDE開發環境創建一批與地址信息無關的算法文件,實現的功能主要有初始化,擦除,編程,讀取,校驗等,然后STM32CubeProg下載階段,會將算法文件加載到芯片的內部RAM里面,然后STM32CubeProg通過與這個算法文件的交互,實現程序下載,數據讀取等操作。

85.3.2 算法程序中擦除操作執行流程

注:下面是MDK的算法執行流程,STM32CubeProg是類似的。

擦除操作大致流程:

 

  1.   加載算法到芯片RAM。
  2.   執行初始化函數Init。
  3.   執行擦除操作,根據用戶配置,這里可以選擇整個芯片擦除或者扇區擦除。
  4.   執行Uinit函數。
  5.   操作完畢。

85.3.3 算法程序中編程操作執行流程

注:下面是MDK的算法執行流程,STM32CubeProg是類似的(沒有Unint函數)。

編程操作大致流程:

 

  •   針對IDE生成的axf(elf)可執行文件做Init初始化,這個axf(elf)文件是指的大家自己創建應用程序生成的。
  •   查看Flash算法是否在FLM文件。如果沒有在,操作失敗。如果在:
    •   加載算法到RAM。
    •   執行Init函數。
    •   加載用戶到RAM緩沖。
    •   執行Program Page頁編程函數。
    •   執行Uninit函數。
  •   操作完畢。

85.3.4 算法程序中校驗操作執行流程

注:下面是MDK的算法執行流程,STM32CubeProg是類似的(沒有Unint函數)。

校驗操作大致流程:

 

  •   校驗要用到IDE生成的axf(elf)可執行文件。校驗就是axf(elf)文件中下載到芯片的程序和實際下載的程序讀出來做比較。
  •   查看Flash算法是否在FLM文件。如果沒有在,操作失敗。如果在:
    •  加載算法到RAM。
    •  執行Init函數。
    •  查看校驗算法是否存在
  •   如果有,加載應用程序到RAM並執行校驗。
  •   如果沒有,執行計算CRC,將芯片中讀取數據出來和RAM中加載應用計算輸出的CRC值做比較。
    •   執行Uninit函數。
    •   替換BKPT(BreakPoint斷點指令)為 B. 死循環指令。
    •   執行RecoverySupportStop,回復支持停止。
    •   執行DebugCoreStop,調試內核停止。
  •   運行應用:
    •   執行失敗
    •   執行成功,再執行硬件復位。
  •   操作完畢,停止調試端口。

85.4 創建STM32CubeProg下載算法通用流程

下面是STM32CubeProg給的一種大致操作流程,不限制必須采用這種方法,自己創建也可以的。

85.4.1 第1步,使用STM32CubeProg提供好的程序模板

位於路徑:STMicroelectronics\STM32Cube\STM32CubeProgrammer\bin\ExternalLoader

 

以M25P64為例(注,其余步驟就以這個為例子進行說明):

 

85.4.2 第2步,修改工程名

STM32CubeProg提供的工程模板原始名字是M25P64_STM3210E-EVAL.uvproj,大家可以根據自己的需要做修改。比如修改為MyDevice.uvproj(MDK4的后綴)或者MyDevice.uvprojx(MDK5的后綴)。

85.4.3 第3步,修改使用的器件

在MDK的Option選項里面設置使用的器件。

 

85.4.4 第4步,修改輸出算法文件的名字

這個名字是方便用戶查看的,比如設置為stm32h7,那么輸出的算法文件就是stm32h7.stldr。

 

注:STM32CubeProg軟件里面別的文件名並不采用這個,而是由用戶在文件Dev_Inf.c里面定義的:

 

85.4.5 第5步,修改使用的庫文件和頭文件路徑

根據大家使用的主控芯片,添加相應的庫文件和頭文件路徑。

85.4.6 第5步,修改編程算法文件Loader_Src.c

模板工程里面提供的是M25P64,部分代碼如下:

/**
  * Description :
  * Initilize the MCU Clock, the GPIO Pins corresponding to the
  * device and initilize the FSMC with the chosen configuration 
  * Inputs    :
  *      None
  * outputs   :
  *      R0             : "1"             : Operation succeeded
  *               "0"             : Operation failure
  * Note: Mandatory for all types of device 
  */
int Init (void)
{  
  SystemInit();
  sFLASH_Init();
  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   :
  *      R0             : "1"             : Operation succeeded
  *               "0"             : Operation failure
  * Note: Mandatory for all types except SRAM and PSRAM    
  */
int Read (uint32_t Address, uint32_t Size, uint8_t* buffer)
{ 
  sFLASH_ReadBuffer(buffer, Address, Size);
  return 1;
} 

    
/**
  * Description :
  * Write data from the device 
  * Inputs    :
  *      Address       : Write location
  *      Size          : Length in bytes  
  *      buffer        : Address where to get the data to write
  * outputs   :
  *      R0           : "1"             : Operation succeeded
  *                     "0"             : Operation failure
  * Note: Mandatory for all types except SRAM and PSRAM    
  */
int Write (uint32_t Address, uint32_t Size, uint8_t* buffer)
{
  sFLASH_WriteBuffer(buffer, Address, Size);
  return 1;
} 


/**
  * Description :
  * Erase a full sector in the device
  * Inputs    :
  *     None
  * outputs   :
  *     R0             : "1" : Operation succeeded
  *              "0" : Operation failure
  * Note: Not Mandatory for SRAM PSRAM and NOR_FLASH
  */
int MassErase (void)
{  
  sFLASH_EraseBulk();
  return 1;    
}

85.4.7 第6步,修改配置文件Dev_Inf.c

模板工程里面提供簡單的配置說明:

#if defined (__ICCARM__)
__root struct StorageInfo const StorageInfo  =  {
#else
struct StorageInfo const StorageInfo  =  {
#endif
   "M25P64_STM3210E-EVAL",           // Device Name + version number
   SPI_FLASH,                       // Device Type
   0x00000000,                     // Device Start Address
   0x00800000,                      // Device Size in Bytes (8MBytes/64Mbits)
   0x00000100,                      // Programming Page Size 16Bytes
   0xFF,                            // Initial Content of Erased Memory
// Specify Size and Address of Sectors (view example below)
   0x00000080, 0x00010000,          // Sector Num : 128 ,Sector Size: 64KBytes 
   0x00000000, 0x00000000,
};

注:名字M25P64_STM3210E-EVAL就是我們第4步所說的。STM32CubeProg會識別出這個名字。

 

85.4.8 第7步,保證生成的算法文件中RO和RW段的獨立性,即與地址無關。

C和匯編的配置都勾選上:

 

匯編:

 

如果程序的所有只讀段都與位置無關,則該程序為只讀位置無關(ROPI, Read-only position independence)。ROPI段通常是位置無關代碼(PIC,position-independent code),但可以是只讀數據,也可以是PIC和只讀數據的組合。選擇“ ROPI”選項,可以避免不得不將代碼加載到內存中的特定位置。這對於以下例程特別有用:

(1)加載以響應運行事件。

(2)在不同情況下使用其他例程的不同組合加載到內存中。

(3)在執行期間映射到不同的地址。

 

使用Read-Write position independence同理,表示的可讀可寫數據段。

85.4.9 第8步,將程序可執行文件axf修改為stldr格式

通過下面的命令就可以將生成的axf可執行文件修改為stldr。

 

85.4.10   第9步,分散加載設置

我們這里的分散加載文件直接使用MDK模板工程里提供好的即可。

 

分散加載文件中的內容如下:

FLASH_LOADER 0x20000004 PI   ; FlashLoader Functions
{
  PrgCode +0           ; Code
  {
    * (+RO)
  }
  PrgData +0           ; Data
  {
    * (+RW,+ZI)
  }
}

DEVICE_INFO +0               ; Device Info
{
  DevInfo +0           ; Info structure
  {
    dev_inf.o
  }
}

這里要修改下Flash算法加載地址,將0x20000004修改為STM32H7的RAM地址,任何RAM塊地址均可,只要夠存儲Flash算法。推薦設置為AXI SRAM地址0x24000004,因為空間夠大,有512KB。

--diag_suppress L6305用於屏蔽L6503類型警告信息。

特別注意,設置了分散加載后,此處的配置就不再起作用了:

 

85.5 SPI Flash的STM32CubeProg下載算法制作

下面將SPI Flash算法制作過程中的幾個關鍵點為大家做個說明。

85.5.1 第1步,制作前重要提示

這兩點非常重要:

  •   程序里面不要開啟任何中斷,全部查詢方式。
  •   HAL庫里面各種時間基准相關的API全部處理掉。簡單省事些,我們這里是直接注釋,采用死等即可。無需做超時等待,因為超時后,已經意味着操作失敗了,跟死等沒有區別。

85.5.2 第2步,准備一個工程模板

 推薦大家直接使用我們本章工程准備好的模板即可,如果大家自己制作,注意一點,請使用當前最新的HAL庫。

 

85.5.3 第3步,修改HAL庫

這一步比較重要,主要修改了以下三個文件:

 

主要是修改了HAL庫時間基准相關的幾個API,並注釋掉了一批無關的API。具體修改內容,大家可以找個比較軟件,對比修改后的這個文件和CubeH7軟件包V1.8.0(軟件包里面的HAL庫版本是V1.9.0)的差異即可。

85.5.4 第4步,時鍾初始化

我們已經用不到滴答定時器了,直接在bsp.c文件里面對滴答初始化函數做重定向:

/*
*********************************************************************************************************
*    函 數 名: HAL_InitTick
*    功能說明: 重定向,不使用
*    形    參: TickPriority
*    返 回 值: 無
*********************************************************************************************************
*/
HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
    return HAL_OK;
}

然后就是HSE外置晶振的配置,大家根據自己的板子實際外掛晶振大小,修改stm32h7xx_hal_conf.h文件中HSE_VALUE大小,實際晶振多大,這里就修改為多大:

#if !defined  (HSE_VALUE) 
#define HSE_VALUE    ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */
#endif /* HSE_VALUE */

最后修改PLL:

/*
*********************************************************************************************************
*    函 數 名: SystemClock_Config
*    功能說明: 初始化系統時鍾
*                System Clock source            = PLL (HSE)
*                SYSCLK(Hz)                     = 400000000 (CPU Clock)
*               HCLK(Hz)                       = 200000000 (AXI and AHBs Clock)
*                AHB Prescaler                  = 2
*                D1 APB3 Prescaler              = 2 (APB3 Clock  100MHz)
*                D2 APB1 Prescaler              = 2 (APB1 Clock  100MHz)
*                D2 APB2 Prescaler              = 2 (APB2 Clock  100MHz)
*                D3 APB4 Prescaler              = 2 (APB4 Clock  100MHz)
*                HSE Frequency(Hz)              = 25000000
*               PLL_M                          = 5
*                PLL_N                          = 160
*                PLL_P                          = 2
*                PLL_Q                          = 4
*                PLL_R                          = 2
*                VDD(V)                         = 3.3
*                Flash Latency(WS)              = 4
*    形    參: 無
*    返 回 值: 1 表示失敗,0 表示成功
*********************************************************************************************************
*/
int SystemClock_Config(void)
{
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    HAL_StatusTypeDef ret = HAL_OK;

    /* 鎖住SCU(Supply configuration update) */
    MODIFY_REG(PWR->CR3, PWR_CR3_SCUEN, 0);

    /* 
      1、芯片內部的LDO穩壓器輸出的電壓范圍,可選VOS1,VOS2和VOS3,不同范圍對應不同的Flash讀速度,
         詳情看參考手冊的Table 12的表格。
      2、這里選擇使用VOS1,電壓范圍1.15V - 1.26V。
    */
    __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

    while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}

    /* 使能HSE,並選擇HSE作為PLL時鍾源 */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.HSIState = RCC_HSI_OFF;
    RCC_OscInitStruct.CSIState = RCC_CSI_OFF;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
        
    RCC_OscInitStruct.PLL.PLLM = 5;
    RCC_OscInitStruct.PLL.PLLN = 160;
    RCC_OscInitStruct.PLL.PLLP = 2;
    RCC_OscInitStruct.PLL.PLLR = 2;
    RCC_OscInitStruct.PLL.PLLQ = 4;        
        
    RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
    RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2;    
    ret = HAL_RCC_OscConfig(&RCC_OscInitStruct);
    if(ret != HAL_OK)
    {
        return 1;        
    }

    /* 
       選擇PLL的輸出作為系統時鍾
       配置RCC_CLOCKTYPE_SYSCLK系統時鍾
       配置RCC_CLOCKTYPE_HCLK 時鍾,對應AHB1,AHB2,AHB3和AHB4總線
       配置RCC_CLOCKTYPE_PCLK1時鍾,對應APB1總線
       配置RCC_CLOCKTYPE_PCLK2時鍾,對應APB2總線
       配置RCC_CLOCKTYPE_D1PCLK1時鍾,對應APB3總線
       配置RCC_CLOCKTYPE_D3PCLK1時鍾,對應APB4總線     
    */
    RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_D1PCLK1 | RCC_CLOCKTYPE_PCLK1 | \
                                 RCC_CLOCKTYPE_PCLK2  | RCC_CLOCKTYPE_D3PCLK1);

    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
    RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;  
    RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2; 
    RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2; 
    RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2; 
    
    /* 此函數會更新SystemCoreClock,並重新配置HAL_InitTick */
    ret = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4);
    if(ret != HAL_OK)
    {
        return 1;
    }

    /*
      使用IO的高速模式,要使能IO補償,即調用下面三個函數 
      (1)使能CSI clock
      (2)使能SYSCFG clock
      (3)使能I/O補償單元, 設置SYSCFG_CCCSR寄存器的bit0
    */
    __HAL_RCC_CSI_ENABLE() ;

    __HAL_RCC_SYSCFG_CLK_ENABLE() ;

    HAL_EnableCompensationCell();

    __HAL_RCC_D2SRAM1_CLK_ENABLE();
    __HAL_RCC_D2SRAM2_CLK_ENABLE();
    __HAL_RCC_D2SRAM3_CLK_ENABLE();
    
    return 0;
}

85.5.5 第5步,配置文件Dev_Inf.c的實現

配置如下:

#if defined (__ICCARM__)
__root struct StorageInfo const StorageInfo  =  {
#else
struct StorageInfo const StorageInfo =  {
#endif
    "ARMFLY_STM32H743_SPI_W25Q64", /* 算法名,添加算法到STM32CubeProg安裝目錄會顯示此名字 */
    NOR_FLASH,                      /* 設備類型 */
    0xC0000000,                     /* Flash起始地址 */
    8 * 1024 * 1024,                /* Flash大小,8MB */
    4096,                           /* 編程頁大小 */
    0xFF,                           /* 擦除后的數值 */
    2048 , 4 * 1024,                /* 塊個數和塊大小 */
    0x00000000, 0x00000000,
};

注釋已經比較詳細,大家根據自己的需要做修改即可。注意一點,算法名ARMFLY_STM32H743_SPI_W25Q64會反饋到這個地方:

 

85.5.6 第6步,編程文件Loader_Src.c的實現

下面將變成文件中實現的幾個函數為大家做個說明:

  •   初始化函數Init
/*
*********************************************************************************************************
*    函 數 名: Init
*    功能說明: Flash編程初始化
*    形    參: 無
*    返 回 值: 0 表示失敗, 1表示成功
*********************************************************************************************************
*/
int Init(void)
{   
    int result = 0;

    /* 系統初始化 */
    SystemInit(); 

    /* 時鍾初始化 */
    result = SystemClock_Config();
    if (result == 1)
    {
        return 0;
    }

    /* SPI Flash初始化 */
    bsp_InitSPIBus();
    bsp_InitSFlash();

    return 1;
}
  •   整個芯片擦除函數MassErase

整個芯片的擦除實現如下:

/*
*********************************************************************************************************
*    函 數 名: MassErase
*    功能說明: 整個芯片擦除
*    形    參: 無
*    返 回 值: 1 表示成功,0表示失敗
*********************************************************************************************************
*/
int MassErase(void)
{
    sf_EraseChip();

    return 1;   
}
  •   扇區擦除函數SectorErase
/*
*********************************************************************************************************
*    函 數 名: SectorErase
*    功能說明: EraseStartAddress 擦除起始地址
*             EraseEndAddress   擦除結束地址
*    形    參: adr 擦除地址
*    返 回 值: 1 表示成功,0表示失敗
*********************************************************************************************************
*/
int SectorErase (uint32_t EraseStartAddress ,uint32_t EraseEndAddress)
{
    uint32_t BlockAddr;
    
    EraseStartAddress -= SPI_FLASH_MEM_ADDR;
    EraseEndAddress -= SPI_FLASH_MEM_ADDR;
    EraseStartAddress = EraseStartAddress -  EraseStartAddress % 0x1000; /* 4KB首地址 */
    
    while (EraseEndAddress >= EraseStartAddress)
    {
        BlockAddr = EraseStartAddress & 0x0FFFFFFF;

        sf_EraseSector(BlockAddr);    

        EraseStartAddress += 0x1000;
    }

    return 1;
}

這里要注意兩點:

(1)     程序里面的操作EraseStartAddress-= SPI_FLASH_MEM_ADDR,實際傳遞進來的地址是帶了首地址的,即0xC0000000。

(2)     這里執行的擦除大小要前面Dev_Inf.c文件中配置的扇區大小一致,這里是執行的4KB為扇區進行擦除。

  •   頁編程函數Write

頁編程函數實現如下:

/*
*********************************************************************************************************
*    函 數 名: Write
*    功能說明: 寫數據到Device
*    形    參: Address 寫入地址
*             Size   寫入大小,單位字節
*             buffer 要寫入的數據地址
*    返 回 值: 1 表示成功,0表示失敗
*********************************************************************************************************
*/
int Write(uint32_t Address, uint32_t Size, uint8_t* buffer)
{  
    Address -= SPI_FLASH_MEM_ADDR;

    sf_WriteBuffer(buffer, Address, Size);
    
    return 1; 
}

這里注意兩點:

(1)     W25Q256的頁大小是256字節,前面FlashDev.c中將頁編程大小設置為4096字節,主要是方便擦除操作。

(2)     程序里面的操作Address-= SPI_FLASH_MEM_ADDR,實際傳遞進來的地址是帶了首地址的,即0xC0000000。

  •   讀取函數
/*
*********************************************************************************************************
*    函 數 名: Read
*    功能說明: 從SPI Flash讀取數據
*    形    參: Address 讀取地址
*             Size   讀取大小,單位字節
*             buffer 讀取存放的數據緩沖
*    返 回 值: 1 表示成功,0表示失敗
*********************************************************************************************************
*/
int Read(uint32_t Address, uint32_t Size, uint8_t* Buffer)
{ 
    Address -= SPI_FLASH_MEM_ADDR;
    sf_ReadBuffer(Buffer, Address, Size);

    return 1;
}
  •   讀取和校驗函數

我們程序中未做校驗函數。如果程序中未做校驗函數,那么STM32CubeProg會讀取數據做校驗。

85.5.7 第7步,修改SPI Flash驅動文件(引腳,命令等)

最后一步就是SPI Flash(W25Q64)的驅動修改,大家可以根據自己的需求做修改。使用的引腳定義在文件bsp_spi_bus.c:

/*
*********************************************************************************************************
*                                時鍾,引腳,DMA,中斷等宏定義
*********************************************************************************************************
*/
#define SPIx                            SPI1
#define SPIx_CLK_ENABLE()                __HAL_RCC_SPI1_CLK_ENABLE()
#define DMAx_CLK_ENABLE()                __HAL_RCC_DMA2_CLK_ENABLE()

#define SPIx_FORCE_RESET()                __HAL_RCC_SPI1_FORCE_RESET()
#define SPIx_RELEASE_RESET()            __HAL_RCC_SPI1_RELEASE_RESET()

#define SPIx_SCK_CLK_ENABLE()            __HAL_RCC_GPIOB_CLK_ENABLE()
#define SPIx_SCK_GPIO                    GPIOB
#define SPIx_SCK_PIN                    GPIO_PIN_3
#define SPIx_SCK_AF                        GPIO_AF5_SPI1

#define SPIx_MISO_CLK_ENABLE()            __HAL_RCC_GPIOB_CLK_ENABLE()
#define SPIx_MISO_GPIO                    GPIOB
#define SPIx_MISO_PIN                     GPIO_PIN_4
#define SPIx_MISO_AF                    GPIO_AF5_SPI1

#define SPIx_MOSI_CLK_ENABLE()            __HAL_RCC_GPIOB_CLK_ENABLE()
#define SPIx_MOSI_GPIO                    GPIOB
#define SPIx_MOSI_PIN                     GPIO_PIN_5
#define SPIx_MOSI_AF                    GPIO_AF5_SPI1

硬件設置了之后,剩下就是SPI Flash相關的幾個配置和片選引腳配置,在文件bsp_spi_flash.c:

主要是下面這幾個:

/* 串行Flash的片選GPIO端口, PD13  */
#define SF_CS_CLK_ENABLE()             __HAL_RCC_GPIOD_CLK_ENABLE()
#define SF_CS_GPIO                    GPIOD
#define SF_CS_PIN                    GPIO_PIN_13

#define SF_CS_0()                    SF_CS_GPIO->BSRR = ((uint32_t)SF_CS_PIN << 16U) 
#define SF_CS_1()                    SF_CS_GPIO->BSRR = SF_CS_PIN
    
#define CMD_AAI       0xAD      /* AAI 連續編程指令(FOR SST25VF016B) */
#define CMD_DISWR      0x04        /* 禁止寫, 退出AAI狀態 */
#define CMD_EWRSR      0x50        /* 允許寫狀態寄存器的命令 */
#define CMD_WRSR      0x01      /* 寫狀態寄存器命令 */
#define CMD_WREN      0x06        /* 寫使能命令 */
#define CMD_READ      0x03      /* 讀數據區命令 */
#define CMD_RDSR      0x05        /* 讀狀態寄存器命令 */
#define CMD_RDID      0x9F        /* 讀器件ID命令 */
#define CMD_SE        0x20        /* 擦除扇區命令 */
#define CMD_BE        0xC7        /* 批量擦除命令 */
#define DUMMY_BYTE    0xA5        /* 啞命令,可以為任意值,用於讀操作 */

#define WIP_FLAG      0x01        /* 狀態寄存器中的正在編程標志(WIP) */

85.6 QSPI Flash的STM32CubeProg下載算法使用方法

編譯本章教程配套的例子,生成的算法文件位於此路徑下:

 

85.6.1 下載算法存放位置

生成此文件后,需要大家將其存放到STM32CubeProg安裝目錄路徑:

\STMicroelectronics\STM32Cube\STM32CubeProgrammer\bin\ExternalLoader

 

85.6.2 STM32CubeProg下載配置

我們這里以STLINK連接開發板為例進行說明(USB DFU或者串口方式不支持下載外部Flash)。

 

點擊Connect后效果如下:

 

在這里選擇我們制作的下載算法:

 

任意加載個hex或者bin文件,並按照如下配置,然后點擊Start Programming

 

下載完成后的效果如下:

 

85.6.3 驗證算法文件是否可以正常使用

為了驗證算法文件是否可以正常使用,大家可以運行本教程第86章配套的例子。也可以使用STM32CubeProg直接讀取:

 

85.7 實驗例程說明

本章配套例子:V7-066_SPI Flash的STM32CubeProg下載算法制作。

編譯本章教程配套的例子,生成的算法文件位於此路徑下:

 

85.8 總結

本章節就為大家講解這么多,為了熟練掌握,大家可以嘗試自己實現一個Flash下載算法。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM