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 = .;
|
||||
} >flash
|
||||
|
||||
/* Non-volatile storage area in flash */
|
||||
.nvstore (NOLOAD) :
|
||||
{
|
||||
. = ALIGN(1K);
|
||||
*(.nvstore*)
|
||||
. = ALIGN(1K);
|
||||
_end_nvstore = .;
|
||||
} > flash_nvstore
|
||||
|
||||
/* C++ initialiser code segments */
|
||||
.preinit_array :
|
||||
{
|
|
@ -1,7 +1,8 @@
|
|||
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
|
||||
}
|
||||
|
||||
INCLUDE ld/common.ld
|
||||
INCLUDE ld/common_nvs.ld
|
2
makefile
2
makefile
|
@ -10,7 +10,7 @@ DEBUG := yes
|
|||
H_DEVICE = STM32F030x6
|
||||
STARTUP_SOURCE_DIR = src
|
||||
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)
|
||||
DEBUG_FLAGS = -DDEBUG -g3
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "animation.h"
|
||||
#include "animation_lut.h"
|
||||
#include "light_sensor.h"
|
||||
#include "nvs.h"
|
||||
|
||||
volatile bool Animation_FrameFlag = false;
|
||||
|
||||
|
@ -75,18 +76,19 @@ void Animation_Poll(void)
|
|||
}
|
||||
Animation_FrameFlag = false;
|
||||
|
||||
static unsigned int bottom = 0;
|
||||
static unsigned int top = 0;
|
||||
|
||||
bottom += ANIMATION_STEPS / ANIMATION_CYCLE_TIME_BOTTOM
|
||||
NVS_Data->animation_step_bottom += ANIMATION_STEPS
|
||||
/ ANIMATION_CYCLE_TIME_BOTTOM
|
||||
/ ANIMATION_REFRESH_RATE;
|
||||
top += ANIMATION_STEPS / ANIMATION_CYCLE_TIME_TOP
|
||||
NVS_Data->animation_step_top += ANIMATION_STEPS
|
||||
/ ANIMATION_CYCLE_TIME_TOP
|
||||
/ ANIMATION_REFRESH_RATE;
|
||||
|
||||
bottom %= 2 * ANIMATION_STEPS;
|
||||
top %= 2 * ANIMATION_STEPS;
|
||||
NVS_Data->animation_step_bottom %= 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();
|
||||
}
|
||||
|
||||
|
|
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