手把手系列--编写Keil MDK 外部FLASH下载算法
声明:博文中涉及到的版权软件只用于教学使用
一、目的
完整工程下载地址:
链接:https://pan.baidu.com/s/1xtr8m_KGsyx64wN6rcnZyg
提取码:re4i
很多同学都是从STM32F103开始了STM32的开发之旅,在使用Keil进行下载的时候需要设置下载算法,此时我们直接选择Keil提供的下载算法完成了代码的下载。
最近淘了一块STM32H750XBH6 ArtPi开发板,属于M7内核,内部Flash的大小为128KBytes,同时板子上还有一块W25QJV64的华邦的Flash芯片(8MBytes),连接在QUADSPI硬件接口上。
本篇博文主要介绍如何实现下载算法,以便后续将代码或者数据存储在外部Flash中,所有的操作都是基于此文档进行的。
链接:https://pan.baidu.com/s/1x0ljEoBC7k1pa_kOrW24Dw
提取码:w2ox
二、准备
MDK5 Software Packs (keil.com)https://www.keil.com/dd2/pack/#
下载此PACK
STMicroelectronics STM32H7 Series Device Support and Examples
关于STM32CubeMX的使用我会在另外的博文中介绍。
关于Keil的安装以及科学使用,请自行百度。我的Keil安装目录在H:\Keil_v5
三、实战
下面我们开始构建Keil工程。
(1)首先从拷贝目录H:\Keil_v5\ARM\Flash\_Template到H:\STM32目录下
修改工程文件夹以及功能名称STM32H750XBH6_ArtPi_QSPI_W25Q64JV;
删除STM32H750XBH6_ArtPi_QSPI_W25Q64JV目录下的文件
删除 Test文件夹
修改NewDevice.uvprojx为STM32H750XBH6_ArtPi_QSPI_W25Q64JV.uvprojx
修改NewDevice.uvproj为STM32H750XBH6_ArtPi_QSPI_W25Q64JV.uvproj
这些操作以后目录如下
(2)打开工程
修改Device选项
修改编译器选项
修改Name of Executable为STM32H750XBH6_ArtPi_QSPI_W25Q64JV
确认C/C++(AC6)以及Asm选项中都选择Read-Only Position Independent、Read-Write Position Independent
在Manage Run-Time Environment选项中选中如图
在上图中STM32CubeMX行点击播放按钮运行STM32CubeMX程序。
在GPIO选项中设置对应的IO配置,主要是QUADSP的配置,另外我额外设置PC15/PI8这两个IO用于控制板载的两个LED
具体如下
尤其要注意要设置IO速度为Very High
设置RCC参数
设置QUADSPI相关参数
其中分频系数为1,即二分频;Flash Size为22,即8MBytes;
设置系统时钟
系统主时钟480MHz
QUADSPI选用HCLK3作为时钟输入
这样设置下来QUAPSPI的时钟为240MHz / 2 = 120MHz;而W25Q64JV Flash的最大时钟频率133MHz。
设置工程属性
点击Close关闭工程并且关闭STM32CubeMX程序。
点击Manage Run-Time Environment选项中OK按钮。
修改文件FlashDev.c
/**************************************************************************//**
* @file FlashDev.c
* @brief Flash Device Description for New Device Flash
* @version V1.0.0
* @date 10. January 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.
*/
#include "FlashOS.H" // FlashOS Structures
struct FlashDevice const FlashDevice = {
FLASH_DRV_VERS, // Driver Version, do not modify!
"STM32H750XBH6_ArtPi_QSPI_W25Q64JV", // Device Name
EXTSPI, // Device Type
0x90000000, // Device Start Address
0x000800000, // Device Size in Bytes (8MB)
1024, // Programming Page Size
0, // Reserved, must be 0
0xFF, // Initial Content of Erased Memory
1000, // Program Page Timeout 1000 mSec
3000, // Erase Sector Timeout 3000 mSec
// Specify Size and Address of Sectors
0x001000, 0x000000, // Sector Size 4kB
SECTOR_END
};
移除Device里面的Startup内容
添加System File组并添加文件 ./RTE/Device/STM32F769NIHx/system_stm32h7xx.c”
在工程目录下添加W25Q64JV文件夹
H:\STM32\STM32H750XBH6_ArtPi_QSPI_W25Q64JV\W25Q64JV
添加组QUADSPI Memory组,并添加quadspi.c文件
并将文件quadspi.c、quadspi.h拷贝进去
文件内容为quadspi.h
#ifndef QUADSPI_H
#define QUADSPI_H
#ifdef __cplusplus
extern "C" {
#endif
#include "main.h"
#include <stdint.h>
#define W25Q64JV_WRITE_ENABLE (0x06)
/*
* The Quad Enable (QE) bit is set to 1 by default in the factory, therefore the device supports Standard/Dual
SPI as well as Quad SPI after power on. This bit cannot be reset to 1.
*/
#define W25Q64JV_INPUT_FAST_READ (0xeb)
#define W25Q64JV_PAGE_PROGRAM (0x02)
#define W25Q64JV_STATUS_REG1 (0x05)
#define W25Q64JV_ENABLE_RESET (0x66)
#define W25Q64JV_RESET_DEVICE (0x99)
#define W25Q64JV_DEVICE_ID (0x90)
#define W25Q64JV_ID_NUMBER (0x4b)
#define W25Q64JV_ERASE_SECTOR (0x20)
#define W25Q64JV_ERASE_CHIP (0xc7)
#define MEMORY_FLASH_SIZE 0x800000 /* 64MBits => 8MBytes */
#define MEMORY_BLOCK_SIZE 0x10000 /* 64KBytes */
#define MEMORY_SECTOR_SIZE 0x1000 /* 4KBytes */
#define MEMORY_PAGE_SIZE 0x100 /* 32768 pages of 256Bytes */
uint8_t CSP_QUADSPI_Init(void);
uint8_t CSP_QSPI_EraseSector(uint32_t EraseStartAddress, uint32_t EraseEndAddress);
uint8_t CSP_QSPI_WriteMemory(uint8_t *buffer, uint32_t address, uint32_t buffer_size);
uint8_t CSP_QSPI_EnableMemoryMappedMode(void);
uint8_t CSP_QSPI_Erase_Chip(void);
#ifdef __cplusplus
}
#endif
#endif
quadspi.c文件
#include "quadspi.h"
extern QSPI_HandleTypeDef hqspi;
static uint8_t QSPI_WriteEnable(void);
static uint8_t QSPI_AutoPollingMemReady(void);
static uint8_t QSPI_ResetChip(void);
uint8_t QSPI_ResetChip(void) {
QSPI_CommandTypeDef cmd = {
.InstructionMode = QSPI_INSTRUCTION_1_LINE,
.Instruction = W25Q64JV_ENABLE_RESET,
};
if (HAL_QSPI_Command(&hqspi, &cmd, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return HAL_ERROR;
}
cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE;
cmd.Instruction = W25Q64JV_RESET_DEVICE;
if (HAL_QSPI_Command(&hqspi, &cmd, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return HAL_ERROR;
}
if (QSPI_AutoPollingMemReady() != HAL_OK) {
return HAL_ERROR;
}
return HAL_OK;
}
uint8_t QSPI_AutoPollingMemReady(void) {
QSPI_CommandTypeDef cmd = {
.InstructionMode = QSPI_INSTRUCTION_1_LINE,
.Instruction = W25Q64JV_STATUS_REG1,
.DataMode = QSPI_DATA_1_LINE,
};
QSPI_AutoPollingTypeDef conf = {
.Match = 0x00,
.Mask = 0x01,
.MatchMode = QSPI_MATCH_MODE_AND,
.StatusBytesSize = 1,
.Interval = 0x10,
.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE,
};
if (HAL_QSPI_AutoPolling(&hqspi, &cmd, &conf, HAL_MAX_DELAY) != HAL_OK) {
return HAL_ERROR;
}
return HAL_OK;
}
uint8_t QSPI_WriteEnable(void) {
QSPI_CommandTypeDef cmd = {
.InstructionMode = QSPI_INSTRUCTION_1_LINE,
.Instruction = W25Q64JV_WRITE_ENABLE,
};
if (HAL_QSPI_Command(&hqspi, &cmd, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return HAL_ERROR;
}
cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE;
cmd.Instruction = W25Q64JV_STATUS_REG1;
cmd.DataMode = QSPI_DATA_1_LINE;
cmd.DummyCycles = 0;
cmd.NbData = 0;
QSPI_AutoPollingTypeDef conf = {
.Match = 0x02,
.Mask = 0x02,
.MatchMode = QSPI_MATCH_MODE_AND,
.StatusBytesSize = 1,
.Interval = 0x10,
.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE,
};
if (HAL_QSPI_AutoPolling(&hqspi, &cmd, &conf, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return HAL_ERROR;
}
return HAL_OK;
}
uint8_t CSP_QUADSPI_Init(void) {
hqspi.Instance = QUADSPI;
if (HAL_QSPI_DeInit(&hqspi) != HAL_OK) {
return HAL_ERROR;
}
MX_QUADSPI_Init();
if (QSPI_ResetChip() != HAL_OK) {
return HAL_ERROR;
}
HAL_Delay(1);
if (QSPI_AutoPollingMemReady() != HAL_OK) {
return HAL_ERROR;
}
return HAL_OK;
}
uint8_t CSP_QSPI_EraseSector(uint32_t EraseStartAddress, uint32_t EraseEndAddress) {
EraseStartAddress = EraseStartAddress - EraseStartAddress % MEMORY_SECTOR_SIZE;
if (QSPI_WriteEnable() != HAL_OK) {
return HAL_ERROR;
}
QSPI_CommandTypeDef cmd = {
.InstructionMode = QSPI_INSTRUCTION_1_LINE,
.Instruction = W25Q64JV_ERASE_SECTOR,
.AddressMode = QSPI_ADDRESS_1_LINE,
.AddressSize = QSPI_ADDRESS_24_BITS,
};
while (EraseEndAddress >= EraseStartAddress) {
cmd.Address = (EraseStartAddress & 0x0FFFFFFF);
if (QSPI_WriteEnable() != HAL_OK) {
return HAL_ERROR;
}
if (HAL_QSPI_Command(&hqspi, &cmd, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return HAL_ERROR;
}
EraseStartAddress += MEMORY_SECTOR_SIZE;
if (QSPI_AutoPollingMemReady() != HAL_OK) {
return HAL_ERROR;
}
}
return HAL_OK;
}
uint8_t CSP_QSPI_WriteMemory(uint8_t *buffer, uint32_t address, uint32_t buffer_size) {
uint32_t end_addr, current_size, current_addr;
current_addr = 0;
while (current_addr <= address) {
current_addr += MEMORY_PAGE_SIZE;
}
current_size = current_addr - address;
if (current_size > buffer_size) {
current_size = buffer_size;
}
current_addr = address;
end_addr = address + buffer_size;
QSPI_CommandTypeDef cmd = {
.InstructionMode = QSPI_INSTRUCTION_1_LINE,
.Instruction = W25Q64JV_PAGE_PROGRAM,
.AddressMode = QSPI_ADDRESS_1_LINE,
.AddressSize = QSPI_ADDRESS_24_BITS,
.DataMode = QSPI_DATA_1_LINE,
.DummyCycles = 0,
};
do {
cmd.Address = current_addr;
cmd.NbData = current_size;
if (current_size == 0) {
return HAL_OK;
}
if (QSPI_WriteEnable() != HAL_OK) {
return HAL_ERROR;
}
if (HAL_QSPI_Command(&hqspi, &cmd, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return HAL_ERROR;
}
if (HAL_QSPI_Transmit(&hqspi, buffer, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return HAL_ERROR;
}
if (QSPI_AutoPollingMemReady() != HAL_OK) {
return HAL_ERROR;
}
current_addr += current_size;
buffer += current_size;
current_size = ((current_addr + MEMORY_PAGE_SIZE) > end_addr) ?
(end_addr - current_addr) : MEMORY_PAGE_SIZE;
} while (current_addr <= end_addr);
return HAL_OK;
}
uint8_t CSP_QSPI_EnableMemoryMappedMode(void) {
QSPI_MemoryMappedTypeDef mem_mapped_cfg = {
.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE,
};
QSPI_CommandTypeDef cmd = {
.InstructionMode = QSPI_INSTRUCTION_1_LINE,
.Instruction = W25Q64JV_INPUT_FAST_READ,
.AddressMode = QSPI_ADDRESS_4_LINES,
.Address = 0,
.AddressSize = QSPI_ADDRESS_24_BITS,
.AlternateByteMode = QSPI_ALTERNATE_BYTES_4_LINES,
.AlternateBytesSize= QSPI_ALTERNATE_BYTES_8_BITS,
.AlternateBytes = 0xf0, //datasheet p22
.DataMode = QSPI_DATA_4_LINES,
.DummyCycles = 4,
.NbData = 0,
};
if (HAL_QSPI_MemoryMapped(&hqspi, &cmd, &mem_mapped_cfg) != HAL_OK) {
return HAL_ERROR;
}
return HAL_OK;
}
uint8_t CSP_QSPI_Erase_Chip(void) {
if (QSPI_WriteEnable() != HAL_OK) {
return HAL_ERROR;
}
QSPI_CommandTypeDef cmd = {
.InstructionMode = QSPI_INSTRUCTION_1_LINE,
.Instruction = W25Q64JV_ERASE_CHIP,
};
if (HAL_QSPI_Command(&hqspi, &cmd, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return HAL_ERROR;
}
if (QSPI_AutoPollingMemReady() != HAL_OK) {
return HAL_ERROR;
}
return HAL_OK;
}
拷贝文件FlashOS.h到工程根目录
/**************************************************************************//**
* @file FlashOS.h
* @brief Data structures and entries Functions
* @version V1.0.0
* @date 10. January 2018
******************************************************************************/
/*
* Copyright (c) 2010-2020 Arm Limited (or its affiliates). 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 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);
拷贝文件FlashProg.c
注意:我在对应的函数里面调用了一些LED控制的操作,当然这个操作只是为了在操作flash时有一些UI效果,非必须可以删除掉。
/**************************************************************************//**
* @file FlashPrg.c
* @brief Flash Programming Functions adapted for New Device Flash
* @version V1.0.0
* @date 28. October 2020
******************************************************************************/
/*
* 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.
*/
#include "FlashOS.h" // FlashOS Structures
/*
Mandatory Flash Programming Functions (Called by FlashOS):
int Init (unsigned long adr, // Initialize Flash
unsigned long clk,
unsigned long fnc);
int UnInit (unsigned long fnc); // De-initialize Flash
int EraseSector (unsigned long adr); // Erase Sector Function
int ProgramPage (unsigned long adr, // Program Page Function
unsigned long sz,
unsigned char *buf);
Optional Flash Programming Functions (Called by FlashOS):
int BlankCheck (unsigned long adr, // Blank Check
unsigned long sz,
unsigned char pat);
int EraseChip (void); // Erase complete Device
unsigned long Verify (unsigned long adr, // Verify Function
unsigned long sz,
unsigned char *buf);
- BlanckCheck is necessary if Flash space is not mapped into CPU memory space
- Verify is necessary if Flash space is not mapped into CPU memory space
- if EraseChip is not provided than EraseSector for all sectors is called
*/
#include "main.h"
#include "quadspi.h"
extern QSPI_HandleTypeDef hqspi;
unsigned int DevAddr;
/*
* 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
*/
int Init (unsigned long adr, unsigned long clk, unsigned long fnc) {
int ret = 0;
volatile int i;
volatile unsigned char * ptr = (volatile unsigned char * )&hqspi;
for (i = 0; i < sizeof(hqspi); i++) {
*ptr++ = 0U;
}
DevAddr = adr;
__disable_irq();
HAL_Init();
SystemInit();
SystemClock_Config();
SystemCoreClockUpdate();
MX_GPIO_Init();
if (CSP_QUADSPI_Init() != HAL_OK) {
ret = 1;
}
//HAL_GPIO_WritePin(GPIOC, GPIO_PIN_15, GPIO_PIN_RESET);
//HAL_GPIO_WritePin(GPIOI, GPIO_PIN_8, GPIO_PIN_RESET);
//HAL_GPIO_TogglePin(GPIOI, GPIO_PIN_8);
//HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_15);
return (ret);
}
/*
* 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) {
int ret = 0;
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_15, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOI, GPIO_PIN_8, GPIO_PIN_SET);
if (hqspi.State != HAL_QSPI_STATE_BUSY_MEM_MAPPED) {
if (CSP_QSPI_EnableMemoryMappedMode() != HAL_OK) {
ret = 1;
}
}
return (ret);
}
/*
* Erase complete Flash Memory
* Return Value: 0 - OK, 1 - Failed
*/
int EraseChip (void) {
int ret = 0;
HAL_GPIO_TogglePin(GPIOI, GPIO_PIN_8);
if (CSP_QSPI_Erase_Chip () != HAL_OK) {
ret = 1;
}
HAL_GPIO_TogglePin(GPIOI, GPIO_PIN_8);
return (ret);
}
/*
* Erase Sector in Flash Memory
* Parameter: adr: Sector Address
* Return Value: 0 - OK, 1 - Failed
*/
int EraseSector (unsigned long adr) {
int ret = 1;
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_15);
if (adr >= DevAddr) {
adr -= DevAddr;
if (CSP_QSPI_EraseSector (adr, adr + MEMORY_BLOCK_SIZE) == HAL_OK) {
ret = 0;
}
}
return (ret);
}
/*
* 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) {
int ret = 1;
HAL_GPIO_TogglePin(GPIOI, GPIO_PIN_8);
if (adr >= DevAddr) {
adr -= DevAddr;
if (CSP_QSPI_WriteMemory (buf, adr, sz) == HAL_OK) {
ret = 0;
}
}
return (ret);
}
unsigned long Verify (unsigned long adr, unsigned long sz, unsigned char *buf){
volatile unsigned long ret = adr + sz;
volatile int i;
if (hqspi.State != HAL_QSPI_STATE_BUSY_MEM_MAPPED) {
if (CSP_QSPI_EnableMemoryMappedMode() != HAL_OK) {
ret = 0U;
}
}
if (ret != 0U) {
for (i = 0; i < sz; i++) {
if ((*((volatile unsigned char *) (adr+i))) != buf[i]) {
// Verification Failed (return address)
ret = adr + i;
break;
}
HAL_GPIO_TogglePin(GPIOI, GPIO_PIN_8);
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_15);
}
}
return (ret);
}
int BlankCheck (unsigned long adr, unsigned long sz, unsigned char pat) {
int ret = 0;
volatile int i;
if (hqspi.State != HAL_QSPI_STATE_BUSY_MEM_MAPPED) {
if (CSP_QSPI_EnableMemoryMappedMode() != HAL_OK) {
ret = 1;
}
}
if (ret == 0) {
for (i = 0; i < sz; i++) {
if ((*((volatile unsigned char *) (adr+i))) != pat) {
ret = 1;
break;
}
}
}
if (CSP_QUADSPI_Init() != HAL_OK) {
HAL_Delay (100);
if (CSP_QUADSPI_Init() != HAL_OK) {
ret = 1;
}
}
return (ret);
}
添加头文件路径以及宏定义
替换main.c文件
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2021 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
QSPI_HandleTypeDef hqspi;
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority) {
return HAL_OK;
}
uint32_t HAL_GetTick(void) {
static uint32_t ticks = 0U;
uint32_t i;
for (i = (SystemCoreClock >> 14U); i > 0U; i--) {
__NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
__NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
}
return ++ticks;
}
void HAL_Delay(uint32_t Delay) {
uint32_t tickstart = HAL_GetTick();
uint32_t wait = Delay;
if (wait < HAL_MAX_DELAY) {
wait += (uint32_t)(HAL_TICK_FREQ_DEFAULT);
}
while ((HAL_GetTick() - tickstart) < wait) {
__NOP();
}
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Supply configuration update enable
*/
HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);
/** Configure the main internal regulator output voltage
*/
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0);
while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 5;
RCC_OscInitStruct.PLL.PLLN = 192;
RCC_OscInitStruct.PLL.PLLP = 2;
RCC_OscInitStruct.PLL.PLLQ = 2;
RCC_OscInitStruct.PLL.PLLR = 2;
RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2;
RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
RCC_OscInitStruct.PLL.PLLFRACN = 0;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
|RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
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;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief QUADSPI Initialization Function
* @param None
* @retval None
*/
void MX_QUADSPI_Init(void)
{
/* USER CODE BEGIN QUADSPI_Init 0 */
/* USER CODE END QUADSPI_Init 0 */
/* USER CODE BEGIN QUADSPI_Init 1 */
/* USER CODE END QUADSPI_Init 1 */
/* QUADSPI parameter configuration*/
hqspi.Instance = QUADSPI;
hqspi.Init.ClockPrescaler = 1;
hqspi.Init.FifoThreshold = 4;
hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;
hqspi.Init.FlashSize = 22;
hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_5_CYCLE;
hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0;
hqspi.Init.FlashID = QSPI_FLASH_ID_1;
hqspi.Init.DualFlash = QSPI_DUALFLASH_DISABLE;
if (HAL_QSPI_Init(&hqspi) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN QUADSPI_Init 2 */
/* USER CODE END QUADSPI_Init 2 */
}
/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOI_CLK_ENABLE();
__HAL_RCC_GPIOG_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOF_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_15, GPIO_PIN_SET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOI, GPIO_PIN_8, GPIO_PIN_SET);
/*Configure GPIO pin : PC15 */
GPIO_InitStruct.Pin = GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/*Configure GPIO pin : PI8 */
GPIO_InitStruct.Pin = GPIO_PIN_8;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
替换main.h文件
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.h
* @brief : Header for main.c file.
* This file contains the common defines of the application.
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2021 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __MAIN_H
#define __MAIN_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32h7xx_hal.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */
/* USER CODE END ET */
/* Exported constants --------------------------------------------------------*/
/* USER CODE BEGIN EC */
/* USER CODE END EC */
/* Exported macro ------------------------------------------------------------*/
/* USER CODE BEGIN EM */
/* USER CODE END EM */
/* Exported functions prototypes ---------------------------------------------*/
void Error_Handler(void);
/* USER CODE BEGIN EFP */
void SystemClock_Config(void);
void MX_QUADSPI_Init(void);
/* USER CODE END EFP */
/* Private defines -----------------------------------------------------------*/
void MX_GPIO_Init(void);
void MX_QUADSPI_Init(void);
/* USER CODE BEGIN Private defines */
/* USER CODE END Private defines */
#ifdef __cplusplus
}
#endif
#endif /* __MAIN_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
编译成功后输出
完整工程下载地址:
链接:https://pan.baidu.com/s/1xtr8m_KGsyx64wN6rcnZyg
提取码:re4i
至此,我们就完成了 STM32H750XBH6_ArtPi_QSPI_W25Q64JV下载算法的工程。
后续
本篇中主要介绍了如何实现特定平台STM32H750XBH6 ART RTHREAD开发板W25Q64JV的下载算法。在下一篇博文中会介绍如何验证我们实现的下载算法是否可用。