Move animation steps to NVS data
This commit is contained in:
		
							parent
							
								
									1e8da90156
								
							
						
					
					
						commit
						99b3d6a36c
					
				
					 7 changed files with 230 additions and 12 deletions
				
			
		|  | @ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue