summaryrefslogtreecommitdiff
path: root/drivers/src
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/src')
-rw-r--r--drivers/src/fsl_adc16.c370
-rw-r--r--drivers/src/fsl_clock.c1784
-rw-r--r--drivers/src/fsl_cmp.c285
-rw-r--r--drivers/src/fsl_cmt.c265
-rw-r--r--drivers/src/fsl_common.c176
-rw-r--r--drivers/src/fsl_crc.c282
-rw-r--r--drivers/src/fsl_dac.c220
-rw-r--r--drivers/src/fsl_dmamux.c93
-rw-r--r--drivers/src/fsl_dspi.c1712
-rw-r--r--drivers/src/fsl_dspi_edma.c1273
-rw-r--r--drivers/src/fsl_dspi_freertos.c121
-rw-r--r--drivers/src/fsl_edma.c1754
-rw-r--r--drivers/src/fsl_ewm.c102
-rw-r--r--drivers/src/fsl_flash.c3432
-rw-r--r--drivers/src/fsl_flexbus.c196
-rw-r--r--drivers/src/fsl_flexcan.c1450
-rw-r--r--drivers/src/fsl_ftm.c908
-rw-r--r--drivers/src/fsl_gpio.c195
-rw-r--r--drivers/src/fsl_i2c.c1757
-rw-r--r--drivers/src/fsl_i2c_edma.c568
-rw-r--r--drivers/src/fsl_i2c_freertos.c121
-rw-r--r--drivers/src/fsl_llwu.c404
-rw-r--r--drivers/src/fsl_lptmr.c143
-rw-r--r--drivers/src/fsl_mpu.c239
-rw-r--r--drivers/src/fsl_pdb.c141
-rw-r--r--drivers/src/fsl_pit.c125
-rw-r--r--drivers/src/fsl_pmc.c93
-rw-r--r--drivers/src/fsl_rcm.c65
-rw-r--r--drivers/src/fsl_rtc.c381
-rw-r--r--drivers/src/fsl_sai.c1066
-rw-r--r--drivers/src/fsl_sai_edma.c379
-rw-r--r--drivers/src/fsl_sdhc.c1416
-rw-r--r--drivers/src/fsl_sim.c53
-rw-r--r--drivers/src/fsl_smc.c400
-rw-r--r--drivers/src/fsl_sysmpu.c249
-rw-r--r--drivers/src/fsl_tsi_v2.c215
-rw-r--r--drivers/src/fsl_uart.c1230
-rw-r--r--drivers/src/fsl_uart_edma.c368
-rw-r--r--drivers/src/fsl_uart_freertos.c332
-rw-r--r--drivers/src/fsl_vref.c230
-rw-r--r--drivers/src/fsl_wdog.c153
41 files changed, 24746 insertions, 0 deletions
diff --git a/drivers/src/fsl_adc16.c b/drivers/src/fsl_adc16.c
new file mode 100644
index 0000000..0af6a44
--- /dev/null
+++ b/drivers/src/fsl_adc16.c
@@ -0,0 +1,370 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsl_adc16.h"
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Get instance number for ADC16 module.
+ *
+ * @param base ADC16 peripheral base address
+ */
+static uint32_t ADC16_GetInstance(ADC_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to ADC16 bases for each instance. */
+static ADC_Type *const s_adc16Bases[] = ADC_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to ADC16 clocks for each instance. */
+static const clock_ip_name_t s_adc16Clocks[] = ADC16_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t ADC16_GetInstance(ADC_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_adc16Bases); instance++)
+ {
+ if (s_adc16Bases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_adc16Bases));
+
+ return instance;
+}
+
+void ADC16_Init(ADC_Type *base, const adc16_config_t *config)
+{
+ assert(NULL != config);
+
+ uint32_t tmp32;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable the clock. */
+ CLOCK_EnableClock(s_adc16Clocks[ADC16_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* ADCx_CFG1. */
+ tmp32 = ADC_CFG1_ADICLK(config->clockSource) | ADC_CFG1_MODE(config->resolution);
+ if (kADC16_LongSampleDisabled != config->longSampleMode)
+ {
+ tmp32 |= ADC_CFG1_ADLSMP_MASK;
+ }
+ tmp32 |= ADC_CFG1_ADIV(config->clockDivider);
+ if (config->enableLowPower)
+ {
+ tmp32 |= ADC_CFG1_ADLPC_MASK;
+ }
+ base->CFG1 = tmp32;
+
+ /* ADCx_CFG2. */
+ tmp32 = base->CFG2 & ~(ADC_CFG2_ADACKEN_MASK | ADC_CFG2_ADHSC_MASK | ADC_CFG2_ADLSTS_MASK);
+ if (kADC16_LongSampleDisabled != config->longSampleMode)
+ {
+ tmp32 |= ADC_CFG2_ADLSTS(config->longSampleMode);
+ }
+ if (config->enableHighSpeed)
+ {
+ tmp32 |= ADC_CFG2_ADHSC_MASK;
+ }
+ if (config->enableAsynchronousClock)
+ {
+ tmp32 |= ADC_CFG2_ADACKEN_MASK;
+ }
+ base->CFG2 = tmp32;
+
+ /* ADCx_SC2. */
+ tmp32 = base->SC2 & ~(ADC_SC2_REFSEL_MASK);
+ tmp32 |= ADC_SC2_REFSEL(config->referenceVoltageSource);
+ base->SC2 = tmp32;
+
+ /* ADCx_SC3. */
+ if (config->enableContinuousConversion)
+ {
+ base->SC3 |= ADC_SC3_ADCO_MASK;
+ }
+ else
+ {
+ base->SC3 &= ~ADC_SC3_ADCO_MASK;
+ }
+}
+
+void ADC16_Deinit(ADC_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Disable the clock. */
+ CLOCK_DisableClock(s_adc16Clocks[ADC16_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+void ADC16_GetDefaultConfig(adc16_config_t *config)
+{
+ assert(NULL != config);
+
+ config->referenceVoltageSource = kADC16_ReferenceVoltageSourceVref;
+ config->clockSource = kADC16_ClockSourceAsynchronousClock;
+ config->enableAsynchronousClock = true;
+ config->clockDivider = kADC16_ClockDivider8;
+ config->resolution = kADC16_ResolutionSE12Bit;
+ config->longSampleMode = kADC16_LongSampleDisabled;
+ config->enableHighSpeed = false;
+ config->enableLowPower = false;
+ config->enableContinuousConversion = false;
+}
+
+#if defined(FSL_FEATURE_ADC16_HAS_CALIBRATION) && FSL_FEATURE_ADC16_HAS_CALIBRATION
+status_t ADC16_DoAutoCalibration(ADC_Type *base)
+{
+ bool bHWTrigger = false;
+ volatile uint32_t tmp32; /* 'volatile' here is for the dummy read of ADCx_R[0] register. */
+ status_t status = kStatus_Success;
+
+ /* The calibration would be failed when in hardwar mode.
+ * Remember the hardware trigger state here and restore it later if the hardware trigger is enabled.*/
+ if (0U != (ADC_SC2_ADTRG_MASK & base->SC2))
+ {
+ bHWTrigger = true;
+ base->SC2 &= ~ADC_SC2_ADTRG_MASK;
+ }
+
+ /* Clear the CALF and launch the calibration. */
+ base->SC3 |= ADC_SC3_CAL_MASK | ADC_SC3_CALF_MASK;
+ while (0U == (kADC16_ChannelConversionDoneFlag & ADC16_GetChannelStatusFlags(base, 0U)))
+ {
+ /* Check the CALF when the calibration is active. */
+ if (0U != (kADC16_CalibrationFailedFlag & ADC16_GetStatusFlags(base)))
+ {
+ status = kStatus_Fail;
+ break;
+ }
+ }
+ tmp32 = base->R[0]; /* Dummy read to clear COCO caused by calibration. */
+
+ /* Restore the hardware trigger setting if it was enabled before. */
+ if (bHWTrigger)
+ {
+ base->SC2 |= ADC_SC2_ADTRG_MASK;
+ }
+ /* Check the CALF at the end of calibration. */
+ if (0U != (kADC16_CalibrationFailedFlag & ADC16_GetStatusFlags(base)))
+ {
+ status = kStatus_Fail;
+ }
+ if (kStatus_Success != status) /* Check if the calibration process is succeed. */
+ {
+ return status;
+ }
+
+ /* Calculate the calibration values. */
+ tmp32 = base->CLP0 + base->CLP1 + base->CLP2 + base->CLP3 + base->CLP4 + base->CLPS;
+ tmp32 = 0x8000U | (tmp32 >> 1U);
+ base->PG = tmp32;
+
+#if defined(FSL_FEATURE_ADC16_HAS_DIFF_MODE) && FSL_FEATURE_ADC16_HAS_DIFF_MODE
+ tmp32 = base->CLM0 + base->CLM1 + base->CLM2 + base->CLM3 + base->CLM4 + base->CLMS;
+ tmp32 = 0x8000U | (tmp32 >> 1U);
+ base->MG = tmp32;
+#endif /* FSL_FEATURE_ADC16_HAS_DIFF_MODE */
+
+ return kStatus_Success;
+}
+#endif /* FSL_FEATURE_ADC16_HAS_CALIBRATION */
+
+#if defined(FSL_FEATURE_ADC16_HAS_MUX_SELECT) && FSL_FEATURE_ADC16_HAS_MUX_SELECT
+void ADC16_SetChannelMuxMode(ADC_Type *base, adc16_channel_mux_mode_t mode)
+{
+ if (kADC16_ChannelMuxA == mode)
+ {
+ base->CFG2 &= ~ADC_CFG2_MUXSEL_MASK;
+ }
+ else /* kADC16_ChannelMuxB. */
+ {
+ base->CFG2 |= ADC_CFG2_MUXSEL_MASK;
+ }
+}
+#endif /* FSL_FEATURE_ADC16_HAS_MUX_SELECT */
+
+void ADC16_SetHardwareCompareConfig(ADC_Type *base, const adc16_hardware_compare_config_t *config)
+{
+ uint32_t tmp32 = base->SC2 & ~(ADC_SC2_ACFE_MASK | ADC_SC2_ACFGT_MASK | ADC_SC2_ACREN_MASK);
+
+ if (!config) /* Pass "NULL" to disable the feature. */
+ {
+ base->SC2 = tmp32;
+ return;
+ }
+ /* Enable the feature. */
+ tmp32 |= ADC_SC2_ACFE_MASK;
+
+ /* Select the hardware compare working mode. */
+ switch (config->hardwareCompareMode)
+ {
+ case kADC16_HardwareCompareMode0:
+ break;
+ case kADC16_HardwareCompareMode1:
+ tmp32 |= ADC_SC2_ACFGT_MASK;
+ break;
+ case kADC16_HardwareCompareMode2:
+ tmp32 |= ADC_SC2_ACREN_MASK;
+ break;
+ case kADC16_HardwareCompareMode3:
+ tmp32 |= ADC_SC2_ACFGT_MASK | ADC_SC2_ACREN_MASK;
+ break;
+ default:
+ break;
+ }
+ base->SC2 = tmp32;
+
+ /* Load the compare values. */
+ base->CV1 = ADC_CV1_CV(config->value1);
+ base->CV2 = ADC_CV2_CV(config->value2);
+}
+
+#if defined(FSL_FEATURE_ADC16_HAS_HW_AVERAGE) && FSL_FEATURE_ADC16_HAS_HW_AVERAGE
+void ADC16_SetHardwareAverage(ADC_Type *base, adc16_hardware_average_mode_t mode)
+{
+ uint32_t tmp32 = base->SC3 & ~(ADC_SC3_AVGE_MASK | ADC_SC3_AVGS_MASK);
+
+ if (kADC16_HardwareAverageDisabled != mode)
+ {
+ tmp32 |= ADC_SC3_AVGE_MASK | ADC_SC3_AVGS(mode);
+ }
+ base->SC3 = tmp32;
+}
+#endif /* FSL_FEATURE_ADC16_HAS_HW_AVERAGE */
+
+#if defined(FSL_FEATURE_ADC16_HAS_PGA) && FSL_FEATURE_ADC16_HAS_PGA
+void ADC16_SetPGAConfig(ADC_Type *base, const adc16_pga_config_t *config)
+{
+ uint32_t tmp32;
+
+ if (!config) /* Passing "NULL" is to disable the feature. */
+ {
+ base->PGA = 0U;
+ return;
+ }
+
+ /* Enable the PGA and set the gain value. */
+ tmp32 = ADC_PGA_PGAEN_MASK | ADC_PGA_PGAG(config->pgaGain);
+
+ /* Configure the misc features for PGA. */
+ if (config->enableRunInNormalMode)
+ {
+ tmp32 |= ADC_PGA_PGALPb_MASK;
+ }
+#if defined(FSL_FEATURE_ADC16_HAS_PGA_CHOPPING) && FSL_FEATURE_ADC16_HAS_PGA_CHOPPING
+ if (config->disablePgaChopping)
+ {
+ tmp32 |= ADC_PGA_PGACHPb_MASK;
+ }
+#endif /* FSL_FEATURE_ADC16_HAS_PGA_CHOPPING */
+#if defined(FSL_FEATURE_ADC16_HAS_PGA_OFFSET_MEASUREMENT) && FSL_FEATURE_ADC16_HAS_PGA_OFFSET_MEASUREMENT
+ if (config->enableRunInOffsetMeasurement)
+ {
+ tmp32 |= ADC_PGA_PGAOFSM_MASK;
+ }
+#endif /* FSL_FEATURE_ADC16_HAS_PGA_OFFSET_MEASUREMENT */
+ base->PGA = tmp32;
+}
+#endif /* FSL_FEATURE_ADC16_HAS_PGA */
+
+uint32_t ADC16_GetStatusFlags(ADC_Type *base)
+{
+ uint32_t ret = 0;
+
+ if (0U != (base->SC2 & ADC_SC2_ADACT_MASK))
+ {
+ ret |= kADC16_ActiveFlag;
+ }
+#if defined(FSL_FEATURE_ADC16_HAS_CALIBRATION) && FSL_FEATURE_ADC16_HAS_CALIBRATION
+ if (0U != (base->SC3 & ADC_SC3_CALF_MASK))
+ {
+ ret |= kADC16_CalibrationFailedFlag;
+ }
+#endif /* FSL_FEATURE_ADC16_HAS_CALIBRATION */
+ return ret;
+}
+
+void ADC16_ClearStatusFlags(ADC_Type *base, uint32_t mask)
+{
+#if defined(FSL_FEATURE_ADC16_HAS_CALIBRATION) && FSL_FEATURE_ADC16_HAS_CALIBRATION
+ if (0U != (mask & kADC16_CalibrationFailedFlag))
+ {
+ base->SC3 |= ADC_SC3_CALF_MASK;
+ }
+#endif /* FSL_FEATURE_ADC16_HAS_CALIBRATION */
+}
+
+void ADC16_SetChannelConfig(ADC_Type *base, uint32_t channelGroup, const adc16_channel_config_t *config)
+{
+ assert(channelGroup < ADC_SC1_COUNT);
+ assert(NULL != config);
+
+ uint32_t sc1 = ADC_SC1_ADCH(config->channelNumber); /* Set the channel number. */
+
+#if defined(FSL_FEATURE_ADC16_HAS_DIFF_MODE) && FSL_FEATURE_ADC16_HAS_DIFF_MODE
+ /* Enable the differential conversion. */
+ if (config->enableDifferentialConversion)
+ {
+ sc1 |= ADC_SC1_DIFF_MASK;
+ }
+#endif /* FSL_FEATURE_ADC16_HAS_DIFF_MODE */
+ /* Enable the interrupt when the conversion is done. */
+ if (config->enableInterruptOnConversionCompleted)
+ {
+ sc1 |= ADC_SC1_AIEN_MASK;
+ }
+ base->SC1[channelGroup] = sc1;
+}
+
+uint32_t ADC16_GetChannelStatusFlags(ADC_Type *base, uint32_t channelGroup)
+{
+ assert(channelGroup < ADC_SC1_COUNT);
+
+ uint32_t ret = 0U;
+
+ if (0U != (base->SC1[channelGroup] & ADC_SC1_COCO_MASK))
+ {
+ ret |= kADC16_ChannelConversionDoneFlag;
+ }
+ return ret;
+}
diff --git a/drivers/src/fsl_clock.c b/drivers/src/fsl_clock.c
new file mode 100644
index 0000000..210c080
--- /dev/null
+++ b/drivers/src/fsl_clock.c
@@ -0,0 +1,1784 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright (c) 2016 - 2017 , NXP
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsl_clock.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Macro definition remap workaround. */
+#if (defined(MCG_C2_EREFS_MASK) && !(defined(MCG_C2_EREFS0_MASK)))
+#define MCG_C2_EREFS0_MASK MCG_C2_EREFS_MASK
+#endif
+#if (defined(MCG_C2_HGO_MASK) && !(defined(MCG_C2_HGO0_MASK)))
+#define MCG_C2_HGO0_MASK MCG_C2_HGO_MASK
+#endif
+#if (defined(MCG_C2_RANGE_MASK) && !(defined(MCG_C2_RANGE0_MASK)))
+#define MCG_C2_RANGE0_MASK MCG_C2_RANGE_MASK
+#endif
+#if (defined(MCG_C6_CME_MASK) && !(defined(MCG_C6_CME0_MASK)))
+#define MCG_C6_CME0_MASK MCG_C6_CME_MASK
+#endif
+
+/* PLL fixed multiplier when there is not PRDIV and VDIV. */
+#define PLL_FIXED_MULT (375U)
+/* Max frequency of the reference clock used for internal clock trim. */
+#define TRIM_REF_CLK_MIN (8000000U)
+/* Min frequency of the reference clock used for internal clock trim. */
+#define TRIM_REF_CLK_MAX (16000000U)
+/* Max trim value of fast internal reference clock. */
+#define TRIM_FIRC_MAX (5000000U)
+/* Min trim value of fast internal reference clock. */
+#define TRIM_FIRC_MIN (3000000U)
+/* Max trim value of fast internal reference clock. */
+#define TRIM_SIRC_MAX (39063U)
+/* Min trim value of fast internal reference clock. */
+#define TRIM_SIRC_MIN (31250U)
+
+#define MCG_S_IRCST_VAL ((MCG->S & MCG_S_IRCST_MASK) >> MCG_S_IRCST_SHIFT)
+#define MCG_S_CLKST_VAL ((MCG->S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT)
+#define MCG_S_IREFST_VAL ((MCG->S & MCG_S_IREFST_MASK) >> MCG_S_IREFST_SHIFT)
+#define MCG_S_PLLST_VAL ((MCG->S & MCG_S_PLLST_MASK) >> MCG_S_PLLST_SHIFT)
+#define MCG_C1_FRDIV_VAL ((MCG->C1 & MCG_C1_FRDIV_MASK) >> MCG_C1_FRDIV_SHIFT)
+#define MCG_C2_LP_VAL ((MCG->C2 & MCG_C2_LP_MASK) >> MCG_C2_LP_SHIFT)
+#define MCG_C2_RANGE_VAL ((MCG->C2 & MCG_C2_RANGE_MASK) >> MCG_C2_RANGE_SHIFT)
+#define MCG_SC_FCRDIV_VAL ((MCG->SC & MCG_SC_FCRDIV_MASK) >> MCG_SC_FCRDIV_SHIFT)
+#define MCG_S2_PLLCST_VAL ((MCG->S2 & MCG_S2_PLLCST_MASK) >> MCG_S2_PLLCST_SHIFT)
+#define MCG_C7_OSCSEL_VAL ((MCG->C7 & MCG_C7_OSCSEL_MASK) >> MCG_C7_OSCSEL_SHIFT)
+#define MCG_C4_DMX32_VAL ((MCG->C4 & MCG_C4_DMX32_MASK) >> MCG_C4_DMX32_SHIFT)
+#define MCG_C4_DRST_DRS_VAL ((MCG->C4 & MCG_C4_DRST_DRS_MASK) >> MCG_C4_DRST_DRS_SHIFT)
+#define MCG_C7_PLL32KREFSEL_VAL ((MCG->C7 & MCG_C7_PLL32KREFSEL_MASK) >> MCG_C7_PLL32KREFSEL_SHIFT)
+#define MCG_C5_PLLREFSEL0_VAL ((MCG->C5 & MCG_C5_PLLREFSEL0_MASK) >> MCG_C5_PLLREFSEL0_SHIFT)
+#define MCG_C11_PLLREFSEL1_VAL ((MCG->C11 & MCG_C11_PLLREFSEL1_MASK) >> MCG_C11_PLLREFSEL1_SHIFT)
+#define MCG_C11_PRDIV1_VAL ((MCG->C11 & MCG_C11_PRDIV1_MASK) >> MCG_C11_PRDIV1_SHIFT)
+#define MCG_C12_VDIV1_VAL ((MCG->C12 & MCG_C12_VDIV1_MASK) >> MCG_C12_VDIV1_SHIFT)
+#define MCG_C5_PRDIV0_VAL ((MCG->C5 & MCG_C5_PRDIV0_MASK) >> MCG_C5_PRDIV0_SHIFT)
+#define MCG_C6_VDIV0_VAL ((MCG->C6 & MCG_C6_VDIV0_MASK) >> MCG_C6_VDIV0_SHIFT)
+
+#define OSC_MODE_MASK (MCG_C2_EREFS0_MASK | MCG_C2_HGO0_MASK | MCG_C2_RANGE0_MASK)
+
+#define SIM_CLKDIV1_OUTDIV1_VAL ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV1_MASK) >> SIM_CLKDIV1_OUTDIV1_SHIFT)
+#define SIM_CLKDIV1_OUTDIV2_VAL ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV2_MASK) >> SIM_CLKDIV1_OUTDIV2_SHIFT)
+#define SIM_CLKDIV1_OUTDIV3_VAL ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV3_MASK) >> SIM_CLKDIV1_OUTDIV3_SHIFT)
+#define SIM_CLKDIV1_OUTDIV4_VAL ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV4_MASK) >> SIM_CLKDIV1_OUTDIV4_SHIFT)
+#define SIM_SOPT1_OSC32KSEL_VAL ((SIM->SOPT1 & SIM_SOPT1_OSC32KSEL_MASK) >> SIM_SOPT1_OSC32KSEL_SHIFT)
+#define SIM_SOPT2_PLLFLLSEL_VAL ((SIM->SOPT2 & SIM_SOPT2_PLLFLLSEL_MASK) >> SIM_SOPT2_PLLFLLSEL_SHIFT)
+
+/* MCG_S_CLKST definition. */
+enum _mcg_clkout_stat
+{
+ kMCG_ClkOutStatFll, /* FLL. */
+ kMCG_ClkOutStatInt, /* Internal clock. */
+ kMCG_ClkOutStatExt, /* External clock. */
+ kMCG_ClkOutStatPll /* PLL. */
+};
+
+/* MCG_S_PLLST definition. */
+enum _mcg_pllst
+{
+ kMCG_PllstFll, /* FLL is used. */
+ kMCG_PllstPll /* PLL is used. */
+};
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/* Slow internal reference clock frequency. */
+static uint32_t s_slowIrcFreq = 32768U;
+/* Fast internal reference clock frequency. */
+static uint32_t s_fastIrcFreq = 4000000U;
+
+/* External XTAL0 (OSC0) clock frequency. */
+uint32_t g_xtal0Freq;
+/* External XTAL32K clock frequency. */
+uint32_t g_xtal32Freq;
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Get the MCG external reference clock frequency.
+ *
+ * Get the current MCG external reference clock frequency in Hz. It is
+ * the frequency select by MCG_C7[OSCSEL]. This is an internal function.
+ *
+ * @return MCG external reference clock frequency in Hz.
+ */
+static uint32_t CLOCK_GetMcgExtClkFreq(void);
+
+/*!
+ * @brief Get the MCG FLL external reference clock frequency.
+ *
+ * Get the current MCG FLL external reference clock frequency in Hz. It is
+ * the frequency after by MCG_C1[FRDIV]. This is an internal function.
+ *
+ * @return MCG FLL external reference clock frequency in Hz.
+ */
+static uint32_t CLOCK_GetFllExtRefClkFreq(void);
+
+/*!
+ * @brief Get the MCG FLL reference clock frequency.
+ *
+ * Get the current MCG FLL reference clock frequency in Hz. It is
+ * the frequency select by MCG_C1[IREFS]. This is an internal function.
+ *
+ * @return MCG FLL reference clock frequency in Hz.
+ */
+static uint32_t CLOCK_GetFllRefClkFreq(void);
+
+/*!
+ * @brief Get the frequency of clock selected by MCG_C2[IRCS].
+ *
+ * This clock's two output:
+ * 1. MCGOUTCLK when MCG_S[CLKST]=0.
+ * 2. MCGIRCLK when MCG_C1[IRCLKEN]=1.
+ *
+ * @return The frequency in Hz.
+ */
+static uint32_t CLOCK_GetInternalRefClkSelectFreq(void);
+
+/*!
+ * @brief Get the MCG PLL/PLL0 reference clock frequency.
+ *
+ * Get the current MCG PLL/PLL0 reference clock frequency in Hz.
+ * This is an internal function.
+ *
+ * @return MCG PLL/PLL0 reference clock frequency in Hz.
+ */
+static uint32_t CLOCK_GetPll0RefFreq(void);
+
+/*!
+ * @brief Calculate the RANGE value base on crystal frequency.
+ *
+ * To setup external crystal oscillator, must set the register bits RANGE
+ * base on the crystal frequency. This function returns the RANGE base on the
+ * input frequency. This is an internal function.
+ *
+ * @param freq Crystal frequency in Hz.
+ * @return The RANGE value.
+ */
+static uint8_t CLOCK_GetOscRangeFromFreq(uint32_t freq);
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+#ifndef MCG_USER_CONFIG_FLL_STABLE_DELAY_EN
+/*!
+ * @brief Delay function to wait FLL stable.
+ *
+ * Delay function to wait FLL stable in FEI mode or FEE mode, should wait at least
+ * 1ms. Every time changes FLL setting, should wait this time for FLL stable.
+ */
+void CLOCK_FllStableDelay(void)
+{
+ /*
+ Should wait at least 1ms. Because in these modes, the core clock is 100MHz
+ at most, so this function could obtain the 1ms delay.
+ */
+ volatile uint32_t i = 30000U;
+ while (i--)
+ {
+ __NOP();
+ }
+}
+#else /* With MCG_USER_CONFIG_FLL_STABLE_DELAY_EN defined. */
+/* Once user defines the MCG_USER_CONFIG_FLL_STABLE_DELAY_EN to use their own delay function, he has to
+ * create his own CLOCK_FllStableDelay() function in application code. Since the clock functions in this
+ * file would call the CLOCK_FllStableDelay() regardness how it is defined.
+ */
+extern void CLOCK_FllStableDelay(void);
+#endif /* MCG_USER_CONFIG_FLL_STABLE_DELAY_EN */
+
+static uint32_t CLOCK_GetMcgExtClkFreq(void)
+{
+ uint32_t freq;
+
+ switch (MCG_C7_OSCSEL_VAL)
+ {
+ case 0U:
+ /* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */
+ assert(g_xtal0Freq);
+ freq = g_xtal0Freq;
+ break;
+ case 1U:
+ /* Please call CLOCK_SetXtal32Freq base on board setting before using XTAL32K/RTC_CLKIN clock. */
+ assert(g_xtal32Freq);
+ freq = g_xtal32Freq;
+ break;
+ default:
+ freq = 0U;
+ break;
+ }
+
+ return freq;
+}
+
+static uint32_t CLOCK_GetFllExtRefClkFreq(void)
+{
+ /* FllExtRef = McgExtRef / FllExtRefDiv */
+ uint8_t frdiv;
+ uint8_t range;
+ uint8_t oscsel;
+
+ uint32_t freq = CLOCK_GetMcgExtClkFreq();
+
+ if (!freq)
+ {
+ return freq;
+ }
+
+ frdiv = MCG_C1_FRDIV_VAL;
+ freq >>= frdiv;
+
+ range = MCG_C2_RANGE_VAL;
+ oscsel = MCG_C7_OSCSEL_VAL;
+
+ /*
+ When should use divider 32, 64, 128, 256, 512, 1024, 1280, 1536.
+ 1. MCG_C7[OSCSEL] selects IRC48M.
+ 2. MCG_C7[OSCSEL] selects OSC0 and MCG_C2[RANGE] is not 0.
+ */
+ if (((0U != range) && (kMCG_OscselOsc == oscsel)))
+ {
+ switch (frdiv)
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ freq >>= 5u;
+ break;
+ case 6:
+ /* 64*20=1280 */
+ freq /= 20u;
+ break;
+ case 7:
+ /* 128*12=1536 */
+ freq /= 12u;
+ break;
+ default:
+ freq = 0u;
+ break;
+ }
+ }
+
+ return freq;
+}
+
+static uint32_t CLOCK_GetInternalRefClkSelectFreq(void)
+{
+ if (kMCG_IrcSlow == MCG_S_IRCST_VAL)
+ {
+ /* Slow internal reference clock selected*/
+ return s_slowIrcFreq;
+ }
+ else
+ {
+ /* Fast internal reference clock selected*/
+ return s_fastIrcFreq >> MCG_SC_FCRDIV_VAL;
+ }
+}
+
+static uint32_t CLOCK_GetFllRefClkFreq(void)
+{
+ /* If use external reference clock. */
+ if (kMCG_FllSrcExternal == MCG_S_IREFST_VAL)
+ {
+ return CLOCK_GetFllExtRefClkFreq();
+ }
+ /* If use internal reference clock. */
+ else
+ {
+ return s_slowIrcFreq;
+ }
+}
+
+static uint32_t CLOCK_GetPll0RefFreq(void)
+{
+ /* MCG external reference clock. */
+ return CLOCK_GetMcgExtClkFreq();
+}
+
+static uint8_t CLOCK_GetOscRangeFromFreq(uint32_t freq)
+{
+ uint8_t range;
+
+ if (freq <= 39063U)
+ {
+ range = 0U;
+ }
+ else if (freq <= 8000000U)
+ {
+ range = 1U;
+ }
+ else
+ {
+ range = 2U;
+ }
+
+ return range;
+}
+
+uint32_t CLOCK_GetOsc0ErClkFreq(void)
+{
+ if (OSC0->CR & OSC_CR_ERCLKEN_MASK)
+ {
+ /* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */
+ assert(g_xtal0Freq);
+ return g_xtal0Freq;
+ }
+ else
+ {
+ return 0U;
+ }
+}
+
+uint32_t CLOCK_GetEr32kClkFreq(void)
+{
+ uint32_t freq;
+
+ switch (SIM_SOPT1_OSC32KSEL_VAL)
+ {
+ case 0U: /* OSC 32k clock */
+ freq = (CLOCK_GetOsc0ErClkFreq() == 32768U) ? 32768U : 0U;
+ break;
+ case 2U: /* RTC 32k clock */
+ /* Please call CLOCK_SetXtal32Freq base on board setting before using XTAL32K/RTC_CLKIN clock. */
+ assert(g_xtal32Freq);
+ freq = g_xtal32Freq;
+ break;
+ case 3U: /* LPO clock */
+ freq = LPO_CLK_FREQ;
+ break;
+ default:
+ freq = 0U;
+ break;
+ }
+ return freq;
+}
+
+uint32_t CLOCK_GetPllFllSelClkFreq(void)
+{
+ uint32_t freq;
+
+ switch (SIM_SOPT2_PLLFLLSEL_VAL)
+ {
+ case 0U: /* FLL. */
+ freq = CLOCK_GetFllFreq();
+ break;
+ case 1U: /* PLL. */
+ freq = CLOCK_GetPll0Freq();
+ break;
+ default:
+ freq = 0U;
+ break;
+ }
+
+ return freq;
+}
+
+uint32_t CLOCK_GetPlatClkFreq(void)
+{
+ return CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1);
+}
+
+uint32_t CLOCK_GetFlashClkFreq(void)
+{
+ return CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV4_VAL + 1);
+}
+
+uint32_t CLOCK_GetFlexBusClkFreq(void)
+{
+ return CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV3_VAL + 1);
+}
+
+uint32_t CLOCK_GetBusClkFreq(void)
+{
+ return CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV2_VAL + 1);
+}
+
+uint32_t CLOCK_GetCoreSysClkFreq(void)
+{
+ return CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1);
+}
+
+uint32_t CLOCK_GetFreq(clock_name_t clockName)
+{
+ uint32_t freq;
+
+ switch (clockName)
+ {
+ case kCLOCK_CoreSysClk:
+ case kCLOCK_PlatClk:
+ freq = CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1);
+ break;
+ case kCLOCK_BusClk:
+ freq = CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV2_VAL + 1);
+ break;
+ case kCLOCK_FlexBusClk:
+ freq = CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV3_VAL + 1);
+ break;
+ case kCLOCK_FlashClk:
+ freq = CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV4_VAL + 1);
+ break;
+ case kCLOCK_PllFllSelClk:
+ freq = CLOCK_GetPllFllSelClkFreq();
+ break;
+ case kCLOCK_Er32kClk:
+ freq = CLOCK_GetEr32kClkFreq();
+ break;
+ case kCLOCK_Osc0ErClk:
+ freq = CLOCK_GetOsc0ErClkFreq();
+ break;
+ case kCLOCK_McgFixedFreqClk:
+ freq = CLOCK_GetFixedFreqClkFreq();
+ break;
+ case kCLOCK_McgInternalRefClk:
+ freq = CLOCK_GetInternalRefClkFreq();
+ break;
+ case kCLOCK_McgFllClk:
+ freq = CLOCK_GetFllFreq();
+ break;
+ case kCLOCK_McgPll0Clk:
+ freq = CLOCK_GetPll0Freq();
+ break;
+ case kCLOCK_LpoClk:
+ freq = LPO_CLK_FREQ;
+ break;
+ default:
+ freq = 0U;
+ break;
+ }
+
+ return freq;
+}
+
+void CLOCK_SetSimConfig(sim_clock_config_t const *config)
+{
+ SIM->CLKDIV1 = config->clkdiv1;
+ CLOCK_SetPllFllSelClock(config->pllFllSel);
+ CLOCK_SetEr32kClock(config->er32kSrc);
+}
+
+bool CLOCK_EnableUsbfs0Clock(clock_usb_src_t src, uint32_t freq)
+{
+ bool ret = true;
+
+ CLOCK_DisableClock(kCLOCK_Usbfs0);
+
+ if (kCLOCK_UsbSrcExt == src)
+ {
+ SIM->SOPT2 &= ~SIM_SOPT2_USBSRC_MASK;
+ }
+ else
+ {
+ switch (freq)
+ {
+ case 120000000U:
+ SIM->CLKDIV2 = SIM_CLKDIV2_USBDIV(4) | SIM_CLKDIV2_USBFRAC(1);
+ break;
+ case 96000000U:
+ SIM->CLKDIV2 = SIM_CLKDIV2_USBDIV(1) | SIM_CLKDIV2_USBFRAC(0);
+ break;
+ case 72000000U:
+ SIM->CLKDIV2 = SIM_CLKDIV2_USBDIV(2) | SIM_CLKDIV2_USBFRAC(1);
+ break;
+ case 48000000U:
+ SIM->CLKDIV2 = SIM_CLKDIV2_USBDIV(0) | SIM_CLKDIV2_USBFRAC(0);
+ break;
+ default:
+ ret = false;
+ break;
+ }
+
+ SIM->SOPT2 = ((SIM->SOPT2 & ~(SIM_SOPT2_PLLFLLSEL_MASK | SIM_SOPT2_USBSRC_MASK)) | (uint32_t)src);
+ }
+
+ CLOCK_EnableClock(kCLOCK_Usbfs0);
+
+ return ret;
+}
+
+uint32_t CLOCK_GetOutClkFreq(void)
+{
+ uint32_t mcgoutclk;
+ uint32_t clkst = MCG_S_CLKST_VAL;
+
+ switch (clkst)
+ {
+ case kMCG_ClkOutStatPll:
+ mcgoutclk = CLOCK_GetPll0Freq();
+ break;
+ case kMCG_ClkOutStatFll:
+ mcgoutclk = CLOCK_GetFllFreq();
+ break;
+ case kMCG_ClkOutStatInt:
+ mcgoutclk = CLOCK_GetInternalRefClkSelectFreq();
+ break;
+ case kMCG_ClkOutStatExt:
+ mcgoutclk = CLOCK_GetMcgExtClkFreq();
+ break;
+ default:
+ mcgoutclk = 0U;
+ break;
+ }
+ return mcgoutclk;
+}
+
+uint32_t CLOCK_GetFllFreq(void)
+{
+ static const uint16_t fllFactorTable[4][2] = {{640, 732}, {1280, 1464}, {1920, 2197}, {2560, 2929}};
+
+ uint8_t drs, dmx32;
+ uint32_t freq;
+
+ /* If FLL is not enabled currently, then return 0U. */
+ if ((MCG->C2 & MCG_C2_LP_MASK) || (MCG->S & MCG_S_PLLST_MASK))
+ {
+ return 0U;
+ }
+
+ /* Get FLL reference clock frequency. */
+ freq = CLOCK_GetFllRefClkFreq();
+ if (!freq)
+ {
+ return freq;
+ }
+
+ drs = MCG_C4_DRST_DRS_VAL;
+ dmx32 = MCG_C4_DMX32_VAL;
+
+ return freq * fllFactorTable[drs][dmx32];
+}
+
+uint32_t CLOCK_GetInternalRefClkFreq(void)
+{
+ /* If MCGIRCLK is gated. */
+ if (!(MCG->C1 & MCG_C1_IRCLKEN_MASK))
+ {
+ return 0U;
+ }
+
+ return CLOCK_GetInternalRefClkSelectFreq();
+}
+
+uint32_t CLOCK_GetFixedFreqClkFreq(void)
+{
+ uint32_t freq = CLOCK_GetFllRefClkFreq();
+
+ /* MCGFFCLK must be no more than MCGOUTCLK/8. */
+ if ((freq) && (freq <= (CLOCK_GetOutClkFreq() / 8U)))
+ {
+ return freq;
+ }
+ else
+ {
+ return 0U;
+ }
+}
+
+uint32_t CLOCK_GetPll0Freq(void)
+{
+ uint32_t mcgpll0clk;
+
+ /* If PLL0 is not enabled, return 0. */
+ if (!(MCG->S & MCG_S_LOCK0_MASK))
+ {
+ return 0U;
+ }
+
+ mcgpll0clk = CLOCK_GetPll0RefFreq();
+
+ /*
+ * Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock.
+ * Please call CLOCK_SetXtal1Freq base on board setting before using OSC1 clock.
+ */
+ assert(mcgpll0clk);
+
+ mcgpll0clk /= (FSL_FEATURE_MCG_PLL_PRDIV_BASE + MCG_C5_PRDIV0_VAL);
+ mcgpll0clk *= (FSL_FEATURE_MCG_PLL_VDIV_BASE + MCG_C6_VDIV0_VAL);
+
+ return mcgpll0clk;
+}
+
+status_t CLOCK_SetExternalRefClkConfig(mcg_oscsel_t oscsel)
+{
+ bool needDelay;
+ uint32_t i;
+
+#if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
+ /* If change MCG_C7[OSCSEL] and external reference clock is system clock source, return error. */
+ if ((MCG_C7_OSCSEL_VAL != oscsel) && (!(MCG->S & MCG_S_IREFST_MASK)))
+ {
+ return kStatus_MCG_SourceUsed;
+ }
+#endif /* MCG_CONFIG_CHECK_PARAM */
+
+ if (MCG_C7_OSCSEL_VAL != oscsel)
+ {
+ /* If change OSCSEL, need to delay, ERR009878. */
+ needDelay = true;
+ }
+ else
+ {
+ needDelay = false;
+ }
+
+ MCG->C7 = (MCG->C7 & ~MCG_C7_OSCSEL_MASK) | MCG_C7_OSCSEL(oscsel);
+ if (needDelay)
+ {
+ /* ERR009878 Delay at least 50 micro-seconds for external clock change valid. */
+ i = 1500U;
+ while (i--)
+ {
+ __NOP();
+ }
+ }
+
+ return kStatus_Success;
+}
+
+status_t CLOCK_SetInternalRefClkConfig(uint8_t enableMode, mcg_irc_mode_t ircs, uint8_t fcrdiv)
+{
+ uint32_t mcgOutClkState = MCG_S_CLKST_VAL;
+ mcg_irc_mode_t curIrcs = (mcg_irc_mode_t)MCG_S_IRCST_VAL;
+ uint8_t curFcrdiv = MCG_SC_FCRDIV_VAL;
+
+#if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
+ /* If MCGIRCLK is used as system clock source. */
+ if (kMCG_ClkOutStatInt == mcgOutClkState)
+ {
+ /* If need to change MCGIRCLK source or driver, return error. */
+ if (((kMCG_IrcFast == curIrcs) && (fcrdiv != curFcrdiv)) || (ircs != curIrcs))
+ {
+ return kStatus_MCG_SourceUsed;
+ }
+ }
+#endif
+
+ /* If need to update the FCRDIV. */
+ if (fcrdiv != curFcrdiv)
+ {
+ /* If fast IRC is in use currently, change to slow IRC. */
+ if ((kMCG_IrcFast == curIrcs) && ((mcgOutClkState == kMCG_ClkOutStatInt) || (MCG->C1 & MCG_C1_IRCLKEN_MASK)))
+ {
+ MCG->C2 = ((MCG->C2 & ~MCG_C2_IRCS_MASK) | (MCG_C2_IRCS(kMCG_IrcSlow)));
+ while (MCG_S_IRCST_VAL != kMCG_IrcSlow)
+ {
+ }
+ }
+ /* Update FCRDIV. */
+ MCG->SC = (MCG->SC & ~(MCG_SC_FCRDIV_MASK | MCG_SC_ATMF_MASK | MCG_SC_LOCS0_MASK)) | MCG_SC_FCRDIV(fcrdiv);
+ }
+
+ /* Set internal reference clock selection. */
+ MCG->C2 = (MCG->C2 & ~MCG_C2_IRCS_MASK) | (MCG_C2_IRCS(ircs));
+ MCG->C1 = (MCG->C1 & ~(MCG_C1_IRCLKEN_MASK | MCG_C1_IREFSTEN_MASK)) | (uint8_t)enableMode;
+
+ /* If MCGIRCLK is used, need to wait for MCG_S_IRCST. */
+ if ((mcgOutClkState == kMCG_ClkOutStatInt) || (enableMode & kMCG_IrclkEnable))
+ {
+ while (MCG_S_IRCST_VAL != ircs)
+ {
+ }
+ }
+
+ return kStatus_Success;
+}
+
+uint32_t CLOCK_CalcPllDiv(uint32_t refFreq, uint32_t desireFreq, uint8_t *prdiv, uint8_t *vdiv)
+{
+ uint8_t ret_prdiv; /* PRDIV to return. */
+ uint8_t ret_vdiv; /* VDIV to return. */
+ uint8_t prdiv_min; /* Min PRDIV value to make reference clock in allowed range. */
+ uint8_t prdiv_max; /* Max PRDIV value to make reference clock in allowed range. */
+ uint8_t prdiv_cur; /* PRDIV value for iteration. */
+ uint8_t vdiv_cur; /* VDIV value for iteration. */
+ uint32_t ret_freq = 0U; /* PLL output fequency to return. */
+ uint32_t diff = 0xFFFFFFFFU; /* Difference between desireFreq and return frequency. */
+ uint32_t ref_div; /* Reference frequency after PRDIV. */
+
+ /*
+ Steps:
+ 1. Get allowed prdiv with such rules:
+ 1). refFreq / prdiv >= FSL_FEATURE_MCG_PLL_REF_MIN.
+ 2). refFreq / prdiv <= FSL_FEATURE_MCG_PLL_REF_MAX.
+ 2. For each allowed prdiv, there are two candidate vdiv values:
+ 1). (desireFreq / (refFreq / prdiv)).
+ 2). (desireFreq / (refFreq / prdiv)) + 1.
+ If could get the precise desired frequency, return current prdiv and
+ vdiv directly. Otherwise choose the one which is closer to desired
+ frequency.
+ */
+
+ /* Reference frequency is out of range. */
+ if ((refFreq < FSL_FEATURE_MCG_PLL_REF_MIN) ||
+ (refFreq > (FSL_FEATURE_MCG_PLL_REF_MAX * (FSL_FEATURE_MCG_PLL_PRDIV_MAX + FSL_FEATURE_MCG_PLL_PRDIV_BASE))))
+ {
+ return 0U;
+ }
+
+ /* refFreq/PRDIV must in a range. First get the allowed PRDIV range. */
+ prdiv_max = refFreq / FSL_FEATURE_MCG_PLL_REF_MIN;
+ prdiv_min = (refFreq + FSL_FEATURE_MCG_PLL_REF_MAX - 1U) / FSL_FEATURE_MCG_PLL_REF_MAX;
+
+ /* PRDIV traversal. */
+ for (prdiv_cur = prdiv_max; prdiv_cur >= prdiv_min; prdiv_cur--)
+ {
+ /* Reference frequency after PRDIV. */
+ ref_div = refFreq / prdiv_cur;
+
+ vdiv_cur = desireFreq / ref_div;
+
+ if ((vdiv_cur < FSL_FEATURE_MCG_PLL_VDIV_BASE - 1U) || (vdiv_cur > FSL_FEATURE_MCG_PLL_VDIV_BASE + 31U))
+ {
+ /* No VDIV is available with this PRDIV. */
+ continue;
+ }
+
+ ret_freq = vdiv_cur * ref_div;
+
+ if (vdiv_cur >= FSL_FEATURE_MCG_PLL_VDIV_BASE)
+ {
+ if (ret_freq == desireFreq) /* If desire frequency is got. */
+ {
+ *prdiv = prdiv_cur - FSL_FEATURE_MCG_PLL_PRDIV_BASE;
+ *vdiv = vdiv_cur - FSL_FEATURE_MCG_PLL_VDIV_BASE;
+ return ret_freq;
+ }
+ /* New PRDIV/VDIV is closer. */
+ if (diff > desireFreq - ret_freq)
+ {
+ diff = desireFreq - ret_freq;
+ ret_prdiv = prdiv_cur;
+ ret_vdiv = vdiv_cur;
+ }
+ }
+ vdiv_cur++;
+ if (vdiv_cur <= (FSL_FEATURE_MCG_PLL_VDIV_BASE + 31U))
+ {
+ ret_freq += ref_div;
+ /* New PRDIV/VDIV is closer. */
+ if (diff > ret_freq - desireFreq)
+ {
+ diff = ret_freq - desireFreq;
+ ret_prdiv = prdiv_cur;
+ ret_vdiv = vdiv_cur;
+ }
+ }
+ }
+
+ if (0xFFFFFFFFU != diff)
+ {
+ /* PRDIV/VDIV found. */
+ *prdiv = ret_prdiv - FSL_FEATURE_MCG_PLL_PRDIV_BASE;
+ *vdiv = ret_vdiv - FSL_FEATURE_MCG_PLL_VDIV_BASE;
+ ret_freq = (refFreq / ret_prdiv) * ret_vdiv;
+ return ret_freq;
+ }
+ else
+ {
+ /* No proper PRDIV/VDIV found. */
+ return 0U;
+ }
+}
+
+void CLOCK_EnablePll0(mcg_pll_config_t const *config)
+{
+ assert(config);
+
+ uint8_t mcg_c5 = 0U;
+
+ mcg_c5 |= MCG_C5_PRDIV0(config->prdiv);
+ MCG->C5 = mcg_c5; /* Disable the PLL first. */
+
+ MCG->C6 = (MCG->C6 & ~MCG_C6_VDIV0_MASK) | MCG_C6_VDIV0(config->vdiv);
+
+ /* Set enable mode. */
+ MCG->C5 |= ((uint32_t)kMCG_PllEnableIndependent | (uint32_t)config->enableMode);
+
+ /* Wait for PLL lock. */
+ while (!(MCG->S & MCG_S_LOCK0_MASK))
+ {
+ }
+}
+
+void CLOCK_SetOsc0MonitorMode(mcg_monitor_mode_t mode)
+{
+ /* Clear the previous flag, MCG_SC[LOCS0]. */
+ MCG->SC &= ~MCG_SC_ATMF_MASK;
+
+ if (kMCG_MonitorNone == mode)
+ {
+ MCG->C6 &= ~MCG_C6_CME0_MASK;
+ }
+ else
+ {
+ if (kMCG_MonitorInt == mode)
+ {
+ MCG->C2 &= ~MCG_C2_LOCRE0_MASK;
+ }
+ else
+ {
+ MCG->C2 |= MCG_C2_LOCRE0_MASK;
+ }
+ MCG->C6 |= MCG_C6_CME0_MASK;
+ }
+}
+
+void CLOCK_SetRtcOscMonitorMode(mcg_monitor_mode_t mode)
+{
+ uint8_t mcg_c8 = MCG->C8;
+
+ mcg_c8 &= ~(MCG_C8_CME1_MASK | MCG_C8_LOCRE1_MASK);
+
+ if (kMCG_MonitorNone != mode)
+ {
+ if (kMCG_MonitorReset == mode)
+ {
+ mcg_c8 |= MCG_C8_LOCRE1_MASK;
+ }
+ mcg_c8 |= MCG_C8_CME1_MASK;
+ }
+ MCG->C8 = mcg_c8;
+}
+
+void CLOCK_SetPll0MonitorMode(mcg_monitor_mode_t mode)
+{
+ uint8_t mcg_c8;
+
+ /* Clear previous flag. */
+ MCG->S = MCG_S_LOLS0_MASK;
+
+ if (kMCG_MonitorNone == mode)
+ {
+ MCG->C6 &= ~MCG_C6_LOLIE0_MASK;
+ }
+ else
+ {
+ mcg_c8 = MCG->C8;
+
+ mcg_c8 &= ~MCG_C8_LOCS1_MASK;
+
+ if (kMCG_MonitorInt == mode)
+ {
+ mcg_c8 &= ~MCG_C8_LOLRE_MASK;
+ }
+ else
+ {
+ mcg_c8 |= MCG_C8_LOLRE_MASK;
+ }
+ MCG->C8 = mcg_c8;
+ MCG->C6 |= MCG_C6_LOLIE0_MASK;
+ }
+}
+
+uint32_t CLOCK_GetStatusFlags(void)
+{
+ uint32_t ret = 0U;
+ uint8_t mcg_s = MCG->S;
+
+ if (MCG->SC & MCG_SC_LOCS0_MASK)
+ {
+ ret |= kMCG_Osc0LostFlag;
+ }
+ if (mcg_s & MCG_S_OSCINIT0_MASK)
+ {
+ ret |= kMCG_Osc0InitFlag;
+ }
+ if (MCG->C8 & MCG_C8_LOCS1_MASK)
+ {
+ ret |= kMCG_RtcOscLostFlag;
+ }
+ if (mcg_s & MCG_S_LOLS0_MASK)
+ {
+ ret |= kMCG_Pll0LostFlag;
+ }
+ if (mcg_s & MCG_S_LOCK0_MASK)
+ {
+ ret |= kMCG_Pll0LockFlag;
+ }
+ return ret;
+}
+
+void CLOCK_ClearStatusFlags(uint32_t mask)
+{
+ uint8_t reg;
+
+ if (mask & kMCG_Osc0LostFlag)
+ {
+ MCG->SC &= ~MCG_SC_ATMF_MASK;
+ }
+ if (mask & kMCG_RtcOscLostFlag)
+ {
+ reg = MCG->C8;
+ MCG->C8 = reg;
+ }
+ if (mask & kMCG_Pll0LostFlag)
+ {
+ MCG->S = MCG_S_LOLS0_MASK;
+ }
+}
+
+void CLOCK_InitOsc0(osc_config_t const *config)
+{
+ uint8_t range = CLOCK_GetOscRangeFromFreq(config->freq);
+
+ OSC_SetCapLoad(OSC0, config->capLoad);
+ OSC_SetExtRefClkConfig(OSC0, &config->oscerConfig);
+
+ MCG->C2 = ((MCG->C2 & ~OSC_MODE_MASK) | MCG_C2_RANGE(range) | (uint8_t)config->workMode);
+
+ if ((kOSC_ModeExt != config->workMode) && (OSC0->CR & OSC_CR_ERCLKEN_MASK))
+ {
+ /* Wait for stable. */
+ while (!(MCG->S & MCG_S_OSCINIT0_MASK))
+ {
+ }
+ }
+}
+
+void CLOCK_DeinitOsc0(void)
+{
+ OSC0->CR = 0U;
+ MCG->C2 &= ~OSC_MODE_MASK;
+}
+
+status_t CLOCK_TrimInternalRefClk(uint32_t extFreq, uint32_t desireFreq, uint32_t *actualFreq, mcg_atm_select_t atms)
+{
+ uint32_t multi; /* extFreq / desireFreq */
+ uint32_t actv; /* Auto trim value. */
+ uint8_t mcg_sc;
+
+ static const uint32_t trimRange[2][2] = {
+ /* Min Max */
+ {TRIM_SIRC_MIN, TRIM_SIRC_MAX}, /* Slow IRC. */
+ {TRIM_FIRC_MIN, TRIM_FIRC_MAX} /* Fast IRC. */
+ };
+
+ if ((extFreq > TRIM_REF_CLK_MAX) || (extFreq < TRIM_REF_CLK_MIN))
+ {
+ return kStatus_MCG_AtmBusClockInvalid;
+ }
+
+ /* Check desired frequency range. */
+ if ((desireFreq < trimRange[atms][0]) || (desireFreq > trimRange[atms][1]))
+ {
+ return kStatus_MCG_AtmDesiredFreqInvalid;
+ }
+
+ /*
+ Make sure internal reference clock is not used to generate bus clock.
+ Here only need to check (MCG_S_IREFST == 1).
+ */
+ if (MCG_S_IREFST(kMCG_FllSrcInternal) == (MCG->S & MCG_S_IREFST_MASK))
+ {
+ return kStatus_MCG_AtmIrcUsed;
+ }
+
+ multi = extFreq / desireFreq;
+ actv = multi * 21U;
+
+ if (kMCG_AtmSel4m == atms)
+ {
+ actv *= 128U;
+ }
+
+ /* Now begin to start trim. */
+ MCG->ATCVL = (uint8_t)actv;
+ MCG->ATCVH = (uint8_t)(actv >> 8U);
+
+ mcg_sc = MCG->SC;
+ mcg_sc &= ~(MCG_SC_ATMS_MASK | MCG_SC_LOCS0_MASK);
+ mcg_sc |= (MCG_SC_ATMF_MASK | MCG_SC_ATMS(atms));
+ MCG->SC = (mcg_sc | MCG_SC_ATME_MASK);
+
+ /* Wait for finished. */
+ while (MCG->SC & MCG_SC_ATME_MASK)
+ {
+ }
+
+ /* Error occurs? */
+ if (MCG->SC & MCG_SC_ATMF_MASK)
+ {
+ /* Clear the failed flag. */
+ MCG->SC = mcg_sc;
+ return kStatus_MCG_AtmHardwareFail;
+ }
+
+ *actualFreq = extFreq / multi;
+
+ if (kMCG_AtmSel4m == atms)
+ {
+ s_fastIrcFreq = *actualFreq;
+ }
+ else
+ {
+ s_slowIrcFreq = *actualFreq;
+ }
+
+ return kStatus_Success;
+}
+
+mcg_mode_t CLOCK_GetMode(void)
+{
+ mcg_mode_t mode = kMCG_ModeError;
+ uint32_t clkst = MCG_S_CLKST_VAL;
+ uint32_t irefst = MCG_S_IREFST_VAL;
+ uint32_t lp = MCG_C2_LP_VAL;
+ uint32_t pllst = MCG_S_PLLST_VAL;
+
+ /*------------------------------------------------------------------
+ Mode and Registers
+ ____________________________________________________________________
+
+ Mode | CLKST | IREFST | PLLST | LP
+ ____________________________________________________________________
+
+ FEI | 00(FLL) | 1(INT) | 0(FLL) | X
+ ____________________________________________________________________
+
+ FEE | 00(FLL) | 0(EXT) | 0(FLL) | X
+ ____________________________________________________________________
+
+ FBE | 10(EXT) | 0(EXT) | 0(FLL) | 0(NORMAL)
+ ____________________________________________________________________
+
+ FBI | 01(INT) | 1(INT) | 0(FLL) | 0(NORMAL)
+ ____________________________________________________________________
+
+ BLPI | 01(INT) | 1(INT) | 0(FLL) | 1(LOW POWER)
+ ____________________________________________________________________
+
+ BLPE | 10(EXT) | 0(EXT) | X | 1(LOW POWER)
+ ____________________________________________________________________
+
+ PEE | 11(PLL) | 0(EXT) | 1(PLL) | X
+ ____________________________________________________________________
+
+ PBE | 10(EXT) | 0(EXT) | 1(PLL) | O(NORMAL)
+ ____________________________________________________________________
+
+ PBI | 01(INT) | 1(INT) | 1(PLL) | 0(NORMAL)
+ ____________________________________________________________________
+
+ PEI | 11(PLL) | 1(INT) | 1(PLL) | X
+ ____________________________________________________________________
+
+ ----------------------------------------------------------------------*/
+
+ switch (clkst)
+ {
+ case kMCG_ClkOutStatFll:
+ if (kMCG_FllSrcExternal == irefst)
+ {
+ mode = kMCG_ModeFEE;
+ }
+ else
+ {
+ mode = kMCG_ModeFEI;
+ }
+ break;
+ case kMCG_ClkOutStatInt:
+ if (lp)
+ {
+ mode = kMCG_ModeBLPI;
+ }
+ else
+ {
+ {
+ mode = kMCG_ModeFBI;
+ }
+ }
+ break;
+ case kMCG_ClkOutStatExt:
+ if (lp)
+ {
+ mode = kMCG_ModeBLPE;
+ }
+ else
+ {
+ if (kMCG_PllstPll == pllst)
+ {
+ mode = kMCG_ModePBE;
+ }
+ else
+ {
+ mode = kMCG_ModeFBE;
+ }
+ }
+ break;
+ case kMCG_ClkOutStatPll:
+ {
+ mode = kMCG_ModePEE;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return mode;
+}
+
+status_t CLOCK_SetFeiMode(mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
+{
+ uint8_t mcg_c4;
+ bool change_drs = false;
+
+#if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
+ mcg_mode_t mode = CLOCK_GetMode();
+ if (!((kMCG_ModeFEI == mode) || (kMCG_ModeFBI == mode) || (kMCG_ModeFBE == mode) || (kMCG_ModeFEE == mode)))
+ {
+ return kStatus_MCG_ModeUnreachable;
+ }
+#endif
+ mcg_c4 = MCG->C4;
+
+ /*
+ Errata: ERR007993
+ Workaround: Invert MCG_C4[DMX32] or change MCG_C4[DRST_DRS] before
+ reference clock source changes, then reset to previous value after
+ reference clock changes.
+ */
+ if (kMCG_FllSrcExternal == MCG_S_IREFST_VAL)
+ {
+ change_drs = true;
+ /* Change the LSB of DRST_DRS. */
+ MCG->C4 ^= (1U << MCG_C4_DRST_DRS_SHIFT);
+ }
+
+ /* Set CLKS and IREFS. */
+ MCG->C1 =
+ ((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_IREFS_MASK))) | (MCG_C1_CLKS(kMCG_ClkOutSrcOut) /* CLKS = 0 */
+ | MCG_C1_IREFS(kMCG_FllSrcInternal)); /* IREFS = 1 */
+
+ /* Wait and check status. */
+ while (kMCG_FllSrcInternal != MCG_S_IREFST_VAL)
+ {
+ }
+
+ /* Errata: ERR007993 */
+ if (change_drs)
+ {
+ MCG->C4 = mcg_c4;
+ }
+
+ /* In FEI mode, the MCG_C4[DMX32] is set to 0U. */
+ MCG->C4 = (mcg_c4 & ~(MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) | (MCG_C4_DMX32(dmx32) | MCG_C4_DRST_DRS(drs));
+
+ /* Check MCG_S[CLKST] */
+ while (kMCG_ClkOutStatFll != MCG_S_CLKST_VAL)
+ {
+ }
+
+ /* Wait for FLL stable time. */
+ if (fllStableDelay)
+ {
+ fllStableDelay();
+ }
+
+ return kStatus_Success;
+}
+
+status_t CLOCK_SetFeeMode(uint8_t frdiv, mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
+{
+ uint8_t mcg_c4;
+ bool change_drs = false;
+
+#if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
+ mcg_mode_t mode = CLOCK_GetMode();
+ if (!((kMCG_ModeFEE == mode) || (kMCG_ModeFBI == mode) || (kMCG_ModeFBE == mode) || (kMCG_ModeFEI == mode)))
+ {
+ return kStatus_MCG_ModeUnreachable;
+ }
+#endif
+ mcg_c4 = MCG->C4;
+
+ /*
+ Errata: ERR007993
+ Workaround: Invert MCG_C4[DMX32] or change MCG_C4[DRST_DRS] before
+ reference clock source changes, then reset to previous value after
+ reference clock changes.
+ */
+ if (kMCG_FllSrcInternal == MCG_S_IREFST_VAL)
+ {
+ change_drs = true;
+ /* Change the LSB of DRST_DRS. */
+ MCG->C4 ^= (1U << MCG_C4_DRST_DRS_SHIFT);
+ }
+
+ /* Set CLKS and IREFS. */
+ MCG->C1 = ((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_FRDIV_MASK | MCG_C1_IREFS_MASK)) |
+ (MCG_C1_CLKS(kMCG_ClkOutSrcOut) /* CLKS = 0 */
+ | MCG_C1_FRDIV(frdiv) /* FRDIV */
+ | MCG_C1_IREFS(kMCG_FllSrcExternal))); /* IREFS = 0 */
+
+ /* If use external crystal as clock source, wait for it stable. */
+ if (MCG_C7_OSCSEL(kMCG_OscselOsc) == (MCG->C7 & MCG_C7_OSCSEL_MASK))
+ {
+ if (MCG->C2 & MCG_C2_EREFS_MASK)
+ {
+ while (!(MCG->S & MCG_S_OSCINIT0_MASK))
+ {
+ }
+ }
+ }
+
+ /* Wait and check status. */
+ while (kMCG_FllSrcExternal != MCG_S_IREFST_VAL)
+ {
+ }
+
+ /* Errata: ERR007993 */
+ if (change_drs)
+ {
+ MCG->C4 = mcg_c4;
+ }
+
+ /* Set DRS and DMX32. */
+ mcg_c4 = ((mcg_c4 & ~(MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) | (MCG_C4_DMX32(dmx32) | MCG_C4_DRST_DRS(drs)));
+ MCG->C4 = mcg_c4;
+
+ /* Wait for DRST_DRS update. */
+ while (MCG->C4 != mcg_c4)
+ {
+ }
+
+ /* Check MCG_S[CLKST] */
+ while (kMCG_ClkOutStatFll != MCG_S_CLKST_VAL)
+ {
+ }
+
+ /* Wait for FLL stable time. */
+ if (fllStableDelay)
+ {
+ fllStableDelay();
+ }
+
+ return kStatus_Success;
+}
+
+status_t CLOCK_SetFbiMode(mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
+{
+ uint8_t mcg_c4;
+ bool change_drs = false;
+
+#if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
+ mcg_mode_t mode = CLOCK_GetMode();
+
+ if (!((kMCG_ModeFEE == mode) || (kMCG_ModeFBI == mode) || (kMCG_ModeFBE == mode) || (kMCG_ModeFEI == mode) ||
+ (kMCG_ModeBLPI == mode)))
+
+ {
+ return kStatus_MCG_ModeUnreachable;
+ }
+#endif
+
+ mcg_c4 = MCG->C4;
+
+ MCG->C2 &= ~MCG_C2_LP_MASK; /* Disable lowpower. */
+
+ /*
+ Errata: ERR007993
+ Workaround: Invert MCG_C4[DMX32] or change MCG_C4[DRST_DRS] before
+ reference clock source changes, then reset to previous value after
+ reference clock changes.
+ */
+ if (kMCG_FllSrcExternal == MCG_S_IREFST_VAL)
+ {
+ change_drs = true;
+ /* Change the LSB of DRST_DRS. */
+ MCG->C4 ^= (1U << MCG_C4_DRST_DRS_SHIFT);
+ }
+
+ /* Set CLKS and IREFS. */
+ MCG->C1 =
+ ((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_IREFS_MASK)) | (MCG_C1_CLKS(kMCG_ClkOutSrcInternal) /* CLKS = 1 */
+ | MCG_C1_IREFS(kMCG_FllSrcInternal))); /* IREFS = 1 */
+
+ /* Wait and check status. */
+ while (kMCG_FllSrcInternal != MCG_S_IREFST_VAL)
+ {
+ }
+
+ /* Errata: ERR007993 */
+ if (change_drs)
+ {
+ MCG->C4 = mcg_c4;
+ }
+
+ while (kMCG_ClkOutStatInt != MCG_S_CLKST_VAL)
+ {
+ }
+
+ MCG->C4 = (mcg_c4 & ~(MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) | (MCG_C4_DMX32(dmx32) | MCG_C4_DRST_DRS(drs));
+
+ /* Wait for FLL stable time. */
+ if (fllStableDelay)
+ {
+ fllStableDelay();
+ }
+
+ return kStatus_Success;
+}
+
+status_t CLOCK_SetFbeMode(uint8_t frdiv, mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
+{
+ uint8_t mcg_c4;
+ bool change_drs = false;
+
+#if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
+ mcg_mode_t mode = CLOCK_GetMode();
+ if (!((kMCG_ModeFEE == mode) || (kMCG_ModeFBI == mode) || (kMCG_ModeFBE == mode) || (kMCG_ModeFEI == mode) ||
+ (kMCG_ModePBE == mode) || (kMCG_ModeBLPE == mode)))
+ {
+ return kStatus_MCG_ModeUnreachable;
+ }
+#endif
+
+ /* Change to FLL mode. */
+ MCG->C6 &= ~MCG_C6_PLLS_MASK;
+ while (MCG->S & MCG_S_PLLST_MASK)
+ {
+ }
+
+ /* Set LP bit to enable the FLL */
+ MCG->C2 &= ~MCG_C2_LP_MASK;
+
+ mcg_c4 = MCG->C4;
+
+ /*
+ Errata: ERR007993
+ Workaround: Invert MCG_C4[DMX32] or change MCG_C4[DRST_DRS] before
+ reference clock source changes, then reset to previous value after
+ reference clock changes.
+ */
+ if (kMCG_FllSrcInternal == MCG_S_IREFST_VAL)
+ {
+ change_drs = true;
+ /* Change the LSB of DRST_DRS. */
+ MCG->C4 ^= (1U << MCG_C4_DRST_DRS_SHIFT);
+ }
+
+ /* Set CLKS and IREFS. */
+ MCG->C1 = ((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_FRDIV_MASK | MCG_C1_IREFS_MASK)) |
+ (MCG_C1_CLKS(kMCG_ClkOutSrcExternal) /* CLKS = 2 */
+ | MCG_C1_FRDIV(frdiv) /* FRDIV = frdiv */
+ | MCG_C1_IREFS(kMCG_FllSrcExternal))); /* IREFS = 0 */
+
+ /* If use external crystal as clock source, wait for it stable. */
+ if (MCG_C7_OSCSEL(kMCG_OscselOsc) == (MCG->C7 & MCG_C7_OSCSEL_MASK))
+ {
+ if (MCG->C2 & MCG_C2_EREFS_MASK)
+ {
+ while (!(MCG->S & MCG_S_OSCINIT0_MASK))
+ {
+ }
+ }
+ }
+
+ /* Wait for Reference clock Status bit to clear */
+ while (kMCG_FllSrcExternal != MCG_S_IREFST_VAL)
+ {
+ }
+
+ /* Errata: ERR007993 */
+ if (change_drs)
+ {
+ MCG->C4 = mcg_c4;
+ }
+
+ /* Set DRST_DRS and DMX32. */
+ mcg_c4 = ((mcg_c4 & ~(MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) | (MCG_C4_DMX32(dmx32) | MCG_C4_DRST_DRS(drs)));
+
+ /* Wait for clock status bits to show clock source is ext ref clk */
+ while (kMCG_ClkOutStatExt != MCG_S_CLKST_VAL)
+ {
+ }
+
+ /* Wait for fll stable time. */
+ if (fllStableDelay)
+ {
+ fllStableDelay();
+ }
+
+ return kStatus_Success;
+}
+
+status_t CLOCK_SetBlpiMode(void)
+{
+#if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
+ if (MCG_S_CLKST_VAL != kMCG_ClkOutStatInt)
+ {
+ return kStatus_MCG_ModeUnreachable;
+ }
+#endif /* MCG_CONFIG_CHECK_PARAM */
+
+ /* Set LP. */
+ MCG->C2 |= MCG_C2_LP_MASK;
+
+ return kStatus_Success;
+}
+
+status_t CLOCK_SetBlpeMode(void)
+{
+#if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
+ if (MCG_S_CLKST_VAL != kMCG_ClkOutStatExt)
+ {
+ return kStatus_MCG_ModeUnreachable;
+ }
+#endif
+
+ /* Set LP bit to enter BLPE mode. */
+ MCG->C2 |= MCG_C2_LP_MASK;
+
+ return kStatus_Success;
+}
+
+status_t CLOCK_SetPbeMode(mcg_pll_clk_select_t pllcs, mcg_pll_config_t const *config)
+{
+ assert(config);
+
+ /*
+ This function is designed to change MCG to PBE mode from PEE/BLPE/FBE,
+ but with this workflow, the source mode could be all modes except PEI/PBI.
+ */
+ MCG->C2 &= ~MCG_C2_LP_MASK; /* Disable lowpower. */
+
+ /* Change to use external clock first. */
+ MCG->C1 = ((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_IREFS_MASK)) | MCG_C1_CLKS(kMCG_ClkOutSrcExternal));
+
+ /* Wait for CLKST clock status bits to show clock source is ext ref clk */
+ while ((MCG->S & (MCG_S_IREFST_MASK | MCG_S_CLKST_MASK)) !=
+ (MCG_S_IREFST(kMCG_FllSrcExternal) | MCG_S_CLKST(kMCG_ClkOutStatExt)))
+ {
+ }
+
+ /* Disable PLL first, then configure PLL. */
+ MCG->C6 &= ~MCG_C6_PLLS_MASK;
+ while (MCG->S & MCG_S_PLLST_MASK)
+ {
+ }
+
+ /* Configure the PLL. */
+ {
+ CLOCK_EnablePll0(config);
+ }
+
+ /* Change to PLL mode. */
+ MCG->C6 |= MCG_C6_PLLS_MASK;
+
+ /* Wait for PLL mode changed. */
+ while (!(MCG->S & MCG_S_PLLST_MASK))
+ {
+ }
+
+ return kStatus_Success;
+}
+
+status_t CLOCK_SetPeeMode(void)
+{
+#if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
+ mcg_mode_t mode = CLOCK_GetMode();
+ if (kMCG_ModePBE != mode)
+ {
+ return kStatus_MCG_ModeUnreachable;
+ }
+#endif
+
+ /* Change to use PLL/FLL output clock first. */
+ MCG->C1 = (MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcOut);
+
+ /* Wait for clock status bits to update */
+ while (MCG_S_CLKST_VAL != kMCG_ClkOutStatPll)
+ {
+ }
+
+ return kStatus_Success;
+}
+
+status_t CLOCK_ExternalModeToFbeModeQuick(void)
+{
+#if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
+ if (MCG->S & MCG_S_IREFST_MASK)
+ {
+ return kStatus_MCG_ModeInvalid;
+ }
+#endif /* MCG_CONFIG_CHECK_PARAM */
+
+ /* Disable low power */
+ MCG->C2 &= ~MCG_C2_LP_MASK;
+
+ MCG->C1 = ((MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcExternal));
+ while (MCG_S_CLKST_VAL != kMCG_ClkOutStatExt)
+ {
+ }
+
+ /* Disable PLL. */
+ MCG->C6 &= ~MCG_C6_PLLS_MASK;
+ while (MCG->S & MCG_S_PLLST_MASK)
+ {
+ }
+
+ return kStatus_Success;
+}
+
+status_t CLOCK_InternalModeToFbiModeQuick(void)
+{
+#if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
+ if (!(MCG->S & MCG_S_IREFST_MASK))
+ {
+ return kStatus_MCG_ModeInvalid;
+ }
+#endif
+
+ /* Disable low power */
+ MCG->C2 &= ~MCG_C2_LP_MASK;
+
+ MCG->C1 = ((MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcInternal));
+ while (MCG_S_CLKST_VAL != kMCG_ClkOutStatInt)
+ {
+ }
+
+ return kStatus_Success;
+}
+
+status_t CLOCK_BootToFeiMode(mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
+{
+ return CLOCK_SetFeiMode(dmx32, drs, fllStableDelay);
+}
+
+status_t CLOCK_BootToFeeMode(
+ mcg_oscsel_t oscsel, uint8_t frdiv, mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
+{
+ CLOCK_SetExternalRefClkConfig(oscsel);
+
+ return CLOCK_SetFeeMode(frdiv, dmx32, drs, fllStableDelay);
+}
+
+status_t CLOCK_BootToBlpiMode(uint8_t fcrdiv, mcg_irc_mode_t ircs, uint8_t ircEnableMode)
+{
+ /* If reset mode is FEI mode, set MCGIRCLK and always success. */
+ CLOCK_SetInternalRefClkConfig(ircEnableMode, ircs, fcrdiv);
+
+ /* If reset mode is not BLPI, first enter FBI mode. */
+ MCG->C1 = (MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcInternal);
+ while (MCG_S_CLKST_VAL != kMCG_ClkOutStatInt)
+ {
+ }
+
+ /* Enter BLPI mode. */
+ MCG->C2 |= MCG_C2_LP_MASK;
+
+ return kStatus_Success;
+}
+
+status_t CLOCK_BootToBlpeMode(mcg_oscsel_t oscsel)
+{
+ CLOCK_SetExternalRefClkConfig(oscsel);
+
+ /* Set to FBE mode. */
+ MCG->C1 =
+ ((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_IREFS_MASK)) | (MCG_C1_CLKS(kMCG_ClkOutSrcExternal) /* CLKS = 2 */
+ | MCG_C1_IREFS(kMCG_FllSrcExternal))); /* IREFS = 0 */
+
+ /* If use external crystal as clock source, wait for it stable. */
+ if (MCG_C7_OSCSEL(kMCG_OscselOsc) == (MCG->C7 & MCG_C7_OSCSEL_MASK))
+ {
+ if (MCG->C2 & MCG_C2_EREFS_MASK)
+ {
+ while (!(MCG->S & MCG_S_OSCINIT0_MASK))
+ {
+ }
+ }
+ }
+
+ /* Wait for MCG_S[CLKST] and MCG_S[IREFST]. */
+ while ((MCG->S & (MCG_S_IREFST_MASK | MCG_S_CLKST_MASK)) !=
+ (MCG_S_IREFST(kMCG_FllSrcExternal) | MCG_S_CLKST(kMCG_ClkOutStatExt)))
+ {
+ }
+
+ /* In FBE now, start to enter BLPE. */
+ MCG->C2 |= MCG_C2_LP_MASK;
+
+ return kStatus_Success;
+}
+
+status_t CLOCK_BootToPeeMode(mcg_oscsel_t oscsel, mcg_pll_clk_select_t pllcs, mcg_pll_config_t const *config)
+{
+ assert(config);
+
+ CLOCK_SetExternalRefClkConfig(oscsel);
+
+ CLOCK_SetPbeMode(pllcs, config);
+
+ /* Change to use PLL output clock. */
+ MCG->C1 = (MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcOut);
+ while (MCG_S_CLKST_VAL != kMCG_ClkOutStatPll)
+ {
+ }
+
+ return kStatus_Success;
+}
+
+/*
+ The transaction matrix. It defines the path for mode switch, the row is for
+ current mode and the column is target mode.
+ For example, switch from FEI to PEE:
+ 1. Current mode FEI, next mode is mcgModeMatrix[FEI][PEE] = FBE, so swith to FBE.
+ 2. Current mode FBE, next mode is mcgModeMatrix[FBE][PEE] = PBE, so swith to PBE.
+ 3. Current mode PBE, next mode is mcgModeMatrix[PBE][PEE] = PEE, so swith to PEE.
+ Thus the MCG mode has changed from FEI to PEE.
+ */
+static const mcg_mode_t mcgModeMatrix[8][8] = {
+ {kMCG_ModeFEI, kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeFEE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE,
+ kMCG_ModeFBE}, /* FEI */
+ {kMCG_ModeFEI, kMCG_ModeFBI, kMCG_ModeBLPI, kMCG_ModeFEE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE,
+ kMCG_ModeFBE}, /* FBI */
+ {kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeBLPI, kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeFBI,
+ kMCG_ModeFBI}, /* BLPI */
+ {kMCG_ModeFEI, kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeFEE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE,
+ kMCG_ModeFBE}, /* FEE */
+ {kMCG_ModeFEI, kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeFEE, kMCG_ModeFBE, kMCG_ModeBLPE, kMCG_ModePBE,
+ kMCG_ModePBE}, /* FBE */
+ {kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeBLPE, kMCG_ModePBE,
+ kMCG_ModePBE}, /* BLPE */
+ {kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeBLPE, kMCG_ModePBE,
+ kMCG_ModePEE}, /* PBE */
+ {kMCG_ModePBE, kMCG_ModePBE, kMCG_ModePBE, kMCG_ModePBE, kMCG_ModePBE, kMCG_ModePBE, kMCG_ModePBE,
+ kMCG_ModePBE} /* PEE */
+ /* FEI FBI BLPI FEE FBE BLPE PBE PEE */
+};
+
+status_t CLOCK_SetMcgConfig(const mcg_config_t *config)
+{
+ mcg_mode_t next_mode;
+ status_t status = kStatus_Success;
+
+ mcg_pll_clk_select_t pllcs = kMCG_PllClkSelPll0;
+
+ /* If need to change external clock, MCG_C7[OSCSEL]. */
+ if (MCG_C7_OSCSEL_VAL != config->oscsel)
+ {
+ /* If external clock is in use, change to FEI first. */
+ if (!(MCG->S & MCG_S_IRCST_MASK))
+ {
+ CLOCK_ExternalModeToFbeModeQuick();
+ CLOCK_SetFeiMode(config->dmx32, config->drs, (void (*)(void))0);
+ }
+
+ CLOCK_SetExternalRefClkConfig(config->oscsel);
+ }
+
+ /* Re-configure MCGIRCLK, if MCGIRCLK is used as system clock source, then change to FEI/PEI first. */
+ if (MCG_S_CLKST_VAL == kMCG_ClkOutStatInt)
+ {
+ MCG->C2 &= ~MCG_C2_LP_MASK; /* Disable lowpower. */
+
+ {
+ CLOCK_SetFeiMode(config->dmx32, config->drs, CLOCK_FllStableDelay);
+ }
+ }
+
+ /* Configure MCGIRCLK. */
+ CLOCK_SetInternalRefClkConfig(config->irclkEnableMode, config->ircs, config->fcrdiv);
+
+ next_mode = CLOCK_GetMode();
+
+ do
+ {
+ next_mode = mcgModeMatrix[next_mode][config->mcgMode];
+
+ switch (next_mode)
+ {
+ case kMCG_ModeFEI:
+ status = CLOCK_SetFeiMode(config->dmx32, config->drs, CLOCK_FllStableDelay);
+ break;
+ case kMCG_ModeFEE:
+ status = CLOCK_SetFeeMode(config->frdiv, config->dmx32, config->drs, CLOCK_FllStableDelay);
+ break;
+ case kMCG_ModeFBI:
+ status = CLOCK_SetFbiMode(config->dmx32, config->drs, (void (*)(void))0);
+ break;
+ case kMCG_ModeFBE:
+ status = CLOCK_SetFbeMode(config->frdiv, config->dmx32, config->drs, (void (*)(void))0);
+ break;
+ case kMCG_ModeBLPI:
+ status = CLOCK_SetBlpiMode();
+ break;
+ case kMCG_ModeBLPE:
+ status = CLOCK_SetBlpeMode();
+ break;
+ case kMCG_ModePBE:
+ /* If target mode is not PBE or PEE, then only need to set CLKS = EXT here. */
+ if ((kMCG_ModePEE == config->mcgMode) || (kMCG_ModePBE == config->mcgMode))
+ {
+ {
+ status = CLOCK_SetPbeMode(pllcs, &config->pll0Config);
+ }
+ }
+ else
+ {
+ MCG->C1 = ((MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcExternal));
+ while (MCG_S_CLKST_VAL != kMCG_ClkOutStatExt)
+ {
+ }
+ }
+ break;
+ case kMCG_ModePEE:
+ status = CLOCK_SetPeeMode();
+ break;
+ default:
+ break;
+ }
+ if (kStatus_Success != status)
+ {
+ return status;
+ }
+ } while (next_mode != config->mcgMode);
+
+ if (config->pll0Config.enableMode & kMCG_PllEnableIndependent)
+ {
+ CLOCK_EnablePll0(&config->pll0Config);
+ }
+ else
+ {
+ MCG->C5 &= ~(uint32_t)kMCG_PllEnableIndependent;
+ }
+ return kStatus_Success;
+}
diff --git a/drivers/src/fsl_cmp.c b/drivers/src/fsl_cmp.c
new file mode 100644
index 0000000..6a5f15a
--- /dev/null
+++ b/drivers/src/fsl_cmp.c
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsl_cmp.h"
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Get instance number for CMP module.
+ *
+ * @param base CMP peripheral base address
+ */
+static uint32_t CMP_GetInstance(CMP_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to CMP bases for each instance. */
+static CMP_Type *const s_cmpBases[] = CMP_BASE_PTRS;
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to CMP clocks for each instance. */
+static const clock_ip_name_t s_cmpClocks[] = CMP_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Codes
+ ******************************************************************************/
+static uint32_t CMP_GetInstance(CMP_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_cmpBases); instance++)
+ {
+ if (s_cmpBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_cmpBases));
+
+ return instance;
+}
+
+void CMP_Init(CMP_Type *base, const cmp_config_t *config)
+{
+ assert(NULL != config);
+
+ uint8_t tmp8;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable the clock. */
+ CLOCK_EnableClock(s_cmpClocks[CMP_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Configure. */
+ CMP_Enable(base, false); /* Disable the CMP module during configuring. */
+ /* CMPx_CR1. */
+ tmp8 = base->CR1 & ~(CMP_CR1_PMODE_MASK | CMP_CR1_INV_MASK | CMP_CR1_COS_MASK | CMP_CR1_OPE_MASK);
+ if (config->enableHighSpeed)
+ {
+ tmp8 |= CMP_CR1_PMODE_MASK;
+ }
+ if (config->enableInvertOutput)
+ {
+ tmp8 |= CMP_CR1_INV_MASK;
+ }
+ if (config->useUnfilteredOutput)
+ {
+ tmp8 |= CMP_CR1_COS_MASK;
+ }
+ if (config->enablePinOut)
+ {
+ tmp8 |= CMP_CR1_OPE_MASK;
+ }
+#if defined(FSL_FEATURE_CMP_HAS_TRIGGER_MODE) && FSL_FEATURE_CMP_HAS_TRIGGER_MODE
+ if (config->enableTriggerMode)
+ {
+ tmp8 |= CMP_CR1_TRIGM_MASK;
+ }
+ else
+ {
+ tmp8 &= ~CMP_CR1_TRIGM_MASK;
+ }
+#endif /* FSL_FEATURE_CMP_HAS_TRIGGER_MODE */
+ base->CR1 = tmp8;
+
+ /* CMPx_CR0. */
+ tmp8 = base->CR0 & ~CMP_CR0_HYSTCTR_MASK;
+ tmp8 |= CMP_CR0_HYSTCTR(config->hysteresisMode);
+ base->CR0 = tmp8;
+
+ CMP_Enable(base, config->enableCmp); /* Enable the CMP module after configured or not. */
+}
+
+void CMP_Deinit(CMP_Type *base)
+{
+ /* Disable the CMP module. */
+ CMP_Enable(base, false);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Disable the clock. */
+ CLOCK_DisableClock(s_cmpClocks[CMP_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+void CMP_GetDefaultConfig(cmp_config_t *config)
+{
+ assert(NULL != config);
+
+ config->enableCmp = true; /* Enable the CMP module after initialization. */
+ config->hysteresisMode = kCMP_HysteresisLevel0;
+ config->enableHighSpeed = false;
+ config->enableInvertOutput = false;
+ config->useUnfilteredOutput = false;
+ config->enablePinOut = false;
+#if defined(FSL_FEATURE_CMP_HAS_TRIGGER_MODE) && FSL_FEATURE_CMP_HAS_TRIGGER_MODE
+ config->enableTriggerMode = false;
+#endif /* FSL_FEATURE_CMP_HAS_TRIGGER_MODE */
+}
+
+void CMP_SetInputChannels(CMP_Type *base, uint8_t positiveChannel, uint8_t negativeChannel)
+{
+ uint8_t tmp8 = base->MUXCR;
+
+ tmp8 &= ~(CMP_MUXCR_PSEL_MASK | CMP_MUXCR_MSEL_MASK);
+ tmp8 |= CMP_MUXCR_PSEL(positiveChannel) | CMP_MUXCR_MSEL(negativeChannel);
+ base->MUXCR = tmp8;
+}
+
+#if defined(FSL_FEATURE_CMP_HAS_DMA) && FSL_FEATURE_CMP_HAS_DMA
+void CMP_EnableDMA(CMP_Type *base, bool enable)
+{
+ uint8_t tmp8 = base->SCR & ~(CMP_SCR_CFR_MASK | CMP_SCR_CFF_MASK); /* To avoid change the w1c bits. */
+
+ if (enable)
+ {
+ tmp8 |= CMP_SCR_DMAEN_MASK;
+ }
+ else
+ {
+ tmp8 &= ~CMP_SCR_DMAEN_MASK;
+ }
+ base->SCR = tmp8;
+}
+#endif /* FSL_FEATURE_CMP_HAS_DMA */
+
+void CMP_SetFilterConfig(CMP_Type *base, const cmp_filter_config_t *config)
+{
+ assert(NULL != config);
+
+ uint8_t tmp8;
+
+#if defined(FSL_FEATURE_CMP_HAS_EXTERNAL_SAMPLE_SUPPORT) && FSL_FEATURE_CMP_HAS_EXTERNAL_SAMPLE_SUPPORT
+ /* Choose the clock source for sampling. */
+ if (config->enableSample)
+ {
+ base->CR1 |= CMP_CR1_SE_MASK; /* Choose the external SAMPLE clock. */
+ }
+ else
+ {
+ base->CR1 &= ~CMP_CR1_SE_MASK; /* Choose the internal divided bus clock. */
+ }
+#endif /* FSL_FEATURE_CMP_HAS_EXTERNAL_SAMPLE_SUPPORT */
+ /* Set the filter count. */
+ tmp8 = base->CR0 & ~CMP_CR0_FILTER_CNT_MASK;
+ tmp8 |= CMP_CR0_FILTER_CNT(config->filterCount);
+ base->CR0 = tmp8;
+ /* Set the filter period. It is used as the divider to bus clock. */
+ base->FPR = CMP_FPR_FILT_PER(config->filterPeriod);
+}
+
+void CMP_SetDACConfig(CMP_Type *base, const cmp_dac_config_t *config)
+{
+ uint8_t tmp8 = 0U;
+
+ if (NULL == config)
+ {
+ /* Passing "NULL" as input parameter means no available configuration. So the DAC feature is disabled.*/
+ base->DACCR = 0U;
+ return;
+ }
+ /* CMPx_DACCR. */
+ tmp8 |= CMP_DACCR_DACEN_MASK; /* Enable the internal DAC. */
+ if (kCMP_VrefSourceVin2 == config->referenceVoltageSource)
+ {
+ tmp8 |= CMP_DACCR_VRSEL_MASK;
+ }
+ tmp8 |= CMP_DACCR_VOSEL(config->DACValue);
+
+ base->DACCR = tmp8;
+}
+
+void CMP_EnableInterrupts(CMP_Type *base, uint32_t mask)
+{
+ uint8_t tmp8 = base->SCR & ~(CMP_SCR_CFR_MASK | CMP_SCR_CFF_MASK); /* To avoid change the w1c bits. */
+
+ if (0U != (kCMP_OutputRisingInterruptEnable & mask))
+ {
+ tmp8 |= CMP_SCR_IER_MASK;
+ }
+ if (0U != (kCMP_OutputFallingInterruptEnable & mask))
+ {
+ tmp8 |= CMP_SCR_IEF_MASK;
+ }
+ base->SCR = tmp8;
+}
+
+void CMP_DisableInterrupts(CMP_Type *base, uint32_t mask)
+{
+ uint8_t tmp8 = base->SCR & ~(CMP_SCR_CFR_MASK | CMP_SCR_CFF_MASK); /* To avoid change the w1c bits. */
+
+ if (0U != (kCMP_OutputRisingInterruptEnable & mask))
+ {
+ tmp8 &= ~CMP_SCR_IER_MASK;
+ }
+ if (0U != (kCMP_OutputFallingInterruptEnable & mask))
+ {
+ tmp8 &= ~CMP_SCR_IEF_MASK;
+ }
+ base->SCR = tmp8;
+}
+
+uint32_t CMP_GetStatusFlags(CMP_Type *base)
+{
+ uint32_t ret32 = 0U;
+
+ if (0U != (CMP_SCR_CFR_MASK & base->SCR))
+ {
+ ret32 |= kCMP_OutputRisingEventFlag;
+ }
+ if (0U != (CMP_SCR_CFF_MASK & base->SCR))
+ {
+ ret32 |= kCMP_OutputFallingEventFlag;
+ }
+ if (0U != (CMP_SCR_COUT_MASK & base->SCR))
+ {
+ ret32 |= kCMP_OutputAssertEventFlag;
+ }
+ return ret32;
+}
+
+void CMP_ClearStatusFlags(CMP_Type *base, uint32_t mask)
+{
+ uint8_t tmp8 = base->SCR & ~(CMP_SCR_CFR_MASK | CMP_SCR_CFF_MASK); /* To avoid change the w1c bits. */
+
+ if (0U != (kCMP_OutputRisingEventFlag & mask))
+ {
+ tmp8 |= CMP_SCR_CFR_MASK;
+ }
+ if (0U != (kCMP_OutputFallingEventFlag & mask))
+ {
+ tmp8 |= CMP_SCR_CFF_MASK;
+ }
+ base->SCR = tmp8;
+}
diff --git a/drivers/src/fsl_cmt.c b/drivers/src/fsl_cmt.c
new file mode 100644
index 0000000..8cf72bc
--- /dev/null
+++ b/drivers/src/fsl_cmt.c
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsl_cmt.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* The standard intermediate frequency (IF). */
+#define CMT_INTERMEDIATEFREQUENCY_8MHZ (8000000U)
+/* CMT data modulate mask. */
+#define CMT_MODULATE_COUNT_WIDTH (8U)
+/* CMT diver 1. */
+#define CMT_CMTDIV_ONE (1)
+/* CMT diver 2. */
+#define CMT_CMTDIV_TWO (2)
+/* CMT diver 4. */
+#define CMT_CMTDIV_FOUR (4)
+/* CMT diver 8. */
+#define CMT_CMTDIV_EIGHT (8)
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Get instance number for CMT module.
+ *
+ * @param base CMT peripheral base address.
+ */
+static uint32_t CMT_GetInstance(CMT_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to cmt clocks for each instance. */
+static const clock_ip_name_t s_cmtClock[FSL_FEATURE_SOC_CMT_COUNT] = CMT_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*! @brief Pointers to cmt bases for each instance. */
+static CMT_Type *const s_cmtBases[] = CMT_BASE_PTRS;
+
+/*! @brief Pointers to cmt IRQ number for each instance. */
+static const IRQn_Type s_cmtIrqs[] = CMT_IRQS;
+
+/*******************************************************************************
+ * Codes
+ ******************************************************************************/
+
+static uint32_t CMT_GetInstance(CMT_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_cmtBases); instance++)
+ {
+ if (s_cmtBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_cmtBases));
+
+ return instance;
+}
+
+void CMT_GetDefaultConfig(cmt_config_t *config)
+{
+ assert(config);
+
+ /* Default infrared output is enabled and set with high active, the divider is set to 1. */
+ config->isInterruptEnabled = false;
+ config->isIroEnabled = true;
+ config->iroPolarity = kCMT_IROActiveHigh;
+ config->divider = kCMT_SecondClkDiv1;
+}
+
+void CMT_Init(CMT_Type *base, const cmt_config_t *config, uint32_t busClock_Hz)
+{
+ assert(config);
+ assert(busClock_Hz >= CMT_INTERMEDIATEFREQUENCY_8MHZ);
+
+ uint8_t divider;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Ungate clock. */
+ CLOCK_EnableClock(s_cmtClock[CMT_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Sets clock divider. The divider set in pps should be set
+ to make sycClock_Hz/divder = 8MHz */
+ base->PPS = CMT_PPS_PPSDIV(busClock_Hz / CMT_INTERMEDIATEFREQUENCY_8MHZ - 1);
+ divider = base->MSC;
+ divider &= ~CMT_MSC_CMTDIV_MASK;
+ divider |= CMT_MSC_CMTDIV(config->divider);
+ base->MSC = divider;
+
+ /* Set the IRO signal. */
+ base->OC = CMT_OC_CMTPOL(config->iroPolarity) | CMT_OC_IROPEN(config->isIroEnabled);
+
+ /* Set interrupt. */
+ if (config->isInterruptEnabled)
+ {
+ CMT_EnableInterrupts(base, kCMT_EndOfCycleInterruptEnable);
+ EnableIRQ(s_cmtIrqs[CMT_GetInstance(base)]);
+ }
+}
+
+void CMT_Deinit(CMT_Type *base)
+{
+ /*Disable the CMT modulator. */
+ base->MSC = 0;
+
+ /* Disable the interrupt. */
+ CMT_DisableInterrupts(base, kCMT_EndOfCycleInterruptEnable);
+ DisableIRQ(s_cmtIrqs[CMT_GetInstance(base)]);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Gate the clock. */
+ CLOCK_DisableClock(s_cmtClock[CMT_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+void CMT_SetMode(CMT_Type *base, cmt_mode_t mode, cmt_modulate_config_t *modulateConfig)
+{
+ uint8_t mscReg = base->MSC;
+
+ /* Judge the mode. */
+ if (mode != kCMT_DirectIROCtl)
+ {
+ assert(modulateConfig);
+
+ /* Set carrier generator. */
+ CMT_SetCarrirGenerateCountOne(base, modulateConfig->highCount1, modulateConfig->lowCount1);
+ if (mode == kCMT_FSKMode)
+ {
+ CMT_SetCarrirGenerateCountTwo(base, modulateConfig->highCount2, modulateConfig->lowCount2);
+ }
+
+ /* Set carrier modulator. */
+ CMT_SetModulateMarkSpace(base, modulateConfig->markCount, modulateConfig->spaceCount);
+ mscReg &= ~ (CMT_MSC_FSK_MASK | CMT_MSC_BASE_MASK);
+ mscReg |= mode;
+ }
+ else
+ {
+ mscReg &= ~CMT_MSC_MCGEN_MASK;
+ }
+ /* Set the CMT mode. */
+ base->MSC = mscReg;
+}
+
+cmt_mode_t CMT_GetMode(CMT_Type *base)
+{
+ uint8_t mode = base->MSC;
+
+ if (!(mode & CMT_MSC_MCGEN_MASK))
+ { /* Carrier modulator disabled and the IRO signal is in direct software control. */
+ return kCMT_DirectIROCtl;
+ }
+ else
+ {
+ /* Carrier modulator is enabled. */
+ if (mode & CMT_MSC_BASE_MASK)
+ {
+ /* Base band mode. */
+ return kCMT_BasebandMode;
+ }
+ else if (mode & CMT_MSC_FSK_MASK)
+ {
+ /* FSK mode. */
+ return kCMT_FSKMode;
+ }
+ else
+ {
+ /* Time mode. */
+ return kCMT_TimeMode;
+ }
+ }
+}
+
+uint32_t CMT_GetCMTFrequency(CMT_Type *base, uint32_t busClock_Hz)
+{
+ uint32_t frequency;
+ uint32_t divider;
+
+ /* Get intermediate frequency. */
+ frequency = busClock_Hz / ((base->PPS & CMT_PPS_PPSDIV_MASK) + 1);
+
+ /* Get the second divider. */
+ divider = ((base->MSC & CMT_MSC_CMTDIV_MASK) >> CMT_MSC_CMTDIV_SHIFT);
+ /* Get CMT frequency. */
+ switch ((cmt_second_clkdiv_t)divider)
+ {
+ case kCMT_SecondClkDiv1:
+ frequency = frequency / CMT_CMTDIV_ONE;
+ break;
+ case kCMT_SecondClkDiv2:
+ frequency = frequency / CMT_CMTDIV_TWO;
+ break;
+ case kCMT_SecondClkDiv4:
+ frequency = frequency / CMT_CMTDIV_FOUR;
+ break;
+ case kCMT_SecondClkDiv8:
+ frequency = frequency / CMT_CMTDIV_EIGHT;
+ break;
+ default:
+ frequency = frequency / CMT_CMTDIV_ONE;
+ break;
+ }
+
+ return frequency;
+}
+
+void CMT_SetModulateMarkSpace(CMT_Type *base, uint32_t markCount, uint32_t spaceCount)
+{
+ /* Set modulate mark. */
+ base->CMD1 = (markCount >> CMT_MODULATE_COUNT_WIDTH) & CMT_CMD1_MB_MASK;
+ base->CMD2 = (markCount & CMT_CMD2_MB_MASK);
+ /* Set modulate space. */
+ base->CMD3 = (spaceCount >> CMT_MODULATE_COUNT_WIDTH) & CMT_CMD3_SB_MASK;
+ base->CMD4 = spaceCount & CMT_CMD4_SB_MASK;
+}
+
+void CMT_SetIroState(CMT_Type *base, cmt_infrared_output_state_t state)
+{
+ uint8_t ocReg = base->OC;
+
+ ocReg &= ~CMT_OC_IROL_MASK;
+ ocReg |= CMT_OC_IROL(state);
+
+ /* Set the infrared output signal control. */
+ base->OC = ocReg;
+}
diff --git a/drivers/src/fsl_common.c b/drivers/src/fsl_common.c
new file mode 100644
index 0000000..2fe4957
--- /dev/null
+++ b/drivers/src/fsl_common.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2015-2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsl_common.h"
+#include "fsl_debug_console.h"
+
+#ifndef NDEBUG
+#if (defined(__CC_ARM)) || (defined(__ICCARM__))
+void __aeabi_assert(const char *failedExpr, const char *file, int line)
+{
+ PRINTF("ASSERT ERROR \" %s \": file \"%s\" Line \"%d\" \n", failedExpr, file, line);
+ for (;;)
+ {
+ __BKPT(0);
+ }
+}
+#elif(defined(__REDLIB__))
+
+#if SDK_DEBUGCONSOLE
+void __assertion_failed(char *_Expr)
+{
+ PRINTF("%s\n", _Expr);
+ for (;;)
+ {
+ __asm("bkpt #0");
+ }
+}
+#endif
+
+#elif(defined(__GNUC__))
+void __assert_func(const char *file, int line, const char *func, const char *failedExpr)
+{
+ PRINTF("ASSERT ERROR \" %s \": file \"%s\" Line \"%d\" function name \"%s\" \n", failedExpr, file, line, func);
+ for (;;)
+ {
+ __BKPT(0);
+ }
+}
+#endif /* (defined(__CC_ARM)) || (defined (__ICCARM__)) */
+#endif /* NDEBUG */
+
+#ifndef __GIC_PRIO_BITS
+uint32_t InstallIRQHandler(IRQn_Type irq, uint32_t irqHandler)
+{
+/* Addresses for VECTOR_TABLE and VECTOR_RAM come from the linker file */
+#if defined(__CC_ARM)
+ extern uint32_t Image$$VECTOR_ROM$$Base[];
+ extern uint32_t Image$$VECTOR_RAM$$Base[];
+ extern uint32_t Image$$RW_m_data$$Base[];
+
+#define __VECTOR_TABLE Image$$VECTOR_ROM$$Base
+#define __VECTOR_RAM Image$$VECTOR_RAM$$Base
+#define __RAM_VECTOR_TABLE_SIZE (((uint32_t)Image$$RW_m_data$$Base - (uint32_t)Image$$VECTOR_RAM$$Base))
+#elif defined(__ICCARM__)
+ extern uint32_t __RAM_VECTOR_TABLE_SIZE[];
+ extern uint32_t __VECTOR_TABLE[];
+ extern uint32_t __VECTOR_RAM[];
+#elif defined(__GNUC__)
+ extern uint32_t __VECTOR_TABLE[];
+ extern uint32_t __VECTOR_RAM[];
+ extern uint32_t __RAM_VECTOR_TABLE_SIZE_BYTES[];
+ uint32_t __RAM_VECTOR_TABLE_SIZE = (uint32_t)(__RAM_VECTOR_TABLE_SIZE_BYTES);
+#endif /* defined(__CC_ARM) */
+ uint32_t n;
+ uint32_t ret;
+ uint32_t irqMaskValue;
+
+ irqMaskValue = DisableGlobalIRQ();
+ if (SCB->VTOR != (uint32_t)__VECTOR_RAM)
+ {
+ /* Copy the vector table from ROM to RAM */
+ for (n = 0; n < ((uint32_t)__RAM_VECTOR_TABLE_SIZE) / sizeof(uint32_t); n++)
+ {
+ __VECTOR_RAM[n] = __VECTOR_TABLE[n];
+ }
+ /* Point the VTOR to the position of vector table */
+ SCB->VTOR = (uint32_t)__VECTOR_RAM;
+ }
+
+ ret = __VECTOR_RAM[irq + 16];
+ /* make sure the __VECTOR_RAM is noncachable */
+ __VECTOR_RAM[irq + 16] = irqHandler;
+
+ EnableGlobalIRQ(irqMaskValue);
+
+ return ret;
+}
+#endif
+
+#ifndef CPU_QN908X
+#if (defined(FSL_FEATURE_SOC_SYSCON_COUNT) && (FSL_FEATURE_SOC_SYSCON_COUNT > 0))
+
+void EnableDeepSleepIRQ(IRQn_Type interrupt)
+{
+ uint32_t index = 0;
+ uint32_t intNumber = (uint32_t)interrupt;
+ while (intNumber >= 32u)
+ {
+ index++;
+ intNumber -= 32u;
+ }
+
+ SYSCON->STARTERSET[index] = 1u << intNumber;
+ EnableIRQ(interrupt); /* also enable interrupt at NVIC */
+}
+
+void DisableDeepSleepIRQ(IRQn_Type interrupt)
+{
+ uint32_t index = 0;
+ uint32_t intNumber = (uint32_t)interrupt;
+ while (intNumber >= 32u)
+ {
+ index++;
+ intNumber -= 32u;
+ }
+
+ DisableIRQ(interrupt); /* also disable interrupt at NVIC */
+ SYSCON->STARTERCLR[index] = 1u << intNumber;
+}
+#endif /* FSL_FEATURE_SOC_SYSCON_COUNT */
+#else
+void EnableDeepSleepIRQ(IRQn_Type interrupt)
+{
+ uint32_t index = 0;
+ uint32_t intNumber = (uint32_t)interrupt;
+ while (intNumber >= 32u)
+ {
+ index++;
+ intNumber -= 32u;
+ }
+
+ /* SYSCON->STARTERSET[index] = 1u << intNumber; */
+ EnableIRQ(interrupt); /* also enable interrupt at NVIC */
+}
+
+void DisableDeepSleepIRQ(IRQn_Type interrupt)
+{
+ uint32_t index = 0;
+ uint32_t intNumber = (uint32_t)interrupt;
+ while (intNumber >= 32u)
+ {
+ index++;
+ intNumber -= 32u;
+ }
+
+ DisableIRQ(interrupt); /* also disable interrupt at NVIC */
+ /* SYSCON->STARTERCLR[index] = 1u << intNumber; */
+}
+#endif /*CPU_QN908X */
diff --git a/drivers/src/fsl_crc.c b/drivers/src/fsl_crc.c
new file mode 100644
index 0000000..dba1db8
--- /dev/null
+++ b/drivers/src/fsl_crc.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2015-2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "fsl_crc.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+/*! @internal @brief Has data register with name CRC. */
+#if defined(FSL_FEATURE_CRC_HAS_CRC_REG) && FSL_FEATURE_CRC_HAS_CRC_REG
+#define DATA CRC
+#define DATALL CRCLL
+#endif
+
+#if defined(CRC_DRIVER_USE_CRC16_CCIT_FALSE_AS_DEFAULT) && CRC_DRIVER_USE_CRC16_CCIT_FALSE_AS_DEFAULT
+/* @brief Default user configuration structure for CRC-16-CCITT */
+#define CRC_DRIVER_DEFAULT_POLYNOMIAL 0x1021U
+/*< CRC-16-CCIT polynomial x**16 + x**12 + x**5 + x**0 */
+#define CRC_DRIVER_DEFAULT_SEED 0xFFFFU
+/*< Default initial checksum */
+#define CRC_DRIVER_DEFAULT_REFLECT_IN false
+/*< Default is no transpose */
+#define CRC_DRIVER_DEFAULT_REFLECT_OUT false
+/*< Default is transpose bytes */
+#define CRC_DRIVER_DEFAULT_COMPLEMENT_CHECKSUM false
+/*< Default is without complement of CRC data register read data */
+#define CRC_DRIVER_DEFAULT_CRC_BITS kCrcBits16
+/*< Default is 16-bit CRC protocol */
+#define CRC_DRIVER_DEFAULT_CRC_RESULT kCrcFinalChecksum
+/*< Default is resutl type is final checksum */
+#endif /* CRC_DRIVER_USE_CRC16_CCIT_FALSE_AS_DEFAULT */
+
+/*! @brief CRC type of transpose of read write data */
+typedef enum _crc_transpose_type
+{
+ kCrcTransposeNone = 0U, /*! No transpose */
+ kCrcTransposeBits = 1U, /*! Tranpose bits in bytes */
+ kCrcTransposeBitsAndBytes = 2U, /*! Transpose bytes and bits in bytes */
+ kCrcTransposeBytes = 3U, /*! Transpose bytes */
+} crc_transpose_type_t;
+
+/*!
+* @brief CRC module configuration.
+*
+* This structure holds the configuration for the CRC module.
+*/
+typedef struct _crc_module_config
+{
+ uint32_t polynomial; /*!< CRC Polynomial, MSBit first.@n
+ Example polynomial: 0x1021 = 1_0000_0010_0001 = x^12+x^5+1 */
+ uint32_t seed; /*!< Starting checksum value */
+ crc_transpose_type_t readTranspose; /*!< Type of transpose when reading CRC result. */
+ crc_transpose_type_t writeTranspose; /*!< Type of transpose when writing CRC input data. */
+ bool complementChecksum; /*!< True if the result shall be complement of the actual checksum. */
+ crc_bits_t crcBits; /*!< Selects 16- or 32- bit CRC protocol. */
+} crc_module_config_t;
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+/*!
+ * @brief Returns transpose type for CRC protocol reflect in parameter.
+ *
+ * This functions helps to set writeTranspose member of crc_config_t structure. Reflect in is CRC protocol parameter.
+ *
+ * @param enable True or false for the selected CRC protocol Reflect In (refin) parameter.
+ */
+static inline crc_transpose_type_t CRC_GetTransposeTypeFromReflectIn(bool enable)
+{
+ return ((enable) ? kCrcTransposeBitsAndBytes : kCrcTransposeBytes);
+}
+
+/*!
+ * @brief Returns transpose type for CRC protocol reflect out parameter.
+ *
+ * This functions helps to set readTranspose member of crc_config_t structure. Reflect out is CRC protocol parameter.
+ *
+ * @param enable True or false for the selected CRC protocol Reflect Out (refout) parameter.
+ */
+static inline crc_transpose_type_t CRC_GetTransposeTypeFromReflectOut(bool enable)
+{
+ return ((enable) ? kCrcTransposeBitsAndBytes : kCrcTransposeNone);
+}
+
+/*!
+ * @brief Starts checksum computation.
+ *
+ * Configures the CRC module for the specified CRC protocol. @n
+ * Starts the checksum computation by writing the seed value
+ *
+ * @param base CRC peripheral address.
+ * @param config Pointer to protocol configuration structure.
+ */
+static void CRC_ConfigureAndStart(CRC_Type *base, const crc_module_config_t *config)
+{
+ uint32_t crcControl;
+
+ /* pre-compute value for CRC control registger based on user configuraton without WAS field */
+ crcControl = 0 | CRC_CTRL_TOT(config->writeTranspose) | CRC_CTRL_TOTR(config->readTranspose) |
+ CRC_CTRL_FXOR(config->complementChecksum) | CRC_CTRL_TCRC(config->crcBits);
+
+ /* make sure the control register is clear - WAS is deasserted, and protocol is set */
+ base->CTRL = crcControl;
+
+ /* write polynomial register */
+ base->GPOLY = config->polynomial;
+
+ /* write pre-computed control register value along with WAS to start checksum computation */
+ base->CTRL = crcControl | CRC_CTRL_WAS(true);
+
+ /* write seed (initial checksum) */
+ base->DATA = config->seed;
+
+ /* deassert WAS by writing pre-computed CRC control register value */
+ base->CTRL = crcControl;
+}
+
+/*!
+ * @brief Starts final checksum computation.
+ *
+ * Configures the CRC module for the specified CRC protocol. @n
+ * Starts final checksum computation by writing the seed value.
+ * @note CRC_Get16bitResult() or CRC_Get32bitResult() return final checksum
+ * (output reflection and xor functions are applied).
+ *
+ * @param base CRC peripheral address.
+ * @param protocolConfig Pointer to protocol configuration structure.
+ */
+static void CRC_SetProtocolConfig(CRC_Type *base, const crc_config_t *protocolConfig)
+{
+ crc_module_config_t moduleConfig;
+ /* convert protocol to CRC peripheral module configuration, prepare for final checksum */
+ moduleConfig.polynomial = protocolConfig->polynomial;
+ moduleConfig.seed = protocolConfig->seed;
+ moduleConfig.readTranspose = CRC_GetTransposeTypeFromReflectOut(protocolConfig->reflectOut);
+ moduleConfig.writeTranspose = CRC_GetTransposeTypeFromReflectIn(protocolConfig->reflectIn);
+ moduleConfig.complementChecksum = protocolConfig->complementChecksum;
+ moduleConfig.crcBits = protocolConfig->crcBits;
+
+ CRC_ConfigureAndStart(base, &moduleConfig);
+}
+
+/*!
+ * @brief Starts intermediate checksum computation.
+ *
+ * Configures the CRC module for the specified CRC protocol. @n
+ * Starts intermediate checksum computation by writing the seed value.
+ * @note CRC_Get16bitResult() or CRC_Get32bitResult() return intermediate checksum (raw data register value).
+ *
+ * @param base CRC peripheral address.
+ * @param protocolConfig Pointer to protocol configuration structure.
+ */
+static void CRC_SetRawProtocolConfig(CRC_Type *base, const crc_config_t *protocolConfig)
+{
+ crc_module_config_t moduleConfig;
+ /* convert protocol to CRC peripheral module configuration, prepare for intermediate checksum */
+ moduleConfig.polynomial = protocolConfig->polynomial;
+ moduleConfig.seed = protocolConfig->seed;
+ moduleConfig.readTranspose =
+ kCrcTransposeNone; /* intermediate checksum does no transpose of data register read value */
+ moduleConfig.writeTranspose = CRC_GetTransposeTypeFromReflectIn(protocolConfig->reflectIn);
+ moduleConfig.complementChecksum = false; /* intermediate checksum does no xor of data register read value */
+ moduleConfig.crcBits = protocolConfig->crcBits;
+
+ CRC_ConfigureAndStart(base, &moduleConfig);
+}
+
+void CRC_Init(CRC_Type *base, const crc_config_t *config)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* ungate clock */
+ CLOCK_EnableClock(kCLOCK_Crc0);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+ /* configure CRC module and write the seed */
+ if (config->crcResult == kCrcFinalChecksum)
+ {
+ CRC_SetProtocolConfig(base, config);
+ }
+ else
+ {
+ CRC_SetRawProtocolConfig(base, config);
+ }
+}
+
+void CRC_GetDefaultConfig(crc_config_t *config)
+{
+ static const crc_config_t crc16ccit = {
+ CRC_DRIVER_DEFAULT_POLYNOMIAL, CRC_DRIVER_DEFAULT_SEED,
+ CRC_DRIVER_DEFAULT_REFLECT_IN, CRC_DRIVER_DEFAULT_REFLECT_OUT,
+ CRC_DRIVER_DEFAULT_COMPLEMENT_CHECKSUM, CRC_DRIVER_DEFAULT_CRC_BITS,
+ CRC_DRIVER_DEFAULT_CRC_RESULT,
+ };
+
+ *config = crc16ccit;
+}
+
+void CRC_WriteData(CRC_Type *base, const uint8_t *data, size_t dataSize)
+{
+ const uint32_t *data32;
+
+ /* 8-bit reads and writes till source address is aligned 4 bytes */
+ while ((dataSize) && ((uint32_t)data & 3U))
+ {
+ base->ACCESS8BIT.DATALL = *data;
+ data++;
+ dataSize--;
+ }
+
+ /* use 32-bit reads and writes as long as possible */
+ data32 = (const uint32_t *)data;
+ while (dataSize >= sizeof(uint32_t))
+ {
+ base->DATA = *data32;
+ data32++;
+ dataSize -= sizeof(uint32_t);
+ }
+
+ data = (const uint8_t *)data32;
+
+ /* 8-bit reads and writes till end of data buffer */
+ while (dataSize)
+ {
+ base->ACCESS8BIT.DATALL = *data;
+ data++;
+ dataSize--;
+ }
+}
+
+uint32_t CRC_Get32bitResult(CRC_Type *base)
+{
+ return base->DATA;
+}
+
+uint16_t CRC_Get16bitResult(CRC_Type *base)
+{
+ uint32_t retval;
+ uint32_t totr; /* type of transpose read bitfield */
+
+ retval = base->DATA;
+ totr = (base->CTRL & CRC_CTRL_TOTR_MASK) >> CRC_CTRL_TOTR_SHIFT;
+
+ /* check transpose type to get 16-bit out of 32-bit register */
+ if (totr >= 2U)
+ {
+ /* transpose of bytes for read is set, the result CRC is in CRC_DATA[HU:HL] */
+ retval &= 0xFFFF0000U;
+ retval = retval >> 16U;
+ }
+ else
+ {
+ /* no transpose of bytes for read, the result CRC is in CRC_DATA[LU:LL] */
+ retval &= 0x0000FFFFU;
+ }
+ return (uint16_t)retval;
+}
diff --git a/drivers/src/fsl_dac.c b/drivers/src/fsl_dac.c
new file mode 100644
index 0000000..8d13d62
--- /dev/null
+++ b/drivers/src/fsl_dac.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsl_dac.h"
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Get instance number for DAC module.
+ *
+ * @param base DAC peripheral base address
+ */
+static uint32_t DAC_GetInstance(DAC_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to DAC bases for each instance. */
+static DAC_Type *const s_dacBases[] = DAC_BASE_PTRS;
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to DAC clocks for each instance. */
+static const clock_ip_name_t s_dacClocks[] = DAC_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Codes
+ ******************************************************************************/
+static uint32_t DAC_GetInstance(DAC_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_dacBases); instance++)
+ {
+ if (s_dacBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_dacBases));
+
+ return instance;
+}
+
+void DAC_Init(DAC_Type *base, const dac_config_t *config)
+{
+ assert(NULL != config);
+
+ uint8_t tmp8;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable the clock. */
+ CLOCK_EnableClock(s_dacClocks[DAC_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Configure. */
+ /* DACx_C0. */
+ tmp8 = base->C0 & ~(DAC_C0_DACRFS_MASK | DAC_C0_LPEN_MASK);
+ if (kDAC_ReferenceVoltageSourceVref2 == config->referenceVoltageSource)
+ {
+ tmp8 |= DAC_C0_DACRFS_MASK;
+ }
+ if (config->enableLowPowerMode)
+ {
+ tmp8 |= DAC_C0_LPEN_MASK;
+ }
+ base->C0 = tmp8;
+
+ /* DAC_Enable(base, true); */
+ /* Tip: The DAC output can be enabled till then after user sets their own available data in application. */
+}
+
+void DAC_Deinit(DAC_Type *base)
+{
+ DAC_Enable(base, false);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Disable the clock. */
+ CLOCK_DisableClock(s_dacClocks[DAC_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+void DAC_GetDefaultConfig(dac_config_t *config)
+{
+ assert(NULL != config);
+
+ config->referenceVoltageSource = kDAC_ReferenceVoltageSourceVref2;
+ config->enableLowPowerMode = false;
+}
+
+void DAC_SetBufferConfig(DAC_Type *base, const dac_buffer_config_t *config)
+{
+ assert(NULL != config);
+
+ uint8_t tmp8;
+
+ /* DACx_C0. */
+ tmp8 = base->C0 & ~(DAC_C0_DACTRGSEL_MASK);
+ if (kDAC_BufferTriggerBySoftwareMode == config->triggerMode)
+ {
+ tmp8 |= DAC_C0_DACTRGSEL_MASK;
+ }
+ base->C0 = tmp8;
+
+ /* DACx_C1. */
+ tmp8 = base->C1 &
+ ~(
+#if defined(FSL_FEATURE_DAC_HAS_WATERMARK_SELECTION) && FSL_FEATURE_DAC_HAS_WATERMARK_SELECTION
+ DAC_C1_DACBFWM_MASK |
+#endif /* FSL_FEATURE_DAC_HAS_WATERMARK_SELECTION */
+ DAC_C1_DACBFMD_MASK);
+#if defined(FSL_FEATURE_DAC_HAS_WATERMARK_SELECTION) && FSL_FEATURE_DAC_HAS_WATERMARK_SELECTION
+ tmp8 |= DAC_C1_DACBFWM(config->watermark);
+#endif /* FSL_FEATURE_DAC_HAS_WATERMARK_SELECTION */
+ tmp8 |= DAC_C1_DACBFMD(config->workMode);
+ base->C1 = tmp8;
+
+ /* DACx_C2. */
+ tmp8 = base->C2 & ~DAC_C2_DACBFUP_MASK;
+ tmp8 |= DAC_C2_DACBFUP(config->upperLimit);
+ base->C2 = tmp8;
+}
+
+void DAC_GetDefaultBufferConfig(dac_buffer_config_t *config)
+{
+ assert(NULL != config);
+
+ config->triggerMode = kDAC_BufferTriggerBySoftwareMode;
+#if defined(FSL_FEATURE_DAC_HAS_WATERMARK_SELECTION) && FSL_FEATURE_DAC_HAS_WATERMARK_SELECTION
+ config->watermark = kDAC_BufferWatermark1Word;
+#endif /* FSL_FEATURE_DAC_HAS_WATERMARK_SELECTION */
+ config->workMode = kDAC_BufferWorkAsNormalMode;
+ config->upperLimit = DAC_DATL_COUNT - 1U;
+}
+
+void DAC_SetBufferValue(DAC_Type *base, uint8_t index, uint16_t value)
+{
+ assert(index < DAC_DATL_COUNT);
+
+ base->DAT[index].DATL = (uint8_t)(0xFFU & value); /* Low 8-bit. */
+ base->DAT[index].DATH = (uint8_t)((0xF00U & value) >> 8); /* High 4-bit. */
+}
+
+void DAC_SetBufferReadPointer(DAC_Type *base, uint8_t index)
+{
+ assert(index < DAC_DATL_COUNT);
+
+ uint8_t tmp8 = base->C2 & ~DAC_C2_DACBFRP_MASK;
+
+ tmp8 |= DAC_C2_DACBFRP(index);
+ base->C2 = tmp8;
+}
+
+void DAC_EnableBufferInterrupts(DAC_Type *base, uint32_t mask)
+{
+ mask &= (
+#if defined(FSL_FEATURE_DAC_HAS_WATERMARK_DETECTION) && FSL_FEATURE_DAC_HAS_WATERMARK_DETECTION
+ DAC_C0_DACBWIEN_MASK |
+#endif /* FSL_FEATURE_DAC_HAS_WATERMARK_DETECTION */
+ DAC_C0_DACBTIEN_MASK | DAC_C0_DACBBIEN_MASK);
+ base->C0 |= ((uint8_t)mask); /* Write 1 to enable. */
+}
+
+void DAC_DisableBufferInterrupts(DAC_Type *base, uint32_t mask)
+{
+ mask &= (
+#if defined(FSL_FEATURE_DAC_HAS_WATERMARK_DETECTION) && FSL_FEATURE_DAC_HAS_WATERMARK_DETECTION
+ DAC_C0_DACBWIEN_MASK |
+#endif /* FSL_FEATURE_DAC_HAS_WATERMARK_DETECTION */
+ DAC_C0_DACBTIEN_MASK | DAC_C0_DACBBIEN_MASK);
+ base->C0 &= (uint8_t)(~((uint8_t)mask)); /* Write 0 to disable. */
+}
+
+uint32_t DAC_GetBufferStatusFlags(DAC_Type *base)
+{
+ return (uint32_t)(base->SR & (
+#if defined(FSL_FEATURE_DAC_HAS_WATERMARK_DETECTION) && FSL_FEATURE_DAC_HAS_WATERMARK_DETECTION
+ DAC_SR_DACBFWMF_MASK |
+#endif /* FSL_FEATURE_DAC_HAS_WATERMARK_DETECTION */
+ DAC_SR_DACBFRPTF_MASK | DAC_SR_DACBFRPBF_MASK));
+}
+
+void DAC_ClearBufferStatusFlags(DAC_Type *base, uint32_t mask)
+{
+ mask &= (
+#if defined(FSL_FEATURE_DAC_HAS_WATERMARK_DETECTION) && FSL_FEATURE_DAC_HAS_WATERMARK_DETECTION
+ DAC_SR_DACBFWMF_MASK |
+#endif /* FSL_FEATURE_DAC_HAS_WATERMARK_DETECTION */
+ DAC_SR_DACBFRPTF_MASK | DAC_SR_DACBFRPBF_MASK);
+ base->SR &= (uint8_t)(~((uint8_t)mask)); /* Write 0 to clear flags. */
+}
diff --git a/drivers/src/fsl_dmamux.c b/drivers/src/fsl_dmamux.c
new file mode 100644
index 0000000..39ce9cf
--- /dev/null
+++ b/drivers/src/fsl_dmamux.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsl_dmamux.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Get instance number for DMAMUX.
+ *
+ * @param base DMAMUX peripheral base address.
+ */
+static uint32_t DMAMUX_GetInstance(DMAMUX_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*! @brief Array to map DMAMUX instance number to base pointer. */
+static DMAMUX_Type *const s_dmamuxBases[] = DMAMUX_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Array to map DMAMUX instance number to clock name. */
+static const clock_ip_name_t s_dmamuxClockName[] = DMAMUX_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t DMAMUX_GetInstance(DMAMUX_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_dmamuxBases); instance++)
+ {
+ if (s_dmamuxBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_dmamuxBases));
+
+ return instance;
+}
+
+void DMAMUX_Init(DMAMUX_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_EnableClock(s_dmamuxClockName[DMAMUX_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+void DMAMUX_Deinit(DMAMUX_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_DisableClock(s_dmamuxClockName[DMAMUX_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
diff --git a/drivers/src/fsl_dspi.c b/drivers/src/fsl_dspi.c
new file mode 100644
index 0000000..1ec01b3
--- /dev/null
+++ b/drivers/src/fsl_dspi.c
@@ -0,0 +1,1712 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsl_dspi.h"
+#include "com_task.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+/*! @brief Typedef for master interrupt handler. */
+typedef void (*dspi_master_isr_t)(SPI_Type *base, dspi_master_handle_t *handle);
+
+/*! @brief Typedef for slave interrupt handler. */
+typedef void (*dspi_slave_isr_t)(SPI_Type *base, dspi_slave_handle_t *handle);
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Get instance number for DSPI module.
+ *
+ * @param base DSPI peripheral base address.
+ */
+uint32_t DSPI_GetInstance(SPI_Type *base);
+
+/*!
+ * @brief Configures the DSPI peripheral chip select polarity.
+ *
+ * This function takes in the desired peripheral chip select (Pcs) and it's corresponding desired polarity and
+ * configures the Pcs signal to operate with the desired characteristic.
+ *
+ * @param base DSPI peripheral address.
+ * @param pcs The particular peripheral chip select (parameter value is of type dspi_which_pcs_t) for which we wish to
+ * apply the active high or active low characteristic.
+ * @param activeLowOrHigh The setting for either "active high, inactive low (0)" or "active low, inactive high(1)" of
+ * type dspi_pcs_polarity_config_t.
+ */
+static void DSPI_SetOnePcsPolarity(SPI_Type *base, dspi_which_pcs_t pcs, dspi_pcs_polarity_config_t activeLowOrHigh);
+
+/*!
+ * @brief Master fill up the TX FIFO with data.
+ * This is not a public API.
+ */
+static void DSPI_MasterTransferFillUpTxFifo(SPI_Type *base, dspi_master_handle_t *handle);
+
+/*!
+ * @brief Master finish up a transfer.
+ * It would call back if there is callback function and set the state to idle.
+ * This is not a public API.
+ */
+static void DSPI_MasterTransferComplete(SPI_Type *base, dspi_master_handle_t *handle);
+
+/*!
+ * @brief Slave fill up the TX FIFO with data.
+ * This is not a public API.
+ */
+static void DSPI_SlaveTransferFillUpTxFifo(SPI_Type *base, dspi_slave_handle_t *handle);
+
+/*!
+ * @brief Slave finish up a transfer.
+ * It would call back if there is callback function and set the state to idle.
+ * This is not a public API.
+ */
+static void DSPI_SlaveTransferComplete(SPI_Type *base, dspi_slave_handle_t *handle);
+
+/*!
+ * @brief DSPI common interrupt handler.
+ *
+ * @param base DSPI peripheral address.
+ * @param handle pointer to g_dspiHandle which stores the transfer state.
+ */
+static void DSPI_CommonIRQHandler(SPI_Type *base, void *param);
+
+/*!
+ * @brief Master prepare the transfer.
+ * Basically it set up dspi_master_handle .
+ * This is not a public API.
+ */
+static void DSPI_MasterTransferPrepare(SPI_Type *base, dspi_master_handle_t *handle, dspi_transfer_t *transfer);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/* Defines constant value arrays for the baud rate pre-scalar and scalar divider values.*/
+static const uint32_t s_baudratePrescaler[] = {2, 3, 5, 7};
+static const uint32_t s_baudrateScaler[] = {2, 4, 6, 8, 16, 32, 64, 128,
+ 256, 512, 1024, 2048, 4096, 8192, 16384, 32768};
+
+static const uint32_t s_delayPrescaler[] = {1, 3, 5, 7};
+static const uint32_t s_delayScaler[] = {2, 4, 8, 16, 32, 64, 128, 256,
+ 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536};
+
+/*! @brief Pointers to dspi bases for each instance. */
+static SPI_Type *const s_dspiBases[] = SPI_BASE_PTRS;
+
+/*! @brief Pointers to dspi IRQ number for each instance. */
+static IRQn_Type const s_dspiIRQ[] = SPI_IRQS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to dspi clocks for each instance. */
+static clock_ip_name_t const s_dspiClock[] = DSPI_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*! @brief Pointers to dspi handles for each instance. */
+static void *g_dspiHandle[ARRAY_SIZE(s_dspiBases)];
+
+/*! @brief Pointer to master IRQ handler for each instance. */
+static dspi_master_isr_t s_dspiMasterIsr;
+
+/*! @brief Pointer to slave IRQ handler for each instance. */
+static dspi_slave_isr_t s_dspiSlaveIsr;
+
+/**********************************************************************************************************************
+* Code
+*********************************************************************************************************************/
+uint32_t DSPI_GetInstance(SPI_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_dspiBases); instance++)
+ {
+ if (s_dspiBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_dspiBases));
+
+ return instance;
+}
+
+void DSPI_MasterInit(SPI_Type *base, const dspi_master_config_t *masterConfig, uint32_t srcClock_Hz)
+{
+ assert(masterConfig);
+
+ uint32_t temp;
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* enable DSPI clock */
+ CLOCK_EnableClock(s_dspiClock[DSPI_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ DSPI_Enable(base, true);
+ DSPI_StopTransfer(base);
+
+ DSPI_SetMasterSlaveMode(base, kDSPI_Master);
+
+ temp = base->MCR & (~(SPI_MCR_CONT_SCKE_MASK | SPI_MCR_MTFE_MASK | SPI_MCR_ROOE_MASK | SPI_MCR_SMPL_PT_MASK |
+ SPI_MCR_DIS_TXF_MASK | SPI_MCR_DIS_RXF_MASK));
+
+ base->MCR = temp | SPI_MCR_CONT_SCKE(masterConfig->enableContinuousSCK) |
+ SPI_MCR_MTFE(masterConfig->enableModifiedTimingFormat) |
+ SPI_MCR_ROOE(masterConfig->enableRxFifoOverWrite) | SPI_MCR_SMPL_PT(masterConfig->samplePoint) |
+ SPI_MCR_DIS_TXF(false) | SPI_MCR_DIS_RXF(false);
+
+ DSPI_SetOnePcsPolarity(base, masterConfig->whichPcs, masterConfig->pcsActiveHighOrLow);
+
+ if (0 == DSPI_MasterSetBaudRate(base, masterConfig->whichCtar, masterConfig->ctarConfig.baudRate, srcClock_Hz))
+ {
+ assert(false);
+ }
+
+ temp = base->CTAR[masterConfig->whichCtar] &
+ ~(SPI_CTAR_FMSZ_MASK | SPI_CTAR_CPOL_MASK | SPI_CTAR_CPHA_MASK | SPI_CTAR_LSBFE_MASK);
+
+ base->CTAR[masterConfig->whichCtar] =
+ temp | SPI_CTAR_FMSZ(masterConfig->ctarConfig.bitsPerFrame - 1) | SPI_CTAR_CPOL(masterConfig->ctarConfig.cpol) |
+ SPI_CTAR_CPHA(masterConfig->ctarConfig.cpha) | SPI_CTAR_LSBFE(masterConfig->ctarConfig.direction);
+
+ DSPI_MasterSetDelayTimes(base, masterConfig->whichCtar, kDSPI_PcsToSck, srcClock_Hz,
+ masterConfig->ctarConfig.pcsToSckDelayInNanoSec);
+ DSPI_MasterSetDelayTimes(base, masterConfig->whichCtar, kDSPI_LastSckToPcs, srcClock_Hz,
+ masterConfig->ctarConfig.lastSckToPcsDelayInNanoSec);
+ DSPI_MasterSetDelayTimes(base, masterConfig->whichCtar, kDSPI_BetweenTransfer, srcClock_Hz,
+ masterConfig->ctarConfig.betweenTransferDelayInNanoSec);
+
+ DSPI_StartTransfer(base);
+}
+
+void DSPI_MasterGetDefaultConfig(dspi_master_config_t *masterConfig)
+{
+ assert(masterConfig);
+
+ masterConfig->whichCtar = kDSPI_Ctar0;
+ masterConfig->ctarConfig.baudRate = 500000;
+ masterConfig->ctarConfig.bitsPerFrame = 8;
+ masterConfig->ctarConfig.cpol = kDSPI_ClockPolarityActiveHigh;
+ masterConfig->ctarConfig.cpha = kDSPI_ClockPhaseFirstEdge;
+ masterConfig->ctarConfig.direction = kDSPI_MsbFirst;
+
+ masterConfig->ctarConfig.pcsToSckDelayInNanoSec = 1000;
+ masterConfig->ctarConfig.lastSckToPcsDelayInNanoSec = 1000;
+ masterConfig->ctarConfig.betweenTransferDelayInNanoSec = 1000;
+
+ masterConfig->whichPcs = kDSPI_Pcs0;
+ masterConfig->pcsActiveHighOrLow = kDSPI_PcsActiveLow;
+
+ masterConfig->enableContinuousSCK = false;
+ masterConfig->enableRxFifoOverWrite = false;
+ masterConfig->enableModifiedTimingFormat = false;
+ masterConfig->samplePoint = kDSPI_SckToSin0Clock;
+}
+
+void DSPI_SlaveInit(SPI_Type *base, const dspi_slave_config_t *slaveConfig)
+{
+ assert(slaveConfig);
+
+ uint32_t temp = 0;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* enable DSPI clock */
+ CLOCK_EnableClock(s_dspiClock[DSPI_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ DSPI_Enable(base, true);
+ DSPI_StopTransfer(base);
+
+ DSPI_SetMasterSlaveMode(base, kDSPI_Slave);
+
+ temp = base->MCR & (~(SPI_MCR_CONT_SCKE_MASK | SPI_MCR_MTFE_MASK | SPI_MCR_ROOE_MASK | SPI_MCR_SMPL_PT_MASK |
+ SPI_MCR_DIS_TXF_MASK | SPI_MCR_DIS_RXF_MASK));
+
+ base->MCR = temp | SPI_MCR_CONT_SCKE(slaveConfig->enableContinuousSCK) |
+ SPI_MCR_MTFE(slaveConfig->enableModifiedTimingFormat) |
+ SPI_MCR_ROOE(slaveConfig->enableRxFifoOverWrite) | SPI_MCR_SMPL_PT(slaveConfig->samplePoint) |
+ SPI_MCR_DIS_TXF(false) | SPI_MCR_DIS_RXF(false);
+
+ DSPI_SetOnePcsPolarity(base, kDSPI_Pcs0, kDSPI_PcsActiveLow);
+
+ temp = base->CTAR[slaveConfig->whichCtar] &
+ ~(SPI_CTAR_FMSZ_MASK | SPI_CTAR_CPOL_MASK | SPI_CTAR_CPHA_MASK | SPI_CTAR_LSBFE_MASK);
+
+ base->CTAR[slaveConfig->whichCtar] = temp | SPI_CTAR_SLAVE_FMSZ(slaveConfig->ctarConfig.bitsPerFrame - 1) |
+ SPI_CTAR_SLAVE_CPOL(slaveConfig->ctarConfig.cpol) |
+ SPI_CTAR_SLAVE_CPHA(slaveConfig->ctarConfig.cpha);
+
+ DSPI_StartTransfer(base);
+}
+
+void DSPI_SlaveGetDefaultConfig(dspi_slave_config_t *slaveConfig)
+{
+ assert(slaveConfig);
+
+ slaveConfig->whichCtar = kDSPI_Ctar0;
+ slaveConfig->ctarConfig.bitsPerFrame = 8;
+ slaveConfig->ctarConfig.cpol = kDSPI_ClockPolarityActiveHigh;
+ slaveConfig->ctarConfig.cpha = kDSPI_ClockPhaseFirstEdge;
+
+ slaveConfig->enableContinuousSCK = false;
+ slaveConfig->enableRxFifoOverWrite = false;
+ slaveConfig->enableModifiedTimingFormat = false;
+ slaveConfig->samplePoint = kDSPI_SckToSin0Clock;
+}
+
+void DSPI_Deinit(SPI_Type *base)
+{
+ DSPI_StopTransfer(base);
+ DSPI_Enable(base, false);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* disable DSPI clock */
+ CLOCK_DisableClock(s_dspiClock[DSPI_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+static void DSPI_SetOnePcsPolarity(SPI_Type *base, dspi_which_pcs_t pcs, dspi_pcs_polarity_config_t activeLowOrHigh)
+{
+ uint32_t temp;
+
+ temp = base->MCR;
+
+ if (activeLowOrHigh == kDSPI_PcsActiveLow)
+ {
+ temp |= SPI_MCR_PCSIS(pcs);
+ }
+ else
+ {
+ temp &= ~SPI_MCR_PCSIS(pcs);
+ }
+
+ base->MCR = temp;
+}
+
+uint32_t DSPI_MasterSetBaudRate(SPI_Type *base,
+ dspi_ctar_selection_t whichCtar,
+ uint32_t baudRate_Bps,
+ uint32_t srcClock_Hz)
+{
+ /* for master mode configuration, if slave mode detected, return 0*/
+ if (!DSPI_IsMaster(base))
+ {
+ return 0;
+ }
+ uint32_t temp;
+ uint32_t prescaler, bestPrescaler;
+ uint32_t scaler, bestScaler;
+ uint32_t dbr, bestDbr;
+ uint32_t realBaudrate, bestBaudrate;
+ uint32_t diff, min_diff;
+ uint32_t baudrate = baudRate_Bps;
+
+ /* find combination of prescaler and scaler resulting in baudrate closest to the requested value */
+ min_diff = 0xFFFFFFFFU;
+ bestPrescaler = 0;
+ bestScaler = 0;
+ bestDbr = 1;
+ bestBaudrate = 0; /* required to avoid compilation warning */
+
+ /* In all for loops, if min_diff = 0, the exit for loop*/
+ for (prescaler = 0; (prescaler < 4) && min_diff; prescaler++)
+ {
+ for (scaler = 0; (scaler < 16) && min_diff; scaler++)
+ {
+ for (dbr = 1; (dbr < 3) && min_diff; dbr++)
+ {
+ realBaudrate = ((srcClock_Hz * dbr) / (s_baudratePrescaler[prescaler] * (s_baudrateScaler[scaler])));
+
+ /* calculate the baud rate difference based on the conditional statement that states that the calculated
+ * baud rate must not exceed the desired baud rate.
+ */
+ if (baudrate >= realBaudrate)
+ {
+ diff = baudrate - realBaudrate;
+ if (min_diff > diff)
+ {
+ /* a better match found */
+ min_diff = diff;
+ bestPrescaler = prescaler;
+ bestScaler = scaler;
+ bestBaudrate = realBaudrate;
+ bestDbr = dbr;
+ }
+ }
+ }
+ }
+ }
+
+ /* write the best dbr, prescalar, and baud rate scalar to the CTAR */
+ temp = base->CTAR[whichCtar] & ~(SPI_CTAR_DBR_MASK | SPI_CTAR_PBR_MASK | SPI_CTAR_BR_MASK);
+
+ base->CTAR[whichCtar] = temp | ((bestDbr - 1) << SPI_CTAR_DBR_SHIFT) | (bestPrescaler << SPI_CTAR_PBR_SHIFT) |
+ (bestScaler << SPI_CTAR_BR_SHIFT);
+
+ /* return the actual calculated baud rate */
+ return bestBaudrate;
+}
+
+void DSPI_MasterSetDelayScaler(
+ SPI_Type *base, dspi_ctar_selection_t whichCtar, uint32_t prescaler, uint32_t scaler, dspi_delay_type_t whichDelay)
+{
+ /* these settings are only relevant in master mode */
+ if (DSPI_IsMaster(base))
+ {
+ switch (whichDelay)
+ {
+ case kDSPI_PcsToSck:
+ base->CTAR[whichCtar] = (base->CTAR[whichCtar] & (~SPI_CTAR_PCSSCK_MASK) & (~SPI_CTAR_CSSCK_MASK)) |
+ SPI_CTAR_PCSSCK(prescaler) | SPI_CTAR_CSSCK(scaler);
+ break;
+ case kDSPI_LastSckToPcs:
+ base->CTAR[whichCtar] = (base->CTAR[whichCtar] & (~SPI_CTAR_PASC_MASK) & (~SPI_CTAR_ASC_MASK)) |
+ SPI_CTAR_PASC(prescaler) | SPI_CTAR_ASC(scaler);
+ break;
+ case kDSPI_BetweenTransfer:
+ base->CTAR[whichCtar] = (base->CTAR[whichCtar] & (~SPI_CTAR_PDT_MASK) & (~SPI_CTAR_DT_MASK)) |
+ SPI_CTAR_PDT(prescaler) | SPI_CTAR_DT(scaler);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+uint32_t DSPI_MasterSetDelayTimes(SPI_Type *base,
+ dspi_ctar_selection_t whichCtar,
+ dspi_delay_type_t whichDelay,
+ uint32_t srcClock_Hz,
+ uint32_t delayTimeInNanoSec)
+{
+ /* for master mode configuration, if slave mode detected, return 0 */
+ if (!DSPI_IsMaster(base))
+ {
+ return 0;
+ }
+
+ uint32_t prescaler, bestPrescaler;
+ uint32_t scaler, bestScaler;
+ uint32_t realDelay, bestDelay;
+ uint32_t diff, min_diff;
+ uint32_t initialDelayNanoSec;
+
+ /* find combination of prescaler and scaler resulting in the delay closest to the
+ * requested value
+ */
+ min_diff = 0xFFFFFFFFU;
+ /* Initialize prescaler and scaler to their max values to generate the max delay */
+ bestPrescaler = 0x3;
+ bestScaler = 0xF;
+ bestDelay = (((1000000000U * 4) / srcClock_Hz) * s_delayPrescaler[bestPrescaler] * s_delayScaler[bestScaler]) / 4;
+
+ /* First calculate the initial, default delay */
+ initialDelayNanoSec = 1000000000U / srcClock_Hz * 2;
+
+ /* If the initial, default delay is already greater than the desired delay, then
+ * set the delays to their initial value (0) and return the delay. In other words,
+ * there is no way to decrease the delay value further.
+ */
+ if (initialDelayNanoSec >= delayTimeInNanoSec)
+ {
+ DSPI_MasterSetDelayScaler(base, whichCtar, 0, 0, whichDelay);
+ return initialDelayNanoSec;
+ }
+
+ /* In all for loops, if min_diff = 0, the exit for loop */
+ for (prescaler = 0; (prescaler < 4) && min_diff; prescaler++)
+ {
+ for (scaler = 0; (scaler < 16) && min_diff; scaler++)
+ {
+ realDelay = ((4000000000U / srcClock_Hz) * s_delayPrescaler[prescaler] * s_delayScaler[scaler]) / 4;
+
+ /* calculate the delay difference based on the conditional statement
+ * that states that the calculated delay must not be less then the desired delay
+ */
+ if (realDelay >= delayTimeInNanoSec)
+ {
+ diff = realDelay - delayTimeInNanoSec;
+ if (min_diff > diff)
+ {
+ /* a better match found */
+ min_diff = diff;
+ bestPrescaler = prescaler;
+ bestScaler = scaler;
+ bestDelay = realDelay;
+ }
+ }
+ }
+ }
+
+ /* write the best dbr, prescalar, and baud rate scalar to the CTAR */
+ DSPI_MasterSetDelayScaler(base, whichCtar, bestPrescaler, bestScaler, whichDelay);
+
+ /* return the actual calculated baud rate */
+ return bestDelay;
+}
+
+void DSPI_GetDefaultDataCommandConfig(dspi_command_data_config_t *command)
+{
+ assert(command);
+
+ command->isPcsContinuous = false;
+ command->whichCtar = kDSPI_Ctar0;
+ command->whichPcs = kDSPI_Pcs0;
+ command->isEndOfQueue = false;
+ command->clearTransferCount = false;
+}
+
+void DSPI_MasterWriteDataBlocking(SPI_Type *base, dspi_command_data_config_t *command, uint16_t data)
+{
+ assert(command);
+
+ /* First, clear Transmit Complete Flag (TCF) */
+ DSPI_ClearStatusFlags(base, kDSPI_TxCompleteFlag);
+
+ while (!(DSPI_GetStatusFlags(base) & kDSPI_TxFifoFillRequestFlag))
+ {
+ DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag);
+ }
+
+ base->PUSHR = SPI_PUSHR_CONT(command->isPcsContinuous) | SPI_PUSHR_CTAS(command->whichCtar) |
+ SPI_PUSHR_PCS(command->whichPcs) | SPI_PUSHR_EOQ(command->isEndOfQueue) |
+ SPI_PUSHR_CTCNT(command->clearTransferCount) | SPI_PUSHR_TXDATA(data);
+ DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag);
+
+ /* Wait till TCF sets */
+ while (!(DSPI_GetStatusFlags(base) & kDSPI_TxCompleteFlag))
+ {
+ }
+}
+
+void DSPI_MasterWriteCommandDataBlocking(SPI_Type *base, uint32_t data)
+{
+ /* First, clear Transmit Complete Flag (TCF) */
+ DSPI_ClearStatusFlags(base, kDSPI_TxCompleteFlag);
+
+ while (!(DSPI_GetStatusFlags(base) & kDSPI_TxFifoFillRequestFlag))
+ {
+ DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag);
+ }
+
+ base->PUSHR = data;
+
+ DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag);
+
+ /* Wait till TCF sets */
+ while (!(DSPI_GetStatusFlags(base) & kDSPI_TxCompleteFlag))
+ {
+ }
+}
+
+void DSPI_SlaveWriteDataBlocking(SPI_Type *base, uint32_t data)
+{
+ /* First, clear Transmit Complete Flag (TCF) */
+ DSPI_ClearStatusFlags(base, kDSPI_TxCompleteFlag);
+
+ while (!(DSPI_GetStatusFlags(base) & kDSPI_TxFifoFillRequestFlag))
+ {
+ DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag);
+ }
+
+ base->PUSHR_SLAVE = data;
+
+ DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag);
+
+ /* Wait till TCF sets */
+ while (!(DSPI_GetStatusFlags(base) & kDSPI_TxCompleteFlag))
+ {
+ }
+}
+
+void DSPI_EnableInterrupts(SPI_Type *base, uint32_t mask)
+{
+ if (mask & SPI_RSER_TFFF_RE_MASK)
+ {
+ base->RSER &= ~SPI_RSER_TFFF_DIRS_MASK;
+ }
+ if (mask & SPI_RSER_RFDF_RE_MASK)
+ {
+ base->RSER &= ~SPI_RSER_RFDF_DIRS_MASK;
+ }
+ base->RSER |= mask;
+}
+
+/*Transactional APIs -- Master*/
+
+void DSPI_MasterTransferCreateHandle(SPI_Type *base,
+ dspi_master_handle_t *handle,
+ dspi_master_transfer_callback_t callback,
+ void *userData)
+{
+ assert(handle);
+
+ /* Zero the handle. */
+ memset(handle, 0, sizeof(*handle));
+
+ g_dspiHandle[DSPI_GetInstance(base)] = handle;
+
+ handle->callback = callback;
+ handle->userData = userData;
+}
+
+status_t DSPI_MasterTransferBlocking(SPI_Type *base, dspi_transfer_t *transfer)
+{
+ assert(transfer);
+
+ uint16_t wordToSend = 0;
+ uint16_t wordReceived = 0;
+ uint8_t dummyData = DSPI_DUMMY_DATA;
+ uint8_t bitsPerFrame;
+
+ uint32_t command;
+ uint32_t lastCommand;
+
+ uint8_t *txData;
+ uint8_t *rxData;
+ uint32_t remainingSendByteCount;
+ uint32_t remainingReceiveByteCount;
+
+ uint32_t fifoSize;
+ dspi_command_data_config_t commandStruct;
+
+ /* If the transfer count is zero, then return immediately.*/
+ if (transfer->dataSize == 0)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ DSPI_StopTransfer(base);
+ DSPI_DisableInterrupts(base, kDSPI_AllInterruptEnable);
+ DSPI_FlushFifo(base, true, true);
+ DSPI_ClearStatusFlags(base, kDSPI_AllStatusFlag);
+
+ /*Calculate the command and lastCommand*/
+ commandStruct.whichPcs =
+ (dspi_which_pcs_t)(1U << ((transfer->configFlags & DSPI_MASTER_PCS_MASK) >> DSPI_MASTER_PCS_SHIFT));
+ commandStruct.isEndOfQueue = false;
+ commandStruct.clearTransferCount = false;
+ commandStruct.whichCtar =
+ (dspi_ctar_selection_t)((transfer->configFlags & DSPI_MASTER_CTAR_MASK) >> DSPI_MASTER_CTAR_SHIFT);
+ commandStruct.isPcsContinuous = (bool)(transfer->configFlags & kDSPI_MasterPcsContinuous);
+
+ command = DSPI_MasterGetFormattedCommand(&(commandStruct));
+
+ commandStruct.isEndOfQueue = true;
+ commandStruct.isPcsContinuous = (bool)(transfer->configFlags & kDSPI_MasterActiveAfterTransfer);
+ lastCommand = DSPI_MasterGetFormattedCommand(&(commandStruct));
+
+ /*Calculate the bitsPerFrame*/
+ bitsPerFrame = ((base->CTAR[commandStruct.whichCtar] & SPI_CTAR_FMSZ_MASK) >> SPI_CTAR_FMSZ_SHIFT) + 1;
+
+ txData = transfer->txData;
+ rxData = transfer->rxData;
+ remainingSendByteCount = transfer->dataSize;
+ remainingReceiveByteCount = transfer->dataSize;
+
+ if ((base->MCR & SPI_MCR_DIS_RXF_MASK) || (base->MCR & SPI_MCR_DIS_TXF_MASK))
+ {
+ fifoSize = 1;
+ }
+ else
+ {
+ fifoSize = FSL_FEATURE_DSPI_FIFO_SIZEn(base);
+ }
+
+ DSPI_StartTransfer(base);
+
+ if (bitsPerFrame <= 8)
+ {
+ while (remainingSendByteCount > 0)
+ {
+ if (remainingSendByteCount == 1)
+ {
+ while (!(DSPI_GetStatusFlags(base) & kDSPI_TxFifoFillRequestFlag))
+ {
+ DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag);
+ }
+
+ if (txData != NULL)
+ {
+ base->PUSHR = (*txData) | (lastCommand);
+ txData++;
+ }
+ else
+ {
+ base->PUSHR = (lastCommand) | (dummyData);
+ }
+ DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag);
+ remainingSendByteCount--;
+
+ while (remainingReceiveByteCount > 0)
+ {
+ if (DSPI_GetStatusFlags(base) & kDSPI_RxFifoDrainRequestFlag)
+ {
+ if (rxData != NULL)
+ {
+ /* Read data from POPR*/
+ *(rxData) = DSPI_ReadData(base);
+ rxData++;
+ }
+ else
+ {
+ DSPI_ReadData(base);
+ }
+ remainingReceiveByteCount--;
+
+ DSPI_ClearStatusFlags(base, kDSPI_RxFifoDrainRequestFlag);
+ }
+ }
+ }
+ else
+ {
+ /*Wait until Tx Fifo is not full*/
+ while (!(DSPI_GetStatusFlags(base) & kDSPI_TxFifoFillRequestFlag))
+ {
+ DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag);
+ }
+ if (txData != NULL)
+ {
+ base->PUSHR = command | (uint16_t)(*txData);
+ txData++;
+ }
+ else
+ {
+ base->PUSHR = command | dummyData;
+ }
+ remainingSendByteCount--;
+
+ DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag);
+
+ while ((remainingReceiveByteCount - remainingSendByteCount) >= fifoSize)
+ {
+ if (DSPI_GetStatusFlags(base) & kDSPI_RxFifoDrainRequestFlag)
+ {
+ if (rxData != NULL)
+ {
+ *(rxData) = DSPI_ReadData(base);
+ rxData++;
+ }
+ else
+ {
+ DSPI_ReadData(base);
+ }
+ remainingReceiveByteCount--;
+
+ DSPI_ClearStatusFlags(base, kDSPI_RxFifoDrainRequestFlag);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ while (remainingSendByteCount > 0)
+ {
+ if (remainingSendByteCount <= 2)
+ {
+ while (!(DSPI_GetStatusFlags(base) & kDSPI_TxFifoFillRequestFlag))
+ {
+ DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag);
+ }
+
+ if (txData != NULL)
+ {
+ wordToSend = *(txData);
+ ++txData;
+
+ if (remainingSendByteCount > 1)
+ {
+ wordToSend |= (unsigned)(*(txData)) << 8U;
+ ++txData;
+ }
+ }
+ else
+ {
+ wordToSend = dummyData;
+ }
+
+ base->PUSHR = lastCommand | wordToSend;
+
+ DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag);
+ remainingSendByteCount = 0;
+
+ while (remainingReceiveByteCount > 0)
+ {
+ if (DSPI_GetStatusFlags(base) & kDSPI_RxFifoDrainRequestFlag)
+ {
+ wordReceived = DSPI_ReadData(base);
+
+ if (remainingReceiveByteCount != 1)
+ {
+ if (rxData != NULL)
+ {
+ *(rxData) = wordReceived;
+ ++rxData;
+ *(rxData) = wordReceived >> 8;
+ ++rxData;
+ }
+ remainingReceiveByteCount -= 2;
+ }
+ else
+ {
+ if (rxData != NULL)
+ {
+ *(rxData) = wordReceived;
+ ++rxData;
+ }
+ remainingReceiveByteCount--;
+ }
+ DSPI_ClearStatusFlags(base, kDSPI_RxFifoDrainRequestFlag);
+ }
+ }
+ }
+ else
+ {
+ /*Wait until Tx Fifo is not full*/
+ while (!(DSPI_GetStatusFlags(base) & kDSPI_TxFifoFillRequestFlag))
+ {
+ DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag);
+ }
+
+ if (txData != NULL)
+ {
+ wordToSend = *(txData);
+ ++txData;
+ wordToSend |= (unsigned)(*(txData)) << 8U;
+ ++txData;
+ }
+ else
+ {
+ wordToSend = dummyData;
+ }
+ base->PUSHR = command | wordToSend;
+ remainingSendByteCount -= 2;
+
+ DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag);
+
+ while (((remainingReceiveByteCount - remainingSendByteCount) / 2) >= fifoSize)
+ {
+ if (DSPI_GetStatusFlags(base) & kDSPI_RxFifoDrainRequestFlag)
+ {
+ wordReceived = DSPI_ReadData(base);
+
+ if (rxData != NULL)
+ {
+ *rxData = wordReceived;
+ ++rxData;
+ *rxData = wordReceived >> 8;
+ ++rxData;
+ }
+ remainingReceiveByteCount -= 2;
+
+ DSPI_ClearStatusFlags(base, kDSPI_RxFifoDrainRequestFlag);
+ }
+ }
+ }
+ }
+ }
+
+ return kStatus_Success;
+}
+
+static void DSPI_MasterTransferPrepare(SPI_Type *base, dspi_master_handle_t *handle, dspi_transfer_t *transfer)
+{
+ assert(handle);
+ assert(transfer);
+
+ dspi_command_data_config_t commandStruct;
+
+ DSPI_StopTransfer(base);
+ DSPI_FlushFifo(base, true, true);
+ DSPI_ClearStatusFlags(base, kDSPI_AllStatusFlag);
+
+ commandStruct.whichPcs =
+ (dspi_which_pcs_t)(1U << ((transfer->configFlags & DSPI_MASTER_PCS_MASK) >> DSPI_MASTER_PCS_SHIFT));
+ commandStruct.isEndOfQueue = false;
+ commandStruct.clearTransferCount = false;
+ commandStruct.whichCtar =
+ (dspi_ctar_selection_t)((transfer->configFlags & DSPI_MASTER_CTAR_MASK) >> DSPI_MASTER_CTAR_SHIFT);
+ commandStruct.isPcsContinuous = (bool)(transfer->configFlags & kDSPI_MasterPcsContinuous);
+ handle->command = DSPI_MasterGetFormattedCommand(&(commandStruct));
+
+ commandStruct.isEndOfQueue = true;
+ commandStruct.isPcsContinuous = (bool)(transfer->configFlags & kDSPI_MasterActiveAfterTransfer);
+ handle->lastCommand = DSPI_MasterGetFormattedCommand(&(commandStruct));
+
+ handle->bitsPerFrame = ((base->CTAR[commandStruct.whichCtar] & SPI_CTAR_FMSZ_MASK) >> SPI_CTAR_FMSZ_SHIFT) + 1;
+
+ if ((base->MCR & SPI_MCR_DIS_RXF_MASK) || (base->MCR & SPI_MCR_DIS_TXF_MASK))
+ {
+ handle->fifoSize = 1;
+ }
+ else
+ {
+ handle->fifoSize = FSL_FEATURE_DSPI_FIFO_SIZEn(base);
+ }
+ handle->txData = transfer->txData;
+ handle->rxData = transfer->rxData;
+ handle->remainingSendByteCount = transfer->dataSize;
+ handle->remainingReceiveByteCount = transfer->dataSize;
+ handle->totalByteCount = transfer->dataSize;
+}
+
+status_t DSPI_MasterTransferNonBlocking(SPI_Type *base, dspi_master_handle_t *handle, dspi_transfer_t *transfer)
+{
+ assert(handle);
+ assert(transfer);
+
+ /* If the transfer count is zero, then return immediately.*/
+ if (transfer->dataSize == 0)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Check that we're not busy.*/
+ if (handle->state == kDSPI_Busy)
+ {
+ return kStatus_DSPI_Busy;
+ }
+
+ handle->state = kDSPI_Busy;
+
+ DSPI_MasterTransferPrepare(base, handle, transfer);
+ DSPI_StartTransfer(base);
+
+ /* Enable the NVIC for DSPI peripheral. */
+ EnableIRQ(s_dspiIRQ[DSPI_GetInstance(base)]);
+
+ DSPI_MasterTransferFillUpTxFifo(base, handle);
+
+ /* RX FIFO Drain request: RFDF_RE to enable RFDF interrupt
+ * Since SPI is a synchronous interface, we only need to enable the RX interrupt.
+ * The IRQ handler will get the status of RX and TX interrupt flags.
+ */
+ s_dspiMasterIsr = DSPI_MasterTransferHandleIRQ;
+
+ DSPI_EnableInterrupts(base, kDSPI_RxFifoDrainRequestInterruptEnable);
+
+ return kStatus_Success;
+}
+
+status_t DSPI_MasterTransferGetCount(SPI_Type *base, dspi_master_handle_t *handle, size_t *count)
+{
+ assert(handle);
+
+ if (!count)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Catch when there is not an active transfer. */
+ if (handle->state != kDSPI_Busy)
+ {
+ *count = 0;
+ return kStatus_NoTransferInProgress;
+ }
+
+ *count = handle->totalByteCount - handle->remainingReceiveByteCount;
+ return kStatus_Success;
+}
+
+static void DSPI_MasterTransferComplete(SPI_Type *base, dspi_master_handle_t *handle)
+{
+ assert(handle);
+
+ /* Disable interrupt requests*/
+ DSPI_DisableInterrupts(base, kDSPI_RxFifoDrainRequestInterruptEnable | kDSPI_TxFifoFillRequestInterruptEnable);
+
+ status_t status = 0;
+ if (handle->state == kDSPI_Error)
+ {
+ status = kStatus_DSPI_Error;
+ }
+ else
+ {
+ status = kStatus_Success;
+ }
+
+ handle->state = kDSPI_Idle;
+
+ if (handle->callback)
+ {
+ handle->callback(base, handle, status, handle->userData);
+ }
+}
+
+static void DSPI_MasterTransferFillUpTxFifo(SPI_Type *base, dspi_master_handle_t *handle)
+{
+ assert(handle);
+
+ uint16_t wordToSend = 0;
+ uint8_t dummyData = DSPI_DUMMY_DATA;
+
+ /* If bits/frame is greater than one byte */
+ if (handle->bitsPerFrame > 8)
+ {
+ /* Fill the fifo until it is full or until the send word count is 0 or until the difference
+ * between the remainingReceiveByteCount and remainingSendByteCount equals the FIFO depth.
+ * The reason for checking the difference is to ensure we only send as much as the
+ * RX FIFO can receive.
+ * For this case where bitsPerFrame > 8, each entry in the FIFO contains 2 bytes of the
+ * send data, hence the difference between the remainingReceiveByteCount and
+ * remainingSendByteCount must be divided by 2 to convert this difference into a
+ * 16-bit (2 byte) value.
+ */
+ while ((DSPI_GetStatusFlags(base) & kDSPI_TxFifoFillRequestFlag) &&
+ ((handle->remainingReceiveByteCount - handle->remainingSendByteCount) / 2 < handle->fifoSize))
+ {
+ if (handle->remainingSendByteCount <= 2)
+ {
+ if (handle->txData)
+ {
+ if (handle->remainingSendByteCount == 1)
+ {
+ wordToSend = *(handle->txData);
+ }
+ else
+ {
+ wordToSend = *(handle->txData);
+ ++handle->txData; /* increment to next data byte */
+ wordToSend |= (unsigned)(*(handle->txData)) << 8U;
+ }
+ }
+ else
+ {
+ wordToSend = dummyData;
+ }
+ handle->remainingSendByteCount = 0;
+ base->PUSHR = handle->lastCommand | wordToSend;
+ }
+ /* For all words except the last word */
+ else
+ {
+ if (handle->txData)
+ {
+ wordToSend = *(handle->txData);
+ ++handle->txData; /* increment to next data byte */
+ wordToSend |= (unsigned)(*(handle->txData)) << 8U;
+ ++handle->txData; /* increment to next data byte */
+ }
+ else
+ {
+ wordToSend = dummyData;
+ }
+ handle->remainingSendByteCount -= 2; /* decrement remainingSendByteCount by 2 */
+ base->PUSHR = handle->command | wordToSend;
+ }
+
+ /* Try to clear the TFFF; if the TX FIFO is full this will clear */
+ DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag);
+
+ /* exit loop if send count is zero, else update local variables for next loop */
+ if (handle->remainingSendByteCount == 0)
+ {
+ break;
+ }
+ } /* End of TX FIFO fill while loop */
+ }
+ /* Optimized for bits/frame less than or equal to one byte. */
+ else
+ {
+ /* Fill the fifo until it is full or until the send word count is 0 or until the difference
+ * between the remainingReceiveByteCount and remainingSendByteCount equals the FIFO depth.
+ * The reason for checking the difference is to ensure we only send as much as the
+ * RX FIFO can receive.
+ */
+ while ((DSPI_GetStatusFlags(base) & kDSPI_TxFifoFillRequestFlag) &&
+ ((handle->remainingReceiveByteCount - handle->remainingSendByteCount) < handle->fifoSize))
+ {
+ if (handle->txData)
+ {
+ wordToSend = *(handle->txData);
+ ++handle->txData;
+ }
+ else
+ {
+ wordToSend = dummyData;
+ }
+
+ if (handle->remainingSendByteCount == 1)
+ {
+ base->PUSHR = handle->lastCommand | wordToSend;
+ }
+ else
+ {
+ base->PUSHR = handle->command | wordToSend;
+ }
+
+ /* Try to clear the TFFF; if the TX FIFO is full this will clear */
+ DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag);
+
+ --handle->remainingSendByteCount;
+
+ /* exit loop if send count is zero, else update local variables for next loop */
+ if (handle->remainingSendByteCount == 0)
+ {
+ break;
+ }
+ }
+ }
+}
+
+void DSPI_MasterTransferAbort(SPI_Type *base, dspi_master_handle_t *handle)
+{
+ assert(handle);
+
+ DSPI_StopTransfer(base);
+
+ /* Disable interrupt requests*/
+ DSPI_DisableInterrupts(base, kDSPI_RxFifoDrainRequestInterruptEnable | kDSPI_TxFifoFillRequestInterruptEnable);
+
+ handle->state = kDSPI_Idle;
+}
+
+void DSPI_MasterTransferHandleIRQ(SPI_Type *base, dspi_master_handle_t *handle)
+{
+ assert(handle);
+
+ /* RECEIVE IRQ handler: Check read buffer only if there are remaining bytes to read. */
+ if (handle->remainingReceiveByteCount)
+ {
+ /* Check read buffer.*/
+ uint16_t wordReceived; /* Maximum supported data bit length in master mode is 16-bits */
+
+ /* If bits/frame is greater than one byte */
+ if (handle->bitsPerFrame > 8)
+ {
+ while (DSPI_GetStatusFlags(base) & kDSPI_RxFifoDrainRequestFlag)
+ {
+ wordReceived = DSPI_ReadData(base);
+ /* clear the rx fifo drain request, needed for non-DMA applications as this flag
+ * will remain set even if the rx fifo is empty. By manually clearing this flag, it
+ * either remain clear if no more data is in the fifo, or it will set if there is
+ * more data in the fifo.
+ */
+ DSPI_ClearStatusFlags(base, kDSPI_RxFifoDrainRequestFlag);
+
+ /* Store read bytes into rx buffer only if a buffer pointer was provided */
+ if (handle->rxData)
+ {
+ /* For the last word received, if there is an extra byte due to the odd transfer
+ * byte count, only save the the last byte and discard the upper byte
+ */
+ if (handle->remainingReceiveByteCount == 1)
+ {
+ *handle->rxData = wordReceived; /* Write first data byte */
+ --handle->remainingReceiveByteCount;
+ }
+ else
+ {
+ *handle->rxData = wordReceived; /* Write first data byte */
+ ++handle->rxData; /* increment to next data byte */
+ *handle->rxData = wordReceived >> 8; /* Write second data byte */
+ ++handle->rxData; /* increment to next data byte */
+ handle->remainingReceiveByteCount -= 2;
+ }
+ }
+ else
+ {
+ if (handle->remainingReceiveByteCount == 1)
+ {
+ --handle->remainingReceiveByteCount;
+ }
+ else
+ {
+ handle->remainingReceiveByteCount -= 2;
+ }
+ }
+ if (handle->remainingReceiveByteCount == 0)
+ {
+ break;
+ }
+ } /* End of RX FIFO drain while loop */
+ }
+ /* Optimized for bits/frame less than or equal to one byte. */
+ else
+ {
+ while (DSPI_GetStatusFlags(base) & kDSPI_RxFifoDrainRequestFlag)
+ {
+ wordReceived = DSPI_ReadData(base);
+ /* clear the rx fifo drain request, needed for non-DMA applications as this flag
+ * will remain set even if the rx fifo is empty. By manually clearing this flag, it
+ * either remain clear if no more data is in the fifo, or it will set if there is
+ * more data in the fifo.
+ */
+ DSPI_ClearStatusFlags(base, kDSPI_RxFifoDrainRequestFlag);
+
+ /* Store read bytes into rx buffer only if a buffer pointer was provided */
+ if (handle->rxData)
+ {
+ *handle->rxData = wordReceived;
+ ++handle->rxData;
+ }
+
+ --handle->remainingReceiveByteCount;
+
+ if (handle->remainingReceiveByteCount == 0)
+ {
+ break;
+ }
+ } /* End of RX FIFO drain while loop */
+ }
+ }
+
+ /* Check write buffer. We always have to send a word in order to keep the transfer
+ * moving. So if the caller didn't provide a send buffer, we just send a zero.
+ */
+ if (handle->remainingSendByteCount)
+ {
+ DSPI_MasterTransferFillUpTxFifo(base, handle);
+ }
+
+ /* Check if we're done with this transfer.*/
+ if ((handle->remainingSendByteCount == 0) && (handle->remainingReceiveByteCount == 0))
+ {
+ /* Complete the transfer and disable the interrupts */
+ DSPI_MasterTransferComplete(base, handle);
+ }
+}
+
+/*Transactional APIs -- Slave*/
+void DSPI_SlaveTransferCreateHandle(SPI_Type *base,
+ dspi_slave_handle_t *handle,
+ dspi_slave_transfer_callback_t callback,
+ void *userData)
+{
+ assert(handle);
+
+ /* Zero the handle. */
+ memset(handle, 0, sizeof(*handle));
+
+ g_dspiHandle[DSPI_GetInstance(base)] = handle;
+
+ handle->callback = callback;
+ handle->userData = userData;
+}
+
+status_t DSPI_SlaveTransferNonBlocking(SPI_Type *base, dspi_slave_handle_t *handle, dspi_transfer_t *transfer)
+{
+ assert(handle);
+ assert(transfer);
+
+ /* If receive length is zero */
+ if (transfer->dataSize == 0)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* If both send buffer and receive buffer is null */
+ if ((!(transfer->txData)) && (!(transfer->rxData)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Check that we're not busy.*/
+ if (handle->state == kDSPI_Busy)
+ {
+ return kStatus_DSPI_Busy;
+ }
+ handle->state = kDSPI_Busy;
+
+ /* Enable the NVIC for DSPI peripheral. */
+ EnableIRQ(s_dspiIRQ[DSPI_GetInstance(base)]);
+
+ /* Store transfer information */
+ handle->txData = transfer->txData;
+ handle->rxData = transfer->rxData;
+ handle->remainingSendByteCount = transfer->dataSize;
+ handle->remainingReceiveByteCount = transfer->dataSize;
+ handle->totalByteCount = transfer->dataSize;
+
+ handle->errorCount = 0;
+
+ //uint8_t whichCtar = (transfer->configFlags & DSPI_SLAVE_CTAR_MASK) >> DSPI_SLAVE_CTAR_SHIFT;
+ handle->bitsPerFrame = 8;
+ //(((base->CTAR_SLAVE[whichCtar]) & SPI_CTAR_SLAVE_FMSZ_MASK) >> SPI_CTAR_SLAVE_FMSZ_SHIFT) + 1;
+
+ DSPI_StopTransfer(base);
+
+ DSPI_FlushFifo(base, true, true);
+ DSPI_ClearStatusFlags(base, kDSPI_AllStatusFlag);
+
+ DSPI_StartTransfer(base);
+
+ /* Prepare data to transmit */
+ DSPI_SlaveTransferFillUpTxFifo(base, handle);
+
+ s_dspiSlaveIsr = DSPI_SlaveTransferHandleIRQ;
+
+ /* Enable RX FIFO drain request, the slave only use this interrupt */
+ DSPI_EnableInterrupts(base, kDSPI_RxFifoDrainRequestInterruptEnable);
+
+ if (handle->rxData)
+ {
+ /* RX FIFO overflow request enable */
+ DSPI_EnableInterrupts(base, kDSPI_RxFifoOverflowInterruptEnable);
+ }
+ if (handle->txData)
+ {
+ /* TX FIFO underflow request enable */
+ DSPI_EnableInterrupts(base, kDSPI_TxFifoUnderflowInterruptEnable);
+ }
+
+ return kStatus_Success;
+}
+
+status_t DSPI_SlaveTransferGetCount(SPI_Type *base, dspi_slave_handle_t *handle, size_t *count)
+{
+ assert(handle);
+
+ if (!count)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Catch when there is not an active transfer. */
+ if (handle->state != kDSPI_Busy)
+ {
+ *count = 0;
+ return kStatus_NoTransferInProgress;
+ }
+
+ *count = handle->totalByteCount - handle->remainingReceiveByteCount;
+ return kStatus_Success;
+}
+
+static void DSPI_SlaveTransferFillUpTxFifo(SPI_Type *base, dspi_slave_handle_t *handle)
+{
+ assert(handle);
+
+ uint16_t transmitData = 0;
+ uint8_t dummyPattern = DSPI_DUMMY_DATA;
+
+ /* Service the transmitter, if transmit buffer provided, transmit the data,
+ * else transmit dummy pattern
+ */
+ while (DSPI_GetStatusFlags(base) & kDSPI_TxFifoFillRequestFlag)
+ {
+ /* Transmit data */
+ if (handle->remainingSendByteCount > 0)
+ {
+#if 0
+ /* Have data to transmit, update the transmit data and push to FIFO */
+ if (handle->bitsPerFrame <= 8)
+ {
+#endif
+ /* bits/frame is 1 byte */
+ if (handle->txData)
+ {
+ /* Update transmit data and transmit pointer */
+ transmitData = *handle->txData;
+ handle->txData++;
+ }
+ else
+ {
+ transmitData = dummyPattern;
+ }
+
+ /* Decrease remaining dataSize */
+ --handle->remainingSendByteCount;
+#if 0
+ }
+ /* bits/frame is 2 bytes */
+ else
+ {
+ /* With multibytes per frame transmission, the transmit frame contains data from
+ * transmit buffer until sent dataSize matches user request. Other bytes will set to
+ * dummy pattern value.
+ */
+ if (handle->txData)
+ {
+ /* Update first byte of transmit data and transmit pointer */
+ transmitData = *handle->txData;
+ handle->txData++;
+
+ if (handle->remainingSendByteCount == 1)
+ {
+ /* Decrease remaining dataSize */
+ --handle->remainingSendByteCount;
+ /* Update second byte of transmit data to second byte of dummy pattern */
+ transmitData = transmitData | (uint16_t)(((uint16_t)dummyPattern) << 8);
+ }
+ else
+ {
+ /* Update second byte of transmit data and transmit pointer */
+ transmitData = transmitData | (uint16_t)((uint16_t)(*handle->txData) << 8);
+ handle->txData++;
+ handle->remainingSendByteCount -= 2;
+ }
+ }
+ else
+ {
+ if (handle->remainingSendByteCount == 1)
+ {
+ --handle->remainingSendByteCount;
+ }
+ else
+ {
+ handle->remainingSendByteCount -= 2;
+ }
+ transmitData = (uint16_t)((uint16_t)(dummyPattern) << 8) | dummyPattern;
+ }
+ }
+#endif
+ }
+ else
+ {
+ break;
+ }
+
+ /* Write the data to the DSPI data register */
+ base->PUSHR_SLAVE = transmitData;
+
+ /* Try to clear TFFF by writing a one to it; it will not clear if TX FIFO not full */
+ DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag);
+ }
+}
+
+static void DSPI_SlaveTransferComplete(SPI_Type *base, dspi_slave_handle_t *handle)
+{
+ assert(handle);
+
+ /* Disable interrupt requests */
+ DSPI_DisableInterrupts(base, kDSPI_TxFifoUnderflowInterruptEnable | kDSPI_TxFifoFillRequestInterruptEnable |
+ kDSPI_RxFifoOverflowInterruptEnable | kDSPI_RxFifoDrainRequestInterruptEnable);
+
+ /* The transfer is complete. */
+ handle->txData = NULL;
+ handle->rxData = NULL;
+ handle->remainingReceiveByteCount = 0;
+ handle->remainingSendByteCount = 0;
+
+ status_t status = 0;
+ if (handle->state == kDSPI_Error)
+ {
+ status = kStatus_DSPI_Error;
+ }
+ else
+ {
+ status = kStatus_Success;
+ }
+
+ handle->state = kDSPI_Idle;
+
+ if (handle->callback)
+ {
+ handle->callback(base, handle, status, handle->userData);
+ }
+}
+
+void DSPI_SlaveTransferAbort(SPI_Type *base, dspi_slave_handle_t *handle)
+{
+ assert(handle);
+
+ DSPI_StopTransfer(base);
+
+ /* Disable interrupt requests */
+ DSPI_DisableInterrupts(base, kDSPI_TxFifoUnderflowInterruptEnable | kDSPI_TxFifoFillRequestInterruptEnable |
+ kDSPI_RxFifoOverflowInterruptEnable | kDSPI_RxFifoDrainRequestInterruptEnable);
+
+ handle->state = kDSPI_Idle;
+ handle->remainingSendByteCount = 0;
+ handle->remainingReceiveByteCount = 0;
+}
+
+void DSPI_SlaveTransferHandleIRQ(SPI_Type *base, dspi_slave_handle_t *handle)
+{
+ assert(handle);
+
+ volatile uint32_t dataReceived;
+// uint32_t dataSend = 0;
+
+ /* Because SPI protocol is synchronous, the number of bytes that that slave received from the
+ * master is the actual number of bytes that the slave transmitted to the master. So we only
+ * monitor the received dataSize to know when the transfer is complete.
+ */
+ if (handle->remainingReceiveByteCount > 0)
+ {
+ while (DSPI_GetStatusFlags(base) & kDSPI_RxFifoDrainRequestFlag)
+ {
+ /* Have received data in the buffer. */
+ dataReceived = base->POPR;
+ /*Clear the rx fifo drain request, needed for non-DMA applications as this flag
+ * will remain set even if the rx fifo is empty. By manually clearing this flag, it
+ * either remain clear if no more data is in the fifo, or it will set if there is
+ * more data in the fifo.
+ */
+ DSPI_ClearStatusFlags(base, kDSPI_RxFifoDrainRequestFlag);
+
+ /* If bits/frame is one byte */
+#if 0
+ if (handle->bitsPerFrame <= 8)
+ {
+#endif
+ if (handle->rxData)
+ {
+ if ((handle->totalByteCount - handle->remainingReceiveByteCount) == 2){
+
+ if ( *(handle->rxData - 2) == APALIS_TK1_K20_BULK_WRITE_INST) {
+ handle->remainingReceiveByteCount += dataReceived;
+ handle->totalByteCount += dataReceived;
+ handle->remainingSendByteCount += dataReceived;
+ }
+ }
+ /* Receive buffer is not null, store data into it */
+ *handle->rxData = dataReceived;
+ ++handle->rxData;
+
+ if (handle->remainingSendByteCount == 0){
+ if ( *(handle->rxData - 2) == APALIS_TK1_K20_READ_INST)
+ {
+ base->PUSHR_SLAVE = registers[dataReceived];
+ switch (dataReceived)
+ {
+ case APALIS_TK1_K20_IRQREG:
+ registers[APALIS_TK1_K20_IRQREG] = 0;
+ break;
+ case APALIS_TK1_K20_CANERR:
+ registers[APALIS_TK1_K20_CANERR] = 0x00;
+ case APALIS_TK1_K20_CANERR + APALIS_TK1_K20_CAN_OFFSET:
+ registers[APALIS_TK1_K20_CANERR
+ + APALIS_TK1_K20_CAN_OFFSET] = 0x00;
+ }
+ }
+ else
+ {
+ if ( *(handle->rxData - 1) == APALIS_TK1_K20_READ_INST)
+ {
+ base->PUSHR_SLAVE = 0x55;
+ }
+ }
+ }
+ }
+
+ /* Decrease remaining receive byte count */
+ --handle->remainingReceiveByteCount;
+#ifndef SPI_DMA
+ if (handle->remainingSendByteCount > 0)
+ {
+ if (handle->txData)
+ {
+ dataSend = *handle->txData;
+ ++handle->txData;
+ }
+ else
+ {
+ dataSend = 0x44;
+ }
+
+ --handle->remainingSendByteCount;
+ /* Write the data to the DSPI data register */
+ base->PUSHR_SLAVE = dataSend;
+ }
+#endif
+#if 0
+ }
+ else /* If bits/frame is 2 bytes */
+ {
+ /* With multibytes frame receiving, we only receive till the received dataSize
+ * matches user request. Other bytes will be ignored.
+ */
+ if (handle->rxData)
+ {
+ /* Receive buffer is not null, store first byte into it */
+ *handle->rxData = dataReceived;
+ ++handle->rxData;
+
+ if (handle->remainingReceiveByteCount == 1)
+ {
+ /* Decrease remaining receive byte count */
+ --handle->remainingReceiveByteCount;
+ }
+ else
+ {
+ /* Receive buffer is not null, store second byte into it */
+ *handle->rxData = dataReceived >> 8;
+ ++handle->rxData;
+ handle->remainingReceiveByteCount -= 2;
+ }
+ }
+ /* If no handle->rxData*/
+ else
+ {
+ if (handle->remainingReceiveByteCount == 1)
+ {
+ /* Decrease remaining receive byte count */
+ --handle->remainingReceiveByteCount;
+ }
+ else
+ {
+ handle->remainingReceiveByteCount -= 2;
+ }
+ }
+
+ if (handle->remainingSendByteCount > 0)
+ {
+ if (handle->txData)
+ {
+ dataSend = *handle->txData;
+ ++handle->txData;
+
+ if (handle->remainingSendByteCount == 1)
+ {
+ --handle->remainingSendByteCount;
+ dataSend |= (uint16_t)((uint16_t)(dummyPattern) << 8);
+ }
+ else
+ {
+ dataSend |= (uint32_t)(*handle->txData) << 8;
+ ++handle->txData;
+ handle->remainingSendByteCount -= 2;
+ }
+ }
+ /* If no handle->txData*/
+ else
+ {
+ if (handle->remainingSendByteCount == 1)
+ {
+ --handle->remainingSendByteCount;
+ }
+ else
+ {
+ handle->remainingSendByteCount -= 2;
+ }
+ dataSend = (uint16_t)((uint16_t)(dummyPattern) << 8) | dummyPattern;
+ }
+ /* Write the data to the DSPI data register */
+ base->PUSHR_SLAVE = dataSend;
+ }
+ }
+#endif
+ /* Try to clear TFFF by writing a one to it; it will not clear if TX FIFO not full */
+ DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag);
+
+ if (handle->remainingReceiveByteCount == 0)
+ {
+ break;
+ }
+ }
+ }
+ /* Check if remaining receive byte count matches user request */
+ if ((handle->remainingReceiveByteCount == 0) || (handle->state == kDSPI_Error))
+ {
+ /* Other cases, stop the transfer. */
+ DSPI_SlaveTransferComplete(base, handle);
+ return;
+ }
+
+ /* Catch tx fifo underflow conditions, service only if tx under flow interrupt enabled */
+ if ((DSPI_GetStatusFlags(base) & kDSPI_TxFifoUnderflowFlag) && (base->RSER & SPI_RSER_TFUF_RE_MASK))
+ {
+ DSPI_ClearStatusFlags(base, kDSPI_TxFifoUnderflowFlag);
+ /* Change state to error and clear flag */
+ if (handle->txData)
+ {
+ handle->state = kDSPI_Error;
+ }
+ handle->errorCount++;
+ }
+ /* Catch rx fifo overflow conditions, service only if rx over flow interrupt enabled */
+ if ((DSPI_GetStatusFlags(base) & kDSPI_RxFifoOverflowFlag) && (base->RSER & SPI_RSER_RFOF_RE_MASK))
+ {
+ DSPI_ClearStatusFlags(base, kDSPI_RxFifoOverflowFlag);
+ /* Change state to error and clear flag */
+ if (handle->txData)
+ {
+ handle->state = kDSPI_Error;
+ }
+ handle->errorCount++;
+ }
+}
+
+static void DSPI_CommonIRQHandler(SPI_Type *base, void *param)
+{
+ if (DSPI_IsMaster(base))
+ {
+ s_dspiMasterIsr(base, (dspi_master_handle_t *)param);
+ }
+ else
+ {
+ s_dspiSlaveIsr(base, (dspi_slave_handle_t *)param);
+ }
+}
+
+#if defined(SPI0)
+void SPI0_DriverIRQHandler(void)
+{
+ assert(g_dspiHandle[0]);
+ DSPI_CommonIRQHandler(SPI0, g_dspiHandle[0]);
+}
+#endif
+
+#if defined(SPI1)
+void SPI1_DriverIRQHandler(void)
+{
+ assert(g_dspiHandle[1]);
+ DSPI_CommonIRQHandler(SPI1, g_dspiHandle[1]);
+}
+#endif
+
+#if defined(SPI2)
+void SPI2_DriverIRQHandler(void)
+{
+ assert(g_dspiHandle[2]);
+ DSPI_CommonIRQHandler(SPI2, g_dspiHandle[2]);
+}
+#endif
+
+#if defined(SPI3)
+void SPI3_DriverIRQHandler(void)
+{
+ assert(g_dspiHandle[3]);
+ DSPI_CommonIRQHandler(SPI3, g_dspiHandle[3]);
+}
+#endif
+
+#if defined(SPI4)
+void SPI4_DriverIRQHandler(void)
+{
+ assert(g_dspiHandle[4]);
+ DSPI_CommonIRQHandler(SPI4, g_dspiHandle[4]);
+}
+#endif
+
+#if defined(SPI5)
+void SPI5_DriverIRQHandler(void)
+{
+ assert(g_dspiHandle[5]);
+ DSPI_CommonIRQHandler(SPI5, g_dspiHandle[5]);
+}
+#endif
+
+#if (FSL_FEATURE_SOC_DSPI_COUNT > 6)
+#error "Should write the SPIx_DriverIRQHandler function that instance greater than 5 !"
+#endif
diff --git a/drivers/src/fsl_dspi_edma.c b/drivers/src/fsl_dspi_edma.c
new file mode 100644
index 0000000..2b91cdc
--- /dev/null
+++ b/drivers/src/fsl_dspi_edma.c
@@ -0,0 +1,1273 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsl_dspi_edma.h"
+
+/***********************************************************************************************************************
+* Definitons
+***********************************************************************************************************************/
+
+/*!
+* @brief Structure definition for dspi_master_edma_private_handle_t. The structure is private.
+*/
+typedef struct _dspi_master_edma_private_handle
+{
+ SPI_Type *base; /*!< DSPI peripheral base address. */
+ dspi_master_edma_handle_t *handle; /*!< dspi_master_edma_handle_t handle */
+} dspi_master_edma_private_handle_t;
+
+/*!
+* @brief Structure definition for dspi_slave_edma_private_handle_t. The structure is private.
+*/
+typedef struct _dspi_slave_edma_private_handle
+{
+ SPI_Type *base; /*!< DSPI peripheral base address. */
+ dspi_slave_edma_handle_t *handle; /*!< dspi_master_edma_handle_t handle */
+} dspi_slave_edma_private_handle_t;
+
+/***********************************************************************************************************************
+* Prototypes
+***********************************************************************************************************************/
+/*!
+* @brief EDMA_DspiMasterCallback after the DSPI master transfer completed by using EDMA.
+* This is not a public API.
+*/
+static void EDMA_DspiMasterCallback(edma_handle_t *edmaHandle,
+ void *g_dspiEdmaPrivateHandle,
+ bool transferDone,
+ uint32_t tcds);
+
+/*!
+* @brief EDMA_DspiSlaveCallback after the DSPI slave transfer completed by using EDMA.
+* This is not a public API.
+*/
+static void EDMA_DspiSlaveCallback(edma_handle_t *edmaHandle,
+ void *g_dspiEdmaPrivateHandle,
+ bool transferDone,
+ uint32_t tcds);
+/*!
+* @brief Get instance number for DSPI module.
+*
+* This is not a public API and it's extern from fsl_dspi.c.
+*
+* @param base DSPI peripheral base address
+*/
+extern uint32_t DSPI_GetInstance(SPI_Type *base);
+
+/***********************************************************************************************************************
+* Variables
+***********************************************************************************************************************/
+
+/*! @brief Pointers to dspi edma handles for each instance. */
+static dspi_master_edma_private_handle_t s_dspiMasterEdmaPrivateHandle[FSL_FEATURE_SOC_DSPI_COUNT];
+static dspi_slave_edma_private_handle_t s_dspiSlaveEdmaPrivateHandle[FSL_FEATURE_SOC_DSPI_COUNT];
+
+/***********************************************************************************************************************
+* Code
+***********************************************************************************************************************/
+
+void DSPI_MasterTransferCreateHandleEDMA(SPI_Type *base,
+ dspi_master_edma_handle_t *handle,
+ dspi_master_edma_transfer_callback_t callback,
+ void *userData,
+ edma_handle_t *edmaRxRegToRxDataHandle,
+ edma_handle_t *edmaTxDataToIntermediaryHandle,
+ edma_handle_t *edmaIntermediaryToTxRegHandle)
+{
+ assert(handle);
+ assert(edmaRxRegToRxDataHandle);
+ assert(edmaTxDataToIntermediaryHandle);
+ assert(edmaIntermediaryToTxRegHandle);
+
+ /* Zero the handle. */
+ memset(handle, 0, sizeof(*handle));
+
+ uint32_t instance = DSPI_GetInstance(base);
+
+ s_dspiMasterEdmaPrivateHandle[instance].base = base;
+ s_dspiMasterEdmaPrivateHandle[instance].handle = handle;
+
+ handle->callback = callback;
+ handle->userData = userData;
+
+ handle->edmaRxRegToRxDataHandle = edmaRxRegToRxDataHandle;
+ handle->edmaTxDataToIntermediaryHandle = edmaTxDataToIntermediaryHandle;
+ handle->edmaIntermediaryToTxRegHandle = edmaIntermediaryToTxRegHandle;
+}
+
+status_t DSPI_MasterTransferEDMA(SPI_Type *base, dspi_master_edma_handle_t *handle, dspi_transfer_t *transfer)
+{
+ assert(handle);
+ assert(transfer);
+
+ /* If the transfer count is zero, then return immediately.*/
+ if (transfer->dataSize == 0)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* If both send buffer and receive buffer is null */
+ if ((!(transfer->txData)) && (!(transfer->rxData)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Check that we're not busy.*/
+ if (handle->state == kDSPI_Busy)
+ {
+ return kStatus_DSPI_Busy;
+ }
+
+ handle->state = kDSPI_Busy;
+
+ uint32_t instance = DSPI_GetInstance(base);
+ uint16_t wordToSend = 0;
+ uint8_t dummyData = DSPI_DUMMY_DATA;
+ uint8_t dataAlreadyFed = 0;
+ uint8_t dataFedMax = 2;
+
+ uint32_t rxAddr = DSPI_GetRxRegisterAddress(base);
+ uint32_t txAddr = DSPI_MasterGetTxRegisterAddress(base);
+
+ edma_tcd_t *softwareTCD = (edma_tcd_t *)((uint32_t)(&handle->dspiSoftwareTCD[1]) & (~0x1FU));
+
+ edma_transfer_config_t transferConfigA;
+ edma_transfer_config_t transferConfigB;
+ edma_transfer_config_t transferConfigC;
+
+ handle->txBuffIfNull = ((uint32_t)DSPI_DUMMY_DATA << 8) | DSPI_DUMMY_DATA;
+
+ dspi_command_data_config_t commandStruct;
+ DSPI_StopTransfer(base);
+ DSPI_FlushFifo(base, true, true);
+ DSPI_ClearStatusFlags(base, kDSPI_AllStatusFlag);
+
+ commandStruct.whichPcs =
+ (dspi_which_pcs_t)(1U << ((transfer->configFlags & DSPI_MASTER_PCS_MASK) >> DSPI_MASTER_PCS_SHIFT));
+ commandStruct.isEndOfQueue = false;
+ commandStruct.clearTransferCount = false;
+ commandStruct.whichCtar =
+ (dspi_ctar_selection_t)((transfer->configFlags & DSPI_MASTER_CTAR_MASK) >> DSPI_MASTER_CTAR_SHIFT);
+ commandStruct.isPcsContinuous = (bool)(transfer->configFlags & kDSPI_MasterPcsContinuous);
+ handle->command = DSPI_MasterGetFormattedCommand(&(commandStruct));
+
+ commandStruct.isEndOfQueue = true;
+ commandStruct.isPcsContinuous = (bool)(transfer->configFlags & kDSPI_MasterActiveAfterTransfer);
+ handle->lastCommand = DSPI_MasterGetFormattedCommand(&(commandStruct));
+
+ handle->bitsPerFrame = ((base->CTAR[commandStruct.whichCtar] & SPI_CTAR_FMSZ_MASK) >> SPI_CTAR_FMSZ_SHIFT) + 1;
+
+ if ((base->MCR & SPI_MCR_DIS_RXF_MASK) || (base->MCR & SPI_MCR_DIS_TXF_MASK))
+ {
+ handle->fifoSize = 1;
+ }
+ else
+ {
+ handle->fifoSize = FSL_FEATURE_DSPI_FIFO_SIZEn(base);
+ }
+ handle->txData = transfer->txData;
+ handle->rxData = transfer->rxData;
+ handle->remainingSendByteCount = transfer->dataSize;
+ handle->remainingReceiveByteCount = transfer->dataSize;
+ handle->totalByteCount = transfer->dataSize;
+
+ /* If using a shared RX/TX DMA request, then this limits the amount of data we can transfer
+ * due to the linked channel. The max bytes is 511 if 8-bit/frame or 1022 if 16-bit/frame
+ */
+ uint32_t limited_size = 0;
+ if (1 == FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base))
+ {
+ limited_size = 32767u;
+ }
+ else
+ {
+ limited_size = 511u;
+ }
+
+ if (handle->bitsPerFrame > 8)
+ {
+ if (transfer->dataSize > (limited_size << 1u))
+ {
+ handle->state = kDSPI_Idle;
+ return kStatus_DSPI_OutOfRange;
+ }
+ }
+ else
+ {
+ if (transfer->dataSize > limited_size)
+ {
+ handle->state = kDSPI_Idle;
+ return kStatus_DSPI_OutOfRange;
+ }
+ }
+
+ /*The data size should be even if the bitsPerFrame is greater than 8 (that is 2 bytes per frame in dspi) */
+ if ((handle->bitsPerFrame > 8) && (transfer->dataSize & 0x1))
+ {
+ handle->state = kDSPI_Idle;
+ return kStatus_InvalidArgument;
+ }
+
+ DSPI_DisableDMA(base, kDSPI_RxDmaEnable | kDSPI_TxDmaEnable);
+
+ EDMA_SetCallback(handle->edmaRxRegToRxDataHandle, EDMA_DspiMasterCallback,
+ &s_dspiMasterEdmaPrivateHandle[instance]);
+
+ /*
+ (1)For DSPI instances with shared RX/TX DMA requests: Rx DMA request -> channel_A -> channel_B-> channel_C.
+ channel_A minor link to channel_B , channel_B minor link to channel_C.
+
+ Already pushed 1 or 2 data in SPI_PUSHR , then start the DMA tansfer.
+ channel_A:SPI_POPR to rxData,
+ channel_B:next txData to handle->command (low 16 bits),
+ channel_C:handle->command (32 bits) to SPI_PUSHR, and use the scatter/gather to transfer the last data
+ (handle->lastCommand to SPI_PUSHR).
+
+ (2)For DSPI instances with separate RX and TX DMA requests:
+ Rx DMA request -> channel_A
+ Tx DMA request -> channel_C -> channel_B .
+ channel_C major link to channel_B.
+ So need prepare the first data in "intermediary" before the DMA
+ transfer and then channel_B is used to prepare the next data to "intermediary"
+
+ channel_A:SPI_POPR to rxData,
+ channel_C: handle->command (32 bits) to SPI_PUSHR,
+ channel_B: next txData to handle->command (low 16 bits), and use the scatter/gather to prepare the last data
+ (handle->lastCommand to handle->Command).
+ */
+
+ /*If dspi has separate dma request , prepare the first data in "intermediary" .
+ else (dspi has shared dma request) , send first 2 data if there is fifo or send first 1 data if there is no fifo*/
+ if (1 == FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base))
+ {
+ /* For DSPI instances with separate RX/TX DMA requests, we'll use the TX DMA request to
+ * trigger the TX DMA channel and RX DMA request to trigger the RX DMA channel
+ */
+
+ /*Prepare the firt data*/
+ if (handle->bitsPerFrame > 8)
+ {
+ /* If it's the last word */
+ if (handle->remainingSendByteCount <= 2)
+ {
+ if (handle->txData)
+ {
+ wordToSend = *(handle->txData);
+ ++handle->txData; /* increment to next data byte */
+ wordToSend |= (unsigned)(*(handle->txData)) << 8U;
+ }
+ else
+ {
+ wordToSend = ((uint32_t)dummyData << 8) | dummyData;
+ }
+ handle->lastCommand = (handle->lastCommand & 0xffff0000U) | wordToSend;
+ handle->command = handle->lastCommand;
+ }
+ else /* For all words except the last word , frame > 8bits */
+ {
+ if (handle->txData)
+ {
+ wordToSend = *(handle->txData);
+ ++handle->txData; /* increment to next data byte */
+ wordToSend |= (unsigned)(*(handle->txData)) << 8U;
+ ++handle->txData; /* increment to next data byte */
+ }
+ else
+ {
+ wordToSend = ((uint32_t)dummyData << 8) | dummyData;
+ }
+ handle->command = (handle->command & 0xffff0000U) | wordToSend;
+ }
+ }
+ else /* Optimized for bits/frame less than or equal to one byte. */
+ {
+ if (handle->txData)
+ {
+ wordToSend = *(handle->txData);
+ ++handle->txData; /* increment to next data word*/
+ }
+ else
+ {
+ wordToSend = dummyData;
+ }
+
+ if (handle->remainingSendByteCount == 1)
+ {
+ handle->lastCommand = (handle->lastCommand & 0xffff0000U) | wordToSend;
+ handle->command = handle->lastCommand;
+ }
+ else
+ {
+ handle->command = (handle->command & 0xffff0000U) | wordToSend;
+ }
+ }
+ }
+
+ else /*dspi has shared dma request*/
+
+ {
+ /* For DSPI instances with shared RX/TX DMA requests, we'll use the RX DMA request to
+ * trigger ongoing transfers and will link to the TX DMA channel from the RX DMA channel.
+ */
+
+ /* If bits/frame is greater than one byte */
+ if (handle->bitsPerFrame > 8)
+ {
+ while (DSPI_GetStatusFlags(base) & kDSPI_TxFifoFillRequestFlag)
+ {
+ if (handle->remainingSendByteCount <= 2)
+ {
+ if (handle->txData)
+ {
+ wordToSend = *(handle->txData);
+ ++handle->txData;
+ wordToSend |= (unsigned)(*(handle->txData)) << 8U;
+ }
+ else
+ {
+ wordToSend = ((uint32_t)dummyData << 8) | dummyData;
+ }
+ handle->remainingSendByteCount = 0;
+ base->PUSHR = (handle->lastCommand & 0xffff0000U) | wordToSend;
+ }
+ /* For all words except the last word */
+ else
+ {
+ if (handle->txData)
+ {
+ wordToSend = *(handle->txData);
+ ++handle->txData;
+ wordToSend |= (unsigned)(*(handle->txData)) << 8U;
+ ++handle->txData;
+ }
+ else
+ {
+ wordToSend = ((uint32_t)dummyData << 8) | dummyData;
+ }
+ handle->remainingSendByteCount -= 2;
+ base->PUSHR = (handle->command & 0xffff0000U) | wordToSend;
+ }
+
+ /* Try to clear the TFFF; if the TX FIFO is full this will clear */
+ DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag);
+
+ dataAlreadyFed += 2;
+
+ /* exit loop if send count is zero, else update local variables for next loop */
+ if ((handle->remainingSendByteCount == 0) || (dataAlreadyFed == (dataFedMax * 2)))
+ {
+ break;
+ }
+ } /* End of TX FIFO fill while loop */
+ }
+ else /* Optimized for bits/frame less than or equal to one byte. */
+ {
+ while (DSPI_GetStatusFlags(base) & kDSPI_TxFifoFillRequestFlag)
+ {
+ if (handle->txData)
+ {
+ wordToSend = *(handle->txData);
+ ++handle->txData;
+ }
+ else
+ {
+ wordToSend = dummyData;
+ }
+
+ if (handle->remainingSendByteCount == 1)
+ {
+ base->PUSHR = (handle->lastCommand & 0xffff0000U) | wordToSend;
+ }
+ else
+ {
+ base->PUSHR = (handle->command & 0xffff0000U) | wordToSend;
+ }
+
+ /* Try to clear the TFFF; if the TX FIFO is full this will clear */
+ DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag);
+
+ --handle->remainingSendByteCount;
+
+ dataAlreadyFed++;
+
+ /* exit loop if send count is zero, else update local variables for next loop */
+ if ((handle->remainingSendByteCount == 0) || (dataAlreadyFed == dataFedMax))
+ {
+ break;
+ }
+ } /* End of TX FIFO fill while loop */
+ }
+ }
+
+ /***channel_A *** used for carry the data from Rx_Data_Register(POPR) to User_Receive_Buffer(rxData)*/
+ EDMA_ResetChannel(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel);
+
+ transferConfigA.srcAddr = (uint32_t)rxAddr;
+ transferConfigA.srcOffset = 0;
+
+ if (handle->rxData)
+ {
+ transferConfigA.destAddr = (uint32_t) & (handle->rxData[0]);
+ transferConfigA.destOffset = 1;
+ }
+ else
+ {
+ transferConfigA.destAddr = (uint32_t) & (handle->rxBuffIfNull);
+ transferConfigA.destOffset = 0;
+ }
+
+ transferConfigA.destTransferSize = kEDMA_TransferSize1Bytes;
+
+ if (handle->bitsPerFrame <= 8)
+ {
+ transferConfigA.srcTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfigA.minorLoopBytes = 1;
+ transferConfigA.majorLoopCounts = handle->remainingReceiveByteCount;
+ }
+ else
+ {
+ transferConfigA.srcTransferSize = kEDMA_TransferSize2Bytes;
+ transferConfigA.minorLoopBytes = 2;
+ transferConfigA.majorLoopCounts = handle->remainingReceiveByteCount / 2;
+ }
+
+ /* Store the initially configured eDMA minor byte transfer count into the DSPI handle */
+ handle->nbytes = transferConfigA.minorLoopBytes;
+
+ EDMA_SetTransferConfig(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
+ &transferConfigA, NULL);
+ EDMA_EnableChannelInterrupts(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
+ kEDMA_MajorInterruptEnable);
+
+ /***channel_B *** used for carry the data from User_Send_Buffer to "intermediary" because the SPIx_PUSHR should
+ write the 32bits at once time . Then use channel_C to carry the "intermediary" to SPIx_PUSHR. Note that the
+ SPIx_PUSHR upper 16 bits are the "command" and the low 16bits are data */
+
+ EDMA_ResetChannel(handle->edmaTxDataToIntermediaryHandle->base, handle->edmaTxDataToIntermediaryHandle->channel);
+
+ /*Calculate the last data : handle->lastCommand*/
+ if (((handle->remainingSendByteCount > 0) && (1 != FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base))) ||
+ ((((handle->remainingSendByteCount > 1) && (handle->bitsPerFrame <= 8)) ||
+ ((handle->remainingSendByteCount > 2) && (handle->bitsPerFrame > 8))) &&
+ (1 == FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base))))
+ {
+ if (handle->txData)
+ {
+ uint32_t bufferIndex = 0;
+
+ if (1 == FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base))
+ {
+ if (handle->bitsPerFrame <= 8)
+ {
+ bufferIndex = handle->remainingSendByteCount - 1;
+ }
+ else
+ {
+ bufferIndex = handle->remainingSendByteCount - 2;
+ }
+ }
+ else
+ {
+ bufferIndex = handle->remainingSendByteCount;
+ }
+
+ if (handle->bitsPerFrame <= 8)
+ {
+ handle->lastCommand = (handle->lastCommand & 0xffff0000U) | handle->txData[bufferIndex - 1];
+ }
+ else
+ {
+ handle->lastCommand = (handle->lastCommand & 0xffff0000U) |
+ ((uint32_t)handle->txData[bufferIndex - 1] << 8) |
+ handle->txData[bufferIndex - 2];
+ }
+ }
+ else
+ {
+ if (handle->bitsPerFrame <= 8)
+ {
+ wordToSend = dummyData;
+ }
+ else
+ {
+ wordToSend = ((uint32_t)dummyData << 8) | dummyData;
+ }
+ handle->lastCommand = (handle->lastCommand & 0xffff0000U) | wordToSend;
+ }
+ }
+
+ /*For DSPI instances with separate RX and TX DMA requests: use the scatter/gather to prepare the last data
+ * (handle->lastCommand) to handle->Command*/
+ if (1 == FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base))
+ {
+ transferConfigB.srcAddr = (uint32_t) & (handle->lastCommand);
+ transferConfigB.destAddr = (uint32_t) & (handle->command);
+ transferConfigB.srcTransferSize = kEDMA_TransferSize4Bytes;
+ transferConfigB.destTransferSize = kEDMA_TransferSize4Bytes;
+ transferConfigB.srcOffset = 0;
+ transferConfigB.destOffset = 0;
+ transferConfigB.minorLoopBytes = 4;
+ transferConfigB.majorLoopCounts = 1;
+
+ EDMA_TcdReset(softwareTCD);
+ EDMA_TcdSetTransferConfig(softwareTCD, &transferConfigB, NULL);
+ }
+
+ /*User_Send_Buffer(txData) to intermediary(handle->command)*/
+ if (((((handle->remainingSendByteCount > 2) && (handle->bitsPerFrame <= 8)) ||
+ ((handle->remainingSendByteCount > 4) && (handle->bitsPerFrame > 8))) &&
+ (1 == FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base))) ||
+ (1 != FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base)))
+ {
+ if (handle->txData)
+ {
+ transferConfigB.srcAddr = (uint32_t)(handle->txData);
+ transferConfigB.srcOffset = 1;
+ }
+ else
+ {
+ transferConfigB.srcAddr = (uint32_t)(&handle->txBuffIfNull);
+ transferConfigB.srcOffset = 0;
+ }
+
+ transferConfigB.destAddr = (uint32_t)(&handle->command);
+ transferConfigB.destOffset = 0;
+
+ transferConfigB.srcTransferSize = kEDMA_TransferSize1Bytes;
+
+ if (handle->bitsPerFrame <= 8)
+ {
+ transferConfigB.destTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfigB.minorLoopBytes = 1;
+
+ if (1 == FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base))
+ {
+ transferConfigB.majorLoopCounts = handle->remainingSendByteCount - 2;
+ }
+ else
+ {
+ /*Only enable channel_B minorlink to channel_C , so need to add one count due to the last time is
+ majorlink , the majorlink would not trigger the channel_C*/
+ transferConfigB.majorLoopCounts = handle->remainingSendByteCount + 1;
+ }
+ }
+ else
+ {
+ transferConfigB.destTransferSize = kEDMA_TransferSize2Bytes;
+ transferConfigB.minorLoopBytes = 2;
+ if (1 == FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base))
+ {
+ transferConfigB.majorLoopCounts = handle->remainingSendByteCount / 2 - 2;
+ }
+ else
+ {
+ /*Only enable channel_B minorlink to channel_C , so need to add one count due to the last time is
+ * majorlink*/
+ transferConfigB.majorLoopCounts = handle->remainingSendByteCount / 2 + 1;
+ }
+ }
+
+ if (1 == FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base))
+ {
+ EDMA_SetTransferConfig(handle->edmaTxDataToIntermediaryHandle->base,
+ handle->edmaTxDataToIntermediaryHandle->channel, &transferConfigB, softwareTCD);
+ EDMA_EnableAutoStopRequest(handle->edmaIntermediaryToTxRegHandle->base,
+ handle->edmaIntermediaryToTxRegHandle->channel, false);
+ }
+ else
+ {
+ EDMA_SetTransferConfig(handle->edmaTxDataToIntermediaryHandle->base,
+ handle->edmaTxDataToIntermediaryHandle->channel, &transferConfigB, NULL);
+ }
+ }
+ else
+ {
+ EDMA_SetTransferConfig(handle->edmaTxDataToIntermediaryHandle->base,
+ handle->edmaTxDataToIntermediaryHandle->channel, &transferConfigB, NULL);
+ }
+
+ /***channel_C ***carry the "intermediary" to SPIx_PUSHR. used the edma Scatter Gather function on channel_C to
+ handle the last data */
+
+ EDMA_ResetChannel(handle->edmaIntermediaryToTxRegHandle->base, handle->edmaIntermediaryToTxRegHandle->channel);
+
+ /*For DSPI instances with shared RX/TX DMA requests: use the scatter/gather to prepare the last data
+ * (handle->lastCommand) to SPI_PUSHR*/
+ if (((1 != FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base)) && (handle->remainingSendByteCount > 0)))
+ {
+ transferConfigC.srcAddr = (uint32_t) & (handle->lastCommand);
+ transferConfigC.destAddr = (uint32_t)txAddr;
+ transferConfigC.srcTransferSize = kEDMA_TransferSize4Bytes;
+ transferConfigC.destTransferSize = kEDMA_TransferSize4Bytes;
+ transferConfigC.srcOffset = 0;
+ transferConfigC.destOffset = 0;
+ transferConfigC.minorLoopBytes = 4;
+ transferConfigC.majorLoopCounts = 1;
+
+ EDMA_TcdReset(softwareTCD);
+ EDMA_TcdSetTransferConfig(softwareTCD, &transferConfigC, NULL);
+ }
+
+ if (((handle->remainingSendByteCount > 1) && (handle->bitsPerFrame <= 8)) ||
+ ((handle->remainingSendByteCount > 2) && (handle->bitsPerFrame > 8)) ||
+ (1 == FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base)))
+ {
+ transferConfigC.srcAddr = (uint32_t)(&(handle->command));
+ transferConfigC.destAddr = (uint32_t)txAddr;
+
+ transferConfigC.srcTransferSize = kEDMA_TransferSize4Bytes;
+ transferConfigC.destTransferSize = kEDMA_TransferSize4Bytes;
+ transferConfigC.srcOffset = 0;
+ transferConfigC.destOffset = 0;
+ transferConfigC.minorLoopBytes = 4;
+ if (1 != FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base))
+ {
+ if (handle->bitsPerFrame <= 8)
+ {
+ transferConfigC.majorLoopCounts = handle->remainingSendByteCount - 1;
+ }
+ else
+ {
+ transferConfigC.majorLoopCounts = handle->remainingSendByteCount / 2 - 1;
+ }
+
+ EDMA_SetTransferConfig(handle->edmaIntermediaryToTxRegHandle->base,
+ handle->edmaIntermediaryToTxRegHandle->channel, &transferConfigC, softwareTCD);
+ }
+ else
+ {
+ transferConfigC.majorLoopCounts = 1;
+
+ EDMA_SetTransferConfig(handle->edmaIntermediaryToTxRegHandle->base,
+ handle->edmaIntermediaryToTxRegHandle->channel, &transferConfigC, NULL);
+ }
+
+ EDMA_EnableAutoStopRequest(handle->edmaIntermediaryToTxRegHandle->base,
+ handle->edmaIntermediaryToTxRegHandle->channel, false);
+ }
+ else
+ {
+ EDMA_SetTransferConfig(handle->edmaIntermediaryToTxRegHandle->base,
+ handle->edmaIntermediaryToTxRegHandle->channel, &transferConfigC, NULL);
+ }
+
+ /*Start the EDMA channel_A , channel_B , channel_C transfer*/
+ EDMA_StartTransfer(handle->edmaRxRegToRxDataHandle);
+ EDMA_StartTransfer(handle->edmaTxDataToIntermediaryHandle);
+ EDMA_StartTransfer(handle->edmaIntermediaryToTxRegHandle);
+
+ /*Set channel priority*/
+ uint8_t channelPriorityLow = handle->edmaRxRegToRxDataHandle->channel;
+ uint8_t channelPriorityMid = handle->edmaTxDataToIntermediaryHandle->channel;
+ uint8_t channelPriorityHigh = handle->edmaIntermediaryToTxRegHandle->channel;
+ uint8_t t = 0;
+ if (channelPriorityLow > channelPriorityMid)
+ {
+ t = channelPriorityLow;
+ channelPriorityLow = channelPriorityMid;
+ channelPriorityMid = t;
+ }
+
+ if (channelPriorityLow > channelPriorityHigh)
+ {
+ t = channelPriorityLow;
+ channelPriorityLow = channelPriorityHigh;
+ channelPriorityHigh = t;
+ }
+
+ if (channelPriorityMid > channelPriorityHigh)
+ {
+ t = channelPriorityMid;
+ channelPriorityMid = channelPriorityHigh;
+ channelPriorityHigh = t;
+ }
+ edma_channel_Preemption_config_t preemption_config_t;
+ preemption_config_t.enableChannelPreemption = true;
+ preemption_config_t.enablePreemptAbility = true;
+ preemption_config_t.channelPriority = channelPriorityLow;
+
+ if (1 != FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base))
+ {
+ EDMA_SetChannelPreemptionConfig(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
+ &preemption_config_t);
+
+ preemption_config_t.channelPriority = channelPriorityMid;
+ EDMA_SetChannelPreemptionConfig(handle->edmaTxDataToIntermediaryHandle->base,
+ handle->edmaTxDataToIntermediaryHandle->channel, &preemption_config_t);
+
+ preemption_config_t.channelPriority = channelPriorityHigh;
+ EDMA_SetChannelPreemptionConfig(handle->edmaIntermediaryToTxRegHandle->base,
+ handle->edmaIntermediaryToTxRegHandle->channel, &preemption_config_t);
+ }
+ else
+ {
+ EDMA_SetChannelPreemptionConfig(handle->edmaIntermediaryToTxRegHandle->base,
+ handle->edmaIntermediaryToTxRegHandle->channel, &preemption_config_t);
+
+ preemption_config_t.channelPriority = channelPriorityMid;
+ EDMA_SetChannelPreemptionConfig(handle->edmaTxDataToIntermediaryHandle->base,
+ handle->edmaTxDataToIntermediaryHandle->channel, &preemption_config_t);
+
+ preemption_config_t.channelPriority = channelPriorityHigh;
+ EDMA_SetChannelPreemptionConfig(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
+ &preemption_config_t);
+ }
+
+ /*Set the channel link.*/
+ if (1 == FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base))
+ {
+ /*if there is Tx DMA request , carry the 32bits data (handle->command) to PUSHR first , then link to channelB
+ to prepare the next 32bits data (txData to handle->command) */
+ if (handle->remainingSendByteCount > 1)
+ {
+ EDMA_SetChannelLink(handle->edmaIntermediaryToTxRegHandle->base,
+ handle->edmaIntermediaryToTxRegHandle->channel, kEDMA_MajorLink,
+ handle->edmaTxDataToIntermediaryHandle->channel);
+ }
+
+ DSPI_EnableDMA(base, kDSPI_RxDmaEnable | kDSPI_TxDmaEnable);
+ }
+ else
+ {
+ if (handle->remainingSendByteCount > 0)
+ {
+ EDMA_SetChannelLink(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
+ kEDMA_MinorLink, handle->edmaTxDataToIntermediaryHandle->channel);
+
+ EDMA_SetChannelLink(handle->edmaTxDataToIntermediaryHandle->base,
+ handle->edmaTxDataToIntermediaryHandle->channel, kEDMA_MinorLink,
+ handle->edmaIntermediaryToTxRegHandle->channel);
+ }
+
+ DSPI_EnableDMA(base, kDSPI_RxDmaEnable);
+ }
+
+ DSPI_StartTransfer(base);
+
+ return kStatus_Success;
+}
+
+static void EDMA_DspiMasterCallback(edma_handle_t *edmaHandle,
+ void *g_dspiEdmaPrivateHandle,
+ bool transferDone,
+ uint32_t tcds)
+{
+ assert(edmaHandle);
+ assert(g_dspiEdmaPrivateHandle);
+
+ dspi_master_edma_private_handle_t *dspiEdmaPrivateHandle;
+
+ dspiEdmaPrivateHandle = (dspi_master_edma_private_handle_t *)g_dspiEdmaPrivateHandle;
+
+ DSPI_DisableDMA((dspiEdmaPrivateHandle->base), kDSPI_RxDmaEnable | kDSPI_TxDmaEnable);
+
+ dspiEdmaPrivateHandle->handle->state = kDSPI_Idle;
+
+ if (dspiEdmaPrivateHandle->handle->callback)
+ {
+ dspiEdmaPrivateHandle->handle->callback(dspiEdmaPrivateHandle->base, dspiEdmaPrivateHandle->handle,
+ kStatus_Success, dspiEdmaPrivateHandle->handle->userData);
+ }
+}
+
+void DSPI_MasterTransferAbortEDMA(SPI_Type *base, dspi_master_edma_handle_t *handle)
+{
+ assert(handle);
+
+ DSPI_StopTransfer(base);
+
+ DSPI_DisableDMA(base, kDSPI_RxDmaEnable | kDSPI_TxDmaEnable);
+
+ EDMA_AbortTransfer(handle->edmaRxRegToRxDataHandle);
+ EDMA_AbortTransfer(handle->edmaTxDataToIntermediaryHandle);
+ EDMA_AbortTransfer(handle->edmaIntermediaryToTxRegHandle);
+
+ handle->state = kDSPI_Idle;
+}
+
+status_t DSPI_MasterTransferGetCountEDMA(SPI_Type *base, dspi_master_edma_handle_t *handle, size_t *count)
+{
+ assert(handle);
+
+ if (!count)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Catch when there is not an active transfer. */
+ if (handle->state != kDSPI_Busy)
+ {
+ *count = 0;
+ return kStatus_NoTransferInProgress;
+ }
+
+ size_t bytes;
+
+ bytes = (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(handle->edmaRxRegToRxDataHandle->base,
+ handle->edmaRxRegToRxDataHandle->channel);
+
+ *count = handle->totalByteCount - bytes;
+
+ return kStatus_Success;
+}
+
+void DSPI_SlaveTransferCreateHandleEDMA(SPI_Type *base,
+ dspi_slave_edma_handle_t *handle,
+ dspi_slave_edma_transfer_callback_t callback,
+ void *userData,
+ edma_handle_t *edmaRxRegToRxDataHandle,
+ edma_handle_t *edmaTxDataToTxRegHandle)
+{
+ assert(handle);
+ assert(edmaRxRegToRxDataHandle);
+ assert(edmaTxDataToTxRegHandle);
+
+ /* Zero the handle. */
+ memset(handle, 0, sizeof(*handle));
+
+ uint32_t instance = DSPI_GetInstance(base);
+
+ s_dspiSlaveEdmaPrivateHandle[instance].base = base;
+ s_dspiSlaveEdmaPrivateHandle[instance].handle = handle;
+
+ handle->callback = callback;
+ handle->userData = userData;
+
+ handle->edmaRxRegToRxDataHandle = edmaRxRegToRxDataHandle;
+ handle->edmaTxDataToTxRegHandle = edmaTxDataToTxRegHandle;
+}
+
+status_t DSPI_SlaveTransferEDMA(SPI_Type *base, dspi_slave_edma_handle_t *handle, dspi_transfer_t *transfer)
+{
+ assert(handle);
+ assert(transfer);
+
+ /* If send/receive length is zero */
+ if (transfer->dataSize == 0)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* If both send buffer and receive buffer is null */
+ if ((!(transfer->txData)) && (!(transfer->rxData)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Check that we're not busy.*/
+ if (handle->state == kDSPI_Busy)
+ {
+ return kStatus_DSPI_Busy;
+ }
+
+ handle->state = kDSPI_Busy;
+
+ uint32_t instance = DSPI_GetInstance(base);
+ //uint8_t whichCtar = (transfer->configFlags & DSPI_SLAVE_CTAR_MASK) >> DSPI_SLAVE_CTAR_SHIFT;
+ handle->bitsPerFrame = 8;
+ //(((base->CTAR_SLAVE[whichCtar]) & SPI_CTAR_SLAVE_FMSZ_MASK) >> SPI_CTAR_SLAVE_FMSZ_SHIFT) + 1;
+
+ /* If using a shared RX/TX DMA request, then this limits the amount of data we can transfer
+ * due to the linked channel. The max bytes is 511 if 8-bit/frame or 1022 if 16-bit/frame
+ */
+ uint32_t limited_size = 0;
+ if (1 == FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base))
+ {
+ limited_size = 32767u;
+ }
+ else
+ {
+ limited_size = 511u;
+ }
+
+ if (handle->bitsPerFrame > 8)
+ {
+ if (transfer->dataSize > (limited_size << 1u))
+ {
+ handle->state = kDSPI_Idle;
+ return kStatus_DSPI_OutOfRange;
+ }
+ }
+ else
+ {
+ if (transfer->dataSize > limited_size)
+ {
+ handle->state = kDSPI_Idle;
+ return kStatus_DSPI_OutOfRange;
+ }
+ }
+
+ /*The data size should be even if the bitsPerFrame is greater than 8 (that is 2 bytes per frame in dspi) */
+ if ((handle->bitsPerFrame > 8) && (transfer->dataSize & 0x1))
+ {
+ handle->state = kDSPI_Idle;
+ return kStatus_InvalidArgument;
+ }
+
+ EDMA_SetCallback(handle->edmaRxRegToRxDataHandle, EDMA_DspiSlaveCallback, &s_dspiSlaveEdmaPrivateHandle[instance]);
+
+ /* Store transfer information */
+ handle->txData = transfer->txData;
+ handle->rxData = transfer->rxData;
+ handle->remainingSendByteCount = transfer->dataSize;
+ handle->remainingReceiveByteCount = transfer->dataSize;
+ handle->totalByteCount = transfer->dataSize;
+
+ uint16_t wordToSend = 0;
+ uint8_t dummyData = DSPI_DUMMY_DATA;
+ uint8_t dataAlreadyFed = 0;
+ uint8_t dataFedMax = 2;
+
+ uint32_t rxAddr = DSPI_GetRxRegisterAddress(base);
+ uint32_t txAddr = DSPI_SlaveGetTxRegisterAddress(base);
+
+ edma_transfer_config_t transferConfigA;
+ edma_transfer_config_t transferConfigC;
+
+ DSPI_StopTransfer(base);
+
+ DSPI_FlushFifo(base, true, true);
+ DSPI_ClearStatusFlags(base, kDSPI_AllStatusFlag);
+
+ DSPI_DisableDMA(base, kDSPI_RxDmaEnable | kDSPI_TxDmaEnable);
+
+ DSPI_StartTransfer(base);
+
+ /*if dspi has separate dma request , need not prepare data first .
+ else (dspi has shared dma request) , send first 2 data into fifo if there is fifo or send first 1 data to
+ slaveGetTxRegister if there is no fifo*/
+ if (1 != FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base))
+ {
+ /* For DSPI instances with shared RX/TX DMA requests, we'll use the RX DMA request to
+ * trigger ongoing transfers and will link to the TX DMA channel from the RX DMA channel.
+ */
+ /* If bits/frame is greater than one byte */
+ if (handle->bitsPerFrame > 8)
+ {
+ while (DSPI_GetStatusFlags(base) & kDSPI_TxFifoFillRequestFlag)
+ {
+ if (handle->txData)
+ {
+ wordToSend = *(handle->txData);
+ ++handle->txData; /* Increment to next data byte */
+
+ wordToSend |= (unsigned)(*(handle->txData)) << 8U;
+ ++handle->txData; /* Increment to next data byte */
+ }
+ else
+ {
+ wordToSend = ((uint32_t)dummyData << 8) | dummyData;
+ }
+ handle->remainingSendByteCount -= 2; /* decrement remainingSendByteCount by 2 */
+ base->PUSHR_SLAVE = wordToSend;
+
+ /* Try to clear the TFFF; if the TX FIFO is full this will clear */
+ DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag);
+
+ dataAlreadyFed += 2;
+
+ /* Exit loop if send count is zero, else update local variables for next loop */
+ if ((handle->remainingSendByteCount == 0) || (dataAlreadyFed == (dataFedMax * 2)))
+ {
+ break;
+ }
+ } /* End of TX FIFO fill while loop */
+ }
+ else /* Optimized for bits/frame less than or equal to one byte. */
+ {
+ while (DSPI_GetStatusFlags(base) & kDSPI_TxFifoFillRequestFlag)
+ {
+ if (handle->txData)
+ {
+ wordToSend = *(handle->txData);
+ /* Increment to next data word*/
+ ++handle->txData;
+ }
+ else
+ {
+ wordToSend = dummyData;
+ }
+
+ base->PUSHR_SLAVE = wordToSend;
+
+ /* Try to clear the TFFF; if the TX FIFO is full this will clear */
+ DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag);
+ /* Decrement remainingSendByteCount*/
+ --handle->remainingSendByteCount;
+
+ dataAlreadyFed++;
+
+ /* Exit loop if send count is zero, else update local variables for next loop */
+ if ((handle->remainingSendByteCount == 0) || (dataAlreadyFed == dataFedMax))
+ {
+ break;
+ }
+ } /* End of TX FIFO fill while loop */
+ }
+ }
+
+ /***channel_A *** used for carry the data from Rx_Data_Register(POPR) to User_Receive_Buffer*/
+ if (handle->remainingReceiveByteCount > 0)
+ {
+ EDMA_ResetChannel(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel);
+
+ transferConfigA.srcAddr = (uint32_t)rxAddr;
+ transferConfigA.srcOffset = 0;
+
+ if (handle->rxData)
+ {
+ transferConfigA.destAddr = (uint32_t) & (handle->rxData[0]);
+ transferConfigA.destOffset = 1;
+ }
+ else
+ {
+ transferConfigA.destAddr = (uint32_t) & (handle->rxBuffIfNull);
+ transferConfigA.destOffset = 0;
+ }
+
+ transferConfigA.destTransferSize = kEDMA_TransferSize1Bytes;
+
+ if (handle->bitsPerFrame <= 8)
+ {
+ transferConfigA.srcTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfigA.minorLoopBytes = 1;
+ transferConfigA.majorLoopCounts = handle->remainingReceiveByteCount;
+ }
+ else
+ {
+ transferConfigA.srcTransferSize = kEDMA_TransferSize2Bytes;
+ transferConfigA.minorLoopBytes = 2;
+ transferConfigA.majorLoopCounts = handle->remainingReceiveByteCount / 2;
+ }
+
+ /* Store the initially configured eDMA minor byte transfer count into the DSPI handle */
+ handle->nbytes = transferConfigA.minorLoopBytes;
+
+ EDMA_SetTransferConfig(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
+ &transferConfigA, NULL);
+ EDMA_EnableChannelInterrupts(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
+ kEDMA_MajorInterruptEnable);
+ }
+
+ if (handle->remainingSendByteCount > 0)
+ {
+ /***channel_C *** used for carry the data from User_Send_Buffer to Tx_Data_Register(PUSHR_SLAVE)*/
+ EDMA_ResetChannel(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel);
+
+ transferConfigC.destAddr = (uint32_t)txAddr;
+ transferConfigC.destOffset = 0;
+
+ if (handle->txData)
+ {
+ transferConfigC.srcAddr = (uint32_t)(&(handle->txData[0]));
+ transferConfigC.srcOffset = 1;
+ }
+ else
+ {
+ transferConfigC.srcAddr = (uint32_t)(&handle->txBuffIfNull);
+ transferConfigC.srcOffset = 0;
+ if (handle->bitsPerFrame <= 8)
+ {
+ handle->txBuffIfNull = DSPI_DUMMY_DATA;
+ }
+ else
+ {
+ handle->txBuffIfNull = (DSPI_DUMMY_DATA << 8) | DSPI_DUMMY_DATA;
+ }
+ }
+
+ transferConfigC.srcTransferSize = kEDMA_TransferSize1Bytes;
+
+ if (handle->bitsPerFrame <= 8)
+ {
+ transferConfigC.destTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfigC.minorLoopBytes = 1;
+ transferConfigC.majorLoopCounts = handle->remainingSendByteCount;
+ }
+ else
+ {
+ transferConfigC.destTransferSize = kEDMA_TransferSize2Bytes;
+ transferConfigC.minorLoopBytes = 2;
+ transferConfigC.majorLoopCounts = handle->remainingSendByteCount / 2;
+ }
+
+ EDMA_SetTransferConfig(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel,
+ &transferConfigC, NULL);
+
+ EDMA_StartTransfer(handle->edmaTxDataToTxRegHandle);
+ }
+
+ EDMA_StartTransfer(handle->edmaRxRegToRxDataHandle);
+
+ /*Set channel priority*/
+ uint8_t channelPriorityLow = handle->edmaRxRegToRxDataHandle->channel;
+ uint8_t channelPriorityHigh = handle->edmaTxDataToTxRegHandle->channel;
+ uint8_t t = 0;
+
+ if (channelPriorityLow > channelPriorityHigh)
+ {
+ t = channelPriorityLow;
+ channelPriorityLow = channelPriorityHigh;
+ channelPriorityHigh = t;
+ }
+
+ edma_channel_Preemption_config_t preemption_config_t;
+ preemption_config_t.enableChannelPreemption = true;
+ preemption_config_t.enablePreemptAbility = true;
+ preemption_config_t.channelPriority = channelPriorityLow;
+
+ if (1 != FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base))
+ {
+ EDMA_SetChannelPreemptionConfig(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
+ &preemption_config_t);
+
+ preemption_config_t.channelPriority = channelPriorityHigh;
+ EDMA_SetChannelPreemptionConfig(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel,
+ &preemption_config_t);
+ }
+ else
+ {
+ EDMA_SetChannelPreemptionConfig(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel,
+ &preemption_config_t);
+
+ preemption_config_t.channelPriority = channelPriorityHigh;
+ EDMA_SetChannelPreemptionConfig(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
+ &preemption_config_t);
+ }
+
+ /*Set the channel link.
+ For DSPI instances with shared RX/TX DMA requests: Rx DMA request -> channel_A -> channel_C.
+ For DSPI instances with separate RX and TX DMA requests:
+ Rx DMA request -> channel_A
+ Tx DMA request -> channel_C */
+ if (1 != FSL_FEATURE_DSPI_HAS_SEPARATE_DMA_RX_TX_REQn(base))
+ {
+ if (handle->remainingSendByteCount > 0)
+ {
+ EDMA_SetChannelLink(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
+ kEDMA_MinorLink, handle->edmaTxDataToTxRegHandle->channel);
+ }
+ DSPI_EnableDMA(base, kDSPI_RxDmaEnable);
+ }
+ else
+ {
+ DSPI_EnableDMA(base, kDSPI_RxDmaEnable | kDSPI_TxDmaEnable);
+ }
+
+ return kStatus_Success;
+}
+#if 0
+static void EDMA_DspiSlaveCallback(edma_handle_t *edmaHandle,
+ void *g_dspiEdmaPrivateHandle,
+ bool transferDone,
+ uint32_t tcds)
+{
+
+ assert(edmaHandle);
+ assert(g_dspiEdmaPrivateHandle);
+
+ dspi_slave_edma_private_handle_t *dspiEdmaPrivateHandle;
+
+
+ dspiEdmaPrivateHandle = (dspi_slave_edma_private_handle_t *)g_dspiEdmaPrivateHandle;
+
+ DSPI_DisableDMA((dspiEdmaPrivateHandle->base), kDSPI_RxDmaEnable | kDSPI_TxDmaEnable);
+ GPIO_ClearPinsOutput(GPIOE, 1u << 5u);
+ dspiEdmaPrivateHandle->handle->state = kDSPI_Idle;
+
+ if (dspiEdmaPrivateHandle->handle->callback)
+ {
+
+ dspiEdmaPrivateHandle->handle->callback(dspiEdmaPrivateHandle->base, dspiEdmaPrivateHandle->handle,
+ kStatus_Success, dspiEdmaPrivateHandle->handle->userData);
+ }
+}
+#else
+extern dspi_slave_edma_handle_t g_dspi_edma_s_handle;
+
+static void EDMA_DspiSlaveCallback(edma_handle_t *edmaHandle,
+ void *g_dspiEdmaPrivateHandle,
+ bool transferDone,
+ uint32_t tcds)
+{
+
+ assert(edmaHandle);
+
+ DSPI_DisableDMA(SPI2, kDSPI_RxDmaEnable | kDSPI_TxDmaEnable);
+
+ g_dspi_edma_s_handle.state = kDSPI_Idle;
+
+ if (g_dspi_edma_s_handle.callback)
+ {
+
+ g_dspi_edma_s_handle.callback(SPI2, &g_dspi_edma_s_handle,
+ kStatus_Success, g_dspi_edma_s_handle.userData);
+ }
+}
+#endif
+void DSPI_SlaveTransferAbortEDMA(SPI_Type *base, dspi_slave_edma_handle_t *handle)
+{
+ assert(handle);
+
+ DSPI_StopTransfer(base);
+
+ DSPI_DisableDMA(base, kDSPI_RxDmaEnable | kDSPI_TxDmaEnable);
+
+ EDMA_AbortTransfer(handle->edmaRxRegToRxDataHandle);
+ EDMA_AbortTransfer(handle->edmaTxDataToTxRegHandle);
+
+ handle->state = kDSPI_Idle;
+}
+
+status_t DSPI_SlaveTransferGetCountEDMA(SPI_Type *base, dspi_slave_edma_handle_t *handle, size_t *count)
+{
+ assert(handle);
+
+ if (!count)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Catch when there is not an active transfer. */
+ if (handle->state != kDSPI_Busy)
+ {
+ *count = 0;
+ return kStatus_NoTransferInProgress;
+ }
+
+ size_t bytes;
+
+ bytes = (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(handle->edmaRxRegToRxDataHandle->base,
+ handle->edmaRxRegToRxDataHandle->channel);
+
+ *count = handle->totalByteCount - bytes;
+
+ return kStatus_Success;
+}
diff --git a/drivers/src/fsl_dspi_freertos.c b/drivers/src/fsl_dspi_freertos.c
new file mode 100644
index 0000000..da5eeca
--- /dev/null
+++ b/drivers/src/fsl_dspi_freertos.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsl_dspi_freertos.h"
+
+static void DSPI_RTOS_Callback(SPI_Type *base, dspi_master_handle_t *drv_handle, status_t status, void *userData)
+{
+ dspi_rtos_handle_t *handle = (dspi_rtos_handle_t *)userData;
+ BaseType_t reschedule;
+
+ xSemaphoreGiveFromISR(handle->event, &reschedule);
+ portYIELD_FROM_ISR(reschedule);
+}
+
+status_t DSPI_RTOS_Init(dspi_rtos_handle_t *handle,
+ SPI_Type *base,
+ const dspi_master_config_t *masterConfig,
+ uint32_t srcClock_Hz)
+{
+ if (handle == NULL)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ if (base == NULL)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ memset(handle, 0, sizeof(dspi_rtos_handle_t));
+
+#if (configSUPPORT_STATIC_ALLOCATION == 1)
+ handle->mutex = xSemaphoreCreateMutexStatic(&handle->mutexBuffer);
+#else
+ handle->mutex = xSemaphoreCreateMutex();
+#endif
+ if (handle->mutex == NULL)
+ {
+ return kStatus_Fail;
+ }
+#if (configSUPPORT_STATIC_ALLOCATION == 1)
+ handle->event = xSemaphoreCreateBinaryStatic(&handle->semaphoreBuffer);
+#else
+ handle->event = xSemaphoreCreateBinary();
+#endif
+ if (handle->event == NULL)
+ {
+ vSemaphoreDelete(handle->mutex);
+ return kStatus_Fail;
+ }
+
+ handle->base = base;
+
+ DSPI_MasterInit(handle->base, masterConfig, srcClock_Hz);
+ DSPI_MasterTransferCreateHandle(handle->base, &handle->drv_handle, DSPI_RTOS_Callback, (void *)handle);
+
+ return kStatus_Success;
+}
+
+status_t DSPI_RTOS_Deinit(dspi_rtos_handle_t *handle)
+{
+ DSPI_Deinit(handle->base);
+ vSemaphoreDelete(handle->event);
+ vSemaphoreDelete(handle->mutex);
+
+ return kStatus_Success;
+}
+
+status_t DSPI_RTOS_Transfer(dspi_rtos_handle_t *handle, dspi_transfer_t *transfer)
+{
+ status_t status;
+
+ /* Lock resource mutex */
+ if (xSemaphoreTake(handle->mutex, portMAX_DELAY) != pdTRUE)
+ {
+ return kStatus_DSPI_Busy;
+ }
+
+ status = DSPI_MasterTransferNonBlocking(handle->base, &handle->drv_handle, transfer);
+ if (status != kStatus_Success)
+ {
+ xSemaphoreGive(handle->mutex);
+ return status;
+ }
+
+ /* Wait for transfer to finish */
+ xSemaphoreTake(handle->event, portMAX_DELAY);
+
+ /* Unlock resource mutex */
+ xSemaphoreGive(handle->mutex);
+
+ /* Return status captured by callback function */
+ return handle->async_status;
+}
diff --git a/drivers/src/fsl_edma.c b/drivers/src/fsl_edma.c
new file mode 100644
index 0000000..be51f4c
--- /dev/null
+++ b/drivers/src/fsl_edma.c
@@ -0,0 +1,1754 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsl_edma.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+#define EDMA_TRANSFER_ENABLED_MASK 0x80U
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Get instance number for EDMA.
+ *
+ * @param base EDMA peripheral base address.
+ */
+static uint32_t EDMA_GetInstance(DMA_Type *base);
+
+/*!
+ * @brief Push content of TCD structure into hardware TCD register.
+ *
+ * @param base EDMA peripheral base address.
+ * @param channel EDMA channel number.
+ * @param tcd Point to TCD structure.
+ */
+static void EDMA_InstallTCD(DMA_Type *base, uint32_t channel, edma_tcd_t *tcd);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*! @brief Array to map EDMA instance number to base pointer. */
+static DMA_Type *const s_edmaBases[] = DMA_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Array to map EDMA instance number to clock name. */
+static const clock_ip_name_t s_edmaClockName[] = EDMA_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*! @brief Array to map EDMA instance number to IRQ number. */
+static const IRQn_Type s_edmaIRQNumber[][FSL_FEATURE_EDMA_MODULE_CHANNEL] = DMA_CHN_IRQS;
+
+/*! @brief Pointers to transfer handle for each EDMA channel. */
+static edma_handle_t *s_EDMAHandle[FSL_FEATURE_EDMA_MODULE_CHANNEL * FSL_FEATURE_SOC_EDMA_COUNT];
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static uint32_t EDMA_GetInstance(DMA_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_edmaBases); instance++)
+ {
+ if (s_edmaBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_edmaBases));
+
+ return instance;
+}
+
+static void EDMA_InstallTCD(DMA_Type *base, uint32_t channel, edma_tcd_t *tcd)
+{
+ assert(channel < FSL_FEATURE_EDMA_MODULE_CHANNEL);
+ assert(tcd != NULL);
+ assert(((uint32_t)tcd & 0x1FU) == 0);
+
+ /* Push tcd into hardware TCD register */
+ base->TCD[channel].SADDR = tcd->SADDR;
+ base->TCD[channel].SOFF = tcd->SOFF;
+ base->TCD[channel].ATTR = tcd->ATTR;
+ base->TCD[channel].NBYTES_MLNO = tcd->NBYTES;
+ base->TCD[channel].SLAST = tcd->SLAST;
+ base->TCD[channel].DADDR = tcd->DADDR;
+ base->TCD[channel].DOFF = tcd->DOFF;
+ base->TCD[channel].CITER_ELINKNO = tcd->CITER;
+ base->TCD[channel].DLAST_SGA = tcd->DLAST_SGA;
+ /* Clear DONE bit first, otherwise ESG cannot be set */
+ base->TCD[channel].CSR = 0;
+ base->TCD[channel].CSR = tcd->CSR;
+ base->TCD[channel].BITER_ELINKNO = tcd->BITER;
+}
+
+void EDMA_Init(DMA_Type *base, const edma_config_t *config)
+{
+ assert(config != NULL);
+
+ uint32_t tmpreg;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Ungate EDMA periphral clock */
+ CLOCK_EnableClock(s_edmaClockName[EDMA_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+ /* Configure EDMA peripheral according to the configuration structure. */
+ tmpreg = base->CR;
+ tmpreg &= ~(DMA_CR_ERCA_MASK | DMA_CR_HOE_MASK | DMA_CR_CLM_MASK | DMA_CR_EDBG_MASK);
+ tmpreg |= (DMA_CR_ERCA(config->enableRoundRobinArbitration) | DMA_CR_HOE(config->enableHaltOnError) |
+ DMA_CR_CLM(config->enableContinuousLinkMode) | DMA_CR_EDBG(config->enableDebugMode) | DMA_CR_EMLM(true));
+ base->CR = tmpreg;
+}
+
+void EDMA_Deinit(DMA_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Gate EDMA periphral clock */
+ CLOCK_DisableClock(s_edmaClockName[EDMA_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+void EDMA_GetDefaultConfig(edma_config_t *config)
+{
+ assert(config != NULL);
+
+ config->enableRoundRobinArbitration = false;
+ config->enableHaltOnError = true;
+ config->enableContinuousLinkMode = false;
+ config->enableDebugMode = false;
+}
+
+void EDMA_ResetChannel(DMA_Type *base, uint32_t channel)
+{
+ assert(channel < FSL_FEATURE_EDMA_MODULE_CHANNEL);
+
+ EDMA_TcdReset((edma_tcd_t *)&base->TCD[channel]);
+}
+
+void EDMA_SetTransferConfig(DMA_Type *base, uint32_t channel, const edma_transfer_config_t *config, edma_tcd_t *nextTcd)
+{
+ assert(channel < FSL_FEATURE_EDMA_MODULE_CHANNEL);
+ assert(config != NULL);
+ assert(((uint32_t)nextTcd & 0x1FU) == 0);
+
+ EDMA_TcdSetTransferConfig((edma_tcd_t *)&base->TCD[channel], config, nextTcd);
+}
+
+void EDMA_SetMinorOffsetConfig(DMA_Type *base, uint32_t channel, const edma_minor_offset_config_t *config)
+{
+ assert(channel < FSL_FEATURE_EDMA_MODULE_CHANNEL);
+ assert(config != NULL);
+
+ uint32_t tmpreg;
+
+ tmpreg = base->TCD[channel].NBYTES_MLOFFYES;
+ tmpreg &= ~(DMA_NBYTES_MLOFFYES_SMLOE_MASK | DMA_NBYTES_MLOFFYES_DMLOE_MASK | DMA_NBYTES_MLOFFYES_MLOFF_MASK);
+ tmpreg |=
+ (DMA_NBYTES_MLOFFYES_SMLOE(config->enableSrcMinorOffset) |
+ DMA_NBYTES_MLOFFYES_DMLOE(config->enableDestMinorOffset) | DMA_NBYTES_MLOFFYES_MLOFF(config->minorOffset));
+ base->TCD[channel].NBYTES_MLOFFYES = tmpreg;
+}
+
+void EDMA_SetChannelLink(DMA_Type *base, uint32_t channel, edma_channel_link_type_t type, uint32_t linkedChannel)
+{
+ assert(channel < FSL_FEATURE_EDMA_MODULE_CHANNEL);
+ assert(linkedChannel < FSL_FEATURE_EDMA_MODULE_CHANNEL);
+
+ EDMA_TcdSetChannelLink((edma_tcd_t *)&base->TCD[channel], type, linkedChannel);
+}
+
+void EDMA_SetBandWidth(DMA_Type *base, uint32_t channel, edma_bandwidth_t bandWidth)
+{
+ assert(channel < FSL_FEATURE_EDMA_MODULE_CHANNEL);
+
+ base->TCD[channel].CSR = (base->TCD[channel].CSR & (~DMA_CSR_BWC_MASK)) | DMA_CSR_BWC(bandWidth);
+}
+
+void EDMA_SetModulo(DMA_Type *base, uint32_t channel, edma_modulo_t srcModulo, edma_modulo_t destModulo)
+{
+ assert(channel < FSL_FEATURE_EDMA_MODULE_CHANNEL);
+
+ uint32_t tmpreg;
+
+ tmpreg = base->TCD[channel].ATTR & (~(DMA_ATTR_SMOD_MASK | DMA_ATTR_DMOD_MASK));
+ base->TCD[channel].ATTR = tmpreg | DMA_ATTR_DMOD(destModulo) | DMA_ATTR_SMOD(srcModulo);
+}
+
+void EDMA_EnableChannelInterrupts(DMA_Type *base, uint32_t channel, uint32_t mask)
+{
+ assert(channel < FSL_FEATURE_EDMA_MODULE_CHANNEL);
+
+ /* Enable error interrupt */
+ if (mask & kEDMA_ErrorInterruptEnable)
+ {
+ base->EEI |= (0x1U << channel);
+ }
+
+ /* Enable Major interrupt */
+ if (mask & kEDMA_MajorInterruptEnable)
+ {
+ base->TCD[channel].CSR |= DMA_CSR_INTMAJOR_MASK;
+ }
+
+ /* Enable Half major interrupt */
+ if (mask & kEDMA_HalfInterruptEnable)
+ {
+ base->TCD[channel].CSR |= DMA_CSR_INTHALF_MASK;
+ }
+}
+
+void EDMA_DisableChannelInterrupts(DMA_Type *base, uint32_t channel, uint32_t mask)
+{
+ assert(channel < FSL_FEATURE_EDMA_MODULE_CHANNEL);
+
+ /* Disable error interrupt */
+ if (mask & kEDMA_ErrorInterruptEnable)
+ {
+ base->EEI &= ~(0x1U << channel);
+ }
+
+ /* Disable Major interrupt */
+ if (mask & kEDMA_MajorInterruptEnable)
+ {
+ base->TCD[channel].CSR &= ~DMA_CSR_INTMAJOR_MASK;
+ }
+
+ /* Disable Half major interrupt */
+ if (mask & kEDMA_HalfInterruptEnable)
+ {
+ base->TCD[channel].CSR &= ~DMA_CSR_INTHALF_MASK;
+ }
+}
+
+void EDMA_TcdReset(edma_tcd_t *tcd)
+{
+ assert(tcd != NULL);
+ assert(((uint32_t)tcd & 0x1FU) == 0);
+
+ /* Reset channel TCD */
+ tcd->SADDR = 0U;
+ tcd->SOFF = 0U;
+ tcd->ATTR = 0U;
+ tcd->NBYTES = 0U;
+ tcd->SLAST = 0U;
+ tcd->DADDR = 0U;
+ tcd->DOFF = 0U;
+ tcd->CITER = 0U;
+ tcd->DLAST_SGA = 0U;
+ /* Enable auto disable request feature */
+ tcd->CSR = DMA_CSR_DREQ(true);
+ tcd->BITER = 0U;
+}
+
+void EDMA_TcdSetTransferConfig(edma_tcd_t *tcd, const edma_transfer_config_t *config, edma_tcd_t *nextTcd)
+{
+ assert(tcd != NULL);
+ assert(((uint32_t)tcd & 0x1FU) == 0);
+ assert(config != NULL);
+ assert(((uint32_t)nextTcd & 0x1FU) == 0);
+
+ /* source address */
+ tcd->SADDR = config->srcAddr;
+ /* destination address */
+ tcd->DADDR = config->destAddr;
+ /* Source data and destination data transfer size */
+ tcd->ATTR = DMA_ATTR_SSIZE(config->srcTransferSize) | DMA_ATTR_DSIZE(config->destTransferSize);
+ /* Source address signed offset */
+ tcd->SOFF = config->srcOffset;
+ /* Destination address signed offset */
+ tcd->DOFF = config->destOffset;
+ /* Minor byte transfer count */
+ tcd->NBYTES = config->minorLoopBytes;
+ /* Current major iteration count */
+ tcd->CITER = config->majorLoopCounts;
+ /* Starting major iteration count */
+ tcd->BITER = config->majorLoopCounts;
+ /* Enable scatter/gather processing */
+ if (nextTcd != NULL)
+ {
+ tcd->DLAST_SGA = (uint32_t)nextTcd;
+ /*
+ Before call EDMA_TcdSetTransferConfig or EDMA_SetTransferConfig,
+ user must call EDMA_TcdReset or EDMA_ResetChannel which will set
+ DREQ, so must use "|" or "&" rather than "=".
+
+ Clear the DREQ bit because scatter gather has been enabled, so the
+ previous transfer is not the last transfer, and channel request should
+ be enabled at the next transfer(the next TCD).
+ */
+ tcd->CSR = (tcd->CSR | DMA_CSR_ESG_MASK) & ~DMA_CSR_DREQ_MASK;
+ }
+}
+
+void EDMA_TcdSetMinorOffsetConfig(edma_tcd_t *tcd, const edma_minor_offset_config_t *config)
+{
+ assert(tcd != NULL);
+ assert(((uint32_t)tcd & 0x1FU) == 0);
+
+ uint32_t tmpreg;
+
+ tmpreg = tcd->NBYTES &
+ ~(DMA_NBYTES_MLOFFYES_SMLOE_MASK | DMA_NBYTES_MLOFFYES_DMLOE_MASK | DMA_NBYTES_MLOFFYES_MLOFF_MASK);
+ tmpreg |=
+ (DMA_NBYTES_MLOFFYES_SMLOE(config->enableSrcMinorOffset) |
+ DMA_NBYTES_MLOFFYES_DMLOE(config->enableDestMinorOffset) | DMA_NBYTES_MLOFFYES_MLOFF(config->minorOffset));
+ tcd->NBYTES = tmpreg;
+}
+
+void EDMA_TcdSetChannelLink(edma_tcd_t *tcd, edma_channel_link_type_t type, uint32_t linkedChannel)
+{
+ assert(tcd != NULL);
+ assert(((uint32_t)tcd & 0x1FU) == 0);
+ assert(linkedChannel < FSL_FEATURE_EDMA_MODULE_CHANNEL);
+
+ if (type == kEDMA_MinorLink) /* Minor link config */
+ {
+ uint32_t tmpreg;
+
+ /* Enable minor link */
+ tcd->CITER |= DMA_CITER_ELINKYES_ELINK_MASK;
+ tcd->BITER |= DMA_BITER_ELINKYES_ELINK_MASK;
+ /* Set likned channel */
+ tmpreg = tcd->CITER & (~DMA_CITER_ELINKYES_LINKCH_MASK);
+ tmpreg |= DMA_CITER_ELINKYES_LINKCH(linkedChannel);
+ tcd->CITER = tmpreg;
+ tmpreg = tcd->BITER & (~DMA_BITER_ELINKYES_LINKCH_MASK);
+ tmpreg |= DMA_BITER_ELINKYES_LINKCH(linkedChannel);
+ tcd->BITER = tmpreg;
+ }
+ else if (type == kEDMA_MajorLink) /* Major link config */
+ {
+ uint32_t tmpreg;
+
+ /* Enable major link */
+ tcd->CSR |= DMA_CSR_MAJORELINK_MASK;
+ /* Set major linked channel */
+ tmpreg = tcd->CSR & (~DMA_CSR_MAJORLINKCH_MASK);
+ tcd->CSR = tmpreg | DMA_CSR_MAJORLINKCH(linkedChannel);
+ }
+ else /* Link none */
+ {
+ tcd->CITER &= ~DMA_CITER_ELINKYES_ELINK_MASK;
+ tcd->BITER &= ~DMA_BITER_ELINKYES_ELINK_MASK;
+ tcd->CSR &= ~DMA_CSR_MAJORELINK_MASK;
+ }
+}
+
+void EDMA_TcdSetModulo(edma_tcd_t *tcd, edma_modulo_t srcModulo, edma_modulo_t destModulo)
+{
+ assert(tcd != NULL);
+ assert(((uint32_t)tcd & 0x1FU) == 0);
+
+ uint32_t tmpreg;
+
+ tmpreg = tcd->ATTR & (~(DMA_ATTR_SMOD_MASK | DMA_ATTR_DMOD_MASK));
+ tcd->ATTR = tmpreg | DMA_ATTR_DMOD(destModulo) | DMA_ATTR_SMOD(srcModulo);
+}
+
+void EDMA_TcdEnableInterrupts(edma_tcd_t *tcd, uint32_t mask)
+{
+ assert(tcd != NULL);
+
+ /* Enable Major interrupt */
+ if (mask & kEDMA_MajorInterruptEnable)
+ {
+ tcd->CSR |= DMA_CSR_INTMAJOR_MASK;
+ }
+
+ /* Enable Half major interrupt */
+ if (mask & kEDMA_HalfInterruptEnable)
+ {
+ tcd->CSR |= DMA_CSR_INTHALF_MASK;
+ }
+}
+
+void EDMA_TcdDisableInterrupts(edma_tcd_t *tcd, uint32_t mask)
+{
+ assert(tcd != NULL);
+
+ /* Disable Major interrupt */
+ if (mask & kEDMA_MajorInterruptEnable)
+ {
+ tcd->CSR &= ~DMA_CSR_INTMAJOR_MASK;
+ }
+
+ /* Disable Half major interrupt */
+ if (mask & kEDMA_HalfInterruptEnable)
+ {
+ tcd->CSR &= ~DMA_CSR_INTHALF_MASK;
+ }
+}
+
+uint32_t EDMA_GetRemainingMajorLoopCount(DMA_Type *base, uint32_t channel)
+{
+ assert(channel < FSL_FEATURE_EDMA_MODULE_CHANNEL);
+
+ uint32_t remainingCount = 0;
+
+ if (DMA_CSR_DONE_MASK & base->TCD[channel].CSR)
+ {
+ remainingCount = 0;
+ }
+ else
+ {
+ /* Calculate the unfinished bytes */
+ if (base->TCD[channel].CITER_ELINKNO & DMA_CITER_ELINKNO_ELINK_MASK)
+ {
+ remainingCount =
+ (base->TCD[channel].CITER_ELINKYES & DMA_CITER_ELINKYES_CITER_MASK) >> DMA_CITER_ELINKYES_CITER_SHIFT;
+ }
+ else
+ {
+ remainingCount =
+ (base->TCD[channel].CITER_ELINKNO & DMA_CITER_ELINKNO_CITER_MASK) >> DMA_CITER_ELINKNO_CITER_SHIFT;
+ }
+ }
+
+ return remainingCount;
+}
+
+uint32_t EDMA_GetChannelStatusFlags(DMA_Type *base, uint32_t channel)
+{
+ assert(channel < FSL_FEATURE_EDMA_MODULE_CHANNEL);
+
+ uint32_t retval = 0;
+
+ /* Get DONE bit flag */
+ retval |= ((base->TCD[channel].CSR & DMA_CSR_DONE_MASK) >> DMA_CSR_DONE_SHIFT);
+ /* Get ERROR bit flag */
+ retval |= (((base->ERR >> channel) & 0x1U) << 1U);
+ /* Get INT bit flag */
+ retval |= (((base->INT >> channel) & 0x1U) << 2U);
+
+ return retval;
+}
+
+void EDMA_ClearChannelStatusFlags(DMA_Type *base, uint32_t channel, uint32_t mask)
+{
+ assert(channel < FSL_FEATURE_EDMA_MODULE_CHANNEL);
+
+ /* Clear DONE bit flag */
+ if (mask & kEDMA_DoneFlag)
+ {
+ base->CDNE = channel;
+ }
+ /* Clear ERROR bit flag */
+ if (mask & kEDMA_ErrorFlag)
+ {
+ base->CERR = channel;
+ }
+ /* Clear INT bit flag */
+ if (mask & kEDMA_InterruptFlag)
+ {
+ base->CINT = channel;
+ }
+}
+
+void EDMA_CreateHandle(edma_handle_t *handle, DMA_Type *base, uint32_t channel)
+{
+ assert(handle != NULL);
+ assert(channel < FSL_FEATURE_EDMA_MODULE_CHANNEL);
+
+ uint32_t edmaInstance;
+ uint32_t channelIndex;
+ edma_tcd_t *tcdRegs;
+
+ /* Zero the handle */
+ memset(handle, 0, sizeof(*handle));
+
+ handle->base = base;
+ handle->channel = channel;
+ /* Get the DMA instance number */
+ edmaInstance = EDMA_GetInstance(base);
+ channelIndex = (edmaInstance * FSL_FEATURE_EDMA_MODULE_CHANNEL) + channel;
+ s_EDMAHandle[channelIndex] = handle;
+
+ /* Enable NVIC interrupt */
+ EnableIRQ(s_edmaIRQNumber[edmaInstance][channel]);
+
+ /*
+ Reset TCD registers to zero. Unlike the EDMA_TcdReset(DREQ will be set),
+ CSR will be 0. Because in order to suit EDMA busy check mechanism in
+ EDMA_SubmitTransfer, CSR must be set 0.
+ */
+ tcdRegs = (edma_tcd_t *)&handle->base->TCD[handle->channel];
+ tcdRegs->SADDR = 0;
+ tcdRegs->SOFF = 0;
+ tcdRegs->ATTR = 0;
+ tcdRegs->NBYTES = 0;
+ tcdRegs->SLAST = 0;
+ tcdRegs->DADDR = 0;
+ tcdRegs->DOFF = 0;
+ tcdRegs->CITER = 0;
+ tcdRegs->DLAST_SGA = 0;
+ tcdRegs->CSR = 0;
+ tcdRegs->BITER = 0;
+}
+
+void EDMA_InstallTCDMemory(edma_handle_t *handle, edma_tcd_t *tcdPool, uint32_t tcdSize)
+{
+ assert(handle != NULL);
+ assert(((uint32_t)tcdPool & 0x1FU) == 0);
+
+ /* Initialize tcd queue attibute. */
+ handle->header = 0;
+ handle->tail = 0;
+ handle->tcdUsed = 0;
+ handle->tcdSize = tcdSize;
+ handle->flags = 0;
+ handle->tcdPool = tcdPool;
+}
+
+void EDMA_SetCallback(edma_handle_t *handle, edma_callback callback, void *userData)
+{
+ assert(handle != NULL);
+
+ handle->callback = callback;
+ handle->userData = userData;
+}
+
+void EDMA_PrepareTransfer(edma_transfer_config_t *config,
+ void *srcAddr,
+ uint32_t srcWidth,
+ void *destAddr,
+ uint32_t destWidth,
+ uint32_t bytesEachRequest,
+ uint32_t transferBytes,
+ edma_transfer_type_t type)
+{
+ assert(config != NULL);
+ assert(srcAddr != NULL);
+ assert(destAddr != NULL);
+ assert((srcWidth == 1U) || (srcWidth == 2U) || (srcWidth == 4U) || (srcWidth == 16U) || (srcWidth == 32U));
+ assert((destWidth == 1U) || (destWidth == 2U) || (destWidth == 4U) || (destWidth == 16U) || (destWidth == 32U));
+ assert(transferBytes % bytesEachRequest == 0);
+
+ config->destAddr = (uint32_t)destAddr;
+ config->srcAddr = (uint32_t)srcAddr;
+ config->minorLoopBytes = bytesEachRequest;
+ config->majorLoopCounts = transferBytes / bytesEachRequest;
+ switch (srcWidth)
+ {
+ case 1U:
+ config->srcTransferSize = kEDMA_TransferSize1Bytes;
+ break;
+ case 2U:
+ config->srcTransferSize = kEDMA_TransferSize2Bytes;
+ break;
+ case 4U:
+ config->srcTransferSize = kEDMA_TransferSize4Bytes;
+ break;
+ case 16U:
+ config->srcTransferSize = kEDMA_TransferSize16Bytes;
+ break;
+ case 32U:
+ config->srcTransferSize = kEDMA_TransferSize32Bytes;
+ break;
+ default:
+ break;
+ }
+ switch (destWidth)
+ {
+ case 1U:
+ config->destTransferSize = kEDMA_TransferSize1Bytes;
+ break;
+ case 2U:
+ config->destTransferSize = kEDMA_TransferSize2Bytes;
+ break;
+ case 4U:
+ config->destTransferSize = kEDMA_TransferSize4Bytes;
+ break;
+ case 16U:
+ config->destTransferSize = kEDMA_TransferSize16Bytes;
+ break;
+ case 32U:
+ config->destTransferSize = kEDMA_TransferSize32Bytes;
+ break;
+ default:
+ break;
+ }
+ switch (type)
+ {
+ case kEDMA_MemoryToMemory:
+ config->destOffset = destWidth;
+ config->srcOffset = srcWidth;
+ break;
+ case kEDMA_MemoryToPeripheral:
+ config->destOffset = 0U;
+ config->srcOffset = srcWidth;
+ break;
+ case kEDMA_PeripheralToMemory:
+ config->destOffset = destWidth;
+ config->srcOffset = 0U;
+ break;
+ default:
+ break;
+ }
+}
+
+status_t EDMA_SubmitTransfer(edma_handle_t *handle, const edma_transfer_config_t *config)
+{
+ assert(handle != NULL);
+ assert(config != NULL);
+
+ edma_tcd_t *tcdRegs = (edma_tcd_t *)&handle->base->TCD[handle->channel];
+
+ if (handle->tcdPool == NULL)
+ {
+ /*
+ Check if EDMA is busy: if the given channel started transfer, CSR will be not zero. Because
+ if it is the last transfer, DREQ will be set. If not, ESG will be set. So in order to suit
+ this check mechanism, EDMA_CreatHandle will clear CSR register.
+ */
+ if ((tcdRegs->CSR != 0) && ((tcdRegs->CSR & DMA_CSR_DONE_MASK) == 0))
+ {
+ return kStatus_EDMA_Busy;
+ }
+ else
+ {
+ EDMA_SetTransferConfig(handle->base, handle->channel, config, NULL);
+ /* Enable auto disable request feature */
+ handle->base->TCD[handle->channel].CSR |= DMA_CSR_DREQ_MASK;
+ /* Enable major interrupt */
+ handle->base->TCD[handle->channel].CSR |= DMA_CSR_INTMAJOR_MASK;
+
+ return kStatus_Success;
+ }
+ }
+ else /* Use the TCD queue. */
+ {
+ uint32_t primask;
+ uint32_t csr;
+ int8_t currentTcd;
+ int8_t previousTcd;
+ int8_t nextTcd;
+
+ /* Check if tcd pool is full. */
+ primask = DisableGlobalIRQ();
+ if (handle->tcdUsed >= handle->tcdSize)
+ {
+ EnableGlobalIRQ(primask);
+
+ return kStatus_EDMA_QueueFull;
+ }
+ currentTcd = handle->tail;
+ handle->tcdUsed++;
+ /* Calculate index of next TCD */
+ nextTcd = currentTcd + 1U;
+ if (nextTcd == handle->tcdSize)
+ {
+ nextTcd = 0U;
+ }
+ /* Advance queue tail index */
+ handle->tail = nextTcd;
+ EnableGlobalIRQ(primask);
+ /* Calculate index of previous TCD */
+ previousTcd = currentTcd ? currentTcd - 1U : handle->tcdSize - 1U;
+ /* Configure current TCD block. */
+ EDMA_TcdReset(&handle->tcdPool[currentTcd]);
+ EDMA_TcdSetTransferConfig(&handle->tcdPool[currentTcd], config, NULL);
+ /* Enable major interrupt */
+ handle->tcdPool[currentTcd].CSR |= DMA_CSR_INTMAJOR_MASK;
+ /* Link current TCD with next TCD for identification of current TCD */
+ handle->tcdPool[currentTcd].DLAST_SGA = (uint32_t)&handle->tcdPool[nextTcd];
+ /* Chain from previous descriptor unless tcd pool size is 1(this descriptor is its own predecessor). */
+ if (currentTcd != previousTcd)
+ {
+ /* Enable scatter/gather feature in the previous TCD block. */
+ csr = (handle->tcdPool[previousTcd].CSR | DMA_CSR_ESG_MASK) & ~DMA_CSR_DREQ_MASK;
+ handle->tcdPool[previousTcd].CSR = csr;
+ /*
+ Check if the TCD blcok in the registers is the previous one (points to current TCD block). It
+ is used to check if the previous TCD linked has been loaded in TCD register. If so, it need to
+ link the TCD register in case link the current TCD with the dead chain when TCD loading occurs
+ before link the previous TCD block.
+ */
+ if (tcdRegs->DLAST_SGA == (uint32_t)&handle->tcdPool[currentTcd])
+ {
+ /* Enable scatter/gather also in the TCD registers. */
+ csr = (tcdRegs->CSR | DMA_CSR_ESG_MASK) & ~DMA_CSR_DREQ_MASK;
+ /* Must write the CSR register one-time, because the transfer maybe finished anytime. */
+ tcdRegs->CSR = csr;
+ /*
+ It is very important to check the ESG bit!
+ Because this hardware design: if DONE bit is set, the ESG bit can not be set. So it can
+ be used to check if the dynamic TCD link operation is successful. If ESG bit is not set
+ and the DLAST_SGA is not the next TCD address(it means the dynamic TCD link succeed and
+ the current TCD block has been loaded into TCD registers), it means transfer finished
+ and TCD link operation fail, so must install TCD content into TCD registers and enable
+ transfer again. And if ESG is set, it means transfer has notfinished, so TCD dynamic
+ link succeed.
+ */
+ if (tcdRegs->CSR & DMA_CSR_ESG_MASK)
+ {
+ return kStatus_Success;
+ }
+ /*
+ Check whether the current TCD block is already loaded in the TCD registers. It is another
+ condition when ESG bit is not set: it means the dynamic TCD link succeed and the current
+ TCD block has been loaded into TCD registers.
+ */
+ if (tcdRegs->DLAST_SGA == (uint32_t)&handle->tcdPool[nextTcd])
+ {
+ return kStatus_Success;
+ }
+ /*
+ If go to this, means the previous transfer finished, and the DONE bit is set.
+ So shall configure TCD registers.
+ */
+ }
+ else if (tcdRegs->DLAST_SGA != 0)
+ {
+ /* The current TCD block has been linked successfully. */
+ return kStatus_Success;
+ }
+ else
+ {
+ /*
+ DLAST_SGA is 0 and it means the first submit transfer, so shall configure
+ TCD registers.
+ */
+ }
+ }
+ /* There is no live chain, TCD block need to be installed in TCD registers. */
+ EDMA_InstallTCD(handle->base, handle->channel, &handle->tcdPool[currentTcd]);
+ /* Enable channel request again. */
+ if (handle->flags & EDMA_TRANSFER_ENABLED_MASK)
+ {
+ handle->base->SERQ = DMA_SERQ_SERQ(handle->channel);
+ }
+
+ return kStatus_Success;
+ }
+}
+
+void EDMA_StartTransfer(edma_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ if (handle->tcdPool == NULL)
+ {
+ handle->base->SERQ = DMA_SERQ_SERQ(handle->channel);
+ }
+ else /* Use the TCD queue. */
+ {
+ uint32_t primask;
+ edma_tcd_t *tcdRegs = (edma_tcd_t *)&handle->base->TCD[handle->channel];
+
+ handle->flags |= EDMA_TRANSFER_ENABLED_MASK;
+
+ /* Check if there was at least one descriptor submitted since reset (TCD in registers is valid) */
+ if (tcdRegs->DLAST_SGA != 0U)
+ {
+ primask = DisableGlobalIRQ();
+ /* Check if channel request is actually disable. */
+ if ((handle->base->ERQ & (1U << handle->channel)) == 0U)
+ {
+ /* Check if transfer is paused. */
+ if ((!(tcdRegs->CSR & DMA_CSR_DONE_MASK)) || (tcdRegs->CSR & DMA_CSR_ESG_MASK))
+ {
+ /*
+ Re-enable channel request must be as soon as possible, so must put it into
+ critical section to avoid task switching or interrupt service routine.
+ */
+ handle->base->SERQ = DMA_SERQ_SERQ(handle->channel);
+ }
+ }
+ EnableGlobalIRQ(primask);
+ }
+ }
+}
+
+void EDMA_StopTransfer(edma_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ handle->flags &= (~EDMA_TRANSFER_ENABLED_MASK);
+ handle->base->CERQ = DMA_CERQ_CERQ(handle->channel);
+}
+
+void EDMA_AbortTransfer(edma_handle_t *handle)
+{
+ handle->base->CERQ = DMA_CERQ_CERQ(handle->channel);
+ /*
+ Clear CSR to release channel. Because if the given channel started transfer,
+ CSR will be not zero. Because if it is the last transfer, DREQ will be set.
+ If not, ESG will be set.
+ */
+ handle->base->TCD[handle->channel].CSR = 0;
+ /* Cancel all next TCD transfer. */
+ handle->base->TCD[handle->channel].DLAST_SGA = 0;
+}
+
+void EDMA_HandleIRQ(edma_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Clear EDMA interrupt flag */
+ handle->base->CINT = handle->channel;
+ if ((handle->tcdPool == NULL) && (handle->callback != NULL))
+ {
+ (handle->callback)(handle, handle->userData, true, 0);
+ }
+ else /* Use the TCD queue. Please refer to the API descriptions in the eDMA header file for detailed information. */
+ {
+ uint32_t sga = handle->base->TCD[handle->channel].DLAST_SGA;
+ uint32_t sga_index;
+ int32_t tcds_done;
+ uint8_t new_header;
+ bool transfer_done;
+
+ /* Check if transfer is already finished. */
+ transfer_done = ((handle->base->TCD[handle->channel].CSR & DMA_CSR_DONE_MASK) != 0);
+ /* Get the offset of the next transfer TCD blcoks to be loaded into the eDMA engine. */
+ sga -= (uint32_t)handle->tcdPool;
+ /* Get the index of the next transfer TCD blcoks to be loaded into the eDMA engine. */
+ sga_index = sga / sizeof(edma_tcd_t);
+ /* Adjust header positions. */
+ if (transfer_done)
+ {
+ /* New header shall point to the next TCD to be loaded (current one is already finished) */
+ new_header = sga_index;
+ }
+ else
+ {
+ /* New header shall point to this descriptor currently loaded (not finished yet) */
+ new_header = sga_index ? sga_index - 1U : handle->tcdSize - 1U;
+ }
+ /* Calculate the number of finished TCDs */
+ if (new_header == handle->header)
+ {
+ if (handle->tcdUsed == handle->tcdSize)
+ {
+ tcds_done = handle->tcdUsed;
+ }
+ else
+ {
+ /* No TCD in the memory are going to be loaded or internal error occurs. */
+ tcds_done = 0;
+ }
+ }
+ else
+ {
+ tcds_done = new_header - handle->header;
+ if (tcds_done < 0)
+ {
+ tcds_done += handle->tcdSize;
+ }
+ }
+ /* Advance header which points to the TCD to be loaded into the eDMA engine from memory. */
+ handle->header = new_header;
+ /* Release TCD blocks. tcdUsed is the TCD number which can be used/loaded in the memory pool. */
+ handle->tcdUsed -= tcds_done;
+ /* Invoke callback function. */
+ if (handle->callback)
+ {
+ (handle->callback)(handle, handle->userData, transfer_done, tcds_done);
+ }
+ }
+}
+
+/* 8 channels (Shared): kl28 */
+#if defined(FSL_FEATURE_EDMA_MODULE_CHANNEL) && FSL_FEATURE_EDMA_MODULE_CHANNEL == 8U
+
+void DMA0_04_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 0U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[0]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 4U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[4]);
+ }
+}
+
+void DMA0_15_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 1U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[1]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 5U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[5]);
+ }
+}
+
+void DMA0_26_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 2U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[2]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 6U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[6]);
+ }
+}
+
+void DMA0_37_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 3U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[3]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 7U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[7]);
+ }
+}
+
+#if defined(DMA1)
+void DMA1_04_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 0U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[8]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 4U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[12]);
+ }
+}
+
+void DMA1_15_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 1U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[9]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 5U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[13]);
+ }
+}
+
+void DMA1_26_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 2U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[10]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 6U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[14]);
+ }
+}
+
+void DMA1_37_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 3U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[11]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 7U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[15]);
+ }
+}
+#endif
+#endif /* 8 channels (Shared) */
+
+/* 16 channels (Shared): K32H844P */
+#if defined(FSL_FEATURE_EDMA_MODULE_CHANNEL) && FSL_FEATURE_EDMA_MODULE_CHANNEL == 16U
+
+void DMA0_08_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 0U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[0]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 8U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[8]);
+ }
+}
+
+void DMA0_19_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 1U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[1]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 9U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[9]);
+ }
+}
+
+void DMA0_210_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 2U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[2]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 10U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[10]);
+ }
+}
+
+void DMA0_311_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 3U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[3]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 11U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[11]);
+ }
+}
+
+void DMA0_412_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 4U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[4]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 12U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[12]);
+ }
+}
+
+void DMA0_513_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 5U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[5]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 13U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[13]);
+ }
+}
+
+void DMA0_614_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 6U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[6]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 14U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[14]);
+ }
+}
+
+void DMA0_715_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 7U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[7]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 15U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[15]);
+ }
+}
+
+#if defined(DMA1)
+void DMA1_08_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 0U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[16]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 8U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[24]);
+ }
+}
+
+void DMA1_19_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 1U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[17]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 9U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[25]);
+ }
+}
+
+void DMA1_210_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 2U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[18]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 10U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[26]);
+ }
+}
+
+void DMA1_311_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 3U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[19]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 11U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[27]);
+ }
+}
+
+void DMA1_412_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 4U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[20]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 12U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[28]);
+ }
+}
+
+void DMA1_513_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 5U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[21]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 13U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[29]);
+ }
+}
+
+void DMA1_614_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 6U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[22]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 14U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[30]);
+ }
+}
+
+void DMA1_715_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 7U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[23]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 15U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[31]);
+ }
+}
+#endif
+#endif /* 16 channels (Shared) */
+
+/* 32 channels (Shared): k80 */
+#if defined(FSL_FEATURE_EDMA_MODULE_CHANNEL) && FSL_FEATURE_EDMA_MODULE_CHANNEL == 32U
+
+void DMA0_DMA16_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 0U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[0]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 16U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[16]);
+ }
+}
+
+void DMA1_DMA17_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 1U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[1]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 17U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[17]);
+ }
+}
+
+void DMA2_DMA18_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 2U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[2]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 18U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[18]);
+ }
+}
+
+void DMA3_DMA19_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 3U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[3]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 19U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[19]);
+ }
+}
+
+void DMA4_DMA20_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 4U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[4]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 20U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[20]);
+ }
+}
+
+void DMA5_DMA21_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 5U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[5]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 21U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[21]);
+ }
+}
+
+void DMA6_DMA22_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 6U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[6]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 22U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[22]);
+ }
+}
+
+void DMA7_DMA23_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 7U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[7]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 23U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[23]);
+ }
+}
+
+void DMA8_DMA24_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 8U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[8]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 24U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[24]);
+ }
+}
+
+void DMA9_DMA25_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 9U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[9]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 25U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[25]);
+ }
+}
+
+void DMA10_DMA26_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 10U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[10]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 26U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[26]);
+ }
+}
+
+void DMA11_DMA27_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 11U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[11]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 27U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[27]);
+ }
+}
+
+void DMA12_DMA28_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 12U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[12]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 28U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[28]);
+ }
+}
+
+void DMA13_DMA29_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 13U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[13]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 29U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[29]);
+ }
+}
+
+void DMA14_DMA30_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 14U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[14]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 30U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[30]);
+ }
+}
+
+void DMA15_DMA31_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 15U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[15]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 31U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[31]);
+ }
+}
+#endif /* 32 channels (Shared) */
+
+/* 32 channels (Shared): MCIMX7U5_M4 */
+#if defined(FSL_FEATURE_EDMA_MODULE_CHANNEL) && FSL_FEATURE_EDMA_MODULE_CHANNEL == 32U
+
+void DMA0_0_4_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 0U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[0]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 4U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[4]);
+ }
+}
+
+void DMA0_1_5_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 1U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[1]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 5U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[5]);
+ }
+}
+
+void DMA0_2_6_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 2U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[2]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 6U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[6]);
+ }
+}
+
+void DMA0_3_7_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 3U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[3]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 7U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[7]);
+ }
+}
+
+void DMA0_8_12_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 8U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[8]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 12U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[12]);
+ }
+}
+
+void DMA0_9_13_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 9U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[9]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 13U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[13]);
+ }
+}
+
+void DMA0_10_14_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 10U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[10]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 14U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[14]);
+ }
+}
+
+void DMA0_11_15_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 11U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[11]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 15U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[15]);
+ }
+}
+
+void DMA0_16_20_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 16U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[16]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 20U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[20]);
+ }
+}
+
+void DMA0_17_21_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 17U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[17]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 21U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[21]);
+ }
+}
+
+void DMA0_18_22_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 18U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[18]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 22U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[22]);
+ }
+}
+
+void DMA0_19_23_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 19U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[19]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 23U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[23]);
+ }
+}
+
+void DMA0_24_28_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 24U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[24]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 28U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[28]);
+ }
+}
+
+void DMA0_25_29_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 25U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[25]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 29U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[29]);
+ }
+}
+
+void DMA0_26_30_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 26U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[26]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 30U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[30]);
+ }
+}
+
+void DMA0_27_31_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 27U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[27]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 31U) & kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[31]);
+ }
+}
+#endif /* 32 channels (Shared): MCIMX7U5 */
+
+/* 4 channels (No Shared): kv10 */
+#if defined(FSL_FEATURE_EDMA_MODULE_CHANNEL) && FSL_FEATURE_EDMA_MODULE_CHANNEL > 0
+
+void DMA0_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[0]);
+}
+
+void DMA1_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[1]);
+}
+
+void DMA2_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[2]);
+}
+
+void DMA3_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[3]);
+}
+
+/* 8 channels (No Shared) */
+#if defined(FSL_FEATURE_EDMA_MODULE_CHANNEL) && FSL_FEATURE_EDMA_MODULE_CHANNEL > 4U
+
+void DMA4_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[4]);
+}
+
+void DMA5_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[5]);
+}
+
+void DMA6_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[6]);
+}
+
+void DMA7_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[7]);
+}
+#endif /* FSL_FEATURE_EDMA_MODULE_CHANNEL == 8 */
+
+/* 16 channels (No Shared) */
+#if defined(FSL_FEATURE_EDMA_MODULE_CHANNEL) && FSL_FEATURE_EDMA_MODULE_CHANNEL > 8U
+
+void DMA8_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[8]);
+}
+
+void DMA9_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[9]);
+}
+
+void DMA10_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[10]);
+}
+
+void DMA11_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[11]);
+}
+
+void DMA12_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[12]);
+}
+
+void DMA13_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[13]);
+}
+
+void DMA14_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[14]);
+}
+
+void DMA15_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[15]);
+}
+#endif /* FSL_FEATURE_EDMA_MODULE_CHANNEL == 16 */
+
+/* 32 channels (No Shared) */
+#if defined(FSL_FEATURE_EDMA_MODULE_CHANNEL) && FSL_FEATURE_EDMA_MODULE_CHANNEL > 16U
+
+void DMA16_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[16]);
+}
+
+void DMA17_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[17]);
+}
+
+void DMA18_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[18]);
+}
+
+void DMA19_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[19]);
+}
+
+void DMA20_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[20]);
+}
+
+void DMA21_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[21]);
+}
+
+void DMA22_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[22]);
+}
+
+void DMA23_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[23]);
+}
+
+void DMA24_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[24]);
+}
+
+void DMA25_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[25]);
+}
+
+void DMA26_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[26]);
+}
+
+void DMA27_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[27]);
+}
+
+void DMA28_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[28]);
+}
+
+void DMA29_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[29]);
+}
+
+void DMA30_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[30]);
+}
+
+void DMA31_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[31]);
+}
+#endif /* FSL_FEATURE_EDMA_MODULE_CHANNEL == 32 */
+
+#endif /* 4/8/16/32 channels (No Shared) */
diff --git a/drivers/src/fsl_ewm.c b/drivers/src/fsl_ewm.c
new file mode 100644
index 0000000..f22eff9
--- /dev/null
+++ b/drivers/src/fsl_ewm.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsl_ewm.h"
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+void EWM_Init(EWM_Type *base, const ewm_config_t *config)
+{
+ assert(config);
+
+ uint32_t value = 0U;
+
+#if !((defined(FSL_FEATURE_SOC_PCC_COUNT) && FSL_FEATURE_SOC_PCC_COUNT) && \
+ (defined(FSL_FEATURE_PCC_SUPPORT_EWM_CLOCK_REMOVE) && FSL_FEATURE_PCC_SUPPORT_EWM_CLOCK_REMOVE))
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_EnableClock(kCLOCK_Ewm0);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+#endif
+ value = EWM_CTRL_EWMEN(config->enableEwm) | EWM_CTRL_ASSIN(config->setInputAssertLogic) |
+ EWM_CTRL_INEN(config->enableEwmInput) | EWM_CTRL_INTEN(config->enableInterrupt);
+#if defined(FSL_FEATURE_EWM_HAS_PRESCALER) && FSL_FEATURE_EWM_HAS_PRESCALER
+ base->CLKPRESCALER = config->prescaler;
+#endif /* FSL_FEATURE_EWM_HAS_PRESCALER */
+
+#if defined(FSL_FEATURE_EWM_HAS_CLOCK_SELECT) && FSL_FEATURE_EWM_HAS_CLOCK_SELECT
+ base->CLKCTRL = config->clockSource;
+#endif /* FSL_FEATURE_EWM_HAS_CLOCK_SELECT*/
+
+ base->CMPL = config->compareLowValue;
+ base->CMPH = config->compareHighValue;
+ base->CTRL = value;
+}
+
+void EWM_Deinit(EWM_Type *base)
+{
+ EWM_DisableInterrupts(base, kEWM_InterruptEnable);
+#if !((defined(FSL_FEATURE_SOC_PCC_COUNT) && FSL_FEATURE_SOC_PCC_COUNT) && \
+ (defined(FSL_FEATURE_PCC_SUPPORT_EWM_CLOCK_REMOVE) && FSL_FEATURE_PCC_SUPPORT_EWM_CLOCK_REMOVE))
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_DisableClock(kCLOCK_Ewm0);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+#endif /* FSL_FEATURE_PCC_SUPPORT_EWM_CLOCK_REMOVE */
+}
+
+void EWM_GetDefaultConfig(ewm_config_t *config)
+{
+ assert(config);
+
+ config->enableEwm = true;
+ config->enableEwmInput = false;
+ config->setInputAssertLogic = false;
+ config->enableInterrupt = false;
+#if defined(FSL_FEATURE_EWM_HAS_CLOCK_SELECT) && FSL_FEATURE_EWM_HAS_CLOCK_SELECT
+ config->clockSource = kEWM_LpoClockSource0;
+#endif /* FSL_FEATURE_EWM_HAS_CLOCK_SELECT*/
+#if defined(FSL_FEATURE_EWM_HAS_PRESCALER) && FSL_FEATURE_EWM_HAS_PRESCALER
+ config->prescaler = 0U;
+#endif /* FSL_FEATURE_EWM_HAS_PRESCALER */
+ config->compareLowValue = 0U;
+ config->compareHighValue = 0xFEU;
+}
+
+void EWM_Refresh(EWM_Type *base)
+{
+ uint32_t primaskValue = 0U;
+
+ /* Disable the global interrupt to protect refresh sequence */
+ primaskValue = DisableGlobalIRQ();
+ base->SERV = (uint8_t)0xB4U;
+ base->SERV = (uint8_t)0x2CU;
+ EnableGlobalIRQ(primaskValue);
+}
diff --git a/drivers/src/fsl_flash.c b/drivers/src/fsl_flash.c
new file mode 100644
index 0000000..f63e6c9
--- /dev/null
+++ b/drivers/src/fsl_flash.c
@@ -0,0 +1,3432 @@
+/*
+ * Copyright (c) 2015-2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsl_flash.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*!
+ * @name Misc utility defines
+ * @{
+ */
+/*! @brief Alignment utility. */
+#ifndef ALIGN_DOWN
+#define ALIGN_DOWN(x, a) ((x) & (uint32_t)(-((int32_t)(a))))
+#endif
+#ifndef ALIGN_UP
+#define ALIGN_UP(x, a) (-((int32_t)((uint32_t)(-((int32_t)(x))) & (uint32_t)(-((int32_t)(a))))))
+#endif
+
+/*! @brief Join bytes to word utility. */
+#define B1P4(b) (((uint32_t)(b)&0xFFU) << 24)
+#define B1P3(b) (((uint32_t)(b)&0xFFU) << 16)
+#define B1P2(b) (((uint32_t)(b)&0xFFU) << 8)
+#define B1P1(b) ((uint32_t)(b)&0xFFU)
+#define B2P3(b) (((uint32_t)(b)&0xFFFFU) << 16)
+#define B2P2(b) (((uint32_t)(b)&0xFFFFU) << 8)
+#define B2P1(b) ((uint32_t)(b)&0xFFFFU)
+#define B3P2(b) (((uint32_t)(b)&0xFFFFFFU) << 8)
+#define B3P1(b) ((uint32_t)(b)&0xFFFFFFU)
+#define BYTES_JOIN_TO_WORD_1_3(x, y) (B1P4(x) | B3P1(y))
+#define BYTES_JOIN_TO_WORD_2_2(x, y) (B2P3(x) | B2P1(y))
+#define BYTES_JOIN_TO_WORD_3_1(x, y) (B3P2(x) | B1P1(y))
+#define BYTES_JOIN_TO_WORD_1_1_2(x, y, z) (B1P4(x) | B1P3(y) | B2P1(z))
+#define BYTES_JOIN_TO_WORD_1_2_1(x, y, z) (B1P4(x) | B2P2(y) | B1P1(z))
+#define BYTES_JOIN_TO_WORD_2_1_1(x, y, z) (B2P3(x) | B1P2(y) | B1P1(z))
+#define BYTES_JOIN_TO_WORD_1_1_1_1(x, y, z, w) (B1P4(x) | B1P3(y) | B1P2(z) | B1P1(w))
+/*@}*/
+
+/*!
+ * @name Secondary flash configuration
+ * @{
+ */
+/*! @brief Indicates whether the secondary flash has its own protection register in flash module. */
+#if defined(FSL_FEATURE_FLASH_HAS_MULTIPLE_FLASH) && defined(FTFE_FPROTS_PROTS_MASK)
+#define FLASH_SSD_SECONDARY_FLASH_HAS_ITS_OWN_PROTECTION_REGISTER (1)
+#else
+#define FLASH_SSD_SECONDARY_FLASH_HAS_ITS_OWN_PROTECTION_REGISTER (0)
+#endif
+
+/*! @brief Indicates whether the secondary flash has its own Execute-Only access register in flash module. */
+#if defined(FSL_FEATURE_FLASH_HAS_MULTIPLE_FLASH) && defined(FTFE_FACSSS_SGSIZE_S_MASK)
+#define FLASH_SSD_SECONDARY_FLASH_HAS_ITS_OWN_ACCESS_REGISTER (1)
+#else
+#define FLASH_SSD_SECONDARY_FLASH_HAS_ITS_OWN_ACCESS_REGISTER (0)
+#endif
+/*@}*/
+
+/*!
+ * @name Flash cache ands speculation control defines
+ * @{
+ */
+#if defined(MCM_PLACR_CFCC_MASK) || defined(MCM_CPCR2_CCBC_MASK)
+#define FLASH_CACHE_IS_CONTROLLED_BY_MCM (1)
+#else
+#define FLASH_CACHE_IS_CONTROLLED_BY_MCM (0)
+#endif
+#if defined(FMC_PFB0CR_CINV_WAY_MASK) || defined(FMC_PFB01CR_CINV_WAY_MASK)
+#define FLASH_CACHE_IS_CONTROLLED_BY_FMC (1)
+#else
+#define FLASH_CACHE_IS_CONTROLLED_BY_FMC (0)
+#endif
+#if defined(MCM_PLACR_DFCS_MASK)
+#define FLASH_PREFETCH_SPECULATION_IS_CONTROLLED_BY_MCM (1)
+#else
+#define FLASH_PREFETCH_SPECULATION_IS_CONTROLLED_BY_MCM (0)
+#endif
+#if defined(MSCM_OCMDR_OCM1_MASK) || defined(MSCM_OCMDR_OCMC1_MASK)
+#define FLASH_PREFETCH_SPECULATION_IS_CONTROLLED_BY_MSCM (1)
+#else
+#define FLASH_PREFETCH_SPECULATION_IS_CONTROLLED_BY_MSCM (0)
+#endif
+#if defined(FMC_PFB0CR_S_INV_MASK) || defined(FMC_PFB0CR_S_B_INV_MASK) || defined(FMC_PFB01CR_S_INV_MASK) || \
+ defined(FMC_PFB01CR_S_B_INV_MASK)
+#define FLASH_PREFETCH_SPECULATION_IS_CONTROLLED_BY_FMC (1)
+#else
+#define FLASH_PREFETCH_SPECULATION_IS_CONTROLLED_BY_FMC (0)
+#endif
+/*@}*/
+
+/*! @brief Data flash IFR map Field*/
+#if defined(FSL_FEATURE_FLASH_IS_FTFE) && FSL_FEATURE_FLASH_IS_FTFE
+#define DFLASH_IFR_READRESOURCE_START_ADDRESS 0x8003F8U
+#else /* FSL_FEATURE_FLASH_IS_FTFL == 1 or FSL_FEATURE_FLASH_IS_FTFA = =1 */
+#define DFLASH_IFR_READRESOURCE_START_ADDRESS 0x8000F8U
+#endif
+
+/*!
+ * @name Reserved FlexNVM size (For a variety of purposes) defines
+ * @{
+ */
+#define FLEX_NVM_DFLASH_SIZE_FOR_DEPART_RESERVED 0xFFFFFFFFU
+#define FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_RESERVED 0xFFFFU
+/*@}*/
+
+/*!
+ * @name Flash Program Once Field defines
+ * @{
+ */
+#if defined(FSL_FEATURE_FLASH_IS_FTFA) && FSL_FEATURE_FLASH_IS_FTFA
+/* FTFA parts(eg. K80, KL80, L5K) support both 4-bytes and 8-bytes unit size */
+#define FLASH_PROGRAM_ONCE_MIN_ID_8BYTES \
+ 0x10U /* Minimum Index indcating one of Progam Once Fields which is accessed in 8-byte records */
+#define FLASH_PROGRAM_ONCE_MAX_ID_8BYTES \
+ 0x13U /* Maximum Index indcating one of Progam Once Fields which is accessed in 8-byte records */
+#define FLASH_PROGRAM_ONCE_IS_4BYTES_UNIT_SUPPORT 1
+#define FLASH_PROGRAM_ONCE_IS_8BYTES_UNIT_SUPPORT 1
+#elif defined(FSL_FEATURE_FLASH_IS_FTFE) && FSL_FEATURE_FLASH_IS_FTFE
+/* FTFE parts(eg. K65, KE18) only support 8-bytes unit size */
+#define FLASH_PROGRAM_ONCE_IS_4BYTES_UNIT_SUPPORT 0
+#define FLASH_PROGRAM_ONCE_IS_8BYTES_UNIT_SUPPORT 1
+#elif defined(FSL_FEATURE_FLASH_IS_FTFL) && FSL_FEATURE_FLASH_IS_FTFL
+/* FTFL parts(eg. K20) only support 4-bytes unit size */
+#define FLASH_PROGRAM_ONCE_IS_4BYTES_UNIT_SUPPORT 1
+#define FLASH_PROGRAM_ONCE_IS_8BYTES_UNIT_SUPPORT 0
+#endif
+/*@}*/
+
+/*!
+ * @name Flash security status defines
+ * @{
+ */
+#define FLASH_SECURITY_STATE_KEYEN 0x80U
+#define FLASH_SECURITY_STATE_UNSECURED 0x02U
+#define FLASH_NOT_SECURE 0x01U
+#define FLASH_SECURE_BACKDOOR_ENABLED 0x02U
+#define FLASH_SECURE_BACKDOOR_DISABLED 0x04U
+/*@}*/
+
+/*!
+ * @name Flash controller command numbers
+ * @{
+ */
+#define FTFx_VERIFY_BLOCK 0x00U /*!< RD1BLK*/
+#define FTFx_VERIFY_SECTION 0x01U /*!< RD1SEC*/
+#define FTFx_PROGRAM_CHECK 0x02U /*!< PGMCHK*/
+#define FTFx_READ_RESOURCE 0x03U /*!< RDRSRC*/
+#define FTFx_PROGRAM_LONGWORD 0x06U /*!< PGM4*/
+#define FTFx_PROGRAM_PHRASE 0x07U /*!< PGM8*/
+#define FTFx_ERASE_BLOCK 0x08U /*!< ERSBLK*/
+#define FTFx_ERASE_SECTOR 0x09U /*!< ERSSCR*/
+#define FTFx_PROGRAM_SECTION 0x0BU /*!< PGMSEC*/
+#define FTFx_GENERATE_CRC 0x0CU /*!< CRCGEN*/
+#define FTFx_VERIFY_ALL_BLOCK 0x40U /*!< RD1ALL*/
+#define FTFx_READ_ONCE 0x41U /*!< RDONCE or RDINDEX*/
+#define FTFx_PROGRAM_ONCE 0x43U /*!< PGMONCE or PGMINDEX*/
+#define FTFx_ERASE_ALL_BLOCK 0x44U /*!< ERSALL*/
+#define FTFx_SECURITY_BY_PASS 0x45U /*!< VFYKEY*/
+#define FTFx_SWAP_CONTROL 0x46U /*!< SWAP*/
+#define FTFx_ERASE_ALL_BLOCK_UNSECURE 0x49U /*!< ERSALLU*/
+#define FTFx_VERIFY_ALL_EXECUTE_ONLY_SEGMENT 0x4AU /*!< RD1XA*/
+#define FTFx_ERASE_ALL_EXECUTE_ONLY_SEGMENT 0x4BU /*!< ERSXA*/
+#define FTFx_PROGRAM_PARTITION 0x80U /*!< PGMPART)*/
+#define FTFx_SET_FLEXRAM_FUNCTION 0x81U /*!< SETRAM*/
+ /*@}*/
+
+/*!
+ * @name Common flash register info defines
+ * @{
+ */
+#if defined(FTFA)
+#define FTFx FTFA
+#define FTFx_BASE FTFA_BASE
+#define FTFx_FSTAT_CCIF_MASK FTFA_FSTAT_CCIF_MASK
+#define FTFx_FSTAT_RDCOLERR_MASK FTFA_FSTAT_RDCOLERR_MASK
+#define FTFx_FSTAT_ACCERR_MASK FTFA_FSTAT_ACCERR_MASK
+#define FTFx_FSTAT_FPVIOL_MASK FTFA_FSTAT_FPVIOL_MASK
+#define FTFx_FSTAT_MGSTAT0_MASK FTFA_FSTAT_MGSTAT0_MASK
+#define FTFx_FSEC_SEC_MASK FTFA_FSEC_SEC_MASK
+#define FTFx_FSEC_KEYEN_MASK FTFA_FSEC_KEYEN_MASK
+#if defined(FSL_FEATURE_FLASH_HAS_FLEX_RAM) && FSL_FEATURE_FLASH_HAS_FLEX_RAM
+#define FTFx_FCNFG_RAMRDY_MASK FTFA_FCNFG_RAMRDY_MASK
+#endif /* FSL_FEATURE_FLASH_HAS_FLEX_RAM */
+#if defined(FSL_FEATURE_FLASH_HAS_FLEX_NVM) && FSL_FEATURE_FLASH_HAS_FLEX_NVM
+#define FTFx_FCNFG_EEERDY_MASK FTFA_FCNFG_EEERDY_MASK
+#endif /* FSL_FEATURE_FLASH_HAS_FLEX_NVM */
+#elif defined(FTFE)
+#define FTFx FTFE
+#define FTFx_BASE FTFE_BASE
+#define FTFx_FSTAT_CCIF_MASK FTFE_FSTAT_CCIF_MASK
+#define FTFx_FSTAT_RDCOLERR_MASK FTFE_FSTAT_RDCOLERR_MASK
+#define FTFx_FSTAT_ACCERR_MASK FTFE_FSTAT_ACCERR_MASK
+#define FTFx_FSTAT_FPVIOL_MASK FTFE_FSTAT_FPVIOL_MASK
+#define FTFx_FSTAT_MGSTAT0_MASK FTFE_FSTAT_MGSTAT0_MASK
+#define FTFx_FSEC_SEC_MASK FTFE_FSEC_SEC_MASK
+#define FTFx_FSEC_KEYEN_MASK FTFE_FSEC_KEYEN_MASK
+#if defined(FSL_FEATURE_FLASH_HAS_FLEX_RAM) && FSL_FEATURE_FLASH_HAS_FLEX_RAM
+#define FTFx_FCNFG_RAMRDY_MASK FTFE_FCNFG_RAMRDY_MASK
+#endif /* FSL_FEATURE_FLASH_HAS_FLEX_RAM */
+#if defined(FSL_FEATURE_FLASH_HAS_FLEX_NVM) && FSL_FEATURE_FLASH_HAS_FLEX_NVM
+#define FTFx_FCNFG_EEERDY_MASK FTFE_FCNFG_EEERDY_MASK
+#endif /* FSL_FEATURE_FLASH_HAS_FLEX_NVM */
+#elif defined(FTFL)
+#define FTFx FTFL
+#define FTFx_BASE FTFL_BASE
+#define FTFx_FSTAT_CCIF_MASK FTFL_FSTAT_CCIF_MASK
+#define FTFx_FSTAT_RDCOLERR_MASK FTFL_FSTAT_RDCOLERR_MASK
+#define FTFx_FSTAT_ACCERR_MASK FTFL_FSTAT_ACCERR_MASK
+#define FTFx_FSTAT_FPVIOL_MASK FTFL_FSTAT_FPVIOL_MASK
+#define FTFx_FSTAT_MGSTAT0_MASK FTFL_FSTAT_MGSTAT0_MASK
+#define FTFx_FSEC_SEC_MASK FTFL_FSEC_SEC_MASK
+#define FTFx_FSEC_KEYEN_MASK FTFL_FSEC_KEYEN_MASK
+#if defined(FSL_FEATURE_FLASH_HAS_FLEX_RAM) && FSL_FEATURE_FLASH_HAS_FLEX_RAM
+#define FTFx_FCNFG_RAMRDY_MASK FTFL_FCNFG_RAMRDY_MASK
+#endif /* FSL_FEATURE_FLASH_HAS_FLEX_RAM */
+#if defined(FSL_FEATURE_FLASH_HAS_FLEX_NVM) && FSL_FEATURE_FLASH_HAS_FLEX_NVM
+#define FTFx_FCNFG_EEERDY_MASK FTFL_FCNFG_EEERDY_MASK
+#endif /* FSL_FEATURE_FLASH_HAS_FLEX_NVM */
+#else
+#error "Unknown flash controller"
+#endif
+/*@}*/
+
+/*!
+ * @name Common flash register access info defines
+ * @{
+ */
+#define FTFx_FCCOB3_REG (FTFx->FCCOB3)
+#define FTFx_FCCOB5_REG (FTFx->FCCOB5)
+#define FTFx_FCCOB6_REG (FTFx->FCCOB6)
+#define FTFx_FCCOB7_REG (FTFx->FCCOB7)
+
+#if defined(FTFA_FPROTH0_PROT_MASK) || defined(FTFE_FPROTH0_PROT_MASK) || defined(FTFL_FPROTH0_PROT_MASK)
+#define FTFx_FPROT_HIGH_REG (FTFx->FPROTH3)
+#define FTFx_FPROTH3_REG (FTFx->FPROTH3)
+#define FTFx_FPROTH2_REG (FTFx->FPROTH2)
+#define FTFx_FPROTH1_REG (FTFx->FPROTH1)
+#define FTFx_FPROTH0_REG (FTFx->FPROTH0)
+#endif
+
+#if defined(FTFA_FPROTL0_PROT_MASK) || defined(FTFE_FPROTL0_PROT_MASK) || defined(FTFL_FPROTL0_PROT_MASK)
+#define FTFx_FPROT_LOW_REG (FTFx->FPROTL3)
+#define FTFx_FPROTL3_REG (FTFx->FPROTL3)
+#define FTFx_FPROTL2_REG (FTFx->FPROTL2)
+#define FTFx_FPROTL1_REG (FTFx->FPROTL1)
+#define FTFx_FPROTL0_REG (FTFx->FPROTL0)
+#elif defined(FTFA_FPROT0_PROT_MASK) || defined(FTFE_FPROT0_PROT_MASK) || defined(FTFL_FPROT0_PROT_MASK)
+#define FTFx_FPROT_LOW_REG (FTFx->FPROT3)
+#define FTFx_FPROTL3_REG (FTFx->FPROT3)
+#define FTFx_FPROTL2_REG (FTFx->FPROT2)
+#define FTFx_FPROTL1_REG (FTFx->FPROT1)
+#define FTFx_FPROTL0_REG (FTFx->FPROT0)
+#endif
+
+#if FLASH_SSD_IS_SECONDARY_FLASH_ENABLED && FLASH_SSD_SECONDARY_FLASH_HAS_ITS_OWN_PROTECTION_REGISTER
+#define FTFx_FPROTSH_REG (FTFx->FPROTSH)
+#define FTFx_FPROTSL_REG (FTFx->FPROTSL)
+#endif
+
+#define FTFx_XACCH3_REG (FTFx->XACCH3)
+#define FTFx_XACCL3_REG (FTFx->XACCL3)
+
+#if FLASH_SSD_IS_SECONDARY_FLASH_ENABLED && FLASH_SSD_SECONDARY_FLASH_HAS_ITS_OWN_ACCESS_REGISTER
+#define FTFx_XACCSH_REG (FTFx->XACCSH)
+#define FTFx_XACCSL_REG (FTFx->XACCSL)
+#endif
+/*@}*/
+
+/*!
+ * @brief Enumeration for access segment property.
+ */
+enum _flash_access_segment_property
+{
+ kFLASH_AccessSegmentBase = 256UL,
+};
+
+/*!
+ * @brief Enumeration for flash config area.
+ */
+enum _flash_config_area_range
+{
+ kFLASH_ConfigAreaStart = 0x400U,
+ kFLASH_ConfigAreaEnd = 0x40FU
+};
+
+/*!
+ * @name Flash register access type defines
+ * @{
+ */
+#define FTFx_REG8_ACCESS_TYPE volatile uint8_t *
+#define FTFx_REG32_ACCESS_TYPE volatile uint32_t *
+/*@}*/
+
+/*!
+ * @brief MCM cache register access info defines.
+ */
+#if defined(MCM_PLACR_CFCC_MASK)
+#define MCM_CACHE_CLEAR_MASK MCM_PLACR_CFCC_MASK
+#define MCM_CACHE_CLEAR_SHIFT MCM_PLACR_CFCC_SHIFT
+#if defined(MCM)
+#define MCM0_CACHE_REG MCM->PLACR
+#elif defined(MCM0)
+#define MCM0_CACHE_REG MCM0->PLACR
+#endif
+#if defined(MCM1)
+#define MCM1_CACHE_REG MCM1->PLACR
+#endif
+#elif defined(MCM_CPCR2_CCBC_MASK)
+#define MCM_CACHE_CLEAR_MASK MCM_CPCR2_CCBC_MASK
+#define MCM_CACHE_CLEAR_SHIFT MCM_CPCR2_CCBC_SHIFT
+#if defined(MCM)
+#define MCM0_CACHE_REG MCM->CPCR2
+#elif defined(MCM0)
+#define MCM0_CACHE_REG MCM0->CPCR2
+#endif
+#if defined(MCM1)
+#define MCM1_CACHE_REG MCM1->CPCR2
+#endif
+#endif
+
+/*!
+ * @brief MSCM cache register access info defines.
+ */
+#if defined(MSCM_OCMDR_OCM1_MASK)
+#define MSCM_SPECULATION_DISABLE_MASK MSCM_OCMDR_OCM1_MASK
+#define MSCM_SPECULATION_DISABLE_SHIFT MSCM_OCMDR_OCM1_SHIFT
+#define MSCM_SPECULATION_DISABLE(x) MSCM_OCMDR_OCM1(x)
+#elif defined(MSCM_OCMDR_OCMC1_MASK)
+#define MSCM_SPECULATION_DISABLE_MASK MSCM_OCMDR_OCMC1_MASK
+#define MSCM_SPECULATION_DISABLE_SHIFT MSCM_OCMDR_OCMC1_SHIFT
+#define MSCM_SPECULATION_DISABLE(x) MSCM_OCMDR_OCMC1(x)
+#endif
+
+/*!
+ * @brief MSCM prefetch speculation defines.
+ */
+#define MSCM_OCMDR_OCMC1_DFDS_MASK (0x10U)
+#define MSCM_OCMDR_OCMC1_DFCS_MASK (0x20U)
+
+#define MSCM_OCMDR_OCMC1_DFDS_SHIFT (4U)
+#define MSCM_OCMDR_OCMC1_DFCS_SHIFT (5U)
+
+/*!
+ * @brief Flash size encoding rule.
+ */
+#define FLASH_MEMORY_SIZE_ENCODING_RULE_K1_2 (0x00U)
+#define FLASH_MEMORY_SIZE_ENCODING_RULE_K3 (0x01U)
+
+#if defined(K32W042S1M2_M0P_SERIES) || defined(K32W042S1M2_M4_SERIES)
+#define FLASH_MEMORY_SIZE_ENCODING_RULE (FLASH_MEMORY_SIZE_ENCODING_RULE_K3)
+#else
+#define FLASH_MEMORY_SIZE_ENCODING_RULE (FLASH_MEMORY_SIZE_ENCODING_RULE_K1_2)
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+#if FLASH_DRIVER_IS_FLASH_RESIDENT
+/*! @brief Copy flash_run_command() to RAM*/
+static void copy_flash_run_command(uint32_t *flashRunCommand);
+/*! @brief Copy flash_cache_clear_command() to RAM*/
+static void copy_flash_common_bit_operation(uint32_t *flashCommonBitOperation);
+/*! @brief Check whether flash execute-in-ram functions are ready*/
+static status_t flash_check_execute_in_ram_function_info(flash_config_t *config);
+#endif /* FLASH_DRIVER_IS_FLASH_RESIDENT */
+
+/*! @brief Internal function Flash command sequence. Called by driver APIs only*/
+static status_t flash_command_sequence(flash_config_t *config);
+
+/*! @brief Perform the cache clear to the flash*/
+void flash_cache_clear(flash_config_t *config);
+
+/*! @brief Process the cache to the flash*/
+static void flash_cache_clear_process(flash_config_t *config, flash_cache_clear_process_t process);
+
+/*! @brief Validates the range and alignment of the given address range.*/
+static status_t flash_check_range(flash_config_t *config,
+ uint32_t startAddress,
+ uint32_t lengthInBytes,
+ uint32_t alignmentBaseline);
+/*! @brief Gets the right address, sector and block size of current flash type which is indicated by address.*/
+static status_t flash_get_matched_operation_info(flash_config_t *config,
+ uint32_t address,
+ flash_operation_config_t *info);
+/*! @brief Validates the given user key for flash erase APIs.*/
+static status_t flash_check_user_key(uint32_t key);
+
+#if FLASH_SSD_IS_FLEXNVM_ENABLED
+/*! @brief Updates FlexNVM memory partition status according to data flash 0 IFR.*/
+static status_t flash_update_flexnvm_memory_partition_status(flash_config_t *config);
+#endif /* FLASH_SSD_IS_FLEXNVM_ENABLED */
+
+#if defined(FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD) && FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD
+/*! @brief Validates the range of the given resource address.*/
+static status_t flash_check_resource_range(uint32_t start,
+ uint32_t lengthInBytes,
+ uint32_t alignmentBaseline,
+ flash_read_resource_option_t option);
+#endif /* FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD */
+
+#if defined(FSL_FEATURE_FLASH_HAS_SWAP_CONTROL_CMD) && FSL_FEATURE_FLASH_HAS_SWAP_CONTROL_CMD
+/*! @brief Validates the gived swap control option.*/
+static status_t flash_check_swap_control_option(flash_swap_control_option_t option);
+#endif /* FSL_FEATURE_FLASH_HAS_SWAP_CONTROL_CMD */
+
+#if defined(FSL_FEATURE_FLASH_HAS_PFLASH_BLOCK_SWAP) && FSL_FEATURE_FLASH_HAS_PFLASH_BLOCK_SWAP
+/*! @brief Validates the gived address to see if it is equal to swap indicator address in pflash swap IFR.*/
+static status_t flash_validate_swap_indicator_address(flash_config_t *config, uint32_t address);
+#endif /* FSL_FEATURE_FLASH_HAS_PFLASH_BLOCK_SWAP */
+
+#if defined(FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD) && FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD
+/*! @brief Validates the gived flexram function option.*/
+static inline status_t flasn_check_flexram_function_option_range(flash_flexram_function_option_t option);
+#endif /* FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD */
+
+/*! @brief Gets the flash protection information (region size, region count).*/
+static status_t flash_get_protection_info(flash_config_t *config, flash_protection_config_t *info);
+
+#if defined(FSL_FEATURE_FLASH_HAS_ACCESS_CONTROL) && FSL_FEATURE_FLASH_HAS_ACCESS_CONTROL
+/*! @brief Gets the flash Execute-Only access information (Segment size, Segment count).*/
+static status_t flash_get_access_info(flash_config_t *config, flash_access_config_t *info);
+#endif /* FSL_FEATURE_FLASH_HAS_ACCESS_CONTROL */
+
+#if FLASH_CACHE_IS_CONTROLLED_BY_MCM
+/*! @brief Performs the cache clear to the flash by MCM.*/
+void mcm_flash_cache_clear(flash_config_t *config);
+#endif /* FLASH_CACHE_IS_CONTROLLED_BY_MCM */
+
+#if FLASH_CACHE_IS_CONTROLLED_BY_FMC
+/*! @brief Performs the cache clear to the flash by FMC.*/
+void fmc_flash_cache_clear(void);
+#endif /* FLASH_CACHE_IS_CONTROLLED_BY_FMC */
+
+#if FLASH_PREFETCH_SPECULATION_IS_CONTROLLED_BY_MSCM
+/*! @brief Sets the prefetch speculation buffer to the flash by MSCM.*/
+void mscm_flash_prefetch_speculation_enable(bool enable);
+#endif /* FLASH_PREFETCH_SPECULATION_IS_CONTROLLED_BY_MSCM */
+
+#if FLASH_PREFETCH_SPECULATION_IS_CONTROLLED_BY_FMC
+/*! @brief Performs the prefetch speculation buffer clear to the flash by FMC.*/
+void fmc_flash_prefetch_speculation_clear(void);
+#endif /* FLASH_PREFETCH_SPECULATION_IS_CONTROLLED_BY_FMC */
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*! @brief Access to FTFx->FCCOB */
+volatile uint32_t *const kFCCOBx = (volatile uint32_t *)&FTFx_FCCOB3_REG;
+/*! @brief Access to FTFx->FPROT */
+volatile uint32_t *const kFPROTL = (volatile uint32_t *)&FTFx_FPROT_LOW_REG;
+#if defined(FTFx_FPROT_HIGH_REG)
+volatile uint32_t *const kFPROTH = (volatile uint32_t *)&FTFx_FPROT_HIGH_REG;
+#endif
+
+#if FLASH_SSD_IS_SECONDARY_FLASH_ENABLED && FLASH_SSD_SECONDARY_FLASH_HAS_ITS_OWN_PROTECTION_REGISTER
+volatile uint8_t *const kFPROTSL = (volatile uint8_t *)&FTFx_FPROTSL_REG;
+volatile uint8_t *const kFPROTSH = (volatile uint8_t *)&FTFx_FPROTSH_REG;
+#endif
+
+#if FLASH_DRIVER_IS_FLASH_RESIDENT
+/*! @brief A function pointer used to point to relocated flash_run_command() */
+static void (*callFlashRunCommand)(FTFx_REG8_ACCESS_TYPE ftfx_fstat);
+/*! @brief A function pointer used to point to relocated flash_common_bit_operation() */
+static void (*callFlashCommonBitOperation)(FTFx_REG32_ACCESS_TYPE base,
+ uint32_t bitMask,
+ uint32_t bitShift,
+ uint32_t bitValue);
+
+/*!
+ * @brief Position independent code of flash_run_command()
+ *
+ * Note1: The prototype of C function is shown as below:
+ * @code
+ * void flash_run_command(FTFx_REG8_ACCESS_TYPE ftfx_fstat)
+ * {
+ * // clear CCIF bit
+ * *ftfx_fstat = FTFx_FSTAT_CCIF_MASK;
+ *
+ * // Check CCIF bit of the flash status register, wait till it is set.
+ * // IP team indicates that this loop will always complete.
+ * while (!((*ftfx_fstat) & FTFx_FSTAT_CCIF_MASK))
+ * {
+ * }
+ * }
+ * @endcode
+ * Note2: The binary code is generated by IAR 7.70.1
+ */
+const static uint16_t s_flashRunCommandFunctionCode[] = {
+ 0x2180, /* MOVS R1, #128 ; 0x80 */
+ 0x7001, /* STRB R1, [R0] */
+ /* @4: */
+ 0x7802, /* LDRB R2, [R0] */
+ 0x420a, /* TST R2, R1 */
+ 0xd0fc, /* BEQ.N @4 */
+ 0x4770 /* BX LR */
+};
+
+/*!
+ * @brief Position independent code of flash_common_bit_operation()
+ *
+ * Note1: The prototype of C function is shown as below:
+ * @code
+ * void flash_common_bit_operation(FTFx_REG32_ACCESS_TYPE base, uint32_t bitMask, uint32_t bitShift, uint32_t
+ * bitValue)
+ * {
+ * if (bitMask)
+ * {
+ * uint32_t value = (((uint32_t)(((uint32_t)(bitValue)) << bitShift)) & bitMask);
+ * *base = (*base & (~bitMask)) | value;
+ * }
+ *
+ * __ISB();
+ * __DSB();
+ * }
+ * @endcode
+ * Note2: The binary code is generated by IAR 7.70.1
+ */
+const static uint16_t s_flashCommonBitOperationFunctionCode[] = {
+ 0xb510, /* PUSH {R4, LR} */
+ 0x2900, /* CMP R1, #0 */
+ 0xd005, /* BEQ.N @12 */
+ 0x6804, /* LDR R4, [R0] */
+ 0x438c, /* BICS R4, R4, R1 */
+ 0x4093, /* LSLS R3, R3, R2 */
+ 0x4019, /* ANDS R1, R1, R3 */
+ 0x4321, /* ORRS R1, R1, R4 */
+ 0x6001, /* STR R1, [R0] */
+ /* @12: */
+ 0xf3bf, 0x8f6f, /* ISB */
+ 0xf3bf, 0x8f4f, /* DSB */
+ 0xbd10 /* POP {R4, PC} */
+};
+#endif /* FLASH_DRIVER_IS_FLASH_RESIDENT */
+
+#if (FLASH_DRIVER_IS_FLASH_RESIDENT && !FLASH_DRIVER_IS_EXPORTED)
+/*! @brief A static buffer used to hold flash_run_command() */
+static uint32_t s_flashRunCommand[kFLASH_ExecuteInRamFunctionMaxSizeInWords];
+/*! @brief A static buffer used to hold flash_common_bit_operation() */
+static uint32_t s_flashCommonBitOperation[kFLASH_ExecuteInRamFunctionMaxSizeInWords];
+/*! @brief Flash execute-in-ram function information */
+static flash_execute_in_ram_function_config_t s_flashExecuteInRamFunctionInfo;
+#endif
+
+/*!
+ * @brief Table of pflash sizes.
+ *
+ * The index into this table is the value of the SIM_FCFG1.PFSIZE bitfield.
+ *
+ * The values in this table have been right shifted 10 bits so that they will all fit within
+ * an 16-bit integer. To get the actual flash density, you must left shift the looked up value
+ * by 10 bits.
+ *
+ * Elements of this table have a value of 0 in cases where the PFSIZE bitfield value is
+ * reserved.
+ *
+ * Code to use the table:
+ * @code
+ * uint8_t pfsize = (SIM->FCFG1 & SIM_FCFG1_PFSIZE_MASK) >> SIM_FCFG1_PFSIZE_SHIFT;
+ * flashDensity = ((uint32_t)kPFlashDensities[pfsize]) << 10;
+ * @endcode
+ */
+#if (FLASH_MEMORY_SIZE_ENCODING_RULE == FLASH_MEMORY_SIZE_ENCODING_RULE_K1_2)
+const uint16_t kPFlashDensities[] = {
+ 8, /* 0x0 - 8192, 8KB */
+ 16, /* 0x1 - 16384, 16KB */
+ 24, /* 0x2 - 24576, 24KB */
+ 32, /* 0x3 - 32768, 32KB */
+ 48, /* 0x4 - 49152, 48KB */
+ 64, /* 0x5 - 65536, 64KB */
+ 96, /* 0x6 - 98304, 96KB */
+ 128, /* 0x7 - 131072, 128KB */
+ 192, /* 0x8 - 196608, 192KB */
+ 256, /* 0x9 - 262144, 256KB */
+ 384, /* 0xa - 393216, 384KB */
+ 512, /* 0xb - 524288, 512KB */
+ 768, /* 0xc - 786432, 768KB */
+ 1024, /* 0xd - 1048576, 1MB */
+ 1536, /* 0xe - 1572864, 1.5MB */
+ /* 2048, 0xf - 2097152, 2MB */
+};
+#elif(FLASH_MEMORY_SIZE_ENCODING_RULE == FLASH_MEMORY_SIZE_ENCODING_RULE_K3)
+const uint16_t kPFlashDensities[] = {
+ 0, /* 0x0 - undefined */
+ 0, /* 0x1 - undefined */
+ 0, /* 0x2 - undefined */
+ 0, /* 0x3 - undefined */
+ 0, /* 0x4 - undefined */
+ 0, /* 0x5 - undefined */
+ 0, /* 0x6 - undefined */
+ 0, /* 0x7 - undefined */
+ 0, /* 0x8 - undefined */
+ 0, /* 0x9 - undefined */
+ 256, /* 0xa - 262144, 256KB */
+ 0, /* 0xb - undefined */
+ 1024, /* 0xc - 1048576, 1MB */
+ 0, /* 0xd - undefined */
+ 0, /* 0xe - undefined */
+ 0, /* 0xf - undefined */
+};
+#endif
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+status_t FLASH_Init(flash_config_t *config)
+{
+ if (config == NULL)
+ {
+ return kStatus_FLASH_InvalidArgument;
+ }
+
+#if FLASH_SSD_IS_SECONDARY_FLASH_ENABLED
+ if (config->FlashMemoryIndex == (uint8_t)kFLASH_MemoryIndexSecondaryFlash)
+ {
+/* calculate the flash density from SIM_FCFG1.PFSIZE */
+#if defined(SIM_FCFG1_CORE1_PFSIZE_MASK)
+ uint32_t flashDensity;
+ uint8_t pfsize = (SIM->FCFG1 & SIM_FCFG1_CORE1_PFSIZE_MASK) >> SIM_FCFG1_CORE1_PFSIZE_SHIFT;
+ if (pfsize == 0xf)
+ {
+ flashDensity = FSL_FEATURE_FLASH_PFLASH_1_BLOCK_COUNT * FSL_FEATURE_FLASH_PFLASH_1_BLOCK_SIZE;
+ }
+ else
+ {
+ flashDensity = ((uint32_t)kPFlashDensities[pfsize]) << 10;
+ }
+ config->PFlashTotalSize = flashDensity;
+#else
+ /* Unused code to solve MISRA-C issue*/
+ config->PFlashBlockBase = kPFlashDensities[0];
+ config->PFlashTotalSize = FSL_FEATURE_FLASH_PFLASH_1_BLOCK_COUNT * FSL_FEATURE_FLASH_PFLASH_1_BLOCK_SIZE;
+#endif
+ config->PFlashBlockBase = FSL_FEATURE_FLASH_PFLASH_1_START_ADDRESS;
+ config->PFlashBlockCount = FSL_FEATURE_FLASH_PFLASH_1_BLOCK_COUNT;
+ config->PFlashSectorSize = FSL_FEATURE_FLASH_PFLASH_1_BLOCK_SECTOR_SIZE;
+ }
+ else
+#endif /* FLASH_SSD_IS_SECONDARY_FLASH_ENABLED */
+ {
+ uint32_t flashDensity;
+
+/* calculate the flash density from SIM_FCFG1.PFSIZE */
+#if defined(SIM_FCFG1_CORE0_PFSIZE_MASK)
+ uint8_t pfsize = (SIM->FCFG1 & SIM_FCFG1_CORE0_PFSIZE_MASK) >> SIM_FCFG1_CORE0_PFSIZE_SHIFT;
+#elif defined(SIM_FCFG1_PFSIZE_MASK)
+ uint8_t pfsize = (SIM->FCFG1 & SIM_FCFG1_PFSIZE_MASK) >> SIM_FCFG1_PFSIZE_SHIFT;
+#else
+#error "Unknown flash size"
+#endif
+ /* PFSIZE=0xf means that on customer parts the IFR was not correctly programmed.
+ * We just use the pre-defined flash size in feature file here to support pre-production parts */
+ if (pfsize == 0xf)
+ {
+ flashDensity = FSL_FEATURE_FLASH_PFLASH_BLOCK_COUNT * FSL_FEATURE_FLASH_PFLASH_BLOCK_SIZE;
+ }
+ else
+ {
+ flashDensity = ((uint32_t)kPFlashDensities[pfsize]) << 10;
+ }
+
+ /* fill out a few of the structure members */
+ config->PFlashBlockBase = FSL_FEATURE_FLASH_PFLASH_START_ADDRESS;
+ config->PFlashTotalSize = flashDensity;
+ config->PFlashBlockCount = FSL_FEATURE_FLASH_PFLASH_BLOCK_COUNT;
+ config->PFlashSectorSize = FSL_FEATURE_FLASH_PFLASH_BLOCK_SECTOR_SIZE;
+ }
+
+ {
+#if defined(FSL_FEATURE_FLASH_HAS_ACCESS_CONTROL) && FSL_FEATURE_FLASH_HAS_ACCESS_CONTROL
+#if FLASH_SSD_IS_SECONDARY_FLASH_ENABLED && FLASH_SSD_SECONDARY_FLASH_HAS_ITS_OWN_ACCESS_REGISTER
+ if (config->FlashMemoryIndex == (uint8_t)kFLASH_MemoryIndexSecondaryFlash)
+ {
+ config->PFlashAccessSegmentSize = kFLASH_AccessSegmentBase << FTFx->FACSSS;
+ config->PFlashAccessSegmentCount = FTFx->FACSNS;
+ }
+ else
+#endif
+ {
+ config->PFlashAccessSegmentSize = kFLASH_AccessSegmentBase << FTFx->FACSS;
+ config->PFlashAccessSegmentCount = FTFx->FACSN;
+ }
+#else
+ config->PFlashAccessSegmentSize = 0;
+ config->PFlashAccessSegmentCount = 0;
+#endif /* FSL_FEATURE_FLASH_HAS_ACCESS_CONTROL */
+ }
+
+ config->PFlashCallback = NULL;
+
+/* copy required flash commands to RAM */
+#if (FLASH_DRIVER_IS_FLASH_RESIDENT && !FLASH_DRIVER_IS_EXPORTED)
+ if (kStatus_FLASH_Success != flash_check_execute_in_ram_function_info(config))
+ {
+ s_flashExecuteInRamFunctionInfo.activeFunctionCount = 0;
+ s_flashExecuteInRamFunctionInfo.flashRunCommand = s_flashRunCommand;
+ s_flashExecuteInRamFunctionInfo.flashCommonBitOperation = s_flashCommonBitOperation;
+ config->flashExecuteInRamFunctionInfo = &s_flashExecuteInRamFunctionInfo.activeFunctionCount;
+ FLASH_PrepareExecuteInRamFunctions(config);
+ }
+#endif
+
+ config->FlexRAMBlockBase = FSL_FEATURE_FLASH_FLEX_RAM_START_ADDRESS;
+ config->FlexRAMTotalSize = FSL_FEATURE_FLASH_FLEX_RAM_SIZE;
+
+#if FLASH_SSD_IS_FLEXNVM_ENABLED
+ {
+ status_t returnCode;
+ config->DFlashBlockBase = FSL_FEATURE_FLASH_FLEX_NVM_START_ADDRESS;
+ returnCode = flash_update_flexnvm_memory_partition_status(config);
+ if (returnCode != kStatus_FLASH_Success)
+ {
+ return returnCode;
+ }
+ }
+#endif
+
+ return kStatus_FLASH_Success;
+}
+
+status_t FLASH_SetCallback(flash_config_t *config, flash_callback_t callback)
+{
+ if (config == NULL)
+ {
+ return kStatus_FLASH_InvalidArgument;
+ }
+
+ config->PFlashCallback = callback;
+
+ return kStatus_FLASH_Success;
+}
+
+#if FLASH_DRIVER_IS_FLASH_RESIDENT
+status_t FLASH_PrepareExecuteInRamFunctions(flash_config_t *config)
+{
+ flash_execute_in_ram_function_config_t *flashExecuteInRamFunctionInfo;
+
+ if (config == NULL)
+ {
+ return kStatus_FLASH_InvalidArgument;
+ }
+
+ flashExecuteInRamFunctionInfo = (flash_execute_in_ram_function_config_t *)config->flashExecuteInRamFunctionInfo;
+
+ copy_flash_run_command(flashExecuteInRamFunctionInfo->flashRunCommand);
+ copy_flash_common_bit_operation(flashExecuteInRamFunctionInfo->flashCommonBitOperation);
+ flashExecuteInRamFunctionInfo->activeFunctionCount = kFLASH_ExecuteInRamFunctionTotalNum;
+
+ return kStatus_FLASH_Success;
+}
+#endif /* FLASH_DRIVER_IS_FLASH_RESIDENT */
+
+status_t FLASH_EraseAll(flash_config_t *config, uint32_t key)
+{
+ status_t returnCode;
+
+ if (config == NULL)
+ {
+ return kStatus_FLASH_InvalidArgument;
+ }
+
+ /* preparing passing parameter to erase all flash blocks */
+ kFCCOBx[0] = BYTES_JOIN_TO_WORD_1_3(FTFx_ERASE_ALL_BLOCK, 0xFFFFFFU);
+
+ /* Validate the user key */
+ returnCode = flash_check_user_key(key);
+ if (returnCode)
+ {
+ return returnCode;
+ }
+
+ flash_cache_clear_process(config, kFLASH_CacheClearProcessPre);
+
+ /* calling flash command sequence function to execute the command */
+ returnCode = flash_command_sequence(config);
+
+ flash_cache_clear(config);
+
+#if FLASH_SSD_IS_FLEXNVM_ENABLED
+ /* Data flash IFR will be erased by erase all command, so we need to
+ * update FlexNVM memory partition status synchronously */
+ if (returnCode == kStatus_FLASH_Success)
+ {
+ returnCode = flash_update_flexnvm_memory_partition_status(config);
+ }
+#endif
+
+ return returnCode;
+}
+
+status_t FLASH_Erase(flash_config_t *config, uint32_t start, uint32_t lengthInBytes, uint32_t key)
+{
+ uint32_t sectorSize;
+ flash_operation_config_t flashOperationInfo;
+ uint32_t endAddress; /* storing end address */
+ uint32_t numberOfSectors; /* number of sectors calculated by endAddress */
+ status_t returnCode;
+
+ flash_get_matched_operation_info(config, start, &flashOperationInfo);
+
+ /* Check the supplied address range. */
+ returnCode = flash_check_range(config, start, lengthInBytes, flashOperationInfo.sectorCmdAddressAligment);
+ if (returnCode)
+ {
+ return returnCode;
+ }
+
+ /* Validate the user key */
+ returnCode = flash_check_user_key(key);
+ if (returnCode)
+ {
+ return returnCode;
+ }
+
+ start = flashOperationInfo.convertedAddress;
+ sectorSize = flashOperationInfo.activeSectorSize;
+
+ /* calculating Flash end address */
+ endAddress = start + lengthInBytes - 1;
+
+ /* re-calculate the endAddress and align it to the start of the next sector
+ * which will be used in the comparison below */
+ if (endAddress % sectorSize)
+ {
+ numberOfSectors = endAddress / sectorSize + 1;
+ endAddress = numberOfSectors * sectorSize - 1;
+ }
+
+ flash_cache_clear_process(config, kFLASH_CacheClearProcessPre);
+
+ /* the start address will increment to the next sector address
+ * until it reaches the endAdddress */
+ while (start <= endAddress)
+ {
+ /* preparing passing parameter to erase a flash block */
+ kFCCOBx[0] = BYTES_JOIN_TO_WORD_1_3(FTFx_ERASE_SECTOR, start);
+
+ /* calling flash command sequence function to execute the command */
+ returnCode = flash_command_sequence(config);
+
+ /* calling flash callback function if it is available */
+ if (config->PFlashCallback)
+ {
+ config->PFlashCallback();
+ }
+
+ /* checking the success of command execution */
+ if (kStatus_FLASH_Success != returnCode)
+ {
+ break;
+ }
+ else
+ {
+ /* Increment to the next sector */
+ start += sectorSize;
+ }
+ }
+
+ flash_cache_clear(config);
+
+ return (returnCode);
+}
+
+#if defined(FSL_FEATURE_FLASH_HAS_ERASE_ALL_BLOCKS_UNSECURE_CMD) && FSL_FEATURE_FLASH_HAS_ERASE_ALL_BLOCKS_UNSECURE_CMD
+status_t FLASH_EraseAllUnsecure(flash_config_t *config, uint32_t key)
+{
+ status_t returnCode;
+
+ if (config == NULL)
+ {
+ return kStatus_FLASH_InvalidArgument;
+ }
+
+ /* Prepare passing parameter to erase all flash blocks (unsecure). */
+ kFCCOBx[0] = BYTES_JOIN_TO_WORD_1_3(FTFx_ERASE_ALL_BLOCK_UNSECURE, 0xFFFFFFU);
+
+ /* Validate the user key */
+ returnCode = flash_check_user_key(key);
+ if (returnCode)
+ {
+ return returnCode;
+ }
+
+ flash_cache_clear_process(config, kFLASH_CacheClearProcessPre);
+
+ /* calling flash command sequence function to execute the command */
+ returnCode = flash_command_sequence(config);
+
+ flash_cache_clear(config);
+
+#if FLASH_SSD_IS_FLEXNVM_ENABLED
+ /* Data flash IFR will be erased by erase all unsecure command, so we need to
+ * update FlexNVM memory partition status synchronously */
+ if (returnCode == kStatus_FLASH_Success)
+ {
+ returnCode = flash_update_flexnvm_memory_partition_status(config);
+ }
+#endif
+
+ return returnCode;
+}
+#endif /* FSL_FEATURE_FLASH_HAS_ERASE_ALL_BLOCKS_UNSECURE_CMD */
+
+status_t FLASH_EraseAllExecuteOnlySegments(flash_config_t *config, uint32_t key)
+{
+ status_t returnCode;
+
+ if (config == NULL)
+ {
+ return kStatus_FLASH_InvalidArgument;
+ }
+
+ /* preparing passing parameter to erase all execute-only segments
+ * 1st element for the FCCOB register */
+ kFCCOBx[0] = BYTES_JOIN_TO_WORD_1_3(FTFx_ERASE_ALL_EXECUTE_ONLY_SEGMENT, 0xFFFFFFU);
+
+ /* Validate the user key */
+ returnCode = flash_check_user_key(key);
+ if (returnCode)
+ {
+ return returnCode;
+ }
+
+ flash_cache_clear_process(config, kFLASH_CacheClearProcessPre);
+
+ /* calling flash command sequence function to execute the command */
+ returnCode = flash_command_sequence(config);
+
+ flash_cache_clear(config);
+
+ return returnCode;
+}
+
+status_t FLASH_Program(flash_config_t *config, uint32_t start, uint32_t *src, uint32_t lengthInBytes)
+{
+ status_t returnCode;
+ flash_operation_config_t flashOperationInfo;
+
+ if (src == NULL)
+ {
+ return kStatus_FLASH_InvalidArgument;
+ }
+
+ flash_get_matched_operation_info(config, start, &flashOperationInfo);
+
+ /* Check the supplied address range. */
+ returnCode = flash_check_range(config, start, lengthInBytes, flashOperationInfo.blockWriteUnitSize);
+ if (returnCode)
+ {
+ return returnCode;
+ }
+
+ start = flashOperationInfo.convertedAddress;
+
+ flash_cache_clear_process(config, kFLASH_CacheClearProcessPre);
+
+ while (lengthInBytes > 0)
+ {
+ /* preparing passing parameter to program the flash block */
+ kFCCOBx[1] = *src++;
+ if (4 == flashOperationInfo.blockWriteUnitSize)
+ {
+ kFCCOBx[0] = BYTES_JOIN_TO_WORD_1_3(FTFx_PROGRAM_LONGWORD, start);
+ }
+ else if (8 == flashOperationInfo.blockWriteUnitSize)
+ {
+ kFCCOBx[2] = *src++;
+ kFCCOBx[0] = BYTES_JOIN_TO_WORD_1_3(FTFx_PROGRAM_PHRASE, start);
+ }
+ else
+ {
+ }
+
+ /* calling flash command sequence function to execute the command */
+ returnCode = flash_command_sequence(config);
+
+ /* calling flash callback function if it is available */
+ if (config->PFlashCallback)
+ {
+ config->PFlashCallback();
+ }
+
+ /* checking for the success of command execution */
+ if (kStatus_FLASH_Success != returnCode)
+ {
+ break;
+ }
+ else
+ {
+ /* update start address for next iteration */
+ start += flashOperationInfo.blockWriteUnitSize;
+
+ /* update lengthInBytes for next iteration */
+ lengthInBytes -= flashOperationInfo.blockWriteUnitSize;
+ }
+ }
+
+ flash_cache_clear(config);
+
+ return (returnCode);
+}
+
+status_t FLASH_ProgramOnce(flash_config_t *config, uint32_t index, uint32_t *src, uint32_t lengthInBytes)
+{
+ status_t returnCode;
+
+ if ((config == NULL) || (src == NULL))
+ {
+ return kStatus_FLASH_InvalidArgument;
+ }
+
+ /* pass paramters to FTFx */
+ kFCCOBx[0] = BYTES_JOIN_TO_WORD_1_1_2(FTFx_PROGRAM_ONCE, index, 0xFFFFU);
+
+ kFCCOBx[1] = *src;
+
+/* Note: Have to seperate the first index from the rest if it equals 0
+ * to avoid a pointless comparison of unsigned int to 0 compiler warning */
+#if FLASH_PROGRAM_ONCE_IS_8BYTES_UNIT_SUPPORT
+#if FLASH_PROGRAM_ONCE_IS_4BYTES_UNIT_SUPPORT
+ if (((index == FLASH_PROGRAM_ONCE_MIN_ID_8BYTES) ||
+ /* Range check */
+ ((index >= FLASH_PROGRAM_ONCE_MIN_ID_8BYTES + 1) && (index <= FLASH_PROGRAM_ONCE_MAX_ID_8BYTES))) &&
+ (lengthInBytes == 8))
+#endif /* FLASH_PROGRAM_ONCE_IS_4BYTES_UNIT_SUPPORT */
+ {
+ kFCCOBx[2] = *(src + 1);
+ }
+#endif /* FLASH_PROGRAM_ONCE_IS_8BYTES_UNIT_SUPPORT */
+
+ flash_cache_clear_process(config, kFLASH_CacheClearProcessPre);
+
+ /* calling flash command sequence function to execute the command */
+ returnCode = flash_command_sequence(config);
+
+ flash_cache_clear(config);
+
+ return returnCode;
+}
+
+#if defined(FSL_FEATURE_FLASH_HAS_PROGRAM_SECTION_CMD) && FSL_FEATURE_FLASH_HAS_PROGRAM_SECTION_CMD
+status_t FLASH_ProgramSection(flash_config_t *config, uint32_t start, uint32_t *src, uint32_t lengthInBytes)
+{
+ status_t returnCode;
+ uint32_t sectorSize;
+ flash_operation_config_t flashOperationInfo;
+#if defined(FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD) && FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD
+ bool needSwitchFlexRamMode = false;
+#endif /* FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD */
+
+ if (src == NULL)
+ {
+ return kStatus_FLASH_InvalidArgument;
+ }
+
+ flash_get_matched_operation_info(config, start, &flashOperationInfo);
+
+ /* Check the supplied address range. */
+ returnCode = flash_check_range(config, start, lengthInBytes, flashOperationInfo.sectionCmdAddressAligment);
+ if (returnCode)
+ {
+ return returnCode;
+ }
+
+ start = flashOperationInfo.convertedAddress;
+ sectorSize = flashOperationInfo.activeSectorSize;
+
+#if defined(FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD) && FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD
+ /* Switch function of FlexRAM if needed */
+ if (!(FTFx->FCNFG & FTFx_FCNFG_RAMRDY_MASK))
+ {
+ needSwitchFlexRamMode = true;
+
+ returnCode = FLASH_SetFlexramFunction(config, kFLASH_FlexramFunctionOptionAvailableAsRam);
+ if (returnCode != kStatus_FLASH_Success)
+ {
+ return kStatus_FLASH_SetFlexramAsRamError;
+ }
+ }
+#endif /* FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD */
+
+ flash_cache_clear_process(config, kFLASH_CacheClearProcessPre);
+
+ while (lengthInBytes > 0)
+ {
+ /* Make sure the write operation doesn't span two sectors */
+ uint32_t endAddressOfCurrentSector = ALIGN_UP(start, sectorSize);
+ uint32_t lengthTobeProgrammedOfCurrentSector;
+ uint32_t currentOffset = 0;
+
+ if (endAddressOfCurrentSector == start)
+ {
+ endAddressOfCurrentSector += sectorSize;
+ }
+
+ if (lengthInBytes + start > endAddressOfCurrentSector)
+ {
+ lengthTobeProgrammedOfCurrentSector = endAddressOfCurrentSector - start;
+ }
+ else
+ {
+ lengthTobeProgrammedOfCurrentSector = lengthInBytes;
+ }
+
+ /* Program Current Sector */
+ while (lengthTobeProgrammedOfCurrentSector > 0)
+ {
+ /* Make sure the program size doesn't exceeds Acceleration RAM size */
+ uint32_t programSizeOfCurrentPass;
+ uint32_t numberOfPhases;
+
+ if (lengthTobeProgrammedOfCurrentSector > kFLASH_AccelerationRamSize)
+ {
+ programSizeOfCurrentPass = kFLASH_AccelerationRamSize;
+ }
+ else
+ {
+ programSizeOfCurrentPass = lengthTobeProgrammedOfCurrentSector;
+ }
+
+ /* Copy data to FlexRAM */
+ memcpy((void *)FSL_FEATURE_FLASH_FLEX_RAM_START_ADDRESS, src + currentOffset / 4, programSizeOfCurrentPass);
+ /* Set start address of the data to be programmed */
+ kFCCOBx[0] = BYTES_JOIN_TO_WORD_1_3(FTFx_PROGRAM_SECTION, start + currentOffset);
+ /* Set program size in terms of FEATURE_FLASH_SECTION_CMD_ADDRESS_ALIGMENT */
+ numberOfPhases = programSizeOfCurrentPass / flashOperationInfo.sectionCmdAddressAligment;
+
+ kFCCOBx[1] = BYTES_JOIN_TO_WORD_2_2(numberOfPhases, 0xFFFFU);
+
+ /* Peform command sequence */
+ returnCode = flash_command_sequence(config);
+
+ /* calling flash callback function if it is available */
+ if (config->PFlashCallback)
+ {
+ config->PFlashCallback();
+ }
+
+ if (returnCode != kStatus_FLASH_Success)
+ {
+ flash_cache_clear(config);
+ return returnCode;
+ }
+
+ lengthTobeProgrammedOfCurrentSector -= programSizeOfCurrentPass;
+ currentOffset += programSizeOfCurrentPass;
+ }
+
+ src += currentOffset / 4;
+ start += currentOffset;
+ lengthInBytes -= currentOffset;
+ }
+
+ flash_cache_clear(config);
+
+#if defined(FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD) && FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD
+ /* Restore function of FlexRAM if needed. */
+ if (needSwitchFlexRamMode)
+ {
+ returnCode = FLASH_SetFlexramFunction(config, kFLASH_FlexramFunctionOptionAvailableForEeprom);
+ if (returnCode != kStatus_FLASH_Success)
+ {
+ return kStatus_FLASH_RecoverFlexramAsEepromError;
+ }
+ }
+#endif /* FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD */
+
+ return returnCode;
+}
+#endif /* FSL_FEATURE_FLASH_HAS_PROGRAM_SECTION_CMD */
+
+#if FLASH_SSD_IS_FLEXNVM_ENABLED
+status_t FLASH_EepromWrite(flash_config_t *config, uint32_t start, uint8_t *src, uint32_t lengthInBytes)
+{
+ status_t returnCode;
+ bool needSwitchFlexRamMode = false;
+
+ if (config == NULL)
+ {
+ return kStatus_FLASH_InvalidArgument;
+ }
+
+ /* Validates the range of the given address */
+ if ((start < config->FlexRAMBlockBase) ||
+ ((start + lengthInBytes) > (config->FlexRAMBlockBase + config->EEpromTotalSize)))
+ {
+ return kStatus_FLASH_AddressError;
+ }
+
+ returnCode = kStatus_FLASH_Success;
+
+ /* Switch function of FlexRAM if needed */
+ if (!(FTFx->FCNFG & FTFx_FCNFG_EEERDY_MASK))
+ {
+ needSwitchFlexRamMode = true;
+
+ returnCode = FLASH_SetFlexramFunction(config, kFLASH_FlexramFunctionOptionAvailableForEeprom);
+ if (returnCode != kStatus_FLASH_Success)
+ {
+ return kStatus_FLASH_SetFlexramAsEepromError;
+ }
+ }
+
+ /* Write data to FlexRAM when it is used as EEPROM emulator */
+ while (lengthInBytes > 0)
+ {
+ if ((!(start & 0x3U)) && (lengthInBytes >= 4))
+ {
+ *(uint32_t *)start = *(uint32_t *)src;
+ start += 4;
+ src += 4;
+ lengthInBytes -= 4;
+ }
+ else if ((!(start & 0x1U)) && (lengthInBytes >= 2))
+ {
+ *(uint16_t *)start = *(uint16_t *)src;
+ start += 2;
+ src += 2;
+ lengthInBytes -= 2;
+ }
+ else
+ {
+ *(uint8_t *)start = *src;
+ start += 1;
+ src += 1;
+ lengthInBytes -= 1;
+ }
+ /* Wait till EEERDY bit is set */
+ while (!(FTFx->FCNFG & FTFx_FCNFG_EEERDY_MASK))
+ {
+ }
+
+ /* Check for protection violation error */
+ if (FTFx->FSTAT & FTFx_FSTAT_FPVIOL_MASK)
+ {
+ return kStatus_FLASH_ProtectionViolation;
+ }
+ }
+
+ /* Switch function of FlexRAM if needed */
+ if (needSwitchFlexRamMode)
+ {
+ returnCode = FLASH_SetFlexramFunction(config, kFLASH_FlexramFunctionOptionAvailableAsRam);
+ if (returnCode != kStatus_FLASH_Success)
+ {
+ return kStatus_FLASH_RecoverFlexramAsRamError;
+ }
+ }
+
+ return returnCode;
+}
+#endif /* FLASH_SSD_IS_FLEXNVM_ENABLED */
+
+#if defined(FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD) && FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD
+status_t FLASH_ReadResource(
+ flash_config_t *config, uint32_t start, uint32_t *dst, uint32_t lengthInBytes, flash_read_resource_option_t option)
+{
+ status_t returnCode;
+ flash_operation_config_t flashOperationInfo;
+
+ if ((config == NULL) || (dst == NULL))
+ {
+ return kStatus_FLASH_InvalidArgument;
+ }
+
+ flash_get_matched_operation_info(config, start, &flashOperationInfo);
+
+ /* Check the supplied address range. */
+ returnCode =
+ flash_check_resource_range(start, lengthInBytes, flashOperationInfo.resourceCmdAddressAligment, option);
+ if (returnCode != kStatus_FLASH_Success)
+ {
+ return returnCode;
+ }
+
+ while (lengthInBytes > 0)
+ {
+ /* preparing passing parameter */
+ kFCCOBx[0] = BYTES_JOIN_TO_WORD_1_3(FTFx_READ_RESOURCE, start);
+ if (flashOperationInfo.resourceCmdAddressAligment == 4)
+ {
+ kFCCOBx[2] = BYTES_JOIN_TO_WORD_1_3(option, 0xFFFFFFU);
+ }
+ else if (flashOperationInfo.resourceCmdAddressAligment == 8)
+ {
+ kFCCOBx[1] = BYTES_JOIN_TO_WORD_1_3(option, 0xFFFFFFU);
+ }
+ else
+ {
+ }
+
+ /* calling flash command sequence function to execute the command */
+ returnCode = flash_command_sequence(config);
+
+ if (kStatus_FLASH_Success != returnCode)
+ {
+ break;
+ }
+
+ /* fetch data */
+ *dst++ = kFCCOBx[1];
+ if (flashOperationInfo.resourceCmdAddressAligment == 8)
+ {
+ *dst++ = kFCCOBx[2];
+ }
+ /* update start address for next iteration */
+ start += flashOperationInfo.resourceCmdAddressAligment;
+ /* update lengthInBytes for next iteration */
+ lengthInBytes -= flashOperationInfo.resourceCmdAddressAligment;
+ }
+
+ return (returnCode);
+}
+#endif /* FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD */
+
+status_t FLASH_ReadOnce(flash_config_t *config, uint32_t index, uint32_t *dst, uint32_t lengthInBytes)
+{
+ status_t returnCode;
+
+ if ((config == NULL) || (dst == NULL))
+ {
+ return kStatus_FLASH_InvalidArgument;
+ }
+
+ /* pass paramters to FTFx */
+ kFCCOBx[0] = BYTES_JOIN_TO_WORD_1_1_2(FTFx_READ_ONCE, index, 0xFFFFU);
+
+ /* calling flash command sequence function to execute the command */
+ returnCode = flash_command_sequence(config);
+
+ if (kStatus_FLASH_Success == returnCode)
+ {
+ *dst = kFCCOBx[1];
+/* Note: Have to seperate the first index from the rest if it equals 0
+ * to avoid a pointless comparison of unsigned int to 0 compiler warning */
+#if FLASH_PROGRAM_ONCE_IS_8BYTES_UNIT_SUPPORT
+#if FLASH_PROGRAM_ONCE_IS_4BYTES_UNIT_SUPPORT
+ if (((index == FLASH_PROGRAM_ONCE_MIN_ID_8BYTES) ||
+ /* Range check */
+ ((index >= FLASH_PROGRAM_ONCE_MIN_ID_8BYTES + 1) && (index <= FLASH_PROGRAM_ONCE_MAX_ID_8BYTES))) &&
+ (lengthInBytes == 8))
+#endif /* FLASH_PROGRAM_ONCE_IS_4BYTES_UNIT_SUPPORT */
+ {
+ *(dst + 1) = kFCCOBx[2];
+ }
+#endif /* FLASH_PROGRAM_ONCE_IS_8BYTES_UNIT_SUPPORT */
+ }
+
+ return returnCode;
+}
+
+status_t FLASH_GetSecurityState(flash_config_t *config, flash_security_state_t *state)
+{
+ /* store data read from flash register */
+ uint8_t registerValue;
+
+ if ((config == NULL) || (state == NULL))
+ {
+ return kStatus_FLASH_InvalidArgument;
+ }
+
+ /* Get flash security register value */
+ registerValue = FTFx->FSEC;
+
+ /* check the status of the flash security bits in the security register */
+ if (FLASH_SECURITY_STATE_UNSECURED == (registerValue & FTFx_FSEC_SEC_MASK))
+ {
+ /* Flash in unsecured state */
+ *state = kFLASH_SecurityStateNotSecure;
+ }
+ else
+ {
+ /* Flash in secured state
+ * check for backdoor key security enable bit */
+ if (FLASH_SECURITY_STATE_KEYEN == (registerValue & FTFx_FSEC_KEYEN_MASK))
+ {
+ /* Backdoor key security enabled */
+ *state = kFLASH_SecurityStateBackdoorEnabled;
+ }
+ else
+ {
+ /* Backdoor key security disabled */
+ *state = kFLASH_SecurityStateBackdoorDisabled;
+ }
+ }
+
+ return (kStatus_FLASH_Success);
+}
+
+status_t FLASH_SecurityBypass(flash_config_t *config, const uint8_t *backdoorKey)
+{
+ uint8_t registerValue; /* registerValue */
+ status_t returnCode; /* return code variable */
+
+ if ((config == NULL) || (backdoorKey == NULL))
+ {
+ return kStatus_FLASH_InvalidArgument;
+ }
+
+ /* set the default return code as kStatus_Success */
+ returnCode = kStatus_FLASH_Success;
+
+ /* Get flash security register value */
+ registerValue = FTFx->FSEC;
+
+ /* Check to see if flash is in secure state (any state other than 0x2)
+ * If not, then skip this since flash is not secure */
+ if (0x02 != (registerValue & 0x03))
+ {
+ /* preparing passing parameter to erase a flash block */
+ kFCCOBx[0] = BYTES_JOIN_TO_WORD_1_3(FTFx_SECURITY_BY_PASS, 0xFFFFFFU);
+ kFCCOBx[1] = BYTES_JOIN_TO_WORD_1_1_1_1(backdoorKey[0], backdoorKey[1], backdoorKey[2], backdoorKey[3]);
+ kFCCOBx[2] = BYTES_JOIN_TO_WORD_1_1_1_1(backdoorKey[4], backdoorKey[5], backdoorKey[6], backdoorKey[7]);
+
+ /* calling flash command sequence function to execute the command */
+ returnCode = flash_command_sequence(config);
+ }
+
+ return (returnCode);
+}
+
+status_t FLASH_VerifyEraseAll(flash_config_t *config, flash_margin_value_t margin)
+{
+ if (config == NULL)
+ {
+ return kStatus_FLASH_InvalidArgument;
+ }
+
+ /* preparing passing parameter to verify all block command */
+ kFCCOBx[0] = BYTES_JOIN_TO_WORD_1_1_2(FTFx_VERIFY_ALL_BLOCK, margin, 0xFFFFU);
+
+ /* calling flash command sequence function to execute the command */
+ return flash_command_sequence(config);
+}
+
+status_t FLASH_VerifyErase(flash_config_t *config, uint32_t start, uint32_t lengthInBytes, flash_margin_value_t margin)
+{
+ /* Check arguments. */
+ uint32_t blockSize;
+ flash_operation_config_t flashOperationInfo;
+ uint32_t nextBlockStartAddress;
+ uint32_t remainingBytes;
+ status_t returnCode;
+
+ flash_get_matched_operation_info(config, start, &flashOperationInfo);
+
+ returnCode = flash_check_range(config, start, lengthInBytes, flashOperationInfo.sectionCmdAddressAligment);
+ if (returnCode)
+ {
+ return returnCode;
+ }
+
+ flash_get_matched_operation_info(config, start, &flashOperationInfo);
+ start = flashOperationInfo.convertedAddress;
+ blockSize = flashOperationInfo.activeBlockSize;
+
+ nextBlockStartAddress = ALIGN_UP(start, blockSize);
+ if (nextBlockStartAddress == start)
+ {
+ nextBlockStartAddress += blockSize;
+ }
+
+ remainingBytes = lengthInBytes;
+
+ while (remainingBytes)
+ {
+ uint32_t numberOfPhrases;
+ uint32_t verifyLength = nextBlockStartAddress - start;
+ if (verifyLength > remainingBytes)
+ {
+ verifyLength = remainingBytes;
+ }
+
+ numberOfPhrases = verifyLength / flashOperationInfo.sectionCmdAddressAligment;
+
+ /* Fill in verify section command parameters. */
+ kFCCOBx[0] = BYTES_JOIN_TO_WORD_1_3(FTFx_VERIFY_SECTION, start);
+ kFCCOBx[1] = BYTES_JOIN_TO_WORD_2_1_1(numberOfPhrases, margin, 0xFFU);
+
+ /* calling flash command sequence function to execute the command */
+ returnCode = flash_command_sequence(config);
+ if (returnCode)
+ {
+ return returnCode;
+ }
+
+ remainingBytes -= verifyLength;
+ start += verifyLength;
+ nextBlockStartAddress += blockSize;
+ }
+
+ return kStatus_FLASH_Success;
+}
+
+status_t FLASH_VerifyProgram(flash_config_t *config,
+ uint32_t start,
+ uint32_t lengthInBytes,
+ const uint32_t *expectedData,
+ flash_margin_value_t margin,
+ uint32_t *failedAddress,
+ uint32_t *failedData)
+{
+ status_t returnCode;
+ flash_operation_config_t flashOperationInfo;
+
+ if (expectedData == NULL)
+ {
+ return kStatus_FLASH_InvalidArgument;
+ }
+
+ flash_get_matched_operation_info(config, start, &flashOperationInfo);
+
+ returnCode = flash_check_range(config, start, lengthInBytes, flashOperationInfo.checkCmdAddressAligment);
+ if (returnCode)
+ {
+ return returnCode;
+ }
+
+ start = flashOperationInfo.convertedAddress;
+
+ while (lengthInBytes)
+ {
+ /* preparing passing parameter to program check the flash block */
+ kFCCOBx[0] = BYTES_JOIN_TO_WORD_1_3(FTFx_PROGRAM_CHECK, start);
+ kFCCOBx[1] = BYTES_JOIN_TO_WORD_1_3(margin, 0xFFFFFFU);
+ kFCCOBx[2] = *expectedData;
+
+ /* calling flash command sequence function to execute the command */
+ returnCode = flash_command_sequence(config);
+
+ /* checking for the success of command execution */
+ if (kStatus_FLASH_Success != returnCode)
+ {
+ if (failedAddress)
+ {
+ *failedAddress = start;
+ }
+ if (failedData)
+ {
+ *failedData = 0;
+ }
+ break;
+ }
+
+ lengthInBytes -= flashOperationInfo.checkCmdAddressAligment;
+ expectedData += flashOperationInfo.checkCmdAddressAligment / sizeof(*expectedData);
+ start += flashOperationInfo.checkCmdAddressAligment;
+ }
+
+ return (returnCode);
+}
+
+status_t FLASH_VerifyEraseAllExecuteOnlySegments(flash_config_t *config, flash_margin_value_t margin)
+{
+ if (config == NULL)
+ {
+ return kStatus_FLASH_InvalidArgument;
+ }
+
+ /* preparing passing parameter to verify erase all execute-only segments command */
+ kFCCOBx[0] = BYTES_JOIN_TO_WORD_1_1_2(FTFx_VERIFY_ALL_EXECUTE_ONLY_SEGMENT, margin, 0xFFFFU);
+
+ /* calling flash command sequence function to execute the command */
+ return flash_command_sequence(config);
+}
+
+status_t FLASH_IsProtected(flash_config_t *config,
+ uint32_t start,
+ uint32_t lengthInBytes,
+ flash_protection_state_t *protection_state)
+{
+ uint32_t endAddress; /* end address for protection check */
+ uint32_t regionCheckedCounter; /* increments each time the flash address was checked for
+ * protection status */
+ uint32_t regionCounter; /* incrementing variable used to increment through the flash
+ * protection regions */
+ uint32_t protectStatusCounter; /* increments each time a flash region was detected as protected */
+
+ uint8_t flashRegionProtectStatus[FSL_FEATURE_FLASH_PFLASH_PROTECTION_REGION_COUNT]; /* array of the protection
+ * status for each
+ * protection region */
+ uint32_t flashRegionAddress[FSL_FEATURE_FLASH_PFLASH_PROTECTION_REGION_COUNT +
+ 1]; /* array of the start addresses for each flash
+ * protection region. Note this is REGION_COUNT+1
+ * due to requiring the next start address after
+ * the end of flash for loop-check purposes below */
+ flash_protection_config_t flashProtectionInfo; /* flash protection information */
+ status_t returnCode;
+
+ if (protection_state == NULL)
+ {
+ return kStatus_FLASH_InvalidArgument;
+ }
+
+ /* Check the supplied address range. */
+ returnCode = flash_check_range(config, start, lengthInBytes, FSL_FEATURE_FLASH_PFLASH_BLOCK_WRITE_UNIT_SIZE);
+ if (returnCode)
+ {
+ return returnCode;
+ }
+
+ /* Get necessary flash protection information. */
+ returnCode = flash_get_protection_info(config, &flashProtectionInfo);
+ if (returnCode)
+ {
+ return returnCode;
+ }
+
+ /* calculating Flash end address */
+ endAddress = start + lengthInBytes;
+
+ /* populate the flashRegionAddress array with the start address of each flash region */
+ regionCounter = 0; /* make sure regionCounter is initialized to 0 first */
+
+ /* populate up to 33rd element of array, this is the next address after end of flash array */
+ while (regionCounter <= flashProtectionInfo.regionCount)
+ {
+ flashRegionAddress[regionCounter] =
+ flashProtectionInfo.regionBase + flashProtectionInfo.regionSize * regionCounter;
+ regionCounter++;
+ }
+
+ /* populate flashRegionProtectStatus array with status information
+ * Protection status for each region is stored in the FPROT[3:0] registers
+ * Each bit represents one region of flash
+ * 4 registers * 8-bits-per-register = 32-bits (32-regions)
+ * The convention is:
+ * FPROT3[bit 0] is the first protection region (start of flash memory)
+ * FPROT0[bit 7] is the last protection region (end of flash memory)
+ * regionCounter is used to determine which FPROT[3:0] register to check for protection status
+ * Note: FPROT=1 means NOT protected, FPROT=0 means protected */
+ regionCounter = 0; /* make sure regionCounter is initialized to 0 first */
+ while (regionCounter < flashProtectionInfo.regionCount)
+ {
+#if FLASH_SSD_IS_SECONDARY_FLASH_ENABLED && FLASH_SSD_SECONDARY_FLASH_HAS_ITS_OWN_PROTECTION_REGISTER
+ if (config->FlashMemoryIndex == (uint8_t)kFLASH_MemoryIndexSecondaryFlash)
+ {
+ if (regionCounter < 8)
+ {
+ flashRegionProtectStatus[regionCounter] = (FTFx_FPROTSL_REG >> regionCounter) & (0x01u);
+ }
+ else if ((regionCounter >= 8) && (regionCounter < 16))
+ {
+ flashRegionProtectStatus[regionCounter] = (FTFx_FPROTSH_REG >> (regionCounter - 8)) & (0x01u);
+ }
+ else
+ {
+ break;
+ }
+ }
+ else
+#endif
+ {
+ /* Note: So far protection region count may be 16/20/24/32/64 */
+ if (regionCounter < 8)
+ {
+ flashRegionProtectStatus[regionCounter] = (FTFx_FPROTL3_REG >> regionCounter) & (0x01u);
+ }
+ else if ((regionCounter >= 8) && (regionCounter < 16))
+ {
+ flashRegionProtectStatus[regionCounter] = (FTFx_FPROTL2_REG >> (regionCounter - 8)) & (0x01u);
+ }
+#if defined(FSL_FEATURE_FLASH_PFLASH_PROTECTION_REGION_COUNT) && (FSL_FEATURE_FLASH_PFLASH_PROTECTION_REGION_COUNT > 16)
+#if (FSL_FEATURE_FLASH_PFLASH_PROTECTION_REGION_COUNT == 20)
+ else if ((regionCounter >= 16) && (regionCounter < 20))
+ {
+ flashRegionProtectStatus[regionCounter] = (FTFx_FPROTL1_REG >> (regionCounter - 16)) & (0x01u);
+ }
+#else
+ else if ((regionCounter >= 16) && (regionCounter < 24))
+ {
+ flashRegionProtectStatus[regionCounter] = (FTFx_FPROTL1_REG >> (regionCounter - 16)) & (0x01u);
+ }
+#endif /* (FSL_FEATURE_FLASH_PFLASH_PROTECTION_REGION_COUNT == 20) */
+#endif
+#if defined(FSL_FEATURE_FLASH_PFLASH_PROTECTION_REGION_COUNT) && (FSL_FEATURE_FLASH_PFLASH_PROTECTION_REGION_COUNT > 24)
+ else if ((regionCounter >= 24) && (regionCounter < 32))
+ {
+ flashRegionProtectStatus[regionCounter] = (FTFx_FPROTL0_REG >> (regionCounter - 24)) & (0x01u);
+ }
+#endif
+#if defined(FSL_FEATURE_FLASH_PFLASH_PROTECTION_REGION_COUNT) && \
+ (FSL_FEATURE_FLASH_PFLASH_PROTECTION_REGION_COUNT == 64)
+ else if (regionCounter < 40)
+ {
+ flashRegionProtectStatus[regionCounter] = (FTFx_FPROTH3_REG >> (regionCounter - 32)) & (0x01u);
+ }
+ else if (regionCounter < 48)
+ {
+ flashRegionProtectStatus[regionCounter] = (FTFx_FPROTH2_REG >> (regionCounter - 40)) & (0x01u);
+ }
+ else if (regionCounter < 56)
+ {
+ flashRegionProtectStatus[regionCounter] = (FTFx_FPROTH1_REG >> (regionCounter - 48)) & (0x01u);
+ }
+ else if (regionCounter < 64)
+ {
+ flashRegionProtectStatus[regionCounter] = (FTFx_FPROTH0_REG >> (regionCounter - 56)) & (0x01u);
+ }
+#endif
+ else
+ {
+ break;
+ }
+ }
+
+ regionCounter++;
+ }
+
+ /* loop through the flash regions and check
+ * desired flash address range for protection status
+ * loop stops when it is detected that start has exceeded the endAddress */
+ regionCounter = 0; /* make sure regionCounter is initialized to 0 first */
+ regionCheckedCounter = 0;
+ protectStatusCounter = 0; /* make sure protectStatusCounter is initialized to 0 first */
+ while (start < endAddress)
+ {
+ /* check to see if the address falls within this protection region
+ * Note that if the entire flash is to be checked, the last protection
+ * region checked would consist of the last protection start address and
+ * the start address following the end of flash */
+ if ((start >= flashRegionAddress[regionCounter]) && (start < flashRegionAddress[regionCounter + 1]))
+ {
+ /* increment regionCheckedCounter to indicate this region was checked */
+ regionCheckedCounter++;
+
+ /* check the protection status of this region
+ * Note: FPROT=1 means NOT protected, FPROT=0 means protected */
+ if (!flashRegionProtectStatus[regionCounter])
+ {
+ /* increment protectStatusCounter to indicate this region is protected */
+ protectStatusCounter++;
+ }
+ start += flashProtectionInfo.regionSize; /* increment to an address within the next region */
+ }
+ regionCounter++; /* increment regionCounter to check for the next flash protection region */
+ }
+
+ /* if protectStatusCounter == 0, then no region of the desired flash region is protected */
+ if (protectStatusCounter == 0)
+ {
+ *protection_state = kFLASH_ProtectionStateUnprotected;
+ }
+ /* if protectStatusCounter == regionCheckedCounter, then each region checked was protected */
+ else if (protectStatusCounter == regionCheckedCounter)
+ {
+ *protection_state = kFLASH_ProtectionStateProtected;
+ }
+ /* if protectStatusCounter != regionCheckedCounter, then protection status is mixed
+ * In other words, some regions are protected while others are unprotected */
+ else
+ {
+ *protection_state = kFLASH_ProtectionStateMixed;
+ }
+
+ return (returnCode);
+}
+
+status_t FLASH_IsExecuteOnly(flash_config_t *config,
+ uint32_t start,
+ uint32_t lengthInBytes,
+ flash_execute_only_access_state_t *access_state)
+{
+#if defined(FSL_FEATURE_FLASH_HAS_ACCESS_CONTROL) && FSL_FEATURE_FLASH_HAS_ACCESS_CONTROL
+ flash_access_config_t flashAccessInfo; /* flash Execute-Only information */
+#endif /* FSL_FEATURE_FLASH_HAS_ACCESS_CONTROL */
+ status_t returnCode;
+
+ if (access_state == NULL)
+ {
+ return kStatus_FLASH_InvalidArgument;
+ }
+
+ /* Check the supplied address range. */
+ returnCode = flash_check_range(config, start, lengthInBytes, FSL_FEATURE_FLASH_PFLASH_BLOCK_WRITE_UNIT_SIZE);
+ if (returnCode)
+ {
+ return returnCode;
+ }
+
+#if defined(FSL_FEATURE_FLASH_HAS_ACCESS_CONTROL) && FSL_FEATURE_FLASH_HAS_ACCESS_CONTROL
+ /* Get necessary flash Execute-Only information. */
+ returnCode = flash_get_access_info(config, &flashAccessInfo);
+ if (returnCode)
+ {
+ return returnCode;
+ }
+
+ {
+ uint32_t executeOnlySegmentCounter = 0;
+
+ /* calculating end address */
+ uint32_t endAddress = start + lengthInBytes;
+
+ /* Aligning start address and end address */
+ uint32_t alignedStartAddress = ALIGN_DOWN(start, flashAccessInfo.SegmentSize);
+ uint32_t alignedEndAddress = ALIGN_UP(endAddress, flashAccessInfo.SegmentSize);
+
+ uint32_t segmentIndex = 0;
+ uint32_t maxSupportedExecuteOnlySegmentCount =
+ (alignedEndAddress - alignedStartAddress) / flashAccessInfo.SegmentSize;
+
+ while (start < endAddress)
+ {
+ uint32_t xacc;
+
+ segmentIndex = (start - flashAccessInfo.SegmentBase) / flashAccessInfo.SegmentSize;
+
+#if FLASH_SSD_IS_SECONDARY_FLASH_ENABLED && FLASH_SSD_SECONDARY_FLASH_HAS_ITS_OWN_ACCESS_REGISTER
+ if (config->FlashMemoryIndex == (uint8_t)kFLASH_MemoryIndexSecondaryFlash)
+ {
+ /* For secondary flash, The two XACCS registers allow up to 16 restricted segments of equal memory size.
+ */
+ if (segmentIndex < 8)
+ {
+ xacc = *(const volatile uint8_t *)&FTFx_XACCSL_REG;
+ }
+ else if (segmentIndex < flashAccessInfo.SegmentCount)
+ {
+ xacc = *(const volatile uint8_t *)&FTFx_XACCSH_REG;
+ segmentIndex -= 8;
+ }
+ else
+ {
+ break;
+ }
+ }
+ else
+#endif
+ {
+ /* For primary flash, The eight XACC registers allow up to 64 restricted segments of equal memory size.
+ */
+ if (segmentIndex < 32)
+ {
+ xacc = *(const volatile uint32_t *)&FTFx_XACCL3_REG;
+ }
+ else if (segmentIndex < flashAccessInfo.SegmentCount)
+ {
+ xacc = *(const volatile uint32_t *)&FTFx_XACCH3_REG;
+ segmentIndex -= 32;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ /* Determine if this address range is in a execute-only protection flash segment. */
+ if ((~xacc) & (1u << segmentIndex))
+ {
+ executeOnlySegmentCounter++;
+ }
+
+ start += flashAccessInfo.SegmentSize;
+ }
+
+ if (executeOnlySegmentCounter < 1u)
+ {
+ *access_state = kFLASH_AccessStateUnLimited;
+ }
+ else if (executeOnlySegmentCounter < maxSupportedExecuteOnlySegmentCount)
+ {
+ *access_state = kFLASH_AccessStateMixed;
+ }
+ else
+ {
+ *access_state = kFLASH_AccessStateExecuteOnly;
+ }
+ }
+#else
+ *access_state = kFLASH_AccessStateUnLimited;
+#endif /* FSL_FEATURE_FLASH_HAS_ACCESS_CONTROL */
+
+ return (returnCode);
+}
+
+status_t FLASH_GetProperty(flash_config_t *config, flash_property_tag_t whichProperty, uint32_t *value)
+{
+ if ((config == NULL) || (value == NULL))
+ {
+ return kStatus_FLASH_InvalidArgument;
+ }
+
+ switch (whichProperty)
+ {
+ case kFLASH_PropertyPflashSectorSize:
+ *value = config->PFlashSectorSize;
+ break;
+
+ case kFLASH_PropertyPflashTotalSize:
+ *value = config->PFlashTotalSize;
+ break;
+
+ case kFLASH_PropertyPflashBlockSize:
+ *value = config->PFlashTotalSize / FSL_FEATURE_FLASH_PFLASH_BLOCK_COUNT;
+ break;
+
+ case kFLASH_PropertyPflashBlockCount:
+ *value = (uint32_t)config->PFlashBlockCount;
+ break;
+
+ case kFLASH_PropertyPflashBlockBaseAddr:
+ *value = config->PFlashBlockBase;
+ break;
+
+ case kFLASH_PropertyPflashFacSupport:
+#if defined(FSL_FEATURE_FLASH_HAS_ACCESS_CONTROL)
+ *value = FSL_FEATURE_FLASH_HAS_ACCESS_CONTROL;
+#else
+ *value = 0;
+#endif /* FSL_FEATURE_FLASH_HAS_ACCESS_CONTROL */
+ break;
+
+ case kFLASH_PropertyPflashAccessSegmentSize:
+ *value = config->PFlashAccessSegmentSize;
+ break;
+
+ case kFLASH_PropertyPflashAccessSegmentCount:
+ *value = config->PFlashAccessSegmentCount;
+ break;
+
+ case kFLASH_PropertyFlexRamBlockBaseAddr:
+ *value = config->FlexRAMBlockBase;
+ break;
+
+ case kFLASH_PropertyFlexRamTotalSize:
+ *value = config->FlexRAMTotalSize;
+ break;
+
+#if FLASH_SSD_IS_FLEXNVM_ENABLED
+ case kFLASH_PropertyDflashSectorSize:
+ *value = FSL_FEATURE_FLASH_FLEX_NVM_BLOCK_SECTOR_SIZE;
+ break;
+ case kFLASH_PropertyDflashTotalSize:
+ *value = config->DFlashTotalSize;
+ break;
+ case kFLASH_PropertyDflashBlockSize:
+ *value = FSL_FEATURE_FLASH_FLEX_NVM_BLOCK_SIZE;
+ break;
+ case kFLASH_PropertyDflashBlockCount:
+ *value = FSL_FEATURE_FLASH_FLEX_NVM_BLOCK_COUNT;
+ break;
+ case kFLASH_PropertyDflashBlockBaseAddr:
+ *value = config->DFlashBlockBase;
+ break;
+ case kFLASH_PropertyEepromTotalSize:
+ *value = config->EEpromTotalSize;
+ break;
+#endif /* FLASH_SSD_IS_FLEXNVM_ENABLED */
+
+ default: /* catch inputs that are not recognized */
+ return kStatus_FLASH_UnknownProperty;
+ }
+
+ return kStatus_FLASH_Success;
+}
+
+status_t FLASH_SetProperty(flash_config_t *config, flash_property_tag_t whichProperty, uint32_t value)
+{
+ status_t status = kStatus_FLASH_Success;
+
+ if (config == NULL)
+ {
+ return kStatus_FLASH_InvalidArgument;
+ }
+
+ switch (whichProperty)
+ {
+#if FLASH_SSD_IS_SECONDARY_FLASH_ENABLED
+ case kFLASH_PropertyFlashMemoryIndex:
+ if ((value != (uint32_t)kFLASH_MemoryIndexPrimaryFlash) &&
+ (value != (uint32_t)kFLASH_MemoryIndexSecondaryFlash))
+ {
+ return kStatus_FLASH_InvalidPropertyValue;
+ }
+ config->FlashMemoryIndex = (uint8_t)value;
+ break;
+#endif /* FLASH_SSD_IS_SECONDARY_FLASH_ENABLED */
+
+ case kFLASH_PropertyFlashCacheControllerIndex:
+ if ((value != (uint32_t)kFLASH_CacheControllerIndexForCore0) &&
+ (value != (uint32_t)kFLASH_CacheControllerIndexForCore1))
+ {
+ return kStatus_FLASH_InvalidPropertyValue;
+ }
+ config->FlashCacheControllerIndex = (uint8_t)value;
+ break;
+
+ case kFLASH_PropertyPflashSectorSize:
+ case kFLASH_PropertyPflashTotalSize:
+ case kFLASH_PropertyPflashBlockSize:
+ case kFLASH_PropertyPflashBlockCount:
+ case kFLASH_PropertyPflashBlockBaseAddr:
+ case kFLASH_PropertyPflashFacSupport:
+ case kFLASH_PropertyPflashAccessSegmentSize:
+ case kFLASH_PropertyPflashAccessSegmentCount:
+ case kFLASH_PropertyFlexRamBlockBaseAddr:
+ case kFLASH_PropertyFlexRamTotalSize:
+#if FLASH_SSD_IS_FLEXNVM_ENABLED
+ case kFLASH_PropertyDflashSectorSize:
+ case kFLASH_PropertyDflashTotalSize:
+ case kFLASH_PropertyDflashBlockSize:
+ case kFLASH_PropertyDflashBlockCount:
+ case kFLASH_PropertyDflashBlockBaseAddr:
+ case kFLASH_PropertyEepromTotalSize:
+#endif /* FLASH_SSD_IS_FLEXNVM_ENABLED */
+ status = kStatus_FLASH_ReadOnlyProperty;
+ break;
+ default: /* catch inputs that are not recognized */
+ status = kStatus_FLASH_UnknownProperty;
+ break;
+ }
+
+ return status;
+}
+
+#if defined(FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD) && FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD
+status_t FLASH_SetFlexramFunction(flash_config_t *config, flash_flexram_function_option_t option)
+{
+ status_t status;
+
+ if (config == NULL)
+ {
+ return kStatus_FLASH_InvalidArgument;
+ }
+
+ status = flasn_check_flexram_function_option_range(option);
+ if (status != kStatus_FLASH_Success)
+ {
+ return status;
+ }
+
+ /* preparing passing parameter to verify all block command */
+ kFCCOBx[0] = BYTES_JOIN_TO_WORD_1_1_2(FTFx_SET_FLEXRAM_FUNCTION, option, 0xFFFFU);
+
+ /* calling flash command sequence function to execute the command */
+ return flash_command_sequence(config);
+}
+#endif /* FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD */
+
+#if defined(FSL_FEATURE_FLASH_HAS_SWAP_CONTROL_CMD) && FSL_FEATURE_FLASH_HAS_SWAP_CONTROL_CMD
+status_t FLASH_SwapControl(flash_config_t *config,
+ uint32_t address,
+ flash_swap_control_option_t option,
+ flash_swap_state_config_t *returnInfo)
+{
+ status_t returnCode;
+
+ if ((config == NULL) || (returnInfo == NULL))
+ {
+ return kStatus_FLASH_InvalidArgument;
+ }
+
+ if (address & (FSL_FEATURE_FLASH_PFLASH_SWAP_CONTROL_CMD_ADDRESS_ALIGMENT - 1))
+ {
+ return kStatus_FLASH_AlignmentError;
+ }
+
+ /* Make sure address provided is in the lower half of Program flash but not in the Flash Configuration Field */
+ if ((address >= (config->PFlashTotalSize / 2)) ||
+ ((address >= kFLASH_ConfigAreaStart) && (address <= kFLASH_ConfigAreaEnd)))
+ {
+ return kStatus_FLASH_SwapIndicatorAddressError;
+ }
+
+ /* Check the option. */
+ returnCode = flash_check_swap_control_option(option);
+ if (returnCode)
+ {
+ return returnCode;
+ }
+
+ kFCCOBx[0] = BYTES_JOIN_TO_WORD_1_3(FTFx_SWAP_CONTROL, address);
+ kFCCOBx[1] = BYTES_JOIN_TO_WORD_1_3(option, 0xFFFFFFU);
+
+ returnCode = flash_command_sequence(config);
+
+ returnInfo->flashSwapState = (flash_swap_state_t)FTFx_FCCOB5_REG;
+ returnInfo->currentSwapBlockStatus = (flash_swap_block_status_t)FTFx_FCCOB6_REG;
+ returnInfo->nextSwapBlockStatus = (flash_swap_block_status_t)FTFx_FCCOB7_REG;
+
+ return returnCode;
+}
+#endif /* FSL_FEATURE_FLASH_HAS_SWAP_CONTROL_CMD */
+
+#if defined(FSL_FEATURE_FLASH_HAS_PFLASH_BLOCK_SWAP) && FSL_FEATURE_FLASH_HAS_PFLASH_BLOCK_SWAP
+status_t FLASH_Swap(flash_config_t *config, uint32_t address, flash_swap_function_option_t option)
+{
+ flash_swap_state_config_t returnInfo;
+ status_t returnCode;
+
+ memset(&returnInfo, 0xFFU, sizeof(returnInfo));
+
+ do
+ {
+ returnCode = FLASH_SwapControl(config, address, kFLASH_SwapControlOptionReportStatus, &returnInfo);
+ if (returnCode != kStatus_FLASH_Success)
+ {
+ return returnCode;
+ }
+
+ if (kFLASH_SwapFunctionOptionDisable == option)
+ {
+ if (returnInfo.flashSwapState == kFLASH_SwapStateDisabled)
+ {
+ return kStatus_FLASH_Success;
+ }
+ else if (returnInfo.flashSwapState == kFLASH_SwapStateUninitialized)
+ {
+ /* The swap system changed to the DISABLED state with Program flash block 0
+ * located at relative flash address 0x0_0000 */
+ returnCode = FLASH_SwapControl(config, address, kFLASH_SwapControlOptionDisableSystem, &returnInfo);
+ }
+ else
+ {
+ /* Swap disable should be requested only when swap system is in the uninitialized state */
+ return kStatus_FLASH_SwapSystemNotInUninitialized;
+ }
+ }
+ else
+ {
+ /* When first swap: the initial swap state is Uninitialized, flash swap inidicator address is unset,
+ * the swap procedure should be Uninitialized -> Update-Erased -> Complete.
+ * After the first swap has been completed, the flash swap inidicator address cannot be modified
+ * unless EraseAllBlocks command is issued, the swap procedure is changed to Update -> Update-Erased ->
+ * Complete. */
+ switch (returnInfo.flashSwapState)
+ {
+ case kFLASH_SwapStateUninitialized:
+ /* If current swap mode is Uninitialized, Initialize Swap to Initialized/READY state. */
+ returnCode =
+ FLASH_SwapControl(config, address, kFLASH_SwapControlOptionIntializeSystem, &returnInfo);
+ break;
+ case kFLASH_SwapStateReady:
+ /* Validate whether the address provided to the swap system is matched to
+ * swap indicator address in the IFR */
+ returnCode = flash_validate_swap_indicator_address(config, address);
+ if (returnCode == kStatus_FLASH_Success)
+ {
+ /* If current swap mode is Initialized/Ready, Initialize Swap to UPDATE state. */
+ returnCode =
+ FLASH_SwapControl(config, address, kFLASH_SwapControlOptionSetInUpdateState, &returnInfo);
+ }
+ break;
+ case kFLASH_SwapStateUpdate:
+ /* If current swap mode is Update, Erase indicator sector in non active block
+ * to proceed swap system to update-erased state */
+ returnCode = FLASH_Erase(config, address + (config->PFlashTotalSize >> 1),
+ FSL_FEATURE_FLASH_PFLASH_SECTOR_CMD_ADDRESS_ALIGMENT, kFLASH_ApiEraseKey);
+ break;
+ case kFLASH_SwapStateUpdateErased:
+ /* If current swap mode is Update or Update-Erased, progress Swap to COMPLETE State */
+ returnCode =
+ FLASH_SwapControl(config, address, kFLASH_SwapControlOptionSetInCompleteState, &returnInfo);
+ break;
+ case kFLASH_SwapStateComplete:
+ break;
+ case kFLASH_SwapStateDisabled:
+ /* When swap system is in disabled state, We need to clear swap system back to uninitialized
+ * by issuing EraseAllBlocks command */
+ returnCode = kStatus_FLASH_SwapSystemNotInUninitialized;
+ break;
+ default:
+ returnCode = kStatus_FLASH_InvalidArgument;
+ break;
+ }
+ }
+ if (returnCode != kStatus_FLASH_Success)
+ {
+ break;
+ }
+ } while (!((kFLASH_SwapStateComplete == returnInfo.flashSwapState) && (kFLASH_SwapFunctionOptionEnable == option)));
+
+ return returnCode;
+}
+#endif /* FSL_FEATURE_FLASH_HAS_PFLASH_BLOCK_SWAP */
+
+#if defined(FSL_FEATURE_FLASH_HAS_PROGRAM_PARTITION_CMD) && FSL_FEATURE_FLASH_HAS_PROGRAM_PARTITION_CMD
+status_t FLASH_ProgramPartition(flash_config_t *config,
+ flash_partition_flexram_load_option_t option,
+ uint32_t eepromDataSizeCode,
+ uint32_t flexnvmPartitionCode)
+{
+ status_t returnCode;
+
+ if (config == NULL)
+ {
+ return kStatus_FLASH_InvalidArgument;
+ }
+
+ /* eepromDataSizeCode[7:6], flexnvmPartitionCode[7:4] should be all 1'b0
+ * or it will cause access error. */
+ /* eepromDataSizeCode &= 0x3FU; */
+ /* flexnvmPartitionCode &= 0x0FU; */
+
+ /* preparing passing parameter to program the flash block */
+ kFCCOBx[0] = BYTES_JOIN_TO_WORD_1_2_1(FTFx_PROGRAM_PARTITION, 0xFFFFU, option);
+ kFCCOBx[1] = BYTES_JOIN_TO_WORD_1_1_2(eepromDataSizeCode, flexnvmPartitionCode, 0xFFFFU);
+
+ flash_cache_clear_process(config, kFLASH_CacheClearProcessPre);
+
+ /* calling flash command sequence function to execute the command */
+ returnCode = flash_command_sequence(config);
+
+ flash_cache_clear(config);
+
+#if FLASH_SSD_IS_FLEXNVM_ENABLED
+ /* Data flash IFR will be updated by program partition command during reset sequence,
+ * so we just set reserved values for partitioned FlexNVM size here */
+ config->EEpromTotalSize = FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_RESERVED;
+ config->DFlashTotalSize = FLEX_NVM_DFLASH_SIZE_FOR_DEPART_RESERVED;
+#endif
+
+ return (returnCode);
+}
+#endif /* FSL_FEATURE_FLASH_HAS_PROGRAM_PARTITION_CMD */
+
+status_t FLASH_PflashSetProtection(flash_config_t *config, pflash_protection_status_t *protectStatus)
+{
+ if (config == NULL)
+ {
+ return kStatus_FLASH_InvalidArgument;
+ }
+
+#if FLASH_SSD_IS_SECONDARY_FLASH_ENABLED && FLASH_SSD_SECONDARY_FLASH_HAS_ITS_OWN_PROTECTION_REGISTER
+ if (config->FlashMemoryIndex == (uint8_t)kFLASH_MemoryIndexSecondaryFlash)
+ {
+ *kFPROTSL = protectStatus->valueLow32b.prots16b.protsl;
+ if (protectStatus->valueLow32b.prots16b.protsl != *kFPROTSL)
+ {
+ return kStatus_FLASH_CommandFailure;
+ }
+
+ *kFPROTSH = protectStatus->valueLow32b.prots16b.protsh;
+ if (protectStatus->valueLow32b.prots16b.protsh != *kFPROTSH)
+ {
+ return kStatus_FLASH_CommandFailure;
+ }
+ }
+ else
+#endif
+ {
+ *kFPROTL = protectStatus->valueLow32b.protl32b;
+ if (protectStatus->valueLow32b.protl32b != *kFPROTL)
+ {
+ return kStatus_FLASH_CommandFailure;
+ }
+
+#if defined(FTFx_FPROT_HIGH_REG)
+ *kFPROTH = protectStatus->valueHigh32b.proth32b;
+ if (protectStatus->valueHigh32b.proth32b != *kFPROTH)
+ {
+ return kStatus_FLASH_CommandFailure;
+ }
+#endif
+ }
+
+ return kStatus_FLASH_Success;
+}
+
+status_t FLASH_PflashGetProtection(flash_config_t *config, pflash_protection_status_t *protectStatus)
+{
+ if ((config == NULL) || (protectStatus == NULL))
+ {
+ return kStatus_FLASH_InvalidArgument;
+ }
+
+#if FLASH_SSD_IS_SECONDARY_FLASH_ENABLED && FLASH_SSD_SECONDARY_FLASH_HAS_ITS_OWN_PROTECTION_REGISTER
+ if (config->FlashMemoryIndex == (uint8_t)kFLASH_MemoryIndexSecondaryFlash)
+ {
+ protectStatus->valueLow32b.prots16b.protsl = *kFPROTSL;
+ protectStatus->valueLow32b.prots16b.protsh = *kFPROTSH;
+ }
+ else
+#endif
+ {
+ protectStatus->valueLow32b.protl32b = *kFPROTL;
+#if defined(FTFx_FPROT_HIGH_REG)
+ protectStatus->valueHigh32b.proth32b = *kFPROTH;
+#endif
+ }
+
+ return kStatus_FLASH_Success;
+}
+
+#if FLASH_SSD_IS_FLEXNVM_ENABLED
+status_t FLASH_DflashSetProtection(flash_config_t *config, uint8_t protectStatus)
+{
+ if (config == NULL)
+ {
+ return kStatus_FLASH_InvalidArgument;
+ }
+
+ if ((config->DFlashTotalSize == 0) || (config->DFlashTotalSize == FLEX_NVM_DFLASH_SIZE_FOR_DEPART_RESERVED))
+ {
+ return kStatus_FLASH_CommandNotSupported;
+ }
+
+ FTFx->FDPROT = protectStatus;
+
+ if (FTFx->FDPROT != protectStatus)
+ {
+ return kStatus_FLASH_CommandFailure;
+ }
+
+ return kStatus_FLASH_Success;
+}
+#endif /* FLASH_SSD_IS_FLEXNVM_ENABLED */
+
+#if FLASH_SSD_IS_FLEXNVM_ENABLED
+status_t FLASH_DflashGetProtection(flash_config_t *config, uint8_t *protectStatus)
+{
+ if ((config == NULL) || (protectStatus == NULL))
+ {
+ return kStatus_FLASH_InvalidArgument;
+ }
+
+ if ((config->DFlashTotalSize == 0) || (config->DFlashTotalSize == FLEX_NVM_DFLASH_SIZE_FOR_DEPART_RESERVED))
+ {
+ return kStatus_FLASH_CommandNotSupported;
+ }
+
+ *protectStatus = FTFx->FDPROT;
+
+ return kStatus_FLASH_Success;
+}
+#endif /* FLASH_SSD_IS_FLEXNVM_ENABLED */
+
+#if FLASH_SSD_IS_FLEXNVM_ENABLED
+status_t FLASH_EepromSetProtection(flash_config_t *config, uint8_t protectStatus)
+{
+ if (config == NULL)
+ {
+ return kStatus_FLASH_InvalidArgument;
+ }
+
+ if ((config->EEpromTotalSize == 0) || (config->EEpromTotalSize == FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_RESERVED))
+ {
+ return kStatus_FLASH_CommandNotSupported;
+ }
+
+ FTFx->FEPROT = protectStatus;
+
+ if (FTFx->FEPROT != protectStatus)
+ {
+ return kStatus_FLASH_CommandFailure;
+ }
+
+ return kStatus_FLASH_Success;
+}
+#endif /* FLASH_SSD_IS_FLEXNVM_ENABLED */
+
+#if FLASH_SSD_IS_FLEXNVM_ENABLED
+status_t FLASH_EepromGetProtection(flash_config_t *config, uint8_t *protectStatus)
+{
+ if ((config == NULL) || (protectStatus == NULL))
+ {
+ return kStatus_FLASH_InvalidArgument;
+ }
+
+ if ((config->EEpromTotalSize == 0) || (config->EEpromTotalSize == FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_RESERVED))
+ {
+ return kStatus_FLASH_CommandNotSupported;
+ }
+
+ *protectStatus = FTFx->FEPROT;
+
+ return kStatus_FLASH_Success;
+}
+#endif /* FLASH_SSD_IS_FLEXNVM_ENABLED */
+
+status_t FLASH_PflashSetPrefetchSpeculation(flash_prefetch_speculation_status_t *speculationStatus)
+{
+#if FLASH_PREFETCH_SPECULATION_IS_CONTROLLED_BY_MCM
+ {
+ FTFx_REG32_ACCESS_TYPE regBase;
+#if defined(MCM)
+ regBase = (FTFx_REG32_ACCESS_TYPE)&MCM->PLACR;
+#elif defined(MCM0)
+ regBase = (FTFx_REG32_ACCESS_TYPE)&MCM0->PLACR;
+#endif
+ if (speculationStatus->instructionOption == kFLASH_prefetchSpeculationOptionDisable)
+ {
+ if (speculationStatus->dataOption == kFLASH_prefetchSpeculationOptionEnable)
+ {
+ return kStatus_FLASH_InvalidSpeculationOption;
+ }
+ else
+ {
+ *regBase |= MCM_PLACR_DFCS_MASK;
+ }
+ }
+ else
+ {
+ *regBase &= ~MCM_PLACR_DFCS_MASK;
+ if (speculationStatus->dataOption == kFLASH_prefetchSpeculationOptionEnable)
+ {
+ *regBase |= MCM_PLACR_EFDS_MASK;
+ }
+ else
+ {
+ *regBase &= ~MCM_PLACR_EFDS_MASK;
+ }
+ }
+ }
+#elif FLASH_PREFETCH_SPECULATION_IS_CONTROLLED_BY_FMC
+ {
+ FTFx_REG32_ACCESS_TYPE regBase;
+ uint32_t b0dpeMask, b0ipeMask;
+#if defined(FMC_PFB01CR_B0DPE_MASK)
+ regBase = (FTFx_REG32_ACCESS_TYPE)&FMC->PFB01CR;
+ b0dpeMask = FMC_PFB01CR_B0DPE_MASK;
+ b0ipeMask = FMC_PFB01CR_B0IPE_MASK;
+#elif defined(FMC_PFB0CR_B0DPE_MASK)
+ regBase = (FTFx_REG32_ACCESS_TYPE)&FMC->PFB0CR;
+ b0dpeMask = FMC_PFB0CR_B0DPE_MASK;
+ b0ipeMask = FMC_PFB0CR_B0IPE_MASK;
+#endif
+ if (speculationStatus->instructionOption == kFLASH_prefetchSpeculationOptionEnable)
+ {
+ *regBase |= b0ipeMask;
+ }
+ else
+ {
+ *regBase &= ~b0ipeMask;
+ }
+ if (speculationStatus->dataOption == kFLASH_prefetchSpeculationOptionEnable)
+ {
+ *regBase |= b0dpeMask;
+ }
+ else
+ {
+ *regBase &= ~b0dpeMask;
+ }
+
+/* Invalidate Prefetch Speculation Buffer */
+#if defined(FMC_PFB01CR_S_INV_MASK)
+ FMC->PFB01CR |= FMC_PFB01CR_S_INV_MASK;
+#elif defined(FMC_PFB01CR_S_B_INV_MASK)
+ FMC->PFB01CR |= FMC_PFB01CR_S_B_INV_MASK;
+#elif defined(FMC_PFB0CR_S_INV_MASK)
+ FMC->PFB0CR |= FMC_PFB0CR_S_INV_MASK;
+#elif defined(FMC_PFB0CR_S_B_INV_MASK)
+ FMC->PFB0CR |= FMC_PFB0CR_S_B_INV_MASK;
+#endif
+ }
+#elif FLASH_PREFETCH_SPECULATION_IS_CONTROLLED_BY_MSCM
+ {
+ FTFx_REG32_ACCESS_TYPE regBase;
+ uint32_t flashSpeculationMask, dataPrefetchMask;
+ regBase = (FTFx_REG32_ACCESS_TYPE)&MSCM->OCMDR[0];
+ flashSpeculationMask = MSCM_OCMDR_OCMC1_DFCS_MASK;
+ dataPrefetchMask = MSCM_OCMDR_OCMC1_DFDS_MASK;
+
+ if (speculationStatus->instructionOption == kFLASH_prefetchSpeculationOptionDisable)
+ {
+ if (speculationStatus->dataOption == kFLASH_prefetchSpeculationOptionEnable)
+ {
+ return kStatus_FLASH_InvalidSpeculationOption;
+ }
+ else
+ {
+ *regBase |= flashSpeculationMask;
+ }
+ }
+ else
+ {
+ *regBase &= ~flashSpeculationMask;
+ if (speculationStatus->dataOption == kFLASH_prefetchSpeculationOptionEnable)
+ {
+ *regBase &= ~dataPrefetchMask;
+ }
+ else
+ {
+ *regBase |= dataPrefetchMask;
+ }
+ }
+ }
+#endif /* FSL_FEATURE_FTFx_MCM_FLASH_CACHE_CONTROLS */
+
+ return kStatus_FLASH_Success;
+}
+
+status_t FLASH_PflashGetPrefetchSpeculation(flash_prefetch_speculation_status_t *speculationStatus)
+{
+ memset(speculationStatus, 0, sizeof(flash_prefetch_speculation_status_t));
+
+ /* Assuming that all speculation options are enabled. */
+ speculationStatus->instructionOption = kFLASH_prefetchSpeculationOptionEnable;
+ speculationStatus->dataOption = kFLASH_prefetchSpeculationOptionEnable;
+
+#if FLASH_PREFETCH_SPECULATION_IS_CONTROLLED_BY_MCM
+ {
+ uint32_t value;
+#if defined(MCM)
+ value = MCM->PLACR;
+#elif defined(MCM0)
+ value = MCM0->PLACR;
+#endif
+ if (value & MCM_PLACR_DFCS_MASK)
+ {
+ /* Speculation buffer is off. */
+ speculationStatus->instructionOption = kFLASH_prefetchSpeculationOptionDisable;
+ speculationStatus->dataOption = kFLASH_prefetchSpeculationOptionDisable;
+ }
+ else
+ {
+ /* Speculation buffer is on for instruction. */
+ if (!(value & MCM_PLACR_EFDS_MASK))
+ {
+ /* Speculation buffer is off for data. */
+ speculationStatus->dataOption = kFLASH_prefetchSpeculationOptionDisable;
+ }
+ }
+ }
+#elif FLASH_PREFETCH_SPECULATION_IS_CONTROLLED_BY_FMC
+ {
+ uint32_t value;
+ uint32_t b0dpeMask, b0ipeMask;
+#if defined(FMC_PFB01CR_B0DPE_MASK)
+ value = FMC->PFB01CR;
+ b0dpeMask = FMC_PFB01CR_B0DPE_MASK;
+ b0ipeMask = FMC_PFB01CR_B0IPE_MASK;
+#elif defined(FMC_PFB0CR_B0DPE_MASK)
+ value = FMC->PFB0CR;
+ b0dpeMask = FMC_PFB0CR_B0DPE_MASK;
+ b0ipeMask = FMC_PFB0CR_B0IPE_MASK;
+#endif
+ if (!(value & b0dpeMask))
+ {
+ /* Do not prefetch in response to data references. */
+ speculationStatus->dataOption = kFLASH_prefetchSpeculationOptionDisable;
+ }
+ if (!(value & b0ipeMask))
+ {
+ /* Do not prefetch in response to instruction fetches. */
+ speculationStatus->instructionOption = kFLASH_prefetchSpeculationOptionDisable;
+ }
+ }
+#elif FLASH_PREFETCH_SPECULATION_IS_CONTROLLED_BY_MSCM
+ {
+ uint32_t value;
+ uint32_t flashSpeculationMask, dataPrefetchMask;
+ value = MSCM->OCMDR[0];
+ flashSpeculationMask = MSCM_OCMDR_OCMC1_DFCS_MASK;
+ dataPrefetchMask = MSCM_OCMDR_OCMC1_DFDS_MASK;
+
+ if (value & flashSpeculationMask)
+ {
+ /* Speculation buffer is off. */
+ speculationStatus->instructionOption = kFLASH_prefetchSpeculationOptionDisable;
+ speculationStatus->dataOption = kFLASH_prefetchSpeculationOptionDisable;
+ }
+ else
+ {
+ /* Speculation buffer is on for instruction. */
+ if (value & dataPrefetchMask)
+ {
+ /* Speculation buffer is off for data. */
+ speculationStatus->dataOption = kFLASH_prefetchSpeculationOptionDisable;
+ }
+ }
+ }
+#endif
+
+ return kStatus_FLASH_Success;
+}
+
+#if FLASH_DRIVER_IS_FLASH_RESIDENT
+/*!
+ * @brief Copy PIC of flash_run_command() to RAM
+ */
+static void copy_flash_run_command(uint32_t *flashRunCommand)
+{
+ assert(sizeof(s_flashRunCommandFunctionCode) <= (kFLASH_ExecuteInRamFunctionMaxSizeInWords * 4));
+
+ /* Since the value of ARM function pointer is always odd, but the real start address
+ * of function memory should be even, that's why +1 operation exist. */
+ memcpy((void *)flashRunCommand, (void *)s_flashRunCommandFunctionCode, sizeof(s_flashRunCommandFunctionCode));
+ callFlashRunCommand = (void (*)(FTFx_REG8_ACCESS_TYPE ftfx_fstat))((uint32_t)flashRunCommand + 1);
+}
+#endif /* FLASH_DRIVER_IS_FLASH_RESIDENT */
+
+/*!
+ * @brief Flash Command Sequence
+ *
+ * This function is used to perform the command write sequence to the flash.
+ *
+ * @param driver Pointer to storage for the driver runtime state.
+ * @return An error code or kStatus_FLASH_Success
+ */
+static status_t flash_command_sequence(flash_config_t *config)
+{
+ uint8_t registerValue;
+
+#if FLASH_DRIVER_IS_FLASH_RESIDENT
+ /* clear RDCOLERR & ACCERR & FPVIOL flag in flash status register */
+ FTFx->FSTAT = FTFx_FSTAT_RDCOLERR_MASK | FTFx_FSTAT_ACCERR_MASK | FTFx_FSTAT_FPVIOL_MASK;
+
+ status_t returnCode = flash_check_execute_in_ram_function_info(config);
+ if (kStatus_FLASH_Success != returnCode)
+ {
+ return returnCode;
+ }
+
+ /* We pass the ftfx_fstat address as a parameter to flash_run_comamnd() instead of using
+ * pre-processed MICRO sentences or operating global variable in flash_run_comamnd()
+ * to make sure that flash_run_command() will be compiled into position-independent code (PIC). */
+ callFlashRunCommand((FTFx_REG8_ACCESS_TYPE)(&FTFx->FSTAT));
+#else
+ /* clear RDCOLERR & ACCERR & FPVIOL flag in flash status register */
+ FTFx->FSTAT = FTFx_FSTAT_RDCOLERR_MASK | FTFx_FSTAT_ACCERR_MASK | FTFx_FSTAT_FPVIOL_MASK;
+
+ /* clear CCIF bit */
+ FTFx->FSTAT = FTFx_FSTAT_CCIF_MASK;
+
+ /* Check CCIF bit of the flash status register, wait till it is set.
+ * IP team indicates that this loop will always complete. */
+ while (!(FTFx->FSTAT & FTFx_FSTAT_CCIF_MASK))
+ {
+ }
+#endif /* FLASH_DRIVER_IS_FLASH_RESIDENT */
+
+ /* Check error bits */
+ /* Get flash status register value */
+ registerValue = FTFx->FSTAT;
+
+ /* checking access error */
+ if (registerValue & FTFx_FSTAT_ACCERR_MASK)
+ {
+ return kStatus_FLASH_AccessError;
+ }
+ /* checking protection error */
+ else if (registerValue & FTFx_FSTAT_FPVIOL_MASK)
+ {
+ return kStatus_FLASH_ProtectionViolation;
+ }
+ /* checking MGSTAT0 non-correctable error */
+ else if (registerValue & FTFx_FSTAT_MGSTAT0_MASK)
+ {
+ return kStatus_FLASH_CommandFailure;
+ }
+ else
+ {
+ return kStatus_FLASH_Success;
+ }
+}
+
+#if FLASH_DRIVER_IS_FLASH_RESIDENT
+/*!
+ * @brief Copy PIC of flash_common_bit_operation() to RAM
+ *
+ */
+static void copy_flash_common_bit_operation(uint32_t *flashCommonBitOperation)
+{
+ assert(sizeof(s_flashCommonBitOperationFunctionCode) <= (kFLASH_ExecuteInRamFunctionMaxSizeInWords * 4));
+
+ /* Since the value of ARM function pointer is always odd, but the real start address
+ * of function memory should be even, that's why +1 operation exist. */
+ memcpy((void *)flashCommonBitOperation, (void *)s_flashCommonBitOperationFunctionCode,
+ sizeof(s_flashCommonBitOperationFunctionCode));
+ callFlashCommonBitOperation = (void (*)(FTFx_REG32_ACCESS_TYPE base, uint32_t bitMask, uint32_t bitShift,
+ uint32_t bitValue))((uint32_t)flashCommonBitOperation + 1);
+ /* Workround for some devices which doesn't need this function */
+ callFlashCommonBitOperation((FTFx_REG32_ACCESS_TYPE)0, 0, 0, 0);
+}
+#endif /* FLASH_DRIVER_IS_FLASH_RESIDENT */
+
+#if FLASH_CACHE_IS_CONTROLLED_BY_MCM
+/*! @brief Performs the cache clear to the flash by MCM.*/
+void mcm_flash_cache_clear(flash_config_t *config)
+{
+ FTFx_REG32_ACCESS_TYPE regBase = (FTFx_REG32_ACCESS_TYPE)&MCM0_CACHE_REG;
+
+#if defined(MCM0) && defined(MCM1)
+ if (config->FlashCacheControllerIndex == (uint8_t)kFLASH_CacheControllerIndexForCore1)
+ {
+ regBase = (FTFx_REG32_ACCESS_TYPE)&MCM1_CACHE_REG;
+ }
+#endif
+
+#if FLASH_DRIVER_IS_FLASH_RESIDENT
+ callFlashCommonBitOperation(regBase, MCM_CACHE_CLEAR_MASK, MCM_CACHE_CLEAR_SHIFT, 1U);
+#else /* !FLASH_DRIVER_IS_FLASH_RESIDENT */
+ *regBase |= MCM_CACHE_CLEAR_MASK;
+
+ /* Memory barriers for good measure.
+ * All Cache, Branch predictor and TLB maintenance operations before this instruction complete */
+ __ISB();
+ __DSB();
+#endif /* FLASH_DRIVER_IS_FLASH_RESIDENT */
+}
+#endif /* FLASH_CACHE_IS_CONTROLLED_BY_MCM */
+
+#if FLASH_CACHE_IS_CONTROLLED_BY_FMC
+/*! @brief Performs the cache clear to the flash by FMC.*/
+void fmc_flash_cache_clear(void)
+{
+#if FLASH_DRIVER_IS_FLASH_RESIDENT
+ FTFx_REG32_ACCESS_TYPE regBase = (FTFx_REG32_ACCESS_TYPE)0;
+#if defined(FMC_PFB01CR_CINV_WAY_MASK)
+ regBase = (FTFx_REG32_ACCESS_TYPE)&FMC->PFB01CR;
+ callFlashCommonBitOperation(regBase, FMC_PFB01CR_CINV_WAY_MASK, FMC_PFB01CR_CINV_WAY_SHIFT, 0xFU);
+#else
+ regBase = (FTFx_REG32_ACCESS_TYPE)&FMC->PFB0CR;
+ callFlashCommonBitOperation(regBase, FMC_PFB0CR_CINV_WAY_MASK, FMC_PFB0CR_CINV_WAY_SHIFT, 0xFU);
+#endif
+#else /* !FLASH_DRIVER_IS_FLASH_RESIDENT */
+#if defined(FMC_PFB01CR_CINV_WAY_MASK)
+ FMC->PFB01CR = (FMC->PFB01CR & ~FMC_PFB01CR_CINV_WAY_MASK) | FMC_PFB01CR_CINV_WAY(~0);
+#else
+ FMC->PFB0CR = (FMC->PFB0CR & ~FMC_PFB0CR_CINV_WAY_MASK) | FMC_PFB0CR_CINV_WAY(~0);
+#endif
+ /* Memory barriers for good measure.
+ * All Cache, Branch predictor and TLB maintenance operations before this instruction complete */
+ __ISB();
+ __DSB();
+#endif /* FLASH_DRIVER_IS_FLASH_RESIDENT */
+}
+#endif /* FLASH_CACHE_IS_CONTROLLED_BY_FMC */
+
+#if FLASH_PREFETCH_SPECULATION_IS_CONTROLLED_BY_MSCM
+/*! @brief Performs the prefetch speculation buffer clear to the flash by MSCM.*/
+void mscm_flash_prefetch_speculation_enable(bool enable)
+{
+ uint8_t setValue;
+ if (enable)
+ {
+ setValue = 0x0U;
+ }
+ else
+ {
+ setValue = 0x3U;
+ }
+
+/* The OCMDR[0] is always used to prefetch main Pflash*/
+/* For device with FlexNVM support, the OCMDR[1] is used to prefetch Dflash.
+ * For device with secondary flash support, the OCMDR[1] is used to prefetch secondary Pflash. */
+#if FLASH_DRIVER_IS_FLASH_RESIDENT
+ callFlashCommonBitOperation((FTFx_REG32_ACCESS_TYPE)&MSCM->OCMDR[0], MSCM_SPECULATION_DISABLE_MASK,
+ MSCM_SPECULATION_DISABLE_SHIFT, setValue);
+#if FLASH_SSD_IS_FLEXNVM_ENABLED || BL_HAS_SECONDARY_INTERNAL_FLASH
+ callFlashCommonBitOperation((FTFx_REG32_ACCESS_TYPE)&MSCM->OCMDR[1], MSCM_SPECULATION_DISABLE_MASK,
+ MSCM_SPECULATION_DISABLE_SHIFT, setValue);
+#endif
+#else /* !FLASH_DRIVER_IS_FLASH_RESIDENT */
+ MSCM->OCMDR[0] |= MSCM_SPECULATION_DISABLE(setValue);
+
+ /* Memory barriers for good measure.
+ * All Cache, Branch predictor and TLB maintenance operations before this instruction complete */
+ __ISB();
+ __DSB();
+#if FLASH_SSD_IS_FLEXNVM_ENABLED || BL_HAS_SECONDARY_INTERNAL_FLASH
+ MSCM->OCMDR[1] |= MSCM_SPECULATION_DISABLE(setValue);
+
+ /* Each cahce clear instaruction should be followed by below code*/
+ __ISB();
+ __DSB();
+#endif
+
+#endif /* FLASH_DRIVER_IS_FLASH_RESIDENT */
+}
+#endif /* FLASH_PREFETCH_SPECULATION_IS_CONTROLLED_BY_MSCM */
+
+#if FLASH_PREFETCH_SPECULATION_IS_CONTROLLED_BY_FMC
+/*! @brief Performs the prefetch speculation buffer clear to the flash by FMC.*/
+void fmc_flash_prefetch_speculation_clear(void)
+{
+#if FLASH_DRIVER_IS_FLASH_RESIDENT
+ FTFx_REG32_ACCESS_TYPE regBase = (FTFx_REG32_ACCESS_TYPE)0;
+#if defined(FMC_PFB01CR_S_INV_MASK)
+ regBase = (FTFx_REG32_ACCESS_TYPE)&FMC->PFB01CR;
+ callFlashCommonBitOperation(regBase, FMC_PFB01CR_S_INV_MASK, FMC_PFB01CR_S_INV_SHIFT, 1U);
+#elif defined(FMC_PFB01CR_S_B_INV_MASK)
+ regBase = (FTFx_REG32_ACCESS_TYPE)&FMC->PFB01CR;
+ callFlashCommonBitOperation(regBase, FMC_PFB01CR_S_B_INV_MASK, FMC_PFB01CR_S_B_INV_SHIFT, 1U);
+#elif defined(FMC_PFB0CR_S_INV_MASK)
+ regBase = (FTFx_REG32_ACCESS_TYPE)&FMC->PFB0CR;
+ callFlashCommonBitOperation(regBase, FMC_PFB0CR_S_INV_MASK, FMC_PFB0CR_S_INV_SHIFT, 1U);
+#elif defined(FMC_PFB0CR_S_B_INV_MASK)
+ regBase = (FTFx_REG32_ACCESS_TYPE)&FMC->PFB0CR;
+ callFlashCommonBitOperation(regBase, FMC_PFB0CR_S_B_INV_MASK, FMC_PFB0CR_S_B_INV_SHIFT, 1U);
+#endif
+#else /* !FLASH_DRIVER_IS_FLASH_RESIDENT */
+#if defined(FMC_PFB01CR_S_INV_MASK)
+ FMC->PFB01CR |= FMC_PFB01CR_S_INV_MASK;
+#elif defined(FMC_PFB01CR_S_B_INV_MASK)
+ FMC->PFB01CR |= FMC_PFB01CR_S_B_INV_MASK;
+#elif defined(FMC_PFB0CR_S_INV_MASK)
+ FMC->PFB0CR |= FMC_PFB0CR_S_INV_MASK;
+#elif defined(FMC_PFB0CR_S_B_INV_MASK)
+ FMC->PFB0CR |= FMC_PFB0CR_S_B_INV_MASK;
+#endif
+ /* Memory barriers for good measure.
+ * All Cache, Branch predictor and TLB maintenance operations before this instruction complete */
+ __ISB();
+ __DSB();
+#endif /* FLASH_DRIVER_IS_FLASH_RESIDENT */
+}
+#endif /* FLASH_PREFETCH_SPECULATION_IS_CONTROLLED_BY_FMC */
+
+/*!
+ * @brief Flash Cache Clear
+ *
+ * This function is used to perform the cache and prefetch speculation clear to the flash.
+ */
+void flash_cache_clear(flash_config_t *config)
+{
+ flash_cache_clear_process(config, kFLASH_CacheClearProcessPost);
+}
+
+/*!
+ * @brief Flash Cache Clear Process
+ *
+ * This function is used to perform the cache and prefetch speculation clear process to the flash.
+ */
+static void flash_cache_clear_process(flash_config_t *config, flash_cache_clear_process_t process)
+{
+#if FLASH_DRIVER_IS_FLASH_RESIDENT
+ status_t returnCode = flash_check_execute_in_ram_function_info(config);
+ if (kStatus_FLASH_Success != returnCode)
+ {
+ return;
+ }
+#endif /* FLASH_DRIVER_IS_FLASH_RESIDENT */
+
+ /* We pass the ftfx register address as a parameter to flash_common_bit_operation() instead of using
+ * pre-processed MACROs or a global variable in flash_common_bit_operation()
+ * to make sure that flash_common_bit_operation() will be compiled into position-independent code (PIC). */
+ if (process == kFLASH_CacheClearProcessPost)
+ {
+#if FLASH_CACHE_IS_CONTROLLED_BY_MCM
+ mcm_flash_cache_clear(config);
+#endif
+#if FLASH_CACHE_IS_CONTROLLED_BY_FMC
+ fmc_flash_cache_clear();
+#endif
+#if FLASH_PREFETCH_SPECULATION_IS_CONTROLLED_BY_MSCM
+ mscm_flash_prefetch_speculation_enable(true);
+#endif
+#if FLASH_PREFETCH_SPECULATION_IS_CONTROLLED_BY_FMC
+ fmc_flash_prefetch_speculation_clear();
+#endif
+ }
+ if (process == kFLASH_CacheClearProcessPre)
+ {
+#if FLASH_PREFETCH_SPECULATION_IS_CONTROLLED_BY_MSCM
+ mscm_flash_prefetch_speculation_enable(false);
+#endif
+ }
+}
+
+#if FLASH_DRIVER_IS_FLASH_RESIDENT
+/*! @brief Check whether flash execute-in-ram functions are ready */
+static status_t flash_check_execute_in_ram_function_info(flash_config_t *config)
+{
+ flash_execute_in_ram_function_config_t *flashExecuteInRamFunctionInfo;
+
+ if (config == NULL)
+ {
+ return kStatus_FLASH_InvalidArgument;
+ }
+
+ flashExecuteInRamFunctionInfo = (flash_execute_in_ram_function_config_t *)config->flashExecuteInRamFunctionInfo;
+
+ if ((config->flashExecuteInRamFunctionInfo) &&
+ (kFLASH_ExecuteInRamFunctionTotalNum == flashExecuteInRamFunctionInfo->activeFunctionCount))
+ {
+ return kStatus_FLASH_Success;
+ }
+
+ return kStatus_FLASH_ExecuteInRamFunctionNotReady;
+}
+#endif /* FLASH_DRIVER_IS_FLASH_RESIDENT */
+
+/*! @brief Validates the range and alignment of the given address range.*/
+static status_t flash_check_range(flash_config_t *config,
+ uint32_t startAddress,
+ uint32_t lengthInBytes,
+ uint32_t alignmentBaseline)
+{
+ if (config == NULL)
+ {
+ return kStatus_FLASH_InvalidArgument;
+ }
+
+ /* Verify the start and length are alignmentBaseline aligned. */
+ if ((startAddress & (alignmentBaseline - 1)) || (lengthInBytes & (alignmentBaseline - 1)))
+ {
+ return kStatus_FLASH_AlignmentError;
+ }
+
+ /* check for valid range of the target addresses */
+ if (
+#if FLASH_SSD_IS_FLEXNVM_ENABLED
+ ((startAddress >= config->DFlashBlockBase) &&
+ ((startAddress + lengthInBytes) <= (config->DFlashBlockBase + config->DFlashTotalSize))) ||
+#endif
+ ((startAddress >= config->PFlashBlockBase) &&
+ ((startAddress + lengthInBytes) <= (config->PFlashBlockBase + config->PFlashTotalSize))))
+ {
+ return kStatus_FLASH_Success;
+ }
+
+ return kStatus_FLASH_AddressError;
+}
+
+/*! @brief Gets the right address, sector and block size of current flash type which is indicated by address.*/
+static status_t flash_get_matched_operation_info(flash_config_t *config,
+ uint32_t address,
+ flash_operation_config_t *info)
+{
+ if (config == NULL)
+ {
+ return kStatus_FLASH_InvalidArgument;
+ }
+
+ /* Clean up info Structure*/
+ memset(info, 0, sizeof(flash_operation_config_t));
+
+#if FLASH_SSD_IS_FLEXNVM_ENABLED
+ if ((address >= config->DFlashBlockBase) && (address <= (config->DFlashBlockBase + config->DFlashTotalSize)))
+ {
+ /* When required by the command, address bit 23 selects between program flash memory
+ * (=0) and data flash memory (=1).*/
+ info->convertedAddress = address - config->DFlashBlockBase + 0x800000U;
+ info->activeSectorSize = FSL_FEATURE_FLASH_FLEX_NVM_BLOCK_SECTOR_SIZE;
+ info->activeBlockSize = config->DFlashTotalSize / FSL_FEATURE_FLASH_FLEX_NVM_BLOCK_COUNT;
+
+ info->blockWriteUnitSize = FSL_FEATURE_FLASH_FLEX_NVM_BLOCK_WRITE_UNIT_SIZE;
+ info->sectorCmdAddressAligment = FSL_FEATURE_FLASH_FLEX_NVM_SECTOR_CMD_ADDRESS_ALIGMENT;
+ info->sectionCmdAddressAligment = FSL_FEATURE_FLASH_FLEX_NVM_SECTION_CMD_ADDRESS_ALIGMENT;
+ info->resourceCmdAddressAligment = FSL_FEATURE_FLASH_FLEX_NVM_RESOURCE_CMD_ADDRESS_ALIGMENT;
+ info->checkCmdAddressAligment = FSL_FEATURE_FLASH_FLEX_NVM_CHECK_CMD_ADDRESS_ALIGMENT;
+ }
+ else
+#endif /* FLASH_SSD_IS_FLEXNVM_ENABLED */
+ {
+ info->convertedAddress = address - config->PFlashBlockBase;
+ info->activeSectorSize = config->PFlashSectorSize;
+ info->activeBlockSize = config->PFlashTotalSize / config->PFlashBlockCount;
+#if FLASH_SSD_IS_SECONDARY_FLASH_ENABLED
+ if (config->FlashMemoryIndex == (uint8_t)kFLASH_MemoryIndexSecondaryFlash)
+ {
+#if FLASH_SSD_SECONDARY_FLASH_HAS_ITS_OWN_PROTECTION_REGISTER || FLASH_SSD_SECONDARY_FLASH_HAS_ITS_OWN_ACCESS_REGISTER
+ /* When required by the command, address bit 23 selects between main flash memory
+ * (=0) and secondary flash memory (=1).*/
+ info->convertedAddress += 0x800000U;
+#endif
+ info->blockWriteUnitSize = FSL_FEATURE_FLASH_PFLASH_1_BLOCK_WRITE_UNIT_SIZE;
+ }
+ else
+#endif /* FLASH_SSD_IS_SECONDARY_FLASH_ENABLED */
+ {
+ info->blockWriteUnitSize = FSL_FEATURE_FLASH_PFLASH_BLOCK_WRITE_UNIT_SIZE;
+ }
+
+ info->sectorCmdAddressAligment = FSL_FEATURE_FLASH_PFLASH_SECTOR_CMD_ADDRESS_ALIGMENT;
+ info->sectionCmdAddressAligment = FSL_FEATURE_FLASH_PFLASH_SECTION_CMD_ADDRESS_ALIGMENT;
+ info->resourceCmdAddressAligment = FSL_FEATURE_FLASH_PFLASH_RESOURCE_CMD_ADDRESS_ALIGMENT;
+ info->checkCmdAddressAligment = FSL_FEATURE_FLASH_PFLASH_CHECK_CMD_ADDRESS_ALIGMENT;
+ }
+
+ return kStatus_FLASH_Success;
+}
+
+/*! @brief Validates the given user key for flash erase APIs.*/
+static status_t flash_check_user_key(uint32_t key)
+{
+ /* Validate the user key */
+ if (key != kFLASH_ApiEraseKey)
+ {
+ return kStatus_FLASH_EraseKeyError;
+ }
+
+ return kStatus_FLASH_Success;
+}
+
+#if FLASH_SSD_IS_FLEXNVM_ENABLED
+/*! @brief Updates FlexNVM memory partition status according to data flash 0 IFR.*/
+static status_t flash_update_flexnvm_memory_partition_status(flash_config_t *config)
+{
+ struct
+ {
+ uint32_t reserved0;
+ uint8_t FlexNVMPartitionCode;
+ uint8_t EEPROMDataSetSize;
+ uint16_t reserved1;
+ } dataIFRReadOut;
+ status_t returnCode;
+
+ if (config == NULL)
+ {
+ return kStatus_FLASH_InvalidArgument;
+ }
+
+#if defined(FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD) && FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD
+ /* Get FlexNVM memory partition info from data flash IFR */
+ returnCode = FLASH_ReadResource(config, DFLASH_IFR_READRESOURCE_START_ADDRESS, (uint32_t *)&dataIFRReadOut,
+ sizeof(dataIFRReadOut), kFLASH_ResourceOptionFlashIfr);
+ if (returnCode != kStatus_FLASH_Success)
+ {
+ return kStatus_FLASH_PartitionStatusUpdateFailure;
+ }
+#else
+#error "Cannot get FlexNVM memory partition info"
+#endif
+
+ /* Fill out partitioned EEPROM size */
+ dataIFRReadOut.EEPROMDataSetSize &= 0x0FU;
+ switch (dataIFRReadOut.EEPROMDataSetSize)
+ {
+ case 0x00U:
+ config->EEpromTotalSize = FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_0000;
+ break;
+ case 0x01U:
+ config->EEpromTotalSize = FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_0001;
+ break;
+ case 0x02U:
+ config->EEpromTotalSize = FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_0010;
+ break;
+ case 0x03U:
+ config->EEpromTotalSize = FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_0011;
+ break;
+ case 0x04U:
+ config->EEpromTotalSize = FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_0100;
+ break;
+ case 0x05U:
+ config->EEpromTotalSize = FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_0101;
+ break;
+ case 0x06U:
+ config->EEpromTotalSize = FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_0110;
+ break;
+ case 0x07U:
+ config->EEpromTotalSize = FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_0111;
+ break;
+ case 0x08U:
+ config->EEpromTotalSize = FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_1000;
+ break;
+ case 0x09U:
+ config->EEpromTotalSize = FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_1001;
+ break;
+ case 0x0AU:
+ config->EEpromTotalSize = FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_1010;
+ break;
+ case 0x0BU:
+ config->EEpromTotalSize = FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_1011;
+ break;
+ case 0x0CU:
+ config->EEpromTotalSize = FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_1100;
+ break;
+ case 0x0DU:
+ config->EEpromTotalSize = FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_1101;
+ break;
+ case 0x0EU:
+ config->EEpromTotalSize = FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_1110;
+ break;
+ case 0x0FU:
+ config->EEpromTotalSize = FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_1111;
+ break;
+ default:
+ config->EEpromTotalSize = FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_RESERVED;
+ break;
+ }
+
+ /* Fill out partitioned DFlash size */
+ dataIFRReadOut.FlexNVMPartitionCode &= 0x0FU;
+ switch (dataIFRReadOut.FlexNVMPartitionCode)
+ {
+ case 0x00U:
+#if (FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0000 != 0xFFFFFFFF)
+ config->DFlashTotalSize = FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0000;
+#else
+ config->DFlashTotalSize = FLEX_NVM_DFLASH_SIZE_FOR_DEPART_RESERVED;
+#endif /* FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0000 */
+ break;
+ case 0x01U:
+#if (FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0001 != 0xFFFFFFFF)
+ config->DFlashTotalSize = FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0001;
+#else
+ config->DFlashTotalSize = FLEX_NVM_DFLASH_SIZE_FOR_DEPART_RESERVED;
+#endif /* FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0001 */
+ break;
+ case 0x02U:
+#if (FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0010 != 0xFFFFFFFF)
+ config->DFlashTotalSize = FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0010;
+#else
+ config->DFlashTotalSize = FLEX_NVM_DFLASH_SIZE_FOR_DEPART_RESERVED;
+#endif /* FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0010 */
+ break;
+ case 0x03U:
+#if (FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0011 != 0xFFFFFFFF)
+ config->DFlashTotalSize = FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0011;
+#else
+ config->DFlashTotalSize = FLEX_NVM_DFLASH_SIZE_FOR_DEPART_RESERVED;
+#endif /* FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0011 */
+ break;
+ case 0x04U:
+#if (FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0100 != 0xFFFFFFFF)
+ config->DFlashTotalSize = FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0100;
+#else
+ config->DFlashTotalSize = FLEX_NVM_DFLASH_SIZE_FOR_DEPART_RESERVED;
+#endif /* FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0100 */
+ break;
+ case 0x05U:
+#if (FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0101 != 0xFFFFFFFF)
+ config->DFlashTotalSize = FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0101;
+#else
+ config->DFlashTotalSize = FLEX_NVM_DFLASH_SIZE_FOR_DEPART_RESERVED;
+#endif /* FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0101 */
+ break;
+ case 0x06U:
+#if (FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0110 != 0xFFFFFFFF)
+ config->DFlashTotalSize = FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0110;
+#else
+ config->DFlashTotalSize = FLEX_NVM_DFLASH_SIZE_FOR_DEPART_RESERVED;
+#endif /* FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0110 */
+ break;
+ case 0x07U:
+#if (FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0111 != 0xFFFFFFFF)
+ config->DFlashTotalSize = FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0111;
+#else
+ config->DFlashTotalSize = FLEX_NVM_DFLASH_SIZE_FOR_DEPART_RESERVED;
+#endif /* FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0111 */
+ break;
+ case 0x08U:
+#if (FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1000 != 0xFFFFFFFF)
+ config->DFlashTotalSize = FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1000;
+#else
+ config->DFlashTotalSize = FLEX_NVM_DFLASH_SIZE_FOR_DEPART_RESERVED;
+#endif /* FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1000 */
+ break;
+ case 0x09U:
+#if (FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1001 != 0xFFFFFFFF)
+ config->DFlashTotalSize = FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1001;
+#else
+ config->DFlashTotalSize = FLEX_NVM_DFLASH_SIZE_FOR_DEPART_RESERVED;
+#endif /* FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1001 */
+ break;
+ case 0x0AU:
+#if (FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1010 != 0xFFFFFFFF)
+ config->DFlashTotalSize = FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1010;
+#else
+ config->DFlashTotalSize = FLEX_NVM_DFLASH_SIZE_FOR_DEPART_RESERVED;
+#endif /* FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1010 */
+ break;
+ case 0x0BU:
+#if (FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1011 != 0xFFFFFFFF)
+ config->DFlashTotalSize = FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1011;
+#else
+ config->DFlashTotalSize = FLEX_NVM_DFLASH_SIZE_FOR_DEPART_RESERVED;
+#endif /* FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1011 */
+ break;
+ case 0x0CU:
+#if (FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1100 != 0xFFFFFFFF)
+ config->DFlashTotalSize = FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1100;
+#else
+ config->DFlashTotalSize = FLEX_NVM_DFLASH_SIZE_FOR_DEPART_RESERVED;
+#endif /* FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1100 */
+ break;
+ case 0x0DU:
+#if (FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1101 != 0xFFFFFFFF)
+ config->DFlashTotalSize = FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1101;
+#else
+ config->DFlashTotalSize = FLEX_NVM_DFLASH_SIZE_FOR_DEPART_RESERVED;
+#endif /* FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1101 */
+ break;
+ case 0x0EU:
+#if (FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1110 != 0xFFFFFFFF)
+ config->DFlashTotalSize = FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1110;
+#else
+ config->DFlashTotalSize = FLEX_NVM_DFLASH_SIZE_FOR_DEPART_RESERVED;
+#endif /* FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1110 */
+ break;
+ case 0x0FU:
+#if (FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1111 != 0xFFFFFFFF)
+ config->DFlashTotalSize = FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1111;
+#else
+ config->DFlashTotalSize = FLEX_NVM_DFLASH_SIZE_FOR_DEPART_RESERVED;
+#endif /* FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1111 */
+ break;
+ default:
+ config->DFlashTotalSize = FLEX_NVM_DFLASH_SIZE_FOR_DEPART_RESERVED;
+ break;
+ }
+
+ return kStatus_FLASH_Success;
+}
+#endif /* FLASH_SSD_IS_FLEXNVM_ENABLED */
+
+#if defined(FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD) && FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD
+/*! @brief Validates the range of the given resource address.*/
+static status_t flash_check_resource_range(uint32_t start,
+ uint32_t lengthInBytes,
+ uint32_t alignmentBaseline,
+ flash_read_resource_option_t option)
+{
+ status_t status;
+ uint32_t maxReadbleAddress;
+
+ if ((start & (alignmentBaseline - 1)) || (lengthInBytes & (alignmentBaseline - 1)))
+ {
+ return kStatus_FLASH_AlignmentError;
+ }
+
+ status = kStatus_FLASH_Success;
+
+ maxReadbleAddress = start + lengthInBytes - 1;
+ if (option == kFLASH_ResourceOptionVersionId)
+ {
+ if ((start != kFLASH_ResourceRangeVersionIdStart) ||
+ ((start + lengthInBytes - 1) != kFLASH_ResourceRangeVersionIdEnd))
+ {
+ status = kStatus_FLASH_InvalidArgument;
+ }
+ }
+ else if (option == kFLASH_ResourceOptionFlashIfr)
+ {
+ if (maxReadbleAddress < kFLASH_ResourceRangePflashIfrSizeInBytes)
+ {
+ }
+#if defined(FSL_FEATURE_FLASH_HAS_PFLASH_BLOCK_SWAP) && FSL_FEATURE_FLASH_HAS_PFLASH_BLOCK_SWAP
+ else if ((start >= kFLASH_ResourceRangePflashSwapIfrStart) &&
+ (maxReadbleAddress <= kFLASH_ResourceRangePflashSwapIfrEnd))
+ {
+ }
+#endif /* FSL_FEATURE_FLASH_HAS_PFLASH_BLOCK_SWAP */
+ else if ((start >= kFLASH_ResourceRangeDflashIfrStart) &&
+ (maxReadbleAddress <= kFLASH_ResourceRangeDflashIfrEnd))
+ {
+ }
+ else
+ {
+ status = kStatus_FLASH_InvalidArgument;
+ }
+ }
+ else
+ {
+ status = kStatus_FLASH_InvalidArgument;
+ }
+
+ return status;
+}
+#endif /* FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD */
+
+#if defined(FSL_FEATURE_FLASH_HAS_SWAP_CONTROL_CMD) && FSL_FEATURE_FLASH_HAS_SWAP_CONTROL_CMD
+/*! @brief Validates the gived swap control option.*/
+static status_t flash_check_swap_control_option(flash_swap_control_option_t option)
+{
+ if ((option == kFLASH_SwapControlOptionIntializeSystem) || (option == kFLASH_SwapControlOptionSetInUpdateState) ||
+ (option == kFLASH_SwapControlOptionSetInCompleteState) || (option == kFLASH_SwapControlOptionReportStatus) ||
+ (option == kFLASH_SwapControlOptionDisableSystem))
+ {
+ return kStatus_FLASH_Success;
+ }
+
+ return kStatus_FLASH_InvalidArgument;
+}
+#endif /* FSL_FEATURE_FLASH_HAS_SWAP_CONTROL_CMD */
+
+#if defined(FSL_FEATURE_FLASH_HAS_PFLASH_BLOCK_SWAP) && FSL_FEATURE_FLASH_HAS_PFLASH_BLOCK_SWAP
+/*! @brief Validates the gived address to see if it is equal to swap indicator address in pflash swap IFR.*/
+static status_t flash_validate_swap_indicator_address(flash_config_t *config, uint32_t address)
+{
+ flash_swap_ifr_field_data_t flashSwapIfrFieldData;
+ uint32_t swapIndicatorAddress;
+
+ status_t returnCode;
+#if defined(FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD) && FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD
+ returnCode =
+ FLASH_ReadResource(config, kFLASH_ResourceRangePflashSwapIfrStart, flashSwapIfrFieldData.flashSwapIfrData,
+ sizeof(flashSwapIfrFieldData.flashSwapIfrData), kFLASH_ResourceOptionFlashIfr);
+
+ if (returnCode != kStatus_FLASH_Success)
+ {
+ return returnCode;
+ }
+#else
+ {
+ /* From RM, the actual info are stored in FCCOB6,7 */
+ uint32_t returnValue[2];
+ returnCode = FLASH_ReadOnce(config, kFLASH_RecordIndexSwapAddr, returnValue, 4);
+ if (returnCode != kStatus_FLASH_Success)
+ {
+ return returnCode;
+ }
+ flashSwapIfrFieldData.flashSwapIfrField.swapIndicatorAddress = (uint16_t)returnValue[0];
+ returnCode = FLASH_ReadOnce(config, kFLASH_RecordIndexSwapEnable, returnValue, 4);
+ if (returnCode != kStatus_FLASH_Success)
+ {
+ return returnCode;
+ }
+ flashSwapIfrFieldData.flashSwapIfrField.swapEnableWord = (uint16_t)returnValue[0];
+ returnCode = FLASH_ReadOnce(config, kFLASH_RecordIndexSwapDisable, returnValue, 4);
+ if (returnCode != kStatus_FLASH_Success)
+ {
+ return returnCode;
+ }
+ flashSwapIfrFieldData.flashSwapIfrField.swapDisableWord = (uint16_t)returnValue[0];
+ }
+#endif
+
+ /* The high bits value of Swap Indicator Address is stored in Program Flash Swap IFR Field,
+ * the low severval bit value of Swap Indicator Address is always 1'b0 */
+ swapIndicatorAddress = (uint32_t)flashSwapIfrFieldData.flashSwapIfrField.swapIndicatorAddress *
+ FSL_FEATURE_FLASH_PFLASH_SWAP_CONTROL_CMD_ADDRESS_ALIGMENT;
+ if (address != swapIndicatorAddress)
+ {
+ return kStatus_FLASH_SwapIndicatorAddressError;
+ }
+
+ return returnCode;
+}
+#endif /* FSL_FEATURE_FLASH_HAS_PFLASH_BLOCK_SWAP */
+
+#if defined(FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD) && FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD
+/*! @brief Validates the gived flexram function option.*/
+static inline status_t flasn_check_flexram_function_option_range(flash_flexram_function_option_t option)
+{
+ if ((option != kFLASH_FlexramFunctionOptionAvailableAsRam) &&
+ (option != kFLASH_FlexramFunctionOptionAvailableForEeprom))
+ {
+ return kStatus_FLASH_InvalidArgument;
+ }
+
+ return kStatus_FLASH_Success;
+}
+#endif /* FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD */
+
+/*! @brief Gets the flash protection information (region size, region count).*/
+static status_t flash_get_protection_info(flash_config_t *config, flash_protection_config_t *info)
+{
+ uint32_t pflashTotalSize;
+
+ if (config == NULL)
+ {
+ return kStatus_FLASH_InvalidArgument;
+ }
+
+ /* Clean up info Structure*/
+ memset(info, 0, sizeof(flash_protection_config_t));
+
+/* Note: KW40 has a secondary flash, but it doesn't have independent protection register*/
+#if FLASH_SSD_IS_SECONDARY_FLASH_ENABLED && (!FLASH_SSD_SECONDARY_FLASH_HAS_ITS_OWN_PROTECTION_REGISTER)
+ pflashTotalSize = FSL_FEATURE_FLASH_PFLASH_BLOCK_COUNT * FSL_FEATURE_FLASH_PFLASH_BLOCK_SIZE +
+ FSL_FEATURE_FLASH_PFLASH_1_BLOCK_COUNT * FSL_FEATURE_FLASH_PFLASH_1_BLOCK_SIZE;
+ info->regionBase = FSL_FEATURE_FLASH_PFLASH_START_ADDRESS;
+#else
+ pflashTotalSize = config->PFlashTotalSize;
+ info->regionBase = config->PFlashBlockBase;
+#endif
+
+#if FLASH_SSD_IS_SECONDARY_FLASH_ENABLED && FLASH_SSD_SECONDARY_FLASH_HAS_ITS_OWN_PROTECTION_REGISTER
+ if (config->FlashMemoryIndex == (uint8_t)kFLASH_MemoryIndexSecondaryFlash)
+ {
+ info->regionCount = FSL_FEATURE_FLASH_PFLASH_1_PROTECTION_REGION_COUNT;
+ }
+ else
+#endif
+ {
+ info->regionCount = FSL_FEATURE_FLASH_PFLASH_PROTECTION_REGION_COUNT;
+ }
+
+ /* Calculate the size of the flash protection region
+ * If the flash density is > 32KB, then protection region is 1/32 of total flash density
+ * Else if flash density is < 32KB, then flash protection region is set to 1KB */
+ if (pflashTotalSize > info->regionCount * 1024)
+ {
+ info->regionSize = (pflashTotalSize) / info->regionCount;
+ }
+ else
+ {
+ info->regionSize = 1024;
+ }
+
+ return kStatus_FLASH_Success;
+}
+
+#if defined(FSL_FEATURE_FLASH_HAS_ACCESS_CONTROL) && FSL_FEATURE_FLASH_HAS_ACCESS_CONTROL
+/*! @brief Gets the flash Execute-Only access information (Segment size, Segment count).*/
+static status_t flash_get_access_info(flash_config_t *config, flash_access_config_t *info)
+{
+ if (config == NULL)
+ {
+ return kStatus_FLASH_InvalidArgument;
+ }
+
+ /* Clean up info Structure*/
+ memset(info, 0, sizeof(flash_access_config_t));
+
+/* Note: KW40 has a secondary flash, but it doesn't have independent access register*/
+#if FLASH_SSD_IS_SECONDARY_FLASH_ENABLED && (!FLASH_SSD_SECONDARY_FLASH_HAS_ITS_OWN_ACCESS_REGISTER)
+ info->SegmentBase = FSL_FEATURE_FLASH_PFLASH_START_ADDRESS;
+#else
+ info->SegmentBase = config->PFlashBlockBase;
+#endif
+ info->SegmentSize = config->PFlashAccessSegmentSize;
+ info->SegmentCount = config->PFlashAccessSegmentCount;
+
+ return kStatus_FLASH_Success;
+}
+#endif /* FSL_FEATURE_FLASH_HAS_ACCESS_CONTROL */
diff --git a/drivers/src/fsl_flexbus.c b/drivers/src/fsl_flexbus.c
new file mode 100644
index 0000000..4e29285
--- /dev/null
+++ b/drivers/src/fsl_flexbus.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of Freescale Semiconductor, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsl_flexbus.h"
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Gets the instance from the base address
+ *
+ * @param base FLEXBUS peripheral base address
+ *
+ * @return The FLEXBUS instance
+ */
+static uint32_t FLEXBUS_GetInstance(FB_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*! @brief Pointers to FLEXBUS bases for each instance. */
+static FB_Type *const s_flexbusBases[] = FB_BASE_PTRS;
+
+/*! @brief Pointers to FLEXBUS clocks for each instance. */
+static const clock_ip_name_t s_flexbusClocks[] = FLEXBUS_CLOCKS;
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static uint32_t FLEXBUS_GetInstance(FB_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < FSL_FEATURE_SOC_FB_COUNT; instance++)
+ {
+ if (s_flexbusBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < FSL_FEATURE_SOC_FB_COUNT);
+
+ return instance;
+}
+
+void FLEXBUS_Init(FB_Type *base, const flexbus_config_t *config)
+{
+ assert(config != NULL);
+ assert(config->chip < FB_CSAR_COUNT);
+ assert(config->waitStates <= 0x3FU);
+
+ uint32_t chip = 0;
+ uint32_t reg_value = 0;
+
+ /* Ungate clock for FLEXBUS */
+ CLOCK_EnableClock(s_flexbusClocks[FLEXBUS_GetInstance(base)]);
+
+ /* Reset all the register to default state */
+ for (chip = 0; chip < FB_CSAR_COUNT; chip++)
+ {
+ /* Reset CSMR register, all chips not valid (disabled) */
+ base->CS[chip].CSMR = 0x0000U;
+ /* Set default base address */
+ base->CS[chip].CSAR &= (~FB_CSAR_BA_MASK);
+ /* Reset FB_CSCRx register */
+ base->CS[chip].CSCR = 0x0000U;
+ }
+ /* Set FB_CSPMCR register */
+ /* FlexBus signal group 1 multiplex control */
+ reg_value |= kFLEXBUS_MultiplexGroup1_FB_ALE << FB_CSPMCR_GROUP1_SHIFT;
+ /* FlexBus signal group 2 multiplex control */
+ reg_value |= kFLEXBUS_MultiplexGroup2_FB_CS4 << FB_CSPMCR_GROUP2_SHIFT;
+ /* FlexBus signal group 3 multiplex control */
+ reg_value |= kFLEXBUS_MultiplexGroup3_FB_CS5 << FB_CSPMCR_GROUP3_SHIFT;
+ /* FlexBus signal group 4 multiplex control */
+ reg_value |= kFLEXBUS_MultiplexGroup4_FB_TBST << FB_CSPMCR_GROUP4_SHIFT;
+ /* FlexBus signal group 5 multiplex control */
+ reg_value |= kFLEXBUS_MultiplexGroup5_FB_TA << FB_CSPMCR_GROUP5_SHIFT;
+ /* Write to CSPMCR register */
+ base->CSPMCR = reg_value;
+
+ /* Update chip value */
+ chip = config->chip;
+
+ /* Base address */
+ reg_value = config->chipBaseAddress;
+ /* Write to CSAR register */
+ base->CS[chip].CSAR = reg_value;
+ /* Chip-select validation */
+ reg_value = 0x1U << FB_CSMR_V_SHIFT;
+ /* Write protect */
+ reg_value |= (uint32_t)(config->writeProtect) << FB_CSMR_WP_SHIFT;
+ /* Base address mask */
+ reg_value |= config->chipBaseAddressMask << FB_CSMR_BAM_SHIFT;
+ /* Write to CSMR register */
+ base->CS[chip].CSMR = reg_value;
+ /* Burst write */
+ reg_value = (uint32_t)(config->burstWrite) << FB_CSCR_BSTW_SHIFT;
+ /* Burst read */
+ reg_value |= (uint32_t)(config->burstRead) << FB_CSCR_BSTR_SHIFT;
+ /* Byte-enable mode */
+ reg_value |= (uint32_t)(config->byteEnableMode) << FB_CSCR_BEM_SHIFT;
+ /* Port size */
+ reg_value |= (uint32_t)config->portSize << FB_CSCR_PS_SHIFT;
+ /* The internal transfer acknowledge for accesses */
+ reg_value |= (uint32_t)(config->autoAcknowledge) << FB_CSCR_AA_SHIFT;
+ /* Byte-Lane shift */
+ reg_value |= (uint32_t)config->byteLaneShift << FB_CSCR_BLS_SHIFT;
+ /* The number of wait states */
+ reg_value |= (uint32_t)config->waitStates << FB_CSCR_WS_SHIFT;
+ /* Write address hold or deselect */
+ reg_value |= (uint32_t)config->writeAddressHold << FB_CSCR_WRAH_SHIFT;
+ /* Read address hold or deselect */
+ reg_value |= (uint32_t)config->readAddressHold << FB_CSCR_RDAH_SHIFT;
+ /* Address setup */
+ reg_value |= (uint32_t)config->addressSetup << FB_CSCR_ASET_SHIFT;
+ /* Extended transfer start/extended address latch */
+ reg_value |= (uint32_t)(config->extendTransferAddress) << FB_CSCR_EXTS_SHIFT;
+ /* Secondary wait state */
+ reg_value |= (uint32_t)(config->secondaryWaitStates) << FB_CSCR_SWSEN_SHIFT;
+ /* Write to CSCR register */
+ base->CS[chip].CSCR = reg_value;
+ /* FlexBus signal group 1 multiplex control */
+ reg_value = (uint32_t)config->group1MultiplexControl << FB_CSPMCR_GROUP1_SHIFT;
+ /* FlexBus signal group 2 multiplex control */
+ reg_value |= (uint32_t)config->group2MultiplexControl << FB_CSPMCR_GROUP2_SHIFT;
+ /* FlexBus signal group 3 multiplex control */
+ reg_value |= (uint32_t)config->group3MultiplexControl << FB_CSPMCR_GROUP3_SHIFT;
+ /* FlexBus signal group 4 multiplex control */
+ reg_value |= (uint32_t)config->group4MultiplexControl << FB_CSPMCR_GROUP4_SHIFT;
+ /* FlexBus signal group 5 multiplex control */
+ reg_value |= (uint32_t)config->group5MultiplexControl << FB_CSPMCR_GROUP5_SHIFT;
+ /* Write to CSPMCR register */
+ base->CSPMCR = reg_value;
+}
+
+void FLEXBUS_Deinit(FB_Type *base)
+{
+ /* Gate clock for FLEXBUS */
+ CLOCK_DisableClock(s_flexbusClocks[FLEXBUS_GetInstance(base)]);
+}
+
+void FLEXBUS_GetDefaultConfig(flexbus_config_t *config)
+{
+ config->chip = 0; /* Chip 0 FlexBus for validation */
+ config->writeProtect = 0; /* Write accesses are allowed */
+ config->burstWrite = 0; /* Burst-Write disable */
+ config->burstRead = 0; /* Burst-Read disable */
+ config->byteEnableMode = 0; /* Byte-Enable mode is asserted for data write only */
+ config->autoAcknowledge = true; /* Auto-Acknowledge enable */
+ config->extendTransferAddress = 0; /* Extend transfer start/extend address latch disable */
+ config->secondaryWaitStates = 0; /* Secondary wait state disable */
+ config->byteLaneShift = kFLEXBUS_NotShifted; /* Byte-Lane shift disable */
+ config->writeAddressHold = kFLEXBUS_Hold1Cycle; /* Write address hold 1 cycles */
+ config->readAddressHold = kFLEXBUS_Hold1Or0Cycles; /* Read address hold 0 cycles */
+ config->addressSetup =
+ kFLEXBUS_FirstRisingEdge; /* Assert ~FB_CSn on the first rising clock edge after the address is asserted */
+ config->portSize = kFLEXBUS_1Byte; /* 1 byte port size of transfer */
+ config->group1MultiplexControl = kFLEXBUS_MultiplexGroup1_FB_ALE; /* FB_ALE */
+ config->group2MultiplexControl = kFLEXBUS_MultiplexGroup2_FB_CS4; /* FB_CS4 */
+ config->group3MultiplexControl = kFLEXBUS_MultiplexGroup3_FB_CS5; /* FB_CS5 */
+ config->group4MultiplexControl = kFLEXBUS_MultiplexGroup4_FB_TBST; /* FB_TBST */
+ config->group5MultiplexControl = kFLEXBUS_MultiplexGroup5_FB_TA; /* FB_TA */
+}
diff --git a/drivers/src/fsl_flexcan.c b/drivers/src/fsl_flexcan.c
new file mode 100644
index 0000000..2a07dc5
--- /dev/null
+++ b/drivers/src/fsl_flexcan.c
@@ -0,0 +1,1450 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsl_flexcan.h"
+
+/*******************************************************************************
+ * Definitons
+ ******************************************************************************/
+
+#define FLEXCAN_TIME_QUANTA_NUM (10)
+
+/*! @brief FlexCAN Internal State. */
+enum _flexcan_state
+{
+ kFLEXCAN_StateIdle = 0x0, /*!< MB/RxFIFO idle.*/
+ kFLEXCAN_StateRxData = 0x1, /*!< MB receiving.*/
+ kFLEXCAN_StateRxRemote = 0x2, /*!< MB receiving remote reply.*/
+ kFLEXCAN_StateTxData = 0x3, /*!< MB transmitting.*/
+ kFLEXCAN_StateTxRemote = 0x4, /*!< MB transmitting remote request.*/
+ kFLEXCAN_StateRxFifo = 0x5, /*!< RxFIFO receiving.*/
+};
+
+/*! @brief FlexCAN message buffer CODE for Rx buffers. */
+enum _flexcan_mb_code_rx
+{
+ kFLEXCAN_RxMbInactive = 0x0, /*!< MB is not active.*/
+ kFLEXCAN_RxMbFull = 0x2, /*!< MB is full.*/
+ kFLEXCAN_RxMbEmpty = 0x4, /*!< MB is active and empty.*/
+ kFLEXCAN_RxMbOverrun = 0x6, /*!< MB is overwritten into a full buffer.*/
+ kFLEXCAN_RxMbBusy = 0x8, /*!< FlexCAN is updating the contents of the MB.*/
+ /*! The CPU must not access the MB.*/
+ kFLEXCAN_RxMbRanswer = 0xA, /*!< A frame was configured to recognize a Remote Request Frame */
+ /*! and transmit a Response Frame in return.*/
+ kFLEXCAN_RxMbNotUsed = 0xF, /*!< Not used.*/
+};
+
+/*! @brief FlexCAN message buffer CODE FOR Tx buffers. */
+enum _flexcan_mb_code_tx
+{
+ kFLEXCAN_TxMbInactive = 0x8, /*!< MB is not active.*/
+ kFLEXCAN_TxMbAbort = 0x9, /*!< MB is aborted.*/
+ kFLEXCAN_TxMbDataOrRemote = 0xC, /*!< MB is a TX Data Frame(when MB RTR = 0) or */
+ /*!< MB is a TX Remote Request Frame (when MB RTR = 1).*/
+ kFLEXCAN_TxMbTanswer = 0xE, /*!< MB is a TX Response Request Frame from */
+ /*! an incoming Remote Request Frame.*/
+ kFLEXCAN_TxMbNotUsed = 0xF, /*!< Not used.*/
+};
+
+/* Typedef for interrupt handler. */
+typedef void (*flexcan_isr_t)(CAN_Type *base, flexcan_handle_t *handle);
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Get the FlexCAN instance from peripheral base address.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @return FlexCAN instance.
+ */
+uint32_t FLEXCAN_GetInstance(CAN_Type *base);
+
+#if !defined(NDEBUG)
+/*!
+ * @brief Check if Message Buffer is occupied by Rx FIFO.
+ *
+ * This function check if Message Buffer is occupied by Rx FIFO.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param mbIdx The FlexCAN Message Buffer index.
+ */
+static bool FLEXCAN_IsMbOccupied(CAN_Type *base, uint8_t mbIdx);
+#endif
+#if 0
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641)
+/*!
+ * @brief Get the first valid Message buffer ID of give FlexCAN instance.
+ *
+ * This function is a helper function for Errata 5641 workaround.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @return The first valid Message Buffer Number.
+ */
+static uint32_t FLEXCAN_GetFirstValidMb(CAN_Type *base);
+#endif
+#endif
+/*!
+ * @brief Check if Message Buffer interrupt is enabled.
+ *
+ * This function check if Message Buffer interrupt is enabled.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param mbIdx The FlexCAN Message Buffer index.
+ */
+static bool FLEXCAN_IsMbIntEnabled(CAN_Type *base, uint8_t mbIdx);
+
+/*!
+ * @brief Reset the FlexCAN Instance.
+ *
+ * Restores the FlexCAN module to reset state, notice that this function
+ * will set all the registers to reset state so the FlexCAN module can not work
+ * after calling this API.
+ *
+ * @param base FlexCAN peripheral base address.
+*/
+static void FLEXCAN_Reset(CAN_Type *base);
+
+/*!
+ * @brief Set Baud Rate of FlexCAN.
+ *
+ * This function set the baud rate of FlexCAN.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param sourceClock_Hz Source Clock in Hz.
+ * @param baudRate_Bps Baud Rate in Bps.
+ */
+static void FLEXCAN_SetBaudRate(CAN_Type *base, uint32_t sourceClock_Hz, uint32_t baudRate_Bps);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/* Array of FlexCAN peripheral base address. */
+static CAN_Type *const s_flexcanBases[] = CAN_BASE_PTRS;
+
+/* Array of FlexCAN IRQ number. */
+static const IRQn_Type s_flexcanRxWarningIRQ[] = CAN_Rx_Warning_IRQS;
+static const IRQn_Type s_flexcanTxWarningIRQ[] = CAN_Tx_Warning_IRQS;
+static const IRQn_Type s_flexcanWakeUpIRQ[] = CAN_Wake_Up_IRQS;
+static const IRQn_Type s_flexcanErrorIRQ[] = CAN_Error_IRQS;
+static const IRQn_Type s_flexcanBusOffIRQ[] = CAN_Bus_Off_IRQS;
+static const IRQn_Type s_flexcanMbIRQ[] = CAN_ORed_Message_buffer_IRQS;
+
+/* Array of FlexCAN handle. */
+static flexcan_handle_t *s_flexcanHandle[ARRAY_SIZE(s_flexcanBases)];
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/* Array of FlexCAN clock name. */
+static const clock_ip_name_t s_flexcanClock[] = FLEXCAN_CLOCKS;
+#if defined(FLEXCAN_PERIPH_CLOCKS)
+/* Array of FlexCAN serial clock name. */
+static const clock_ip_name_t s_flexcanPeriphClock[] = FLEXCAN_PERIPH_CLOCKS;
+#endif /* FLEXCAN_PERIPH_CLOCKS */
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/* FlexCAN ISR for transactional APIs. */
+static flexcan_isr_t s_flexcanIsr;
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+uint32_t FLEXCAN_GetInstance(CAN_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_flexcanBases); instance++)
+ {
+ if (s_flexcanBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_flexcanBases));
+
+ return instance;
+}
+
+void FLEXCAN_EnterFreezeMode(CAN_Type *base)
+{
+ /* Set Freeze, Halt bits. */
+ base->MCR |= CAN_MCR_HALT_MASK;
+
+ /* Wait until the FlexCAN Module enter freeze mode. */
+ while (!(base->MCR & CAN_MCR_FRZACK_MASK))
+ {
+ }
+}
+
+void FLEXCAN_ExitFreezeMode(CAN_Type *base)
+{
+ /* Clear Freeze, Halt bits. */
+ base->MCR &= ~CAN_MCR_HALT_MASK;
+
+ /* Wait until the FlexCAN Module exit freeze mode. */
+ while (base->MCR & CAN_MCR_FRZACK_MASK)
+ {
+ }
+}
+
+#if !defined(NDEBUG)
+static bool FLEXCAN_IsMbOccupied(CAN_Type *base, uint8_t mbIdx)
+{
+ uint8_t lastOccupiedMb;
+
+ /* Is Rx FIFO enabled? */
+ if (base->MCR & CAN_MCR_RFEN_MASK)
+ {
+ /* Get RFFN value. */
+ lastOccupiedMb = ((base->CTRL2 & CAN_CTRL2_RFFN_MASK) >> CAN_CTRL2_RFFN_SHIFT);
+ /* Calculate the number of last Message Buffer occupied by Rx FIFO. */
+ lastOccupiedMb = ((lastOccupiedMb + 1) * 2) + 5;
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641)
+ if (mbIdx <= (lastOccupiedMb + 1))
+#else
+ if (mbIdx <= lastOccupiedMb)
+#endif
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641)
+ if (0 == mbIdx)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+#else
+ return false;
+#endif
+ }
+}
+#endif
+#if 0
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641)
+static uint32_t FLEXCAN_GetFirstValidMb(CAN_Type *base)
+{
+ uint32_t firstValidMbNum;
+
+ if (base->MCR & CAN_MCR_RFEN_MASK)
+ {
+ firstValidMbNum = ((base->CTRL2 & CAN_CTRL2_RFFN_MASK) >> CAN_CTRL2_RFFN_SHIFT);
+ firstValidMbNum = ((firstValidMbNum + 1) * 2) + 6;
+ }
+ else
+ {
+ firstValidMbNum = 0;
+ }
+
+ return firstValidMbNum;
+}
+#endif
+#endif
+
+static bool FLEXCAN_IsMbIntEnabled(CAN_Type *base, uint8_t mbIdx)
+{
+ /* Assertion. */
+ assert(mbIdx < FSL_FEATURE_FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBERn(base));
+
+#if (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ if (mbIdx < 32)
+ {
+#endif
+ if (base->IMASK1 & ((uint32_t)(1 << mbIdx)))
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+#if (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ }
+ else
+ {
+ if (base->IMASK2 & ((uint32_t)(1 << (mbIdx - 32))))
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+#endif
+}
+
+static void FLEXCAN_Reset(CAN_Type *base)
+{
+ /* The module must should be first exit from low power
+ * mode, and then soft reset can be applied.
+ */
+ assert(!(base->MCR & CAN_MCR_MDIS_MASK));
+
+ uint8_t i;
+
+#if (FSL_FEATURE_FLEXCAN_HAS_DOZE_MODE_SUPPORT != 0)
+ /* De-assert DOZE Enable Bit. */
+ base->MCR &= ~CAN_MCR_DOZE_MASK;
+#endif
+
+ /* Wait until FlexCAN exit from any Low Power Mode. */
+ while (base->MCR & CAN_MCR_LPMACK_MASK)
+ {
+ }
+
+ /* Assert Soft Reset Signal. */
+ base->MCR |= CAN_MCR_SOFTRST_MASK;
+ /* Wait until FlexCAN reset completes. */
+ while (base->MCR & CAN_MCR_SOFTRST_MASK)
+ {
+ }
+
+/* Reset MCR rigister. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_GLITCH_FILTER) && FSL_FEATURE_FLEXCAN_HAS_GLITCH_FILTER)
+ base->MCR |= CAN_MCR_WRNEN_MASK | CAN_MCR_WAKSRC_MASK |
+ CAN_MCR_MAXMB(FSL_FEATURE_FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBERn(base) - 1);
+#else
+ base->MCR |= CAN_MCR_WRNEN_MASK | CAN_MCR_MAXMB(FSL_FEATURE_FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBERn(base) - 1);
+#endif
+
+ /* Reset CTRL1 and CTRL2 rigister. */
+ base->CTRL1 = CAN_CTRL1_SMP_MASK;
+ base->CTRL2 = CAN_CTRL2_TASD(0x16) | CAN_CTRL2_RRS_MASK | CAN_CTRL2_EACEN_MASK;
+
+ /* Clean all individual Rx Mask of Message Buffers. */
+ for (i = 0; i < FSL_FEATURE_FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBERn(base); i++)
+ {
+ base->RXIMR[i] = 0x3FFFFFFF;
+ }
+
+ /* Clean Global Mask of Message Buffers. */
+ base->RXMGMASK = 0x3FFFFFFF;
+ /* Clean Global Mask of Message Buffer 14. */
+ base->RX14MASK = 0x3FFFFFFF;
+ /* Clean Global Mask of Message Buffer 15. */
+ base->RX15MASK = 0x3FFFFFFF;
+ /* Clean Global Mask of Rx FIFO. */
+ base->RXFGMASK = 0x3FFFFFFF;
+
+ /* Clean all Message Buffer CS fields. */
+ for (i = 0; i < FSL_FEATURE_FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBERn(base); i++)
+ {
+ base->MB[i].CS = 0x0;
+ }
+}
+
+void FLEXCAN_SetBaudRate(CAN_Type *base, uint32_t sourceClock_Hz, uint32_t baudRate_Bps)
+{
+ flexcan_timing_config_t timingConfig;
+ uint32_t priDiv = baudRate_Bps * FLEXCAN_TIME_QUANTA_NUM;
+
+ /* Assertion: Desired baud rate is too high. */
+ assert(baudRate_Bps <= 1000000U);
+ /* Assertion: Source clock should greater than baud rate * FLEXCAN_TIME_QUANTA_NUM. */
+ assert(priDiv <= sourceClock_Hz);
+
+
+ if (0 == priDiv)
+ {
+ priDiv = 1;
+ }
+
+ priDiv = (sourceClock_Hz / priDiv) - 1;
+ /* Desired baud rate is too low. */
+ if (priDiv > 0xFF)
+ {
+ priDiv = 0xFF;
+ }
+
+
+ /* FlexCAN timing setting formula:
+ * FLEXCAN_TIME_QUANTA_NUM = 1 + (PSEG1 + 1) + (PSEG2 + 1) + (PROPSEG + 1);
+ */
+ timingConfig.preDivider = priDiv;
+ timingConfig.phaseSeg1 = 3;
+ timingConfig.phaseSeg2 = 2;
+ timingConfig.propSeg = 1;
+ timingConfig.rJumpwidth = 1;
+
+ /* Update actual timing characteristic. */
+ FLEXCAN_SetTimingConfig(base, &timingConfig);
+}
+
+void FLEXCAN_Init(CAN_Type *base, const flexcan_config_t *config, uint32_t sourceClock_Hz)
+{
+ uint32_t mcrTemp;
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ uint32_t instance;
+#endif
+
+ /* Assertion. */
+ assert(config);
+ assert((config->maxMbNum > 0) && (config->maxMbNum <= FSL_FEATURE_FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBERn(base)));
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ instance = FLEXCAN_GetInstance(base);
+ /* Enable FlexCAN clock. */
+ CLOCK_EnableClock(s_flexcanClock[instance]);
+#if defined(FLEXCAN_PERIPH_CLOCKS)
+ /* Enable FlexCAN serial clock. */
+ CLOCK_EnableClock(s_flexcanPeriphClock[instance]);
+#endif /* FLEXCAN_PERIPH_CLOCKS */
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+#if (!defined(FSL_FEATURE_FLEXCAN_SUPPORT_ENGINE_CLK_SEL_REMOVE)) || !FSL_FEATURE_FLEXCAN_SUPPORT_ENGINE_CLK_SEL_REMOVE
+ /* Disable FlexCAN Module. */
+ FLEXCAN_Enable(base, false);
+
+ /* Protocol-Engine clock source selection, This bit must be set
+ * when FlexCAN Module in Disable Mode.
+ */
+ base->CTRL1 = (kFLEXCAN_ClkSrcOsc == config->clkSrc) ? base->CTRL1 & ~CAN_CTRL1_CLKSRC_MASK :
+ base->CTRL1 | CAN_CTRL1_CLKSRC_MASK;
+#endif /* FSL_FEATURE_FLEXCAN_SUPPORT_ENGINE_CLK_SEL_REMOVE */
+
+ /* Enable FlexCAN Module for configuartion. */
+ FLEXCAN_Enable(base, true);
+
+ /* Reset to known status. */
+ FLEXCAN_Reset(base);
+
+ /* Save current MCR value and enable to enter Freeze mode(enabled by default). */
+ mcrTemp = base->MCR;
+
+ /* Set the maximum number of Message Buffers */
+ mcrTemp = (mcrTemp & ~CAN_MCR_MAXMB_MASK) | CAN_MCR_MAXMB(config->maxMbNum - 1);
+
+ /* Enable Loop Back Mode? */
+ base->CTRL1 = (config->enableLoopBack) ? base->CTRL1 | CAN_CTRL1_LPB_MASK : base->CTRL1 & ~CAN_CTRL1_LPB_MASK;
+
+ /* Enable Self Wake Up Mode? */
+ mcrTemp = (config->enableSelfWakeup) ? mcrTemp | CAN_MCR_SLFWAK_MASK : mcrTemp & ~CAN_MCR_SLFWAK_MASK;
+
+ /* Enable Individual Rx Masking? */
+ mcrTemp = (config->enableIndividMask) ? mcrTemp | CAN_MCR_IRMQ_MASK : mcrTemp & ~CAN_MCR_IRMQ_MASK;
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_DOZE_MODE_SUPPORT) && FSL_FEATURE_FLEXCAN_HAS_DOZE_MODE_SUPPORT)
+ /* Enable Doze Mode? */
+ mcrTemp = (config->enableDoze) ? mcrTemp | CAN_MCR_DOZE_MASK : mcrTemp & ~CAN_MCR_DOZE_MASK;
+#endif
+
+ mcrTemp |= CAN_MCR_HALT_MASK;
+ mcrTemp |= CAN_MCR_FRZ_MASK;
+
+ /* Save MCR Configuation. */
+ base->MCR = mcrTemp;
+
+ /* Baud Rate Configuration.*/
+ FLEXCAN_SetBaudRate(base, sourceClock_Hz, config->baudRate);
+}
+
+void FLEXCAN_Deinit(CAN_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ uint32_t instance;
+#endif
+ /* Reset all Register Contents. */
+ FLEXCAN_Reset(base);
+
+ /* Disable FlexCAN module. */
+ FLEXCAN_Enable(base, false);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ instance = FLEXCAN_GetInstance(base);
+#if defined(FLEXCAN_PERIPH_CLOCKS)
+ /* Disable FlexCAN serial clock. */
+ CLOCK_DisableClock(s_flexcanPeriphClock[instance]);
+#endif /* FLEXCAN_PERIPH_CLOCKS */
+ /* Disable FlexCAN clock. */
+ CLOCK_DisableClock(s_flexcanClock[instance]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+void FLEXCAN_GetDefaultConfig(flexcan_config_t *config)
+{
+ /* Assertion. */
+ assert(config);
+
+ /* Initialize FlexCAN Module config struct with default value. */
+#if (!defined(FSL_FEATURE_FLEXCAN_SUPPORT_ENGINE_CLK_SEL_REMOVE)) || !FSL_FEATURE_FLEXCAN_SUPPORT_ENGINE_CLK_SEL_REMOVE
+ config->clkSrc = kFLEXCAN_ClkSrcOsc;
+#endif /* FSL_FEATURE_FLEXCAN_SUPPORT_ENGINE_CLK_SEL_REMOVE */
+ config->baudRate = 125000U;
+ config->maxMbNum = 16;
+ config->enableLoopBack = false;
+ config->enableSelfWakeup = false;
+ config->enableIndividMask = false;
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_DOZE_MODE_SUPPORT) && FSL_FEATURE_FLEXCAN_HAS_DOZE_MODE_SUPPORT)
+ config->enableDoze = false;
+#endif
+}
+
+void FLEXCAN_SetTimingConfig(CAN_Type *base, const flexcan_timing_config_t *config)
+{
+ /* Assertion. */
+ assert(config);
+ int keep_frozen = 0;
+
+ if (base->MCR & CAN_MCR_FRZACK_MASK)
+ keep_frozen = 1;
+
+ /* Enter Freeze Mode. */
+ FLEXCAN_EnterFreezeMode(base);
+
+ /* Cleaning previous Timing Setting. */
+ base->CTRL1 &= ~(CAN_CTRL1_PRESDIV_MASK | CAN_CTRL1_RJW_MASK | CAN_CTRL1_PSEG1_MASK | CAN_CTRL1_PSEG2_MASK |
+ CAN_CTRL1_PROPSEG_MASK);
+
+ /* Updating Timing Setting according to configuration structure. */
+ base->CTRL1 |=
+ (CAN_CTRL1_PRESDIV(config->preDivider) | CAN_CTRL1_RJW(config->rJumpwidth) |
+ CAN_CTRL1_PSEG1(config->phaseSeg1) | CAN_CTRL1_PSEG2(config->phaseSeg2) | CAN_CTRL1_PROPSEG(config->propSeg));
+
+ /* Exit Freeze Mode. */
+ if (!keep_frozen)
+ FLEXCAN_ExitFreezeMode(base);
+}
+
+void FLEXCAN_SetBitRate(CAN_Type *base, uint32_t sourceClock_Hz, uint32_t baudRate_Bps)
+{
+ int keep_frozen = 0;
+
+ if (base->MCR & CAN_MCR_FRZACK_MASK)
+ keep_frozen = 1;
+
+ /* Enter Freeze Mode. */
+ FLEXCAN_EnterFreezeMode(base);
+
+ FLEXCAN_SetBaudRate(base, sourceClock_Hz, baudRate_Bps);
+
+ /* Exit Freeze Mode. */
+ if (!keep_frozen)
+ FLEXCAN_ExitFreezeMode(base);
+}
+
+void FLEXCAN_SetMode(CAN_Type *base, uint32_t mode)
+{
+ int keep_frozen = 0;
+
+ if (base->MCR & CAN_MCR_FRZACK_MASK)
+ keep_frozen = 1;
+ /* Enter Freeze Mode. */
+ FLEXCAN_EnterFreezeMode(base);
+ switch (mode){
+ case CAN_CTRLMODE_3_SAMPLES:
+ base->CTRL1 &= ~CAN_CTRL1_LPB_MASK;
+ base->CTRL1 &= ~CAN_CTRL1_LOM_MASK;
+ base->CTRL1 |= CAN_CTRL1_SMP_MASK;
+ break;
+ case CAN_CTRLMODE_LISTENONLY:
+ base->CTRL1 &= ~CAN_CTRL1_LPB_MASK;
+ base->CTRL1 &= ~CAN_CTRL1_SMP_MASK;
+ base->CTRL1 |= CAN_CTRL1_LOM_MASK;
+ break;
+ case CAN_CTRLMODE_LOOPBACK:
+ base->CTRL1 &= ~CAN_CTRL1_SMP_MASK;
+ base->CTRL1 &= ~CAN_CTRL1_LOM_MASK;
+ base->CTRL1 |= CAN_CTRL1_LPB_MASK;
+ break;
+ case CAN_CTRLMODE_NORMAL:
+ base->CTRL1 &= ~CAN_CTRL1_LPB_MASK;
+ base->CTRL1 &= ~CAN_CTRL1_LOM_MASK;
+ base->CTRL1 &= ~CAN_CTRL1_SMP_MASK;
+ }
+ /* Exit Freeze Mode. */
+ if (!keep_frozen)
+ FLEXCAN_ExitFreezeMode(base);
+}
+
+void FLEXCAN_SetRxMbGlobalMask(CAN_Type *base, uint32_t mask)
+{
+ /* Enter Freeze Mode. */
+ //FLEXCAN_EnterFreezeMode(base);
+
+ /* Setting Rx Message Buffer Global Mask value. */
+ base->RXMGMASK = mask;
+ base->RX14MASK = mask;
+ base->RX15MASK = mask;
+
+ /* Exit Freeze Mode. */
+ //FLEXCAN_ExitFreezeMode(base);
+}
+
+void FLEXCAN_SetRxFifoGlobalMask(CAN_Type *base, uint32_t mask)
+{
+ /* Enter Freeze Mode. */
+ //FLEXCAN_EnterFreezeMode(base);
+
+ /* Setting Rx FIFO Global Mask value. */
+ base->RXFGMASK = mask;
+
+ /* Exit Freeze Mode. */
+ //FLEXCAN_ExitFreezeMode(base);
+}
+
+void FLEXCAN_SetRxIndividualMask(CAN_Type *base, uint8_t maskIdx, uint32_t mask)
+{
+ assert(maskIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+
+ /* Enter Freeze Mode. */
+ FLEXCAN_EnterFreezeMode(base);
+
+ /* Setting Rx Individual Mask value. */
+ base->RXIMR[maskIdx] = mask;
+
+ /* Exit Freeze Mode. */
+ FLEXCAN_ExitFreezeMode(base);
+}
+
+void FLEXCAN_SetTxMbConfig(CAN_Type *base, uint8_t mbIdx, bool enable)
+{
+ /* Assertion. */
+ assert(mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+ assert(!FLEXCAN_IsMbOccupied(base, mbIdx));
+
+ /* Inactivate Message Buffer. */
+ if (enable)
+ {
+ base->MB[mbIdx].CS = CAN_CS_CODE(kFLEXCAN_TxMbInactive);
+ }
+ else
+ {
+ base->MB[mbIdx].CS = 0;
+ }
+
+ /* Clean Message Buffer content. */
+ base->MB[mbIdx].ID = 0x0;
+ base->MB[mbIdx].WORD0 = 0x0;
+ base->MB[mbIdx].WORD1 = 0x0;
+}
+
+void FLEXCAN_SetRxMbConfig(CAN_Type *base, uint8_t mbIdx, const flexcan_rx_mb_config_t *config, bool enable)
+{
+ /* Assertion. */
+ assert(mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+ assert(((config) || (false == enable)));
+ assert(!FLEXCAN_IsMbOccupied(base, mbIdx));
+
+ uint32_t cs_temp = 0;
+
+ /* Inactivate Message Buffer. */
+ base->MB[mbIdx].CS = 0;
+
+ /* Clean Message Buffer content. */
+ base->MB[mbIdx].ID = 0x0;
+ base->MB[mbIdx].WORD0 = 0x0;
+ base->MB[mbIdx].WORD1 = 0x0;
+
+ if (enable)
+ {
+ /* Setup Message Buffer ID. */
+ base->MB[mbIdx].ID = config->id;
+
+ /* Setup Message Buffer format. */
+ if (kFLEXCAN_FrameFormatExtend == config->format)
+ {
+ cs_temp |= CAN_CS_IDE_MASK;
+ }
+
+ /* Setup Message Buffer type. */
+ if (kFLEXCAN_FrameTypeRemote == config->type)
+ {
+ cs_temp |= CAN_CS_RTR_MASK;
+ }
+
+ /* Activate Rx Message Buffer. */
+ cs_temp |= CAN_CS_CODE(kFLEXCAN_RxMbEmpty);
+ base->MB[mbIdx].CS = cs_temp;
+ }
+}
+
+void FLEXCAN_SetRxFifoConfig(CAN_Type *base, const flexcan_rx_fifo_config_t *config, bool enable)
+{
+ /* Assertion. */
+ assert((config) || (false == enable));
+
+ volatile uint32_t *idFilterRegion = (volatile uint32_t *)(&base->MB[6].CS);
+ uint8_t setup_mb, i, rffn = 0;
+
+ /* Enter Freeze Mode. */
+ //FLEXCAN_EnterFreezeMode(base);
+
+ if (enable)
+ {
+ assert(config->idFilterNum <= 128);
+
+ /* Get the setup_mb value. */
+ setup_mb = (base->MCR & CAN_MCR_MAXMB_MASK) >> CAN_MCR_MAXMB_SHIFT;
+ setup_mb = (setup_mb < FSL_FEATURE_FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBERn(base)) ?
+ setup_mb :
+ FSL_FEATURE_FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBERn(base);
+
+ /* Determine RFFN value. */
+ for (i = 0; i <= 0xF; i++)
+ {
+ if ((8 * (i + 1)) >= config->idFilterNum)
+ {
+ rffn = i;
+ assert(((setup_mb - 8) - (2 * rffn)) > 0);
+
+ base->CTRL2 = (base->CTRL2 & ~CAN_CTRL2_RFFN_MASK) | CAN_CTRL2_RFFN(rffn);
+ break;
+ }
+ }
+ }
+ else
+ {
+ rffn = (base->CTRL2 & CAN_CTRL2_RFFN_MASK) >> CAN_CTRL2_RFFN_SHIFT;
+ }
+
+ /* Clean ID filter table occuyied Message Buffer Region. */
+ rffn = (rffn + 1) * 8;
+ for (i = 0; i < rffn; i++)
+ {
+ idFilterRegion[i] = 0x0;
+ }
+
+ if (enable)
+ {
+ /* Disable unused Rx FIFO Filter. */
+ for (i = config->idFilterNum; i < rffn; i++)
+ {
+ idFilterRegion[i] = 0xFFFFFFFFU;
+ }
+
+ /* Copy ID filter table to Message Buffer Region. */
+ for (i = 0; i < config->idFilterNum; i++)
+ {
+ idFilterRegion[i] = config->idFilterTable[i];
+ }
+
+ /* Setup ID Fitlter Type. */
+ switch (config->idFilterType)
+ {
+ case kFLEXCAN_RxFifoFilterTypeA:
+ base->MCR = (base->MCR & ~CAN_MCR_IDAM_MASK) | CAN_MCR_IDAM(0x0);
+ break;
+ case kFLEXCAN_RxFifoFilterTypeB:
+ base->MCR = (base->MCR & ~CAN_MCR_IDAM_MASK) | CAN_MCR_IDAM(0x1);
+ break;
+ case kFLEXCAN_RxFifoFilterTypeC:
+ base->MCR = (base->MCR & ~CAN_MCR_IDAM_MASK) | CAN_MCR_IDAM(0x2);
+ break;
+ case kFLEXCAN_RxFifoFilterTypeD:
+ /* All frames rejected. */
+ base->MCR = (base->MCR & ~CAN_MCR_IDAM_MASK) | CAN_MCR_IDAM(0x3);
+ break;
+ default:
+ break;
+ }
+
+ /* Setting Message Reception Priority. */
+ base->CTRL2 = (config->priority == kFLEXCAN_RxFifoPrioHigh) ? base->CTRL2 & ~CAN_CTRL2_MRP_MASK :
+ base->CTRL2 | CAN_CTRL2_MRP_MASK;
+
+ /* Enable Rx Message FIFO. */
+ base->MCR |= CAN_MCR_RFEN_MASK;
+ }
+ else
+ {
+ /* Disable Rx Message FIFO. */
+ base->MCR &= ~CAN_MCR_RFEN_MASK;
+
+ /* Clean MB0 ~ MB5. */
+ FLEXCAN_SetRxMbConfig(base, 0, NULL, false);
+ FLEXCAN_SetRxMbConfig(base, 1, NULL, false);
+ FLEXCAN_SetRxMbConfig(base, 2, NULL, false);
+ FLEXCAN_SetRxMbConfig(base, 3, NULL, false);
+ FLEXCAN_SetRxMbConfig(base, 4, NULL, false);
+ FLEXCAN_SetRxMbConfig(base, 5, NULL, false);
+ }
+ base->MCR |= CAN_MCR_SRXDIS_MASK;
+ /* Exit Freeze Mode. */
+ //FLEXCAN_ExitFreezeMode(base);
+}
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_RX_FIFO_DMA) && FSL_FEATURE_FLEXCAN_HAS_RX_FIFO_DMA)
+void FLEXCAN_EnableRxFifoDMA(CAN_Type *base, bool enable)
+{
+ if (enable)
+ {
+ /* Enter Freeze Mode. */
+ FLEXCAN_EnterFreezeMode(base);
+
+ /* Enable FlexCAN DMA. */
+ base->MCR |= CAN_MCR_DMA_MASK;
+
+ /* Exit Freeze Mode. */
+ FLEXCAN_ExitFreezeMode(base);
+ }
+ else
+ {
+ /* Enter Freeze Mode. */
+ FLEXCAN_EnterFreezeMode(base);
+
+ /* Disable FlexCAN DMA. */
+ base->MCR &= ~CAN_MCR_DMA_MASK;
+
+ /* Exit Freeze Mode. */
+ FLEXCAN_ExitFreezeMode(base);
+ }
+}
+#endif /* FSL_FEATURE_FLEXCAN_HAS_RX_FIFO_DMA */
+
+status_t FLEXCAN_WriteTxMb(CAN_Type *base, uint8_t mbIdx, const flexcan_frame_t *txFrame)
+{
+ /* Assertion. */
+ assert(mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+ assert(txFrame);
+ assert(txFrame->length <= 8);
+ assert(!FLEXCAN_IsMbOccupied(base, mbIdx));
+
+ uint32_t cs_temp = 0;
+
+ /* Check if Message Buffer is available. */
+ if (CAN_CS_CODE(kFLEXCAN_TxMbDataOrRemote) != (base->MB[mbIdx].CS & CAN_CS_CODE_MASK))
+ {
+ /* Inactive Tx Message Buffer. */
+ base->MB[mbIdx].CS = (base->MB[mbIdx].CS & ~CAN_CS_CODE_MASK) | CAN_CS_CODE(kFLEXCAN_TxMbInactive);
+
+ /* Fill Message ID field. */
+ base->MB[mbIdx].ID = txFrame->id;
+
+ /* Fill Message Format field. */
+ if (kFLEXCAN_FrameFormatExtend == txFrame->format)
+ {
+ cs_temp |= CAN_CS_SRR_MASK | CAN_CS_IDE_MASK;
+ }
+
+ /* Fill Message Type field. */
+ if (kFLEXCAN_FrameTypeRemote == txFrame->type)
+ {
+ cs_temp |= CAN_CS_RTR_MASK;
+ }
+
+ cs_temp |= CAN_CS_CODE(kFLEXCAN_TxMbDataOrRemote) | CAN_CS_DLC(txFrame->length);
+
+ /* Load Message Payload. */
+ base->MB[mbIdx].WORD0 = txFrame->dataWord0;
+ base->MB[mbIdx].WORD1 = txFrame->dataWord1;
+
+ /* Activate Tx Message Buffer. */
+ base->MB[mbIdx].CS = cs_temp;
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641)
+ base->MB[8].CS = CAN_CS_CODE(kFLEXCAN_TxMbInactive);
+ base->MB[8].CS = CAN_CS_CODE(kFLEXCAN_TxMbInactive);
+#endif
+
+ return kStatus_Success;
+ }
+ else
+ {
+ /* Tx Message Buffer is activated, return immediately. */
+ return kStatus_Fail;
+ }
+}
+
+status_t FLEXCAN_ReadRxMb(CAN_Type *base, uint8_t mbIdx, flexcan_frame_t *rxFrame)
+{
+ /* Assertion. */
+ assert(mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+ assert(rxFrame);
+ assert(!FLEXCAN_IsMbOccupied(base, mbIdx));
+
+ uint32_t cs_temp;
+ uint8_t rx_code;
+
+ /* Read CS field of Rx Message Buffer to lock Message Buffer. */
+ cs_temp = base->MB[mbIdx].CS;
+ /* Get Rx Message Buffer Code field. */
+ rx_code = (cs_temp & CAN_CS_CODE_MASK) >> CAN_CS_CODE_SHIFT;
+
+ /* Check to see if Rx Message Buffer is full. */
+ if ((kFLEXCAN_RxMbFull == rx_code) || (kFLEXCAN_RxMbOverrun == rx_code))
+ {
+ /* Store Message ID. */
+ rxFrame->id = base->MB[mbIdx].ID & (CAN_ID_EXT_MASK | CAN_ID_STD_MASK);
+
+ /* Get the message ID and format. */
+ rxFrame->format = (cs_temp & CAN_CS_IDE_MASK) ? kFLEXCAN_FrameFormatExtend : kFLEXCAN_FrameFormatStandard;
+
+ /* Get the message type. */
+ rxFrame->type = (cs_temp & CAN_CS_RTR_MASK) ? kFLEXCAN_FrameTypeRemote : kFLEXCAN_FrameTypeData;
+
+ /* Get the message length. */
+ rxFrame->length = (cs_temp & CAN_CS_DLC_MASK) >> CAN_CS_DLC_SHIFT;
+
+ /* Store Message Payload. */
+ rxFrame->dataWord0 = base->MB[mbIdx].WORD0;
+ rxFrame->dataWord1 = base->MB[mbIdx].WORD1;
+
+ /* Read free-running timer to unlock Rx Message Buffer. */
+ (void)base->TIMER;
+
+ if (kFLEXCAN_RxMbFull == rx_code)
+ {
+ return kStatus_Success;
+ }
+ else
+ {
+ return kStatus_FLEXCAN_RxOverflow;
+ }
+ }
+ else
+ {
+ /* Read free-running timer to unlock Rx Message Buffer. */
+ (void)base->TIMER;
+
+ return kStatus_Fail;
+ }
+}
+
+status_t FLEXCAN_ReadRxFifo(CAN_Type *base, flexcan_frame_t *rxFrame)
+{
+ /* Assertion. */
+ assert(rxFrame);
+
+ uint32_t cs_temp;
+
+ /* Check if Rx FIFO is Enabled. */
+ if (base->MCR & CAN_MCR_RFEN_MASK)
+ {
+ /* Read CS field of Rx Message Buffer to lock Message Buffer. */
+ cs_temp = base->MB[0].CS;
+
+ /* Read data from Rx FIFO output port. */
+ /* Store Message ID. */
+ rxFrame->id = base->MB[0].ID & (CAN_ID_EXT_MASK | CAN_ID_STD_MASK);
+
+ /* Get the message ID and format. */
+ rxFrame->format = (cs_temp & CAN_CS_IDE_MASK) ? kFLEXCAN_FrameFormatExtend : kFLEXCAN_FrameFormatStandard;
+
+ /* Get the message type. */
+ rxFrame->type = (cs_temp & CAN_CS_RTR_MASK) ? kFLEXCAN_FrameTypeRemote : kFLEXCAN_FrameTypeData;
+
+ /* Get the message length. */
+ rxFrame->length = (cs_temp & CAN_CS_DLC_MASK) >> CAN_CS_DLC_SHIFT;
+
+ /* Store Message Payload. */
+ rxFrame->dataWord0 = base->MB[0].WORD0;
+ rxFrame->dataWord1 = base->MB[0].WORD1;
+
+ /* Store ID Filter Hit Index. */
+ rxFrame->idhit = (uint8_t)(base->RXFIR & CAN_RXFIR_IDHIT_MASK);
+
+ /* Read free-running timer to unlock Rx Message Buffer. */
+ (void)base->TIMER;
+
+ return kStatus_Success;
+ }
+ else
+ {
+ return kStatus_Fail;
+ }
+}
+
+status_t FLEXCAN_TransferSendBlocking(CAN_Type *base, uint8_t mbIdx, flexcan_frame_t *txFrame)
+{
+ /* Write Tx Message Buffer to initiate a data sending. */
+ if (kStatus_Success == FLEXCAN_WriteTxMb(base, mbIdx, txFrame))
+ {
+ /* Wait until CAN Message send out. */
+ while (!FLEXCAN_GetMbStatusFlags(base, 1 << mbIdx))
+ {
+ }
+
+ /* Clean Tx Message Buffer Flag. */
+ FLEXCAN_ClearMbStatusFlags(base, 1 << mbIdx);
+
+ return kStatus_Success;
+ }
+ else
+ {
+ return kStatus_Fail;
+ }
+}
+
+status_t FLEXCAN_TransferReceiveBlocking(CAN_Type *base, uint8_t mbIdx, flexcan_frame_t *rxFrame)
+{
+ /* Wait until Rx Message Buffer non-empty. */
+ while (!FLEXCAN_GetMbStatusFlags(base, 1 << mbIdx))
+ {
+ }
+
+ /* Clean Rx Message Buffer Flag. */
+ FLEXCAN_ClearMbStatusFlags(base, 1 << mbIdx);
+
+ /* Read Received CAN Message. */
+ return FLEXCAN_ReadRxMb(base, mbIdx, rxFrame);
+}
+
+status_t FLEXCAN_TransferReceiveFifoBlocking(CAN_Type *base, flexcan_frame_t *rxFrame)
+{
+ status_t rxFifoStatus;
+
+ /* Wait until Rx FIFO non-empty. */
+ while (!FLEXCAN_GetMbStatusFlags(base, kFLEXCAN_RxFifoFrameAvlFlag))
+ {
+ }
+
+ /* */
+ rxFifoStatus = FLEXCAN_ReadRxFifo(base, rxFrame);
+
+ /* Clean Rx Fifo available flag. */
+ FLEXCAN_ClearMbStatusFlags(base, kFLEXCAN_RxFifoFrameAvlFlag);
+
+ return rxFifoStatus;
+}
+
+void FLEXCAN_TransferCreateHandle(CAN_Type *base,
+ flexcan_handle_t *handle,
+ flexcan_transfer_callback_t callback,
+ void *userData)
+{
+ assert(handle);
+
+ uint8_t instance;
+
+ /* Clean FlexCAN transfer handle. */
+ memset(handle, 0, sizeof(*handle));
+
+ /* Get instance from peripheral base address. */
+ instance = FLEXCAN_GetInstance(base);
+
+ /* Save the context in global variables to support the double weak mechanism. */
+ s_flexcanHandle[instance] = handle;
+
+ /* Register Callback function. */
+ handle->callback = callback;
+ handle->userData = userData;
+
+ s_flexcanIsr = FLEXCAN_TransferHandleIRQ;
+
+ /* We Enable Error & Status interrupt here, because this interrupt just
+ * report current status of FlexCAN module through Callback function.
+ * It is insignificance without a available callback function.
+ */
+ if (handle->callback != NULL)
+ {
+ FLEXCAN_EnableInterrupts(base, kFLEXCAN_BusOffInterruptEnable | kFLEXCAN_ErrorInterruptEnable |
+ kFLEXCAN_RxWarningInterruptEnable | kFLEXCAN_TxWarningInterruptEnable |
+ kFLEXCAN_WakeUpInterruptEnable);
+ }
+ else
+ {
+ FLEXCAN_DisableInterrupts(base, kFLEXCAN_BusOffInterruptEnable | kFLEXCAN_ErrorInterruptEnable |
+ kFLEXCAN_RxWarningInterruptEnable | kFLEXCAN_TxWarningInterruptEnable |
+ kFLEXCAN_WakeUpInterruptEnable);
+ }
+
+ /* Enable interrupts in NVIC. */
+ EnableIRQ((IRQn_Type)(s_flexcanRxWarningIRQ[instance]));
+ EnableIRQ((IRQn_Type)(s_flexcanTxWarningIRQ[instance]));
+ EnableIRQ((IRQn_Type)(s_flexcanWakeUpIRQ[instance]));
+ EnableIRQ((IRQn_Type)(s_flexcanErrorIRQ[instance]));
+ EnableIRQ((IRQn_Type)(s_flexcanBusOffIRQ[instance]));
+ EnableIRQ((IRQn_Type)(s_flexcanMbIRQ[instance]));
+}
+
+status_t FLEXCAN_TransferSendNonBlocking(CAN_Type *base, flexcan_handle_t *handle, flexcan_mb_transfer_t *xfer)
+{
+ /* Assertion. */
+ assert(handle);
+ assert(xfer);
+ assert(xfer->mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+ assert(!FLEXCAN_IsMbOccupied(base, xfer->mbIdx));
+
+ /* Check if Message Buffer is idle. */
+ if (kFLEXCAN_StateIdle == handle->mbState[xfer->mbIdx])
+ {
+ /* Distinguish transmit type. */
+ if (kFLEXCAN_FrameTypeRemote == xfer->frame->type)
+ {
+ handle->mbState[xfer->mbIdx] = kFLEXCAN_StateTxRemote;
+
+ /* Register user Frame buffer to receive remote Frame. */
+ handle->mbFrameBuf[xfer->mbIdx] = xfer->frame;
+ }
+ else
+ {
+ handle->mbState[xfer->mbIdx] = kFLEXCAN_StateTxData;
+ }
+
+ if (kStatus_Success == FLEXCAN_WriteTxMb(base, xfer->mbIdx, xfer->frame))
+ {
+ /* Enable Message Buffer Interrupt. */
+ FLEXCAN_EnableMbInterrupts(base, 1 << xfer->mbIdx);
+
+ return kStatus_Success;
+ }
+ else
+ {
+ handle->mbState[xfer->mbIdx] = kFLEXCAN_StateIdle;
+ return kStatus_Fail;
+ }
+ }
+ else
+ {
+ return kStatus_FLEXCAN_TxBusy;
+ }
+}
+
+status_t FLEXCAN_TransferReceiveNonBlocking(CAN_Type *base, flexcan_handle_t *handle, flexcan_mb_transfer_t *xfer)
+{
+ /* Assertion. */
+ assert(handle);
+ assert(xfer);
+ assert(xfer->mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+ assert(!FLEXCAN_IsMbOccupied(base, xfer->mbIdx));
+
+ /* Check if Message Buffer is idle. */
+ if (kFLEXCAN_StateIdle == handle->mbState[xfer->mbIdx])
+ {
+ handle->mbState[xfer->mbIdx] = kFLEXCAN_StateRxData;
+
+ /* Register Message Buffer. */
+ handle->mbFrameBuf[xfer->mbIdx] = xfer->frame;
+
+ /* Enable Message Buffer Interrupt. */
+ FLEXCAN_EnableMbInterrupts(base, 1 << xfer->mbIdx);
+
+ return kStatus_Success;
+ }
+ else
+ {
+ return kStatus_FLEXCAN_RxBusy;
+ }
+}
+
+status_t FLEXCAN_TransferReceiveFifoNonBlocking(CAN_Type *base, flexcan_handle_t *handle, flexcan_fifo_transfer_t *xfer)
+{
+ /* Assertion. */
+ assert(handle);
+ assert(xfer);
+
+ /* Check if Message Buffer is idle. */
+ if (kFLEXCAN_StateIdle == handle->rxFifoState)
+ {
+ handle->rxFifoState = kFLEXCAN_StateRxFifo;
+
+ /* Register Message Buffer. */
+ handle->rxFifoFrameBuf = xfer->frame;
+
+ /* Enable Message Buffer Interrupt. */
+ FLEXCAN_EnableMbInterrupts(
+ base, kFLEXCAN_RxFifoOverflowFlag | kFLEXCAN_RxFifoWarningFlag | kFLEXCAN_RxFifoFrameAvlFlag);
+
+ return kStatus_Success;
+ }
+ else
+ {
+ return kStatus_FLEXCAN_RxFifoBusy;
+ }
+}
+
+void FLEXCAN_TransferAbortSend(CAN_Type *base, flexcan_handle_t *handle, uint8_t mbIdx)
+{
+ /* Assertion. */
+ assert(handle);
+ assert(mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+ assert(!FLEXCAN_IsMbOccupied(base, mbIdx));
+
+ /* Disable Message Buffer Interrupt. */
+ //FLEXCAN_DisableMbInterrupts(base, 1 << mbIdx);
+
+ /* Un-register handle. */
+ handle->mbFrameBuf[mbIdx] = 0x0;
+
+ /* Clean Message Buffer. */
+ FLEXCAN_SetTxMbConfig(base, mbIdx, true);
+
+ handle->mbState[mbIdx] = kFLEXCAN_StateIdle;
+}
+
+void FLEXCAN_TransferAbortReceive(CAN_Type *base, flexcan_handle_t *handle, uint8_t mbIdx)
+{
+ /* Assertion. */
+ assert(handle);
+ assert(mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+ assert(!FLEXCAN_IsMbOccupied(base, mbIdx));
+
+ /* Disable Message Buffer Interrupt. */
+ FLEXCAN_DisableMbInterrupts(base, 1 << mbIdx);
+
+ /* Un-register handle. */
+ handle->mbFrameBuf[mbIdx] = 0x0;
+ handle->mbState[mbIdx] = kFLEXCAN_StateIdle;
+}
+
+void FLEXCAN_TransferAbortReceiveFifo(CAN_Type *base, flexcan_handle_t *handle)
+{
+ /* Assertion. */
+ assert(handle);
+
+ /* Check if Rx FIFO is enabled. */
+ if (base->MCR & CAN_MCR_RFEN_MASK)
+ {
+ /* Disable Rx Message FIFO Interrupts. */
+ FLEXCAN_DisableMbInterrupts(
+ base, kFLEXCAN_RxFifoOverflowFlag | kFLEXCAN_RxFifoWarningFlag | kFLEXCAN_RxFifoFrameAvlFlag);
+
+ /* Un-register handle. */
+ handle->rxFifoFrameBuf = 0x0;
+ }
+
+ handle->rxFifoState = kFLEXCAN_StateIdle;
+}
+
+void FLEXCAN_TransferHandleIRQ(CAN_Type *base, flexcan_handle_t *handle)
+{
+ /* Assertion. */
+ assert(handle);
+
+ status_t status = kStatus_FLEXCAN_UnHandled;
+ uint32_t result;
+ BaseType_t reschedule = pdFALSE;
+
+ /* Store Current FlexCAN Module Error and Status. */
+ result = base->ESR1;
+
+ do
+ {
+ /* Solve FlexCAN Error and Status Interrupt. */
+ if (result & (kFLEXCAN_TxWarningIntFlag | kFLEXCAN_RxWarningIntFlag | kFLEXCAN_BusOffIntFlag |
+ kFLEXCAN_ErrorIntFlag | kFLEXCAN_WakeUpIntFlag))
+ {
+ status = kStatus_FLEXCAN_ErrorStatus;
+
+ /* Clear FlexCAN Error and Status Interrupt. */
+ FLEXCAN_ClearStatusFlags(base, kFLEXCAN_TxWarningIntFlag | kFLEXCAN_RxWarningIntFlag |
+ kFLEXCAN_BusOffIntFlag | kFLEXCAN_ErrorIntFlag | kFLEXCAN_WakeUpIntFlag);
+ }
+ /* Solve FlexCAN Rx FIFO & Message Buffer Interrupt. */
+ else
+ {
+ /* For this implementation, we solve the Message with lowest MB index first. */
+ for (result = 0; result < 10/* FSL_FEATURE_FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBERn(base) */; result++)
+ {
+ /* Get the lowest unhandled Message Buffer */
+ if ((FLEXCAN_GetMbStatusFlags(base, 1 << result)) && (FLEXCAN_IsMbIntEnabled(base, result)))
+ {
+ break;
+ }
+ }
+
+ /* Does not find Message to deal with. */
+ if (result == 10)
+ {
+ break;
+ }
+
+ /* Solve Rx FIFO interrupt. */
+ if ((kFLEXCAN_StateIdle != handle->rxFifoState) && ((1 << result) <= kFLEXCAN_RxFifoOverflowFlag))
+ {
+ switch (1 << result)
+ {
+ case kFLEXCAN_RxFifoOverflowFlag:
+ status = kStatus_FLEXCAN_RxFifoOverflow;
+ break;
+
+ case kFLEXCAN_RxFifoWarningFlag:
+ status = kStatus_FLEXCAN_RxFifoWarning;
+ break;
+
+ case kFLEXCAN_RxFifoFrameAvlFlag:
+ status = FLEXCAN_ReadRxFifo(base, handle->rxFifoFrameBuf);
+ if (kStatus_Success == status)
+ {
+ status = kStatus_FLEXCAN_RxFifoIdle;
+ }
+ FLEXCAN_TransferAbortReceiveFifo(base, handle);
+ break;
+
+ default:
+ status = kStatus_FLEXCAN_UnHandled;
+ break;
+ }
+ }
+ else
+ {
+ /* Get current State of Message Buffer. */
+ switch (handle->mbState[result])
+ {
+#if 0
+ /* Solve Rx Data Frame. */
+ case kFLEXCAN_StateRxData:
+ status = FLEXCAN_ReadRxMb(base, result, handle->mbFrameBuf[result]);
+ if (kStatus_Success == status)
+ {
+ status = kStatus_FLEXCAN_RxIdle;
+ }
+ FLEXCAN_TransferAbortReceive(base, handle, result);
+ break;
+
+ /* Solve Rx Remote Frame. */
+ case kFLEXCAN_StateRxRemote:
+ status = FLEXCAN_ReadRxMb(base, result, handle->mbFrameBuf[result]);
+ if (kStatus_Success == status)
+ {
+ status = kStatus_FLEXCAN_RxIdle;
+ }
+ FLEXCAN_TransferAbortReceive(base, handle, result);
+ break;
+#endif
+ /* Solve Tx Remote Frame. */
+ case kFLEXCAN_StateTxRemote: /* fall through */
+ /* Solve Tx Data Frame. */
+ case kFLEXCAN_StateTxData:
+ status = kStatus_FLEXCAN_TxIdle;
+ FLEXCAN_TransferAbortSend(base, handle, result);
+ break;
+
+ default:
+ status = kStatus_FLEXCAN_UnHandled;
+ break;
+ }
+ }
+
+ /* Clear resolved Message Buffer IRQ. */
+ FLEXCAN_ClearMbStatusFlags(base, 1 << result);
+ }
+
+ /* Calling Callback Function if has one. */
+ if (handle->callback != NULL)
+ {
+ if (handle->callback(base, handle, status, result, handle->userData) == pdTRUE)
+ reschedule = pdTRUE;
+ }
+
+ /* Reset return status */
+ status = kStatus_FLEXCAN_UnHandled;
+
+ /* Store Current FlexCAN Module Error and Status. */
+ result = base->ESR1;
+ }
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ while ((0 != FLEXCAN_GetMbStatusFlags(base, 0xFFFFFFFFFFFFFFFFU)) ||
+ (0 != (result & (kFLEXCAN_TxWarningIntFlag | kFLEXCAN_RxWarningIntFlag | kFLEXCAN_BusOffIntFlag |
+ kFLEXCAN_ErrorIntFlag | kFLEXCAN_WakeUpIntFlag))));
+#else
+ while ((0 != FLEXCAN_GetMbStatusFlags(base, 0xFFFFFFFFU)) ||
+ (0 != (result & (kFLEXCAN_TxWarningIntFlag | kFLEXCAN_RxWarningIntFlag | kFLEXCAN_BusOffIntFlag |
+ kFLEXCAN_ErrorIntFlag | kFLEXCAN_WakeUpIntFlag))));
+#endif
+ portYIELD_FROM_ISR(reschedule);
+}
+
+#if defined(CAN0)
+void CAN0_DriverIRQHandler(void)
+{
+ assert(s_flexcanHandle[0]);
+
+ s_flexcanIsr(CAN0, s_flexcanHandle[0]);
+}
+#endif
+
+#if defined(CAN1)
+void CAN1_DriverIRQHandler(void)
+{
+ assert(s_flexcanHandle[1]);
+
+ s_flexcanIsr(CAN1, s_flexcanHandle[1]);
+}
+#endif
+
+#if defined(CAN2)
+void CAN2_DriverIRQHandler(void)
+{
+ assert(s_flexcanHandle[2]);
+
+ s_flexcanIsr(CAN2, s_flexcanHandle[2]);
+}
+#endif
+
+#if defined(CAN3)
+void CAN3_DriverIRQHandler(void)
+{
+ assert(s_flexcanHandle[3]);
+
+ s_flexcanIsr(CAN3, s_flexcanHandle[3]);
+}
+#endif
+
+#if defined(CAN4)
+void CAN4_DriverIRQHandler(void)
+{
+ assert(s_flexcanHandle[4]);
+
+ s_flexcanIsr(CAN4, s_flexcanHandle[4]);
+}
+#endif
+
+#if defined(DMA_CAN0)
+void DMA_FLEXCAN0_DriverIRQHandler(void)
+{
+ assert(s_flexcanHandle[FLEXCAN_GetInstance(DMA_CAN0)]);
+
+ s_flexcanIsr(DMA_CAN0, s_flexcanHandle[FLEXCAN_GetInstance(DMA_CAN0)]);
+}
+#endif
+
+#if defined(DMA_CAN1)
+void DMA_FLEXCAN1_DriverIRQHandler(void)
+{
+ assert(s_flexcanHandle[FLEXCAN_GetInstance(DMA_CAN1)]);
+
+ s_flexcanIsr(DMA_CAN0, s_flexcanHandle[FLEXCAN_GetInstance(DMA_CAN1)]);
+}
+#endif
+
+#if defined(DMA_CAN2)
+void DMA_FLEXCAN2_DriverIRQHandler(void)
+{
+ assert(s_flexcanHandle[FLEXCAN_GetInstance(DMA_CAN2)]);
+
+ s_flexcanIsr(DMA_CAN2, s_flexcanHandle[FLEXCAN_GetInstance(DMA_CAN2)]);
+}
+#endif
diff --git a/drivers/src/fsl_ftm.c b/drivers/src/fsl_ftm.c
new file mode 100644
index 0000000..9cca44b
--- /dev/null
+++ b/drivers/src/fsl_ftm.c
@@ -0,0 +1,908 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsl_ftm.h"
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Gets the instance from the base address
+ *
+ * @param base FTM peripheral base address
+ *
+ * @return The FTM instance
+ */
+static uint32_t FTM_GetInstance(FTM_Type *base);
+
+/*!
+ * @brief Sets the FTM register PWM synchronization method
+ *
+ * This function will set the necessary bits for the PWM synchronization mode that
+ * user wishes to use.
+ *
+ * @param base FTM peripheral base address
+ * @param syncMethod Syncronization methods to use to update buffered registers. This is a logical
+ * OR of members of the enumeration ::ftm_pwm_sync_method_t
+ */
+static void FTM_SetPwmSync(FTM_Type *base, uint32_t syncMethod);
+
+/*!
+ * @brief Sets the reload points used as loading points for register update
+ *
+ * This function will set the necessary bits based on what the user wishes to use as loading
+ * points for FTM register update. When using this it is not required to use PWM synchnronization.
+ *
+ * @param base FTM peripheral base address
+ * @param reloadPoints FTM reload points. This is a logical OR of members of the
+ * enumeration ::ftm_reload_point_t
+ */
+static void FTM_SetReloadPoints(FTM_Type *base, uint32_t reloadPoints);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to FTM bases for each instance. */
+static FTM_Type *const s_ftmBases[] = FTM_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to FTM clocks for each instance. */
+static const clock_ip_name_t s_ftmClocks[] = FTM_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t FTM_GetInstance(FTM_Type *base)
+{
+ uint32_t instance;
+ uint32_t ftmArrayCount = (sizeof(s_ftmBases) / sizeof(s_ftmBases[0]));
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ftmArrayCount; instance++)
+ {
+ if (s_ftmBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ftmArrayCount);
+
+ return instance;
+}
+
+static void FTM_SetPwmSync(FTM_Type *base, uint32_t syncMethod)
+{
+ uint8_t chnlNumber = 0;
+ uint32_t reg = 0, syncReg = 0;
+
+ syncReg = base->SYNC;
+ /* Enable PWM synchronization of output mask register */
+ syncReg |= FTM_SYNC_SYNCHOM_MASK;
+
+ reg = base->COMBINE;
+ for (chnlNumber = 0; chnlNumber < (FSL_FEATURE_FTM_CHANNEL_COUNTn(base) / 2); chnlNumber++)
+ {
+ /* Enable PWM synchronization of registers C(n)V and C(n+1)V */
+ reg |= (1U << (FTM_COMBINE_SYNCEN0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * chnlNumber)));
+ }
+ base->COMBINE = reg;
+
+ reg = base->SYNCONF;
+
+ /* Use enhanced PWM synchronization method. Use PWM sync to update register values */
+ reg |= (FTM_SYNCONF_SYNCMODE_MASK | FTM_SYNCONF_CNTINC_MASK | FTM_SYNCONF_INVC_MASK | FTM_SYNCONF_SWOC_MASK);
+
+ if (syncMethod & FTM_SYNC_SWSYNC_MASK)
+ {
+ /* Enable needed bits for software trigger to update registers with its buffer value */
+ reg |= (FTM_SYNCONF_SWRSTCNT_MASK | FTM_SYNCONF_SWWRBUF_MASK | FTM_SYNCONF_SWINVC_MASK |
+ FTM_SYNCONF_SWSOC_MASK | FTM_SYNCONF_SWOM_MASK);
+ }
+
+ if (syncMethod & (FTM_SYNC_TRIG0_MASK | FTM_SYNC_TRIG1_MASK | FTM_SYNC_TRIG2_MASK))
+ {
+ /* Enable needed bits for hardware trigger to update registers with its buffer value */
+ reg |= (FTM_SYNCONF_HWRSTCNT_MASK | FTM_SYNCONF_HWWRBUF_MASK | FTM_SYNCONF_HWINVC_MASK |
+ FTM_SYNCONF_HWSOC_MASK | FTM_SYNCONF_HWOM_MASK);
+
+ /* Enable the appropriate hardware trigger that is used for PWM sync */
+ if (syncMethod & FTM_SYNC_TRIG0_MASK)
+ {
+ syncReg |= FTM_SYNC_TRIG0_MASK;
+ }
+ if (syncMethod & FTM_SYNC_TRIG1_MASK)
+ {
+ syncReg |= FTM_SYNC_TRIG1_MASK;
+ }
+ if (syncMethod & FTM_SYNC_TRIG2_MASK)
+ {
+ syncReg |= FTM_SYNC_TRIG2_MASK;
+ }
+ }
+
+ /* Write back values to the SYNC register */
+ base->SYNC = syncReg;
+
+ /* Write the PWM synch values to the SYNCONF register */
+ base->SYNCONF = reg;
+}
+
+static void FTM_SetReloadPoints(FTM_Type *base, uint32_t reloadPoints)
+{
+ uint32_t chnlNumber = 0;
+ uint32_t reg = 0;
+
+ /* Need CNTINC bit to be 1 for CNTIN register to update with its buffer value on reload */
+ base->SYNCONF |= FTM_SYNCONF_CNTINC_MASK;
+
+ reg = base->COMBINE;
+ for (chnlNumber = 0; chnlNumber < (FSL_FEATURE_FTM_CHANNEL_COUNTn(base) / 2); chnlNumber++)
+ {
+ /* Need SYNCEN bit to be 1 for CnV reg to update with its buffer value on reload */
+ reg |= (1U << (FTM_COMBINE_SYNCEN0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * chnlNumber)));
+ }
+ base->COMBINE = reg;
+
+ /* Set the reload points */
+ reg = base->PWMLOAD;
+
+ /* Enable the selected channel match reload points */
+ reg &= ~((1U << FSL_FEATURE_FTM_CHANNEL_COUNTn(base)) - 1);
+ reg |= (reloadPoints & ((1U << FSL_FEATURE_FTM_CHANNEL_COUNTn(base)) - 1));
+
+#if defined(FSL_FEATURE_FTM_HAS_HALFCYCLE_RELOAD) && (FSL_FEATURE_FTM_HAS_HALFCYCLE_RELOAD)
+ /* Enable half cycle match as a reload point */
+ if (reloadPoints & kFTM_HalfCycMatch)
+ {
+ reg |= FTM_PWMLOAD_HCSEL_MASK;
+ }
+ else
+ {
+ reg &= ~FTM_PWMLOAD_HCSEL_MASK;
+ }
+#endif /* FSL_FEATURE_FTM_HAS_HALFCYCLE_RELOAD */
+
+ base->PWMLOAD = reg;
+
+ /* These reload points are used when counter is in up-down counting mode */
+ reg = base->SYNC;
+ if (reloadPoints & kFTM_CntMax)
+ {
+ /* Reload when counter turns from up to down */
+ reg |= FTM_SYNC_CNTMAX_MASK;
+ }
+ else
+ {
+ reg &= ~FTM_SYNC_CNTMAX_MASK;
+ }
+
+ if (reloadPoints & kFTM_CntMin)
+ {
+ /* Reload when counter turns from down to up */
+ reg |= FTM_SYNC_CNTMIN_MASK;
+ }
+ else
+ {
+ reg &= ~FTM_SYNC_CNTMIN_MASK;
+ }
+ base->SYNC = reg;
+}
+
+status_t FTM_Init(FTM_Type *base, const ftm_config_t *config)
+{
+ assert(config);
+
+ uint32_t reg;
+
+ if (!(config->pwmSyncMode &
+ (FTM_SYNC_TRIG0_MASK | FTM_SYNC_TRIG1_MASK | FTM_SYNC_TRIG2_MASK | FTM_SYNC_SWSYNC_MASK)))
+ {
+ /* Invalid PWM sync mode */
+ return kStatus_Fail;
+ }
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Ungate the FTM clock*/
+ CLOCK_EnableClock(s_ftmClocks[FTM_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Configure the fault mode, enable FTM mode and disable write protection */
+ base->MODE = FTM_MODE_FAULTM(config->faultMode) | FTM_MODE_FTMEN_MASK | FTM_MODE_WPDIS_MASK;
+
+ /* Configure the update mechanism for buffered registers */
+ FTM_SetPwmSync(base, config->pwmSyncMode);
+
+ /* Setup intermediate register reload points */
+ FTM_SetReloadPoints(base, config->reloadPoints);
+
+ /* Set the clock prescale factor */
+ base->SC = FTM_SC_PS(config->prescale);
+
+ /* Setup the counter operation */
+ base->CONF = (FTM_CONF_BDMMODE(config->bdmMode) | FTM_CONF_GTBEEN(config->useGlobalTimeBase));
+
+ /* Initial state of channel output */
+ base->OUTINIT = config->chnlInitState;
+
+ /* Channel polarity */
+ base->POL = config->chnlPolarity;
+
+ /* Set the external trigger sources */
+ base->EXTTRIG = config->extTriggers;
+#if defined(FSL_FEATURE_FTM_HAS_RELOAD_INITIALIZATION_TRIGGER) && (FSL_FEATURE_FTM_HAS_RELOAD_INITIALIZATION_TRIGGER)
+ if (config->extTriggers & kFTM_ReloadInitTrigger)
+ {
+ base->CONF |= FTM_CONF_ITRIGR_MASK;
+ }
+ else
+ {
+ base->CONF &= ~FTM_CONF_ITRIGR_MASK;
+ }
+#endif /* FSL_FEATURE_FTM_HAS_RELOAD_INITIALIZATION_TRIGGER */
+
+ /* FTM deadtime insertion control */
+ base->DEADTIME = (0u |
+#if defined(FSL_FEATURE_FTM_HAS_EXTENDED_DEADTIME_VALUE) && (FSL_FEATURE_FTM_HAS_EXTENDED_DEADTIME_VALUE)
+ /* Has extended deadtime value register) */
+ FTM_DEADTIME_DTVALEX(config->deadTimeValue >> 6) |
+#endif /* FSL_FEATURE_FTM_HAS_EXTENDED_DEADTIME_VALUE */
+ FTM_DEADTIME_DTPS(config->deadTimePrescale) |
+ FTM_DEADTIME_DTVAL(config->deadTimeValue));
+
+ /* FTM fault filter value */
+ reg = base->FLTCTRL;
+ reg &= ~FTM_FLTCTRL_FFVAL_MASK;
+ reg |= FTM_FLTCTRL_FFVAL(config->faultFilterValue);
+ base->FLTCTRL = reg;
+
+ return kStatus_Success;
+}
+
+void FTM_Deinit(FTM_Type *base)
+{
+ /* Set clock source to none to disable counter */
+ base->SC &= ~(FTM_SC_CLKS_MASK);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Gate the FTM clock */
+ CLOCK_DisableClock(s_ftmClocks[FTM_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+void FTM_GetDefaultConfig(ftm_config_t *config)
+{
+ assert(config);
+
+ /* Divide FTM clock by 1 */
+ config->prescale = kFTM_Prescale_Divide_1;
+ /* FTM behavior in BDM mode */
+ config->bdmMode = kFTM_BdmMode_0;
+ /* Software trigger will be used to update registers */
+ config->pwmSyncMode = kFTM_SoftwareTrigger;
+ /* No intermediate register load */
+ config->reloadPoints = 0;
+ /* Fault control disabled for all channels */
+ config->faultMode = kFTM_Fault_Disable;
+ /* Disable the fault filter */
+ config->faultFilterValue = 0;
+ /* Divide the system clock by 1 */
+ config->deadTimePrescale = kFTM_Deadtime_Prescale_1;
+ /* No counts are inserted */
+ config->deadTimeValue = 0;
+ /* No external trigger */
+ config->extTriggers = 0;
+ /* Initialization value is 0 for all channels */
+ config->chnlInitState = 0;
+ /* Active high polarity for all channels */
+ config->chnlPolarity = 0;
+ /* Use internal FTM counter as timebase */
+ config->useGlobalTimeBase = false;
+}
+
+status_t FTM_SetupPwm(FTM_Type *base,
+ const ftm_chnl_pwm_signal_param_t *chnlParams,
+ uint8_t numOfChnls,
+ ftm_pwm_mode_t mode,
+ uint32_t pwmFreq_Hz,
+ uint32_t srcClock_Hz)
+{
+ assert(chnlParams);
+ assert(srcClock_Hz);
+ assert(pwmFreq_Hz);
+ assert(numOfChnls);
+
+ uint32_t mod, reg;
+ uint32_t ftmClock = (srcClock_Hz / (1U << (base->SC & FTM_SC_PS_MASK)));
+ uint16_t cnv, cnvFirstEdge;
+ uint8_t i;
+
+ switch (mode)
+ {
+ case kFTM_EdgeAlignedPwm:
+ case kFTM_CombinedPwm:
+ base->SC &= ~FTM_SC_CPWMS_MASK;
+ mod = (ftmClock / pwmFreq_Hz) - 1;
+ break;
+ case kFTM_CenterAlignedPwm:
+ base->SC |= FTM_SC_CPWMS_MASK;
+ mod = ftmClock / (pwmFreq_Hz * 2);
+ break;
+ default:
+ return kStatus_Fail;
+ }
+
+ /* Return an error in case we overflow the registers, probably would require changing
+ * clock source to get the desired frequency */
+ if (mod > 65535U)
+ {
+ return kStatus_Fail;
+ }
+ /* Set the PWM period */
+ base->MOD = mod;
+
+ /* Setup each FTM channel */
+ for (i = 0; i < numOfChnls; i++)
+ {
+ /* Return error if requested dutycycle is greater than the max allowed */
+ if (chnlParams->dutyCyclePercent > 100)
+ {
+ return kStatus_Fail;
+ }
+
+ if ((mode == kFTM_EdgeAlignedPwm) || (mode == kFTM_CenterAlignedPwm))
+ {
+ /* Clear the current mode and edge level bits */
+ reg = base->CONTROLS[chnlParams->chnlNumber].CnSC;
+ reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
+
+ /* Setup the active level */
+ reg |= (uint32_t)(chnlParams->level << FTM_CnSC_ELSA_SHIFT);
+
+ /* Edge-aligned mode needs MSB to be 1, don't care for Center-aligned mode */
+ reg |= FTM_CnSC_MSB(1U);
+
+ /* Update the mode and edge level */
+ base->CONTROLS[chnlParams->chnlNumber].CnSC = reg;
+
+ if (chnlParams->dutyCyclePercent == 0)
+ {
+ /* Signal stays low */
+ cnv = 0;
+ }
+ else
+ {
+ cnv = (mod * chnlParams->dutyCyclePercent) / 100;
+ /* For 100% duty cycle */
+ if (cnv >= mod)
+ {
+ cnv = mod + 1;
+ }
+ }
+
+ base->CONTROLS[chnlParams->chnlNumber].CnV = cnv;
+#if defined(FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT) && (FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT)
+ /* Set to output mode */
+ FTM_SetPwmOutputEnable(base, chnlParams->chnlNumber, true);
+#endif
+ }
+ else
+ {
+ /* This check is added for combined mode as the channel number should be the pair number */
+ if (chnlParams->chnlNumber >= (FSL_FEATURE_FTM_CHANNEL_COUNTn(base) / 2))
+ {
+ return kStatus_Fail;
+ }
+
+ /* Return error if requested value is greater than the max allowed */
+ if (chnlParams->firstEdgeDelayPercent > 100)
+ {
+ return kStatus_Fail;
+ }
+
+ /* Configure delay of the first edge */
+ if (chnlParams->firstEdgeDelayPercent == 0)
+ {
+ /* No delay for the first edge */
+ cnvFirstEdge = 0;
+ }
+ else
+ {
+ cnvFirstEdge = (mod * chnlParams->firstEdgeDelayPercent) / 100;
+ }
+
+ /* Configure dutycycle */
+ if (chnlParams->dutyCyclePercent == 0)
+ {
+ /* Signal stays low */
+ cnv = 0;
+ cnvFirstEdge = 0;
+ }
+ else
+ {
+ cnv = (mod * chnlParams->dutyCyclePercent) / 100;
+ /* For 100% duty cycle */
+ if (cnv >= mod)
+ {
+ cnv = mod + 1;
+ }
+ }
+
+ /* Clear the current mode and edge level bits for channel n */
+ reg = base->CONTROLS[chnlParams->chnlNumber * 2].CnSC;
+ reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
+
+ /* Setup the active level for channel n */
+ reg |= (uint32_t)(chnlParams->level << FTM_CnSC_ELSA_SHIFT);
+
+ /* Update the mode and edge level for channel n */
+ base->CONTROLS[chnlParams->chnlNumber * 2].CnSC = reg;
+
+ /* Clear the current mode and edge level bits for channel n + 1 */
+ reg = base->CONTROLS[(chnlParams->chnlNumber * 2) + 1].CnSC;
+ reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
+
+ /* Setup the active level for channel n + 1 */
+ reg |= (uint32_t)(chnlParams->level << FTM_CnSC_ELSA_SHIFT);
+
+ /* Update the mode and edge level for channel n + 1*/
+ base->CONTROLS[(chnlParams->chnlNumber * 2) + 1].CnSC = reg;
+
+ /* Set the combine bit for the channel pair */
+ base->COMBINE |=
+ (1U << (FTM_COMBINE_COMBINE0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * chnlParams->chnlNumber)));
+
+ /* Set the channel pair values */
+ base->CONTROLS[chnlParams->chnlNumber * 2].CnV = cnvFirstEdge;
+ base->CONTROLS[(chnlParams->chnlNumber * 2) + 1].CnV = cnvFirstEdge + cnv;
+
+#if defined(FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT) && (FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT)
+ /* Set to output mode */
+ FTM_SetPwmOutputEnable(base, (ftm_chnl_t)((uint8_t)chnlParams->chnlNumber * 2), true);
+ FTM_SetPwmOutputEnable(base, (ftm_chnl_t)((uint8_t)chnlParams->chnlNumber * 2 + 1), true);
+#endif
+ }
+ chnlParams++;
+ }
+
+ return kStatus_Success;
+}
+
+void FTM_UpdatePwmDutycycle(FTM_Type *base,
+ ftm_chnl_t chnlNumber,
+ ftm_pwm_mode_t currentPwmMode,
+ uint8_t dutyCyclePercent)
+{
+ uint16_t cnv, cnvFirstEdge = 0, mod;
+
+ mod = base->MOD;
+ if ((currentPwmMode == kFTM_EdgeAlignedPwm) || (currentPwmMode == kFTM_CenterAlignedPwm))
+ {
+ cnv = (mod * dutyCyclePercent) / 100;
+ /* For 100% duty cycle */
+ if (cnv >= mod)
+ {
+ cnv = mod + 1;
+ }
+ base->CONTROLS[chnlNumber].CnV = cnv;
+ }
+ else
+ {
+ /* This check is added for combined mode as the channel number should be the pair number */
+ if (chnlNumber >= (FSL_FEATURE_FTM_CHANNEL_COUNTn(base) / 2))
+ {
+ return;
+ }
+
+ cnv = (mod * dutyCyclePercent) / 100;
+ cnvFirstEdge = base->CONTROLS[chnlNumber * 2].CnV;
+ /* For 100% duty cycle */
+ if (cnv >= mod)
+ {
+ cnv = mod + 1;
+ }
+ base->CONTROLS[(chnlNumber * 2) + 1].CnV = cnvFirstEdge + cnv;
+ }
+}
+
+void FTM_UpdateChnlEdgeLevelSelect(FTM_Type *base, ftm_chnl_t chnlNumber, uint8_t level)
+{
+ uint32_t reg = base->CONTROLS[chnlNumber].CnSC;
+
+ /* Clear the field and write the new level value */
+ reg &= ~(FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
+ reg |= ((uint32_t)level << FTM_CnSC_ELSA_SHIFT) & (FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
+
+ base->CONTROLS[chnlNumber].CnSC = reg;
+}
+
+void FTM_SetupInputCapture(FTM_Type *base,
+ ftm_chnl_t chnlNumber,
+ ftm_input_capture_edge_t captureMode,
+ uint32_t filterValue)
+{
+ uint32_t reg;
+
+ /* Clear the combine bit for the channel pair */
+ base->COMBINE &= ~(1U << (FTM_COMBINE_COMBINE0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * (chnlNumber >> 1))));
+ /* Clear the dual edge capture mode because it's it's higher priority */
+ base->COMBINE &= ~(1U << (FTM_COMBINE_DECAPEN0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * (chnlNumber >> 1))));
+ /* Clear the quadrature decoder mode beacause it's higher priority */
+ base->QDCTRL &= ~FTM_QDCTRL_QUADEN_MASK;
+
+ reg = base->CONTROLS[chnlNumber].CnSC;
+ reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
+ reg |= captureMode;
+
+ /* Set the requested input capture mode */
+ base->CONTROLS[chnlNumber].CnSC = reg;
+ /* Input filter available only for channels 0, 1, 2, 3 */
+ if (chnlNumber < kFTM_Chnl_4)
+ {
+ reg = base->FILTER;
+ reg &= ~(FTM_FILTER_CH0FVAL_MASK << (FTM_FILTER_CH1FVAL_SHIFT * chnlNumber));
+ reg |= (filterValue << (FTM_FILTER_CH1FVAL_SHIFT * chnlNumber));
+ base->FILTER = reg;
+ }
+#if defined(FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT) && (FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT)
+ /* Set to input mode */
+ FTM_SetPwmOutputEnable(base, chnlNumber, false);
+#endif
+}
+
+void FTM_SetupOutputCompare(FTM_Type *base,
+ ftm_chnl_t chnlNumber,
+ ftm_output_compare_mode_t compareMode,
+ uint32_t compareValue)
+{
+ uint32_t reg;
+
+ /* Clear the combine bit for the channel pair */
+ base->COMBINE &= ~(1U << (FTM_COMBINE_COMBINE0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * (chnlNumber >> 1))));
+ /* Clear the dual edge capture mode because it's it's higher priority */
+ base->COMBINE &= ~(1U << (FTM_COMBINE_DECAPEN0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * (chnlNumber >> 1))));
+ /* Clear the quadrature decoder mode beacause it's higher priority */
+ base->QDCTRL &= ~FTM_QDCTRL_QUADEN_MASK;
+
+ reg = base->CONTROLS[chnlNumber].CnSC;
+ reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
+ reg |= compareMode;
+ /* Setup the channel output behaviour when a match occurs with the compare value */
+ base->CONTROLS[chnlNumber].CnSC = reg;
+
+ /* Set output on match to the requested level */
+ base->CONTROLS[chnlNumber].CnV = compareValue;
+
+#if defined(FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT) && (FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT)
+ /* Set to output mode */
+ FTM_SetPwmOutputEnable(base, chnlNumber, true);
+#endif
+}
+
+void FTM_SetupDualEdgeCapture(FTM_Type *base,
+ ftm_chnl_t chnlPairNumber,
+ const ftm_dual_edge_capture_param_t *edgeParam,
+ uint32_t filterValue)
+{
+ assert(edgeParam);
+
+ uint32_t reg;
+
+ reg = base->COMBINE;
+ /* Clear the combine bit for the channel pair */
+ reg &= ~(1U << (FTM_COMBINE_COMBINE0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * chnlPairNumber)));
+ /* Enable the DECAPEN bit */
+ reg |= (1U << (FTM_COMBINE_DECAPEN0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * chnlPairNumber)));
+ reg |= (1U << (FTM_COMBINE_DECAP0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * chnlPairNumber)));
+ base->COMBINE = reg;
+
+ /* Setup the edge detection from channel n and n + 1 */
+ reg = base->CONTROLS[chnlPairNumber * 2].CnSC;
+ reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
+ reg |= ((uint32_t)edgeParam->mode | (uint32_t)edgeParam->currChanEdgeMode);
+ base->CONTROLS[chnlPairNumber * 2].CnSC = reg;
+
+ reg = base->CONTROLS[(chnlPairNumber * 2) + 1].CnSC;
+ reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
+ reg |= ((uint32_t)edgeParam->mode | (uint32_t)edgeParam->nextChanEdgeMode);
+ base->CONTROLS[(chnlPairNumber * 2) + 1].CnSC = reg;
+
+ /* Input filter available only for channels 0, 1, 2, 3 */
+ if (chnlPairNumber < kFTM_Chnl_4)
+ {
+ reg = base->FILTER;
+ reg &= ~(FTM_FILTER_CH0FVAL_MASK << (FTM_FILTER_CH1FVAL_SHIFT * chnlPairNumber));
+ reg |= (filterValue << (FTM_FILTER_CH1FVAL_SHIFT * chnlPairNumber));
+ base->FILTER = reg;
+ }
+
+#if defined(FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT) && (FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT)
+ /* Set to input mode */
+ FTM_SetPwmOutputEnable(base, chnlPairNumber, false);
+#endif
+}
+
+void FTM_SetupQuadDecode(FTM_Type *base,
+ const ftm_phase_params_t *phaseAParams,
+ const ftm_phase_params_t *phaseBParams,
+ ftm_quad_decode_mode_t quadMode)
+{
+ assert(phaseAParams);
+ assert(phaseBParams);
+
+ uint32_t reg;
+
+ /* Set Phase A filter value if phase filter is enabled */
+ if (phaseAParams->enablePhaseFilter)
+ {
+ reg = base->FILTER;
+ reg &= ~(FTM_FILTER_CH0FVAL_MASK);
+ reg |= FTM_FILTER_CH0FVAL(phaseAParams->phaseFilterVal);
+ base->FILTER = reg;
+ }
+
+ /* Set Phase B filter value if phase filter is enabled */
+ if (phaseBParams->enablePhaseFilter)
+ {
+ reg = base->FILTER;
+ reg &= ~(FTM_FILTER_CH1FVAL_MASK);
+ reg |= FTM_FILTER_CH1FVAL(phaseBParams->phaseFilterVal);
+ base->FILTER = reg;
+ }
+
+ /* Set Quadrature decode properties */
+ reg = base->QDCTRL;
+ reg &= ~(FTM_QDCTRL_QUADMODE_MASK | FTM_QDCTRL_PHAFLTREN_MASK | FTM_QDCTRL_PHBFLTREN_MASK | FTM_QDCTRL_PHAPOL_MASK |
+ FTM_QDCTRL_PHBPOL_MASK);
+ reg |= (FTM_QDCTRL_QUADMODE(quadMode) | FTM_QDCTRL_PHAFLTREN(phaseAParams->enablePhaseFilter) |
+ FTM_QDCTRL_PHBFLTREN(phaseBParams->enablePhaseFilter) | FTM_QDCTRL_PHAPOL(phaseAParams->phasePolarity) |
+ FTM_QDCTRL_PHBPOL(phaseBParams->phasePolarity));
+ base->QDCTRL = reg;
+ /* Enable Quad decode */
+ base->QDCTRL |= FTM_QDCTRL_QUADEN_MASK;
+}
+
+void FTM_SetupFault(FTM_Type *base, ftm_fault_input_t faultNumber, const ftm_fault_param_t *faultParams)
+{
+ assert(faultParams);
+
+ uint32_t reg;
+
+ reg = base->FLTCTRL;
+ if (faultParams->enableFaultInput)
+ {
+ /* Enable the fault input */
+ reg |= (FTM_FLTCTRL_FAULT0EN_MASK << faultNumber);
+ }
+ else
+ {
+ /* Disable the fault input */
+ reg &= ~(FTM_FLTCTRL_FAULT0EN_MASK << faultNumber);
+ }
+
+ if (faultParams->useFaultFilter)
+ {
+ /* Enable the fault filter */
+ reg |= (FTM_FLTCTRL_FFLTR0EN_MASK << (FTM_FLTCTRL_FFLTR0EN_SHIFT + faultNumber));
+ }
+ else
+ {
+ /* Disable the fault filter */
+ reg &= ~(FTM_FLTCTRL_FFLTR0EN_MASK << (FTM_FLTCTRL_FFLTR0EN_SHIFT + faultNumber));
+ }
+ base->FLTCTRL = reg;
+
+ if (faultParams->faultLevel)
+ {
+ /* Active low polarity for the fault input pin */
+ base->FLTPOL |= (1U << faultNumber);
+ }
+ else
+ {
+ /* Active high polarity for the fault input pin */
+ base->FLTPOL &= ~(1U << faultNumber);
+ }
+}
+
+void FTM_EnableInterrupts(FTM_Type *base, uint32_t mask)
+{
+ uint32_t chnlInts = (mask & 0xFFU);
+ uint8_t chnlNumber = 0;
+
+ /* Enable the timer overflow interrupt */
+ if (mask & kFTM_TimeOverflowInterruptEnable)
+ {
+ base->SC |= FTM_SC_TOIE_MASK;
+ }
+
+ /* Enable the fault interrupt */
+ if (mask & kFTM_FaultInterruptEnable)
+ {
+ base->MODE |= FTM_MODE_FAULTIE_MASK;
+ }
+
+#if defined(FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT) && (FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT)
+ /* Enable the reload interrupt available only on certain SoC's */
+ if (mask & kFTM_ReloadInterruptEnable)
+ {
+ base->SC |= FTM_SC_RIE_MASK;
+ }
+#endif
+
+ /* Enable the channel interrupts */
+ while (chnlInts)
+ {
+ if (chnlInts & 0x1)
+ {
+ base->CONTROLS[chnlNumber].CnSC |= FTM_CnSC_CHIE_MASK;
+ }
+ chnlNumber++;
+ chnlInts = chnlInts >> 1U;
+ }
+}
+
+void FTM_DisableInterrupts(FTM_Type *base, uint32_t mask)
+{
+ uint32_t chnlInts = (mask & 0xFF);
+ uint8_t chnlNumber = 0;
+
+ /* Disable the timer overflow interrupt */
+ if (mask & kFTM_TimeOverflowInterruptEnable)
+ {
+ base->SC &= ~FTM_SC_TOIE_MASK;
+ }
+ /* Disable the fault interrupt */
+ if (mask & kFTM_FaultInterruptEnable)
+ {
+ base->MODE &= ~FTM_MODE_FAULTIE_MASK;
+ }
+
+#if defined(FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT) && (FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT)
+ /* Disable the reload interrupt available only on certain SoC's */
+ if (mask & kFTM_ReloadInterruptEnable)
+ {
+ base->SC &= ~FTM_SC_RIE_MASK;
+ }
+#endif
+
+ /* Disable the channel interrupts */
+ while (chnlInts)
+ {
+ if (chnlInts & 0x1)
+ {
+ base->CONTROLS[chnlNumber].CnSC &= ~FTM_CnSC_CHIE_MASK;
+ }
+ chnlNumber++;
+ chnlInts = chnlInts >> 1U;
+ }
+}
+
+uint32_t FTM_GetEnabledInterrupts(FTM_Type *base)
+{
+ uint32_t enabledInterrupts = 0;
+ int8_t chnlCount = FSL_FEATURE_FTM_CHANNEL_COUNTn(base);
+
+ /* The CHANNEL_COUNT macro returns -1 if it cannot match the FTM instance */
+ assert(chnlCount != -1);
+
+ /* Check if timer overflow interrupt is enabled */
+ if (base->SC & FTM_SC_TOIE_MASK)
+ {
+ enabledInterrupts |= kFTM_TimeOverflowInterruptEnable;
+ }
+ /* Check if fault interrupt is enabled */
+ if (base->MODE & FTM_MODE_FAULTIE_MASK)
+ {
+ enabledInterrupts |= kFTM_FaultInterruptEnable;
+ }
+
+#if defined(FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT) && (FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT)
+ /* Check if the reload interrupt is enabled */
+ if (base->SC & FTM_SC_RIE_MASK)
+ {
+ enabledInterrupts |= kFTM_ReloadInterruptEnable;
+ }
+#endif
+
+ /* Check if the channel interrupts are enabled */
+ while (chnlCount > 0)
+ {
+ chnlCount--;
+ if (base->CONTROLS[chnlCount].CnSC & FTM_CnSC_CHIE_MASK)
+ {
+ enabledInterrupts |= (1U << chnlCount);
+ }
+ }
+
+ return enabledInterrupts;
+}
+
+uint32_t FTM_GetStatusFlags(FTM_Type *base)
+{
+ uint32_t statusFlags = 0;
+
+ /* Check the timer flag */
+ if (base->SC & FTM_SC_TOF_MASK)
+ {
+ statusFlags |= kFTM_TimeOverflowFlag;
+ }
+ /* Check fault flag */
+ if (base->FMS & FTM_FMS_FAULTF_MASK)
+ {
+ statusFlags |= kFTM_FaultFlag;
+ }
+ /* Check channel trigger flag */
+ if (base->EXTTRIG & FTM_EXTTRIG_TRIGF_MASK)
+ {
+ statusFlags |= kFTM_ChnlTriggerFlag;
+ }
+#if defined(FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT) && (FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT)
+ /* Check reload flag */
+ if (base->SC & FTM_SC_RF_MASK)
+ {
+ statusFlags |= kFTM_ReloadFlag;
+ }
+#endif
+
+ /* Lower 8 bits contain the channel status flags */
+ statusFlags |= (base->STATUS & 0xFFU);
+
+ return statusFlags;
+}
+
+void FTM_ClearStatusFlags(FTM_Type *base, uint32_t mask)
+{
+ /* Clear the timer overflow flag by writing a 0 to the bit while it is set */
+ if (mask & kFTM_TimeOverflowFlag)
+ {
+ base->SC &= ~FTM_SC_TOF_MASK;
+ }
+ /* Clear fault flag by writing a 0 to the bit while it is set */
+ if (mask & kFTM_FaultFlag)
+ {
+ base->FMS &= ~FTM_FMS_FAULTF_MASK;
+ }
+ /* Clear channel trigger flag */
+ if (mask & kFTM_ChnlTriggerFlag)
+ {
+ base->EXTTRIG &= ~FTM_EXTTRIG_TRIGF_MASK;
+ }
+
+#if defined(FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT) && (FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT)
+ /* Check reload flag by writing a 0 to the bit while it is set */
+ if (mask & kFTM_ReloadFlag)
+ {
+ base->SC &= ~FTM_SC_RF_MASK;
+ }
+#endif
+ /* Clear the channel status flags by writing a 0 to the bit */
+ base->STATUS &= ~(mask & 0xFFU);
+}
diff --git a/drivers/src/fsl_gpio.c b/drivers/src/fsl_gpio.c
new file mode 100644
index 0000000..b40ee3a
--- /dev/null
+++ b/drivers/src/fsl_gpio.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsl_gpio.h"
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+static PORT_Type *const s_portBases[] = PORT_BASE_PTRS;
+static GPIO_Type *const s_gpioBases[] = GPIO_BASE_PTRS;
+
+/*******************************************************************************
+* Prototypes
+******************************************************************************/
+
+/*!
+* @brief Gets the GPIO instance according to the GPIO base
+*
+* @param base GPIO peripheral base pointer(PTA, PTB, PTC, etc.)
+* @retval GPIO instance
+*/
+static uint32_t GPIO_GetInstance(GPIO_Type *base);
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static uint32_t GPIO_GetInstance(GPIO_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_gpioBases); instance++)
+ {
+ if (s_gpioBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_gpioBases));
+
+ return instance;
+}
+
+void GPIO_PinInit(GPIO_Type *base, uint32_t pin, const gpio_pin_config_t *config)
+{
+ assert(config);
+
+ if (config->pinDirection == kGPIO_DigitalInput)
+ {
+ base->PDDR &= ~(1U << pin);
+ }
+ else
+ {
+ GPIO_WritePinOutput(base, pin, config->outputLogic);
+ base->PDDR |= (1U << pin);
+ }
+}
+
+uint32_t GPIO_GetPinsInterruptFlags(GPIO_Type *base)
+{
+ uint8_t instance;
+ PORT_Type *portBase;
+ instance = GPIO_GetInstance(base);
+ portBase = s_portBases[instance];
+ return portBase->ISFR;
+}
+
+void GPIO_ClearPinsInterruptFlags(GPIO_Type *base, uint32_t mask)
+{
+ uint8_t instance;
+ PORT_Type *portBase;
+ instance = GPIO_GetInstance(base);
+ portBase = s_portBases[instance];
+ portBase->ISFR = mask;
+}
+
+#if defined(FSL_FEATURE_GPIO_HAS_ATTRIBUTE_CHECKER) && FSL_FEATURE_GPIO_HAS_ATTRIBUTE_CHECKER
+void GPIO_CheckAttributeBytes(GPIO_Type *base, gpio_checker_attribute_t attribute)
+{
+ base->GACR = ((uint32_t)attribute << GPIO_GACR_ACB0_SHIFT) | ((uint32_t)attribute << GPIO_GACR_ACB1_SHIFT) |
+ ((uint32_t)attribute << GPIO_GACR_ACB2_SHIFT) | ((uint32_t)attribute << GPIO_GACR_ACB3_SHIFT);
+}
+#endif
+
+#if defined(FSL_FEATURE_SOC_FGPIO_COUNT) && FSL_FEATURE_SOC_FGPIO_COUNT
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+static FGPIO_Type *const s_fgpioBases[] = FGPIO_BASE_PTRS;
+
+/*******************************************************************************
+* Prototypes
+******************************************************************************/
+/*!
+* @brief Gets the FGPIO instance according to the GPIO base
+*
+* @param base FGPIO peripheral base pointer(PTA, PTB, PTC, etc.)
+* @retval FGPIO instance
+*/
+static uint32_t FGPIO_GetInstance(FGPIO_Type *base);
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static uint32_t FGPIO_GetInstance(FGPIO_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_fgpioBases); instance++)
+ {
+ if (s_fgpioBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_fgpioBases));
+
+ return instance;
+}
+
+void FGPIO_PinInit(FGPIO_Type *base, uint32_t pin, const gpio_pin_config_t *config)
+{
+ assert(config);
+
+ if (config->pinDirection == kGPIO_DigitalInput)
+ {
+ base->PDDR &= ~(1U << pin);
+ }
+ else
+ {
+ FGPIO_WritePinOutput(base, pin, config->outputLogic);
+ base->PDDR |= (1U << pin);
+ }
+}
+
+uint32_t FGPIO_GetPinsInterruptFlags(FGPIO_Type *base)
+{
+ uint8_t instance;
+ instance = FGPIO_GetInstance(base);
+ PORT_Type *portBase;
+ portBase = s_portBases[instance];
+ return portBase->ISFR;
+}
+
+void FGPIO_ClearPinsInterruptFlags(FGPIO_Type *base, uint32_t mask)
+{
+ uint8_t instance;
+ instance = FGPIO_GetInstance(base);
+ PORT_Type *portBase;
+ portBase = s_portBases[instance];
+ portBase->ISFR = mask;
+}
+
+#if defined(FSL_FEATURE_FGPIO_HAS_ATTRIBUTE_CHECKER) && FSL_FEATURE_FGPIO_HAS_ATTRIBUTE_CHECKER
+void FGPIO_CheckAttributeBytes(FGPIO_Type *base, gpio_checker_attribute_t attribute)
+{
+ base->GACR = (attribute << FGPIO_GACR_ACB0_SHIFT) | (attribute << FGPIO_GACR_ACB1_SHIFT) |
+ (attribute << FGPIO_GACR_ACB2_SHIFT) | (attribute << FGPIO_GACR_ACB3_SHIFT);
+}
+#endif
+
+#endif /* FSL_FEATURE_SOC_FGPIO_COUNT */
diff --git a/drivers/src/fsl_i2c.c b/drivers/src/fsl_i2c.c
new file mode 100644
index 0000000..6c9770a
--- /dev/null
+++ b/drivers/src/fsl_i2c.c
@@ -0,0 +1,1757 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "fsl_i2c.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @brief i2c transfer state. */
+enum _i2c_transfer_states
+{
+ kIdleState = 0x0U, /*!< I2C bus idle. */
+ kCheckAddressState = 0x1U, /*!< 7-bit address check state. */
+ kSendCommandState = 0x2U, /*!< Send command byte phase. */
+ kSendDataState = 0x3U, /*!< Send data transfer phase. */
+ kReceiveDataBeginState = 0x4U, /*!< Receive data transfer phase begin. */
+ kReceiveDataState = 0x5U, /*!< Receive data transfer phase. */
+};
+
+/*! @brief Common sets of flags used by the driver. */
+enum _i2c_flag_constants
+{
+/*! All flags which are cleared by the driver upon starting a transfer. */
+#if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT
+ kClearFlags = kI2C_ArbitrationLostFlag | kI2C_IntPendingFlag | kI2C_StartDetectFlag | kI2C_StopDetectFlag,
+ kIrqFlags = kI2C_GlobalInterruptEnable | kI2C_StartStopDetectInterruptEnable,
+#elif defined(FSL_FEATURE_I2C_HAS_STOP_DETECT) && FSL_FEATURE_I2C_HAS_STOP_DETECT
+ kClearFlags = kI2C_ArbitrationLostFlag | kI2C_IntPendingFlag | kI2C_StopDetectFlag,
+ kIrqFlags = kI2C_GlobalInterruptEnable | kI2C_StopDetectInterruptEnable,
+#else
+ kClearFlags = kI2C_ArbitrationLostFlag | kI2C_IntPendingFlag,
+ kIrqFlags = kI2C_GlobalInterruptEnable,
+#endif
+
+};
+
+/*! @brief Typedef for interrupt handler. */
+typedef void (*i2c_isr_t)(I2C_Type *base, void *i2cHandle);
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Get instance number for I2C module.
+ *
+ * @param base I2C peripheral base address.
+ */
+uint32_t I2C_GetInstance(I2C_Type *base);
+
+/*!
+* @brief Set SCL/SDA hold time, this API receives SCL stop hold time, calculate the
+* closest SCL divider and MULT value for the SDA hold time, SCL start and SCL stop
+* hold time. To reduce the ROM size, SDA/SCL hold value mapping table is not provided,
+* assume SCL divider = SCL stop hold value *2 to get the closest SCL divider value and MULT
+* value, then the related SDA hold time, SCL start and SCL stop hold time is used.
+*
+* @param base I2C peripheral base address.
+* @param sourceClock_Hz I2C functional clock frequency in Hertz.
+* @param sclStopHoldTime_ns SCL stop hold time in ns.
+*/
+static void I2C_SetHoldTime(I2C_Type *base, uint32_t sclStopHoldTime_ns, uint32_t sourceClock_Hz);
+
+/*!
+ * @brief Set up master transfer, send slave address and decide the initial
+ * transfer state.
+ *
+ * @param base I2C peripheral base address.
+ * @param handle pointer to i2c_master_handle_t structure which stores the transfer state.
+ * @param xfer pointer to i2c_master_transfer_t structure.
+ */
+static status_t I2C_InitTransferStateMachine(I2C_Type *base, i2c_master_handle_t *handle, i2c_master_transfer_t *xfer);
+
+/*!
+ * @brief Check and clear status operation.
+ *
+ * @param base I2C peripheral base address.
+ * @param status current i2c hardware status.
+ * @retval kStatus_Success No error found.
+ * @retval kStatus_I2C_ArbitrationLost Transfer error, arbitration lost.
+ * @retval kStatus_I2C_Nak Received Nak error.
+ */
+static status_t I2C_CheckAndClearError(I2C_Type *base, uint32_t status);
+
+/*!
+ * @brief Master run transfer state machine to perform a byte of transfer.
+ *
+ * @param base I2C peripheral base address.
+ * @param handle pointer to i2c_master_handle_t structure which stores the transfer state
+ * @param isDone input param to get whether the thing is done, true is done
+ * @retval kStatus_Success No error found.
+ * @retval kStatus_I2C_ArbitrationLost Transfer error, arbitration lost.
+ * @retval kStatus_I2C_Nak Received Nak error.
+ * @retval kStatus_I2C_Timeout Transfer error, wait signal timeout.
+ */
+static status_t I2C_MasterTransferRunStateMachine(I2C_Type *base, i2c_master_handle_t *handle, bool *isDone);
+
+/*!
+ * @brief I2C common interrupt handler.
+ *
+ * @param base I2C peripheral base address.
+ * @param handle pointer to i2c_master_handle_t structure which stores the transfer state
+ */
+static void I2C_TransferCommonIRQHandler(I2C_Type *base, void *handle);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*! @brief Pointers to i2c handles for each instance. */
+static void *s_i2cHandle[FSL_FEATURE_SOC_I2C_COUNT] = {NULL};
+
+/*! @brief SCL clock divider used to calculate baudrate. */
+static const uint16_t s_i2cDividerTable[] = {
+ 20, 22, 24, 26, 28, 30, 34, 40, 28, 32, 36, 40, 44, 48, 56, 68,
+ 48, 56, 64, 72, 80, 88, 104, 128, 80, 96, 112, 128, 144, 160, 192, 240,
+ 160, 192, 224, 256, 288, 320, 384, 480, 320, 384, 448, 512, 576, 640, 768, 960,
+ 640, 768, 896, 1024, 1152, 1280, 1536, 1920, 1280, 1536, 1792, 2048, 2304, 2560, 3072, 3840};
+
+/*! @brief Pointers to i2c bases for each instance. */
+static I2C_Type *const s_i2cBases[] = I2C_BASE_PTRS;
+
+/*! @brief Pointers to i2c IRQ number for each instance. */
+static const IRQn_Type s_i2cIrqs[] = I2C_IRQS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to i2c clocks for each instance. */
+static const clock_ip_name_t s_i2cClocks[] = I2C_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*! @brief Pointer to master IRQ handler for each instance. */
+static i2c_isr_t s_i2cMasterIsr;
+
+/*! @brief Pointer to slave IRQ handler for each instance. */
+static i2c_isr_t s_i2cSlaveIsr;
+
+/*******************************************************************************
+ * Codes
+ ******************************************************************************/
+
+uint32_t I2C_GetInstance(I2C_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_i2cBases); instance++)
+ {
+ if (s_i2cBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_i2cBases));
+
+ return instance;
+}
+
+static void I2C_SetHoldTime(I2C_Type *base, uint32_t sclStopHoldTime_ns, uint32_t sourceClock_Hz)
+{
+ uint32_t multiplier;
+ uint32_t computedSclHoldTime;
+ uint32_t absError;
+ uint32_t bestError = UINT32_MAX;
+ uint32_t bestMult = 0u;
+ uint32_t bestIcr = 0u;
+ uint8_t mult;
+ uint8_t i;
+
+ /* Search for the settings with the lowest error. Mult is the MULT field of the I2C_F register,
+ * and ranges from 0-2. It selects the multiplier factor for the divider. */
+ /* SDA hold time = bus period (s) * mul * SDA hold value. */
+ /* SCL start hold time = bus period (s) * mul * SCL start hold value. */
+ /* SCL stop hold time = bus period (s) * mul * SCL stop hold value. */
+
+ for (mult = 0u; (mult <= 2u) && (bestError != 0); ++mult)
+ {
+ multiplier = 1u << mult;
+
+ /* Scan table to find best match. */
+ for (i = 0u; i < sizeof(s_i2cDividerTable) / sizeof(s_i2cDividerTable[0]); ++i)
+ {
+ /* Assume SCL hold(stop) value = s_i2cDividerTable[i]/2. */
+ computedSclHoldTime = ((multiplier * s_i2cDividerTable[i]) * 500000000U) / sourceClock_Hz;
+ absError = sclStopHoldTime_ns > computedSclHoldTime ? (sclStopHoldTime_ns - computedSclHoldTime) :
+ (computedSclHoldTime - sclStopHoldTime_ns);
+
+ if (absError < bestError)
+ {
+ bestMult = mult;
+ bestIcr = i;
+ bestError = absError;
+
+ /* If the error is 0, then we can stop searching because we won't find a better match. */
+ if (absError == 0)
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ /* Set frequency register based on best settings. */
+ base->F = I2C_F_MULT(bestMult) | I2C_F_ICR(bestIcr);
+}
+
+static status_t I2C_InitTransferStateMachine(I2C_Type *base, i2c_master_handle_t *handle, i2c_master_transfer_t *xfer)
+{
+ status_t result = kStatus_Success;
+ i2c_direction_t direction = xfer->direction;
+
+ /* Initialize the handle transfer information. */
+ handle->transfer = *xfer;
+
+ /* Save total transfer size. */
+ handle->transferSize = xfer->dataSize;
+
+ /* Initial transfer state. */
+ if (handle->transfer.subaddressSize > 0)
+ {
+ if (xfer->direction == kI2C_Read)
+ {
+ direction = kI2C_Write;
+ }
+ }
+
+ handle->state = kCheckAddressState;
+
+ /* Clear all status before transfer. */
+ I2C_MasterClearStatusFlags(base, kClearFlags);
+
+ /* If repeated start is requested, send repeated start. */
+ if (handle->transfer.flags & kI2C_TransferRepeatedStartFlag)
+ {
+ result = I2C_MasterRepeatedStart(base, handle->transfer.slaveAddress, direction);
+ }
+ else /* For normal transfer, send start. */
+ {
+ result = I2C_MasterStart(base, handle->transfer.slaveAddress, direction);
+ }
+
+ return result;
+}
+
+static status_t I2C_CheckAndClearError(I2C_Type *base, uint32_t status)
+{
+ status_t result = kStatus_Success;
+
+ /* Check arbitration lost. */
+ if (status & kI2C_ArbitrationLostFlag)
+ {
+ /* Clear arbitration lost flag. */
+ base->S = kI2C_ArbitrationLostFlag;
+ result = kStatus_I2C_ArbitrationLost;
+ }
+ /* Check NAK */
+ else if (status & kI2C_ReceiveNakFlag)
+ {
+ result = kStatus_I2C_Nak;
+ }
+ else
+ {
+ }
+
+ return result;
+}
+
+static status_t I2C_MasterTransferRunStateMachine(I2C_Type *base, i2c_master_handle_t *handle, bool *isDone)
+{
+ status_t result = kStatus_Success;
+ uint32_t statusFlags = base->S;
+ *isDone = false;
+ volatile uint8_t dummy = 0;
+ bool ignoreNak = ((handle->state == kSendDataState) && (handle->transfer.dataSize == 0U)) ||
+ ((handle->state == kReceiveDataState) && (handle->transfer.dataSize == 1U));
+
+ /* Add this to avoid build warning. */
+ dummy++;
+
+ /* Check & clear error flags. */
+ result = I2C_CheckAndClearError(base, statusFlags);
+
+ /* Ignore Nak when it's appeared for last byte. */
+ if ((result == kStatus_I2C_Nak) && ignoreNak)
+ {
+ result = kStatus_Success;
+ }
+
+ /* Handle Check address state to check the slave address is Acked in slave
+ probe application. */
+ if (handle->state == kCheckAddressState)
+ {
+ if (statusFlags & kI2C_ReceiveNakFlag)
+ {
+ result = kStatus_I2C_Addr_Nak;
+ }
+ else
+ {
+ if (handle->transfer.subaddressSize > 0)
+ {
+ handle->state = kSendCommandState;
+ }
+ else
+ {
+ if (handle->transfer.direction == kI2C_Write)
+ {
+ /* Next state, send data. */
+ handle->state = kSendDataState;
+ }
+ else
+ {
+ /* Next state, receive data begin. */
+ handle->state = kReceiveDataBeginState;
+ }
+ }
+ }
+ }
+
+ if (result)
+ {
+ return result;
+ }
+
+ /* Run state machine. */
+ switch (handle->state)
+ {
+ /* Send I2C command. */
+ case kSendCommandState:
+ if (handle->transfer.subaddressSize)
+ {
+ handle->transfer.subaddressSize--;
+ base->D = ((handle->transfer.subaddress) >> (8 * handle->transfer.subaddressSize));
+ }
+ else
+ {
+ if (handle->transfer.direction == kI2C_Write)
+ {
+ /* Next state, send data. */
+ handle->state = kSendDataState;
+
+ /* Send first byte of data. */
+ if (handle->transfer.dataSize > 0)
+ {
+ base->D = *handle->transfer.data;
+ handle->transfer.data++;
+ handle->transfer.dataSize--;
+ }
+ }
+ else
+ {
+ /* Send repeated start and slave address. */
+ result = I2C_MasterRepeatedStart(base, handle->transfer.slaveAddress, kI2C_Read);
+
+ /* Next state, receive data begin. */
+ handle->state = kReceiveDataBeginState;
+ }
+ }
+ break;
+
+ /* Send I2C data. */
+ case kSendDataState:
+ /* Send one byte of data. */
+ if (handle->transfer.dataSize > 0)
+ {
+ base->D = *handle->transfer.data;
+ handle->transfer.data++;
+ handle->transfer.dataSize--;
+ }
+ else
+ {
+ *isDone = true;
+ }
+ break;
+
+ /* Start I2C data receive. */
+ case kReceiveDataBeginState:
+ base->C1 &= ~(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK);
+
+ /* Send nak at the last receive byte. */
+ if (handle->transfer.dataSize == 1)
+ {
+ base->C1 |= I2C_C1_TXAK_MASK;
+ }
+
+ /* Read dummy to release the bus. */
+ dummy = base->D;
+
+ /* Next state, receive data. */
+ handle->state = kReceiveDataState;
+ break;
+
+ /* Receive I2C data. */
+ case kReceiveDataState:
+ /* Receive one byte of data. */
+ if (handle->transfer.dataSize--)
+ {
+ if (handle->transfer.dataSize == 0)
+ {
+ *isDone = true;
+
+ /* Send stop if kI2C_TransferNoStop is not asserted. */
+ if (!(handle->transfer.flags & kI2C_TransferNoStopFlag))
+ {
+ result = I2C_MasterStop(base);
+ }
+ else
+ {
+ base->C1 |= I2C_C1_TX_MASK;
+ }
+ }
+
+ /* Send NAK at the last receive byte. */
+ if (handle->transfer.dataSize == 1)
+ {
+ base->C1 |= I2C_C1_TXAK_MASK;
+ }
+
+ /* Read the data byte into the transfer buffer. */
+ *handle->transfer.data = base->D;
+ handle->transfer.data++;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return result;
+}
+
+static void I2C_TransferCommonIRQHandler(I2C_Type *base, void *handle)
+{
+ /* Check if master interrupt. */
+ if ((base->S & kI2C_ArbitrationLostFlag) || (base->C1 & I2C_C1_MST_MASK))
+ {
+ s_i2cMasterIsr(base, handle);
+ }
+ else
+ {
+ s_i2cSlaveIsr(base, handle);
+ }
+ __DSB();
+}
+
+void I2C_MasterInit(I2C_Type *base, const i2c_master_config_t *masterConfig, uint32_t srcClock_Hz)
+{
+ assert(masterConfig && srcClock_Hz);
+
+ /* Temporary register for filter read. */
+ uint8_t fltReg;
+#if defined(FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE) && FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE
+ uint8_t s2Reg;
+#endif
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable I2C clock. */
+ CLOCK_EnableClock(s_i2cClocks[I2C_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Reset the module. */
+ base->A1 = 0;
+ base->F = 0;
+ base->C1 = 0;
+ base->S = 0xFFU;
+ base->C2 = 0;
+#if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT
+ base->FLT = 0x50U;
+#elif defined(FSL_FEATURE_I2C_HAS_STOP_DETECT) && FSL_FEATURE_I2C_HAS_STOP_DETECT
+ base->FLT = 0x40U;
+#endif
+ base->RA = 0;
+
+ /* Disable I2C prior to configuring it. */
+ base->C1 &= ~(I2C_C1_IICEN_MASK);
+
+ /* Clear all flags. */
+ I2C_MasterClearStatusFlags(base, kClearFlags);
+
+ /* Configure baud rate. */
+ I2C_MasterSetBaudRate(base, masterConfig->baudRate_Bps, srcClock_Hz);
+
+ /* Read out the FLT register. */
+ fltReg = base->FLT;
+
+#if defined(FSL_FEATURE_I2C_HAS_STOP_HOLD_OFF) && FSL_FEATURE_I2C_HAS_STOP_HOLD_OFF
+ /* Configure the stop / hold enable. */
+ fltReg &= ~(I2C_FLT_SHEN_MASK);
+ fltReg |= I2C_FLT_SHEN(masterConfig->enableStopHold);
+#endif
+
+ /* Configure the glitch filter value. */
+ fltReg &= ~(I2C_FLT_FLT_MASK);
+ fltReg |= I2C_FLT_FLT(masterConfig->glitchFilterWidth);
+
+ /* Write the register value back to the filter register. */
+ base->FLT = fltReg;
+
+/* Enable/Disable double buffering. */
+#if defined(FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE) && FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE
+ s2Reg = base->S2 & (~I2C_S2_DFEN_MASK);
+ base->S2 = s2Reg | I2C_S2_DFEN(masterConfig->enableDoubleBuffering);
+#endif
+
+ /* Enable the I2C peripheral based on the configuration. */
+ base->C1 = I2C_C1_IICEN(masterConfig->enableMaster);
+}
+
+void I2C_MasterDeinit(I2C_Type *base)
+{
+ /* Disable I2C module. */
+ I2C_Enable(base, false);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Disable I2C clock. */
+ CLOCK_DisableClock(s_i2cClocks[I2C_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+void I2C_MasterGetDefaultConfig(i2c_master_config_t *masterConfig)
+{
+ assert(masterConfig);
+
+ /* Default baud rate at 100kbps. */
+ masterConfig->baudRate_Bps = 100000U;
+
+/* Default stop hold enable is disabled. */
+#if defined(FSL_FEATURE_I2C_HAS_STOP_HOLD_OFF) && FSL_FEATURE_I2C_HAS_STOP_HOLD_OFF
+ masterConfig->enableStopHold = false;
+#endif
+
+ /* Default glitch filter value is no filter. */
+ masterConfig->glitchFilterWidth = 0U;
+
+/* Default enable double buffering. */
+#if defined(FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE) && FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE
+ masterConfig->enableDoubleBuffering = true;
+#endif
+
+ /* Enable the I2C peripheral. */
+ masterConfig->enableMaster = true;
+}
+
+void I2C_EnableInterrupts(I2C_Type *base, uint32_t mask)
+{
+#ifdef I2C_HAS_STOP_DETECT
+ uint8_t fltReg;
+#endif
+
+ if (mask & kI2C_GlobalInterruptEnable)
+ {
+ base->C1 |= I2C_C1_IICIE_MASK;
+ }
+
+#if defined(FSL_FEATURE_I2C_HAS_STOP_DETECT) && FSL_FEATURE_I2C_HAS_STOP_DETECT
+ if (mask & kI2C_StopDetectInterruptEnable)
+ {
+ fltReg = base->FLT;
+
+ /* Keep STOPF flag. */
+ fltReg &= ~I2C_FLT_STOPF_MASK;
+
+ /* Stop detect enable. */
+ fltReg |= I2C_FLT_STOPIE_MASK;
+ base->FLT = fltReg;
+ }
+#endif /* FSL_FEATURE_I2C_HAS_STOP_DETECT */
+
+#if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT
+ if (mask & kI2C_StartStopDetectInterruptEnable)
+ {
+ fltReg = base->FLT;
+
+ /* Keep STARTF and STOPF flags. */
+ fltReg &= ~(I2C_FLT_STOPF_MASK | I2C_FLT_STARTF_MASK);
+
+ /* Start and stop detect enable. */
+ fltReg |= I2C_FLT_SSIE_MASK;
+ base->FLT = fltReg;
+ }
+#endif /* FSL_FEATURE_I2C_HAS_START_STOP_DETECT */
+}
+
+void I2C_DisableInterrupts(I2C_Type *base, uint32_t mask)
+{
+ if (mask & kI2C_GlobalInterruptEnable)
+ {
+ base->C1 &= ~I2C_C1_IICIE_MASK;
+ }
+
+#if defined(FSL_FEATURE_I2C_HAS_STOP_DETECT) && FSL_FEATURE_I2C_HAS_STOP_DETECT
+ if (mask & kI2C_StopDetectInterruptEnable)
+ {
+ base->FLT &= ~(I2C_FLT_STOPIE_MASK | I2C_FLT_STOPF_MASK);
+ }
+#endif /* FSL_FEATURE_I2C_HAS_STOP_DETECT */
+
+#if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT
+ if (mask & kI2C_StartStopDetectInterruptEnable)
+ {
+ base->FLT &= ~(I2C_FLT_SSIE_MASK | I2C_FLT_STOPF_MASK | I2C_FLT_STARTF_MASK);
+ }
+#endif /* FSL_FEATURE_I2C_HAS_START_STOP_DETECT */
+}
+
+void I2C_MasterSetBaudRate(I2C_Type *base, uint32_t baudRate_Bps, uint32_t srcClock_Hz)
+{
+ uint32_t multiplier;
+ uint32_t computedRate;
+ uint32_t absError;
+ uint32_t bestError = UINT32_MAX;
+ uint32_t bestMult = 0u;
+ uint32_t bestIcr = 0u;
+ uint8_t mult;
+ uint8_t i;
+
+ /* Search for the settings with the lowest error. Mult is the MULT field of the I2C_F register,
+ * and ranges from 0-2. It selects the multiplier factor for the divider. */
+ for (mult = 0u; (mult <= 2u) && (bestError != 0); ++mult)
+ {
+ multiplier = 1u << mult;
+
+ /* Scan table to find best match. */
+ for (i = 0u; i < sizeof(s_i2cDividerTable) / sizeof(uint16_t); ++i)
+ {
+ computedRate = srcClock_Hz / (multiplier * s_i2cDividerTable[i]);
+ absError = baudRate_Bps > computedRate ? (baudRate_Bps - computedRate) : (computedRate - baudRate_Bps);
+
+ if (absError < bestError)
+ {
+ bestMult = mult;
+ bestIcr = i;
+ bestError = absError;
+
+ /* If the error is 0, then we can stop searching because we won't find a better match. */
+ if (absError == 0)
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ /* Set frequency register based on best settings. */
+ base->F = I2C_F_MULT(bestMult) | I2C_F_ICR(bestIcr);
+}
+
+status_t I2C_MasterStart(I2C_Type *base, uint8_t address, i2c_direction_t direction)
+{
+ status_t result = kStatus_Success;
+ uint32_t statusFlags = I2C_MasterGetStatusFlags(base);
+
+ /* Return an error if the bus is already in use. */
+ if (statusFlags & kI2C_BusBusyFlag)
+ {
+ result = kStatus_I2C_Busy;
+ }
+ else
+ {
+ /* Send the START signal. */
+ base->C1 |= I2C_C1_MST_MASK | I2C_C1_TX_MASK;
+
+#if defined(FSL_FEATURE_I2C_HAS_DOUBLE_BUFFERING) && FSL_FEATURE_I2C_HAS_DOUBLE_BUFFERING
+ while (!(base->S2 & I2C_S2_EMPTY_MASK))
+ {
+ }
+#endif /* FSL_FEATURE_I2C_HAS_DOUBLE_BUFFERING */
+
+ base->D = (((uint32_t)address) << 1U | ((direction == kI2C_Read) ? 1U : 0U));
+ }
+
+ return result;
+}
+
+status_t I2C_MasterRepeatedStart(I2C_Type *base, uint8_t address, i2c_direction_t direction)
+{
+ status_t result = kStatus_Success;
+ uint8_t savedMult;
+ uint32_t statusFlags = I2C_MasterGetStatusFlags(base);
+ uint8_t timeDelay = 6;
+
+ /* Return an error if the bus is already in use, but not by us. */
+ if ((statusFlags & kI2C_BusBusyFlag) && ((base->C1 & I2C_C1_MST_MASK) == 0))
+ {
+ result = kStatus_I2C_Busy;
+ }
+ else
+ {
+ savedMult = base->F;
+ base->F = savedMult & (~I2C_F_MULT_MASK);
+
+ /* We are already in a transfer, so send a repeated start. */
+ base->C1 |= I2C_C1_RSTA_MASK | I2C_C1_TX_MASK;
+
+ /* Restore the multiplier factor. */
+ base->F = savedMult;
+
+ /* Add some delay to wait the Re-Start signal. */
+ while (timeDelay--)
+ {
+ __NOP();
+ }
+
+#if defined(FSL_FEATURE_I2C_HAS_DOUBLE_BUFFERING) && FSL_FEATURE_I2C_HAS_DOUBLE_BUFFERING
+ while (!(base->S2 & I2C_S2_EMPTY_MASK))
+ {
+ }
+#endif /* FSL_FEATURE_I2C_HAS_DOUBLE_BUFFERING */
+
+ base->D = (((uint32_t)address) << 1U | ((direction == kI2C_Read) ? 1U : 0U));
+ }
+
+ return result;
+}
+
+status_t I2C_MasterStop(I2C_Type *base)
+{
+ status_t result = kStatus_Success;
+ uint16_t timeout = UINT16_MAX;
+
+ /* Issue the STOP command on the bus. */
+ base->C1 &= ~(I2C_C1_MST_MASK | I2C_C1_TX_MASK | I2C_C1_TXAK_MASK);
+
+ /* Wait until data transfer complete. */
+ while ((base->S & kI2C_BusBusyFlag) && (--timeout))
+ {
+ }
+
+ if (timeout == 0)
+ {
+ result = kStatus_I2C_Timeout;
+ }
+
+ return result;
+}
+
+uint32_t I2C_MasterGetStatusFlags(I2C_Type *base)
+{
+ uint32_t statusFlags = base->S;
+
+#ifdef I2C_HAS_STOP_DETECT
+ /* Look up the STOPF bit from the filter register. */
+ if (base->FLT & I2C_FLT_STOPF_MASK)
+ {
+ statusFlags |= kI2C_StopDetectFlag;
+ }
+#endif
+
+#if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT
+ /* Look up the STARTF bit from the filter register. */
+ if (base->FLT & I2C_FLT_STARTF_MASK)
+ {
+ statusFlags |= kI2C_StartDetectFlag;
+ }
+#endif /* FSL_FEATURE_I2C_HAS_START_STOP_DETECT */
+
+ return statusFlags;
+}
+
+status_t I2C_MasterWriteBlocking(I2C_Type *base, const uint8_t *txBuff, size_t txSize, uint32_t flags)
+{
+ status_t result = kStatus_Success;
+ uint8_t statusFlags = 0;
+
+ /* Wait until the data register is ready for transmit. */
+ while (!(base->S & kI2C_TransferCompleteFlag))
+ {
+ }
+
+ /* Clear the IICIF flag. */
+ base->S = kI2C_IntPendingFlag;
+
+ /* Setup the I2C peripheral to transmit data. */
+ base->C1 |= I2C_C1_TX_MASK;
+
+ while (txSize--)
+ {
+ /* Send a byte of data. */
+ base->D = *txBuff++;
+
+ /* Wait until data transfer complete. */
+ while (!(base->S & kI2C_IntPendingFlag))
+ {
+ }
+
+ statusFlags = base->S;
+
+ /* Clear the IICIF flag. */
+ base->S = kI2C_IntPendingFlag;
+
+ /* Check if arbitration lost or no acknowledgement (NAK), return failure status. */
+ if (statusFlags & kI2C_ArbitrationLostFlag)
+ {
+ base->S = kI2C_ArbitrationLostFlag;
+ result = kStatus_I2C_ArbitrationLost;
+ }
+
+ if ((statusFlags & kI2C_ReceiveNakFlag) && txSize)
+ {
+ base->S = kI2C_ReceiveNakFlag;
+ result = kStatus_I2C_Nak;
+ }
+
+ if (result != kStatus_Success)
+ {
+ /* Breaking out of the send loop. */
+ break;
+ }
+ }
+
+ if (((result == kStatus_Success) && (!(flags & kI2C_TransferNoStopFlag))) || (result == kStatus_I2C_Nak))
+ {
+ /* Clear the IICIF flag. */
+ base->S = kI2C_IntPendingFlag;
+
+ /* Send stop. */
+ result = I2C_MasterStop(base);
+ }
+
+ return result;
+}
+
+status_t I2C_MasterReadBlocking(I2C_Type *base, uint8_t *rxBuff, size_t rxSize, uint32_t flags)
+{
+ status_t result = kStatus_Success;
+ volatile uint8_t dummy = 0;
+
+ /* Add this to avoid build warning. */
+ dummy++;
+
+ /* Wait until the data register is ready for transmit. */
+ while (!(base->S & kI2C_TransferCompleteFlag))
+ {
+ }
+
+ /* Clear the IICIF flag. */
+ base->S = kI2C_IntPendingFlag;
+
+ /* Setup the I2C peripheral to receive data. */
+ base->C1 &= ~(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK);
+
+ /* If rxSize equals 1, configure to send NAK. */
+ if (rxSize == 1)
+ {
+ /* Issue NACK on read. */
+ base->C1 |= I2C_C1_TXAK_MASK;
+ }
+
+ /* Do dummy read. */
+ dummy = base->D;
+
+ while ((rxSize--))
+ {
+ /* Wait until data transfer complete. */
+ while (!(base->S & kI2C_IntPendingFlag))
+ {
+ }
+
+ /* Clear the IICIF flag. */
+ base->S = kI2C_IntPendingFlag;
+
+ /* Single byte use case. */
+ if (rxSize == 0)
+ {
+ if (!(flags & kI2C_TransferNoStopFlag))
+ {
+ /* Issue STOP command before reading last byte. */
+ result = I2C_MasterStop(base);
+ }
+ else
+ {
+ /* Change direction to Tx to avoid extra clocks. */
+ base->C1 |= I2C_C1_TX_MASK;
+ }
+ }
+
+ if (rxSize == 1)
+ {
+ /* Issue NACK on read. */
+ base->C1 |= I2C_C1_TXAK_MASK;
+ }
+
+ /* Read from the data register. */
+ *rxBuff++ = base->D;
+ }
+
+ return result;
+}
+
+status_t I2C_MasterTransferBlocking(I2C_Type *base, i2c_master_transfer_t *xfer)
+{
+ assert(xfer);
+
+ i2c_direction_t direction = xfer->direction;
+ status_t result = kStatus_Success;
+
+ /* Clear all status before transfer. */
+ I2C_MasterClearStatusFlags(base, kClearFlags);
+
+ /* Wait until ready to complete. */
+ while (!(base->S & kI2C_TransferCompleteFlag))
+ {
+ }
+
+ /* Change to send write address when it's a read operation with command. */
+ if ((xfer->subaddressSize > 0) && (xfer->direction == kI2C_Read))
+ {
+ direction = kI2C_Write;
+ }
+
+ /* If repeated start is requested, send repeated start. */
+ if (xfer->flags & kI2C_TransferRepeatedStartFlag)
+ {
+ result = I2C_MasterRepeatedStart(base, xfer->slaveAddress, direction);
+ }
+ else /* For normal transfer, send start. */
+ {
+ result = I2C_MasterStart(base, xfer->slaveAddress, direction);
+ }
+
+ /* Return if error. */
+ if (result)
+ {
+ return result;
+ }
+
+ while (!(base->S & kI2C_IntPendingFlag))
+ {
+ }
+
+ /* Check if there's transfer error. */
+ result = I2C_CheckAndClearError(base, base->S);
+
+ /* Return if error. */
+ if (result)
+ {
+ if (result == kStatus_I2C_Nak)
+ {
+ result = kStatus_I2C_Addr_Nak;
+
+ I2C_MasterStop(base);
+ }
+
+ return result;
+ }
+
+ /* Send subaddress. */
+ if (xfer->subaddressSize)
+ {
+ do
+ {
+ /* Clear interrupt pending flag. */
+ base->S = kI2C_IntPendingFlag;
+
+ xfer->subaddressSize--;
+ base->D = ((xfer->subaddress) >> (8 * xfer->subaddressSize));
+
+ /* Wait until data transfer complete. */
+ while (!(base->S & kI2C_IntPendingFlag))
+ {
+ }
+
+ /* Check if there's transfer error. */
+ result = I2C_CheckAndClearError(base, base->S);
+
+ if (result)
+ {
+ if (result == kStatus_I2C_Nak)
+ {
+ I2C_MasterStop(base);
+ }
+
+ return result;
+ }
+
+ } while ((xfer->subaddressSize > 0) && (result == kStatus_Success));
+
+ if (xfer->direction == kI2C_Read)
+ {
+ /* Clear pending flag. */
+ base->S = kI2C_IntPendingFlag;
+
+ /* Send repeated start and slave address. */
+ result = I2C_MasterRepeatedStart(base, xfer->slaveAddress, kI2C_Read);
+
+ /* Return if error. */
+ if (result)
+ {
+ return result;
+ }
+
+ /* Wait until data transfer complete. */
+ while (!(base->S & kI2C_IntPendingFlag))
+ {
+ }
+
+ /* Check if there's transfer error. */
+ result = I2C_CheckAndClearError(base, base->S);
+
+ if (result)
+ {
+ if (result == kStatus_I2C_Nak)
+ {
+ result = kStatus_I2C_Addr_Nak;
+
+ I2C_MasterStop(base);
+ }
+
+ return result;
+ }
+ }
+ }
+
+ /* Transmit data. */
+ if ((xfer->direction == kI2C_Write) && (xfer->dataSize > 0))
+ {
+ /* Send Data. */
+ result = I2C_MasterWriteBlocking(base, xfer->data, xfer->dataSize, xfer->flags);
+ }
+
+ /* Receive Data. */
+ if ((xfer->direction == kI2C_Read) && (xfer->dataSize > 0))
+ {
+ result = I2C_MasterReadBlocking(base, xfer->data, xfer->dataSize, xfer->flags);
+ }
+
+ return result;
+}
+
+void I2C_MasterTransferCreateHandle(I2C_Type *base,
+ i2c_master_handle_t *handle,
+ i2c_master_transfer_callback_t callback,
+ void *userData)
+{
+ assert(handle);
+
+ uint32_t instance = I2C_GetInstance(base);
+
+ /* Zero handle. */
+ memset(handle, 0, sizeof(*handle));
+
+ /* Set callback and userData. */
+ handle->completionCallback = callback;
+ handle->userData = userData;
+
+ /* Save the context in global variables to support the double weak mechanism. */
+ s_i2cHandle[instance] = handle;
+
+ /* Save master interrupt handler. */
+ s_i2cMasterIsr = I2C_MasterTransferHandleIRQ;
+
+ /* Enable NVIC interrupt. */
+ EnableIRQ(s_i2cIrqs[instance]);
+}
+
+status_t I2C_MasterTransferNonBlocking(I2C_Type *base, i2c_master_handle_t *handle, i2c_master_transfer_t *xfer)
+{
+ assert(handle);
+ assert(xfer);
+
+ status_t result = kStatus_Success;
+
+ /* Check if the I2C bus is idle - if not return busy status. */
+ if (handle->state != kIdleState)
+ {
+ result = kStatus_I2C_Busy;
+ }
+ else
+ {
+ /* Start up the master transfer state machine. */
+ result = I2C_InitTransferStateMachine(base, handle, xfer);
+
+ if (result == kStatus_Success)
+ {
+ /* Enable the I2C interrupts. */
+ I2C_EnableInterrupts(base, kI2C_GlobalInterruptEnable);
+ }
+ }
+
+ return result;
+}
+
+void I2C_MasterTransferAbort(I2C_Type *base, i2c_master_handle_t *handle)
+{
+ assert(handle);
+
+ volatile uint8_t dummy = 0;
+
+ /* Add this to avoid build warning. */
+ dummy++;
+
+ /* Disable interrupt. */
+ I2C_DisableInterrupts(base, kI2C_GlobalInterruptEnable);
+
+ /* Reset the state to idle. */
+ handle->state = kIdleState;
+
+ /* Send STOP signal. */
+ if (handle->transfer.direction == kI2C_Read)
+ {
+ base->C1 |= I2C_C1_TXAK_MASK;
+ while (!(base->S & kI2C_IntPendingFlag))
+ {
+ }
+ base->S = kI2C_IntPendingFlag;
+
+ base->C1 &= ~(I2C_C1_MST_MASK | I2C_C1_TX_MASK | I2C_C1_TXAK_MASK);
+ dummy = base->D;
+ }
+ else
+ {
+ while (!(base->S & kI2C_IntPendingFlag))
+ {
+ }
+ base->S = kI2C_IntPendingFlag;
+ base->C1 &= ~(I2C_C1_MST_MASK | I2C_C1_TX_MASK | I2C_C1_TXAK_MASK);
+ }
+}
+
+status_t I2C_MasterTransferGetCount(I2C_Type *base, i2c_master_handle_t *handle, size_t *count)
+{
+ assert(handle);
+
+ if (!count)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ *count = handle->transferSize - handle->transfer.dataSize;
+
+ return kStatus_Success;
+}
+
+void I2C_MasterTransferHandleIRQ(I2C_Type *base, void *i2cHandle)
+{
+ assert(i2cHandle);
+
+ i2c_master_handle_t *handle = (i2c_master_handle_t *)i2cHandle;
+ status_t result = kStatus_Success;
+ bool isDone;
+
+ /* Clear the interrupt flag. */
+ base->S = kI2C_IntPendingFlag;
+
+ /* Check transfer complete flag. */
+ result = I2C_MasterTransferRunStateMachine(base, handle, &isDone);
+
+ if (isDone || result)
+ {
+ /* Send stop command if transfer done or received Nak. */
+ if ((!(handle->transfer.flags & kI2C_TransferNoStopFlag)) || (result == kStatus_I2C_Nak) ||
+ (result == kStatus_I2C_Addr_Nak))
+ {
+ /* Ensure stop command is a need. */
+ if ((base->C1 & I2C_C1_MST_MASK))
+ {
+ if (I2C_MasterStop(base) != kStatus_Success)
+ {
+ result = kStatus_I2C_Timeout;
+ }
+ }
+ }
+
+ /* Restore handle to idle state. */
+ handle->state = kIdleState;
+
+ /* Disable interrupt. */
+ I2C_DisableInterrupts(base, kI2C_GlobalInterruptEnable);
+
+ /* Call the callback function after the function has completed. */
+ if (handle->completionCallback)
+ {
+ handle->completionCallback(base, handle, result, handle->userData);
+ }
+ }
+}
+
+void I2C_SlaveInit(I2C_Type *base, const i2c_slave_config_t *slaveConfig, uint32_t srcClock_Hz)
+{
+ assert(slaveConfig);
+
+ uint8_t tmpReg;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_EnableClock(s_i2cClocks[I2C_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Reset the module. */
+ base->A1 = 0;
+ base->F = 0;
+ base->C1 = 0;
+ base->S = 0xFFU;
+ base->C2 = 0;
+#if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT
+ base->FLT = 0x50U;
+#elif defined(FSL_FEATURE_I2C_HAS_STOP_DETECT) && FSL_FEATURE_I2C_HAS_STOP_DETECT
+ base->FLT = 0x40U;
+#endif
+ base->RA = 0;
+
+ /* Configure addressing mode. */
+ switch (slaveConfig->addressingMode)
+ {
+ case kI2C_Address7bit:
+ base->A1 = ((uint32_t)(slaveConfig->slaveAddress)) << 1U;
+ break;
+
+ case kI2C_RangeMatch:
+ assert(slaveConfig->slaveAddress < slaveConfig->upperAddress);
+ base->A1 = ((uint32_t)(slaveConfig->slaveAddress)) << 1U;
+ base->RA = ((uint32_t)(slaveConfig->upperAddress)) << 1U;
+ base->C2 |= I2C_C2_RMEN_MASK;
+ break;
+
+ default:
+ break;
+ }
+
+ /* Configure low power wake up feature. */
+ tmpReg = base->C1;
+ tmpReg &= ~I2C_C1_WUEN_MASK;
+ base->C1 = tmpReg | I2C_C1_WUEN(slaveConfig->enableWakeUp) | I2C_C1_IICEN(slaveConfig->enableSlave);
+
+ /* Configure general call & baud rate control. */
+ tmpReg = base->C2;
+ tmpReg &= ~(I2C_C2_SBRC_MASK | I2C_C2_GCAEN_MASK);
+ tmpReg |= I2C_C2_SBRC(slaveConfig->enableBaudRateCtl) | I2C_C2_GCAEN(slaveConfig->enableGeneralCall);
+ base->C2 = tmpReg;
+
+/* Enable/Disable double buffering. */
+#if defined(FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE) && FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE
+ tmpReg = base->S2 & (~I2C_S2_DFEN_MASK);
+ base->S2 = tmpReg | I2C_S2_DFEN(slaveConfig->enableDoubleBuffering);
+#endif
+
+ /* Set hold time. */
+ I2C_SetHoldTime(base, slaveConfig->sclStopHoldTime_ns, srcClock_Hz);
+}
+
+void I2C_SlaveDeinit(I2C_Type *base)
+{
+ /* Disable I2C module. */
+ I2C_Enable(base, false);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Disable I2C clock. */
+ CLOCK_DisableClock(s_i2cClocks[I2C_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+void I2C_SlaveGetDefaultConfig(i2c_slave_config_t *slaveConfig)
+{
+ assert(slaveConfig);
+
+ /* By default slave is addressed with 7-bit address. */
+ slaveConfig->addressingMode = kI2C_Address7bit;
+
+ /* General call mode is disabled by default. */
+ slaveConfig->enableGeneralCall = false;
+
+ /* Slave address match waking up MCU from low power mode is disabled. */
+ slaveConfig->enableWakeUp = false;
+
+ /* Independent slave mode baud rate at maximum frequency is disabled. */
+ slaveConfig->enableBaudRateCtl = false;
+
+/* Default enable double buffering. */
+#if defined(FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE) && FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE
+ slaveConfig->enableDoubleBuffering = true;
+#endif
+
+ /* Set default SCL stop hold time to 4us which is minimum requirement in I2C spec. */
+ slaveConfig->sclStopHoldTime_ns = 4000;
+
+ /* Enable the I2C peripheral. */
+ slaveConfig->enableSlave = true;
+}
+
+status_t I2C_SlaveWriteBlocking(I2C_Type *base, const uint8_t *txBuff, size_t txSize)
+{
+ status_t result = kStatus_Success;
+ volatile uint8_t dummy = 0;
+
+ /* Add this to avoid build warning. */
+ dummy++;
+
+#if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT
+ /* Check start flag. */
+ while (!(base->FLT & I2C_FLT_STARTF_MASK))
+ {
+ }
+ /* Clear STARTF flag. */
+ base->FLT |= I2C_FLT_STARTF_MASK;
+ /* Clear the IICIF flag. */
+ base->S = kI2C_IntPendingFlag;
+#endif /* FSL_FEATURE_I2C_HAS_START_STOP_DETECT */
+
+ /* Wait for address match flag. */
+ while (!(base->S & kI2C_AddressMatchFlag))
+ {
+ }
+
+ /* Read dummy to release bus. */
+ dummy = base->D;
+
+ result = I2C_MasterWriteBlocking(base, txBuff, txSize, kI2C_TransferDefaultFlag);
+
+ /* Switch to receive mode. */
+ base->C1 &= ~(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK);
+
+ /* Read dummy to release bus. */
+ dummy = base->D;
+
+ return result;
+}
+
+void I2C_SlaveReadBlocking(I2C_Type *base, uint8_t *rxBuff, size_t rxSize)
+{
+ volatile uint8_t dummy = 0;
+
+ /* Add this to avoid build warning. */
+ dummy++;
+
+/* Wait until address match. */
+#if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT
+ /* Check start flag. */
+ while (!(base->FLT & I2C_FLT_STARTF_MASK))
+ {
+ }
+ /* Clear STARTF flag. */
+ base->FLT |= I2C_FLT_STARTF_MASK;
+ /* Clear the IICIF flag. */
+ base->S = kI2C_IntPendingFlag;
+#endif /* FSL_FEATURE_I2C_HAS_START_STOP_DETECT */
+
+ /* Wait for address match and int pending flag. */
+ while (!(base->S & kI2C_AddressMatchFlag))
+ {
+ }
+ while (!(base->S & kI2C_IntPendingFlag))
+ {
+ }
+
+ /* Read dummy to release bus. */
+ dummy = base->D;
+
+ /* Clear the IICIF flag. */
+ base->S = kI2C_IntPendingFlag;
+
+ /* Setup the I2C peripheral to receive data. */
+ base->C1 &= ~(I2C_C1_TX_MASK);
+
+ while (rxSize--)
+ {
+ /* Wait until data transfer complete. */
+ while (!(base->S & kI2C_IntPendingFlag))
+ {
+ }
+ /* Clear the IICIF flag. */
+ base->S = kI2C_IntPendingFlag;
+
+ /* Read from the data register. */
+ *rxBuff++ = base->D;
+ }
+}
+
+void I2C_SlaveTransferCreateHandle(I2C_Type *base,
+ i2c_slave_handle_t *handle,
+ i2c_slave_transfer_callback_t callback,
+ void *userData)
+{
+ assert(handle);
+
+ uint32_t instance = I2C_GetInstance(base);
+
+ /* Zero handle. */
+ memset(handle, 0, sizeof(*handle));
+
+ /* Set callback and userData. */
+ handle->callback = callback;
+ handle->userData = userData;
+
+ /* Save the context in global variables to support the double weak mechanism. */
+ s_i2cHandle[instance] = handle;
+
+ /* Save slave interrupt handler. */
+ s_i2cSlaveIsr = I2C_SlaveTransferHandleIRQ;
+
+ /* Enable NVIC interrupt. */
+ EnableIRQ(s_i2cIrqs[instance]);
+}
+
+status_t I2C_SlaveTransferNonBlocking(I2C_Type *base, i2c_slave_handle_t *handle, uint32_t eventMask)
+{
+ assert(handle);
+
+ /* Check if the I2C bus is idle - if not return busy status. */
+ if (handle->isBusy)
+ {
+ return kStatus_I2C_Busy;
+ }
+ else
+ {
+ /* Disable LPI2C IRQ sources while we configure stuff. */
+ I2C_DisableInterrupts(base, kIrqFlags);
+
+ /* Clear transfer in handle. */
+ memset(&handle->transfer, 0, sizeof(handle->transfer));
+
+ /* Record that we're busy. */
+ handle->isBusy = true;
+
+ /* Set up event mask. tx and rx are always enabled. */
+ handle->eventMask = eventMask | kI2C_SlaveTransmitEvent | kI2C_SlaveReceiveEvent | kI2C_SlaveGenaralcallEvent;
+
+ /* Clear all flags. */
+ I2C_SlaveClearStatusFlags(base, kClearFlags);
+
+ /* Enable I2C internal IRQ sources. NVIC IRQ was enabled in CreateHandle() */
+ I2C_EnableInterrupts(base, kIrqFlags);
+ }
+
+ return kStatus_Success;
+}
+
+void I2C_SlaveTransferAbort(I2C_Type *base, i2c_slave_handle_t *handle)
+{
+ assert(handle);
+
+ if (handle->isBusy)
+ {
+ /* Disable interrupts. */
+ I2C_DisableInterrupts(base, kIrqFlags);
+
+ /* Reset transfer info. */
+ memset(&handle->transfer, 0, sizeof(handle->transfer));
+
+ /* Reset the state to idle. */
+ handle->isBusy = false;
+ }
+}
+
+status_t I2C_SlaveTransferGetCount(I2C_Type *base, i2c_slave_handle_t *handle, size_t *count)
+{
+ assert(handle);
+
+ if (!count)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Catch when there is not an active transfer. */
+ if (!handle->isBusy)
+ {
+ *count = 0;
+ return kStatus_NoTransferInProgress;
+ }
+
+ /* For an active transfer, just return the count from the handle. */
+ *count = handle->transfer.transferredCount;
+
+ return kStatus_Success;
+}
+
+void I2C_SlaveTransferHandleIRQ(I2C_Type *base, void *i2cHandle)
+{
+ assert(i2cHandle);
+
+ uint16_t status;
+ bool doTransmit = false;
+ i2c_slave_handle_t *handle = (i2c_slave_handle_t *)i2cHandle;
+ i2c_slave_transfer_t *xfer;
+ volatile uint8_t dummy = 0;
+
+ /* Add this to avoid build warning. */
+ dummy++;
+
+ status = I2C_SlaveGetStatusFlags(base);
+ xfer = &(handle->transfer);
+
+#ifdef I2C_HAS_STOP_DETECT
+ /* Check stop flag. */
+ if (status & kI2C_StopDetectFlag)
+ {
+ I2C_MasterClearStatusFlags(base, kI2C_StopDetectFlag);
+
+ /* Clear the interrupt flag. */
+ base->S = kI2C_IntPendingFlag;
+
+ /* Call slave callback if this is the STOP of the transfer. */
+ if (handle->isBusy)
+ {
+ xfer->event = kI2C_SlaveCompletionEvent;
+ xfer->completionStatus = kStatus_Success;
+ handle->isBusy = false;
+
+ if ((handle->eventMask & xfer->event) && (handle->callback))
+ {
+ handle->callback(base, xfer, handle->userData);
+ }
+ }
+
+ if (!(status & kI2C_AddressMatchFlag))
+ {
+ return;
+ }
+ }
+#endif /* I2C_HAS_STOP_DETECT */
+
+#if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT
+ /* Check start flag. */
+ if (status & kI2C_StartDetectFlag)
+ {
+ I2C_MasterClearStatusFlags(base, kI2C_StartDetectFlag);
+
+ /* Clear the interrupt flag. */
+ base->S = kI2C_IntPendingFlag;
+
+ xfer->event = kI2C_SlaveStartEvent;
+
+ if ((handle->eventMask & xfer->event) && (handle->callback))
+ {
+ handle->callback(base, xfer, handle->userData);
+ }
+
+ if (!(status & kI2C_AddressMatchFlag))
+ {
+ return;
+ }
+ }
+#endif /* FSL_FEATURE_I2C_HAS_START_STOP_DETECT */
+
+ /* Clear the interrupt flag. */
+ base->S = kI2C_IntPendingFlag;
+
+ /* Check NAK */
+ if (status & kI2C_ReceiveNakFlag)
+ {
+ /* Set receive mode. */
+ base->C1 &= ~(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK);
+
+ /* Read dummy. */
+ dummy = base->D;
+
+ if (handle->transfer.dataSize != 0)
+ {
+ xfer->event = kI2C_SlaveCompletionEvent;
+ xfer->completionStatus = kStatus_I2C_Nak;
+ handle->isBusy = false;
+
+ if ((handle->eventMask & xfer->event) && (handle->callback))
+ {
+ handle->callback(base, xfer, handle->userData);
+ }
+ }
+ else
+ {
+#ifndef I2C_HAS_STOP_DETECT
+ xfer->event = kI2C_SlaveCompletionEvent;
+ xfer->completionStatus = kStatus_Success;
+ handle->isBusy = false;
+
+ if ((handle->eventMask & xfer->event) && (handle->callback))
+ {
+ handle->callback(base, xfer, handle->userData);
+ }
+#endif /* !FSL_FEATURE_I2C_HAS_START_STOP_DETECT or !FSL_FEATURE_I2C_HAS_STOP_DETECT */
+ }
+ }
+ /* Check address match. */
+ else if (status & kI2C_AddressMatchFlag)
+ {
+ handle->isBusy = true;
+ xfer->event = kI2C_SlaveAddressMatchEvent;
+
+ /* Slave transmit, master reading from slave. */
+ if (status & kI2C_TransferDirectionFlag)
+ {
+ /* Change direction to send data. */
+ base->C1 |= I2C_C1_TX_MASK;
+
+ doTransmit = true;
+ }
+ else
+ {
+ /* Slave receive, master writing to slave. */
+ base->C1 &= ~(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK);
+
+ /* Read dummy to release the bus. */
+ dummy = base->D;
+
+ if (dummy == 0)
+ {
+ xfer->event = kI2C_SlaveGenaralcallEvent;
+ }
+ }
+
+ if ((handle->eventMask & xfer->event) && (handle->callback))
+ {
+ handle->callback(base, xfer, handle->userData);
+ }
+ }
+ /* Check transfer complete flag. */
+ else if (status & kI2C_TransferCompleteFlag)
+ {
+ /* Slave transmit, master reading from slave. */
+ if (status & kI2C_TransferDirectionFlag)
+ {
+ doTransmit = true;
+ }
+ else
+ {
+ /* If we're out of data, invoke callback to get more. */
+ if ((!xfer->data) || (!xfer->dataSize))
+ {
+ xfer->event = kI2C_SlaveReceiveEvent;
+
+ if (handle->callback)
+ {
+ handle->callback(base, xfer, handle->userData);
+ }
+
+ /* Clear the transferred count now that we have a new buffer. */
+ xfer->transferredCount = 0;
+ }
+
+ /* Slave receive, master writing to slave. */
+ uint8_t data = base->D;
+
+ if (handle->transfer.dataSize)
+ {
+ /* Receive data. */
+ *handle->transfer.data++ = data;
+ handle->transfer.dataSize--;
+ xfer->transferredCount++;
+ if (!handle->transfer.dataSize)
+ {
+#ifndef I2C_HAS_STOP_DETECT
+ xfer->event = kI2C_SlaveCompletionEvent;
+ xfer->completionStatus = kStatus_Success;
+ handle->isBusy = false;
+
+ /* Proceed receive complete event. */
+ if ((handle->eventMask & xfer->event) && (handle->callback))
+ {
+ handle->callback(base, xfer, handle->userData);
+ }
+#endif /* !FSL_FEATURE_I2C_HAS_START_STOP_DETECT or !FSL_FEATURE_I2C_HAS_STOP_DETECT */
+ }
+ }
+ }
+ }
+ else
+ {
+ /* Read dummy to release bus. */
+ dummy = base->D;
+ }
+
+ /* Send data if there is the need. */
+ if (doTransmit)
+ {
+ /* If we're out of data, invoke callback to get more. */
+ if ((!xfer->data) || (!xfer->dataSize))
+ {
+ xfer->event = kI2C_SlaveTransmitEvent;
+
+ if (handle->callback)
+ {
+ handle->callback(base, xfer, handle->userData);
+ }
+
+ /* Clear the transferred count now that we have a new buffer. */
+ xfer->transferredCount = 0;
+ }
+
+ if (handle->transfer.dataSize)
+ {
+ /* Send data. */
+ base->D = *handle->transfer.data++;
+ handle->transfer.dataSize--;
+ xfer->transferredCount++;
+ }
+ else
+ {
+ /* Switch to receive mode. */
+ base->C1 &= ~(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK);
+
+ /* Read dummy to release bus. */
+ dummy = base->D;
+
+#ifndef I2C_HAS_STOP_DETECT
+ xfer->event = kI2C_SlaveCompletionEvent;
+ xfer->completionStatus = kStatus_Success;
+ handle->isBusy = false;
+
+ /* Proceed txdone event. */
+ if ((handle->eventMask & xfer->event) && (handle->callback))
+ {
+ handle->callback(base, xfer, handle->userData);
+ }
+#endif /* !FSL_FEATURE_I2C_HAS_START_STOP_DETECT or !FSL_FEATURE_I2C_HAS_STOP_DETECT */
+ }
+ }
+}
+
+#if defined(I2C0)
+void I2C0_DriverIRQHandler(void)
+{
+ I2C_TransferCommonIRQHandler(I2C0, s_i2cHandle[0]);
+}
+#endif
+
+#if defined(I2C1)
+void I2C1_DriverIRQHandler(void)
+{
+ I2C_TransferCommonIRQHandler(I2C1, s_i2cHandle[1]);
+}
+#endif
+
+#if defined(I2C2)
+void I2C2_DriverIRQHandler(void)
+{
+ I2C_TransferCommonIRQHandler(I2C2, s_i2cHandle[2]);
+}
+#endif
+
+#if defined(I2C3)
+void I2C3_DriverIRQHandler(void)
+{
+ I2C_TransferCommonIRQHandler(I2C3, s_i2cHandle[3]);
+}
+#endif
diff --git a/drivers/src/fsl_i2c_edma.c b/drivers/src/fsl_i2c_edma.c
new file mode 100644
index 0000000..28a415e
--- /dev/null
+++ b/drivers/src/fsl_i2c_edma.c
@@ -0,0 +1,568 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsl_i2c_edma.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*<! @breif Structure definition for i2c_master_edma_private_handle_t. The structure is private. */
+typedef struct _i2c_master_edma_private_handle
+{
+ I2C_Type *base;
+ i2c_master_edma_handle_t *handle;
+} i2c_master_edma_private_handle_t;
+
+/*! @brief i2c master DMA transfer state. */
+enum _i2c_master_dma_transfer_states
+{
+ kIdleState = 0x0U, /*!< I2C bus idle. */
+ kTransferDataState = 0x1U, /*!< 7-bit address check state. */
+};
+
+/*! @brief Common sets of flags used by the driver. */
+enum _i2c_flag_constants
+{
+/*! All flags which are cleared by the driver upon starting a transfer. */
+#if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT
+ kClearFlags = kI2C_ArbitrationLostFlag | kI2C_IntPendingFlag | kI2C_StartDetectFlag | kI2C_StopDetectFlag,
+#elif defined(FSL_FEATURE_I2C_HAS_STOP_DETECT) && FSL_FEATURE_I2C_HAS_STOP_DETECT
+ kClearFlags = kI2C_ArbitrationLostFlag | kI2C_IntPendingFlag | kI2C_StopDetectFlag,
+#else
+ kClearFlags = kI2C_ArbitrationLostFlag | kI2C_IntPendingFlag,
+#endif
+};
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief EDMA callback for I2C master EDMA driver.
+ *
+ * @param handle EDMA handler for I2C master EDMA driver
+ * @param userData user param passed to the callback function
+ */
+static void I2C_MasterTransferCallbackEDMA(edma_handle_t *handle, void *userData, bool transferDone, uint32_t tcds);
+
+/*!
+ * @brief Check and clear status operation.
+ *
+ * @param base I2C peripheral base address.
+ * @param status current i2c hardware status.
+ * @retval kStatus_Success No error found.
+ * @retval kStatus_I2C_ArbitrationLost Transfer error, arbitration lost.
+ * @retval kStatus_I2C_Nak Received Nak error.
+ */
+static status_t I2C_CheckAndClearError(I2C_Type *base, uint32_t status);
+
+/*!
+ * @brief EDMA config for I2C master driver.
+ *
+ * @param base I2C peripheral base address.
+ * @param handle pointer to i2c_master_edma_handle_t structure which stores the transfer state
+ */
+static void I2C_MasterTransferEDMAConfig(I2C_Type *base, i2c_master_edma_handle_t *handle);
+
+/*!
+ * @brief Set up master transfer, send slave address and sub address(if any), wait until the
+ * wait until address sent status return.
+ *
+ * @param base I2C peripheral base address.
+ * @param handle pointer to i2c_master_edma_handle_t structure which stores the transfer state
+ * @param xfer pointer to i2c_master_transfer_t structure
+ */
+static status_t I2C_InitTransferStateMachineEDMA(I2C_Type *base,
+ i2c_master_edma_handle_t *handle,
+ i2c_master_transfer_t *xfer);
+
+/*!
+ * @brief Get the I2C instance from peripheral base address.
+ *
+ * @param base I2C peripheral base address.
+ * @return I2C instance.
+ */
+extern uint32_t I2C_GetInstance(I2C_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*<! Private handle only used for internally. */
+static i2c_master_edma_private_handle_t s_edmaPrivateHandle[FSL_FEATURE_SOC_I2C_COUNT];
+
+/*******************************************************************************
+ * Codes
+ ******************************************************************************/
+
+static void I2C_MasterTransferCallbackEDMA(edma_handle_t *handle, void *userData, bool transferDone, uint32_t tcds)
+{
+ i2c_master_edma_private_handle_t *i2cPrivateHandle = (i2c_master_edma_private_handle_t *)userData;
+ status_t result = kStatus_Success;
+
+ /* Disable DMA. */
+ I2C_EnableDMA(i2cPrivateHandle->base, false);
+
+ /* Send stop if kI2C_TransferNoStop flag is not asserted. */
+ if (!(i2cPrivateHandle->handle->transfer.flags & kI2C_TransferNoStopFlag))
+ {
+ if (i2cPrivateHandle->handle->transfer.direction == kI2C_Read)
+ {
+ /* Change to send NAK at the last byte. */
+ i2cPrivateHandle->base->C1 |= I2C_C1_TXAK_MASK;
+
+ /* Wait the last data to be received. */
+ while (!(i2cPrivateHandle->base->S & kI2C_TransferCompleteFlag))
+ {
+ }
+
+ /* Send stop signal. */
+ result = I2C_MasterStop(i2cPrivateHandle->base);
+
+ /* Read the last data byte. */
+ *(i2cPrivateHandle->handle->transfer.data + i2cPrivateHandle->handle->transfer.dataSize - 1) =
+ i2cPrivateHandle->base->D;
+ }
+ else
+ {
+ /* Wait the last data to be sent. */
+ while (!(i2cPrivateHandle->base->S & kI2C_TransferCompleteFlag))
+ {
+ }
+
+ /* Send stop signal. */
+ result = I2C_MasterStop(i2cPrivateHandle->base);
+ }
+ }
+ else
+ {
+ if (i2cPrivateHandle->handle->transfer.direction == kI2C_Read)
+ {
+ /* Change to send NAK at the last byte. */
+ i2cPrivateHandle->base->C1 |= I2C_C1_TXAK_MASK;
+
+ /* Wait the last data to be received. */
+ while (!(i2cPrivateHandle->base->S & kI2C_TransferCompleteFlag))
+ {
+ }
+
+ /* Change direction to send. */
+ i2cPrivateHandle->base->C1 |= I2C_C1_TX_MASK;
+
+ /* Read the last data byte. */
+ *(i2cPrivateHandle->handle->transfer.data + i2cPrivateHandle->handle->transfer.dataSize - 1) =
+ i2cPrivateHandle->base->D;
+ }
+ }
+
+ i2cPrivateHandle->handle->state = kIdleState;
+
+ if (i2cPrivateHandle->handle->completionCallback)
+ {
+ i2cPrivateHandle->handle->completionCallback(i2cPrivateHandle->base, i2cPrivateHandle->handle, result,
+ i2cPrivateHandle->handle->userData);
+ }
+}
+
+static status_t I2C_CheckAndClearError(I2C_Type *base, uint32_t status)
+{
+ status_t result = kStatus_Success;
+
+ /* Check arbitration lost. */
+ if (status & kI2C_ArbitrationLostFlag)
+ {
+ /* Clear arbitration lost flag. */
+ base->S = kI2C_ArbitrationLostFlag;
+ result = kStatus_I2C_ArbitrationLost;
+ }
+ /* Check NAK */
+ else if (status & kI2C_ReceiveNakFlag)
+ {
+ result = kStatus_I2C_Nak;
+ }
+ else
+ {
+ }
+
+ return result;
+}
+
+static status_t I2C_InitTransferStateMachineEDMA(I2C_Type *base,
+ i2c_master_edma_handle_t *handle,
+ i2c_master_transfer_t *xfer)
+{
+ assert(handle);
+ assert(xfer);
+
+ status_t result = kStatus_Success;
+
+ if (handle->state != kIdleState)
+ {
+ return kStatus_I2C_Busy;
+ }
+ else
+ {
+ i2c_direction_t direction = xfer->direction;
+
+ /* Init the handle member. */
+ handle->transfer = *xfer;
+
+ /* Save total transfer size. */
+ handle->transferSize = xfer->dataSize;
+
+ handle->state = kTransferDataState;
+
+ /* Clear all status before transfer. */
+ I2C_MasterClearStatusFlags(base, kClearFlags);
+
+ /* Change to send write address when it's a read operation with command. */
+ if ((xfer->subaddressSize > 0) && (xfer->direction == kI2C_Read))
+ {
+ direction = kI2C_Write;
+ }
+
+ /* If repeated start is requested, send repeated start. */
+ if (handle->transfer.flags & kI2C_TransferRepeatedStartFlag)
+ {
+ result = I2C_MasterRepeatedStart(base, handle->transfer.slaveAddress, direction);
+ }
+ else /* For normal transfer, send start. */
+ {
+ result = I2C_MasterStart(base, handle->transfer.slaveAddress, direction);
+ }
+
+ if (result)
+ {
+ return result;
+ }
+
+ while (!(base->S & kI2C_IntPendingFlag))
+ {
+ }
+
+ /* Check if there's transfer error. */
+ result = I2C_CheckAndClearError(base, base->S);
+
+ /* Return if error. */
+ if (result)
+ {
+ if (result == kStatus_I2C_Nak)
+ {
+ result = kStatus_I2C_Addr_Nak;
+
+ if (I2C_MasterStop(base) != kStatus_Success)
+ {
+ result = kStatus_I2C_Timeout;
+ }
+
+ if (handle->completionCallback)
+ {
+ (handle->completionCallback)(base, handle, result, handle->userData);
+ }
+ }
+
+ return result;
+ }
+
+ /* Send subaddress. */
+ if (handle->transfer.subaddressSize)
+ {
+ do
+ {
+ /* Clear interrupt pending flag. */
+ base->S = kI2C_IntPendingFlag;
+
+ handle->transfer.subaddressSize--;
+ base->D = ((handle->transfer.subaddress) >> (8 * handle->transfer.subaddressSize));
+
+ /* Wait until data transfer complete. */
+ while (!(base->S & kI2C_IntPendingFlag))
+ {
+ }
+
+ /* Check if there's transfer error. */
+ result = I2C_CheckAndClearError(base, base->S);
+
+ if (result)
+ {
+ return result;
+ }
+
+ } while ((handle->transfer.subaddressSize > 0) && (result == kStatus_Success));
+
+ if (handle->transfer.direction == kI2C_Read)
+ {
+ /* Clear pending flag. */
+ base->S = kI2C_IntPendingFlag;
+
+ /* Send repeated start and slave address. */
+ result = I2C_MasterRepeatedStart(base, handle->transfer.slaveAddress, kI2C_Read);
+
+ if (result)
+ {
+ return result;
+ }
+
+ /* Wait until data transfer complete. */
+ while (!(base->S & kI2C_IntPendingFlag))
+ {
+ }
+
+ /* Check if there's transfer error. */
+ result = I2C_CheckAndClearError(base, base->S);
+
+ if (result)
+ {
+ return result;
+ }
+ }
+ }
+
+ /* Clear pending flag. */
+ base->S = kI2C_IntPendingFlag;
+ }
+
+ return result;
+}
+
+static void I2C_MasterTransferEDMAConfig(I2C_Type *base, i2c_master_edma_handle_t *handle)
+{
+ edma_transfer_config_t transfer_config;
+
+ if (handle->transfer.direction == kI2C_Read)
+ {
+ transfer_config.srcAddr = (uint32_t)I2C_GetDataRegAddr(base);
+ transfer_config.destAddr = (uint32_t)(handle->transfer.data);
+ transfer_config.majorLoopCounts = (handle->transfer.dataSize - 1);
+ transfer_config.srcTransferSize = kEDMA_TransferSize1Bytes;
+ transfer_config.srcOffset = 0;
+ transfer_config.destTransferSize = kEDMA_TransferSize1Bytes;
+ transfer_config.destOffset = 1;
+ transfer_config.minorLoopBytes = 1;
+ }
+ else
+ {
+ transfer_config.srcAddr = (uint32_t)(handle->transfer.data + 1);
+ transfer_config.destAddr = (uint32_t)I2C_GetDataRegAddr(base);
+ transfer_config.majorLoopCounts = (handle->transfer.dataSize - 1);
+ transfer_config.srcTransferSize = kEDMA_TransferSize1Bytes;
+ transfer_config.srcOffset = 1;
+ transfer_config.destTransferSize = kEDMA_TransferSize1Bytes;
+ transfer_config.destOffset = 0;
+ transfer_config.minorLoopBytes = 1;
+ }
+
+ /* Store the initially configured eDMA minor byte transfer count into the I2C handle */
+ handle->nbytes = transfer_config.minorLoopBytes;
+
+ EDMA_SubmitTransfer(handle->dmaHandle, &transfer_config);
+ EDMA_StartTransfer(handle->dmaHandle);
+}
+
+void I2C_MasterCreateEDMAHandle(I2C_Type *base,
+ i2c_master_edma_handle_t *handle,
+ i2c_master_edma_transfer_callback_t callback,
+ void *userData,
+ edma_handle_t *edmaHandle)
+{
+ assert(handle);
+ assert(edmaHandle);
+
+ uint32_t instance = I2C_GetInstance(base);
+
+ /* Zero handle. */
+ memset(handle, 0, sizeof(*handle));
+
+ /* Set the user callback and userData. */
+ handle->completionCallback = callback;
+ handle->userData = userData;
+
+ /* Set the base for the handle. */
+ base = base;
+
+ /* Set the handle for EDMA. */
+ handle->dmaHandle = edmaHandle;
+
+ s_edmaPrivateHandle[instance].base = base;
+ s_edmaPrivateHandle[instance].handle = handle;
+
+ EDMA_SetCallback(edmaHandle, (edma_callback)I2C_MasterTransferCallbackEDMA, &s_edmaPrivateHandle[instance]);
+}
+
+status_t I2C_MasterTransferEDMA(I2C_Type *base, i2c_master_edma_handle_t *handle, i2c_master_transfer_t *xfer)
+{
+ assert(handle);
+ assert(xfer);
+
+ status_t result;
+ uint8_t tmpReg;
+ volatile uint8_t dummy = 0;
+
+ /* Add this to avoid build warning. */
+ dummy++;
+
+ /* Disable dma xfer. */
+ I2C_EnableDMA(base, false);
+
+ /* Send address and command buffer(if there is), until senddata phase or receive data phase. */
+ result = I2C_InitTransferStateMachineEDMA(base, handle, xfer);
+
+ if (result)
+ {
+ /* Send stop if received Nak. */
+ if (result == kStatus_I2C_Nak)
+ {
+ if (I2C_MasterStop(base) != kStatus_Success)
+ {
+ result = kStatus_I2C_Timeout;
+ }
+ }
+
+ /* Reset the state to idle state. */
+ handle->state = kIdleState;
+
+ return result;
+ }
+
+ /* Configure dma transfer. */
+ /* For i2c send, need to send 1 byte first to trigger the dma, for i2c read,
+ need to send stop before reading the last byte, so the dma transfer size should
+ be (xSize - 1). */
+ if (handle->transfer.dataSize > 1)
+ {
+ I2C_MasterTransferEDMAConfig(base, handle);
+ if (handle->transfer.direction == kI2C_Read)
+ {
+ /* Change direction for receive. */
+ base->C1 &= ~(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK);
+
+ /* Read dummy to release the bus. */
+ dummy = base->D;
+
+ /* Enabe dma transfer. */
+ I2C_EnableDMA(base, true);
+ }
+ else
+ {
+ /* Enabe dma transfer. */
+ I2C_EnableDMA(base, true);
+
+ /* Send the first data. */
+ base->D = *handle->transfer.data;
+ }
+ }
+ else /* If transfer size is 1, use polling method. */
+ {
+ if (handle->transfer.direction == kI2C_Read)
+ {
+ tmpReg = base->C1;
+
+ /* Change direction to Rx. */
+ tmpReg &= ~I2C_C1_TX_MASK;
+
+ /* Configure send NAK */
+ tmpReg |= I2C_C1_TXAK_MASK;
+
+ base->C1 = tmpReg;
+
+ /* Read dummy to release the bus. */
+ dummy = base->D;
+ }
+ else
+ {
+ base->D = *handle->transfer.data;
+ }
+
+ /* Wait until data transfer complete. */
+ while (!(base->S & kI2C_IntPendingFlag))
+ {
+ }
+
+ /* Clear pending flag. */
+ base->S = kI2C_IntPendingFlag;
+
+ /* Send stop if kI2C_TransferNoStop flag is not asserted. */
+ if (!(handle->transfer.flags & kI2C_TransferNoStopFlag))
+ {
+ result = I2C_MasterStop(base);
+ }
+ else
+ {
+ /* Change direction to send. */
+ base->C1 |= I2C_C1_TX_MASK;
+ }
+
+ /* Read the last byte of data. */
+ if (handle->transfer.direction == kI2C_Read)
+ {
+ *handle->transfer.data = base->D;
+ }
+
+ /* Reset the state to idle. */
+ handle->state = kIdleState;
+ }
+
+ return result;
+}
+
+status_t I2C_MasterTransferGetCountEDMA(I2C_Type *base, i2c_master_edma_handle_t *handle, size_t *count)
+{
+ assert(handle->dmaHandle);
+
+ if (!count)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ if (kIdleState != handle->state)
+ {
+ *count = (handle->transferSize -
+ (uint32_t)handle->nbytes *
+ EDMA_GetRemainingMajorLoopCount(handle->dmaHandle->base, handle->dmaHandle->channel));
+ }
+ else
+ {
+ *count = handle->transferSize;
+ }
+
+ return kStatus_Success;
+}
+
+void I2C_MasterTransferAbortEDMA(I2C_Type *base, i2c_master_edma_handle_t *handle)
+{
+ EDMA_AbortTransfer(handle->dmaHandle);
+
+ /* Disable dma transfer. */
+ I2C_EnableDMA(base, false);
+
+ /* Reset the state to idle. */
+ handle->state = kIdleState;
+}
diff --git a/drivers/src/fsl_i2c_freertos.c b/drivers/src/fsl_i2c_freertos.c
new file mode 100644
index 0000000..e622fbe
--- /dev/null
+++ b/drivers/src/fsl_i2c_freertos.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsl_i2c_freertos.h"
+
+static void I2C_RTOS_Callback(I2C_Type *base, i2c_master_handle_t *drv_handle, status_t status, void *userData)
+{
+ i2c_rtos_handle_t *handle = (i2c_rtos_handle_t *)userData;
+ BaseType_t reschedule;
+ handle->async_status = status;
+ xSemaphoreGiveFromISR(handle->semaphore, &reschedule);
+ portYIELD_FROM_ISR(reschedule);
+}
+
+status_t I2C_RTOS_Init(i2c_rtos_handle_t *handle,
+ I2C_Type *base,
+ const i2c_master_config_t *masterConfig,
+ uint32_t srcClock_Hz)
+{
+ if (handle == NULL)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ if (base == NULL)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ memset(handle, 0, sizeof(i2c_rtos_handle_t));
+#if (configSUPPORT_STATIC_ALLOCATION == 1)
+ handle->mutex = xSemaphoreCreateMutexStatic(&handle->mutexBuffer);
+#else
+ handle->mutex = xSemaphoreCreateMutex();
+#endif
+ if (handle->mutex == NULL)
+ {
+ return kStatus_Fail;
+ }
+#if (configSUPPORT_STATIC_ALLOCATION == 1)
+ handle->semaphore = xSemaphoreCreateBinaryStatic(&handle->semaphoreBuffer);
+#else
+ handle->semaphore = xSemaphoreCreateBinary();
+#endif
+ if (handle->semaphore == NULL)
+ {
+ vSemaphoreDelete(handle->mutex);
+ return kStatus_Fail;
+ }
+
+ handle->base = base;
+
+ I2C_MasterInit(handle->base, masterConfig, srcClock_Hz);
+ I2C_MasterTransferCreateHandle(base, &handle->drv_handle, I2C_RTOS_Callback, (void *)handle);
+
+ return kStatus_Success;
+}
+
+status_t I2C_RTOS_Deinit(i2c_rtos_handle_t *handle)
+{
+ I2C_MasterDeinit(handle->base);
+
+ vSemaphoreDelete(handle->semaphore);
+ vSemaphoreDelete(handle->mutex);
+
+ return kStatus_Success;
+}
+
+status_t I2C_RTOS_Transfer(i2c_rtos_handle_t *handle, i2c_master_transfer_t *transfer)
+{
+ status_t status;
+
+ /* Lock resource mutex */
+ if (xSemaphoreTake(handle->mutex, portMAX_DELAY) != pdTRUE)
+ {
+ return kStatus_I2C_Busy;
+ }
+
+ status = I2C_MasterTransferNonBlocking(handle->base, &handle->drv_handle, transfer);
+ if (status != kStatus_Success)
+ {
+ xSemaphoreGive(handle->mutex);
+ return status;
+ }
+
+ /* Wait for transfer to finish */
+ xSemaphoreTake(handle->semaphore, portMAX_DELAY);
+
+ /* Unlock resource mutex */
+ xSemaphoreGive(handle->mutex);
+
+ /* Return status captured by callback function */
+ return handle->async_status;
+}
diff --git a/drivers/src/fsl_llwu.c b/drivers/src/fsl_llwu.c
new file mode 100644
index 0000000..74b1001
--- /dev/null
+++ b/drivers/src/fsl_llwu.c
@@ -0,0 +1,404 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsl_llwu.h"
+
+#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN)
+void LLWU_SetExternalWakeupPinMode(LLWU_Type *base, uint32_t pinIndex, llwu_external_pin_mode_t pinMode)
+{
+#if (defined(FSL_FEATURE_LLWU_REG_BITWIDTH) && (FSL_FEATURE_LLWU_REG_BITWIDTH == 32))
+ volatile uint32_t *regBase;
+ uint32_t regOffset;
+ uint32_t reg;
+
+ switch (pinIndex >> 4U)
+ {
+ case 0U:
+ regBase = &base->PE1;
+ break;
+#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 16))
+ case 1U:
+ regBase = &base->PE2;
+ break;
+#endif
+ default:
+ regBase = NULL;
+ break;
+ }
+#else
+ volatile uint8_t *regBase;
+ uint8_t regOffset;
+ uint8_t reg;
+ switch (pinIndex >> 2U)
+ {
+ case 0U:
+ regBase = &base->PE1;
+ break;
+ case 1U:
+ regBase = &base->PE2;
+ break;
+#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 8))
+ case 2U:
+ regBase = &base->PE3;
+ break;
+#endif
+#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 12))
+ case 3U:
+ regBase = &base->PE4;
+ break;
+#endif
+#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 16))
+ case 4U:
+ regBase = &base->PE5;
+ break;
+#endif
+#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 20))
+ case 5U:
+ regBase = &base->PE6;
+ break;
+#endif
+#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 24))
+ case 6U:
+ regBase = &base->PE7;
+ break;
+#endif
+#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 28))
+ case 7U:
+ regBase = &base->PE8;
+ break;
+#endif
+ default:
+ regBase = NULL;
+ break;
+ }
+#endif /* FSL_FEATURE_LLWU_REG_BITWIDTH == 32 */
+
+ if (regBase)
+ {
+ reg = *regBase;
+#if (defined(FSL_FEATURE_LLWU_REG_BITWIDTH) && (FSL_FEATURE_LLWU_REG_BITWIDTH == 32))
+ regOffset = ((pinIndex & 0x0FU) << 1U);
+#else
+ regOffset = ((pinIndex & 0x03U) << 1U);
+#endif
+ reg &= ~(0x3U << regOffset);
+ reg |= ((uint32_t)pinMode << regOffset);
+ *regBase = reg;
+ }
+}
+
+bool LLWU_GetExternalWakeupPinFlag(LLWU_Type *base, uint32_t pinIndex)
+{
+#if (defined(FSL_FEATURE_LLWU_REG_BITWIDTH) && (FSL_FEATURE_LLWU_REG_BITWIDTH == 32))
+ return (bool)(base->PF & (1U << pinIndex));
+#else
+ volatile uint8_t *regBase;
+
+ switch (pinIndex >> 3U)
+ {
+#if (defined(FSL_FEATURE_LLWU_HAS_PF) && FSL_FEATURE_LLWU_HAS_PF)
+ case 0U:
+ regBase = &base->PF1;
+ break;
+#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 8))
+ case 1U:
+ regBase = &base->PF2;
+ break;
+#endif /* FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN */
+#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 16))
+ case 2U:
+ regBase = &base->PF3;
+ break;
+#endif /* FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN */
+#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 24))
+ case 3U:
+ regBase = &base->PF4;
+ break;
+#endif /* FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN */
+#else
+ case 0U:
+ regBase = &base->F1;
+ break;
+#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 8))
+ case 1U:
+ regBase = &base->F2;
+ break;
+#endif /* FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN */
+#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 16))
+ case 2U:
+ regBase = &base->F3;
+ break;
+#endif /* FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN */
+#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 24))
+ case 3U:
+ regBase = &base->F4;
+ break;
+#endif /* FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN */
+#endif /* FSL_FEATURE_LLWU_HAS_PF */
+ default:
+ regBase = NULL;
+ break;
+ }
+
+ if (regBase)
+ {
+ return (bool)(*regBase & (1U << pinIndex % 8));
+ }
+ else
+ {
+ return false;
+ }
+#endif /* FSL_FEATURE_LLWU_REG_BITWIDTH */
+}
+
+void LLWU_ClearExternalWakeupPinFlag(LLWU_Type *base, uint32_t pinIndex)
+{
+#if (defined(FSL_FEATURE_LLWU_REG_BITWIDTH) && (FSL_FEATURE_LLWU_REG_BITWIDTH == 32))
+ base->PF = (1U << pinIndex);
+#else
+ volatile uint8_t *regBase;
+ switch (pinIndex >> 3U)
+ {
+#if (defined(FSL_FEATURE_LLWU_HAS_PF) && FSL_FEATURE_LLWU_HAS_PF)
+ case 0U:
+ regBase = &base->PF1;
+ break;
+#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 8))
+ case 1U:
+ regBase = &base->PF2;
+ break;
+#endif /* FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN */
+#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 16))
+ case 2U:
+ regBase = &base->PF3;
+ break;
+#endif /* FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN */
+#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 24))
+ case 3U:
+ regBase = &base->PF4;
+ break;
+#endif /* FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN */
+#else
+ case 0U:
+ regBase = &base->F1;
+ break;
+#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 8))
+ case 1U:
+ regBase = &base->F2;
+ break;
+#endif /* FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN */
+#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 16))
+ case 2U:
+ regBase = &base->F3;
+ break;
+#endif /* FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN */
+#if (defined(FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN) && (FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN > 24))
+ case 3U:
+ regBase = &base->F4;
+ break;
+#endif /* FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN */
+#endif /* FSL_FEATURE_LLWU_HAS_PF */
+ default:
+ regBase = NULL;
+ break;
+ }
+ if (regBase)
+ {
+ *regBase = (1U << pinIndex % 8U);
+ }
+#endif /* FSL_FEATURE_LLWU_REG_BITWIDTH */
+}
+#endif /* FSL_FEATURE_LLWU_HAS_EXTERNAL_PIN */
+
+#if (defined(FSL_FEATURE_LLWU_HAS_PIN_FILTER) && FSL_FEATURE_LLWU_HAS_PIN_FILTER)
+void LLWU_SetPinFilterMode(LLWU_Type *base, uint32_t filterIndex, llwu_external_pin_filter_mode_t filterMode)
+{
+#if (defined(FSL_FEATURE_LLWU_REG_BITWIDTH) && (FSL_FEATURE_LLWU_REG_BITWIDTH == 32))
+ uint32_t reg;
+
+ reg = base->FILT;
+ reg &= ~((LLWU_FILT_FILTSEL1_MASK | LLWU_FILT_FILTE1_MASK) << (filterIndex * 8U - 1U));
+ reg |= (((filterMode.pinIndex << LLWU_FILT_FILTSEL1_SHIFT) | (filterMode.filterMode << LLWU_FILT_FILTE1_SHIFT)
+ /* Clear the Filter Detect Flag */
+ | LLWU_FILT_FILTF1_MASK)
+ << (filterIndex * 8U - 1U));
+ base->FILT = reg;
+#else
+ volatile uint8_t *regBase;
+ uint8_t reg;
+
+ switch (filterIndex)
+ {
+ case 1:
+ regBase = &base->FILT1;
+ break;
+#if (defined(FSL_FEATURE_LLWU_HAS_PIN_FILTER) && (FSL_FEATURE_LLWU_HAS_PIN_FILTER > 1))
+ case 2:
+ regBase = &base->FILT2;
+ break;
+#endif /* FSL_FEATURE_LLWU_HAS_PIN_FILTER */
+#if (defined(FSL_FEATURE_LLWU_HAS_PIN_FILTER) && (FSL_FEATURE_LLWU_HAS_PIN_FILTER > 2))
+ case 3:
+ regBase = &base->FILT3;
+ break;
+#endif /* FSL_FEATURE_LLWU_HAS_PIN_FILTER */
+#if (defined(FSL_FEATURE_LLWU_HAS_PIN_FILTER) && (FSL_FEATURE_LLWU_HAS_PIN_FILTER > 3))
+ case 4:
+ regBase = &base->FILT4;
+ break;
+#endif /* FSL_FEATURE_LLWU_HAS_PIN_FILTER */
+ default:
+ regBase = NULL;
+ break;
+ }
+
+ if (regBase)
+ {
+ reg = *regBase;
+ reg &= ~(LLWU_FILT1_FILTSEL_MASK | LLWU_FILT1_FILTE_MASK);
+ reg |= ((uint32_t)filterMode.pinIndex << LLWU_FILT1_FILTSEL_SHIFT);
+ reg |= ((uint32_t)filterMode.filterMode << LLWU_FILT1_FILTE_SHIFT);
+ /* Clear the Filter Detect Flag */
+ reg |= LLWU_FILT1_FILTF_MASK;
+ *regBase = reg;
+ }
+#endif /* FSL_FEATURE_LLWU_REG_BITWIDTH */
+}
+
+bool LLWU_GetPinFilterFlag(LLWU_Type *base, uint32_t filterIndex)
+{
+#if (defined(FSL_FEATURE_LLWU_REG_BITWIDTH) && (FSL_FEATURE_LLWU_REG_BITWIDTH == 32))
+ return (bool)(base->FILT & (1U << (filterIndex * 8U - 1)));
+#else
+ bool status = false;
+
+ switch (filterIndex)
+ {
+ case 1:
+ status = (base->FILT1 & LLWU_FILT1_FILTF_MASK);
+ break;
+#if (defined(FSL_FEATURE_LLWU_HAS_PIN_FILTER) && (FSL_FEATURE_LLWU_HAS_PIN_FILTER > 1))
+ case 2:
+ status = (base->FILT2 & LLWU_FILT2_FILTF_MASK);
+ break;
+#endif /* FSL_FEATURE_LLWU_HAS_PIN_FILTER */
+#if (defined(FSL_FEATURE_LLWU_HAS_PIN_FILTER) && (FSL_FEATURE_LLWU_HAS_PIN_FILTER > 2))
+ case 3:
+ status = (base->FILT3 & LLWU_FILT3_FILTF_MASK);
+ break;
+#endif /* FSL_FEATURE_LLWU_HAS_PIN_FILTER */
+#if (defined(FSL_FEATURE_LLWU_HAS_PIN_FILTER) && (FSL_FEATURE_LLWU_HAS_PIN_FILTER > 3))
+ case 4:
+ status = (base->FILT4 & LLWU_FILT4_FILTF_MASK);
+ break;
+#endif /* FSL_FEATURE_LLWU_HAS_PIN_FILTER */
+ default:
+ break;
+ }
+
+ return status;
+#endif /* FSL_FEATURE_LLWU_REG_BITWIDTH */
+}
+
+void LLWU_ClearPinFilterFlag(LLWU_Type *base, uint32_t filterIndex)
+{
+#if (defined(FSL_FEATURE_LLWU_REG_BITWIDTH) && (FSL_FEATURE_LLWU_REG_BITWIDTH == 32))
+ uint32_t reg;
+
+ reg = base->FILT;
+ switch (filterIndex)
+ {
+ case 1:
+ reg |= LLWU_FILT_FILTF1_MASK;
+ break;
+ case 2:
+ reg |= LLWU_FILT_FILTF2_MASK;
+ break;
+ case 3:
+ reg |= LLWU_FILT_FILTF3_MASK;
+ break;
+ case 4:
+ reg |= LLWU_FILT_FILTF4_MASK;
+ break;
+ default:
+ break;
+ }
+ base->FILT = reg;
+#else
+ volatile uint8_t *regBase;
+ uint8_t reg;
+
+ switch (filterIndex)
+ {
+ case 1:
+ regBase = &base->FILT1;
+ break;
+#if (defined(FSL_FEATURE_LLWU_HAS_PIN_FILTER) && (FSL_FEATURE_LLWU_HAS_PIN_FILTER > 1))
+ case 2:
+ regBase = &base->FILT2;
+ break;
+#endif /* FSL_FEATURE_LLWU_HAS_PIN_FILTER */
+#if (defined(FSL_FEATURE_LLWU_HAS_PIN_FILTER) && (FSL_FEATURE_LLWU_HAS_PIN_FILTER > 2))
+ case 3:
+ regBase = &base->FILT3;
+ break;
+#endif /* FSL_FEATURE_LLWU_HAS_PIN_FILTER */
+#if (defined(FSL_FEATURE_LLWU_HAS_PIN_FILTER) && (FSL_FEATURE_LLWU_HAS_PIN_FILTER > 3))
+ case 4:
+ regBase = &base->FILT4;
+ break;
+#endif /* FSL_FEATURE_LLWU_HAS_PIN_FILTER */
+ default:
+ regBase = NULL;
+ break;
+ }
+
+ if (regBase)
+ {
+ reg = *regBase;
+ reg |= LLWU_FILT1_FILTF_MASK;
+ *regBase = reg;
+ }
+#endif /* FSL_FEATURE_LLWU_REG_BITWIDTH */
+}
+#endif /* FSL_FEATURE_LLWU_HAS_PIN_FILTER */
+
+#if (defined(FSL_FEATURE_LLWU_HAS_RESET_ENABLE) && FSL_FEATURE_LLWU_HAS_RESET_ENABLE)
+void LLWU_SetResetPinMode(LLWU_Type *base, bool pinEnable, bool enableInLowLeakageMode)
+{
+ uint8_t reg;
+
+ reg = base->RST;
+ reg &= ~(LLWU_RST_LLRSTE_MASK | LLWU_RST_RSTFILT_MASK);
+ reg |=
+ (((uint32_t)pinEnable << LLWU_RST_LLRSTE_SHIFT) | ((uint32_t)enableInLowLeakageMode << LLWU_RST_RSTFILT_SHIFT));
+ base->RST = reg;
+}
+#endif /* FSL_FEATURE_LLWU_HAS_RESET_ENABLE */
diff --git a/drivers/src/fsl_lptmr.c b/drivers/src/fsl_lptmr.c
new file mode 100644
index 0000000..67b3b97
--- /dev/null
+++ b/drivers/src/fsl_lptmr.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsl_lptmr.h"
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Gets the instance from the base address to be used to gate or ungate the module clock
+ *
+ * @param base LPTMR peripheral base address
+ *
+ * @return The LPTMR instance
+ */
+static uint32_t LPTMR_GetInstance(LPTMR_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to LPTMR bases for each instance. */
+static LPTMR_Type *const s_lptmrBases[] = LPTMR_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to LPTMR clocks for each instance. */
+static const clock_ip_name_t s_lptmrClocks[] = LPTMR_CLOCKS;
+
+#if defined(LPTMR_PERIPH_CLOCKS)
+/* Array of LPTMR functional clock name. */
+static const clock_ip_name_t s_lptmrPeriphClocks[] = LPTMR_PERIPH_CLOCKS;
+#endif
+
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t LPTMR_GetInstance(LPTMR_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_lptmrBases); instance++)
+ {
+ if (s_lptmrBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_lptmrBases));
+
+ return instance;
+}
+
+void LPTMR_Init(LPTMR_Type *base, const lptmr_config_t *config)
+{
+ assert(config);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+
+ uint32_t instance = LPTMR_GetInstance(base);
+
+ /* Ungate the LPTMR clock*/
+ CLOCK_EnableClock(s_lptmrClocks[instance]);
+#if defined(LPTMR_PERIPH_CLOCKS)
+ CLOCK_EnableClock(s_lptmrPeriphClocks[instance]);
+#endif
+
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Configure the timers operation mode and input pin setup */
+ base->CSR = (LPTMR_CSR_TMS(config->timerMode) | LPTMR_CSR_TFC(config->enableFreeRunning) |
+ LPTMR_CSR_TPP(config->pinPolarity) | LPTMR_CSR_TPS(config->pinSelect));
+
+ /* Configure the prescale value and clock source */
+ base->PSR = (LPTMR_PSR_PRESCALE(config->value) | LPTMR_PSR_PBYP(config->bypassPrescaler) |
+ LPTMR_PSR_PCS(config->prescalerClockSource));
+}
+
+void LPTMR_Deinit(LPTMR_Type *base)
+{
+ /* Disable the LPTMR and reset the internal logic */
+ base->CSR &= ~LPTMR_CSR_TEN_MASK;
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+
+ uint32_t instance = LPTMR_GetInstance(base);
+
+ /* Gate the LPTMR clock*/
+ CLOCK_DisableClock(s_lptmrClocks[instance]);
+#if defined(LPTMR_PERIPH_CLOCKS)
+ CLOCK_DisableClock(s_lptmrPeriphClocks[instance]);
+#endif
+
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+void LPTMR_GetDefaultConfig(lptmr_config_t *config)
+{
+ assert(config);
+
+ /* Use time counter mode */
+ config->timerMode = kLPTMR_TimerModeTimeCounter;
+ /* Use input 0 as source in pulse counter mode */
+ config->pinSelect = kLPTMR_PinSelectInput_0;
+ /* Pulse input pin polarity is active-high */
+ config->pinPolarity = kLPTMR_PinPolarityActiveHigh;
+ /* Counter resets whenever TCF flag is set */
+ config->enableFreeRunning = false;
+ /* Bypass the prescaler */
+ config->bypassPrescaler = true;
+ /* LPTMR clock source */
+ config->prescalerClockSource = kLPTMR_PrescalerClock_1;
+ /* Divide the prescaler clock by 2 */
+ config->value = kLPTMR_Prescale_Glitch_0;
+}
diff --git a/drivers/src/fsl_mpu.c b/drivers/src/fsl_mpu.c
new file mode 100644
index 0000000..8e0e77d
--- /dev/null
+++ b/drivers/src/fsl_mpu.c
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of Freescale Semiconductor, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsl_mpu.h"
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+const clock_ip_name_t g_mpuClock[FSL_FEATURE_SOC_MPU_COUNT] = MPU_CLOCKS;
+
+/*******************************************************************************
+ * Codes
+ ******************************************************************************/
+
+void MPU_Init(MPU_Type *base, const mpu_config_t *config)
+{
+ assert(config);
+ uint8_t count;
+
+ /* Un-gate MPU clock */
+ CLOCK_EnableClock(g_mpuClock[0]);
+
+ /* Initializes the regions. */
+ for (count = 1; count < FSL_FEATURE_MPU_DESCRIPTOR_COUNT; count++)
+ {
+ base->WORD[count][3] = 0; /* VLD/VID+PID. */
+ base->WORD[count][0] = 0; /* Start address. */
+ base->WORD[count][1] = 0; /* End address. */
+ base->WORD[count][2] = 0; /* Access rights. */
+ base->RGDAAC[count] = 0; /* Alternate access rights. */
+ }
+
+ /* MPU configure. */
+ while (config)
+ {
+ MPU_SetRegionConfig(base, &(config->regionConfig));
+ config = config->next;
+ }
+ /* Enable MPU. */
+ MPU_Enable(base, true);
+}
+
+void MPU_Deinit(MPU_Type *base)
+{
+ /* Disable MPU. */
+ MPU_Enable(base, false);
+
+ /* Gate the clock. */
+ CLOCK_DisableClock(g_mpuClock[0]);
+}
+
+void MPU_GetHardwareInfo(MPU_Type *base, mpu_hardware_info_t *hardwareInform)
+{
+ assert(hardwareInform);
+
+ uint32_t cesReg = base->CESR;
+
+ hardwareInform->hardwareRevisionLevel = (cesReg & MPU_CESR_HRL_MASK) >> MPU_CESR_HRL_SHIFT;
+ hardwareInform->slavePortsNumbers = (cesReg & MPU_CESR_NSP_MASK) >> MPU_CESR_NSP_SHIFT;
+ hardwareInform->regionsNumbers = (mpu_region_total_num_t)((cesReg & MPU_CESR_NRGD_MASK) >> MPU_CESR_NRGD_SHIFT);
+}
+
+void MPU_SetRegionConfig(MPU_Type *base, const mpu_region_config_t *regionConfig)
+{
+ assert(regionConfig);
+ assert(regionConfig->regionNum < FSL_FEATURE_MPU_DESCRIPTOR_COUNT);
+
+ uint32_t wordReg = 0;
+ uint8_t msPortNum;
+ uint8_t regNumber = regionConfig->regionNum;
+
+ /* The start and end address of the region descriptor. */
+ base->WORD[regNumber][0] = regionConfig->startAddress;
+ base->WORD[regNumber][1] = regionConfig->endAddress;
+
+ /* Set the privilege rights for master 0 ~ master 3. */
+ for (msPortNum = 0; msPortNum <= FSL_FEATURE_MPU_PRIVILEGED_RIGHTS_MASTER_MAX_INDEX; msPortNum++)
+ {
+ wordReg |= MPU_REGION_RWXRIGHTS_MASTER(
+ msPortNum, (((uint32_t)regionConfig->accessRights1[msPortNum].superAccessRights << 3U) |
+ (uint32_t)regionConfig->accessRights1[msPortNum].userAccessRights));
+
+#if FSL_FEATURE_MPU_HAS_PROCESS_IDENTIFIER
+ wordReg |=
+ MPU_REGION_RWXRIGHTS_MASTER_PE(msPortNum, regionConfig->accessRights1[msPortNum].processIdentifierEnable);
+#endif /* FSL_FEATURE_MPU_HAS_PROCESS_IDENTIFIER */
+ }
+
+ /* Set the normal read write rights for master 4 ~ master 7. */
+ for (msPortNum = FSL_FEATURE_MPU_PRIVILEGED_RIGHTS_MASTER_COUNT; msPortNum < FSL_FEATURE_MPU_MASTER_COUNT;
+ msPortNum++)
+ {
+ wordReg |= MPU_REGION_RWRIGHTS_MASTER(msPortNum,
+ ((uint32_t)regionConfig->accessRights2[msPortNum - FSL_FEATURE_MPU_PRIVILEGED_RIGHTS_MASTER_COUNT].readEnable << 1U |
+ (uint32_t)regionConfig->accessRights2[msPortNum - FSL_FEATURE_MPU_PRIVILEGED_RIGHTS_MASTER_COUNT].writeEnable));
+ }
+
+ /* Set region descriptor access rights. */
+ base->WORD[regNumber][2] = wordReg;
+
+ wordReg = MPU_WORD_VLD(1);
+#if FSL_FEATURE_MPU_HAS_PROCESS_IDENTIFIER
+ wordReg |= MPU_WORD_PID(regionConfig->processIdentifier) | MPU_WORD_PIDMASK(regionConfig->processIdMask);
+#endif /* FSL_FEATURE_MPU_HAS_PROCESS_IDENTIFIER */
+
+ base->WORD[regNumber][3] = wordReg;
+}
+
+void MPU_SetRegionAddr(MPU_Type *base, uint32_t regionNum, uint32_t startAddr, uint32_t endAddr)
+{
+ assert(regionNum < FSL_FEATURE_MPU_DESCRIPTOR_COUNT);
+
+ base->WORD[regionNum][0] = startAddr;
+ base->WORD[regionNum][1] = endAddr;
+}
+
+void MPU_SetRegionRwxMasterAccessRights(MPU_Type *base,
+ uint32_t regionNum,
+ uint32_t masterNum,
+ const mpu_rwxrights_master_access_control_t *accessRights)
+{
+ assert(accessRights);
+ assert(regionNum < FSL_FEATURE_MPU_DESCRIPTOR_COUNT);
+ assert(masterNum <= FSL_FEATURE_MPU_PRIVILEGED_RIGHTS_MASTER_MAX_INDEX);
+
+ uint32_t mask = MPU_REGION_RWXRIGHTS_MASTER_MASK(masterNum);
+ uint32_t right = base->RGDAAC[regionNum];
+
+#if FSL_FEATURE_MPU_HAS_PROCESS_IDENTIFIER
+ mask |= MPU_REGION_RWXRIGHTS_MASTER_PE_MASK(masterNum);
+#endif
+
+ /* Build rights control value. */
+ right &= ~mask;
+ right |= MPU_REGION_RWXRIGHTS_MASTER(
+ masterNum, ((uint32_t)(accessRights->superAccessRights << 3U) | accessRights->userAccessRights));
+#if FSL_FEATURE_MPU_HAS_PROCESS_IDENTIFIER
+ right |= MPU_REGION_RWXRIGHTS_MASTER_PE(masterNum, accessRights->processIdentifierEnable);
+#endif /* FSL_FEATURE_MPU_HAS_PROCESS_IDENTIFIER */
+
+ /* Set low master region access rights. */
+ base->RGDAAC[regionNum] = right;
+}
+
+void MPU_SetRegionRwMasterAccessRights(MPU_Type *base,
+ uint32_t regionNum,
+ uint32_t masterNum,
+ const mpu_rwrights_master_access_control_t *accessRights)
+{
+ assert(accessRights);
+ assert(regionNum < FSL_FEATURE_MPU_DESCRIPTOR_COUNT);
+ assert(masterNum > FSL_FEATURE_MPU_PRIVILEGED_RIGHTS_MASTER_MAX_INDEX);
+ assert(masterNum <= FSL_FEATURE_MPU_MASTER_MAX_INDEX);
+
+ uint32_t mask = MPU_REGION_RWRIGHTS_MASTER_MASK(masterNum);
+ uint32_t right = base->RGDAAC[regionNum];
+
+ /* Build rights control value. */
+ right &= ~mask;
+ right |=
+ MPU_REGION_RWRIGHTS_MASTER(masterNum, (((uint32_t)accessRights->readEnable << 1U) | accessRights->writeEnable));
+ /* Set low master region access rights. */
+ base->RGDAAC[regionNum] = right;
+}
+
+bool MPU_GetSlavePortErrorStatus(MPU_Type *base, mpu_slave_t slaveNum)
+{
+ uint8_t sperr;
+
+ sperr = ((base->CESR & MPU_CESR_SPERR_MASK) >> MPU_CESR_SPERR_SHIFT) & (0x1U << slaveNum);
+
+ return (sperr != 0) ? true : false;
+}
+
+void MPU_GetDetailErrorAccessInfo(MPU_Type *base, mpu_slave_t slaveNum, mpu_access_err_info_t *errInform)
+{
+ assert(errInform);
+
+ uint16_t value;
+ uint32_t cesReg;
+
+ /* Error address. */
+ errInform->address = base->SP[slaveNum].EAR;
+
+ /* Error detail information. */
+ value = (base->SP[slaveNum].EDR & MPU_EDR_EACD_MASK) >> MPU_EDR_EACD_SHIFT;
+ if (!value)
+ {
+ errInform->accessControl = kMPU_NoRegionHit;
+ }
+ else if (!(value & (uint16_t)(value - 1)))
+ {
+ errInform->accessControl = kMPU_NoneOverlappRegion;
+ }
+ else
+ {
+ errInform->accessControl = kMPU_OverlappRegion;
+ }
+
+ value = base->SP[slaveNum].EDR;
+ errInform->master = (uint32_t)((value & MPU_EDR_EMN_MASK) >> MPU_EDR_EMN_SHIFT);
+ errInform->attributes = (mpu_err_attributes_t)((value & MPU_EDR_EATTR_MASK) >> MPU_EDR_EATTR_SHIFT);
+ errInform->accessType = (mpu_err_access_type_t)((value & MPU_EDR_ERW_MASK) >> MPU_EDR_ERW_SHIFT);
+#if FSL_FEATURE_MPU_HAS_PROCESS_IDENTIFIER
+ errInform->processorIdentification = (uint8_t)((value & MPU_EDR_EPID_MASK) >> MPU_EDR_EPID_SHIFT);
+#endif
+
+ /* Clears error slave port bit. */
+ cesReg = (base->CESR & ~MPU_CESR_SPERR_MASK) | ((0x1U << slaveNum) << MPU_CESR_SPERR_SHIFT);
+ base->CESR = cesReg;
+}
diff --git a/drivers/src/fsl_pdb.c b/drivers/src/fsl_pdb.c
new file mode 100644
index 0000000..1fc4a9a
--- /dev/null
+++ b/drivers/src/fsl_pdb.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsl_pdb.h"
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Get instance number for PDB module.
+ *
+ * @param base PDB peripheral base address
+ */
+static uint32_t PDB_GetInstance(PDB_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to PDB bases for each instance. */
+static PDB_Type *const s_pdbBases[] = PDB_BASE_PTRS;
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to PDB clocks for each instance. */
+static const clock_ip_name_t s_pdbClocks[] = PDB_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Codes
+ ******************************************************************************/
+static uint32_t PDB_GetInstance(PDB_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_pdbBases); instance++)
+ {
+ if (s_pdbBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_pdbBases));
+
+ return instance;
+}
+
+void PDB_Init(PDB_Type *base, const pdb_config_t *config)
+{
+ assert(NULL != config);
+
+ uint32_t tmp32;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable the clock. */
+ CLOCK_EnableClock(s_pdbClocks[PDB_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Configure. */
+ /* PDBx_SC. */
+ tmp32 = base->SC &
+ ~(PDB_SC_LDMOD_MASK | PDB_SC_PRESCALER_MASK | PDB_SC_TRGSEL_MASK | PDB_SC_MULT_MASK | PDB_SC_CONT_MASK);
+
+ tmp32 |= PDB_SC_LDMOD(config->loadValueMode) | PDB_SC_PRESCALER(config->prescalerDivider) |
+ PDB_SC_TRGSEL(config->triggerInputSource) | PDB_SC_MULT(config->dividerMultiplicationFactor);
+ if (config->enableContinuousMode)
+ {
+ tmp32 |= PDB_SC_CONT_MASK;
+ }
+ base->SC = tmp32;
+
+ PDB_Enable(base, true); /* Enable the PDB module. */
+}
+
+void PDB_Deinit(PDB_Type *base)
+{
+ PDB_Enable(base, false); /* Disable the PDB module. */
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Disable the clock. */
+ CLOCK_DisableClock(s_pdbClocks[PDB_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+void PDB_GetDefaultConfig(pdb_config_t *config)
+{
+ assert(NULL != config);
+
+ config->loadValueMode = kPDB_LoadValueImmediately;
+ config->prescalerDivider = kPDB_PrescalerDivider1;
+ config->dividerMultiplicationFactor = kPDB_DividerMultiplicationFactor1;
+ config->triggerInputSource = kPDB_TriggerSoftware;
+ config->enableContinuousMode = false;
+}
+
+#if defined(FSL_FEATURE_PDB_HAS_DAC) && FSL_FEATURE_PDB_HAS_DAC
+void PDB_SetDACTriggerConfig(PDB_Type *base, uint32_t channel, pdb_dac_trigger_config_t *config)
+{
+ assert(channel < PDB_INTC_COUNT);
+ assert(NULL != config);
+
+ uint32_t tmp32 = 0U;
+
+ /* PDBx_DACINTC. */
+ if (config->enableExternalTriggerInput)
+ {
+ tmp32 |= PDB_INTC_EXT_MASK;
+ }
+ if (config->enableIntervalTrigger)
+ {
+ tmp32 |= PDB_INTC_TOE_MASK;
+ }
+ base->DAC[channel].INTC = tmp32;
+}
+#endif /* FSL_FEATURE_PDB_HAS_DAC */
diff --git a/drivers/src/fsl_pit.c b/drivers/src/fsl_pit.c
new file mode 100644
index 0000000..e5c3c4e
--- /dev/null
+++ b/drivers/src/fsl_pit.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsl_pit.h"
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Gets the instance from the base address to be used to gate or ungate the module clock
+ *
+ * @param base PIT peripheral base address
+ *
+ * @return The PIT instance
+ */
+static uint32_t PIT_GetInstance(PIT_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to PIT bases for each instance. */
+static PIT_Type *const s_pitBases[] = PIT_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to PIT clocks for each instance. */
+static const clock_ip_name_t s_pitClocks[] = PIT_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t PIT_GetInstance(PIT_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_pitBases); instance++)
+ {
+ if (s_pitBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_pitBases));
+
+ return instance;
+}
+
+void PIT_Init(PIT_Type *base, const pit_config_t *config)
+{
+ assert(config);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Ungate the PIT clock*/
+ CLOCK_EnableClock(s_pitClocks[PIT_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Enable PIT timers */
+ base->MCR &= ~PIT_MCR_MDIS_MASK;
+
+ /* Config timer operation when in debug mode */
+ if (config->enableRunInDebug)
+ {
+ base->MCR &= ~PIT_MCR_FRZ_MASK;
+ }
+ else
+ {
+ base->MCR |= PIT_MCR_FRZ_MASK;
+ }
+}
+
+void PIT_Deinit(PIT_Type *base)
+{
+ /* Disable PIT timers */
+ base->MCR |= PIT_MCR_MDIS_MASK;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Gate the PIT clock*/
+ CLOCK_DisableClock(s_pitClocks[PIT_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+#if defined(FSL_FEATURE_PIT_HAS_LIFETIME_TIMER) && FSL_FEATURE_PIT_HAS_LIFETIME_TIMER
+
+uint64_t PIT_GetLifetimeTimerCount(PIT_Type *base)
+{
+ uint32_t valueH = 0U;
+ uint32_t valueL = 0U;
+
+ /* LTMR64H should be read before LTMR64L */
+ valueH = base->LTMR64H;
+ valueL = base->LTMR64L;
+
+ return (((uint64_t)valueH << 32U) + (uint64_t)(valueL));
+}
+
+#endif /* FSL_FEATURE_PIT_HAS_LIFETIME_TIMER */
diff --git a/drivers/src/fsl_pmc.c b/drivers/src/fsl_pmc.c
new file mode 100644
index 0000000..bcdd5cb
--- /dev/null
+++ b/drivers/src/fsl_pmc.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "fsl_pmc.h"
+
+#if (defined(FSL_FEATURE_PMC_HAS_PARAM) && FSL_FEATURE_PMC_HAS_PARAM)
+void PMC_GetParam(PMC_Type *base, pmc_param_t *param)
+{
+ uint32_t reg = base->PARAM;
+ ;
+ param->vlpoEnable = (bool)(reg & PMC_PARAM_VLPOE_MASK);
+ param->hvdEnable = (bool)(reg & PMC_PARAM_HVDE_MASK);
+}
+#endif /* FSL_FEATURE_PMC_HAS_PARAM */
+
+void PMC_ConfigureLowVoltDetect(PMC_Type *base, const pmc_low_volt_detect_config_t *config)
+{
+ base->LVDSC1 = (0U |
+#if (defined(FSL_FEATURE_PMC_HAS_LVDV) && FSL_FEATURE_PMC_HAS_LVDV)
+ ((uint32_t)config->voltSelect << PMC_LVDSC1_LVDV_SHIFT) |
+#endif
+ ((uint32_t)config->enableInt << PMC_LVDSC1_LVDIE_SHIFT) |
+ ((uint32_t)config->enableReset << PMC_LVDSC1_LVDRE_SHIFT)
+ /* Clear the Low Voltage Detect Flag with previouse power detect setting */
+ | PMC_LVDSC1_LVDACK_MASK);
+}
+
+void PMC_ConfigureLowVoltWarning(PMC_Type *base, const pmc_low_volt_warning_config_t *config)
+{
+ base->LVDSC2 = (0U |
+#if (defined(FSL_FEATURE_PMC_HAS_LVWV) && FSL_FEATURE_PMC_HAS_LVWV)
+ ((uint32_t)config->voltSelect << PMC_LVDSC2_LVWV_SHIFT) |
+#endif
+ ((uint32_t)config->enableInt << PMC_LVDSC2_LVWIE_SHIFT)
+ /* Clear the Low Voltage Warning Flag with previouse power detect setting */
+ | PMC_LVDSC2_LVWACK_MASK);
+}
+
+#if (defined(FSL_FEATURE_PMC_HAS_HVDSC1) && FSL_FEATURE_PMC_HAS_HVDSC1)
+void PMC_ConfigureHighVoltDetect(PMC_Type *base, const pmc_high_volt_detect_config_t *config)
+{
+ base->HVDSC1 = (((uint32_t)config->voltSelect << PMC_HVDSC1_HVDV_SHIFT) |
+ ((uint32_t)config->enableInt << PMC_HVDSC1_HVDIE_SHIFT) |
+ ((uint32_t)config->enableReset << PMC_HVDSC1_HVDRE_SHIFT)
+ /* Clear the High Voltage Detect Flag with previouse power detect setting */
+ | PMC_HVDSC1_HVDACK_MASK);
+}
+#endif /* FSL_FEATURE_PMC_HAS_HVDSC1 */
+
+#if ((defined(FSL_FEATURE_PMC_HAS_BGBE) && FSL_FEATURE_PMC_HAS_BGBE) || \
+ (defined(FSL_FEATURE_PMC_HAS_BGEN) && FSL_FEATURE_PMC_HAS_BGEN) || \
+ (defined(FSL_FEATURE_PMC_HAS_BGBDS) && FSL_FEATURE_PMC_HAS_BGBDS))
+void PMC_ConfigureBandgapBuffer(PMC_Type *base, const pmc_bandgap_buffer_config_t *config)
+{
+ base->REGSC = (0U
+#if (defined(FSL_FEATURE_PMC_HAS_BGBE) && FSL_FEATURE_PMC_HAS_BGBE)
+ | ((uint32_t)config->enable << PMC_REGSC_BGBE_SHIFT)
+#endif /* FSL_FEATURE_PMC_HAS_BGBE */
+#if (defined(FSL_FEATURE_PMC_HAS_BGEN) && FSL_FEATURE_PMC_HAS_BGEN)
+ | (((uint32_t)config->enableInLowPowerMode << PMC_REGSC_BGEN_SHIFT))
+#endif /* FSL_FEATURE_PMC_HAS_BGEN */
+#if (defined(FSL_FEATURE_PMC_HAS_BGBDS) && FSL_FEATURE_PMC_HAS_BGBDS)
+ | ((uint32_t)config->drive << PMC_REGSC_BGBDS_SHIFT)
+#endif /* FSL_FEATURE_PMC_HAS_BGBDS */
+ );
+}
+#endif
diff --git a/drivers/src/fsl_rcm.c b/drivers/src/fsl_rcm.c
new file mode 100644
index 0000000..0d73864
--- /dev/null
+++ b/drivers/src/fsl_rcm.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsl_rcm.h"
+
+void RCM_ConfigureResetPinFilter(RCM_Type *base, const rcm_reset_pin_filter_config_t *config)
+{
+ assert(config);
+
+#if (defined(FSL_FEATURE_RCM_REG_WIDTH) && (FSL_FEATURE_RCM_REG_WIDTH == 32))
+ uint32_t reg;
+
+ reg = (((uint32_t)config->enableFilterInStop << RCM_RPC_RSTFLTSS_SHIFT) | (uint32_t)config->filterInRunWait);
+ if (config->filterInRunWait == kRCM_FilterBusClock)
+ {
+ reg |= ((uint32_t)config->busClockFilterCount << RCM_RPC_RSTFLTSEL_SHIFT);
+ }
+ base->RPC = reg;
+#else
+ base->RPFC = ((uint8_t)(config->enableFilterInStop << RCM_RPFC_RSTFLTSS_SHIFT) | (uint8_t)config->filterInRunWait);
+ if (config->filterInRunWait == kRCM_FilterBusClock)
+ {
+ base->RPFW = config->busClockFilterCount;
+ }
+#endif /* FSL_FEATURE_RCM_REG_WIDTH */
+}
+
+#if (defined(FSL_FEATURE_RCM_HAS_BOOTROM) && FSL_FEATURE_RCM_HAS_BOOTROM)
+void RCM_SetForceBootRomSource(RCM_Type *base, rcm_boot_rom_config_t config)
+{
+ uint32_t reg;
+
+ reg = base->FM;
+ reg &= ~RCM_FM_FORCEROM_MASK;
+ reg |= ((uint32_t)config << RCM_FM_FORCEROM_SHIFT);
+ base->FM = reg;
+}
+#endif /* #if FSL_FEATURE_RCM_HAS_BOOTROM */
diff --git a/drivers/src/fsl_rtc.c b/drivers/src/fsl_rtc.c
new file mode 100644
index 0000000..d68055a
--- /dev/null
+++ b/drivers/src/fsl_rtc.c
@@ -0,0 +1,381 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsl_rtc.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+#define SECONDS_IN_A_DAY (86400U)
+#define SECONDS_IN_A_HOUR (3600U)
+#define SECONDS_IN_A_MINUTE (60U)
+#define DAYS_IN_A_YEAR (365U)
+#define YEAR_RANGE_START (1970U)
+#define YEAR_RANGE_END (2099U)
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Checks whether the date and time passed in is valid
+ *
+ * @param datetime Pointer to structure where the date and time details are stored
+ *
+ * @return Returns false if the date & time details are out of range; true if in range
+ */
+static bool RTC_CheckDatetimeFormat(const rtc_datetime_t *datetime);
+
+/*!
+ * @brief Converts time data from datetime to seconds
+ *
+ * @param datetime Pointer to datetime structure where the date and time details are stored
+ *
+ * @return The result of the conversion in seconds
+ */
+static uint32_t RTC_ConvertDatetimeToSeconds(const rtc_datetime_t *datetime);
+
+/*!
+ * @brief Converts time data from seconds to a datetime structure
+ *
+ * @param seconds Seconds value that needs to be converted to datetime format
+ * @param datetime Pointer to the datetime structure where the result of the conversion is stored
+ */
+static void RTC_ConvertSecondsToDatetime(uint32_t seconds, rtc_datetime_t *datetime);
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static bool RTC_CheckDatetimeFormat(const rtc_datetime_t *datetime)
+{
+ assert(datetime);
+
+ /* Table of days in a month for a non leap year. First entry in the table is not used,
+ * valid months start from 1
+ */
+ uint8_t daysPerMonth[] = {0U, 31U, 28U, 31U, 30U, 31U, 30U, 31U, 31U, 30U, 31U, 30U, 31U};
+
+ /* Check year, month, hour, minute, seconds */
+ if ((datetime->year < YEAR_RANGE_START) || (datetime->year > YEAR_RANGE_END) || (datetime->month > 12U) ||
+ (datetime->month < 1U) || (datetime->hour >= 24U) || (datetime->minute >= 60U) || (datetime->second >= 60U))
+ {
+ /* If not correct then error*/
+ return false;
+ }
+
+ /* Adjust the days in February for a leap year */
+ if ((((datetime->year & 3U) == 0) && (datetime->year % 100 != 0)) || (datetime->year % 400 == 0))
+ {
+ daysPerMonth[2] = 29U;
+ }
+
+ /* Check the validity of the day */
+ if ((datetime->day > daysPerMonth[datetime->month]) || (datetime->day < 1U))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+static uint32_t RTC_ConvertDatetimeToSeconds(const rtc_datetime_t *datetime)
+{
+ assert(datetime);
+
+ /* Number of days from begin of the non Leap-year*/
+ /* Number of days from begin of the non Leap-year*/
+ uint16_t monthDays[] = {0U, 0U, 31U, 59U, 90U, 120U, 151U, 181U, 212U, 243U, 273U, 304U, 334U};
+ uint32_t seconds;
+
+ /* Compute number of days from 1970 till given year*/
+ seconds = (datetime->year - 1970U) * DAYS_IN_A_YEAR;
+ /* Add leap year days */
+ seconds += ((datetime->year / 4) - (1970U / 4));
+ /* Add number of days till given month*/
+ seconds += monthDays[datetime->month];
+ /* Add days in given month. We subtract the current day as it is
+ * represented in the hours, minutes and seconds field*/
+ seconds += (datetime->day - 1);
+ /* For leap year if month less than or equal to Febraury, decrement day counter*/
+ if ((!(datetime->year & 3U)) && (datetime->month <= 2U))
+ {
+ seconds--;
+ }
+
+ seconds = (seconds * SECONDS_IN_A_DAY) + (datetime->hour * SECONDS_IN_A_HOUR) +
+ (datetime->minute * SECONDS_IN_A_MINUTE) + datetime->second;
+
+ return seconds;
+}
+
+static void RTC_ConvertSecondsToDatetime(uint32_t seconds, rtc_datetime_t *datetime)
+{
+ assert(datetime);
+
+ uint32_t x;
+ uint32_t secondsRemaining, days;
+ uint16_t daysInYear;
+ /* Table of days in a month for a non leap year. First entry in the table is not used,
+ * valid months start from 1
+ */
+ uint8_t daysPerMonth[] = {0U, 31U, 28U, 31U, 30U, 31U, 30U, 31U, 31U, 30U, 31U, 30U, 31U};
+
+ /* Start with the seconds value that is passed in to be converted to date time format */
+ secondsRemaining = seconds;
+
+ /* Calcuate the number of days, we add 1 for the current day which is represented in the
+ * hours and seconds field
+ */
+ days = secondsRemaining / SECONDS_IN_A_DAY + 1;
+
+ /* Update seconds left*/
+ secondsRemaining = secondsRemaining % SECONDS_IN_A_DAY;
+
+ /* Calculate the datetime hour, minute and second fields */
+ datetime->hour = secondsRemaining / SECONDS_IN_A_HOUR;
+ secondsRemaining = secondsRemaining % SECONDS_IN_A_HOUR;
+ datetime->minute = secondsRemaining / 60U;
+ datetime->second = secondsRemaining % SECONDS_IN_A_MINUTE;
+
+ /* Calculate year */
+ daysInYear = DAYS_IN_A_YEAR;
+ datetime->year = YEAR_RANGE_START;
+ while (days > daysInYear)
+ {
+ /* Decrease day count by a year and increment year by 1 */
+ days -= daysInYear;
+ datetime->year++;
+
+ /* Adjust the number of days for a leap year */
+ if (datetime->year & 3U)
+ {
+ daysInYear = DAYS_IN_A_YEAR;
+ }
+ else
+ {
+ daysInYear = DAYS_IN_A_YEAR + 1;
+ }
+ }
+
+ /* Adjust the days in February for a leap year */
+ if (!(datetime->year & 3U))
+ {
+ daysPerMonth[2] = 29U;
+ }
+
+ for (x = 1U; x <= 12U; x++)
+ {
+ if (days <= daysPerMonth[x])
+ {
+ datetime->month = x;
+ break;
+ }
+ else
+ {
+ days -= daysPerMonth[x];
+ }
+ }
+
+ datetime->day = days;
+}
+
+void RTC_Init(RTC_Type *base, const rtc_config_t *config)
+{
+ assert(config);
+
+ uint32_t reg;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_EnableClock(kCLOCK_Rtc0);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Issue a software reset if timer is invalid */
+ if (RTC_GetStatusFlags(RTC) & kRTC_TimeInvalidFlag)
+ {
+ RTC_Reset(RTC);
+ }
+
+ reg = base->CR;
+ /* Setup the update mode and supervisor access mode */
+ reg &= ~(RTC_CR_UM_MASK | RTC_CR_SUP_MASK);
+ reg |= RTC_CR_UM(config->updateMode) | RTC_CR_SUP(config->supervisorAccess);
+#if defined(FSL_FEATURE_RTC_HAS_WAKEUP_PIN_SELECTION) && FSL_FEATURE_RTC_HAS_WAKEUP_PIN_SELECTION
+ /* Setup the wakeup pin select */
+ reg &= ~(RTC_CR_WPS_MASK);
+ reg |= RTC_CR_WPS(config->wakeupSelect);
+#endif /* FSL_FEATURE_RTC_HAS_WAKEUP_PIN */
+ base->CR = reg;
+
+ /* Configure the RTC time compensation register */
+ base->TCR = (RTC_TCR_CIR(config->compensationInterval) | RTC_TCR_TCR(config->compensationTime));
+}
+
+void RTC_GetDefaultConfig(rtc_config_t *config)
+{
+ assert(config);
+
+ /* Wakeup pin will assert if the RTC interrupt asserts or if the wakeup pin is turned on */
+ config->wakeupSelect = false;
+ /* Registers cannot be written when locked */
+ config->updateMode = false;
+ /* Non-supervisor mode write accesses are not supported and will generate a bus error */
+ config->supervisorAccess = false;
+ /* Compensation interval used by the crystal compensation logic */
+ config->compensationInterval = 0;
+ /* Compensation time used by the crystal compensation logic */
+ config->compensationTime = 0;
+}
+
+status_t RTC_SetDatetime(RTC_Type *base, const rtc_datetime_t *datetime)
+{
+ assert(datetime);
+
+ /* Return error if the time provided is not valid */
+ if (!(RTC_CheckDatetimeFormat(datetime)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Set time in seconds */
+ base->TSR = RTC_ConvertDatetimeToSeconds(datetime);
+
+ return kStatus_Success;
+}
+
+void RTC_GetDatetime(RTC_Type *base, rtc_datetime_t *datetime)
+{
+ assert(datetime);
+
+ uint32_t seconds = 0;
+
+ seconds = base->TSR;
+ RTC_ConvertSecondsToDatetime(seconds, datetime);
+}
+
+status_t RTC_SetAlarm(RTC_Type *base, const rtc_datetime_t *alarmTime)
+{
+ assert(alarmTime);
+
+ uint32_t alarmSeconds = 0;
+ uint32_t currSeconds = 0;
+
+ /* Return error if the alarm time provided is not valid */
+ if (!(RTC_CheckDatetimeFormat(alarmTime)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ alarmSeconds = RTC_ConvertDatetimeToSeconds(alarmTime);
+
+ /* Get the current time */
+ currSeconds = base->TSR;
+
+ /* Return error if the alarm time has passed */
+ if (alarmSeconds < currSeconds)
+ {
+ return kStatus_Fail;
+ }
+
+ /* Set alarm in seconds*/
+ base->TAR = alarmSeconds;
+
+ return kStatus_Success;
+}
+
+void RTC_GetAlarm(RTC_Type *base, rtc_datetime_t *datetime)
+{
+ assert(datetime);
+
+ uint32_t alarmSeconds = 0;
+
+ /* Get alarm in seconds */
+ alarmSeconds = base->TAR;
+
+ RTC_ConvertSecondsToDatetime(alarmSeconds, datetime);
+}
+
+void RTC_ClearStatusFlags(RTC_Type *base, uint32_t mask)
+{
+ /* The alarm flag is cleared by writing to the TAR register */
+ if (mask & kRTC_AlarmFlag)
+ {
+ base->TAR = 0U;
+ }
+
+ /* The timer overflow flag is cleared by initializing the TSR register.
+ * The time counter should be disabled for this write to be successful
+ */
+ if (mask & kRTC_TimeOverflowFlag)
+ {
+ base->TSR = 1U;
+ }
+
+ /* The timer overflow flag is cleared by initializing the TSR register.
+ * The time counter should be disabled for this write to be successful
+ */
+ if (mask & kRTC_TimeInvalidFlag)
+ {
+ base->TSR = 1U;
+ }
+}
+
+#if defined(FSL_FEATURE_RTC_HAS_MONOTONIC) && (FSL_FEATURE_RTC_HAS_MONOTONIC)
+
+void RTC_GetMonotonicCounter(RTC_Type *base, uint64_t *counter)
+{
+ assert(counter);
+
+ *counter = (((uint64_t)base->MCHR << 32) | ((uint64_t)base->MCLR));
+}
+
+void RTC_SetMonotonicCounter(RTC_Type *base, uint64_t counter)
+{
+ /* Prepare to initialize the register with the new value written */
+ base->MER &= ~RTC_MER_MCE_MASK;
+
+ base->MCHR = (uint32_t)((counter) >> 32);
+ base->MCLR = (uint32_t)(counter);
+}
+
+status_t RTC_IncrementMonotonicCounter(RTC_Type *base)
+{
+ if (base->SR & (RTC_SR_MOF_MASK | RTC_SR_TIF_MASK))
+ {
+ return kStatus_Fail;
+ }
+
+ /* Prepare to switch to increment mode */
+ base->MER |= RTC_MER_MCE_MASK;
+ /* Write anything so the counter increments*/
+ base->MCLR = 1U;
+
+ return kStatus_Success;
+}
+
+#endif /* FSL_FEATURE_RTC_HAS_MONOTONIC */
diff --git a/drivers/src/fsl_sai.c b/drivers/src/fsl_sai.c
new file mode 100644
index 0000000..c38165e
--- /dev/null
+++ b/drivers/src/fsl_sai.c
@@ -0,0 +1,1066 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of Freescale Semiconductor, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsl_sai.h"
+
+/*******************************************************************************
+ * Definitations
+ ******************************************************************************/
+enum _sai_transfer_state
+{
+ kSAI_Busy = 0x0U, /*!< SAI is busy */
+ kSAI_Idle, /*!< Transfer is done. */
+ kSAI_Error /*!< Transfer error occured. */
+};
+
+/*! @brief Typedef for sai tx interrupt handler. */
+typedef void (*sai_tx_isr_t)(I2S_Type *base, sai_handle_t *saiHandle);
+
+/*! @brief Typedef for sai rx interrupt handler. */
+typedef void (*sai_rx_isr_t)(I2S_Type *base, sai_handle_t *saiHandle);
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+#if defined(FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER) && (FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER)
+
+/*!
+ * @brief Set the master clock divider.
+ *
+ * This API will compute the master clock divider according to master clock frequency and master
+ * clock source clock source frequency.
+ *
+ * @param base SAI base pointer.
+ * @param mclk_Hz Mater clock frequency in Hz.
+ * @param mclkSrcClock_Hz Master clock source frequency in Hz.
+ */
+static void SAI_SetMasterClockDivider(I2S_Type *base, uint32_t mclk_Hz, uint32_t mclkSrcClock_Hz);
+#endif /* FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER */
+
+/*!
+ * @brief Get the instance number for SAI.
+ *
+ * @param base SAI base pointer.
+ */
+uint32_t SAI_GetInstance(I2S_Type *base);
+
+/*!
+ * @brief sends a piece of data in non-blocking way.
+ *
+ * @param base SAI base pointer
+ * @param channel Data channel used.
+ * @param bitWidth How many bits in a audio word, usually 8/16/24/32 bits.
+ * @param buffer Pointer to the data to be written.
+ * @param size Bytes to be written.
+ */
+static void SAI_WriteNonBlocking(I2S_Type *base, uint32_t channel, uint32_t bitWidth, uint8_t *buffer, uint32_t size);
+
+/*!
+ * @brief Receive a piece of data in non-blocking way.
+ *
+ * @param base SAI base pointer
+ * @param channel Data channel used.
+ * @param bitWidth How many bits in a audio word, usually 8/16/24/32 bits.
+ * @param buffer Pointer to the data to be read.
+ * @param size Bytes to be read.
+ */
+static void SAI_ReadNonBlocking(I2S_Type *base, uint32_t channel, uint32_t bitWidth, uint8_t *buffer, uint32_t size);
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*!@brief SAI handle pointer */
+sai_handle_t *s_saiHandle[FSL_FEATURE_SOC_I2S_COUNT][2];
+/* Base pointer array */
+static I2S_Type *const s_saiBases[] = I2S_BASE_PTRS;
+/* IRQ number array */
+static const IRQn_Type s_saiTxIRQ[] = I2S_TX_IRQS;
+static const IRQn_Type s_saiRxIRQ[] = I2S_RX_IRQS;
+/* Clock name array */
+static const clock_ip_name_t s_saiClock[] = SAI_CLOCKS;
+/*! @brief Pointer to tx IRQ handler for each instance. */
+static sai_tx_isr_t s_saiTxIsr;
+/*! @brief Pointer to tx IRQ handler for each instance. */
+static sai_rx_isr_t s_saiRxIsr;
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+#if defined(FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER) && (FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER)
+static void SAI_SetMasterClockDivider(I2S_Type *base, uint32_t mclk_Hz, uint32_t mclkSrcClock_Hz)
+{
+ uint32_t freq = mclkSrcClock_Hz;
+ uint16_t fract, divide;
+ uint32_t remaind = 0;
+ uint32_t current_remainder = 0xFFFFFFFFU;
+ uint16_t current_fract = 0;
+ uint16_t current_divide = 0;
+ uint32_t mul_freq = 0;
+ uint32_t max_fract = 256;
+
+ /*In order to prevent overflow */
+ freq /= 100;
+ mclk_Hz /= 100;
+
+ /* Compute the max fract number */
+ max_fract = mclk_Hz * 4096 / freq + 1;
+ if (max_fract > 256)
+ {
+ max_fract = 256;
+ }
+
+ /* Looking for the closet frequency */
+ for (fract = 1; fract < max_fract; fract++)
+ {
+ mul_freq = freq * fract;
+ remaind = mul_freq % mclk_Hz;
+ divide = mul_freq / mclk_Hz;
+
+ /* Find the exactly frequency */
+ if (remaind == 0)
+ {
+ current_fract = fract;
+ current_divide = mul_freq / mclk_Hz;
+ break;
+ }
+
+ /* Closer to next one, set the closest to next data */
+ if (remaind > mclk_Hz / 2)
+ {
+ remaind = mclk_Hz - remaind;
+ divide += 1;
+ }
+
+ /* Update the closest div and fract */
+ if (remaind < current_remainder)
+ {
+ current_fract = fract;
+ current_divide = divide;
+ current_remainder = remaind;
+ }
+ }
+
+ /* Fill the computed fract and divider to registers */
+ base->MDR = I2S_MDR_DIVIDE(current_divide - 1) | I2S_MDR_FRACT(current_fract - 1);
+
+ /* Waiting for the divider updated */
+ while (base->MCR & I2S_MCR_DUF_MASK)
+ {
+ }
+}
+#endif /* FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER */
+
+uint32_t SAI_GetInstance(I2S_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < FSL_FEATURE_SOC_I2S_COUNT; instance++)
+ {
+ if (s_saiBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < FSL_FEATURE_SOC_I2S_COUNT);
+
+ return instance;
+}
+
+static void SAI_WriteNonBlocking(I2S_Type *base, uint32_t channel, uint32_t bitWidth, uint8_t *buffer, uint32_t size)
+{
+ uint32_t i = 0;
+ uint8_t j = 0;
+ uint8_t bytesPerWord = bitWidth / 8U;
+ uint32_t data = 0;
+ uint32_t temp = 0;
+
+ for (i = 0; i < size / bytesPerWord; i++)
+ {
+ for (j = 0; j < bytesPerWord; j++)
+ {
+ temp = (uint32_t)(*buffer);
+ data |= (temp << (8U * j));
+ buffer++;
+ }
+ base->TDR[channel] = data;
+ data = 0;
+ }
+}
+
+static void SAI_ReadNonBlocking(I2S_Type *base, uint32_t channel, uint32_t bitWidth, uint8_t *buffer, uint32_t size)
+{
+ uint32_t i = 0;
+ uint8_t j = 0;
+ uint8_t bytesPerWord = bitWidth / 8U;
+ uint32_t data = 0;
+
+ for (i = 0; i < size / bytesPerWord; i++)
+ {
+ data = base->RDR[channel];
+ for (j = 0; j < bytesPerWord; j++)
+ {
+ *buffer = (data >> (8U * j)) & 0xFF;
+ buffer++;
+ }
+ }
+}
+
+void SAI_TxInit(I2S_Type *base, const sai_config_t *config)
+{
+ uint32_t val = 0;
+
+ /* Enable the SAI clock */
+ CLOCK_EnableClock(s_saiClock[SAI_GetInstance(base)]);
+
+#if defined(FSL_FEATURE_SAI_HAS_MCR) && (FSL_FEATURE_SAI_HAS_MCR)
+ /* Master clock source setting */
+ val = (base->MCR & ~I2S_MCR_MICS_MASK);
+ base->MCR = (val | I2S_MCR_MICS(config->mclkSource));
+
+ /* Configure Master clock output enable */
+ val = (base->MCR & ~I2S_MCR_MOE_MASK);
+ base->MCR = (val | I2S_MCR_MOE(config->mclkOutputEnable));
+#endif /* FSL_FEATURE_SAI_HAS_MCR */
+
+ /* Configure audio protocol */
+ switch (config->protocol)
+ {
+ case kSAI_BusLeftJustified:
+ base->TCR2 |= I2S_TCR2_BCP_MASK;
+ base->TCR3 &= ~I2S_TCR3_WDFL_MASK;
+ base->TCR4 = I2S_TCR4_MF(1U) | I2S_TCR4_SYWD(31U) | I2S_TCR4_FSE(0U) | I2S_TCR4_FSP(0U) | I2S_TCR4_FRSZ(1U);
+ break;
+
+ case kSAI_BusRightJustified:
+ base->TCR2 |= I2S_TCR2_BCP_MASK;
+ base->TCR3 &= ~I2S_TCR3_WDFL_MASK;
+ base->TCR4 = I2S_TCR4_MF(1U) | I2S_TCR4_SYWD(31U) | I2S_TCR4_FSE(0U) | I2S_TCR4_FSP(0U) | I2S_TCR4_FRSZ(1U);
+ break;
+
+ case kSAI_BusI2S:
+ base->TCR2 |= I2S_TCR2_BCP_MASK;
+ base->TCR3 &= ~I2S_TCR3_WDFL_MASK;
+ base->TCR4 = I2S_TCR4_MF(1U) | I2S_TCR4_SYWD(31U) | I2S_TCR4_FSE(1U) | I2S_TCR4_FSP(1U) | I2S_TCR4_FRSZ(1U);
+ break;
+
+ case kSAI_BusPCMA:
+ base->TCR2 &= ~I2S_TCR2_BCP_MASK;
+ base->TCR3 &= ~I2S_TCR3_WDFL_MASK;
+ base->TCR4 = I2S_TCR4_MF(1U) | I2S_TCR4_SYWD(0U) | I2S_TCR4_FSE(1U) | I2S_TCR4_FSP(0U) | I2S_TCR4_FRSZ(1U);
+ break;
+
+ case kSAI_BusPCMB:
+ base->TCR2 &= ~I2S_TCR2_BCP_MASK;
+ base->TCR3 &= ~I2S_TCR3_WDFL_MASK;
+ base->TCR4 = I2S_TCR4_MF(1U) | I2S_TCR4_SYWD(0U) | I2S_TCR4_FSE(0U) | I2S_TCR4_FSP(0U) | I2S_TCR4_FRSZ(1U);
+ break;
+
+ default:
+ break;
+ }
+
+ /* Set master or slave */
+ if (config->masterSlave == kSAI_Master)
+ {
+ base->TCR2 |= I2S_TCR2_BCD_MASK;
+ base->TCR4 |= I2S_TCR4_FSD_MASK;
+
+ /* Bit clock source setting */
+ val = base->TCR2 & (~I2S_TCR2_MSEL_MASK);
+ base->TCR2 = (val | I2S_TCR2_MSEL(config->bclkSource));
+ }
+ else
+ {
+ base->TCR2 &= ~I2S_TCR2_BCD_MASK;
+ base->TCR4 &= ~I2S_TCR4_FSD_MASK;
+ }
+
+ /* Set Sync mode */
+ switch (config->syncMode)
+ {
+ case kSAI_ModeAsync:
+ val = base->TCR2;
+ val &= ~I2S_TCR2_SYNC_MASK;
+ base->TCR2 = (val | I2S_TCR2_SYNC(0U));
+ break;
+ case kSAI_ModeSync:
+ val = base->TCR2;
+ val &= ~I2S_TCR2_SYNC_MASK;
+ base->TCR2 = (val | I2S_TCR2_SYNC(1U));
+ /* If sync with Rx, should set Rx to async mode */
+ val = base->RCR2;
+ val &= ~I2S_RCR2_SYNC_MASK;
+ base->RCR2 = (val | I2S_RCR2_SYNC(0U));
+ break;
+ case kSAI_ModeSyncWithOtherTx:
+ val = base->TCR2;
+ val &= ~I2S_TCR2_SYNC_MASK;
+ base->TCR2 = (val | I2S_TCR2_SYNC(2U));
+ break;
+ case kSAI_ModeSyncWithOtherRx:
+ val = base->TCR2;
+ val &= ~I2S_TCR2_SYNC_MASK;
+ base->TCR2 = (val | I2S_TCR2_SYNC(3U));
+ break;
+ default:
+ break;
+ }
+}
+
+void SAI_RxInit(I2S_Type *base, const sai_config_t *config)
+{
+ uint32_t val = 0;
+
+ /* Enable SAI clock first. */
+ CLOCK_EnableClock(s_saiClock[SAI_GetInstance(base)]);
+
+#if defined(FSL_FEATURE_SAI_HAS_MCR) && (FSL_FEATURE_SAI_HAS_MCR)
+ /* Master clock source setting */
+ val = (base->MCR & ~I2S_MCR_MICS_MASK);
+ base->MCR = (val | I2S_MCR_MICS(config->mclkSource));
+
+ /* Configure Master clock output enable */
+ val = (base->MCR & ~I2S_MCR_MOE_MASK);
+ base->MCR = (val | I2S_MCR_MOE(config->mclkOutputEnable));
+#endif /* FSL_FEATURE_SAI_HAS_MCR */
+
+ /* Configure audio protocol */
+ switch (config->protocol)
+ {
+ case kSAI_BusLeftJustified:
+ base->RCR2 |= I2S_RCR2_BCP_MASK;
+ base->RCR3 &= ~I2S_RCR3_WDFL_MASK;
+ base->RCR4 = I2S_RCR4_MF(1U) | I2S_RCR4_SYWD(31U) | I2S_RCR4_FSE(0U) | I2S_RCR4_FSP(0U) | I2S_RCR4_FRSZ(1U);
+ break;
+
+ case kSAI_BusRightJustified:
+ base->RCR2 |= I2S_RCR2_BCP_MASK;
+ base->RCR3 &= ~I2S_RCR3_WDFL_MASK;
+ base->RCR4 = I2S_RCR4_MF(1U) | I2S_RCR4_SYWD(31U) | I2S_RCR4_FSE(0U) | I2S_RCR4_FSP(0U) | I2S_RCR4_FRSZ(1U);
+ break;
+
+ case kSAI_BusI2S:
+ base->RCR2 |= I2S_RCR2_BCP_MASK;
+ base->RCR3 &= ~I2S_RCR3_WDFL_MASK;
+ base->RCR4 = I2S_RCR4_MF(1U) | I2S_RCR4_SYWD(31U) | I2S_RCR4_FSE(1U) | I2S_RCR4_FSP(1U) | I2S_RCR4_FRSZ(1U);
+ break;
+
+ case kSAI_BusPCMA:
+ base->RCR2 &= ~I2S_RCR2_BCP_MASK;
+ base->RCR3 &= ~I2S_RCR3_WDFL_MASK;
+ base->RCR4 = I2S_RCR4_MF(1U) | I2S_RCR4_SYWD(0U) | I2S_RCR4_FSE(1U) | I2S_RCR4_FSP(0U) | I2S_RCR4_FRSZ(1U);
+ break;
+
+ case kSAI_BusPCMB:
+ base->RCR2 &= ~I2S_RCR2_BCP_MASK;
+ base->RCR3 &= ~I2S_RCR3_WDFL_MASK;
+ base->RCR4 = I2S_RCR4_MF(1U) | I2S_RCR4_SYWD(0U) | I2S_RCR4_FSE(0U) | I2S_RCR4_FSP(0U) | I2S_RCR4_FRSZ(1U);
+ break;
+
+ default:
+ break;
+ }
+
+ /* Set master or slave */
+ if (config->masterSlave == kSAI_Master)
+ {
+ base->RCR2 |= I2S_RCR2_BCD_MASK;
+ base->RCR4 |= I2S_RCR4_FSD_MASK;
+
+ /* Bit clock source setting */
+ val = base->RCR2 & (~I2S_RCR2_MSEL_MASK);
+ base->RCR2 = (val | I2S_RCR2_MSEL(config->bclkSource));
+ }
+ else
+ {
+ base->RCR2 &= ~I2S_RCR2_BCD_MASK;
+ base->RCR4 &= ~I2S_RCR4_FSD_MASK;
+ }
+
+ /* Set Sync mode */
+ switch (config->syncMode)
+ {
+ case kSAI_ModeAsync:
+ val = base->RCR2;
+ val &= ~I2S_RCR2_SYNC_MASK;
+ base->RCR2 = (val | I2S_RCR2_SYNC(0U));
+ break;
+ case kSAI_ModeSync:
+ val = base->RCR2;
+ val &= ~I2S_RCR2_SYNC_MASK;
+ base->RCR2 = (val | I2S_RCR2_SYNC(1U));
+ /* If sync with Tx, should set Tx to async mode */
+ val = base->TCR2;
+ val &= ~I2S_TCR2_SYNC_MASK;
+ base->TCR2 = (val | I2S_TCR2_SYNC(0U));
+ break;
+ case kSAI_ModeSyncWithOtherTx:
+ val = base->RCR2;
+ val &= ~I2S_RCR2_SYNC_MASK;
+ base->RCR2 = (val | I2S_RCR2_SYNC(2U));
+ break;
+ case kSAI_ModeSyncWithOtherRx:
+ val = base->RCR2;
+ val &= ~I2S_RCR2_SYNC_MASK;
+ base->RCR2 = (val | I2S_RCR2_SYNC(3U));
+ break;
+ default:
+ break;
+ }
+}
+
+void SAI_Deinit(I2S_Type *base)
+{
+ SAI_TxEnable(base, false);
+ SAI_RxEnable(base, false);
+ CLOCK_DisableClock(s_saiClock[SAI_GetInstance(base)]);
+}
+
+void SAI_TxGetDefaultConfig(sai_config_t *config)
+{
+ config->bclkSource = kSAI_BclkSourceMclkDiv;
+ config->masterSlave = kSAI_Master;
+ config->mclkSource = kSAI_MclkSourceSysclk;
+ config->protocol = kSAI_BusLeftJustified;
+ config->syncMode = kSAI_ModeAsync;
+#if defined(FSL_FEATURE_SAI_HAS_MCR) && (FSL_FEATURE_SAI_HAS_MCR)
+ config->mclkOutputEnable = true;
+#endif /* FSL_FEATURE_SAI_HAS_MCR */
+}
+
+void SAI_RxGetDefaultConfig(sai_config_t *config)
+{
+ config->bclkSource = kSAI_BclkSourceMclkDiv;
+ config->masterSlave = kSAI_Master;
+ config->mclkSource = kSAI_MclkSourceSysclk;
+ config->protocol = kSAI_BusLeftJustified;
+ config->syncMode = kSAI_ModeSync;
+#if defined(FSL_FEATURE_SAI_HAS_MCR) && (FSL_FEATURE_SAI_HAS_MCR)
+ config->mclkOutputEnable = true;
+#endif /* FSL_FEATURE_SAI_HAS_MCR */
+}
+
+void SAI_TxReset(I2S_Type *base)
+{
+ /* Set the software reset and FIFO reset to clear internal state */
+ base->TCSR = I2S_TCSR_SR_MASK | I2S_TCSR_FR_MASK;
+
+ /* Clear software reset bit, this should be done by software */
+ base->TCSR &= ~I2S_TCSR_SR_MASK;
+
+ /* Reset all Tx register values */
+ base->TCR2 = 0;
+ base->TCR3 = 0;
+ base->TCR4 = 0;
+ base->TCR5 = 0;
+ base->TMR = 0;
+}
+
+void SAI_RxReset(I2S_Type *base)
+{
+ /* Set the software reset and FIFO reset to clear internal state */
+ base->RCSR = I2S_RCSR_SR_MASK | I2S_RCSR_FR_MASK;
+
+ /* Clear software reset bit, this should be done by software */
+ base->RCSR &= ~I2S_RCSR_SR_MASK;
+
+ /* Reset all Rx register values */
+ base->RCR2 = 0;
+ base->RCR3 = 0;
+ base->RCR4 = 0;
+ base->RCR5 = 0;
+ base->RMR = 0;
+}
+
+void SAI_TxEnable(I2S_Type *base, bool enable)
+{
+ if (enable)
+ {
+ /* If clock is sync with Rx, should enable RE bit. */
+ if (((base->TCR2 & I2S_TCR2_SYNC_MASK) >> I2S_TCR2_SYNC_SHIFT) == 0x1U)
+ {
+ base->RCSR = ((base->RCSR & 0xFFE3FFFFU) | I2S_RCSR_RE_MASK);
+ }
+ base->TCSR = ((base->TCSR & 0xFFE3FFFFU) | I2S_TCSR_TE_MASK);
+ }
+ else
+ {
+ /* Should not close RE even sync with Rx */
+ base->TCSR = ((base->TCSR & 0xFFE3FFFFU) & (~I2S_TCSR_TE_MASK));
+ }
+}
+
+void SAI_RxEnable(I2S_Type *base, bool enable)
+{
+ if (enable)
+ {
+ /* If clock is sync with Tx, should enable TE bit. */
+ if (((base->RCR2 & I2S_RCR2_SYNC_MASK) >> I2S_RCR2_SYNC_SHIFT) == 0x1U)
+ {
+ base->TCSR = ((base->TCSR & 0xFFE3FFFFU) | I2S_TCSR_TE_MASK);
+ }
+ base->RCSR = ((base->RCSR & 0xFFE3FFFFU) | I2S_RCSR_RE_MASK);
+ }
+ else
+ {
+ base->RCSR = ((base->RCSR & 0xFFE3FFFFU) & (~I2S_RCSR_RE_MASK));
+ }
+}
+
+void SAI_TxSetFormat(I2S_Type *base,
+ sai_transfer_format_t *format,
+ uint32_t mclkSourceClockHz,
+ uint32_t bclkSourceClockHz)
+{
+ uint32_t bclk = format->sampleRate_Hz * 32U * 2U;
+
+/* Compute the mclk */
+#if defined(FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER) && (FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER)
+ /* Check if master clock divider enabled, then set master clock divider */
+ if (base->MCR & I2S_MCR_MOE_MASK)
+ {
+ SAI_SetMasterClockDivider(base, format->masterClockHz, mclkSourceClockHz);
+ }
+#endif /* FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER */
+
+ /* Set bclk if needed */
+ if (base->TCR2 & I2S_TCR2_BCD_MASK)
+ {
+ base->TCR2 &= ~I2S_TCR2_DIV_MASK;
+ base->TCR2 |= I2S_TCR2_DIV((bclkSourceClockHz / bclk) / 2U - 1U);
+ }
+
+ /* Set bitWidth */
+ if (format->protocol == kSAI_BusRightJustified)
+ {
+ base->TCR5 = I2S_TCR5_WNW(31U) | I2S_TCR5_W0W(31U) | I2S_TCR5_FBT(31U);
+ }
+ else
+ {
+ base->TCR5 = I2S_TCR5_WNW(31U) | I2S_TCR5_W0W(31U) | I2S_TCR5_FBT(format->bitWidth - 1);
+ }
+
+ /* Set mono or stereo */
+ base->TMR = (uint32_t)format->stereo;
+
+ /* Set data channel */
+ base->TCR3 &= ~I2S_TCR3_TCE_MASK;
+ base->TCR3 |= I2S_TCR3_TCE(1U << format->channel);
+
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ /* Set watermark */
+ base->TCR1 = format->watermark;
+#endif /* FSL_FEATURE_SAI_FIFO_COUNT */
+}
+
+void SAI_RxSetFormat(I2S_Type *base,
+ sai_transfer_format_t *format,
+ uint32_t mclkSourceClockHz,
+ uint32_t bclkSourceClockHz)
+{
+ uint32_t bclk = format->sampleRate_Hz * 32U * 2U;
+
+/* Compute the mclk */
+#if defined(FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER) && (FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER)
+ /* Check if master clock divider enabled */
+ if (base->MCR & I2S_MCR_MOE_MASK)
+ {
+ SAI_SetMasterClockDivider(base, format->masterClockHz, mclkSourceClockHz);
+ }
+#endif /* FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER */
+
+ /* Set bclk if needed */
+ if (base->RCR2 & I2S_RCR2_BCD_MASK)
+ {
+ base->RCR2 &= ~I2S_RCR2_DIV_MASK;
+ base->RCR2 |= I2S_RCR2_DIV((bclkSourceClockHz / bclk) / 2U - 1U);
+ }
+
+ /* Set bitWidth */
+ if (format->protocol == kSAI_BusRightJustified)
+ {
+ base->RCR5 = I2S_RCR5_WNW(31U) | I2S_RCR5_W0W(31U) | I2S_RCR5_FBT(31U);
+ }
+ else
+ {
+ base->RCR5 = I2S_RCR5_WNW(31U) | I2S_RCR5_W0W(31U) | I2S_RCR5_FBT(format->bitWidth - 1);
+ }
+
+ /* Set mono or stereo */
+ base->RMR = (uint32_t)format->stereo;
+
+ /* Set data channel */
+ base->RCR3 &= ~I2S_RCR3_RCE_MASK;
+ base->RCR3 |= I2S_RCR3_RCE(1U << format->channel);
+
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ /* Set watermark */
+ base->RCR1 = format->watermark;
+#endif /* FSL_FEATURE_SAI_FIFO_COUNT */
+}
+
+void SAI_WriteBlocking(I2S_Type *base, uint32_t channel, uint32_t bitWidth, uint8_t *buffer, uint32_t size)
+{
+ uint32_t i = 0;
+ uint8_t bytesPerWord = bitWidth / 8U;
+
+ for (i = 0; i < size; i++)
+ {
+ /* Wait until it can write data */
+ while (!(base->TCSR & I2S_TCSR_FWF_MASK))
+ {
+ }
+
+ SAI_WriteNonBlocking(base, channel, bitWidth, buffer, bytesPerWord);
+ buffer += bytesPerWord;
+ }
+
+ /* Wait until the last data is sent */
+ while (!(base->TCSR & I2S_TCSR_FWF_MASK))
+ {
+ }
+}
+
+void SAI_ReadBlocking(I2S_Type *base, uint32_t channel, uint32_t bitWidth, uint8_t *buffer, uint32_t size)
+{
+ uint32_t i = 0;
+ uint8_t bytesPerWord = bitWidth / 8U;
+
+ for (i = 0; i < size; i++)
+ {
+ /* Wait until data is received */
+ while (!(base->RCSR & I2S_RCSR_FWF_MASK))
+ {
+ }
+
+ SAI_ReadNonBlocking(base, channel, bitWidth, buffer, bytesPerWord);
+ buffer += bytesPerWord;
+ }
+}
+
+void SAI_TransferTxCreateHandle(I2S_Type *base, sai_handle_t *handle, sai_transfer_callback_t callback, void *userData)
+{
+ assert(handle);
+
+ s_saiHandle[SAI_GetInstance(base)][0] = handle;
+
+ handle->callback = callback;
+ handle->userData = userData;
+
+ /* Set the isr pointer */
+ s_saiTxIsr = SAI_TransferTxHandleIRQ;
+
+ /* Enable Tx irq */
+ EnableIRQ(s_saiTxIRQ[SAI_GetInstance(base)]);
+}
+
+void SAI_TransferRxCreateHandle(I2S_Type *base, sai_handle_t *handle, sai_transfer_callback_t callback, void *userData)
+{
+ assert(handle);
+
+ s_saiHandle[SAI_GetInstance(base)][1] = handle;
+
+ handle->callback = callback;
+ handle->userData = userData;
+
+ /* Set the isr pointer */
+ s_saiRxIsr = SAI_TransferRxHandleIRQ;
+
+ /* Enable Rx irq */
+ EnableIRQ(s_saiRxIRQ[SAI_GetInstance(base)]);
+}
+
+status_t SAI_TransferTxSetFormat(I2S_Type *base,
+ sai_handle_t *handle,
+ sai_transfer_format_t *format,
+ uint32_t mclkSourceClockHz,
+ uint32_t bclkSourceClockHz)
+{
+ assert(handle);
+
+ if ((mclkSourceClockHz < format->sampleRate_Hz) || (bclkSourceClockHz < format->sampleRate_Hz))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Copy format to handle */
+ handle->bitWidth = format->bitWidth;
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ handle->watermark = format->watermark;
+#endif
+ handle->channel = format->channel;
+
+ SAI_TxSetFormat(base, format, mclkSourceClockHz, bclkSourceClockHz);
+
+ return kStatus_Success;
+}
+
+status_t SAI_TransferRxSetFormat(I2S_Type *base,
+ sai_handle_t *handle,
+ sai_transfer_format_t *format,
+ uint32_t mclkSourceClockHz,
+ uint32_t bclkSourceClockHz)
+{
+ assert(handle);
+
+ if ((mclkSourceClockHz < format->sampleRate_Hz) || (bclkSourceClockHz < format->sampleRate_Hz))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Copy format to handle */
+ handle->bitWidth = format->bitWidth;
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ handle->watermark = format->watermark;
+#endif
+ handle->channel = format->channel;
+
+ SAI_RxSetFormat(base, format, mclkSourceClockHz, bclkSourceClockHz);
+
+ return kStatus_Success;
+}
+
+status_t SAI_TransferSendNonBlocking(I2S_Type *base, sai_handle_t *handle, sai_transfer_t *xfer)
+{
+ assert(handle);
+
+ /* Check if the queue is full */
+ if (handle->saiQueue[handle->queueUser].data)
+ {
+ return kStatus_SAI_QueueFull;
+ }
+
+ /* Add into queue */
+ handle->transferSize[handle->queueUser] = xfer->dataSize;
+ handle->saiQueue[handle->queueUser].data = xfer->data;
+ handle->saiQueue[handle->queueUser].dataSize = xfer->dataSize;
+ handle->queueUser = (handle->queueUser + 1) % SAI_XFER_QUEUE_SIZE;
+
+ /* Set the state to busy */
+ handle->state = kSAI_Busy;
+
+/* Enable interrupt */
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ /* Use FIFO request interrupt and fifo error*/
+ SAI_TxEnableInterrupts(base, kSAI_FIFOErrorInterruptEnable | kSAI_FIFORequestInterruptEnable);
+#else
+ SAI_TxEnableInterrupts(base, kSAI_FIFOErrorInterruptEnable | kSAI_FIFOWarningInterruptEnable);
+#endif /* FSL_FEATURE_SAI_FIFO_COUNT */
+
+ /* Enable Tx transfer */
+ SAI_TxEnable(base, true);
+
+ return kStatus_Success;
+}
+
+status_t SAI_TransferReceiveNonBlocking(I2S_Type *base, sai_handle_t *handle, sai_transfer_t *xfer)
+{
+ assert(handle);
+
+ /* Check if the queue is full */
+ if (handle->saiQueue[handle->queueUser].data)
+ {
+ return kStatus_SAI_QueueFull;
+ }
+
+ /* Add into queue */
+ handle->transferSize[handle->queueUser] = xfer->dataSize;
+ handle->saiQueue[handle->queueUser].data = xfer->data;
+ handle->saiQueue[handle->queueUser].dataSize = xfer->dataSize;
+ handle->queueUser = (handle->queueUser + 1) % SAI_XFER_QUEUE_SIZE;
+
+ /* Set state to busy */
+ handle->state = kSAI_Busy;
+
+/* Enable interrupt */
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ /* Use FIFO request interrupt and fifo error*/
+ SAI_RxEnableInterrupts(base, kSAI_FIFOErrorInterruptEnable | kSAI_FIFORequestInterruptEnable);
+#else
+ SAI_RxEnableInterrupts(base, kSAI_FIFOErrorInterruptEnable | kSAI_FIFOWarningInterruptEnable);
+#endif /* FSL_FEATURE_SAI_FIFO_COUNT */
+
+ /* Enable Rx transfer */
+ SAI_RxEnable(base, true);
+
+ return kStatus_Success;
+}
+
+status_t SAI_TransferGetSendCount(I2S_Type *base, sai_handle_t *handle, size_t *count)
+{
+ assert(handle);
+
+ status_t status = kStatus_Success;
+
+ if (handle->state != kSAI_Busy)
+ {
+ status = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ *count = (handle->transferSize[handle->queueDriver] - handle->saiQueue[handle->queueDriver].dataSize);
+ }
+
+ return status;
+}
+
+status_t SAI_TransferGetReceiveCount(I2S_Type *base, sai_handle_t *handle, size_t *count)
+{
+ assert(handle);
+
+ status_t status = kStatus_Success;
+
+ if (handle->state != kSAI_Busy)
+ {
+ status = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ *count = (handle->transferSize[handle->queueDriver] - handle->saiQueue[handle->queueDriver].dataSize);
+ }
+
+ return status;
+}
+
+void SAI_TransferAbortSend(I2S_Type *base, sai_handle_t *handle)
+{
+ assert(handle);
+
+ /* Stop Tx transfer and disable interrupt */
+ SAI_TxEnable(base, false);
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ /* Use FIFO request interrupt and fifo error */
+ SAI_TxDisableInterrupts(base, kSAI_FIFOErrorInterruptEnable | kSAI_FIFORequestInterruptEnable);
+#else
+ SAI_TxDisableInterrupts(base, kSAI_FIFOErrorInterruptEnable | kSAI_FIFOWarningInterruptEnable);
+#endif /* FSL_FEATURE_SAI_FIFO_COUNT */
+
+ handle->state = kSAI_Idle;
+
+ /* Clear the queue */
+ memset(handle->saiQueue, 0, sizeof(sai_transfer_t) * SAI_XFER_QUEUE_SIZE);
+ handle->queueDriver = 0;
+ handle->queueUser = 0;
+}
+
+void SAI_TransferAbortReceive(I2S_Type *base, sai_handle_t *handle)
+{
+ assert(handle);
+
+ /* Stop Tx transfer and disable interrupt */
+ SAI_RxEnable(base, false);
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ /* Use FIFO request interrupt and fifo error */
+ SAI_RxDisableInterrupts(base, kSAI_FIFOErrorInterruptEnable | kSAI_FIFORequestInterruptEnable);
+#else
+ SAI_RxDisableInterrupts(base, kSAI_FIFOErrorInterruptEnable | kSAI_FIFOWarningInterruptEnable);
+#endif /* FSL_FEATURE_SAI_FIFO_COUNT */
+
+ handle->state = kSAI_Idle;
+
+ /* Clear the queue */
+ memset(handle->saiQueue, 0, sizeof(sai_transfer_t) * SAI_XFER_QUEUE_SIZE);
+ handle->queueDriver = 0;
+ handle->queueUser = 0;
+}
+
+void SAI_TransferTxHandleIRQ(I2S_Type *base, sai_handle_t *handle)
+{
+ assert(handle);
+
+ uint8_t *buffer = handle->saiQueue[handle->queueDriver].data;
+ uint8_t dataSize = handle->bitWidth / 8U;
+
+ /* Handle Error */
+ if (base->TCSR & I2S_TCSR_FEF_MASK)
+ {
+ /* Clear FIFO error flag to continue transfer */
+ SAI_TxClearStatusFlags(base, kSAI_FIFOErrorFlag);
+
+ /* Call the callback */
+ if (handle->callback)
+ {
+ (handle->callback)(base, handle, kStatus_SAI_TxError, handle->userData);
+ }
+ }
+
+/* Handle transfer */
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if (base->TCSR & I2S_TCSR_FRF_MASK)
+ {
+ /* Judge if the data need to transmit is less than space */
+ uint8_t size = MIN((handle->saiQueue[handle->queueDriver].dataSize),
+ (size_t)((FSL_FEATURE_SAI_FIFO_COUNT - handle->watermark) * dataSize));
+
+ /* Copy the data from sai buffer to FIFO */
+ SAI_WriteNonBlocking(base, handle->channel, handle->bitWidth, buffer, size);
+
+ /* Update the internal counter */
+ handle->saiQueue[handle->queueDriver].dataSize -= size;
+ handle->saiQueue[handle->queueDriver].data += size;
+ }
+#else
+ if (base->TCSR & I2S_TCSR_FWF_MASK)
+ {
+ uint8_t size = MIN((handle->saiQueue[handle->queueDriver].dataSize), dataSize);
+
+ SAI_WriteNonBlocking(base, handle->channel, handle->bitWidth, buffer, size);
+
+ /* Update internal counter */
+ handle->saiQueue[handle->queueDriver].dataSize -= size;
+ handle->saiQueue[handle->queueDriver].data += size;
+ }
+#endif /* FSL_FEATURE_SAI_FIFO_COUNT */
+
+ /* If finished a blcok, call the callback function */
+ if (handle->saiQueue[handle->queueDriver].dataSize == 0U)
+ {
+ memset(&handle->saiQueue[handle->queueDriver], 0, sizeof(sai_transfer_t));
+ handle->queueDriver = (handle->queueDriver + 1) % SAI_XFER_QUEUE_SIZE;
+ if (handle->callback)
+ {
+ (handle->callback)(base, handle, kStatus_SAI_TxIdle, handle->userData);
+ }
+ }
+
+ /* If all data finished, just stop the transfer */
+ if (handle->saiQueue[handle->queueDriver].data == NULL)
+ {
+ SAI_TransferAbortSend(base, handle);
+ }
+}
+
+void SAI_TransferRxHandleIRQ(I2S_Type *base, sai_handle_t *handle)
+{
+ assert(handle);
+
+ uint8_t *buffer = handle->saiQueue[handle->queueDriver].data;
+ uint8_t dataSize = handle->bitWidth / 8U;
+
+ /* Handle Error */
+ if (base->RCSR & I2S_RCSR_FEF_MASK)
+ {
+ /* Clear FIFO error flag to continue transfer */
+ SAI_RxClearStatusFlags(base, kSAI_FIFOErrorFlag);
+
+ /* Call the callback */
+ if (handle->callback)
+ {
+ (handle->callback)(base, handle, kStatus_SAI_RxError, handle->userData);
+ }
+ }
+
+/* Handle transfer */
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if (base->RCSR & I2S_RCSR_FRF_MASK)
+ {
+ /* Judge if the data need to transmit is less than space */
+ uint8_t size = MIN((handle->saiQueue[handle->queueDriver].dataSize), (handle->watermark * dataSize));
+
+ /* Copy the data from sai buffer to FIFO */
+ SAI_ReadNonBlocking(base, handle->channel, handle->bitWidth, buffer, size);
+
+ /* Update the internal counter */
+ handle->saiQueue[handle->queueDriver].dataSize -= size;
+ handle->saiQueue[handle->queueDriver].data += size;
+ }
+#else
+ if (base->RCSR & I2S_RCSR_FWF_MASK)
+ {
+ uint8_t size = MIN((handle->saiQueue[handle->queueDriver].dataSize), dataSize);
+
+ SAI_ReadNonBlocking(base, handle->channel, handle->bitWidth, buffer, size);
+
+ /* Update internal state */
+ handle->saiQueue[handle->queueDriver].dataSize -= size;
+ handle->saiQueue[handle->queueDriver].data += size;
+ }
+#endif /* FSL_FEATURE_SAI_FIFO_COUNT */
+
+ /* If finished a blcok, call the callback function */
+ if (handle->saiQueue[handle->queueDriver].dataSize == 0U)
+ {
+ memset(&handle->saiQueue[handle->queueDriver], 0, sizeof(sai_transfer_t));
+ handle->queueDriver = (handle->queueDriver + 1) % SAI_XFER_QUEUE_SIZE;
+ if (handle->callback)
+ {
+ (handle->callback)(base, handle, kStatus_SAI_RxIdle, handle->userData);
+ }
+ }
+
+ /* If all data finished, just stop the transfer */
+ if (handle->saiQueue[handle->queueDriver].data == NULL)
+ {
+ SAI_TransferAbortReceive(base, handle);
+ }
+}
+
+#if defined(I2S0)
+#if defined(FSL_FEATURE_SAI_INT_SOURCE_NUM) && (FSL_FEATURE_SAI_INT_SOURCE_NUM == 1)
+void I2S0_DriverIRQHandler(void)
+{
+ if ((s_saiHandle[0][1]) && ((I2S0->RCSR & kSAI_FIFOWarningFlag) || (I2S0->RCSR & kSAI_FIFOErrorFlag)))
+ {
+ s_saiRxIsr(I2S0, s_saiHandle[0][1]);
+ }
+ if ((s_saiHandle[0][0]) && ((I2S0->TCSR & kSAI_FIFOWarningFlag) || (I2S0->TCSR & kSAI_FIFOErrorFlag)))
+ {
+ s_saiTxIsr(I2S0, s_saiHandle[0][0]);
+ }
+}
+#else
+void I2S0_Tx_DriverIRQHandler(void)
+{
+ assert(s_saiHandle[0][0]);
+ s_saiTxIsr(I2S0, s_saiHandle[0][0]);
+}
+
+void I2S0_Rx_DriverIRQHandler(void)
+{
+ assert(s_saiHandle[0][1]);
+ s_saiRxIsr(I2S0, s_saiHandle[0][1]);
+}
+#endif /* FSL_FEATURE_SAI_INT_SOURCE_NUM */
+#endif /* I2S0*/
+
+#if defined(I2S1)
+void I2S1_Tx_DriverIRQHandler(void)
+{
+ assert(s_saiHandle[1][0]);
+ s_saiTxIsr(I2S1, s_saiHandle[1][0]);
+}
+
+void I2S1_Rx_DriverIRQHandler(void)
+{
+ assert(s_saiHandle[1][1]);
+ s_saiRxIsr(I2S1, s_saiHandle[1][1]);
+}
+#endif
diff --git a/drivers/src/fsl_sai_edma.c b/drivers/src/fsl_sai_edma.c
new file mode 100644
index 0000000..9b1b2f6
--- /dev/null
+++ b/drivers/src/fsl_sai_edma.c
@@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of Freescale Semiconductor, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsl_sai_edma.h"
+
+/*******************************************************************************
+ * Definitations
+ ******************************************************************************/
+/* Used for 32byte aligned */
+#define STCD_ADDR(address) (edma_tcd_t *)(((uint32_t)address + 32) & ~0x1FU)
+
+/*<! Structure definition for uart_edma_private_handle_t. The structure is private. */
+typedef struct _sai_edma_private_handle
+{
+ I2S_Type *base;
+ sai_edma_handle_t *handle;
+} sai_edma_private_handle_t;
+
+enum _sai_edma_transfer_state
+{
+ kSAI_Busy = 0x0U, /*!< SAI is busy */
+ kSAI_Idle, /*!< Transfer is done. */
+};
+
+/*<! Private handle only used for internally. */
+static sai_edma_private_handle_t s_edmaPrivateHandle[FSL_FEATURE_SOC_I2S_COUNT][2];
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Get the instance number for SAI.
+ *
+ * @param base SAI base pointer.
+ */
+extern uint32_t SAI_GetInstance(I2S_Type *base);
+
+/*!
+ * @brief SAI EDMA callback for send.
+ *
+ * @param handle pointer to sai_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 SAI_TxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds);
+
+/*!
+ * @brief SAI EDMA callback for receive.
+ *
+ * @param handle pointer to sai_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 SAI_RxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds);
+
+/*******************************************************************************
+* Code
+******************************************************************************/
+static void SAI_TxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds)
+{
+ sai_edma_private_handle_t *privHandle = (sai_edma_private_handle_t *)userData;
+ sai_edma_handle_t *saiHandle = privHandle->handle;
+
+ /* If finished a blcok, call the callback function */
+ memset(&saiHandle->saiQueue[saiHandle->queueDriver], 0, sizeof(sai_transfer_t));
+ saiHandle->queueDriver = (saiHandle->queueDriver + 1) % SAI_XFER_QUEUE_SIZE;
+ if (saiHandle->callback)
+ {
+ (saiHandle->callback)(privHandle->base, saiHandle, kStatus_SAI_TxIdle, saiHandle->userData);
+ }
+
+ /* If all data finished, just stop the transfer */
+ if (saiHandle->saiQueue[saiHandle->queueDriver].data == NULL)
+ {
+ SAI_TransferAbortSendEDMA(privHandle->base, saiHandle);
+ }
+}
+
+static void SAI_RxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds)
+{
+ sai_edma_private_handle_t *privHandle = (sai_edma_private_handle_t *)userData;
+ sai_edma_handle_t *saiHandle = privHandle->handle;
+
+ /* If finished a blcok, call the callback function */
+ memset(&saiHandle->saiQueue[saiHandle->queueDriver], 0, sizeof(sai_transfer_t));
+ saiHandle->queueDriver = (saiHandle->queueDriver + 1) % SAI_XFER_QUEUE_SIZE;
+ if (saiHandle->callback)
+ {
+ (saiHandle->callback)(privHandle->base, saiHandle, kStatus_SAI_RxIdle, saiHandle->userData);
+ }
+
+ /* If all data finished, just stop the transfer */
+ if (saiHandle->saiQueue[saiHandle->queueDriver].data == NULL)
+ {
+ SAI_TransferAbortReceiveEDMA(privHandle->base, saiHandle);
+ }
+}
+
+void SAI_TransferTxCreateHandleEDMA(
+ I2S_Type *base, sai_edma_handle_t *handle, sai_edma_callback_t callback, void *userData, edma_handle_t *dmaHandle)
+{
+ assert(handle && dmaHandle);
+
+ uint32_t instance = SAI_GetInstance(base);
+
+ /* Set sai base to handle */
+ handle->dmaHandle = dmaHandle;
+ handle->callback = callback;
+ handle->userData = userData;
+
+ /* Set SAI state to idle */
+ handle->state = kSAI_Idle;
+
+ s_edmaPrivateHandle[instance][0].base = base;
+ s_edmaPrivateHandle[instance][0].handle = handle;
+
+ /* Need to use scatter gather */
+ EDMA_InstallTCDMemory(dmaHandle, STCD_ADDR(handle->tcd), SAI_XFER_QUEUE_SIZE);
+
+ /* Install callback for Tx dma channel */
+ EDMA_SetCallback(dmaHandle, SAI_TxEDMACallback, &s_edmaPrivateHandle[instance][0]);
+}
+
+void SAI_TransferRxCreateHandleEDMA(
+ I2S_Type *base, sai_edma_handle_t *handle, sai_edma_callback_t callback, void *userData, edma_handle_t *dmaHandle)
+{
+ assert(handle && dmaHandle);
+
+ uint32_t instance = SAI_GetInstance(base);
+
+ /* Set sai base to handle */
+ handle->dmaHandle = dmaHandle;
+ handle->callback = callback;
+ handle->userData = userData;
+
+ /* Set SAI state to idle */
+ handle->state = kSAI_Idle;
+
+ s_edmaPrivateHandle[instance][1].base = base;
+ s_edmaPrivateHandle[instance][1].handle = handle;
+
+ /* Need to use scatter gather */
+ EDMA_InstallTCDMemory(dmaHandle, STCD_ADDR(handle->tcd), SAI_XFER_QUEUE_SIZE);
+
+ /* Install callback for Tx dma channel */
+ EDMA_SetCallback(dmaHandle, SAI_RxEDMACallback, &s_edmaPrivateHandle[instance][1]);
+}
+
+void SAI_TransferTxSetFormatEDMA(I2S_Type *base,
+ sai_edma_handle_t *handle,
+ sai_transfer_format_t *format,
+ uint32_t mclkSourceClockHz,
+ uint32_t bclkSourceClockHz)
+{
+ assert(handle && format);
+
+ /* Configure the audio format to SAI registers */
+ SAI_TxSetFormat(base, format, mclkSourceClockHz, bclkSourceClockHz);
+
+ /* Get the tranfer size from format, this should be used in EDMA configuration */
+ handle->bytesPerFrame = format->bitWidth / 8U;
+
+ /* Update the data channel SAI used */
+ handle->channel = format->channel;
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ handle->count = FSL_FEATURE_SAI_FIFO_COUNT - format->watermark;
+#else
+ handle->count = 1U;
+#endif /* FSL_FEATURE_SAI_FIFO_COUNT */
+}
+
+void SAI_TransferRxSetFormatEDMA(I2S_Type *base,
+ sai_edma_handle_t *handle,
+ sai_transfer_format_t *format,
+ uint32_t mclkSourceClockHz,
+ uint32_t bclkSourceClockHz)
+{
+ assert(handle && format);
+
+ /* Configure the audio format to SAI registers */
+ SAI_RxSetFormat(base, format, mclkSourceClockHz, bclkSourceClockHz);
+
+ /* Get the tranfer size from format, this should be used in EDMA configuration */
+ handle->bytesPerFrame = format->bitWidth / 8U;
+
+ /* Update the data channel SAI used */
+ handle->channel = format->channel;
+
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ handle->count = format->watermark;
+#else
+ handle->count = 1U;
+#endif /* FSL_FEATURE_SAI_FIFO_COUNT */
+}
+
+status_t SAI_TransferSendEDMA(I2S_Type *base, sai_edma_handle_t *handle, sai_transfer_t *xfer)
+{
+ assert(handle && xfer);
+
+ edma_transfer_config_t config = {0};
+ uint32_t destAddr = SAI_TxGetDataRegisterAddress(base, handle->channel);
+
+ /* Check if input parameter invalid */
+ if ((xfer->data == NULL) || (xfer->dataSize == 0U))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ if (handle->saiQueue[handle->queueUser].data)
+ {
+ return kStatus_SAI_QueueFull;
+ }
+
+ /* Change the state of handle */
+ handle->state = kSAI_Busy;
+
+ /* Update the queue state */
+ handle->transferSize[handle->queueUser] = xfer->dataSize;
+ handle->saiQueue[handle->queueUser].data = xfer->data;
+ handle->saiQueue[handle->queueUser].dataSize = xfer->dataSize;
+ handle->queueUser = (handle->queueUser + 1) % SAI_XFER_QUEUE_SIZE;
+
+ /* Prepare edma configure */
+ EDMA_PrepareTransfer(&config, xfer->data, handle->bytesPerFrame, (void *)destAddr, handle->bytesPerFrame,
+ handle->count * handle->bytesPerFrame, xfer->dataSize, kEDMA_MemoryToPeripheral);
+
+ EDMA_SubmitTransfer(handle->dmaHandle, &config);
+
+ /* Start DMA transfer */
+ EDMA_StartTransfer(handle->dmaHandle);
+
+ /* Enable DMA enable bit */
+ SAI_TxEnableDMA(base, kSAI_FIFORequestDMAEnable, true);
+
+ /* Enable SAI Tx clock */
+ SAI_TxEnable(base, true);
+
+ return kStatus_Success;
+}
+
+status_t SAI_TransferReceiveEDMA(I2S_Type *base, sai_edma_handle_t *handle, sai_transfer_t *xfer)
+{
+ assert(handle && xfer);
+
+ edma_transfer_config_t config = {0};
+ uint32_t srcAddr = SAI_RxGetDataRegisterAddress(base, handle->channel);
+
+ /* Check if input parameter invalid */
+ if ((xfer->data == NULL) || (xfer->dataSize == 0U))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ if (handle->saiQueue[handle->queueUser].data)
+ {
+ return kStatus_SAI_QueueFull;
+ }
+
+ /* Change the state of handle */
+ handle->state = kSAI_Busy;
+
+ /* Update queue state */
+ handle->transferSize[handle->queueUser] = xfer->dataSize;
+ handle->saiQueue[handle->queueUser].data = xfer->data;
+ handle->saiQueue[handle->queueUser].dataSize = xfer->dataSize;
+ handle->queueUser = (handle->queueUser + 1) % SAI_XFER_QUEUE_SIZE;
+
+ /* Prepare edma configure */
+ EDMA_PrepareTransfer(&config, (void *)srcAddr, handle->bytesPerFrame, xfer->data, handle->bytesPerFrame,
+ handle->count * handle->bytesPerFrame, xfer->dataSize, kEDMA_PeripheralToMemory);
+
+ EDMA_SubmitTransfer(handle->dmaHandle, &config);
+
+ /* Start DMA transfer */
+ EDMA_StartTransfer(handle->dmaHandle);
+
+ /* Enable DMA enable bit */
+ SAI_RxEnableDMA(base, kSAI_FIFORequestDMAEnable, true);
+
+ /* Enable SAI Rx clock */
+ SAI_RxEnable(base, true);
+
+ return kStatus_Success;
+}
+
+void SAI_TransferAbortSendEDMA(I2S_Type *base, sai_edma_handle_t *handle)
+{
+ assert(handle);
+
+ /* Disable dma */
+ EDMA_AbortTransfer(handle->dmaHandle);
+
+ /* Disable DMA enable bit */
+ SAI_TxEnableDMA(base, kSAI_FIFORequestDMAEnable, false);
+
+ /* Set the handle state */
+ handle->state = kSAI_Idle;
+}
+
+void SAI_TransferAbortReceiveEDMA(I2S_Type *base, sai_edma_handle_t *handle)
+{
+ assert(handle);
+
+ /* Disable dma */
+ EDMA_AbortTransfer(handle->dmaHandle);
+
+ /* Disable DMA enable bit */
+ SAI_RxEnableDMA(base, kSAI_FIFORequestDMAEnable, false);
+
+ /* Set the handle state */
+ handle->state = kSAI_Idle;
+}
+
+status_t SAI_TransferGetSendCountEDMA(I2S_Type *base, sai_edma_handle_t *handle, size_t *count)
+{
+ assert(handle);
+
+ status_t status = kStatus_Success;
+
+ if (handle->state != kSAI_Busy)
+ {
+ status = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ *count = (handle->transferSize[handle->queueDriver] -
+ EDMA_GetRemainingBytes(handle->dmaHandle->base, handle->dmaHandle->channel));
+ }
+
+ return status;
+}
+
+status_t SAI_TransferGetReceiveCountEDMA(I2S_Type *base, sai_edma_handle_t *handle, size_t *count)
+{
+ assert(handle);
+
+ status_t status = kStatus_Success;
+
+ if (handle->state != kSAI_Busy)
+ {
+ status = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ *count = (handle->transferSize[handle->queueDriver] -
+ EDMA_GetRemainingBytes(handle->dmaHandle->base, handle->dmaHandle->channel));
+ }
+
+ return status;
+}
diff --git a/drivers/src/fsl_sdhc.c b/drivers/src/fsl_sdhc.c
new file mode 100644
index 0000000..3151cd2
--- /dev/null
+++ b/drivers/src/fsl_sdhc.c
@@ -0,0 +1,1416 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsl_sdhc.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+/*! @brief Clock setting */
+/* Max SD clock divisor from base clock */
+#define SDHC_MAX_DVS ((SDHC_SYSCTL_DVS_MASK >> SDHC_SYSCTL_DVS_SHIFT) + 1U)
+#define SDHC_PREV_DVS(x) ((x) -= 1U)
+#define SDHC_MAX_CLKFS ((SDHC_SYSCTL_SDCLKFS_MASK >> SDHC_SYSCTL_SDCLKFS_SHIFT) + 1U)
+#define SDHC_PREV_CLKFS(x) ((x) >>= 1U)
+
+/* Typedef for interrupt handler. */
+typedef void (*sdhc_isr_t)(SDHC_Type *base, sdhc_handle_t *handle);
+
+/*! @brief ADMA table configuration */
+typedef struct _sdhc_adma_table_config
+{
+ uint32_t *admaTable; /*!< ADMA table address, can't be null if transfer way is ADMA1/ADMA2 */
+ uint32_t admaTableWords; /*!< ADMA table length united as words, can't be 0 if transfer way is ADMA1/ADMA2 */
+} sdhc_adma_table_config_t;
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Get the instance.
+ *
+ * @param base SDHC peripheral base address.
+ * @return Instance number.
+ */
+static uint32_t SDHC_GetInstance(SDHC_Type *base);
+
+/*!
+ * @brief Set transfer interrupt.
+ *
+ * @param base SDHC peripheral base address.
+ * @param usingInterruptSignal True to use IRQ signal.
+ */
+static void SDHC_SetTransferInterrupt(SDHC_Type *base, bool usingInterruptSignal);
+
+/*!
+ * @brief Start transfer according to current transfer state
+ *
+ * @param base SDHC peripheral base address.
+ * @param command Command to be sent.
+ * @param data Data to be transferred.
+ * @param DMA mode selection
+ */
+static void SDHC_StartTransfer(SDHC_Type *base, sdhc_command_t *command, sdhc_data_t *data, sdhc_dma_mode_t dmaMode);
+
+/*!
+ * @brief Receive command response
+ *
+ * @param base SDHC peripheral base address.
+ * @param command Command to be sent.
+ */
+static status_t SDHC_ReceiveCommandResponse(SDHC_Type *base, sdhc_command_t *command);
+
+/*!
+ * @brief Read DATAPORT when buffer enable bit is set.
+ *
+ * @param base SDHC peripheral base address.
+ * @param data Data to be read.
+ * @param transferredWords The number of data words have been transferred last time transaction.
+ * @return The number of total data words have been transferred after this time transaction.
+ */
+static uint32_t SDHC_ReadDataPort(SDHC_Type *base, sdhc_data_t *data, uint32_t transferredWords);
+
+/*!
+ * @brief Read data by using DATAPORT polling way.
+ *
+ * @param base SDHC peripheral base address.
+ * @param data Data to be read.
+ * @retval kStatus_Fail Read DATAPORT failed.
+ * @retval kStatus_Success Operate successfully.
+ */
+static status_t SDHC_ReadByDataPortBlocking(SDHC_Type *base, sdhc_data_t *data);
+
+/*!
+ * @brief Write DATAPORT when buffer enable bit is set.
+ *
+ * @param base SDHC peripheral base address.
+ * @param data Data to be read.
+ * @param transferredWords The number of data words have been transferred last time.
+ * @return The number of total data words have been transferred after this time transaction.
+ */
+static uint32_t SDHC_WriteDataPort(SDHC_Type *base, sdhc_data_t *data, uint32_t transferredWords);
+
+/*!
+ * @brief Write data by using DATAPORT polling way.
+ *
+ * @param base SDHC peripheral base address.
+ * @param data Data to be transferred.
+ * @retval kStatus_Fail Write DATAPORT failed.
+ * @retval kStatus_Success Operate successfully.
+ */
+static status_t SDHC_WriteByDataPortBlocking(SDHC_Type *base, sdhc_data_t *data);
+
+/*!
+ * @brief Send command by using polling way.
+ *
+ * @param base SDHC peripheral base address.
+ * @param command Command to be sent.
+ * @retval kStatus_Fail Send command failed.
+ * @retval kStatus_Success Operate successfully.
+ */
+static status_t SDHC_SendCommandBlocking(SDHC_Type *base, sdhc_command_t *command);
+
+/*!
+ * @brief Transfer data by DATAPORT and polling way.
+ *
+ * @param base SDHC peripheral base address.
+ * @param data Data to be transferred.
+ * @retval kStatus_Fail Transfer data failed.
+ * @retval kStatus_Success Operate successfully.
+ */
+static status_t SDHC_TransferByDataPortBlocking(SDHC_Type *base, sdhc_data_t *data);
+
+/*!
+ * @brief Transfer data by ADMA2 and polling way.
+ *
+ * @param base SDHC peripheral base address.
+ * @param data Data to be transferred.
+ * @retval kStatus_Fail Transfer data failed.
+ * @retval kStatus_Success Operate successfully.
+ */
+static status_t SDHC_TransferByAdma2Blocking(SDHC_Type *base, sdhc_data_t *data);
+
+/*!
+ * @brief Transfer data by polling way.
+ *
+ * @param dmaMode DMA mode.
+ * @param base SDHC peripheral base address.
+ * @param data Data to be transferred.
+ * @retval kStatus_Fail Transfer data failed.
+ * @retval kStatus_InvalidArgument Argument is invalid.
+ * @retval kStatus_Success Operate successfully.
+ */
+static status_t SDHC_TransferDataBlocking(sdhc_dma_mode_t dmaMode, SDHC_Type *base, sdhc_data_t *data);
+
+/*!
+ * @brief Handle card detect interrupt.
+ *
+ * @param handle SDHC handle.
+ * @param interruptFlags Card detect related interrupt flags.
+ */
+static void SDHC_TransferHandleCardDetect(sdhc_handle_t *handle, uint32_t interruptFlags);
+
+/*!
+ * @brief Handle command interrupt.
+ *
+ * @param base SDHC peripheral base address.
+ * @param handle SDHC handle.
+ * @param interruptFlags Command related interrupt flags.
+ */
+static void SDHC_TransferHandleCommand(SDHC_Type *base, sdhc_handle_t *handle, uint32_t interruptFlags);
+
+/*!
+ * @brief Handle data interrupt.
+ *
+ * @param base SDHC peripheral base address.
+ * @param handle SDHC handle.
+ * @param interruptFlags Data related interrupt flags.
+ */
+static void SDHC_TransferHandleData(SDHC_Type *base, sdhc_handle_t *handle, uint32_t interruptFlags);
+
+/*!
+ * @brief Handle SDIO card interrupt signal.
+ *
+ * @param handle SDHC handle.
+ */
+static void SDHC_TransferHandleSdioInterrupt(sdhc_handle_t *handle);
+
+/*!
+ * @brief Handle SDIO block gap event.
+ *
+ * @param handle SDHC handle.
+ */
+static void SDHC_TransferHandleSdioBlockGap(sdhc_handle_t *handle);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief SDHC internal handle pointer array */
+static sdhc_handle_t *s_sdhcHandle[FSL_FEATURE_SOC_SDHC_COUNT];
+
+/*! @brief SDHC base pointer array */
+static SDHC_Type *const s_sdhcBase[] = SDHC_BASE_PTRS;
+
+/*! @brief SDHC IRQ name array */
+static const IRQn_Type s_sdhcIRQ[] = SDHC_IRQS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief SDHC clock array name */
+static const clock_ip_name_t s_sdhcClock[] = SDHC_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/* SDHC ISR for transactional APIs. */
+static sdhc_isr_t s_sdhcIsr;
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t SDHC_GetInstance(SDHC_Type *base)
+{
+ uint8_t instance = 0;
+
+ while ((instance < ARRAY_SIZE(s_sdhcBase)) && (s_sdhcBase[instance] != base))
+ {
+ instance++;
+ }
+
+ assert(instance < ARRAY_SIZE(s_sdhcBase));
+
+ return instance;
+}
+
+static void SDHC_SetTransferInterrupt(SDHC_Type *base, bool usingInterruptSignal)
+{
+ uint32_t interruptEnabled; /* The Interrupt status flags to be enabled */
+ bool cardDetectDat3 = (bool)(base->PROCTL & SDHC_PROCTL_D3CD_MASK);
+
+ /* Disable all interrupts */
+ SDHC_DisableInterruptStatus(base, (uint32_t)kSDHC_AllInterruptFlags);
+ SDHC_DisableInterruptSignal(base, (uint32_t)kSDHC_AllInterruptFlags);
+ DisableIRQ(s_sdhcIRQ[SDHC_GetInstance(base)]);
+
+ interruptEnabled =
+ (kSDHC_CommandIndexErrorFlag | kSDHC_CommandCrcErrorFlag | kSDHC_CommandEndBitErrorFlag |
+ kSDHC_CommandTimeoutFlag | kSDHC_CommandCompleteFlag | kSDHC_DataTimeoutFlag | kSDHC_DataCrcErrorFlag |
+ kSDHC_DataEndBitErrorFlag | kSDHC_DataCompleteFlag | kSDHC_AutoCommand12ErrorFlag | kSDHC_BufferReadReadyFlag |
+ kSDHC_BufferWriteReadyFlag | kSDHC_DmaErrorFlag | kSDHC_DmaCompleteFlag);
+ if (cardDetectDat3)
+ {
+ interruptEnabled |= (kSDHC_CardInsertionFlag | kSDHC_CardRemovalFlag);
+ }
+
+ SDHC_EnableInterruptStatus(base, interruptEnabled);
+ if (usingInterruptSignal)
+ {
+ SDHC_EnableInterruptSignal(base, interruptEnabled);
+ }
+}
+
+static void SDHC_StartTransfer(SDHC_Type *base, sdhc_command_t *command, sdhc_data_t *data, sdhc_dma_mode_t dmaMode)
+{
+ uint32_t flags = 0U;
+ sdhc_transfer_config_t sdhcTransferConfig = {0};
+
+ /* Define the flag corresponding to each response type. */
+ switch (command->responseType)
+ {
+ case kCARD_ResponseTypeNone:
+ break;
+ case kCARD_ResponseTypeR1: /* Response 1 */
+ flags |= (kSDHC_ResponseLength48Flag | kSDHC_EnableCrcCheckFlag | kSDHC_EnableIndexCheckFlag);
+ break;
+ case kCARD_ResponseTypeR1b: /* Response 1 with busy */
+ flags |= (kSDHC_ResponseLength48BusyFlag | kSDHC_EnableCrcCheckFlag | kSDHC_EnableIndexCheckFlag);
+ break;
+ case kCARD_ResponseTypeR2: /* Response 2 */
+ flags |= (kSDHC_ResponseLength136Flag | kSDHC_EnableCrcCheckFlag);
+ break;
+ case kCARD_ResponseTypeR3: /* Response 3 */
+ flags |= (kSDHC_ResponseLength48Flag);
+ break;
+ case kCARD_ResponseTypeR4: /* Response 4 */
+ flags |= (kSDHC_ResponseLength48Flag);
+ break;
+ case kCARD_ResponseTypeR5: /* Response 5 */
+ flags |= (kSDHC_ResponseLength48Flag | kSDHC_EnableCrcCheckFlag | kSDHC_EnableIndexCheckFlag);
+ break;
+ case kCARD_ResponseTypeR5b: /* Response 5 with busy */
+ flags |= (kSDHC_ResponseLength48BusyFlag | kSDHC_EnableCrcCheckFlag | kSDHC_EnableIndexCheckFlag);
+ break;
+ case kCARD_ResponseTypeR6: /* Response 6 */
+ flags |= (kSDHC_ResponseLength48Flag | kSDHC_EnableCrcCheckFlag | kSDHC_EnableIndexCheckFlag);
+ break;
+ case kCARD_ResponseTypeR7: /* Response 7 */
+ flags |= (kSDHC_ResponseLength48Flag | kSDHC_EnableCrcCheckFlag | kSDHC_EnableIndexCheckFlag);
+ break;
+ default:
+ break;
+ }
+ if (command->type == kCARD_CommandTypeAbort)
+ {
+ flags |= kSDHC_CommandTypeAbortFlag;
+ }
+
+ if (data)
+ {
+ flags |= kSDHC_DataPresentFlag;
+
+ if (dmaMode != kSDHC_DmaModeNo)
+ {
+ flags |= kSDHC_EnableDmaFlag;
+ }
+ if (data->rxData)
+ {
+ flags |= kSDHC_DataReadFlag;
+ }
+ if (data->blockCount > 1U)
+ {
+ flags |= (kSDHC_MultipleBlockFlag | kSDHC_EnableBlockCountFlag);
+ if (data->enableAutoCommand12)
+ {
+ /* Enable Auto command 12. */
+ flags |= kSDHC_EnableAutoCommand12Flag;
+ }
+ }
+
+ sdhcTransferConfig.dataBlockSize = data->blockSize;
+ sdhcTransferConfig.dataBlockCount = data->blockCount;
+ }
+ else
+ {
+ sdhcTransferConfig.dataBlockSize = 0U;
+ sdhcTransferConfig.dataBlockCount = 0U;
+ }
+
+ sdhcTransferConfig.commandArgument = command->argument;
+ sdhcTransferConfig.commandIndex = command->index;
+ sdhcTransferConfig.flags = flags;
+ SDHC_SetTransferConfig(base, &sdhcTransferConfig);
+}
+
+static status_t SDHC_ReceiveCommandResponse(SDHC_Type *base, sdhc_command_t *command)
+{
+ uint32_t i;
+
+ if (command->responseType != kCARD_ResponseTypeNone)
+ {
+ command->response[0U] = SDHC_GetCommandResponse(base, 0U);
+ if (command->responseType == kCARD_ResponseTypeR2)
+ {
+ command->response[1U] = SDHC_GetCommandResponse(base, 1U);
+ command->response[2U] = SDHC_GetCommandResponse(base, 2U);
+ command->response[3U] = SDHC_GetCommandResponse(base, 3U);
+
+ i = 4U;
+ /* R3-R2-R1-R0(lowest 8 bit is invalid bit) has the same format as R2 format in SD specification document
+ after removed internal CRC7 and end bit. */
+ do
+ {
+ command->response[i - 1U] <<= 8U;
+ if (i > 1U)
+ {
+ command->response[i - 1U] |= ((command->response[i - 2U] & 0xFF000000U) >> 24U);
+ }
+ } while (i--);
+ }
+ }
+ /* check response error flag */
+ if ((command->responseErrorFlags != 0U) &&
+ ((command->responseType == kCARD_ResponseTypeR1) || (command->responseType == kCARD_ResponseTypeR1b) ||
+ (command->responseType == kCARD_ResponseTypeR6) || (command->responseType == kCARD_ResponseTypeR5)))
+ {
+ if (((command->responseErrorFlags) & (command->response[0U])) != 0U)
+ {
+ return kStatus_SDHC_SendCommandFailed;
+ }
+ }
+
+ return kStatus_Success;
+}
+
+static uint32_t SDHC_ReadDataPort(SDHC_Type *base, sdhc_data_t *data, uint32_t transferredWords)
+{
+ uint32_t i;
+ uint32_t totalWords;
+ uint32_t wordsCanBeRead; /* The words can be read at this time. */
+ uint32_t readWatermark = ((base->WML & SDHC_WML_RDWML_MASK) >> SDHC_WML_RDWML_SHIFT);
+
+ /*
+ * Add non aligned access support ,user need make sure your buffer size is big
+ * enough to hold the data,in other words,user need make sure the buffer size
+ * is 4 byte aligned
+ */
+ if (data->blockSize % sizeof(uint32_t) != 0U)
+ {
+ data->blockSize +=
+ sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */
+ }
+
+ totalWords = ((data->blockCount * data->blockSize) / sizeof(uint32_t));
+
+ /* If watermark level is equal or bigger than totalWords, transfers totalWords data. */
+ if (readWatermark >= totalWords)
+ {
+ wordsCanBeRead = totalWords;
+ }
+ /* If watermark level is less than totalWords and left words to be sent is equal or bigger than readWatermark,
+ transfers watermark level words. */
+ else if ((readWatermark < totalWords) && ((totalWords - transferredWords) >= readWatermark))
+ {
+ wordsCanBeRead = readWatermark;
+ }
+ /* If watermark level is less than totalWords and left words to be sent is less than readWatermark, transfers left
+ words. */
+ else
+ {
+ wordsCanBeRead = (totalWords - transferredWords);
+ }
+
+ i = 0U;
+ while (i < wordsCanBeRead)
+ {
+ data->rxData[transferredWords++] = SDHC_ReadData(base);
+ i++;
+ }
+
+ return transferredWords;
+}
+
+static status_t SDHC_ReadByDataPortBlocking(SDHC_Type *base, sdhc_data_t *data)
+{
+ uint32_t totalWords;
+ uint32_t transferredWords = 0U;
+ status_t error = kStatus_Success;
+
+ /*
+ * Add non aligned access support ,user need make sure your buffer size is big
+ * enough to hold the data,in other words,user need make sure the buffer size
+ * is 4 byte aligned
+ */
+ if (data->blockSize % sizeof(uint32_t) != 0U)
+ {
+ data->blockSize +=
+ sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */
+ }
+
+ totalWords = ((data->blockCount * data->blockSize) / sizeof(uint32_t));
+
+ while ((error == kStatus_Success) && (transferredWords < totalWords))
+ {
+ while (!(SDHC_GetInterruptStatusFlags(base) & (kSDHC_BufferReadReadyFlag | kSDHC_DataErrorFlag)))
+ {
+ }
+
+ if (SDHC_GetInterruptStatusFlags(base) & kSDHC_DataErrorFlag)
+ {
+ if (!(data->enableIgnoreError))
+ {
+ error = kStatus_Fail;
+ }
+ }
+ if (error == kStatus_Success)
+ {
+ transferredWords = SDHC_ReadDataPort(base, data, transferredWords);
+ }
+ /* clear buffer ready and error */
+ SDHC_ClearInterruptStatusFlags(base, kSDHC_BufferReadReadyFlag | kSDHC_DataErrorFlag);
+ }
+
+ /* Clear data complete flag after the last read operation. */
+ SDHC_ClearInterruptStatusFlags(base, kSDHC_DataCompleteFlag | kSDHC_DataErrorFlag);
+
+ return error;
+}
+
+static uint32_t SDHC_WriteDataPort(SDHC_Type *base, sdhc_data_t *data, uint32_t transferredWords)
+{
+ uint32_t i;
+ uint32_t totalWords;
+ uint32_t wordsCanBeWrote; /* Words can be wrote at this time. */
+ uint32_t writeWatermark = ((base->WML & SDHC_WML_WRWML_MASK) >> SDHC_WML_WRWML_SHIFT);
+
+ /*
+ * Add non aligned access support ,user need make sure your buffer size is big
+ * enough to hold the data,in other words,user need make sure the buffer size
+ * is 4 byte aligned
+ */
+ if (data->blockSize % sizeof(uint32_t) != 0U)
+ {
+ data->blockSize +=
+ sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */
+ }
+
+ totalWords = ((data->blockCount * data->blockSize) / sizeof(uint32_t));
+
+ /* If watermark level is equal or bigger than totalWords, transfers totalWords data.*/
+ if (writeWatermark >= totalWords)
+ {
+ wordsCanBeWrote = totalWords;
+ }
+ /* If watermark level is less than totalWords and left words to be sent is equal or bigger than watermark,
+ transfers watermark level words. */
+ else if ((writeWatermark < totalWords) && ((totalWords - transferredWords) >= writeWatermark))
+ {
+ wordsCanBeWrote = writeWatermark;
+ }
+ /* If watermark level is less than totalWords and left words to be sent is less than watermark, transfers left
+ words. */
+ else
+ {
+ wordsCanBeWrote = (totalWords - transferredWords);
+ }
+
+ i = 0U;
+ while (i < wordsCanBeWrote)
+ {
+ SDHC_WriteData(base, data->txData[transferredWords++]);
+ i++;
+ }
+
+ return transferredWords;
+}
+
+static status_t SDHC_WriteByDataPortBlocking(SDHC_Type *base, sdhc_data_t *data)
+{
+ uint32_t totalWords;
+ uint32_t transferredWords = 0U;
+ status_t error = kStatus_Success;
+
+ /*
+ * Add non aligned access support ,user need make sure your buffer size is big
+ * enough to hold the data,in other words,user need make sure the buffer size
+ * is 4 byte aligned
+ */
+ if (data->blockSize % sizeof(uint32_t) != 0U)
+ {
+ data->blockSize +=
+ sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */
+ }
+
+ totalWords = (data->blockCount * data->blockSize) / sizeof(uint32_t);
+
+ while ((error == kStatus_Success) && (transferredWords < totalWords))
+ {
+ while (!(SDHC_GetInterruptStatusFlags(base) & (kSDHC_BufferWriteReadyFlag | kSDHC_DataErrorFlag)))
+ {
+ }
+
+ if (SDHC_GetInterruptStatusFlags(base) & kSDHC_DataErrorFlag)
+ {
+ if (!(data->enableIgnoreError))
+ {
+ error = kStatus_Fail;
+ }
+ }
+ if (error == kStatus_Success)
+ {
+ transferredWords = SDHC_WriteDataPort(base, data, transferredWords);
+ }
+
+ /* Clear buffer enable flag to trigger transfer. Clear error flag when SDHC encounter error. */
+ SDHC_ClearInterruptStatusFlags(base, (kSDHC_BufferWriteReadyFlag | kSDHC_DataErrorFlag));
+ }
+
+ /* Wait write data complete or data transfer error after the last writing operation. */
+ while (!(SDHC_GetInterruptStatusFlags(base) & (kSDHC_DataCompleteFlag | kSDHC_DataErrorFlag)))
+ {
+ }
+ if (SDHC_GetInterruptStatusFlags(base) & kSDHC_DataErrorFlag)
+ {
+ if (!(data->enableIgnoreError))
+ {
+ error = kStatus_Fail;
+ }
+ }
+
+ SDHC_ClearInterruptStatusFlags(base, (kSDHC_DataCompleteFlag | kSDHC_DataErrorFlag));
+
+ return error;
+}
+
+static status_t SDHC_SendCommandBlocking(SDHC_Type *base, sdhc_command_t *command)
+{
+ status_t error = kStatus_Success;
+
+ /* Wait command complete or SDHC encounters error. */
+ while (!(SDHC_GetInterruptStatusFlags(base) & (kSDHC_CommandCompleteFlag | kSDHC_CommandErrorFlag)))
+ {
+ }
+
+ if (SDHC_GetInterruptStatusFlags(base) & kSDHC_CommandErrorFlag)
+ {
+ error = kStatus_Fail;
+ }
+ /* Receive response when command completes successfully. */
+ if (error == kStatus_Success)
+ {
+ error = SDHC_ReceiveCommandResponse(base, command);
+ }
+
+ SDHC_ClearInterruptStatusFlags(base, (kSDHC_CommandCompleteFlag | kSDHC_CommandErrorFlag));
+
+ return error;
+}
+
+static status_t SDHC_TransferByDataPortBlocking(SDHC_Type *base, sdhc_data_t *data)
+{
+ status_t error = kStatus_Success;
+
+ if (data->rxData)
+ {
+ error = SDHC_ReadByDataPortBlocking(base, data);
+ }
+ else
+ {
+ error = SDHC_WriteByDataPortBlocking(base, data);
+ }
+
+ return error;
+}
+
+static status_t SDHC_TransferByAdma2Blocking(SDHC_Type *base, sdhc_data_t *data)
+{
+ status_t error = kStatus_Success;
+
+ /* Wait data complete or SDHC encounters error. */
+ while (!(SDHC_GetInterruptStatusFlags(base) & (kSDHC_DataCompleteFlag | kSDHC_DataErrorFlag | kSDHC_DmaErrorFlag)))
+ {
+ }
+ if (SDHC_GetInterruptStatusFlags(base) & (kSDHC_DataErrorFlag | kSDHC_DmaErrorFlag))
+ {
+ if (!(data->enableIgnoreError))
+ {
+ error = kStatus_Fail;
+ }
+ }
+ SDHC_ClearInterruptStatusFlags(
+ base, (kSDHC_DataCompleteFlag | kSDHC_DmaCompleteFlag | kSDHC_DataErrorFlag | kSDHC_DmaErrorFlag));
+ return error;
+}
+
+#if defined FSL_SDHC_ENABLE_ADMA1
+#define SDHC_TransferByAdma1Blocking(base, data) SDHC_TransferByAdma2Blocking(base, data)
+#endif /* FSL_SDHC_ENABLE_ADMA1 */
+
+static status_t SDHC_TransferDataBlocking(sdhc_dma_mode_t dmaMode, SDHC_Type *base, sdhc_data_t *data)
+{
+ status_t error = kStatus_Success;
+
+ switch (dmaMode)
+ {
+ case kSDHC_DmaModeNo:
+ error = SDHC_TransferByDataPortBlocking(base, data);
+ break;
+#if defined FSL_SDHC_ENABLE_ADMA1
+ case kSDHC_DmaModeAdma1:
+ error = SDHC_TransferByAdma1Blocking(base, data);
+ break;
+#endif /* FSL_SDHC_ENABLE_ADMA1 */
+ case kSDHC_DmaModeAdma2:
+ error = SDHC_TransferByAdma2Blocking(base, data);
+ break;
+ default:
+ error = kStatus_InvalidArgument;
+ break;
+ }
+
+ return error;
+}
+
+static void SDHC_TransferHandleCardDetect(sdhc_handle_t *handle, uint32_t interruptFlags)
+{
+ if (interruptFlags & kSDHC_CardInsertionFlag)
+ {
+ if (handle->callback.CardInserted)
+ {
+ handle->callback.CardInserted();
+ }
+ }
+ else
+ {
+ if (handle->callback.CardRemoved)
+ {
+ handle->callback.CardRemoved();
+ }
+ }
+}
+
+static void SDHC_TransferHandleCommand(SDHC_Type *base, sdhc_handle_t *handle, uint32_t interruptFlags)
+{
+ assert(handle->command);
+
+ if ((interruptFlags & kSDHC_CommandErrorFlag) && (!(handle->data)) && (handle->callback.TransferComplete))
+ {
+ handle->callback.TransferComplete(base, handle, kStatus_SDHC_SendCommandFailed, handle->userData);
+ }
+ else
+ {
+ /* Receive response */
+ SDHC_ReceiveCommandResponse(base, handle->command);
+ if ((!(handle->data)) && (handle->callback.TransferComplete))
+ {
+ handle->callback.TransferComplete(base, handle, kStatus_Success, handle->userData);
+ }
+ }
+}
+
+static void SDHC_TransferHandleData(SDHC_Type *base, sdhc_handle_t *handle, uint32_t interruptFlags)
+{
+ assert(handle->data);
+
+ if ((!(handle->data->enableIgnoreError)) && (interruptFlags & (kSDHC_DataErrorFlag | kSDHC_DmaErrorFlag)) &&
+ (handle->callback.TransferComplete))
+ {
+ handle->callback.TransferComplete(base, handle, kStatus_SDHC_TransferDataFailed, handle->userData);
+ }
+ else
+ {
+ if (interruptFlags & kSDHC_BufferReadReadyFlag)
+ {
+ handle->transferredWords = SDHC_ReadDataPort(base, handle->data, handle->transferredWords);
+ }
+ else if (interruptFlags & kSDHC_BufferWriteReadyFlag)
+ {
+ handle->transferredWords = SDHC_WriteDataPort(base, handle->data, handle->transferredWords);
+ }
+ else
+ {
+ }
+
+ if ((interruptFlags & kSDHC_DataCompleteFlag) && (handle->callback.TransferComplete))
+ {
+ handle->callback.TransferComplete(base, handle, kStatus_Success, handle->userData);
+ }
+ else
+ {
+ /* Do nothing when DMA complete flag is set. Wait until data complete flag is set. */
+ }
+ }
+}
+
+static void SDHC_TransferHandleSdioInterrupt(sdhc_handle_t *handle)
+{
+ if (handle->callback.SdioInterrupt)
+ {
+ handle->callback.SdioInterrupt();
+ }
+}
+
+static void SDHC_TransferHandleSdioBlockGap(sdhc_handle_t *handle)
+{
+ if (handle->callback.SdioBlockGap)
+ {
+ handle->callback.SdioBlockGap();
+ }
+}
+
+void SDHC_Init(SDHC_Type *base, const sdhc_config_t *config)
+{
+ assert(config);
+#if !defined FSL_SDHC_ENABLE_ADMA1
+ assert(config->dmaMode != kSDHC_DmaModeAdma1);
+#endif /* FSL_SDHC_ENABLE_ADMA1 */
+ assert((config->writeWatermarkLevel >= 1U) && (config->writeWatermarkLevel <= 128U));
+ assert((config->readWatermarkLevel >= 1U) && (config->readWatermarkLevel <= 128U));
+
+ uint32_t proctl;
+ uint32_t wml;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable SDHC clock. */
+ CLOCK_EnableClock(s_sdhcClock[SDHC_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Reset SDHC. */
+ SDHC_Reset(base, kSDHC_ResetAll, 100);
+
+ proctl = base->PROCTL;
+ wml = base->WML;
+
+ proctl &= ~(SDHC_PROCTL_D3CD_MASK | SDHC_PROCTL_EMODE_MASK | SDHC_PROCTL_DMAS_MASK);
+ /* Set DAT3 as card detection pin */
+ if (config->cardDetectDat3)
+ {
+ proctl |= SDHC_PROCTL_D3CD_MASK;
+ }
+ /* Endian mode and DMA mode */
+ proctl |= (SDHC_PROCTL_EMODE(config->endianMode) | SDHC_PROCTL_DMAS(config->dmaMode));
+
+ /* Watermark level */
+ wml &= ~(SDHC_WML_RDWML_MASK | SDHC_WML_WRWML_MASK);
+ wml |= (SDHC_WML_RDWML(config->readWatermarkLevel) | SDHC_WML_WRWML(config->writeWatermarkLevel));
+
+ base->WML = wml;
+ base->PROCTL = proctl;
+
+ /* Disable all clock auto gated off feature because of DAT0 line logic(card buffer full status) can't be updated
+ correctly when clock auto gated off is enabled. */
+ base->SYSCTL |= (SDHC_SYSCTL_PEREN_MASK | SDHC_SYSCTL_HCKEN_MASK | SDHC_SYSCTL_IPGEN_MASK);
+
+ /* Enable interrupt status but doesn't enable interrupt signal. */
+ SDHC_SetTransferInterrupt(base, false);
+}
+
+void SDHC_Deinit(SDHC_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Disable clock. */
+ CLOCK_DisableClock(s_sdhcClock[SDHC_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+bool SDHC_Reset(SDHC_Type *base, uint32_t mask, uint32_t timeout)
+{
+ base->SYSCTL |= (mask & (SDHC_SYSCTL_RSTA_MASK | SDHC_SYSCTL_RSTC_MASK | SDHC_SYSCTL_RSTD_MASK));
+ /* Delay some time to wait reset success. */
+ while ((base->SYSCTL & mask))
+ {
+ if (!timeout)
+ {
+ break;
+ }
+ timeout--;
+ }
+
+ return ((!timeout) ? false : true);
+}
+
+void SDHC_GetCapability(SDHC_Type *base, sdhc_capability_t *capability)
+{
+ assert(capability);
+
+ uint32_t htCapability;
+ uint32_t hostVer;
+ uint32_t maxBlockLength;
+
+ hostVer = base->HOSTVER;
+ htCapability = base->HTCAPBLT;
+
+ /* Get the capability of SDHC. */
+ capability->specVersion = ((hostVer & SDHC_HOSTVER_SVN_MASK) >> SDHC_HOSTVER_SVN_SHIFT);
+ capability->vendorVersion = ((hostVer & SDHC_HOSTVER_VVN_MASK) >> SDHC_HOSTVER_VVN_SHIFT);
+ maxBlockLength = ((htCapability & SDHC_HTCAPBLT_MBL_MASK) >> SDHC_HTCAPBLT_MBL_SHIFT);
+ capability->maxBlockLength = (512U << maxBlockLength);
+ /* Other attributes not in HTCAPBLT register. */
+ capability->maxBlockCount = SDHC_MAX_BLOCK_COUNT;
+ capability->flags = (htCapability & (kSDHC_SupportAdmaFlag | kSDHC_SupportHighSpeedFlag | kSDHC_SupportDmaFlag |
+ kSDHC_SupportSuspendResumeFlag | kSDHC_SupportV330Flag));
+#if defined FSL_FEATURE_SDHC_HAS_V300_SUPPORT && FSL_FEATURE_SDHC_HAS_V300_SUPPORT
+ capability->flags |= (htCapability & kSDHC_SupportV300Flag);
+#endif
+#if defined FSL_FEATURE_SDHC_HAS_V180_SUPPORT && FSL_FEATURE_SDHC_HAS_V180_SUPPORT
+ capability->flags |= (htCapability & kSDHC_SupportV180Flag);
+#endif
+ /* eSDHC on all kinetis boards will support 4/8 bit data bus width. */
+ capability->flags |= (kSDHC_Support4BitFlag | kSDHC_Support8BitFlag);
+}
+
+uint32_t SDHC_SetSdClock(SDHC_Type *base, uint32_t srcClock_Hz, uint32_t busClock_Hz)
+{
+ assert(srcClock_Hz != 0U);
+ assert((busClock_Hz != 0U) && (busClock_Hz <= srcClock_Hz));
+
+ uint32_t totalDiv = 0U;
+ uint32_t divisor = 0U;
+ uint32_t prescaler = 0U;
+ uint32_t sysctl = 0U;
+ uint32_t nearestFrequency = 0U;
+
+ /* calucate total divisor first */
+ totalDiv = srcClock_Hz / busClock_Hz;
+
+ if (totalDiv != 0U)
+ {
+ /* calucate the divisor (srcClock_Hz / divisor) <= busClock_Hz */
+ if ((srcClock_Hz / totalDiv) > busClock_Hz)
+ {
+ totalDiv++;
+ }
+
+ /* divide the total divisor to div and prescaler */
+ if (totalDiv > SDHC_MAX_DVS)
+ {
+ prescaler = totalDiv / SDHC_MAX_DVS;
+ /* prescaler must be a value which equal 2^n and smaller than SDHC_MAX_CLKFS */
+ while (((SDHC_MAX_CLKFS % prescaler) != 0U) || (prescaler == 1U))
+ {
+ prescaler++;
+ }
+ /* calucate the divisor */
+ divisor = totalDiv / prescaler;
+ /* fine tuning the divisor until divisor * prescaler >= totalDiv */
+ while ((divisor * prescaler) < totalDiv)
+ {
+ divisor++;
+ }
+ nearestFrequency = srcClock_Hz / divisor / prescaler;
+ }
+ else
+ {
+ divisor = totalDiv;
+ prescaler = 0U;
+ nearestFrequency = srcClock_Hz / divisor;
+ }
+ }
+ /* in this condition , srcClock_Hz = busClock_Hz, */
+ else
+ {
+ /* total divider = 1U */
+ divisor = 0U;
+ prescaler = 0U;
+ nearestFrequency = srcClock_Hz;
+ }
+
+ /* calucate the value write to register */
+ if (divisor != 0U)
+ {
+ SDHC_PREV_DVS(divisor);
+ }
+ /* calucate the value write to register */
+ if (prescaler != 0U)
+ {
+ SDHC_PREV_CLKFS(prescaler);
+ }
+
+ /* Disable SD clock. It should be disabled before changing the SD clock frequency.*/
+ base->SYSCTL &= ~SDHC_SYSCTL_SDCLKEN_MASK;
+
+ /* Set the SD clock frequency divisor, SD clock frequency select, data timeout counter value. */
+ sysctl = base->SYSCTL;
+ sysctl &= ~(SDHC_SYSCTL_DVS_MASK | SDHC_SYSCTL_SDCLKFS_MASK | SDHC_SYSCTL_DTOCV_MASK);
+ sysctl |= (SDHC_SYSCTL_DVS(divisor) | SDHC_SYSCTL_SDCLKFS(prescaler) | SDHC_SYSCTL_DTOCV(0xEU));
+ base->SYSCTL = sysctl;
+
+ /* Wait until the SD clock is stable. */
+ while (!(base->PRSSTAT & SDHC_PRSSTAT_SDSTB_MASK))
+ {
+ }
+ /* Enable the SD clock. */
+ base->SYSCTL |= SDHC_SYSCTL_SDCLKEN_MASK;
+
+ return nearestFrequency;
+}
+
+bool SDHC_SetCardActive(SDHC_Type *base, uint32_t timeout)
+{
+ base->SYSCTL |= SDHC_SYSCTL_INITA_MASK;
+ /* Delay some time to wait card become active state. */
+ while (base->SYSCTL & SDHC_SYSCTL_INITA_MASK)
+ {
+ if (!timeout)
+ {
+ break;
+ }
+ timeout--;
+ }
+
+ return ((!timeout) ? false : true);
+}
+
+void SDHC_SetTransferConfig(SDHC_Type *base, const sdhc_transfer_config_t *config)
+{
+ assert(config);
+ assert(config->dataBlockSize <= (SDHC_BLKATTR_BLKSIZE_MASK >> SDHC_BLKATTR_BLKSIZE_SHIFT));
+ assert(config->dataBlockCount <= (SDHC_BLKATTR_BLKCNT_MASK >> SDHC_BLKATTR_BLKCNT_SHIFT));
+
+ base->BLKATTR = ((base->BLKATTR & ~(SDHC_BLKATTR_BLKSIZE_MASK | SDHC_BLKATTR_BLKCNT_MASK)) |
+ (SDHC_BLKATTR_BLKSIZE(config->dataBlockSize) | SDHC_BLKATTR_BLKCNT(config->dataBlockCount)));
+ base->CMDARG = config->commandArgument;
+ base->XFERTYP = (((config->commandIndex << SDHC_XFERTYP_CMDINX_SHIFT) & SDHC_XFERTYP_CMDINX_MASK) |
+ (config->flags & (SDHC_XFERTYP_DMAEN_MASK | SDHC_XFERTYP_MSBSEL_MASK | SDHC_XFERTYP_DPSEL_MASK |
+ SDHC_XFERTYP_CMDTYP_MASK | SDHC_XFERTYP_BCEN_MASK | SDHC_XFERTYP_CICEN_MASK |
+ SDHC_XFERTYP_CCCEN_MASK | SDHC_XFERTYP_RSPTYP_MASK | SDHC_XFERTYP_DTDSEL_MASK |
+ SDHC_XFERTYP_AC12EN_MASK)));
+}
+
+void SDHC_EnableSdioControl(SDHC_Type *base, uint32_t mask, bool enable)
+{
+ uint32_t proctl = base->PROCTL;
+ uint32_t vendor = base->VENDOR;
+
+ if (enable)
+ {
+ if (mask & kSDHC_StopAtBlockGapFlag)
+ {
+ proctl |= SDHC_PROCTL_SABGREQ_MASK;
+ }
+ if (mask & kSDHC_ReadWaitControlFlag)
+ {
+ proctl |= SDHC_PROCTL_RWCTL_MASK;
+ }
+ if (mask & kSDHC_InterruptAtBlockGapFlag)
+ {
+ proctl |= SDHC_PROCTL_IABG_MASK;
+ }
+ if (mask & kSDHC_ExactBlockNumberReadFlag)
+ {
+ vendor |= SDHC_VENDOR_EXBLKNU_MASK;
+ }
+ }
+ else
+ {
+ if (mask & kSDHC_StopAtBlockGapFlag)
+ {
+ proctl &= ~SDHC_PROCTL_SABGREQ_MASK;
+ }
+ if (mask & kSDHC_ReadWaitControlFlag)
+ {
+ proctl &= ~SDHC_PROCTL_RWCTL_MASK;
+ }
+ if (mask & kSDHC_InterruptAtBlockGapFlag)
+ {
+ proctl &= ~SDHC_PROCTL_IABG_MASK;
+ }
+ if (mask & kSDHC_ExactBlockNumberReadFlag)
+ {
+ vendor &= ~SDHC_VENDOR_EXBLKNU_MASK;
+ }
+ }
+
+ base->PROCTL = proctl;
+ base->VENDOR = vendor;
+}
+
+void SDHC_SetMmcBootConfig(SDHC_Type *base, const sdhc_boot_config_t *config)
+{
+ assert(config);
+ assert(config->ackTimeoutCount <= (SDHC_MMCBOOT_DTOCVACK_MASK >> SDHC_MMCBOOT_DTOCVACK_SHIFT));
+ assert(config->blockCount <= (SDHC_MMCBOOT_BOOTBLKCNT_MASK >> SDHC_MMCBOOT_BOOTBLKCNT_SHIFT));
+
+ uint32_t mmcboot = 0U;
+
+ mmcboot = (SDHC_MMCBOOT_DTOCVACK(config->ackTimeoutCount) | SDHC_MMCBOOT_BOOTMODE(config->bootMode) |
+ SDHC_MMCBOOT_BOOTBLKCNT(config->blockCount));
+ if (config->enableBootAck)
+ {
+ mmcboot |= SDHC_MMCBOOT_BOOTACK_MASK;
+ }
+ if (config->enableBoot)
+ {
+ mmcboot |= SDHC_MMCBOOT_BOOTEN_MASK;
+ }
+ if (config->enableAutoStopAtBlockGap)
+ {
+ mmcboot |= SDHC_MMCBOOT_AUTOSABGEN_MASK;
+ }
+ base->MMCBOOT = mmcboot;
+}
+
+status_t SDHC_SetAdmaTableConfig(SDHC_Type *base,
+ sdhc_dma_mode_t dmaMode,
+ uint32_t *table,
+ uint32_t tableWords,
+ const uint32_t *data,
+ uint32_t dataBytes)
+{
+ status_t error = kStatus_Success;
+ const uint32_t *startAddress = data;
+ uint32_t entries;
+ uint32_t i;
+#if defined FSL_SDHC_ENABLE_ADMA1
+ sdhc_adma1_descriptor_t *adma1EntryAddress;
+#endif
+ sdhc_adma2_descriptor_t *adma2EntryAddress;
+
+ if ((((!table) || (!tableWords)) && ((dmaMode == kSDHC_DmaModeAdma1) || (dmaMode == kSDHC_DmaModeAdma2))) ||
+ (!data) || (!dataBytes)
+#if !defined FSL_SDHC_ENABLE_ADMA1
+ || (dmaMode == kSDHC_DmaModeAdma1)
+#endif
+ )
+ {
+ error = kStatus_InvalidArgument;
+ }
+ else if (((dmaMode == kSDHC_DmaModeAdma2) && (((uint32_t)startAddress % SDHC_ADMA2_LENGTH_ALIGN) != 0U))
+#if defined FSL_SDHC_ENABLE_ADMA1
+ || ((dmaMode == kSDHC_DmaModeAdma1) && (((uint32_t)startAddress % SDHC_ADMA1_LENGTH_ALIGN) != 0U))
+#endif
+ )
+ {
+ error = kStatus_SDHC_DMADataBufferAddrNotAlign;
+ }
+ else
+ {
+ switch (dmaMode)
+ {
+ case kSDHC_DmaModeNo:
+ break;
+#if defined FSL_SDHC_ENABLE_ADMA1
+ case kSDHC_DmaModeAdma1:
+ /*
+ * Add non aligned access support ,user need make sure your buffer size is big
+ * enough to hold the data,in other words,user need make sure the buffer size
+ * is 4 byte aligned
+ */
+ if (dataBytes % sizeof(uint32_t) != 0U)
+ {
+ dataBytes +=
+ sizeof(uint32_t) - (dataBytes % sizeof(uint32_t)); /* make the data length as word-aligned */
+ }
+
+ /* Check if ADMA descriptor's number is enough. */
+ entries = ((dataBytes / SDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) + 1U);
+ /* ADMA1 needs two descriptors to finish a transfer */
+ entries <<= 1U;
+ if (entries > ((tableWords * sizeof(uint32_t)) / sizeof(sdhc_adma1_descriptor_t)))
+ {
+ error = kStatus_OutOfRange;
+ }
+ else
+ {
+ adma1EntryAddress = (sdhc_adma1_descriptor_t *)(table);
+ for (i = 0U; i < entries; i += 2U)
+ {
+ /* Each descriptor for ADMA1 is 32-bit in length */
+ if ((dataBytes - sizeof(uint32_t) * (startAddress - data)) <=
+ SDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY)
+ {
+ /* The last piece of data, setting end flag in descriptor */
+ adma1EntryAddress[i] = ((uint32_t)(dataBytes - sizeof(uint32_t) * (startAddress - data))
+ << SDHC_ADMA1_DESCRIPTOR_LENGTH_SHIFT);
+ adma1EntryAddress[i] |= kSDHC_Adma1DescriptorTypeSetLength;
+ adma1EntryAddress[i + 1U] =
+ ((uint32_t)(startAddress) << SDHC_ADMA1_DESCRIPTOR_ADDRESS_SHIFT);
+ adma1EntryAddress[i + 1U] |=
+ (kSDHC_Adma1DescriptorTypeTransfer | kSDHC_Adma1DescriptorEndFlag);
+ }
+ else
+ {
+ adma1EntryAddress[i] = ((uint32_t)SDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY
+ << SDHC_ADMA1_DESCRIPTOR_LENGTH_SHIFT);
+ adma1EntryAddress[i] |= kSDHC_Adma1DescriptorTypeSetLength;
+ adma1EntryAddress[i + 1U] =
+ ((uint32_t)(startAddress) << SDHC_ADMA1_DESCRIPTOR_ADDRESS_SHIFT);
+ adma1EntryAddress[i + 1U] |= kSDHC_Adma1DescriptorTypeTransfer;
+ startAddress += SDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY / sizeof(uint32_t);
+ }
+ }
+
+ /* When use ADMA, disable simple DMA */
+ base->DSADDR = 0U;
+ base->ADSADDR = (uint32_t)table;
+ /* disable the buffer ready flag in DMA mode */
+ SDHC_DisableInterruptSignal(base, kSDHC_BufferReadReadyFlag | kSDHC_BufferWriteReadyFlag);
+ SDHC_DisableInterruptStatus(base, kSDHC_BufferReadReadyFlag | kSDHC_BufferWriteReadyFlag);
+ }
+ break;
+#endif /* FSL_SDHC_ENABLE_ADMA1 */
+ case kSDHC_DmaModeAdma2:
+ /*
+ * Add non aligned access support ,user need make sure your buffer size is big
+ * enough to hold the data,in other words,user need make sure the buffer size
+ * is 4 byte aligned
+ */
+ if (dataBytes % sizeof(uint32_t) != 0U)
+ {
+ dataBytes +=
+ sizeof(uint32_t) - (dataBytes % sizeof(uint32_t)); /* make the data length as word-aligned */
+ }
+
+ /* Check if ADMA descriptor's number is enough. */
+ entries = ((dataBytes / SDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) + 1U);
+ if (entries > ((tableWords * sizeof(uint32_t)) / sizeof(sdhc_adma2_descriptor_t)))
+ {
+ error = kStatus_OutOfRange;
+ }
+ else
+ {
+ adma2EntryAddress = (sdhc_adma2_descriptor_t *)(table);
+ for (i = 0U; i < entries; i++)
+ {
+ /* Each descriptor for ADMA2 is 64-bit in length */
+ if ((dataBytes - sizeof(uint32_t) * (startAddress - data)) <=
+ SDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY)
+ {
+ /* The last piece of data, setting end flag in descriptor */
+ adma2EntryAddress[i].address = startAddress;
+ adma2EntryAddress[i].attribute = ((dataBytes - sizeof(uint32_t) * (startAddress - data))
+ << SDHC_ADMA2_DESCRIPTOR_LENGTH_SHIFT);
+ adma2EntryAddress[i].attribute |=
+ (kSDHC_Adma2DescriptorTypeTransfer | kSDHC_Adma2DescriptorEndFlag);
+ }
+ else
+ {
+ adma2EntryAddress[i].address = startAddress;
+ adma2EntryAddress[i].attribute =
+ (((SDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY / sizeof(uint32_t)) * sizeof(uint32_t))
+ << SDHC_ADMA2_DESCRIPTOR_LENGTH_SHIFT);
+ adma2EntryAddress[i].attribute |= kSDHC_Adma2DescriptorTypeTransfer;
+ startAddress += (SDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY / sizeof(uint32_t));
+ }
+ }
+
+ /* When use ADMA, disable simple DMA */
+ base->DSADDR = 0U;
+ base->ADSADDR = (uint32_t)table;
+ /* disable the buffer read flag in DMA mode */
+ SDHC_DisableInterruptSignal(base, kSDHC_BufferReadReadyFlag | kSDHC_BufferWriteReadyFlag);
+ SDHC_DisableInterruptStatus(base, kSDHC_BufferReadReadyFlag | kSDHC_BufferWriteReadyFlag);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ return error;
+}
+
+status_t SDHC_TransferBlocking(SDHC_Type *base, uint32_t *admaTable, uint32_t admaTableWords, sdhc_transfer_t *transfer)
+{
+ assert(transfer);
+
+ status_t error = kStatus_Success;
+ sdhc_dma_mode_t dmaMode = (sdhc_dma_mode_t)((base->PROCTL & SDHC_PROCTL_DMAS_MASK) >> SDHC_PROCTL_DMAS_SHIFT);
+ sdhc_command_t *command = transfer->command;
+ sdhc_data_t *data = transfer->data;
+
+ /* make sure the cmd/block count is valid */
+ if ((!command) || (data && (data->blockCount > SDHC_MAX_BLOCK_COUNT)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Wait until command/data bus out of busy status. */
+ while (SDHC_GetPresentStatusFlags(base) & kSDHC_CommandInhibitFlag)
+ {
+ }
+ while (data && (SDHC_GetPresentStatusFlags(base) & kSDHC_DataInhibitFlag))
+ {
+ }
+
+ /* Update ADMA descriptor table according to different DMA mode(no DMA, ADMA1, ADMA2).*/
+ if (data && (NULL != admaTable))
+ {
+ error =
+ SDHC_SetAdmaTableConfig(base, dmaMode, admaTable, admaTableWords,
+ (data->rxData ? data->rxData : data->txData), (data->blockCount * data->blockSize));
+ /* in this situation , we disable the DMA instead of polling transfer mode */
+ if (error == kStatus_SDHC_DMADataBufferAddrNotAlign)
+ {
+ dmaMode = kSDHC_DmaModeNo;
+ SDHC_EnableInterruptStatus(base, kSDHC_BufferReadReadyFlag | kSDHC_BufferWriteReadyFlag);
+ }
+ else if (error != kStatus_Success)
+ {
+ return error;
+ }
+ else
+ {
+ }
+ }
+
+ /* Send command and receive data. */
+ SDHC_StartTransfer(base, command, data, dmaMode);
+ if (kStatus_Success != SDHC_SendCommandBlocking(base, command))
+ {
+ return kStatus_SDHC_SendCommandFailed;
+ }
+ else if (data && (kStatus_Success != SDHC_TransferDataBlocking(dmaMode, base, data)))
+ {
+ return kStatus_SDHC_TransferDataFailed;
+ }
+ else
+ {
+ }
+
+ return kStatus_Success;
+}
+
+void SDHC_TransferCreateHandle(SDHC_Type *base,
+ sdhc_handle_t *handle,
+ const sdhc_transfer_callback_t *callback,
+ void *userData)
+{
+ assert(handle);
+ assert(callback);
+
+ /* Zero the handle. */
+ memset(handle, 0, sizeof(*handle));
+
+ /* Set the callback. */
+ handle->callback.CardInserted = callback->CardInserted;
+ handle->callback.CardRemoved = callback->CardRemoved;
+ handle->callback.SdioInterrupt = callback->SdioInterrupt;
+ handle->callback.SdioBlockGap = callback->SdioBlockGap;
+ handle->callback.TransferComplete = callback->TransferComplete;
+ handle->userData = userData;
+
+ /* Save the handle in global variables to support the double weak mechanism. */
+ s_sdhcHandle[SDHC_GetInstance(base)] = handle;
+
+ /* Enable interrupt in NVIC. */
+ SDHC_SetTransferInterrupt(base, true);
+
+ /* save IRQ handler */
+ s_sdhcIsr = SDHC_TransferHandleIRQ;
+
+ EnableIRQ(s_sdhcIRQ[SDHC_GetInstance(base)]);
+}
+
+status_t SDHC_TransferNonBlocking(
+ SDHC_Type *base, sdhc_handle_t *handle, uint32_t *admaTable, uint32_t admaTableWords, sdhc_transfer_t *transfer)
+{
+ assert(transfer);
+
+ sdhc_dma_mode_t dmaMode = (sdhc_dma_mode_t)((base->PROCTL & SDHC_PROCTL_DMAS_MASK) >> SDHC_PROCTL_DMAS_SHIFT);
+ status_t error = kStatus_Success;
+ sdhc_command_t *command = transfer->command;
+ sdhc_data_t *data = transfer->data;
+
+ /* make sure cmd/block count is valid */
+ if ((!command) || (data && (data->blockCount > SDHC_MAX_BLOCK_COUNT)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Wait until command/data bus out of busy status. */
+ if ((SDHC_GetPresentStatusFlags(base) & kSDHC_CommandInhibitFlag) ||
+ (data && (SDHC_GetPresentStatusFlags(base) & kSDHC_DataInhibitFlag)))
+ {
+ return kStatus_SDHC_BusyTransferring;
+ }
+
+ /* Update ADMA descriptor table according to different DMA mode(no DMA, ADMA1, ADMA2).*/
+ if (data && (NULL != admaTable))
+ {
+ error =
+ SDHC_SetAdmaTableConfig(base, dmaMode, admaTable, admaTableWords,
+ (data->rxData ? data->rxData : data->txData), (data->blockCount * data->blockSize));
+ /* in this situation , we disable the DMA instead of polling transfer mode */
+ if (error == kStatus_SDHC_DMADataBufferAddrNotAlign)
+ {
+ /* change to polling mode */
+ dmaMode = kSDHC_DmaModeNo;
+ SDHC_EnableInterruptSignal(base, kSDHC_BufferReadReadyFlag | kSDHC_BufferWriteReadyFlag);
+ SDHC_EnableInterruptStatus(base, kSDHC_BufferReadReadyFlag | kSDHC_BufferWriteReadyFlag);
+ }
+ else if (error != kStatus_Success)
+ {
+ return error;
+ }
+ else
+ {
+ }
+ }
+
+ /* Save command and data into handle before transferring. */
+ handle->command = command;
+ handle->data = data;
+ handle->interruptFlags = 0U;
+ /* transferredWords will only be updated in ISR when transfer way is DATAPORT. */
+ handle->transferredWords = 0U;
+
+ SDHC_StartTransfer(base, command, data, dmaMode);
+
+ return kStatus_Success;
+}
+
+void SDHC_TransferHandleIRQ(SDHC_Type *base, sdhc_handle_t *handle)
+{
+ assert(handle);
+
+ uint32_t interruptFlags;
+
+ interruptFlags = SDHC_GetInterruptStatusFlags(base);
+ handle->interruptFlags = interruptFlags;
+
+ if (interruptFlags & kSDHC_CardDetectFlag)
+ {
+ SDHC_TransferHandleCardDetect(handle, (interruptFlags & kSDHC_CardDetectFlag));
+ }
+ if (interruptFlags & kSDHC_CommandFlag)
+ {
+ SDHC_TransferHandleCommand(base, handle, (interruptFlags & kSDHC_CommandFlag));
+ }
+ if (interruptFlags & kSDHC_DataFlag)
+ {
+ SDHC_TransferHandleData(base, handle, (interruptFlags & kSDHC_DataFlag));
+ }
+ if (interruptFlags & kSDHC_CardInterruptFlag)
+ {
+ SDHC_TransferHandleSdioInterrupt(handle);
+ }
+ if (interruptFlags & kSDHC_BlockGapEventFlag)
+ {
+ SDHC_TransferHandleSdioBlockGap(handle);
+ }
+
+ SDHC_ClearInterruptStatusFlags(base, interruptFlags);
+}
+
+#if defined(SDHC)
+void SDHC_DriverIRQHandler(void)
+{
+ assert(s_sdhcHandle[0]);
+
+ s_sdhcIsr(SDHC, s_sdhcHandle[0]);
+}
+#endif
diff --git a/drivers/src/fsl_sim.c b/drivers/src/fsl_sim.c
new file mode 100644
index 0000000..ade512f
--- /dev/null
+++ b/drivers/src/fsl_sim.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsl_sim.h"
+
+/*******************************************************************************
+ * Codes
+ ******************************************************************************/
+#if (defined(FSL_FEATURE_SIM_OPT_HAS_USB_VOLTAGE_REGULATOR) && FSL_FEATURE_SIM_OPT_HAS_USB_VOLTAGE_REGULATOR)
+void SIM_SetUsbVoltRegulatorEnableMode(uint32_t mask)
+{
+ SIM->SOPT1CFG |= (SIM_SOPT1CFG_URWE_MASK | SIM_SOPT1CFG_UVSWE_MASK | SIM_SOPT1CFG_USSWE_MASK);
+
+ SIM->SOPT1 = (SIM->SOPT1 & ~kSIM_UsbVoltRegEnableInAllModes) | mask;
+}
+#endif /* FSL_FEATURE_SIM_OPT_HAS_USB_VOLTAGE_REGULATOR */
+
+void SIM_GetUniqueId(sim_uid_t *uid)
+{
+#if defined(SIM_UIDH)
+ uid->H = SIM->UIDH;
+#endif
+ uid->MH = SIM->UIDMH;
+ uid->ML = SIM->UIDML;
+ uid->L = SIM->UIDL;
+}
diff --git a/drivers/src/fsl_smc.c b/drivers/src/fsl_smc.c
new file mode 100644
index 0000000..dacf193
--- /dev/null
+++ b/drivers/src/fsl_smc.c
@@ -0,0 +1,400 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsl_smc.h"
+#include "fsl_flash.h"
+
+#if (defined(FSL_FEATURE_SMC_HAS_PARAM) && FSL_FEATURE_SMC_HAS_PARAM)
+void SMC_GetParam(SMC_Type *base, smc_param_t *param)
+{
+ uint32_t reg = base->PARAM;
+ param->hsrunEnable = (bool)(reg & SMC_PARAM_EHSRUN_MASK);
+ param->llsEnable = (bool)(reg & SMC_PARAM_ELLS_MASK);
+ param->lls2Enable = (bool)(reg & SMC_PARAM_ELLS2_MASK);
+ param->vlls0Enable = (bool)(reg & SMC_PARAM_EVLLS0_MASK);
+}
+#endif /* FSL_FEATURE_SMC_HAS_PARAM */
+
+void SMC_PreEnterStopModes(void)
+{
+ flash_prefetch_speculation_status_t speculationStatus =
+ {
+ kFLASH_prefetchSpeculationOptionDisable, /* Disable instruction speculation.*/
+ kFLASH_prefetchSpeculationOptionDisable, /* Disable data speculation.*/
+ };
+
+ __disable_irq();
+ __ISB();
+
+ /*
+ * Before enter stop modes, the flash cache prefetch should be disabled.
+ * Otherwise the prefetch might be interrupted by stop, then the data and
+ * and instruction from flash are wrong.
+ */
+ FLASH_PflashSetPrefetchSpeculation(&speculationStatus);
+}
+
+void SMC_PostExitStopModes(void)
+{
+ flash_prefetch_speculation_status_t speculationStatus =
+ {
+ kFLASH_prefetchSpeculationOptionEnable, /* Enable instruction speculation.*/
+ kFLASH_prefetchSpeculationOptionEnable, /* Enable data speculation.*/
+ };
+
+ FLASH_PflashSetPrefetchSpeculation(&speculationStatus);
+
+ __enable_irq();
+ __ISB();
+}
+
+status_t SMC_SetPowerModeRun(SMC_Type *base)
+{
+ uint8_t reg;
+
+ reg = base->PMCTRL;
+ /* configure Normal RUN mode */
+ reg &= ~SMC_PMCTRL_RUNM_MASK;
+ reg |= (kSMC_RunNormal << SMC_PMCTRL_RUNM_SHIFT);
+ base->PMCTRL = reg;
+
+ return kStatus_Success;
+}
+
+#if (defined(FSL_FEATURE_SMC_HAS_HIGH_SPEED_RUN_MODE) && FSL_FEATURE_SMC_HAS_HIGH_SPEED_RUN_MODE)
+status_t SMC_SetPowerModeHsrun(SMC_Type *base)
+{
+ uint8_t reg;
+
+ reg = base->PMCTRL;
+ /* configure High Speed RUN mode */
+ reg &= ~SMC_PMCTRL_RUNM_MASK;
+ reg |= (kSMC_Hsrun << SMC_PMCTRL_RUNM_SHIFT);
+ base->PMCTRL = reg;
+
+ return kStatus_Success;
+}
+#endif /* FSL_FEATURE_SMC_HAS_HIGH_SPEED_RUN_MODE */
+
+status_t SMC_SetPowerModeWait(SMC_Type *base)
+{
+ /* configure Normal Wait mode */
+ SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
+ __DSB();
+ __WFI();
+ __ISB();
+
+ return kStatus_Success;
+}
+
+status_t SMC_SetPowerModeStop(SMC_Type *base, smc_partial_stop_option_t option)
+{
+ uint8_t reg;
+
+#if (defined(FSL_FEATURE_SMC_HAS_PSTOPO) && FSL_FEATURE_SMC_HAS_PSTOPO)
+ /* configure the Partial Stop mode in Noraml Stop mode */
+ reg = base->STOPCTRL;
+ reg &= ~SMC_STOPCTRL_PSTOPO_MASK;
+ reg |= ((uint32_t)option << SMC_STOPCTRL_PSTOPO_SHIFT);
+ base->STOPCTRL = reg;
+#endif
+
+ /* configure Normal Stop mode */
+ reg = base->PMCTRL;
+ reg &= ~SMC_PMCTRL_STOPM_MASK;
+ reg |= (kSMC_StopNormal << SMC_PMCTRL_STOPM_SHIFT);
+ base->PMCTRL = reg;
+
+ /* Set the SLEEPDEEP bit to enable deep sleep mode (stop mode) */
+ SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
+
+ /* read back to make sure the configuration valid before enter stop mode */
+ (void)base->PMCTRL;
+ __DSB();
+ __WFI();
+ __ISB();
+
+ /* check whether the power mode enter Stop mode succeed */
+ if (base->PMCTRL & SMC_PMCTRL_STOPA_MASK)
+ {
+ return kStatus_SMC_StopAbort;
+ }
+ else
+ {
+ return kStatus_Success;
+ }
+}
+
+status_t SMC_SetPowerModeVlpr(SMC_Type *base
+#if (defined(FSL_FEATURE_SMC_HAS_LPWUI) && FSL_FEATURE_SMC_HAS_LPWUI)
+ ,
+ bool wakeupMode
+#endif
+ )
+{
+ uint8_t reg;
+
+ reg = base->PMCTRL;
+#if (defined(FSL_FEATURE_SMC_HAS_LPWUI) && FSL_FEATURE_SMC_HAS_LPWUI)
+ /* configure whether the system remains in VLP mode on an interrupt */
+ if (wakeupMode)
+ {
+ /* exits to RUN mode on an interrupt */
+ reg |= SMC_PMCTRL_LPWUI_MASK;
+ }
+ else
+ {
+ /* remains in VLP mode on an interrupt */
+ reg &= ~SMC_PMCTRL_LPWUI_MASK;
+ }
+#endif /* FSL_FEATURE_SMC_HAS_LPWUI */
+
+ /* configure VLPR mode */
+ reg &= ~SMC_PMCTRL_RUNM_MASK;
+ reg |= (kSMC_RunVlpr << SMC_PMCTRL_RUNM_SHIFT);
+ base->PMCTRL = reg;
+
+ return kStatus_Success;
+}
+
+status_t SMC_SetPowerModeVlpw(SMC_Type *base)
+{
+ /* configure VLPW mode */
+ /* Set the SLEEPDEEP bit to enable deep sleep mode */
+ SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
+ __DSB();
+ __WFI();
+ __ISB();
+
+ return kStatus_Success;
+}
+
+status_t SMC_SetPowerModeVlps(SMC_Type *base)
+{
+ uint8_t reg;
+
+ /* configure VLPS mode */
+ reg = base->PMCTRL;
+ reg &= ~SMC_PMCTRL_STOPM_MASK;
+ reg |= (kSMC_StopVlps << SMC_PMCTRL_STOPM_SHIFT);
+ base->PMCTRL = reg;
+
+ /* Set the SLEEPDEEP bit to enable deep sleep mode */
+ SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
+
+ /* read back to make sure the configuration valid before enter stop mode */
+ (void)base->PMCTRL;
+ __DSB();
+ __WFI();
+ __ISB();
+
+ /* check whether the power mode enter VLPS mode succeed */
+ if (base->PMCTRL & SMC_PMCTRL_STOPA_MASK)
+ {
+ return kStatus_SMC_StopAbort;
+ }
+ else
+ {
+ return kStatus_Success;
+ }
+}
+
+#if (defined(FSL_FEATURE_SMC_HAS_LOW_LEAKAGE_STOP_MODE) && FSL_FEATURE_SMC_HAS_LOW_LEAKAGE_STOP_MODE)
+status_t SMC_SetPowerModeLls(SMC_Type *base
+#if ((defined(FSL_FEATURE_SMC_HAS_LLS_SUBMODE) && FSL_FEATURE_SMC_HAS_LLS_SUBMODE) || \
+ (defined(FSL_FEATURE_SMC_HAS_LPOPO) && FSL_FEATURE_SMC_HAS_LPOPO))
+ ,
+ const smc_power_mode_lls_config_t *config
+#endif
+ )
+{
+ uint8_t reg;
+
+ /* configure to LLS mode */
+ reg = base->PMCTRL;
+ reg &= ~SMC_PMCTRL_STOPM_MASK;
+ reg |= (kSMC_StopLls << SMC_PMCTRL_STOPM_SHIFT);
+ base->PMCTRL = reg;
+
+/* configure LLS sub-mode*/
+#if (defined(FSL_FEATURE_SMC_HAS_LLS_SUBMODE) && FSL_FEATURE_SMC_HAS_LLS_SUBMODE)
+ reg = base->STOPCTRL;
+ reg &= ~SMC_STOPCTRL_LLSM_MASK;
+ reg |= ((uint32_t)config->subMode << SMC_STOPCTRL_LLSM_SHIFT);
+ base->STOPCTRL = reg;
+#endif /* FSL_FEATURE_SMC_HAS_LLS_SUBMODE */
+
+#if (defined(FSL_FEATURE_SMC_HAS_LPOPO) && FSL_FEATURE_SMC_HAS_LPOPO)
+ if (config->enableLpoClock)
+ {
+ base->STOPCTRL &= ~SMC_STOPCTRL_LPOPO_MASK;
+ }
+ else
+ {
+ base->STOPCTRL |= SMC_STOPCTRL_LPOPO_MASK;
+ }
+#endif /* FSL_FEATURE_SMC_HAS_LPOPO */
+
+ /* Set the SLEEPDEEP bit to enable deep sleep mode */
+ SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
+
+ /* read back to make sure the configuration valid before enter stop mode */
+ (void)base->PMCTRL;
+ __DSB();
+ __WFI();
+ __ISB();
+
+ /* check whether the power mode enter LLS mode succeed */
+ if (base->PMCTRL & SMC_PMCTRL_STOPA_MASK)
+ {
+ return kStatus_SMC_StopAbort;
+ }
+ else
+ {
+ return kStatus_Success;
+ }
+}
+#endif /* FSL_FEATURE_SMC_HAS_LOW_LEAKAGE_STOP_MODE */
+
+#if (defined(FSL_FEATURE_SMC_HAS_VERY_LOW_LEAKAGE_STOP_MODE) && FSL_FEATURE_SMC_HAS_VERY_LOW_LEAKAGE_STOP_MODE)
+status_t SMC_SetPowerModeVlls(SMC_Type *base, const smc_power_mode_vlls_config_t *config)
+{
+ uint8_t reg;
+
+#if (defined(FSL_FEATURE_SMC_HAS_PORPO) && FSL_FEATURE_SMC_HAS_PORPO)
+#if (defined(FSL_FEATURE_SMC_USE_VLLSCTRL_REG) && FSL_FEATURE_SMC_USE_VLLSCTRL_REG) || \
+ (defined(FSL_FEATURE_SMC_USE_STOPCTRL_VLLSM) && FSL_FEATURE_SMC_USE_STOPCTRL_VLLSM) || \
+ (defined(FSL_FEATURE_SMC_HAS_LLS_SUBMODE) && FSL_FEATURE_SMC_HAS_LLS_SUBMODE)
+ if (config->subMode == kSMC_StopSub0)
+#endif
+ {
+ /* configure whether the Por Detect work in Vlls0 mode */
+ if (config->enablePorDetectInVlls0)
+ {
+#if (defined(FSL_FEATURE_SMC_USE_VLLSCTRL_REG) && FSL_FEATURE_SMC_USE_VLLSCTRL_REG)
+ base->VLLSCTRL &= ~SMC_VLLSCTRL_PORPO_MASK;
+#else
+ base->STOPCTRL &= ~SMC_STOPCTRL_PORPO_MASK;
+#endif
+ }
+ else
+ {
+#if (defined(FSL_FEATURE_SMC_USE_VLLSCTRL_REG) && FSL_FEATURE_SMC_USE_VLLSCTRL_REG)
+ base->VLLSCTRL |= SMC_VLLSCTRL_PORPO_MASK;
+#else
+ base->STOPCTRL |= SMC_STOPCTRL_PORPO_MASK;
+#endif
+ }
+ }
+#endif /* FSL_FEATURE_SMC_HAS_PORPO */
+
+#if (defined(FSL_FEATURE_SMC_HAS_RAM2_POWER_OPTION) && FSL_FEATURE_SMC_HAS_RAM2_POWER_OPTION)
+ else if (config->subMode == kSMC_StopSub2)
+ {
+ /* configure whether the Por Detect work in Vlls0 mode */
+ if (config->enableRam2InVlls2)
+ {
+#if (defined(FSL_FEATURE_SMC_USE_VLLSCTRL_REG) && FSL_FEATURE_SMC_USE_VLLSCTRL_REG)
+ base->VLLSCTRL |= SMC_VLLSCTRL_RAM2PO_MASK;
+#else
+ base->STOPCTRL |= SMC_STOPCTRL_RAM2PO_MASK;
+#endif
+ }
+ else
+ {
+#if (defined(FSL_FEATURE_SMC_USE_VLLSCTRL_REG) && FSL_FEATURE_SMC_USE_VLLSCTRL_REG)
+ base->VLLSCTRL &= ~SMC_VLLSCTRL_RAM2PO_MASK;
+#else
+ base->STOPCTRL &= ~SMC_STOPCTRL_RAM2PO_MASK;
+#endif
+ }
+ }
+ else
+ {
+ }
+#endif /* FSL_FEATURE_SMC_HAS_RAM2_POWER_OPTION */
+
+ /* configure to VLLS mode */
+ reg = base->PMCTRL;
+ reg &= ~SMC_PMCTRL_STOPM_MASK;
+ reg |= (kSMC_StopVlls << SMC_PMCTRL_STOPM_SHIFT);
+ base->PMCTRL = reg;
+
+/* configure the VLLS sub-mode */
+#if (defined(FSL_FEATURE_SMC_USE_VLLSCTRL_REG) && FSL_FEATURE_SMC_USE_VLLSCTRL_REG)
+ reg = base->VLLSCTRL;
+ reg &= ~SMC_VLLSCTRL_VLLSM_MASK;
+ reg |= ((uint32_t)config->subMode << SMC_VLLSCTRL_VLLSM_SHIFT);
+ base->VLLSCTRL = reg;
+#else
+#if (defined(FSL_FEATURE_SMC_HAS_LLS_SUBMODE) && FSL_FEATURE_SMC_HAS_LLS_SUBMODE)
+ reg = base->STOPCTRL;
+ reg &= ~SMC_STOPCTRL_LLSM_MASK;
+ reg |= ((uint32_t)config->subMode << SMC_STOPCTRL_LLSM_SHIFT);
+ base->STOPCTRL = reg;
+#else
+ reg = base->STOPCTRL;
+ reg &= ~SMC_STOPCTRL_VLLSM_MASK;
+ reg |= ((uint32_t)config->subMode << SMC_STOPCTRL_VLLSM_SHIFT);
+ base->STOPCTRL = reg;
+#endif /* FSL_FEATURE_SMC_HAS_LLS_SUBMODE */
+#endif
+
+#if (defined(FSL_FEATURE_SMC_HAS_LPOPO) && FSL_FEATURE_SMC_HAS_LPOPO)
+ if (config->enableLpoClock)
+ {
+ base->STOPCTRL &= ~SMC_STOPCTRL_LPOPO_MASK;
+ }
+ else
+ {
+ base->STOPCTRL |= SMC_STOPCTRL_LPOPO_MASK;
+ }
+#endif /* FSL_FEATURE_SMC_HAS_LPOPO */
+
+ /* Set the SLEEPDEEP bit to enable deep sleep mode */
+ SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
+
+ /* read back to make sure the configuration valid before enter stop mode */
+ (void)base->PMCTRL;
+ __DSB();
+ __WFI();
+ __ISB();
+
+ /* check whether the power mode enter LLS mode succeed */
+ if (base->PMCTRL & SMC_PMCTRL_STOPA_MASK)
+ {
+ return kStatus_SMC_StopAbort;
+ }
+ else
+ {
+ return kStatus_Success;
+ }
+}
+#endif /* FSL_FEATURE_SMC_HAS_VERY_LOW_LEAKAGE_STOP_MODE */
diff --git a/drivers/src/fsl_sysmpu.c b/drivers/src/fsl_sysmpu.c
new file mode 100644
index 0000000..b89a7b2
--- /dev/null
+++ b/drivers/src/fsl_sysmpu.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsl_sysmpu.h"
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+const clock_ip_name_t g_sysmpuClock[FSL_FEATURE_SOC_SYSMPU_COUNT] = SYSMPU_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Codes
+ ******************************************************************************/
+
+void SYSMPU_Init(SYSMPU_Type *base, const sysmpu_config_t *config)
+{
+ assert(config);
+ uint8_t count;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Un-gate SYSMPU clock */
+ CLOCK_EnableClock(g_sysmpuClock[0]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Initializes the regions. */
+ for (count = 1; count < FSL_FEATURE_SYSMPU_DESCRIPTOR_COUNT; count++)
+ {
+ base->WORD[count][3] = 0; /* VLD/VID+PID. */
+ base->WORD[count][0] = 0; /* Start address. */
+ base->WORD[count][1] = 0; /* End address. */
+ base->WORD[count][2] = 0; /* Access rights. */
+ base->RGDAAC[count] = 0; /* Alternate access rights. */
+ }
+
+ /* SYSMPU configure. */
+ while (config)
+ {
+ SYSMPU_SetRegionConfig(base, &(config->regionConfig));
+ config = config->next;
+ }
+ /* Enable SYSMPU. */
+ SYSMPU_Enable(base, true);
+}
+
+void SYSMPU_Deinit(SYSMPU_Type *base)
+{
+ /* Disable SYSMPU. */
+ SYSMPU_Enable(base, false);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Gate the clock. */
+ CLOCK_DisableClock(g_sysmpuClock[0]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+void SYSMPU_GetHardwareInfo(SYSMPU_Type *base, sysmpu_hardware_info_t *hardwareInform)
+{
+ assert(hardwareInform);
+
+ uint32_t cesReg = base->CESR;
+
+ hardwareInform->hardwareRevisionLevel = (cesReg & SYSMPU_CESR_HRL_MASK) >> SYSMPU_CESR_HRL_SHIFT;
+ hardwareInform->slavePortsNumbers = (cesReg & SYSMPU_CESR_NSP_MASK) >> SYSMPU_CESR_NSP_SHIFT;
+ hardwareInform->regionsNumbers = (sysmpu_region_total_num_t)((cesReg & SYSMPU_CESR_NRGD_MASK) >> SYSMPU_CESR_NRGD_SHIFT);
+}
+
+void SYSMPU_SetRegionConfig(SYSMPU_Type *base, const sysmpu_region_config_t *regionConfig)
+{
+ assert(regionConfig);
+ assert(regionConfig->regionNum < FSL_FEATURE_SYSMPU_DESCRIPTOR_COUNT);
+
+ uint32_t wordReg = 0;
+ uint8_t msPortNum;
+ uint8_t regNumber = regionConfig->regionNum;
+
+ /* The start and end address of the region descriptor. */
+ base->WORD[regNumber][0] = regionConfig->startAddress;
+ base->WORD[regNumber][1] = regionConfig->endAddress;
+
+ /* Set the privilege rights for master 0 ~ master 3. */
+ for (msPortNum = 0; msPortNum < SYSMPU_MASTER_RWATTRIBUTE_START_PORT; msPortNum++)
+ {
+ wordReg |= SYSMPU_REGION_RWXRIGHTS_MASTER(
+ msPortNum, (((uint32_t)regionConfig->accessRights1[msPortNum].superAccessRights << 3U) |
+ (uint32_t)regionConfig->accessRights1[msPortNum].userAccessRights));
+
+#if FSL_FEATURE_SYSMPU_HAS_PROCESS_IDENTIFIER
+ wordReg |=
+ SYSMPU_REGION_RWXRIGHTS_MASTER_PE(msPortNum, regionConfig->accessRights1[msPortNum].processIdentifierEnable);
+#endif /* FSL_FEATURE_SYSMPU_HAS_PROCESS_IDENTIFIER */
+ }
+
+#if FSL_FEATURE_SYSMPU_MASTER_COUNT > SYSMPU_MASTER_RWATTRIBUTE_START_PORT
+ /* Set the normal read write rights for master 4 ~ master 7. */
+ for (msPortNum = SYSMPU_MASTER_RWATTRIBUTE_START_PORT; msPortNum < FSL_FEATURE_SYSMPU_MASTER_COUNT;
+ msPortNum++)
+ {
+ wordReg |= SYSMPU_REGION_RWRIGHTS_MASTER(msPortNum,
+ ((uint32_t)regionConfig->accessRights2[msPortNum - SYSMPU_MASTER_RWATTRIBUTE_START_PORT].readEnable << 1U |
+ (uint32_t)regionConfig->accessRights2[msPortNum - SYSMPU_MASTER_RWATTRIBUTE_START_PORT].writeEnable));
+ }
+#endif /* FSL_FEATURE_SYSMPU_MASTER_COUNT > SYSMPU_MASTER_RWATTRIBUTE_START_PORT */
+
+ /* Set region descriptor access rights. */
+ base->WORD[regNumber][2] = wordReg;
+
+ wordReg = SYSMPU_WORD_VLD(1);
+#if FSL_FEATURE_SYSMPU_HAS_PROCESS_IDENTIFIER
+ wordReg |= SYSMPU_WORD_PID(regionConfig->processIdentifier) | SYSMPU_WORD_PIDMASK(regionConfig->processIdMask);
+#endif /* FSL_FEATURE_SYSMPU_HAS_PROCESS_IDENTIFIER */
+
+ base->WORD[regNumber][3] = wordReg;
+}
+
+void SYSMPU_SetRegionAddr(SYSMPU_Type *base, uint32_t regionNum, uint32_t startAddr, uint32_t endAddr)
+{
+ assert(regionNum < FSL_FEATURE_SYSMPU_DESCRIPTOR_COUNT);
+
+ base->WORD[regionNum][0] = startAddr;
+ base->WORD[regionNum][1] = endAddr;
+}
+
+void SYSMPU_SetRegionRwxMasterAccessRights(SYSMPU_Type *base,
+ uint32_t regionNum,
+ uint32_t masterNum,
+ const sysmpu_rwxrights_master_access_control_t *accessRights)
+{
+ assert(accessRights);
+ assert(regionNum < FSL_FEATURE_SYSMPU_DESCRIPTOR_COUNT);
+ assert(masterNum < SYSMPU_MASTER_RWATTRIBUTE_START_PORT);
+
+ uint32_t mask = SYSMPU_REGION_RWXRIGHTS_MASTER_MASK(masterNum);
+ uint32_t right = base->RGDAAC[regionNum];
+
+#if FSL_FEATURE_SYSMPU_HAS_PROCESS_IDENTIFIER
+ mask |= SYSMPU_REGION_RWXRIGHTS_MASTER_PE_MASK(masterNum);
+#endif
+
+ /* Build rights control value. */
+ right &= ~mask;
+ right |= SYSMPU_REGION_RWXRIGHTS_MASTER(
+ masterNum, ((uint32_t)(accessRights->superAccessRights << 3U) | accessRights->userAccessRights));
+#if FSL_FEATURE_SYSMPU_HAS_PROCESS_IDENTIFIER
+ right |= SYSMPU_REGION_RWXRIGHTS_MASTER_PE(masterNum, accessRights->processIdentifierEnable);
+#endif /* FSL_FEATURE_SYSMPU_HAS_PROCESS_IDENTIFIER */
+
+ /* Set low master region access rights. */
+ base->RGDAAC[regionNum] = right;
+}
+
+#if FSL_FEATURE_SYSMPU_MASTER_COUNT > 4
+void SYSMPU_SetRegionRwMasterAccessRights(SYSMPU_Type *base,
+ uint32_t regionNum,
+ uint32_t masterNum,
+ const sysmpu_rwrights_master_access_control_t *accessRights)
+{
+ assert(accessRights);
+ assert(regionNum < FSL_FEATURE_SYSMPU_DESCRIPTOR_COUNT);
+ assert(masterNum >= SYSMPU_MASTER_RWATTRIBUTE_START_PORT);
+ assert(masterNum <= (FSL_FEATURE_SYSMPU_MASTER_COUNT - 1));
+
+ uint32_t mask = SYSMPU_REGION_RWRIGHTS_MASTER_MASK(masterNum);
+ uint32_t right = base->RGDAAC[regionNum];
+
+ /* Build rights control value. */
+ right &= ~mask;
+ right |=
+ SYSMPU_REGION_RWRIGHTS_MASTER(masterNum, (((uint32_t)accessRights->readEnable << 1U) | accessRights->writeEnable));
+ /* Set low master region access rights. */
+ base->RGDAAC[regionNum] = right;
+}
+#endif /* FSL_FEATURE_SYSMPU_MASTER_COUNT > 4 */
+
+bool SYSMPU_GetSlavePortErrorStatus(SYSMPU_Type *base, sysmpu_slave_t slaveNum)
+{
+ uint8_t sperr;
+
+ sperr = ((base->CESR & SYSMPU_CESR_SPERR_MASK) >> SYSMPU_CESR_SPERR_SHIFT) & (0x1U << (FSL_FEATURE_SYSMPU_SLAVE_COUNT - slaveNum - 1));
+
+ return (sperr != 0) ? true : false;
+}
+
+void SYSMPU_GetDetailErrorAccessInfo(SYSMPU_Type *base, sysmpu_slave_t slaveNum, sysmpu_access_err_info_t *errInform)
+{
+ assert(errInform);
+
+ uint16_t value;
+ uint32_t cesReg;
+
+ /* Error address. */
+ errInform->address = base->SP[slaveNum].EAR;
+
+ /* Error detail information. */
+ value = (base->SP[slaveNum].EDR & SYSMPU_EDR_EACD_MASK) >> SYSMPU_EDR_EACD_SHIFT;
+ if (!value)
+ {
+ errInform->accessControl = kSYSMPU_NoRegionHit;
+ }
+ else if (!(value & (uint16_t)(value - 1)))
+ {
+ errInform->accessControl = kSYSMPU_NoneOverlappRegion;
+ }
+ else
+ {
+ errInform->accessControl = kSYSMPU_OverlappRegion;
+ }
+
+ value = base->SP[slaveNum].EDR;
+ errInform->master = (uint32_t)((value & SYSMPU_EDR_EMN_MASK) >> SYSMPU_EDR_EMN_SHIFT);
+ errInform->attributes = (sysmpu_err_attributes_t)((value & SYSMPU_EDR_EATTR_MASK) >> SYSMPU_EDR_EATTR_SHIFT);
+ errInform->accessType = (sysmpu_err_access_type_t)((value & SYSMPU_EDR_ERW_MASK) >> SYSMPU_EDR_ERW_SHIFT);
+#if FSL_FEATURE_SYSMPU_HAS_PROCESS_IDENTIFIER
+ errInform->processorIdentification = (uint8_t)((value & SYSMPU_EDR_EPID_MASK) >> SYSMPU_EDR_EPID_SHIFT);
+#endif
+
+ /* Clears error slave port bit. */
+ cesReg = (base->CESR & ~SYSMPU_CESR_SPERR_MASK) | ((0x1U << (FSL_FEATURE_SYSMPU_SLAVE_COUNT - slaveNum - 1)) << SYSMPU_CESR_SPERR_SHIFT);
+ base->CESR = cesReg;
+}
diff --git a/drivers/src/fsl_tsi_v2.c b/drivers/src/fsl_tsi_v2.c
new file mode 100644
index 0000000..1934982
--- /dev/null
+++ b/drivers/src/fsl_tsi_v2.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2014 - 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "fsl_tsi_v2.h"
+
+void TSI_Init(TSI_Type *base, const tsi_config_t *config)
+{
+ assert(config != NULL);
+
+ bool is_module_enabled = false;
+ bool is_int_enabled = false;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_EnableClock(kCLOCK_Tsi0);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+ if (base->GENCS & TSI_GENCS_TSIEN_MASK)
+ {
+ is_module_enabled = true;
+ TSI_EnableModule(base, false); /* Disable module */
+ }
+ if (base->GENCS & TSI_GENCS_TSIIE_MASK)
+ {
+ is_int_enabled = true;
+ TSI_DisableInterrupts(base, kTSI_GlobalInterruptEnable);
+ }
+
+ TSI_SetHighThreshold(base, config->thresh);
+ TSI_SetLowThreshold(base, config->thresl);
+ TSI_SetLowPowerClock(base, config->lpclks);
+ TSI_SetLowPowerScanInterval(base, config->lpscnitv);
+ TSI_SetActiveModeSource(base, config->amclks);
+ TSI_SetActiveModePrescaler(base, config->ampsc);
+ TSI_SetElectrodeOSCPrescaler(base, config->ps);
+ TSI_SetElectrodeChargeCurrent(base, config->extchrg);
+ TSI_SetReferenceChargeCurrent(base, config->refchrg);
+ TSI_SetNumberOfScans(base, config->nscn);
+
+ if (is_module_enabled)
+ {
+ TSI_EnableModule(base, true);
+ }
+ if (is_int_enabled)
+ {
+ TSI_EnableInterrupts(base, kTSI_GlobalInterruptEnable);
+ }
+}
+
+void TSI_Deinit(TSI_Type *base)
+{
+ base->GENCS = 0U;
+ base->SCANC = 0U;
+ base->PEN = 0U;
+ base->THRESHOLD = 0U;
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_DisableClock(kCLOCK_Tsi0);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+void TSI_GetNormalModeDefaultConfig(tsi_config_t *userConfig)
+{
+ userConfig->thresh = 0U;
+ userConfig->thresl = 0U;
+ userConfig->lpclks = kTSI_LowPowerClockSource_LPOCLK;
+ userConfig->lpscnitv = kTSI_LowPowerInterval_100ms;
+ userConfig->amclks = kTSI_ActiveClkSource_LPOSCCLK;
+ userConfig->ampsc = kTSI_ActiveModePrescaler_8div;
+ userConfig->ps = kTSI_ElecOscPrescaler_2div;
+ userConfig->extchrg = kTSI_ExtOscChargeCurrent_10uA;
+ userConfig->refchrg = kTSI_RefOscChargeCurrent_10uA;
+ userConfig->nscn = kTSI_ConsecutiveScansNumber_8time;
+}
+
+void TSI_GetLowPowerModeDefaultConfig(tsi_config_t *userConfig)
+{
+ userConfig->thresh = 15000U;
+ userConfig->thresl = 1000U;
+ userConfig->lpclks = kTSI_LowPowerClockSource_LPOCLK;
+ userConfig->lpscnitv = kTSI_LowPowerInterval_100ms;
+ userConfig->amclks = kTSI_ActiveClkSource_LPOSCCLK;
+ userConfig->ampsc = kTSI_ActiveModePrescaler_64div;
+ userConfig->ps = kTSI_ElecOscPrescaler_1div;
+ userConfig->extchrg = kTSI_ExtOscChargeCurrent_2uA;
+ userConfig->refchrg = kTSI_RefOscChargeCurrent_32uA;
+ userConfig->nscn = kTSI_ConsecutiveScansNumber_26time;
+}
+
+void TSI_Calibrate(TSI_Type *base, tsi_calibration_data_t *calBuff)
+{
+ assert(calBuff != NULL);
+
+ uint8_t i = 0U;
+ bool is_int_enabled = false;
+
+ if (base->GENCS & TSI_GENCS_TSIIE_MASK)
+ {
+ is_int_enabled = true;
+ TSI_DisableInterrupts(base, kTSI_GlobalInterruptEnable);
+ }
+
+ TSI_EnableChannels(base, 0xFFFFU, true);
+ TSI_StartSoftwareTrigger(base);
+ while (!(TSI_GetStatusFlags(base) & kTSI_EndOfScanFlag))
+ {
+ }
+
+ for (i = 0U; i < FSL_FEATURE_TSI_CHANNEL_COUNT; i++)
+ {
+ calBuff->calibratedData[i] = TSI_GetNormalModeCounter(base, i);
+ }
+ TSI_ClearStatusFlags(base, kTSI_EndOfScanFlag);
+ TSI_EnableChannels(base, 0xFFFFU, false);
+
+ if (is_int_enabled)
+ {
+ TSI_EnableInterrupts(base, kTSI_GlobalInterruptEnable);
+ }
+}
+
+void TSI_EnableInterrupts(TSI_Type *base, uint32_t mask)
+{
+ uint32_t regValue = base->GENCS & (~ALL_FLAGS_MASK);
+
+ if (mask & kTSI_GlobalInterruptEnable)
+ {
+ regValue |= TSI_GENCS_TSIIE_MASK;
+ }
+ if (mask & kTSI_OutOfRangeInterruptEnable)
+ {
+ regValue &= (~TSI_GENCS_ESOR_MASK);
+ }
+ if (mask & kTSI_EndOfScanInterruptEnable)
+ {
+ regValue |= TSI_GENCS_ESOR_MASK;
+ }
+ if (mask & kTSI_ErrorInterrruptEnable)
+ {
+ regValue |= TSI_GENCS_ERIE_MASK;
+ }
+
+ base->GENCS = regValue; /* write value to register */
+}
+
+void TSI_DisableInterrupts(TSI_Type *base, uint32_t mask)
+{
+ uint32_t regValue = base->GENCS & (~ALL_FLAGS_MASK);
+
+ if (mask & kTSI_GlobalInterruptEnable)
+ {
+ regValue &= (~TSI_GENCS_TSIIE_MASK);
+ }
+ if (mask & kTSI_OutOfRangeInterruptEnable)
+ {
+ regValue |= TSI_GENCS_ESOR_MASK;
+ }
+ if (mask & kTSI_EndOfScanInterruptEnable)
+ {
+ regValue &= (~TSI_GENCS_ESOR_MASK);
+ }
+ if (mask & kTSI_ErrorInterrruptEnable)
+ {
+ regValue &= (~TSI_GENCS_ERIE_MASK);
+ }
+
+ base->GENCS = regValue; /* write value to register */
+}
+
+void TSI_ClearStatusFlags(TSI_Type *base, uint32_t mask)
+{
+ uint32_t regValue = base->GENCS & (~ALL_FLAGS_MASK);
+
+ if (mask & kTSI_EndOfScanFlag)
+ {
+ regValue |= TSI_GENCS_EOSF_MASK;
+ }
+ if (mask & kTSI_OutOfRangeFlag)
+ {
+ regValue |= TSI_GENCS_OUTRGF_MASK;
+ }
+ if (mask & kTSI_ExternalElectrodeErrorFlag)
+ {
+ regValue |= TSI_GENCS_EXTERF_MASK;
+ }
+ if (mask & kTSI_OverrunErrorFlag)
+ {
+ regValue |= TSI_GENCS_OVRF_MASK;
+ }
+
+ base->GENCS = regValue; /* write value to register */
+}
diff --git a/drivers/src/fsl_uart.c b/drivers/src/fsl_uart.c
new file mode 100644
index 0000000..17d9260
--- /dev/null
+++ b/drivers/src/fsl_uart.c
@@ -0,0 +1,1230 @@
+/*
+ * Copyright (c) 2015-2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsl_uart.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* UART transfer state. */
+enum _uart_tansfer_states
+{
+ kUART_TxIdle, /* TX idle. */
+ kUART_TxBusy, /* TX busy. */
+ kUART_RxIdle, /* RX idle. */
+ kUART_RxBusy, /* RX busy. */
+ kUART_RxFramingError, /* Rx framing error */
+ kUART_RxParityError /* Rx parity error */
+};
+
+/* Typedef for interrupt handler. */
+typedef void (*uart_isr_t)(UART_Type *base, uart_handle_t *handle);
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Get the UART instance from peripheral base address.
+ *
+ * @param base UART peripheral base address.
+ * @return UART instance.
+ */
+uint32_t UART_GetInstance(UART_Type *base);
+
+/*!
+ * @brief Get the length of received data in RX ring buffer.
+ *
+ * @param handle UART handle pointer.
+ * @return Length of received data in RX ring buffer.
+ */
+static size_t UART_TransferGetRxRingBufferLength(uart_handle_t *handle);
+
+/*!
+ * @brief Check whether the RX ring buffer is full.
+ *
+ * @param handle UART handle pointer.
+ * @retval true RX ring buffer is full.
+ * @retval false RX ring buffer is not full.
+ */
+static bool UART_TransferIsRxRingBufferFull(uart_handle_t *handle);
+
+/*!
+ * @brief Read RX register using non-blocking method.
+ *
+ * This function reads data from the TX register directly, upper layer must make
+ * sure the RX register is full or TX FIFO has data before calling this function.
+ *
+ * @param base UART peripheral base address.
+ * @param data Start addresss of the buffer to store the received data.
+ * @param length Size of the buffer.
+ */
+static void UART_ReadNonBlocking(UART_Type *base, uint8_t *data, size_t length);
+
+/*!
+ * @brief Write to TX register using non-blocking method.
+ *
+ * This function writes data to the TX register directly, upper layer must make
+ * sure the TX register is empty or TX FIFO has empty room before calling this function.
+ *
+ * @note This function does not check whether all the data has been sent out to bus,
+ * so before disable TX, check kUART_TransmissionCompleteFlag to ensure the TX is
+ * finished.
+ *
+ * @param base UART peripheral base address.
+ * @param data Start addresss of the data to write.
+ * @param length Size of the buffer to be sent.
+ */
+static void UART_WriteNonBlocking(UART_Type *base, const uint8_t *data, size_t length);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/* Array of UART handle. */
+#if (defined(UART5))
+#define UART_HANDLE_ARRAY_SIZE 6
+#else /* UART5 */
+#if (defined(UART4))
+#define UART_HANDLE_ARRAY_SIZE 5
+#else /* UART4 */
+#if (defined(UART3))
+#define UART_HANDLE_ARRAY_SIZE 4
+#else /* UART3 */
+#if (defined(UART2))
+#define UART_HANDLE_ARRAY_SIZE 3
+#else /* UART2 */
+#if (defined(UART1))
+#define UART_HANDLE_ARRAY_SIZE 2
+#else /* UART1 */
+#if (defined(UART0))
+#define UART_HANDLE_ARRAY_SIZE 1
+#else /* UART0 */
+#error No UART instance.
+#endif /* UART 0 */
+#endif /* UART 1 */
+#endif /* UART 2 */
+#endif /* UART 3 */
+#endif /* UART 4 */
+#endif /* UART 5 */
+static uart_handle_t *s_uartHandle[UART_HANDLE_ARRAY_SIZE];
+/* Array of UART peripheral base address. */
+static UART_Type *const s_uartBases[] = UART_BASE_PTRS;
+
+/* Array of UART IRQ number. */
+static const IRQn_Type s_uartIRQ[] = UART_RX_TX_IRQS;
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/* Array of UART clock name. */
+static const clock_ip_name_t s_uartClock[] = UART_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/* UART ISR for transactional APIs. */
+static uart_isr_t s_uartIsr;
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+uint32_t UART_GetInstance(UART_Type *base)
+{
+ uint32_t instance;
+ uint32_t uartArrayCount = (sizeof(s_uartBases) / sizeof(s_uartBases[0]));
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < uartArrayCount; instance++)
+ {
+ if (s_uartBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < uartArrayCount);
+
+ return instance;
+}
+
+static size_t UART_TransferGetRxRingBufferLength(uart_handle_t *handle)
+{
+ assert(handle);
+
+ size_t size;
+
+ if (handle->rxRingBufferTail > handle->rxRingBufferHead)
+ {
+ size = (size_t)(handle->rxRingBufferHead + handle->rxRingBufferSize - handle->rxRingBufferTail);
+ }
+ else
+ {
+ size = (size_t)(handle->rxRingBufferHead - handle->rxRingBufferTail);
+ }
+
+ return size;
+}
+
+static bool UART_TransferIsRxRingBufferFull(uart_handle_t *handle)
+{
+ assert(handle);
+
+ bool full;
+
+ if (UART_TransferGetRxRingBufferLength(handle) == (handle->rxRingBufferSize - 1U))
+ {
+ full = true;
+ }
+ else
+ {
+ full = false;
+ }
+
+ return full;
+}
+
+status_t UART_Init(UART_Type *base, const uart_config_t *config, uint32_t srcClock_Hz)
+{
+ assert(config);
+ assert(config->baudRate_Bps);
+#if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
+ assert(FSL_FEATURE_UART_FIFO_SIZEn(base) >= config->txFifoWatermark);
+ assert(FSL_FEATURE_UART_FIFO_SIZEn(base) >= config->rxFifoWatermark);
+#endif
+
+ uint16_t sbr = 0;
+ uint8_t temp = 0;
+ uint32_t baudDiff = 0;
+
+ /* Calculate the baud rate modulo divisor, sbr*/
+ sbr = srcClock_Hz / (config->baudRate_Bps * 16);
+ /* set sbrTemp to 1 if the sourceClockInHz can not satisfy the desired baud rate */
+ if (sbr == 0)
+ {
+ sbr = 1;
+ }
+#if defined(FSL_FEATURE_UART_HAS_BAUD_RATE_FINE_ADJUST_SUPPORT) && FSL_FEATURE_UART_HAS_BAUD_RATE_FINE_ADJUST_SUPPORT
+ /* Determine if a fractional divider is needed to fine tune closer to the
+ * desired baud, each value of brfa is in 1/32 increments,
+ * hence the multiply-by-32. */
+ uint32_t tempBaud = 0;
+
+ uint16_t brfa = (2 * srcClock_Hz / (config->baudRate_Bps)) - 32 * sbr;
+
+ /* Calculate the baud rate based on the temporary SBR values and BRFA */
+ tempBaud = (srcClock_Hz * 2 / ((sbr * 32 + brfa)));
+ baudDiff =
+ (tempBaud > config->baudRate_Bps) ? (tempBaud - config->baudRate_Bps) : (config->baudRate_Bps - tempBaud);
+
+#else
+ /* Calculate the baud rate based on the temporary SBR values */
+ baudDiff = (srcClock_Hz / (sbr * 16)) - config->baudRate_Bps;
+
+ /* Select the better value between sbr and (sbr + 1) */
+ if (baudDiff > (config->baudRate_Bps - (srcClock_Hz / (16 * (sbr + 1)))))
+ {
+ baudDiff = config->baudRate_Bps - (srcClock_Hz / (16 * (sbr + 1)));
+ sbr++;
+ }
+#endif
+
+ /* next, check to see if actual baud rate is within 3% of desired baud rate
+ * based on the calculate SBR value */
+ if (baudDiff > ((config->baudRate_Bps / 100) * 3))
+ {
+ /* Unacceptable baud rate difference of more than 3%*/
+ return kStatus_UART_BaudrateNotSupport;
+ }
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable uart clock */
+ CLOCK_EnableClock(s_uartClock[UART_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Disable UART TX RX before setting. */
+ base->C2 &= ~(UART_C2_TE_MASK | UART_C2_RE_MASK);
+
+ /* Write the sbr value to the BDH and BDL registers*/
+ base->BDH = (base->BDH & ~UART_BDH_SBR_MASK) | (uint8_t)(sbr >> 8);
+ base->BDL = (uint8_t)sbr;
+
+#if defined(FSL_FEATURE_UART_HAS_BAUD_RATE_FINE_ADJUST_SUPPORT) && FSL_FEATURE_UART_HAS_BAUD_RATE_FINE_ADJUST_SUPPORT
+ /* Write the brfa value to the register*/
+ base->C4 = (base->C4 & ~UART_C4_BRFA_MASK) | (brfa & UART_C4_BRFA_MASK);
+#endif
+
+ /* Set bit count and parity mode. */
+ temp = base->C1 & ~(UART_C1_PE_MASK | UART_C1_PT_MASK | UART_C1_M_MASK);
+
+ if (kUART_ParityDisabled != config->parityMode)
+ {
+ temp |= (UART_C1_M_MASK | (uint8_t)config->parityMode);
+ }
+
+ base->C1 = temp;
+
+#if defined(FSL_FEATURE_UART_HAS_STOP_BIT_CONFIG_SUPPORT) && FSL_FEATURE_UART_HAS_STOP_BIT_CONFIG_SUPPORT
+ /* Set stop bit per char */
+ base->BDH = (base->BDH & ~UART_BDH_SBNS_MASK) | UART_BDH_SBNS((uint8_t)config->stopBitCount);
+#endif
+
+#if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
+ /* Set tx/rx FIFO watermark */
+ base->TWFIFO = config->txFifoWatermark;
+ base->RWFIFO = config->rxFifoWatermark;
+
+ /* Enable tx/rx FIFO */
+ base->PFIFO |= (UART_PFIFO_TXFE_MASK | UART_PFIFO_RXFE_MASK);
+
+ /* Flush FIFO */
+ base->CFIFO |= (UART_CFIFO_TXFLUSH_MASK | UART_CFIFO_RXFLUSH_MASK);
+#endif
+
+ /* Enable TX/RX base on configure structure. */
+ temp = base->C2;
+
+ if (config->enableTx)
+ {
+ temp |= UART_C2_TE_MASK;
+ }
+
+ if (config->enableRx)
+ {
+ temp |= UART_C2_RE_MASK;
+ }
+
+ base->C2 = temp;
+
+ return kStatus_Success;
+}
+
+void UART_Deinit(UART_Type *base)
+{
+#if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
+ /* Wait tx FIFO send out*/
+ while (0 != base->TCFIFO)
+ {
+ }
+#endif
+ /* Wait last char shoft out */
+ while (0 == (base->S1 & UART_S1_TC_MASK))
+ {
+ }
+
+ /* Disable the module. */
+ base->C2 = 0;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Disable uart clock */
+ CLOCK_DisableClock(s_uartClock[UART_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+void UART_GetDefaultConfig(uart_config_t *config)
+{
+ assert(config);
+
+ config->baudRate_Bps = 115200U;
+ config->parityMode = kUART_ParityDisabled;
+#if defined(FSL_FEATURE_UART_HAS_STOP_BIT_CONFIG_SUPPORT) && FSL_FEATURE_UART_HAS_STOP_BIT_CONFIG_SUPPORT
+ config->stopBitCount = kUART_OneStopBit;
+#endif
+#if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
+ config->txFifoWatermark = 0;
+ config->rxFifoWatermark = 1;
+#endif
+ config->enableTx = false;
+ config->enableRx = false;
+}
+
+status_t UART_SetBaudRate(UART_Type *base, uint32_t baudRate_Bps, uint32_t srcClock_Hz)
+{
+ assert(baudRate_Bps);
+
+ uint16_t sbr = 0;
+ uint32_t baudDiff = 0;
+ uint8_t oldCtrl;
+
+ /* Calculate the baud rate modulo divisor, sbr*/
+ sbr = srcClock_Hz / (baudRate_Bps * 16);
+ /* set sbrTemp to 1 if the sourceClockInHz can not satisfy the desired baud rate */
+ if (sbr == 0)
+ {
+ sbr = 1;
+ }
+#if defined(FSL_FEATURE_UART_HAS_BAUD_RATE_FINE_ADJUST_SUPPORT) && FSL_FEATURE_UART_HAS_BAUD_RATE_FINE_ADJUST_SUPPORT
+ /* Determine if a fractional divider is needed to fine tune closer to the
+ * desired baud, each value of brfa is in 1/32 increments,
+ * hence the multiply-by-32. */
+ uint32_t tempBaud = 0;
+
+ uint16_t brfa = (2 * srcClock_Hz / (baudRate_Bps)) - 32 * sbr;
+
+ /* Calculate the baud rate based on the temporary SBR values and BRFA */
+ tempBaud = (srcClock_Hz * 2 / ((sbr * 32 + brfa)));
+ baudDiff = (tempBaud > baudRate_Bps) ? (tempBaud - baudRate_Bps) : (baudRate_Bps - tempBaud);
+#else
+ /* Calculate the baud rate based on the temporary SBR values */
+ baudDiff = (srcClock_Hz / (sbr * 16)) - baudRate_Bps;
+
+ /* Select the better value between sbr and (sbr + 1) */
+ if (baudDiff > (baudRate_Bps - (srcClock_Hz / (16 * (sbr + 1)))))
+ {
+ baudDiff = baudRate_Bps - (srcClock_Hz / (16 * (sbr + 1)));
+ sbr++;
+ }
+#endif
+
+ /* next, check to see if actual baud rate is within 3% of desired baud rate
+ * based on the calculate SBR value */
+ if (baudDiff < ((baudRate_Bps / 100) * 3))
+ {
+ /* Store C2 before disable Tx and Rx */
+ oldCtrl = base->C2;
+
+ /* Disable UART TX RX before setting. */
+ base->C2 &= ~(UART_C2_TE_MASK | UART_C2_RE_MASK);
+
+ /* Write the sbr value to the BDH and BDL registers*/
+ base->BDH = (base->BDH & ~UART_BDH_SBR_MASK) | (uint8_t)(sbr >> 8);
+ base->BDL = (uint8_t)sbr;
+
+#if defined(FSL_FEATURE_UART_HAS_BAUD_RATE_FINE_ADJUST_SUPPORT) && FSL_FEATURE_UART_HAS_BAUD_RATE_FINE_ADJUST_SUPPORT
+ /* Write the brfa value to the register*/
+ base->C4 = (base->C4 & ~UART_C4_BRFA_MASK) | (brfa & UART_C4_BRFA_MASK);
+#endif
+ /* Restore C2. */
+ base->C2 = oldCtrl;
+
+ return kStatus_Success;
+ }
+ else
+ {
+ /* Unacceptable baud rate difference of more than 3%*/
+ return kStatus_UART_BaudrateNotSupport;
+ }
+}
+
+void UART_EnableInterrupts(UART_Type *base, uint32_t mask)
+{
+ mask &= kUART_AllInterruptsEnable;
+
+ /* The interrupt mask is combined by control bits from several register: ((CFIFO<<24) | (C3<<16) | (C2<<8) |(BDH))
+ */
+ base->BDH |= mask;
+ base->C2 |= (mask >> 8);
+ base->C3 |= (mask >> 16);
+
+#if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
+ base->CFIFO |= (mask >> 24);
+#endif
+}
+
+void UART_DisableInterrupts(UART_Type *base, uint32_t mask)
+{
+ mask &= kUART_AllInterruptsEnable;
+
+ /* The interrupt mask is combined by control bits from several register: ((CFIFO<<24) | (C3<<16) | (C2<<8) |(BDH))
+ */
+ base->BDH &= ~mask;
+ base->C2 &= ~(mask >> 8);
+ base->C3 &= ~(mask >> 16);
+
+#if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
+ base->CFIFO &= ~(mask >> 24);
+#endif
+}
+
+uint32_t UART_GetEnabledInterrupts(UART_Type *base)
+{
+ uint32_t temp;
+
+ temp = base->BDH | ((uint32_t)(base->C2) << 8) | ((uint32_t)(base->C3) << 16);
+
+#if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
+ temp |= ((uint32_t)(base->CFIFO) << 24);
+#endif
+
+ return temp & kUART_AllInterruptsEnable;
+}
+
+uint32_t UART_GetStatusFlags(UART_Type *base)
+{
+ uint32_t status_flag;
+
+ status_flag = base->S1 | ((uint32_t)(base->S2) << 8);
+
+#if defined(FSL_FEATURE_UART_HAS_EXTENDED_DATA_REGISTER_FLAGS) && FSL_FEATURE_UART_HAS_EXTENDED_DATA_REGISTER_FLAGS
+ status_flag |= ((uint32_t)(base->ED) << 16);
+#endif
+
+#if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
+ status_flag |= ((uint32_t)(base->SFIFO) << 24);
+#endif
+
+ return status_flag;
+}
+
+status_t UART_ClearStatusFlags(UART_Type *base, uint32_t mask)
+{
+ uint8_t reg = base->S2;
+ status_t status;
+
+#if defined(FSL_FEATURE_UART_HAS_LIN_BREAK_DETECT) && FSL_FEATURE_UART_HAS_LIN_BREAK_DETECT
+ reg &= ~(UART_S2_RXEDGIF_MASK | UART_S2_LBKDIF_MASK);
+#else
+ reg &= ~UART_S2_RXEDGIF_MASK;
+#endif
+
+ base->S2 = reg | (uint8_t)(mask >> 8);
+
+#if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
+ base->SFIFO = (uint8_t)(mask >> 24);
+#endif
+
+ if (mask & (kUART_IdleLineFlag | kUART_NoiseErrorFlag | kUART_FramingErrorFlag | kUART_ParityErrorFlag))
+ {
+ /* Read base->D to clear the flags. */
+ (void)base->S1;
+ (void)base->D;
+ }
+
+ if (mask & kUART_RxOverrunFlag)
+ {
+ /* Read base->D to clear the flags and Flush all data in FIFO. */
+ (void)base->S1;
+ (void)base->D;
+#if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
+ /* Flush FIFO date, otherwise FIFO pointer will be in unknown state. */
+ base->CFIFO |= UART_CFIFO_RXFLUSH_MASK;
+#endif
+ }
+
+ /* If some flags still pending. */
+ if (mask & UART_GetStatusFlags(base))
+ {
+ /* Some flags can only clear or set by the hardware itself, these flags are: kUART_TxDataRegEmptyFlag,
+ kUART_TransmissionCompleteFlag, kUART_RxDataRegFullFlag, kUART_RxActiveFlag, kUART_NoiseErrorInRxDataRegFlag,
+ kUART_ParityErrorInRxDataRegFlag, kUART_TxFifoEmptyFlag, kUART_RxFifoEmptyFlag. */
+ status = kStatus_UART_FlagCannotClearManually;
+ }
+ else
+ {
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+void UART_WriteBlocking(UART_Type *base, const uint8_t *data, size_t length)
+{
+ /* This API can only ensure that the data is written into the data buffer but can't
+ ensure all data in the data buffer are sent into the transmit shift buffer. */
+ while (length--)
+ {
+ while (!(base->S1 & UART_S1_TDRE_MASK))
+ {
+ }
+ base->D = *(data++);
+ }
+}
+
+static void UART_WriteNonBlocking(UART_Type *base, const uint8_t *data, size_t length)
+{
+ assert(data);
+
+ size_t i;
+
+ /* The Non Blocking write data API assume user have ensured there is enough space in
+ peripheral to write. */
+ for (i = 0; i < length; i++)
+ {
+ base->D = data[i];
+ }
+}
+
+status_t UART_ReadBlocking(UART_Type *base, uint8_t *data, size_t length)
+{
+ assert(data);
+
+ uint32_t statusFlag;
+
+ while (length--)
+ {
+#if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
+ while (!base->RCFIFO)
+#else
+ while (!(base->S1 & UART_S1_RDRF_MASK))
+#endif
+ {
+ statusFlag = UART_GetStatusFlags(base);
+
+ if (statusFlag & kUART_RxOverrunFlag)
+ {
+ return kStatus_UART_RxHardwareOverrun;
+ }
+
+ if (statusFlag & kUART_NoiseErrorFlag)
+ {
+ return kStatus_UART_NoiseError;
+ }
+
+ if (statusFlag & kUART_FramingErrorFlag)
+ {
+ return kStatus_UART_FramingError;
+ }
+
+ if (statusFlag & kUART_ParityErrorFlag)
+ {
+ return kStatus_UART_ParityError;
+ }
+ }
+ *(data++) = base->D;
+ }
+
+ return kStatus_Success;
+}
+
+static void UART_ReadNonBlocking(UART_Type *base, uint8_t *data, size_t length)
+{
+ assert(data);
+
+ size_t i;
+
+ /* The Non Blocking read data API assume user have ensured there is enough space in
+ peripheral to write. */
+ for (i = 0; i < length; i++)
+ {
+ data[i] = base->D;
+ }
+}
+
+void UART_TransferCreateHandle(UART_Type *base,
+ uart_handle_t *handle,
+ uart_transfer_callback_t callback,
+ void *userData)
+{
+ assert(handle);
+
+ uint32_t instance;
+
+ /* Zero the handle. */
+ memset(handle, 0, sizeof(*handle));
+
+ /* Set the TX/RX state. */
+ handle->rxState = kUART_RxIdle;
+ handle->txState = kUART_TxIdle;
+
+ /* Set the callback and user data. */
+ handle->callback = callback;
+ handle->userData = userData;
+
+#if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
+ /* Note:
+ Take care of the RX FIFO, RX interrupt request only assert when received bytes
+ equal or more than RX water mark, there is potential issue if RX water
+ mark larger than 1.
+ For example, if RX FIFO water mark is 2, upper layer needs 5 bytes and
+ 5 bytes are received. the last byte will be saved in FIFO but not trigger
+ RX interrupt because the water mark is 2.
+ */
+ base->RWFIFO = 1U;
+#endif
+
+ /* Get instance from peripheral base address. */
+ instance = UART_GetInstance(base);
+
+ /* Save the handle in global variables to support the double weak mechanism. */
+ s_uartHandle[instance] = handle;
+
+ s_uartIsr = UART_TransferHandleIRQ;
+ /* Enable interrupt in NVIC. */
+ EnableIRQ(s_uartIRQ[instance]);
+}
+
+void UART_TransferStartRingBuffer(UART_Type *base, uart_handle_t *handle, uint8_t *ringBuffer, size_t ringBufferSize)
+{
+ assert(handle);
+ assert(ringBuffer);
+
+ /* Setup the ringbuffer address */
+ handle->rxRingBuffer = ringBuffer;
+ handle->rxRingBufferSize = ringBufferSize;
+ handle->rxRingBufferHead = 0U;
+ handle->rxRingBufferTail = 0U;
+
+ /* Enable the interrupt to accept the data when user need the ring buffer. */
+ UART_EnableInterrupts(
+ base, kUART_RxDataRegFullInterruptEnable | kUART_RxOverrunInterruptEnable | kUART_FramingErrorInterruptEnable);
+ /* Enable parity error interrupt when parity mode is enable*/
+ if (UART_C1_PE_MASK & base->C1)
+ {
+ UART_EnableInterrupts(base, kUART_ParityErrorInterruptEnable);
+ }
+}
+
+void UART_TransferStopRingBuffer(UART_Type *base, uart_handle_t *handle)
+{
+ assert(handle);
+
+ if (handle->rxState == kUART_RxIdle)
+ {
+ UART_DisableInterrupts(base, kUART_RxDataRegFullInterruptEnable | kUART_RxOverrunInterruptEnable |
+ kUART_FramingErrorInterruptEnable);
+ /* Disable parity error interrupt when parity mode is enable*/
+ if (UART_C1_PE_MASK & base->C1)
+ {
+ UART_DisableInterrupts(base, kUART_ParityErrorInterruptEnable);
+ }
+ }
+
+ handle->rxRingBuffer = NULL;
+ handle->rxRingBufferSize = 0U;
+ handle->rxRingBufferHead = 0U;
+ handle->rxRingBufferTail = 0U;
+}
+
+status_t UART_TransferSendNonBlocking(UART_Type *base, uart_handle_t *handle, uart_transfer_t *xfer)
+{
+ assert(handle);
+ assert(xfer);
+ assert(xfer->dataSize);
+ assert(xfer->data);
+
+ status_t status;
+
+ /* Return error if current TX busy. */
+ if (kUART_TxBusy == handle->txState)
+ {
+ status = kStatus_UART_TxBusy;
+ }
+ else
+ {
+ handle->txData = xfer->data;
+ handle->txDataSize = xfer->dataSize;
+ handle->txDataSizeAll = xfer->dataSize;
+ handle->txState = kUART_TxBusy;
+
+ /* Enable transmiter interrupt. */
+ UART_EnableInterrupts(base, kUART_TxDataRegEmptyInterruptEnable);
+
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+void UART_TransferAbortSend(UART_Type *base, uart_handle_t *handle)
+{
+ assert(handle);
+
+ UART_DisableInterrupts(base, kUART_TxDataRegEmptyInterruptEnable | kUART_TransmissionCompleteInterruptEnable);
+
+ handle->txDataSize = 0;
+ handle->txState = kUART_TxIdle;
+}
+
+status_t UART_TransferGetSendCount(UART_Type *base, uart_handle_t *handle, uint32_t *count)
+{
+ assert(handle);
+ assert(count);
+
+ if (kUART_TxIdle == handle->txState)
+ {
+ return kStatus_NoTransferInProgress;
+ }
+
+ *count = handle->txDataSizeAll - handle->txDataSize;
+
+ return kStatus_Success;
+}
+
+status_t UART_TransferReceiveNonBlocking(UART_Type *base,
+ uart_handle_t *handle,
+ uart_transfer_t *xfer,
+ size_t *receivedBytes)
+{
+ assert(handle);
+ assert(xfer);
+ assert(xfer->data);
+ assert(xfer->dataSize);
+
+ uint32_t i;
+ status_t status;
+ /* How many bytes to copy from ring buffer to user memory. */
+ size_t bytesToCopy = 0U;
+ /* How many bytes to receive. */
+ size_t bytesToReceive;
+ /* How many bytes currently have received. */
+ size_t bytesCurrentReceived;
+
+ /* How to get data:
+ 1. If RX ring buffer is not enabled, then save xfer->data and xfer->dataSize
+ to uart handle, enable interrupt to store received data to xfer->data. When
+ all data received, trigger callback.
+ 2. If RX ring buffer is enabled and not empty, get data from ring buffer first.
+ If there are enough data in ring buffer, copy them to xfer->data and return.
+ If there are not enough data in ring buffer, copy all of them to xfer->data,
+ save the xfer->data remained empty space to uart handle, receive data
+ to this empty space and trigger callback when finished. */
+
+ if (kUART_RxBusy == handle->rxState)
+ {
+ status = kStatus_UART_RxBusy;
+ }
+ else
+ {
+ bytesToReceive = xfer->dataSize;
+ bytesCurrentReceived = 0U;
+
+ /* If RX ring buffer is used. */
+ if (handle->rxRingBuffer)
+ {
+ /* Disable UART RX IRQ, protect ring buffer. */
+ UART_DisableInterrupts(base, kUART_RxDataRegFullInterruptEnable);
+
+ /* How many bytes in RX ring buffer currently. */
+ bytesToCopy = UART_TransferGetRxRingBufferLength(handle);
+
+ if (bytesToCopy)
+ {
+ bytesToCopy = MIN(bytesToReceive, bytesToCopy);
+
+ bytesToReceive -= bytesToCopy;
+
+ /* Copy data from ring buffer to user memory. */
+ for (i = 0U; i < bytesToCopy; i++)
+ {
+ xfer->data[bytesCurrentReceived++] = handle->rxRingBuffer[handle->rxRingBufferTail];
+
+ /* Wrap to 0. Not use modulo (%) because it might be large and slow. */
+ if (handle->rxRingBufferTail + 1U == handle->rxRingBufferSize)
+ {
+ handle->rxRingBufferTail = 0U;
+ }
+ else
+ {
+ handle->rxRingBufferTail++;
+ }
+ }
+ }
+
+ /* If ring buffer does not have enough data, still need to read more data. */
+ if (bytesToReceive)
+ {
+ /* No data in ring buffer, save the request to UART handle. */
+ handle->rxData = xfer->data + bytesCurrentReceived;
+ handle->rxDataSize = bytesToReceive;
+ handle->rxDataSizeAll = bytesToReceive;
+ handle->rxState = kUART_RxBusy;
+ }
+
+ /* Enable UART RX IRQ if previously enabled. */
+ UART_EnableInterrupts(base, kUART_RxDataRegFullInterruptEnable);
+
+ /* Call user callback since all data are received. */
+ if (0 == bytesToReceive)
+ {
+ if (handle->callback)
+ {
+ handle->callback(base, handle, kStatus_UART_RxIdle, handle->userData);
+ }
+ }
+ }
+ /* Ring buffer not used. */
+ else
+ {
+ handle->rxData = xfer->data + bytesCurrentReceived;
+ handle->rxDataSize = bytesToReceive;
+ handle->rxDataSizeAll = bytesToReceive;
+ handle->rxState = kUART_RxBusy;
+
+ /* Enable RX/Rx overrun/framing error interrupt. */
+ UART_EnableInterrupts(base, kUART_RxDataRegFullInterruptEnable | kUART_RxOverrunInterruptEnable |
+ kUART_FramingErrorInterruptEnable);
+ /* Enable parity error interrupt when parity mode is enable*/
+ if (UART_C1_PE_MASK & base->C1)
+ {
+ UART_EnableInterrupts(base, kUART_ParityErrorInterruptEnable);
+ }
+ }
+
+ /* Return the how many bytes have read. */
+ if (receivedBytes)
+ {
+ *receivedBytes = bytesCurrentReceived;
+ }
+
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+void UART_TransferAbortReceive(UART_Type *base, uart_handle_t *handle)
+{
+ assert(handle);
+
+ /* Only abort the receive to handle->rxData, the RX ring buffer is still working. */
+ if (!handle->rxRingBuffer)
+ {
+ /* Disable RX interrupt. */
+ UART_DisableInterrupts(base, kUART_RxDataRegFullInterruptEnable | kUART_RxOverrunInterruptEnable |
+ kUART_FramingErrorInterruptEnable);
+ /* Disable parity error interrupt when parity mode is enable*/
+ if (UART_C1_PE_MASK & base->C1)
+ {
+ UART_DisableInterrupts(base, kUART_ParityErrorInterruptEnable);
+ }
+ }
+
+ handle->rxDataSize = 0U;
+ handle->rxState = kUART_RxIdle;
+}
+
+status_t UART_TransferGetReceiveCount(UART_Type *base, uart_handle_t *handle, uint32_t *count)
+{
+ assert(handle);
+ assert(count);
+
+ if (kUART_RxIdle == handle->rxState)
+ {
+ return kStatus_NoTransferInProgress;
+ }
+
+ if (!count)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ *count = handle->rxDataSizeAll - handle->rxDataSize;
+
+ return kStatus_Success;
+}
+
+void UART_TransferHandleIRQ(UART_Type *base, uart_handle_t *handle)
+{
+ assert(handle);
+
+ uint8_t count;
+ uint8_t tempCount;
+
+ /* If RX framing error */
+ if (UART_S1_FE_MASK & base->S1)
+ {
+ /* Read base->D to clear framing error flag, otherwise the RX does not work. */
+ while (base->S1 & UART_S1_RDRF_MASK)
+ {
+ (void)base->D;
+ }
+#if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
+ /* Flush FIFO date, otherwise FIFO pointer will be in unknown state. */
+ base->CFIFO |= UART_CFIFO_RXFLUSH_MASK;
+#endif
+
+ handle->rxState = kUART_RxFramingError;
+ handle->rxDataSize = 0U;
+ /* Trigger callback. */
+ if (handle->callback)
+ {
+ handle->callback(base, handle, kStatus_UART_FramingError, handle->userData);
+ }
+ }
+
+ /* If RX parity error */
+ if (UART_S1_PF_MASK & base->S1)
+ {
+ /* Read base->D to clear parity error flag, otherwise the RX does not work. */
+ while (base->S1 & UART_S1_RDRF_MASK)
+ {
+ (void)base->D;
+ }
+#if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
+ /* Flush FIFO date, otherwise FIFO pointer will be in unknown state. */
+ base->CFIFO |= UART_CFIFO_RXFLUSH_MASK;
+#endif
+
+ handle->rxState = kUART_RxParityError;
+ handle->rxDataSize = 0U;
+ /* Trigger callback. */
+ if (handle->callback)
+ {
+ handle->callback(base, handle, kStatus_UART_ParityError, handle->userData);
+ }
+ }
+
+ /* If RX overrun. */
+ if (UART_S1_OR_MASK & base->S1)
+ {
+ /* Read base->D to clear overrun flag, otherwise the RX does not work. */
+ while (base->S1 & UART_S1_RDRF_MASK)
+ {
+ (void)base->D;
+ }
+#if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
+ /* Flush FIFO date, otherwise FIFO pointer will be in unknown state. */
+ base->CFIFO |= UART_CFIFO_RXFLUSH_MASK;
+#endif
+ /* Trigger callback. */
+ if (handle->callback)
+ {
+ handle->callback(base, handle, kStatus_UART_RxHardwareOverrun, handle->userData);
+ }
+ }
+
+ /* Receive data register full */
+ if ((UART_S1_RDRF_MASK & base->S1) && (UART_C2_RIE_MASK & base->C2))
+ {
+/* Get the size that can be stored into buffer for this interrupt. */
+#if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
+ count = base->RCFIFO;
+#else
+ count = 1;
+#endif
+
+ /* If handle->rxDataSize is not 0, first save data to handle->rxData. */
+ while ((count) && (handle->rxDataSize))
+ {
+#if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
+ tempCount = MIN(handle->rxDataSize, count);
+#else
+ tempCount = 1;
+#endif
+
+ /* Using non block API to read the data from the registers. */
+ UART_ReadNonBlocking(base, handle->rxData, tempCount);
+ handle->rxData += tempCount;
+ handle->rxDataSize -= tempCount;
+ count -= tempCount;
+
+ /* If all the data required for upper layer is ready, trigger callback. */
+ if (!handle->rxDataSize)
+ {
+ handle->rxState = kUART_RxIdle;
+
+ if (handle->callback)
+ {
+ handle->callback(base, handle, kStatus_UART_RxIdle, handle->userData);
+ }
+ }
+ }
+
+ /* If use RX ring buffer, receive data to ring buffer. */
+ if (handle->rxRingBuffer)
+ {
+ while (count--)
+ {
+ /* If RX ring buffer is full, trigger callback to notify over run. */
+ if (UART_TransferIsRxRingBufferFull(handle))
+ {
+ if (handle->callback)
+ {
+ handle->callback(base, handle, kStatus_UART_RxRingBufferOverrun, handle->userData);
+ }
+ }
+
+ /* If ring buffer is still full after callback function, the oldest data is overrided. */
+ if (UART_TransferIsRxRingBufferFull(handle))
+ {
+ /* Increase handle->rxRingBufferTail to make room for new data. */
+ if (handle->rxRingBufferTail + 1U == handle->rxRingBufferSize)
+ {
+ handle->rxRingBufferTail = 0U;
+ }
+ else
+ {
+ handle->rxRingBufferTail++;
+ }
+ }
+
+ /* Read data. */
+ handle->rxRingBuffer[handle->rxRingBufferHead] = base->D;
+
+ /* Increase handle->rxRingBufferHead. */
+ if (handle->rxRingBufferHead + 1U == handle->rxRingBufferSize)
+ {
+ handle->rxRingBufferHead = 0U;
+ }
+ else
+ {
+ handle->rxRingBufferHead++;
+ }
+ }
+ }
+
+ else if (!handle->rxDataSize)
+ {
+ /* Disable RX interrupt/overrun interrupt/fram error interrupt */
+ UART_DisableInterrupts(base, kUART_RxDataRegFullInterruptEnable | kUART_RxOverrunInterruptEnable |
+ kUART_FramingErrorInterruptEnable);
+
+ /* Disable parity error interrupt when parity mode is enable*/
+ if (UART_C1_PE_MASK & base->C1)
+ {
+ UART_DisableInterrupts(base, kUART_ParityErrorInterruptEnable);
+ }
+ }
+ else
+ {
+ }
+ }
+
+ /* If framing error or parity error happened, stop the RX interrupt when ues no ring buffer */
+ if (((handle->rxState == kUART_RxFramingError) || (handle->rxState == kUART_RxParityError)) &&
+ (!handle->rxRingBuffer))
+ {
+ UART_DisableInterrupts(base, kUART_RxDataRegFullInterruptEnable | kUART_RxOverrunInterruptEnable |
+ kUART_FramingErrorInterruptEnable);
+
+ /* Disable parity error interrupt when parity mode is enable*/
+ if (UART_C1_PE_MASK & base->C1)
+ {
+ UART_DisableInterrupts(base, kUART_ParityErrorInterruptEnable);
+ }
+ }
+
+ /* Send data register empty and the interrupt is enabled. */
+ if ((base->S1 & UART_S1_TDRE_MASK) && (base->C2 & UART_C2_TIE_MASK))
+ {
+/* Get the bytes that available at this moment. */
+#if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
+ count = FSL_FEATURE_UART_FIFO_SIZEn(base) - base->TCFIFO;
+#else
+ count = 1;
+#endif
+
+ while ((count) && (handle->txDataSize))
+ {
+#if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
+ tempCount = MIN(handle->txDataSize, count);
+#else
+ tempCount = 1;
+#endif
+
+ /* Using non block API to write the data to the registers. */
+ UART_WriteNonBlocking(base, handle->txData, tempCount);
+ handle->txData += tempCount;
+ handle->txDataSize -= tempCount;
+ count -= tempCount;
+
+ /* If all the data are written to data register, TX finished. */
+ if (!handle->txDataSize)
+ {
+ handle->txState = kUART_TxIdle;
+
+ /* Disable TX register empty interrupt. */
+ base->C2 = (base->C2 & ~UART_C2_TIE_MASK);
+
+ /* Trigger callback. */
+ if (handle->callback)
+ {
+ handle->callback(base, handle, kStatus_UART_TxIdle, handle->userData);
+ }
+ }
+ }
+ }
+}
+
+void UART_TransferHandleErrorIRQ(UART_Type *base, uart_handle_t *handle)
+{
+ /* To be implemented by User. */
+}
+
+#if defined(UART0)
+#if ((!(defined(FSL_FEATURE_SOC_LPSCI_COUNT))) || \
+ ((defined(FSL_FEATURE_SOC_LPSCI_COUNT)) && (FSL_FEATURE_SOC_LPSCI_COUNT == 0)))
+void UART0_DriverIRQHandler(void)
+{
+ s_uartIsr(UART0, s_uartHandle[0]);
+}
+
+void UART0_RX_TX_DriverIRQHandler(void)
+{
+ UART0_DriverIRQHandler();
+}
+#endif
+#endif
+
+#if defined(UART1)
+void UART1_DriverIRQHandler(void)
+{
+ s_uartIsr(UART1, s_uartHandle[1]);
+}
+
+void UART1_RX_TX_DriverIRQHandler(void)
+{
+ UART1_DriverIRQHandler();
+}
+#endif
+
+#if defined(UART2)
+void UART2_DriverIRQHandler(void)
+{
+ s_uartIsr(UART2, s_uartHandle[2]);
+}
+
+void UART2_RX_TX_DriverIRQHandler(void)
+{
+ UART2_DriverIRQHandler();
+}
+#endif
+
+#if defined(UART3)
+void UART3_DriverIRQHandler(void)
+{
+ s_uartIsr(UART3, s_uartHandle[3]);
+}
+
+void UART3_RX_TX_DriverIRQHandler(void)
+{
+ UART3_DriverIRQHandler();
+}
+#endif
+
+#if defined(UART4)
+void UART4_DriverIRQHandler(void)
+{
+ s_uartIsr(UART4, s_uartHandle[4]);
+}
+
+void UART4_RX_TX_DriverIRQHandler(void)
+{
+ UART4_DriverIRQHandler();
+}
+#endif
+
+#if defined(UART5)
+void UART5_DriverIRQHandler(void)
+{
+ s_uartIsr(UART5, s_uartHandle[5]);
+}
+
+void UART5_RX_TX_DriverIRQHandler(void)
+{
+ UART5_DriverIRQHandler();
+}
+#endif
diff --git a/drivers/src/fsl_uart_edma.c b/drivers/src/fsl_uart_edma.c
new file mode 100644
index 0000000..c51e493
--- /dev/null
+++ b/drivers/src/fsl_uart_edma.c
@@ -0,0 +1,368 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsl_uart_edma.h"
+#include "fsl_dmamux.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Array of UART handle. */
+#if (defined(UART5))
+#define UART_HANDLE_ARRAY_SIZE 6
+#else /* UART5 */
+#if (defined(UART4))
+#define UART_HANDLE_ARRAY_SIZE 5
+#else /* UART4 */
+#if (defined(UART3))
+#define UART_HANDLE_ARRAY_SIZE 4
+#else /* UART3 */
+#if (defined(UART2))
+#define UART_HANDLE_ARRAY_SIZE 3
+#else /* UART2 */
+#if (defined(UART1))
+#define UART_HANDLE_ARRAY_SIZE 2
+#else /* UART1 */
+#if (defined(UART0))
+#define UART_HANDLE_ARRAY_SIZE 1
+#else /* UART0 */
+#error No UART instance.
+#endif /* UART 0 */
+#endif /* UART 1 */
+#endif /* UART 2 */
+#endif /* UART 3 */
+#endif /* UART 4 */
+#endif /* UART 5 */
+
+/*<! Structure definition for uart_edma_private_handle_t. The structure is private. */
+typedef struct _uart_edma_private_handle
+{
+ UART_Type *base;
+ uart_edma_handle_t *handle;
+} uart_edma_private_handle_t;
+
+/* UART EDMA transfer handle. */
+enum _uart_edma_tansfer_states
+{
+ kUART_TxIdle, /* TX idle. */
+ kUART_TxBusy, /* TX busy. */
+ kUART_RxIdle, /* RX idle. */
+ kUART_RxBusy /* RX busy. */
+};
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*<! Private handle only used for internally. */
+static uart_edma_private_handle_t s_edmaPrivateHandle[UART_HANDLE_ARRAY_SIZE];
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief UART EDMA send finished callback function.
+ *
+ * This function is called when UART EDMA send finished. It disables the UART
+ * TX EDMA request and sends @ref kStatus_UART_TxIdle to UART callback.
+ *
+ * @param handle The EDMA handle.
+ * @param param Callback function parameter.
+ */
+static void UART_SendEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds);
+
+/*!
+ * @brief UART EDMA receive finished callback function.
+ *
+ * This function is called when UART EDMA receive finished. It disables the UART
+ * RX EDMA request and sends @ref kStatus_UART_RxIdle to UART callback.
+ *
+ * @param handle The EDMA handle.
+ * @param param Callback function parameter.
+ */
+static void UART_ReceiveEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds);
+
+/*!
+ * @brief Get the UART instance from peripheral base address.
+ *
+ * @param base UART peripheral base address.
+ * @return UART instance.
+ */
+extern uint32_t UART_GetInstance(UART_Type *base);
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static void UART_SendEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
+{
+ assert(param);
+
+ uart_edma_private_handle_t *uartPrivateHandle = (uart_edma_private_handle_t *)param;
+
+ /* Avoid the warning for unused variables. */
+ handle = handle;
+ tcds = tcds;
+
+ if (transferDone)
+ {
+ UART_TransferAbortSendEDMA(uartPrivateHandle->base, uartPrivateHandle->handle);
+
+ if (uartPrivateHandle->handle->callback)
+ {
+ uartPrivateHandle->handle->callback(uartPrivateHandle->base, uartPrivateHandle->handle, kStatus_UART_TxIdle,
+ uartPrivateHandle->handle->userData);
+ }
+ }
+}
+
+static void UART_ReceiveEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
+{
+ assert(param);
+
+ uart_edma_private_handle_t *uartPrivateHandle = (uart_edma_private_handle_t *)param;
+
+ /* Avoid warning for unused parameters. */
+ handle = handle;
+ tcds = tcds;
+
+ if (transferDone)
+ {
+ /* Disable transfer. */
+ UART_TransferAbortReceiveEDMA(uartPrivateHandle->base, uartPrivateHandle->handle);
+
+ if (uartPrivateHandle->handle->callback)
+ {
+ uartPrivateHandle->handle->callback(uartPrivateHandle->base, uartPrivateHandle->handle, kStatus_UART_RxIdle,
+ uartPrivateHandle->handle->userData);
+ }
+ }
+}
+
+void UART_TransferCreateHandleEDMA(UART_Type *base,
+ uart_edma_handle_t *handle,
+ uart_edma_transfer_callback_t callback,
+ void *userData,
+ edma_handle_t *txEdmaHandle,
+ edma_handle_t *rxEdmaHandle)
+{
+ assert(handle);
+
+ uint32_t instance = UART_GetInstance(base);
+
+ s_edmaPrivateHandle[instance].base = base;
+ s_edmaPrivateHandle[instance].handle = handle;
+
+ memset(handle, 0, sizeof(*handle));
+
+ handle->rxState = kUART_RxIdle;
+ handle->txState = kUART_TxIdle;
+
+ handle->rxEdmaHandle = rxEdmaHandle;
+ handle->txEdmaHandle = txEdmaHandle;
+
+ handle->callback = callback;
+ handle->userData = userData;
+
+#if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
+ /* Note:
+ Take care of the RX FIFO, EDMA request only assert when received bytes
+ equal or more than RX water mark, there is potential issue if RX water
+ mark larger than 1.
+ For example, if RX FIFO water mark is 2, upper layer needs 5 bytes and
+ 5 bytes are received. the last byte will be saved in FIFO but not trigger
+ EDMA transfer because the water mark is 2.
+ */
+ if (rxEdmaHandle)
+ {
+ base->RWFIFO = 1U;
+ }
+#endif
+
+ /* Configure TX. */
+ if (txEdmaHandle)
+ {
+ EDMA_SetCallback(handle->txEdmaHandle, UART_SendEDMACallback, &s_edmaPrivateHandle[instance]);
+ }
+
+ /* Configure RX. */
+ if (rxEdmaHandle)
+ {
+ EDMA_SetCallback(handle->rxEdmaHandle, UART_ReceiveEDMACallback, &s_edmaPrivateHandle[instance]);
+ }
+}
+
+status_t UART_SendEDMA(UART_Type *base, uart_edma_handle_t *handle, uart_transfer_t *xfer)
+{
+ assert(handle);
+ assert(handle->txEdmaHandle);
+ assert(xfer);
+ assert(xfer->data);
+ assert(xfer->dataSize);
+
+ edma_transfer_config_t xferConfig;
+ status_t status;
+
+ /* If previous TX not finished. */
+ if (kUART_TxBusy == handle->txState)
+ {
+ status = kStatus_UART_TxBusy;
+ }
+ else
+ {
+ handle->txState = kUART_TxBusy;
+ handle->txDataSizeAll = xfer->dataSize;
+
+ /* Prepare transfer. */
+ EDMA_PrepareTransfer(&xferConfig, xfer->data, sizeof(uint8_t), (void *)UART_GetDataRegisterAddress(base),
+ sizeof(uint8_t), sizeof(uint8_t), xfer->dataSize, kEDMA_MemoryToPeripheral);
+
+ /* Store the initially configured eDMA minor byte transfer count into the UART handle */
+ handle->nbytes = sizeof(uint8_t);
+
+ /* Submit transfer. */
+ EDMA_SubmitTransfer(handle->txEdmaHandle, &xferConfig);
+ EDMA_StartTransfer(handle->txEdmaHandle);
+
+ /* Enable UART TX EDMA. */
+ UART_EnableTxDMA(base, true);
+
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+status_t UART_ReceiveEDMA(UART_Type *base, uart_edma_handle_t *handle, uart_transfer_t *xfer)
+{
+ assert(handle);
+ assert(handle->rxEdmaHandle);
+ assert(xfer);
+ assert(xfer->data);
+ assert(xfer->dataSize);
+
+ edma_transfer_config_t xferConfig;
+ status_t status;
+
+ /* If previous RX not finished. */
+ if (kUART_RxBusy == handle->rxState)
+ {
+ status = kStatus_UART_RxBusy;
+ }
+ else
+ {
+ handle->rxState = kUART_RxBusy;
+ handle->rxDataSizeAll = xfer->dataSize;
+
+ /* Prepare transfer. */
+ EDMA_PrepareTransfer(&xferConfig, (void *)UART_GetDataRegisterAddress(base), sizeof(uint8_t), xfer->data,
+ sizeof(uint8_t), sizeof(uint8_t), xfer->dataSize, kEDMA_PeripheralToMemory);
+
+ /* Store the initially configured eDMA minor byte transfer count into the UART handle */
+ handle->nbytes = sizeof(uint8_t);
+
+ /* Submit transfer. */
+ EDMA_SubmitTransfer(handle->rxEdmaHandle, &xferConfig);
+ EDMA_StartTransfer(handle->rxEdmaHandle);
+
+ /* Enable UART RX EDMA. */
+ UART_EnableRxDMA(base, true);
+
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+void UART_TransferAbortSendEDMA(UART_Type *base, uart_edma_handle_t *handle)
+{
+ assert(handle);
+ assert(handle->txEdmaHandle);
+
+ /* Disable UART TX EDMA. */
+ UART_EnableTxDMA(base, false);
+
+ /* Stop transfer. */
+ EDMA_AbortTransfer(handle->txEdmaHandle);
+
+ handle->txState = kUART_TxIdle;
+}
+
+void UART_TransferAbortReceiveEDMA(UART_Type *base, uart_edma_handle_t *handle)
+{
+ assert(handle);
+ assert(handle->rxEdmaHandle);
+
+ /* Disable UART RX EDMA. */
+ UART_EnableRxDMA(base, false);
+
+ /* Stop transfer. */
+ EDMA_AbortTransfer(handle->rxEdmaHandle);
+
+ handle->rxState = kUART_RxIdle;
+}
+
+status_t UART_TransferGetReceiveCountEDMA(UART_Type *base, uart_edma_handle_t *handle, uint32_t *count)
+{
+ assert(handle);
+ assert(handle->rxEdmaHandle);
+ assert(count);
+
+ if (kUART_RxIdle == handle->rxState)
+ {
+ return kStatus_NoTransferInProgress;
+ }
+
+ *count = handle->rxDataSizeAll -
+ (uint32_t)handle->nbytes *
+ EDMA_GetRemainingMajorLoopCount(handle->rxEdmaHandle->base, handle->rxEdmaHandle->channel);
+
+ return kStatus_Success;
+}
+
+status_t UART_TransferGetSendCountEDMA(UART_Type *base, uart_edma_handle_t *handle, uint32_t *count)
+{
+ assert(handle);
+ assert(handle->txEdmaHandle);
+ assert(count);
+
+ if (kUART_TxIdle == handle->txState)
+ {
+ return kStatus_NoTransferInProgress;
+ }
+
+ *count = handle->txDataSizeAll -
+ (uint32_t)handle->nbytes *
+ EDMA_GetRemainingMajorLoopCount(handle->txEdmaHandle->base, handle->txEdmaHandle->channel);
+
+ return kStatus_Success;
+}
diff --git a/drivers/src/fsl_uart_freertos.c b/drivers/src/fsl_uart_freertos.c
new file mode 100644
index 0000000..4d1da17
--- /dev/null
+++ b/drivers/src/fsl_uart_freertos.c
@@ -0,0 +1,332 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsl_uart_freertos.h"
+#include <FreeRTOS.h>
+#include <event_groups.h>
+#include <semphr.h>
+
+static void UART_RTOS_Callback(UART_Type *base, uart_handle_t *state, status_t status, void *param)
+{
+ uart_rtos_handle_t *handle = (uart_rtos_handle_t *)param;
+ BaseType_t xHigherPriorityTaskWoken, xResult;
+
+ xHigherPriorityTaskWoken = pdFALSE;
+ xResult = pdFAIL;
+
+ if (status == kStatus_UART_RxIdle)
+ {
+ xResult = xEventGroupSetBitsFromISR(handle->rxEvent, RTOS_UART_COMPLETE, &xHigherPriorityTaskWoken);
+ }
+ else if (status == kStatus_UART_TxIdle)
+ {
+ xResult = xEventGroupSetBitsFromISR(handle->txEvent, RTOS_UART_COMPLETE, &xHigherPriorityTaskWoken);
+ }
+ else if (status == kStatus_UART_RxRingBufferOverrun)
+ {
+ xResult = xEventGroupSetBitsFromISR(handle->rxEvent, RTOS_UART_RING_BUFFER_OVERRUN, &xHigherPriorityTaskWoken);
+ }
+ else if (status == kStatus_UART_RxHardwareOverrun)
+ {
+ /* Clear Overrun flag (OR) in UART S1 register */
+ UART_ClearStatusFlags(base, kUART_RxOverrunFlag);
+ xResult =
+ xEventGroupSetBitsFromISR(handle->rxEvent, RTOS_UART_HARDWARE_BUFFER_OVERRUN, &xHigherPriorityTaskWoken);
+ }
+
+ if (xResult != pdFAIL)
+ {
+ portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
+ }
+}
+
+/*FUNCTION**********************************************************************
+ *
+ * Function Name : UART_RTOS_Init
+ * Description : Initializes the UART instance for application
+ *
+ *END**************************************************************************/
+int UART_RTOS_Init(uart_rtos_handle_t *handle, uart_handle_t *t_handle, const uart_rtos_config_t *cfg)
+{
+ uart_config_t defcfg;
+
+ if (NULL == handle)
+ {
+ return kStatus_InvalidArgument;
+ }
+ if (NULL == t_handle)
+ {
+ return kStatus_InvalidArgument;
+ }
+ if (NULL == cfg)
+ {
+ return kStatus_InvalidArgument;
+ }
+ if (NULL == cfg->base)
+ {
+ return kStatus_InvalidArgument;
+ }
+ if (0 == cfg->srcclk)
+ {
+ return kStatus_InvalidArgument;
+ }
+ if (0 == cfg->baudrate)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ handle->base = cfg->base;
+ handle->t_state = t_handle;
+#if (configSUPPORT_STATIC_ALLOCATION == 1)
+ handle->txSemaphore = xSemaphoreCreateMutexStatic(&handle->txSemaphoreBuffer);
+#else
+ handle->txSemaphore = xSemaphoreCreateMutex();
+#endif
+ if (NULL == handle->txSemaphore)
+ {
+ return kStatus_Fail;
+ }
+#if (configSUPPORT_STATIC_ALLOCATION == 1)
+ handle->rxSemaphore = xSemaphoreCreateMutexStatic(&handle->rxSemaphoreBuffer);
+#else
+ handle->rxSemaphore = xSemaphoreCreateMutex();
+#endif
+ if (NULL == handle->rxSemaphore)
+ {
+ vSemaphoreDelete(handle->txSemaphore);
+ return kStatus_Fail;
+ }
+#if (configSUPPORT_STATIC_ALLOCATION == 1)
+ handle->txEvent = xEventGroupCreateStatic(&handle->txEventBuffer);
+#else
+ handle->txEvent = xEventGroupCreate();
+#endif
+ if (NULL == handle->txEvent)
+ {
+ vSemaphoreDelete(handle->rxSemaphore);
+ vSemaphoreDelete(handle->txSemaphore);
+ return kStatus_Fail;
+ }
+#if (configSUPPORT_STATIC_ALLOCATION == 1)
+ handle->rxEvent = xEventGroupCreateStatic(&handle->rxEventBuffer);
+#else
+ handle->rxEvent = xEventGroupCreate();
+#endif
+ if (NULL == handle->rxEvent)
+ {
+ vEventGroupDelete(handle->txEvent);
+ vSemaphoreDelete(handle->rxSemaphore);
+ vSemaphoreDelete(handle->txSemaphore);
+ return kStatus_Fail;
+ }
+ UART_GetDefaultConfig(&defcfg);
+
+ defcfg.baudRate_Bps = cfg->baudrate;
+ defcfg.parityMode = cfg->parity;
+#if defined(FSL_FEATURE_UART_HAS_STOP_BIT_CONFIG_SUPPORT) && FSL_FEATURE_UART_HAS_STOP_BIT_CONFIG_SUPPORT
+ defcfg.stopBitCount = cfg->stopbits;
+#endif
+
+ UART_Init(handle->base, &defcfg, cfg->srcclk);
+ UART_TransferCreateHandle(handle->base, handle->t_state, UART_RTOS_Callback, handle);
+ UART_TransferStartRingBuffer(handle->base, handle->t_state, cfg->buffer, cfg->buffer_size);
+
+ UART_EnableTx(handle->base, true);
+ UART_EnableRx(handle->base, true);
+
+ return 0;
+}
+
+/*FUNCTION**********************************************************************
+ *
+ * Function Name : UART_RTOS_Deinit
+ * Description : Deinitializes the UART instance and frees resources
+ *
+ *END**************************************************************************/
+int UART_RTOS_Deinit(uart_rtos_handle_t *handle)
+{
+ UART_Deinit(handle->base);
+
+ vEventGroupDelete(handle->txEvent);
+ vEventGroupDelete(handle->rxEvent);
+
+ /* Give the semaphore. This is for functional safety */
+ xSemaphoreGive(handle->txSemaphore);
+ xSemaphoreGive(handle->rxSemaphore);
+
+ vSemaphoreDelete(handle->txSemaphore);
+ vSemaphoreDelete(handle->rxSemaphore);
+
+ /* Invalidate the handle */
+ handle->base = NULL;
+ handle->t_state = NULL;
+
+ return 0;
+}
+
+/*FUNCTION**********************************************************************
+ *
+ * Function Name : UART_RTOS_Send
+ * Description : Initializes the UART instance for application
+ *
+ *END**************************************************************************/
+int UART_RTOS_Send(uart_rtos_handle_t *handle, const uint8_t *buffer, uint32_t length)
+{
+ EventBits_t ev;
+ int retval = kStatus_Success;
+
+ if (NULL == handle->base)
+ {
+ /* Invalid handle. */
+ return kStatus_Fail;
+ }
+ if (0 == length)
+ {
+ return 0;
+ }
+ if (NULL == buffer)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ if (pdFALSE == xSemaphoreTake(handle->txSemaphore, 0))
+ {
+ /* We could not take the semaphore, exit with 0 data received */
+ return kStatus_Fail;
+ }
+
+ handle->txTransfer.data = (uint8_t *)buffer;
+ handle->txTransfer.dataSize = (uint32_t)length;
+
+ /* Non-blocking call */
+ UART_TransferSendNonBlocking(handle->base, handle->t_state, &handle->txTransfer);
+
+ ev = xEventGroupWaitBits(handle->txEvent, RTOS_UART_COMPLETE, pdTRUE, pdFALSE, portMAX_DELAY);
+ if (!(ev & RTOS_UART_COMPLETE))
+ {
+ retval = kStatus_Fail;
+ }
+
+ if (pdFALSE == xSemaphoreGive(handle->txSemaphore))
+ {
+ /* We could not post the semaphore, exit with error */
+ retval = kStatus_Fail;
+ }
+
+ return retval;
+}
+
+/*FUNCTION**********************************************************************
+ *
+ * Function Name : UART_RTOS_Recv
+ * Description : Receives chars for the application
+ *
+ *END**************************************************************************/
+int UART_RTOS_Receive(uart_rtos_handle_t *handle, uint8_t *buffer, uint32_t length, size_t *received)
+{
+ EventBits_t ev;
+ size_t n = 0;
+ int retval = kStatus_Fail;
+ size_t local_received = 0;
+
+ if (NULL == handle->base)
+ {
+ /* Invalid handle. */
+ return kStatus_Fail;
+ }
+ if (0 == length)
+ {
+ if (received != NULL)
+ {
+ *received = n;
+ }
+ return 0;
+ }
+ if (NULL == buffer)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* New transfer can be performed only after current one is finished */
+ if (pdFALSE == xSemaphoreTake(handle->rxSemaphore, portMAX_DELAY))
+ {
+ /* We could not take the semaphore, exit with 0 data received */
+ return kStatus_Fail;
+ }
+
+ handle->rxTransfer.data = buffer;
+ handle->rxTransfer.dataSize = (uint32_t)length;
+
+ /* Non-blocking call */
+ UART_TransferReceiveNonBlocking(handle->base, handle->t_state, &handle->rxTransfer, &n);
+
+ ev = xEventGroupWaitBits(handle->rxEvent,
+ RTOS_UART_COMPLETE | RTOS_UART_RING_BUFFER_OVERRUN | RTOS_UART_HARDWARE_BUFFER_OVERRUN,
+ pdTRUE, pdFALSE, portMAX_DELAY);
+ if (ev & RTOS_UART_HARDWARE_BUFFER_OVERRUN)
+ {
+ /* Stop data transfer to application buffer, ring buffer is still active */
+ UART_TransferAbortReceive(handle->base, handle->t_state);
+ /* Prevent false indication of successful transfer in next call of UART_RTOS_Receive.
+ RTOS_UART_COMPLETE flag could be set meanwhile overrun is handled */
+ xEventGroupClearBits(handle->rxEvent, RTOS_UART_COMPLETE);
+ retval = kStatus_UART_RxHardwareOverrun;
+ local_received = 0;
+ }
+ else if (ev & RTOS_UART_RING_BUFFER_OVERRUN)
+ {
+ /* Stop data transfer to application buffer, ring buffer is still active */
+ UART_TransferAbortReceive(handle->base, handle->t_state);
+ /* Prevent false indication of successful transfer in next call of UART_RTOS_Receive.
+ RTOS_UART_COMPLETE flag could be set meanwhile overrun is handled */
+ xEventGroupClearBits(handle->rxEvent, RTOS_UART_COMPLETE);
+ retval = kStatus_UART_RxRingBufferOverrun;
+ local_received = 0;
+ }
+ else if (ev & RTOS_UART_COMPLETE)
+ {
+ retval = kStatus_Success;
+ local_received = length;
+ }
+
+ /* Prevent repetitive NULL check */
+ if (received != NULL)
+ {
+ *received = local_received;
+ }
+
+ /* Enable next transfer. Current one is finished */
+ if (pdFALSE == xSemaphoreGive(handle->rxSemaphore))
+ {
+ /* We could not post the semaphore, exit with error */
+ retval = kStatus_Fail;
+ }
+ return retval;
+}
diff --git a/drivers/src/fsl_vref.c b/drivers/src/fsl_vref.c
new file mode 100644
index 0000000..24f2d1d
--- /dev/null
+++ b/drivers/src/fsl_vref.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsl_vref.h"
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Gets the instance from the base address
+ *
+ * @param base VREF peripheral base address
+ *
+ * @return The VREF instance
+ */
+static uint32_t VREF_GetInstance(VREF_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*! @brief Pointers to VREF bases for each instance. */
+static VREF_Type *const s_vrefBases[] = VREF_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to VREF clocks for each instance. */
+static const clock_ip_name_t s_vrefClocks[] = VREF_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static uint32_t VREF_GetInstance(VREF_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_vrefBases); instance++)
+ {
+ if (s_vrefBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_vrefBases));
+
+ return instance;
+}
+
+void VREF_Init(VREF_Type *base, const vref_config_t *config)
+{
+ assert(config != NULL);
+
+ uint8_t reg = 0U;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Ungate clock for VREF */
+ CLOCK_EnableClock(s_vrefClocks[VREF_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/* Configure VREF to a known state */
+#if defined(FSL_FEATURE_VREF_HAS_CHOP_OSC) && FSL_FEATURE_VREF_HAS_CHOP_OSC
+ /* Set chop oscillator bit */
+ base->TRM |= VREF_TRM_CHOPEN_MASK;
+#endif /* FSL_FEATURE_VREF_HAS_CHOP_OSC */
+ /* Get current SC register */
+#if defined(FSL_FEATURE_VREF_HAS_LOW_REFERENCE) && FSL_FEATURE_VREF_HAS_LOW_REFERENCE
+ reg = base->VREFH_SC;
+#else
+ reg = base->SC;
+#endif/* FSL_FEATURE_VREF_HAS_LOW_REFERENCE */
+ /* Clear old buffer mode selection bits */
+ reg &= ~VREF_SC_MODE_LV_MASK;
+ /* Set buffer Mode selection and Regulator enable bit */
+ reg |= VREF_SC_MODE_LV(config->bufferMode) | VREF_SC_REGEN(1U);
+#if defined(FSL_FEATURE_VREF_HAS_COMPENSATION) && FSL_FEATURE_VREF_HAS_COMPENSATION
+ /* Set second order curvature compensation enable bit */
+ reg |= VREF_SC_ICOMPEN(1U);
+#endif /* FSL_FEATURE_VREF_HAS_COMPENSATION */
+ /* Enable VREF module */
+ reg |= VREF_SC_VREFEN(1U);
+ /* Update bit-field from value to Status and Control register */
+#if defined(FSL_FEATURE_VREF_HAS_LOW_REFERENCE) && FSL_FEATURE_VREF_HAS_LOW_REFERENCE
+ base->VREFH_SC = reg;
+#else
+ base->SC = reg;
+#endif/* FSL_FEATURE_VREF_HAS_LOW_REFERENCE */
+#if defined(FSL_FEATURE_VREF_HAS_LOW_REFERENCE) && FSL_FEATURE_VREF_HAS_LOW_REFERENCE
+ reg = base->VREFL_TRM;
+ /* Clear old select external voltage reference and VREFL (0.4 V) reference buffer enable bits */
+ reg &= ~(VREF_VREFL_TRM_VREFL_EN_MASK | VREF_VREFL_TRM_VREFL_SEL_MASK);
+ /* Select external voltage reference and set VREFL (0.4 V) reference buffer enable */
+ reg |= VREF_VREFL_TRM_VREFL_SEL(config->enableExternalVoltRef) | VREF_VREFL_TRM_VREFL_EN(config->enableLowRef);
+ base->VREFL_TRM = reg;
+#endif /* FSL_FEATURE_VREF_HAS_LOW_REFERENCE */
+
+#if defined(FSL_FEATURE_VREF_HAS_TRM4) && FSL_FEATURE_VREF_HAS_TRM4
+ reg = base->TRM4;
+ /* Clear old select internal voltage reference bit (2.1V) */
+ reg &= ~VREF_TRM4_VREF2V1_EN_MASK;
+ /* Select internal voltage reference (2.1V) */
+ reg |= VREF_TRM4_VREF2V1_EN(config->enable2V1VoltRef);
+ base->TRM4 = reg;
+#endif /* FSL_FEATURE_VREF_HAS_TRM4 */
+
+ /* Wait until internal voltage stable */
+#if defined(FSL_FEATURE_VREF_HAS_LOW_REFERENCE) && FSL_FEATURE_VREF_HAS_LOW_REFERENCE
+ while ((base->VREFH_SC & VREF_SC_VREFST_MASK) == 0)
+#else
+ while ((base->SC & VREF_SC_VREFST_MASK) == 0)
+#endif/* FSL_FEATURE_VREF_HAS_LOW_REFERENCE */
+ {
+ }
+}
+
+void VREF_Deinit(VREF_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Gate clock for VREF */
+ CLOCK_DisableClock(s_vrefClocks[VREF_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+void VREF_GetDefaultConfig(vref_config_t *config)
+{
+ assert(config);
+
+/* Set High power buffer mode in */
+#if defined(FSL_FEATURE_VREF_MODE_LV_TYPE) && FSL_FEATURE_VREF_MODE_LV_TYPE
+ config->bufferMode = kVREF_ModeHighPowerBuffer;
+#else
+ config->bufferMode = kVREF_ModeTightRegulationBuffer;
+#endif /* FSL_FEATURE_VREF_MODE_LV_TYPE */
+
+#if defined(FSL_FEATURE_VREF_HAS_LOW_REFERENCE) && FSL_FEATURE_VREF_HAS_LOW_REFERENCE
+ /* Select internal voltage reference */
+ config->enableExternalVoltRef = false;
+ /* Set VREFL (0.4 V) reference buffer disable */
+ config->enableLowRef = false;
+#endif /* FSL_FEATURE_VREF_HAS_LOW_REFERENCE */
+
+#if defined(FSL_FEATURE_VREF_HAS_TRM4) && FSL_FEATURE_VREF_HAS_TRM4
+ /* Disable internal voltage reference (2.1V) */
+ config->enable2V1VoltRef = false;
+#endif /* FSL_FEATURE_VREF_HAS_TRM4 */
+}
+
+void VREF_SetTrimVal(VREF_Type *base, uint8_t trimValue)
+{
+ uint8_t reg = 0U;
+
+ /* Set TRIM bits value in voltage reference */
+ reg = base->TRM;
+ reg = ((reg & ~VREF_TRM_TRIM_MASK) | VREF_TRM_TRIM(trimValue));
+ base->TRM = reg;
+ /* Wait until internal voltage stable */
+#if defined(FSL_FEATURE_VREF_HAS_LOW_REFERENCE) && FSL_FEATURE_VREF_HAS_LOW_REFERENCE
+ while ((base->VREFH_SC & VREF_SC_VREFST_MASK) == 0)
+#else
+ while ((base->SC & VREF_SC_VREFST_MASK) == 0)
+#endif/* FSL_FEATURE_VREF_HAS_LOW_REFERENCE */
+ {
+ }
+}
+
+#if defined(FSL_FEATURE_VREF_HAS_TRM4) && FSL_FEATURE_VREF_HAS_TRM4
+void VREF_SetTrim2V1Val(VREF_Type *base, uint8_t trimValue)
+{
+ uint8_t reg = 0U;
+
+ /* Set TRIM bits value in voltage reference (2V1) */
+ reg = base->TRM4;
+ reg = ((reg & ~VREF_TRM4_TRIM2V1_MASK) | VREF_TRM4_TRIM2V1(trimValue));
+ base->TRM4 = reg;
+ /* Wait until internal voltage stable */
+ while ((base->SC & VREF_SC_VREFST_MASK) == 0)
+ {
+ }
+}
+#endif /* FSL_FEATURE_VREF_HAS_TRM4 */
+
+#if defined(FSL_FEATURE_VREF_HAS_LOW_REFERENCE) && FSL_FEATURE_VREF_HAS_LOW_REFERENCE
+void VREF_SetLowReferenceTrimVal(VREF_Type *base, uint8_t trimValue)
+{
+ /* The values 111b and 110b are NOT valid/allowed */
+ assert((trimValue != 0x7U) && (trimValue != 0x6U));
+
+ uint8_t reg = 0U;
+
+ /* Set TRIM bits value in low voltage reference */
+ reg = base->VREFL_TRM;
+ reg = ((reg & ~VREF_VREFL_TRM_VREFL_TRIM_MASK) | VREF_VREFL_TRM_VREFL_TRIM(trimValue));
+ base->VREFL_TRM = reg;
+ /* Wait until internal voltage stable */
+
+ while ((base->VREFH_SC & VREF_SC_VREFST_MASK) == 0)
+ {
+ }
+}
+#endif /* FSL_FEATURE_VREF_HAS_LOW_REFERENCE */
diff --git a/drivers/src/fsl_wdog.c b/drivers/src/fsl_wdog.c
new file mode 100644
index 0000000..781ac13
--- /dev/null
+++ b/drivers/src/fsl_wdog.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsl_wdog.h"
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+void WDOG_GetDefaultConfig(wdog_config_t *config)
+{
+ assert(config);
+
+ config->enableWdog = true;
+ config->clockSource = kWDOG_LpoClockSource;
+ config->prescaler = kWDOG_ClockPrescalerDivide1;
+#if defined(FSL_FEATURE_WDOG_HAS_WAITEN) && FSL_FEATURE_WDOG_HAS_WAITEN
+ config->workMode.enableWait = true;
+#endif /* FSL_FEATURE_WDOG_HAS_WAITEN */
+ config->workMode.enableStop = false;
+ config->workMode.enableDebug = false;
+ config->enableUpdate = true;
+ config->enableInterrupt = false;
+ config->enableWindowMode = false;
+ config->windowValue = 0U;
+ config->timeoutValue = 0xFFFFU;
+}
+
+void WDOG_Init(WDOG_Type *base, const wdog_config_t *config)
+{
+ assert(config);
+
+ uint32_t value = 0U;
+ uint32_t primaskValue = 0U;
+
+ value = WDOG_STCTRLH_WDOGEN(config->enableWdog) | WDOG_STCTRLH_CLKSRC(config->clockSource) |
+ WDOG_STCTRLH_IRQRSTEN(config->enableInterrupt) | WDOG_STCTRLH_WINEN(config->enableWindowMode) |
+ WDOG_STCTRLH_ALLOWUPDATE(config->enableUpdate) | WDOG_STCTRLH_DBGEN(config->workMode.enableDebug) |
+ WDOG_STCTRLH_STOPEN(config->workMode.enableStop) |
+#if defined(FSL_FEATURE_WDOG_HAS_WAITEN) && FSL_FEATURE_WDOG_HAS_WAITEN
+ WDOG_STCTRLH_WAITEN(config->workMode.enableWait) |
+#endif /* FSL_FEATURE_WDOG_HAS_WAITEN */
+ WDOG_STCTRLH_DISTESTWDOG(1U);
+
+ /* Disable the global interrupts. Otherwise, an interrupt could effectively invalidate the unlock sequence
+ * and the WCT may expire. After the configuration finishes, re-enable the global interrupts. */
+ primaskValue = DisableGlobalIRQ();
+ WDOG_Unlock(base);
+ /* Wait one bus clock cycle */
+ base->RSTCNT = 0U;
+ /* Set configruation */
+ base->PRESC = WDOG_PRESC_PRESCVAL(config->prescaler);
+ base->WINH = (uint16_t)((config->windowValue >> 16U) & 0xFFFFU);
+ base->WINL = (uint16_t)((config->windowValue) & 0xFFFFU);
+ base->TOVALH = (uint16_t)((config->timeoutValue >> 16U) & 0xFFFFU);
+ base->TOVALL = (uint16_t)((config->timeoutValue) & 0xFFFFU);
+ base->STCTRLH = value;
+ EnableGlobalIRQ(primaskValue);
+}
+
+void WDOG_Deinit(WDOG_Type *base)
+{
+ uint32_t primaskValue = 0U;
+
+ /* Disable the global interrupts */
+ primaskValue = DisableGlobalIRQ();
+ WDOG_Unlock(base);
+ /* Wait one bus clock cycle */
+ base->RSTCNT = 0U;
+ WDOG_Disable(base);
+ EnableGlobalIRQ(primaskValue);
+ WDOG_ClearResetCount(base);
+}
+
+void WDOG_SetTestModeConfig(WDOG_Type *base, wdog_test_config_t *config)
+{
+ assert(config);
+
+ uint32_t value = 0U;
+ uint32_t primaskValue = 0U;
+
+ value = WDOG_STCTRLH_DISTESTWDOG(0U) | WDOG_STCTRLH_TESTWDOG(1U) | WDOG_STCTRLH_TESTSEL(config->testMode) |
+ WDOG_STCTRLH_BYTESEL(config->testedByte) | WDOG_STCTRLH_IRQRSTEN(0U) | WDOG_STCTRLH_WDOGEN(1U) |
+ WDOG_STCTRLH_ALLOWUPDATE(1U);
+
+ /* Disable the global interrupts. Otherwise, an interrupt could effectively invalidate the unlock sequence
+ * and the WCT may expire. After the configuration finishes, re-enable the global interrupts. */
+ primaskValue = DisableGlobalIRQ();
+ WDOG_Unlock(base);
+ /* Wait one bus clock cycle */
+ base->RSTCNT = 0U;
+ /* Set configruation */
+ base->TOVALH = (uint16_t)((config->timeoutValue >> 16U) & 0xFFFFU);
+ base->TOVALL = (uint16_t)((config->timeoutValue) & 0xFFFFU);
+ base->STCTRLH = value;
+ EnableGlobalIRQ(primaskValue);
+}
+
+uint32_t WDOG_GetStatusFlags(WDOG_Type *base)
+{
+ uint32_t status_flag = 0U;
+
+ status_flag |= (base->STCTRLH & WDOG_STCTRLH_WDOGEN_MASK);
+ status_flag |= (base->STCTRLL & WDOG_STCTRLL_INTFLG_MASK);
+
+ return status_flag;
+}
+
+void WDOG_ClearStatusFlags(WDOG_Type *base, uint32_t mask)
+{
+ if (mask & kWDOG_TimeoutFlag)
+ {
+ base->STCTRLL |= WDOG_STCTRLL_INTFLG_MASK;
+ }
+}
+
+void WDOG_Refresh(WDOG_Type *base)
+{
+ uint32_t primaskValue = 0U;
+
+ /* Disable the global interrupt to protect refresh sequence */
+ primaskValue = DisableGlobalIRQ();
+ base->REFRESH = WDOG_FIRST_WORD_OF_REFRESH;
+ base->REFRESH = WDOG_SECOND_WORD_OF_REFRESH;
+ EnableGlobalIRQ(primaskValue);
+}