Flash控制器
基础信息介绍
- 该Flash为ls1c102的内部Flash
- 数据空间大小为128KB,页大小为128Bytes,一共1024个页。
- Flash存储空间地址为0xbf000000,该地址是访问Flash数据的起始地址,从此地址开始往后128KB的空间都是Flash空间中保存的数据
- Flash寄存器空间地址为0xbfe60000,该地址是Flash控制器配置空间的基地址
- 片内系统时钟校准频率位于0xbf0201b0,单位为KHz
- Flash的写操作只支持32位写
配置寄存器
配置空间基于基地址的偏移分别为:
- 0x00:CMD(命令寄存器)
- 0x10:VRF(数据校验寄存器)
- 0x14:STS(状态寄存器)
- 0x18:PET(擦写时间寄存器)
寄存器的详细解释参考用户手册
Flash数据的读取
在ls1c102中,片内Flash直接将自己的空间映射在了0xbf000000起始的地址处,对于获取片内Flash的数据直接像访问内存地址一样去读取从0xbf000000开始长度为128KB的范围即可。如果将片内Flash作为启动空间,那么在0x1c000000开始的128KB范围内访问也是一样的。
Flash数据的擦写
ls1c102的片内Flash的最小擦除单位是一个页,也就是128Bytes.在写入新数据前必须先进行擦除操作然后再写入。想要对上层抽象为对随机地址写入随机长度的数据思路大致如下:
- 通过传入的地址计算出所在的页
- 将该页数据全部拷贝到内存进行临时保存
- 用需要修改的数据覆盖临时保存的那一页数据
- 对页进行擦除
- 将修改过的页数据写会
对于以上步骤,需要考虑要写入的数据跨页的情况,同时也应当注意片内Flash写操作只支持32位写的硬件限制。
代码实现
Flash读实现
unsigned int read_flash(unsigned int flash_addr, unsigned char *buff, unsigned int buff_len)
{
if(flash_addr < 0xbf000000 || flash_addr > 0xbf01FFFF)
{
printf("flash address error 0x%08x\n", flash_addr);
return 0;
}
unsigned char *tmp = (unsigned char *)flash_addr;
unsigned int i=0;
for(i=0; i<buff_len; ++i)
{
buff[i] = tmp[i];
}
return i;
}
Flash写实现
static void flash_waite(unsigned int timeout, unsigned char mask)
{
unsigned char status = FLASH->STS & 0x0F;
while((!(status & mask)))
{
status = FLASH->STS & 0x0F;
delay_ms(1);
timeout--;
}
if(timeout == 0x00)
{
printf("flash time out\n");
}
}
static void write_flash_page(unsigned int *page_start, unsigned int *buff)
{
unsigned int i=0;
unsigned int tmp_addr = ((unsigned int)page_start) & (~(FLASH_PAGE_SIZE-1));
if(tmp_addr != (unsigned int)page_start)
{
printf("page_start not start address\n");
return;
}
FLASH->CMD = FLASH_PAGE_LATCH_CLEAR;
for(i=0; i<(FLASH_PAGE_SIZE>>2); ++i)
{
page_start[i] = buff[i];
}
FLASH->CMD = FLASH_ERASE_CMD | ((unsigned int)page_start & FLASH_ADDR_MASK);
flash_waite((uint32_t)0x00002000, 0x04);
FLASH->CMD = FLASH_WRITE_CMD | ((unsigned int)page_start & FLASH_ADDR_MASK);
flash_waite((uint32_t)0x00001000, 0x04);
}
void write_flash(unsigned int flash_addr, unsigned char *buff, unsigned int num)
{
if(!num)
{
return;
}
if(flash_addr < 0xbf000000 || flash_addr > 0xbf01FFFF)
{
printf("flash address error 0x%08x\n", flash_addr);
return;
}
unsigned char tmp_area[FLASH_PAGE_SIZE] = {0};
unsigned char *start_addr = (unsigned char *)(flash_addr & (~(FLASH_PAGE_SIZE-1)));
unsigned int offset = flash_addr & (FLASH_PAGE_SIZE-1);
unsigned int i=0;
unsigned int buff_index = 0;
while(1)
{
for(i=0; i<FLASH_PAGE_SIZE; ++i)
{
tmp_area[i] = start_addr[i];
}
while(buff_index<num && offset<FLASH_PAGE_SIZE)
{
tmp_area[offset++] = buff[buff_index++];
}
write_flash_page((unsigned int *)start_addr, (unsigned int *)tmp_area);
if(buff_index >= num)
{
break;
}else{
start_addr += FLASH_PAGE_SIZE;
offset=0;
}
}
}