搜索
bottom↓
回复: 6

【经验分享】C90TFS_FTFx KL25 flash例程讲解

[复制链接]

出0入0汤圆

发表于 2014-9-30 20:02:38 | 显示全部楼层 |阅读模式
【经验分享】C90TFS_FTFx KL25 flash例程讲解
一,经验分享简介
        之前写过一篇关于官方C90TFS_FTFX flash标准软件驱动简介这篇文章,主要简单介绍了C90TFS这个flash驱动所支持的芯片,函数结构,以及一些API函数基本意思。其实在C90TFS的驱动文档中也能找到。从C90TFS来看,这个驱动软件对于使用kinetis芯片的flash控制还是很有帮助的,通过各种API函数,能够完成所有的kinetis芯片的flash操作,无需自己再重新编写相关的寄存器控制函数去实现。
     为了便于大家进一步了解C90TFS驱动在kinetis芯片中的实现情况,本文以测试平台TWR-KL25Z48M为例,集合C90TFS驱动中的demo_normal工程具体讲解如何使用C90TFS flash驱动实现kinetis 芯片的flash操作。
C90TFS FLASH 下载链接:
http://cache.freescale.com/files ... xe?fromsite=zh-Hans
二,经验分享前提准备
       本章节主要讲解C90TFS中,关于KL25的例程工程构成,配置文件情况,要讲解的例程选择以及测试平台的选择等,为后续的详细代码讲解以及验证做一个准备。
1, C90TFS flash KL25例程工程构成
        安装好C90TFS flash之后,可以从如下的路径找到KL25的相关代码。
安装路径\Standard Sotfware Driver v101\C90TFS\Demos\build\MKL25Z128xxx4
可以看到,供有两种编译器的代码,分别为IAR以及CW10.4, CW10.4 的工程可以用CW10.4及其以后的版本打开。IAR的工程可以使用IAR embedded workbench for ARM 6.4.2之后的版本打开。
        打开路径下IAR的工程,可以看到C90TFS具体包含的KL25flash例程情况,如下图:

图 1 例程情况
从上图中可以看到,一共具有4个例程, 具体例程的功能已经在图中标出。本次例程讲解使用demo_normal例程,旨在让大家熟悉C90TFS flashAPI函数的使用。
2, C90TFS flash例程配置文件情况
        这里以demo_normal 工程为例,讲解配置文件。程序一共有两种运行方式, 分别为从RAM运行,以及从Flash运行。通过配置相应的.icf文件(IAR)或者.ld文件(CW 10.x)实现。
     IAR中,.icf文件可以打开project后在link_file文件夹下找到。
CW中,.ld 文件可以打开project后在project_settings->linker_files文件夹下找到。
这里以CW工程为例讲解,IAR的情况也类似,主要是空间的起始结束地址,以及堆栈分配,中断向量的分配等。
(1)        CW 16KB_Ram.ld

图2 ram ld
(2)        CW 128KB_Pflash.ld


图3 flash ld
3. 测试平台
CW10.6 以及TWR-KL25Z48M。
选择使用CW10.6,是因为,测试的时候,可以直接看出哪些代码在编译范围内,便于查看代码,如下图:

图4 CW代码查看
三,代码讲解及测试
通过实例的代码讲解即测试,进一步了解flash驱动的API函数使用。
1:KL25的结构体定义
原FLASH_SSD_CONFIG结构体定义:
typedef struct _ssd_config
{
UINT32 ftfxRegBase;
UINT32 PFlashBlockBase;
UINT32 PFlashBlockSize;
UINT32 DFlashBlockBase;
UINT32 DFlashBlockSize;
UINT32 EERAMBlockBase;
UINT32 EEEBlockSize;
BOOL DebugEnable;
PCALLBACK CallBack;
} FLASH_SSD_CONFIG, *PFLASH_SSD_CONFIG;
其中:
ftfxRegBase,UINT32 , flash模块基地址
PFlashBlockBase ,UINT32,Pflash块的基地址
PFlashBlockSize,UINT32,Pflash块的大小
DFlashBlockBase,UINT32,FlexNVM区中划分为Dflash的基地址。无FlexNVM则无用
DFlashBlockSize,UINT32,FlexNVM区中划分为Dflash的块大小
EERAMBlockBase,UINT32,flexRAM的基地址。
EEEBlockSize,UINT32,EEPROM的大小(flexRAM)中
DebugEnable,BOOL,后台调试模式,TRUE:使能调试模式;FALSE:禁止调试模式
CallBack,函数指针,回调函数用于时间要求高的事件

