基于APM32F407如何制作I2C EEPROM(AT24C02型号)的MDK-Keil下载算法

描述

 

前言

最近在做的一个项目中,需要经常把一些参数下载到I2C EEPROM中,然后MCU上电去读取。如果在产品量产过程中,可以使用烧录治具往EEPROM写入一次即可。但是在调试开发阶段,需要经常修改这些数据,调试起来非常不方便。

我调试的环境是MDK-Keil,于是网上了解了下如何制作Keil的下载算法,下面介绍下基于APM32F407如何制作I2C EEPROM(AT24C02型号)的Keil下载算法,这样在我们下载代码时可以一键把数据烧录到EEPROM中。

对于 Keil 的下载算法文件相关的详细介绍可以到官方在线文档进行了解,这些文档详细介绍了下载算法的实现细节。文档链接如下:

https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/flashAlgorithm.html

1. Keil如何调用下载算法

Keil的下载算法,我的理解就是可以通过Keil去调用该下载算法,然后可以去编程各种存储设备,比如MCU内部的Flash,通过MCU外设连接外扩的SPI Flash或者I2C EEPROM等器件。

要想通过Keil IDE的下载按钮一键编程这些存储设备,那么需要有对应器件的下载算法才能去编程。对于Keil来说通过调试界面指定相应的下载算法 xxx.FLM 文件,然后就可以被调用了,如下图:

keil

‍‍Keil 在调试下载阶段,会把算法文件加载到芯片的内部 RAM 里面,加载的芯片内部的RAM地址和大小可以在上面的配置截图进行设置。然后就可以在 RAM 中执行这个下载算法文件的擦除、编程等函数,从而实现对存储设备下载程序或者在调试阶段读取数据等操作。

大致流程如下图:‍‍

keil

主要是分为两步:

通过SWD/JTAG调试接口,把下载算法加载到RAM。

执行下载算法的擦除、编程等函数,从而对内部Flash进行编程或者通过MCU的片上外设对外扩的SPI FLASH/I2C EEPROM执行编程操作。

另外,前面说到会把下载算法文件加载到 RAM 运行,而且我们可以设置加载到任何的 RAM 地址运行,那么对下载算法生成的代码必须是与位置无关的代码,这样才能加载到任意 RAM 地址运行。

2.Keil下载算法函数和执行流程

2.1 下载算法需要实现哪些函数

根据官方文档介绍,要制作一个新的下载算法需要实现函数有:

keil

一共有7个函数,而且这些函数的原型已经规定好了的,只需要我们根据不同的存储设备实现具体的功能即可。

其中有 mandatory 修饰的函数,是制作一个新的下载算法必须要实现的函数是,而 optional 修饰的函数则可根据需要实现还是不实现。

2.2 擦除流程

keil

加载算法到芯片 RAM。

执行初始化函数 Init。

执行擦除操作。其中擦除操作会根据Keil的配置选项,选择是擦除整个芯片还是扇区擦除。

执行 Uinit 函数。

擦除完成。

2.3 编程流程

编程流程,就是把编译出来的可执行程序下载到Flash或者其他存储器。

keil

对于所有 AXF 文件内容,执行 Init 初始化函数

判断 Flash 算法是否在FLM文件中。不在则编程结束,返回失败。如果编程算法存在,则执行下面操作:

(1)加载算法到RAM

(2)执行Init函数

(3)加载应用程序(待编程的数据)到RAM Buffer中

(4)执行Program Page编程函数

(5)执行Uninit函数

编程完成。

2.4 校验流程

校验就是把 AXF 文件中需要下载到Flash的数据,与实际下载到Flash的数据读出来进行比较。

keil

判断 Flash 算法是否在FLM文件中,不在则操作失败。如果编程算法存在,则执行下面操作:

(1)加载算法到RAM

(2)执行Init函数

(3)判断FLM文件是否存在校验算法。

存在则加载应用程序到RAM,然后执行FLM文件中的校验算法

不存在则计算和比较CRC值。把下载到Flash的数据读出来计算的CRC值,与 加载 axf 文件的数据到RAM中计算的CRC值进行比较。

执行Uninit函数

执行完 Uninit 函数后面的步骤,不是很理解,这后面的步骤是不是和调试有关的,在下载代码时并没有关系?

3. 制作Keil环境的I2C EEPROM下载算法

下面我基于APM32F407,制作AT24C02 EEPROM存储芯片的下载算法。

对于下载算法的制作流程,官网已经给出了详细的步骤,下面的步骤是从官网翻译过来的。一个新的下载算法制作步骤:

