Move animation steps to NVS data
This commit is contained in:
parent
1e8da90156
commit
99b3d6a36c
|
@ -1 +1 @@
|
||||||
442
|
445
|
||||||
|
|
|
@ -12,6 +12,15 @@ SECTIONS
|
||||||
_end_text = .;
|
_end_text = .;
|
||||||
} >flash
|
} >flash
|
||||||
|
|
||||||
|
/* Non-volatile storage area in flash */
|
||||||
|
.nvstore (NOLOAD) :
|
||||||
|
{
|
||||||
|
. = ALIGN(1K);
|
||||||
|
*(.nvstore*)
|
||||||
|
. = ALIGN(1K);
|
||||||
|
_end_nvstore = .;
|
||||||
|
} > flash_nvstore
|
||||||
|
|
||||||
/* C++ initialiser code segments */
|
/* C++ initialiser code segments */
|
||||||
.preinit_array :
|
.preinit_array :
|
||||||
{
|
{
|
|
@ -1,7 +1,8 @@
|
||||||
MEMORY
|
MEMORY
|
||||||
{
|
{
|
||||||
flash (rx) : ORIGIN = 0x08000000, LENGTH = 16K
|
flash (rx) : ORIGIN = 0x08000000, LENGTH = 15K
|
||||||
|
flash_nvstore (rw) : ORIGIN = 0x08003c00, LENGTH = 1K
|
||||||
sram (xrw) : ORIGIN = 0x20000000, LENGTH = 4K
|
sram (xrw) : ORIGIN = 0x20000000, LENGTH = 4K
|
||||||
}
|
}
|
||||||
|
|
||||||
INCLUDE ld/common.ld
|
INCLUDE ld/common_nvs.ld
|
2
makefile
2
makefile
|
@ -10,7 +10,7 @@ DEBUG := yes
|
||||||
H_DEVICE = STM32F030x6
|
H_DEVICE = STM32F030x6
|
||||||
STARTUP_SOURCE_DIR = src
|
STARTUP_SOURCE_DIR = src
|
||||||
STARTUP_SOURCES = $(STARTUP_SOURCE_DIR)/startup.S
|
STARTUP_SOURCES = $(STARTUP_SOURCE_DIR)/startup.S
|
||||||
LD_SCRIPT = ld/stm32f030f4_flash.ld
|
LD_SCRIPT = ld/stm32f030f4_15k_flash_1k_nvs.ld
|
||||||
|
|
||||||
ifeq ($(DEBUG),yes)
|
ifeq ($(DEBUG),yes)
|
||||||
DEBUG_FLAGS = -DDEBUG -g3
|
DEBUG_FLAGS = -DDEBUG -g3
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "animation.h"
|
#include "animation.h"
|
||||||
#include "animation_lut.h"
|
#include "animation_lut.h"
|
||||||
#include "light_sensor.h"
|
#include "light_sensor.h"
|
||||||
|
#include "nvs.h"
|
||||||
|
|
||||||
volatile bool Animation_FrameFlag = false;
|
volatile bool Animation_FrameFlag = false;
|
||||||
|
|
||||||
|
@ -75,18 +76,19 @@ void Animation_Poll(void)
|
||||||
}
|
}
|
||||||
Animation_FrameFlag = false;
|
Animation_FrameFlag = false;
|
||||||
|
|
||||||
static unsigned int bottom = 0;
|
NVS_Data->animation_step_bottom += ANIMATION_STEPS
|
||||||
static unsigned int top = 0;
|
/ ANIMATION_CYCLE_TIME_BOTTOM
|
||||||
|
|
||||||
bottom += ANIMATION_STEPS / ANIMATION_CYCLE_TIME_BOTTOM
|
|
||||||
/ ANIMATION_REFRESH_RATE;
|
/ ANIMATION_REFRESH_RATE;
|
||||||
top += ANIMATION_STEPS / ANIMATION_CYCLE_TIME_TOP
|
NVS_Data->animation_step_top += ANIMATION_STEPS
|
||||||
|
/ ANIMATION_CYCLE_TIME_TOP
|
||||||
/ ANIMATION_REFRESH_RATE;
|
/ ANIMATION_REFRESH_RATE;
|
||||||
|
|
||||||
bottom %= 2 * ANIMATION_STEPS;
|
NVS_Data->animation_step_bottom %= 2 * ANIMATION_STEPS;
|
||||||
top %= 2 * ANIMATION_STEPS;
|
NVS_Data->animation_step_top %= 2 * ANIMATION_STEPS;
|
||||||
|
|
||||||
Animation_DrawGradient(bottom, top, LightSensor_RelativeBrightness);
|
Animation_DrawGradient(NVS_Data->animation_step_bottom,
|
||||||
|
NVS_Data->animation_step_top,
|
||||||
|
LightSensor_RelativeBrightness);
|
||||||
LED_Commit();
|
LED_Commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
183
src/nvs.c
Normal file
183
src/nvs.c
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "nvs.h"
|
||||||
|
|
||||||
|
// Note that the area used for storage must be aligned to the flash's pages. If
|
||||||
|
// you want to use a larger area, be sure to also change the size and location
|
||||||
|
// in the linker script.
|
||||||
|
#define NVS_AREA_SIZE 1024
|
||||||
|
#define NVS_BLOCK_COUNT (NVS_AREA_SIZE / sizeof(NVS_Block_t))
|
||||||
|
#define NVS_VALID_BLOCK_MARKER 0xab34
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
__attribute__((packed))
|
||||||
|
{
|
||||||
|
// Actual block data
|
||||||
|
NVS_Data_t data;
|
||||||
|
|
||||||
|
// Ensure struct size is divisible by two
|
||||||
|
uint8_t padding[sizeof(NVS_Data_t) % 2];
|
||||||
|
|
||||||
|
// Block marker for detecting if the block is the current or an old block
|
||||||
|
uint16_t marker;
|
||||||
|
|
||||||
|
uint32_t crc;
|
||||||
|
} NVS_Block_t;
|
||||||
|
|
||||||
|
__attribute__((used, section(".nvstore")))
|
||||||
|
volatile NVS_Block_t NVS_Area[NVS_BLOCK_COUNT];
|
||||||
|
|
||||||
|
volatile NVS_Block_t *NVS_FlashData;
|
||||||
|
__attribute__((used))
|
||||||
|
NVS_Block_t NVS_RAMData;
|
||||||
|
|
||||||
|
NVS_Data_t *const NVS_Data = &NVS_RAMData.data;
|
||||||
|
|
||||||
|
static uint32_t NVS_CalculateCRC(NVS_Data_t *data)
|
||||||
|
{
|
||||||
|
CRC->CR = CRC_CR_RESET;
|
||||||
|
for(int i = 0; i < sizeof(NVS_Data_t); i++)
|
||||||
|
{
|
||||||
|
CRC->DR = ((uint8_t*)(data))[i];
|
||||||
|
}
|
||||||
|
return CRC->DR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void NVS_ProgramHalfWord(uint16_t *dest, uint16_t value)
|
||||||
|
{
|
||||||
|
FLASH->CR |= FLASH_CR_PG;
|
||||||
|
*(volatile uint16_t*)dest = value;
|
||||||
|
while(FLASH->SR & FLASH_SR_BSY);
|
||||||
|
if(*dest != value)
|
||||||
|
{
|
||||||
|
// Write failed
|
||||||
|
__asm__("bkpt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void NVS_UnlockFlash(void)
|
||||||
|
{
|
||||||
|
while(FLASH->SR & FLASH_SR_BSY);
|
||||||
|
if(FLASH->CR & FLASH_CR_LOCK)
|
||||||
|
{
|
||||||
|
FLASH->KEYR = 0x45670123;
|
||||||
|
FLASH->KEYR = 0xcdef89ab;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void NVS_EraseArea(void)
|
||||||
|
{
|
||||||
|
for(int i = 0; i < NVS_AREA_SIZE; i += 1024)
|
||||||
|
{
|
||||||
|
while(FLASH->SR & FLASH_SR_BSY);
|
||||||
|
FLASH->CR |= FLASH_CR_PER;
|
||||||
|
FLASH->AR = (uint32_t)NVS_Area + i;
|
||||||
|
FLASH->CR |= FLASH_CR_STRT;
|
||||||
|
while(FLASH->SR & FLASH_SR_BSY);
|
||||||
|
if(FLASH->SR & FLASH_SR_EOP)
|
||||||
|
{
|
||||||
|
// Clear EOP flag
|
||||||
|
FLASH->SR = FLASH_SR_EOP;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Erase failed
|
||||||
|
__asm__("bkpt");
|
||||||
|
}
|
||||||
|
FLASH->CR &= ~FLASH_CR_PER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool NVS_BlockEmpty(NVS_Block_t *block)
|
||||||
|
{
|
||||||
|
for(int i = 0; i < sizeof(NVS_Block_t) / 2; i++)
|
||||||
|
{
|
||||||
|
if(*((uint16_t*)block + i) != 0xffff)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void NVS_LoadDefaults(void)
|
||||||
|
{
|
||||||
|
NVS_Data->animation_step_bottom = 0;
|
||||||
|
NVS_Data->animation_step_top = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NVS_Load(void)
|
||||||
|
{
|
||||||
|
RCC->AHBENR |= RCC_AHBENR_CRCEN;
|
||||||
|
|
||||||
|
volatile NVS_Block_t *block = NULL;
|
||||||
|
|
||||||
|
// Find valid block
|
||||||
|
for(int i = 0; i < NVS_BLOCK_COUNT; i++)
|
||||||
|
{
|
||||||
|
block = &NVS_Area[i];
|
||||||
|
if(block->marker == NVS_VALID_BLOCK_MARKER)
|
||||||
|
{
|
||||||
|
// Valid block found, next up is the CRC check
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if(block->marker == 0xffff)
|
||||||
|
{
|
||||||
|
// This block was erased and no block before was valid, so we can
|
||||||
|
// assume there is no valid block
|
||||||
|
block = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(block == NULL || block->marker != NVS_VALID_BLOCK_MARKER
|
||||||
|
|| block->crc != NVS_CalculateCRC(&block->data))
|
||||||
|
{
|
||||||
|
// No valid block found
|
||||||
|
NVS_LoadDefaults();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Valid block and CRC check successful
|
||||||
|
NVS_FlashData = block;
|
||||||
|
memcpy(&NVS_RAMData, (void*)block, sizeof(NVS_Block_t));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NVS_Save(void)
|
||||||
|
{
|
||||||
|
NVS_UnlockFlash();
|
||||||
|
|
||||||
|
// Currently loaded block. Is NULL if the defaults were loaded in NVS_Load()
|
||||||
|
// instead of some flash contents.
|
||||||
|
NVS_Block_t *current_block = NVS_FlashData;
|
||||||
|
NVS_Block_t *next_block = NVS_FlashData + 1;
|
||||||
|
|
||||||
|
if(current_block == NULL || next_block > NVS_Area + NVS_BLOCK_COUNT
|
||||||
|
|| !NVS_BlockEmpty(next_block))
|
||||||
|
{
|
||||||
|
NVS_EraseArea();
|
||||||
|
next_block = &NVS_Area[0];
|
||||||
|
current_block = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
NVS_RAMData.crc = NVS_CalculateCRC(NVS_Data);
|
||||||
|
NVS_RAMData.marker = NVS_VALID_BLOCK_MARKER;
|
||||||
|
|
||||||
|
// The block length is guaranteed to be divisible by 2
|
||||||
|
for(int i = 0; i < sizeof(NVS_Block_t) / 2; i++)
|
||||||
|
{
|
||||||
|
NVS_ProgramHalfWord((uint16_t*)next_block + i,
|
||||||
|
*((uint16_t*)&NVS_RAMData + i));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(current_block != NULL)
|
||||||
|
{
|
||||||
|
NVS_ProgramHalfWord((uint16_t*)¤t_block->marker, 0x0000);
|
||||||
|
}
|
||||||
|
|
||||||
|
NVS_FlashData = next_block;
|
||||||
|
}
|
23
src/nvs.h
Normal file
23
src/nvs.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "stm32f030x6.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
__attribute__((packed))
|
||||||
|
{
|
||||||
|
unsigned int animation_step_bottom;
|
||||||
|
unsigned int animation_step_top;
|
||||||
|
} NVS_Data_t;
|
||||||
|
|
||||||
|
extern NVS_Data_t *const NVS_Data;
|
||||||
|
|
||||||
|
// Returns true if the data was successfully loaded from flash and false if the
|
||||||
|
// defaults were restored instead
|
||||||
|
bool NVS_Load(void);
|
||||||
|
|
||||||
|
// Stores the current contents of NVS_Data to flash
|
||||||
|
void NVS_Save(void);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue