Initial public release.

This commit is contained in:
Joe Kearney 2025-02-01 19:22:12 -06:00
parent 7b169e8116
commit dac4af8d25
255 changed files with 68595 additions and 2 deletions

View file

@ -0,0 +1,302 @@
/** \file
* \brief This file contains functions that manage the external EEPROM.
*
*/
/* Include Files */
#include "KTag.h"
/* Local Definitions and Constants */
//! This is the same for both the MCP98243 and the CAT24C256.
#define EXTERNAL_EEPROM_I2C_ADDRESS 0x50
#define EXTERNAL_EEPROM_TEMP_SENSOR_I2C_ADDRESS 0x18
//! Read-only register used to identify the temperature sensor capability.
#define MCP98243_REGISTER_CAPABILITY 0x00
//! Sensor configuration register.
#define MCP98243_REGISTER_CONFIG 0x01
//! Upper temperature limit register.
#define MCP98243_REGISTER_T_UPPER 0x02
//! Lower temperature limit register.
#define MCP98243_REGISTER_T_LOWER 0x03
//! Critical temperature limit register.
#define MCP98243_REGISTER_T_CRIT 0x04
//! Ambient temperature register.
#define MCP98243_REGISTER_T_A 0x05
//! Read-only register used to identify the manufacturer of the device.
#define MCP98243_REGISTER_MANUFACTURER_ID 0x06
//! Read-only register indicating the device identification and device revision.
#define MCP98243_REGISTER_DEVICE_ID 0x07
//! Temperature sensor resolution register.
#define MCP98243_REGISTER_RESOLUTION 0x08
/* 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 xSemaphoreExternalEEPROMLock;
TaskHandle_t NVM_ExternalEEPROM_Task_Handle;
volatile bool NVM_IsExternalEEPROMInitialized = false;
/* Private Variables */
static QueueHandle_t xQueueExternalEEPROM;
//! Shared master transfer configuration variable.
static cy_stc_scb_i2c_master_xfer_config_t Master_Transfer_Config =
{
.slaveAddress = EXTERNAL_EEPROM_I2C_ADDRESS,
.buffer = NULL,
.bufferSize = 0U,
.xferPending = false
};
/* Private Function Prototypes */
/* Inline Functions */
//! Waits a given time for an I²C transfer to complete.
/*!
* \param timeout_in_ms The time (in milliseconds) to wait for the transfer to complete.
* \return #true if the transfer completed, or #false if the time ran out without
* a successful transfer.
*/
static inline bool Wait_For_Transfer_To_Complete(uint16_t timeout_in_ms)
{
bool success = false;
// Time to wait for an in-process transfer before looking again. This wait grows longer as time
// passes, until timeout_in_ms runs out.
uint16_t HOLDOFF_TIME_IN_ms = 1;
while ((success == false) && (timeout_in_ms > 0))
{
vTaskDelay(pdMS_TO_TICKS(HOLDOFF_TIME_IN_ms));
if (timeout_in_ms > HOLDOFF_TIME_IN_ms)
{
timeout_in_ms -= HOLDOFF_TIME_IN_ms;
// Wait a little longer next time.
HOLDOFF_TIME_IN_ms++;
}
else
{
timeout_in_ms = 0;
}
if ((I2C_MasterGetStatus() & CY_SCB_I2C_MASTER_BUSY) != CY_SCB_I2C_MASTER_BUSY)
{
success = true;
}
}
return success;
}
//! 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)
{
uint8_t xfer_buffer[5];
if (xSemaphoreTake(COMM_I2C_Bus_Mutex, portMAX_DELAY) == pdTRUE)
{
// Write the initial address to the EEPROM.
xfer_buffer[0] = (source >> 8);
xfer_buffer[1] = source & 0xFF;
Master_Transfer_Config.buffer = (uint8_t *)xfer_buffer;
Master_Transfer_Config.bufferSize = 2;
cy_en_scb_i2c_status_t errStatus = I2C_MasterWrite(&Master_Transfer_Config);
if (errStatus == CY_SCB_I2C_SUCCESS)
{
(void) Wait_For_Transfer_To_Complete(100);
}
else
{
// What?
}
// Read n bytes at EEPROM[source].
Master_Transfer_Config.buffer = (uint8_t *)destination;
Master_Transfer_Config.bufferSize = n;
errStatus = I2C_MasterRead(&Master_Transfer_Config);
if (errStatus == CY_SCB_I2C_SUCCESS)
{
(void) Wait_For_Transfer_To_Complete(100);
}
else
{
// What?
}
xSemaphoreGive(COMM_I2C_Bus_Mutex);
}
}
//! 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)
{
uint8_t xfer_buffer[4];
if (xSemaphoreTake(COMM_I2C_Bus_Mutex, portMAX_DELAY) == pdTRUE)
{
// Write the data one byte at a time.
for (uint8_t i = 0; i < n; i++)
{
uint16_t destination_address = destination + i;
xfer_buffer[0] = (destination_address >> 8);
xfer_buffer[1] = destination_address & 0xFF;
xfer_buffer[2] = *(source + i);
Master_Transfer_Config.buffer = (uint8_t *)xfer_buffer;
Master_Transfer_Config.bufferSize = 3;
cy_en_scb_i2c_status_t errStatus = I2C_MasterWrite(&Master_Transfer_Config);
if (errStatus == CY_SCB_I2C_SUCCESS)
{
(void) Wait_For_Transfer_To_Complete(100);
}
else
{
// What?
}
// The CAT24C256 has a nominal Write Cycle time (t_WR) of 5ms (no maximum specified).
// Wait 6ms between writes to have some margin (and avoid being NAKed).
vTaskDelay(pdMS_TO_TICKS(6));
}
xSemaphoreGive(COMM_I2C_Bus_Mutex);
}
}
/* Public Functions */
//! Sets up the external EEPROM, but does not read from it (yet).
void NVM_InitExternalEEPROM(void)
{
/// Create a mutex-type semaphore.
xSemaphoreExternalEEPROMLock = xSemaphoreCreateMutex();
if (xSemaphoreExternalEEPROMLock == NULL)
{
CY_ASSERT(0);
}
xQueueExternalEEPROM = xQueueCreate(5, sizeof(uint8_t));
}
//! Handles the ongoing external EEPROM tasks.
/*!
* First, it loops through all the external EEPROM entries, and reads them in to RAM.
* Then, it priodically loops through all the external EEPROM entries, and saves the ones that have been flagged.
*/
void NVM_ExternalEEPROMTask(void * pvParameters)
{
portBASE_TYPE xStatus;
static TickType_t xTicksToWait = pdMS_TO_TICKS(NVM_EXTERNAL_EEPROM_TASK_RATE_IN_ms);
for (uint8_t i = 0; i < NVM_N_EXTERNAL_EEPROM_ENTRIES; i++)
{
NVM_CRC_t calculated_crc;
NVM_CRC_t stored_crc = 0;
EEPROM_read_block(NVM_ExternalEEPROMEntries[i]->Value, NVM_ExternalEEPROMEntries[i]->EE_Address, NVM_ExternalEEPROMEntries[i]->Size);
EEPROM_read_block((uint8_t *)&stored_crc, NVM_ExternalEEPROMEntries[i]->EE_CRC_Address, sizeof(NVM_CRC_t));
calculated_crc = NVM_CRC_init();
calculated_crc = NVM_CRC_update(calculated_crc, NVM_ExternalEEPROMEntries[i]->Value, NVM_ExternalEEPROMEntries[i]->Size);
calculated_crc = NVM_CRC_finalize(calculated_crc);
if (calculated_crc == stored_crc)
{
NVM_ExternalEEPROMEntries[i]->State = NVM_STATE_IDLE;
}
else
{
NVM_ExternalEEPROMEntries[i]->State = NVM_STATE_CRC_FAILED;
COMM_Console_Print_String("[NVMEx ");
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("[NVMEx ");
COMM_Console_Print_UInt16((uint16_t) i);
COMM_Console_Print_String("] Applying defaults.\n");
memcpy(NVM_ExternalEEPROMEntries[i]->Value, NVM_ExternalEEPROMEntries[i]->Default, NVM_ExternalEEPROMEntries[i]->Size);
// Auto-fix the CRC.
NVM_SaveExternalEEPROMEntry(NVM_ExternalEEPROMEntries[i]);
}
}
taskENTER_CRITICAL();
NVM_IsExternalEEPROMInitialized = true;
taskEXIT_CRITICAL();
while(true)
{
uint8_t dummy;
// Wait for a call to NVM_SaveExternalEEPROMEntry().
xStatus = xQueueReceive(xQueueExternalEEPROM, &dummy, xTicksToWait);
if (xStatus == pdPASS)
{
for (uint8_t i = 0; i < NVM_N_EXTERNAL_EEPROM_ENTRIES; i++)
{
NVM_CRC_t crc;
if (NVM_ExternalEEPROMEntries[i]->State == NVM_STATE_SAVE_REQUESTED)
{
if (xSemaphoreTake(xSemaphoreExternalEEPROMLock, portMAX_DELAY) == pdTRUE)
{
EEPROM_write_block(NVM_ExternalEEPROMEntries[i]->Value, NVM_ExternalEEPROMEntries[i]->EE_Address, NVM_ExternalEEPROMEntries[i]->Size);
// Calculate the CRC.
crc = NVM_CRC_init();
crc = NVM_CRC_update(crc, NVM_ExternalEEPROMEntries[i]->Value, NVM_ExternalEEPROMEntries[i]->Size);
crc = NVM_CRC_finalize(crc);
EEPROM_write_block((uint8_t *)&crc, NVM_ExternalEEPROMEntries[i]->EE_CRC_Address, sizeof(uint16_t));
NVM_ExternalEEPROMEntries[i]->State = NVM_STATE_IDLE;
xSemaphoreGive(xSemaphoreExternalEEPROMLock);
}
}
}
}
}
}
//! Flags the given external EEPROM entry to be saved next time the NVM_ExternalEEPROMTask() is run.
void NVM_SaveExternalEEPROMEntry(NVM_EEPROMEntry_T * const this)
{
if (xSemaphoreTake(xSemaphoreExternalEEPROMLock, portMAX_DELAY) == pdTRUE)
{
this->State = NVM_STATE_SAVE_REQUESTED;
xSemaphoreGive(xSemaphoreExternalEEPROMLock);
uint8_t dummy = 0;
xQueueSend(xQueueExternalEEPROM, &dummy, 0);
}
}
/* Private Functions */