diff options
Diffstat (limited to 'bsps/arm/imxrt/mcux-sdk/drivers/asrc')
-rw-r--r-- | bsps/arm/imxrt/mcux-sdk/drivers/asrc/fsl_asrc.c | 1031 | ||||
-rw-r--r-- | bsps/arm/imxrt/mcux-sdk/drivers/asrc/fsl_asrc.h | 761 | ||||
-rw-r--r-- | bsps/arm/imxrt/mcux-sdk/drivers/asrc/fsl_asrc_edma.c | 470 | ||||
-rw-r--r-- | bsps/arm/imxrt/mcux-sdk/drivers/asrc/fsl_asrc_edma.h | 245 |
4 files changed, 2507 insertions, 0 deletions
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/asrc/fsl_asrc.c b/bsps/arm/imxrt/mcux-sdk/drivers/asrc/fsl_asrc.c new file mode 100644 index 0000000000..be4f6c1b4d --- /dev/null +++ b/bsps/arm/imxrt/mcux-sdk/drivers/asrc/fsl_asrc.c @@ -0,0 +1,1031 @@ +/* + * Copyright 2019-2021 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_asrc.h" + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.asrc" +#endif + +/******************************************************************************* + * Definitations + ******************************************************************************/ +/*! @brief Typedef for asrc tx interrupt handler. */ +typedef void (*asrc_isr_t)(ASRC_Type *base, asrc_handle_t *asrcHandle); +/*! @brief ASRC support maximum channel number */ +#define ASRC_SUPPORT_MAXIMUM_CHANNEL_NUMER (10U) +#define ASRC_SAMPLE_RATIO_DECIMAL_DEPTH (26U) +/******************************************************************************* + * Prototypes + ******************************************************************************/ +/*! + * @brief ASRC read non blocking. + * + * @param base ASRC base pointer. + * @param channelPair ASRC channel pair. + * @param destAddress dest buffer address. + * @param samples number of samples to read. + * @param sampleWidth the width that one sample takes. + */ +static void ASRC_ReadNonBlocking( + ASRC_Type *base, asrc_channel_pair_t channelPair, uint32_t *destAddress, uint32_t samples, uint32_t sampleWidth); + +/*! + * @brief ASRC write non blocking. + * + * @param base ASRC base pointer. + * @param channelPair ASRC channel pair. + * @param srcAddress source buffer address. + * @param samples number of samples to read. + * @param sampleMask the mask of sample data. + * @param sampleWidth the width that one sample takes. + */ +static void ASRC_WriteNonBlocking(ASRC_Type *base, + asrc_channel_pair_t channelPair, + const uint32_t *srcAddress, + uint32_t samples, + uint32_t sampleMask, + uint32_t sampleWidth); + +/*! + * @brief ASRC calculate divider and prescaler. + * + * @param sampleRate_Hz sample rate. + * @param sourceClock_Hz source clock. + */ +static uint32_t ASRC_CalculateClockDivider(uint32_t sampleRate_Hz, uint32_t sourceClock_Hz); + +/*! + * @brief ASRC pre/post processing selection. + * + * @param inSampleRate in audio data sample rate. + * @param outSampleRate out audio data sample rate. + * @param preProc pre processing selection. + * @param postProc post precessing selection. + */ +static status_t ASRC_ProcessSelection(uint32_t inSampleRate, + uint32_t outSampleRate, + uint32_t *preProc, + uint32_t *postProc); +/******************************************************************************* + * Variables + ******************************************************************************/ +/* Base pointer array */ +static ASRC_Type *const s_asrcBases[] = ASRC_BASE_PTRS; +/*!@brief asrc handle pointer */ +static asrc_handle_t *s_asrcHandle[ARRAY_SIZE(s_asrcBases)][FSL_ASRC_CHANNEL_PAIR_COUNT]; +/* IRQ number array */ +static const IRQn_Type s_asrcIRQ[] = ASRC_IRQS; + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) +/* Clock name array */ +static const clock_ip_name_t s_asrcClock[] = ASRC_CLOCKS; +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ +/*! @brief Pointer to IRQ handler for each instance. */ +static asrc_isr_t s_asrcIsr; +/******************************************************************************* + * Code + ******************************************************************************/ +uint32_t ASRC_GetInstance(ASRC_Type *base) +{ + uint32_t instance; + + /* Find the instance index from base address mappings. */ + for (instance = 0; instance < ARRAY_SIZE(s_asrcBases); instance++) + { + if (s_asrcBases[instance] == base) + { + break; + } + } + + assert(instance < ARRAY_SIZE(s_asrcBases)); + + return instance; +} + +static void ASRC_ReadNonBlocking( + ASRC_Type *base, asrc_channel_pair_t channelPair, uint32_t *destAddress, uint32_t samples, uint32_t sampleWidth) +{ + uint32_t i = 0U; + uint32_t *destAddr = destAddress; + volatile uint32_t *srcAddr = ASRC_ASRDO_ADDR(base, channelPair); + + for (i = 0U; i < samples; i++) + { + *destAddr = *srcAddr; + destAddr = (uint32_t *)((uint32_t)destAddr + sampleWidth); + } +} + +static void ASRC_WriteNonBlocking(ASRC_Type *base, + asrc_channel_pair_t channelPair, + const uint32_t *srcAddress, + uint32_t samples, + uint32_t sampleMask, + uint32_t sampleWidth) +{ + uint32_t i = 0U; + const uint32_t *srcAddr = srcAddress; + volatile uint32_t *destAddr = ASRC_ASRDI_ADDR(base, channelPair); + + for (i = 0U; i < samples; i++) + { + *destAddr = *srcAddr & sampleMask; + srcAddr = (uint32_t *)((uint32_t)srcAddr + sampleWidth); + } +} + +static uint32_t ASRC_CalculateClockDivider(uint32_t sampleRate_Hz, uint32_t sourceClock_Hz) +{ + assert(sourceClock_Hz >= sampleRate_Hz); + + uint32_t divider = sourceClock_Hz / sampleRate_Hz; + uint32_t prescaler = 0U; + + /* sourceClock_Hz = sampleRate_Hz * divider * (2 ^ prescaler) */ + while (divider > 8U) + { + divider >>= 1U; + prescaler++; + } + /* Hardware limitation: + * If the prescaler is set to 1, the clock divider can only be set to 1 and the clock source must have a 50% duty + * cycle + */ + if ((prescaler == 1U) && (divider != 1U)) + { + divider >>= 1U; + prescaler++; + } + /* fine tuning */ + if (sourceClock_Hz / ((1UL << prescaler) * divider) > sampleRate_Hz) + { + divider++; + } + + return ((divider - 1U) << 3U) | (prescaler & 0x7U); +} + +static status_t ASRC_ProcessSelection(uint32_t inSampleRate, + uint32_t outSampleRate, + uint32_t *preProc, + uint32_t *postProc) +{ + bool op2Cond = false; + bool op0Cond = false; + + op2Cond = (((inSampleRate * 15U > outSampleRate * 16U) && (outSampleRate < 56000U)) || + ((inSampleRate > 56000U) && (outSampleRate < 56000U))); + op0Cond = (inSampleRate * 23U < outSampleRate * 8U); + + /* preProc == 4 or preProc == 5 is not support now */ + if ((inSampleRate * 8U > 129U * outSampleRate) || ((inSampleRate * 8U > 65U * outSampleRate))) + { + return kStatus_ASRCNotSupport; + } + + if (inSampleRate * 8U > 33U * outSampleRate) + { + *preProc = 2U; + } + else if (inSampleRate * 8U > 15U * outSampleRate) + { + if (inSampleRate > 152000U) + { + *preProc = 2U; + } + else + { + *preProc = 1U; + } + } + else if (inSampleRate < 76000U) + { + *preProc = 0; + } + else if (inSampleRate > 152000U) + { + *preProc = 2; + } + else + { + *preProc = 1; + } + + if (op2Cond) + { + *postProc = 2; + } + else if (op0Cond) + { + *postProc = 0; + } + else + { + *postProc = 1; + } + + return kStatus_Success; +} + +/*! + * brief Map register sample width to real sample width. + * + * note This API is depends on the ASRC configuration, should be called after the ASRC_SetChannelPairConfig. + * param base asrc base pointer. + * param channelPair asrc channel pair index. + * param inWidth ASRC channel pair number. + * param outWidth input sample rate. + * retval input sample mask value. + */ +uint32_t ASRC_MapSamplesWidth(ASRC_Type *base, asrc_channel_pair_t channelPair, uint32_t *inWidth, uint32_t *outWidth) +{ + uint32_t sampleMask = 0U, + inRegWidth = (ASRC_ASRMCR1(base, channelPair) & ASRC_ASRMCR1_IWD_MASK) >> ASRC_ASRMCR1_IWD_SHIFT, + outRegWidth = ASRC_ASRMCR1(base, channelPair) & ASRC_ASRMCR1_OW16_MASK, + inDataAlign = (ASRC_ASRMCR1(base, channelPair) & ASRC_ASRMCR1_IMSB_MASK) >> ASRC_ASRMCR1_IMSB_SHIFT, + outDataAlign = (ASRC_ASRMCR1(base, channelPair) & ASRC_ASRMCR1_OMSB_MASK) >> ASRC_ASRMCR1_OMSB_SHIFT; + /* get in sample width */ + if (inRegWidth == (uint32_t)kASRC_DataWidth8Bit) + { + *inWidth = 1U; + sampleMask = 0xFFU; + if (inDataAlign == (uint32_t)kASRC_DataAlignMSB) + { + *inWidth = 2U; + sampleMask = 0xFF00U; + } + } + else if (inRegWidth == (uint32_t)kASRC_DataWidth16Bit) + { + *inWidth = 2U; + sampleMask = 0xFFFFU; + if (inDataAlign == (uint32_t)kASRC_DataAlignMSB) + { + *inWidth = 4U; + sampleMask = 0xFFFF0000U; + } + } + else + { + *inWidth = 3U; + sampleMask = 0xFFFFFFU; + + if (inDataAlign == (uint32_t)kASRC_DataAlignMSB) + { + sampleMask = 0xFFFFFF00U; + *inWidth = 4U; + } + } + /* get out sample width */ + if (outRegWidth == (uint32_t)kASRC_DataWidth16Bit) + { + *outWidth = 2U; + if (outDataAlign == (uint32_t)kASRC_DataAlignMSB) + { + *outWidth = 4U; + } + } + else + { + *outWidth = 4U; + } + + return sampleMask; +} + +/*! + * brief ASRC configure ideal ratio. + * The ideal ratio should be used when input clock source is not avalible. + * + * param base ASRC base pointer. + * param channelPair ASRC channel pair. + * param inputSampleRate input audio data sample rate. + * param outputSampleRate output audio data sample rate. + */ +status_t ASRC_SetIdealRatioConfig(ASRC_Type *base, + asrc_channel_pair_t channelPair, + uint32_t inputSampleRate, + uint32_t outputSampleRate) +{ + uint32_t ratio = 0U, i = 0U; + uint32_t preProc = 0U, postProc = 0U; + uint32_t asrcfg = base->ASRCFG; + /* caculate integer part */ + ratio = (inputSampleRate / outputSampleRate) << ASRC_SAMPLE_RATIO_DECIMAL_DEPTH; + + inputSampleRate %= outputSampleRate; + /* get decimal part */ + for (i = 1U; i <= ASRC_SAMPLE_RATIO_DECIMAL_DEPTH; i++) + { + inputSampleRate <<= 1; + + if (inputSampleRate < outputSampleRate) + { + continue; + } + + ratio |= 1UL << (ASRC_SAMPLE_RATIO_DECIMAL_DEPTH - i); + inputSampleRate -= outputSampleRate; + + if (0U == inputSampleRate) + { + break; + } + } + /* select pre/post precessing option */ + if (ASRC_ProcessSelection(inputSampleRate, outputSampleRate, &preProc, &postProc) != kStatus_Success) + { + return kStatus_ASRCNotSupport; + } + + ASRC_IDEAL_RATIO_HIGH(base, channelPair) = ASRC_ASRIDRHA_IDRATIOA_H(ratio >> 24U); + ASRC_IDEAL_RATIO_LOW(base, channelPair) = ASRC_ASRIDRLA_IDRATIOA_L(ratio); + base->ASRCTR &= ~ASRC_ASRCTR_AT_MASK(channelPair); + asrcfg &= ~(ASRC_ASRCFG_PRE_MODE_MASK(channelPair) | ASRC_ASRCFG_POST_MODE_MASK(channelPair)); + asrcfg |= ASRC_ASRCFG_PRE_MODE(preProc, channelPair) | ASRC_ASRCFG_POST_MODE(postProc, channelPair); + base->ASRCFG = asrcfg; + + return kStatus_Success; +} + +/*! + * brief Initializes the asrc peripheral. + * + * This API gates the asrc clock. The asrc module can't operate unless ASRC_Init is called to enable the clock. + * + * param base asrc base pointer. + * param asrcPeripheralClock_Hz peripheral clock of ASRC. + */ +void ASRC_Init(ASRC_Type *base, uint32_t asrcPeripheralClock_Hz) +{ +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + /* Enable the asrc clock */ + CLOCK_EnableClock(s_asrcClock[ASRC_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + + /* disable ASRC channel pair, enable ASRC */ + base->ASRCTR = 1U; + + /* disable all the interrupt */ + base->ASRIER = 0U; + +#if (defined FSL_FEATURE_ASRC_PARAMETER_REGISTER_NAME_ASRPM) && FSL_FEATURE_ASRC_PARAMETER_REGISTER_NAME_ASRPM + /* set paramter register to default configurations per recommand value in reference manual */ + base->ASRPM[0] = 0x7fffffU; + base->ASRPM[1] = 0x255555U; + base->ASRPM[2] = 0xff7280U; + base->ASRPM[3] = 0xff7280U; + base->ASRPM[4] = 0xff7280U; +#else + /* set paramter register to default configurations per recommand value in reference manual */ + base->ASRPMn[0] = 0x7fffffU; + base->ASRPMn[1] = 0x255555U; + base->ASRPMn[2] = 0xff7280U; + base->ASRPMn[3] = 0xff7280U; + base->ASRPMn[4] = 0xff7280U; +#endif /*FSL_FEATURE_ASRC_PARAMETER_REGISTER_NAME_ASRPM*/ + /* set task queue fifo */ + base->ASRTFR1 = ASRC_ASRTFR1_TF_BASE(0x7C); + /* 76K/56K divider */ + base->ASR76K = ASRC_ASR76K_ASR76K(asrcPeripheralClock_Hz / 76000U); + base->ASR56K = ASRC_ASR56K_ASR56K(asrcPeripheralClock_Hz / 56000U); +} + +/*! + * brief De-initializes the ASRC peripheral. + * + * This API gates the ASRC clock and disable ASRC module. The ASRC module can't operate unless ASRC_Init + * + * param base ASRC base pointer. + */ +void ASRC_Deinit(ASRC_Type *base) +{ + /* disable ASRC module */ + ASRC_ModuleEnable(base, false); + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + CLOCK_DisableClock(s_asrcClock[ASRC_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ +} + +/*! + * brief Do software reset . + * + * This software reset bit is self-clear bit, it will generate a software reset signal inside ASRC. + * After 9 cycles of the ASRC processing clock, this reset process will stop and this bit will cleared + * automatically. + * + * param base ASRC base pointer + */ +void ASRC_SoftwareReset(ASRC_Type *base) +{ + base->ASRCTR |= ASRC_ASRCTR_SRST_MASK; + /* polling reset clear automatically */ + while ((base->ASRCTR & ASRC_ASRCTR_SRST_MASK) != 0U) + { + } +} + +/*! + * brief ASRC configure channel pair. + * + * param base ASRC base pointer. + * param channelPair index of channel pair, reference _asrc_channel_pair. + * param config ASRC channel pair configuration pointer. + * param inputSampleRate in audio data sample rate. + * param outSampleRate out audio data sample rate. + */ +status_t ASRC_SetChannelPairConfig(ASRC_Type *base, + asrc_channel_pair_t channelPair, + asrc_channel_pair_config_t *config, + uint32_t inputSampleRate, + uint32_t outputSampleRate) +{ + assert(config != NULL); + + if (config->outDataWidth == kASRC_DataWidth8Bit) + { + return kStatus_InvalidArgument; + } + + if (((inputSampleRate < (uint32_t)kASRC_SampleRate_8000HZ) || + (inputSampleRate > (uint32_t)kASRC_SampleRate_192000HZ)) || + ((outputSampleRate < (uint32_t)kASRC_SampleRate_8000HZ) || + (outputSampleRate > (uint32_t)kASRC_SampleRate_192000HZ)) || + (((outputSampleRate > (uint32_t)kASRC_SampleRate_8000HZ) && + (outputSampleRate < (uint32_t)kASRC_SampleRate_30000HZ)) && + (inputSampleRate / outputSampleRate > 8U || outputSampleRate / inputSampleRate > 24U))) + { + return kStatus_InvalidArgument; + } + + uint32_t i = 0U; + /* channel pair processing selection and ratio configuration */ + uint32_t asrctr = base->ASRCTR & (~(ASRC_ASRCTR_AT_MASK(channelPair) | ASRC_ASRCTR_RATIO_MASK(channelPair))); + /* use automatic selection for processing option by default */ + asrctr |= ASRC_ASRCTR_AT_MASK(channelPair); + /* ratio configuration */ + asrctr |= ASRC_ASRCTR_RATIO(config->sampleRateRatio, channelPair); + base->ASRCTR = asrctr; + + /* audio data channel counter configurations */ + uint32_t asrcncr = base->ASRCNCR & (~ASRC_ASRCNCR_CHANNEL_COUNTER_MASK(channelPair)); + base->ASRCNCR = asrcncr | ASRC_ASRCNCR_CHANNEL_COUNTER(config->audioDataChannels, channelPair); + + /* in clock source and out clock source configurations */ + uint32_t asrcsr = + base->ASRCSR & + (~(ASRC_ASRCSR_INPUT_CLOCK_SOURCE_MASK(channelPair) | ASRC_ASRCSR_OUTPUT_CLOCK_SOURCE_MASK(channelPair))); + asrcsr |= ASRC_ASRCSR_OUTPUT_CLOCK_SOURCE(config->outClockSource, channelPair); + if (config->inClockSource != kASRC_ClockSourceNotAvalible) + { + asrcsr |= ASRC_ASRCSR_INPUT_CLOCK_SOURCE(config->inClockSource, channelPair); + } + base->ASRCSR = asrcsr; + + /* clock divider configuration */ + uint32_t asrcdr = + base->ASRCDR1 & + (~(ASRC_ASRCDR_INPUT_PRESCALER_MASK(channelPair) | ASRC_ASRCDR_INPUT_DIVIDER_MASK(channelPair) | + ASRC_ASRCDR_OUTPUT_PRESCALER_MASK(channelPair) | ASRC_ASRCDR_OUTPUT_DIVIDER_MASK(channelPair))); + + asrcdr |= ASCR_ASRCDR_OUTPUT_CLOCK_DIVIDER_PRESCALER( + ASRC_CalculateClockDivider(outputSampleRate, config->outSourceClock_Hz), channelPair); + if (config->inClockSource != kASRC_ClockSourceNotAvalible) + { + asrcdr |= ASCR_ASRCDR_INPUT_CLOCK_DIVIDER_PRESCALER( + ASRC_CalculateClockDivider(inputSampleRate, config->inSourceClock_Hz), channelPair); + } + + if (channelPair == kASRC_ChannelPairC) + { + base->ASRCDR2 = asrcdr; + } + else + { + base->ASRCDR1 = asrcdr; + } + + /* data width/sign extension/data align configuration */ + ASRC_ASRMCR1(base, channelPair) = ASRC_ASRMCR1_OW16(config->outDataWidth) | ASRC_ASRMCR1_IWD(config->inDataWidth) | + ASRC_ASRMCR1_OSGN(config->outSignExtension) | + ASRC_ASRMCR1_OMSB(config->outDataAlign) | ASRC_ASRMCR1_IMSB(config->inDataAlign); + /* data configurations, MISC */ + uint32_t asrmcra = ASRC_ASRMCR(base, channelPair) & + (~(ASRC_ASRMCRA_BUFSTALLA_MASK | ASRC_ASRMCRA_EXTTHRSHA_MASK | + ASRC_ASRMCRA_INFIFO_THRESHOLDA_MASK | ASRC_ASRMCRA_OUTFIFO_THRESHOLDA_MASK)); + /* buffer stall */ + asrmcra |= ASRC_ASRMCRA_BUFSTALLA(config->bufStallWhenFifoEmptyFull); + /* in fifo and out fifo threshold */ + asrmcra |= ASRC_ASRMCRA_EXTTHRSHA_MASK | ASRC_ASRMCRA_INFIFO_THRESHOLDA(config->inFifoThreshold - 1UL) | + ASRC_ASRMCRA_OUTFIFO_THRESHOLDA(config->outFifoThreshold - 1UL); + ASRC_ASRMCR(base, channelPair) = asrmcra; + + if (config->sampleRateRatio == kASRC_RatioUseIdealRatio) + { + if (ASRC_SetIdealRatioConfig(base, channelPair, inputSampleRate, outputSampleRate) != kStatus_Success) + { + return kStatus_ASRCChannelPairConfigureFailed; + } + } + + /* channel pair enable */ + ASRC_ChannelPairEnable(base, channelPair, true); + + /* wait channel initial served */ + while (!ASRC_GetChannelPairInitialStatus(base, channelPair)) + { + } + + for (i = 0U; i < (uint32_t)config->audioDataChannels * 4U; i++) + { + ASRC_ChannelPairWriteData(base, channelPair, 0U); + } + + return kStatus_Success; +} + +/*! + * brief Get output sample buffer size. + * + * note This API is depends on the ASRC output configuration, should be called after the ASRC_SetChannelPairConfig. + * + * param base asrc base pointer. + * param channelPair ASRC channel pair number. + * param inSampleRate input sample rate. + * param outSampleRate output sample rate. + * param inSamples input sampleS size. + * retval output buffer size in byte. + */ +uint32_t ASRC_GetOutSamplesSize(ASRC_Type *base, + asrc_channel_pair_t channelPair, + uint32_t inSampleRate, + uint32_t outSampleRate, + uint32_t inSamplesize) +{ + uint32_t inSamples = 0U; + uint32_t outSamples = 0U; + uint32_t outSamplesBufSize = 0U, audioChannels = ASRC_GET_CHANNEL_COUNTER(base, channelPair); + ; + asrc_data_width_t outWdith = (base->ASRMCR1[channelPair] & ASRC_ASRMCR1_OW16_MASK) == ASRC_ASRMCR1_OW16_MASK ? + kASRC_DataWidth16Bit : + kASRC_DataWidth24Bit; + asrc_data_align_t outAlign = (base->ASRMCR1[channelPair] & ASRC_ASRMCR1_OMSB_MASK) == ASRC_ASRMCR1_OMSB_MASK ? + kASRC_DataAlignMSB : + kASRC_DataAlignLSB; + uint32_t inWdith = (base->ASRMCR1[channelPair] & ASRC_ASRMCR1_IWD_MASK) >> ASRC_ASRMCR1_IWD_SHIFT; + asrc_data_align_t inAlign = (base->ASRMCR1[channelPair] & ASRC_ASRMCR1_IMSB_MASK) == ASRC_ASRMCR1_IMSB_MASK ? + kASRC_DataAlignMSB : + kASRC_DataAlignLSB; + + bool signExtend = (base->ASRMCR1[channelPair] & ASRC_ASRMCR1_OSGN_MASK) == ASRC_ASRMCR1_OSGN_MASK ? true : false; + + /* 24bit input data */ + if (inWdith == 0U) + { + inSamples = inSamplesize / (inAlign == kASRC_DataAlignMSB ? 4U : 3U); + } + /* 16bit input data */ + else if (inWdith == 1U) + { + inSamples = inSamplesize / (inAlign == kASRC_DataAlignMSB ? 4U : 2U); + } + /* 8bit input data */ + else + { + inSamples = inSamplesize / (inAlign == kASRC_DataAlignMSB ? 2U : 1U); + } + + outSamples = (uint32_t)((uint64_t)inSamples * outSampleRate / inSampleRate); + /* make sure output samples is in group */ + outSamples = outSamples - outSamples % audioChannels; + + if (outWdith == kASRC_DataWidth16Bit) + { + if ((outAlign == kASRC_DataAlignMSB) || signExtend) + { + outSamplesBufSize = outSamples * 4U; + } + else + { + outSamplesBufSize = outSamples * 2U; + } + } + + if (outWdith == kASRC_DataWidth24Bit) + { + outSamplesBufSize = outSamples * 4U; + } + + return outSamplesBufSize; +} + +/*! + * brief Performs an blocking convert on asrc. + * + * note This API returns immediately after the convert finished. + * + * param base asrc base pointer. + * param channelPair channel pair index. + * param xfer Pointer to the ASRC_transfer_t structure. + * retval kStatus_Success Successfully started the data receive. + */ +status_t ASRC_TransferBlocking(ASRC_Type *base, asrc_channel_pair_t channelPair, asrc_transfer_t *xfer) +{ + assert(xfer != NULL); + + uint32_t inWaterMark = ASRC_ASRMCR(base, channelPair) & ASRC_ASRMCRA_INFIFO_THRESHOLDA_MASK, + outWaterMark = (ASRC_ASRMCR(base, channelPair) & ASRC_ASRMCRA_OUTFIFO_THRESHOLDA_MASK) >> + ASRC_ASRMCRA_OUTFIFO_THRESHOLDA_SHIFT, + audioChannels = ASRC_GET_CHANNEL_COUNTER(base, channelPair); + uint8_t *inAddr = (uint8_t *)xfer->inData, *outAddr = (uint8_t *)xfer->outData; + uint32_t onceWriteSamples = 0U; + uint32_t status = 0U, inSampleMask = 0U, inSamples = 0U, outSamples = 0U, inWidth = 0U, outWidth = 0U; + + inSampleMask = ASRC_MapSamplesWidth(base, channelPair, &inWidth, &outWidth); + inSamples = xfer->inDataSize / inWidth; + outSamples = xfer->outDataSize / outWidth; + inWaterMark *= audioChannels; + outWaterMark *= audioChannels; + + while (outSamples != 0U) + { + status = ASRC_GetStatus(base); + + if ((status & ((uint32_t)kASRC_StatusPairCInputReady | (uint32_t)kASRC_StatusPairBInputReady | + (uint32_t)kASRC_StatusPairAInputReady)) != 0U) + { + onceWriteSamples = + MIN(inSamples, (size_t)((FSL_ASRC_CHANNEL_PAIR_FIFO_DEPTH * audioChannels - inWaterMark))); + ASRC_WriteNonBlocking(base, channelPair, (uint32_t *)(uint32_t)inAddr, onceWriteSamples, inSampleMask, + inWidth); + inAddr = (uint8_t *)((uint32_t)inAddr + onceWriteSamples * inWidth); + inSamples -= onceWriteSamples; + } + + if (outSamples > outWaterMark) + { + if ((status & ((uint32_t)kASRC_StatusPairCOutputReady | (uint32_t)kASRC_StatusPairAOutputReady | + (uint32_t)kASRC_StatusPairBOutputReady)) != 0U) + { + ASRC_ReadNonBlocking(base, channelPair, (uint32_t *)(uint32_t)outAddr, outWaterMark, outWidth); + outAddr = (uint8_t *)((uint32_t)outAddr + outWaterMark * outWidth); + outSamples -= outWaterMark; + } + } + else + { + outSamples -= + ASRC_GetRemainFifoSamples(base, channelPair, (uint32_t *)(uint32_t)outAddr, outWidth, outSamples); + continue; + } + } + + return kStatus_Success; +} + +/*! + * brief ASRC configure channel pair. + * + * param base ASRC base pointer. + * param handle ASRC transactional handle pointer. + * param config ASRC channel pair configuration pointer. + * param inputSampleRate in audio data sample rate. + * param outputSampleRate out audio data sample rate. + */ +status_t ASRC_TransferSetChannelPairConfig(ASRC_Type *base, + asrc_handle_t *handle, + asrc_channel_pair_config_t *config, + uint32_t inputSampleRate, + uint32_t outputSampleRate) +{ + assert(handle != NULL); + + handle->in.fifoThreshold = config->inFifoThreshold * (uint32_t)config->audioDataChannels; + handle->out.fifoThreshold = config->outFifoThreshold * (uint32_t)config->audioDataChannels; + handle->audioDataChannels = config->audioDataChannels; + + if (ASRC_SetChannelPairConfig(base, handle->channelPair, config, inputSampleRate, outputSampleRate) != + kStatus_Success) + { + return kStatus_ASRCChannelPairConfigureFailed; + } + + handle->in.sampleMask = + ASRC_MapSamplesWidth(base, handle->channelPair, &handle->in.sampleWidth, &handle->out.sampleWidth); + + return kStatus_Success; +} + +/*! + * brief Get left samples in fifo. + * + * param base asrc base pointer. + * param channelPair ASRC channel pair number. + * param buffer input sample numbers. + * param outSampleWidth output sample width. + * param remainSamples output sample rate. + * retval remain samples number. + */ +uint32_t ASRC_GetRemainFifoSamples( + ASRC_Type *base, asrc_channel_pair_t channelPair, uint32_t *buffer, uint32_t outSampleWidth, uint32_t remainSamples) +{ + uint32_t remainSamplesInFifo = 0U; + uint32_t audioChannels = ASRC_GET_CHANNEL_COUNTER(base, channelPair); + remainSamplesInFifo = + ((ASRC_ASRFST_ADDR(base, channelPair) & ASRC_ASRFSTA_OUTFIFO_FILLA_MASK) >> ASRC_ASRFSTA_OUTFIFO_FILLA_SHIFT) * + audioChannels; + + if (remainSamples < remainSamplesInFifo) + { + remainSamplesInFifo = remainSamples; + } + + ASRC_ReadNonBlocking(base, channelPair, (uint32_t *)buffer, remainSamplesInFifo, outSampleWidth); + + return remainSamplesInFifo; +} + +/*! + * brief Initializes the ASRC handle. + * + * This function initializes the handle for the ASRC transactional APIs. Call + * this function once to get the handle initialized. + * + * param base ASRC base pointer + * param handle ASRC handle pointer. + * param inCallback Pointer to the user callback function. + * param outCallback Pointer to the user callback function. + * param userData User parameter passed to the callback function + */ +void ASRC_TransferCreateHandle(ASRC_Type *base, + asrc_handle_t *handle, + asrc_channel_pair_t channelPair, + asrc_transfer_callback_t inCallback, + asrc_transfer_callback_t outCallback, + void *userData) +{ + assert(handle != NULL); + + uint32_t instance = ASRC_GetInstance(base); + + (void)memset(handle, 0, sizeof(*handle)); + + s_asrcHandle[instance][channelPair] = handle; + + handle->in.callback = inCallback; + handle->out.callback = outCallback; + handle->userData = userData; + handle->channelPair = channelPair; + /* Set the isr pointer */ + s_asrcIsr = ASRC_TransferHandleIRQ; + + (void)EnableIRQ(s_asrcIRQ[instance]); +} + +/*! + * brief Performs an interrupt non-blocking convert on asrc. + * + * note This API returns immediately after the transfer initiates, application should check the wait and check the + * callback status. + * + * param base asrc base pointer. + * param handle Pointer to the asrc_handle_t structure which stores the transfer state. + * param xfer Pointer to the ASRC_transfer_t structure. + * retval kStatus_Success Successfully started the data receive. + * retval kStatus_ASRCBusy Previous receive still not finished. + */ +status_t ASRC_TransferNonBlocking(ASRC_Type *base, asrc_handle_t *handle, asrc_transfer_t *xfer) +{ + assert(handle != NULL); + assert(xfer != NULL); + + /* Check if the queue is full */ + if ((handle->in.asrcQueue[handle->in.queueUser] != NULL) || (handle->out.asrcQueue[handle->out.queueUser] != NULL)) + { + return kStatus_ASRCBusy; + } + + /* Add into queue */ + handle->in.transferSamples[handle->in.queueUser] = xfer->inDataSize / handle->in.sampleWidth; + handle->in.asrcQueue[handle->in.queueUser] = xfer->inData; + handle->in.queueUser = (handle->in.queueUser + 1U) % ASRC_XFER_QUEUE_SIZE; + + handle->out.asrcQueue[handle->out.queueUser] = xfer->outData; + handle->out.transferSamples[handle->out.queueUser] = xfer->outDataSize / handle->out.sampleWidth; + handle->out.queueUser = (handle->out.queueUser + 1U) % ASRC_XFER_QUEUE_SIZE; + + if (handle->state != (uint32_t)kStatus_ASRCBusy) + { + /* enable channel pair interrupt */ + ASRC_EnableInterrupt(base, ASRC_ASRIER_INPUT_INTERRUPT_MASK(handle->channelPair) | + (uint32_t)kASRC_OverLoadInterruptMask | + ASRC_ASRIER_OUTPUTPUT_INTERRUPT_MASK(handle->channelPair)); + } + + /* Set the state to busy */ + handle->state = kStatus_ASRCBusy; + + return kStatus_Success; +} + +/*! + * brief Gets a set byte count. + * + * param base asrc base pointer. + * param handle Pointer to the ASRC_handle_t structure which stores the transfer state. + * param count Bytes count sent. + * retval kStatus_Success Succeed get the transfer count. + * retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress. + */ +status_t ASRC_TransferGetConvertedCount(ASRC_Type *base, asrc_handle_t *handle, size_t *count) +{ + assert(handle != NULL); + + status_t status = kStatus_Success; + + if (handle->state != (uint32_t)kStatus_ASRCBusy) + { + status = kStatus_ASRCIdle; + } + else + { + *count = handle->out.transferSamples[handle->out.queueDriver]; + } + + return status; +} + +/*! + * brief Aborts the current convert. + * + * note This API can be called any time when an interrupt non-blocking transfer initiates + * to abort the transfer early. + * + * param base asrc base pointer. + * param handle Pointer to the ASRC_handle_t structure which stores the transfer state. + */ +void ASRC_TransferAbortConvert(ASRC_Type *base, asrc_handle_t *handle) +{ + assert(handle != NULL); + + /* enable ASRC module */ + ASRC_ModuleEnable(base, false); + + handle->state = kStatus_ASRCIdle; + + handle->in.queueDriver = 0; + handle->in.queueUser = 0; + handle->out.queueDriver = 0; + handle->out.queueUser = 0; +} + +/*! + * brief Terminate all asrc convert. + * + * This function will clear all transfer slots buffered in the asrc queue. If users only want to abort the + * current transfer slot, please call ASRC_TransferAbortSend. + * + * param base asrc base pointer. + * param handle asrc eDMA handle pointer. + */ +void ASRC_TransferTerminateConvert(ASRC_Type *base, asrc_handle_t *handle) +{ + assert(handle != NULL); + + /* Abort the current transfer */ + ASRC_TransferAbortConvert(base, handle); + + /* Clear all the internal information */ + (void)memset(handle->in.asrcQueue, 0, sizeof(handle->in.asrcQueue)); + (void)memset(handle->in.transferSamples, 0, sizeof(handle->in.transferSamples)); + (void)memset(handle->out.asrcQueue, 0, sizeof(handle->out.asrcQueue)); + (void)memset(handle->out.transferSamples, 0, sizeof(handle->out.transferSamples)); +} + +/*! + * brief ASRC convert interrupt handler. + * + * param base asrc base pointer. + * param handle Pointer to the asrc_handle_t structure. + */ +void ASRC_TransferHandleIRQ(ASRC_Type *base, asrc_handle_t *handle) +{ + assert(handle != NULL); + + uint32_t status = base->ASRSTR; + + /* Handle Error */ + if ((status & (uint32_t)kASRC_StatusInputError) != 0U) + { + /* Call the callback */ + if (handle->in.callback != NULL) + { + (handle->in.callback)(base, handle, kStatus_ASRCConvertError, handle->userData); + } + } + + if ((status & (uint32_t)kASRC_StatusOutputError) != 0U) + { + /* Call the callback */ + if (handle->out.callback != NULL) + { + (handle->out.callback)(base, handle, kStatus_ASRCConvertError, handle->userData); + } + } + + /* Handle transfer */ + if ((status & ((uint32_t)kASRC_StatusPairCOutputReady | (uint32_t)kASRC_StatusPairAOutputReady | + (uint32_t)kASRC_StatusPairBOutputReady)) != 0U) + { + if (handle->out.transferSamples[handle->out.queueDriver] != 0U) + { + ASRC_ReadNonBlocking(base, handle->channelPair, + (uint32_t *)(uint32_t)handle->out.asrcQueue[handle->out.queueDriver], + handle->out.fifoThreshold, handle->out.sampleWidth); + handle->out.transferSamples[handle->out.queueDriver] -= handle->out.fifoThreshold; + handle->out.asrcQueue[handle->out.queueDriver] = + (uint8_t *)((uint32_t)handle->out.asrcQueue[handle->out.queueDriver] + + handle->out.fifoThreshold * handle->out.sampleWidth); + } + } + + if ((status & ((uint32_t)kASRC_StatusPairCInputReady | (uint32_t)kASRC_StatusPairBInputReady | + (uint32_t)kASRC_StatusPairAInputReady)) != 0U) + { + /* Judge if the data need to transmit is less than space */ + uint32_t size = MIN((handle->in.transferSamples[handle->in.queueDriver]), + (size_t)((FSL_ASRC_CHANNEL_PAIR_FIFO_DEPTH * (uint32_t)handle->audioDataChannels - + handle->in.fifoThreshold))); + ASRC_WriteNonBlocking(base, handle->channelPair, + (uint32_t *)(uint32_t)handle->in.asrcQueue[handle->in.queueDriver], size, + handle->in.sampleMask, handle->in.sampleWidth); + handle->in.transferSamples[handle->in.queueDriver] -= size; + handle->in.asrcQueue[handle->in.queueDriver] = + (uint8_t *)((uint32_t)handle->in.asrcQueue[handle->in.queueDriver] + size * handle->in.sampleWidth); + } + + /* If finished a block, call the callback function */ + if (handle->in.transferSamples[handle->in.queueDriver] == 0U) + { + handle->in.asrcQueue[handle->in.queueDriver] = NULL; + handle->in.queueDriver = (handle->in.queueDriver + 1U) % ASRC_XFER_QUEUE_SIZE; + if (handle->in.callback != NULL) + { + (handle->in.callback)(base, handle, kStatus_ASRCIdle, handle->userData); + } + } + + if (handle->out.transferSamples[handle->out.queueDriver] < (handle->out.fifoThreshold + 1U)) + { + handle->out.transferSamples[handle->out.queueDriver] -= ASRC_GetRemainFifoSamples( + base, handle->channelPair, (uint32_t *)(uint32_t)handle->out.asrcQueue[handle->out.queueDriver], + handle->out.sampleWidth, handle->out.transferSamples[handle->out.queueDriver]); + } + + if (handle->out.transferSamples[handle->out.queueDriver] == 0U) + { + handle->out.asrcQueue[handle->out.queueDriver] = NULL; + handle->out.queueDriver = (handle->out.queueDriver + 1U) % ASRC_XFER_QUEUE_SIZE; + if (handle->out.callback != NULL) + { + (handle->out.callback)(base, handle, kStatus_ASRCIdle, handle->userData); + } + } + + /* If all data finished, just stop the transfer */ + if (handle->out.asrcQueue[handle->out.queueDriver] == NULL) + { + ASRC_TransferAbortConvert(base, handle); + } +} + +#if defined ASRC +void ASRC_DriverIRQHandler(void); +void ASRC_DriverIRQHandler(void) +{ + /* channel PAIR A interrupt handling*/ + if ((ASRC->ASRSTR & (uint32_t)kASRC_StatusPairAInterrupt) != 0U) + { + s_asrcIsr(ASRC, s_asrcHandle[0][0U]); + } + /* channel PAIR B interrupt handling*/ + if ((ASRC->ASRSTR & (uint32_t)kASRC_StatusPairBInterrupt) != 0U) + { + s_asrcIsr(ASRC, s_asrcHandle[0][1U]); + } + /* channel PAIR C interrupt handling*/ + if ((ASRC->ASRSTR & (uint32_t)kASRC_StatusPairCInterrupt) != 0U) + { + s_asrcIsr(ASRC, s_asrcHandle[0][2U]); + } + SDK_ISR_EXIT_BARRIER; +} +#endif /* ASRC */ diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/asrc/fsl_asrc.h b/bsps/arm/imxrt/mcux-sdk/drivers/asrc/fsl_asrc.h new file mode 100644 index 0000000000..e4f8ce384a --- /dev/null +++ b/bsps/arm/imxrt/mcux-sdk/drivers/asrc/fsl_asrc.h @@ -0,0 +1,761 @@ +/* + * Copyright 2019-2021 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _FSL_ASRC_H_ +#define _FSL_ASRC_H_ + +#include "fsl_common.h" + +/*! + * @addtogroup asrc_driver + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @name Driver version */ +/*@{*/ +#define FSL_ASRC_DRIVER_VERSION (MAKE_VERSION(2, 1, 2)) /*!< Version 2.1.2 */ +/*@}*/ + +#ifndef ASRC_XFER_QUEUE_SIZE +/*!@brief ASRC transfer queue size, user can refine it according to use case. */ +#define ASRC_XFER_QUEUE_SIZE (4U) +#endif +/*!@brief ASRC channel pair count */ +#define FSL_ASRC_CHANNEL_PAIR_COUNT (4U) +/*! @brief ASRC FIFO depth */ +#define FSL_ASRC_CHANNEL_PAIR_FIFO_DEPTH (64U) + +/*! @brief ASRC register access macro */ +#define ASRC_ASRCTR_AT_MASK(index) ((uint32_t)1U << (ASRC_ASRCTR_ATSA_SHIFT + (uint32_t)(index))) +#define ASRC_ASRCTR_RATIO_MASK(index) ((uint32_t)3U << (ASRC_ASRCTR_IDRA_SHIFT + (uint32_t)(index)*2U)) +#define ASRC_ASRCTR_RATIO(ratio, index) \ + (((uint32_t)((uint32_t)(ratio) << (ASRC_ASRCTR_IDRA_SHIFT + (uint32_t)(index)*2U))) & ASRC_ASRCTR_RATIO_MASK(index)) +#define ASRC_ASRIER_INPUT_INTERRUPT_MASK(index) ((uint32_t)1U << (ASRC_ASRIER_ADIEA_SHIFT + (uint32_t)(index))) +#define ASRC_ASRIER_OUTPUTPUT_INTERRUPT_MASK(index) ((uint32_t)1U << (ASRC_ASRIER_ADOEA_SHIFT + (uint32_t)(index))) +#define ASRC_ASRCNCR_CHANNEL_COUNTER_MASK(index) ((uint32_t)0xFU << (ASRC_ASRCNCR_ANCA_SHIFT + (uint32_t)(index)*4U)) +#define ASRC_ASRCNCR_CHANNEL_COUNTER(counter, index) \ + ((uint32_t)((uint32_t)(counter) << (ASRC_ASRCNCR_ANCA_SHIFT + (uint32_t)(index)*4U)) & \ + ASRC_ASRCNCR_CHANNEL_COUNTER_MASK(index)) +#define ASRC_ASRCFG_PRE_MODE_MASK(index) ((uint32_t)3U << (ASRC_ASRCFG_PREMODA_SHIFT + (uint32_t)(index)*4U)) +#define ASRC_ASRCFG_PRE_MODE(mode, index) \ + ((uint32_t)((uint32_t)(mode) << (ASRC_ASRCFG_PREMODA_SHIFT + (uint32_t)(index)*4U)) & \ + ASRC_ASRCFG_PRE_MODE_MASK(index)) +#define ASRC_ASRCFG_POST_MODE_MASK(index) ((uint32_t)3U << (ASRC_ASRCFG_POSTMODA_SHIFT + (uint32_t)(index)*4U)) +#define ASRC_ASRCFG_POST_MODE(mode, index) \ + ((uint32_t)((uint32_t)(mode) << (ASRC_ASRCFG_POSTMODA_SHIFT + (uint32_t)(index)*4U)) & \ + ASRC_ASRCFG_POST_MODE_MASK(index)) +#define ASRC_ASRCFG_INIT_DONE_MASK(index) ((uint32_t)1U << (ASRC_ASRCFG_INIRQA_SHIFT + (uint32_t)(index))) +#define ASRC_ASRCSR_INPUT_CLOCK_SOURCE_MASK(index) ((uint32_t)0xFU << (ASRC_ASRCSR_AICSA_SHIFT + (uint32_t)(index)*4U)) +#define ASRC_ASRCSR_INPUT_CLOCK_SOURCE(source, index) \ + ((uint32_t)((uint32_t)(source) << (ASRC_ASRCSR_AICSA_SHIFT + (uint32_t)(index)*4U)) & \ + ASRC_ASRCSR_INPUT_CLOCK_SOURCE_MASK(index)) +#define ASRC_ASRCSR_OUTPUT_CLOCK_SOURCE_MASK(index) ((uint32_t)0xFU << (ASRC_ASRCSR_AOCSA_SHIFT + (uint32_t)(index)*4U)) +#define ASRC_ASRCSR_OUTPUT_CLOCK_SOURCE(source, index) \ + ((uint32_t)((uint32_t)(source) << (ASRC_ASRCSR_AOCSA_SHIFT + (uint32_t)(index)*4U)) & \ + ASRC_ASRCSR_OUTPUT_CLOCK_SOURCE_MASK(index)) + +#define ASRC_ASRCDR_INPUT_PRESCALER_MASK(index) \ + ((uint32_t)(index) < 2U ? ((uint32_t)7U << (ASRC_ASRCDR1_AICPA_SHIFT + (uint32_t)(index)*6U)) : 7U) +#define ASRC_ASRCDR_INPUT_PRESCALER(prescaler, index) \ + (((index) < 2U ? ((uint32_t)(prescaler) << (ASRC_ASRCDR1_AICPA_SHIFT + (uint32_t)(index)*6U)) : (prescaler)) & \ + ASRC_ASRCDR1_INPUT_PRESCALER_MASK(index)) +#define ASRC_ASRCDR_INPUT_DIVIDER_MASK(index) \ + ((uint32_t)(index) < 2U ? ((uint32_t)7U << (ASRC_ASRCDR1_AICDA_SHIFT + (uint32_t)(index)*6U)) : \ + (7U << ASRC_ASRCDR1_AICDA_SHIFT)) +#define ASRC_ASRCDR_INPUT_DIVIDER(divider, index) \ + (((uint32_t)(index) < 2U ? ((uint32_t)(divider) << (ASRC_ASRCDR1_AICDA_SHIFT + (uint32_t)(index)*6U)) : \ + ((uint32_t)(divider) << ASRC_ASRCDR1_AICDA_SHIFT)) & \ + ASRC_ASRCDR_INPUT_DIVIDER_MASK(index)) +#define ASRC_ASRCDR_OUTPUT_PRESCALER_MASK(index) \ + ((uint32_t)(index) < 2U ? ((uint32_t)7U << (ASRC_ASRCDR1_AOCPA_SHIFT + (uint32_t)(index)*6U)) : (7U << 6U)) +#define ASRC_ASRCDR_OUTPUT_PRESCALER(prescaler, index) \ + (((uint32_t)(index) < 2U ? ((uint32_t)(prescaler) << (ASRC_ASRCDR1_AOCPA_SHIFT + (uint32_t)(index)*6U)) : \ + ((uint32_t)(prescaler) << 6U)) & \ + ASRC_ASRCDR_OUTPUT_PRESCALER_MASK(index)) +#define ASRC_ASRCDR_OUTPUT_DIVIDER_MASK(index) \ + ((uint32_t)(index) < 2U ? ((uint32_t)7U << (ASRC_ASRCDR1_AOCDA_SHIFT + (uint32_t)(index)*6U)) : (7UL << 9U)) +#define ASRC_ASRCDR_OUTPUT_DIVIDER(divider, index) \ + (((uint32_t)(index) < 2U ? ((uint32_t)(divider) << (ASRC_ASRCDR1_AOCDA_SHIFT + (uint32_t)(index)*6U)) : \ + ((uint32_t)(divider) << 9U)) & \ + ASRC_ASRCDR_OUTPUT_DIVIDER_MASK(index)) + +#define ASCR_ASRCDR_OUTPUT_CLOCK_DIVIDER_PRESCALER(value, index) \ + (((uint32_t)(index) < 2U ? ((uint32_t)(value) << (ASRC_ASRCDR1_AOCPA_SHIFT + (uint32_t)(index)*6U)) : \ + ((uint32_t)(value) << 6U))) +#define ASCR_ASRCDR_INPUT_CLOCK_DIVIDER_PRESCALER(value, index) \ + (((uint32_t)(index) < 2U ? ((uint32_t)(value) << ((uint32_t)(index)*6U)) : ((uint32_t)(value)))) + +#define ASRC_IDEAL_RATIO_HIGH(base, index) *(volatile uint32_t *)((uint32_t)(&(base)->ASRIDRHA) + (uint32_t)(index)*8U) +#define ASRC_IDEAL_RATIO_LOW(base, index) *(volatile uint32_t *)((uint32_t)(&(base)->ASRIDRLA) + (uint32_t)(index)*8U) +#define ASRC_ASRMCR(base, index) *(volatile uint32_t *)((uint32_t)(&(base)->ASRMCRA) + (uint32_t)(index)*8U) +#define ASRC_ASRMCR1(base, index) *(volatile uint32_t *)((uint32_t)(&((base)->ASRMCR1[(index)]))) +#define ASRC_ASRDI(base, index) *(volatile uint32_t *)((uint32_t)(&(base)->ASRDIA) + (uint32_t)(index)*8U) +#define ASRC_ASRDO(base, index) *(volatile uint32_t *)((uint32_t)(&(base)->ASRDOA) + (uint32_t)(index)*8U) +#define ASRC_ASRDI_ADDR(base, index) (volatile uint32_t *)((uint32_t)(&(base)->ASRDIA) + (uint32_t)(index)*8U) +#define ASRC_ASRDO_ADDR(base, index) (volatile uint32_t *)((uint32_t)(&(base)->ASRDOA) + (uint32_t)(index)*8U) +#define ASRC_ASRFST_ADDR(base, index) (*(volatile uint32_t *)((uint32_t)(&(base)->ASRFSTA) + (uint32_t)(index)*8U)) +#define ASRC_GET_CHANNEL_COUNTER(base, index) (((base)->ASRCNCR >> ((uint32_t)(index)*4U)) & 0xFU) + +/*! @brief ASRC return status + * @anchor _asrc_status_t + */ +enum +{ + kStatus_ASRCIdle = MAKE_STATUS(kStatusGroup_ASRC, 0), /*!< ASRC is idle. */ + kStatus_ASRCInIdle = MAKE_STATUS(kStatusGroup_ASRC, 1), /*!< ASRC in is idle. */ + kStatus_ASRCOutIdle = MAKE_STATUS(kStatusGroup_ASRC, 2), /*!< ASRC out is idle. */ + kStatus_ASRCBusy = MAKE_STATUS(kStatusGroup_ASRC, 3), /*!< ASRC is busy. */ + kStatus_ASRCInvalidArgument = MAKE_STATUS(kStatusGroup_ASRC, 4), /*!< ASRC invalid argument. */ + kStatus_ASRCClockConfigureFailed = MAKE_STATUS(kStatusGroup_ASRC, 5), /*!< ASRC clock configure failed */ + kStatus_ASRCChannelPairConfigureFailed = MAKE_STATUS(kStatusGroup_ASRC, 6), /*!< ASRC clock configure failed */ + kStatus_ASRCConvertError = MAKE_STATUS(kStatusGroup_ASRC, 7), /*!< ASRC clock configure failed */ + kStatus_ASRCNotSupport = MAKE_STATUS(kStatusGroup_ASRC, 8), /*!< ASRC not support */ + kStatus_ASRCQueueFull = MAKE_STATUS(kStatusGroup_ASRC, 9), /*!< ASRC queue is full */ + kStatus_ASRCOutQueueIdle = MAKE_STATUS(kStatusGroup_ASRC, 10), /*!< ASRC out queue is idle */ + kStatus_ASRCInQueueIdle = MAKE_STATUS(kStatusGroup_ASRC, 11), /*!< ASRC in queue is idle */ +}; + +/*! @brief ASRC channel pair mask */ +typedef enum _asrc_channel_pair +{ + kASRC_ChannelPairA = 0, /*!< channel pair A value */ + kASRC_ChannelPairB = 1, /*!< channel pair B value */ + kASRC_ChannelPairC = 2, /*!< channel pair C value */ +} asrc_channel_pair_t; + +/*! @brief ASRC support sample rate + * @anchor _asrc_sample_rate + */ +enum +{ + kASRC_SampleRate_8000HZ = 8000U, /*!< asrc sample rate 8KHZ */ + kASRC_SampleRate_11025HZ = 11025U, /*!< asrc sample rate 11.025KHZ */ + kASRC_SampleRate_12000HZ = 12000U, /*!< asrc sample rate 12KHZ */ + kASRC_SampleRate_16000HZ = 16000U, /*!< asrc sample rate 16KHZ */ + kASRC_SampleRate_22050HZ = 22050U, /*!< asrc sample rate 22.05KHZ */ + kASRC_SampleRate_24000HZ = 24000U, /*!< asrc sample rate 24KHZ */ + kASRC_SampleRate_30000HZ = 30000U, /*!< asrc sample rate 30KHZ */ + kASRC_SampleRate_32000HZ = 32000U, /*!< asrc sample rate 32KHZ */ + kASRC_SampleRate_44100HZ = 44100U, /*!< asrc sample rate 44.1KHZ */ + kASRC_SampleRate_48000HZ = 48000U, /*!< asrc sample rate 48KHZ */ + kASRC_SampleRate_64000HZ = 64000U, /*!< asrc sample rate 64KHZ */ + kASRC_SampleRate_88200HZ = 88200U, /*!< asrc sample rate 88.2KHZ */ + kASRC_SampleRate_96000HZ = 96000U, /*!< asrc sample rate 96KHZ */ + kASRC_SampleRate_128000HZ = 128000U, /*!< asrc sample rate 128KHZ */ + kASRC_SampleRate_176400HZ = 176400U, /*!< asrc sample rate 176.4KHZ */ + kASRC_SampleRate_192000HZ = 192000U, /*!< asrc sample rate 192KHZ */ +}; + +/*! @brief The ASRC interrupt enable flag + * @anchor _asrc_interrupt_mask + */ +enum +{ + kASRC_FPInWaitStateInterruptEnable = ASRC_ASRIER_AFPWE_MASK, /*!< FP in wait state mask */ + kASRC_OverLoadInterruptMask = ASRC_ASRIER_AOLIE_MASK, /*!< overload interrupt mask */ + kASRC_DataOutputCInterruptMask = ASRC_ASRIER_ADOEC_MASK, /*!< data output c interrupt mask */ + kASRC_DataOutputBInterruptMask = ASRC_ASRIER_ADOEB_MASK, /*!< data output b interrupt mask */ + kASRC_DataOutputAInterruptMask = ASRC_ASRIER_ADOEA_MASK, /*!< data output a interrupt mask */ + kASRC_DataInputCInterruptMask = ASRC_ASRIER_ADIEC_MASK, /*!< data input c interrupt mask */ + kASRC_DataInputBInterruptMask = ASRC_ASRIER_ADIEB_MASK, /*!< data input b interrupt mask */ + kASRC_DataInputAInterruptMask = ASRC_ASRIER_ADIEA_MASK, /*!< data input a interrupt mask */ +}; + +/*! @brief The ASRC interrupt status + * @anchor _asrc_interrupt_status + */ +enum +{ + kASRC_StatusDSLCounterReady = ASRC_ASRSTR_DSLCNT_MASK, /*!< DSL counter */ + kASRC_StatusTaskQueueOverLoad = ASRC_ASRSTR_ATQOL_MASK, /*!< task queue overload */ + kASRC_StatusPairCOutputOverLoad = ASRC_ASRSTR_AOOLC_MASK, /*!< pair c output overload */ + kASRC_StatusPairBOutputOverLoad = ASRC_ASRSTR_AOOLB_MASK, /*!< pair b output overload */ + kASRC_StatusPairAOutputOverLoad = ASRC_ASRSTR_AOOLA_MASK, /*!< pair a output overload */ + kASRC_StatusPairCInputOverLoad = ASRC_ASRSTR_AIOLC_MASK, /*!< pair c input overload */ + kASRC_StatusPairBInputOverLoad = ASRC_ASRSTR_AIOLB_MASK, /*!<pair b input overload */ + kASRC_StatusPairAInputOverLoad = ASRC_ASRSTR_AIOLA_MASK, /*!< pair a input overload */ + kASRC_StatusPairCOutputOverflow = ASRC_ASRSTR_AODOC_MASK, /*!< pair c output overflow */ + kASRC_StatusPairBOutputOverflow = ASRC_ASRSTR_AODOB_MASK, /*!< pair b output overflow */ + kASRC_StatusPairAOutputOverflow = ASRC_ASRSTR_AODOA_MASK, /*!< pair a output overflow */ + kASRC_StatusPairCInputUnderflow = ASRC_ASRSTR_AIDUC_MASK, /*!< pair c input underflow*/ + kASRC_StatusPairBInputUnderflow = ASRC_ASRSTR_AIDUB_MASK, /*!< pair b input under flow */ + kASRC_StatusPairAInputUnderflow = ASRC_ASRSTR_AIDUA_MASK, /*!< pair a input underflow*/ + kASRC_StatusFPInWaitState = ASRC_ASRSTR_FPWT_MASK, /*!< FP in wait state */ + kASRC_StatusOverloadError = ASRC_ASRSTR_AOLE_MASK, /*!< overload error */ + + kASRC_StatusInputError = kASRC_StatusPairCInputOverLoad | kASRC_StatusPairBInputOverLoad | + kASRC_StatusPairAInputOverLoad | kASRC_StatusPairCInputUnderflow | + kASRC_StatusPairBInputUnderflow | + kASRC_StatusPairAInputUnderflow, /*!< input error status */ + + kASRC_StatusOutputError = kASRC_StatusPairCOutputOverLoad | kASRC_StatusPairBOutputOverLoad | + kASRC_StatusPairAOutputOverLoad | kASRC_StatusPairCOutputOverflow | + kASRC_StatusPairBOutputOverflow | + kASRC_StatusPairAOutputOverflow, /*!< output error status */ + + kASRC_StatusPairCOutputReady = ASRC_ASRSTR_AODFC_MASK, /*!< pair c output ready */ + kASRC_StatusPairBOutputReady = ASRC_ASRSTR_AODFB_MASK, /*!< pair b output ready */ + kASRC_StatusPairAOutputReady = ASRC_ASRSTR_AODFA_MASK, /*!< pair a output ready */ + kASRC_StatusPairCInputReady = ASRC_ASRSTR_AIDEC_MASK, /*!< pair c input ready */ + kASRC_StatusPairBInputReady = ASRC_ASRSTR_AIDEB_MASK, /*!< pair b input ready */ + kASRC_StatusPairAInputReady = ASRC_ASRSTR_AIDEA_MASK, /*!< pair a input ready */ + kASRC_StatusPairAInterrupt = kASRC_StatusPairAInputReady | kASRC_StatusPairAOutputReady, /*!< pair A interrupt */ + kASRC_StatusPairBInterrupt = kASRC_StatusPairBInputReady | kASRC_StatusPairBOutputReady, /*!< pair B interrupt */ + kASRC_StatusPairCInterrupt = kASRC_StatusPairCInputReady | kASRC_StatusPairCOutputReady, /*!< pair C interrupt */ + +}; + +/*! @brief ASRC channel pair status + * @anchor _asrc_channel_pair_status + */ +enum +{ + kASRC_OutputFifoNearFull = ASRC_ASRFSTA_OAFA_MASK, /*!< channel pair output fifo near full */ + kASRC_InputFifoNearEmpty = ASRC_ASRFSTA_IAEA_MASK, /*!< channel pair input fifo near empty */ +}; + +/*! @brief ASRC ideal ratio */ +typedef enum _asrc_ratio +{ + kASRC_RatioNotUsed = 0U, /*!< ideal ratio not used */ + kASRC_RatioUseInternalMeasured = + 2U, /*!< ideal ratio use internal measure ratio, can be used for real time streaming audio */ + kASRC_RatioUseIdealRatio = + 3U, /*!< ideal ratio use manual configure ratio, can be used for the non-real time streaming audio */ +} asrc_ratio_t; + +/*! @brief Number of channels in audio data */ +typedef enum _asrc_audio_channel +{ + kASRC_ChannelsNumber1 = 1U, /*!< channel number is 1 */ + kASRC_ChannelsNumber2 = 2U, /*!< channel number is 2 */ + kASRC_ChannelsNumber3 = 3U, /*!< channel number is 3 */ + kASRC_ChannelsNumber4 = 4U, /*!< channel number is 4 */ + kASRC_ChannelsNumber5 = 5U, /*!< channel number is 5 */ + kASRC_ChannelsNumber6 = 6U, /*!< channel number is 6 */ + kASRC_ChannelsNumber7 = 7U, /*!< channel number is 7 */ + kASRC_ChannelsNumber8 = 8U, /*!< channel number is 8 */ + kASRC_ChannelsNumber9 = 9U, /*!< channel number is 9 */ + kASRC_ChannelsNumber10 = 10U, /*!< channel number is 10 */ +} asrc_audio_channel_t; + +/*! @brief data width */ +typedef enum _asrc_data_width +{ + kASRC_DataWidth24Bit = 0U, /*!< data width 24bit */ + kASRC_DataWidth16Bit = 1U, /*!< data width 16bit */ + kASRC_DataWidth8Bit = 2U, /*!< data width 8bit */ +} asrc_data_width_t; + +/*! @brief data alignment */ +typedef enum _asrc_data_align +{ + kASRC_DataAlignMSB = 1U, /*!< data alignment MSB */ + kASRC_DataAlignLSB = 0U, /*!< data alignment LSB */ +} asrc_data_align_t; + +/*! @brief sign extension */ +typedef enum _asrc_sign_extension +{ + kASRC_NoSignExtension = 0U, /*!< no sign extension */ + kASRC_SignExtension = 1U, /*!< sign extension */ +} asrc_sign_extension_t; + +/*! @brief asrc channel pair configuation */ +typedef struct _asrc_channel_pair_config +{ + asrc_audio_channel_t audioDataChannels; /*!< audio data channel numbers */ + asrc_clock_source_t + inClockSource; /*!< input clock source, reference the clock source definition in SOC header file */ + uint32_t inSourceClock_Hz; /*!< input source clock frequency */ + + asrc_clock_source_t + outClockSource; /*!< output clock source, reference the clock source definition in SOC header file */ + uint32_t outSourceClock_Hz; /*!< output source clock frequency */ + + asrc_ratio_t sampleRateRatio; /*!< sample rate ratio type */ + + asrc_data_width_t inDataWidth; /*!< input data width */ + asrc_data_align_t inDataAlign; /*!< input data alignment */ + + asrc_data_width_t outDataWidth; /*!< output data width */ + asrc_data_align_t outDataAlign; /*!< output data alignment */ + asrc_sign_extension_t outSignExtension; /*!< output extension */ + + uint8_t outFifoThreshold; /*!< output fifo threshold */ + uint8_t inFifoThreshold; /*!< input fifo threshold */ + + bool bufStallWhenFifoEmptyFull; /*!< stall Pair A conversion in case of Buffer near empty full condition */ + +} asrc_channel_pair_config_t; + +/*! @brief SAI transfer structure */ +typedef struct _asrc_transfer +{ + void *inData; /*!< Data address to convert.*/ + size_t inDataSize; /*!< input data size. */ + void *outData; /*!< Data address to store converted data */ + size_t outDataSize; /*!< output data size. */ +} asrc_transfer_t; + +/*! @brief asrc handler */ +typedef struct _asrc_handle asrc_handle_t; + +/*! @brief ASRC transfer callback prototype */ +typedef void (*asrc_transfer_callback_t)(ASRC_Type *base, asrc_handle_t *handle, status_t status, void *userData); + +/*! @brief asrc in handler */ +typedef struct _asrc_in_handle +{ + asrc_transfer_callback_t callback; /*!< Callback function called at convert complete */ + uint32_t sampleWidth; /*!< data width */ + uint32_t sampleMask; /*!< data mask */ + uint32_t fifoThreshold; /*!< fifo threshold */ + uint8_t *asrcQueue[ASRC_XFER_QUEUE_SIZE]; /*!< Transfer queue storing queued transfer */ + size_t transferSamples[ASRC_XFER_QUEUE_SIZE]; /*!< Data bytes need to convert */ + volatile uint8_t queueUser; /*!< Index for user to queue transfer */ + volatile uint8_t queueDriver; /*!< Index for driver to get the transfer data and size */ +} asrc_in_handle_t; + +/*! @brief output handler */ +typedef struct _asrc_out_handle +{ + asrc_transfer_callback_t callback; /*!< Callback function called at convert complete */ + uint32_t sampleWidth; /*!< data width */ + uint32_t fifoThreshold; /*!< fifo threshold */ + uint8_t *asrcQueue[ASRC_XFER_QUEUE_SIZE]; /*!< Transfer queue storing queued transfer */ + size_t transferSamples[ASRC_XFER_QUEUE_SIZE]; /*!< Data bytes need to convert */ + volatile uint8_t queueUser; /*!< Index for user to queue transfer */ + volatile uint8_t queueDriver; /*!< Index for driver to get the transfer data and size */ +} asrc_out_handle_t; + +/*! @brief ASRC handle structure */ +struct _asrc_handle +{ + ASRC_Type *base; /*!< base address */ + + uint32_t state; /*!< Transfer status */ + void *userData; /*!< Callback parameter passed to callback function*/ + + asrc_audio_channel_t audioDataChannels; /*!< audio channel number */ + asrc_channel_pair_t channelPair; /*!< channel pair mask */ + + asrc_in_handle_t in; /*!< asrc input handler */ + asrc_out_handle_t out; /*!< asrc output handler */ +}; +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif /*_cplusplus*/ + +/*! + * @name Initialization and deinitialization + * @{ + */ + +/*! + * @brief Get instance number of the ASRC peripheral. + * + * @param base ASRC base pointer. + */ +uint32_t ASRC_GetInstance(ASRC_Type *base); + +/*! + * brief Initializes the asrc peripheral. + * + * This API gates the asrc clock. The asrc module can't operate unless ASRC_Init is called to enable the clock. + * + * param base asrc base pointer. + * param asrcPeripheralClock_Hz peripheral clock of ASRC. + */ +void ASRC_Init(ASRC_Type *base, uint32_t asrcPeripheralClock_Hz); + +/*! + * @brief De-initializes the ASRC peripheral. + * + * This API gates the ASRC clock and disable ASRC module. The ASRC module can't operate unless ASRC_Init + * + * @param base ASRC base pointer. + */ +void ASRC_Deinit(ASRC_Type *base); + +/*! + * @brief Do software reset . + * + * This software reset bit is self-clear bit, it will generate a software reset signal inside ASRC. + * After 9 cycles of the ASRC processing clock, this reset process will stop and this bit will cleared + * automatically. + * + * @param base ASRC base pointer + */ +void ASRC_SoftwareReset(ASRC_Type *base); + +/*! + * @brief ASRC configure channel pair. + * + * @param base ASRC base pointer. + * @param channelPair index of channel pair, reference _asrc_channel_pair. + * @param config ASRC channel pair configuration pointer. + * @param inputSampleRate input audio data sample rate. + * @param outputSampleRate output audio data sample rate. + */ +status_t ASRC_SetChannelPairConfig(ASRC_Type *base, + asrc_channel_pair_t channelPair, + asrc_channel_pair_config_t *config, + uint32_t inputSampleRate, + uint32_t outputSampleRate); + +/*! + * @brief Get output sample buffer size. + * + * @note This API is depends on the ASRC output configuration, should be called after the ASRC_SetChannelPairConfig. + * + * @param base asrc base pointer. + * @param channelPair ASRC channel pair number. + * @param inSampleRate input sample rate. + * @param outSampleRate output sample rate. + * @param inSamplesize input sampleS size. + * @retval output buffer size in byte. + */ +uint32_t ASRC_GetOutSamplesSize(ASRC_Type *base, + asrc_channel_pair_t channelPair, + uint32_t inSampleRate, + uint32_t outSampleRate, + uint32_t inSamplesize); + +/*! + * @brief Map register sample width to real sample width. + * + * @note This API is depends on the ASRC configuration, should be called after the ASRC_SetChannelPairConfig. + * @param base asrc base pointer. + * @param channelPair asrc channel pair index. + * @param inWidth ASRC channel pair number. + * @param outWidth input sample rate. + * @retval input sample mask value. + */ +uint32_t ASRC_MapSamplesWidth(ASRC_Type *base, asrc_channel_pair_t channelPair, uint32_t *inWidth, uint32_t *outWidth); + +/*! + * @brief Get left samples in fifo. + * + * @param base asrc base pointer. + * @param channelPair ASRC channel pair number. + * @param buffer input sample numbers. + * @param outSampleWidth output sample width. + * @param remainSamples output sample rate. + * @retval remain samples number. + */ +uint32_t ASRC_GetRemainFifoSamples(ASRC_Type *base, + asrc_channel_pair_t channelPair, + uint32_t *buffer, + uint32_t outSampleWidth, + uint32_t remainSamples); + +/*! + * @brief ASRC module enable. + * + * @param base ASRC base pointer. + * @param enable true is enable, false is disable + */ +static inline void ASRC_ModuleEnable(ASRC_Type *base, bool enable) +{ + if (enable) + { + base->ASRCTR |= ASRC_ASRCTR_ASRCEN_MASK; + } + else + { + base->ASRCTR &= ~ASRC_ASRCTR_ASRCEN_MASK; + } +} + +/*! + * @brief ASRC enable channel pair. + * + * @param base ASRC base pointer. + * @param channelPair channel pair mask value, reference _asrc_channel_pair_mask. + * @param enable true is enable, false is disable. + */ +static inline void ASRC_ChannelPairEnable(ASRC_Type *base, asrc_channel_pair_t channelPair, bool enable) +{ + if (enable) + { + base->ASRCTR |= 1UL << ((uint32_t)channelPair + 1U); + } + else + { + base->ASRCTR &= ~(1UL << ((uint32_t)channelPair + 1U)); + } +} +/*! @} */ + +/*! + * @name Interrupts + * @{ + */ + +/*! + * @brief ASRC interrupt enable + * This function enable the ASRC interrupt with the provided mask. + * + * @param base ASRC peripheral base address. + * @param mask The interrupts to enable. Logical OR of @ref _asrc_interrupt_mask. + */ +static inline void ASRC_EnableInterrupt(ASRC_Type *base, uint32_t mask) +{ + base->ASRIER |= mask; +} + +/*! + * @brief ASRC interrupt disable + * This function disable the ASRC interrupt with the provided mask. + * + * @param base ASRC peripheral base address. + * @param mask The interrupts to disable. Logical OR of @ref _asrc_interrupt_mask. + */ +static inline void ASRC_DisableInterrupt(ASRC_Type *base, uint32_t mask) +{ + base->ASRIER &= ~mask; +} + +/*! @} */ + +/*! + * @name Status + * @{ + */ + +/*! + * @brief Gets the ASRC status flag state. + * + * @param base ASRC base pointer + * @return ASRC Tx status flag value. Use the Status Mask to get the status value needed. + */ +static inline uint32_t ASRC_GetStatus(ASRC_Type *base) +{ + return base->ASRSTR; +} + +/*! + * @brief Gets the ASRC channel pair initialization state. + * + * @param base ASRC base pointer + * @param channel ASRC channel pair. + * @return ASRC Tx status flag value. Use the Status Mask to get the status value needed. + */ +static inline bool ASRC_GetChannelPairInitialStatus(ASRC_Type *base, asrc_channel_pair_t channel) +{ + return ((base->ASRCFG >> ASRC_ASRCFG_INIRQA_SHIFT) & (1U << (uint32_t)channel)) == 0U ? false : true; +} + +/*! + * @brief Gets the ASRC channel A fifo a status flag state. + * + * @param base ASRC base pointer + * @param channelPair ASRC channel pair. + * @return ASRC channel pair a fifo status flag value. Use the Status Mask to get the status value needed. + */ +static inline uint32_t ASRC_GetChannelPairFifoStatus(ASRC_Type *base, asrc_channel_pair_t channelPair) +{ + return ASRC_ASRMCR(base, channelPair) & ((uint32_t)kASRC_OutputFifoNearFull | (uint32_t)kASRC_InputFifoNearEmpty); +} + +/*! @} */ + +/*! + * @name Bus Operations + * @{ + */ + +/*! + * @brief Writes data into ASRC channel pair FIFO. + * Note: ASRC fifo width is 24bit. + * @param base ASRC base pointer. + * @param channelPair ASRC channel pair. + * @param data Data needs to be written. + */ +static inline void ASRC_ChannelPairWriteData(ASRC_Type *base, asrc_channel_pair_t channelPair, uint32_t data) +{ + ASRC_ASRDI(base, channelPair) = data; +} + +/*! + * @brief Read data from ASRC channel pair FIFO. + * Note: ASRC fifo width is 24bit. + * + * @param base ASRC base pointer. + * @param channelPair ASRC channel pair. + * @retval value read from fifo. + */ +static inline uint32_t ASRC_ChannelPairReadData(ASRC_Type *base, asrc_channel_pair_t channelPair) +{ + return ASRC_ASRDO(base, channelPair); +} + +/*! + * @brief Get input data fifo address. + * Note: ASRC fifo width is 24bit. + * + * @param base ASRC base pointer. + * @param channelPair ASRC channel pair. + */ +static inline uint32_t ASRC_GetInputDataRegisterAddress(ASRC_Type *base, asrc_channel_pair_t channelPair) +{ + return (uint32_t)ASRC_ASRDI_ADDR(base, channelPair); +} + +/*! + * @brief Get output data fifo address. + * Note: ASRC fifo width is 24bit. + * + * @param base ASRC base pointer. + * @param channelPair ASRC channel pair. + */ +static inline uint32_t ASRC_GetOutputDataRegisterAddress(ASRC_Type *base, asrc_channel_pair_t channelPair) +{ + return (uint32_t)ASRC_ASRDO_ADDR(base, channelPair); +} + +/*! + * @brief ASRC configure ideal ratio. + * The ideal ratio should be used when input clock source is not avalible. + * + * @param base ASRC base pointer. + * @param channelPair ASRC channel pair. + * @param inputSampleRate input audio data sample rate. + * @param outputSampleRate output audio data sample rate. + */ +status_t ASRC_SetIdealRatioConfig(ASRC_Type *base, + asrc_channel_pair_t channelPair, + uint32_t inputSampleRate, + uint32_t outputSampleRate); + +/*! @} */ + +/*! + * @name Transactional + * @{ + */ + +/*! + * @brief ASRC configure channel pair. + * + * @param base ASRC base pointer. + * @param handle ASRC transactional handle pointer. + * @param config ASRC channel pair configuration pointer. + * @param inputSampleRate input audio data sample rate. + * @param outputSampleRate output audio data sample rate. + */ +status_t ASRC_TransferSetChannelPairConfig(ASRC_Type *base, + asrc_handle_t *handle, + asrc_channel_pair_config_t *config, + uint32_t inputSampleRate, + uint32_t outputSampleRate); + +/*! + * @brief Initializes the ASRC handle. + * + * This function initializes the handle for the ASRC transactional APIs. Call + * this function once to get the handle initialized. + * + * @param base ASRC base pointer + * @param handle ASRC handle pointer. + * @param channelPair ASRC channel pair. + * @param inCallback Pointer to the user callback function. + * @param outCallback Pointer to the user callback function. + * @param userData User parameter passed to the callback function + */ +void ASRC_TransferCreateHandle(ASRC_Type *base, + asrc_handle_t *handle, + asrc_channel_pair_t channelPair, + asrc_transfer_callback_t inCallback, + asrc_transfer_callback_t outCallback, + void *userData); + +/*! + * @brief Performs an interrupt non-blocking convert on asrc. + * + * @note This API returns immediately after the transfer initiates, application should check the wait and check the + * callback status. + * + * @param base asrc base pointer. + * @param handle Pointer to the asrc_handle_t structure which stores the transfer state. + * @param xfer Pointer to the ASRC_transfer_t structure. + * @retval kStatus_Success Successfully started the data receive. + * @retval kStatus_ASRCBusy Previous receive still not finished. + */ +status_t ASRC_TransferNonBlocking(ASRC_Type *base, asrc_handle_t *handle, asrc_transfer_t *xfer); + +/*! + * @brief Performs an blocking convert on asrc. + * + * @note This API returns immediately after the convert finished. + * + * @param base asrc base pointer. + * @param channelPair channel pair index. + * @param xfer Pointer to the ASRC_transfer_t structure. + * @retval kStatus_Success Successfully started the data receive. + */ +status_t ASRC_TransferBlocking(ASRC_Type *base, asrc_channel_pair_t channelPair, asrc_transfer_t *xfer); + +/*! + * @brief Get converted byte count. + * + * @param base ASRC base pointer. + * @param handle Pointer to the asrc_handle_t structure which stores the transfer state. + * @param count Bytes count sent. + * @retval kStatus_Success Succeed get the transfer count. + * @retval kStatus_ASRCIdle There is not a non-blocking transaction currently in progress. + */ +status_t ASRC_TransferGetConvertedCount(ASRC_Type *base, asrc_handle_t *handle, size_t *count); + +/*! + * @brief Aborts the current convert. + * + * @note This API can be called any time when an interrupt non-blocking transfer initiates + * to abort the transfer early. + * + * @param base ASRC base pointer. + * @param handle Pointer to the asrc_handle_t structure which stores the transfer state. + */ +void ASRC_TransferAbortConvert(ASRC_Type *base, asrc_handle_t *handle); + +/*! + * @brief Terminate all ASRC convert. + * + * This function will clear all transfer slots buffered in the asrc queue. If users only want to abort the + * current transfer slot, please call ASRC_TransferAbortConvert. + * + * @param base ASRC base pointer. + * @param handle ASRC eDMA handle pointer. + */ +void ASRC_TransferTerminateConvert(ASRC_Type *base, asrc_handle_t *handle); + +/*! + * @brief ASRC convert interrupt handler. + * + * @param base ASRC base pointer. + * @param handle Pointer to the asrc_handle_t structure. + */ +void ASRC_TransferHandleIRQ(ASRC_Type *base, asrc_handle_t *handle); + +/*! @} */ + +#if defined(__cplusplus) +} +#endif /*_cplusplus*/ + +/*! @} */ + +#endif /* _FSL_ASRC_H_ */ diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/asrc/fsl_asrc_edma.c b/bsps/arm/imxrt/mcux-sdk/drivers/asrc/fsl_asrc_edma.c new file mode 100644 index 0000000000..8731a8e8fe --- /dev/null +++ b/bsps/arm/imxrt/mcux-sdk/drivers/asrc/fsl_asrc_edma.c @@ -0,0 +1,470 @@ +/* + * Copyright 2019-2020 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_asrc_edma.h" + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.asrc_edma" +#endif + +/******************************************************************************* + * Definitations + ******************************************************************************/ +/* Used for 32byte aligned */ +#define STCD_ADDR(address) (edma_tcd_t *)(((uint32_t)(address) + 32U) & ~0x1FU) + +/*<! Structure definition for uart_edma_private_handle_t. The structure is private. */ +typedef struct _asrc_edma_private_handle +{ + ASRC_Type *base; + asrc_edma_handle_t *handle; +} asrc_edma_private_handle_t; + +/*<! Private handle only used for internally. */ +static asrc_edma_private_handle_t s_edmaPrivateHandle[FSL_FEATURE_SOC_ASRC_COUNT][FSL_ASRC_CHANNEL_PAIR_COUNT]; + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +/*! + * @brief ASRC EDMA callback for input. + * + * @param handle pointer to asrc_edma_handle_t structure which stores the transfer state. + * @param userData Parameter for user callback. + * @param done If the DMA transfer finished. + * @param tcds The TCD index. + */ +static void ASRC_InEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds); + +/*! + * @brief ASRC EDMA callback for output. + * + * @param handle pointer to asrc_edma_handle_t structure which stores the transfer state. + * @param userData Parameter for user callback. + * @param done If the DMA transfer finished. + * @param tcds The TCD index. + */ +static void ASRC_OutEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds); +/******************************************************************************* + * Code + ******************************************************************************/ +static void ASRC_InEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds) +{ + asrc_edma_private_handle_t *privHandle = (asrc_edma_private_handle_t *)userData; + asrc_edma_handle_t *asrcHandle = privHandle->handle; + asrc_in_edma_handle_t *asrcInHandle = &(privHandle->handle->in); + status_t inStatus = kStatus_ASRCInIdle; + /* If finished a block, call the callback function */ + asrcInHandle->asrcQueue[asrcInHandle->queueDriver] = NULL; + asrcInHandle->queueDriver = (asrcInHandle->queueDriver + 1U) % ASRC_XFER_QUEUE_SIZE; + + /* If all data finished, just stop the transfer */ + if (asrcInHandle->asrcQueue[asrcInHandle->queueDriver] == NULL) + { + EDMA_AbortTransfer(asrcInHandle->inDmaHandle); + inStatus = kStatus_ASRCInQueueIdle; + } + + if (asrcHandle->callback != NULL) + { + (asrcHandle->callback)(privHandle->base, asrcHandle, inStatus, asrcHandle->userData); + } +} + +static void ASRC_OutEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds) +{ + asrc_edma_private_handle_t *privHandle = (asrc_edma_private_handle_t *)userData; + asrc_edma_handle_t *asrcHandle = privHandle->handle; + asrc_out_edma_handle_t *asrcOutHandle = &(privHandle->handle->out); + uint32_t queueDriverIndex = asrcOutHandle->queueDriver; + status_t callbackStatus = kStatus_ASRCOutIdle; + + /* If finished a block, call the callback function */ + asrcOutHandle->asrcQueue[queueDriverIndex] = NULL; + asrcOutHandle->queueDriver = (uint8_t)((queueDriverIndex + 1U) % ASRC_XFER_OUT_QUEUE_SIZE); + + /* If all data finished, just stop the transfer */ + if (asrcOutHandle->asrcQueue[asrcOutHandle->queueDriver] == NULL) + { + EDMA_AbortTransfer(asrcOutHandle->outDmaHandle); + callbackStatus = kStatus_ASRCOutQueueIdle; + } + + if (asrcHandle->callback != NULL) + { + (asrcHandle->callback)(privHandle->base, asrcHandle, callbackStatus, asrcHandle->userData); + } +} +/*! + * brief Initializes the ASRC IN eDMA handle. + * + * This function initializes the ASRC DMA handle, which can be used for other ASRC transactional APIs. + * Usually, for a specified ASRC channel pair, call this API once to get the initialized handle. + * + * param base ASRC base pointer. + * param channelPair ASRC channel pair + * param handle ASRC eDMA handle pointer. + * param callback Pointer to user callback function. + * param txDmaHandle ASRC send edma handle pointer. + * param periphConfig peripheral configuration. + * param userData User parameter passed to the callback function. + */ +void ASRC_TransferInCreateHandleEDMA(ASRC_Type *base, + asrc_edma_handle_t *handle, + asrc_channel_pair_t channelPair, + asrc_edma_callback_t callback, + edma_handle_t *inDmaHandle, + const asrc_p2p_edma_config_t *periphConfig, + void *userData) +{ + assert((handle != NULL) && (inDmaHandle != NULL)); + + uint32_t instance = ASRC_GetInstance(base); + + /* Zero the handle */ + (void)memset(&handle->in, 0, sizeof(asrc_in_edma_handle_t)); + + handle->in.inDmaHandle = inDmaHandle; + handle->callback = callback; + handle->userData = userData; + + /* Set ASRC state to idle */ + handle->in.state = kStatus_ASRCIdle; + handle->channelPair = channelPair; + handle->in.peripheralConfig = periphConfig; + + s_edmaPrivateHandle[instance][channelPair].base = base; + s_edmaPrivateHandle[instance][channelPair].handle = handle; + + /* Need to use scatter gather */ + EDMA_InstallTCDMemory(inDmaHandle, (edma_tcd_t *)(STCD_ADDR(handle->in.tcd)), ASRC_XFER_OUT_QUEUE_SIZE); + /* Install callback for Tx dma channel */ + EDMA_SetCallback(inDmaHandle, ASRC_InEDMACallback, &s_edmaPrivateHandle[instance][channelPair]); +} + +/*! + * brief Initializes the ASRC OUT eDMA handle. + * + * This function initializes the ASRC DMA handle, which can be used for other ASRC transactional APIs. + * Usually, for a specified ASRC channel pair, call this API once to get the initialized handle. + * + * param base ASRC base pointer. + * param channelPair ASRC channel pair + * param handle ASRC eDMA handle pointer. + * param callback Pointer to user callback function. + * param txDmaHandle ASRC send edma handle pointer. + * param periphConfig peripheral configuration. + * param userData User parameter passed to the callback function. + */ +void ASRC_TransferOutCreateHandleEDMA(ASRC_Type *base, + asrc_edma_handle_t *handle, + asrc_channel_pair_t channelPair, + asrc_edma_callback_t callback, + edma_handle_t *outDmaHandle, + const asrc_p2p_edma_config_t *periphConfig, + void *userData) +{ + assert((handle != NULL) && (NULL != outDmaHandle)); + + uint32_t instance = ASRC_GetInstance(base); + + /* Zero the handle */ + (void)memset(&handle->out, 0, sizeof(asrc_out_edma_handle_t)); + + handle->out.outDmaHandle = outDmaHandle; + handle->callback = callback; + handle->userData = userData; + + /* Set ASRC state to idle */ + handle->out.state = kStatus_ASRCIdle; + handle->channelPair = channelPair; + handle->out.peripheralConfig = periphConfig; + + s_edmaPrivateHandle[instance][channelPair].base = base; + s_edmaPrivateHandle[instance][channelPair].handle = handle; + + /* Need to use scatter gather */ + EDMA_InstallTCDMemory(outDmaHandle, (edma_tcd_t *)(STCD_ADDR(handle->out.tcd)), ASRC_XFER_OUT_QUEUE_SIZE); + /* Install callback for Tx dma channel */ + EDMA_SetCallback(outDmaHandle, ASRC_OutEDMACallback, &s_edmaPrivateHandle[instance][channelPair]); +} + +/*! + * brief Configures the ASRC channel pair. + * + * param base ASRC base pointer. + * param handle ASRC eDMA handle pointer. + * param asrcConfig asrc configurations. + * param periphConfig peripheral configuration. + * param inputSampleRate ASRC input sample rate. + * param outputSampleRate ASRC output sample rate. + */ +status_t ASRC_TransferSetChannelPairConfigEDMA(ASRC_Type *base, + asrc_edma_handle_t *handle, + asrc_channel_pair_config_t *asrcConfig, + uint32_t inSampleRate, + uint32_t outSampleRate) +{ + assert((handle != NULL) && (NULL != asrcConfig)); + + /* Configure the audio format to ASRC registers */ + if (ASRC_SetChannelPairConfig(base, handle->channelPair, asrcConfig, inSampleRate, outSampleRate) != + kStatus_Success) + { + return kStatus_ASRCChannelPairConfigureFailed; + } + handle->in.fifoThreshold = (asrcConfig->inFifoThreshold) * (uint32_t)asrcConfig->audioDataChannels; + handle->out.fifoThreshold = (asrcConfig->outFifoThreshold) * (uint32_t)asrcConfig->audioDataChannels; + (void)ASRC_MapSamplesWidth(base, handle->channelPair, &handle->in.sampleWidth, &handle->out.sampleWidth); + + return kStatus_Success; +} + +/*! + * brief Get output sample buffer size can be transferred by edma. + * + * note This API is depends on the ASRC output configuration, should be called after the + * ASRC_TransferSetChannelPairConfigEDMA. + * + * param base asrc base pointer. + * param handle ASRC channel pair edma handle. + * param inSampleRate input sample rate. + * param outSampleRate output sample rate. + * param inSamples input sampleS size. + * retval output buffer size in byte. + */ +uint32_t ASRC_GetOutSamplesSizeEDMA( + ASRC_Type *base, asrc_edma_handle_t *handle, uint32_t inSampleRate, uint32_t outSampleRate, uint32_t inSamplesize) +{ + uint32_t outputSize = ASRC_GetOutSamplesSize(base, handle->channelPair, inSampleRate, outSampleRate, inSamplesize); + + return outputSize - outputSize % handle->out.fifoThreshold; +} + +static status_t ASRC_TransferOutSubmitEDMA(ASRC_Type *base, + asrc_edma_handle_t *handle, + uint32_t *outDataAddr, + uint32_t outDataSize) +{ + assert(outDataAddr != NULL); + assert(outDataSize != 0U); + + uint32_t outAddr = ASRC_GetOutputDataRegisterAddress(base, handle->channelPair); + edma_transfer_config_t config = {0}; + edma_transfer_type_t type = kEDMA_PeripheralToMemory; + + if (handle->out.asrcQueue[handle->out.queueUser] != NULL) + { + return kStatus_ASRCQueueFull; + } + + if (handle->out.peripheralConfig != NULL) + { + type = kEDMA_PeripheralToPeripheral; + } + + if (handle->out.asrcQueue[handle->out.queueUser] != NULL) + { + return kStatus_ASRCQueueFull; + } + + handle->out.asrcQueue[handle->out.queueUser] = outDataAddr; + handle->out.transferSize[handle->out.queueUser] = outDataSize; + handle->out.queueUser = (handle->out.queueUser + 1U) % ASRC_XFER_OUT_QUEUE_SIZE; + /* Prepare ASRC output edma configuration */ + EDMA_PrepareTransfer(&config, (uint32_t *)outAddr, handle->out.sampleWidth, outDataAddr, handle->out.sampleWidth, + handle->out.fifoThreshold * handle->out.sampleWidth, outDataSize, type); + + if (handle->out.state != (uint32_t)kStatus_ASRCBusy) + { + (void)EDMA_SubmitTransfer(handle->out.outDmaHandle, &config); + + EDMA_StartTransfer(handle->out.outDmaHandle); + + if ((handle->out.peripheralConfig != NULL) && (handle->out.peripheralConfig->startPeripheral != NULL)) + { + handle->out.peripheralConfig->startPeripheral(true); + } + } + + return kStatus_Success; +} + +static status_t ASRC_TransferInSubmitEDMA(ASRC_Type *base, + asrc_edma_handle_t *handle, + uint32_t *inDataAddr, + uint32_t inDataSize) +{ + assert(inDataAddr != NULL); + assert(inDataSize != 0U); + + uint32_t inAddr = ASRC_GetInputDataRegisterAddress(base, handle->channelPair); + edma_transfer_config_t config = {0}; + + if (handle->in.asrcQueue[handle->in.queueUser] != NULL) + { + return kStatus_ASRCQueueFull; + } + + /* Add into queue */ + handle->in.asrcQueue[handle->in.queueUser] = inDataAddr; + handle->in.transferSize[handle->in.queueUser] = inDataSize; + handle->in.queueUser = (handle->in.queueUser + 1U) % ASRC_XFER_IN_QUEUE_SIZE; + + /* Prepare ASRC input edma configuration */ + EDMA_PrepareTransfer(&config, (uint32_t *)inDataAddr, handle->in.sampleWidth, (uint32_t *)inAddr, + handle->in.sampleWidth, handle->in.fifoThreshold * handle->in.sampleWidth, inDataSize, + handle->in.peripheralConfig == NULL ? kEDMA_MemoryToPeripheral : kEDMA_PeripheralToPeripheral); + + if (handle->in.state != (uint32_t)kStatus_ASRCBusy) + { + (void)EDMA_SubmitTransfer(handle->in.inDmaHandle, &config); + EDMA_StartTransfer(handle->in.inDmaHandle); + /* start peripheral */ + if ((handle->in.peripheralConfig != NULL) && (handle->in.peripheralConfig->startPeripheral != NULL)) + { + handle->in.peripheralConfig->startPeripheral(true); + } + } + + return kStatus_Success; +} + +/*! + * brief Performs a non-blocking ASRC convert using EDMA. + * + * note This interface returns immediately after the transfer initiates. + + * param base ASRC base pointer. + * param handle ASRC eDMA handle pointer. + * param xfer Pointer to the DMA transfer structure. + * retval kStatus_Success Start a ASRC eDMA send successfully. + * retval kStatus_InvalidArgument The input argument is invalid. + * retval kStatus_ASRCQueueFull ASRC EDMA driver queue is full. + */ +status_t ASRC_TransferEDMA(ASRC_Type *base, asrc_edma_handle_t *handle, asrc_transfer_t *xfer) +{ + assert(handle != NULL); + + if (ASRC_TransferOutSubmitEDMA(base, handle, xfer->outData, xfer->outDataSize) != kStatus_Success) + { + return kStatus_ASRCQueueFull; + } + + if (ASRC_TransferInSubmitEDMA(base, handle, xfer->inData, xfer->inDataSize) != kStatus_Success) + { + return kStatus_ASRCQueueFull; + } + + return kStatus_Success; +} + +/*! + * brief Aborts a ASRC IN transfer using eDMA. + * + * This function only aborts the current transfer slots, the other transfer slots' information still kept + * in the handler. If users want to terminate all transfer slots, just call ASRC_TransferTerminalP2PEDMA. + * + * param base ASRC base pointer. + * param handle ASRC eDMA handle pointer. + */ +void ASRC_TransferInAbortEDMA(ASRC_Type *base, asrc_edma_handle_t *handle) +{ + assert(handle != NULL); + + /* Disable dma */ + EDMA_AbortTransfer(handle->in.inDmaHandle); + + /* Handle the queue index */ + handle->in.asrcQueue[handle->in.queueDriver] = NULL; + handle->in.queueDriver = (handle->in.queueDriver + 1U) % ASRC_XFER_QUEUE_SIZE; + + /* Set the handle state */ + handle->in.state = kStatus_ASRCIdle; +} + +/*! + * brief Aborts a ASRC OUT transfer using eDMA. + * + * This function only aborts the current transfer slots, the other transfer slots' information still kept + * in the handler. If users want to terminate all transfer slots, just call ASRC_TransferTerminalP2PEDMA. + * + * param base ASRC base pointer. + * param handle ASRC eDMA handle pointer. + */ +void ASRC_TransferOutAbortEDMA(ASRC_Type *base, asrc_edma_handle_t *handle) +{ + assert(handle != NULL); + + /* Disable dma */ + EDMA_AbortTransfer(handle->out.outDmaHandle); + + /* Handle the queue index */ + handle->out.asrcQueue[handle->out.queueDriver] = NULL; + handle->out.queueDriver = (handle->out.queueDriver + 1U) % ASRC_XFER_QUEUE_SIZE; + + /* Set the handle state */ + handle->out.state = kStatus_ASRCIdle; +} + +/*! + * brief Terminate In ASRC Convert. + * + * This function will clear all transfer slots buffered in the asrc queue. If users only want to abort the + * current transfer slot, please call ASRC_TransferAbortPP2PEDMA. + * + * param base ASRC base pointer. + * param handle ASRC eDMA handle pointer. + */ +void ASRC_TransferInTerminalEDMA(ASRC_Type *base, asrc_edma_handle_t *handle) +{ + assert(handle != NULL); + + /* Abort the current transfer */ + ASRC_TransferInAbortEDMA(base, handle); + /* stop peripheral */ + if ((handle->in.peripheralConfig != NULL) && (handle->in.peripheralConfig->startPeripheral != NULL)) + { + handle->in.peripheralConfig->startPeripheral(false); + } + + /* Clear all the internal information */ + (void)memset(handle->in.tcd, 0, sizeof(handle->in.tcd)); + (void)memset(handle->in.asrcQueue, 0, sizeof(handle->in.asrcQueue)); + (void)memset(handle->in.transferSize, 0, sizeof(handle->in.transferSize)); + handle->in.queueUser = 0U; + handle->in.queueDriver = 0U; +} + +/*! + * brief Terminate Out ASRC Convert. + * + * This function will clear all transfer slots buffered in the asrc queue. If users only want to abort the + * current transfer slot, please call ASRC_TransferAbortPP2PEDMA. + * + * param base ASRC base pointer. + * param handle ASRC eDMA handle pointer. + */ +void ASRC_TransferOutTerminalEDMA(ASRC_Type *base, asrc_edma_handle_t *handle) +{ + assert(handle != NULL); + + /* Abort the current transfer */ + ASRC_TransferOutAbortEDMA(base, handle); + + if ((handle->out.peripheralConfig != NULL) && (handle->out.peripheralConfig->startPeripheral != NULL)) + { + handle->out.peripheralConfig->startPeripheral(false); + } + + (void)memset(handle->out.tcd, 0, sizeof(handle->out.tcd)); + (void)memset(handle->out.asrcQueue, 0, sizeof(handle->out.asrcQueue)); + (void)memset(handle->out.transferSize, 0, sizeof(handle->out.transferSize)); + handle->out.queueUser = 0U; + handle->out.queueDriver = 0U; +} diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/asrc/fsl_asrc_edma.h b/bsps/arm/imxrt/mcux-sdk/drivers/asrc/fsl_asrc_edma.h new file mode 100644 index 0000000000..89053232c8 --- /dev/null +++ b/bsps/arm/imxrt/mcux-sdk/drivers/asrc/fsl_asrc_edma.h @@ -0,0 +1,245 @@ +/* + * Copyright 2019-2020 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef _FSL_ASRC_P2P_EDMA_H_ +#define _FSL_ASRC_P2P_EDMA_H_ + +#include "fsl_edma.h" +#include "fsl_asrc.h" + +/*! + * @addtogroup asrc_edma_driver + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @name Driver version */ +/*@{*/ +#define FSL_ASRC_EDMA_DRIVER_VERSION (MAKE_VERSION(2, 1, 0)) /*!< Version 2.1.0 */ +/*@}*/ +/*!< @brief ASRC IN edma QUEUE size */ +#define ASRC_XFER_IN_QUEUE_SIZE 4U +#define ASRC_XFER_OUT_QUEUE_SIZE (ASRC_XFER_QUEUE_SIZE * 2U) + +typedef struct _asrc_edma_handle asrc_edma_handle_t; + +/*! @brief ASRC eDMA transfer callback function for finish and error */ +typedef void (*asrc_edma_callback_t)(ASRC_Type *base, asrc_edma_handle_t *handle, status_t status, void *userData); + +/*! @brief ASRC trigger peripheral function pointer */ +typedef void (*asrc_start_peripheral_t)(bool start); +/*! @brief destination peripheral configuration */ +typedef struct _asrc_p2p_edma_config +{ + uint8_t watermark; /*!< peripheral watermark */ + uint8_t channel; /*!< peripheral channel number */ + asrc_start_peripheral_t startPeripheral; /*!< trigger peripheral start */ +} asrc_p2p_edma_config_t; + +/*!@ brief asrc in edma handler */ +typedef struct _asrc_in_edma_handle +{ + edma_handle_t *inDmaHandle; /*!< DMA handler for ASRC in */ + + uint8_t tcd[(ASRC_XFER_IN_QUEUE_SIZE + 1U) * sizeof(edma_tcd_t)]; /*!< TCD pool for eDMA send. */ + + uint32_t sampleWidth; /*!< input data width */ + uint32_t fifoThreshold; /*!< ASRC input fifo threshold */ + uint32_t *asrcQueue[ASRC_XFER_IN_QUEUE_SIZE]; /*!< Transfer queue storing queued transfer. */ + size_t transferSize[ASRC_XFER_IN_QUEUE_SIZE]; /*!< Data bytes need to transfer */ + volatile uint8_t queueUser; /*!< Index for user to queue transfer. */ + volatile uint8_t queueDriver; /*!< Index for driver to get the transfer data and size */ + uint32_t state; /*!< Internal state for ASRC eDMA transfer */ + + const asrc_p2p_edma_config_t *peripheralConfig; /*!< peripheral configuration pointer */ +} asrc_in_edma_handle_t; + +/*!@ brief asrc out edma handler */ +typedef struct _asrc_out_edma_handle +{ + edma_handle_t *outDmaHandle; /*!< DMA handler for ASRC out */ + + uint8_t tcd[(ASRC_XFER_OUT_QUEUE_SIZE + 1U) * sizeof(edma_tcd_t)]; /*!< TCD pool for eDMA send. */ + + uint32_t sampleWidth; /*!< output data width */ + uint32_t fifoThreshold; /*!< ASRC output fifo threshold */ + uint32_t *asrcQueue[ASRC_XFER_OUT_QUEUE_SIZE]; /*!< Transfer queue storing queued transfer. */ + size_t transferSize[ASRC_XFER_OUT_QUEUE_SIZE]; /*!< Data bytes need to transfer */ + volatile uint8_t queueUser; /*!< Index for user to queue transfer. */ + volatile uint8_t queueDriver; /*!< Index for driver to get the transfer data and size */ + uint32_t state; /*!< Internal state for ASRC eDMA transfer */ + const asrc_p2p_edma_config_t *peripheralConfig; /*!< peripheral configuration pointer */ +} asrc_out_edma_handle_t; + +/*! @brief ASRC DMA transfer handle.*/ +struct _asrc_edma_handle +{ + asrc_in_edma_handle_t in; /*!< asrc in handler */ + asrc_out_edma_handle_t out; /*!< asrc out handler */ + asrc_channel_pair_t channelPair; /*!< channel pair */ + void *userData; /*!< User callback parameter */ + asrc_edma_callback_t callback; /*!< Callback for users while transfer finish or error occurs */ +}; + +/******************************************************************************* + * APIs + ******************************************************************************/ +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @name eDMA Transactional + * @{ + */ + +/*! + * @brief Initializes the ASRC IN eDMA handle. + * + * This function initializes the ASRC DMA handle, which can be used for other ASRC transactional APIs. + * Usually, for a specified ASRC channel pair, call this API once to get the initialized handle. + * + * @param base ASRC base pointer. + * @param channelPair ASRC channel pair + * @param handle ASRC eDMA handle pointer. + * @param callback Pointer to user callback function. + * @param inDmaHandle DMA handler for ASRC in. + * @param periphConfig peripheral configuration. + * @param userData User parameter passed to the callback function. + */ +void ASRC_TransferInCreateHandleEDMA(ASRC_Type *base, + asrc_edma_handle_t *handle, + asrc_channel_pair_t channelPair, + asrc_edma_callback_t callback, + edma_handle_t *inDmaHandle, + const asrc_p2p_edma_config_t *periphConfig, + void *userData); + +/*! + * @brief Initializes the ASRC OUT eDMA handle. + * + * This function initializes the ASRC DMA handle, which can be used for other ASRC transactional APIs. + * Usually, for a specified ASRC channel pair, call this API once to get the initialized handle. + * + * @param base ASRC base pointer. + * @param channelPair ASRC channel pair + * @param handle ASRC eDMA handle pointer. + * @param callback Pointer to user callback function. + * @param outDmaHandle DMA handler for ASRC out. + * @param periphConfig peripheral configuration. + * @param userData User parameter passed to the callback function. + */ +void ASRC_TransferOutCreateHandleEDMA(ASRC_Type *base, + asrc_edma_handle_t *handle, + asrc_channel_pair_t channelPair, + asrc_edma_callback_t callback, + edma_handle_t *outDmaHandle, + const asrc_p2p_edma_config_t *periphConfig, + void *userData); + +/*! + * @brief Configures the ASRC P2P channel pair. + * + * + * @param base ASRC base pointer. + * @param handle ASRC eDMA handle pointer. + * @param asrcConfig asrc configurations. + * @param inSampleRate ASRC input sample rate. + * @param outSampleRate ASRC output sample rate. + */ +status_t ASRC_TransferSetChannelPairConfigEDMA(ASRC_Type *base, + asrc_edma_handle_t *handle, + asrc_channel_pair_config_t *asrcConfig, + uint32_t inSampleRate, + uint32_t outSampleRate); + +/*! + * @brief Get output sample buffer size can be transferred by edma. + * + * @note This API is depends on the ASRC output configuration, should be called after the + * ASRC_TransferSetChannelPairConfigEDMA. + * + * @param base asrc base pointer. + * @param handle ASRC channel pair edma handle. + * @param inSampleRate input sample rate. + * @param outSampleRate output sample rate. + * @param inSamplesize input sampleS size. + * @retval output buffer size in byte. + */ +uint32_t ASRC_GetOutSamplesSizeEDMA( + ASRC_Type *base, asrc_edma_handle_t *handle, uint32_t inSampleRate, uint32_t outSampleRate, uint32_t inSamplesize); + +/*! + * @brief Performs a non-blocking ASRC m2m convert using EDMA. + * + * @note This interface returns immediately after the transfer initiates. + + * @param base ASRC base pointer. + * @param handle ASRC eDMA handle pointer. + * @param xfer Pointer to the DMA transfer structure. + * @retval kStatus_Success Start a ASRC eDMA send successfully. + * @retval kStatus_InvalidArgument The input argument is invalid. + * @retval kStatus_ASRCQueueFull ASRC EDMA driver queue is full. + */ +status_t ASRC_TransferEDMA(ASRC_Type *base, asrc_edma_handle_t *handle, asrc_transfer_t *xfer); + +/*! + * @brief Aborts a ASRC IN transfer using eDMA. + * + * This function only aborts the current transfer slots, the other transfer slots' information still kept + * in the handler. If users want to terminate all transfer slots, just call ASRC_TransferTerminalP2PEDMA. + * + * @param base ASRC base pointer. + * @param handle ASRC eDMA handle pointer. + */ +void ASRC_TransferInAbortEDMA(ASRC_Type *base, asrc_edma_handle_t *handle); + +/*! + * @brief Aborts a ASRC OUT transfer using eDMA. + * + * This function only aborts the current transfer slots, the other transfer slots' information still kept + * in the handler. If users want to terminate all transfer slots, just call ASRC_TransferTerminalP2PEDMA. + * + * @param base ASRC base pointer. + * @param handle ASRC eDMA handle pointer. + */ +void ASRC_TransferOutAbortEDMA(ASRC_Type *base, asrc_edma_handle_t *handle); + +/*! + * @brief Terminate In ASRC Convert. + * + * This function will clear all transfer slots buffered in the asrc queue. If users only want to abort the + * current transfer slot, please call ASRC_TransferAbortPP2PEDMA. + * + * @param base ASRC base pointer. + * @param handle ASRC eDMA handle pointer. + */ +void ASRC_TransferInTerminalEDMA(ASRC_Type *base, asrc_edma_handle_t *handle); + +/*! + * @brief Terminate Out ASRC Convert. + * + * This function will clear all transfer slots buffered in the asrc queue. If users only want to abort the + * current transfer slot, please call ASRC_TransferAbortPP2PEDMA. + * + * @param base ASRC base pointer. + * @param handle ASRC eDMA handle pointer. + */ +void ASRC_TransferOutTerminalEDMA(ASRC_Type *base, asrc_edma_handle_t *handle); + +/*! @} */ + +#if defined(__cplusplus) +} +#endif + +/*! + * @} + */ +#endif |