[嵌入式开发模块]MC9S12XEP100 FTM模块 驱动程序

MC9S12XEP100的Flash包含:

  • 128KB的P-Flash 内存,由两个物理Flash block组成,用于存储非易失性代码。
  • 32KB的D-Flash内存,由一个物理Flash block组成,可作为Flash内存存储非易失性数据,或用于支持内建的模拟EEPROM。
  • 2KB的缓存RAM,由一个物理RAM block组成,可用作普通的RAM,或者用于支持内建的模拟EEPROM。

MC9S12(X)系列单片机的Flash内存可以在不加外部电压的情况下自我重编程(擦除/写入),这是通过FTM模块提供的一个内存控制器来完成的,内存控制器独立于内核运行,用户通过给内存控制器传递命令及参数以使内存控制器修改Flash内存内容或配置模拟EEPROM资源;控制过程如下图:

FTM内存控制器控制流程

本驱动程序对这个控制过程进行了封装(即FTM_LaunchCommand函数),并进一步对所有可用的命令进行了封装,提供了用户友好的接口,方便各位使用。

下面上代码:
先是FTM.h文件

/*
*********************************************************************************************************
*
*
*                              FLASH TECHNOLOGY MODULE SUPPORT MODULE
*                                      FREESCALE MC9S12XEP100
*                              飞思卡尔单片机 FLASH模块(FTM) 支持包
*
* File    : FTM.h
* By      : Lin Shijun(http://blog.csdn.net/lin_strong)
* Date    : 2018/04/12
* Version : V2.0
* Note    : 1. this module is customized for MC9S12XEP100. If used for other derivation, it may need
*              some modification according to the PARTID.
* History : 2018/03/12  v1.0  prototype of the package.
*           2018/03/31  v1.1  a little modification.
*           2018/04/12  v2.0  encapsulate all of the FLASH COMMON COMMAND into more user-friendly interface.
*********************************************************************************************************
*/

#ifndef _FTM_H
#define _FTM_H
/*
*********************************************************************************************************
*                                   TYPE DEFINITION 类型定义
*********************************************************************************************************
*/

/*** FSTAT - Flash Status Register; ***/
typedef union {
  unsigned char Byte;
  struct {
    unsigned int MGSTAT0     :1;             /* Memory Controller Command Completion Status Flag 0 */
    unsigned int MGSTAT1     :1;             /* Memory Controller Command Completion Status Flag 1 */
    unsigned int             :1; 
    unsigned int MGBUSY      :1;             /* Memory Controller Busy Flag */
    unsigned int FPVIOL      :1;             /* Flash Protection Violation Flag */
    unsigned int ACCERR      :1;             /* Flash Access Error Flag */
    unsigned int             :1; 
    unsigned int CCIF        :1;             /* Command Complete Interrupt Flag */
  } Bits;
} FTM_FSTAT;

#define FTM_FSTAT_MASK_MGSTAT0             1U
#define FTM_FSTAT_MASK_MGSTAT1             2U
#define FTM_FSTAT_MASK_MGBUSY              8U
#define FTM_FSTAT_MASK_FPVIOL              16U
#define FTM_FSTAT_MASK_ACCERR              32U
#define FTM_FSTAT_MASK_CCIF                128U
#define FTM_FSTAT_MASK_ANYERR      (FTM_FSTAT_MASK_MGSTAT0 | FTM_FSTAT_MASK_MGSTAT1 | FTM_FSTAT_MASK_MGBUSY |\
                                     FTM_FSTAT_MASK_FPVIOL | FTM_FSTAT_MASK_ACCERR)

/*** FERSTAT - Flash Error Status Register; ***/
typedef union {
  unsigned char Byte;
  struct {
    unsigned int SFDIF       :1;              /* Single Bit Fault Detect Interrupt Flag */
    unsigned int DFDIF       :1;              /* Double Bit Fault Detect Interrupt Flag */
    unsigned int ERSVIF0     :1;              /* EEE Error Type 0 Interrupt Flag */
    unsigned int ERSVIF1     :1;              /* EEE Error Type 1 Interrupt Flag */
    unsigned int EPVIOLIF    :1;              /* EEE Protection Violation Interrupt Flag */
    unsigned int             :1; 
    unsigned int PGMERIF     :1;              /* EEE Program Error Interrupt Flag */
    unsigned int ERSERIF     :1;              /* EEE Erase Error Interrupt Flag */
  } Bits;
} FTM_FERSTAT;

#define FTM_FERSTAT_MASK_SFDIF             1U
#define FTM_FERSTAT_MASK_DFDIF             2U
#define FTM_FERSTAT_MASK_ERSVIF0           4U
#define FTM_FERSTAT_MASK_ERSVIF1           8U
#define FTM_FERSTAT_MASK_EPVIOLIF          16U
#define FTM_FERSTAT_MASK_PGMERIF           64U
#define FTM_FERSTAT_MASK_ERSERIF           128U
#define FTM_FERSTAT_MASK_ERSVIF            12U
#define FTM_FERSTAT_MASK_ANYERR  (FTM_FERSTAT_MASK_SFDIF | FTM_FERSTAT_MASK_DFDIF | FTM_FERSTAT_MASK_ERSVIF0 | \
                         FTM_FERSTAT_MASK_ERSVIF1 | FTM_FERSTAT_MASK_EPVIOLIF | FTM_FERSTAT_MASK_PGMERIF | \
                         FTM_FERSTAT_MASK_ERSERIF)

typedef union{    //Used to copy and store Flash error status registers.
  unsigned short Word;
  struct{
    FTM_FSTAT fstat;
    FTM_FERSTAT ferstat;
  } Regs;
} FTM_STATUS;

#define FTM_STATUS_WORD(status)             ((status).Word)
#define FTM_STATUS_FSTAT_BYTE(status)       ((status).Regs.fstat.Byte)
#define FTM_STATUS_FERSTAT_BYTE(status)     ((status).Regs.ferstat.Byte)

typedef struct {
  // values if prior to partitioning.
  // dfPart = 0xffff, erPart = 0xffff, ECOUNT = 0xffff, deadCnt = 0x00, rdyCnt = 0x00
  unsigned short dfPart;  // the number of D-flash Sector for genernal use. 0 - 128.
  unsigned short erPart;  // the number of EEE RAM sections for the FTM (Flash module) to use as EEE. 0 - 16.
  unsigned short ersCnt;  // sector erase count. 
  unsigned char deadCnt;  // dead sector count.
  unsigned char  rdyCnt;  // ready sector count.
} FTM_EEE_STATUS,*pFTM_EEE_STATUS;

typedef struct {
  unsigned short word0;
  unsigned short word1;
  unsigned short word2;
  unsigned short word3;
} INT64U,FTM_KEYGEN;
/*
*********************************************************************************************************
*                               FLASH COMMON COMMAND    FLASH通用命令
*********************************************************************************************************
*/
/**** P-Flash and D-Flash Commands ****/

#define ERASE_VERIFY_ALL_BLOCKS  0x01 
// Verify that all program and data Flash blocks are erased.
// CCOBIX end = 0
// CCOB Params - NONE
// MGSTAT set if fault

#define ERASE_VERIFY_BLOCK       0x02
// Verify that a Flash block is erased.
// CCOBIX end = 0
// CCOB Params - gpage
// MGSTAT set if fault

#define ERASE_ALL_BLOCKS         0x08
// Erase all program and data Flash blocks.
// An erase of all Flash blocks is only possible when the FPLDIS, FPHDIS, and FPOPEN
// bits in the FPROT register and the EPDIS and EPOPEN bits in the EPROM register are
// set prior to launching the command.
// CCOBIX end = 0
// CCOB Params - NONE
// MGSTAT set if fault, FPVIOL / ACCERR set where appropriate

#define UNSECURE_FLASH           0x0B 
// Supports a method of releasing MCU security by erasing all program and data Flash
// blocks and verifying that all program and data Flash blocks are erased.
// CCOBIX end = 0
// CCOB Params - NONE
// MGSTAT set if fault

#define SET_USER_MARGIN_LEVEL    0x0D 
// Specifies a user margin read level for all program Flash blocks.
// CCOBIX end = 1
// CCOB Params - gpage, level setting (0-2) in CCOB[1]
// ACCERR set if invalid level

#define SET_FIELD_MARGIN_LEVEL   0x0E 
// Specifies a field margin read level for all program Flash blocks (special modes only).
// CCOBIX end = 1
// CCOB Params - gpage, level setting (0-4) in CCOB[1]
// ACCERR set if invalid level

/* **** P-Flash Only Commands ****/

#define ERASE_VERIFY_P_FLASH_SECTION 0x03  
// Verify that a given number of words starting at the address provided are erased.
// CCOBIX end = 2
// CCOB Params - global address, number of phrases in CCOB[2]
// MGSTAT set if fault

#define READ_ONCE                  0x04  
// Read a phrase from a dedicated 64 word area in a hidden region of a programFlash block
// that was previously programmed using the Program Once command.
// CCOBIX end = 1
// CCOB Params - read once index (0-3) in CCOB[1], phrase in CCOB [5:2]
// returns phrase in CCOB [4:1]

#define LOAD_DATA_FIELD          0x05 
// Load data for simultaneous multiple program Flash block operations.
// CCOBIX end = 5
// CCOB Params - global address, phrase in CCOB [5:2]

#define PROGRAM_P_FLASH          0x06 
// Program a phrase in a program Flash block and any previously loaded phrases for any
// other program Flash block (see Load Data Field command).
// CCOBIX end = 5
// CCOB Params - global address, phrase in CCOB [5:2]
// MGSTAT set if fault, FPVIOL / ACCERR set where appropriate

#define PROGRAM_ONCE             0x07 
// Program a dedicated 64 word area in a hidden region of a program Flash block that is
// allowed to be programmed only once.
// CCOBIX end = 5
// CCOB Params - read once index (0-3) in CCOB[1], phrase in CCOB [5:2]
// MGSTAT set if fault

#define ERASE_P_FLASH_BLOCK      0x09 
// Erase a program Flash block.
// An erase of the full program Flash block is only possible when FPLDIS, FPHDIS and
// FPOPEN bits in the FPROT register are set prior to launching the command.
// CCOBIX end = 1
// CCOB Params - global address
// MGSTAT set if fault, FPVIOL / ACCERR set where appropriate

#define ERASE_P_FLASH_SECTOR 0x0A 
// Erase all bytes in a program Flash sector.
// CCOBIX end = 1
// CCOB Params - global address
// MGSTAT set if fault, FPVIOL / ACCERR set where appropriate

#define VERIFY_BACKDOOR_ACCESS_KEY 0x0C 
// Supports a method of releasing MCU security by verifying a set of security keys.
// CCOBIX end = 4
// CCOB Params - backdoor key in CCOB [1:4]
// ACCERR set if not verified

/**** D-Flash Only Commands ****/

#define ENABLE_D_FLASH 0x0F 
// Partition a section of D-Flash for user access and EEE.
// CCOBIX end = 2
// CCOB Params - number of sectors for D-Flash in CCOB[1],  number of sectors for EEE in CCOB[2]
// ACCERR set if fault

#define FULL_PARTITION_D_FLASH 0x0F 
// Partition a section of D-Flash for user access and EEE.
// CCOBIX end = 2
// CCOB Params - number of sectors for D-Flash in CCOB[1],  number of sectors for EEE in CCOB[2]
// ACCERR set if fault

#define ERASE_VERIFY_D_FLASH_SECTION 0x10 
// Verify that a given number of words starting at the address provided are erased.
// CCOBIX end = 2
// CCOB Params - global address of first word, number of words to verify CCOB[2]
// MGSTAT set if fault

#define PROGRAM_D_FLASH         0x11 
// Program up to four words in the data Flash block (see Load Data Field command).
// CCOBIX end = 2
// CCOB Params - global address, up to 4 data words in CCOB [2:5]
// MGSTAT set if fault, EPVIOL / ACCERR set where appropriate

#define ERASE_D_FLASH_SECTOR    0x12 
// Erase all bytes in a data Flash sector.
// CCOBIX end = 2
// CCOB Params - global address
// MGSTAT set if fault, EPVIOL  set where appropriate

#define ENABLE_EEPROM_EMULATION    0x13 
// Requests the FTMSM to enable EEPROM emulation.
// CCOBIX end = 0
// CCOB Params - NONE

#define DISABLE_EEPROM_EMULATION   0x14 
// Requests the FTMSM to suspend all current erase and program activity related to
// EEPROM emulation but leave current EEE tags set.
// CCOBIX end = 0
// CCOB Params - NONE

//#define CANCEL_EEPROM_EMULATION    0x15   /* M22E mask only */
// Requests the FTMSM to suspend all current erase and program activity related to
// EEPROM emulation and clear all outstanding EEE tags.
// CCOBIX end = 0
// CCOB Params - NONE

#define EEPROM_QUERY    0x15
// Requests EEE status information.
// CCOBIX end = 0
// CCOB Return Params -
// CCOB[1] DFPART - size of D-Flash user partition (x256 bytes)
// CCOB[2] ERPART - size of EEE ram (x256 bytes)
// CCOB[3] ECOUNT - typical number of erase cycles for the EEE sectors
// CCOB[4] Dead sector count / Ready sector count

#define PARTITION_D_FLASH 0x20
// Partition a section of D-Flash for user access and EEE.
// CCOBIX end = 2
// CCOB Params - number of sectors for D-Flash in CCOB[1],  number of sectors for EEE in CCOB[2]
// ACCERR set if fault


/*
*********************************************************************************************************
*                                       CONFIGURATION  配置
*********************************************************************************************************
*/

//Define the FCLK_DIV value according to the oscillator crystal.
//This table is extracted from the MC9S12XE100 datasheet.
//  | OSCCLK Frequency(MHz) |    FDIV    |
//  |    min    |    max    |            |
//  |    1.60   |    2.10   |    0x01    |
//  |    2.40   |    3.15   |    0x02    |
//  |    3.20   |    4.20   |    0x03    |
//  |    4.20   |    5.25   |    0x04    |
//  |    5.25   |    6.30   |    0x05    |
//  |    6.30   |    7.35   |    0x06    |
//  |    7.35   |    8.40   |    0x07    |
//  |    8.40   |    9.45   |    0x08    |
//  |    9.45   |   10.50   |    0x09    |
//  |   10.50   |   11.55   |    0x0A    |
//  |   11.55   |   12.60   |    0x0B    |
//  |   12.60   |   13.65   |    0x0C    |
//  |   13.65   |   14.70   |    0x0D    |
//  |   14.70   |   15.75   |    0x0E    |
//  |   15.75   |   16.80   |    0x0F    |
//  |   16.80   |   17.85   |    0x10    |
//  |   17.85   |   18.90   |    0x11    |
//  |   18.90   |   19.95   |    0x12    |
//  |   19.95   |   21.00   |    0x13    |
//  |   21.00   |   22.05   |    0x14    |
//  |   22.05   |   23.10   |    0x15    |
//  |   23.10   |   24.15   |    0x16    |
//  |   24.15   |   25.20   |    0x17    |
//  |   25.20   |   26.25   |    0x18    |
//  |   26.25   |   27.30   |    0x19    |
//  |   27.30   |   28.35   |    0x1A    |
//  |   28.35   |   29.40   |    0x1B    |
//  |   29.40   |   30.45   |    0x1C    |
//  |   30.45   |   31.50   |    0x1D    |
//  |   31.50   |   32.55   |    0x1E    |
//  |   32.55   |   33.60   |    0x1F    |
//  |   33.60   |   34.65   |    0x20    |
//  |   34.65   |   35.70   |    0x21    |
//  |   35.70   |   36.75   |    0x22    |
//  |   36.75   |   37.80   |    0x23    |
//  |   37.80   |   38.85   |    0x24    |
//  |   38.85   |   39.90   |    0x25    |
//  |   39.90   |   40.95   |    0x26    |
//  |   40.95   |   42.00   |    0x27    |
//  |   42.00   |   43.05   |    0x28    |
//  |   43.05   |   44.10   |    0x29    |
//  |   44.10   |   45.15   |    0x2A    |
//  |   45.15   |   46.20   |    0x2B    |
//  |   46.20   |   47.25   |    0x2C    |
//  |   47.25   |   48.30   |    0x2D    |
//  |   48.30   |   49.35   |    0x2E    |
//  |   49.35   |   50.40   |    0x2F    |

#define FCLK_DIV 0x0F

//EEE SIZE SECTION
#define EEE_RAM 16 //Specify the # of EEE RAM sections for the FTM (Flash
                  //module) to use as EEE. The valid range is 0-16 sections.

/**** CALCULATES AMOUNT OF DATA FLASH FOR GENERAL USE ****/
#if(EEE_RAM == 1)
   #define DFPART (128 - 12)
#else
   #define DFPART (128 - (8 * EEE_RAM))
#endif

//uncomment below if you are not debugging!!!!!!!!!!!!!!!!!
#define NDEBUG

/*
*********************************************************************************************************
*                                       CONSTANT  常量
*********************************************************************************************************
*/

#define  FLASH_SECTOR_SIZE   0x400

// error code 
#define FTM_ERR_NONE              0x00
#define FTM_ERR_UNKNOWN           0x01  // 未知错误
#define FTM_ERR_ACCERR            0x02  // ACCERR错误,不同命令的可能情况不一样
#define FTM_ERR_READERR           0x03  // 读取内存(FTM256K2)中遇到错误
#define FTM_ERR_READERR_FATAL     0x04  // 读取内存中遇到不可修正的错误
#define FTM_ERR_PROTECTED_PFLASH  0x05  // 如果尝试擦/写PFlash受保护的区域
#define FTM_ERR_WRITEERR          0x06  // 写内存(FTM256K2)时发生错误
#define FTM_ERR_WRITEERR_FATAL    0x07  // 写内存(FTM256K2)时发生不可修正的错误
#define FTM_ERR_PROTECTED_EEE     0x08  // 如果尝试擦/写EEE受保护的区域
#define FTM_ERR_EREASEERR         0x09  // 擦除内存(FTM256K2)时发生错误
#define FTM_ERR_EREASEERR_FATAL   0x0A  // 擦除内存(FTM256K2)时发生不可修正的错误

