STM32H750片外QSPI启动配置简要
- 📍参考信息源:《STM32H750片外Flash启动(W25Q64JVSIQ)》
- 🔖本例程基于Keil MDk开发平台。
- 🍁配置框架:
✨为什么使用要使用QSPI启动方式
不管对于STM32H7系列单片机,还是其他单片机,其自身内部自带的flash容量都是很有限的,容量越大,价格翻倍。QSPI启动方式就是,将主控程序放置到外部SPI flash当中,这样程序空间可以做到很大,仅需要占用一个QSPI硬件接口。同时也方便程序的更新和维护。
🔨QSPI Flash的MDK下载算法制作
- 🌿以上面的参考源为例。这里以我使用的
W25Q64JVSSIQ
为例,这是一颗8MB的 SPI flash。
- 🌿 在
FlashDev.c
文件中,找到有关宏FLASH_MEM
的定义内容,填写对应的参数
c
#ifdef FLASH_MEM
struct FlashDevice const FlashDevice = {
FLASH_DRV_VERS, /* 驱动版本,勿修改,这个是MDK定的 */
"DIY_STM32H7x_QSPI_W25Q64B", /* 算法名,添加算法到MDK安装目录会显示此名字 */
EXTSPI, /* 设备类型 */
0x90000000, /* Flash起始地址 */
8 * 1024 * 1024, /* Flash大小,8MB */
1024, /* 编程页大小 */
0, /* 保留,必须为0 */
0xFF, /* 擦除后的数值 */
1000, /* 页编程等待时间 */
6000, /* 扇区擦除等待时间 */
4 * 1024, 0x000000, /* 扇区大小,扇区地址 */
SECTOR_END
};
#endif
- 🌿主控时钟可以和后面的Bootloader程序以及APP程序的时钟初始化一样的。可以直接拷贝过来。
-
- 🌿生成的下载算法文件,拷贝到Keil安装目录下的ARM/flash文件夹内,例如:
D:\Keil_v5\ARM\Flash
- 🌿生成的下载算法文件,拷贝到Keil安装目录下的ARM/flash文件夹内,例如:
🔧QSPI信息STM32CubeMX软件配置
- 🔖也就是STM32h7主控搭载的QSPI flash硬件信息填写
- 🌿QSPI信息配置:后面的的Bootloader程序里面,也保持相同配置。
- 🔖我这里NCS引脚使用的是
PB6
引脚,
c
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 */
hqspi.Instance = QUADSPI;
hqspi.Init.ClockPrescaler = 3;//针对HCLK3分频
hqspi.Init.FifoThreshold = 32;
hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;
hqspi.Init.FlashSize = 24;
hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_2_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 */
}
📘APP程序程序配置
- ⚡APP应用程序的IROM1起始地址,一定要和Bootloader程序中的程序跳转地址是一致的才行。
-
🌿IROM1起始地址配置:(注意这里是
0x90000000
)
-
🔰 Bootloader程序IROM1起始地址保持默认的
0x8000000
地址位。不要改。
-
🌿APP程序下载和更新,算法文件配置:
-
⚡上面的下载时的RAM大小是
1000
,需要该大一点,否则下载时会报错。
⛳采坑注意事项
🔰参数差异
- 🔱由于每个人所使用的主控不同,时钟频率不一样,又或者配置的外置spi flash容量和引脚复用不同,上面的资源参考中,仅仅提供的是一个模板,需要根据个人所使用的硬件差异和参数进行稍微改动。
- 在个人首次移植时,需要对自己手上的硬件信息有个,基本的了解,主控搭载的外部晶振频率、SPI flash容量、以及flash引脚与主控对应连接的脚位。
- spi flash容量参数直接根据个人具体型号直接在工程中填写。如果不知道的可以烧录Bootloader程序时启用串口和启用
BspQspiBoot_Test()
测试函数,并其中插入调试打印信息。
c
void BspQspiBoot_Test(void)
{
bool bTestResult = true;
uint8_t ucTestCnt;
uint32_t ulTestAddr;
uint32_t ulSectorAddr = 0x2000;
ulFlashID = BspQspiBoot_ReadID();
// if(ulFlashID != 0x00EF4018) //16MB:15679512
if (ulFlashID != 0x00EF4017) // 8MB:15679511
{
bTestResult = false;
}
else
HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin | LED3_Pin, GPIO_PIN_RESET);
while (bTestResult == false)
{
HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin | LED2_Pin | LED3_Pin);
HAL_Delay(800);
// printf("FlashID:%d \r\n",ulFlashID);//查看容量,十进制的
}
BspQspiBoot_EraseSector(ulSectorAddr);
for (ucTestCnt = 0; ucTestCnt < 16; ucTestCnt++)
{
ulTestAddr = ulSectorAddr + (ucTestCnt * QSPI_FLASH_PAGE_SIZE);
{
uint16_t i;
for (i = 0; i < sizeof(ucaTestBuff); i++)
{
ucaTestBuff[i] = i;
}
}
BspQspiBoot_WritePage(ucaTestBuff, ulTestAddr, sizeof(ucaTestBuff));
memset(ucaTestBuff, 0, sizeof(ucaTestBuff));
BspQspiBoot_ReadBuff(ucaTestBuff, ulTestAddr, sizeof(ucaTestBuff));
{
uint16_t i;
for (i = 0; i < sizeof(ucaTestBuff); i++)
{
if (ucaTestBuff[i] != i)
{
bTestResult = false;
break;
}
}
}
}
while (bTestResult == false)
;
while (1)
{
}
}
-
🌿外部时钟时钟初始化函数可以通过
STM32CubeMX
配置设定好参数自动生成工程,然后拷贝对应的时钟初始化函数到工程中进行替换。来匹配个人使用的主控芯片。 -
🌿QSP NCS引脚复用调整:
c
#define QSPI_CS_PIN GPIO_PIN_6 // 注意修改 GPIO_PIN_10
#define QSPI_CS_GPIO_PORT GPIOB
#define QSPI_CS_GPIO_AF GPIO_AF10_QUADSPI // 注意修改 GPIO_AF9_QUADSPI