• 创建Cortex-M系列芯片下载算法


         我们平时在使用 S T M 32 STM32 STM32系列芯片的时候,在编译好程序之后,可能就是一个简单的鼠标操作,单机一下 K e i l M D K I D E Keil\quad MDK\quad IDE KeilMDKIDE上的 D o w n l o a d Download Download就可以了,但是实际上在下载程序到 F l a s h Flash Flash上的时候还需要一个叫做 F l a s h p r o g r a m m i n g a l g o r i t h m Flash\quad programming\quad algorithm Flashprogrammingalgorithm的东西,如图1所示。因为我们知道一般芯片内部的 F l a s h Flash Flash如果要进行烧录的话,需要先擦除,那么这个 F l a s h p r o g r a m m i n g a l g o r i t h m Flash\quad programming\quad algorithm Flashprogrammingalgorithm就相当于给 K e i l M D K I D E Keil\quad MDK\quad IDE KeilMDKIDE提供了一系列操作内部的 F l a s h Flash Flash的接口。

     
    图1.

         一般情况下,芯片供应商已经在对应的 P A C K PACK PACK包里面为你准备好了对应的 F l a s h p r o g r a m m i n g a l g o r i t h m Flash\quad programming\quad algorithm Flashprogrammingalgorithm。那我们现在的问题是如何自己去构建 F l a s h p r o g r a m m i n g a l g o r i t h m Flash\quad programming\quad algorithm Flashprogrammingalgorithm文件。关于这一点大家可以先看一看 A R M ARM ARM公司关于这一块的官方介绍。下面我将简单的介绍一下 C O R T E X − M CORTEX-M CORTEXM系列芯片的 F l a s h p r o g r a m m i n g a l g o r i t h m Flash\quad programming\quad algorithm Flashprogrammingalgorithm文件的构建过程,注意这里是 C O R T E X − M CORTEX-M CORTEXM系列芯片, A R M ARM ARM公司其他系列芯片的 F l a s h p r o g r a m m i n g a l g o r i t h m Flash\quad programming\quad algorithm Flashprogrammingalgorithm文件的构建过程可能还不同。下面的讲解主要基于 C M S I S CMSIS CMSIS官方介绍
         首先找到你的 K e i l M D K I D E Keil\quad MDK\quad IDE KeilMDKIDE P A C K PACK PACK包的安装目录,然后将到图1(这里是我的 K e i l M D K I D E Keil\quad MDK\quad IDE KeilMDKIDE P A C K PACK PACK包的安装目录,你需要确定你自己的)所示的 F l a s h p r o g r a m m i n g a l g o r i t h m Flash\quad programming\quad algorithm Flashprogrammingalgorithm模板工程复制出来。然后可以根据自己的喜好改一下图4和图5中的名字,当然这里不改也是可以的,但是图3的地方还是需要改一下,因为我打算用 S T M 32 F 103 STM32F103 STM32F103作为测试的例子, S T M 32 F 103 STM32F103 STM32F103 M 3 M3 M3的内核,因此这里选择 M 3 M3 M3。最后一步也是最重要的一步是更改图6中的那两个文件,也就是一系列操作内部的 F l a s h Flash Flash的接口,接下来我们会重点讲到。有了这些之后编译这个工程就会生成你所需的 F l a s h p r o g r a m m i n g a l g o r i t h m Flash\quad programming\quad algorithm Flashprogrammingalgorithm

     
    图2.
     
    图3.
     
    图4.
     
    图5.
     
    图6.

         文件 F l a s h D e v . c FlashDev.c FlashDev.c里面主要是一些参数定义,定义在一个结构体中。图7是这个参数结构体的定义,结构体的第1个元素是下载算法的版本,这里自己填写,第2个元素是芯片相关描述,这里自己填写,第3个元素是 F l a s h Flash Flash所在位置,是片上( O N C H I P ONCHIP ONCHIP),还是片外( E X T _ x _ B I T EXT\_x\_BIT EXT_x_BIT),这里自己填写。第4个元素和第5个元素分别是 F l a s h Flash Flash的起始地址和大小(因为我这里的测试芯片是 S T M 32 F 103 Z E T 6 STM32F103ZET6 STM32F103ZET6,因此 F l a s h Flash Flash 512 K B = 0 x 00080000 512KB=0x00080000 512KB=0x00080000,虽然芯片在启动的时候,地址 0 x 00000000 0x00000000 0x00000000可以自动映射到地址 0 x 08000000 0x08000000 0x08000000,但是这里的起始地址只能写为 0 x 08000000 0x08000000 0x08000000),第6个元素是 F l a s h Flash Flash的一个页的大小, S T M 32 F 103 Z E T 6 STM32F103ZET6 STM32F103ZET6 F l a s h Flash Flash的一个页的大小为 2 K B = 2048 B Y T E S 2KB=2048BYTES 2KB=2048BYTES,第7个元素保留,第8个元素说明 F l a s h Flash Flash擦除完之后的内容,一般擦除完之后都是全F。第9个元素和第10个元素分别是 F l a s h Flash Flash页擦除和片擦除超时时间。最后一个元素定义了整片 F l a s h Flash Flash的页的分布情况,它是一个结构体数组。这个结构体有两个元素,第一个是一个页的大小,另一个是页的起始地址,要注意的是这里不用把每一个页的起始地址和大小都列出来,比如 S T M 32 F 103 Z E T 6 STM32F103ZET6 STM32F103ZET6 F l a s h Flash Flash一共有256个页,每一个页的大小都是 2 K B = 2048 B Y T E S 2KB=2048BYTES 2KB=2048BYTES,因此这里结构体数组的第0个元素写为 ( 2048 , 0 x 00000000 ) (2048,0x00000000) (2048,0x00000000)就可以了(注意这里的起始地址只能写为 0 x 00000000 0x00000000 0x00000000而不能写为 0 x 08000000 0x08000000 0x08000000,具体的细节的原因我占时不知道,如果你这里写为 0 x 08000000 0x08000000 0x08000000,在下载程序的时候会报错,程序无法下载成功),这就表明整片 F l a s h Flash Flash的大小都是 2 K B = 2048 B Y T E S 2KB=2048BYTES 2KB=2048BYTES。别忘了最后还要加一个数组元素 S E C T O R _ E N D SECTOR\_END SECTOR_END。那如果出现 F l a s h Flash Flash的所有页不是同样大小的情况怎么样,我们现在举一个简单的例子,假如 F l a s h Flash Flash开头的8页,每一页的大小都是 8 K B 8KB 8KB,接下来的两页,每一页的大小都是 64 K B 64KB 64KB,接下来的所有页,每一页的大小都是 8 K B 8KB 8KB,如图8所示,这个例子也是上面复制的模板工程里面原来的代码。改完之后的参数结构体如图9所示。

     
    图7.
     
    图8.
     
    图9.

         下面我们来详细介绍一下 F l a s h p r o g r a m m i n g a l g o r i t h m Flash\quad programming\quad algorithm Flashprogrammingalgorithm需要用到的一些接口函数以及相应的流程,这些函数都在文 F l a s h P r g . c FlashPrg.c FlashPrg.c中,如下所示,其中前面4个是必须的,后面3个可以根据需求可选,这里我在测试的时候只实现了必须要实现的接口函数。

    • I n i t ,(必须) Init,(必须) Init,(必须)
    • U n I n i t ,(必须) UnInit,(必须) UnInit,(必须)
    • E r a s e S e c t o r ,(必须) EraseSector,(必须) EraseSector,(必须)
    • P r o g r a m P a g e ,(必须) ProgramPage,(必须) ProgramPage,(必须)
    • E r a s e C h i p ,(可选) EraseChip,(可选) EraseChip,(可选)
    • B l a n k C h e c k ,(可选) BlankCheck,(可选) BlankCheck,(可选)
    • V e r i f y ,(可选) Verify,(可选) Verify,(可选)

         接口函数 B l a n k C h e c k BlankCheck BlankCheck主要的功能是用来检查当前的 F l a s h Flash Flash区域是否是空的,注意对于 F l a s h Flash Flash区域来说空的含义就是这个区域的每一个字节的内容都是全 F F F 0 x F F 0xFF 0xFF,起始如果对于一个区域是全 F F F的话,我们不去擦除就可以直接去烧录。当然这个函数也可以用来检查一块特定的 F l a s h Flash Flash区域的内容是否等于特定的值,比如每一个字节的内容是否等于 0 x A A 0xAA 0xAA。其中参数 a d r adr adr表示要检查的 F l a s h Flash Flash区域的起始地址,参数 s z sz sz表示要检查的 F l a s h Flash Flash区域的大小,参数 p a t pat pat表示要检查的 F l a s h Flash Flash区域的预期的特定值,比如 0 x F F 0xFF 0xFF

    int BlankCheck (unsigned long adr, unsigned long sz, unsigned char pat);
    Parameters
        adr	Block start address
        sz	Block size in bytes
        pat	Pattern to compare
    Returns
        status information:0 when the block content is equal to the pattern pat.
        status information:1 when the block content differs from the pattern pat.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

         接口函数 E r a s e C h i p EraseChip EraseChip主要的功能是用来擦除整片 F l a s h Flash Flash区域,如果我们在图10中配置下载算法的对话框中勾选了 E r a s e F u l l C h i p Erase\quad Full\quad Chip EraseFullChip的话,在下载程序的过程中, K e i l M D K I D E Keil\quad MDK\quad IDE KeilMDKIDE就会调用下载算法中的这个接口首先将整片 F l a s h Flash Flash区域擦除,这个函数实现起来是比较简单的,一般芯片设计公司提供的库函数里面就有响应功能的接口函数,参考一下就可以了,比如 S T ST ST公司的 S T M 32 F 103 STM32F103 STM32F103提供的擦除整片 F l a s h Flash Flash区域的接口函数如图11所示。如果我们没有实现这个接口函数的话, K e i l M D K I D E Keil\quad MDK\quad IDE KeilMDKIDE会不断调用 E r a s e S e c t o r EraseSector EraseSector接口函数,直到整片 F l a s h Flash Flash区域被擦除。

    int EraseChip (void);
    Returns 
        status information: 0 on success.
        status information: 1 on failure.
    
    • 1
    • 2
    • 3
    • 4
     
    图10.
    /*
     *  Erase complete Flash Memory
     *    Return Value:   0 - OK,  1 - Failed
     */
    
    int EraseChip (void) 
    {
        FLASH_Status status = FLASH_COMPLETE;
    
        /* Wait for last operation to be completed */
        status = FLASH_WaitForLastOperation(EraseTimeout);
        if(status == FLASH_COMPLETE)
        {
            /* if the previous operation is completed, proceed to erase all pages */
            FLASH->CR |= CR_MER_Set;
            FLASH->CR |= CR_STRT_Set;
        
            /* Wait for last operation to be completed */
            status = FLASH_WaitForLastOperation(EraseTimeout);
    
            /* Disable the MER Bit */
            FLASH->CR &= CR_MER_Reset;
        }
        /* Return the Erase Status */
        if(status == FLASH_COMPLETE)
        { 
            return (0);  		
    	}
    	else
        {
            return (1);  	
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
     
    图11.

         接口函数 E r a s e S e c t o r EraseSector EraseSector主要的功能是用来擦除 F l a s h Flash Flash区域的一页内容,如果我们在图10中配置下载算法的对话框中勾选了 E r a s e F u l l S e c t o r s Erase\quad Full\quad Sectors EraseFullSectors的话,在下载程序的过程中, K e i l M D K I D E Keil\quad MDK\quad IDE KeilMDKIDE就会调用下载算法中的这个接口。参数 a d r adr adr表示要擦除的 F l a s h Flash Flash区域的页的起始地址,这个函数实现起来是比较简单的,一般芯片设计公司提供的库函数里面就有响应功能的接口函数,参考一下就可以了,比如 S T ST ST公司的 S T M 32 F 103 STM32F103 STM32F103提供的擦除 F l a s h Flash Flash区域的一页接口函数如图12所示。

    int EraseSector (unsigned long adr);
    Parameters
        adr	Sector address
    Returns
        status information:0 on success.
        status information:1 on failure.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

         接口函数 E r a s e S e c t o r EraseSector EraseSector我的具体实现如下所示,因为原本的工程里面没有下面函数中 F L A S H FLASH FLASH等结构体的定义,因此这些结构体的定义,你需要自己添加进去。

    /*
     *  Erase Sector in Flash Memory
     *    Parameter:      adr:  Sector Address
     *    Return Value:   0 - OK,  1 - Failed
     */
    
    int EraseSector (unsigned long adr) 
    {
        FLASH_Status status = FLASH_COMPLETE;
    
        /* Wait for last operation to be completed */
        status = FLASH_WaitForLastOperation(EraseTimeout);
      
        if(status == FLASH_COMPLETE)
        { 
            /* if the previous operation is completed, proceed to erase the page */
            FLASH->CR|= CR_PER_Set;
            FLASH->AR = adr; 
            FLASH->CR|= CR_STRT_Set;
        
            /* Wait for last operation to be completed */
            status = FLASH_WaitForLastOperation(EraseTimeout);
        
            /* Disable the PER Bit */
            FLASH->CR &= CR_PER_Reset;
        }
    
        /* Return the Erase Status */
        if(status == FLASH_COMPLETE)
        { 
            return (0);  		
        }
        else
        {
            return (1);  	
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
     
    图12.

         接口函数 I n i t Init Init用来在操作 F l a s h Flash Flash区域前的一些初始化操作,像最基本的,在操作 F l a s h Flash Flash相关的寄存器前需要先解锁。参数 a d r adr adr表示 F l a s h Flash Flash设备的基地址,参数 f n c fnc fnc表示不同的操作,1表示擦除,2表示烧录,3表示验证,参数 c l k clk clk表示操作时的时钟频率,但是我看官方的模板函数里面这三个参数基本没有用到,这里我也没有细究了。这里我的具体实现也比较简单,也就是给 F l a s h Flash Flash操作解锁了。

    int Init (unsigned long adr, unsigned long clk, unsigned long fnc);
    Parameters
        adr	Device base address
        clk	Clock frequency (Hz)
        fnc	Function code
    Returns
        status information:0 on success.
        status information:1 on failure.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    /*
     *  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) 
    {
      FLASH_Unlock();
      return (0);                                 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

         接口函数 P r o g r a m P a g e ProgramPage ProgramPage主要的功能是在下载程序的过程中将编译好的代码文件烧录到 F l a s h Flash Flash区域中,每调用一次该函数只能烧录一页的内容。参数 a d r adr adr表示要烧录的 F l a s h Flash Flash区域的页的起始地址,参数 s z sz sz表示要烧录的 F l a s h Flash Flash区域的页的大小,参数 b u f buf buf存储要烧录到 F l a s h Flash Flash区域的页中的代码的实际内容。这个函数实现起来是比较简单的,但是这里 S T ST ST公司的 S T M 32 F 103 STM32F103 STM32F103的库函数里面没有直接的烧录一页的接口函数,只有烧录一个字或半个字的接口函数, S T M 32 F 103 STM32F103 STM32F103 F l a s h Flash Flash区域一次只能烧录半个字,我们可以可以调用如图13所示的烧录半个字的接口来实现烧录一页的接口函数。

    int ProgramPage (unsigned long adr, unsigned long sz, unsigned char *buf);
    Parameters
        adr	Page start address
        sz	Page size
        buf	Data to be written
    Returns
        status information: 0 on success.
        status information: 1 on failure.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    /*
     *  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) 
    {
        FLASH_Status status = FLASH_COMPLETE;	
        sz = (sz + 1) & ~1;                          // Adjust size for Half Words
     
        while (sz) 
        {
            status = FLASH_COMPLETE;
            status=FLASH_ProgramHalfWord(adr, *((unsigned short *)buf));		
            /* Return the Program Status */
            if(status != FLASH_COMPLETE)
            { 
                return (1);  	
    	    }	
            /* Go to next Half Word */
            adr += 2;
            buf += 2;
            sz  -= 2;				
        }
        return (0);                                 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
     
    图13.

         接口函数 U n I n i t UnInit UnInit用来进行在操作(擦除,烧录,验证) F l a s h Flash Flash区域后的一些操作,像最基本的,对 F l a s h Flash Flash相关的寄存器重新上锁。参数 f n c fnc fnc表示不同的操作,1表示擦除,2表示烧录,3表示验证,但是我看官方的模板函数里面这个参数基本没有用到,这里我也没有细究了。这里我的具体实现也比较简单,也就是给 F l a s h Flash Flash重新上锁。

    int UnInit (unsigned long fnc);
    Parameters
        fnc	Function code
    Returns
        status information:0 on success.
        status information:1 on failure.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    /*
     *  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) 
    {
      FLASH_Lock();
      return (0);                                 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

         接口函数 V e r i f y Verify Verify主要的功能是对比已经下载到 F l a s h Flash Flash区域中的代码和代码文件,也就是看下载到 F l a s h Flash Flash区域中的代码和编译生成的代码是否一致。参数 a d r adr adr表示要对比的 F l a s h Flash Flash区域的起始地址,参数 s z sz sz表示要对比的 F l a s h Flash Flash区域的大小,参数 b u f buf buf存储要对比的代码的实际内容。

    unsigned long Verify (unsigned long adr, unsigned long sz, unsigned char *buf);
    Parameters
        adr	Start address
        sz	Size in bytes
        buf	Data to be compared
    Returns
        status information:the sum of (adr+sz) - on success.
        status information:any other number - on failure, and represents the failing address.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

         有了以上修改之后,编译这个模板工程就可以生成你所需的下载算法了,下载算法的文件名后缀为 F L M FLM FLM,可以将这个生成的下载算法替代以前的下载算法,测试看看能否下载成功。最后图14是 F l a s h p r o g r a m m i n g a l g o r i t h m Flash\quad programming\quad algorithm Flashprogrammingalgorithm的擦除流程,图15是 F l a s h p r o g r a m m i n g a l g o r i t h m Flash\quad programming\quad algorithm Flashprogrammingalgorithm的程序烧录流程,图16是 F l a s h p r o g r a m m i n g a l g o r i t h m Flash\quad programming\quad algorithm Flashprogrammingalgorithm的验证流程。我的测试工程在这里。

     
    图14.
     
    图15.
     
    图16.
  • 相关阅读:
    FME读写cass数据的方案及操作流程
    es6语法import()的使用
    Javaweb之Vue的概述
    建立对象模型— 划分主题
    华为eNSP配置专题-VLAN和DHCP的配置
    基于stm32单片机的智能恒温箱游泳池
    scitb包1.5版本发布—增加了统计值的结果和自动判断数据是否正态分布的功能
    Vue——Vue脚手架安装的详细教程
    2023年度中国开源研究报告
    2022下半年(软考高级)信息系统项目师备考开班啦!
  • 原文地址:https://blog.csdn.net/caoleiwe/article/details/125956790