// margin level
#define FTM_MARGINLEVEL_NORMAL    0x00
#define FTM_MARGINLEVEL_USER1     0x01  // Read margin to the erased state
#define FTM_MARGINLEVEL_USER0     0x02  // Read margin to the programmed state
#define FTM_MARGINLEVEL_FIELD1    0x03  // Read margin to the erased state
#define FTM_MARGINLEVEL_FIELD0    0x04  // Read margin to the programmed state

/*
*********************************************************************************************************
*                                  FUNCTION DECLARATION  函数声明
*********************************************************************************************************
*/

void FTM_Init(void);             // remember this!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

#define FTM_LaunchCommand_p0(ccobhigh,ccoblow) \
            FTM_LaunchCommand(0,ccobhigh,ccoblow)
#define FTM_LaunchCommand_p1(ccobhigh,ccoblow,param1) \
            FTM_LaunchCommand(1,ccobhigh,ccoblow,(unsigned short)(param1))
#define FTM_LaunchCommand_p2(ccobhigh,ccoblow,param1,param2) \
            FTM_LaunchCommand(2,ccobhigh,ccoblow,(unsigned short)(param1),(unsigned short)(param2))
#define FTM_LaunchCommand_p3(ccobhigh,ccoblow,param1,param2,param3) \
            FTM_LaunchCommand(3,ccobhigh,ccoblow,(unsigned short)(param1),(unsigned short)(param2),\
            (unsigned short)(param3))
#define FTM_LaunchCommand_p4(ccobhigh,ccoblow,param1,param2,param3,param4) \
            FTM_LaunchCommand(4,ccobhigh,ccoblow,(unsigned short)(param1),(unsigned short)(param2),\
            (unsigned short)(param3),(unsigned short)(param4))
#define FTM_LaunchCommand_p5(ccobhigh,ccoblow,param1,param2,param3,param4,param5) \
            FTM_LaunchCommand(5,ccobhigh,ccoblow,(unsigned short)(param1),(unsigned short)(param2),\
            (unsigned short)(param3),(unsigned short)(param4),(unsigned short)(param5))
#define FTM_LaunchCommand_p6(ccobhigh,ccoblow,param1,param2,param3,param4,param5,param6) \
            FTM_LaunchCommand(6,ccobhigh,ccoblow,(unsigned short)(param1),(unsigned short)(param2),\
            (unsigned short)(param3),(unsigned short)(param4),(unsigned short)(param5),\
            (unsigned short)(param6))
#define FTM_LaunchCommand_p7(ccobhigh,ccoblow,param1,param2,param3,param4,param5,param6,param7) \
            FTM_LaunchCommand(7,ccobhigh,ccoblow,(unsigned short)(param1),(unsigned short)(param2),\
            (unsigned short)(param3),(unsigned short)(param4),(unsigned short)(param5),\
            (unsigned short)(param6),(unsigned short)(param7))

#pragma push
#pragma CODE_SEG RAM_CODE
FTM_STATUS FTM_LaunchCommand(unsigned char paramCnt, unsigned char ccob0high, unsigned char ccob0low ,...);
#pragma pop

void ErrorCheck(FTM_STATUS status, unsigned char statbits, unsigned char ferstatbits);

unsigned char FTM_anyErrHappened(FTM_STATUS status); 

/****************************************************************************/ 
/****          以下函数返回的是FTM_STATUS结构体(即两个寄存器的值)       *****/ 
/****************************************************************************/ 

/********************************  BOTH  ************************************/ 
#define _FTM_EraseVerifyAllBlocks()    FTM_LaunchCommand_p0(ERASE_VERIFY_ALL_BLOCKS, 0)
#define _FTM_EraseVerifyBlock(gPage)   FTM_LaunchCommand_p0(ERASE_VERIFY_BLOCK, gPage)
#define _FTM_EraseAllBlocks()          FTM_LaunchCommand_p0(ERASE_ALL_BLOCKS, 0)
#define _FTM_Unsecure()                FTM_LaunchCommand_p0(UNSECURE_FLASH, 0) 
#define _FTM_VerifyBackdoorAccessKey(key0,key1,key2,key3) \
               FTM_LaunchCommand_p4(VERIFY_BACKDOOR_ACCESS_KEY, 0,key0,key1,key2,key3)
#define _FTM_SetUserMarginLevel(gPage,MarginLevel) \
               FTM_LaunchCommand_p1(SET_USER_MARGIN_LEVEL, gPage,MarginLevel)
#define _FTM_SetFieldMarginLevel(gPage,MarginLevel) \
               FTM_LaunchCommand_p1(SET_FIELD_MARGIN_LEVEL, gPage,MarginLevel)

/******************************** PFlash ************************************/ 
#define _FTM_PFlash_Program(gPage,gAddrLow,w0,w1,w2,w3) \
    FTM_LaunchCommand_p5(PROGRAM_P_FLASH,gPage,gAddrLow,w0,w1,w2,w3)
#define _FTM_PFlash_ProgramOnce(phraseIndex,w0,w1,w2,w3)  \
    FTM_LaunchCommand_p5(PROGRAM_ONCE,0,phraseIndex,w0,w1,w2,w3)

#define _FTM_EraseVerifyPFlashSection(gPage,gAddrLow,NumOfPhrase) \
               FTM_LaunchCommand_p2(ERASE_VERIFY_P_FLASH_SECTION, gPage, gAddrLow, NumOfPhrase)

// 如果使用擦除扇区函数的话,整个函数调用过程中PC都必须在RAM中,否则会异常退出。
// 也就是说,如果使用了中断的话,整个中断函数,包括调用到的子函数都必须在RAM_CODE中。
#define _FTM_PFlash_EraseSector(gPage,gAddrLow) \
    FTM_LaunchCommand_p1(ERASE_P_FLASH_SECTOR,gPage,gAddrLow)
#define _FTM_PFlash_EraseBlock(gPage,gAddrLow) \
    FTM_LaunchCommand_p1(ERASE_P_FLASH_BLOCK,gPage,gAddrLow)

/******************************** DFlash/EEPROM ************************************/ 

// EEPROM full partition command, only valid in Debug mode.
// Call this function before the first time you use EEPROM or when reallocate EEPROM in developing.
#define _FTM_EEPROM_FullPartition()    FTM_LaunchCommand_p2(FULL_PARTITION_D_FLASH, 0, DFPART, EEE_RAM)

#define _FTM_EEPROM_Partition()        FTM_LaunchCommand_p2(PARTITION_D_FLASH, 0, DFPART, EEE_RAM)

// Enable the EEPROM. If you use EEPROM, you should enable EEPROM after each reset.
#define _FTM_EEPROM_Enable()           FTM_LaunchCommand_p0(ENABLE_EEPROM_EMULATION, 0)

#define _FTM_EEPROM_Disable()          FTM_LaunchCommand_p0(DISABLE_EEPROM_EMULATION, 0)
#define _FTM_DFlash_EraseVerifySection(gPage,gAddrLow,wordsCnt)   \
                          FTM_LaunchCommand_p2(ERASE_VERIFY_D_FLASH_SECTION, gPage, gAddrLow, wordsCnt)

#define _FTM_DFlash_ProgramOneWord(gPage,gAddrLow,w0)   \
                          FTM_LaunchCommand_p2(PROGRAM_D_FLASH, gPage, gAddrLow, w0)
#define _FTM_DFlash_ProgramTwoWords(gPage,gAddrLow,w0,w1)   \
                          FTM_LaunchCommand_p3(PROGRAM_D_FLASH, gPage, gAddrLow, w0, w1)
#define _FTM_DFlash_ProgramThreeWords(gPage,gAddrLow,w0,w1,w2)   \
                          FTM_LaunchCommand_p4(PROGRAM_D_FLASH, gPage, gAddrLow, w0, w1, w2)
#define _FTM_DFlash_ProgramFourWords(gPage,gAddrLow,w0,w1,w2,w3)   \
                          FTM_LaunchCommand_p5(PROGRAM_D_FLASH, gPage, gAddrLow, w0, w1, w2, w3)
#define _FTM_DFlash_EraseSector(gPage,gAddrLow) \
                          FTM_LaunchCommand_p1(ERASE_D_FLASH_SECTOR,gPage,gAddrLow)

/****************************************************************************/
/****        more user-friendly interface    更加用户友好的接口         *****/
/****************************************************************************/

/********************************  BOTH  ************************************/

