651 lines
21 KiB
C
651 lines
21 KiB
C
/******************************************************************************/
|
|
/* Copyright (c) 2016 MD Automotive Controls. */
|
|
/* All rights reserved. */
|
|
/******************************************************************************/
|
|
/* */
|
|
/* PACKAGE TITLE: LSUH */
|
|
/* DESCRIPTION: This code module initialises the required ADC, DAC */
|
|
/* CTRL, spread, table, DIO and TEPM resources for */
|
|
/* managing the heater control for the LSU4.X sensor/s */
|
|
/* */
|
|
/* FILE NAME: LSUH.c */
|
|
/* REVISION HISTORY: 07-03-2016 | 1.0 | Initial revision */
|
|
/* */
|
|
/******************************************************************************/
|
|
#define _LSUH_C
|
|
|
|
/******************************************************************************/
|
|
/* HEADER FILES */
|
|
/******************************************************************************/
|
|
#include "build.h"
|
|
|
|
#ifdef BUILD_USER
|
|
|
|
#include "LSUH.h"
|
|
#include "USERMATH.h"
|
|
|
|
/* LOCAL MACRO DEFINITIONS ****************************************************/
|
|
#define LSUH_nADConfigCount (sizeof(LSUH_rastADConfig) / sizeof(LSUH_tstADConfig))
|
|
|
|
/* LOCAL VARIABLE DEFINITIONS (STATIC) ****************************************/
|
|
#ifdef LSUH_TEPM
|
|
TEPMAPI_tstTimedEvent LSUH_aastTimedEvents[LSU_DEVICE_COUNT][TEPMAPI_nEventsMax];
|
|
#endif //LSUH_TEPM
|
|
uint32 LSUH_au32TEPMTimeout[LSU_DEVICE_COUNT];
|
|
uint32 LSUH_u32HeaterDutyMax;
|
|
uint32 LSUH_au32HeaterLowADCOnRaw[LSU_DEVICE_COUNT];
|
|
uint32 LSUH_au32HeaterLowADCOffRaw[LSU_DEVICE_COUNT];
|
|
uint32 LSUH_au32HeaterLowADCDeltaFiltered[LSU_DEVICE_COUNT];
|
|
GPM6_ttVolts LSUH_atHeaterSenseVolts[LSU_DEVICE_COUNT];/*CR1_54*/
|
|
GPM6_ttAmps LSUH_atHeaterAmps[LSU_DEVICE_COUNT];/*CR1_54*/
|
|
GPM6_ttMilliVolts LSUH_tHeaterEffMax;/*CR1_54*/
|
|
GPM6_ttMilliWatts LSUH_atHeaterPower[LSU_DEVICE_COUNT];
|
|
bool LSUH_aboADCQueuePending[LSU_DEVICE_COUNT];
|
|
CTRLAPI_ttPIDIDX LSUH_atPIDLSUH1IDX[LSU_DEVICE_COUNT];
|
|
sint32 LSUH_ai32PIDTarget[LSU_DEVICE_COUNT];
|
|
sint32 LSUH_ai32PIDFeedback[LSU_DEVICE_COUNT];
|
|
sint32 LSUH_ai32PIDOutput[LSU_DEVICE_COUNT];
|
|
uint32 LSUH_au32ACSampleCounter[LSU_DEVICE_COUNT];
|
|
bool LSUH_aboNernstRNewValue[LSU_DEVICE_COUNT];
|
|
uint32 LSUH_au32NoNewNernstValueCount[LSU_DEVICE_COUNT];
|
|
bool LSUH_aboNernstTempMode[LSU_DEVICE_COUNT];
|
|
|
|
|
|
/* LOCAL FUNCTION PROTOTYPES (STATIC) *****************************************/
|
|
/*******************************************************************************
|
|
* Interface : LSUH_vADCCallBack
|
|
*
|
|
* Implementation : Callback to receive the measured ADC value
|
|
*
|
|
* Parameter
|
|
* Par1 : enEHIOResource enum of the ADC resource
|
|
* Par2 : u32ADCResult the ADC conversion value
|
|
*
|
|
* Return Value : NIL
|
|
*******************************************************************************/
|
|
static void LSUH_vADCCallBack(IOAPI_tenEHIOResource enEHIOResource, uint32 u32ADCResult);/*CR1_53*/
|
|
|
|
/*******************************************************************************
|
|
* Interface : LSUH_vInitiateTEPMQueue
|
|
*
|
|
* Implementation : Function to initiate a new TEPM queue timed output
|
|
*
|
|
* Parameter
|
|
* Par1 : enEHIOResource enum of the timer resource
|
|
* Par2 : tEventTime the timer value at the last timer event of interest
|
|
*
|
|
* Return Value : NIL
|
|
*******************************************************************************/
|
|
#ifdef LSUH_TEPM
|
|
static void LSUH_vInitiateTEPMQueue(IOAPI_tenEHIOResource enEHIOResource, TEPMAPI_ttEventTime tEventTime);
|
|
#endif //LSUH_TEPM
|
|
|
|
/* LOCAL CONSTANT DEFINITIONS (STATIC) ****************************************/
|
|
const LSUH_tstADConfig LSUH_rastADConfig[] = LSUH_nADConfig;
|
|
|
|
|
|
/* GLOBAL FUNCTION DEFINITIONS ************************************************/
|
|
void LSUH_vStart(uint32 * const pu32Arg)
|
|
{
|
|
IOAPI_tenEHIOResource enEHIOResource;
|
|
IOAPI_tenEHIOType enEHIOType;
|
|
ADCAPI_tstADCCB stADCCB;
|
|
CTRLAPI_tstPIDCB stPIDCB;
|
|
CTRLAPI_tenCTRLType enCTRLType;
|
|
|
|
IOAPI_tenDriveStrength enDriveStrength = IOAPI_enWeak;
|
|
uint32 u32ADConfigIDX;
|
|
bool boInitFailed = FALSE;
|
|
|
|
#ifdef BUILD_SPARKDOG_PF
|
|
/* not yet tested */
|
|
return;
|
|
#endif
|
|
|
|
LSUH_tHeaterEffMax = LSUH_nHeaterEffInit;
|
|
LSUH_au32ACSampleCounter[0] = 0;
|
|
|
|
#ifdef LSUH_TEPM
|
|
TEPMAPI_tstTEPMResourceCB stTEPMResourceCB;
|
|
TEPMAPI_tstTEPMChannelCB stTEPMChannelCB;
|
|
|
|
/* Request and initialise FTM for EH_IO_TMR15 and EH_IO_TMR16 */
|
|
enEHIOResource = EH_VIO_FTM0;
|
|
enEHIOType = IOAPI_enTEPM;
|
|
USER_vSVC(SYSAPI_enRequestIOResource, (void*)&enEHIOResource, (void*)NULL, (void*)NULL);
|
|
|
|
if (SYSAPI_enOK == pstSVCDataStruct->enSVCResult)
|
|
{
|
|
stTEPMResourceCB.enEHIOResource = EH_VIO_FTM0;
|
|
stTEPMResourceCB.enPreScalar = TEPMAPI_enDiv32;
|
|
stTEPMResourceCB.enCountType = TEPMAPI_enCountUp;
|
|
|
|
USER_vSVC(SYSAPI_enInitialiseIOResource, (void*)&enEHIOResource,
|
|
(void*)&enEHIOType, (void*)&stTEPMResourceCB);
|
|
}
|
|
|
|
/* Request and initialise EH_IO_TMR15 */
|
|
enEHIOResource = EH_IO_TMR15;
|
|
enEHIOType = IOAPI_enCaptureCompare;
|
|
USER_vSVC(SYSAPI_enRequestIOResource, (void*)&enEHIOResource, (void*)NULL, (void*)NULL);
|
|
|
|
/* Initialise the TEPM channel EH_IO_TMR15 */
|
|
if (SYSAPI_enOK == pstSVCDataStruct->enSVCResult)
|
|
{
|
|
stTEPMChannelCB.enAction = TEPMAPI_enToggle;
|
|
stTEPMChannelCB.boInterruptEnable = TRUE;
|
|
|
|
USER_vSVC(SYSAPI_enInitialiseIOResource, (void*)&enEHIOResource,
|
|
(void*)&enEHIOType, (void*)&stTEPMChannelCB);
|
|
}
|
|
|
|
/* Request and initialise EH_IO_TMR16 */
|
|
enEHIOResource = EH_IO_TMR16;
|
|
enEHIOType = IOAPI_enCaptureCompare;
|
|
USER_vSVC(SYSAPI_enRequestIOResource, (void*)&enEHIOResource, (void*)NULL, (void*)NULL);
|
|
|
|
/* Initialise the TEPM channel EH_IO_TMR16 */
|
|
if (SYSAPI_enOK == pstSVCDataStruct->enSVCResult)
|
|
{
|
|
stTEPMChannelCB.enAction = TEPMAPI_enToggle;
|
|
stTEPMChannelCB.boInterruptEnable = TRUE;
|
|
|
|
USER_vSVC(SYSAPI_enInitialiseIOResource, (void*)&enEHIOResource,
|
|
(void*)&enEHIOType, (void*)&stTEPMChannelCB);
|
|
}
|
|
#endif //LSUH_TEPM
|
|
|
|
/* Request and initialise AD converter resources */
|
|
for (u32ADConfigIDX = 0; u32ADConfigIDX < LSUH_nADConfigCount; u32ADConfigIDX++)
|
|
{
|
|
enEHIOResource = LSUH_rastADConfig[u32ADConfigIDX].enEHIOResource;
|
|
enEHIOType = LSUH_rastADConfig[u32ADConfigIDX].enEHIOType;
|
|
stADCCB.enSamplesAv = LSUH_rastADConfig[u32ADConfigIDX].enSamplesAv;
|
|
stADCCB.pfResultCB = LSUH_rastADConfig[u32ADConfigIDX].pfResultCB;
|
|
stADCCB.enTrigger = LSUH_rastADConfig[u32ADConfigIDX].enTrigger;
|
|
|
|
USER_vSVC(SYSAPI_enRequestIOResource, (void*)&enEHIOResource, (void*)NULL, (void*)NULL);
|
|
|
|
if (SYSAPI_enOK == pstSVCDataStruct->enSVCResult)
|
|
{
|
|
USER_vSVC(SYSAPI_enInitialiseIOResource, (void*)&enEHIOResource,
|
|
(void*)&enEHIOType, (void*)&stADCCB);
|
|
|
|
if (SYSAPI_enOK != pstSVCDataStruct->enSVCResult) boInitFailed = TRUE;
|
|
}
|
|
else
|
|
{
|
|
boInitFailed = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Initialise HMEN enable control lines */
|
|
if (SYSAPI_enOK == pstSVCDataStruct->enSVCResult)
|
|
{
|
|
enEHIOResource = LSUH_nHMENResource;
|
|
enEHIOType = IOAPI_enDIOOutput;
|
|
enDriveStrength = IOAPI_enStrong;
|
|
|
|
USER_vSVC(SYSAPI_enRequestIOResource, (void*)&enEHIOResource, (void*)NULL, (void*)NULL);
|
|
|
|
if (SYSAPI_enOK == pstSVCDataStruct->enSVCResult)
|
|
{
|
|
USER_vSVC(SYSAPI_enInitialiseIOResource, (void*)&enEHIOResource,
|
|
(void*)&enEHIOType, (void*)&enDriveStrength);
|
|
|
|
if (SYSAPI_enOK != pstSVCDataStruct->enSVCResult) boInitFailed = TRUE;
|
|
}
|
|
else
|
|
{
|
|
boInitFailed = TRUE;
|
|
}
|
|
}
|
|
|
|
/* Request and initialise the LSUH1 PID controller */
|
|
stPIDCB.enPIDRate = CTRLAPI_enPIDCall;
|
|
stPIDCB.pi32Target = &LSUH_ai32PIDTarget[0];
|
|
stPIDCB.pi32Feedback = &LSUH_ai32PIDFeedback[0];
|
|
stPIDCB.pi32Output = &LSUH_ai32PIDOutput[0];
|
|
stPIDCB.u8PTerm = 0xFF;
|
|
stPIDCB.u8ITerm = 0x03;
|
|
stPIDCB.u8DTerm = 0x08;
|
|
stPIDCB.boNoWindUp = TRUE;
|
|
stPIDCB.boReset = FALSE;
|
|
stPIDCB.boResetIntegrator = FALSE;
|
|
stPIDCB.boRun = TRUE;
|
|
stPIDCB.i32OutputMin = -2500000;
|
|
stPIDCB.i32OutputMax = 2500000;
|
|
enCTRLType = CTRLAPI_enPID;
|
|
|
|
USER_vSVC(SYSAPI_enInitialiseCTRLResource, (void*)&enCTRLType, (void*)&stPIDCB, NULL);
|
|
|
|
LSUH_atPIDLSUH1IDX[0] = (SYSAPI_enOK == pstSVCDataStruct->enSVCResult) ?
|
|
(CTRLAPI_ttPIDIDX)pstSVCDataStruct->tClientHandle : -1;
|
|
|
|
*pu32Arg = ((SYSAPI_enOK == pstSVCDataStruct->enSVCResult) && !boInitFailed) ?
|
|
*pu32Arg | SYSAPI_CALL_MASK_FAIL_RES_INIT :
|
|
*pu32Arg & ~SYSAPI_CALL_MASK_FAIL_RES_INIT;
|
|
|
|
|
|
/* Initialise variables */
|
|
LSUH_au32TEPMTimeout[0] = ~0;
|
|
LSUH_au32HeaterDuty[0] = 80 * LSU_DUTY_RES;
|
|
LSUH_ai32PIDTarget[0] = 300000u;
|
|
LSUH_au32ACADCDeltaFiltered[0] = 0;
|
|
LSUH_au32HeaterLowADCDeltaFiltered[0] = 0;
|
|
LSUH_aboSensorReady[0] = FALSE;
|
|
LSU4X_atNernstSenseOhms[0] = 1000000u;
|
|
}
|
|
|
|
void LSUH_vRun(uint32* const pu32Arg )
|
|
{
|
|
uint32 u32Temp;
|
|
uint32 u32MaxDuty;
|
|
CTRLAPI_tenCTRLType enCTRLType;
|
|
ADCAPI_tenTrigger enTrigger = ADCAPI_enTrigger3;
|
|
static uint32 u32RunCount = 0;/*CR1_56*/;
|
|
static uint32 u32TempControllerRunCount;
|
|
|
|
#ifdef BUILD_SPARKDOG_PF
|
|
/* not yet tested */
|
|
return;
|
|
#endif
|
|
|
|
if (0 == (u32RunCount++ % (uint32)LSUH_nCallsIn100Ms))/*CR1_57*/
|
|
{
|
|
LSUH_tHeaterEffMax = (LSUH_nHeffVLimit > LSUH_tHeaterEffMax) ?
|
|
LSUH_tHeaterEffMax + (LSUH_nHeffVRampRate / LSUH_nRateHZ) : LSUH_tHeaterEffMax; /*CR1_57*/
|
|
}
|
|
|
|
|
|
#ifdef LSUH_TEPM
|
|
enEHIOResourceTimer = (0 == u32LSUDeviceIDX ) ? EH_IO_TMR15 : EH_IO_TMR16;
|
|
enEHIOResourceADC = (0 == u32LSUDeviceIDX ) ? EH_IO_ADSE8 : EH_IO_ADSE9;
|
|
|
|
/* Catch a lost TEPM for heater */
|
|
if (10000 < LSUH_au32TEPMTimeout[u32LSUDeviceIDX]++)
|
|
{
|
|
LSUH_vInitiateTEPMQueue(enEHIOResourceTimer, 0u);
|
|
}
|
|
#endif //LSUH_TEPM
|
|
|
|
/* ADC pending flags are expected to be syncronised... */
|
|
if (TRUE == LSUH_aboADCQueuePending[0])
|
|
{
|
|
USER_vSVC(SYSAPI_enTriggerADQueue, (void*)&enTrigger, NULL, NULL);
|
|
LSUH_aboADCQueuePending[0] = FALSE;
|
|
}
|
|
|
|
/* Iterate the heater PID controller if new R value */
|
|
if (TRUE == LSUH_aboNernstRNewValue[0])
|
|
{
|
|
enCTRLType = CTRLAPI_enPID;
|
|
|
|
USER_vSVC(SYSAPI_enIterateCTRLResource, (void*)&enCTRLType, (void*)&LSUH_atPIDLSUH1IDX[0], NULL);
|
|
LSUH_aboNernstRNewValue[0] = FALSE;
|
|
|
|
LSUH_au32NoNewNernstValueCount[0] =
|
|
200 < LSUH_au32NoNewNernstValueCount[0] ?
|
|
LSUH_au32NoNewNernstValueCount[0] - 200 : 0;
|
|
|
|
LSUH_aboNernstTempMode[0] = 0 == LSUH_au32NoNewNernstValueCount[0] ? TRUE :
|
|
LSUH_aboNernstTempMode[0];
|
|
|
|
u32TempControllerRunCount = 0;
|
|
}
|
|
else
|
|
{
|
|
LSUH_au32NoNewNernstValueCount[0] =
|
|
1000 > LSUH_au32NoNewNernstValueCount[0] ?
|
|
LSUH_au32NoNewNernstValueCount[0] + 1 : LSUH_au32NoNewNernstValueCount[0];
|
|
|
|
LSUH_aboNernstTempMode[0] = 999 < LSUH_au32NoNewNernstValueCount[0] ? FALSE :
|
|
LSUH_aboNernstTempMode[0];
|
|
}
|
|
|
|
/* Run the alternate heater resistance based controller if required */
|
|
if ((FALSE == LSUH_aboNernstTempMode[0]) && (0 == (++u32TempControllerRunCount % 40)))
|
|
{
|
|
u32Temp = LSUH_atHeaterOhms[0];
|
|
u32Temp = 14400 > u32Temp ? u32Temp : 14400;
|
|
LSU4X_atNernstSenseOhms[0] = (14400 - u32Temp) * 42;
|
|
|
|
enCTRLType = CTRLAPI_enPID;
|
|
USER_vSVC(SYSAPI_enIterateCTRLResource, (void*)&enCTRLType, (void*)&LSUH_atPIDLSUH1IDX[0], NULL);
|
|
}
|
|
|
|
|
|
|
|
LSUH_atHeaterSenseVolts[0] = CONV_tADCToVolts(
|
|
EH_IO_UART1_CTS, LSUH_au32HeaterLowADCDeltaFiltered[0]);
|
|
|
|
LSUH_atHeaterAmps[0] = CONV_tOhmsVoltsToAmps(LSUH_nHeaterSenseOhms, LSUH_atHeaterSenseVolts[0]);
|
|
LSUH_atHeaterOhms[0] = CONV_tVoltsAmpsToOhms(BVM_tBattVolts - LSUH_atHeaterSenseVolts[0] - 800u,
|
|
LSUH_atHeaterAmps[0]);
|
|
|
|
LSUH_ai32PIDFeedback[0] = LSU4X_atNernstSenseOhms[0];
|
|
LSUH_atHeaterPower[0] = (10000000 - (3 * LSUH_ai32PIDOutput[0])) / 1000;
|
|
|
|
/* Calculate the maximum duty cycle sustained by the current sense resistors */
|
|
u32MaxDuty = (1000000u * (uint32)LSUH_nMaxDutyDenom) / LSUH_atHeaterAmps[0];
|
|
u32MaxDuty /= LSUH_atHeaterAmps[0];
|
|
|
|
/* Calculated the duty cycle to deliver requested power (n = Preq / VI))*/
|
|
u32Temp = LSUH_atHeaterPower[0] * 1000u;
|
|
u32Temp /= (BVM_tBattVolts - LSUH_atHeaterSenseVolts[0] - 800u);
|
|
u32Temp *= 1000;
|
|
u32Temp /= LSUH_atHeaterAmps[0];
|
|
u32Temp = (u32MaxDuty > u32Temp) ? u32Temp : u32MaxDuty;
|
|
u32Temp = (LSUH_nMaxDuty > u32Temp) ? u32Temp : LSUH_nMaxDuty;
|
|
u32Temp = (LSUH_nMinDuty < u32Temp) ? u32Temp : LSUH_nMinDuty;
|
|
LSUH_au32HeaterDuty[0] = u32Temp;
|
|
|
|
/* Max duty cycle until sensor ready */
|
|
LSUH_au32HeaterDuty[0] = (FALSE == LSUH_aboSensorReady[0]) ? LSUH_nMaxDuty : LSUH_au32HeaterDuty[0];
|
|
|
|
/* Limit to max heater power during startup */
|
|
u32Temp = LSUH_tHeaterEffMax * LSUH_tHeaterEffMax;
|
|
u32Temp /= (BVM_tBattVolts - LSUH_atHeaterSenseVolts[0] - 800u);
|
|
u32Temp *= 1000u;
|
|
u32Temp /= (BVM_tBattVolts - LSUH_atHeaterSenseVolts[0] - 800u);
|
|
|
|
LSUH_u32HeaterDutyMax = u32Temp;
|
|
LSUH_au32HeaterDuty[0] = MIN(LSUH_au32HeaterDuty[0], LSUH_u32HeaterDutyMax);
|
|
}
|
|
|
|
void LSUH_vTerminate(uint32* const pu32Arg )
|
|
{
|
|
|
|
}
|
|
|
|
void LSUH_vCallBack(uint32* const pu32Arg )
|
|
{
|
|
|
|
}
|
|
|
|
static void LSUH_vADCCallBack(IOAPI_tenEHIOResource enEHIOResource, uint32 u32ADCResult)
|
|
{
|
|
uint16 u16ADCDelta;
|
|
uint32 u32Temp;/*CR1_65*/
|
|
|
|
if (TRUE == LSUH_aboHeaterIsOn[0])
|
|
{
|
|
LSUH_au32HeaterLowADCOnRaw[0] = u32ADCResult;
|
|
u32Temp = (LSUH_au32HeaterLowADCOnRaw[0] > LSUH_au32HeaterLowADCOffRaw[0]) ?
|
|
LSUH_au32HeaterLowADCOnRaw[0] - LSUH_au32HeaterLowADCOffRaw[0] : 0;
|
|
|
|
u32Temp = MIN(u32Temp, 0xffff);/*CR1_65*/
|
|
u16ADCDelta = (uint16)u32Temp;/*CR1_65*/
|
|
|
|
(void)USERMATH_u16SinglePoleLowPassFilter16(u16ADCDelta, LSUH_nHeatCurrFilt,
|
|
&LSUH_au32HeaterLowADCDeltaFiltered[0]);
|
|
}
|
|
else
|
|
{
|
|
LSUH_au32HeaterLowADCOffRaw[0] = 4;
|
|
}
|
|
}
|
|
|
|
void LSUH_vTurnHeaterOff(void)
|
|
{
|
|
uint32 u32SampleCount;
|
|
uint32 u32SampleDiscard;
|
|
puint32 pu32SampleArray;
|
|
uint32 u32SampleIDX;
|
|
bool boSamplesOK = TRUE;
|
|
IOAPI_tenEHIOResource enEHIOResource;
|
|
IOAPI_tenTriState enTriState;
|
|
|
|
enEHIOResource = LSUH_nHMENResource;
|
|
enTriState = IOAPI_enLow;
|
|
USER_vSVC(SYSAPI_enAssertDIOResource, (void*)&enEHIOResource, (void*)&enTriState, (void*)NULL);
|
|
|
|
pu32SampleArray = (puint32)(&LSU4X_aau32ACSamples[0][0]);
|
|
|
|
/* Limit the amount of samples - use the last 8 samples */
|
|
if (8 < LSU4X_au32ACSampleCount[0])
|
|
{
|
|
pu32SampleArray += (LSU4X_au32ACSampleCount[0] - 8);
|
|
LSU4X_au32ACSampleCount[0] = 8;
|
|
}
|
|
|
|
u32SampleCount = LSU4X_au32ACSampleCount[0];
|
|
u32SampleCount = MAX(u32SampleCount, 2u);
|
|
u32SampleDiscard = (u32SampleCount - 1) >> 1;
|
|
|
|
LSUH_aboADCQueuePending[0] = TRUE;
|
|
LSUH_aboHeaterIsOn[0] = FALSE;
|
|
LSU4X_au8ACCallBackWait[0] = 0;
|
|
LSUH_au32ACADCDelta[0] = USERMATH_u32DiscardAndAverage32(pu32SampleArray, u32SampleCount, u32SampleDiscard);
|
|
|
|
if ((LSUH_nHeaterOhmsSamples - 1) > LSUH_au32ACSampleCounter[0])
|
|
{
|
|
LSUH_aau32ADADCSamples[0][LSUH_au32ACSampleCounter[0]] = LSUH_au32ACADCDelta[0];
|
|
LSUH_au32ACSampleCounter[0]++;
|
|
}
|
|
else
|
|
{
|
|
u32SampleCount = LSUH_nHeaterOhmsSamples;
|
|
u32SampleDiscard = u32SampleCount >> 1;
|
|
LSUH_aau32ADADCSamples[0][LSUH_au32ACSampleCounter[0]] = LSUH_au32ACADCDelta[0];
|
|
LSUH_au32ACADCDeltaFiltered[0] = USERMATH_u32DiscardAndAverage32(&LSUH_aau32ADADCSamples[0][0], u32SampleCount, u32SampleDiscard);
|
|
|
|
for (u32SampleIDX = 0; u32SampleIDX < LSUH_nHeaterOhmsSamples; u32SampleIDX++)
|
|
{
|
|
if ((LSUH_nMinACSample > LSUH_aau32ADADCSamples[0][u32SampleIDX]) ||
|
|
(LSUH_nMaxACSample < LSUH_aau32ADADCSamples[0][u32SampleIDX]))
|
|
{
|
|
boSamplesOK = FALSE;
|
|
}
|
|
}
|
|
|
|
if (TRUE == boSamplesOK)
|
|
{
|
|
LSU4X_atNernstSenseOhms[0] = CONV_tADCToOhms(EH_I_ADD1, LSUH_au32ACADCDeltaFiltered[0]);
|
|
LSUH_aboNernstRNewValue[0] = true;
|
|
}
|
|
|
|
LSUH_au32ACSampleCounter[0] = 0;
|
|
}
|
|
}
|
|
|
|
void LSUH_vTurnHeaterOn(void)
|
|
{
|
|
IOAPI_tenEHIOResource enEHIOResource;
|
|
IOAPI_tenTriState enTriState;
|
|
|
|
enEHIOResource = LSUH_nHMENResource;
|
|
enTriState = IOAPI_enHigh;
|
|
USER_vSVC(SYSAPI_enAssertDIOResource, (void*)&enEHIOResource, (void*)&enTriState, (void*)NULL);
|
|
|
|
LSUH_aboADCQueuePending[0] = TRUE;
|
|
LSUH_aboHeaterIsOn[0] = TRUE;
|
|
}
|
|
|
|
#ifdef LSUH_TEPM
|
|
IOAPI_tenEHIOType;
|
|
enEHIOType = IOAPI_enDIOOutput;
|
|
|
|
void LSUH_vTEPMCallBackLow(IOAPI_tenEHIOResource enEHIOResource, TEPMAPI_ttEventTime tEventTime)
|
|
{
|
|
uint32 u32SampleCount;
|
|
uint32 u32SampleDiscard;
|
|
puint32 pu32SampleArray;
|
|
uint32 u32LSUDeviceIDX;
|
|
uint32 u32SampleIDX;
|
|
bool boSamplesOK = TRUE;
|
|
IOAPI_tenEHIOResource enEHIOResourceAD;
|
|
|
|
switch (enEHIOResource)
|
|
{
|
|
case EH_IO_TMR15:
|
|
{
|
|
u32LSUDeviceIDX = 0;
|
|
enEHIOResourceAD = EH_I_ADD5;
|
|
break;
|
|
}
|
|
case EH_IO_TMR16:
|
|
{
|
|
u32LSUDeviceIDX = 1;
|
|
enEHIOResourceAD = EH_I_ADD7;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
u32LSUDeviceIDX = 0xffffffff;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Trap invalid timer error */
|
|
if (LSU_DEVICE_COUNT <= u32LSUDeviceIDX) return;
|
|
|
|
pu32SampleArray = (puint32)(&LSU4X_aau32ACSamples[u32LSUDeviceIDX][0]);
|
|
|
|
/* Limit the amount of samples - use the last 8 samples */
|
|
if (8 < LSU4X_au32ACSampleCount[u32LSUDeviceIDX])
|
|
{
|
|
pu32SampleArray += (LSU4X_au32ACSampleCount[u32LSUDeviceIDX] - 8);
|
|
LSU4X_au32ACSampleCount[u32LSUDeviceIDX] = 8;
|
|
}
|
|
|
|
u32SampleCount = LSU4X_au32ACSampleCount[u32LSUDeviceIDX];
|
|
u32SampleCount = MAX(u32SampleCount, 2u);
|
|
u32SampleDiscard = (u32SampleCount - 1) >> 1;
|
|
|
|
LSUH_aboADCQueuePending[u32LSUDeviceIDX] = TRUE;
|
|
LSUH_aboHeaterIsOn[u32LSUDeviceIDX] = FALSE;
|
|
LSU4X_au8ACCallBackWait[u32LSUDeviceIDX] = 0;
|
|
LSUH_au32ACADCDelta[u32LSUDeviceIDX] = USERMATH_u32DiscardAndAverage32(pu32SampleArray, u32SampleCount, u32SampleDiscard);
|
|
|
|
if ((LSUH_nHeaterOhmsSamples - 1) > LSUH_au32ACSampleCounter[u32LSUDeviceIDX])
|
|
{
|
|
LSUH_aau32ADADCSamples[u32LSUDeviceIDX][LSUH_au32ACSampleCounter[u32LSUDeviceIDX]] = LSUH_au32ACADCDelta[u32LSUDeviceIDX];
|
|
LSUH_au32ACSampleCounter[u32LSUDeviceIDX]++;
|
|
}
|
|
else
|
|
{
|
|
u32SampleCount = LSUH_nHeaterOhmsSamples;
|
|
u32SampleDiscard = u32SampleCount >> 1;
|
|
LSUH_aau32ADADCSamples[u32LSUDeviceIDX][LSUH_au32ACSampleCounter[u32LSUDeviceIDX]] = LSUH_au32ACADCDelta[u32LSUDeviceIDX];
|
|
LSUH_au32ACADCDeltaFiltered[u32LSUDeviceIDX] = USERMATH_u32DiscardAndAverage32(&LSUH_aau32ADADCSamples[u32LSUDeviceIDX][0], u32SampleCount, u32SampleDiscard);
|
|
|
|
for (u32SampleIDX = 0; u32SampleIDX < LSUH_nHeaterOhmsSamples; u32SampleIDX++)
|
|
{
|
|
if ((LSUH_nMinACSample > LSUH_aau32ADADCSamples[u32LSUDeviceIDX][u32SampleIDX]) ||
|
|
(LSUH_nMaxACSample < LSUH_aau32ADADCSamples[u32LSUDeviceIDX][u32SampleIDX]))
|
|
{
|
|
boSamplesOK = FALSE;
|
|
}
|
|
}
|
|
|
|
if (TRUE == boSamplesOK)
|
|
{
|
|
LSU4X_atNernstSenseOhms[u32LSUDeviceIDX] = CONV_tADCToOhms(enEHIOResourceAD, LSUH_au32ACADCDeltaFiltered[u32LSUDeviceIDX]);
|
|
LSUH_aboNernstRNewValue[u32LSUDeviceIDX] = true;
|
|
}
|
|
|
|
LSUH_au32ACSampleCounter[u32LSUDeviceIDX] = 0;
|
|
}
|
|
}
|
|
|
|
void LSUH_vTEPMCallBackHigh(IOAPI_tenEHIOResource enEHIOResource, TEPMAPI_ttEventTime tEventTime)
|
|
{
|
|
uint32 u32LSUDeviceIDX;
|
|
|
|
switch (enEHIOResource)
|
|
{
|
|
case EH_IO_TMR15:
|
|
{
|
|
u32LSUDeviceIDX = 0;
|
|
break;
|
|
}
|
|
case EH_IO_TMR16:
|
|
{
|
|
u32LSUDeviceIDX = 1;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
u32LSUDeviceIDX = 0xffffffff;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Trap invalid timer error */
|
|
if (LSU_DEVICE_COUNT <= u32LSUDeviceIDX) return;
|
|
|
|
LSUH_aboADCQueuePending[u32LSUDeviceIDX] = TRUE;
|
|
LSUH_aboHeaterIsOn[u32LSUDeviceIDX] = TRUE;
|
|
LSUH_vInitiateTEPMQueue(enEHIOResource, tEventTime);
|
|
}
|
|
|
|
static void LSUH_vInitiateTEPMQueue(IOAPI_tenEHIOResource enEHIOResource, TEPMAPI_ttEventTime tEventTime)
|
|
{
|
|
TEPMAPI_ttEventCount tEventCount;
|
|
uint16 u16LongPhase;
|
|
uint16 u16ShortPhase;
|
|
sint16 s16PLLTrim;
|
|
uint32 u32LSUDeviceIDX;
|
|
|
|
switch (enEHIOResource)
|
|
{
|
|
case EH_IO_TMR15:
|
|
{
|
|
u32LSUDeviceIDX = 0;
|
|
break;
|
|
}
|
|
case EH_IO_TMR16:
|
|
{
|
|
u32LSUDeviceIDX = 1;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
u32LSUDeviceIDX = 0xffffffff;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Trap invalid timer error */
|
|
if (LSU_DEVICE_COUNT <= u32LSUDeviceIDX) return;
|
|
|
|
/* Calculate the phase error between AC waveform and heater duty start */
|
|
u16LongPhase = (uint16)tEventTime - LSU4X_u16PWMLastStart;
|
|
u16ShortPhase = u16LongPhase % (LSU4X_u16PWMPeriod / 10);
|
|
|
|
/* Calculate the required PLL trim */
|
|
s16PLLTrim = (LSU4X_u16PWMPeriod / 20) < u16ShortPhase ?
|
|
(sint16)(u16ShortPhase - (LSU4X_u16PWMPeriod / 10)) :
|
|
(sint16)u16ShortPhase;
|
|
|
|
s16PLLTrim /= 4;
|
|
tEventCount = 2;
|
|
|
|
LSUH_aastTimedEvents[u32LSUDeviceIDX][0].enAction = TEPMAPI_enSetLow;
|
|
LSUH_aastTimedEvents[u32LSUDeviceIDX][0].enMethod = TEPMAPI_enHardLinkedTimeStep;
|
|
LSUH_aastTimedEvents[u32LSUDeviceIDX][0].tEventTime =
|
|
((uint16)(LSU4X_u16PWMPeriod - s16PLLTrim) * LSUH_au32HeaterDuty[u32LSUDeviceIDX]) / (100ul * LSU_DUTY_RES);
|
|
LSUH_aastTimedEvents[u32LSUDeviceIDX][0].pfEventCB = &LSUH_vTEPMCallBackLow;
|
|
|
|
LSUH_aastTimedEvents[u32LSUDeviceIDX][1].enAction = TEPMAPI_enSetHigh;
|
|
LSUH_aastTimedEvents[u32LSUDeviceIDX][1].enMethod = TEPMAPI_enHardLinkedTimeStep;
|
|
LSUH_aastTimedEvents[u32LSUDeviceIDX][1].tEventTime =
|
|
((uint16)(LSU4X_u16PWMPeriod - s16PLLTrim) * (100ul * LSU_DUTY_RES - LSUH_au32HeaterDuty[u32LSUDeviceIDX]) / (100ul * LSU_DUTY_RES));
|
|
LSUH_aastTimedEvents[u32LSUDeviceIDX][1].pfEventCB = &LSUH_vTEPMCallBackHigh;
|
|
|
|
USER_vSVC(SYSAPI_enAppendTEPMQueue, (void*)&enEHIOResource,
|
|
(void*)&LSUH_aastTimedEvents[u32LSUDeviceIDX][0], (void*)&tEventCount);
|
|
|
|
LSUH_au32TEPMTimeout[u32LSUDeviceIDX] = 0;
|
|
}
|
|
#endif //LSUH_TEPM
|
|
|
|
|
|
#endif //BUILD_USER
|
|
|
|
|
|
|
|
|