QSPI下载算法制作

了解到可以使用下载算法将代码直接下载到QSPI flash, 有以下三种工具

  • 使用mdk keil下载
  • 使用CubeProgrammer下载
  • 使用ST-LINK Utility下载

个人觉得使用MDK下载比较方便,在使用keil的过程中,我们也会常使用到下载算法,如下,我们要制作的就是这个,只不过它是下载到外部QSPI flash上

image-20231013204621008

在上一章节 调好了W25Q64的驱动 接下来就开始制作下载算法吧

在keil的安装目录下都有一个示例工程供我们制作自己的下载算法

搜索 _Template 可找到

找到之后我们将它拷贝到此目录下

image-20231014095830974

image-20231014100054749

image-20231014100301450

改写好如下,如下这是我的

image-20231014100438677

打开工程就会有制作说明,但并不详细 这里给出了官方的说明:https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/flashAlgorithm.html

image-20231014100718657

步骤一

更改为自己的芯片

image-20231014100551164

步骤二

更改我们文件名

image-20231014101330834

步骤三

更改QSPI配置参数

参考链接: https://blog.csdn.net/Simon223/article/details/109772910?ops_request_misc=&request_id=&biz_id=102&utm_term=QSPI%E4%B8%8B%E8%BD%BD%E7%AE%97%E6%B3%95&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-1-109772910.142^v96^pc_search_result_base5&spm=1018.2226.3001.4187

理解QSPI下载算法实现的本质, 实际上也就是一个工程,可以操作QSPI读写擦除等等,这里提供了一个模板,按照这个模板来就好了

FlashOS.H是一个头文件,它定义了用于编写Flash编程算法的结构和函数原型,我们需要适配为自己的

image-20231014112720853

接着我们需要在FlashPrg这些函数中来添加对应的QSPI操作

image-20231014112918121

需要添加的函数操作

int Init (unsigned long adr, unsigned long clk, unsigned long fnc) {

  /* Add your Code */
  return (0);                                  // Finished without Errors
}


/*
 *  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) {

  /* Add your Code */
  return (0);                                  // Finished without Errors
}


/*
 *  Erase complete Flash Memory
 *    Return Value:   0 - OK,  1 - Failed
 */

int EraseChip (void) {

  /* Add your Code */
  return (0);                                  // Finished without Errors
}


/*
 *  Erase Sector in Flash Memory
 *    Parameter:      adr:  Sector Address
 *    Return Value:   0 - OK,  1 - Failed
 */

int EraseSector (unsigned long adr) {

  /* Add your Code */
  return (0);                                  // 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) {

  /* Add your Code */
  return (0);                                  // Finished without Errors
}

整理如下: (我们要在对应的函数下添加对应的功能)

/* 添加flash初始化的函数  这里我们还要初始化系统时钟让芯片可以正常工作,下载算法实质也是驱动QSPI的擦除和写入操作 */
int Init (unsigned long adr, unsigned long clk, unsigned long fnc) {

  /* Add your Code */
  return (0);                                  
}


/*flash 解初始化*/

int UnInit (unsigned long fnc) {

  /* Add your Code */
  return (0);                                  // Finished without Errors
}


/* 擦除全部chpi */

int EraseChip (void) {

  /* Add your Code */
  return (0);                                  // Finished without Errors
}


/* 擦除扇区 */

int EraseSector (unsigned long adr) {

  /* Add your Code */
  return (0);                                  // Finished without Errors
}


/* 写入页 */

int ProgramPage (unsigned long adr, unsigned long sz, unsigned char *buf) {

  /* Add your Code */
  return (0);                                  // Finished without Errors
}

既然要驱动QSPI,我们需要将原工程的文件包含进来, 找到上一个QSPI的工程打开,查看头文件路径以及包含对应文件进来,编译后无报错即可,这里不用添加启动文件

image-20231014125649646


 uint8_t  Verify_Data[8*1024]; //校验时缓存的数据,不能小于一个 Programming Page Size 的大小


/*
 *  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) 
{

    SystemInit();                 // 系统初始化
    SystemClock_Config();    // 配置系统时钟,主频480MHz
    MX_QUADSPI_Init();   /* QSPI初始化 * /

    if ( QSPI_W25Qxx_Init() != QSPI_W25Qxx_OK )  // 初始化W25Q64
    {
        return 1;
    }
    
    return 0;
}


/*
 *  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) 
{ 
    if ( QSPI_W25Qxx_Init() != QSPI_W25Qxx_OK )  // 初始化W25Q64
    {
        return 1;
    }
    return 0;
}


/*
 *  Erase complete Flash Memory
 *    Return Value:   0 - OK,  1 - Failed
 */
int EraseChip (void) 
{    
    if ( QSPI_W25Qxx_ChipErase() != QSPI_W25Qxx_OK )  // 整片擦除
    {
        return 1;
    }
    
    return 0;  
}


/*
 *  Erase Sector in Flash Memory
 *    Parameter:      adr:  Sector Address
 *    Return Value:   0 - OK,  1 - Failed
 */

int EraseSector (unsigned long adr) 
{    
    adr = adr - W25Qxx_Mem_Addr; 
    
    if ( QSPI_W25Qxx_BlockErase_64K(adr) != QSPI_W25Qxx_OK )  // 擦除对应扇区
    {
        return 1;
    }
    
    return 0;      
}


/*
 *  Blank Check Checks if Memory is Blank
 *    Parameter:      adr:  Block Start Address
 *                    sz:   Block Size (in bytes)
 *                    pat:  Block Pattern
 *    Return Value:   0 - OK,  1 - Failed
 */

int BlankCheck (unsigned long adr, unsigned long sz, unsigned char pat)
{
    return (1); /* Always Force Erase */
}


/*
 *  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) 
{

    QSPI_W25Qxx_WriteBuffer(buf, adr -W25Qxx_Mem_Addr,sz);    

    return (0);                      
}

/*  
 *  Verify Flash Contents
 *    Parameter:      adr:  Start Address
 *                    sz:   Size (in bytes)
 *                    buf:  Data
 *    Return Value:   (adr+sz) - OK, Failed Address
 */

/*
   Verify function is obsolete because all other function leave 
    the SPIFI in memory mode so a memory compare could be used.
 */
unsigned long Verify (unsigned long adr, unsigned long sz, unsigned char *buf)
{
    unsigned long i;

    QSPI_W25Qxx_ReadBuffer(Verify_Data, adr - W25Qxx_Mem_Addr, sz);    

    for (i = 0; i < sz; i++)
    {
        if (Verify_Data[i] != buf[i])
        {
            return (adr + i); // Verification Failed (return address)
        }
    }
    
    return (adr + sz); // Done successfully
}

生成下载算法如下,

image-20231014153912151

虽然这一步生成了算法,但是似乎运行不起来,算法是加载到sram里面的,hal库太多文件了,我在尝试把ram加到最大也不行,他们居然能精简到一百多k,很显然这是直接操作寄存器了,对于这部分需要花大量时间去实现,目前先不探究了,因为我使用的平台有适配好的下载算法我就直接使用了

image-20231014163120301

待解决

解决方法1:

  • 需要使用寄存器来驱动芯片运行
  • 需要使用寄存器来驱动QSPI

解决方法2:精简hal库

目前主要实现bootloader的跳转,它的优先级较高,后续补充

如果觉得我的文章对你有用,请随意赞赏