preface
The chip STM32H750 is used in a recent project. Its on-chip flash is only 128KB in size (although it is said on the Internet that it actually has 2MB as H743, this method is not used for insurance). Because the project uses RTOS, LWIP, TLS, etc., and the generation program is relatively large, W25Q32 (4MB in size) is added as off chip flash, The function of serial port upgrade program is required. In addition, QSPI needs to be initialized before starting, and then memory mapping to off chip flash is set. Bootloader (on-chip) + App (off chip) is adopted. That's the problem. Bootloader can be loaded directly by STLink, but App can't be downloaded directly. Serial port upgrade and debugging can't be used all the time, Even if it goes down to SAM to run, it is not a long-term plan. After thinking over and over again, you still have to use the download algorithm to directly go down to off chip flash to run.
Create and download Algorithm Project
If Keil is installed on your computer, you can find the official project template in the following directory:
{Keil installation directory} \ ARM\PACK\ARM\CMSIS.3.0\Device\_Template_Flash
Copy all these to the new folder, then copy the relevant chip driver library, and then open the project. If you open it, you will be prompted:
You need to select the file of the project template, right-click the attribute option, remove the read-only option, and then reopen it.
After reopening, click the magic wand, select the corresponding chip, and then add the driver files to be used one by one.
All files added here are Bootloader program files (generated by STM32CubeMX). Several files here need to be modified:
Shield the interrupt and timeout judgment parts inside. Because there is no system interrupt, the timer of hal library does not work.
After that, click compile. If you encounter the following problems:
\xxx.axf: Error: L6265E: Non-PI Section xxxxxxxxx.o(.data) cannot be assigned to PI Exec region PrgData.
You can refer to this blog to solve the following problems: Problems encountered in STM32 burning external FLASH with STLINK , compilation result:
Algorithm implementation
First, adjust the parameters according to the off chip FLASH chip, in flashdev C structure in the document:
struct FlashDevice const FlashDevice = { FLASH_DRV_VERS, // The driver version does not need to be modified! "STM32H750 QSPI(W25Q32) 4MB Flash", // Download algorithm name (displayed in Keil) EXTSPI, // Device type: off chip FLASH 0x90000000, // Off chip FLASH address 4 * 1024 *1024, // Off chip FLASH size (4MB) 1024, // Page size (the data size written at one time. The page size of W25Q32 here is 256. In order to write faster, 1024 is set here) 0, // Reserved bit, must be 0 0xFF, // Data value after erasure 1000, // Page write timeout (1S) 6000, // Sector erase timeout (6S) 4 * 1024, 0x000000, // Sector size: 4KB address: 0x000000 SECTOR_END };
Then implement flashprg Correlation function in C:
/**************************************************************************//** * @file FlashPrg.c * @brief Flash Programming Functions adapted 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 #include "led.h" #include "main.h" #include "w25q32_qspi.h" /* 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 */ /* * 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) { userSystemInit(); LED1_ON(); if (W25_Qspi_Get_ID() != W25X_MF_ID) return (1); // Finished without Errors return (0); // Finished without OK } /* * 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) { LED1_OFF(); return (0); // Finished without OK } // Blank Check int BlankCheck(unsigned long adr, unsigned long sz, unsigned char pat) { return (0); // Memory is blank by default. You will judge by yourself when writing the program } /* * Erase complete Flash Memory * Return Value: 0 - OK, 1 - Failed */ int EraseChip (void) { LED1_FLASH(); if (W25_Qspi_WriteEnable()) { if (W25_Qspi_EraseDatas(0, 3)) return (0); // Finished without OK } return (1); // Finished without Errors } /* * Erase Sector in Flash Memory * Parameter: adr: Sector Address * Return Value: 0 - OK, 1 - Failed */ int EraseSector (unsigned long adr) { adr -= QSPI_FLASH_MEM_ADDR; LED1_FLASH(); if (W25_Qspi_WriteEnable()) { if (W25_Qspi_EraseDatas(adr, 0)) return (0); // Finished without OK } return (1); // Finished without Errors } /* * 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) { adr -= QSPI_FLASH_MEM_ADDR; LED1_FLASH(); if (W25_Qspi_WriteDatas_API(adr, buf, sz)) return (0); // Finished without OK return (1); // Finished without Errors } // Verify Function extern uint8_t checkBuf[W25X_SECTOR_SIZE]; unsigned long Verify (unsigned long adr, unsigned long sz, unsigned char *buf) { unsigned long i; adr -= QSPI_FLASH_MEM_ADDR; LED1_FLASH(); if (W25_Qspi_ReadDatas(adr, checkBuf, sz) == 0) return (1); // Finished without Errors for (i=0; i<sz; i++) if (buf[i] != checkBuf[i]) break; return (adr + i + QSPI_FLASH_MEM_ADDR); }
Then compile and generate the downloaded algorithm file
Add to Keil for use
XXXX to be generated Copy FLM file to keil download algorithm Directory:
{Keil installation directory} \ ARM\Flash
Then you can see it in the configuration interface
Compile APP program, use the algorithm to download verification and run