rotl_quotes/FlashStorage.cpp

143 lines
3.9 KiB
C++

/*
* File: FlashStorage.cpp
* Author: amr
*
* Created on October 1, 2020, 5:03 PM
*/
#include "FlashStorage.hpp"
FlashStorage::FlashStorage(FIFO *fifobuffer, UART *serialBus) {
buffer = fifobuffer;
serial = serialBus;
}
void FlashStorage::enableFlashWrite(void) {
// enable writing
PORTACLR = 0x10; // set CS low
while(SPI1STAT & 0x02); // wait for buffer to be empty
SPI1BUF = 0x06; // send WREN
PORTASET = 0x10; // set CS high
return;
}
uint8_t FlashStorage::readStatusRegister(void) {
uint8_t statusReg = 0;
uint32_t rxBufSize = 0;
PORTACLR = 0x10; // set CS low
while(SPI1STAT & 0x02); // wait for buffer to be empty
SPI1BUF = 0x05;
while(SPI1STAT & 0x02);
SPI1BUF = 0xFF;
while(!(SPI1STAT & 0x01)); // wait for byte
statusReg = SPI1BUF;
PORTASET = 0x10;
if(statusReg & 0x01) {
return FLASH_BUSY;
} else if(statusReg & 0x20) {
return FLASH_ERASE_ERROR;
} else if(statusReg & 0x40) {
return FLASH_PROG_ERROR;
} else {
return FLASH_OKAY;
}
}
void FlashStorage::sectorErase(uint8_t sector) {
const uint8_t sectorTable[] = { 0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C, 0x20 };
sector = sectorTable[sector]; // convert sector number to address prefix
// erase sectors
PORTACLR = 0x10; // set CS low
while(SPI1STAT & 0x02); // wait for buffer to be empty
SPI1BUF = 0xD8; // send sector erase
while(SPI1STAT & 0x02);
SPI1BUF = sector;
while(SPI1STAT & 0x02);
SPI1BUF = 0x00;
while(SPI1STAT & 0x02);
SPI1BUF = 0x00;
while(SPI1STAT & 0x02);
PORTASET = 0x10; // set CS high
// we need to wait for the erase
while(readStatusRegister() != FLASH_OKAY) ;
// this might end up crashing if there's an error, but... whatever
}
uint8_t FlashStorage::read(uint32_t addr, uint32_t length) {
uint8_t readByte = 0;
PORTACLR = 0x10; // set CS low
while(SPI1STAT & 0x02); // wait for buffer to be empty
readByte = SPI1BUF;
SPI1BUF = 0x03;
while(SPI1STAT & 0x02);
readByte = SPI1BUF;
SPI1BUF = (uint8_t)((addr >> 16) & 0x000000FF);
while(SPI1STAT & 0x02);
readByte = SPI1BUF;
SPI1BUF = (uint8_t)((addr >> 8) & 0x000000FF);
while(SPI1STAT & 0x02);
readByte = SPI1BUF;
SPI1BUF = (uint8_t)((addr) & 0x000000FF);
while(SPI1STAT & 0x02);
for(uint32_t i = 0; i < length; i++) {
SPI1BUF = 0xFF;
while(!(SPI1STAT & 0x01));
readByte = SPI1BUF;
if(buffer->write(readByte) == 0) {
return 0;
}
}
PORTASET = 0x10; // set CS high
return length;
}
uint8_t FlashStorage::write(uint32_t addr, uint32_t length, uint8_t *data) {
enableFlashWrite();
// send address and data
PORTACLR = 0x10; // set CS low
while(SPI1STAT & 0x02); // wait for buffer to be empty
SPI1BUF = 0x02;
while(SPI1STAT & 0x02);
SPI1BUF = (uint8_t)((addr >> 16) & 0x000000FF);
while(SPI1STAT & 0x02);
SPI1BUF = (uint8_t)((addr >> 8) & 0x000000FF);
while(SPI1STAT & 0x02);
SPI1BUF = (uint8_t)((addr) & 0x000000FF);
for(uint32_t i = 0; i < length; i++) {
while(SPI1STAT & 0x02);
SPI1BUF = *(data + i);
}
PORTASET = 0x10; // set CS high
while(readStatusRegister() != FLASH_OKAY) ; // wait for programming
return 0;
}
uint8_t FlashStorage::program(void) {
const uint8_t readySend = 0x33;
uint8_t *progBuffer = (uint8_t *)malloc(sizeof(uint8_t) * 64); // 64-byte buffer
uint8_t length = 0;
uint64_t curAddr = 0;
enableFlashWrite();
sectorErase(0);
sectorErase(1);
sectorErase(2);
while(1) {
length = 0;
serial->send(readySend);
do {
*(progBuffer + length) = serial->receive();
} while(++length < 64);
// write to SPI
this->write(curAddr, 64, progBuffer);
curAddr += 64;
}
free(progBuffer);
return 0;
}