ARM:CMSIS Pack 文件夹(通常为 C:KeilARMPackARMCMSIS version Device_Template_Flash)中的内容复制到新文件夹。

重命名项目文件NewDevice.uvprojx以表示新的闪存 ROM 设备名称,例如MyDevice.uvprojx

使用 uVision 打开项目。从工具栏中,使用下拉菜单选择目标”来定义处理器架构。Cortex-M适用于所有 Cortex-M0/M0+、M3 和 M4 设备。该配置假定采用小端微控制器。如果是大端微控制器,请使用Project - Options for Target - Device选择正确的处理器内核。

打开对话框“项目-目标选项-输出” ,然后更改“可执行文件名称”字段的内容以表示设备,例如MyDevice

调整文件FlashPrg中的编程算法。

调整文件FlashDev中的设备参数。

使用Project - Build Target生成新的Flash 编程算法。输出文件(例如MyDevice.FLM)必须添加到DFP中。

上面的步骤就是官网给出的,下面我们就根据官网给出的步骤制作一个新的下载算法。

3.1 准备下载算法模板

下载算法的模板,我们在安装Keil的时候就有了的。官网说在 keil 的安装目录下能找到,但是我安装的是 5.36 版本,Keil安装目录没有找到,而是在 C:Users你的用户名目录AppDataLocalArmPacksARMCMSIS5.8.0Device_Template_Flash  这个目录找的的下载算法模板。

keil

我们把该目录复制一份备用,然后记得把该文件夹的只读属性去掉。

3.2 Keil环境设置

1、把复制的模板工程的工程名,可以根据我们基于什么芯片制作下载算法修改一下工程名称,这样更具有辨识度。

2、修改选择的目标芯片。

keil

我是基于APM32F407制作下载算法文件,所以选择M4内核就行。

3、修改编译生成的下载算法文件的名称。

keil

4、添加APM32F407的外设驱动库以及I2C EEPROM的读写驱动文件

由于我们是要实现 I2C EEPROM 的下载算法,在编写这些下载算法函数之前,我们必须要先确保 I2C EEPROM 的驱动可以正常读写。I2C EEPROM 的驱动可以从我们实现的例程验证可行之后,然后挪过来使用即可。

keil

3.3 修改FlashPrg.c文件中的编程算法函数

这一步是最重要的,我们实现Keil编程算法主要就是要实现 FlashPrg.c 文件中的各个下载算法函数。根据前面的介绍,一个新的下载算法必须要实现的函数有:Init/EraseSector/ProgramPage/Uninit 这4个函数,其他函数可以根据需要是否实现。下面我们来一一实现这些函数。

1、Init函数的实现

/*

 *  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();  // 如果使用了库文件的该函数会导致下载是0x08000000地址校验失败,但是实际测试又是下载进去了。不知道什么原因

    I2C_Init();

    return 0;

}

在该函数中,我们可以初始化编程存储器的一些操作,比如配置时钟,GPIO的初始化等等。

2、扇区擦除和整片芯片擦除函数

/*

 *  Erase complete Flash Memory

 *    Return Value:   0 - OK,  1 - Failed

 */

int EraseChip (void) 

{

    volatile int i = 0;

    unsigned char tmepbuf[EE_PAGE_SIZE];

    unsigned char adr = 0;

    for(i = 0; i < EE_PAGE_SIZE; i++)

    {

        tmepbuf[i] = 0xFF;

    }

    for (i = 0; i < EE_SIZE / EE_PAGE_SIZE; i++)

    {

        ee_WriteBytes(tmepbuf, adr, EE_PAGE_SIZE);

        adr += EE_PAGE_SIZE;

    }

    return 0;

}

/*

 *  Erase Sector in Flash Memory

 *    Parameter:      adr:  Sector Address

 *    Return Value:   0 - OK,  1 - Failed

 */

int EraseSector (unsigned long adr) 

{

    volatile int i = 0;

    unsigned char tmepbuf[EE_PAGE_SIZE];

    adr -= I2C_EEPROM_ADDR;

    for(i = 0; i < EE_PAGE_SIZE; i++)

    {

        tmepbuf[i] = 0xFF;

    }

    ee_WriteBytes(tmepbuf, adr, EE_PAGE_SIZE);

    return 0;

}

实际上对于EEPROM芯片,不需要擦除就能写入数据的。不过为了示例,我们也实现这两个擦除函数好了。对于EERPOM来说,擦除就是往它写入0xFF数据即可。

3、ProgramPage 页编程函数实现

#define I2C_EEPROM_ADDR 0x01000000

/*

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

{

volatile int i = 0;

adr -= I2C_EEPROM_ADDR;

for(i = 0; i < sz/EE_PAGE_SIZE; i++)

{

ee_WriteBytes(buf+EE_PAGE_SIZE*i, adr+EE_PAGE_SIZE*i, EE_PAGE_SIZE);    

}

if(sz%EE_PAGE_SIZE)

{

ee_WriteBytes(buf+EE_PAGE_SIZE*i, adr+EE_PAGE_SIZE*i, sz%EE_PAGE_SIZE);    

}

return (0);

}

直接调用EEPROM的驱动写函数即可。另外 I2C_EEPROM_ADDR 这个宏定义,是为了在我们的应用代码中,定义数据时选择哪一块区域存储EEPROM的数据,地址是我们可以随意定义的。但是不能与MCU的外设地址,以及Flash、RAM等地址重合就行。

4、Uninit函数实现

该函数根据前面的Keil执行各编程流程,一般是退出编程时会被调用的,我们可以在该函数进行恢复的操作。该函数是必须实现的,如果不需要做任何动作,那么我们保持该函数为空函数就行。

/*

 *  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

}

3.4 修改FlashDev.c文件的设备参数

在FlashDev.c文件中有一个名为FlashDevice的结构体常量,这个结构体的信息是给 Keil 提供编程设备的信息的,比如编程的起始地址,总大小,一个扇区的大小,设备类型等等信息。我们根据自己的需要编程的设备类型修改即可。

struct FlashDevice const FlashDevice  =  {

   FLASH_DRV_VERS,             // Driver Version, do not modify!

   "APM32F407_I2C_EEPROM_AT24C02",   // Device Name 

   EXTSPI,                     // Device Type

   0x01000000,                 // Device Start Address. EEPROM的编程地址。

   0x00000100,                 // Device Size in Bytes

   8,                       // Programming Page Size

   0,                          // Reserved, must be 0

   0xFF,                       // Initial Content of Erased Memory

   6000,                        // Program Page Timeout 6000 mSec

   6000,                       // Erase Sector Timeout 6000 mSec

// Specify Size and Address of Sectors

   0x000008, 0x000000,         // Sector Size  8B (32 Sectors)

//   0x010000, 0x010000,         // Sector Size 64kB (2 Sectors) 

//   0x002000, 0x030000,         // Sector Size  8kB (8 Sectors)

   SECTOR_END

};

3.5 生成算法文件

我们实现了 FlashPrg.c 文件的编程算法函数之后,直接编译就可以生成 xxx.FLM 算法文件了。

在编译之前,我们需要检查生成的代码是位置无关码。在Keil设置如下:

keil

C/C++和Asm选项卡都要检查是否已经勾选了上面的配置。

点击编译即可生成Keil下载算法文件。

keil

4. 新制作的下载算法文件使用和测试

1、把生成的下载算法文件放置到Keil安装的目录 C:Keil_v5ARMFlash 下待使用

keil

2、Keil环境配置下载算法

keil

3、APM32F407_I2C_EEPROM算法测试验证。

我们使用下载算法下载数据到EERPOM,然后再通过应用程序读出来进行对比写进去的数据是否一致,就可以知道EEPROM下载算法是否起作用。

我们找一个 APM32F407 EEPROM 的例程进行测试。

(1)首先在例程里面定义下面待烧录到EEPROM的数据:

const uint8_t EEPROM_FLM_Test1[16] __attribute__((at(0x01000000))) = {

    0xCB,0xFF,0x01,0x02,0x03,0xAA,0x06,0x07,

    0x08,0x09,0x10,0xA1,0xA2,0xA3,0xA4,0xBB

};

const uint8_t EEPROM_FLM_Test2[16] __attribute__((at(0x010000A0))) = {

    0x12,0x34,0x01,0x02,0x03,0xAA,0x06,0x07,

    0x08,0x09,0x10,0xA1,0xA2,0xA3,0xA4,0xBB

};

其中我们规定这些数组必须链接到 0x01000000 起始的地址,这是因为我们制作的 EEPROM 的下载算法编程地址就是在该范围,这个地址会在下载算法内部转换为EEPROM 编程的 0 地址,比如说 0x01000000 起始地址,对应的就算EEPROM的0地址。

(2)然后编译下载代码到Flash和EEPROM即可。

下载代码时,检测的0x01000000地址需要下载数据,Keil就会自动调用EEPROM的下载算法把数据编程到EEPROM了。

如下在下载程序没有报错,下载完成。

keil

然后运行代码,把EEPROM的数据读出来,对比是否一致。

keil

《APM32芯得》系列内容为用户使用APM32系列产品的经验总结,来自21ic论坛极海半导体专区。在此特别鸣谢!

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分