int flashPageErase(flashpage_t page){ /* Only write on pages in the user area */ if (!(FLASH_IS_ADDRESS_USERSPACE(FLASH_ADDRESS_OF_PAGE(page)))) return FLASH_RETURN_NO_PERMISSION; /* Unlock flash for write access */ if(flashUnlock() == CH_FAILED) return FLASH_RETURN_NO_PERMISSION; /* Wait for any busy flags. */ flashWaitWhileBusy(); /* Start deletion of page. */ FLASH->CR |= FLASH_CR_PER; FLASH->AR = FLASH_ADDRESS_OF_PAGE(page); FLASH->CR |= FLASH_CR_STRT; /* Wait until it's finished. */ flashWaitWhileBusy(); /* Page erase flag does not clear automatically. */ FLASH->CR &= !FLASH_CR_PER; /* Lock flash again */ flashLock(); /* Check deleted page for errors */ if(flashPageCheckErased(page) == FALSE) return FLASH_RETURN_BADFLASH; /* Page is not empty despite the erase cycle! */ /* Successfully deleted page */ return FLASH_RETURN_SUCCESS; }
int flashSectorErase(flashsector_t sector) { /* Unlock flash for write access */ if (flashUnlock() == CH_FAILED) return FLASH_RETURN_NO_PERMISSION; /* Wait for any busy flags. */ flashWaitWhileBusy(); /* Setup parallelism before any program/erase */ FLASH->CR &= ~FLASH_CR_PSIZE_MASK; FLASH->CR |= FLASH_CR_PSIZE_VALUE; /* Start deletion of sector. * SNB(3:1) is defined as: * 0000 sector 0 * 0001 sector 1 * ... * 1011 sector 11 * others not allowed */ FLASH->CR &= ~(FLASH_CR_SNB_0 | FLASH_CR_SNB_1 | FLASH_CR_SNB_2 | FLASH_CR_SNB_3); if (sector & 0x1) FLASH->CR |= FLASH_CR_SNB_0; if (sector & 0x2) FLASH->CR |= FLASH_CR_SNB_1; if (sector & 0x4) FLASH->CR |= FLASH_CR_SNB_2; if (sector & 0x8) FLASH->CR |= FLASH_CR_SNB_3; FLASH->CR |= FLASH_CR_SER; FLASH->CR |= FLASH_CR_STRT; /* Wait until it's finished. */ flashWaitWhileBusy(); /* Sector erase flag does not clear automatically. */ FLASH->CR &= ~FLASH_CR_SER; /* Lock flash again */ flashLock() ; /* Check deleted sector for errors */ if (flashIsErased(flashSectorBegin(sector), flashSectorSize(sector)) == FALSE) return FLASH_RETURN_BAD_FLASH; /* Sector is not empty despite the erase cycle! */ /* Successfully deleted sector */ return FLASH_RETURN_SUCCESS; }
int flashPageWrite(flashpage_t page, const flashdata_t* buffer){ volatile flashdata_t* const pageAddr = (flashdata_t*) FLASH_ADDRESS_OF_PAGE(page); /* Only write on pages in the user area */ if (!(FLASH_IS_ADDRESS_USERSPACE(FLASH_ADDRESS_OF_PAGE(page)))) return FLASH_RETURN_NO_PERMISSION; unsigned int pos; /* Unlock flash for write access */ if(flashUnlock() == CH_FAILED) return FLASH_RETURN_NO_PERMISSION; flashWaitWhileBusy(); for(pos = 0; pos < FLASH_PAGE_SIZE / sizeof(flashdata_t); pos++) { /* Enter flash programming mode. */ FLASH->CR |= FLASH_CR_PG; /* Write half-word to flash. */ pageAddr[pos] = buffer[pos]; /* Wait for completion */ flashWaitWhileBusy(); /* Exit flash programming mode. */ FLASH->CR &= ~FLASH_CR_PG; /* Check for flash error. */ if (pageAddr[pos] != buffer[pos]) return FLASH_RETURN_BADFLASH; } flashLock(); return 0; }
static void flashWriteData(flashaddr_t address, const flashdata_t data) { /* Enter flash programming mode */ FLASH->CR |= FLASH_CR_PG; /* Write the data */ *(flashdata_t*) address = data; /* Wait for completion */ flashWaitWhileBusy(); /* Exit flash programming mode */ FLASH->CR &= ~FLASH_CR_PG; }
int flashWrite(flashaddr_t address, const char* buffer, size_t size) { /* Unlock flash for write access */ if (flashUnlock() == CH_FAILED) return FLASH_RETURN_NO_PERMISSION; /* Wait for any busy flags */ flashWaitWhileBusy(); /* Setup parallelism before any program/erase */ FLASH->CR &= ~FLASH_CR_PSIZE_MASK; FLASH->CR |= FLASH_CR_PSIZE_VALUE; /* Check if the flash address is correctly aligned */ size_t alignOffset = address % sizeof(flashdata_t); // print("flash alignOffset=%d\r\n", alignOffset); if (alignOffset != 0) { /* Not aligned, thus we have to read the data in flash already present * and update them with buffer's data */ /* Align the flash address correctly */ flashaddr_t alignedFlashAddress = address - alignOffset; /* Read already present data */ flashdata_t tmp = *(volatile flashdata_t*) alignedFlashAddress; /* Compute how much bytes one must update in the data read */ size_t chunkSize = sizeof(flashdata_t) - alignOffset; if (chunkSize > size) chunkSize = size; // this happens when both address and address + size are not aligned /* Update the read data with buffer's data */ memcpy((char*) &tmp + alignOffset, buffer, chunkSize); /* Write the new data in flash */ flashWriteData(alignedFlashAddress, tmp); /* Advance */ address += chunkSize; buffer += chunkSize; size -= chunkSize; } /* Now, address is correctly aligned. One can copy data directly from * buffer's data to flash memory until the size of the data remaining to be * copied requires special treatment. */ while (size >= sizeof(flashdata_t)) { // print("flash write size=%d\r\n", size); flashWriteData(address, *(const flashdata_t*) buffer); address += sizeof(flashdata_t); buffer += sizeof(flashdata_t); size -= sizeof(flashdata_t); } /* Now, address is correctly aligned, but the remaining data are to * small to fill a entier flashdata_t. Thus, one must read data already * in flash and update them with buffer's data before writing an entire * flashdata_t to flash memory. */ if (size > 0) { flashdata_t tmp = *(volatile flashdata_t*) address; memcpy(&tmp, buffer, size); flashWriteData(address, tmp); } /* Lock flash again */ flashLock() ; return FLASH_RETURN_SUCCESS; }