// 验证所有P-Flash和D-Flash块都被擦除了
unsigned char FTM_EraseVerifyAllBlocks(void);
// 验证指定GPAGE页的P-Flash或D-Flash块被擦除了
unsigned char FTM_EraseVerifyBlock(unsigned char gPage);
// 擦除所有P-Flash和D-Flash内存,包括EEE非易失性信息寄存器
unsigned char FTM_EraseAllBlocks(void);
// 擦除所有P-Flash和D-Flash内存,如果成功则解密
unsigned char FTM_Unsecure(void);
// 如果给的秘钥与Flash配置字段中的匹配,则解密
unsigned char FTM_VerifyBackdoorAccessKey(FTM_KEYGEN *key);
// 设置指定P-Flash或D-Flash块的margin level
unsigned char FTM_SetUserMarginLevel(unsigned char gPage,unsigned char MarginLevel);

/******************************** PFlash ************************************/

// 验证P-Flash中的一个代码块被擦除了
unsigned char FTM_PFlash_EraseVerifySection(unsigned long globalAddr,unsigned char NumOfPhrase);
// 读取位于P-Flash block 0 非易失性信息寄存器的8个phrase(8字节)中的指定的一个
unsigned char FTM_PFlash_ReadOnce(unsigned char phraseIndex,INT64U *rst);
// 写P-Flash中一个擦除状态的phrase
unsigned char FTM_PFlash_Program(unsigned long globalAddr,INT64U *src);
// 写位于P-Flash block 0 非易失性信息寄存器的8个phrase(8字节)中的指定的一个,分别只能写1次,因为无法擦除
unsigned char FTM_PFlash_ProgramOnce(unsigned char phraseIndex,INT64U *src);
// 擦除给定地址所处的P-Flash block
unsigned char FTM_PFlash_EraseBlock(unsigned long globalAddr);
// 擦除给定地址所处的P-Flash sector
unsigned char FTM_PFlash_EraseSector(unsigned long globalAddr);

/******************************** DFlash/EEPROM ************************************/

// 对EEE进行全分区
unsigned char FTM_EEPROM_FullPartition(void);
// 对EEE进行分区
unsigned char FTM_EEPROM_Partition(void);
// 使能EEE,重置后默认是禁用状态
unsigned char FTM_EEPROM_Enable(void);
// 禁用EEE
unsigned char FTM_EEPROM_Disable(void);
// 查询EEE状态
unsigned char FTM_EEPROM_Query(pFTM_EEE_STATUS rst);
// 验证D-Flash的用户分区中的一个代码块是擦除状态
unsigned char FTM_DFlash_EraseVerifySection(unsigned long globalAddrStart,unsigned short wordsCnt);
// 编程D-Flash指定地址起的n个word
unsigned char FTM_DFlash_ProgramOneWord(unsigned long globalAddr,unsigned short w0);
unsigned char FTM_DFlash_ProgramTwoWords(unsigned long globalAddr,unsigned short w0,unsigned short w1);
unsigned char FTM_DFlash_ProgramThreeWords(unsigned long globalAddr,unsigned short w0,unsigned short w1,
                                       unsigned short w2);
unsigned char FTM_DFlash_ProgramFourWords(unsigned long globalAddr,unsigned short w0,unsigned short w1,
                                       unsigned short w2,unsigned short w3);
// 擦除指定地址所处的D-Flash用户分区
unsigned char FTM_DFlash_EraseSector(unsigned long globalAddr);


#endif

然后是FTM.c文件

/*
*********************************************************************************************************
*
*
*                              Flash Technology Module SUPPORT PACKAGE
*                                      Freescale MC9S12XEP100
*                              飞思卡尔单片机 FLASH模块(FTM) 支持包
*
* File    : FTM.c
* By      : Lin Shijun(http://blog.csdn.net/lin_strong)
* Date    : 2018/04/12
* Version : V2.0
* Note    : 
*
*********************************************************************************************************
*/

/*
*********************************************************************************************************
*                                            INCLUDE
*********************************************************************************************************
*/

#include "FTM.h"
#include <MC9S12XEP100.h>
#include <assert.h>
#include <stdarg.h>

/*
*********************************************************************************************************
*                                         LOCAL FUNCTION DECLARATION
*********************************************************************************************************
*/
//Wait a while for CCIF to be set
#define _FTM_waitUntilReady()               while((FSTAT & FSTAT_CCIF_MASK) == 0);  
#define _FTM_EEPROM_Query()                 FTM_LaunchCommand_p0(EEPROM_QUERY, 0)
#define _FTM_anyErrHappened(status)         ((FTM_STATUS_FSTAT_BYTE(status) & FTM_FSTAT_MASK_ANYERR) \
                                          || (FTM_STATUS_FERSTAT_BYTE(status) & FTM_FERSTAT_MASK_ANYERR))
#define _FTM_PFlash_ReadOnce(phraseIndex)   FTM_LaunchCommand_p1(READ_ONCE,0,phraseIndex)
static unsigned char _getErrorCode(FTM_STATUS statusWord,unsigned char accerrCode,unsigned char fpviolCode,
                                   unsigned char mgstat1Code,unsigned char mgstat0Code,unsigned char epviolifCode);

/*
*********************************************************************************************************
*                                       FTM_Init()
*
* Description : This function is used to initialize the FTM module.you should call this function before 
*                 using anyother function in FTM module.
*
* Return      : 
* Notes       : 
*********************************************************************************************************
*/

void FTM_Init(void){
  _FTM_waitUntilReady();               //Wait for FTM to be ready
  FCLKDIV = FCLK_DIV;                 //write FCLKDIV before using the FTM.
  //if(FCLKDIV != (FCLK_DIV | 0x80))    //Check to make sure value is written.
  //  while(1);
}

/*
*********************************************************************************************************
*                                       FTM_LaunchCommand()
*
* Description : This function is used to launch FTM command.
* Arguments   : paramCnt(<= 7) the count of parameters used in this command, pass the parameters one by one
*                              after the ccob0low.
*               ccob0high      undicates the high byte command portion of the ccob0 word.
*               ccob0low       Forms the low byte of the ccob0 word parameter, if needed.
*               ...            the params in order.
* Return      : Flash module status registers
* Notes       : 1. the type of params is unsigned short(16 bits) !!!
*               2. the number of addtional params should be exactly same to the paramCnt.
*               3. this function will clears any error flags and uses parameters to initiate an FTM command.
*               4. this function does not check if the Flash is erased, and does not explicitely verify that
*                  data has been sucessfully programmed.
*               5. if you are programming PFLASH, this function should run in RAM
*********************************************************************************************************
*/
#pragma push
#pragma CODE_SEG RAM_CODE
FTM_STATUS FTM_LaunchCommand(unsigned char paramCnt, unsigned char ccob0high, unsigned char ccob0low ,...){
  va_list ap;
  FTM_STATUS status;                //Used to copy and store Flash status registers.

  assert(paramCnt <= 7);

  va_start(ap,ccob0low);
  _FTM_waitUntilReady();
  FSTAT = 0x30;                   //Use store instruction to clear ACCERR, FPVIOL.
  /**********SET UP THE FTM COMMAND AND PARAMETERS***********/
  FCCOBIX = 0;                    //Set CCOB index to 0 to begin command setup.
  FCCOBHI = ccob0high;            //Write ccob0 high-byte command value.
  FCCOBLO = ccob0low;             //Write ccob0 low-byte parameter, if used.
  //write parameters one by one to CCOB buffer.
  while(paramCnt >= 1){
    FCCOBIX++;
    FCCOB = va_arg(ap,unsigned short);
    paramCnt--;
  }
  va_end(ap);

  FSTAT = 0x80;                   //Clear buffer-empty-flag to start FTM command.
  _FTM_waitUntilReady();           //Now wait for the FTM command to complete.
  //Copy FSTAT and FERSTAT register state for later comparison.
  FTM_STATUS_FSTAT_BYTE(status) = FSTAT;
  FTM_STATUS_FERSTAT_BYTE(status) = FERSTAT;
  return(status);                 //After FTM command completed, return status.
}
#pragma pop

/*
*********************************************************************************************************
*                                       FTM_anyErrHappened()
*
* Description : To quickly check whether there is an error.
* Arguments   : status    value returned by most functions in this module.
*
* Return      : TRUE       if any error happened.
*               FALSE      if every thing goes well.
* Notes       : 
*********************************************************************************************************
*/
unsigned char FTM_anyErrHappened(FTM_STATUS status){
  return _FTM_anyErrHappened(status);
}

//Compare the copied FSTAT and FERSTAT register results against the selected
//error bits. A match indicates an error and loops forever.
void ErrorCheck(FTM_STATUS status, unsigned char statbits, unsigned char ferstatbits){
  if((FTM_STATUS_FSTAT_BYTE(status) & statbits) || (FTM_STATUS_FERSTAT_BYTE(status) & ferstatbits))
  {
    asm BGND;
  }
}
/*
*********************************************************************************************************
*                                       FTM_EraseVerifyAllBlocks()
* 
* Description : To verify that all P-Flash and D-Flash blocks have been erased.
* 
* Arguments   : 
*
* Return      : FTM_ERR_NONE           if no err.
*               FTM_ERR_UNKNOWN        if known error encountered.
*               FTM_ERR_ACCERR         error most likely caused by uninitialized FCLKDIV.
*               FTM_ERR_READERR        if any errors have been encountered during the read
*               FTM_ERR_READERR_FATAL  if any non-correctable errors have been encountered during the read
*
* Notes       : if return FTM_ERR_READERR, verify fail.
*********************************************************************************************************
*/

