STM32 MDK off chip FLASH download algorithm -- Based on QSPI (W25Q32)

Posted by Keith Scott on Fri, 04 Feb 2022 06:09:23 +0100

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

 

Topics: Algorithm stm32 ARM Flash