143 lines
3.9 KiB
C++
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;
|
|
} |