mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-29 11:39:58 +02:00
The datasheet advises to wait for BSY to be cleared before performing any operation on the Flash. That being said, in the only two cases where BSY could be set in the first place (writing to or erasing the flash), we already wait for it to be cleared. There's therefore no need to double check it afterwards.
104 lines
2.3 KiB
C++
104 lines
2.3 KiB
C++
#include "flash.h"
|
|
#include <assert.h>
|
|
|
|
namespace Ion {
|
|
namespace Flash {
|
|
namespace Device {
|
|
|
|
static inline void wait() {
|
|
// Wait for pending Flash operations to complete
|
|
while (FLASH.SR()->getBSY()) {
|
|
}
|
|
}
|
|
|
|
static void open() {
|
|
// Unlock the Flash configuration register if needed
|
|
if (FLASH.CR()->getLOCK()) {
|
|
FLASH.KEYR()->set(0x45670123);
|
|
FLASH.KEYR()->set(0xCDEF89AB);
|
|
}
|
|
assert(FLASH.CR()->getLOCK() == false);
|
|
|
|
// Set the programming parallelism
|
|
FLASH.CR()->setPSIZE(MemoryAccessWidth);
|
|
}
|
|
|
|
static void close() {
|
|
// Lock the Flash configuration register
|
|
assert(!FLASH.CR()->getMER());
|
|
assert(!FLASH.CR()->getSER());
|
|
assert(!FLASH.CR()->getPG());
|
|
FLASH.CR()->setLOCK(true);
|
|
|
|
// Purge Data and instruction cache
|
|
if (FLASH.ACR()->getDCEN()) {
|
|
FLASH.ACR()->setDCEN(false);
|
|
FLASH.ACR()->setDCRST(true);
|
|
FLASH.ACR()->setDCRST(false);
|
|
FLASH.ACR()->setDCEN(true);
|
|
}
|
|
if (FLASH.ACR()->getICEN()) {
|
|
FLASH.ACR()->setICEN(false);
|
|
FLASH.ACR()->setICRST(true);
|
|
FLASH.ACR()->setICRST(false);
|
|
FLASH.ACR()->setICEN(true);
|
|
}
|
|
}
|
|
|
|
static void typed_memcpy(uint8_t * source, uint8_t * destination, size_t length) {
|
|
MemoryAccessType * src = reinterpret_cast<MemoryAccessType *>(source);
|
|
MemoryAccessType * dst = reinterpret_cast<MemoryAccessType *>(destination);
|
|
for (size_t i=0; i<length/sizeof(MemoryAccessType); i++) {
|
|
*dst++ = *src++;
|
|
}
|
|
}
|
|
|
|
int SectorAtAddress(uint32_t address) {
|
|
uint32_t sectorAddresses[NumberOfSectors] = {
|
|
0x08000000, 0x08004000, 0x08008000, 0x0800C000,
|
|
0x08010000, 0x08020000, 0x08040000, 0x08060000,
|
|
0x08080000, 0x080A0000, 0x080C0000, 0x080E0000
|
|
};
|
|
for (int i=0; i<NumberOfSectors; i++) {
|
|
if (sectorAddresses[i] == address) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
void MassErase() {
|
|
open();
|
|
FLASH.CR()->setMER(true);
|
|
FLASH.CR()->setSTRT(true);
|
|
wait();
|
|
FLASH.CR()->setMER(false);
|
|
close();
|
|
}
|
|
|
|
void EraseSector(int i) {
|
|
assert(i >= 0 && i < NumberOfSectors);
|
|
open();
|
|
FLASH.CR()->setSNB(i);
|
|
FLASH.CR()->setSER(true);
|
|
FLASH.CR()->setSTRT(true);
|
|
wait();
|
|
FLASH.CR()->setSNB(0);
|
|
FLASH.CR()->setSER(false);
|
|
close();
|
|
}
|
|
|
|
void WriteMemory(uint8_t * source, uint8_t * destination, size_t length) {
|
|
open();
|
|
FLASH.CR()->setPG(true);
|
|
typed_memcpy(source, destination, length);
|
|
wait();
|
|
FLASH.CR()->setPG(false);
|
|
close();
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|