#include "flash.h" #include "stm32f10x_flash.h" #include "stm32f10x_rcc.h" #include "usart.h" #include "sysport.h" /******************************************************************************** * @file flash.c * @author 晏诚科技 Mr.Wang * @version V1.0.0 * @date 11-Dec-2018 * @brief 提供STM32内部flash相关驱动 ****************************************************************************** *******************************************************************************/ /**************************************************************************** * 名 称:void Read_Flash_Byte(uint32_t readAddr, uint8_t *p, uint16_t length) * 功 能:从FLASH的readAddr地址处读取readLen字节长度的数据到p地址的缓冲区中 * 入口参数: * @param1 readAddr 读FLASH起始地址 * @param2 *readBuf 读取数据缓冲区的地址 * @param3 readLen 需要读出字节数据的长度 * 出口参数:无 ****************************************************************************/ void Read_Flash_Byte(uint32_t readAddr, uint8_t *readBuf, uint16_t readLen) { while(readLen--) { *(readBuf++) = *((uint8_t*)readAddr++) ; } } /**************************************************************************** * 名 称:void Read_Flash_Byte(uint32_t readAddr, uint8_t *p, uint16_t length) * 功 能:从FLASH的readAddr地质处读取readLen半字超度的数据到p地址的缓冲区中 * 入口参数: * @param1 readAddr 读FLASH起始地址 * @param2 *readBuf 读取数据缓冲区的地址 * @param3 readLen 需要读出半字数据的长度 * 出口参数:无 ****************************************************************************/ void Read_Flash_HalfWord(u32 readAddr, u16 *readBuf, u16 readLen) { u16 i ; for(i=0;i=(FLASH_BASE+1024*FLASH_SIZE))) return (InParamErr) ;//非法地址 if( SET!= RCC_GetFlagStatus(RCC_FLAG_HSIRDY)) { SysErr("") ; //HSI被禁用,无法写或擦除FLASH! return (RUNERR ); } FLASH_Unlock(); //解锁 offaddr=WriteAddr-FLASH_BASE; //实际偏移地址. secpos=offaddr/FLASH_PAGE_SIZE; //扇区地址 0~127 for STM32F103RBT6 secoff=(offaddr%FLASH_PAGE_SIZE)/2; //在扇区内的偏移(2个字节为基本单位.) secremain=FLASH_PAGE_SIZE/2-secoff; //扇区剩余空间大小 if(writeLen<=secremain)secremain = writeLen;//不大于该扇区范围 while(1) { Read_Flash_HalfWord(secpos*FLASH_PAGE_SIZE+FLASH_BASE,STMFLASH_BUF,FLASH_PAGE_SIZE/2);//读出整个扇区的内容 for(i=0;i(FLASH_PAGE_SIZE/2))secremain=FLASH_PAGE_SIZE/2;//下一个扇区还是写不完 else secremain=writeLen;//下一个扇区可以写完了 } }; FLASH_Lock();//上锁 return (RUNOK ); } /**************************************************************************** * 名 称:RunResult Write_Flash_OnePage(uint32_t writePageAddr, uint8_t *writeBuf, uint16_t writeLen) * 外部引用:ErrorLogPrintf() * 功 能:向页起始地址写入数据,数据长度最多一页长度 * 入口参数: * @param1 writePageAddr 写入的页起始地址 * @param2 *writeBuf 需要写入FLASH中数据缓冲区的地址 * @param3 writeLen 需要写入数据的长度(最大值:FLASH_PAGE_SIZE) * 出口参数: * @param1 RunResult 反馈FLASH写入结果 * @arg RUNERR: FLASH编程错误 * @arg RUNOK: FLASH编程成功 * 说 明:对FLASH进行写入或者擦除需要使能HSI。 ****************************************************************************/ RunResult Write_Flash_OnePage(uint32_t writePageAddr, uint8_t *writeBuf, uint16_t writeLen) { uint16_t halfWord, timeOut = 0 ; writeLen = writeLen/2+(writeLen%2) ; //将length强制改变为2的倍数 if( SET!= RCC_GetFlagStatus(RCC_FLAG_HSIRDY)) { SysErr("") ; //HSI被禁用,无法写或擦除FLASH! return (RUNERR ); } FLASH_Unlock(); //FLASH解锁 if( (writePageAddr=(FLASH_BASE+FLASH_SIZE)) || (writePageAddr%FLASH_PAGE_SIZE != 0) ) //地址必须为页首地址且在FLASH地址范围内 非法地址 { SysErr("") ; //写入FLASH地址非法! FLASH_Lock(); //上锁 return (RUNERR ); } if( writeLen > FLASH_PAGE_SIZE)//写入的数据长度不能超过一页 { SysErr("") ; //写入FLASH长度超限! FLASH_Lock(); //上锁 return (RUNERR ); } FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);//清标志位 if( FLASH_COMPLETE != FLASH_ErasePage(writePageAddr)) //执行页擦除,并监测擦除状态 { SysErr("") ; //FLASH 页擦除失败! } for( timeOut=0; (SET == FLASH_GetFlagStatus(FLASH_FLAG_BSY)); timeOut++) { Wait_For_Nms(10) ; if( timeOut>10 ) { SysErr("") ; //写Flash忙等待超时! FLASH_Unlock(); //FLASH解锁 return (RUNERR); } } while(writeLen--) { FLASH_ClearFlag( FLASH_FLAG_EOP ) ; halfWord = *(writeBuf++); halfWord |= *(writeBuf++) << 8; FLASH_ProgramHalfWord(writePageAddr, halfWord); for( timeOut=0; ( SET != FLASH_GetFlagStatus(FLASH_FLAG_EOP) ); timeOut++) { Wait_For_Nms(10) ; if(timeOut>30) { SysErr("") ; //写Flash出错! return (RUNERR); } } writePageAddr += 2; } FLASH_Lock(); //上锁 return (RUNOK) ; } /**************************************************************************** * 名 称:RunResult Write_Flash(uint32_t writeAddr, uint8_t *writeBuf, uint16_t writeLen) * 功 能:向writeAddr地址写入长度writeLen数据 * 入口参数: * @param1 writeAddr 写入起始地址 * @param2 *writeBuf 需要写入FLASH中数据缓冲区的地址 * @param3 writeLen 需要写入数据的长度 * 出口参数: * @param1 RunResult 反馈FLASH写入结果 * @arg RUNERR: FLASH编程错误 * @arg RUNOK: FLASH编程成功 * 说 明:对FLASH进行写入或者擦除需要使能HSI。 ****************************************************************************/ RunResult Write_Flash(uint32_t writeAddr, uint8_t *writeBuf, uint16_t writeLen) { uint16_t index = 0, timeOut = 0, halfWord = 0 ; u32 writeOffset = 0 ; writeLen = writeLen/2+(writeLen%2) ; //将logLen强制改变为2的倍数 将logLen字节长度转为半字长度 if( SET!= RCC_GetFlagStatus(RCC_FLAG_HSIRDY)) { SysErr("") ; //HSI被禁用,无法写或擦除FLASH! return (RUNERR ); } FLASH_Unlock(); //FLASH解锁 FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);//清标志位 for( timeOut=0; (SET == FLASH_GetFlagStatus(FLASH_FLAG_BSY)); timeOut++) { Wait_For_Nms(50) ; if( timeOut>10 ) { SysErr("") ; //写Flash出错! FLASH_Unlock(); //FLASH解锁 return(RUNERR) ; } } while(writeLen--) { FLASH_ClearFlag( FLASH_FLAG_EOP ) ; halfWord = *(writeBuf+(index++)) ; //取uint16_t类型数据halfWord LSB halfWord |= *(writeBuf+(index++)) << 8 ; //取uint16_t类型数据halfWord HSB if( ( (writeAddr + writeOffset) % FLASH_PAGE_SIZE ) == 0 ) //写入地址为页首地址则擦除此页 { FLASH_ErasePage(writeAddr+writeOffset) ; } FLASH_ProgramHalfWord(writeAddr+writeOffset, halfWord) ; //地址偏移量先偏移后写,防止FLASH_ERROR_PG错误 writeOffset += 2; } FLASH_Lock(); //上锁 return(RUNOK) ; }