/************************************************************************** * * Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. * * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. * * @file InternalADC.c * * @date 08-Nov-2019 * @author S. Nash * * @brief Driver for the internal ADC peripheral. * **************************************************************************/ #include "adc.h" #include "InternalADC.h" // ********** private definitions ********** #define MAX_ADC_CHANNELS 24 // ADC supports up to 24 channels #define SIZE_OF_ROLLING_AVG 16 // samples in rolling average calculations #define ROLLING_AVG_SHIFT_DIVIDER 4 // rolling average shift divider const INT_ADC_CHANNEL_T adcChannelNum2ChannelId[ MAX_ADC_CHANNELS ] = { INT_ADC_DIAL_IN_PUMP_SPEED, // 0 INT_ADC_NOT_USED, // 1 INT_ADC_NOT_USED, // 2 INT_ADC_NOT_USED, // 3 INT_ADC_NOT_USED, // 4 INT_ADC_NOT_USED, // 5 INT_ADC_NOT_USED, // 6 INT_ADC_DIAL_IN_PUMP_MOTOR_CURRENT, // 7 INT_ADC_NOT_USED, // 8 INT_ADC_NOT_USED, // 9 INT_ADC_NOT_USED, // 10 INT_ADC_NOT_USED, // 11 INT_ADC_NOT_USED, // 12 INT_ADC_NOT_USED, // 13 INT_ADC_NOT_USED, // 14 INT_ADC_NOT_USED, // 15 INT_ADC_BLOOD_PUMP_SPEED, // 16 INT_ADC_BLOOD_PUMP_MOTOR_CURRENT, // 17 INT_ADC_DIAL_OUT_PUMP_SPEED, // 18 INT_ADC_DIAL_OUT_PUMP_MOTOR_CURRENT,// 19 INT_ADC_NOT_USED, // 20 INT_ADC_NOT_USED, // 21 INT_ADC_NOT_USED, // 22 INT_ADC_NOT_USED // 23 }; // ********** private data ********** static adcData_t adcRawReadings[ NUM_OF_INT_ADC_CHANNELS ]; // buffer holds latest adc channel readings static U32 adcRawReadingsCount = 0; // readings count for raw readings buffer static U16 adcReadings[ NUM_OF_INT_ADC_CHANNELS ][ SIZE_OF_ROLLING_AVG ]; // holds samples for each channel for a rolling average static U32 adcReadingsIdx[ NUM_OF_INT_ADC_CHANNELS ]; // index for next reading in each rolling average array static U32 adcReadingsTotals[ NUM_OF_INT_ADC_CHANNELS ]; // rolling total for each channel - used to calc average static U32 adcReadingsAvgs[ NUM_OF_INT_ADC_CHANNELS ]; // rolling average for each channel // ********** private function prototypes ********** /************************************************************************* * @brief initInternalADC * The initInternalADC function initializes the InternalADC module. * @details * Inputs : none * Outputs : InternalADC module is initialized. * @param none * @return none *************************************************************************/ void initInternalADC( void ) { U32 c,r; // zero all adc values and stats adcRawReadingsCount = 0; for ( c = 0; c < NUM_OF_INT_ADC_CHANNELS; c++ ) { adcRawReadings[ c ].id = 0; adcRawReadings[ c ].value = 0; adcReadingsIdx[ c ] = 0; adcReadingsTotals[ c ] = 0; adcReadingsAvgs[ c ] = 0; for ( r = 0; r < SIZE_OF_ROLLING_AVG; r++ ) { adcReadings[ c ][ r ] = 0; } } // enable interrupt when all channels converted adcEnableNotification( adcREG1, adcGROUP1 ); } /************************************************************************* * @brief adcNotification * The adcNotification function handles an ADC conversion complete interrupt. \n * All channel readings in the FIFO are retrieved. * @details * Inputs : ADC FIFO * Outputs : adcRawReadingsCount, adcRawReadings[] * @param adc : pointer to the ADC1 controller * @param group : ADC channel group ID * @return none *************************************************************************/ void adcNotification( adcBASE_t *adc, uint32 group ) { if ( adcGROUP1 == group ) { adcRawReadingsCount = adcGetData( adcREG1, adcGROUP1, adcRawReadings ); } } /************************************************************************* * @brief execInternalADC * The execInternalADC function processes the last set of raw ADC channel \n * readings and kicks off the next conversion of ADC channels. * @details * Inputs : adcRawReadingsCount, adcRawReadings[] * Outputs : adcReadings[][], adcReadingsIdx[], adcReadingsTotals[], adcReadingsAvgs[] * @param adc : pointer to the ADC1 controller * @param group : ADC channel group ID * @return none *************************************************************************/ void execInternalADC( void ) { U32 i; if ( adcRawReadingsCount < NUM_OF_INT_ADC_CHANNELS ) { // process readings from last conversion for ( i = 0; i < adcRawReadingsCount; i++ ) { U32 ch = adcChannelNum2ChannelId[ adcRawReadings[ i ].id ]; adcReadingsTotals[ ch ] -= adcReadings[ ch ][ adcReadingsIdx[ ch ] ]; adcReadings[ ch ][ adcReadingsIdx[ ch ] ] = adcRawReadings[i].value; adcReadingsTotals[ ch ] += adcRawReadings[ i ].value; adcReadingsAvgs[ ch ] = adcReadingsTotals[ ch ] >> ROLLING_AVG_SHIFT_DIVIDER; adcReadingsIdx[ ch ] = INC_WRAP( adcReadingsIdx[ ch ], 0, SIZE_OF_ROLLING_AVG - 1 ); } } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_INT_ADC_DATA_OVERRUN, adcRawReadingsCount ) } // start an adc channel group conversion adcStartConversion( adcREG1, adcGROUP1 ); } /************************************************************************* * @brief getIntADCReading * The getIntADCReading function gets the latest average reading for a given \n * channel. * @details * Inputs : adcReadingsAvgs[] * Outputs : none * @param channel : adc channel to retrieve a reading for * @return average reading for the given channel *************************************************************************/ U16 getIntADCReading( INT_ADC_CHANNEL_T channel ) { U16 result = 0; if ( channel < NUM_OF_INT_ADC_CHANNELS ) { result = adcReadingsAvgs[ channel ]; } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_INT_ADC_INVALID_CHANNEL_REQUESTED, channel ) } return result; }