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 = .; | ||||
|     } >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…
	
	Add table
		Add a link
		
	
		Reference in a new issue