Files

522 lines
16 KiB
C
Raw Permalink Normal View History

2016-10-07 23:44:50 +02:00
/*
* Flash.c
*
* Created on: 20.03.2013
* Author: skuser
*/
#include "Memory.h"
#include "Configuration.h"
#include "Common.h"
#include "Settings.h"
#include "LEDHook.h"
#include "System.h"
2016-10-07 23:44:50 +02:00
#define USE_DMA
#define RECV_DMA DMA.CH0
#define SEND_DMA DMA.CH1
/* Convert defines from Makefile */
#define FLASH_DATA_START FLASH_DATA_ADDR
#define FLASH_DATA_END (FLASH_DATA_ADDR + FLASH_DATA_SIZE - 1)
/* Definitions for FRAM */
#define FRAM_USART USARTD0
#define FRAM_PORT PORTD
#define FRAM_CS PIN4_bm
#define FRAM_MOSI PIN3_bm
#define FRAM_MISO PIN2_bm
#define FRAM_SCK PIN1_bm
/* Declarations from assembler file */
uint16_t FlashReadWord(uint32_t Address);
void FlashEraseApplicationPage(uint32_t Address);
void FlashLoadFlashWord(uint16_t Address, uint16_t Data);
void FlashEraseWriteApplicationPage(uint32_t Address);
void FlashEraseFlashBuffer(void);
void FlashWaitForSPM(void);
static uint8_t ScrapBuffer[] = {0};
2019-11-15 10:21:40 +01:00
INLINE uint8_t SPITransferByte(uint8_t Data) {
2017-11-07 15:53:23 +01:00
FRAM_USART.DATA = Data;
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
while (!(FRAM_USART.STATUS & USART_RXCIF_bm));
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
return FRAM_USART.DATA;
2016-10-07 23:44:50 +02:00
}
#ifdef USE_DMA
2019-11-15 10:21:40 +01:00
INLINE void SPIReadBlock(void *Buffer, uint16_t ByteCount) {
2017-11-07 15:53:23 +01:00
/* Set up read and write transfers */
RECV_DMA.ADDRCTRL = DMA_CH_SRCRELOAD_NONE_gc | DMA_CH_SRCDIR_FIXED_gc | DMA_CH_DESTRELOAD_NONE_gc | DMA_CH_DESTDIR_INC_gc;
RECV_DMA.DESTADDR0 = ((uintptr_t) Buffer >> 0) & 0xFF;
RECV_DMA.DESTADDR1 = ((uintptr_t) Buffer >> 8) & 0xFF;
RECV_DMA.TRFCNT = ByteCount;
SEND_DMA.ADDRCTRL = DMA_CH_SRCRELOAD_NONE_gc | DMA_CH_SRCDIR_FIXED_gc | DMA_CH_DESTRELOAD_NONE_gc | DMA_CH_DESTDIR_FIXED_gc;
SEND_DMA.SRCADDR0 = ((uintptr_t) ScrapBuffer >> 0) & 0xFF;
SEND_DMA.SRCADDR1 = ((uintptr_t) ScrapBuffer >> 8) & 0xFF;
SEND_DMA.TRFCNT = ByteCount;
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
/* Enable read and write transfers */
RECV_DMA.CTRLA |= DMA_CH_ENABLE_bm;
SEND_DMA.CTRLA |= DMA_CH_ENABLE_bm;
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
/* Wait for DMA to finish */
2019-11-15 10:21:40 +01:00
while (RECV_DMA.CTRLA & DMA_CH_ENABLE_bm)
2017-11-07 15:53:23 +01:00
;
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
/* Clear Interrupt flag */
RECV_DMA.CTRLB = DMA_CH_TRNIF_bm | DMA_CH_ERRIF_bm;
SEND_DMA.CTRLB = DMA_CH_TRNIF_bm | DMA_CH_ERRIF_bm;
2016-10-07 23:44:50 +02:00
}
#else
2019-11-15 10:21:40 +01:00
INLINE void SPIReadBlock(void *Buffer, uint16_t ByteCount) {
uint8_t *ByteBuffer = (uint8_t *) Buffer;
2016-10-07 23:44:50 +02:00
2019-11-15 10:21:40 +01:00
while (ByteCount-- > 0) {
2017-11-07 15:53:23 +01:00
FRAM_USART.DATA = 0;
while (!(FRAM_USART.STATUS & USART_RXCIF_bm));
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
*ByteBuffer++ = FRAM_USART.DATA;
}
2016-10-07 23:44:50 +02:00
}
#endif
#ifdef USE_DMA
2019-11-15 10:21:40 +01:00
INLINE void SPIWriteBlock(const void *Buffer, uint16_t ByteCount) {
2017-11-07 15:53:23 +01:00
/* Set up read and write transfers */
RECV_DMA.ADDRCTRL = DMA_CH_SRCRELOAD_NONE_gc | DMA_CH_SRCDIR_FIXED_gc | DMA_CH_DESTRELOAD_NONE_gc | DMA_CH_DESTDIR_FIXED_gc;
RECV_DMA.DESTADDR0 = ((uintptr_t) ScrapBuffer >> 0) & 0xFF;
RECV_DMA.DESTADDR1 = ((uintptr_t) ScrapBuffer >> 8) & 0xFF;
RECV_DMA.TRFCNT = ByteCount;
SEND_DMA.ADDRCTRL = DMA_CH_SRCRELOAD_NONE_gc | DMA_CH_SRCDIR_INC_gc | DMA_CH_DESTRELOAD_NONE_gc | DMA_CH_DESTDIR_FIXED_gc;
SEND_DMA.SRCADDR0 = ((uintptr_t) Buffer >> 0) & 0xFF;
SEND_DMA.SRCADDR1 = ((uintptr_t) Buffer >> 8) & 0xFF;
SEND_DMA.TRFCNT = ByteCount;
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
/* Enable read and write transfers */
RECV_DMA.CTRLA |= DMA_CH_ENABLE_bm;
SEND_DMA.CTRLA |= DMA_CH_ENABLE_bm;
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
/* Wait for DMA to finish */
2019-11-15 10:21:40 +01:00
while (RECV_DMA.CTRLA & DMA_CH_ENABLE_bm)
2017-11-07 15:53:23 +01:00
;
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
/* Clear Interrupt flag */
RECV_DMA.CTRLB = DMA_CH_TRNIF_bm | DMA_CH_ERRIF_bm;
SEND_DMA.CTRLB = DMA_CH_TRNIF_bm | DMA_CH_ERRIF_bm;
2016-10-07 23:44:50 +02:00
}
#else
2019-11-15 10:21:40 +01:00
INLINE void SPIWriteBlock(const void *Buffer, uint16_t ByteCount) {
uint8_t *ByteBuffer = (uint8_t *) Buffer;
2016-10-07 23:44:50 +02:00
2019-11-15 10:21:40 +01:00
while (ByteCount-- > 0) {
2017-11-07 15:53:23 +01:00
FRAM_USART.DATA = *ByteBuffer++;
while (!(FRAM_USART.STATUS & USART_RXCIF_bm));
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
FRAM_USART.DATA; /* Flush Buffer */
}
2016-10-07 23:44:50 +02:00
}
#endif
2019-11-15 10:21:40 +01:00
INLINE void FRAMRead(void *Buffer, uint16_t Address, uint16_t ByteCount) {
2017-11-07 15:53:23 +01:00
FRAM_PORT.OUTCLR = FRAM_CS;
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
SPITransferByte(0x03); /* Read command */
2019-11-15 10:21:40 +01:00
SPITransferByte((Address >> 8) & 0xFF); /* Address hi and lo byte */
SPITransferByte((Address >> 0) & 0xFF);
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
SPIReadBlock(Buffer, ByteCount);
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
FRAM_PORT.OUTSET = FRAM_CS;
2016-10-07 23:44:50 +02:00
}
2019-11-15 10:21:40 +01:00
INLINE void FRAMWrite(const void *Buffer, uint16_t Address, uint16_t ByteCount) {
2017-11-07 15:53:23 +01:00
FRAM_PORT.OUTCLR = FRAM_CS;
SPITransferByte(0x06); /* Write Enable */
FRAM_PORT.OUTSET = FRAM_CS;
2016-10-07 23:44:50 +02:00
2019-11-15 10:21:40 +01:00
asm volatile("nop");
asm volatile("nop");
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
FRAM_PORT.OUTCLR = FRAM_CS;
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
SPITransferByte(0x02); /* Write command */
2019-11-15 10:21:40 +01:00
SPITransferByte((Address >> 8) & 0xFF); /* Address hi and lo byte */
SPITransferByte((Address >> 0) & 0xFF);
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
SPIWriteBlock(Buffer, ByteCount);
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
FRAM_PORT.OUTSET = FRAM_CS;
2016-10-07 23:44:50 +02:00
}
2019-11-15 10:21:40 +01:00
INLINE void FlashRead(void *Buffer, uint32_t Address, uint16_t ByteCount) {
uint8_t *BufPtr = (uint8_t *) Buffer;
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
/* We assume that ByteCount is a multiple of 2 */
uint32_t PhysicalAddress = Address + FLASH_DATA_ADDR;
2016-10-07 23:44:50 +02:00
2019-11-15 10:21:40 +01:00
if ((PhysicalAddress >= FLASH_DATA_START) && (PhysicalAddress <= FLASH_DATA_END)) {
2017-11-07 15:53:23 +01:00
/* Sanity check to limit access to the allocated area */
2019-11-15 10:21:40 +01:00
while (ByteCount > 1) {
2017-11-07 15:53:23 +01:00
uint16_t Word = FlashReadWord(PhysicalAddress);
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
*BufPtr++ = (Word >> 0) & 0xFF;
*BufPtr++ = (Word >> 8) & 0xFF;
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
PhysicalAddress += 2;
ByteCount -= 2;
}
}
2016-10-07 23:44:50 +02:00
}
2019-11-15 10:21:40 +01:00
INLINE void FlashWrite(const void *Buffer, uint32_t Address, uint16_t ByteCount) {
const uint8_t *BufPtr = (uint8_t *) Buffer;
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
/* We assume that FlashWrite is always called for write actions that are
* aligned to APP_SECTION_PAGE_SIZE and a multiple of APP_SECTION_PAGE_SIZE.
* Thus only full pages are written into the flash. */
uint16_t PageCount = ByteCount / APP_SECTION_PAGE_SIZE;
uint32_t PhysicalAddress = Address + FLASH_DATA_ADDR;
2016-10-07 23:44:50 +02:00
2019-11-15 10:21:40 +01:00
if ((PhysicalAddress >= FLASH_DATA_START) && (PhysicalAddress <= FLASH_DATA_END)) {
2017-11-07 15:53:23 +01:00
/* Sanity check to limit access to the allocated area */
2016-10-07 23:44:50 +02:00
2019-11-15 10:21:40 +01:00
while (PageCount-- > 0) {
2017-11-07 15:53:23 +01:00
/* For each page to program, wait for NVM to get ready,
* erase the flash page buffer, program all data to the
* flash page buffer and write buffer to flash using
* the atomic erase and write operation. */
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
FlashWaitForSPM();
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
FlashEraseFlashBuffer();
FlashWaitForSPM();
2016-10-07 23:44:50 +02:00
2019-11-15 10:21:40 +01:00
for (uint16_t i = 0; i < APP_SECTION_PAGE_SIZE; i += 2) {
2017-11-07 15:53:23 +01:00
uint16_t Word = 0;
2016-10-07 23:44:50 +02:00
2019-11-15 10:21:40 +01:00
Word |= ((uint16_t) * BufPtr++ << 0);
Word |= ((uint16_t) * BufPtr++ << 8);
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
FlashLoadFlashWord(i, Word);
FlashWaitForSPM();
}
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
FlashEraseWriteApplicationPage(PhysicalAddress);
FlashWaitForSPM();
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
PhysicalAddress += APP_SECTION_PAGE_SIZE;
}
}
2016-10-07 23:44:50 +02:00
}
2019-11-15 10:21:40 +01:00
INLINE void FlashErase(uint32_t Address, uint16_t ByteCount) {
2017-11-07 15:53:23 +01:00
uint16_t PageCount = ByteCount / APP_SECTION_PAGE_SIZE;
uint32_t PhysicalAddress = Address + FLASH_DATA_ADDR;
2016-10-07 23:44:50 +02:00
2019-11-15 10:21:40 +01:00
if ((PhysicalAddress >= FLASH_DATA_START) && (PhysicalAddress <= FLASH_DATA_END)) {
2017-11-07 15:53:23 +01:00
/* Sanity check to limit access to the allocated area */
2019-11-15 10:21:40 +01:00
while (PageCount-- > 0) {
2017-11-07 15:53:23 +01:00
FlashWaitForSPM();
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
FlashEraseApplicationPage(PhysicalAddress);
FlashWaitForSPM();
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
PhysicalAddress += APP_SECTION_PAGE_SIZE;
}
}
2016-10-07 23:44:50 +02:00
}
2019-11-15 10:21:40 +01:00
INLINE void FlashToFRAM(uint32_t Address, uint16_t ByteCount) {
2017-11-07 15:53:23 +01:00
/* We assume that ByteCount is a multiple of 2 */
uint32_t PhysicalAddress = Address + FLASH_DATA_ADDR;
2016-10-07 23:44:50 +02:00
2019-11-15 10:21:40 +01:00
if ((PhysicalAddress >= FLASH_DATA_START) && (PhysicalAddress <= FLASH_DATA_END)) {
2017-11-07 15:53:23 +01:00
/* Sanity check to limit access to the allocated area.
* Set up FRAM memory for writing. */
FRAM_PORT.OUTCLR = FRAM_CS;
SPITransferByte(0x06); /* Write Enable */
FRAM_PORT.OUTSET = FRAM_CS;
2016-10-07 23:44:50 +02:00
2019-11-15 10:21:40 +01:00
asm volatile("nop");
asm volatile("nop");
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
FRAM_PORT.OUTCLR = FRAM_CS;
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
SPITransferByte(0x02); /* Write command */
SPITransferByte(0); /* Address hi and lo byte */
SPITransferByte(0);
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
/* Loop through bytes, read words from flash and write
* double byte into FRAM. */
2019-11-15 10:21:40 +01:00
while (ByteCount > 1) {
2017-11-07 15:53:23 +01:00
uint16_t Word = FlashReadWord(PhysicalAddress);
2016-10-07 23:44:50 +02:00
2019-11-15 10:21:40 +01:00
SPITransferByte((Word >> 0) & 0xFF);
SPITransferByte((Word >> 8) & 0xFF);
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
PhysicalAddress += 2;
ByteCount -= 2;
}
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
/* End write procedure of FRAM */
FRAM_PORT.OUTSET = FRAM_CS;
}
2016-10-07 23:44:50 +02:00
}
2019-11-15 10:21:40 +01:00
INLINE void FRAMToFlash(uint32_t Address, uint16_t ByteCount) {
2017-11-07 15:53:23 +01:00
/* We assume that FlashWrite is always called for write actions that are
* aligned to APP_SECTION_PAGE_SIZE and a multiple of APP_SECTION_PAGE_SIZE.
* Thus only full pages are written into the flash. */
uint16_t PageCount = ByteCount / APP_SECTION_PAGE_SIZE;
uint32_t PhysicalAddress = Address + FLASH_DATA_ADDR;
2016-10-07 23:44:50 +02:00
2019-11-15 10:21:40 +01:00
if ((PhysicalAddress >= FLASH_DATA_START) && (PhysicalAddress <= FLASH_DATA_END)) {
2017-11-07 15:53:23 +01:00
/* Sanity check to limit access to the allocated area and setup FRAM
* read. */
FRAM_PORT.OUTCLR = FRAM_CS;
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
SPITransferByte(0x03); /* Read command */
SPITransferByte(0); /* Address hi and lo byte */
SPITransferByte(0);
2016-10-07 23:44:50 +02:00
2019-11-15 10:21:40 +01:00
while (PageCount-- > 0) {
2017-11-07 15:53:23 +01:00
/* For each page to program, wait for NVM to get ready,
* erase the flash page buffer, program all data to the
* flash page buffer and write buffer to flash using
* the atomic erase and write operation. */
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
FlashWaitForSPM();
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
FlashEraseFlashBuffer();
FlashWaitForSPM();
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
/* Write one page worth of data into flash buffer */
2019-11-15 10:21:40 +01:00
for (uint16_t i = 0; i < APP_SECTION_PAGE_SIZE; i += 2) {
2017-11-07 15:53:23 +01:00
uint16_t Word = 0;
2016-10-07 23:44:50 +02:00
2019-11-15 10:21:40 +01:00
Word |= ((uint16_t) SPITransferByte(0) << 0);
Word |= ((uint16_t) SPITransferByte(0) << 8);
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
FlashLoadFlashWord(i, Word);
FlashWaitForSPM();
}
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
/* Program flash buffer into flash */
FlashEraseWriteApplicationPage(PhysicalAddress);
FlashWaitForSPM();
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
PhysicalAddress += APP_SECTION_PAGE_SIZE;
}
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
/* End read procedure of FRAM */
FRAM_PORT.OUTSET = FRAM_CS;
}
2016-10-07 23:44:50 +02:00
}
2019-11-15 10:21:40 +01:00
void MemoryInit(void) {
2017-11-07 15:53:23 +01:00
/* Configure FRAM_USART for SPI master mode 0 with maximum clock frequency */
FRAM_PORT.OUTSET = FRAM_CS;
2019-11-15 10:21:40 +01:00
2017-11-07 15:53:23 +01:00
FRAM_PORT.OUTCLR = FRAM_SCK;
FRAM_PORT.OUTSET = FRAM_MOSI;
2019-11-15 10:21:40 +01:00
2017-11-07 15:53:23 +01:00
FRAM_PORT.DIRSET = FRAM_SCK | FRAM_MOSI | FRAM_CS;
2016-10-07 23:44:50 +02:00
FRAM_USART.BAUDCTRLA = 0;
FRAM_USART.BAUDCTRLB = 0;
2017-11-07 15:53:23 +01:00
FRAM_USART.CTRLC = USART_CMODE_MSPI_gc;
FRAM_USART.CTRLB = USART_RXEN_bm | USART_TXEN_bm;
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
/* Init DMAs for reading and writing */
RECV_DMA.ADDRCTRL = DMA_CH_SRCRELOAD_NONE_gc | DMA_CH_SRCDIR_FIXED_gc | DMA_CH_DESTRELOAD_NONE_gc | DMA_CH_DESTDIR_FIXED_gc;
RECV_DMA.TRIGSRC = DMA_CH_TRIGSRC_USARTD0_RXC_gc;
RECV_DMA.TRFCNT = 0;
RECV_DMA.SRCADDR0 = ((uintptr_t) &FRAM_USART.DATA >> 0) & 0xFF;
RECV_DMA.SRCADDR1 = ((uintptr_t) &FRAM_USART.DATA >> 8) & 0xFF;
RECV_DMA.SRCADDR2 = 0;
RECV_DMA.DESTADDR0 = 0;
RECV_DMA.DESTADDR1 = 0;
RECV_DMA.DESTADDR2 = 0;
RECV_DMA.CTRLA = DMA_CH_SINGLE_bm | DMA_CH_BURSTLEN_1BYTE_gc;
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
SEND_DMA.ADDRCTRL = DMA_CH_SRCRELOAD_NONE_gc | DMA_CH_SRCDIR_FIXED_gc | DMA_CH_DESTRELOAD_NONE_gc | DMA_CH_DESTDIR_FIXED_gc;
SEND_DMA.TRIGSRC = DMA_CH_TRIGSRC_USARTD0_DRE_gc;
SEND_DMA.TRFCNT = 0;
SEND_DMA.SRCADDR0 = 0;
SEND_DMA.SRCADDR1 = 0;
SEND_DMA.SRCADDR2 = 0;
SEND_DMA.DESTADDR0 = ((uintptr_t) &FRAM_USART.DATA >> 0) & 0xFF;
SEND_DMA.DESTADDR1 = ((uintptr_t) &FRAM_USART.DATA >> 8) & 0xFF;
SEND_DMA.DESTADDR2 = 0;
SEND_DMA.CTRLA = DMA_CH_SINGLE_bm | DMA_CH_BURSTLEN_1BYTE_gc;
2016-10-07 23:44:50 +02:00
}
2019-11-15 10:21:40 +01:00
void MemoryReadBlock(void *Buffer, uint16_t Address, uint16_t ByteCount) {
2017-11-07 15:53:23 +01:00
if (ByteCount == 0)
return;
FRAMRead(Buffer, Address, ByteCount);
2016-10-07 23:44:50 +02:00
}
2019-11-15 10:21:40 +01:00
void MemoryWriteBlock(const void *Buffer, uint16_t Address, uint16_t ByteCount) {
2017-11-07 15:53:23 +01:00
if (ByteCount == 0)
return;
FRAMWrite(Buffer, Address, ByteCount);
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
LEDHook(LED_MEMORY_CHANGED, LED_ON);
2016-10-07 23:44:50 +02:00
}
2019-11-15 10:21:40 +01:00
void MemoryClear(void) {
2017-11-07 15:53:23 +01:00
FlashErase((uint32_t) GlobalSettings.ActiveSettingIdx * MEMORY_SIZE_PER_SETTING, MEMORY_SIZE_PER_SETTING);
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
MemoryRecall();
2016-10-07 23:44:50 +02:00
}
2019-11-15 10:21:40 +01:00
void MemoryRecall(void) {
2017-11-07 15:53:23 +01:00
/* Recall memory from permanent flash */
FlashToFRAM((uint32_t) GlobalSettings.ActiveSettingIdx * MEMORY_SIZE_PER_SETTING, MEMORY_SIZE_PER_SETTING);
SystemTickClearFlag();
2016-10-07 23:44:50 +02:00
}
2019-11-15 10:21:40 +01:00
void MemoryStore(void) {
2017-11-07 15:53:23 +01:00
/* Store current memory into permanent flash */
FRAMToFlash((uint32_t) GlobalSettings.ActiveSettingIdx * MEMORY_SIZE_PER_SETTING, MEMORY_SIZE_PER_SETTING);
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
LEDHook(LED_MEMORY_CHANGED, LED_OFF);
LEDHook(LED_MEMORY_STORED, LED_PULSE);
SystemTickClearFlag();
2016-10-07 23:44:50 +02:00
}
2019-11-15 10:21:40 +01:00
bool MemoryUploadBlock(void *Buffer, uint32_t BlockAddress, uint16_t ByteCount) {
2016-10-07 23:44:50 +02:00
if (BlockAddress >= MEMORY_SIZE_PER_SETTING) {
/* Prevent writing out of bounds by silently ignoring it */
return true;
} else {
2017-11-07 15:53:23 +01:00
/* Calculate bytes left in memory and start writing */
uint32_t BytesLeft = MEMORY_SIZE_PER_SETTING - BlockAddress;
ByteCount = MIN(ByteCount, BytesLeft);
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
/* Store to local memory */
FRAMWrite(Buffer, BlockAddress, ByteCount);
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
return true;
2016-10-07 23:44:50 +02:00
}
}
2019-11-15 10:21:40 +01:00
bool MemoryDownloadBlock(void *Buffer, uint32_t BlockAddress, uint16_t ByteCount) {
2016-10-07 23:44:50 +02:00
if (BlockAddress >= MEMORY_SIZE_PER_SETTING) {
/* There are bytes out of bounds to be read. Notify that we are done. */
return false;
} else {
2017-11-07 15:53:23 +01:00
/* Calculate bytes left in memory and issue reading */
uint32_t BytesLeft = MEMORY_SIZE_PER_SETTING - BlockAddress;
ByteCount = MIN(ByteCount, BytesLeft);
2016-10-07 23:44:50 +02:00
2017-11-07 15:53:23 +01:00
/* Output local memory contents */
FRAMRead(Buffer, BlockAddress, ByteCount);
2016-10-07 23:44:50 +02:00
return true;
}
}
// EEPROM functions
2019-11-15 10:21:40 +01:00
static inline void NVM_EXEC(void) {
2017-11-07 15:53:23 +01:00
void *z = (void *)&NVM_CTRLA;
2017-11-07 15:53:23 +01:00
__asm__ volatile("out %[ccp], %[ioreg]" "\n\t"
2019-11-15 10:21:40 +01:00
"st z, %[cmdex]"
:
: [ccp] "I"(_SFR_IO_ADDR(CCP)),
[ioreg] "d"(CCP_IOREG_gc),
[cmdex] "r"(NVM_CMDEX_bm),
[z] "z"(z)
);
}
2019-11-15 10:21:40 +01:00
void WaitForNVM(void) {
while (NVM.STATUS & NVM_NVMBUSY_bm) { };
}
2019-11-15 10:21:40 +01:00
void FlushNVMBuffer(void) {
2017-11-07 15:53:23 +01:00
WaitForNVM();
2017-11-07 15:53:23 +01:00
if ((NVM.STATUS & NVM_EELOAD_bm) != 0) {
NVM.CMD = NVM_CMD_ERASE_EEPROM_BUFFER_gc;
NVM_EXEC();
}
}
2019-11-15 10:21:40 +01:00
uint16_t ReadEEPBlock(uint16_t Address, void *DestPtr, uint16_t ByteCount) {
2017-11-07 15:53:23 +01:00
uint16_t BytesRead = 0;
2019-11-15 10:21:40 +01:00
uint8_t *BytePtr = (uint8_t *) DestPtr;
2017-11-07 15:53:23 +01:00
NVM.ADDR2 = 0;
2017-11-07 15:53:23 +01:00
WaitForNVM();
2019-11-15 10:21:40 +01:00
while (ByteCount > 0) {
NVM.ADDR0 = Address & 0xFF;
NVM.ADDR1 = (Address >> 8) & 0x1F;
2019-11-15 10:21:40 +01:00
NVM.CMD = NVM_CMD_READ_EEPROM_gc;
NVM_EXEC();
2019-11-15 10:21:40 +01:00
*BytePtr++ = NVM.DATA0;
Address++;
2019-11-15 10:21:40 +01:00
ByteCount--;
BytesRead++;
2017-11-07 15:53:23 +01:00
}
2017-11-07 15:53:23 +01:00
return BytesRead;
}
2019-11-15 10:21:40 +01:00
uint16_t WriteEEPBlock(uint16_t Address, const void *SrcPtr, uint16_t ByteCount) {
const uint8_t *BytePtr = (const uint8_t *) SrcPtr;
2017-11-07 15:53:23 +01:00
uint8_t ByteAddress = Address % EEPROM_PAGE_SIZE;
uint16_t PageAddress = Address - ByteAddress;
uint16_t BytesWritten = 0;
2017-11-07 15:53:23 +01:00
FlushNVMBuffer();
WaitForNVM();
NVM.CMD = NVM_CMD_LOAD_EEPROM_BUFFER_gc;
2017-11-07 15:53:23 +01:00
NVM.ADDR1 = 0;
NVM.ADDR2 = 0;
2019-11-15 10:21:40 +01:00
while (ByteCount > 0) {
2017-11-07 15:53:23 +01:00
NVM.ADDR0 = ByteAddress;
2017-11-07 15:53:23 +01:00
NVM.DATA0 = *BytePtr++;
2017-11-07 15:53:23 +01:00
ByteAddress++;
ByteCount--;
2019-11-15 10:21:40 +01:00
if (ByteCount == 0 || ByteAddress >= EEPROM_PAGE_SIZE) {
2017-11-07 15:53:23 +01:00
NVM.ADDR0 = PageAddress & 0xFF;
NVM.ADDR1 = (PageAddress >> 8) & 0x1F;
2017-11-07 15:53:23 +01:00
NVM.CMD = NVM_CMD_ERASE_WRITE_EEPROM_PAGE_gc;
NVM_EXEC();
2017-11-07 15:53:23 +01:00
PageAddress += EEPROM_PAGE_SIZE;
ByteAddress = 0;
2017-11-07 15:53:23 +01:00
WaitForNVM();
2017-11-07 15:53:23 +01:00
NVM.CMD = NVM_CMD_LOAD_EEPROM_BUFFER_gc;
}
2017-11-07 15:53:23 +01:00
BytesWritten++;
}
2017-11-07 15:53:23 +01:00
return BytesWritten;
}