⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hcs08_eeprom_api.c

📁 在HCS08微控制器上使用FLASH存储器模拟EEPROM
💻 C
字号:
/**
* Copyright (c) 2006, Freescale Semiconductor
* File name : HCS08_EEPROM_API.c
* CPU : MC9S08
* Compiler: CodeWarrior v5.1 08C Compiler
*
* Author : Jerry Shi (b01136@freescale.com)
*
* Description : This file includes definition for subroutines that 
*               emulating EEPROM with FLASH memory on HCS08 MCU.
*                            
* History :   
* 10/08/2006  : API works on MC9S08QG8CDTE 
* 10/11/2006  : add error handling functions
*/

#include <hidef.h> /* for EnableInterrupts macro */
#include <stdio.h>  /* for memcpy() */ 
#include "derivative.h" /* include peripheral declarations */
#include "hcs08_eeprom_api.h"


#pragma MESSAGE DISABLE C4001   // condition always FALSE


static void flash_byte_prog(unsigned int _addr, unsigned char _data);
static void flash_page_erase(unsigned int _addr);
static unsigned char flash_byte_read(unsigned int _addr);

const unsigned char __NVPROT @ 0xFFBD = HCS08_FLASH_PROTECTION; 

/*
** ===================================================================
**     Method      :  HCS08_EE_Init 
**
**     Description :
**         fFCLK initialization code for FLASH programming and erasing.
**         fFCLK must be within the range from 150 kHz to 200 kHz. 
**         After this initialization methdo, fFCLK is always arround 
**         175 kHz, which is within the range of specification.
**     Patameters:
**          no.
**     Return Values:
**          no
** ===================================================================
*/
void HCS08_EE_Init(void) 
{
/** 
** fFCLK setting
** FCDIV: 7 6 5 4 3 2 1 0
**        | | |         
**        | | +DIV[5:0]: fFCLK = fBUS / (8exp(PRDIV8) * DIV +1)
**        | +PRDIV8: Prescale by 8, 1: input to the FLASH clock divider is the bus rate clock divided by 8.
**        +DIVLD: divisor load status, 1: has been written since reset.
*/
   if (!FCDIV_DIVLD) 
   {
      if (HCS08_BUS_FREQUENCY >= 12000)
      {
          FCDIV = (((HCS08_BUS_FREQUENCY / (8*175))) | 0x40) - 1;
      }
      else 
      {
          FCDIV = (HCS08_BUS_FREQUENCY / 175) - 1;
      }
   }  
     
}

/*
** ===================================================================
**     Method      :  HCS08_EE_WriteRecord 
**
**     Description :
**         this function writes the whold data record to the next 
**         available space block of FLASH, also the Record Has Been
**         used flag before the data. If the current page will be full, 
**         it erases the next page.
**     Patameters:
**          unsigned char *.    -- point to the source data
**     Return Values:
**          status
** ===================================================================
*/
unsigned char HCS08_EE_WriteRecord(unsigned char *src)
{
    unsigned int i, j;
    unsigned char flag_page_switch;
    unsigned int ee_current_page, ee_next_page;
    
    flag_page_switch = 0;
    ee_current_page = EEPROM_START_ADDR;
    ee_next_page = EEPROM_START_ADDR + EEPROM_PAGE_SIZE;
    
    // find the current page
    if (FLAG_CURENT_PAGE != 
          flash_byte_read(ee_current_page + EEPROM_PAGE_SIZE - 1))
    {
        ee_current_page = EEPROM_START_ADDR + EEPROM_PAGE_SIZE;
        ee_next_page = EEPROM_START_ADDR;
    }
    
    for (;;) 
    {
        for (i = 0; 
             i < PAGE_REUSE_TIMES * EEPROM_DATA_LEN; 
             i = i + EEPROM_DATA_LEN + 1)
        {
            if (FLAG_RECORD_USED != flash_byte_read(ee_current_page + i))
            {
                // this record space is empty
                // wite flag to mark this record is used
                flash_byte_prog(ee_current_page + i, FLAG_RECORD_USED);
                // then write the record data to the following addresses
                for (j = 0; j < EEPROM_DATA_LEN; j++) 
                {
                    flash_byte_prog(ee_current_page + 1 + i + j, *(src + j)); 
                }
                
                // do we need to switch to next page?
                if (flag_page_switch)
                    flash_page_erase(ee_next_page);
                return HCS08_EE_ERROR_OK;
            }
        }
        
        // all the records are visited now, but does not find the current record
        // page switch
        j = ee_next_page;
        ee_next_page = ee_current_page;
        ee_current_page = j;
        flag_page_switch = 1;
        // mark the current page
        flash_byte_prog((ee_current_page + EEPROM_PAGE_SIZE -1), FLAG_CURENT_PAGE);
    }
}
      
/*
** ===================================================================
**     Method      :  HCS08_EE_ModifyByte 
**
**     Description :
**         this function find the current data record from the current 
**         page, and modifies the specified byte of the record.
**     Patameters:
**          unsigned int *.     -- index of target byte to be modified in the record
**          unsigned char *.    -- source data
**     Return Values:
**          status
** ===================================================================
*/        
unsigned char HCS08_EE_ModifyByte(unsigned int index, unsigned char data)
{
    unsigned char buff[EEPROM_DATA_LEN];
    unsigned char ret;
    
    if (index >= EEPROM_DATA_LEN)
        return HCS08_EE_ERROR_OUT_OF_RANGE;
    
    ret = HCS08_EE_ReadRecord(buff);
    if (ret != HCS08_EE_ERROR_OK)
        return ret;
    
    buff[index] = data;
    ret = HCS08_EE_WriteRecord(buff);
    if (ret != HCS08_EE_ERROR_OK)
        return ret;
    
    return HCS08_EE_ERROR_OK;
}

/*
** ===================================================================
**     Method      :  HCS08_EE_ReadRecord 
**
**     Description :
**         this function finds the current record in the current page,
**         then reads the all the data in the record to a buffer.
**     Patameters:
**          unsigned char *.    -- point to the dest buffer
**     Return Values:
**          status
** ===================================================================
*/
unsigned char HCS08_EE_ReadRecord(unsigned char *dest)
{
    unsigned int i, j;
    unsigned int ee_current_page;
    
    ee_current_page = EEPROM_START_ADDR;
    
    // find the current page
    if (FLAG_CURENT_PAGE != flash_byte_read(ee_current_page + EEPROM_PAGE_SIZE - 1))
        ee_current_page = EEPROM_START_ADDR + EEPROM_PAGE_SIZE;
    
    // visit all the records till find out the 'current' record         
    for (i = 0; 
         i < (PAGE_REUSE_TIMES - 1) * EEPROM_DATA_LEN; 
         i+= EEPROM_DATA_LEN + 1)
    {
        if (FLAG_RECORD_USED != flash_byte_read(ee_current_page + 1 + i + EEPROM_DATA_LEN)) 
            break;
    }

    // when the 'current' record is found, read data of it
    for (j = 0; j < EEPROM_DATA_LEN; j++)
        *(dest + j) = flash_byte_read(ee_current_page + 1 + i + j);
        
    return HCS08_EE_ERROR_OK;
}


/*
** ===================================================================
**     Method      :  HCS08_EE_ReadByte 
**
**     Description :
**         this function find the current data record from the current 
**         page, and reads the specified byte of the record.
**     Patameters:
**          unsigned int.       -- index of target byte to be read in the record
**          unsigned char *.    -- pointer to data container
**     Return Values:
**          unsigned char *.    -- status
** ===================================================================
*/   
unsigned char HCS08_EE_ReadByte(unsigned int index, unsigned char* data)
{
    unsigned int i;
    unsigned int ee_current_page;
    
    if (index >= EEPROM_DATA_LEN)
      return HCS08_EE_ERROR_OUT_OF_RANGE;
    
    ee_current_page = EEPROM_START_ADDR;
    
    // find the current page
    if (FLAG_CURENT_PAGE != flash_byte_read(ee_current_page + EEPROM_PAGE_SIZE - 1))
        ee_current_page = EEPROM_START_ADDR + EEPROM_PAGE_SIZE;
    
    // visit all the records till find out the 'current' record         
    for (i = 0; 
         i < (PAGE_REUSE_TIMES - 1) * EEPROM_DATA_LEN; 
         i+= EEPROM_DATA_LEN + 1)
    {
        if (FLAG_RECORD_USED != flash_byte_read(ee_current_page + 1 + i + EEPROM_DATA_LEN)) 
            break;
    }
    
    // when break, the current record is found
    *data = flash_byte_read(ee_current_page + i + 1 + index);
    
    return HCS08_EE_ERROR_OK;
}

