STM32H750片外QSPI下载算法文件(stldr)生成
- 🌿相关篇《STM32H750片外QSPI启动配置简要》
- 📌参考实现资料:
-
https://github.com/lchnu/STM32H750XBH_ARTPIQSPI_W25Q64JV
-
https://gitee.com/wangchief/H750_W25QXX
- ✨利用以上资料中的任意一个,即可实现的是片外QSPI下载算法文件(stldr)的生成,(结合参考下面贴出的重要参考信息进行修改,即可实现。)可以方便针对
STM32CubeProgrammer
、STM32CubeIDE
工具软件,对片外QSPI Flash进行下载。- 🎉需要注意一点的是,上面的参考资料,对于大部分人手上的硬件,可能都不一样,需要有针对性的做调整和修改,才能用。
- 📍STM32H750片外QSPI下载算法文件(.FLM)生成,可以参考资料:
https://www.armbbs.cn/forum.php?mod=viewthread&tid=101586
- 🔖片外QSPI下载算法文件(.FLM)文件是,针对MDK Keil开发环境需要使用到的。
- ⚡同样的(.FLM)文件通过
STM32 ST-LINK Utility 4.6
工具测试,无法烧录,使用STM32CubeProgrammer
没有问题。
🔰(.stldr)文件和(.FLM)文件的生成,都是基于MDK KEIL工程生成的。工程并不是通用的。(利用生成.FLM的工程区生成.stldr文件是没法识别的。)
⛳移植重点
- 🌿QSPI引脚定义:(具体引脚根据硬件连接进行调整)
#define QSPI_CLK_ENABLE() __HAL_RCC_QSPI_CLK_ENABLE()
#define QSPI_CLK_DISABLE() __HAL_RCC_QSPI_CLK_DISABLE()
#define QSPI_CS_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
#define QSPI_CLK_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
#define QSPI_BK1_D0_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE()
#define QSPI_BK1_D1_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE()
#define QSPI_BK1_D2_GPIO_CLK_ENABLE() __HAL_RCC_GPIOE_CLK_ENABLE()
#define QSPI_BK1_D3_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE()
#define QSPI_MDMA_CLK_ENABLE() __HAL_RCC_MDMA_CLK_ENABLE()
#define QSPI_FORCE_RESET() __HAL_RCC_QSPI_FORCE_RESET()
#define QSPI_RELEASE_RESET() __HAL_RCC_QSPI_RELEASE_RESET()
#define QSPI_CS_PIN GPIO_PIN_6 //注意修改
#define QSPI_CS_GPIO_PORT GPIOB
#define QSPI_CS_GPIO_AF GPIO_AF10_QUADSPI //注意修改 GPIO_AF10_QUADSPI GPIO_AF9_QUADSPI
#define QSPI_CLK_PIN GPIO_PIN_2
#define QSPI_CLK_GPIO_PORT GPIOB
#define QSPI_CLK_GPIO_AF GPIO_AF9_QUADSPI
#define QSPI_BK1_D0_PIN GPIO_PIN_11
#define QSPI_BK1_D0_GPIO_PORT GPIOD
#define QSPI_BK1_D0_GPIO_AF GPIO_AF9_QUADSPI
#define QSPI_BK1_D1_PIN GPIO_PIN_12
#define QSPI_BK1_D1_GPIO_PORT GPIOD
#define QSPI_BK1_D1_GPIO_AF GPIO_AF9_QUADSPI
#define QSPI_BK1_D2_PIN GPIO_PIN_2
#define QSPI_BK1_D2_GPIO_PORT GPIOE
#define QSPI_BK1_D2_GPIO_AF GPIO_AF9_QUADSPI
#define QSPI_BK1_D3_PIN GPIO_PIN_13
#define QSPI_BK1_D3_GPIO_PORT GPIOD
#define QSPI_BK1_D3_GPIO_AF GPIO_AF9_QUADSPI
void HAL_QSPI_MspInit(QSPI_HandleTypeDef *hqspi)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* 使能QPSI时钟 */
QSPI_CLK_ENABLE();
/* 复位时钟接口 */
QSPI_FORCE_RESET();
QSPI_RELEASE_RESET();
/* 使能GPIO时钟 */
QSPI_CS_GPIO_CLK_ENABLE();
QSPI_CLK_GPIO_CLK_ENABLE();
QSPI_BK1_D0_GPIO_CLK_ENABLE();
QSPI_BK1_D1_GPIO_CLK_ENABLE();
QSPI_BK1_D2_GPIO_CLK_ENABLE();
QSPI_BK1_D3_GPIO_CLK_ENABLE();
/* QSPI CS GPIO 引脚配置 */
GPIO_InitStruct.Pin = QSPI_CS_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = QSPI_CS_GPIO_AF;
HAL_GPIO_Init(QSPI_CS_GPIO_PORT, &GPIO_InitStruct);
/* QSPI CLK GPIO 引脚配置 */
GPIO_InitStruct.Pin = QSPI_CLK_PIN;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Alternate = QSPI_CLK_GPIO_AF;
HAL_GPIO_Init(QSPI_CLK_GPIO_PORT, &GPIO_InitStruct);
/* QSPI D0 GPIO pin 引脚配置 */
GPIO_InitStruct.Pin = QSPI_BK1_D0_PIN;
GPIO_InitStruct.Alternate = QSPI_BK1_D0_GPIO_AF;
HAL_GPIO_Init(QSPI_BK1_D0_GPIO_PORT, &GPIO_InitStruct);
/* QSPI D1 GPIO 引脚配置 */
GPIO_InitStruct.Pin = QSPI_BK1_D1_PIN;
GPIO_InitStruct.Alternate = QSPI_BK1_D1_GPIO_AF;
HAL_GPIO_Init(QSPI_BK1_D1_GPIO_PORT, &GPIO_InitStruct);
/* QSPI D2 GPIO 引脚配置 */
GPIO_InitStruct.Pin = QSPI_BK1_D2_PIN;
GPIO_InitStruct.Alternate = QSPI_BK1_D2_GPIO_AF;
HAL_GPIO_Init(QSPI_BK1_D2_GPIO_PORT, &GPIO_InitStruct);
/* QSPI D3 GPIO 引脚配置 */
GPIO_InitStruct.Pin = QSPI_BK1_D3_PIN;
GPIO_InitStruct.Alternate = QSPI_BK1_D3_GPIO_AF;
HAL_GPIO_Init(QSPI_BK1_D3_GPIO_PORT, &GPIO_InitStruct);
}
void HAL_QSPI_MspDeInit(QSPI_HandleTypeDef *hqspi)
{
/* 复位QSPI引脚 */
HAL_GPIO_DeInit(QSPI_CS_GPIO_PORT, QSPI_CS_PIN);
HAL_GPIO_DeInit(QSPI_CLK_GPIO_PORT, QSPI_CLK_PIN);
HAL_GPIO_DeInit(QSPI_BK1_D0_GPIO_PORT, QSPI_BK1_D0_PIN);
HAL_GPIO_DeInit(QSPI_BK1_D1_GPIO_PORT, QSPI_BK1_D1_PIN);
HAL_GPIO_DeInit(QSPI_BK1_D2_GPIO_PORT, QSPI_BK1_D2_PIN);
HAL_GPIO_DeInit(QSPI_BK1_D3_GPIO_PORT, QSPI_BK1_D3_PIN);
/* 复位QSPI */
QSPI_FORCE_RESET();
QSPI_RELEASE_RESET();
/* 关闭QSPI时钟 */
QSPI_CLK_DISABLE();
}
- 🌿 FlashDevice结构体信息(需要根据QSPI flash容量进行配置)
/* 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
"STM32H750_ART_W25Q64JV", // Device Name + EVAL Borad name
SPI_FLASH, // Device Type
0x90000000, // Device Start Address
0x00800000, // Device Size in Bytes (8MBytes)
0x1000, // Programming Page Size 256Bytes
0xFF, // Initial Content of Erased Memory
// Specify Size and Address of Sectors (view example below)
{{0x00000800, 0x00001000,}, // Sector Num : 2048 ,Sector Size: 4KBytes
{0x00000000, 0x00000000,}}
};
- 🌿时钟信息(时钟源可以选择;外部时钟源、内部时钟源)
-
- 🎉时钟主频推荐配置为400MHz,,QSPI挂载在AHB总线线上,STM32H7 QSPI在SDR模式下最高133MHz,DDR模式-双倍数据速率模式:100MHz.
- 🎉时钟主频推荐配置为400MHz,,QSPI挂载在AHB总线线上,STM32H7 QSPI在SDR模式下最高133MHz,DDR模式-双倍数据速率模式:100MHz.
/*********************************************************************************************************
* 函 数 名: 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
* 形 参: 无
*********************************************************************************************************
*/
void SystemClock_Config(void)
{
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
/* 锁住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;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
/*
选择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 */
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4);
/*
使用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();
}
🛠STM32CubeProgrammer配置(.FLM)文件
-
🌿打开STM32CubeProgrammer软件前,将(.FLM)文件拷贝到指定目录:
D:\Program Files\STMicroelectronics\STM32Cube\STM32CubeProgrammer\bin\ExternalLoader
-
🌿加载(.FLM)文件