关于读flash ,两款芯片关于读flash 操作一致,都可采用相同读操作
1 读操作
在通用地址空间内进行直接寻址,任何 8/16/32 位数据的读操作都能访问闪存模块的内容并得到
相应的数据。相应代码如下:
/**@brief FLASH读字节
*
* @param[in] Addr 指明地址
*
* @retval 返回字节数据
*/
INT8U bsp_flash_read_byte(INT32U Addr)
{
INT8U Temp;
Temp = (INT8U)(*((INT8U*)Addr));
return Temp;
}
INT32U bsp_flash_read_dword(INT32U Addr)
{
INT32U Temp;
Temp = (INT32U)(*((INT32U*)Addr));
return Temp;
}
INT16U bsp_flash_read_word(INT32U Addr)
{
INT16U Temp;
Temp = (INT16U)(*((INT32U*)Addr));
return Temp;
}
对于解锁闪存锁,两款芯片也是一致的,需要通过写入序列到特定寄存器才能进行解锁:
解除闪存锁
系统复位后,闪存控制器(FPEC)和 FLASH_CTLR 寄存器是被锁定的,不可访问。通过写入序列
到 FLASH_KEYR 寄存器可解锁闪存控制器模块。
解锁序列:
1) 向 FLASH_KEYR 寄存器写入 KEY1 = 0x45670123(第 1 步必须是 KEY1);
2) 向 FLASH_KEYR 寄存器写入 KEY2 = 0xCDEF89AB(第 2 步必须是 KEY2)。
上述操作必须按序并连续执行,否则属于错误操作,会锁死 FPEC 模块和 FLASH_CTLR 寄存器并产
生总线错误,直到下次系统复位。
闪存控制器(FPEC)和 FLASH_CTLR 寄存器可以通过将 FLASH_CTLR 寄存器的“LOCK”位,置 1 来
再次锁定。
/* Flash Operation Key */
volatile uint32_t Flash_Operation_Key0;
volatile uint32_t Flash_Operation_Key1;
/* Verify Keys, No flash operation if keys are not correct */
if((Flash_Operation_Key0 != DEF_FLASH_OPERATION_KEY_CODE_0) || (Flash_Operation_Key1 != DEF_FLASH_OPERATION_KEY_CODE_1))
{
/* ERR: Risk of code running away */
return 0xFF;
}
对于写入flash操作,V203和0x35有不一样的差别
V203主存储器标准编程 2字节,4字节:
标准编程每次可以写入 2 字节。当 FLASH_CTLR 寄存器的 PG 位为‘1’时,每次向闪存地址写入
半字(2 字节)将启动一次编程,写入任何非半字数据,FPEC 都会产生总线错误。编程过程中,BSY
位为‘1’,编程结束,BSY 位为‘0’,EOP 位为‘1’。
注:当 BSY 位为‘1’时,将禁止对任何寄存器执行写操作。
代码如下:
INT32U bsp_flash_write_dword(INT32U Addr, INT32U Data)
{
FLASH_Status status = FLASH_COMPLETE;
status = FLASH_ProgramWord(Addr, Data);
return (status == FLASH_COMPLETE) ? 1 : 0;
}
INT16U bsp_flash_write_word(INT32U Addr, INT16U Data)
{
FLASH_Status status = FLASH_COMPLETE;
status = FLASH_ProgramHalfWord(Addr, Data);
return (status == FLASH_COMPLETE) ? 1 : 0;
}
V203主存储器快速编程 256B:
/*********************************************************************
* @fn FLASH_ProgramPage_Fast
*
* @brief Program a specified FLASH page (1page = 256Byte).
*
* @param Page_Address - The page address to be programed.
*
* @return none
*/
void FLASH_ProgramPage_Fast(uint32_t Page_Address, uint32_t *pbuf)
{
uint8_t size = 64;
Page_Address &= 0xFFFFFF00;
FLASH->CTLR |= CR_PAGE_PG;
while(FLASH->STATR & SR_BSY);
while(FLASH->STATR & SR_WR_BSY);
while(size)
{
*(uint32_t *)Page_Address = *(uint32_t *)pbuf;
Page_Address += 4;
pbuf += 1;
size -= 1;
while(FLASH->STATR & SR_WR_BSY);
}
FLASH->CTLR |= CR_PG_STRT;
while(FLASH->STATR & SR_BSY);
FLASH->CTLR &= ~CR_PAGE_PG;
}
V203主存储器标准擦除:
闪存可以擦除256B,4K,32K
/*********************************************************************
* @fn ROM_ERASE
*
* @brief Select erases a specified FLASH .
*
* @param StartAddr - Erases Flash start address(StartAddr%256 == 0).
* Cnt - Erases count.
* Erase_Size - Erases size select.The returned value can be:
* Size_32KB, Size_4KB, Size_256B.
*
* @return none.
*/
static void ROM_ERASE(uint32_t StartAddr, uint32_t Cnt, uint32_t Erase_Size)
{
do{
if(Erase_Size == Size_32KB)
{
FLASH->CTLR |= CR_BER32;
}
else if(Erase_Size == Size_4KB)
{
FLASH->CTLR |= CR_PER_Set;
}
else if(Erase_Size == Size_256B)
{
FLASH->CTLR |= CR_PAGE_ER;
}
FLASH->ADDR = StartAddr;
FLASH->CTLR |= CR_STRT_Set;
while(FLASH->STATR & SR_BSY)
;
if(Erase_Size == Size_32KB)
{
FLASH->CTLR &= ~CR_BER32;
StartAddr += Size_32KB;
}
else if(Erase_Size == Size_4KB)
{
FLASH->CTLR &= ~CR_PER_Set;
StartAddr += Size_4KB;
}
else if(Erase_Size == Size_256B)
{
FLASH->CTLR &= ~CR_PAGE_ER;
StartAddr += Size_256B;
}
}while(--Cnt);
}
闪存可以擦除256B的倍数
/*********************************************************************
* @fn FLASH_ROM_ERASE
*
* @brief Erases a specified FLASH .
*
* @param StartAddr - Erases Flash start address(StartAddr%256 == 0).
* Length - Erases Flash start Length(Length%256 == 0).
*
* @return FLASH Status - The returned value can be: FLASH_ADR_RANGE_ERROR,
* FLASH_ALIGN_ERROR, FLASH_OP_RANGE_ERROR or FLASH_COMPLETE.
*/
FLASH_Status FLASH_ROM_ERASE(uint32_t StartAddr, uint32_t Length)
{
uint32_t Addr0 = 0, Addr1 = 0, Length0 = 0, Length1 = 0;
FLASH_Status status = FLASH_COMPLETE;
if((StartAddr < ValidAddrStart) || (StartAddr >= ValidAddrEnd))
{
return FLASH_ADR_RANGE_ERROR;
}
if((StartAddr + Length) > ValidAddrEnd)
{
return FLASH_OP_RANGE_ERROR;
}
if((StartAddr & (Size_256B-1)) || (Length & (Size_256B-1)) || (Length == 0))
{
return FLASH_ALIGN_ERROR;
}
/* Authorize the FPEC of Bank1 Access */
FLASH->KEYR = FLASH_KEY1;
FLASH->KEYR = FLASH_KEY2;
/* Fast mode unlock */
FLASH->MODEKEYR = FLASH_KEY1;
FLASH->MODEKEYR = FLASH_KEY2;
Addr0 = StartAddr;
if(Length >= Size_32KB)
{
Length0 = Size_32KB - (Addr0 & (Size_32KB - 1));
Addr1 = StartAddr + Length0;
Length1 = Length - Length0;
}
else if(Length >= Size_4KB)
{
Length0 = Size_4KB - (Addr0 & (Size_4KB - 1));
Addr1 = StartAddr + Length0;
Length1 = Length - Length0;
}
else if(Length >= Size_256B)
{
Length0 = Length;
}
/* Erase 32KB */
if(Length0 >= Size_32KB)//front
{
Length = Length0;
if(Addr0 & (Size_32KB - 1))
{
Length0 = Size_32KB - (Addr0 & (Size_32KB - 1));
}
else
{
Length0 = 0;
}
ROM_ERASE((Addr0 + Length0), ((Length - Length0) >> 15), Size_32KB);
}
if(Length1 >= Size_32KB)//back
{
StartAddr = Addr1;
Length = Length1;
if((Addr1 + Length1) & (Size_32KB - 1))
{
Addr1 = ((StartAddr + Length1) & (~(Size_32KB - 1)));
Length1 = (StartAddr + Length1) & (Size_32KB - 1);
}
else
{
Length1 = 0;
}
ROM_ERASE(StartAddr, ((Length - Length1) >> 15), Size_32KB);
}
/* Erase 4KB */
if(Length0 >= Size_4KB) //front
{
Length = Length0;
if(Addr0 & (Size_4KB - 1))
{
Length0 = Size_4KB - (Addr0 & (Size_4KB - 1));
}
else
{
Length0 = 0;
}
ROM_ERASE((Addr0 + Length0), ((Length - Length0) >> 12), Size_4KB);
}
if(Length1 >= Size_4KB) //back
{
StartAddr = Addr1;
Length = Length1;
if((Addr1 + Length1) & (Size_4KB - 1))
{
Addr1 = ((StartAddr + Length1) & (~(Size_4KB - 1)));
Length1 = (StartAddr + Length1) & (Size_4KB - 1);
}
else
{
Length1 = 0;
}
ROM_ERASE(StartAddr, ((Length - Length1) >> 12), Size_4KB);
}
/* Erase 256B */
if(Length0)//front
{
ROM_ERASE(Addr0, (Length0 >> 8), Size_256B);
}
if(Length1)//back
{
ROM_ERASE(Addr1, (Length1 >> 8), Size_256B);
}
FLASH->CTLR |= CR_FLOCK_Set;
FLASH->CTLR |= CR_LOCK_Set;
return status;
}
V203主存储器快速擦除:
闪存可以按256字节,4K,32K,64K字节擦除,也可以整片擦除
代码如下:
/*********************************************************************
* @fn FLASH_ErasePage_Fast
*
* @brief Erases a specified FLASH page (1page = 256Byte).
*
* @param Page_Address - The page address to be erased.
*
* @return none
*/
void FLASH_ErasePage_Fast(uint32_t Page_Address)
{
Page_Address &= 0xFFFFFF00;
FLASH->CTLR |= CR_PAGE_ER;
FLASH->ADDR = Page_Address;
FLASH->CTLR |= CR_STRT_Set;
while(FLASH->STATR & SR_BSY);
FLASH->CTLR &= ~CR_PAGE_ER;
}
/*********************************************************************
* @fn FLASH_EraseBlock_32K_Fast
*
* @brief Erases a specified FLASH Block (1Block = 32KByte).
*
* @param Block_Address - The block address to be erased.
*
* @return none
*/
void FLASH_EraseBlock_32K_Fast(uint32_t Block_Address)
{
Block_Address &= 0xFFFF8000;
FLASH->CTLR |= CR_BER32;
FLASH->ADDR = Block_Address;
FLASH->CTLR |= CR_STRT_Set;
while(FLASH->STATR & SR_BSY);
FLASH->CTLR &= ~CR_BER32;
}
/*********************************************************************
* @fn FLASH_EraseBlock_64K_Fast
*
* @brief Erases a specified FLASH Block (1Block = 64KByte).
*
* @param Block_Address - The block address to be erased.
*
* @return none
*/
void FLASH_EraseBlock_64K_Fast(uint32_t Block_Address)
{
Block_Address &= 0xFFFF0000;
FLASH->CTLR |= CR_BER64;
FLASH->ADDR = Block_Address;
FLASH->CTLR |= CR_STRT_Set;
while(FLASH->STATR & SR_BSY);
FLASH->CTLR &= ~CR_BER64;
}
而在x035这款芯片当中,仅仅只保留了标准的flash函数进行flash 编程
X035主存储器标准编程:
闪存只能写入256B的倍数大小
/*********************************************************************
* @fn FLASH_ROM_WRITE
*
* @brief Writes a specified FLASH .
*
* @param StartAddr - Writes Flash start address(StartAddr%256 == 0).
* Length - Writes Flash start Length(Length%256 == 0).
* pbuf - Writes Flash value buffer.
*
* @return FLASH Status - The returned value can be: FLASH_ADR_RANGE_ERROR,
* FLASH_ALIGN_ERROR, FLASH_OP_RANGE_ERROR or FLASH_COMPLETE.
*/
FLASH_Status FLASH_ROM_WRITE(uint32_t StartAddr, uint32_t *pbuf, uint32_t Length)
{
uint32_t i, adr;
uint8_t size;
FLASH_Status status = FLASH_COMPLETE;
if((StartAddr < ValidAddrStart) || (StartAddr >= ValidAddrEnd))
{
return FLASH_ADR_RANGE_ERROR;
}
if((StartAddr + Length) > ValidAddrEnd)
{
return FLASH_OP_RANGE_ERROR;
}
if((StartAddr & (Size_256B-1)) || (Length & (Size_256B-1)) || (Length == 0))
{
return FLASH_ALIGN_ERROR;
}
adr = StartAddr;
i = Length >> 8;
/* Authorize the FPEC of Bank1 Access */
FLASH->KEYR = FLASH_KEY1;
FLASH->KEYR = FLASH_KEY2;
/* Fast program mode unlock */
FLASH->MODEKEYR = FLASH_KEY1;
FLASH->MODEKEYR = FLASH_KEY2;
FLASH->CTLR &= (CR_OPTER_Reset & CR_PAGE_ER_Reset);
do{
FLASH->CTLR |= CR_PAGE_PG;
FLASH->CTLR |= CR_BUF_RST;
while(FLASH->STATR & SR_BSY)
;
size = 64;
while(size)
{
*(uint32_t *)StartAddr = *(uint32_t *)pbuf;
FLASH->CTLR |= CR_BUF_LOAD;
while(FLASH->STATR & SR_BSY)
;
StartAddr += 4;
pbuf += 1;
size -= 1;
}
FLASH->ADDR = adr;
FLASH->CTLR |= CR_STRT_Set;
while(FLASH->STATR & SR_BSY)
;
FLASH->CTLR &= ~CR_PAGE_PG;
adr += 256;
}while(--i);
FLASH->CTLR |= CR_FLOCK_Set;
FLASH->CTLR |= CR_LOCK_Set;
return status;
}
还有一个4字节的flash写入函数FLASH_BufLoad
,FLASH_BufLoad
函数中使用了CR_PAGE_PG
(页编程模式)和CR_BUF_LOAD
(缓冲区加载)等控制位,这些操作通常用于页编程的中间步骤(例如先加载数据到缓冲区,再批量写入整页),而非独立的 4 字节写入。所以FLASH_BufLoad
函数不能单独用于写入 4 字节 FLASH,它需要配合页编程的完整流程(解锁、擦除、页数据加载、编程启动等)使用。
/*********************************************************************
* @fn FLASH_BufLoad
*
* @brief Flash Buffer load(4Byte).
*
* @param Address - specifies the address to be programmed.
* Data0 - specifies the data0 to be programmed.
*
* @return none
*/
void FLASH_BufLoad(uint32_t Address, uint32_t Data0)
{
FLASH->CTLR &= (CR_OPTER_Reset & CR_PAGE_ER_Reset);
FLASH->CTLR |= CR_PAGE_PG;
*(__IO uint32_t *)(Address) = Data0;
FLASH->CTLR |= CR_BUF_LOAD;
while(FLASH->STATR & SR_BSY)
;
FLASH->CTLR &= ~CR_PAGE_PG;
}
X035主存储器标准擦除:
256B,1K,32K擦除
/*********************************************************************
* @fn ROM_ERASE
*
* @brief Select erases a specified FLASH .
*
* @param StartAddr - Erases Flash start address(StartAddr%256 == 0).
* Cnt - Erases count.
* Erase_Size - Erases size select.The returned value can be:
* Size_32KB, Size_1KB, Size_256B.
*
* @return none.
*/
static void ROM_ERASE(uint32_t StartAddr, uint32_t Cnt, uint32_t Erase_Size)
{
FLASH->CTLR &= (CR_OPTER_Reset & CR_PAGE_ER_Reset);
do{
if(Erase_Size == Size_32KB)
{
FLASH->CTLR |= CR_BER32;
}
else if(Erase_Size == Size_1KB)
{
FLASH->CTLR |= CR_PER_Set;
}
else if(Erase_Size == Size_256B)
{
FLASH->CTLR |= CR_PAGE_ER;
}
FLASH->ADDR = StartAddr;
FLASH->CTLR |= CR_STRT_Set;
while(FLASH->STATR & SR_BSY)
;
if(Erase_Size == Size_32KB)
{
FLASH->CTLR &= ~CR_BER32;
StartAddr += Size_32KB;
}
else if(Erase_Size == Size_1KB)
{
FLASH->CTLR &= ~CR_PER_Set;
StartAddr += Size_1KB;
}
else if(Erase_Size == Size_256B)
{
FLASH->CTLR &= ~CR_PAGE_ER;
StartAddr += Size_256B;
}
}while(--Cnt);
}
256B倍数擦除
/*********************************************************************
* @fn FLASH_ROM_ERASE
*
* @brief Erases a specified FLASH .
*
* @param StartAddr - Erases Flash start address(StartAddr%256 == 0).
* Length - Erases Flash start Length(Length%256 == 0).
*
* @return FLASH Status - The returned value can be: FLASH_ADR_RANGE_ERROR,
* FLASH_ALIGN_ERROR, FLASH_OP_RANGE_ERROR or FLASH_COMPLETE.
*/
FLASH_Status FLASH_ROM_ERASE(uint32_t StartAddr, uint32_t Length)
{
uint32_t Addr0 = 0, Addr1 = 0, Length0 = 0, Length1 = 0;
FLASH_Status status = FLASH_COMPLETE;
if((StartAddr < ValidAddrStart) || (StartAddr >= ValidAddrEnd))
{
return FLASH_ADR_RANGE_ERROR;
}
if((StartAddr + Length) > ValidAddrEnd)
{
return FLASH_OP_RANGE_ERROR;
}
if((StartAddr & (Size_256B-1)) || (Length & (Size_256B-1)) || (Length == 0))
{
return FLASH_ALIGN_ERROR;
}
/* Authorize the FPEC of Bank1 Access */
FLASH->KEYR = FLASH_KEY1;
FLASH->KEYR = FLASH_KEY2;
/* Fast mode unlock */
FLASH->MODEKEYR = FLASH_KEY1;
FLASH->MODEKEYR = FLASH_KEY2;
Addr0 = StartAddr;
if(Length >= Size_32KB)
{
Length0 = Size_32KB - (Addr0 & (Size_32KB - 1));
Addr1 = StartAddr + Length0;
Length1 = Length - Length0;
}
else if(Length >= Size_1KB)
{
Length0 = Size_1KB - (Addr0 & (Size_1KB - 1));
Addr1 = StartAddr + Length0;
Length1 = Length - Length0;
}
else if(Length >= Size_256B)
{
Length0 = Length;
}
/* Erase 32KB */
if(Length0 >= Size_32KB)//front
{
Length = Length0;
if(Addr0 & (Size_32KB - 1))
{
Length0 = Size_32KB - (Addr0 & (Size_32KB - 1));
}
else
{
Length0 = 0;
}
ROM_ERASE((Addr0 + Length0), ((Length - Length0) >> 15), Size_32KB);
}
if(Length1 >= Size_32KB)//back
{
StartAddr = Addr1;
Length = Length1;
if((Addr1 + Length1) & (Size_32KB - 1))
{
Addr1 = ((StartAddr + Length1) & (~(Size_32KB - 1)));
Length1 = (StartAddr + Length1) & (Size_32KB - 1);
}
else
{
Length1 = 0;
}
ROM_ERASE(StartAddr, ((Length - Length1) >> 15), Size_32KB);
}
/* Erase 1KB */
if(Length0 >= Size_1KB) //front
{
Length = Length0;
if(Addr0 & (Size_1KB - 1))
{
Length0 = Size_1KB - (Addr0 & (Size_1KB - 1));
}
else
{
Length0 = 0;
}
ROM_ERASE((Addr0 + Length0), ((Length - Length0) >> 10), Size_1KB);
}
if(Length1 >= Size_1KB) //back
{
StartAddr = Addr1;
Length = Length1;
if((Addr1 + Length1) & (Size_1KB - 1))
{
Addr1 = ((StartAddr + Length1) & (~(Size_1KB - 1)));
Length1 = (StartAddr + Length1) & (Size_1KB - 1);
}
else
{
Length1 = 0;
}
ROM_ERASE(StartAddr, ((Length - Length1) >> 10), Size_1KB);
}
/* Erase 256B */
if(Length0)//front
{
ROM_ERASE(Addr0, (Length0 >> 8), Size_256B);
}
if(Length1)//back
{
ROM_ERASE(Addr1, (Length1 >> 8), Size_256B);
}
FLASH->CTLR |= CR_FLOCK_Set;
FLASH->CTLR |= CR_LOCK_Set;
return status;
}
X035主存储器快速擦除:
256B,32K
/*********************************************************************
* @fn FLASH_ErasePage_Fast
*
* @brief Erases a specified FLASH page (1page = 256Byte).
*
* @param Page_Address - The page address to be erased.
*
* @return none
*/
void FLASH_ErasePage_Fast(uint32_t Page_Address)
{
FLASH->CTLR &= (CR_OPTER_Reset & CR_PAGE_ER_Reset);
FLASH->CTLR |= CR_PAGE_ER;
FLASH->ADDR = Page_Address;
FLASH->CTLR |= CR_STRT_Set;
while(FLASH->STATR & SR_BSY)
;
FLASH->CTLR &= ~CR_PAGE_ER;
}
/*********************************************************************
* @fn FLASH_EraseBlock_32K_Fast
*
* @brief Erases a specified FLASH Block (1Block = 32KByte).
*
* @param Block_Address - The block address to be erased.
*
* @return none
*/
void FLASH_EraseBlock_32K_Fast(uint32_t Block_Address)
{
FLASH->CTLR &= (CR_OPTER_Reset & CR_PAGE_ER_Reset);
Block_Address &= 0xFFFF8000;
FLASH->CTLR |= CR_BER32;
FLASH->ADDR = Block_Address;
FLASH->CTLR |= CR_STRT_Set;
while(FLASH->STATR & SR_BSY)
;
FLASH->CTLR &= ~CR_BER32;
}
好的,关于v203和0x35两款芯片的flash擦除和写入基本上就是这些函数,基本上分为标准和快速,在快速模式下,flash写入和擦除速度会比标准模式快上许多,适合在高速率通信下使用,两款芯片使用flash的读、写、擦除函数大部分一致,如果想要看具体如何使用,可以去沁恒官方下载案例分析。在不同场景下合理利用这些函数,能够使工作效率大大提升。