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

📄 flashdriver.c

📁 Freescale的HCS12处理器上面的flash驱动。支持块擦除、扇区存储、单字读取、单字烧写等操作。在CodeWarrior中开发。
💻 C
📖 第 1 页 / 共 2 页
字号:

#include "io_map.h"



#define FLASH_ADDR_START    0x8000
#define FLASH_ADDR_END      0xBFFF

// block 0(page 0x3c to 0x3f) is used for code and data, more detail:
// 0~0x0fff for Registers
// 0x1000~0x3fff for Global RW Variants
// 0x4000~0x7fff for Code
// 0xC000~0xffff for RO Variants
// and block 0 is unbanked by default, access by real address

// Block1, Block2, Block3 (page 0x30 to 0x3b) are for common usage.
#define FLASH_PAGE_START    0x30
#define FLASH_PAGE_END      0x3b

// 尚未解决问题:烧写器默认会擦除所有的flash。如何让烧写器只擦除bin所在的块?


#define test_addr_start     (FLASH_ADDR_START)


#define E_FLASH_OK      0x00
#define E_FLASH_BUSY    0x01
#define E_FLASH_ACCESS  0x02
#define E_FLASH_VERIFY  0x03
#define E_FLASH_RANGE   0x04
#define E_FLASH_FAIL    0x05
#define E_FLASH_PARAM   0x06
#define E_FLASH_NOTBLANK   0x07



 // available flash Unbanked, range 0x4000 TO 0x7FFF; 16KB
void flash_delay_bus_cycle(INT16U cycle)
{
    INT16U i ;
    for (i=0; i< cycle; i++)
        ;
}
    

//#pragma CODE_SEG NON_BANKED 
 void flash_init(void)
 {
 // MCU frequency: 16Mhz
 // Bus frequency: 8Mhz
 // Tbus = 0.125us
 // FDIV = 10, FCLK = 181.8Khz according to the formula
 // FDIV = 9, FCLK = 200Khz according to manual optimization
    FCLKDIV_PRDIV8 = 1 ;
    FCLKDIV_FDIV = 9 ; 
    
    
    FCNFG_BKSEL = 0 ;
    FSTAT |= 0x30 ;
    FCNFG_BKSEL = 1 ;
    FSTAT |= 0x30 ;
    FCNFG_BKSEL = 2 ;
    FSTAT |= 0x30 ;
    FCNFG_BKSEL = 3 ;
    FSTAT |= 0x30 ;
    
    
    
    
    FPROT = 0xff ;	 // for mass erase, disable protection
    
    // addr in 8000~BFFF needs to set PPAGE, addr in 4000~7FFF and C000~FFFF need NOT set PPAGE

 }
 
//#pragma CODE_SEG NON_BANKED
// basic operation to flash 
INT8U flash_write_word(INT8U page, INT16U addr, INT16U data16)
{
    // check if there is pending cmds.
    if (0 == FSTAT_CBEIF)
        return  E_FLASH_BUSY ;
    

    // no pending cmds, ok, clear all err flags
    FSTAT |= 0x30 ;
    
    FCNFG_BKSEL = ~((page & 0x0f) >> 2) ;   // page = 0x3A = 00111010, page & 0x0f = 00001010, ~ = 01, BANK = 01
    PPAGE = page ;

    // the next 3-step operation not separated
    *(volatile INT16U *)addr = data16 ;	 // Array address and program data
    FCMD = 0x20 ;						 // Word program command
    FSTAT_CBEIF = 1 ;					 // Clear flag command buffer empty, it will be 0

    flash_delay_bus_cycle(5) ;

    // check if error appears
    if ((1 == FSTAT_PVIOL) || (1 == FSTAT_ACCERR))
        return E_FLASH_ACCESS ;
    
    // wait for cmd buffer to be empty
    while (0 == FSTAT_CBEIF) ;

    // wait for cmd to complete
    while (0 == FSTAT_CCIF) ; 
    
    // verify if data is truely written to flash
    if (data16 != (*(volatile INT16U *)addr))
        return E_FLASH_VERIFY ;
     
    // congratulations, data's been stored.
    return E_FLASH_OK ;
}

//#pragma CODE_SEG NON_BANKED
INT16U flash_read_word(INT8U page, INT16U addr)
{
    // wait for cmd to complete
    while (0 == FSTAT_CCIF) ; 

    FCNFG_BKSEL = ~((page & 0x0f) >> 2) ;   // page = 0x3A = 00111010, page & 0x0f = 00001010, ~ = 01, BANK = 01
    PPAGE = page ;
    
    return (INT16U)(*(volatile INT16U *)addr) ;
}
 



//#pragma CODE_SEG NON_BANKED
INT8U flash_erase_sector(INT8U page, INT16U addr)
{
    // check if there is pending cmds.
    if (0 == FSTAT_CBEIF)
        return  E_FLASH_BUSY ;
    
    // no pending cmds, ok, clear all err flags
    FSTAT |= 0x30 ;
   
    FCNFG_BKSEL = ~((page & 0x0f) >> 2) ;   // page = 0x3A = 00111010, page & 0x0f = 00001010, ~ = 01, BANK = 01
    PPAGE = page ;

    // the next 3-step operation not separated
    *(volatile INT16U *)(addr & 0xffff) = 0x5a5a ;	 // Array address and program data:any addr and data
    FCMD = 0x40 ;						 // Sector Erase command
    FSTAT_CBEIF = 1 ;					 // Clear flag command buffer empty, it will be 0
    
    flash_delay_bus_cycle(5) ;
    
    // check if error appears
    if ((1 == FSTAT_PVIOL) || (1 == FSTAT_ACCERR))
        return E_FLASH_ACCESS ;
    
    // wait for cmd buffer to be empty
    while (0 == FSTAT_CBEIF) ;
    
    // wait for cmd to complete
    while (0 == FSTAT_CCIF) ; 
    
    // congratulations, data's been erased.
    return E_FLASH_OK ;
}    

//#pragma CODE_SEG NON_BANKED
INT8U flash_mass_erase(INT8U blockid)
{
    // check if there is pending cmds.
    if (0 == FSTAT_CBEIF)
        return  E_FLASH_BUSY ;
    
    // no pending cmds, ok, clear all err flags
    FSTAT |= 0x30 ;
   
    FPROT = 0xff ;	 // for mass erase, disable protection
   
    FCNFG_BKSEL = blockid ;
 
    // the next 3-step operation not separated
    *(volatile INT16U *)(0x8000) = 0xffff ;	 // Array address and program data:any addr and data
    FCMD = 0x41 ;						 // Mass Erase command
    FSTAT_CBEIF = 1 ;					 // Clear flag command buffer empty, it will be 0
    
    flash_delay_bus_cycle(5) ;

    // check if error appears
    if ((1 == FSTAT_PVIOL) || (1 == FSTAT_ACCERR))
        return E_FLASH_ACCESS ;
    
    // wait for cmd buffer to be empty
    while (0 == FSTAT_CBEIF) ;
    
    // wait for cmd to complete
    while (0 == FSTAT_CCIF) ; 
    
    // congratulations, data's been erased.
    return E_FLASH_OK ;
}    

//#pragma CODE_SEG NON_BANKED
INT8U flash_erase_verify_block(INT8U blockid)
{
    // check if there is pending cmds.
    if (0 == FSTAT_CBEIF)
        return  E_FLASH_BUSY ;
    
    // no pending cmds, ok, clear all err flags
    FSTAT |= 0x30 ;

    FPROT = 0xff ;	 // for mass erase, disable protection

    FCNFG_BKSEL = blockid ;

    // the next 3-step operation not separated
    *(volatile INT16U *)(0x8000) = 0x5a5a ;	 // Array address and program data:any addr and data
    FCMD = 0x05 ;						 // Erase Verify command
    FSTAT_CBEIF = 1 ;					 // Clear flag command buffer empty, it will be 0
    
    flash_delay_bus_cycle(5) ;

    // check if error appears
    if ((1 == FSTAT_PVIOL) || (1 == FSTAT_ACCERR))
        return E_FLASH_ACCESS ;
    
    // wait for cmd buffer to be empty
    while (0 == FSTAT_CBEIF) ;
    
    // wait for cmd to complete
    while (0 == FSTAT_CCIF) ; 
    
    // check the BLANK flag
    if (1 == FSTAT_BLANK)
        return E_FLASH_OK ;
    else
        return E_FLASH_NOTBLANK ;
    
}    

//#pragma CODE_SEG NON_BANKED
INT8U flash_write(INT8U page, INT16U addr, INT8U *pbuf, INT16U len)
{
    INT16U addrStart = addr ;
    INT16U addrEnd = addr + len -1 ;
    INT16U data16 ;
    INT16U i ;
    
    // check len and buf
    if ((NULL == pbuf) || (len <=0))
        return E_FLASH_PARAM ;
    
    // check if out ranged
    if ((addrStart < FLASH_ADDR_START) || (addrEnd > FLASH_ADDR_END) || (page < FLASH_PAGE_START) || (page > FLASH_PAGE_END))
        return E_FLASH_RANGE ;
    
    // check if start from odd addr
    if (addrStart & 0x0001)    
    {
        // start from an odd addr
        // read the 16bit word and change it
        data16 = *(volatile INT16U *)(addrStart - 1) ;
        // note that HCS12 is big endian!
        data16 = (data16 & 0xff00) | pbuf[0] ;  // keep the lower addr part, and combine the first input byte
        
        if (flash_write_word(page, addrStart - 1, data16) != E_FLASH_OK)
            return E_FLASH_FAIL ;
        
        // write the first byte OK
        addrStart += 1 ;        // addr alignment
        pbuf++ ;                // step to next byte
        
    }
    
    // now, addrStart is aligned
    while (addrStart + 1 <= addrEnd)
    {
        data16 = *(INT16U *)pbuf ;      // read a 16bit word
        if (flash_write_word(page, addrStart, data16) != E_FLASH_OK)
            return E_FLASH_FAIL ;
        
        addrStart += 2 ;
        pbuf += 2 ;
    }

    // check if end at an even addr and write the last 1 byte
    if (addrEnd & 0x0001)    
    {
        // end at an odd addr, good, already written in the while loop
        //data16 = *(INT16U *)pbuf ;      // read a 16bit word
    }
    else
    {
        // end at an even addr, bad

⌨️ 快捷键说明

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