📄 flashdriver.c
字号:
#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 + -