KL25变量声明:
FLASH_SSD_CONFIG flashSSDConfig =
{
    FTFx_REG_BASE,          /* FTFx control register base */
    PFLASH_BLOCK_BASE,      /* base address of PFlash block */
    PBLOCK_SIZE,            /* size of PFlash block */
    DEFLASH_BLOCK_BASE,     /* base address of DFlash block */
    0,                      /* size of DFlash block */
    EERAM_BLOCK_BASE,       /* base address of EERAM block */
    0,                      /* size of EEE block */
    DEBUGENABLE,            /* background debug mode enable bit */
    NULL_CALLBACK           /* pointer to callback function */
};

其中:
FTFx_REG_BASE = 0x40020000
PFLASH_BLOCK_BASE         0x00000000
DEFLASH_BLOCK_BASE        0xFFFFFFFF
PBLOCK_SIZE               0x00020000      /* 128KB size */
EERAM_BLOCK_SIZE          0x00000000   
DEBUGENABLE               0x00
NULL_CALLBACK                   ((PCALLBACK)0xFFFFFFFF)

FTFx_REG_BASE的基地址,可以从用户手册中查看

图5 FTFA基地址
  
图6 flash大小即地址范围

2, flash初始化
    /**************************************************************************
    *                               FlashInit()                                  ***************************************************************************/
    ret = FlashInit(&flashSSDConfig);
    if (FTFx_OK != ret)
    {
        ErrorTrap(ret);
}
初始化API函数,保护清楚错误状态标志位,设置内存的Dflash以及EEPROM大小等情况,由于KL25没有flexNVM以及flexRAM,所以这部分只是设置了Dflash以及EEPROM大小为0.
3,擦除整个flash
    ret = FlashEraseAllBlock(&flashSSDConfig, FlashCommandSequence);
    if (FTFx_OK != ret)
    {
        ErrorTrap(ret);
}
查看API函数FlashEraseAllBlock,会发现其实执行的就是flash全片擦除指令
UINT32 FlashEraseAllBlock (PFLASH_SSD_CONFIG pSSDConfig, \
                       pFLASHCOMMANDSEQUENCE pFlashCommandSequence)

{
    UINT32 ret;         /* return code variable */
   /* clear RDCOLERR & ACCERR & FPVIOL flag in flash status register. Write 1 to clear*/
    REG_WRITE(pSSDConfig->ftfxRegBase + FTFx_SSD_FSTAT_OFFSET,FTFx_SSD_FSTAT_ERROR_BITS);
   
    /* passing parameter to the command */
    REG_WRITE(pSSDConfig->ftfxRegBase + FTFx_SSD_FCCOB0_OFFSET, FTFx_ERASE_ALL_BLOCK);// FTFx_ERASE_ALL_BLOCK=0x44

    /* calling flash command sequence function to execute the command */
           
    ret = pFlashCommandSequence(pSSDConfig);

    /* Enter Debug state if enabled */
    if (TRUE == (pSSDConfig->DebugEnable))
    {
        ENTER_DEBUG_MODE;
    }

    return(ret);
}
命令正如KL25的用户手册规定的一样:

图 7 整片擦除命令
运行之后,可以查看整个flash,会发现就连0X40C,锁的地方0x40c地址也被擦除成0xFF了。

图8 全片擦除查看
4 整片flash验证
    for (i = 0; i < 0x2; i ++) /* scan for normal and user margin levels */
    {
        ret = FlashVerifyAllBlock(&flashSSDConfig, i, FlashCommandSequence);
        if (FTFx_OK != ret)
        {
            ErrorTrap(ret);
        }
    }
擦除了整片的FLASH之后,使用FlashVerifyAllBlock检查下整个flash ,其实就是read 1s all blocks command,详细描述可以参考器件RM, command 如下:

图 9 读 1S 所有block的flash

5 写入加密位到flash configuration field.
UINT8 unsecure_key[PGM_SIZE_BYTE] = {0xFE, 0xFF, 0xFF, 0xFF};  
    /* Program the Security Byte in the Flash Configuration Field to an unsecure value */
    ret = FlashProgram(&flashSSDConfig, SECURITY_LOCATION, PGM_SIZE_BYTE, unsecure_key, FlashCommandSequence);
    if (FTFx_OK != ret)
    {
        ErrorTrap(ret);
    }
函数目的就是给0X40C写入0XFE,也就是让之前因为擦除而导致0X40C为锁状态的情况修改为解锁。该函数使用是program longword command.

图 10 长字节编程命令
写之前flash configuration field,加密字节0X40C情况如下:

图11 加密字节写入解锁数据之前

图12 加密字节写入解锁数据之后
可以看到,运行解密代码之后,0X40C已经变为0XFE,也就是芯片处于解锁状态。
6  给0x00-0XFF写入0到256数据
    for (i = 0; i < BUFFER_SIZE_BYTE; i++)
    {
        /* Set source buffer */
        buffer = i;
    }
   
    /* Program to the first location of PFLASH */
    destination = flashSSDConfig.PFlashBlockBase;
    size = BUFFER_SIZE_BYTE;

    ret = FlashProgram(&flashSSDConfig, destination, size, \
                                       buffer, FlashCommandSequence);
    if (FTFx_OK != ret)
    {
        ErrorTrap(ret);
    }
和第5条一样,也是使用长字节编程写入的。下面直接给出测试结果:

图13 编程之前

图14 编程之后
代码中,后面的给0XC00到0X1300也是用的同样的方法写程序的。
7 FlashReadResource功能
   /**************************************************************************
    *                          FlashReadResource()                            *
    ***************************************************************************/
    /* Read on P-Flash */
    destination = flashSSDConfig.PFlashBlockBase + PFLASH_IFR; /* Start address of Program Once Field */
    ret = FlashReadResource(&flashSSDConfig, destination, DataArray, 0x0, FlashCommandSequence);

    if (FTFx_OK != ret)
    {
        ErrorTrap(ret);
    }
该功能是读取IFR中的0XC0开始的四个字节到DataArray[PGM_SIZE_BYTE];
从下面的图可以知道, DataArray的地址是0X20002054.

图15  DataArray地址查看
查看0X20002054的连续四个字节的数据如下:

图16 运行之前DataArray数组数据

图17 运行之后DataArray数组数据
可以知道,读出来的0XC0开始的IFR数据为0XFF。
IFR地址的情况如下,其实0XC0输入一次编程区域。

图18 IFR 地址情况

8  FlashGetSecurityState功能
    securityStatus = 0x0;
    ret = FlashGetSecurityState(&flashSSDConfig, &securityStatus);

    if (FTFx_OK != ret)
    {
        ErrorTrap(ret);
    }
其实就是读取FTFA_FSEC加密位到securityStatus, securityStatus=1 未加密, 2 加密,后门秘钥允许,4 加密,后门秘钥禁止。
测试结果securityStatus=1, 即不加密

9 按照sector擦除flash
    j = 1;
    destination = flashSSDConfig.PFlashBlockBase;
    while ((destination + BYTE2WORD(j*FTFx_PSECTOR_SIZE)) < (flashSSDConfig.PFlashBlockBase + BYTE2WORD(flashSSDConfig.PFlashBlockSize)))// 0x400<0x20000
    {
        size = j*FTFx_PSECTOR_SIZE;  // j*0x400, j times sectors
        ret = FlashEraseSector(&flashSSDConfig, destination, size, \
                                     FlashCommandSequence); // just erased one sector, from 0x00 to 0x3ff
        if (FTFx_OK != ret)
        {
            ErrorTrap(ret);
        }

        /* Verify section for several sector of PFLASH */
        number = FTFx_PSECTOR_SIZE/PRD1SEC_ALIGN_SIZE;
        for(i = 0; i < 0x2; i ++)
        {
            ret = FlashVerifySection(&flashSSDConfig, destination, number, \
                                            i, FlashCommandSequence);
            if (FTFx_OK != ret)
            {
                ErrorTrap(ret);
            }
        }
        destination += BYTE2WORD(flashSSDConfig.PFlashBlockSize/PBLOCK_NUM - size); // sector erase, after erased, then mins it.
        j ++;
}
功能就是擦除0X00 到0x3FF,这里以前面字节为例查看结果:


图19 擦之前0x00开始的情况

图20 擦之后0x00开始的情况

10 flash保护代码测试
    /**************************************************************************
    *                          PFlashGetProtection()                          *
    ***************************************************************************/
    ret = PFlashGetProtection(&flashSSDConfig, &protectStatus1);
    if (FTFx_OK != ret)
    {
        ErrorTrap(ret);
    }
   
    /**************************************************************************
    *                          PFlashSetProtection()                          *
    ***************************************************************************/
    protectStatus1 = 0x12ABCDEF;
    ret = PFlashSetProtection(&flashSSDConfig, protectStatus1);
    if (FTFx_OK != ret)
    {
        ErrorTrap(ret);
    }
   
    /* Call PFlashGetProtection to verify the set step */
    ret = PFlashGetProtection(&flashSSDConfig, &protectStatus1);
    if (FTFx_OK != ret || 0x12ABCDEF != protectStatus1)
    {
        ErrorTrap(ret);
}
Flash 保护代码功能测试,上面的代码是首选获取flash的代码保护情况,然后设置flash的保护,最后再获取设置后的flash保护情况。获取和设置,其实都是针对的FTFA_FPROT0到FTFA_FPROT3.
下面为测试结果:

图21 第一次获取flash保护
可以看到,flash没有被保护。

图22 设置保护后再次获取flash保护

图23 设置保护后查看寄存器的保护情况

可以看到,这时候寄存器FTFA_FPROT0到FTFA_FPROT3显示的值是保护的。
但是,这样设置寄存器保护了flash,那么有没有改变到flash configuration field呢?毕竟每次reset后,FTFA_FPROT0到FTFA_FPROT3是从flash configuration field调取数据的。

图 24 flash configuration field

图 25 flash configuration field值
可以看到,虽然控制寄存器为flash保护,但是flash configuration field 并没有改变, 则如果要每次都让flash 都要保护,就需要直接修改flash configuration field。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

 楼主| 发表于 2014-9-30 20:03:05 | 显示全部楼层
不足之处,欢迎指正,同时也欢迎大家分享自己的经验。

出0入0汤圆

发表于 2014-9-30 21:32:28 | 显示全部楼层
请问官方C90TFS_FTFX flash标准软件驱动如果要修改一个字节的数据需要先擦一个块,才可以吗?还有就是擦除有几种方式(全片/单个块/单个地址位)?

出0入0汤圆

 楼主| 发表于 2014-9-30 21:36:54 | 显示全部楼层
步之道 发表于 2014-9-30 21:32
请问官方C90TFS_FTFX flash标准软件驱动如果要修改一个字节的数据需要先擦一个块,才可以吗?还有就是擦除 ...

擦除最小是按sector的,只修改一个字节,就需要读出来,然后擦除sector,然后修改写入。

出0入0汤圆

发表于 2014-10-1 00:19:19 | 显示全部楼层
FSL_TICS_ZJJ 发表于 2014-9-30 21:36
擦除最小是按sector的,只修改一个字节,就需要读出来,然后擦除sector,然后修改写入。 ...

如果这样的话,对flash的使用寿命不太好吧。

出100入101汤圆

发表于 2014-10-4 06:14:17 | 显示全部楼层
请教下LZ,Flash擦除或写入时,刚好碰到断电的话,常出现sector数据被破坏情况。有没有好的解决办法?

出0入0汤圆

发表于 2014-10-4 09:00:44 | 显示全部楼层
flash本来就是当程序存储器(rom)使用的,写入时间比机内ram要长许多,使用中应该不会经常去修改的。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-24 01:44

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表