/* ===================================================================*/
// Array of opcode instructions of the Erase/Program function in 
// the HCS08 family 
// size = 40 bytes + 2 bytes           
const unsigned char ROM_PGM[] = 
{
  0x9E, 0xFE, 0x03, // LDHX 3,SP   ; get the target address '_addr'
/* PC is pushed when calling, 2 bytes used (SP is decreased by 2)
** SP is now pointing to the next available unit
** thus '_addr' is at [SP+3]
*/  
  0xF7,	            // STA ,X		   ; store 'data' to 'addr' 
  0xA6, 0x20,	      // LDA #$20    ; load FCMD, CMD should be changed before calling
  0xC7, 0x18, 0x26,	// STA $1826	 ; FCMD
  0x45, 0x18, 0x25,	// LDHX #$1825 ; address of FSTAT
  0xF6,           	// LDA ,X      ; load FSTAT to A
  0xAA, 0x80,     	// ORA #$80    ; set FCBEF to lunch the command
  0xF7,    	        // STA ,X      ; store back to FSTAT
  0x9D,           	// NOP         ; wait for 4 cycles
  0x9D,            	// NOP
  0x9D,           	// NOP
  0x9D,           	// NOP
  0x45, 0x18, 0x25,	// LDHX #$1825 ; check FACCERR and FPVIOL
  0xF6,    	        // LDA ,X
  0xA5, 0x30,      	// BIT #$30
  0x27, 0x04,     	// BEQ *+6     ; branch to label_1
  0xA6, 0xFF,     	// LDA #$FF    ; return 0xFF if flag error
  0x20, 0x07,     	// BRA *+9     ; branch to label_2
//label_1:  
  0xC6, 0x18, 0x25, // LDA $1825   ; wait for command to be completed
  0xA5, 0x40,   	  // BIT #$40
  0x27, 0xF9,     	// BEQ *-5     ; branch to label_1
//label_2:  
  0x81    	        // RTS         ; return
};

/*
** ===================================================================
**     Method      :  flash_byte_prog 
**
**     Description :
**         flash_byte_prog programs one byte of data to the specified 
**         address of FLASH. this is an internal method only used by API.
**     Patameters:
**          unsigned int,       -- target address to be programmed
**          unsigned char.      -- data to be programmed
**     Return Values:
**          no
** ===================================================================
*/
static 
void flash_byte_prog(unsigned int _addr, unsigned char _data)
{
  unsigned char _pgm[sizeof(ROM_PGM) + 2];
  
  // save '_addr'
  _pgm[0] = (unsigned char)((_addr & 0xff00) >> 8);
  _pgm[1] = (unsigned char)(_addr & 0x00ff);
  
  // copy the code to stack (local variable _pgm[]) 
  (void)memcpy(_pgm + 2, ROM_PGM, sizeof(ROM_PGM)); 
  
  _pgm[7] = FLASH_CMD_BYTEPROG; // change FCMD value
 
  DisableInterrupts;
  
  if (FSTAT&0x10){              // Check to see if FACCERR is set
      FSTAT = FSTAT | 0x10;     // write a 1 to FACCERR to clear
  }  
  __asm 
  {
    LDA _data     // pass '_data' thru A
    TSX           // transfer SP to HX
    JSR 2,X       // first 2 bytes of _pgm[] are '_addr'
  }
  EnableInterrupts;
}

/*
** ===================================================================
**     Method      :  flash_page_erase 
**
**     Description :
**         flash_page_erase erases one page that contains the specified 
**         address of FLASH. this is an internal method only used by API.
**     Patameters:
**          unsigned int.    -- target address to be erased
**     Return Values:
**          no
** ===================================================================
*/
static 
void flash_page_erase(unsigned int _addr)
{
  unsigned char _pgm[sizeof(ROM_PGM) + 2];
  
  // save '_addr'
  _pgm[0] = (unsigned char)((_addr & 0xff00) >> 8);
  _pgm[1] = (unsigned char)(_addr & 0x00ff); 
  
  // copy codes to stack (local variable _pgm[])
  (void)memcpy(_pgm + 2, ROM_PGM, sizeof(ROM_PGM)); 
  
  _pgm[7] = FLASH_CMD_PAGEERASE;// change FCMD value
  
  DisableInterrupts;
  
  if (FSTAT&0x10){              // Check to see if FACCERR is set
      FSTAT = FSTAT | 0x10;     // write a 1 to FACCERR to clear
  }  
  __asm 
  {
    TSX           // transfer SP to HX
    JSR 2,X       // first 2 bytes of _pgm[] are '_addr'
  }
  EnableInterrupts;
}

/*
** ===================================================================
**     Method      :  flash_byte_read 
**
**     Description :
**         flash_byte_read reads one byte data from the specified 
**         address of FLASH. this is an internal method only used by API.
**     Patameters:
**          unsigned int.         -- target address to be erased
**     Return Values:
**          unsigned char.        -- the data
** ===================================================================
*/
static 
unsigned char flash_byte_read(unsigned int _addr)
{
    return *(unsigned char *)_addr;  
}




⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -