RabbitECUTeensyMCUXpresso/source/Peripherals/ADCHA.c

432 lines
13 KiB
C

/******************************************************************************/
/* Copyright (c) 2016 MD Automotive Controls. Original Work. */
/* License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher */
/******************************************************************************/
/* CONTEXT:KERNEL */
/* PACKAGE TITLE: XXX */
/* DESCRIPTION: XXX */
/* FILE NAME: XXX.c */
/* REVISION HISTORY: 19-08-2016 | 1.0 | Initial revision */
/* */
/******************************************************************************/
#include <string.h>
#include <stddef.h>
#include <SYS.h>
#include <TYPES.h>
#include "mk64f12.h"
#include "CRC16.h"
#include "CPUAbstract.h"
#include "regset.h"
#include "os.h"
#include "MSG.h"
#include "PERADC.h"
#include "CQUEUE.h"
#include "ADCAPI.h"
#include "SIM.h"
#include "IRQ.h"
#include "dscrio.h"
#include "adcha.h"
const REGSET_tstReg32Val ADCHA_rastADCReg32Val[] = ADCHA_nReg32Set;
const ADCHA_tstADCChannel ADCHA_rastADCChannel[] = ADCHA_nChannelInfo;
const IOAPI_tenEHIOResource ADCHA_raenIOResource[] = ADCHA_nIOResourceMap;
uint32 ADCHA_u32PortClockRequested;
uint32 ADCHA_u32Calibrated;
bool ADCHA_aboModuleBusy[ADCHA_enChannelCount];
#ifdef ADC_CALIBRATE
static void ADCHA_vBackupCalibration(tstADCModule* pstADC, ADCHA_tstADCCalStruct* pstADCCalStruct);
#endif //ADC_CALIBRATE
static void ADCHA_vInitInterrupts(IRQn_Type enIrq);
void ADCHA_vStart(uint32* const pu32Stat)
{
uint32 u32IDX;
for (u32IDX = 0; u32IDX < ADCHA_enChannelCount; u32IDX++)
{
ADCHA_aboModuleBusy[u32IDX] = false;
}
#if defined(BUILD_MK60)
ADC_xInitialise(ADC3, ADC3_IRQn);
ADC_xInitialise(ADC2, ADC2_IRQn);
ADC_xInitialise(ADC1, ADC1_IRQn);
ADC_xInitialise(ADC0, ADC0_IRQn);
REGSET_vInitReg32(&ADCHA_rastADCReg32Val[0]);
#endif //BUILD_MK60
#if defined(BUILD_MK64)
ADCHA_xInitialise(ADC1, ADC1_IRQn);
ADCHA_xInitialise(ADC0, ADC0_IRQn);
REGSET_vInitReg32(ADCHA_rastADCReg32Val);
#endif //BUILD_MK64
#ifdef BUILD_SAM3X8E
tstADCModule* pstADCModule = ADC;
(void)SIM_boEnablePeripheralClock(ADC_IRQn);
ADCHA_u32PortClockRequested = 1;
adc_init(pstADCModule, SYS_FREQ_BUS, ADCHA_nADCCLKFREQ, ADCHA_nADCTRSTTIME);
IRQ_vEnableIRQ(ADC_IRQn, IRQ_enPRIO_8, ADC_vInterruptHandler, NULL);
#endif
}
bool ADCHA_boBackupCalibrations(void)
{
bool boRetCode = FALSE;
/* TODO
#if defined(BUILD_MK60) || defined(BUILD_MK64)
ADCHA_tstADCCalStruct* pstADCCalStruct;
if (TRUE == FEE_boCheckPartition())
{
ADCHA_vBackupCalibration(ADC0, pstADCCalStruct++);
ADCHA_vBackupCalibration(ADC1, pstADCCalStruct++);
boRetCode = TRUE;
}
#endif
*/
return boRetCode;
}
void ADCHA_vInitADCResourcePGA(ADCHA_tstADCConversion* pstADCConversion)
{
#if defined(BUILD_MK60)
tstADCModule* pstADC;
/* Set the differential gain */
pstADC = ADCHA_pstGetADCModule(pstADCConversion->stADCChannel.enADCModule);
pstADC->PGA = (ADC_PGA_PGAG(pstADCCB->enDiffGain) | ADC_PGA_PGAEN_MASK);
#endif //BUILD_MK6X
}
void ADCHA_vInitChannel(IOAPI_tenEHIOResource enIOResource)
{
#ifdef BUILD_SAM3X8E
tstADCModule* pstADC = ADCHA_pstGetADCModule(ADCHA_enADC0);
uint32 u32Channel = ADCHA_rastADCChannel[enIOResource].u32ADChannel;
adc_enable_channel(pstADC, u32Channel);
//adc_enable_interrupt(pstADC, 1 << u32Channel);
#endif //BUILD_SAM3X8E
}
void ADCHA_vTerminate(uint32* const u32Stat)
{
}
bool ADCHA_boInitiateConversion(ADCHA_tstADCConversion* pstADCConversion, ADCHA_tenQueue enQueue, uint32 u32QueueTail, bool boPreserveSeq)
{
bool boADCInitPending = TRUE;
tstADCModule* pstADC;
#if defined(BUILD_MK60) || defined(BUILD_MK64)
uint32 u32Conversion;
pstADC = ADCHA_pstGetADCModule(pstADCConversion->stADCChannel.enADCModule);
if (ADC_SC1_ADCH_MASK == (ADC_SC1_ADCH_MASK & pstADC->SC1[0]))
{
boADCInitPending = FALSE;
pstADC->CFG2 &= ~ADC_CFG2_MUXSEL_MASK;
pstADC->CFG2 |= (pstADCConversion->stADCChannel.enChannelAB << ADC_CFG2_MUXSEL_SHIFT) |
ADC_CFG2_ADHSC_MASK;
pstADC->SC3 = (ADC_SC3_AVGS_MASK | ADC_SC3_AVGE_MASK | (pstADCConversion->stADCChannel.u32Samples));
u32Conversion = ADC_SC1_ADCH_MASK & pstADCConversion->stADCChannel.u32ADChannel;
u32Conversion |= ADC_SC1_AIEN_MASK;
if (TRUE == pstADCConversion->stADCChannel.boIsDiff)
{
u32Conversion |= ADC_SC1_DIFF_MASK;
}
pstADC->SC1[0] = u32Conversion;
}
#endif //BUILD_MK6X
#ifdef BUILD_SAM3X8E
ADCHA_tstADCConversion* pstADCConversionQueue;
uint32 u32ConversionIDX;
enum adc_channel_num_t aenChannels[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
uint32 u32ChannelMask = 0;
uint32 u32Temp = 0;
uint32 u32TerminateInterrupt = 0;
boADCInitPending = FALSE;
ADCHA_aboModuleBusy[0] = true;
pstADC = ADC;
//adc_disable_all_channel(pstADC);
adc_disable_interrupt(pstADC, 0xffff);
///* Clear flags */
//for (u32ConversionIDX = 0; u32ConversionIDX < 16; u32ConversionIDX++)
//{
//u32ChannelMask = MATH_u32IDXToMask(u32ConversionIDX);
//
//if (u32ChannelMask == (pstADC->ADC_ISR & u32ChannelMask))
//{
///* Dummy read the data register to clear the flag */
//u32ChannelMask = pstADC->ADC_CDR[u32ConversionIDX];
//}
//}
/* Enable the required channels except the last */
//pstADCConversionQueue = pstADCConversion;
//for (u32ConversionIDX = 0; u32ConversionIDX < u32QueueTail; u32ConversionIDX++)
//{
//adc_enable_channel(pstADC, (enum adc_channel_num_t)pstADCConversionQueue->stADCChannel.u32ADChannel);
//pstADCConversionQueue++;
//}
/* Configure the sequence */
u32ChannelMask = 0;
pstADCConversionQueue = pstADCConversion;
for (u32ConversionIDX = 0; u32ConversionIDX < u32QueueTail; u32ConversionIDX++)
{
u32ChannelMask |= MATH_u32IDXToMask(pstADCConversionQueue->stADCChannel.u32ADChannel);
pstADCConversionQueue++;
}
for (u32ConversionIDX = 0; u32ConversionIDX < 16; u32ConversionIDX++)
{
u32Temp = MATH_u32IDXToMask(u32ConversionIDX);
u32Temp &= u32ChannelMask;
if (0 != u32Temp)
{
aenChannels[u32ConversionIDX] = (enum adc_channel_num_t)u32ConversionIDX;
u32TerminateInterrupt = u32Temp;
}
}
adc_enable_interrupt(pstADC, u32TerminateInterrupt);
//if (TRUE == boPreserveSeq)
{
adc_start_sequencer(pstADC);
adc_configure_sequence(pstADC, aenChannels, 16);
}
adc_start(pstADC);
#endif //BUILD_SAM3X8E
return boADCInitPending;
}
tstADCModule* ADCHA_pstGetADCModule(ADCHA_tenADCModule enADCModule)
{
tstADCModule* pstADC = NULL;
#if defined(BUILD_MK60)
switch(enADCModule)
{
case ADCHA_enADC0: pstADC = ADC0; break;
case ADCHA_enADC1: pstADC = ADC1; break;
case ADCHA_enADC2: pstADC = ADC2; break;
case ADCHA_enADC3: pstADC = ADC3; break;
default: pstADC = NULL; break;
}
#endif //BUILD_MK6X
#if defined(BUILD_MK64)
switch(enADCModule)
{
case ADCHA_enADC0: pstADC = ADC0; break;
case ADCHA_enADC1: pstADC = ADC1; break;
default: pstADC = NULL; break;
}
#endif //BUILD_MK64
#ifdef BUILD_SAM3X8E
switch(enADCModule)
{
case ADCHA_enADC0: pstADC = ADC; break;
default: pstADC = NULL; break;
}
#endif //BUILD_SAM3X8E
return pstADC;
}
uint32 ADCHA_u32GetAvailableResultCount(tstADCModule* pstADC)
{
uint32 u32RetVal = 1;
#ifdef BUILD_SAM3X8E
u32RetVal = 0;
uint32 u32ChannelMask = 1;
while (0x8000 > u32ChannelMask)
{
if (u32ChannelMask == (u32ChannelMask & pstADC->ADC_CHSR)) u32RetVal++;
u32ChannelMask *= 2;
}
#endif //BUILD_SAM3X8E
return u32RetVal;
}
void ADCHA_vCalibrate(tstADCModule* pstADC, uint32 u32ADCIDX, uint32 u32CalFlag)
{
#ifdef ADC_CALIBRATE
#if defined(BUILD_MK60) || defined(BUILD_MK64)
uint16 u16Temp;
uint16 u16CRC;
ADCHA_tstADCCalStruct* pstADCCalStruct = (ADCHA_tstADCCalStruct*)FEEHA_ADCREC_ADDRESS + u32ADCIDX;
//u16CRC = CRC16_u16CalcCRC(0xffff, (puint8)pstADCCalStruct, sizeof(ADCHA_tstADCCalStruct) - sizeof(uint32));
#if (ADC_nCalFromRecord)
if(true)
//if ((uint32)u16CRC != pstADCCalStruct->u32CRC)
#else
if (true)
#endif
{
pstADC->SC2 &= ~ ADC_SC2_ADTRG_MASK;
pstADC->SC3 |= ADC_SC3_CAL_MASK;
while (0 != (pstADC->SC2 & ADC_SC2_ADACT_MASK)) {};
if (0 == (pstADC->SC3 & ADC_SC3_CALF_MASK))
{
u16Temp = 0;
u16Temp += pstADC->CLP0;
u16Temp += pstADC->CLP1;
u16Temp += pstADC->CLP2;
u16Temp += pstADC->CLP3;
u16Temp += pstADC->CLP4;
u16Temp += pstADC->CLPS;
u16Temp /= 2;
u16Temp |= 0x8000;
pstADC->PG = u16Temp;
u16Temp = 0;
u16Temp += pstADC->CLM0;
u16Temp += pstADC->CLM1;
u16Temp += pstADC->CLM2;
u16Temp += pstADC->CLM3;
u16Temp += pstADC->CLM4;
u16Temp += pstADC->CLMS;
u16Temp /= 2;
u16Temp |= 0x8000;
pstADC->MG = u16Temp;
ADCHA_u32Calibrated |= u32CalFlag;
}
}
else
{
pstADC->OFS = pstADCCalStruct->u32OFS;
pstADC->PG = pstADCCalStruct->u32PG;
pstADC->MG = pstADCCalStruct->u32MG;
}
#endif //BUILD_MK60
#endif //ADC_CALIBRATE
}
#ifdef ADC_CALIBRATE
static void ADCHA_vBackupCalibration(tstADCModule* pstADC, ADCHA_tstADCCalStruct* pstADCCalStruct)
{
#if defined(BUILD_MK60) || defined(BUILD_MK64)
puint8 pu8ADCCalStruct = (puint8)pstADCCalStruct;
ADCHA_tstADCCalStruct stADCCalStruct;
uint16 u16CRC;
stADCCalStruct.u32OFS = pstADC->OFS;
stADCCalStruct.u32PG = pstADC->PG;
stADCCalStruct.u32MG = pstADC->MG;
u16CRC = CRC16_u16CalcCRC(0xffff, pu8ADCCalStruct, sizeof(ADCHA_tstADCCalStruct) - sizeof(uint32));
stADCCalStruct.u32CRC = (uint32)(u16CRC);
FEE_boWriteNVM((puint8)&stADCCalStruct, (puint8)pstADCCalStruct, sizeof(ADCHA_tstADCCalStruct));
#endif //BUILD_MK60
}
#endif //ADC_CALIBRATE
IOAPI_tenEHIOResource ADCHA_enGetResourceAndResult(ADCHA_tenADCModule enADCModule, tstADCModule* pstADC, uint32 u32ADCChannel, puint32 pu32ADCResult)
{
IOAPI_tenEHIOResource enEHIOResource;
#if defined(BUILD_MK60) || defined(BUILD_MK64)
/* Get the queue, channel and resource */
//u32ADCChannel = ADC_SC1_ADCH_MASK & pstADC->SC1[0];//matthew check here against channel
enEHIOResource = ADCHA_raenIOResource[32 * enADCModule + u32ADCChannel];
/* Deactivate the AD module */
pstADC->SC1[0] |= ADC_SC1_ADCH_MASK;
*pu32ADCResult = pstADC->R[0];
#endif //BUILD_MK6X
#ifdef BUILD_SAM3X8E
/* Get the queue, channel and resource */
enEHIOResource = ADCHA_raenIOResource[u32ADCChannel];
*pu32ADCResult = pstADC->ADC_CDR[u32ADCChannel];
#endif //BUILD_MK60
return enEHIOResource;
}
void ADCHA_vInitConversion(IOAPI_tenEHIOResource enIOResource, ADCHA_tstADCConversion* pstADCConversion, ADCAPI_tstADCCB* pstADCCB, uint32 u32QueueIDX)
{
#if defined(BUILD_MK60) || defined (BUILD_MK64)
pstADCConversion->stADCChannel.enEHIOResource = enIOResource;
pstADCConversion->stADCChannel.enADCModule = ADCHA_rastADCChannel[enIOResource].enADCModule;
pstADCConversion->stADCChannel.u32ADChannel = ADCHA_rastADCChannel[enIOResource].u32ADChannel;
pstADCConversion->stADCChannel.enChannelAB = ADCHA_rastADCChannel[enIOResource].enChannelAB;
pstADCConversion->stADCChannel.boIsDiff = ADCHA_rastADCChannel[enIOResource].boIsDiff;
pstADCConversion->stADCChannel.u32Samples = pstADCCB->enSamplesAv;
pstADCConversion->pfResultCB = pstADCCB->pfResultCB;
pstADCConversion->u32ControlCount = 0;
#endif //BUILD_MK6X
#ifdef BUILD_SAM3X8E
pstADCConversion->stADCChannel.enEHIOResource = enIOResource;
pstADCConversion->stADCChannel.enADCModule = ADCHA_rastADCChannel[enIOResource].enADCModule;
pstADCConversion->stADCChannel.u32ADChannel = ADCHA_rastADCChannel[enIOResource].u32ADChannel;
pstADCConversion->stADCChannel.boIsDiff = ADCHA_rastADCChannel[enIOResource].boIsDiff;
pstADCConversion->pfResultCB = pstADCCB->pfResultCB;
pstADCConversion->u32ControlCount = 0;
#endif //BUILD_SAM3X8E
}
static void ADCHA_vInitInterrupts(IRQn_Type enIrq)
{
IRQ_vEnableIRQ(enIrq, IRQ_enPRIO_8, ADC_vInterruptHandler, NULL);
}
bool ADCHA_boGetModuleBusy(ADCHA_tenADCModule enADCModule)
{
bool boModuleBusy;
tstADCModule* pstADC = ADCHA_pstGetADCModule(enADCModule);
#if defined(BUILD_MK60) || defined(BUILD_MK64)
pstADC = ADCHA_pstGetADCModule(enADCModule);
boModuleBusy = (ADC_SC1_ADCH_MASK == (ADC_SC1_ADCH_MASK & pstADC->SC1[0])) ? FALSE : TRUE;
#endif //BUILD_MK6X
#ifdef BUILD_SAM3X8E
pstADC = ADCHA_pstGetADCModule(enADCModule);
boModuleBusy = ADCHA_aboModuleBusy[0];
#endif //BUILD_SAM3X8E
return boModuleBusy;
}
void ADCHA_vClearModuleBusy(ADCHA_tenADCModule enADCModule)
{
ADCHA_aboModuleBusy[enADCModule] = false;
}
void ADCHA_vReset(ADCHA_tenADCModule enADCModule)
{
ADCHA_aboModuleBusy[enADCModule] = false;
}