unsigned char FTM_EraseVerifyAllBlocks(void){
  FTM_STATUS status;
  status = _FTM_EraseVerifyAllBlocks();
  return _getErrorCode(status,FTM_ERR_ACCERR,FTM_ERR_UNKNOWN,FTM_ERR_READERR,FTM_ERR_READERR_FATAL,FTM_ERR_UNKNOWN);
}
/*
*********************************************************************************************************
*                                       FTM_EraseVerifyAllBlocks()
*
* Description : To verify that an entire P-Flash or D-Flash block has been erased.
*               The FCCOB upper global address bits determine which block must be verified.
*
* Arguments   : gPage                  Global address [22:16] of the Flash block(GPAGE) to be verified
*
* Return      : FTM_ERR_NONE           if no err.
*               FTM_ERR_UNKNOWN        if known error encountered.
*               FTM_ERR_ACCERR         if uninitialized FCLKDIV or an invalid global address [22:16]
*                                         is supplied.
*               FTM_ERR_READERR        if any errors have been encountered during the read
*               FTM_ERR_READERR_FATAL  if any non-correctable errors have been encountered during the read
*
* Notes       : if return FTM_ERR_READERR, verify fail.
*********************************************************************************************************
*/

unsigned char FTM_EraseVerifyBlock(unsigned char gPage){
  FTM_STATUS status;
  status = _FTM_EraseVerifyBlock(gPage);
  return _getErrorCode(status,FTM_ERR_ACCERR,FTM_ERR_UNKNOWN,FTM_ERR_READERR,FTM_ERR_READERR_FATAL,FTM_ERR_UNKNOWN);
}

/*
*********************************************************************************************************
*                                    FTM_PFlash_EraseVerifySection()
*
* Description : To verify that a section of code in the P-Flash memory is erased. The Erase Verify
*                 P-Flash Section command defines the starting point of the code to be verified and
*                 the number of phrases( <= 128).
*
* Arguments   : globalAddr             Global address [22:0] of the first phrase of a P-Flash block to be verified.
*               NumOfPhrase            Number of phrases to be verified
*
* Return      : FTM_ERR_NONE           if no err.
*               FTM_ERR_UNKNOWN        if known error encountered.
*               FTM_ERR_ACCERR         if uninitialized FCLKDIV 
*                                        or if command not available in current mode
*                                        or if an invalid global address [22:0] is supplied
*                                        or if a misaligned phrase address is supplied(global address [2:0] != 000)
*                                        of if the requested section crosses a 128 Kbyte boundary
*               FTM_ERR_READERR        if any errors have been encountered during the read
*               FTM_ERR_READERR_FATAL  if any non-correctable errors have been encountered during the read
*
* Notes       : if return FTM_ERR_READERR, verify fail.
*********************************************************************************************************
*/

unsigned char FTM_PFlash_EraseVerifySection(unsigned long globalAddr,unsigned char NumOfPhrase){
  FTM_STATUS status;
  status = _FTM_EraseVerifyPFlashSection(((unsigned char)(globalAddr >> 16) & 0x7F),
                                  ((unsigned short)globalAddr),NumOfPhrase);
  return _getErrorCode(status,FTM_ERR_ACCERR,FTM_ERR_UNKNOWN,FTM_ERR_READERR,FTM_ERR_READERR_FATAL,FTM_ERR_UNKNOWN);
}

/*
*********************************************************************************************************
*                                    FTM_PFlash_ReadOnce()
*
* Description : To provides read access to a reserved 64 byte field (8 phrases) located in the nonvolatile
*                 information register of P-Flash block 0. The Read Once field is programmed using the 
*                 Program Once command.
*
* Arguments   : phraseIndex            Read Once phrase index (0x0000 - 0x0007)
*               rst                    result of Read Once, if no error.
*
* Return      : FTM_ERR_NONE           if no err.
*               FTM_ERR_UNKNOWN        if known error encountered.
*               FTM_ERR_ACCERR         if uninitialized FCLKDIV 
*                                        or if command not available in current mode
*                                        orif an invalid phrase index is supplied
*               FTM_ERR_READERR        if any errors have been encountered during the read
*               FTM_ERR_READERR_FATAL  if any non-correctable errors have been encountered during the read
*
* Notes       : result is returned by argument rst.
*********************************************************************************************************
*/

unsigned char FTM_PFlash_ReadOnce(unsigned char phraseIndex,INT64U *rst){
  unsigned char errCode;
  FTM_STATUS status;
  status = _FTM_PFlash_ReadOnce(phraseIndex);
  errCode = _getErrorCode(status,FTM_ERR_ACCERR,FTM_ERR_UNKNOWN,FTM_ERR_READERR,FTM_ERR_READERR_FATAL,FTM_ERR_UNKNOWN);
  if(errCode != FTM_ERR_NONE)
    return errCode;
  FCCOBIX = 2;
  rst->word0 = FCCOB;
  FCCOBIX++;
  rst->word1 = FCCOB;
  FCCOBIX++;
  rst->word2 = FCCOB;
  FCCOBIX++;
  rst->word3 = FCCOB;
  return FTM_ERR_NONE;
}

/*
*********************************************************************************************************
*                                    FTM_PFlash_Program()
*
* Description : To program a previously erased phrase in the P-Flash memory using an embedded algorithm.
*
* Arguments   : globalAddr             Global address [22:0] of phrase location of P-Flash block to 
*                                        be programmed.
*               src                    4 words to be programmed.
*
* Return      : FTM_ERR_NONE           if no err.
*               FTM_ERR_UNKNOWN        if known error encountered.
*               FTM_ERR_ACCERR         if uninitialized FCLKDIV 
*                                        or if command not available in current mode
*                                        or if an invalid global address [22:0] is supplied
*                                        of if a misaligned phrase address is supplied (global address [2:0] != 000)
*               FTM_ERR_PROTECTED_PFLASH      if the global address [22:0] points to a protected area
*               FTM_ERR_WRITEERR       if any errors have been encountered during the verify operation
*               FTM_ERR_WRITEERR_FATAL if any non-correctable errors have been encountered during the 
*                                         verify operation
*
* Notes       : A P-Flash phrase must be in the erased state before being programmed.
*               Cumulative programming of bits within a Flash phrase is not allowed.
*********************************************************************************************************
*/

unsigned char FTM_PFlash_Program(unsigned long globalAddr,INT64U *src){
  FTM_STATUS status;
  status = _FTM_PFlash_Program(((unsigned char)(globalAddr >> 16) & 0x7F),
                                  ((unsigned short)globalAddr),src->word0,src->word1,src->word2,src->word3);
  return _getErrorCode(status,FTM_ERR_ACCERR,FTM_ERR_PROTECTED_PFLASH,FTM_ERR_WRITEERR,FTM_ERR_WRITEERR_FATAL,FTM_ERR_UNKNOWN);
}

/*
*********************************************************************************************************
*                                    FTM_PFlash_ProgramOnce()
*
* Description : The Program Once command restricts programming to a reserved 64 byte field (8 phrases)
*                in the nonvolatile information register located in P-Flash block 0. The Program Once
*                reserved field can be read using the Read Once command.The Program Once command must
*                only be issued once since the nonvolatile information register in P-Flash block 0 cannot
*                be erased.
*
* Arguments   : phraseIndex            Program Once phrase index (0x0000 - 0x0007)
*               src                    4 words to be programmed.
*
* Return      : FTM_ERR_NONE              if no err.
*               FTM_ERR_UNKNOWN           if known error encountered.
*               FTM_ERR_ACCERR            if uninitialized FCLKDIV 
*                                           or if command not available in current mode
*                                           or if an invalid phrase index is supplied
*                                           of if the requested phrase has already been programmed
*               FTM_ERR_PROTECTED_PFLASH  if any area of the P-Flash memory is protected
*               FTM_ERR_WRITEERR          if any errors have been encountered during the verify operation
*               FTM_ERR_WRITEERR_FATAL    if any non-correctable errors have been encountered during the
*                                         verify operation
* 
* Notes       : The reserved nonvolatile information register accessed by the Program Once command cannot
*                be erased and any attempt to program one of these phrases a second time will not be allowed.
*                Valid phrase index values for the Program Once command range from 0x0000 to 0x0007. During
*                execution of the Program Once command, any attempt to read addresses within P-Flash block 0
*                will return invalid data.
*********************************************************************************************************
*/
unsigned char FTM_PFlash_ProgramOnce(unsigned char phraseIndex,INT64U *src){
  FTM_STATUS status;
  status = _FTM_PFlash_ProgramOnce(phraseIndex,src->word0,src->word1,src->word2,src->word3);
  return _getErrorCode(status,FTM_ERR_ACCERR,FTM_ERR_UNKNOWN,FTM_ERR_WRITEERR,FTM_ERR_WRITEERR_FATAL,FTM_ERR_UNKNOWN);
}

/*
*********************************************************************************************************
*                                       FTM_EraseAllBlocks()
*
* Description : To erase the entire P-Flash and D-Flash memory space including the EEE nonvolatile
*               information register.
*
* Arguments   : 
*
* Return      : FTM_ERR_NONE              if no err.
*               FTM_ERR_UNKNOWN           if known error encountered.
*               FTM_ERR_ACCERR            if uninitialized FCLKDIV 
*                                          or if command not available in current mode
*               FTM_ERR_PROTECTED_PFLASH  if any area of the P-Flash memory is protected
*               FTM_ERR_WRITEERR          if any errors have been encountered during the verify operation
*               FTM_ERR_WRITEERR_FATAL    if any non-correctable errors have been encountered during the
*                                          verify operation
*               FTM_ERR_PROTECTED_EEE  if any area of the buffer RAM EEE partition is protected
*
* Notes       : If the Memory Controller verifies that the entire Flash memory space was properly erased,
*                security will be released.
*********************************************************************************************************
*/
unsigned char FTM_EraseAllBlocks(void){
  FTM_STATUS status;
  status = _FTM_EraseAllBlocks();
  return _getErrorCode(status,FTM_ERR_ACCERR,FTM_ERR_PROTECTED_PFLASH,FTM_ERR_WRITEERR,
               FTM_ERR_WRITEERR_FATAL,FTM_ERR_PROTECTED_EEE);
}
/*
*********************************************************************************************************
*                                       FTM_PFlash_EraseBlock()
*
* Description : To erase all addresses in a P-Flash block.
*
* Arguments   : globalAddr                Global address [22:0] in the P-Flash block to be erased.
*
* Return      : FTM_ERR_NONE              if no err.
*               FTM_ERR_UNKNOWN           if known error encountered.
*               FTM_ERR_ACCERR            if uninitialized FCLKDIV 
*                                          or if command not available in current mode
*                                          or if an invalid global address [22:16] is supplied
*               FTM_ERR_PROTECTED_PFLASH  if an area of the selected P-Flash block is protected
*               FTM_ERR_WRITEERR          if any errors have been encountered during the verify operation
*               FTM_ERR_WRITEERR_FATAL    if any non-correctable errors have been encountered during the
*                                          verify operation
*
* Notes       : 如果使用擦除扇区函数的话,整个函数调用过程中PC都必须在RAM中,否则会异常退出。也就是说,
*               如果使用了中断的话,整个中断函数,包括调用到的子函数都必须在RAM_CODE中。
*********************************************************************************************************
*/
unsigned char FTM_PFlash_EraseBlock(unsigned long globalAddr){
  FTM_STATUS status;
  status = _FTM_PFlash_EraseBlock(((unsigned char)(globalAddr >> 16) & 0x7F),((unsigned short)globalAddr));
  return _getErrorCode(status,FTM_ERR_ACCERR,FTM_ERR_PROTECTED_PFLASH,FTM_ERR_WRITEERR,
               FTM_ERR_WRITEERR_FATAL,FTM_ERR_UNKNOWN);
}
/*
*********************************************************************************************************
*                                       FTM_PFlash_EraseSector()
*
* Description : To erase all addresses in a P-Flash sector.
*
* Arguments   : globalAddr                Global address [22:0] in the P-Flash sector to be erased.
*
* Return      : FTM_ERR_NONE              if no err.
*               FTM_ERR_UNKNOWN           if known error encountered.
*               FTM_ERR_ACCERR            if uninitialized FCLKDIV 
*                                          or if command not available in current mode
*                                          or if an invalid global address [22:16] is supplied
*                                          or if a misaligned phrase address is supplied (global address [2:0] != 000)
*               FTM_ERR_PROTECTED_PFLASH  if the selected P-Flash sector is protected.
*               FTM_ERR_WRITEERR          if any errors have been encountered during the verify operation
*               FTM_ERR_WRITEERR_FATAL    if any non-correctable errors have been encountered during the
*                                          verify operation
*
* Notes       : 如果使用擦除扇区函数的话,整个函数调用过程中PC都必须在RAM中,否则会异常退出。也就是说,
*               如果使用了中断的话,整个中断函数,包括调用到的子函数都必须在RAM_CODE中。
*********************************************************************************************************
*/
unsigned char FTM_PFlash_EraseSector(unsigned long globalAddr){
  FTM_STATUS status;
  status = _FTM_PFlash_EraseSector(((unsigned char)(globalAddr >> 16) & 0x7F),((unsigned short)globalAddr));
  return _getErrorCode(status,FTM_ERR_ACCERR,FTM_ERR_PROTECTED_PFLASH,FTM_ERR_WRITEERR,
               FTM_ERR_WRITEERR_FATAL,FTM_ERR_UNKNOWN);
}
/*
*********************************************************************************************************
*                                       FTM_Unsecure()
*
* Description : The Unsecure Flash command will erase the entire P-Flash and D-Flash memory space and,
*                if the erase is successful, will release security
*
* Arguments   :
*
* Return      : FTM_ERR_NONE              if no err.
*               FTM_ERR_UNKNOWN           if known error encountered.
*               FTM_ERR_ACCERR            if uninitialized FCLKDIV 
*                                          or if command not available in current mode.
*               FTM_ERR_PROTECTED_PFLASH  if any area of the P-Flash memory is protected.
*               FTM_ERR_EREASEERR         if any errors have been encountered during the verify operation
*               FTM_ERR_EREASEERR_FATAL   if any non-correctable errors have been encountered during the
*                                          verify operation
*               FTM_ERR_PROTECTED_EEE     if any area of the buffer RAM EEE partition is protected
*
* Notes       : If the Memory Controller verifies that the entire Flash memory space was properly erased,
*               security will be released. If the erase verify is not successful, the Unsecure Flash 
*               operation sets MGSTAT1(return FTM_ERR_EREASEERR) and terminates without changing the
*               security state.
*********************************************************************************************************
*/
unsigned char FTM_Unsecure(void){
  FTM_STATUS status;
  status = _FTM_Unsecure();
  return _getErrorCode(status,FTM_ERR_ACCERR,FTM_ERR_PROTECTED_PFLASH,FTM_ERR_EREASEERR,
               FTM_ERR_EREASEERR_FATAL,FTM_ERR_PROTECTED_EEE);
}
/*
*********************************************************************************************************
*                                   FTM_VerifyBackdoorAccessKey()
*
* Description : To releases security if user-supplied keys match those stored in the Flash security bytes
*               of the Flash configuration field
*
* Arguments   :
*
* Return      : FTM_ERR_NONE              if no err.
*               FTM_ERR_UNKNOWN           if known error encountered.
*               FTM_ERR_ACCERR            if uninitialized FCLKDIV 
*                                          or if an incorrect backdoor key is supplied
*                                          or if backdoor key access has not been enabled
*                                          or if the backdoor key has mismatched since the last power down
*
* Notes       : The Verify Backdoor Access Key command will only execute if it is enabled by the KEYEN
*               bits in the FSEC register
*********************************************************************************************************
*/
unsigned char FTM_VerifyBackdoorAccessKey(FTM_KEYGEN *key){
  FTM_STATUS status;
  status = _FTM_VerifyBackdoorAccessKey(key->word0,key->word1,key->word2,key->word3);
  return _getErrorCode(status,FTM_ERR_ACCERR,FTM_ERR_UNKNOWN,FTM_ERR_UNKNOWN,
               FTM_ERR_UNKNOWN,FTM_ERR_UNKNOWN);
}
/*
*********************************************************************************************************
*                                   FTM_SetUserMarginLevel()
*
* Description : The Set User Margin Level command causes the Memory Controller to set the margin level 
*               for future read operations of a specific P-Flash or D-Flash block.
*
* Arguments   : gPage              Global address [22:16] to identify the Flash block
*               MarginLevel        Margin level setting,see FTM_MARGINLEVEL_XXXX
*                                    FTM_MARGINLEVEL_NORMAL
*                                    FTM_MARGINLEVEL_USER1
*                                    FTM_MARGINLEVEL_USER0
*
* Return      : FTM_ERR_NONE       if no err.
*               FTM_ERR_UNKNOWN    if known error encountered.
*               FTM_ERR_ACCERR     if uninitialized FCLKDIV 
*                                    or if command not available in current mode
*                                    or if an invalid global address [22:16] is supplied
*                                    or if an invalid margin level setting is supplied
*
* Notes       : User margin levels can be used to check that Flash memory contents have adequate margin
*               for normal level read operations. If unexpected results are encountered when checking
*               Flash memory contents at user margin levels, a potential loss of information has been
*               detected.
*********************************************************************************************************
*/
unsigned char FTM_SetUserMarginLevel(unsigned char gPage,unsigned char MarginLevel){
  FTM_STATUS status;
  status = _FTM_SetUserMarginLevel(gPage,MarginLevel);
  return _getErrorCode(status,FTM_ERR_ACCERR,FTM_ERR_UNKNOWN,FTM_ERR_UNKNOWN,
               FTM_ERR_UNKNOWN,FTM_ERR_UNKNOWN);
}

