Index: firmware/App/Controllers/LoadCell.c =================================================================== diff -u -rf308cc4c35eab630ebbbde405cfe47d049afeafb -rc20d71064bad67c2db392c6383bb410e8a7dfa2a --- firmware/App/Controllers/LoadCell.c (.../LoadCell.c) (revision f308cc4c35eab630ebbbde405cfe47d049afeafb) +++ firmware/App/Controllers/LoadCell.c (.../LoadCell.c) (revision c20d71064bad67c2db392c6383bb410e8a7dfa2a) @@ -8,16 +8,16 @@ * @file LoadCell.c * * @author (last) Quang Nguyen -* @date (last) 21-Jul-2020 +* @date (last) 26-Aug-2020 * * @author (original) Saeed Nejatali * @date (original) 25-Feb-2020 * ***************************************************************************/ +#include "FPGA.h" #include "LoadCell.h" #include "SystemCommMessages.h" -#include "FPGA.h" #include "TaskPriority.h" /** @@ -27,21 +27,28 @@ // ********** private definitions ********** -#define LOAD_CELL_REPORT_PERIOD (100 / TASK_PRIORITY_INTERVAL) ///< Broadcast load cell values message every 100 ms. -#define LOAD_CELL_SAMPLES_TO_AVERAGE LOAD_CELL_REPORT_PERIOD ///< Averaging load cell data over the reporting interval. -#define LOAD_CELL_AVERAGE_MULTIPLIER (1.0 / (F32)LOAD_CELL_SAMPLES_TO_AVERAGE) ///< Optimization - multiplying is faster than dividing. +#define LOAD_CELL_REPORT_PERIOD (100 / TASK_PRIORITY_INTERVAL) ///< Broadcast load cell values message every 100 ms. +#define LOAD_CELL_SAMPLES_TO_AVERAGE (100 / TASK_PRIORITY_INTERVAL) ///< Averaging load cell data over the reporting interval. +#define LOAD_CELL_AVERAGE_MULTIPLIER (1.0 / (F32)LOAD_CELL_SAMPLES_TO_AVERAGE) ///< Optimization - multiplying is faster than dividing. // TODO - gain and offset for load cells should be read from NV Data calibration record. -#define ADC2GRAM (0.0894 * 1.1338) ///< Conversion factor from ADC counts to grams. -#define LOAD_CELL_ZERO_OFFSET -1215.0 ///< Zero offset (in grams). TODO - right now, this is empty reservoir weight. +#define ADC2GRAM (0.0894 * 1.1338) ///< Conversion factor from ADC counts to grams. +#define LOAD_CELL_ZERO_OFFSET -1215.0 ///< Zero offset (in grams). TODO - right now, this is empty reservoir weight. +/// Load cell data structure +typedef struct +{ + U32 measuredReadingSum; ///< Raw load cell sums for averaging + OVERRIDE_F32_T filteredWeight; ///< Latest filtered load cell weights + F32 autoCalOffset; ///< Load cell auto-calibration offset +} LOADCELL_T; + // ********** private data ********** -static OVERRIDE_U32_T loadCellDataPublishInterval = { LOAD_CELL_REPORT_PERIOD, LOAD_CELL_REPORT_PERIOD, 0, 0 }; ///< Broadcast load cell data interval in ms/task interval. -static U32 measuredLoadCellReadingsRaw[ NUM_OF_LOAD_CELLS ]; ///< Latest measured raw load cell readings. -static U32 measuredLoadCellReadingsSum[ NUM_OF_LOAD_CELLS ]; ///< Raw load cell sums for averaging. -static OVERRIDE_F32_T filteredLoadCellWeights[ NUM_OF_LOAD_CELLS ]; ///< Latest filtered load cell weights. -static U32 loadCellFilterTimerCount = 0; ///< used to schedule load cell filtering. -static U32 loadCellDataPublicationTimerCounter = 0; ///< used to schedule load cell data publication to CAN bus. +static OVERRIDE_U32_T loadCellDataPublishInterval = { LOAD_CELL_REPORT_PERIOD, + LOAD_CELL_REPORT_PERIOD, 0, 0 }; ///< Broadcast load cell data publish interval. +static LOADCELL_T loadcells[ NUM_OF_LOAD_CELLS ]; ///< Load cell data structures. +static U32 loadCellFilterTimerCount = 0; ///< Load cell filtering timer count. +static U32 loadCellDataPublicationTimerCounter = 0; ///< Load cell data publication timer counter to CAN bus. // ********** private function prototypes ********** @@ -50,9 +57,8 @@ /*********************************************************************//** * @brief * The initLoadCell function initializes the LoadCell module. - * @details - * Inputs : none - * Outputs : LoadCell module initialized. + * @details Inputs: none + * @details Outputs: LoadCell module initialized. * @return none *************************************************************************/ void initLoadCell( void ) @@ -61,57 +67,48 @@ for ( i = 0; i < NUM_OF_LOAD_CELLS; i++ ) { - filteredLoadCellWeights[ i ].data = 0.0; - filteredLoadCellWeights[ i ].ovData = 0.0; - filteredLoadCellWeights[ i ].ovInitData = 0.0; - filteredLoadCellWeights[ i ].override = OVERRIDE_RESET; + loadcells[ i ].filteredWeight.data = 0.0; + loadcells[ i ].filteredWeight.ovData = 0.0; + loadcells[ i ].filteredWeight.ovInitData = 0.0; + loadcells[ i ].filteredWeight.override = OVERRIDE_RESET; - measuredLoadCellReadingsSum[ i ] = 0; - measuredLoadCellReadingsRaw[ i ] = 0; + loadcells[ i ].measuredReadingSum = 0; + loadcells[ i ].autoCalOffset = 0.0; } } /*********************************************************************//** * @brief - * The execLoadCell function gets load cell data from FPGA and advertises them over CAN. - * @details - * Inputs : none - * Outputs : Advertising load call data. + * The execLoadCell function gets load cell data from FPGA, applies filters, + * and advertises them over CAN. + * @details Inputs: none + * @details Outputs: Filtered and advertised load cell data. * @return none *************************************************************************/ -void execLoadCell(void) +void execLoadCell( void ) { - // get latest raw load cell readings - measuredLoadCellReadingsRaw[ LOAD_CELL_A1 ] = getFPGALoadCellA1(); - measuredLoadCellReadingsRaw[ LOAD_CELL_A2 ] = getFPGALoadCellA2(); - measuredLoadCellReadingsRaw[ LOAD_CELL_B1 ] = getFPGALoadCellB1(); - measuredLoadCellReadingsRaw[ LOAD_CELL_B2 ] = getFPGALoadCellB2(); + U32 ii; + // update sums for load cell average calculations - measuredLoadCellReadingsSum[ LOAD_CELL_A1 ] += measuredLoadCellReadingsRaw[ LOAD_CELL_A1 ]; - measuredLoadCellReadingsSum[ LOAD_CELL_A2 ] += measuredLoadCellReadingsRaw[ LOAD_CELL_A2 ]; - measuredLoadCellReadingsSum[ LOAD_CELL_B1 ] += measuredLoadCellReadingsRaw[ LOAD_CELL_B1 ]; - measuredLoadCellReadingsSum[ LOAD_CELL_B2 ] += measuredLoadCellReadingsRaw[ LOAD_CELL_B2 ]; + loadcells[ LOAD_CELL_RESERVOIR_1_PRIMARY ].measuredReadingSum += getFPGALoadCellA1(); + loadcells[ LOAD_CELL_RESERVOIR_1_BACKUP ].measuredReadingSum += getFPGALoadCellA2(); + loadcells[ LOAD_CELL_RESERVOIR_2_PRIMARY ].measuredReadingSum += getFPGALoadCellB1(); + loadcells[ LOAD_CELL_RESERVOIR_2_BACKUP ].measuredReadingSum += getFPGALoadCellB2(); // filter every 100ms if ( ++loadCellFilterTimerCount >= LOAD_CELL_SAMPLES_TO_AVERAGE ) { - loadCellFilterTimerCount = 0; + for ( ii = 0; ii < NUM_OF_LOAD_CELLS; ++ii ) + { + // calculate load cell average weights + loadcells[ ii ].filteredWeight.data = (F32)loadcells[ ii ].measuredReadingSum * LOAD_CELL_AVERAGE_MULTIPLIER * + ADC2GRAM + LOAD_CELL_ZERO_OFFSET - loadcells[ ii ].autoCalOffset; - // calculate load cell average weights - filteredLoadCellWeights[ LOAD_CELL_A1 ].data = (F32)measuredLoadCellReadingsSum[ LOAD_CELL_A1 ] * - LOAD_CELL_AVERAGE_MULTIPLIER * ADC2GRAM + LOAD_CELL_ZERO_OFFSET; - filteredLoadCellWeights[ LOAD_CELL_A2 ].data = (F32)measuredLoadCellReadingsSum[ LOAD_CELL_A2 ] * - LOAD_CELL_AVERAGE_MULTIPLIER * ADC2GRAM + LOAD_CELL_ZERO_OFFSET; - filteredLoadCellWeights[ LOAD_CELL_B1 ].data = (F32)measuredLoadCellReadingsSum[ LOAD_CELL_B1 ] * - LOAD_CELL_AVERAGE_MULTIPLIER * ADC2GRAM + LOAD_CELL_ZERO_OFFSET; - filteredLoadCellWeights[ LOAD_CELL_B2 ].data = (F32)measuredLoadCellReadingsSum[ LOAD_CELL_B2 ] * - LOAD_CELL_AVERAGE_MULTIPLIER * ADC2GRAM + LOAD_CELL_ZERO_OFFSET; + // reset sums for next averaging + loadcells[ ii ].measuredReadingSum = 0; + } - // reset sums for next averaging - measuredLoadCellReadingsSum[ LOAD_CELL_A1 ] = 0; - measuredLoadCellReadingsSum[ LOAD_CELL_A2 ] = 0; - measuredLoadCellReadingsSum[ LOAD_CELL_B1 ] = 0; - measuredLoadCellReadingsSum[ LOAD_CELL_B2 ] = 0; + loadCellFilterTimerCount = 0; } // broadcast load cell data if we are at scheduled interval. @@ -120,18 +117,43 @@ loadCellDataPublicationTimerCounter = 0; // broadcast load cell data - broadcastLoadCellData( getLoadCellFilteredWeight( LOAD_CELL_A1 ), getLoadCellFilteredWeight( LOAD_CELL_A2 ), - getLoadCellFilteredWeight( LOAD_CELL_B1 ), getLoadCellFilteredWeight( LOAD_CELL_B2 ) ); + broadcastLoadCellData( getLoadCellFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ), getLoadCellFilteredWeight( LOAD_CELL_RESERVOIR_1_BACKUP ), + getLoadCellFilteredWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ), getLoadCellFilteredWeight( LOAD_CELL_RESERVOIR_2_BACKUP ) ); } } /*********************************************************************//** * @brief - * The getLoadCellFilteredWeight function gets the measured filtered load cell \n + * The tareLoadCell function sets the load cell auto calibration offset + * for a given load cell ID. + * @details Inputs: none + * @details Outputs: load cell autoCalOffset + * @param loadCellID ID of load cell to set calibration offset for + *************************************************************************/ +void tareLoadCell( LOAD_CELL_ID_T loadCellID ) +{ + loadcells[ loadCellID ].autoCalOffset = loadcells[ loadCellID ].filteredWeight.data; +} + +/*********************************************************************//** + * @brief + * The resetLoadCellOffset function resets the load cell auto calibration offset + * to zero for a given load cell ID. + * @details Inputs: none + * @details Outputs: load cell autoCalOffset + * @param loadCellID ID of load cell to set calibration offset for + *************************************************************************/ +void resetLoadCellOffset( LOAD_CELL_ID_T loadCellID ) +{ + loadcells[ loadCellID ].autoCalOffset = 0.0; +} + +/*********************************************************************//** + * @brief + * The getLoadCellFilteredWeight function gets the measured filtered load cell * weight for a given load cell ID. - * @details - * Inputs : filteredLoadCellWeights[] - * Outputs : none + * @details Inputs: load cell filtered weight + * @details Outputs: none * @param loadCellID ID of load cell to get filtered weight for * @return the filtered load cell weight for the given load cell ID. *************************************************************************/ @@ -141,13 +163,13 @@ if ( loadCellID < NUM_OF_LOAD_CELLS ) { - if ( OVERRIDE_KEY == filteredLoadCellWeights[ loadCellID ].override ) + if ( OVERRIDE_KEY == loadcells[ loadCellID ].filteredWeight.override ) { - result = filteredLoadCellWeights[ loadCellID ].ovData; + result = loadcells[ loadCellID ].filteredWeight.ovData; } else { - result = filteredLoadCellWeights[ loadCellID ].data; + result = loadcells[ loadCellID ].filteredWeight.data; } } else @@ -160,11 +182,9 @@ /*********************************************************************//** * @brief - * The getLoadCellDataPublishInterval function gets the load cell data \n - * publication interval. - * @details - * Inputs : loadCellDataPublishInterval - * Outputs : none + * The getLoadCellDataPublishInterval function gets the load cell data publish interval. + * @details Inputs: loadCellDataPublishInterval + * @details Outputs: none * @return the current load cell data publication interval (in ms/task interval). *************************************************************************/ static U32 getLoadCellDataPublishInterval( void ) @@ -187,11 +207,9 @@ /*********************************************************************//** * @brief - * The testSetLoadCellOverride function overrides the measured \n - * load cell A1. - * @details - * Inputs : none - * Outputs : filteredLoadCellWeights[] + * The testSetLoadCellOverride function overrides the measured load cell data. + * @details Inputs: none + * @details Outputs: load cell filtered weight * @param loadCellID ID of the load cell to override * @param value override filtered load cell weight * @return TRUE if override successful, FALSE if not @@ -205,8 +223,8 @@ if ( TRUE == isTestingActivated() ) { result = TRUE; - filteredLoadCellWeights[ loadCellID ].ovData = value; - filteredLoadCellWeights[ loadCellID ].override = OVERRIDE_KEY; + loadcells[ loadCellID ].filteredWeight.ovData = value; + loadcells[ loadCellID ].filteredWeight.override = OVERRIDE_KEY; } } @@ -215,11 +233,9 @@ /*********************************************************************//** * @brief - * The testResetLoadCellOverride function resets the override of the \n - * load cell A1. - * @details - * Inputs : none - * Outputs : filteredLoadCellWeights[] + * The testResetLoadCellOverride function resets the override of the load cell. + * @details Inputs: none + * @details Outputs: load cell filtered weight * @param loadCellID ID of the load cell to override * @return TRUE if reset successful, FALSE if not *************************************************************************/ @@ -232,8 +248,8 @@ if ( TRUE == isTestingActivated() ) { result = TRUE; - filteredLoadCellWeights[ loadCellID ].override = OVERRIDE_RESET; - filteredLoadCellWeights[ loadCellID ].ovData = filteredLoadCellWeights[ loadCellID ].ovInitData; + loadcells[ loadCellID ].filteredWeight.override = OVERRIDE_RESET; + loadcells[ loadCellID ].filteredWeight.ovData = loadcells[ loadCellID ].filteredWeight.ovInitData; } } @@ -242,11 +258,10 @@ /*********************************************************************//** * @brief - * The testSetLoadCellDataPublishIntervalOverride function overrides the \n + * The testSetLoadCellDataPublishIntervalOverride function overrides the * load cell data publish interval. - * @details - * Inputs : none - * Outputs : loadCellDataPublishInterval + * @details Inputs: none + * @details Outputs: loadCellDataPublishInterval * @param value override load cell data publish interval with (in ms) * @return TRUE if override successful, FALSE if not *************************************************************************/ @@ -268,11 +283,10 @@ /*********************************************************************//** * @brief - * The testResetLoadCellDataPublishIntervalOverride function resets the override \n + * The testResetLoadCellDataPublishIntervalOverride function resets the override * of the load cell data publish interval. - * @details - * Inputs : none - * Outputs : loadCellDataPublishInterval + * @details Inputs: none + * @details Outputs: loadCellDataPublishInterval * @return TRUE if override reset successful, FALSE if not *************************************************************************/ BOOL testResetLoadCellDataPublishIntervalOverride( void )