569 lines
16 KiB
C
569 lines
16 KiB
C
|
/*
|
||
|
* @brief ADC ROM API declarations and functions
|
||
|
*
|
||
|
* @note
|
||
|
* Copyright(C) NXP Semiconductors, 2014
|
||
|
* All rights reserved.
|
||
|
*
|
||
|
* @par
|
||
|
* Software that is described herein is for illustrative purposes only
|
||
|
* which provides customers with programming information regarding the
|
||
|
* LPC products. This software is supplied "AS IS" without any warranties of
|
||
|
* any kind, and NXP Semiconductors and its licensor disclaim any and
|
||
|
* all warranties, express or implied, including all implied warranties of
|
||
|
* merchantability, fitness for a particular purpose and non-infringement of
|
||
|
* intellectual property rights. NXP Semiconductors assumes no responsibility
|
||
|
* or liability for the use of the software, conveys no license or rights under any
|
||
|
* patent, copyright, mask work right, or any other intellectual property rights in
|
||
|
* or to any products. NXP Semiconductors reserves the right to make changes
|
||
|
* in the software without notification. NXP Semiconductors also makes no
|
||
|
* representation or warranty that such application will be suitable for the
|
||
|
* specified use without further testing or modification.
|
||
|
*
|
||
|
* @par
|
||
|
* Permission to use, copy, modify, and distribute this software and its
|
||
|
* documentation is hereby granted, under NXP Semiconductors' and its
|
||
|
* licensor's relevant copyrights in the software, without fee, provided that it
|
||
|
* is used in conjunction with NXP Semiconductors microcontrollers. This
|
||
|
* copyright, permission, and disclaimer notice must appear in all copies of
|
||
|
* this code.
|
||
|
*/
|
||
|
|
||
|
#include <string.h>
|
||
|
#include "hw_adc_rom_api.h"
|
||
|
|
||
|
/** @brief ADC ROM Driver Version */
|
||
|
#define ADC_DRIVER_VERSION 0x0100
|
||
|
|
||
|
/* Internal defines */
|
||
|
#define SEQ_A_MASK 0x7C0C5FFF
|
||
|
#define SEQ_B_MASK 0x5C0C5FFF
|
||
|
#define CTRL_MASK 0x00007F00
|
||
|
|
||
|
#define ADC_STATE_INACTIVE 0
|
||
|
#define ADC_STATE_IDLE 1
|
||
|
#define ADC_STATE_ACTIVE 2
|
||
|
|
||
|
/** @brief Channel flags offset */
|
||
|
#define CB_THRES(ch) (1UL << (ch))
|
||
|
#define CB_DATA(ch) (0x10000UL << (ch))
|
||
|
|
||
|
/* ADC Buffer management */
|
||
|
typedef struct {
|
||
|
uint16_t *pCurr; /* ReceiveBuffer Pointer */
|
||
|
size_t szCurr; /* Receive Count */
|
||
|
uint16_t *pNext; /* Ring Buffer Pointer */
|
||
|
size_t szNext; /* Receive Count */
|
||
|
uint32_t idx; /* Current index */
|
||
|
int32_t state; /* State of ADC */
|
||
|
} ADC_BUFFER_T;
|
||
|
|
||
|
/* ADC Driver internal data structure */
|
||
|
typedef struct {
|
||
|
void *pUserData; /* Pointer to user data */
|
||
|
ADC_REGS_T *pREGS; /* Pointer to Registers */
|
||
|
uint32_t valSeq[2]; /* Stored SEQ A/B Values */
|
||
|
ADC_BUFFER_T buffer[2]; /* Buffers to store converted data */
|
||
|
uint32_t flags; /* flags */
|
||
|
uint32_t regThrSel; /* Threshold flags */
|
||
|
uint32_t regInt; /* Interrupt register */
|
||
|
uint32_t flag1; /* Flags Extra */
|
||
|
void(*cbTable[ADC_CBIDX_RESERVED]) (ADC_HANDLE_T, ADC_CBINDEX_T, void *);
|
||
|
} ADC_DRIVER_T;
|
||
|
|
||
|
/* Prototype defines */
|
||
|
static ErrorCode_t ADC_StopConversion(ADC_HANDLE_T hADC, ADC_SEQ_INDEX_T seqIndex);
|
||
|
|
||
|
/* PRIVATE: Invoke a call back function */
|
||
|
static void _ADC_InvokeCallback(ADC_DRIVER_T *pADC, ADC_CBINDEX_T idx, void *param)
|
||
|
{
|
||
|
if (pADC->cbTable[idx]) {
|
||
|
pADC->cbTable[idx]((ADC_HANDLE_T) pADC, idx, param);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* PRIVATE: Extract, format data and store into user buffer */
|
||
|
static ErrorCode_t _ADC_GetData(ADC_DRIVER_T *pADC, ADC_SEQ_INDEX_T seqIndex, uint32_t data)
|
||
|
{
|
||
|
uint8_t ch = ADC_DR_CHANNEL(data);
|
||
|
ADC_BUFFER_T *buf = &pADC->buffer[seqIndex];
|
||
|
uint16_t *pDat = &buf->pCurr[buf->idx++];
|
||
|
|
||
|
/* Ignore extra data */
|
||
|
if (!buf->szCurr) {
|
||
|
return LPC_OK;
|
||
|
}
|
||
|
|
||
|
/* If data is not vaild something is wrong! */
|
||
|
if (!(data & ADC_SEQ_GDAT_DATAVALID)) {
|
||
|
return ERR_FAILED;
|
||
|
}
|
||
|
|
||
|
data >>= 4;
|
||
|
if (!(pADC->flag1 & (1UL << ch))) {
|
||
|
data &= 0xFFF;
|
||
|
}
|
||
|
|
||
|
*pDat = data;
|
||
|
/* Invoke the call back for single data read if enabled */
|
||
|
if (pADC->flags & CB_DATA(ch)) {
|
||
|
_ADC_InvokeCallback(pADC, ADC_CHDATA, (void *) ((ch << 16) | data));
|
||
|
}
|
||
|
return LPC_OK;
|
||
|
}
|
||
|
|
||
|
/* PRIVATE: Reads data from the GDAT or DAT register based on mode of operation */
|
||
|
static ErrorCode_t _ADC_ReadData(ADC_DRIVER_T *pADC, ADC_SEQ_INDEX_T seqIndex)
|
||
|
{
|
||
|
ADC_REGS_T *pREGS = pADC->pREGS;
|
||
|
int i;
|
||
|
|
||
|
/* Check if this is End-of-Seq or End-of-SingleConversion */
|
||
|
if (!(pADC->valSeq[seqIndex] & ADC_SEQ_CTRL_MODE_EOS)) {
|
||
|
return _ADC_GetData(pADC, seqIndex, pREGS->SEQ_GDAT[seqIndex]);
|
||
|
}
|
||
|
|
||
|
/* Read channels having conversion data */
|
||
|
for (i = 0; i < sizeof(pREGS->DAT) / sizeof(pREGS->DAT[0]); i++) {
|
||
|
if (pADC->valSeq[seqIndex] & ADC_SEQ_CTRL_CHANSEL(i)) {
|
||
|
if (_ADC_GetData(pADC, seqIndex, pREGS->DAT[i]) != LPC_OK) {
|
||
|
return ERR_FAILED;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return LPC_OK;
|
||
|
}
|
||
|
|
||
|
/* PRIVATE: Overflow handler */
|
||
|
static ErrorCode_t _ADC_Handle_Overflow(ADC_DRIVER_T *pADC, uint32_t flag)
|
||
|
{
|
||
|
_ADC_InvokeCallback(pADC, ADC_OVERFLOW, (void *) ((flag >> 12) & 0x3FFF));
|
||
|
return LPC_OK;
|
||
|
}
|
||
|
|
||
|
/* PRIVATE: ADC Sequence event handler function */
|
||
|
static ErrorCode_t _ADC_Handler_Seq(ADC_DRIVER_T *pADC, ADC_SEQ_INDEX_T seqIndex)
|
||
|
{
|
||
|
ADC_REGS_T *pREGS = pADC->pREGS;
|
||
|
ADC_BUFFER_T *buf = &pADC->buffer[seqIndex];
|
||
|
uint32_t flag = pREGS->FLAGS;
|
||
|
uint32_t tmp;
|
||
|
|
||
|
/* Check if overrun is enabled and got an overrun */
|
||
|
tmp = flag & ADC_FLAGS_SEQN_OVRRUN_MASK(seqIndex);
|
||
|
|
||
|
if (!(flag & ADC_FLAGS_SEQN_INT_MASK(seqIndex))) {
|
||
|
return ERR_ADC_INVALID_SEQUENCE;
|
||
|
}
|
||
|
|
||
|
if (_ADC_ReadData(pADC, seqIndex) != LPC_OK) {
|
||
|
return ERR_FAILED;
|
||
|
}
|
||
|
|
||
|
/* Handle the overflow */
|
||
|
if (tmp) {
|
||
|
_ADC_Handle_Overflow(pADC, flag);
|
||
|
}
|
||
|
|
||
|
/* Clear the interrupt if it is for EOS and not EOC */
|
||
|
if (pADC->valSeq[seqIndex] & ADC_SEQ_CTRL_MODE_EOS) {
|
||
|
pREGS->FLAGS = ADC_FLAGS_SEQN_INT_MASK(seqIndex);
|
||
|
}
|
||
|
|
||
|
/* See if we are done with our buffer */
|
||
|
if (buf->idx >= buf->szCurr) {
|
||
|
_ADC_InvokeCallback(pADC, (ADC_CBINDEX_T) (ADC_BUFFER_DONE + (ADC_CBINDEX_T)seqIndex), buf->pCurr);
|
||
|
if (!buf->pNext || !buf->szNext) {
|
||
|
buf->pCurr = 0;
|
||
|
buf->szCurr = 0;
|
||
|
|
||
|
/* Nothing more to do stop the ADC */
|
||
|
ADC_StopConversion(pADC, seqIndex);
|
||
|
return LPC_OK;
|
||
|
}
|
||
|
buf->pCurr = buf->pNext;
|
||
|
buf->szCurr = buf->szNext;
|
||
|
buf->pNext = 0;
|
||
|
buf->idx = buf->szNext = 0;
|
||
|
}
|
||
|
|
||
|
/* If we are not in burst mode we must trigger next sample */
|
||
|
if (!((pADC->valSeq[seqIndex] >> 12) & 0x1F) && !(pADC->valSeq[seqIndex] & ADC_SEQ_CTRL_BURST)) {
|
||
|
pREGS->SEQ_CTRL[seqIndex] = pADC->valSeq[seqIndex];
|
||
|
}
|
||
|
|
||
|
return LPC_OK;
|
||
|
}
|
||
|
|
||
|
/* PRIVATE: ADC sequence handler polling mode */
|
||
|
static ErrorCode_t _ADC_Handler_SeqPoll(ADC_DRIVER_T *pADC, ADC_SEQ_INDEX_T seqIndex)
|
||
|
{
|
||
|
ADC_REGS_T *pREGS = pADC->pREGS;
|
||
|
ErrorCode_t ret = LPC_OK;
|
||
|
|
||
|
/* Poll as long as the sequence is enabled */
|
||
|
while (pREGS->SEQ_CTRL[seqIndex] & ADC_SEQ_CTRL_SEQ_ENA) {
|
||
|
if (!(pREGS->FLAGS & ADC_FLAGS_SEQN_INT_MASK(seqIndex))) {
|
||
|
continue;
|
||
|
}
|
||
|
ret = _ADC_Handler_Seq(pADC, seqIndex);
|
||
|
if (ret != LPC_OK) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/* PRIVATE: Handler for Overflow event */
|
||
|
static ErrorCode_t _ADC_Handler_Ovr(ADC_DRIVER_T *pADC)
|
||
|
{
|
||
|
uint32_t flags = pADC->pREGS->FLAGS;
|
||
|
|
||
|
/* Invoke Sequence handler to clear-out the data */
|
||
|
if (flags & ADC_FLAGS_SEQA_OVRRUN_MASK) {
|
||
|
return _ADC_Handler_Seq(pADC, ADC_SEQ_A);
|
||
|
}
|
||
|
else if (flags & ADC_FLAGS_SEQB_OVRRUN_MASK) {
|
||
|
return _ADC_Handler_Seq(pADC, ADC_SEQ_B);
|
||
|
}
|
||
|
else {
|
||
|
return ERR_FAILED;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* PRIVATE: Threshold event handler */
|
||
|
static ErrorCode_t _ADC_Handler_Thres(ADC_DRIVER_T *pADC)
|
||
|
{
|
||
|
uint32_t flags = pADC->pREGS->FLAGS;
|
||
|
|
||
|
if (!(flags & ADC_FLAGS_THCMP_INT_MASK)) {
|
||
|
return ERR_FAILED;
|
||
|
}
|
||
|
|
||
|
flags &= 0xFFF;
|
||
|
|
||
|
/* Clear out the interrupts */
|
||
|
pADC->pREGS->FLAGS = flags;
|
||
|
_ADC_InvokeCallback(pADC, ADC_THRESHOLD, (void *) flags);
|
||
|
|
||
|
return LPC_OK;
|
||
|
}
|
||
|
|
||
|
/* EXPORTED API: Register a call-back function */
|
||
|
ErrorCode_t ADC_RegisterCallback(ADC_HANDLE_T hADC, ADC_CBINDEX_T idx, void (*cb_func)(ADC_HANDLE_T,
|
||
|
ADC_CBINDEX_T,
|
||
|
void *))
|
||
|
{
|
||
|
if (idx < ADC_CBIDX_RESERVED) {
|
||
|
((ADC_DRIVER_T *) hADC)->cbTable[idx] = cb_func;
|
||
|
}
|
||
|
else {
|
||
|
return ERR_ADC_PARAM;
|
||
|
}
|
||
|
return LPC_OK;
|
||
|
}
|
||
|
|
||
|
/* EXPORTED API: ADC Initialization function */
|
||
|
ADC_HANDLE_T ADC_Init(void *mem, uint32_t base_addr, void *args)
|
||
|
{
|
||
|
ADC_DRIVER_T *pADC;
|
||
|
|
||
|
/* Check if the memory is word aligned */
|
||
|
if ((uint32_t) mem & 0x3) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/* Assign memory provided by application */
|
||
|
pADC = (ADC_DRIVER_T *) mem;
|
||
|
memset(pADC, 0, sizeof(ADC_DRIVER_T));
|
||
|
|
||
|
/* Assign the base address */
|
||
|
pADC->pREGS = (ADC_REGS_T *) base_addr;
|
||
|
pADC->pUserData = args;
|
||
|
|
||
|
/* To be safe stop the ADC in case it is not stopped */
|
||
|
pADC->pREGS->SEQ_CTRL[0] = 0x00;
|
||
|
pADC->pREGS->SEQ_CTRL[1] = 0x00;
|
||
|
|
||
|
return (ADC_HANDLE_T) pADC;
|
||
|
}
|
||
|
|
||
|
/* EXPORTED API: Setup the ADC threshold registers */
|
||
|
void ADC_SetThreshold(ADC_HANDLE_T hADC, uint32_t valThres0, uint32_t valThres1)
|
||
|
{
|
||
|
ADC_REGS_T *pREGS = ((ADC_DRIVER_T *) hADC)->pREGS;
|
||
|
pREGS->THR0_LOW = (valThres0 << ADC_THR_VAL_POS) & ADC_THR_VAL_MASK;
|
||
|
pREGS->THR1_LOW = (valThres1 << ADC_THR_VAL_POS) & ADC_THR_VAL_MASK;
|
||
|
valThres0 >>= 16;
|
||
|
valThres1 >>= 16;
|
||
|
pREGS->THR0_HIGH = (valThres0 << ADC_THR_VAL_POS) & ADC_THR_VAL_MASK;
|
||
|
pREGS->THR1_HIGH = (valThres1 << ADC_THR_VAL_POS) & ADC_THR_VAL_MASK;
|
||
|
}
|
||
|
|
||
|
/* EXPORTED API: Calibrate the ADC */
|
||
|
ErrorCode_t ADC_Calibrate(ADC_HANDLE_T handle, uint32_t sysclk_freq)
|
||
|
{
|
||
|
ADC_REGS_T *pREGS = ((ADC_DRIVER_T *) handle)->pREGS;
|
||
|
volatile uint32_t i;
|
||
|
|
||
|
pREGS->STARTUP = ADC_STARTUP_ENABLE;
|
||
|
for ( i = 0; i < 0x10; i++ ) {}
|
||
|
if ( !(pREGS->STARTUP & ADC_STARTUP_ENABLE) ) {
|
||
|
return ERR_ADC_NO_POWER;
|
||
|
}
|
||
|
|
||
|
/* If not in by-pass mode do the calibration */
|
||
|
if ( (pREGS->CALIBR & ADC_CALREQD) && !(pREGS->CTRL & ADC_CR_BYPASS) ) {
|
||
|
uint32_t ctrl = pREGS->CTRL & (CTRL_MASK | 0xFF);
|
||
|
uint32_t tmp = ctrl;
|
||
|
|
||
|
/* Set ADC to SYNC mode */
|
||
|
tmp &= ~ADC_CR_ASYNC_MODE;
|
||
|
|
||
|
/* To be safe run calibration at 1MHz UM permits upto 30MHz */
|
||
|
if (sysclk_freq > 1000000UL) {
|
||
|
pREGS->CTRL = tmp | (((sysclk_freq / 1000000UL) - 1) & 0xFF);
|
||
|
}
|
||
|
|
||
|
/* Calibration is needed, do it now. */
|
||
|
pREGS->CALIBR = ADC_CALIB;
|
||
|
i = 0xF0000;
|
||
|
while ( (pREGS->CALIBR & ADC_CALIB) && --i ) {}
|
||
|
pREGS->CTRL = ctrl;
|
||
|
return i ? LPC_OK : ERR_TIME_OUT;
|
||
|
}
|
||
|
|
||
|
/* A dummy conversion cycle will be performed. */
|
||
|
pREGS->STARTUP = (pREGS->STARTUP | ADC_STARTUP_INIT) & 0x03;
|
||
|
i = 0x7FFFF;
|
||
|
while ( (pREGS->STARTUP & ADC_STARTUP_INIT) && --i ) {}
|
||
|
return i ? LPC_OK : ERR_TIME_OUT;
|
||
|
}
|
||
|
|
||
|
/* EXPORTED API: Configure the ADC */
|
||
|
ErrorCode_t ADC_Configure(ADC_HANDLE_T hADC, const ADC_CFG_T *pCfg)
|
||
|
{
|
||
|
ADC_DRIVER_T *pADC = hADC;
|
||
|
ADC_REGS_T *pREGS = pADC->pREGS;
|
||
|
|
||
|
pADC->valSeq[ADC_SEQ_A] = ADC_SEQ_CTRL_SEQ_ENA | ADC_SEQ_CTRL_START | (pCfg->flagSeqA & SEQ_A_MASK);
|
||
|
pADC->valSeq[ADC_SEQ_B] = ADC_SEQ_CTRL_SEQ_ENA | ADC_SEQ_CTRL_START | (pCfg->flagSeqB & SEQ_B_MASK);
|
||
|
|
||
|
/* START is not required for BURST or H/W Trigger */
|
||
|
if ((pCfg->flagSeqA & ADC_SEQ_CTRL_TRIGGER_MASK)) {
|
||
|
pADC->valSeq[ADC_SEQ_A] &= ~ADC_SEQ_CTRL_START;
|
||
|
}
|
||
|
|
||
|
/* START is not required for BURST or H/W Trigger */
|
||
|
if ((pCfg->flagSeqB & ADC_SEQ_CTRL_TRIGGER_MASK)) {
|
||
|
pADC->valSeq[ADC_SEQ_B] &= ~ADC_SEQ_CTRL_START;
|
||
|
}
|
||
|
|
||
|
pREGS->CTRL = (pCfg->flagCfg & CTRL_MASK) | (pCfg->clkDiv & ADC_CR_CLKDIV_MASK);
|
||
|
|
||
|
/* Enable/Disable overflow interrupt */
|
||
|
if (pCfg->flagCfg & ENABLE_OVR) {
|
||
|
pADC->regInt |= ADC_INTEN_OVRRUN_ENABLE;
|
||
|
}
|
||
|
else {
|
||
|
pADC->regInt &= ~ADC_INTEN_OVRRUN_ENABLE;
|
||
|
}
|
||
|
|
||
|
return LPC_OK;
|
||
|
}
|
||
|
|
||
|
/* EXPORTED API: Configure channel specific options */
|
||
|
ErrorCode_t ADC_ConfigureChannel(ADC_HANDLE_T hADC, uint32_t chanNum, uint32_t chanOpts)
|
||
|
{
|
||
|
ADC_DRIVER_T *pADC = hADC;
|
||
|
|
||
|
/* Sanity check */
|
||
|
if (chanNum > ADC_MAX_CHANNEL_NUM) {
|
||
|
return ERR_ADC_PARAM;
|
||
|
}
|
||
|
|
||
|
pADC->regInt &= ~(0x18 << (chanNum * 2));
|
||
|
|
||
|
if (chanOpts & ADC_CH_THRES_SEL1) {
|
||
|
pADC->regThrSel |= 1 << chanNum;
|
||
|
}
|
||
|
else {
|
||
|
pADC->regThrSel &= ~(1 << chanNum);
|
||
|
}
|
||
|
|
||
|
if (chanOpts & ADC_CH_THRES_CROSSING) {
|
||
|
pADC->regInt |= 0x10 << (chanNum * 2);
|
||
|
}
|
||
|
else if (chanOpts & ADC_CH_THRES_OUTSIDE) {
|
||
|
pADC->regInt |= 0x08 << (chanNum * 2);
|
||
|
}
|
||
|
|
||
|
if (chanOpts & ADC_CH_DATA_CALLBACK) {
|
||
|
pADC->flags |= CB_DATA(chanNum);
|
||
|
}
|
||
|
else {
|
||
|
pADC->flags &= ~CB_DATA(chanNum);
|
||
|
}
|
||
|
|
||
|
if (chanOpts & ADC_CH_THRES_CALLBACK) {
|
||
|
pADC->flags |= CB_THRES(chanNum);
|
||
|
}
|
||
|
else {
|
||
|
pADC->flags &= ~CB_THRES(chanNum);
|
||
|
}
|
||
|
|
||
|
if (chanOpts & ADC_CH_THRES_DATA) {
|
||
|
pADC->flag1 |= 1 << chanNum;
|
||
|
}
|
||
|
else {
|
||
|
pADC->flag1 &= ~(1 << chanNum);
|
||
|
}
|
||
|
|
||
|
return LPC_OK;
|
||
|
}
|
||
|
|
||
|
/* EXPORTED API: Start analog to digital conversion on selected sequence */
|
||
|
ErrorCode_t ADC_StartConversion(ADC_HANDLE_T hADC, ADC_SEQ_INDEX_T seqIndex, void *buff, size_t bufCount)
|
||
|
{
|
||
|
ADC_DRIVER_T *pADC = hADC;
|
||
|
ADC_BUFFER_T *buf = &pADC->buffer[seqIndex];
|
||
|
|
||
|
/* Sanity check on parameters */
|
||
|
if ((uint32_t) seqIndex > ADC_SEQ_B) {
|
||
|
return ERR_ADC_INVALID_SEQUENCE;
|
||
|
}
|
||
|
|
||
|
/* If an active conversion is going on set the buffer ptr */
|
||
|
if (buf->state == ADC_STATE_ACTIVE) {
|
||
|
if (buf->szNext) {
|
||
|
return ERR_BUSY;
|
||
|
}
|
||
|
buf->pNext = buff;
|
||
|
buf->szNext = bufCount;
|
||
|
return LPC_OK;
|
||
|
}
|
||
|
|
||
|
/* Assign the buffers */
|
||
|
buf->pCurr = buff;
|
||
|
buf->szCurr = bufCount;
|
||
|
buf->idx = 0;
|
||
|
|
||
|
/* Invoke the call back before start */
|
||
|
_ADC_InvokeCallback(pADC, (ADC_CBINDEX_T) (ADC_START_SEQ + (ADC_CBINDEX_T)seqIndex), (void *) &pADC->pREGS);
|
||
|
|
||
|
buf->state = ADC_STATE_ACTIVE;
|
||
|
pADC->pREGS->SEQ_CTRL[seqIndex] = pADC->valSeq[seqIndex] & ~(ADC_SEQ_CTRL_SEQ_ENA | ADC_SEQ_CTRL_START);
|
||
|
pADC->regInt |= (1 << seqIndex);
|
||
|
pADC->pREGS->INTEN = pADC->regInt;
|
||
|
pADC->pREGS->CHAN_THRSEL = pADC->regThrSel;
|
||
|
pADC->pREGS->SEQ_CTRL[seqIndex] = pADC->valSeq[seqIndex];
|
||
|
|
||
|
return LPC_OK;
|
||
|
}
|
||
|
|
||
|
ErrorCode_t ADC_SwTrigger(ADC_HANDLE_T hADC, ADC_SEQ_INDEX_T seqIndex)
|
||
|
{
|
||
|
ADC_DRIVER_T *pADC = hADC;
|
||
|
|
||
|
/* Sanity check on parameters */
|
||
|
if ((uint32_t) seqIndex > ADC_SEQ_B) {
|
||
|
return ERR_ADC_INVALID_SEQUENCE;
|
||
|
}
|
||
|
|
||
|
pADC->pREGS->SEQ_CTRL[seqIndex] = pADC->valSeq[seqIndex] | ADC_SEQ_CTRL_SEQ_ENA | ADC_SEQ_CTRL_START;
|
||
|
return LPC_OK;
|
||
|
}
|
||
|
|
||
|
/* EXPORTED API: Stop conversion on a given sequence */
|
||
|
ErrorCode_t ADC_StopConversion(ADC_HANDLE_T hADC, ADC_SEQ_INDEX_T seqIndex)
|
||
|
{
|
||
|
ADC_DRIVER_T *pADC = hADC;
|
||
|
|
||
|
/* Sanity check on parameters */
|
||
|
if ((uint32_t) seqIndex > ADC_SEQ_B) {
|
||
|
return ERR_ADC_INVALID_SEQUENCE;
|
||
|
}
|
||
|
|
||
|
pADC->regInt &= ~(1 << seqIndex);
|
||
|
pADC->pREGS->INTEN = pADC->regInt; /* Disable interrupts */
|
||
|
pADC->buffer[seqIndex].state = ADC_STATE_IDLE; /* Set state to IDLE */
|
||
|
|
||
|
/* Stop and disable the sequence */
|
||
|
pADC->pREGS->SEQ_CTRL[seqIndex] = pADC->valSeq[seqIndex] &
|
||
|
~(ADC_SEQ_CTRL_SEQ_ENA | ADC_SEQ_CTRL_BURST | ADC_SEQ_CTRL_START);
|
||
|
_ADC_InvokeCallback(hADC, (ADC_CBINDEX_T)(ADC_STOP_SEQ + (ADC_CBINDEX_T)seqIndex), 0);
|
||
|
return LPC_OK;
|
||
|
}
|
||
|
|
||
|
/* EXPORTED API: ADC Event handler */
|
||
|
ErrorCode_t ADC_Handler(ADC_HANDLE_T hADC, ADC_HEVENT_T hEvent)
|
||
|
{
|
||
|
ADC_DRIVER_T *pADC = hADC;
|
||
|
|
||
|
switch (hEvent) {
|
||
|
case ADC_EV_SEQ_A_POLL:
|
||
|
return _ADC_Handler_SeqPoll(pADC, ADC_SEQ_A);
|
||
|
|
||
|
case ADC_EV_SEQ_B_POLL:
|
||
|
return _ADC_Handler_SeqPoll(pADC, ADC_SEQ_B);
|
||
|
|
||
|
case ADC_EV_SEQ_A_INT:
|
||
|
return _ADC_Handler_Seq(pADC, ADC_SEQ_A);
|
||
|
|
||
|
case ADC_EV_SEQ_B_INT:
|
||
|
return _ADC_Handler_Seq(pADC, ADC_SEQ_B);
|
||
|
|
||
|
case ADC_EV_SEQ_A_DMA:
|
||
|
if (!(pADC->valSeq[ADC_SEQ_A] & 0x3F000)) {
|
||
|
ADC_SwTrigger(hADC, ADC_SEQ_A);
|
||
|
}
|
||
|
return LPC_OK;
|
||
|
|
||
|
case ADC_EV_SEQ_B_DMA:
|
||
|
if (!(pADC->valSeq[ADC_SEQ_B] & 0x3F000)) {
|
||
|
ADC_SwTrigger(hADC, ADC_SEQ_B);
|
||
|
}
|
||
|
return LPC_OK;
|
||
|
|
||
|
case ADC_EV_OVR_INT:
|
||
|
return _ADC_Handler_Ovr(pADC);
|
||
|
|
||
|
case ADC_EV_THRES_INT:
|
||
|
return _ADC_Handler_Thres(pADC);
|
||
|
|
||
|
default:
|
||
|
return ERR_ADC_PARAM;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* EXPROTED API: Returns memory required for ADC driver */
|
||
|
uint32_t ADC_GetMemSize(void)
|
||
|
{
|
||
|
return sizeof(ADC_DRIVER_T);
|
||
|
}
|
||
|
|
||
|
/* EXPORTED API: Function to Get the firmware Version */
|
||
|
uint32_t ADC_GetDriverVersion(void)
|
||
|
{
|
||
|
return ADC_DRIVER_VERSION;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Table of the addresses of all the 12-Bit ADC functions
|
||
|
* @note This table of function pointers is the API interface.
|
||
|
*/
|
||
|
const ROM_ADC_API_T adcrom_api = {
|
||
|
ADC_GetMemSize,
|
||
|
ADC_Init,
|
||
|
ADC_Configure,
|
||
|
ADC_ConfigureChannel,
|
||
|
ADC_SetThreshold,
|
||
|
ADC_RegisterCallback,
|
||
|
ADC_Calibrate,
|
||
|
ADC_Handler,
|
||
|
ADC_StartConversion,
|
||
|
ADC_StopConversion,
|
||
|
ADC_SwTrigger,
|
||
|
ADC_GetDriverVersion,
|
||
|
};
|