CH32F103 FLASH的使用
最近使用CH32F103来替代STM32F103,遇到的flash问题来简单记一下。
程序使用STM32的没有修改直接烧入,能启动,能运行,内部flash写入失败,查看官方文档,标准模式太慢,基本不大行,可以使用快速模式,按照官方例程修改失败,查看文档,按照标准流程进行了修改,成功。
这是官方文档描述:
24.4.6 主存储器快速编程
快速编程按页(128 字节)进行编程。系统内置了 128 字节缓存区,将要待编程的数据线保存到
缓存区后执行一次编程操作,效率更高。
1)检查 FLASH_CTLR 寄存器 LOCK 位,如果为 1,需要执行“解除闪存锁”操作。
2)检查 FLASH_STATR 寄存器的 BSY 位,以确认没有其他正在进行的编程操作。
3)检查 FLASH_CTLR 寄存器 FLOCK 位,如果为 1,需要执行“快速编程模式解锁”操作。
CH32x103 应用手册 272 http://wch.cn
4)设置 FLASH_CTLR 寄存器的 FTPG 位,开启快速编程模式功能。
5)设置 FLASH_CTLR 寄存器的 BUFRST 位,执行清除内部 128 字节缓存区操作。
6)等待 BYS 位变为‘0’或 FLASH_STATR 寄存器的 EOP 位为‘1’表示清除结束,将 EOP 位清 0。
7)向指定地址开始连续写入 16 字节数据(4 字节/次操作,写的地址每次偏移量为 4),然后设置
FLASH_CTLR 寄存器的 BUFLOAD 位,执行加载到缓存区。
8)等待 BYS 位变为‘0’或 FLASH_STATR 寄存器的 EOP 位为‘1’表示加载结束,将 EOP 位清 0。
9)重复步骤 7-8 共 8 次,将 128 字节数据都加载到缓存区(主要 8 轮操作地址要连续)。
10)向 FLASH_ADDR 寄存器写入快速编程页的首地址。
11)设置 FLASH_CTLR 寄存器的 STAT 位为‘1’,启动一次快速页编程动作。
12)等待 BYS 位变为‘0’或 FLASH_STATR 寄存器的 EOP 位为‘1’表示编程结束,将 EOP 位清 0。
13)查询 FLASH_STATR 寄存器看是否有错误,或者读编程地址数据校验。
14)继续快速页编程可以重复 5-13 步骤,结束编程将 FTPG 位清 0。
24.4.7 主存储器快速擦除
快速擦除也按页(128 字节)进行擦除。
1)检查 FLASH_CTLR 寄存器 LOCK 位,如果为 1,需要执行“解除闪存锁”操作。
2)检查 FLASH_STATR 寄存器的 BSY 位,以确认没有其他正在进行的编程操作。
3)检查 FLASH_CTLR 寄存器 FLOCK 位,如果为 1,需要执行“快速编程模式解锁”操作。
4)设置 FLASH_CTLR 寄存器的 FTER 位,开启快速擦除模式功能。
5)向 FLASH_ADDR 寄存器写入快速擦除页的首地址。
6)设置 FLASH_CTLR 寄存器的 STAT 位为‘1’,启动一次快速页擦除动作。
7)等待 BYS 位变为‘0’或 FLASH_STATR 寄存器的 EOP 位为‘1’表示擦除结束,将 EOP 位清 0。
8)查询 FLASH_STATR 寄存器看是否有错误,或者读擦除页地址数据校验。
9)继续快速页擦除可以重复 5-8 步骤,结束擦除将 FTER 位清 0。
这是修改的代码
void FLASH_ErasePage_Fast(uint32_t Page_Address)
{
if(IS_FLASH_ADDRESS(Page_Address))
{
while(FLASH->CR & CR_LOCK_Set)
FLASH_Unlock_Fast();
while(FLASH->SR & SR_BSY);
FLASH->CR |= CR_PAGE_ER;
FLASH->AR = Page_Address;
FLASH->CR |= CR_STRT_Set;
while(FLASH->SR & SR_BSY);
FLASH->CR &= ~CR_PAGE_ER;
*(__IO uint32_t*)0x40022034 = *(__IO uint32_t*)(Page_Address ^ 0x00000100);
}
}
void FLASH_ProgramPage_Fast(uint32_t Page_Address)
{
if(IS_FLASH_ADDRESS(Page_Address))
{
while(FLASH->CR & CR_LOCK_Set)
FLASH_Unlock_Fast();
while(FLASH->SR & SR_BSY);
while(FLASH->CR & CR_LOCK_FK)
FLASH_Unlock_Fast();
FLASH->CR |= CR_PAGE_PG;
FLASH->AR = Page_Address;
FLASH->CR |= CR_STRT_Set;
while(FLASH->SR & SR_BSY);
FLASH->CR &= ~CR_PAGE_PG;
*(__IO uint32_t*)0x40022034 = *(__IO uint32_t*)(Page_Address ^ 0x00000100);
}
}
批量写入程序
int FlashWrite(uint32_t offsetAdd, uint8_t *buf, uint32_t iNbrToWrite)
{
/* Unlock the Flash Bank1 Program Erase controller */
uint32_t secpos, iAddress = _start_addr + offsetAdd;
uint32_t iNumByteToWrite = iNbrToWrite;
uint16_t secoff;
uint16_t secremain;
uint16_t i = 0;
// 定义缓冲区,保存读出的页数据
static uint8_t tmp[128];
u32 *buffer;
if ((_start_addr == 0) || (iAddress >= _end_addr))
{
return 0;
}
secremain = 128 ; //空间大小
if(iNumByteToWrite <= secremain) secremain = iNumByteToWrite;
FLASH_Unlock_Fast();
while( 1 )
{
ebox_flashRead(iAddress, tmp, 128); //读出整个扇区
FLASH_ErasePage_Fast(iAddress);
for(i = 0; i < 128; i++) //复制
{
tmp[i] = buf[i];
}
buffer = (u32 *)tmp;
FLASH_BufReset();
FLASH_BufLoad(iAddress, buffer[0], buffer[1], buffer[2], buffer[3]);
FLASH_BufLoad(iAddress + 0x10, buffer[4], buffer[5], buffer[6], buffer[7]);
FLASH_BufLoad(iAddress + 0x20, buffer[8], buffer[9], buffer[10], buffer[11]);
FLASH_BufLoad(iAddress + 0x30, buffer[12], buffer[13], buffer[14], buffer[15]);
FLASH_BufLoad(iAddress + 0x40, buffer[16], buffer[17], buffer[18], buffer[19]);
FLASH_BufLoad(iAddress + 0x50, buffer[20], buffer[21], buffer[22], buffer[23]);
FLASH_BufLoad(iAddress + 0x60, buffer[24], buffer[25], buffer[26], buffer[27]);
FLASH_BufLoad(iAddress + 0x70, buffer[28], buffer[29], buffer[30], buffer[31]);
FLASH_ProgramPage_Fast(iAddress);
if(iNumByteToWrite == secremain) //写入结束了
{
break;
}
else //不够写入,移到下一个扇区
{
secpos += 128;
if (secpos >= _end_addr)
{
return -1;
}
buf += secremain; //指针偏移
iAddress += secremain;//写地址偏移
iNumByteToWrite -= secremain; //字节数递减
if(iNumByteToWrite > 128) secremain = 128; //下一个扇区还是写不完
else secremain = iNumByteToWrite; //下一个扇区可以写完了
}
}
FLASH_Lock_Fast();
}