/** \file * \brief This file contains functions that manage the on-chip EEPROM. * */ /* Include Files */ #include "KTag.h" /* Local Definitions and Constants */ /* External Variables [Only if necessary!] */ /* External Function Prototypes [Only if necessary!] */ /* Public Variables */ //! Mutex controlling access to the EEPROM to ensure data/CRC integrity. SemaphoreHandle_t xSemaphoreOnChipEEPROMLock; TaskHandle_t NVM_OnChipEEPROM_Task_Handle; volatile bool NVM_IsOnChipEEPROMInitialized = false; /* Private Variables */ static QueueHandle_t xQueueOnChipEEPROM; #if CY_PSOC4 const uint8_t Emulated_EEPROM_Storage[On_Chip_Emulated_EEPROM_PHYSICAL_SIZE] __ALIGNED(CY_FLASH_SIZEOF_ROW) = {0u}; #endif // CY_PSOC4 /* Private Function Prototypes */ /* Inline Functions */ #if CY_PSOC4 //! Reads a block of \a n bytes from EEPROM address \a source to SRAM \a destination. static inline void EEPROM_read_block(uint8_t * destination, uint16_t source, size_t n) { On_Chip_Emulated_EEPROM_Read(source, destination, n); } //! Writes a block of \a n bytes from SRAM \a source to EEPROM address \a destination. static inline void EEPROM_write_block(uint8_t * source, uint16_t destination, size_t n) { On_Chip_Emulated_EEPROM_Write(destination, source, n); } #endif // CY_PSOC4 #if CY_PSOC5 //! Reads a block of \a n bytes from EEPROM address \a source to SRAM \a destination. static inline void EEPROM_read_block(uint8_t * destination, uint16_t source, size_t n) { for (uint_fast16_t i = 0; i < n; i++) { uint8_t temp = On_Chip_EEPROM_ReadByte(source + i); *(destination + i) = temp; } } //! Writes a block of \a n bytes from SRAM \a source to EEPROM address \a destination. static inline void EEPROM_write_block(uint8_t * source, uint16_t destination, size_t n) { for (uint_fast16_t i = 0; i < n; i++) { On_Chip_EEPROM_WriteByte(*(source + i), destination + i); } } #endif // CY_PSOC5 #if CY_PSOC6 //! Reads a block of \a n bytes from EEPROM address \a source to SRAM \a destination. static inline void EEPROM_read_block(uint8_t * destination, uint16_t source, size_t n) { cy_en_em_eeprom_status_t result = On_Chip_EEPROM_Read(source, destination, n); if (result != CY_EM_EEPROM_SUCCESS) { CY_ASSERT(0); } } //! Writes a block of \a n bytes from SRAM \a source to EEPROM address \a destination. static inline void EEPROM_write_block(uint8_t * source, uint16_t destination, size_t n) { cy_en_em_eeprom_status_t result = On_Chip_EEPROM_Write(destination, source, n); if (result != CY_EM_EEPROM_SUCCESS) { CY_ASSERT(0); } } #endif // CY_PSOC6 /* Public Functions */ //! Sets up the on-chip EEPROM, but does not read from it (yet). void NVM_InitOnChipEEPROM(void) { /// Create a mutex-type semaphore. xSemaphoreOnChipEEPROMLock = xSemaphoreCreateMutex(); if (xSemaphoreOnChipEEPROMLock == NULL) { CY_ASSERT(0); } xQueueOnChipEEPROM = xQueueCreate(5, sizeof(uint8_t)); #if CY_PSOC4 On_Chip_Emulated_EEPROM_Init((uint32_t)Emulated_EEPROM_Storage); #endif // CY_PSOC4 #if CY_PSOC5 On_Chip_EEPROM_Start(); #endif // CY_PSOC5 #if CY_PSOC6 // From the docs: "For PSoC 6, if Emulated EEPROM is selected for EEPROM storage, the start address will be // overwritten to some address from Emulated EEPROM flash area." On_Chip_EEPROM_Init(0); #endif // CY_PSOC6 } //! Handles the ongoing on-chip EEPROM tasks. /*! * First, it loops through all the on-chip EEPROM entries, and reads them in to RAM. * Then, it priodically loops through all the on-chip EEPROM entries, and saves the ones that have been flagged. */ void NVM_OnChipEEPROMTask(void * pvParameters) { portBASE_TYPE xStatus; static TickType_t xTicksToWait = pdMS_TO_TICKS(NVM_ON_CHIP_EEPROM_TASK_RATE_IN_ms); for (uint8_t i = 0; i < NVM_N_ONCHIP_EEPROM_ENTRIES; i++) { NVM_CRC_t calculated_crc; NVM_CRC_t stored_crc = 0; EEPROM_read_block(NVM_OnChipEEPROMEntries[i]->Value, NVM_OnChipEEPROMEntries[i]->EE_Address, NVM_OnChipEEPROMEntries[i]->Size); EEPROM_read_block((uint8_t *)&stored_crc, NVM_OnChipEEPROMEntries[i]->EE_CRC_Address, sizeof(NVM_CRC_t)); calculated_crc = NVM_CRC_init(); calculated_crc = NVM_CRC_update(calculated_crc, NVM_OnChipEEPROMEntries[i]->Value, NVM_OnChipEEPROMEntries[i]->Size); calculated_crc = NVM_CRC_finalize(calculated_crc); if (calculated_crc == stored_crc) { NVM_OnChipEEPROMEntries[i]->State = NVM_STATE_IDLE; } else { NVM_OnChipEEPROMEntries[i]->State = NVM_STATE_CRC_FAILED; COMM_Console_Print_String("[NVMOn "); COMM_Console_Print_UInt16((uint16_t) i); COMM_Console_Print_String("] Calculated/Stored CRCs: "); COMM_Console_Print_UInt16((uint16_t) calculated_crc); COMM_Console_Print_String("/"); COMM_Console_Print_UInt16((uint16_t) stored_crc); COMM_Console_Print_String("\n"); COMM_Console_Print_String("[NVMOn "); COMM_Console_Print_UInt16((uint16_t) i); COMM_Console_Print_String("] Applying defaults.\n"); memcpy(NVM_OnChipEEPROMEntries[i]->Value, NVM_OnChipEEPROMEntries[i]->Default, NVM_OnChipEEPROMEntries[i]->Size); // Auto-fix the CRC. NVM_SaveOnChipEEPROMEntry(NVM_OnChipEEPROMEntries[i]); } } taskENTER_CRITICAL(); NVM_IsOnChipEEPROMInitialized = true; taskEXIT_CRITICAL(); while(true) { uint8_t dummy; // Wait for a call to NVM_SaveOnChipEEPROMEntry(). xStatus = xQueueReceive(xQueueOnChipEEPROM, &dummy, xTicksToWait); if (xStatus == pdPASS) { for (uint8_t i = 0; i < NVM_N_ONCHIP_EEPROM_ENTRIES; i++) { NVM_CRC_t crc; #if (defined CY_PSOC4) || (defined CY_PSOC6) if (NVM_OnChipEEPROMEntries[i]->State == NVM_STATE_SAVE_REQUESTED) { if (xSemaphoreTake(xSemaphoreOnChipEEPROMLock, ( TickType_t ) 1000) == pdTRUE) { EEPROM_write_block(NVM_OnChipEEPROMEntries[i]->Value, NVM_OnChipEEPROMEntries[i]->EE_Address, NVM_OnChipEEPROMEntries[i]->Size); // Calculate the CRC. crc = NVM_CRC_init(); crc = NVM_CRC_update(crc, NVM_OnChipEEPROMEntries[i]->Value, NVM_OnChipEEPROMEntries[i]->Size); crc = NVM_CRC_finalize(crc); EEPROM_write_block((uint8_t *)&crc, NVM_OnChipEEPROMEntries[i]->EE_CRC_Address, sizeof(uint16_t)); NVM_OnChipEEPROMEntries[i]->State = NVM_STATE_IDLE; xSemaphoreGive(xSemaphoreOnChipEEPROMLock); } } #endif // (defined CY_PSOC4) || (defined CY_PSOC6) #if CY_PSOC5 // From the component datasheet: // "[On_Chip_EEPROM_UpdateTemperature()] updates the store temperature value. This should // be called anytime the EEPROM is active and temperature may have changed by more than // 10°C." if (On_Chip_EEPROM_UpdateTemperature() == CYRET_SUCCESS) { if (NVM_OnChipEEPROMEntries[i]->State == NVM_STATE_SAVE_REQUESTED) { if (On_Chip_EEPROM_Query() == CYRET_SUCCESS) { if (xSemaphoreTake(xSemaphoreOnChipEEPROMLock, ( TickType_t ) 1000) == pdTRUE) { EEPROM_write_block(NVM_OnChipEEPROMEntries[i]->Value, NVM_OnChipEEPROMEntries[i]->EE_Address, NVM_OnChipEEPROMEntries[i]->Size); // Calculate the CRC. crc = NVM_CRC_init(); crc = NVM_CRC_update(crc, NVM_OnChipEEPROMEntries[i]->Value, NVM_OnChipEEPROMEntries[i]->Size); crc = NVM_CRC_finalize(crc); EEPROM_write_block((uint8_t *)&crc, NVM_OnChipEEPROMEntries[i]->EE_CRC_Address, sizeof(uint16_t)); NVM_OnChipEEPROMEntries[i]->State = NVM_STATE_IDLE; xSemaphoreGive(xSemaphoreOnChipEEPROMLock); } } } } else { vSerialPutString("ERROR: Couldn't update EEPROM temperature!", 80); } #endif // CY_PSOC5 } } } } //! Flags the given on-chip EEPROM entry to be saved next time the NVM_OnChipEEPROMTask() is run. void NVM_SaveOnChipEEPROMEntry(NVM_EEPROMEntry_T * const this) { if (xSemaphoreTake(xSemaphoreOnChipEEPROMLock, ( TickType_t ) 1000) == pdTRUE) { this->State = NVM_STATE_SAVE_REQUESTED; xSemaphoreGive(xSemaphoreOnChipEEPROMLock); uint8_t dummy = 0; xQueueSend(xQueueOnChipEEPROM, &dummy, 0); } } /* Private Functions */