#include "st_sys.h" #include "st_flash.h" #include "hardware_delay.h" typedef struct { uint32_t addr; uint32_t size; } st_flash_page_info; /** * FLASH页分块表 * * @author lxz (121319 18:16:08) */ static const st_flash_page_info page_infos[] = { { ST_FLASH_SECTOR_0, 24 * 1024}, { ST_FLASH_SECTOR_2, 16 * 1024}, { ST_FLASH_SECTOR_3, 4 * 1024}, { ST_FLASH_SECTOR_5, 212 * 1024 } }; /** * flash 操作解锁 * * @author lxz (2019/5/30/鍛ㄥ洓) * * @param void */ void st_flash_unlock(void) { if (FLASH->CR & (1 << 7)) { FLASH->KEYR = FLASH_KEY1; FLASH->KEYR = FLASH_KEY2; } //清除错误标志位 FLASH->SR = FLASH_SR_PGERR |FLASH_SR_WRPRTERR; } /** * flash操作 上锁 * * @author lxz (2019/5/30/鍛ㄥ洓) * * @param void */ void st_flash_lock(void) { FLASH->CR |= ((uint32_t)1) << 7; //Bank1,涓婇攣 } /** * 获取flash状态 * * @author LXZ (121819) * * @return int */ int st_flash_error_no(void) { int res = 0; res = FLASH->SR; if (res & (1 << 0)) return 1; //忙 else if (res & (1 << 2)) return 2; //页面错误 else if (res & (1 << 4)) return 3; //写保护 return 0; //没有任何状态/操作完成 } int flash_last_wait_time = 0; /** * 等待操作完成 * * @author lxz (2019/5/30/鍛ㄥ洓) * * @param bankx * @param time 等待时间 */ int st_flash_wait_done(int time) { int res = 0; do { res = st_flash_error_no(); if (res != 1) break; //非忙,无需等待了,直接退出. hw_delay_us(1); time--; }while (time); if (time == 0) res = 0xff; //TIMEOUT flash_last_wait_time = time; return res; } /** *擦除扇区 * * @author lxz (2019/5/30/鍛ㄥ洓) * * @param sector_no * * @return int */ int st_flash_erase_secotr(uint8_t sector_no) { int res = 0; int number = 0; int blockNumber = page_infos[sector_no].size; uint32_t addr = page_infos[sector_no].addr; int page_size = 1024; //FLASH->ACR &= ~(1 << 4); res = st_flash_wait_done(20000); //绛夊緟涓婃鎿嶄綔缁撴潫,鏈澶?s if (__ST_FLASH_SIZE >= 0x100) { page_size = 2048; } blockNumber /= page_size; while (res == 0 && number < blockNumber) { //FLASH->CR&=~(3<<8); //清除PSIZE原来的设置 //FLASH->CR|=2<<8; //设置为32bit宽,确保VCC=2.7~3.6V之间!! //FLASH->CR&=~(0X1F<<3);//清除原来的设置 //FLASH->CR|=sector_no<<3;//设置要擦除的扇区 FLASH->CR |= 1 << 1; //扇区擦除 FLASH->AR = addr; FLASH->CR |= 1 << 6; //开始擦除 res = st_flash_wait_done(20000); //等待操作结束,最大2s if (res != 1) { //非忙 FLASH->CR &= ~(1 << 1); //清除扇区擦除标志. } number++; addr += page_size; } //FLASH->ACR |= (1 << 4); return res; } /** * 往指定地址写入一个字,地址必须保证字对齐 * * @author lxz (2019/5/30/鍛ㄥ洓) * * @param faddr * @param pdata * * @return int */ int st_flash_write_flash_word(uint32_t faddr, uint32_t pdata) { u8 res; res = st_flash_wait_done(0XFF); if (res == 0) { //OK FLASH->CR |= 1 << 0; *(vu16 *)faddr = pdata; res = st_flash_wait_done(0XFF); if (res == 0) { FLASH->CR &= ~(1 << 0); } } res = st_flash_wait_done(0XFF); faddr += 2; pdata >>= 16; if (res == 0) { FLASH->CR |= 1 << 0; *(vu16 *)faddr = pdata; res = st_flash_wait_done(0XFF); if (res == 0) { FLASH->CR &= ~(1 << 0); } } return res; } int st_flash_write_half_word(uint32_t faddr, uint16_t pdata) { u8 res; res = st_flash_wait_done(0XFF); if (res == 0) { //OK FLASH->CR |= 1 << 0; *(vu16 *)faddr = pdata; res = st_flash_wait_done(0XFF); if (res == 0) { FLASH->CR &= ~(1 << 0); } } return res; } /** * 读取指定地址一个32位数据 * * @author LXZ (121819) * * @param faddr * * @return uint32_t */ uint32_t st_flash_read_word(uint32_t faddr) { return *(vu32 *)faddr; } /** * 閫氳繃鍦板潃鑾峰彇鎵鍦ㄧ殑鎵囧尯鍙? * * @author lxz (2019/5/30/鍛ㄥ洓) * * @param addr * * @return uint8_t */ uint8_t st_flash_addr_to_sector_no(uint32_t addr) { int i = 0; while ((page_infos[i].addr + page_infos[i].size) <= addr && i < (sizeof(page_infos) / sizeof(st_flash_page_info))) { //计算块大小是否已经包含了地址 i++; } return i; } /** * 向指定地址写入32位数据 * * @author LXZ (121819) * * @param addr * @param buffer * @param length * * @return int */ int st_flash_write(uint32_t addr, uint32_t *buffer, uint32_t length) { int status = 0; uint32_t addrx = 0; uint32_t endaddr = 0; if (addr < STM32_FLASH_BASE || addr % 4) return 1; //非法地址 st_flash_unlock(); //解锁 //FLASH->ACR &= ~(1 << 10); //FLASH擦除期间,必须禁止数据缓存!!!搞了我两晚上才发现这个问题! addrx = addr; //写入的起始地址 endaddr = addr + length * 4; //写入的结束地址 if (addrx < 0X1FFF0000) { //只有主存储区,才需要执行擦除操作!! while (addrx < endaddr) { //扫清一切障碍.(对非FFFFFFFF的地方,先擦除) if (st_flash_read_word(addrx) != 0XFFFFFFFF) { //有非0XFFFFFFFF的地方,要擦除这个扇区 status = st_flash_erase_secotr(st_flash_addr_to_sector_no(addrx)); if (status) break; //发生错误了 } else addrx += 4; } } if (status == 0) { uint16_t * dat = (uint16_t *)buffer; while (addr < endaddr) { if (st_flash_write_half_word(addr, *dat)) { //写入数据 break; //写入异常 } //sw_timer_now(&timer); addr += 2; dat++; } /* while (addr < endaddr) { //写数据 //sw_timer_now(&timer2); if (st_flash_write_flash_word(addr, *buffer)) { //写入数据 break; //写入异常 } //sw_timer_now(&timer); addr += 4; buffer++; } */ } else { while (1); } //FLASH->ACR |= 1 << 10; //FLASH擦除结束,开启数据fetch st_flash_lock(); //上锁 return 0; } /** * 读取指定长度的32位数据 * * @author LXZ (121819) * * @param addr * @param buffer * @param length */ void st_flash_read(uint32_t addr, uint32_t *buffer, uint32_t length) { int i; for (i = 0; i < length; i++) { buffer[i] = st_flash_read_word(addr); addr += 4; } }