/*
*********************************************************************************************************
*                                   FTM_SetFieldMarginLevel()
*
* Description : The Set Field Margin Level command, valid in special modes only, causes the Memory
*                Controller to set the margin level specified for future read operations of a specific
*                P-Flash or D-Flash block.
*
* Arguments   : gPage              Global address [22:16] to identify the Flash block
*               MarginLevel        Margin level setting,see FTM_MARGINLEVEL_XXXX
*                                    FTM_MARGINLEVEL_NORMAL
*                                    FTM_MARGINLEVEL_USER1
*                                    FTM_MARGINLEVEL_USER0
*                                    FTM_MARGINLEVEL_FIELD1
*                                    FTM_MARGINLEVEL_FIELD0
*
* Return      : FTM_ERR_NONE       if no err.
*               FTM_ERR_UNKNOWN    if known error encountered.
*               FTM_ERR_ACCERR     if uninitialized FCLKDIV 
*                                    or if command not available in current mode
*                                    or if an invalid global address [22:16] is supplied
*                                    or if an invalid margin level setting is supplied
*
* Notes       : 1. Field margin levels must only be used during verify of the initial factory programming.
*               2. Field margin levels can be used to check that Flash memory contents have adequate 
*                  margin for data retention at the normal level setting. If unexpected results are
*                  encountered when checking Flash memory contents at field margin levels, the Flash
*                  memory contents should be erased and reprogrammed.
*********************************************************************************************************
*/
unsigned char FTM_SetFieldMarginLevel(unsigned char gPage,unsigned char MarginLevel){
  FTM_STATUS status;
  status = _FTM_SetFieldMarginLevel(gPage,MarginLevel);
  return _getErrorCode(status,FTM_ERR_ACCERR,FTM_ERR_UNKNOWN,FTM_ERR_UNKNOWN,
               FTM_ERR_UNKNOWN,FTM_ERR_UNKNOWN);
}
/*
*********************************************************************************************************
*                                   FTM_EEPROM_FullPartition()
*
* Description : To allows the user to allocate sectors within the D-Flash block for applications and a
*               partition within the buffer RAM for EEPROM access. The D-Flash block consists of 128
*               sectors with 256 bytes per sector.
*
* Arguments   : set directly at EEE_RAM in CONFIGURATION in FTM.h 
*
* Return      : FTM_ERR_NONE       if no err.
*               FTM_ERR_UNKNOWN    if known error encountered.
*               FTM_ERR_ACCERR     if uninitialized FCLKDIV 
*                                    or if command not available in current mode
*                                    or if an invalid DFPART or ERPART selection is supplied
*               FTM_ERR_READERR        if any errors have been encountered during the read.
*               FTM_ERR_READERR_FATAL  if any non-correctable errors have been encountered during the read.
*
* Notes       : 
*
*********************************************************************************************************
*/
unsigned char FTM_EEPROM_FullPartition(){
  FTM_STATUS status;
  status = _FTM_EEPROM_FullPartition();
  return _getErrorCode(status,FTM_ERR_ACCERR,FTM_ERR_UNKNOWN,FTM_ERR_READERR,
               FTM_ERR_READERR_FATAL,FTM_ERR_UNKNOWN);
}
/*
*********************************************************************************************************
*                                   FTM_EEPROM_Partition()
*
* Description : To allows the user to allocate sectors within the D-Flash block for applications and a
*                partition within the buffer RAM for EEPROM access. The D-Flash block consists of 32
*                sectors with 256 bytes per sector.
*
* Arguments   : set directly at EEE_RAM in CONFIGURATION in FTM.h 
*
* Return      : FTM_ERR_NONE          if no err.
*               FTM_ERR_UNKNOWN       if known error encountered.
*               FTM_ERR_ACCERR        if uninitialized FCLKDIV 
*                                       or if command not available in current mode
*                                       or if partitions have already been defined
*                                       or if an invalid DFPART or ERPART selection is supplied
*               FTM_ERR_READERR        if any errors have been encountered during the read.
*               FTM_ERR_READERR_FATAL  if any non-correctable errors have been encountered during the read.
*
* Notes       : 1. The Erase All Blocks command must be run prior to launching the Partition D-Flash command.
*               2. Running the Partition D-Flash command a second time will result in the ACCERR bit within
*                  the FSTAT register being set.
*
*********************************************************************************************************
*/
unsigned char FTM_EEPROM_Partition(){
  FTM_STATUS status;
  status = _FTM_EEPROM_Partition();
  return _getErrorCode(status,FTM_ERR_ACCERR,FTM_ERR_UNKNOWN,FTM_ERR_READERR,
               FTM_ERR_READERR_FATAL,FTM_ERR_UNKNOWN);
}

/*
*********************************************************************************************************
*                                   FTM_DFlash_EraseVerifySection()
*
* Description : To verify that a section of code in the D-Flash user partition is erased.
*
* Arguments   : globalAddrStart    Global address [15:0] of the first word to be verified in D-Flash block
*               wordsCnt           Number of words to be verified
*
* Return      : FTM_ERR_NONE       if no err.
*               FTM_ERR_UNKNOWN    if known error encountered.
*               FTM_ERR_ACCERR     if uninitialized FCLKDIV 
*                                    or if command not available in current mode
*                                    or if an invalid global address [22:0] is supplied
*                                    or if a misaligned word address is supplied (global address [0] != 0)
*                                    or if the global address [22:0] points to an area of the D-Flash EEE
*                                        partition
*                                    or if the requested section breaches the end of the D-Flash block or
*                                        goes into the D-Flash EEE partition
*               FTM_ERR_READERR        if any errors have been encountered during the read.
*               FTM_ERR_READERR_FATAL  if any non-correctable errors have been encountered during the read.
*
* Notes       : 
*
*********************************************************************************************************
*/
unsigned char FTM_DFlash_EraseVerifySection(unsigned long globalAddrStart,unsigned short wordsCnt){
  FTM_STATUS status;
  status = _FTM_DFlash_EraseVerifySection(((unsigned char)(globalAddrStart >> 16) & 0x7F),
            ((unsigned short)globalAddrStart),wordsCnt);
  return _getErrorCode(status,FTM_ERR_ACCERR,FTM_ERR_UNKNOWN,FTM_ERR_READERR,
               FTM_ERR_READERR_FATAL,FTM_ERR_UNKNOWN);
}
/*
*********************************************************************************************************
*                                   FTM_DFlash_ProgramXXXXWords()
*
* Description : To programs one to four previously erased words in the D-Flash user partition. The Program
*               D-Flash operation will confirm that the targeted location(s) were successfully programmed
*               upon completion.
*
* Arguments   : globalAddrStart    Global address [15:0] of the words to be programmed in D-Flash block
*               w(n)               Word n program value
*
* Return      : FTM_ERR_NONE       if no err.
*               FTM_ERR_UNKNOWN    if known error encountered.
*               FTM_ERR_ACCERR     if uninitialized FCLKDIV 
*                                    or if command not available in current mode
*                                    or if an invalid global address [22:0] is supplied
*                                    or if a misaligned word address is supplied (global address [0] != 0)
*                                    or if the global address [22:0] points to an area of the D-Flash EEE
*                                        partition
*                                    or if the requested group of words breaches the end of the D-Flash
*                                       block or goes into the D-Flash EEE partition.
*               FTM_ERR_WRITEERR       if any errors have been encountered during the verify operation.
*               FTM_ERR_WRITEERR_FATAL if any non-correctable errors have been encountered during the 
*                                      verify operation.
*
* Notes       : No protection checks are made in the Program D-Flash operation on the D-Flash block,
*               only access error checks
*
*********************************************************************************************************
*/
unsigned char FTM_DFlash_ProgramOneWord(unsigned long globalAddr,unsigned short w0){
  FTM_STATUS status;
  status = _FTM_DFlash_ProgramOneWord(((unsigned char)(globalAddr >> 16) & 0x7F),
            ((unsigned short)globalAddr),w0);
  return _getErrorCode(status,FTM_ERR_ACCERR,FTM_ERR_UNKNOWN,FTM_ERR_WRITEERR,
               FTM_ERR_WRITEERR_FATAL,FTM_ERR_UNKNOWN);
}
unsigned char FTM_DFlash_ProgramTwoWords(unsigned long globalAddr,unsigned short w0,unsigned short w1){
  FTM_STATUS status;
  status = _FTM_DFlash_ProgramTwoWords(((unsigned char)(globalAddr >> 16) & 0x7F),
            ((unsigned short)globalAddr),w0,w1);
  return _getErrorCode(status,FTM_ERR_ACCERR,FTM_ERR_UNKNOWN,FTM_ERR_WRITEERR,
               FTM_ERR_WRITEERR_FATAL,FTM_ERR_UNKNOWN);
}
unsigned char FTM_DFlash_ProgramThreeWords(unsigned long globalAddr,unsigned short w0,unsigned short w1,
                                       unsigned short w2){
  FTM_STATUS status;
  status = _FTM_DFlash_ProgramThreeWords(((unsigned char)(globalAddr >> 16) & 0x7F),
            ((unsigned short)globalAddr),w0,w1,w2);
  return _getErrorCode(status,FTM_ERR_ACCERR,FTM_ERR_UNKNOWN,FTM_ERR_WRITEERR,
               FTM_ERR_WRITEERR_FATAL,FTM_ERR_UNKNOWN);
}
unsigned char FTM_DFlash_ProgramFourWords(unsigned long globalAddr,unsigned short w0,unsigned short w1,
                                       unsigned short w2,unsigned short w3){
  FTM_STATUS status;
  status = _FTM_DFlash_ProgramFourWords(((unsigned char)(globalAddr >> 16) & 0x7F),
            ((unsigned short)globalAddr),w0,w1,w2,w3);
  return _getErrorCode(status,FTM_ERR_ACCERR,FTM_ERR_UNKNOWN,FTM_ERR_WRITEERR,
               FTM_ERR_WRITEERR_FATAL,FTM_ERR_UNKNOWN);
}
/*
*********************************************************************************************************
*                                       FTM_DFlash_EraseSector()
*
* Description : To erase all addresses in a sector of the D-Flash user partition.
*
* Arguments   : globalAddr                Global address [22:0] anywhere in the D-Flash sector to be erased.
*
* Return      : FTM_ERR_NONE              if no err.
*               FTM_ERR_UNKNOWN           if known error encountered.
*               FTM_ERR_ACCERR            if uninitialized FCLKDIV 
*                                          or if command not available in current mode
*                                          or if an invalid global address [22:0] is supplied
*                                          or if a misaligned word address is supplied (global address [0] != 0)
*                                          or if the global address [22:0] points to the D-Flash EEE partition
*               FTM_ERR_EREASEERR         if any errors have been encountered during the verify operation
*               FTM_ERR_EREASEERR_FATAL   if any non-correctable errors have been encountered during the
*                                          verify operation
*
* Notes       : 
*********************************************************************************************************
*/
unsigned char FTM_DFlash_EraseSector(unsigned long globalAddr){
  FTM_STATUS status;
  status = _FTM_DFlash_EraseSector(((unsigned char)(globalAddr >> 16) & 0x7F),((unsigned short)globalAddr));
  return _getErrorCode(status,FTM_ERR_ACCERR,FTM_ERR_UNKNOWN,FTM_ERR_EREASEERR,
               FTM_ERR_EREASEERR_FATAL,FTM_ERR_UNKNOWN);
}
/*
*********************************************************************************************************
*                                       FTM_EEPROM_Enable()
*
* Description : To enable EEE activity.
*
* Arguments   : 
*
* Return      : FTM_ERR_NONE              if no err.
*               FTM_ERR_UNKNOWN           if known error encountered.
*               FTM_ERR_ACCERR            if uninitialized FCLKDIV 
*                                          or if Full Partition D-Flash or Partition D-Flash command not
*                                             previously run
*
* Notes       : 1. EEE activity is disabled after any reset.
*               2. This command can be submitted many times.
*********************************************************************************************************
*/
unsigned char FTM_EEPROM_Enable(void){
  FTM_STATUS status;
  status = _FTM_EEPROM_Enable();
  return _getErrorCode(status,FTM_ERR_ACCERR,FTM_ERR_UNKNOWN,FTM_ERR_UNKNOWN,
               FTM_ERR_UNKNOWN,FTM_ERR_UNKNOWN);
}
/*
*********************************************************************************************************
*                                       FTM_EEPROM_Disable()
*
* Description : To suspend current EEE activity.
*
* Arguments   : 
*
* Return      : FTM_ERR_NONE              if no err.
*               FTM_ERR_UNKNOWN           if known error encountered.
*               FTM_ERR_ACCERR            if uninitialized FCLKDIV.
*
* Notes       : 1. EEE activity is disabled after any reset.
*               2. This command can be submitted many times.
*********************************************************************************************************
*/
unsigned char FTM_EEPROM_Disable(void){
  FTM_STATUS status;
  status = _FTM_EEPROM_Disable();
  return _getErrorCode(status,FTM_ERR_ACCERR,FTM_ERR_UNKNOWN,FTM_ERR_UNKNOWN,
               FTM_ERR_UNKNOWN,FTM_ERR_UNKNOWN);
}

/*
*********************************************************************************************************
*                                       FTM_EEPROM_Query()
*
* Description : To query the status of EEPROM.
*
* Arguments   : rst    used to return the result of the query ,if success.
*
* Return      : FTM_ERR_NONE              if no err.
*               FTM_ERR_UNKNOWN           if known error encountered.
*               FTM_ERR_ACCERR            if uninitialized FCLKDIV
*                                           or if command not available in current mode.
*
* Notes       : 1. if any error happen(check return value), rst will not be changed.
*********************************************************************************************************
*/

unsigned char FTM_EEPROM_Query(pFTM_EEE_STATUS rst){
  unsigned char errCode;
  FTM_STATUS status;
  status = _FTM_EEPROM_Query();
  errCode = _getErrorCode(status,FTM_ERR_ACCERR,FTM_ERR_UNKNOWN,FTM_ERR_UNKNOWN,
               FTM_ERR_UNKNOWN,FTM_ERR_UNKNOWN);
  if(errCode != FTM_ERR_NONE){
    return errCode;
  }
  FCCOBIX = 1;
  rst->dfPart = FCCOB;
  FCCOBIX++;
  rst->erPart = FCCOB;
  FCCOBIX++;
  rst->ersCnt = FCCOB;
  FCCOBIX++;
  rst->rdyCnt = FCCOBLO;
  rst->deadCnt = FCCOBHI;
  return FTM_ERR_NONE;
} 

/*
*********************************************************************************************************
*                                         LOCAL FUNCTION 
*********************************************************************************************************
*/
static unsigned char _getErrorCode(FTM_STATUS status,unsigned char accerrCode,unsigned char fpviolCode,
                                   unsigned char mgstat1Code,unsigned char mgstat0Code,unsigned char epviolifCode){
  if(_FTM_anyErrHappened(status)){
    if((status).Regs.fstat.Bits.ACCERR == 1)
      return accerrCode;
    if((status).Regs.fstat.Bits.FPVIOL == 1)
      return fpviolCode;
    if((status).Regs.fstat.Bits.MGSTAT1 == 1)
      return mgstat1Code;
    if((status).Regs.fstat.Bits.MGSTAT0 == 1)
      return mgstat0Code;
    if((status).Regs.ferstat.Bits.EPVIOLIF == 1)
      return epviolifCode;
    return FTM_ERR_UNKNOWN;
  }
  return FTM_ERR_NONE;
}

有一点需要注意的,很多命令在运行时是不允许程序在P-flash区域跑的,即不允许P-flash区域的代码擦写P-flash,否则单片机会直接跑飞,如果开了中断的话,任何可能在命令运行期间发生的中断的对应代码也必须在RAM区域。下面简单说下把代码移到RAM区域的方法。

我的代码中已经把FTM_LaunchCommand定义在呢 RAM_CODE这个代码块了,所以要做的就是在prm文件中定义RAM_CODE这个代码块。

打开工程的prm文件。找到

SEGMENTS
......
      ROM_C000      = READ_ONLY   DATA_NEAR IBCC_NEAR  0xC000 TO   0xFEFF; 
......
END

将其改成

SEGMENTS
......
      RAM_CODE_SEG  = READ_ONLY       0xFE00 TO   0xFEFF RELOCATE_TO 0x3E00;    
      ROM_C000      = READ_ONLY   DATA_NEAR IBCC_NEAR  0xC000 TO   0xFDFF; 
......
END
PLACEMENT
......
      RAM_CODE        INTO  RAM_CODE_SEG;
......
END

这样FTM_LaunchCommand的代码就会被重定位到0x3E00开始的RAM区域了

但是编译器不会自动帮你复制代码过去,所以在程序中还得在使用这个驱动程序之前先调用次这个函数。

#include <string.h>

#define __SEG_START_REF(a)  __SEG_START_ ## a
#define __SEG_END_REF(a)    __SEG_END_ ## a
#define __SEG_SIZE_REF(a)   __SEG_SIZE_ ## a
#define __SEG_START_DEF(a)  extern char __SEG_START_REF (a) []
#define __SEG_END_DEF(a)    extern char __SEG_END_REF   (a) []
#define __SEG_SIZE_DEF(a)   extern char __SEG_SIZE_REF  (a) []

__SEG_START_DEF (RAM_CODE);
__SEG_END_DEF   (RAM_CODE);
__SEG_SIZE_DEF  (RAM_CODE);

void CopyCodeToRAM(void)
{
  memcpy((unsigned char *)0x3E00,(unsigned char *)__SEG_START_REF(RAM_CODE),(unsigned short)__SEG_SIZE_REF(RAM_CODE));
}

然后就可以愉快地操作Flash内存了。

猜你喜欢

转载自blog.csdn.net/lin_strong/article/details/79938296