#include "gd32f10x.h" #include "fmc.h" /*--------------------------------------------------*/ /*函数名:按页擦除FLASH */ /*参 数:start:擦除起始页 num:擦几个页 */ /*返回值:无 */ /* flash结构: 0x08000000~0x0807FFFF bank0(2KB一页,0~255页,共256页)共512KB 0x08080000~0x082FFFFF bank1(4KB一页,256~895页,共640页)共2.5MB 这个分区连续读内存需要有延时 */ /*-------------------------------------------------*/ void GD32_EraseFlash(uint16_t start, uint16_t num) { uint16_t i; //用于for循环 uint16_t j = 0; if ((start <= 896) && (start + num) > 896) { num = 896 - start; } else if (start > 896) { return; } fmc_unlock(); //解锁 if ((start < 256) && ((start + num) < 256)) { for(i = 0; i < num; i++) //循环num次,一个页一个页的擦除 { fmc_page_erase((0x08000000 + start * 2048) + (2048 * i)); //擦除bank0一个页2KB } } else if ((start < 256) && ((start + num) > 256)) { for(i = 0; i < num; i++) //循环num次,一个页一个页的擦除 { if((start + i) < 256) { fmc_page_erase((0x08000000 + start * 2 * 1024) + (2 * 1024 * i)); //擦除bank0一个页2KB } else { fmc_page_erase(0x08080000 + (4 * 1024 * j)); //擦除bank1一个页4KB j++; } } } else if (start > 256) { for(i = 0; i < num; i++) //循环num次,一个页一个页的擦除 { fmc_page_erase((0x08080000 + (start - 256) * 4 * 1024) + (4 * 1024 * i)); //擦除bank1一个页4KB } } fmc_lock(); //上锁 } /*---------------------------------------------------------------------*/ /*函数名:写入FLASH */ /*参 数:saddr:写入地址 wdata:写入数据指针 wnum:写入多少个字节 */ /*返回值:无 */ /*---------------------------------------------------------------------*/ void GD32_WriteFlash(uint32_t saddr, uint32_t *wdata, uint32_t wnum) { fmc_unlock(); //解锁 while(wnum){ //循环写入,知道num等于0退出while,表示写入完毕 fmc_word_program(saddr,*wdata); //写入一个字(4个字节) wnum-=4; //写入字节数量-4 saddr+=4; //写入地址+4 wdata++; //写入数据的指针,往后挪动一次 } fmc_lock(); //上锁 } // /** // * @brief 读取flash数据 // * // * @param rbuff 接收缓冲区 // * @param addr 起始地址,32位地址 // * @param datalen 数据长度,多少个字节 // */ // void GD32_ReadFlash(uint8_t *rbuff, uint32_t addr, uint32_t datalen) // { // memcpy(rbuff,addr,datalen); // } __align(4) static uint16_t FlashBuffer[GD32FLASH_PAGE_SIZE >> 1]; /// 初始化FLASH void FLASH_Init(void) { fmc_unlock(); fmc_flag_clear(FMC_FLAG_BANK0_END); fmc_flag_clear(FMC_FLAG_BANK0_WPERR); fmc_flag_clear(FMC_FLAG_BANK0_PGERR); fmc_lock(); } /** * 读FLASH * @param Address 地址 * @param Buffer 存放读取的数据 * @param Size 要读取的数据大小,单位字节 * @return 读出成功的字节数 */ uint32_t FLASH_Read(uint32_t Address, void *Buffer, uint32_t Size) { uint32_t nread = Size; uint8_t* d = (uint8_t *)Buffer; const uint8_t* s = (const uint8_t *)Address; if (!Buffer || Address < GD32FLASH_BASE || Address >= GD32FLASH_END) return 0; while (nread >= sizeof(uint32_t) && (((uint32_t)s) <= (GD32FLASH_END - 4))) { *(volatile uint32_t *)d = *(volatile uint32_t *)s; d += sizeof(uint32_t); s += sizeof(uint32_t); nread -= sizeof(uint32_t); } while (nread && (((uint32_t)s) < GD32FLASH_END)) { *d++ = *s++; nread--; } return Size - nread; } /** * 写FLASH * @param Address 写入起始地址,!!!要求2字节对齐!!! * @param Buffer 待写入的数据,!!!要求2字节对齐!!! * @param NumToWrite 要写入的数据量,单位:半字,!!!要求2字节对齐!!! * @return 实际写入的数据量,单位:字节 */ uint32_t FLASH_Write(uint32_t Address, const uint16_t *Buffer, uint32_t NumToWrite) { uint32_t i = 0; uint32_t pagepos = 0; // 页位置 uint32_t pageoff = 0; // 页内偏移地址 uint32_t pagefre = 0; // 页内空余空间 uint32_t offset = 0; // Address在FLASH中的偏移 uint32_t nwrite = NumToWrite; // 记录剩余要写入的数据量 const uint16_t *pBuffer = (const uint16_t *)Buffer; /* 非法地址 */ if (Address < GD32FLASH_BASE || Address > (GD32FLASH_END - 2) || NumToWrite == 0 || pBuffer == NULL) return 0; /* 解锁FLASH */ fmc_unlock(); /* 计算偏移地址 */ offset = Address - GD32FLASH_BASE; /* 计算当前页位置 */ pagepos = offset / GD32FLASH_PAGE_SIZE; /* 计算要写数据的起始地址在当前页内的偏移地址 */ pageoff = ((offset % GD32FLASH_PAGE_SIZE) >> 1); /* 计算当前页内空余空间 */ pagefre = ((GD32FLASH_PAGE_SIZE >> 1) - pageoff); /* 要写入的数据量低于当前页空余量 */ if (nwrite <= pagefre) pagefre = nwrite; while (nwrite != 0) { /* 检查是否超页 */ if (pagepos >= GD32FLASH_PAGE_NUM) break; /* 读取一页 */ FLASH_Read(GD32FLASH_BASE + pagepos * GD32FLASH_PAGE_SIZE, FlashBuffer, GD32FLASH_PAGE_SIZE); /* 检查是否需要擦除 */ for (i = 0; i < pagefre; i++) { if (*(FlashBuffer + pageoff + i) != 0xFFFF) /* FLASH擦出后默认内容全为0xFF */ break; } if (i < pagefre) { uint32_t count = 0; uint32_t index = 0; if(FLASH_ErasePage(GD32FLASH_BASE + pagepos * GD32FLASH_PAGE_SIZE, 1) < 0) break; /* 复制到缓存 */ for (index = 0; index < pagefre; index++) { *(FlashBuffer + pageoff + index) = *(pBuffer + index); } /* 写回FLASH */ count = FLASH_WriteNotErase(GD32FLASH_BASE + pagepos * GD32FLASH_PAGE_SIZE, FlashBuffer, GD32FLASH_PAGE_SIZE >> 1); if (count != (GD32FLASH_PAGE_SIZE >> 1)) { nwrite -= count; break; } } else { /* 无需擦除,直接写 */ uint32_t count = FLASH_WriteNotErase(Address, pBuffer, pagefre); if (count != pagefre) { nwrite -= count; break; } } pBuffer += pagefre; /* 读取地址递增 */ Address += (pagefre << 1); /* 写入地址递增 */ nwrite -= pagefre; /* 更新剩余未写入数据量 */ pagepos++; /* 下一页 */ pageoff = 0; /* 页内偏移地址置零 */ /* 根据剩余量计算下次写入数据量 */ pagefre = nwrite >= (GD32FLASH_PAGE_SIZE >> 1) ? (GD32FLASH_PAGE_SIZE >> 1) : nwrite; } /* 加锁FLASH */ fmc_lock(); return ((NumToWrite - nwrite) << 1); } uint32_t FLASH_WriteNotErase(uint32_t Address, const uint16_t *Buffer, uint32_t NumToWrite) { uint32_t nwrite = NumToWrite; uint32_t addrmax = GD32FLASH_END - 2; while (nwrite) { if (Address > addrmax) break; fmc_halfword_program(Address, *Buffer); if ((*(__IO uint16_t*) Address) != *Buffer) break; nwrite--; Buffer++; Address += 2; } return (NumToWrite - nwrite); } int FLASH_ErasePage(uint32_t PageAddress, uint32_t NbPages) { while(NbPages--) { if(fmc_page_erase(PageAddress) != FMC_READY) { return -1; } PageAddress += GD32FLASH_PAGE_SIZE; } return 0; }