initial check in based on SVN revision 575

This commit is contained in:
2025-05-14 12:57:39 -05:00
commit a3ef12e24a
217 changed files with 95547 additions and 0 deletions

619
drivers/fsl_adc.c Normal file
View File

@@ -0,0 +1,619 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* Copyright 2016-2019 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "fsl_adc.h"
#include "fsl_clock.h"
/* Component ID definition, used by tools. */
#ifndef FSL_COMPONENT_ID
#define FSL_COMPONENT_ID "platform.drivers.lpc_adc"
#endif
static ADC_Type *const s_adcBases[] = ADC_BASE_PTRS;
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
static const clock_ip_name_t s_adcClocks[] = ADC_CLOCKS;
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
#define FREQUENCY_1MHZ (1000000UL)
static uint32_t ADC_GetInstance(ADC_Type *base)
{
uint32_t instance;
/* Find the instance index from base address mappings. */
for (instance = 0; instance < ARRAY_SIZE(s_adcBases); instance++)
{
if (s_adcBases[instance] == base)
{
break;
}
}
assert(instance < ARRAY_SIZE(s_adcBases));
return instance;
}
/*!
* brief Initialize the ADC module.
*
* param base ADC peripheral base address.
* param config Pointer to configuration structure, see to #adc_config_t.
*/
void ADC_Init(ADC_Type *base, const adc_config_t *config)
{
assert(config != NULL);
uint32_t tmp32 = 0U;
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
/* Enable clock. */
CLOCK_EnableClock(s_adcClocks[ADC_GetInstance(base)]);
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
/* Disable the interrupts. */
base->INTEN = 0U; /* Quickly disable all the interrupts. */
/* Configure the ADC block. */
tmp32 = ADC_CTRL_CLKDIV(config->clockDividerNumber);
#if defined(FSL_FEATURE_ADC_HAS_CTRL_ASYNMODE) & FSL_FEATURE_ADC_HAS_CTRL_ASYNMODE
/* Async or Sync clock mode. */
switch (config->clockMode)
{
case kADC_ClockAsynchronousMode:
tmp32 |= ADC_CTRL_ASYNMODE_MASK;
break;
default: /* kADC_ClockSynchronousMode */
break;
}
#endif /* FSL_FEATURE_ADC_HAS_CTRL_ASYNMODE. */
#if defined(FSL_FEATURE_ADC_HAS_CTRL_RESOL) & FSL_FEATURE_ADC_HAS_CTRL_RESOL
/* Resolution. */
tmp32 |= ADC_CTRL_RESOL(config->resolution);
#endif /* FSL_FEATURE_ADC_HAS_CTRL_RESOL. */
#if defined(FSL_FEATURE_ADC_HAS_CTRL_BYPASSCAL) & FSL_FEATURE_ADC_HAS_CTRL_BYPASSCAL
/* Bypass calibration. */
if (config->enableBypassCalibration)
{
tmp32 |= ADC_CTRL_BYPASSCAL_MASK;
}
#endif /* FSL_FEATURE_ADC_HAS_CTRL_BYPASSCAL. */
#if defined(FSL_FEATURE_ADC_HAS_CTRL_TSAMP) & FSL_FEATURE_ADC_HAS_CTRL_TSAMP
/* Sample time clock count. */
#if (defined(FSL_FEATURE_ADC_SYNCHRONOUS_USE_GPADC_CTRL) && FSL_FEATURE_ADC_SYNCHRONOUS_USE_GPADC_CTRL)
if (config->clockMode == kADC_ClockAsynchronousMode)
{
#endif /* FSL_FEATURE_ADC_SYNCHRONOUS_USE_GPADC_CTRL */
tmp32 |= ADC_CTRL_TSAMP(config->sampleTimeNumber);
#if (defined(FSL_FEATURE_ADC_SYNCHRONOUS_USE_GPADC_CTRL) && FSL_FEATURE_ADC_SYNCHRONOUS_USE_GPADC_CTRL)
}
#endif /* FSL_FEATURE_ADC_SYNCHRONOUS_USE_GPADC_CTRL */
#endif /* FSL_FEATURE_ADC_HAS_CTRL_TSAMP. */
#if defined(FSL_FEATURE_ADC_HAS_CTRL_LPWRMODE) & FSL_FEATURE_ADC_HAS_CTRL_LPWRMODE
if (config->enableLowPowerMode)
{
tmp32 |= ADC_CTRL_LPWRMODE_MASK;
}
#endif /* FSL_FEATURE_ADC_HAS_CTRL_LPWRMODE. */
base->CTRL = tmp32;
#if defined(FSL_FEATURE_ADC_HAS_GPADC_CTRL0_LDO_POWER_EN) && FSL_FEATURE_ADC_HAS_GPADC_CTRL0_LDO_POWER_EN
base->GPADC_CTRL0 |= ADC_GPADC_CTRL0_LDO_POWER_EN_MASK;
if (config->clockMode == kADC_ClockSynchronousMode)
{
base->GPADC_CTRL0 |= ADC_GPADC_CTRL0_PASS_ENABLE(config->sampleTimeNumber);
}
SDK_DelayAtLeastUs(300, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
#endif /* FSL_FEATURE_ADC_HAS_GPADC_CTRL0_LDO_POWER_EN */
#if defined(FSL_FEATURE_ADC_HAS_GPADC_CTRL1_OFFSET_CAL) && FSL_FEATURE_ADC_HAS_GPADC_CTRL1_OFFSET_CAL
tmp32 = *(uint32_t *)FSL_FEATURE_FLASH_ADDR_OF_TEMP_CAL;
if (tmp32 & FSL_FEATURE_FLASH_ADDR_OF_TEMP_CAL_VALID)
{
base->GPADC_CTRL1 = (tmp32 >> 1);
}
#if !(defined(FSL_FEATURE_ADC_HAS_STARTUP_ADC_INIT) && FSL_FEATURE_ADC_HAS_STARTUP_ADC_INIT)
base->STARTUP = ADC_STARTUP_ADC_ENA_MASK; /* Set the ADC Start bit */
#endif /* FSL_FEATURE_ADC_HAS_GPADC_CTRL1_OFFSET_CAL */
#endif /* FSL_FEATURE_ADC_HAS_GPADC_CTRL1_OFFSET_CAL */
#if defined(FSL_FEATURE_ADC_HAS_TRIM_REG) & FSL_FEATURE_ADC_HAS_TRIM_REG
base->TRM &= ~ADC_TRM_VRANGE_MASK;
base->TRM |= ADC_TRM_VRANGE(config->voltageRange);
#endif /* FSL_FEATURE_ADC_HAS_TRIM_REG. */
}
/*!
* brief Gets an available pre-defined settings for initial configuration.
*
* This function initializes the initial configuration structure with an available settings. The default values are:
* code
* config->clockMode = kADC_ClockSynchronousMode;
* config->clockDividerNumber = 0U;
* config->resolution = kADC_Resolution12bit;
* config->enableBypassCalibration = false;
* config->sampleTimeNumber = 0U;
* endcode
* param config Pointer to configuration structure.
*/
void ADC_GetDefaultConfig(adc_config_t *config)
{
/* Initializes the configure structure to zero. */
(void)memset(config, 0, sizeof(*config));
#if defined(FSL_FEATURE_ADC_HAS_CTRL_ASYNMODE) & FSL_FEATURE_ADC_HAS_CTRL_ASYNMODE
config->clockMode = kADC_ClockSynchronousMode;
#endif /* FSL_FEATURE_ADC_HAS_CTRL_ASYNMODE. */
config->clockDividerNumber = 0U;
#if defined(FSL_FEATURE_ADC_HAS_CTRL_RESOL) & FSL_FEATURE_ADC_HAS_CTRL_RESOL
config->resolution = kADC_Resolution12bit;
#endif /* FSL_FEATURE_ADC_HAS_CTRL_RESOL. */
#if defined(FSL_FEATURE_ADC_HAS_CTRL_BYPASSCAL) & FSL_FEATURE_ADC_HAS_CTRL_BYPASSCAL
config->enableBypassCalibration = false;
#endif /* FSL_FEATURE_ADC_HAS_CTRL_BYPASSCAL. */
#if defined(FSL_FEATURE_ADC_HAS_CTRL_TSAMP) & FSL_FEATURE_ADC_HAS_CTRL_TSAMP
config->sampleTimeNumber = 0U;
#endif /* FSL_FEATURE_ADC_HAS_CTRL_TSAMP. */
#if defined(FSL_FEATURE_ADC_HAS_CTRL_LPWRMODE) & FSL_FEATURE_ADC_HAS_CTRL_LPWRMODE
config->enableLowPowerMode = false;
#endif /* FSL_FEATURE_ADC_HAS_CTRL_LPWRMODE. */
#if defined(FSL_FEATURE_ADC_HAS_TRIM_REG) & FSL_FEATURE_ADC_HAS_TRIM_REG
config->voltageRange = kADC_HighVoltageRange;
#endif /* FSL_FEATURE_ADC_HAS_TRIM_REG. */
}
/*!
* brief Deinitialize the ADC module.
*
* param base ADC peripheral base address.
*/
void ADC_Deinit(ADC_Type *base)
{
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
/* Disable the clock. */
CLOCK_DisableClock(s_adcClocks[ADC_GetInstance(base)]);
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
}
#if !(defined(FSL_FEATURE_ADC_HAS_NO_CALIB_FUNC) && FSL_FEATURE_ADC_HAS_NO_CALIB_FUNC)
#if defined(FSL_FEATURE_ADC_HAS_CALIB_REG) && FSL_FEATURE_ADC_HAS_CALIB_REG
/*!
* brief Do the hardware self-calibration.
* deprecated Do not use this function. It has been superceded by @ref ADC_DoOffsetCalibration.
*
* To calibrate the ADC, set the ADC clock to 500 kHz. In order to achieve the specified ADC accuracy, the A/D
* converter must be recalibrated, at a minimum, following every chip reset before initiating normal ADC operation.
*
* param base ADC peripheral base address.
* retval true Calibration succeed.
* retval false Calibration failed.
*/
bool ADC_DoSelfCalibration(ADC_Type *base)
{
uint32_t frequency = 0U;
uint32_t delayUs = 0U;
bool ret = true;
/* Enable the converter. */
/* This bit can only be set 1 by software. It is cleared automatically whenever the ADC is powered down.
This bit should be set after at least 10 ms after the ADC is powered on. */
base->STARTUP = ADC_STARTUP_ADC_ENA_MASK;
SDK_DelayAtLeastUs(1U, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
if (0UL == (base->STARTUP & ADC_STARTUP_ADC_ENA_MASK))
{
ret = false; /* ADC is not powered up. */
}
/* Get the ADC clock frequency in synchronous mode. */
frequency = CLOCK_GetFreq(kCLOCK_BusClk) / (((base->CTRL & ADC_CTRL_CLKDIV_MASK) >> ADC_CTRL_CLKDIV_SHIFT) + 1UL);
#if defined(FSL_FEATURE_ADC_HAS_CTRL_ASYNMODE) && FSL_FEATURE_ADC_HAS_CTRL_ASYNMODE
/* Get the ADC clock frequency in asynchronous mode. */
if (ADC_CTRL_ASYNMODE_MASK == (base->CTRL & ADC_CTRL_ASYNMODE_MASK))
{
frequency = CLOCK_GetAdcClkFreq();
}
#endif /* FSL_FEATURE_ADC_HAS_CTRL_ASYNMODE */
assert(0U != frequency);
/* If not in by-pass mode, do the calibration. */
if ((ADC_CALIB_CALREQD_MASK == (base->CALIB & ADC_CALIB_CALREQD_MASK)) &&
(0U == (base->CTRL & ADC_CTRL_BYPASSCAL_MASK)))
{
/* A calibration cycle requires approximately 81 ADC clocks to complete. */
delayUs = (120UL * FREQUENCY_1MHZ) / frequency + 1UL;
/* Calibration is needed, do it now. */
base->CALIB = ADC_CALIB_CALIB_MASK;
SDK_DelayAtLeastUs(delayUs, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
if (ADC_CALIB_CALIB_MASK == (base->CALIB & ADC_CALIB_CALIB_MASK))
{
ret = false; /* Calibration timeout. */
}
}
/* A “dummy” conversion cycle requires approximately 6 ADC clocks */
delayUs = (10UL * FREQUENCY_1MHZ) / frequency + 1UL;
base->STARTUP |= ADC_STARTUP_ADC_INIT_MASK;
SDK_DelayAtLeastUs(delayUs, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
if (ADC_STARTUP_ADC_INIT_MASK == (base->STARTUP & ADC_STARTUP_ADC_INIT_MASK))
{
ret = false;
}
return ret;
}
/*!
* brief Do the hardware offset-calibration.
*
* To calibrate the ADC, set the ADC clock to 500 kHz. In order to achieve the specified ADC accuracy, the A/D
* converter must be recalibrated, at a minimum, following every chip reset before initiating normal ADC operation.
*
* param base ADC peripheral base address.
* param frequency The clock frequency that ADC operates at.
* retval true Calibration succeed.
* retval false Calibration failed.
*/
bool ADC_DoOffsetCalibration(ADC_Type *base, uint32_t frequency)
{
assert(frequency != 0U);
uint32_t delayUs = 0U;
uint32_t tmp32 = base->CTRL;
/* The maximum ADC clock frequency during calibration is 30 MHz. */
const uint32_t maxCalibrationFrequency = 30000000UL;
bool ret = true;
/* Enable the converter. */
/* This bit should be set after at least 10 us after the ADC is powered on. */
SDK_DelayAtLeastUs(10U, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
/* This bit can only be set 1 by software. It is cleared automatically whenever the ADC is powered down. */
base->STARTUP = ADC_STARTUP_ADC_ENA_MASK;
if (0UL == (base->STARTUP & ADC_STARTUP_ADC_ENA_MASK))
{
ret = false; /* ADC is not powered up. */
}
if (frequency >= maxCalibrationFrequency)
{
/* The divider should round up to ensure the frequency be lower than the maximum frequency. */
uint8_t divider = (frequency % maxCalibrationFrequency > 0UL) ?
(uint8_t)(frequency / maxCalibrationFrequency + 1UL) :
(uint8_t)(frequency / maxCalibrationFrequency);
/* Divide the system clock to yield an ADC clock of about 30 MHz. */
base->CTRL &= ~ADC_CTRL_CLKDIV_MASK;
base->CTRL |= ADC_CTRL_CLKDIV(divider - 1UL);
frequency /= divider;
}
/* Launch the calibration cycle or "dummy" conversions. */
if (ADC_CALIB_CALREQD_MASK == (base->CALIB & ADC_CALIB_CALREQD_MASK))
{
/* Calibration is required, do it now. */
base->CALIB = ADC_CALIB_CALIB_MASK;
/* A calibration cycle requires approximately 81 ADC clocks to complete. */
delayUs = (120UL * FREQUENCY_1MHZ) / frequency + 1UL;
SDK_DelayAtLeastUs(delayUs, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
if (ADC_CALIB_CALIB_MASK == (base->CALIB & ADC_CALIB_CALIB_MASK))
{
base->CTRL = tmp32;
ret = false; /* Calibration timeout. */
}
}
else
{
/* If a calibration is not performed, launch the conversion cycle. */
base->STARTUP |= ADC_STARTUP_ADC_INIT_MASK;
/* A “dummy” conversion cycle requires approximately 6 ADC clocks */
delayUs = (10UL * FREQUENCY_1MHZ) / frequency + 1UL;
SDK_DelayAtLeastUs(delayUs, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
if (ADC_STARTUP_ADC_INIT_MASK == (base->STARTUP & ADC_STARTUP_ADC_INIT_MASK))
{
base->CTRL = tmp32;
ret = false; /* Initialization timeout. */
}
}
base->CTRL = tmp32;
return ret;
}
#else
/*!
* brief Do the hardware self-calibration.
*
* To calibrate the ADC, set the ADC clock to 500 kHz. In order to achieve the specified ADC accuracy, the A/D
* converter must be recalibrated, at a minimum, following every chip reset before initiating normal ADC operation.
*
* param base ADC peripheral base address.
* param frequency The clock frequency that ADC operates at.
* retval true Calibration succeed.
* retval false Calibration failed.
*/
bool ADC_DoSelfCalibration(ADC_Type *base, uint32_t frequency)
{
assert(frequency != 0U);
uint32_t tmp32 = 0U;
/* Store the current contents of the ADC CTRL register. */
tmp32 = base->CTRL;
/* Divide the system clock to yield an ADC clock of about 500 kHz. */
base->CTRL &= ~ADC_CTRL_CLKDIV_MASK;
base->CTRL |= ADC_CTRL_CLKDIV((frequency / 500000U) - 1U);
/* Clear the LPWR bit. */
base->CTRL &= ~ADC_CTRL_LPWRMODE_MASK;
/* Start ADC self-calibration. */
base->CTRL |= ADC_CTRL_CALMODE_MASK;
/* Delay for 300 uSec @ 500KHz ADC clock */
SDK_DelayAtLeastUs(300U, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
/* Check the completion of calibration. */
if (ADC_CTRL_CALMODE_MASK == (base->CTRL & ADC_CTRL_CALMODE_MASK))
{
/* Restore the contents of the ADC CTRL register. */
base->CTRL = tmp32;
return false; /* Calibration timeout. */
}
/* Restore the contents of the ADC CTRL register. */
base->CTRL = tmp32;
return true;
}
#endif /* FSL_FEATURE_ADC_HAS_CALIB_REG */
#endif /* FSL_FEATURE_ADC_HAS_NO_CALIB_FUNC*/
/*!
* brief Configure the conversion sequence A.
*
* param base ADC peripheral base address.
* param config Pointer to configuration structure, see to #adc_conv_seq_config_t.
*/
void ADC_SetConvSeqAConfig(ADC_Type *base, const adc_conv_seq_config_t *config)
{
assert(config != NULL);
uint32_t tmp32;
tmp32 = ADC_SEQ_CTRL_CHANNELS(config->channelMask) /* Channel mask. */
| ADC_SEQ_CTRL_TRIGGER(config->triggerMask); /* Trigger mask. */
/* Polarity for tirgger signal. */
switch (config->triggerPolarity)
{
case kADC_TriggerPolarityPositiveEdge:
tmp32 |= ADC_SEQ_CTRL_TRIGPOL_MASK;
break;
default: /* kADC_TriggerPolarityNegativeEdge */
break;
}
/* Bypass the clock Sync. */
if (config->enableSyncBypass)
{
tmp32 |= ADC_SEQ_CTRL_SYNCBYPASS_MASK;
}
/* Interrupt point. */
switch (config->interruptMode)
{
case kADC_InterruptForEachSequence:
tmp32 |= ADC_SEQ_CTRL_MODE_MASK;
break;
default: /* kADC_InterruptForEachConversion */
break;
}
/* One trigger for a conversion, or for a sequence. */
if (config->enableSingleStep)
{
tmp32 |= ADC_SEQ_CTRL_SINGLESTEP_MASK;
}
base->SEQ_CTRL[0] = tmp32;
}
#if !(defined(FSL_FEATURE_ADC_HAS_SINGLE_SEQ) && FSL_FEATURE_ADC_HAS_SINGLE_SEQ)
/*!
* brief Configure the conversion sequence B.
*
* param base ADC peripheral base address.
* param config Pointer to configuration structure, see to #adc_conv_seq_config_t.
*/
void ADC_SetConvSeqBConfig(ADC_Type *base, const adc_conv_seq_config_t *config)
{
assert(config != NULL);
uint32_t tmp32;
tmp32 = ADC_SEQ_CTRL_CHANNELS(config->channelMask) /* Channel mask. */
| ADC_SEQ_CTRL_TRIGGER(config->triggerMask); /* Trigger mask. */
/* Polarity for tirgger signal. */
switch (config->triggerPolarity)
{
case kADC_TriggerPolarityPositiveEdge:
tmp32 |= ADC_SEQ_CTRL_TRIGPOL_MASK;
break;
default: /* kADC_TriggerPolarityPositiveEdge */
break;
}
/* Bypass the clock Sync. */
if (config->enableSyncBypass)
{
tmp32 |= ADC_SEQ_CTRL_SYNCBYPASS_MASK;
}
/* Interrupt point. */
switch (config->interruptMode)
{
case kADC_InterruptForEachSequence:
tmp32 |= ADC_SEQ_CTRL_MODE_MASK;
break;
default: /* kADC_InterruptForEachConversion */
break;
}
/* One trigger for a conversion, or for a sequence. */
if (config->enableSingleStep)
{
tmp32 |= ADC_SEQ_CTRL_SINGLESTEP_MASK;
}
base->SEQ_CTRL[1] = tmp32;
}
#endif /* FSL_FEATURE_ADC_HAS_SINGLE_SEQ */
/*!
* brief Get the global ADC conversion infomation of sequence A.
*
* param base ADC peripheral base address.
* param info Pointer to information structure, see to #adc_result_info_t;
* retval true The conversion result is ready.
* retval false The conversion result is not ready yet.
*/
bool ADC_GetConvSeqAGlobalConversionResult(ADC_Type *base, adc_result_info_t *info)
{
assert(info != NULL);
uint32_t tmp32 = base->SEQ_GDAT[0]; /* Read to clear the status. */
bool ret = true;
if (0U == (ADC_SEQ_GDAT_DATAVALID_MASK & tmp32))
{
ret = false;
}
info->result = (tmp32 & ADC_SEQ_GDAT_RESULT_MASK) >> ADC_SEQ_GDAT_RESULT_SHIFT;
info->thresholdCompareStatus = (adc_threshold_compare_status_t)(uint32_t)((tmp32 & ADC_SEQ_GDAT_THCMPRANGE_MASK) >>
ADC_SEQ_GDAT_THCMPRANGE_SHIFT);
info->thresholdCorssingStatus = (adc_threshold_crossing_status_t)(uint32_t)(
(tmp32 & ADC_SEQ_GDAT_THCMPCROSS_MASK) >> ADC_SEQ_GDAT_THCMPCROSS_SHIFT);
info->channelNumber = (tmp32 & ADC_SEQ_GDAT_CHN_MASK) >> ADC_SEQ_GDAT_CHN_SHIFT;
info->overrunFlag = ((tmp32 & ADC_SEQ_GDAT_OVERRUN_MASK) == ADC_SEQ_GDAT_OVERRUN_MASK);
return ret;
}
#if !(defined(FSL_FEATURE_ADC_HAS_SINGLE_SEQ) && FSL_FEATURE_ADC_HAS_SINGLE_SEQ)
/*!
* brief Get the global ADC conversion infomation of sequence B.
*
* param base ADC peripheral base address.
* param info Pointer to information structure, see to #adc_result_info_t;
* retval true The conversion result is ready.
* retval false The conversion result is not ready yet.
*/
bool ADC_GetConvSeqBGlobalConversionResult(ADC_Type *base, adc_result_info_t *info)
{
assert(info != NULL);
uint32_t tmp32 = base->SEQ_GDAT[1]; /* Read to clear the status. */
bool ret = true;
if (0U == (ADC_SEQ_GDAT_DATAVALID_MASK & tmp32))
{
ret = false;
}
info->result = (tmp32 & ADC_SEQ_GDAT_RESULT_MASK) >> ADC_SEQ_GDAT_RESULT_SHIFT;
info->thresholdCompareStatus = (adc_threshold_compare_status_t)(uint32_t)((tmp32 & ADC_SEQ_GDAT_THCMPRANGE_MASK) >>
ADC_SEQ_GDAT_THCMPRANGE_SHIFT);
info->thresholdCorssingStatus = (adc_threshold_crossing_status_t)(uint32_t)(
(tmp32 & ADC_SEQ_GDAT_THCMPCROSS_MASK) >> ADC_SEQ_GDAT_THCMPCROSS_SHIFT);
info->channelNumber = (tmp32 & ADC_SEQ_GDAT_CHN_MASK) >> ADC_SEQ_GDAT_CHN_SHIFT;
info->overrunFlag = ((tmp32 & ADC_SEQ_GDAT_OVERRUN_MASK) == ADC_SEQ_GDAT_OVERRUN_MASK);
return ret;
}
#endif /* FSL_FEATURE_ADC_HAS_SINGLE_SEQ */
/*!
* brief Get the channel's ADC conversion completed under each conversion sequence.
*
* param base ADC peripheral base address.
* param channel The indicated channel number.
* param info Pointer to information structure, see to #adc_result_info_t;
* retval true The conversion result is ready.
* retval false The conversion result is not ready yet.
*/
bool ADC_GetChannelConversionResult(ADC_Type *base, uint32_t channel, adc_result_info_t *info)
{
assert(info != NULL);
assert(channel < ADC_DAT_COUNT);
uint32_t tmp32 = base->DAT[channel]; /* Read to clear the status. */
bool ret = true;
if (0U == (ADC_DAT_DATAVALID_MASK & tmp32))
{
ret = false;
}
info->result = (tmp32 & ADC_DAT_RESULT_MASK) >> ADC_DAT_RESULT_SHIFT;
#if (defined(FSL_FEATURE_ADC_DAT_OF_HIGH_ALIGNMENT) && FSL_FEATURE_ADC_DAT_OF_HIGH_ALIGNMENT)
switch ((base->CTRL & ADC_CTRL_RESOL_MASK) >> ADC_CTRL_RESOL_SHIFT)
{
case kADC_Resolution10bit:
info->result >>= kADC_Resolution10bitInfoResultShift;
break;
case kADC_Resolution8bit:
info->result >>= kADC_Resolution8bitInfoResultShift;
break;
case kADC_Resolution6bit:
info->result >>= kADC_Resolution6bitInfoResultShift;
break;
default:
assert(false);
break;
}
#endif
info->thresholdCompareStatus =
(adc_threshold_compare_status_t)(uint32_t)((tmp32 & ADC_DAT_THCMPRANGE_MASK) >> ADC_DAT_THCMPRANGE_SHIFT);
info->thresholdCorssingStatus =
(adc_threshold_crossing_status_t)(uint32_t)((tmp32 & ADC_DAT_THCMPCROSS_MASK) >> ADC_DAT_THCMPCROSS_SHIFT);
info->channelNumber = (tmp32 & ADC_DAT_CHANNEL_MASK) >> ADC_DAT_CHANNEL_SHIFT;
info->overrunFlag = ((tmp32 & ADC_DAT_OVERRUN_MASK) == ADC_DAT_OVERRUN_MASK);
return ret;
}
#if defined(FSL_FEATURE_ADC_ASYNC_SYSCON_TEMP) && (FSL_FEATURE_ADC_ASYNC_SYSCON_TEMP)
void ADC_EnableTemperatureSensor(ADC_Type *base, bool enable)
{
if (enable)
{
SYSCON->ASYNCAPBCTRL = SYSCON_ASYNCAPBCTRL_ENABLE_MASK;
ASYNC_SYSCON->TEMPSENSORCTRL = kADC_NoOffsetAdded;
ASYNC_SYSCON->TEMPSENSORCTRL |= ASYNC_SYSCON_TEMPSENSORCTRL_ENABLE_MASK;
base->GPADC_CTRL0 |= (kADC_ADCInUnityGainMode | kADC_Impedance87kOhm);
}
else
{
/* if the temperature sensor is not turned on then ASYNCAPBCTRL is likely to be zero
* and accessing the registers will cause a memory access error. Test for this */
if (SYSCON->ASYNCAPBCTRL == SYSCON_ASYNCAPBCTRL_ENABLE_MASK)
{
ASYNC_SYSCON->TEMPSENSORCTRL = 0x0;
base->GPADC_CTRL0 &= ~(kADC_ADCInUnityGainMode | kADC_Impedance87kOhm);
base->GPADC_CTRL0 |= kADC_Impedance55kOhm;
}
}
}
#endif

775
drivers/fsl_adc.h Normal file
View File

@@ -0,0 +1,775 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* Copyright 2016-2020 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __FSL_ADC_H__
#define __FSL_ADC_H__
#include "fsl_common.h"
/*!
* @addtogroup lpc_adc
* @{
*/
/*! @file */
/*******************************************************************************
* Definitions
******************************************************************************/
/*! @name Driver version */
/*@{*/
/*! @brief ADC driver version 2.5.0. */
#define FSL_ADC_DRIVER_VERSION (MAKE_VERSION(2, 5, 0))
/*@}*/
/*!
* @brief Flags
*/
enum _adc_status_flags
{
kADC_ThresholdCompareFlagOnChn0 = 1U << 0U, /*!< Threshold comparison event on Channel 0. */
kADC_ThresholdCompareFlagOnChn1 = 1U << 1U, /*!< Threshold comparison event on Channel 1. */
kADC_ThresholdCompareFlagOnChn2 = 1U << 2U, /*!< Threshold comparison event on Channel 2. */
kADC_ThresholdCompareFlagOnChn3 = 1U << 3U, /*!< Threshold comparison event on Channel 3. */
kADC_ThresholdCompareFlagOnChn4 = 1U << 4U, /*!< Threshold comparison event on Channel 4. */
kADC_ThresholdCompareFlagOnChn5 = 1U << 5U, /*!< Threshold comparison event on Channel 5. */
kADC_ThresholdCompareFlagOnChn6 = 1U << 6U, /*!< Threshold comparison event on Channel 6. */
kADC_ThresholdCompareFlagOnChn7 = 1U << 7U, /*!< Threshold comparison event on Channel 7. */
kADC_ThresholdCompareFlagOnChn8 = 1U << 8U, /*!< Threshold comparison event on Channel 8. */
kADC_ThresholdCompareFlagOnChn9 = 1U << 9U, /*!< Threshold comparison event on Channel 9. */
kADC_ThresholdCompareFlagOnChn10 = 1U << 10U, /*!< Threshold comparison event on Channel 10. */
kADC_ThresholdCompareFlagOnChn11 = 1U << 11U, /*!< Threshold comparison event on Channel 11. */
kADC_OverrunFlagForChn0 =
1U << 12U, /*!< Mirror the OVERRUN status flag from the result register for ADC channel 0. */
kADC_OverrunFlagForChn1 =
1U << 13U, /*!< Mirror the OVERRUN status flag from the result register for ADC channel 1. */
kADC_OverrunFlagForChn2 =
1U << 14U, /*!< Mirror the OVERRUN status flag from the result register for ADC channel 2. */
kADC_OverrunFlagForChn3 =
1U << 15U, /*!< Mirror the OVERRUN status flag from the result register for ADC channel 3. */
kADC_OverrunFlagForChn4 =
1U << 16U, /*!< Mirror the OVERRUN status flag from the result register for ADC channel 4. */
kADC_OverrunFlagForChn5 =
1U << 17U, /*!< Mirror the OVERRUN status flag from the result register for ADC channel 5. */
kADC_OverrunFlagForChn6 =
1U << 18U, /*!< Mirror the OVERRUN status flag from the result register for ADC channel 6. */
kADC_OverrunFlagForChn7 =
1U << 19U, /*!< Mirror the OVERRUN status flag from the result register for ADC channel 7. */
kADC_OverrunFlagForChn8 =
1U << 20U, /*!< Mirror the OVERRUN status flag from the result register for ADC channel 8. */
kADC_OverrunFlagForChn9 =
1U << 21U, /*!< Mirror the OVERRUN status flag from the result register for ADC channel 9. */
kADC_OverrunFlagForChn10 =
1U << 22U, /*!< Mirror the OVERRUN status flag from the result register for ADC channel 10. */
kADC_OverrunFlagForChn11 =
1U << 23U, /*!< Mirror the OVERRUN status flag from the result register for ADC channel 11. */
kADC_GlobalOverrunFlagForSeqA = 1U << 24U, /*!< Mirror the glabal OVERRUN status flag for conversion sequence A. */
kADC_GlobalOverrunFlagForSeqB = 1U << 25U, /*!< Mirror the global OVERRUN status flag for conversion sequence B. */
kADC_ConvSeqAInterruptFlag = 1U << 28U, /*!< Sequence A interrupt/DMA trigger. */
kADC_ConvSeqBInterruptFlag = 1U << 29U, /*!< Sequence B interrupt/DMA trigger. */
kADC_ThresholdCompareInterruptFlag = 1U << 30U, /*!< Threshold comparision interrupt flag. */
kADC_OverrunInterruptFlag = (int)(1U << 31U), /*!< Overrun interrupt flag. */
};
/*!
* @brief Interrupts
* @note Not all the interrupt options are listed here
*/
enum _adc_interrupt_enable
{
kADC_ConvSeqAInterruptEnable = ADC_INTEN_SEQA_INTEN_MASK, /*!< Enable interrupt upon completion of each individual
conversion in sequence A, or entire sequence. */
#if !(defined(FSL_FEATURE_ADC_HAS_SINGLE_SEQ) && FSL_FEATURE_ADC_HAS_SINGLE_SEQ)
kADC_ConvSeqBInterruptEnable = ADC_INTEN_SEQB_INTEN_MASK, /*!< Enable interrupt upon completion of each individual
conversion in sequence B, or entire sequence. */
#endif /* FSL_FEATURE_ADC_HAS_SINGLE_SEQ */
kADC_OverrunInterruptEnable = ADC_INTEN_OVR_INTEN_MASK, /*!< Enable the detection of an overrun condition on any of
the channel data registers will cause an overrun
interrupt/DMA trigger. */
};
#if defined(FSL_FEATURE_ADC_HAS_CTRL_ASYNMODE) & FSL_FEATURE_ADC_HAS_CTRL_ASYNMODE
/*!
* @brief Define selection of clock mode.
*/
typedef enum _adc_clock_mode
{
kADC_ClockSynchronousMode =
0U, /*!< The ADC clock would be derived from the system clock based on "clockDividerNumber". */
kADC_ClockAsynchronousMode = 1U, /*!< The ADC clock would be based on the SYSCON block's divider. */
} adc_clock_mode_t;
#endif /* FSL_FEATURE_ADC_HAS_CTRL_ASYNMODE. */
#if defined(FSL_FEATURE_ADC_DAT_OF_HIGH_ALIGNMENT) && (FSL_FEATURE_ADC_DAT_OF_HIGH_ALIGNMENT)
/*!
* @brief Define selection of resolution.
*/
typedef enum _adc_resolution
{
kADC_Resolution6bit = 3U,
/*!< 6-bit resolution. */ /* This is a HW issue that the ADC resolution enum configure not align with HW implement,
ES2 chip already fixed the issue, Currently, update ADC enum define as a workaround */
kADC_Resolution8bit = 2U, /*!< 8-bit resolution. */
kADC_Resolution10bit = 1U, /*!< 10-bit resolution. */
kADC_Resolution12bit = 0U, /*!< 12-bit resolution. */
} adc_resolution_t;
#elif defined(FSL_FEATURE_ADC_HAS_CTRL_RESOL) & FSL_FEATURE_ADC_HAS_CTRL_RESOL
/*!
* @brief Define selection of resolution.
*/
typedef enum _adc_resolution
{
kADC_Resolution6bit = 0U, /*!< 6-bit resolution. */
kADC_Resolution8bit = 1U, /*!< 8-bit resolution. */
kADC_Resolution10bit = 2U, /*!< 10-bit resolution. */
kADC_Resolution12bit = 3U, /*!< 12-bit resolution. */
} adc_resolution_t;
#endif
#if defined(FSL_FEATURE_ADC_HAS_TRIM_REG) & FSL_FEATURE_ADC_HAS_TRIM_REG
/*!
* @brief Definfe range of the analog supply voltage VDDA.
*/
typedef enum _adc_voltage_range
{
kADC_HighVoltageRange = 0U, /* High voltage. VDD = 2.7 V to 3.6 V. */
kADC_LowVoltageRange = 1U, /* Low voltage. VDD = 2.4 V to 2.7 V. */
} adc_vdda_range_t;
#endif /* FSL_FEATURE_ADC_HAS_TRIM_REG. */
/*!
* @brief Define selection of polarity of selected input trigger for conversion sequence.
*/
typedef enum _adc_trigger_polarity
{
kADC_TriggerPolarityNegativeEdge = 0U, /*!< A negative edge launches the conversion sequence on the trigger(s). */
kADC_TriggerPolarityPositiveEdge = 1U, /*!< A positive edge launches the conversion sequence on the trigger(s). */
} adc_trigger_polarity_t;
/*!
* @brief Define selection of conversion sequence's priority.
*/
typedef enum _adc_priority
{
kADC_PriorityLow = 0U, /*!< This sequence would be preempted when another sequence is started. */
kADC_PriorityHigh = 1U, /*!< This sequence would preempt other sequence even when it is started. */
} adc_priority_t;
/*!
* @brief Define selection of conversion sequence's interrupt.
*/
typedef enum _adc_seq_interrupt_mode
{
kADC_InterruptForEachConversion = 0U, /*!< The sequence interrupt/DMA trigger will be set at the end of each
individual ADC conversion inside this conversion sequence. */
kADC_InterruptForEachSequence = 1U, /*!< The sequence interrupt/DMA trigger will be set when the entire set of
this sequence conversions completes. */
} adc_seq_interrupt_mode_t;
/*!
* @brief Define status of threshold compare result.
*/
typedef enum _adc_threshold_compare_status
{
kADC_ThresholdCompareInRange = 0U, /*!< LOW threshold <= conversion value <= HIGH threshold. */
kADC_ThresholdCompareBelowRange = 1U, /*!< conversion value < LOW threshold. */
kADC_ThresholdCompareAboveRange = 2U, /*!< conversion value > HIGH threshold. */
} adc_threshold_compare_status_t;
/*!
* @brief Define status of threshold crossing detection result.
*/
typedef enum _adc_threshold_crossing_status
{
/* The conversion on this channel had the same relationship (above or below) to the threshold value established by
* the designated LOW threshold value as did the previous conversion on this channel. */
kADC_ThresholdCrossingNoDetected = 0U, /*!< No threshold Crossing detected. */
/* Indicates that a threshold crossing in the downward direction has occurred - i.e. the previous sample on this
* channel was above the threshold value established by the designated LOW threshold value and the current sample is
* below that threshold. */
kADC_ThresholdCrossingDownward = 2U, /*!< Downward Threshold Crossing detected. */
/* Indicates that a thre shold crossing in the upward direction has occurred - i.e. the previous sample on this
* channel was below the threshold value established by the designated LOW threshold value and the current sample is
* above that threshold. */
kADC_ThresholdCrossingUpward = 3U, /*!< Upward Threshold Crossing Detected. */
} adc_threshold_crossing_status_t;
/*!
* @brief Define interrupt mode for threshold compare event.
*/
typedef enum _adc_threshold_interrupt_mode
{
kADC_ThresholdInterruptDisabled = 0U, /*!< Threshold comparison interrupt is disabled. */
kADC_ThresholdInterruptOnOutside = 1U, /*!< Threshold comparison interrupt is enabled on outside threshold. */
kADC_ThresholdInterruptOnCrossing = 2U, /*!< Threshold comparison interrupt is enabled on crossing threshold. */
} adc_threshold_interrupt_mode_t;
/*!
* @brief Define the info result mode of different resolution.
*/
typedef enum _adc_inforesultshift
{
kADC_Resolution12bitInfoResultShift = 0U, /*!< Info result shift of Resolution12bit. */
kADC_Resolution10bitInfoResultShift = 2U, /*!< Info result shift of Resolution10bit. */
kADC_Resolution8bitInfoResultShift = 4U, /*!< Info result shift of Resolution8bit. */
kADC_Resolution6bitInfoResultShift = 6U, /*!< Info result shift of Resolution6bit. */
} adc_inforesult_t;
/*!
* @brief Define common modes for Temerature sensor.
*/
typedef enum _adc_tempsensor_common_mode
{
kADC_HighNegativeOffsetAdded = 0x0U, /*!< Temperature sensor common mode: high negative offset added. */
kADC_IntermediateNegativeOffsetAdded =
0x4U, /*!< Temperature sensor common mode: intermediate negative offset added. */
kADC_NoOffsetAdded = 0x8U, /*!< Temperature sensor common mode: no offset added. */
kADC_LowPositiveOffsetAdded = 0xcU, /*!< Temperature sensor common mode: low positive offset added. */
} adc_tempsensor_common_mode_t;
/*!
* @brief Define source impedance modes for GPADC control.
*/
typedef enum _adc_second_control
{
kADC_Impedance621Ohm = 0x1U << 9U, /*!< Extand ADC sampling time according to source impedance 1: 0.621 kOhm. */
kADC_Impedance55kOhm =
0x14U << 9U, /*!< Extand ADC sampling time according to source impedance 20 (default): 55 kOhm. */
kADC_Impedance87kOhm = 0x1fU << 9U, /*!< Extand ADC sampling time according to source impedance 31: 87 kOhm. */
kADC_NormalFunctionalMode = 0x0U << 14U, /*!< TEST mode: Normal functional mode. */
kADC_MultiplexeTestMode = 0x1U << 14U, /*!< TEST mode: Multiplexer test mode. */
kADC_ADCInUnityGainMode = 0x2U << 14U, /*!< TEST mode: ADC in unity gain mode. */
} adc_second_control_t;
/*!
* @brief Define structure for configuring the block.
*/
typedef struct _adc_config
{
#if defined(FSL_FEATURE_ADC_HAS_CTRL_ASYNMODE) & FSL_FEATURE_ADC_HAS_CTRL_ASYNMODE
adc_clock_mode_t clockMode; /*!< Select the clock mode for ADC converter. */
#endif /* FSL_FEATURE_ADC_HAS_CTRL_ASYNMODE. */
uint32_t clockDividerNumber; /*!< This field is only available when using kADC_ClockSynchronousMode for "clockMode"
field. The divider would be plused by 1 based on the value in this field. The
available range is in 8 bits. */
#if defined(FSL_FEATURE_ADC_HAS_CTRL_RESOL) & FSL_FEATURE_ADC_HAS_CTRL_RESOL
adc_resolution_t resolution; /*!< Select the conversion bits. */
#endif /* FSL_FEATURE_ADC_HAS_CTRL_RESOL. */
#if defined(FSL_FEATURE_ADC_HAS_CTRL_BYPASSCAL) & FSL_FEATURE_ADC_HAS_CTRL_BYPASSCAL
bool enableBypassCalibration; /*!< By default, a calibration cycle must be performed each time the chip is
powered-up. Re-calibration may be warranted periodically - especially if
operating conditions have changed. To enable this option would avoid the need to
calibrate if offset error is not a concern in the application. */
#endif /* FSL_FEATURE_ADC_HAS_CTRL_BYPASSCAL. */
#if defined(FSL_FEATURE_ADC_HAS_CTRL_TSAMP) & FSL_FEATURE_ADC_HAS_CTRL_TSAMP
uint32_t sampleTimeNumber; /*!< By default, with value as "0U", the sample period would be 2.5 ADC clocks. Then,
to plus the "sampleTimeNumber" value here. The available value range is in 3 bits.*/
#endif /* FSL_FEATURE_ADC_HAS_CTRL_TSAMP. */
#if defined(FSL_FEATURE_ADC_HAS_CTRL_LPWRMODE) & FSL_FEATURE_ADC_HAS_CTRL_LPWRMODE
bool enableLowPowerMode; /*!< If disable low-power mode, ADC remains activated even when no conversions are
requested.
If enable low-power mode, The ADC is automatically powered-down when no conversions are
taking place. */
#endif /* FSL_FEATURE_ADC_HAS_CTRL_LPWRMODE. */
#if defined(FSL_FEATURE_ADC_HAS_TRIM_REG) & FSL_FEATURE_ADC_HAS_TRIM_REG
adc_vdda_range_t
voltageRange; /*!< Configure the ADC for the appropriate operating range of the analog supply voltage VDDA.
Failure to set the area correctly causes the ADC to return incorrect conversion results. */
#endif /* FSL_FEATURE_ADC_HAS_TRIM_REG. */
} adc_config_t;
/*!
* @brief Define structure for configuring conversion sequence.
*/
typedef struct _adc_conv_seq_config
{
uint32_t channelMask; /*!< Selects which one or more of the ADC channels will be sampled and converted when this
sequence is launched. The masked channels would be involved in current conversion
sequence, beginning with the lowest-order. The available range is in 12-bit. */
uint32_t triggerMask; /*!< Selects which one or more of the available hardware trigger sources will cause this
conversion sequence to be initiated. The available range is 6-bit.*/
adc_trigger_polarity_t triggerPolarity; /*!< Select the trigger to launch conversion sequence. */
bool enableSyncBypass; /*!< To enable this feature allows the hardware trigger input to bypass synchronization
flip-flop stages and therefore shorten the time between the trigger input signal and the
start of a conversion. */
bool enableSingleStep; /*!< When enabling this feature, a trigger will launch a single conversion on the next
channel in the sequence instead of the default response of launching an entire sequence
of conversions. */
adc_seq_interrupt_mode_t interruptMode; /*!< Select the interrpt/DMA trigger mode. */
} adc_conv_seq_config_t;
/*!
* @brief Define structure of keeping conversion result information.
*/
typedef struct _adc_result_info
{
uint32_t result; /*!< Keep the conversion data value. */
adc_threshold_compare_status_t thresholdCompareStatus; /*!< Keep the threshold compare status. */
adc_threshold_crossing_status_t thresholdCorssingStatus; /*!< Keep the threshold crossing status. */
uint32_t channelNumber; /*!< Keep the channel number for this conversion. */
bool overrunFlag; /*!< Keep the status whether the conversion is overrun or not. */
/* The data available flag would be returned by the reading result API. */
} adc_result_info_t;
#if defined(__cplusplus)
extern "C" {
#endif
/*******************************************************************************
* API
******************************************************************************/
/*!
* @name Initialization and Deinitialization
* @{
*/
/*!
* @brief Initialize the ADC module.
*
* @param base ADC peripheral base address.
* @param config Pointer to configuration structure, see to #adc_config_t.
*/
void ADC_Init(ADC_Type *base, const adc_config_t *config);
/*!
* @brief Deinitialize the ADC module.
*
* @param base ADC peripheral base address.
*/
void ADC_Deinit(ADC_Type *base);
/*!
* @brief Gets an available pre-defined settings for initial configuration.
*
* This function initializes the initial configuration structure with an available settings. The default values are:
* @code
* config->clockMode = kADC_ClockSynchronousMode;
* config->clockDividerNumber = 0U;
* config->resolution = kADC_Resolution12bit;
* config->enableBypassCalibration = false;
* config->sampleTimeNumber = 0U;
* @endcode
* @param config Pointer to configuration structure.
*/
void ADC_GetDefaultConfig(adc_config_t *config);
#if !(defined(FSL_FEATURE_ADC_HAS_NO_CALIB_FUNC) && FSL_FEATURE_ADC_HAS_NO_CALIB_FUNC)
#if defined(FSL_FEATURE_ADC_HAS_CALIB_REG) && FSL_FEATURE_ADC_HAS_CALIB_REG
/*!
* @brief Do the hardware self-calibration.
* @deprecated Do not use this function. It has been superceded by @ref ADC_DoOffsetCalibration.
*
* To calibrate the ADC, set the ADC clock to 500 kHz. In order to achieve the specified ADC accuracy, the A/D
* converter must be recalibrated, at a minimum, following every chip reset before initiating normal ADC operation.
*
* @param base ADC peripheral base address.
* @retval true Calibration succeed.
* @retval false Calibration failed.
*/
bool ADC_DoSelfCalibration(ADC_Type *base);
/*!
* @brief Do the hardware offset-calibration.
*
* To calibrate the ADC, set the ADC clock to no more then 30 MHz. In order to achieve the specified ADC accuracy, the
* A/D converter must be recalibrated, at a minimum, following every chip reset before initiating normal ADC operation.
*
* @param base ADC peripheral base address.
* @param frequency The clock frequency that ADC operates at.
* @retval true Calibration succeed.
* @retval false Calibration failed.
*/
bool ADC_DoOffsetCalibration(ADC_Type *base, uint32_t frequency);
#else
/*!
* @brief Do the hardware self-calibration.
*
* To calibrate the ADC, set the ADC clock to 500 kHz. In order to achieve the specified ADC accuracy, the A/D
* converter must be recalibrated, at a minimum, following every chip reset before initiating normal ADC operation.
*
* @param base ADC peripheral base address.
* @param frequency The clock frequency that ADC operates at.
* @retval true Calibration succeed.
* @retval false Calibration failed.
*/
bool ADC_DoSelfCalibration(ADC_Type *base, uint32_t frequency);
#endif /* FSL_FEATURE_ADC_HAS_CALIB_REG */
#endif /* FSL_FEATURE_ADC_HAS_NO_CALIB_FUNC */
#if !(defined(FSL_FEATURE_ADC_HAS_NO_INSEL) && FSL_FEATURE_ADC_HAS_NO_INSEL)
/*!
* @brief Enable the internal temperature sensor measurement.
*
* When enabling the internal temperature sensor measurement, the channel 0 would be connected to internal sensor
* instead of external pin.
*
* @param base ADC peripheral base address.
* @param enable Switcher to enable the feature or not.
*/
#if defined(FSL_FEATURE_ADC_ASYNC_SYSCON_TEMP) && (FSL_FEATURE_ADC_ASYNC_SYSCON_TEMP)
void ADC_EnableTemperatureSensor(ADC_Type *base, bool enable);
#else
static inline void ADC_EnableTemperatureSensor(ADC_Type *base, bool enable)
{
if (enable)
{
base->INSEL = (base->INSEL & ~ADC_INSEL_SEL_MASK) | ADC_INSEL_SEL(0x3);
}
else
{
base->INSEL = (base->INSEL & ~ADC_INSEL_SEL_MASK) | ADC_INSEL_SEL(0);
}
}
#endif /* FSL_FEATURE_ADC_ASYNC_SYSCON_TEMP. */
#endif /* FSL_FEATURE_ADC_HAS_NO_INSEL. */
/* @} */
/*!
* @name Control conversion sequence A.
* @{
*/
/*!
* @brief Enable the conversion sequence A.
*
* In order to avoid spuriously triggering the sequence, the trigger to conversion sequence should be ready before the
* sequence is ready. when the sequence is disabled, the trigger would be ignored. Also, it is suggested to disable the
* sequence during changing the sequence's setting.
*
* @param base ADC peripheral base address.
* @param enable Switcher to enable the feature or not.
*/
static inline void ADC_EnableConvSeqA(ADC_Type *base, bool enable)
{
if (enable)
{
base->SEQ_CTRL[0] |= ADC_SEQ_CTRL_SEQ_ENA_MASK;
}
else
{
base->SEQ_CTRL[0] &= ~ADC_SEQ_CTRL_SEQ_ENA_MASK;
}
}
/*!
* @brief Configure the conversion sequence A.
*
* @param base ADC peripheral base address.
* @param config Pointer to configuration structure, see to #adc_conv_seq_config_t.
*/
void ADC_SetConvSeqAConfig(ADC_Type *base, const adc_conv_seq_config_t *config);
/*!
* @brief Do trigger the sequence's conversion by software.
*
* @param base ADC peripheral base address.
*/
static inline void ADC_DoSoftwareTriggerConvSeqA(ADC_Type *base)
{
base->SEQ_CTRL[0] |= ADC_SEQ_CTRL_START_MASK;
}
/*!
* @brief Enable the burst conversion of sequence A.
*
* Enable the burst mode would cause the conversion sequence to be cntinuously cycled through. Other triggers would be
* ignored while this mode is enabled. Repeated conversions could be halted by disabling this mode. And the sequence
* currently in process will be completed before cnversions are terminated.
* Note that a new sequence could begin just before the burst mode is disabled.
*
* @param base ADC peripheral base address.
* @param enable Switcher to enable this feature.
*/
static inline void ADC_EnableConvSeqABurstMode(ADC_Type *base, bool enable)
{
if (enable)
{
base->SEQ_CTRL[0] |= ADC_SEQ_CTRL_BURST_MASK;
}
else
{
base->SEQ_CTRL[0] &= ~ADC_SEQ_CTRL_BURST_MASK;
}
}
#if !(defined(FSL_FEATURE_ADC_HAS_SINGLE_SEQ) && FSL_FEATURE_ADC_HAS_SINGLE_SEQ)
/*!
* @brief Set the high priority for conversion sequence A.
*
* @param base ADC peripheral bass address.
*/
static inline void ADC_SetConvSeqAHighPriority(ADC_Type *base)
{
base->SEQ_CTRL[0] |= ADC_SEQ_CTRL_LOWPRIO_MASK;
}
#endif /* FSL_FEATURE_ADC_HAS_SINGLE_SEQ */
/* @} */
#if !(defined(FSL_FEATURE_ADC_HAS_SINGLE_SEQ) && FSL_FEATURE_ADC_HAS_SINGLE_SEQ)
/*!
* @name Control conversion sequence B.
* @{
*/
/*!
* @brief Enable the conversion sequence B.
*
* In order to avoid spuriously triggering the sequence, the trigger to conversion sequence should be ready before the
* sequence is ready. when the sequence is disabled, the trigger would be ignored. Also, it is suggested to disable the
* sequence during changing the sequence's setting.
*
* @param base ADC peripheral base address.
* @param enable Switcher to enable the feature or not.
*/
static inline void ADC_EnableConvSeqB(ADC_Type *base, bool enable)
{
if (enable)
{
base->SEQ_CTRL[1] |= ADC_SEQ_CTRL_SEQ_ENA_MASK;
}
else
{
base->SEQ_CTRL[1] &= ~ADC_SEQ_CTRL_SEQ_ENA_MASK;
}
}
/*!
* @brief Configure the conversion sequence B.
*
* @param base ADC peripheral base address.
* @param config Pointer to configuration structure, see to #adc_conv_seq_config_t.
*/
void ADC_SetConvSeqBConfig(ADC_Type *base, const adc_conv_seq_config_t *config);
/*!
* @brief Do trigger the sequence's conversion by software.
*
* @param base ADC peripheral base address.
*/
static inline void ADC_DoSoftwareTriggerConvSeqB(ADC_Type *base)
{
base->SEQ_CTRL[1] |= ADC_SEQ_CTRL_START_MASK;
}
/*!
* @brief Enable the burst conversion of sequence B.
*
* Enable the burst mode would cause the conversion sequence to be continuously cycled through. Other triggers would be
* ignored while this mode is enabled. Repeated conversions could be halted by disabling this mode. And the sequence
* currently in process will be completed before cnversions are terminated.
* Note that a new sequence could begin just before the burst mode is disabled.
*
* @param base ADC peripheral base address.
* @param enable Switcher to enable this feature.
*/
static inline void ADC_EnableConvSeqBBurstMode(ADC_Type *base, bool enable)
{
if (enable)
{
base->SEQ_CTRL[1] |= ADC_SEQ_CTRL_BURST_MASK;
}
else
{
base->SEQ_CTRL[1] &= ~ADC_SEQ_CTRL_BURST_MASK;
}
}
/*!
* @brief Set the high priority for conversion sequence B.
*
* @param base ADC peripheral bass address.
*/
static inline void ADC_SetConvSeqBHighPriority(ADC_Type *base)
{
base->SEQ_CTRL[0] &= ~ADC_SEQ_CTRL_LOWPRIO_MASK;
}
/* @} */
#endif /* FSL_FEATURE_ADC_HAS_SINGLE_SEQ */
/*!
* @name Data result.
* @{
*/
/*!
* @brief Get the global ADC conversion infomation of sequence A.
*
* @param base ADC peripheral base address.
* @param info Pointer to information structure, see to #adc_result_info_t;
* @retval true The conversion result is ready.
* @retval false The conversion result is not ready yet.
*/
bool ADC_GetConvSeqAGlobalConversionResult(ADC_Type *base, adc_result_info_t *info);
#if !(defined(FSL_FEATURE_ADC_HAS_SINGLE_SEQ) && FSL_FEATURE_ADC_HAS_SINGLE_SEQ)
/*!
* @brief Get the global ADC conversion infomation of sequence B.
*
* @param base ADC peripheral base address.
* @param info Pointer to information structure, see to #adc_result_info_t;
* @retval true The conversion result is ready.
* @retval false The conversion result is not ready yet.
*/
bool ADC_GetConvSeqBGlobalConversionResult(ADC_Type *base, adc_result_info_t *info);
#endif /* FSL_FEATURE_ADC_HAS_SINGLE_SEQ */
/*!
* @brief Get the channel's ADC conversion completed under each conversion sequence.
*
* @param base ADC peripheral base address.
* @param channel The indicated channel number.
* @param info Pointer to information structure, see to #adc_result_info_t;
* @retval true The conversion result is ready.
* @retval false The conversion result is not ready yet.
*/
bool ADC_GetChannelConversionResult(ADC_Type *base, uint32_t channel, adc_result_info_t *info);
/* @} */
/*!
* @name Threshold function.
* @{
*/
/*!
* @brief Set the threshhold pair 0 with low and high value.
*
* @param base ADC peripheral base address.
* @param lowValue LOW threshold value.
* @param highValue HIGH threshold value.
*/
static inline void ADC_SetThresholdPair0(ADC_Type *base, uint32_t lowValue, uint32_t highValue)
{
base->THR0_LOW = ADC_THR0_LOW_THRLOW(lowValue);
base->THR0_HIGH = ADC_THR0_HIGH_THRHIGH(highValue);
}
/*!
* @brief Set the threshhold pair 1 with low and high value.
*
* @param base ADC peripheral base address.
* @param lowValue LOW threshold value. The available value is with 12-bit.
* @param highValue HIGH threshold value. The available value is with 12-bit.
*/
static inline void ADC_SetThresholdPair1(ADC_Type *base, uint32_t lowValue, uint32_t highValue)
{
base->THR1_LOW = ADC_THR1_LOW_THRLOW(lowValue);
base->THR1_HIGH = ADC_THR1_HIGH_THRHIGH(highValue);
}
/*!
* @brief Set given channels to apply the threshold pare 0.
*
* @param base ADC peripheral base address.
* @param channelMask Indicated channels' mask.
*/
static inline void ADC_SetChannelWithThresholdPair0(ADC_Type *base, uint32_t channelMask)
{
base->CHAN_THRSEL &= ~(channelMask);
}
/*!
* @brief Set given channels to apply the threshold pare 1.
*
* @param base ADC peripheral base address.
* @param channelMask Indicated channels' mask.
*/
static inline void ADC_SetChannelWithThresholdPair1(ADC_Type *base, uint32_t channelMask)
{
base->CHAN_THRSEL |= channelMask;
}
/* @} */
/*!
* @name Interrupts.
* @{
*/
/*!
* @brief Enable interrupts for conversion sequences.
*
* @param base ADC peripheral base address.
* @param mask Mask of interrupt mask value for global block except each channal, see to #_adc_interrupt_enable.
*/
static inline void ADC_EnableInterrupts(ADC_Type *base, uint32_t mask)
{
base->INTEN |= (0x7UL & mask);
}
/*!
* @brief Disable interrupts for conversion sequence.
*
* @param base ADC peripheral base address.
* @param mask Mask of interrupt mask value for global block except each channel, see to #_adc_interrupt_enable.
*/
static inline void ADC_DisableInterrupts(ADC_Type *base, uint32_t mask)
{
base->INTEN &= ~(0x7UL & mask);
}
/*!
* @brief Enable the interrupt of threshold compare event for each channel.
*
* @param base ADC peripheral base address.
* @param channel Channel number.
* @param mode Interrupt mode for threshold compare event, see to #adc_threshold_interrupt_mode_t.
*/
static inline void ADC_EnableThresholdCompareInterrupt(ADC_Type *base,
uint32_t channel,
adc_threshold_interrupt_mode_t mode)
{
base->INTEN = (base->INTEN & ~(0x3UL << ((channel << 1UL) + 3UL))) | ((uint32_t)(mode) << ((channel << 1UL) + 3UL));
}
/* @} */
/*!
* @name Status.
* @{
*/
/*!
* @brief Get status flags of ADC module.
*
* @param base ADC peripheral base address.
* @return Mask of status flags of module, see to #_adc_status_flags.
*/
static inline uint32_t ADC_GetStatusFlags(ADC_Type *base)
{
return base->FLAGS;
}
/*!
* @brief Clear status flags of ADC module.
*
* @param base ADC peripheral base address.
* @param mask Mask of status flags of module, see to #_adc_status_flags.
*/
static inline void ADC_ClearStatusFlags(ADC_Type *base, uint32_t mask)
{
base->FLAGS = mask; /* Write 1 to clear. */
}
/* @} */
#if defined(__cplusplus)
}
#endif
/* @} */
#endif /* __FSL_ADC_H__ */

1777
drivers/fsl_clock.c Normal file

File diff suppressed because it is too large Load Diff

876
drivers/fsl_clock.h Normal file
View File

@@ -0,0 +1,876 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* Copyright 2016 - 2019 , NXP
* All rights reserved.
*
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _FSL_CLOCK_H_
#define _FSL_CLOCK_H_
#include "fsl_common.h"
/*! @addtogroup clock */
/*! @{ */
/*! @file */
/*******************************************************************************
* Definitions
*****************************************************************************/
/*! @name Driver version */
/*@{*/
/*! @brief CLOCK driver version 2.5.1. */
#define FSL_CLOCK_DRIVER_VERSION (MAKE_VERSION(2, 5, 1))
/*@}*/
/*!
* @brief User-defined the size of cache for CLOCK_PllGetConfig() function.
*
* Once define this MACRO to be non-zero value, CLOCK_PllGetConfig() function
* would cache the recent calulation and accelerate the execution to get the
* right settings.
*/
#ifndef CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT
#define CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT 2U
#endif
/* Definition for delay API in clock driver, users can redefine it to the real application. */
#ifndef SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY
#define SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY (150000000UL)
#endif
/*! @brief Clock ip name array for FLEXCOMM. */
#define FLEXCOMM_CLOCKS \
{ \
kCLOCK_FlexComm0, kCLOCK_FlexComm1, kCLOCK_FlexComm2, kCLOCK_FlexComm3, kCLOCK_FlexComm4, kCLOCK_FlexComm5, \
kCLOCK_FlexComm6, kCLOCK_FlexComm7 \
}
/*! @brief Clock ip name array for LPUART. */
#define LPUART_CLOCKS \
{ \
kCLOCK_MinUart0, kCLOCK_MinUart1, kCLOCK_MinUart2, kCLOCK_MinUart3, kCLOCK_MinUart4, kCLOCK_MinUart5, \
kCLOCK_MinUart6, kCLOCK_MinUart7 \
}
/*! @brief Clock ip name array for BI2C. */
#define BI2C_CLOCKS \
{ \
kCLOCK_BI2c0, kCLOCK_BI2c1, kCLOCK_BI2c2, kCLOCK_BI2c3, kCLOCK_BI2c4, kCLOCK_BI2c5, kCLOCK_BI2c6, kCLOCK_BI2c7 \
}
/*! @brief Clock ip name array for LSPI. */
#define LPSI_CLOCKS \
{ \
kCLOCK_LSpi0, kCLOCK_LSpi1, kCLOCK_LSpi2, kCLOCK_LSpi3, kCLOCK_LSpi4, kCLOCK_LSpi5, kCLOCK_LSpi6, kCLOCK_LSpi7 \
}
/*! @brief Clock ip name array for FLEXI2S. */
#define FLEXI2S_CLOCKS \
{ \
kCLOCK_FlexI2s0, kCLOCK_FlexI2s1, kCLOCK_FlexI2s2, kCLOCK_FlexI2s3, kCLOCK_FlexI2s4, kCLOCK_FlexI2s5, \
kCLOCK_FlexI2s6, kCLOCK_FlexI2s7 \
}
/*! @brief Clock ip name array for UTICK. */
#define UTICK_CLOCKS \
{ \
kCLOCK_Utick \
}
/*! @brief Clock ip name array for DMIC. */
#define DMIC_CLOCKS \
{ \
kCLOCK_DMic \
}
/*! @brief Clock ip name array for DMA. */
#define DMA_CLOCKS \
{ \
kCLOCK_Dma \
}
/*! @brief Clock ip name array for CT32B. */
#define CTIMER_CLOCKS \
{ \
kCLOCK_Ct32b0, kCLOCK_Ct32b1, kCLOCK_Ct32b2, kCLOCK_Ct32b3, kCLOCK_Ct32b4 \
}
/*! @brief Clock ip name array for GPIO. */
#define GPIO_CLOCKS \
{ \
kCLOCK_Gpio0, kCLOCK_Gpio1 \
}
/*! @brief Clock ip name array for ADC. */
#define ADC_CLOCKS \
{ \
kCLOCK_Adc0 \
}
/*! @brief Clock ip name array for MRT. */
#define MRT_CLOCKS \
{ \
kCLOCK_Mrt \
}
/*! @brief Clock ip name array for MRT. */
#define SCT_CLOCKS \
{ \
kCLOCK_Sct0 \
}
/*! @brief Clock ip name array for RTC. */
#define RTC_CLOCKS \
{ \
kCLOCK_Rtc \
}
/*! @brief Clock ip name array for WWDT. */
#define WWDT_CLOCKS \
{ \
kCLOCK_Wwdt \
}
/*! @brief Clock ip name array for CRC. */
#define CRC_CLOCKS \
{ \
kCLOCK_Crc \
}
/*! @brief Clock ip name array for USBD. */
#define USBD_CLOCKS \
{ \
kCLOCK_Usbd0 \
}
/*! @brief Clock ip name array for GINT. GINT0 & GINT1 share same slot */
#define GINT_CLOCKS \
{ \
kCLOCK_Gint, kCLOCK_Gint \
}
/*! @brief Clock gate name used for CLOCK_EnableClock/CLOCK_DisableClock. */
/*------------------------------------------------------------------------------
clock_ip_name_t definition:
------------------------------------------------------------------------------*/
#define CLK_GATE_REG_OFFSET_SHIFT 8U
#define CLK_GATE_REG_OFFSET_MASK 0xFFFFFF00U
#define CLK_GATE_BIT_SHIFT_SHIFT 0U
#define CLK_GATE_BIT_SHIFT_MASK 0x000000FFU
#define CLK_GATE_DEFINE(reg_offset, bit_shift) \
((((reg_offset) << CLK_GATE_REG_OFFSET_SHIFT) & CLK_GATE_REG_OFFSET_MASK) | \
(((bit_shift) << CLK_GATE_BIT_SHIFT_SHIFT) & CLK_GATE_BIT_SHIFT_MASK))
#define CLK_GATE_ABSTRACT_REG_OFFSET(x) (((uint32_t)(x)&CLK_GATE_REG_OFFSET_MASK) >> CLK_GATE_REG_OFFSET_SHIFT)
#define CLK_GATE_ABSTRACT_BITS_SHIFT(x) (((uint32_t)(x)&CLK_GATE_BIT_SHIFT_MASK) >> CLK_GATE_BIT_SHIFT_SHIFT)
#define AHB_CLK_CTRL0 0
#define AHB_CLK_CTRL1 1
#define ASYNC_CLK_CTRL0 2
/*! @brief Clock gate name used for CLOCK_EnableClock/CLOCK_DisableClock. */
typedef enum _clock_ip_name
{
kCLOCK_IpInvalid = 0U,
kCLOCK_Rom = CLK_GATE_DEFINE(AHB_CLK_CTRL0, 1),
kCLOCK_Sram1 = CLK_GATE_DEFINE(AHB_CLK_CTRL0, 3),
kCLOCK_Sram2 = CLK_GATE_DEFINE(AHB_CLK_CTRL0, 4),
kCLOCK_Regfile = CLK_GATE_DEFINE(AHB_CLK_CTRL0, 6),
kCLOCK_Flash = CLK_GATE_DEFINE(AHB_CLK_CTRL0, 7),
kCLOCK_Fmc = CLK_GATE_DEFINE(AHB_CLK_CTRL0, 8),
kCLOCK_InputMux = CLK_GATE_DEFINE(AHB_CLK_CTRL0, 11),
kCLOCK_Iocon = CLK_GATE_DEFINE(AHB_CLK_CTRL0, 13),
kCLOCK_Gpio0 = CLK_GATE_DEFINE(AHB_CLK_CTRL0, 14),
kCLOCK_Gpio1 = CLK_GATE_DEFINE(AHB_CLK_CTRL0, 15),
kCLOCK_Gpio2 = CLK_GATE_DEFINE(AHB_CLK_CTRL0, 16),
kCLOCK_Gpio3 = CLK_GATE_DEFINE(AHB_CLK_CTRL0, 17),
kCLOCK_Pint = CLK_GATE_DEFINE(AHB_CLK_CTRL0, 18),
kCLOCK_Gint = CLK_GATE_DEFINE(AHB_CLK_CTRL0, 19), /* GPIO_GLOBALINT0 and GPIO_GLOBALINT1 share the same slot */
kCLOCK_Dma = CLK_GATE_DEFINE(AHB_CLK_CTRL0, 20),
kCLOCK_Crc = CLK_GATE_DEFINE(AHB_CLK_CTRL0, 21),
kCLOCK_Wwdt = CLK_GATE_DEFINE(AHB_CLK_CTRL0, 22),
kCLOCK_Rtc = CLK_GATE_DEFINE(AHB_CLK_CTRL0, 23),
kCLOCK_Mailbox = CLK_GATE_DEFINE(AHB_CLK_CTRL0, 26),
kCLOCK_Adc0 = CLK_GATE_DEFINE(AHB_CLK_CTRL0, 27),
kCLOCK_Mrt = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 0),
kCLOCK_Sct0 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 2),
kCLOCK_SctIpu0 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 6),
kCLOCK_Utick = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 10),
kCLOCK_FlexComm0 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 11),
kCLOCK_FlexComm1 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 12),
kCLOCK_FlexComm2 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 13),
kCLOCK_FlexComm3 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 14),
kCLOCK_FlexComm4 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 15),
kCLOCK_FlexComm5 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 16),
kCLOCK_FlexComm6 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 17),
kCLOCK_FlexComm7 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 18),
kCLOCK_MinUart0 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 11),
kCLOCK_MinUart1 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 12),
kCLOCK_MinUart2 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 13),
kCLOCK_MinUart3 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 14),
kCLOCK_MinUart4 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 15),
kCLOCK_MinUart5 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 16),
kCLOCK_MinUart6 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 17),
kCLOCK_MinUart7 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 18),
kCLOCK_LSpi0 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 11),
kCLOCK_LSpi1 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 12),
kCLOCK_LSpi2 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 13),
kCLOCK_LSpi3 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 14),
kCLOCK_LSpi4 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 15),
kCLOCK_LSpi5 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 16),
kCLOCK_LSpi6 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 17),
kCLOCK_LSpi7 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 18),
kCLOCK_BI2c0 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 11),
kCLOCK_BI2c1 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 12),
kCLOCK_BI2c2 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 13),
kCLOCK_BI2c3 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 14),
kCLOCK_BI2c4 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 15),
kCLOCK_BI2c5 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 16),
kCLOCK_BI2c6 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 17),
kCLOCK_BI2c7 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 18),
kCLOCK_FlexI2s0 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 11),
kCLOCK_FlexI2s1 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 12),
kCLOCK_FlexI2s2 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 13),
kCLOCK_FlexI2s3 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 14),
kCLOCK_FlexI2s4 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 15),
kCLOCK_FlexI2s5 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 16),
kCLOCK_FlexI2s6 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 17),
kCLOCK_FlexI2s7 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 18),
kCLOCK_DMic = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 19),
kCLOCK_Ct32b2 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 22),
kCLOCK_Usbd0 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 25),
kCLOCK_Ct32b0 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 26),
kCLOCK_Ct32b1 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 27),
kCLOCK_Pvtvf0 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 28),
kCLOCK_Pvtvf1 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 28),
kCLOCK_BodyBias0 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 29),
kCLOCK_EzhArchB0 = CLK_GATE_DEFINE(AHB_CLK_CTRL1, 31),
kCLOCK_Ct32b3 = CLK_GATE_DEFINE(ASYNC_CLK_CTRL0, 13),
kCLOCK_Ct32b4 = CLK_GATE_DEFINE(ASYNC_CLK_CTRL0, 14)
} clock_ip_name_t;
/*! @brief Clock name used to get clock frequency. */
typedef enum _clock_name
{
kCLOCK_CoreSysClk, /*!< Core/system clock (aka MAIN_CLK) */
kCLOCK_BusClk, /*!< Bus clock (AHB clock) */
kCLOCK_FroHf, /*!< FRO48/96 */
kCLOCK_Fro12M, /*!< FRO12M */
kCLOCK_ExtClk, /*!< External Clock */
kCLOCK_PllOut, /*!< PLL Output */
kCLOCK_UsbClk, /*!< USB input */
kCLOCK_WdtOsc, /*!< Watchdog Oscillator */
kCLOCK_Frg, /*!< Frg Clock */
kCLOCK_AsyncApbClk, /*!< Async APB clock */
kCLOCK_FlexI2S, /*!< FlexI2S clock */
} clock_name_t;
/**
* Clock source selections for the asynchronous APB clock
*/
typedef enum _async_clock_src
{
kCLOCK_AsyncMainClk = 0, /*!< Main System clock */
kCLOCK_AsyncFro12Mhz, /*!< 12MHz FRO */
} async_clock_src_t;
/*! @brief Clock Mux Switches
* The encoding is as follows each connection identified is 32bits wide while 24bits are valuable
* starting from LSB upwards
*
* [4 bits for choice, 0 means invalid choice] [8 bits mux ID]*
*
*/
#define CLK_ATTACH_ID(mux, sel, pos) ((((uint32_t)(mux) << 0U) | (((uint32_t)(sel) + 1UL) & 0xFU) << 8U) << ((pos)*12U))
#define MUX_A(mux, sel) CLK_ATTACH_ID((mux), (sel), 0U)
#define MUX_B(mux, sel, selector) (CLK_ATTACH_ID((mux), (sel), 1U) | ((selector) << 24U))
#define GET_ID_ITEM(connection) ((connection)&0xFFFU)
#define GET_ID_NEXT_ITEM(connection) ((connection) >> 12U)
#define GET_ID_ITEM_MUX(connection) (((uint8_t)(connection)) & 0xFFU)
#define GET_ID_ITEM_SEL(connection) (uint8_t)(((((uint32_t)(connection)&0xF00U) >> 8U) - 1U))
#define GET_ID_SELECTOR(connection) ((connection)&0xF000000U)
#define CM_MAINCLKSELA 0
#define CM_MAINCLKSELB 1
#define CM_CLKOUTCLKSELA 2
#define CM_CLKOUTCLKSELB 3
#define CM_SYSPLLCLKSEL 4
#define CM_USBPLLCLKSEL 5
#define CM_AUDPLLCLKSEL 6
#define CM_SCTPLLCLKSEL 7
#define CM_SPIFICLKSEL 8
#define CM_ADCASYNCCLKSEL 9
#define CM_USBCLKSEL 10
#define CM_USB1CLKSEL 11
#define CM_FXCOMCLKSEL0 12
#define CM_FXCOMCLKSEL1 13
#define CM_FXCOMCLKSEL2 14
#define CM_FXCOMCLKSEL3 15
#define CM_FXCOMCLKSEL4 16
#define CM_FXCOMCLKSEL5 17
#define CM_FXCOMCLKSEL6 18
#define CM_FXCOMCLKSEL7 19
#define CM_FXCOMCLKSEL8 20
#define CM_FXCOMCLKSEL9 21
#define CM_FXCOMCLKSEL10 22
#define CM_FXCOMCLKSEL11 23
#define CM_FXI2S0MCLKCLKSEL 24
#define CM_FXI2S1MCLKCLKSEL 25
#define CM_FRGCLKSEL 26
#define CM_DMICCLKSEL 27
#define CM_ASYNCAPB 28U
typedef enum _clock_attach_id
{
kFRO12M_to_MAIN_CLK = MUX_A(CM_MAINCLKSELA, 0) | MUX_B(CM_MAINCLKSELB, 0, 0),
kEXT_CLK_to_MAIN_CLK = MUX_A(CM_MAINCLKSELA, 1) | MUX_B(CM_MAINCLKSELB, 0, 0),
kWDT_OSC_to_MAIN_CLK = MUX_A(CM_MAINCLKSELA, 2) | MUX_B(CM_MAINCLKSELB, 0, 0),
kFRO_HF_to_MAIN_CLK = MUX_A(CM_MAINCLKSELA, 3) | MUX_B(CM_MAINCLKSELB, 0, 0),
kSYS_PLL_to_MAIN_CLK = MUX_A(CM_MAINCLKSELA, 0) | MUX_B(CM_MAINCLKSELB, 2, 0),
kOSC32K_to_MAIN_CLK = MUX_A(CM_MAINCLKSELA, 0) | MUX_B(CM_MAINCLKSELB, 3, 0),
kFRO12M_to_SYS_PLL = MUX_A(CM_SYSPLLCLKSEL, 0),
kEXT_CLK_to_SYS_PLL = MUX_A(CM_SYSPLLCLKSEL, 1),
kWDT_OSC_to_SYS_PLL = MUX_A(CM_SYSPLLCLKSEL, 2),
kOSC32K_to_SYS_PLL = MUX_A(CM_SYSPLLCLKSEL, 3),
kNONE_to_SYS_PLL = MUX_A(CM_SYSPLLCLKSEL, 7),
kMAIN_CLK_to_ASYNC_APB = MUX_A(CM_ASYNCAPB, 0),
kFRO12M_to_ASYNC_APB = MUX_A(CM_ASYNCAPB, 1),
kMAIN_CLK_to_ADC_CLK = MUX_A(CM_ADCASYNCCLKSEL, 0),
kSYS_PLL_to_ADC_CLK = MUX_A(CM_ADCASYNCCLKSEL, 1),
kFRO_HF_to_ADC_CLK = MUX_A(CM_ADCASYNCCLKSEL, 2),
kNONE_to_ADC_CLK = MUX_A(CM_ADCASYNCCLKSEL, 7),
kMAIN_CLK_to_SPIFI_CLK = MUX_A(CM_SPIFICLKSEL, 0),
kSYS_PLL_to_SPIFI_CLK = MUX_A(CM_SPIFICLKSEL, 1),
kFRO_HF_to_SPIFI_CLK = MUX_A(CM_SPIFICLKSEL, 3),
kNONE_to_SPIFI_CLK = MUX_A(CM_SPIFICLKSEL, 7),
kFRO12M_to_FLEXCOMM0 = MUX_A(CM_FXCOMCLKSEL0, 0),
kFRO_HF_to_FLEXCOMM0 = MUX_A(CM_FXCOMCLKSEL0, 1),
kSYS_PLL_to_FLEXCOMM0 = MUX_A(CM_FXCOMCLKSEL0, 2),
kMCLK_to_FLEXCOMM0 = MUX_A(CM_FXCOMCLKSEL0, 3),
kFRG_to_FLEXCOMM0 = MUX_A(CM_FXCOMCLKSEL0, 4),
kNONE_to_FLEXCOMM0 = MUX_A(CM_FXCOMCLKSEL0, 7),
kFRO12M_to_FLEXCOMM1 = MUX_A(CM_FXCOMCLKSEL1, 0),
kFRO_HF_to_FLEXCOMM1 = MUX_A(CM_FXCOMCLKSEL1, 1),
kSYS_PLL_to_FLEXCOMM1 = MUX_A(CM_FXCOMCLKSEL1, 2),
kMCLK_to_FLEXCOMM1 = MUX_A(CM_FXCOMCLKSEL1, 3),
kFRG_to_FLEXCOMM1 = MUX_A(CM_FXCOMCLKSEL1, 4),
kNONE_to_FLEXCOMM1 = MUX_A(CM_FXCOMCLKSEL1, 7),
kFRO12M_to_FLEXCOMM2 = MUX_A(CM_FXCOMCLKSEL2, 0),
kFRO_HF_to_FLEXCOMM2 = MUX_A(CM_FXCOMCLKSEL2, 1),
kSYS_PLL_to_FLEXCOMM2 = MUX_A(CM_FXCOMCLKSEL2, 2),
kMCLK_to_FLEXCOMM2 = MUX_A(CM_FXCOMCLKSEL2, 3),
kFRG_to_FLEXCOMM2 = MUX_A(CM_FXCOMCLKSEL2, 4),
kNONE_to_FLEXCOMM2 = MUX_A(CM_FXCOMCLKSEL2, 7),
kFRO12M_to_FLEXCOMM3 = MUX_A(CM_FXCOMCLKSEL3, 0),
kFRO_HF_to_FLEXCOMM3 = MUX_A(CM_FXCOMCLKSEL3, 1),
kSYS_PLL_to_FLEXCOMM3 = MUX_A(CM_FXCOMCLKSEL3, 2),
kMCLK_to_FLEXCOMM3 = MUX_A(CM_FXCOMCLKSEL3, 3),
kFRG_to_FLEXCOMM3 = MUX_A(CM_FXCOMCLKSEL3, 4),
kNONE_to_FLEXCOMM3 = MUX_A(CM_FXCOMCLKSEL3, 7),
kFRO12M_to_FLEXCOMM4 = MUX_A(CM_FXCOMCLKSEL4, 0),
kFRO_HF_to_FLEXCOMM4 = MUX_A(CM_FXCOMCLKSEL4, 1),
kSYS_PLL_to_FLEXCOMM4 = MUX_A(CM_FXCOMCLKSEL4, 2),
kMCLK_to_FLEXCOMM4 = MUX_A(CM_FXCOMCLKSEL4, 3),
kFRG_to_FLEXCOMM4 = MUX_A(CM_FXCOMCLKSEL4, 4),
kNONE_to_FLEXCOMM4 = MUX_A(CM_FXCOMCLKSEL4, 7),
kFRO12M_to_FLEXCOMM5 = MUX_A(CM_FXCOMCLKSEL5, 0),
kFRO_HF_to_FLEXCOMM5 = MUX_A(CM_FXCOMCLKSEL5, 1),
kSYS_PLL_to_FLEXCOMM5 = MUX_A(CM_FXCOMCLKSEL5, 2),
kMCLK_to_FLEXCOMM5 = MUX_A(CM_FXCOMCLKSEL5, 3),
kFRG_to_FLEXCOMM5 = MUX_A(CM_FXCOMCLKSEL5, 4),
kNONE_to_FLEXCOMM5 = MUX_A(CM_FXCOMCLKSEL5, 7),
kFRO12M_to_FLEXCOMM6 = MUX_A(CM_FXCOMCLKSEL6, 0),
kFRO_HF_to_FLEXCOMM6 = MUX_A(CM_FXCOMCLKSEL6, 1),
kSYS_PLL_to_FLEXCOMM6 = MUX_A(CM_FXCOMCLKSEL6, 2),
kMCLK_to_FLEXCOMM6 = MUX_A(CM_FXCOMCLKSEL6, 3),
kFRG_to_FLEXCOMM6 = MUX_A(CM_FXCOMCLKSEL6, 4),
kNONE_to_FLEXCOMM6 = MUX_A(CM_FXCOMCLKSEL6, 7),
kFRO12M_to_FLEXCOMM7 = MUX_A(CM_FXCOMCLKSEL7, 0),
kFRO_HF_to_FLEXCOMM7 = MUX_A(CM_FXCOMCLKSEL7, 1),
kSYS_PLL_to_FLEXCOMM7 = MUX_A(CM_FXCOMCLKSEL7, 2),
kMCLK_to_FLEXCOMM7 = MUX_A(CM_FXCOMCLKSEL7, 3),
kFRG_to_FLEXCOMM7 = MUX_A(CM_FXCOMCLKSEL7, 4),
kNONE_to_FLEXCOMM7 = MUX_A(CM_FXCOMCLKSEL7, 7),
kMAIN_CLK_to_FRG = MUX_A(CM_FRGCLKSEL, 0),
kSYS_PLL_to_FRG = MUX_A(CM_FRGCLKSEL, 1),
kFRO12M_to_FRG = MUX_A(CM_FRGCLKSEL, 2),
kFRO_HF_to_FRG = MUX_A(CM_FRGCLKSEL, 3),
kNONE_to_FRG = MUX_A(CM_FRGCLKSEL, 7),
kFRO_HF_to_MCLK = MUX_A(CM_FXI2S0MCLKCLKSEL, 0),
kSYS_PLL_to_MCLK = MUX_A(CM_FXI2S0MCLKCLKSEL, 1),
kMAIN_CLK_to_MCLK = MUX_A(CM_FXI2S0MCLKCLKSEL, 2),
kNONE_to_MCLK = MUX_A(CM_FXI2S0MCLKCLKSEL, 7),
kFRO12M_to_DMIC = MUX_A(CM_DMICCLKSEL, 0),
kFRO_HF_to_DMIC = MUX_A(CM_DMICCLKSEL, 1),
kSYS_PLL_to_DMIC = MUX_A(CM_DMICCLKSEL, 2),
kMCLK_to_DMIC = MUX_A(CM_DMICCLKSEL, 3),
kMAIN_CLK_to_DMIC = MUX_A(CM_DMICCLKSEL, 4),
kWDT_CLK_to_DMIC = MUX_A(CM_DMICCLKSEL, 5),
kNONE_to_DMIC = MUX_A(CM_DMICCLKSEL, 7),
kFRO_HF_to_USB_CLK = MUX_A(CM_USBCLKSEL, 0),
kSYS_PLL_to_USB_CLK = MUX_A(CM_USBCLKSEL, 1),
kMAIN_CLK_to_USB_CLK = MUX_A(CM_USBCLKSEL, 2),
kNONE_to_USB_CLK = MUX_A(CM_USBCLKSEL, 7),
kMAIN_CLK_to_CLKOUT = MUX_A(CM_CLKOUTCLKSELA, 0),
kEXT_CLK_to_CLKOUT = MUX_A(CM_CLKOUTCLKSELA, 1),
kWDT_OSC_to_CLKOUT = MUX_A(CM_CLKOUTCLKSELA, 2),
kFRO_HF_to_CLKOUT = MUX_A(CM_CLKOUTCLKSELA, 3),
kSYS_PLL_to_CLKOUT = MUX_A(CM_CLKOUTCLKSELA, 4),
kFRO12M_to_CLKOUT = MUX_A(CM_CLKOUTCLKSELA, 5),
kOSC32K_to_CLKOUT = MUX_A(CM_CLKOUTCLKSELA, 6),
kNONE_to_CLKOUT = MUX_A(CM_CLKOUTCLKSELA, 7),
kNONE_to_NONE = (int)0x80000000U,
} clock_attach_id_t;
/* Clock dividers */
typedef enum _clock_div_name
{
kCLOCK_DivSystickClk = 0,
kCLOCK_DivTraceClk = 1,
kCLOCK_DivAhbClk = 32,
kCLOCK_DivClkOut = 33,
kCLOCK_DivSpifiClk = 36,
kCLOCK_DivAdcAsyncClk = 37,
kCLOCK_DivUsbClk = 38,
kCLOCK_DivFrg = 40,
kCLOCK_DivDmicClk = 42,
kCLOCK_DivFxI2s0MClk = 43
} clock_div_name_t;
/*******************************************************************************
* API
******************************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif /* __cplusplus */
static inline void CLOCK_EnableClock(clock_ip_name_t clk)
{
uint32_t index = CLK_GATE_ABSTRACT_REG_OFFSET(clk);
if (index < 2UL)
{
SYSCON->AHBCLKCTRLSET[index] = (1UL << CLK_GATE_ABSTRACT_BITS_SHIFT(clk));
}
else
{
ASYNC_SYSCON->ASYNCAPBCLKCTRLSET = (1UL << CLK_GATE_ABSTRACT_BITS_SHIFT(clk));
}
}
static inline void CLOCK_DisableClock(clock_ip_name_t clk)
{
uint32_t index = CLK_GATE_ABSTRACT_REG_OFFSET(clk);
if (index < 2UL)
{
SYSCON->AHBCLKCTRLCLR[index] = (1UL << CLK_GATE_ABSTRACT_BITS_SHIFT(clk));
}
else
{
ASYNC_SYSCON->ASYNCAPBCLKCTRLCLR = (1UL << CLK_GATE_ABSTRACT_BITS_SHIFT(clk));
}
}
/**
* @brief FLASH Access time definitions
*/
typedef enum _clock_flashtim
{
kCLOCK_Flash1Cycle = 0, /*!< Flash accesses use 1 CPU clock */
kCLOCK_Flash2Cycle, /*!< Flash accesses use 2 CPU clocks */
kCLOCK_Flash3Cycle, /*!< Flash accesses use 3 CPU clocks */
kCLOCK_Flash4Cycle, /*!< Flash accesses use 4 CPU clocks */
kCLOCK_Flash5Cycle, /*!< Flash accesses use 5 CPU clocks */
kCLOCK_Flash6Cycle, /*!< Flash accesses use 6 CPU clocks */
kCLOCK_Flash7Cycle, /*!< Flash accesses use 7 CPU clocks */
} clock_flashtim_t;
/**
* @brief Set FLASH memory access time in clocks
* @param clks : Clock cycles for FLASH access
* @return Nothing
*/
static inline void CLOCK_SetFLASHAccessCycles(clock_flashtim_t clks)
{
uint32_t tmp;
tmp = SYSCON->FLASHCFG & ~(SYSCON_FLASHCFG_FLASHTIM_MASK);
/* Don't alter lower bits */
SYSCON->FLASHCFG = tmp | ((uint32_t)clks << SYSCON_FLASHCFG_FLASHTIM_SHIFT);
}
/**
* @brief Initialize the Core clock to given frequency (12, 48 or 96 MHz).
* Turns on FRO and uses default CCO, if freq is 12000000, then high speed output is off, else high speed output is
* enabled.
* @param iFreq : Desired frequency (must be one of CLK_FRO_12MHZ or CLK_FRO_48MHZ or CLK_FRO_96MHZ)
* @return returns success or fail status.
*/
status_t CLOCK_SetupFROClocking(uint32_t iFreq);
/**
* @brief Configure the clock selection muxes.
* @param connection : Clock to be configured.
* @return Nothing
*/
void CLOCK_AttachClk(clock_attach_id_t connection);
/**
* @brief Get the actual clock attach id.
* This fuction uses the offset in input attach id, then it reads the actual source value in
* the register and combine the offset to obtain an actual attach id.
* @param attachId : Clock attach id to get.
* @return Clock source value.
*/
clock_attach_id_t CLOCK_GetClockAttachId(clock_attach_id_t attachId);
/**
* @brief Setup peripheral clock dividers.
* @param div_name : Clock divider name
* @param divided_by_value: Value to be divided
* @param reset : Whether to reset the divider counter.
* @return Nothing
*/
void CLOCK_SetClkDiv(clock_div_name_t div_name, uint32_t divided_by_value, bool reset);
/**
* @brief Set the flash wait states for the input freuqency.
* @param iFreq : Input frequency
* @return Nothing
*/
void CLOCK_SetFLASHAccessCyclesForFreq(uint32_t iFreq);
/*! @brief Return Frequency of selected clock
* @return Frequency of selected clock
*/
uint32_t CLOCK_GetFreq(clock_name_t clockName);
/*! @brief Return Input frequency for the Fractional baud rate generator
* @return Input Frequency for FRG
*/
uint32_t CLOCK_GetFRGInputClock(void);
/*! @brief Return Input frequency for the DMIC
* @return Input Frequency for DMIC
*/
uint32_t CLOCK_GetDmicClkFreq(void);
/*! @brief Return Input frequency for the FRG
* @return Input Frequency for FRG
*/
uint32_t CLOCK_GetFrgClkFreq(void);
/*! @brief Set output of the Fractional baud rate generator
* @param freq : Desired output frequency
* @return Error Code 0 - fail 1 - success
*/
uint32_t CLOCK_SetFRGClock(uint32_t freq);
/*! @brief Return Frequency of FRO 12MHz
* @return Frequency of FRO 12MHz
*/
uint32_t CLOCK_GetFro12MFreq(void);
/*! @brief Return Frequency of External Clock
* @return Frequency of External Clock. If no external clock is used returns 0.
*/
uint32_t CLOCK_GetExtClkFreq(void);
/*! @brief Return Frequency of Watchdog Oscillator
* @return Frequency of Watchdog Oscillator
*/
uint32_t CLOCK_GetWdtOscFreq(void);
/*! @brief Return Frequency of High-Freq output of FRO
* @return Frequency of High-Freq output of FRO
*/
uint32_t CLOCK_GetFroHfFreq(void);
/*! @brief Return Frequency of USB
* @return Frequency of USB
*/
uint32_t CLOCK_GetUsbClkFreq(void);
/*! @brief Return Frequency of PLL
* @return Frequency of PLL
*/
uint32_t CLOCK_GetPllOutFreq(void);
/*! @brief Return Frequency of 32kHz osc
* @return Frequency of 32kHz osc
*/
uint32_t CLOCK_GetOsc32KFreq(void);
/*! @brief Return Frequency of Core System
* @return Frequency of Core System
*/
uint32_t CLOCK_GetCoreSysClkFreq(void);
/*! @brief Return Frequency of I2S MCLK Clock
* @return Frequency of I2S MCLK Clock
*/
uint32_t CLOCK_GetI2SMClkFreq(void);
/*! @brief Return Frequency of Flexcomm functional Clock
* @return Frequency of Flexcomm functional Clock
*/
uint32_t CLOCK_GetFlexCommClkFreq(uint32_t id);
/*! @brief Return Frequency of Adc Clock
* @return Frequency of Adc Clock.
*/
uint32_t CLOCK_GetAdcClkFreq(void);
/*! @brief Return Asynchronous APB Clock source
* @return Asynchronous APB CLock source
*/
__STATIC_INLINE async_clock_src_t CLOCK_GetAsyncApbClkSrc(void)
{
return (async_clock_src_t)((uint32_t)(ASYNC_SYSCON->ASYNCAPBCLKSELA & 0x3UL));
}
/*! @brief Return Frequency of Asynchronous APB Clock
* @return Frequency of Asynchronous APB Clock Clock
*/
uint32_t CLOCK_GetAsyncApbClkFreq(void);
/*! @brief Return System PLL input clock rate
* @return System PLL input clock rate
*/
uint32_t CLOCK_GetSystemPLLInClockRate(void);
/*! @brief Return System PLL output clock rate
* @param recompute : Forces a PLL rate recomputation if true
* @return System PLL output clock rate
* @note The PLL rate is cached in the driver in a variable as
* the rate computation function can take some time to perform. It
* is recommended to use 'false' with the 'recompute' parameter.
*/
uint32_t CLOCK_GetSystemPLLOutClockRate(bool recompute);
/*! @brief Enables and disables PLL bypass mode
* @brief bypass : true to bypass PLL (PLL output = PLL input, false to disable bypass
* @return System PLL output clock rate
*/
__STATIC_INLINE void CLOCK_SetBypassPLL(bool bypass)
{
if (bypass)
{
SYSCON->SYSPLLCTRL |= (1UL << SYSCON_SYSPLLCTRL_BYPASS_SHIFT);
}
else
{
SYSCON->SYSPLLCTRL &= ~(1UL << SYSCON_SYSPLLCTRL_BYPASS_SHIFT);
}
}
/*! @brief Check if PLL is locked or not
* @return true if the PLL is locked, false if not locked
*/
__STATIC_INLINE bool CLOCK_IsSystemPLLLocked(void)
{
return (bool)((SYSCON->SYSPLLSTAT & SYSCON_SYSPLLSTAT_LOCK_MASK) != 0UL);
}
/*! @brief Store the current PLL rate
* @param rate: Current rate of the PLL
* @return Nothing
**/
void CLOCK_SetStoredPLLClockRate(uint32_t rate);
/*! @brief PLL configuration structure flags for 'flags' field
* These flags control how the PLL configuration function sets up the PLL setup structure.<br>
*
* When the PLL_CONFIGFLAG_USEINRATE flag is selected, the 'InputRate' field in the
* configuration structure must be assigned with the expected PLL frequency. If the
* PLL_CONFIGFLAG_USEINRATE is not used, 'InputRate' is ignored in the configuration
* function and the driver will determine the PLL rate from the currently selected
* PLL source. This flag might be used to configure the PLL input clock more accurately
* when using the WDT oscillator or a more dyanmic CLKIN source.<br>
*
* When the PLL_CONFIGFLAG_FORCENOFRACT flag is selected, the PLL hardware for the
* automatic bandwidth selection, Spread Spectrum (SS) support, and fractional M-divider
* are not used.<br>
*/
#define PLL_CONFIGFLAG_USEINRATE (1U << 0U) /*!< Flag to use InputRate in PLL configuration structure for setup */
#define PLL_CONFIGFLAG_FORCENOFRACT \
(1U << 2U) /*!< Force non-fractional output mode, PLL output will not use the fractional, automatic bandwidth, or \
SS hardware */
/*! @brief PLL Spread Spectrum (SS) Programmable modulation frequency
* See (MF) field in the SYSPLLSSCTRL1 register in the UM.
*/
typedef enum _ss_progmodfm
{
kSS_MF_512 = (0 << 20), /*!< Nss = 512 (fm ? 3.9 - 7.8 kHz) */
kSS_MF_384 = (1 << 20), /*!< Nss ?= 384 (fm ? 5.2 - 10.4 kHz) */
kSS_MF_256 = (2 << 20), /*!< Nss = 256 (fm ? 7.8 - 15.6 kHz) */
kSS_MF_128 = (3 << 20), /*!< Nss = 128 (fm ? 15.6 - 31.3 kHz) */
kSS_MF_64 = (4 << 20), /*!< Nss = 64 (fm ? 32.3 - 64.5 kHz) */
kSS_MF_32 = (5 << 20), /*!< Nss = 32 (fm ? 62.5- 125 kHz) */
kSS_MF_24 = (6 << 20), /*!< Nss ?= 24 (fm ? 83.3- 166.6 kHz) */
kSS_MF_16 = (7 << 20) /*!< Nss = 16 (fm ? 125- 250 kHz) */
} ss_progmodfm_t;
/*! @brief PLL Spread Spectrum (SS) Programmable frequency modulation depth
* See (MR) field in the SYSPLLSSCTRL1 register in the UM.
*/
typedef enum _ss_progmoddp
{
kSS_MR_K0 = (0 << 23), /*!< k = 0 (no spread spectrum) */
kSS_MR_K1 = (1 << 23), /*!< k = 1 */
kSS_MR_K1_5 = (2 << 23), /*!< k = 1.5 */
kSS_MR_K2 = (3 << 23), /*!< k = 2 */
kSS_MR_K3 = (4 << 23), /*!< k = 3 */
kSS_MR_K4 = (5 << 23), /*!< k = 4 */
kSS_MR_K6 = (6 << 23), /*!< k = 6 */
kSS_MR_K8 = (7 << 23) /*!< k = 8 */
} ss_progmoddp_t;
/*! @brief PLL Spread Spectrum (SS) Modulation waveform control
* See (MC) field in the SYSPLLSSCTRL1 register in the UM.<br>
* Compensation for low pass filtering of the PLL to get a triangular
* modulation at the output of the PLL, giving a flat frequency spectrum.
*/
typedef enum _ss_modwvctrl
{
kSS_MC_NOC = (0 << 26), /*!< no compensation */
kSS_MC_RECC = (2 << 26), /*!< recommended setting */
kSS_MC_MAXC = (3 << 26), /*!< max. compensation */
} ss_modwvctrl_t;
/*! @brief PLL configuration structure
*
* This structure can be used to configure the settings for a PLL
* setup structure. Fill in the desired configuration for the PLL
* and call the PLL setup function to fill in a PLL setup structure.
*/
typedef struct _pll_config
{
uint32_t desiredRate; /*!< Desired PLL rate in Hz */
uint32_t inputRate; /*!< PLL input clock in Hz, only used if PLL_CONFIGFLAG_USEINRATE flag is set */
uint32_t flags; /*!< PLL configuration flags, Or'ed value of PLL_CONFIGFLAG_* definitions */
ss_progmodfm_t ss_mf; /*!< SS Programmable modulation frequency, only applicable when not using
PLL_CONFIGFLAG_FORCENOFRACT flag */
ss_progmoddp_t ss_mr; /*!< SS Programmable frequency modulation depth, only applicable when not using
PLL_CONFIGFLAG_FORCENOFRACT flag */
ss_modwvctrl_t
ss_mc; /*!< SS Modulation waveform control, only applicable when not using PLL_CONFIGFLAG_FORCENOFRACT flag */
bool mfDither; /*!< false for fixed modulation frequency or true for dithering, only applicable when not using
PLL_CONFIGFLAG_FORCENOFRACT flag */
} pll_config_t;
/*! @brief PLL setup structure flags for 'flags' field
* These flags control how the PLL setup function sets up the PLL
*/
#define PLL_SETUPFLAG_POWERUP (1U << 0U) /*!< Setup will power on the PLL after setup */
#define PLL_SETUPFLAG_WAITLOCK (1U << 1U) /*!< Setup will wait for PLL to lock, implying the PLL will be pwoered on */
#define PLL_SETUPFLAG_ADGVOLT (1U << 2U) /*!< Optimize system voltage for the new PLL rate */
#define PLL_SETUPFLAG_USEFEEDBACKDIV2 (1U << 3U) /*!< Use feedback divider by 2 in divider path */
/*! @brief PLL setup structure
* This structure can be used to pre-build a PLL setup configuration
* at run-time and quickly set the PLL to the configuration. It can be
* populated with the PLL setup function. If powering up or waiting
* for PLL lock, the PLL input clock source should be configured prior
* to PLL setup.
*/
typedef struct _pll_setup
{
uint32_t syspllctrl; /*!< PLL control register SYSPLLCTRL */
uint32_t syspllndec; /*!< PLL NDEC register SYSPLLNDEC */
uint32_t syspllpdec; /*!< PLL PDEC register SYSPLLPDEC */
uint32_t syspllssctrl[2]; /*!< PLL SSCTL registers SYSPLLSSCTRL */
uint32_t pllRate; /*!< Acutal PLL rate */
uint32_t flags; /*!< PLL setup flags, Or'ed value of PLL_SETUPFLAG_* definitions */
} pll_setup_t;
/*! @brief PLL status definitions
*/
typedef enum _pll_error
{
kStatus_PLL_Success = MAKE_STATUS(kStatusGroup_Generic, 0), /*!< PLL operation was successful */
kStatus_PLL_OutputTooLow = MAKE_STATUS(kStatusGroup_Generic, 1), /*!< PLL output rate request was too low */
kStatus_PLL_OutputTooHigh = MAKE_STATUS(kStatusGroup_Generic, 2), /*!< PLL output rate request was too high */
kStatus_PLL_InputTooLow = MAKE_STATUS(kStatusGroup_Generic, 3), /*!< PLL input rate is too low */
kStatus_PLL_InputTooHigh = MAKE_STATUS(kStatusGroup_Generic, 4), /*!< PLL input rate is too high */
kStatus_PLL_OutsideIntLimit = MAKE_STATUS(kStatusGroup_Generic, 5) /*!< Requested output rate isn't possible */
} pll_error_t;
/*! @brief USB clock source definition. */
typedef enum _clock_usb_src
{
kCLOCK_UsbSrcFro = (uint32_t)kCLOCK_FroHf, /*!< Use FRO 96 or 48 MHz. */
kCLOCK_UsbSrcSystemPll = (uint32_t)kCLOCK_PllOut, /*!< Use System PLL output. */
kCLOCK_UsbSrcMainClock = (uint32_t)kCLOCK_CoreSysClk, /*!< Use Main clock. */
kCLOCK_UsbSrcNone = SYSCON_USBCLKSEL_SEL(
7) /*!< Use None, this may be selected in order to reduce power when no output is needed. */
} clock_usb_src_t;
/*! @brief Return System PLL output clock rate from setup structure
* @param pSetup : Pointer to a PLL setup structure
* @return System PLL output clock rate calculated from the setup structure
*/
uint32_t CLOCK_GetSystemPLLOutFromSetup(pll_setup_t *pSetup);
/*! @brief Set PLL output based on the passed PLL setup data
* @param pControl : Pointer to populated PLL control structure to generate setup with
* @param pSetup : Pointer to PLL setup structure to be filled
* @return PLL_ERROR_SUCCESS on success, or PLL setup error code
* @note Actual frequency for setup may vary from the desired frequency based on the
* accuracy of input clocks, rounding, non-fractional PLL mode, etc.
*/
pll_error_t CLOCK_SetupPLLData(pll_config_t *pControl, pll_setup_t *pSetup);
/*! @brief Set PLL output from PLL setup structure (precise frequency)
* @param pSetup : Pointer to populated PLL setup structure
* @param flagcfg : Flag configuration for PLL config structure
* @return PLL_ERROR_SUCCESS on success, or PLL setup error code
* @note This function will power off the PLL, setup the PLL with the
* new setup data, and then optionally powerup the PLL, wait for PLL lock,
* and adjust system voltages to the new PLL rate. The function will not
* alter any source clocks (ie, main systen clock) that may use the PLL,
* so these should be setup prior to and after exiting the function.
*/
pll_error_t CLOCK_SetupSystemPLLPrec(pll_setup_t *pSetup, uint32_t flagcfg);
/**
* @brief Set PLL output from PLL setup structure (precise frequency)
* @param pSetup : Pointer to populated PLL setup structure
* @return kStatus_PLL_Success on success, or PLL setup error code
* @note This function will power off the PLL, setup the PLL with the
* new setup data, and then optionally powerup the PLL, wait for PLL lock,
* and adjust system voltages to the new PLL rate. The function will not
* alter any source clocks (ie, main systen clock) that may use the PLL,
* so these should be setup prior to and after exiting the function.
*/
pll_error_t CLOCK_SetPLLFreq(const pll_setup_t *pSetup);
/*! @brief Set PLL output based on the multiplier and input frequency
* @param multiply_by : multiplier
* @param input_freq : Clock input frequency of the PLL
* @return Nothing
* @note Unlike the Chip_Clock_SetupSystemPLLPrec() function, this
* function does not disable or enable PLL power, wait for PLL lock,
* or adjust system voltages. These must be done in the application.
* The function will not alter any source clocks (ie, main systen clock)
* that may use the PLL, so these should be setup prior to and after
* exiting the function.
*/
void CLOCK_SetupSystemPLLMult(uint32_t multiply_by, uint32_t input_freq);
/*! @brief Disable USB FS clock.
*
* Disable USB FS clock.
*/
static inline void CLOCK_DisableUsbfs0Clock(void)
{
CLOCK_DisableClock(kCLOCK_Usbd0);
}
bool CLOCK_EnableUsbfs0Clock(clock_usb_src_t src, uint32_t freq);
#if defined(__cplusplus)
}
#endif /* __cplusplus */
/*! @} */
#endif /* _FSL_CLOCK_H_ */

311
drivers/fsl_common.c Normal file
View File

@@ -0,0 +1,311 @@
/*
* Copyright (c) 2015-2016, Freescale Semiconductor, Inc.
* Copyright 2016-2020 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "fsl_common.h"
#define SDK_MEM_MAGIC_NUMBER 12345U
typedef struct _mem_align_control_block
{
uint16_t identifier; /*!< Identifier for the memory control block. */
uint16_t offset; /*!< offset from aligned address to real address */
} mem_align_cb_t;
/* Component ID definition, used by tools. */
#ifndef FSL_COMPONENT_ID
#define FSL_COMPONENT_ID "platform.drivers.common"
#endif
#ifndef __GIC_PRIO_BITS
#if defined(ENABLE_RAM_VECTOR_TABLE)
uint32_t InstallIRQHandler(IRQn_Type irq, uint32_t irqHandler)
{
#ifdef __VECTOR_TABLE
#undef __VECTOR_TABLE
#endif
/* Addresses for VECTOR_TABLE and VECTOR_RAM come from the linker file */
#if defined(__CC_ARM) || defined(__ARMCC_VERSION)
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) || defined(__ARMCC_VERSION) */
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[(int32_t)irq + 16];
/* make sure the __VECTOR_RAM is noncachable */
__VECTOR_RAM[(int32_t)irq + 16] = irqHandler;
EnableGlobalIRQ(irqMaskValue);
SDK_ISR_EXIT_BARRIER;
return ret;
}
#endif /* ENABLE_RAM_VECTOR_TABLE. */
#endif /* __GIC_PRIO_BITS. */
#if (defined(FSL_FEATURE_SOC_SYSCON_COUNT) && (FSL_FEATURE_SOC_SYSCON_COUNT > 0))
/*
* When FSL_FEATURE_POWERLIB_EXTEND is defined to non-zero value,
* powerlib should be used instead of these functions.
*/
#if !(defined(FSL_FEATURE_POWERLIB_EXTEND) && (FSL_FEATURE_POWERLIB_EXTEND != 0))
/*
* When the SYSCON STARTER registers are discontinuous, these functions are
* implemented in fsl_power.c.
*/
#if !(defined(FSL_FEATURE_SYSCON_STARTER_DISCONTINUOUS) && FSL_FEATURE_SYSCON_STARTER_DISCONTINUOUS)
void EnableDeepSleepIRQ(IRQn_Type interrupt)
{
uint32_t intNumber = (uint32_t)interrupt;
uint32_t index = 0;
while (intNumber >= 32u)
{
index++;
intNumber -= 32u;
}
SYSCON->STARTERSET[index] = 1UL << intNumber;
(void)EnableIRQ(interrupt); /* also enable interrupt at NVIC */
}
void DisableDeepSleepIRQ(IRQn_Type interrupt)
{
uint32_t intNumber = (uint32_t)interrupt;
(void)DisableIRQ(interrupt); /* also disable interrupt at NVIC */
uint32_t index = 0;
while (intNumber >= 32u)
{
index++;
intNumber -= 32u;
}
SYSCON->STARTERCLR[index] = 1UL << intNumber;
}
#endif /* FSL_FEATURE_SYSCON_STARTER_DISCONTINUOUS */
#endif /* FSL_FEATURE_POWERLIB_EXTEND */
#endif /* FSL_FEATURE_SOC_SYSCON_COUNT */
void *SDK_Malloc(size_t size, size_t alignbytes)
{
mem_align_cb_t *p_cb = NULL;
uint32_t alignedsize;
/* Check overflow. */
alignedsize = SDK_SIZEALIGN(size, alignbytes);
if (alignedsize < size)
{
return NULL;
}
if (alignedsize > SIZE_MAX - alignbytes - sizeof(mem_align_cb_t))
{
return NULL;
}
alignedsize += alignbytes + sizeof(mem_align_cb_t);
union
{
void *pointer_value;
uint32_t unsigned_value;
} p_align_addr, p_addr;
p_addr.pointer_value = malloc(alignedsize);
if (p_addr.pointer_value == NULL)
{
return NULL;
}
p_align_addr.unsigned_value = SDK_SIZEALIGN(p_addr.unsigned_value + sizeof(mem_align_cb_t), alignbytes);
p_cb = (mem_align_cb_t *)(p_align_addr.unsigned_value - 4U);
p_cb->identifier = SDK_MEM_MAGIC_NUMBER;
p_cb->offset = (uint16_t)(p_align_addr.unsigned_value - p_addr.unsigned_value);
return p_align_addr.pointer_value;
}
void SDK_Free(void *ptr)
{
union
{
void *pointer_value;
uint32_t unsigned_value;
} p_free;
p_free.pointer_value = ptr;
mem_align_cb_t *p_cb = (mem_align_cb_t *)(p_free.unsigned_value - 4U);
if (p_cb->identifier != SDK_MEM_MAGIC_NUMBER)
{
return;
}
p_free.unsigned_value = p_free.unsigned_value - p_cb->offset;
free(p_free.pointer_value);
}
/*!
* @brief Delay function bases on while loop, every loop includes three instructions.
*
* @param count Counts of loop needed for dalay.
*/
#if defined(SDK_DELAY_USE_DWT) && defined(DWT)
static void enableCpuCycleCounter(void)
{
/* Make sure the DWT trace fucntion is enabled. */
if (CoreDebug_DEMCR_TRCENA_Msk != (CoreDebug_DEMCR_TRCENA_Msk & CoreDebug->DEMCR))
{
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
}
/* CYCCNT not supported on this device. */
assert(DWT_CTRL_NOCYCCNT_Msk != (DWT->CTRL & DWT_CTRL_NOCYCCNT_Msk));
/* Read CYCCNT directly if CYCCENT has already been enabled, otherwise enable CYCCENT first. */
if (DWT_CTRL_CYCCNTENA_Msk != (DWT_CTRL_CYCCNTENA_Msk & DWT->CTRL))
{
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
}
}
static uint32_t getCpuCycleCount(void)
{
return DWT->CYCCNT;
}
#elif defined __XCC__
extern uint32_t xthal_get_ccount(void);
static void enableCpuCycleCounter(void)
{
/* do nothing */
}
static uint32_t getCpuCycleCount(void)
{
return xthal_get_ccount();
}
#endif
#ifndef __XCC__
#if (!defined(SDK_DELAY_USE_DWT)) || (!defined(DWT))
#if defined(__CC_ARM) /* This macro is arm v5 specific */
/* clang-format off */
__ASM static void DelayLoop(uint32_t count)
{
loop
SUBS R0, R0, #1
CMP R0, #0
BNE loop
BX LR
}
/* clang-format on */
#elif defined(__ARMCC_VERSION) || defined(__ICCARM__) || defined(__GNUC__)
/* Cortex-M0 has a smaller instruction set, SUBS isn't supported in thumb-16 mode reported from __GNUC__ compiler,
* use SUB and CMP here for compatibility */
static void DelayLoop(uint32_t count)
{
__ASM volatile(" MOV R0, %0" : : "r"(count));
__ASM volatile(
"loop: \n"
#if defined(__GNUC__) && !defined(__ARMCC_VERSION)
" SUB R0, R0, #1 \n"
#else
" SUBS R0, R0, #1 \n"
#endif
" CMP R0, #0 \n"
" BNE loop \n");
}
#endif /* defined(__CC_ARM) */
#endif /* (!defined(SDK_DELAY_USE_DWT)) || (!defined(DWT)) */
#endif /* __XCC__ */
/*!
* @brief Delay at least for some time.
* Please note that, if not uses DWT, this API will use while loop for delay, different run-time environments have
* effect on the delay time. If precise delay is needed, please enable DWT delay. The two parmeters delayTime_us and
* coreClock_Hz have limitation. For example, in the platform with 1GHz coreClock_Hz, the delayTime_us only supports
* up to 4294967 in current code. If long time delay is needed, please implement a new delay function.
*
* @param delayTime_us Delay time in unit of microsecond.
* @param coreClock_Hz Core clock frequency with Hz.
*/
void SDK_DelayAtLeastUs(uint32_t delayTime_us, uint32_t coreClock_Hz)
{
assert(0U != delayTime_us);
uint64_t count = USEC_TO_COUNT(delayTime_us, coreClock_Hz);
assert(count <= UINT32_MAX);
#if defined(SDK_DELAY_USE_DWT) && defined(DWT) || (defined __XCC__) /* Use DWT for better accuracy */
enableCpuCycleCounter();
/* Calculate the count ticks. */
count += getCpuCycleCount();
if (count > UINT32_MAX)
{
count -= UINT32_MAX;
/* Wait for cyccnt overflow. */
while (count < getCpuCycleCount())
{
}
}
/* Wait for cyccnt reach count value. */
while (count > getCpuCycleCount())
{
}
#else
/* Divide value may be different in various environment to ensure delay is precise.
* Every loop count includes three instructions, due to Cortex-M7 sometimes executes
* two instructions in one period, through test here set divide 1.5. Other M cores use
* divide 4. By the way, divide 1.5 or 4 could let the count lose precision, but it does
* not matter because other instructions outside while loop is enough to fill the time.
*/
#if (__CORTEX_M == 7)
count = count / 3U * 2U;
#else
count = count / 4U;
#endif
DelayLoop((uint32_t)count);
#endif /* defined(SDK_DELAY_USE_DWT) && defined(DWT) || (defined __XCC__) */
}

954
drivers/fsl_common.h Normal file
View File

@@ -0,0 +1,954 @@
/*
* Copyright (c) 2015-2016, Freescale Semiconductor, Inc.
* Copyright 2016-2020 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _FSL_COMMON_H_
#define _FSL_COMMON_H_
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#if defined(__ICCARM__) || (defined(__CC_ARM) || defined(__ARMCC_VERSION)) || defined(__GNUC__)
#include <stddef.h>
#endif
/*
* For CMSIS pack RTE.
* CMSIS pack RTE generates "RTC_Components.h" which contains the statements
* of the related <RTE_Components_h> element for all selected software components.
*/
#ifdef _RTE_
#include "RTE_Components.h"
#endif
#include "fsl_device_registers.h"
/*!
* @addtogroup ksdk_common
* @{
*/
/*******************************************************************************
* Definitions
******************************************************************************/
/*! @brief Construct a status code value from a group and code number. */
#define MAKE_STATUS(group, code) ((((group)*100) + (code)))
/*! @brief Construct the version number for drivers. */
#define MAKE_VERSION(major, minor, bugfix) (((major) << 16) | ((minor) << 8) | (bugfix))
/*! @name Driver version */
/*@{*/
/*! @brief common driver version. */
#define FSL_COMMON_DRIVER_VERSION (MAKE_VERSION(2, 2, 9))
/*@}*/
/* Debug console type definition. */
#define DEBUG_CONSOLE_DEVICE_TYPE_NONE 0U /*!< No debug console. */
#define DEBUG_CONSOLE_DEVICE_TYPE_UART 1U /*!< Debug console based on UART. */
#define DEBUG_CONSOLE_DEVICE_TYPE_LPUART 2U /*!< Debug console based on LPUART. */
#define DEBUG_CONSOLE_DEVICE_TYPE_LPSCI 3U /*!< Debug console based on LPSCI. */
#define DEBUG_CONSOLE_DEVICE_TYPE_USBCDC 4U /*!< Debug console based on USBCDC. */
#define DEBUG_CONSOLE_DEVICE_TYPE_FLEXCOMM 5U /*!< Debug console based on FLEXCOMM. */
#define DEBUG_CONSOLE_DEVICE_TYPE_IUART 6U /*!< Debug console based on i.MX UART. */
#define DEBUG_CONSOLE_DEVICE_TYPE_VUSART 7U /*!< Debug console based on LPC_VUSART. */
#define DEBUG_CONSOLE_DEVICE_TYPE_MINI_USART 8U /*!< Debug console based on LPC_USART. */
#define DEBUG_CONSOLE_DEVICE_TYPE_SWO 9U /*!< Debug console based on SWO. */
/*! @brief Status group numbers. */
enum _status_groups
{
kStatusGroup_Generic = 0, /*!< Group number for generic status codes. */
kStatusGroup_FLASH = 1, /*!< Group number for FLASH status codes. */
kStatusGroup_LPSPI = 4, /*!< Group number for LPSPI status codes. */
kStatusGroup_FLEXIO_SPI = 5, /*!< Group number for FLEXIO SPI status codes. */
kStatusGroup_DSPI = 6, /*!< Group number for DSPI status codes. */
kStatusGroup_FLEXIO_UART = 7, /*!< Group number for FLEXIO UART status codes. */
kStatusGroup_FLEXIO_I2C = 8, /*!< Group number for FLEXIO I2C status codes. */
kStatusGroup_LPI2C = 9, /*!< Group number for LPI2C status codes. */
kStatusGroup_UART = 10, /*!< Group number for UART status codes. */
kStatusGroup_I2C = 11, /*!< Group number for UART status codes. */
kStatusGroup_LPSCI = 12, /*!< Group number for LPSCI status codes. */
kStatusGroup_LPUART = 13, /*!< Group number for LPUART status codes. */
kStatusGroup_SPI = 14, /*!< Group number for SPI status code.*/
kStatusGroup_XRDC = 15, /*!< Group number for XRDC status code.*/
kStatusGroup_SEMA42 = 16, /*!< Group number for SEMA42 status code.*/
kStatusGroup_SDHC = 17, /*!< Group number for SDHC status code */
kStatusGroup_SDMMC = 18, /*!< Group number for SDMMC status code */
kStatusGroup_SAI = 19, /*!< Group number for SAI status code */
kStatusGroup_MCG = 20, /*!< Group number for MCG status codes. */
kStatusGroup_SCG = 21, /*!< Group number for SCG status codes. */
kStatusGroup_SDSPI = 22, /*!< Group number for SDSPI status codes. */
kStatusGroup_FLEXIO_I2S = 23, /*!< Group number for FLEXIO I2S status codes */
kStatusGroup_FLEXIO_MCULCD = 24, /*!< Group number for FLEXIO LCD status codes */
kStatusGroup_FLASHIAP = 25, /*!< Group number for FLASHIAP status codes */
kStatusGroup_FLEXCOMM_I2C = 26, /*!< Group number for FLEXCOMM I2C status codes */
kStatusGroup_I2S = 27, /*!< Group number for I2S status codes */
kStatusGroup_IUART = 28, /*!< Group number for IUART status codes */
kStatusGroup_CSI = 29, /*!< Group number for CSI status codes */
kStatusGroup_MIPI_DSI = 30, /*!< Group number for MIPI DSI status codes */
kStatusGroup_SDRAMC = 35, /*!< Group number for SDRAMC status codes. */
kStatusGroup_POWER = 39, /*!< Group number for POWER status codes. */
kStatusGroup_ENET = 40, /*!< Group number for ENET status codes. */
kStatusGroup_PHY = 41, /*!< Group number for PHY status codes. */
kStatusGroup_TRGMUX = 42, /*!< Group number for TRGMUX status codes. */
kStatusGroup_SMARTCARD = 43, /*!< Group number for SMARTCARD status codes. */
kStatusGroup_LMEM = 44, /*!< Group number for LMEM status codes. */
kStatusGroup_QSPI = 45, /*!< Group number for QSPI status codes. */
kStatusGroup_DMA = 50, /*!< Group number for DMA status codes. */
kStatusGroup_EDMA = 51, /*!< Group number for EDMA status codes. */
kStatusGroup_DMAMGR = 52, /*!< Group number for DMAMGR status codes. */
kStatusGroup_FLEXCAN = 53, /*!< Group number for FlexCAN status codes. */
kStatusGroup_LTC = 54, /*!< Group number for LTC status codes. */
kStatusGroup_FLEXIO_CAMERA = 55, /*!< Group number for FLEXIO CAMERA status codes. */
kStatusGroup_LPC_SPI = 56, /*!< Group number for LPC_SPI status codes. */
kStatusGroup_LPC_USART = 57, /*!< Group number for LPC_USART status codes. */
kStatusGroup_DMIC = 58, /*!< Group number for DMIC status codes. */
kStatusGroup_SDIF = 59, /*!< Group number for SDIF status codes.*/
kStatusGroup_SPIFI = 60, /*!< Group number for SPIFI status codes. */
kStatusGroup_OTP = 61, /*!< Group number for OTP status codes. */
kStatusGroup_MCAN = 62, /*!< Group number for MCAN status codes. */
kStatusGroup_CAAM = 63, /*!< Group number for CAAM status codes. */
kStatusGroup_ECSPI = 64, /*!< Group number for ECSPI status codes. */
kStatusGroup_USDHC = 65, /*!< Group number for USDHC status codes.*/
kStatusGroup_LPC_I2C = 66, /*!< Group number for LPC_I2C status codes.*/
kStatusGroup_DCP = 67, /*!< Group number for DCP status codes.*/
kStatusGroup_MSCAN = 68, /*!< Group number for MSCAN status codes.*/
kStatusGroup_ESAI = 69, /*!< Group number for ESAI status codes. */
kStatusGroup_FLEXSPI = 70, /*!< Group number for FLEXSPI status codes. */
kStatusGroup_MMDC = 71, /*!< Group number for MMDC status codes. */
kStatusGroup_PDM = 72, /*!< Group number for MIC status codes. */
kStatusGroup_SDMA = 73, /*!< Group number for SDMA status codes. */
kStatusGroup_ICS = 74, /*!< Group number for ICS status codes. */
kStatusGroup_SPDIF = 75, /*!< Group number for SPDIF status codes. */
kStatusGroup_LPC_MINISPI = 76, /*!< Group number for LPC_MINISPI status codes. */
kStatusGroup_HASHCRYPT = 77, /*!< Group number for Hashcrypt status codes */
kStatusGroup_LPC_SPI_SSP = 78, /*!< Group number for LPC_SPI_SSP status codes. */
kStatusGroup_I3C = 79, /*!< Group number for I3C status codes */
kStatusGroup_LPC_I2C_1 = 97, /*!< Group number for LPC_I2C_1 status codes. */
kStatusGroup_NOTIFIER = 98, /*!< Group number for NOTIFIER status codes. */
kStatusGroup_DebugConsole = 99, /*!< Group number for debug console status codes. */
kStatusGroup_SEMC = 100, /*!< Group number for SEMC status codes. */
kStatusGroup_ApplicationRangeStart = 101, /*!< Starting number for application groups. */
kStatusGroup_IAP = 102, /*!< Group number for IAP status codes */
kStatusGroup_SFA = 103, /*!< Group number for SFA status codes*/
kStatusGroup_SPC = 104, /*!< Group number for SPC status codes. */
kStatusGroup_PUF = 105, /*!< Group number for PUF status codes. */
kStatusGroup_TOUCH_PANEL = 106, /*!< Group number for touch panel status codes */
kStatusGroup_HAL_GPIO = 121, /*!< Group number for HAL GPIO status codes. */
kStatusGroup_HAL_UART = 122, /*!< Group number for HAL UART status codes. */
kStatusGroup_HAL_TIMER = 123, /*!< Group number for HAL TIMER status codes. */
kStatusGroup_HAL_SPI = 124, /*!< Group number for HAL SPI status codes. */
kStatusGroup_HAL_I2C = 125, /*!< Group number for HAL I2C status codes. */
kStatusGroup_HAL_FLASH = 126, /*!< Group number for HAL FLASH status codes. */
kStatusGroup_HAL_PWM = 127, /*!< Group number for HAL PWM status codes. */
kStatusGroup_HAL_RNG = 128, /*!< Group number for HAL RNG status codes. */
kStatusGroup_TIMERMANAGER = 135, /*!< Group number for TiMER MANAGER status codes. */
kStatusGroup_SERIALMANAGER = 136, /*!< Group number for SERIAL MANAGER status codes. */
kStatusGroup_LED = 137, /*!< Group number for LED status codes. */
kStatusGroup_BUTTON = 138, /*!< Group number for BUTTON status codes. */
kStatusGroup_EXTERN_EEPROM = 139, /*!< Group number for EXTERN EEPROM status codes. */
kStatusGroup_SHELL = 140, /*!< Group number for SHELL status codes. */
kStatusGroup_MEM_MANAGER = 141, /*!< Group number for MEM MANAGER status codes. */
kStatusGroup_LIST = 142, /*!< Group number for List status codes. */
kStatusGroup_OSA = 143, /*!< Group number for OSA status codes. */
kStatusGroup_COMMON_TASK = 144, /*!< Group number for Common task status codes. */
kStatusGroup_MSG = 145, /*!< Group number for messaging status codes. */
kStatusGroup_SDK_OCOTP = 146, /*!< Group number for OCOTP status codes. */
kStatusGroup_SDK_FLEXSPINOR = 147, /*!< Group number for FLEXSPINOR status codes.*/
kStatusGroup_CODEC = 148, /*!< Group number for codec status codes. */
kStatusGroup_ASRC = 149, /*!< Group number for codec status ASRC. */
kStatusGroup_OTFAD = 150, /*!< Group number for codec status codes. */
kStatusGroup_SDIOSLV = 151, /*!< Group number for SDIOSLV status codes. */
kStatusGroup_MECC = 152, /*!< Group number for MECC status codes. */
kStatusGroup_ENET_QOS = 153, /*!< Group number for ENET_QOS status codes. */
kStatusGroup_LOG = 154, /*!< Group number for LOG status codes. */
};
/*! \public
* @brief Generic status return codes.
*/
enum
{
kStatus_Success = MAKE_STATUS(kStatusGroup_Generic, 0), /*!< Generic status for Success. */
kStatus_Fail = MAKE_STATUS(kStatusGroup_Generic, 1), /*!< Generic status for Fail. */
kStatus_ReadOnly = MAKE_STATUS(kStatusGroup_Generic, 2), /*!< Generic status for read only failure. */
kStatus_OutOfRange = MAKE_STATUS(kStatusGroup_Generic, 3), /*!< Generic status for out of range access. */
kStatus_InvalidArgument = MAKE_STATUS(kStatusGroup_Generic, 4), /*!< Generic status for invalid argument check. */
kStatus_Timeout = MAKE_STATUS(kStatusGroup_Generic, 5), /*!< Generic status for timeout. */
kStatus_NoTransferInProgress = MAKE_STATUS(kStatusGroup_Generic, 6), /*!< Generic status for no transfer in progress. */
};
/*! @brief Type used for all status and error return values. */
typedef int32_t status_t;
/*
* Macro guard for whether to use default weak IRQ implementation in drivers
*/
#ifndef FSL_DRIVER_TRANSFER_DOUBLE_WEAK_IRQ
#define FSL_DRIVER_TRANSFER_DOUBLE_WEAK_IRQ 1
#endif
/*! @name Min/max macros */
/* @{ */
#if !defined(MIN)
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif
#if !defined(MAX)
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#endif
/* @} */
/*! @brief Computes the number of elements in an array. */
#if !defined(ARRAY_SIZE)
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#endif
/*! @name UINT16_MAX/UINT32_MAX value */
/* @{ */
#if !defined(UINT16_MAX)
#define UINT16_MAX ((uint16_t)-1)
#endif
#if !defined(UINT32_MAX)
#define UINT32_MAX ((uint32_t)-1)
#endif
/* @} */
/*! @name Timer utilities */
/* @{ */
/*! Macro to convert a microsecond period to raw count value */
#define USEC_TO_COUNT(us, clockFreqInHz) (uint64_t)(((uint64_t)(us) * (clockFreqInHz)) / 1000000U)
/*! Macro to convert a raw count value to microsecond */
#define COUNT_TO_USEC(count, clockFreqInHz) (uint64_t)((uint64_t)(count) * 1000000U / (clockFreqInHz))
/*! Macro to convert a millisecond period to raw count value */
#define MSEC_TO_COUNT(ms, clockFreqInHz) (uint64_t)((uint64_t)(ms) * (clockFreqInHz) / 1000U)
/*! Macro to convert a raw count value to millisecond */
#define COUNT_TO_MSEC(count, clockFreqInHz) (uint64_t)((uint64_t)(count) * 1000U / (clockFreqInHz))
/* @} */
/*! @name ISR exit barrier
* @{
*
* ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping
* exception return operation might vector to incorrect interrupt.
* For Cortex-M7, if core speed much faster than peripheral register write speed,
* the peripheral interrupt flags may be still set after exiting ISR, this results to
* the same error similar with errata 83869.
*/
#if (defined __CORTEX_M) && ((__CORTEX_M == 4U) || (__CORTEX_M == 7U))
#define SDK_ISR_EXIT_BARRIER __DSB()
#else
#define SDK_ISR_EXIT_BARRIER
#endif
/* @} */
/*! @name Alignment variable definition macros */
/* @{ */
#if (defined(__ICCARM__))
/**
* Workaround to disable MISRA C message suppress warnings for IAR compiler.
* http:/ /supp.iar.com/Support/?note=24725
*/
_Pragma("diag_suppress=Pm120")
#define SDK_PRAGMA(x) _Pragma(#x)
_Pragma("diag_error=Pm120")
/*! Macro to define a variable with alignbytes alignment */
#define SDK_ALIGN(var, alignbytes) SDK_PRAGMA(data_alignment = alignbytes) var
/*! Macro to define a variable with L1 d-cache line size alignment */
#if defined(FSL_FEATURE_L1DCACHE_LINESIZE_BYTE)
#define SDK_L1DCACHE_ALIGN(var) SDK_PRAGMA(data_alignment = FSL_FEATURE_L1DCACHE_LINESIZE_BYTE) var
#endif
/*! Macro to define a variable with L2 cache line size alignment */
#if defined(FSL_FEATURE_L2CACHE_LINESIZE_BYTE)
#define SDK_L2CACHE_ALIGN(var) SDK_PRAGMA(data_alignment = FSL_FEATURE_L2CACHE_LINESIZE_BYTE) var
#endif
#elif defined(__CC_ARM) || defined(__ARMCC_VERSION)
/*! Macro to define a variable with alignbytes alignment */
#define SDK_ALIGN(var, alignbytes) __attribute__((aligned(alignbytes))) var
/*! Macro to define a variable with L1 d-cache line size alignment */
#if defined(FSL_FEATURE_L1DCACHE_LINESIZE_BYTE)
#define SDK_L1DCACHE_ALIGN(var) __attribute__((aligned(FSL_FEATURE_L1DCACHE_LINESIZE_BYTE))) var
#endif
/*! Macro to define a variable with L2 cache line size alignment */
#if defined(FSL_FEATURE_L2CACHE_LINESIZE_BYTE)
#define SDK_L2CACHE_ALIGN(var) __attribute__((aligned(FSL_FEATURE_L2CACHE_LINESIZE_BYTE))) var
#endif
#elif defined(__GNUC__)
/*! Macro to define a variable with alignbytes alignment */
#define SDK_ALIGN(var, alignbytes) var __attribute__((aligned(alignbytes)))
/*! Macro to define a variable with L1 d-cache line size alignment */
#if defined(FSL_FEATURE_L1DCACHE_LINESIZE_BYTE)
#define SDK_L1DCACHE_ALIGN(var) var __attribute__((aligned(FSL_FEATURE_L1DCACHE_LINESIZE_BYTE)))
#endif
/*! Macro to define a variable with L2 cache line size alignment */
#if defined(FSL_FEATURE_L2CACHE_LINESIZE_BYTE)
#define SDK_L2CACHE_ALIGN(var) var __attribute__((aligned(FSL_FEATURE_L2CACHE_LINESIZE_BYTE)))
#endif
#else
#error Toolchain not supported
#define SDK_ALIGN(var, alignbytes) var
#if defined(FSL_FEATURE_L1DCACHE_LINESIZE_BYTE)
#define SDK_L1DCACHE_ALIGN(var) var
#endif
#if defined(FSL_FEATURE_L2CACHE_LINESIZE_BYTE)
#define SDK_L2CACHE_ALIGN(var) var
#endif
#endif
/*! Macro to change a value to a given size aligned value */
#define SDK_SIZEALIGN(var, alignbytes) \
((unsigned int)((var) + ((alignbytes)-1U)) & (unsigned int)(~(unsigned int)((alignbytes)-1U)))
/* @} */
/*! @name Non-cacheable region definition macros */
/* For initialized non-zero non-cacheable variables, please using "AT_NONCACHEABLE_SECTION_INIT(var) ={xx};" or
* "AT_NONCACHEABLE_SECTION_ALIGN_INIT(var) ={xx};" in your projects to define them, for zero-inited non-cacheable variables,
* please using "AT_NONCACHEABLE_SECTION(var);" or "AT_NONCACHEABLE_SECTION_ALIGN(var);" to define them, these zero-inited variables
* will be initialized to zero in system startup.
*/
/* @{ */
#if (defined(__ICCARM__))
#if ((!(defined(FSL_FEATURE_HAS_NO_NONCACHEABLE_SECTION) && FSL_FEATURE_HAS_NO_NONCACHEABLE_SECTION)) && defined(FSL_FEATURE_L1ICACHE_LINESIZE_BYTE))
#define AT_NONCACHEABLE_SECTION(var) var @"NonCacheable"
#define AT_NONCACHEABLE_SECTION_ALIGN(var, alignbytes) SDK_PRAGMA(data_alignment = alignbytes) var @"NonCacheable"
#define AT_NONCACHEABLE_SECTION_INIT(var) var @"NonCacheable.init"
#define AT_NONCACHEABLE_SECTION_ALIGN_INIT(var, alignbytes) SDK_PRAGMA(data_alignment = alignbytes) var @"NonCacheable.init"
#else
#define AT_NONCACHEABLE_SECTION(var) var
#define AT_NONCACHEABLE_SECTION_ALIGN(var, alignbytes) SDK_PRAGMA(data_alignment = alignbytes) var
#define AT_NONCACHEABLE_SECTION_INIT(var) var
#define AT_NONCACHEABLE_SECTION_ALIGN_INIT(var, alignbytes) SDK_PRAGMA(data_alignment = alignbytes) var
#endif
#elif(defined(__CC_ARM) || defined(__ARMCC_VERSION))
#if ((!(defined(FSL_FEATURE_HAS_NO_NONCACHEABLE_SECTION) && FSL_FEATURE_HAS_NO_NONCACHEABLE_SECTION)) && defined(FSL_FEATURE_L1ICACHE_LINESIZE_BYTE))
#define AT_NONCACHEABLE_SECTION_INIT(var) __attribute__((section("NonCacheable.init"))) var
#define AT_NONCACHEABLE_SECTION_ALIGN_INIT(var, alignbytes) \
__attribute__((section("NonCacheable.init"))) __attribute__((aligned(alignbytes))) var
#if(defined(__CC_ARM))
#define AT_NONCACHEABLE_SECTION(var) __attribute__((section("NonCacheable"), zero_init)) var
#define AT_NONCACHEABLE_SECTION_ALIGN(var, alignbytes) \
__attribute__((section("NonCacheable"), zero_init)) __attribute__((aligned(alignbytes))) var
#else
#define AT_NONCACHEABLE_SECTION(var) __attribute__((section(".bss.NonCacheable"))) var
#define AT_NONCACHEABLE_SECTION_ALIGN(var, alignbytes) \
__attribute__((section(".bss.NonCacheable"))) __attribute__((aligned(alignbytes))) var
#endif
#else
#define AT_NONCACHEABLE_SECTION(var) var
#define AT_NONCACHEABLE_SECTION_ALIGN(var, alignbytes) __attribute__((aligned(alignbytes))) var
#define AT_NONCACHEABLE_SECTION_INIT(var) var
#define AT_NONCACHEABLE_SECTION_ALIGN_INIT(var, alignbytes) __attribute__((aligned(alignbytes))) var
#endif
#elif(defined(__XCC__))
#define AT_NONCACHEABLE_SECTION_INIT(var) __attribute__((section("NonCacheable.init"))) var
#define AT_NONCACHEABLE_SECTION_ALIGN_INIT(var, alignbytes) \
__attribute__((section("NonCacheable.init"))) var __attribute__((aligned(alignbytes)))
#define AT_NONCACHEABLE_SECTION(var) __attribute__((section("NonCacheable"))) var
#define AT_NONCACHEABLE_SECTION_ALIGN(var, alignbytes) \
__attribute__((section("NonCacheable"))) var __attribute__((aligned(alignbytes)))
#elif(defined(__GNUC__))
/* For GCC, when the non-cacheable section is required, please define "__STARTUP_INITIALIZE_NONCACHEDATA"
* in your projects to make sure the non-cacheable section variables will be initialized in system startup.
*/
#if ((!(defined(FSL_FEATURE_HAS_NO_NONCACHEABLE_SECTION) && FSL_FEATURE_HAS_NO_NONCACHEABLE_SECTION)) && defined(FSL_FEATURE_L1ICACHE_LINESIZE_BYTE))
#define AT_NONCACHEABLE_SECTION_INIT(var) __attribute__((section("NonCacheable.init"))) var
#define AT_NONCACHEABLE_SECTION_ALIGN_INIT(var, alignbytes) \
__attribute__((section("NonCacheable.init"))) var __attribute__((aligned(alignbytes)))
#define AT_NONCACHEABLE_SECTION(var) __attribute__((section("NonCacheable,\"aw\",%nobits @"))) var
#define AT_NONCACHEABLE_SECTION_ALIGN(var, alignbytes) \
__attribute__((section("NonCacheable,\"aw\",%nobits @"))) var __attribute__((aligned(alignbytes)))
#else
#define AT_NONCACHEABLE_SECTION(var) var
#define AT_NONCACHEABLE_SECTION_ALIGN(var, alignbytes) var __attribute__((aligned(alignbytes)))
#define AT_NONCACHEABLE_SECTION_INIT(var) var
#define AT_NONCACHEABLE_SECTION_ALIGN_INIT(var, alignbytes) var __attribute__((aligned(alignbytes)))
#endif
#else
#error Toolchain not supported.
#define AT_NONCACHEABLE_SECTION(var) var
#define AT_NONCACHEABLE_SECTION_ALIGN(var, alignbytes) var
#define AT_NONCACHEABLE_SECTION_INIT(var) var
#define AT_NONCACHEABLE_SECTION_ALIGN_INIT(var, alignbytes) var
#endif
/* @} */
/*! @name Time sensitive region */
/* @{ */
#if defined(FSL_SDK_DRIVER_QUICK_ACCESS_ENABLE) && FSL_SDK_DRIVER_QUICK_ACCESS_ENABLE
#if (defined(__ICCARM__))
#define AT_QUICKACCESS_SECTION_CODE(func) func @"CodeQuickAccess"
#define AT_QUICKACCESS_SECTION_DATA(func) func @"DataQuickAccess"
#elif(defined(__CC_ARM) || defined(__ARMCC_VERSION))
#define AT_QUICKACCESS_SECTION_CODE(func) __attribute__((section("CodeQuickAccess"), __noinline__)) func
#define AT_QUICKACCESS_SECTION_DATA(func) __attribute__((section("DataQuickAccess"))) func
#elif(defined(__GNUC__))
#define AT_QUICKACCESS_SECTION_CODE(func) __attribute__((section("CodeQuickAccess"), __noinline__)) func
#define AT_QUICKACCESS_SECTION_DATA(func) __attribute__((section("DataQuickAccess"))) func
#else
#error Toolchain not supported.
#endif /* defined(__ICCARM__) */
#else
#if (defined(__ICCARM__))
#define AT_QUICKACCESS_SECTION_CODE(func) func
#define AT_QUICKACCESS_SECTION_DATA(func) func
#elif(defined(__CC_ARM) || defined(__ARMCC_VERSION))
#define AT_QUICKACCESS_SECTION_CODE(func) func
#define AT_QUICKACCESS_SECTION_DATA(func) func
#elif(defined(__GNUC__))
#define AT_QUICKACCESS_SECTION_CODE(func) func
#define AT_QUICKACCESS_SECTION_DATA(func) func
#else
#error Toolchain not supported.
#endif
#endif /* __FSL_SDK_DRIVER_QUICK_ACCESS_ENABLE */
/* @} */
/*! @name Ram Function */
#if (defined(__ICCARM__))
#define RAMFUNCTION_SECTION_CODE(func) func @"RamFunction"
#elif(defined(__CC_ARM) || defined(__ARMCC_VERSION))
#define RAMFUNCTION_SECTION_CODE(func) __attribute__((section("RamFunction"))) func
#elif(defined(__GNUC__))
#define RAMFUNCTION_SECTION_CODE(func) __attribute__((section("RamFunction"))) func
#else
#error Toolchain not supported.
#endif /* defined(__ICCARM__) */
/* @} */
/*! @name Suppress fallthrough warning macro */
/* For switch case code block, if case section ends without "break;" statement, there wil be
fallthrough warning with compiler flag -Wextra or -Wimplicit-fallthrough=n when using armgcc.
To suppress this warning, "SUPPRESS_FALL_THROUGH_WARNING();" need to be added at the end of each
case section which misses "break;"statement.
*/
/* @{ */
#if defined(__GNUC__) && !defined(__ARMCC_VERSION)
#define SUPPRESS_FALL_THROUGH_WARNING() __attribute__ ((fallthrough))
#else
#define SUPPRESS_FALL_THROUGH_WARNING()
#endif
/* @} */
/*! @name Atomic modification
*
* These macros are used for atomic access, such as read-modify-write
* to the peripheral registers.
*
* - SDK_ATOMIC_LOCAL_ADD
* - SDK_ATOMIC_LOCAL_SET
* - SDK_ATOMIC_LOCAL_CLEAR
* - SDK_ATOMIC_LOCAL_TOGGLE
* - SDK_ATOMIC_LOCAL_CLEAR_AND_SET
*
* Take SDK_ATOMIC_LOCAL_CLEAR_AND_SET as an example: the parameter @c addr
* means the address of the peripheral register or variable you want to modify
* atomically, the parameter @c clearBits is the bits to clear, the parameter
* @c setBits it the bits to set.
* For example, to set a 32-bit register bit1:bit0 to 0b10, use like this:
*
* @code
volatile uint32_t * reg = (volatile uint32_t *)REG_ADDR;
SDK_ATOMIC_LOCAL_CLEAR_AND_SET(reg, 0x03, 0x02);
@endcode
*
* In this example, the register bit1:bit0 are cleared and bit1 is set, as a result,
* register bit1:bit0 = 0b10.
*
* @note For the platforms don't support exclusive load and store, these macros
* disable the global interrupt to pretect the modification.
*
* @note These macros only guarantee the local processor atomic operations. For
* the multi-processor devices, use hardware semaphore such as SEMA42 to
* guarantee exclusive access if necessary.
*
* @{
*/
/* clang-format off */
#if ((defined(__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \
(defined(__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \
(defined(__ARM_ARCH_8M_MAIN__) && (__ARM_ARCH_8M_MAIN__ == 1)) || \
(defined(__ARM_ARCH_8M_BASE__) && (__ARM_ARCH_8M_BASE__ == 1)))
/* clang-format on */
/* If the LDREX and STREX are supported, use them. */
#define _SDK_ATOMIC_LOCAL_OPS_1BYTE(addr, val, ops) \
do \
{ \
(val) = __LDREXB(addr); \
(ops); \
} while (0UL != __STREXB((val), (addr)))
#define _SDK_ATOMIC_LOCAL_OPS_2BYTE(addr, val, ops) \
do \
{ \
(val) = __LDREXH(addr); \
(ops); \
} while (0UL != __STREXH((val), (addr)))
#define _SDK_ATOMIC_LOCAL_OPS_4BYTE(addr, val, ops) \
do \
{ \
(val) = __LDREXW(addr); \
(ops); \
} while (0UL != __STREXW((val), (addr)))
static inline void _SDK_AtomicLocalAdd1Byte(volatile uint8_t *addr, uint8_t val)
{
uint8_t s_val;
_SDK_ATOMIC_LOCAL_OPS_1BYTE(addr, s_val, s_val += val);
}
static inline void _SDK_AtomicLocalAdd2Byte(volatile uint16_t *addr, uint16_t val)
{
uint16_t s_val;
_SDK_ATOMIC_LOCAL_OPS_2BYTE(addr, s_val, s_val += val);
}
static inline void _SDK_AtomicLocalAdd4Byte(volatile uint32_t *addr, uint32_t val)
{
uint32_t s_val;
_SDK_ATOMIC_LOCAL_OPS_4BYTE(addr, s_val, s_val += val);
}
static inline void _SDK_AtomicLocalSub1Byte(volatile uint8_t *addr, uint8_t val)
{
uint8_t s_val;
_SDK_ATOMIC_LOCAL_OPS_1BYTE(addr, s_val, s_val -= val);
}
static inline void _SDK_AtomicLocalSub2Byte(volatile uint16_t *addr, uint16_t val)
{
uint16_t s_val;
_SDK_ATOMIC_LOCAL_OPS_2BYTE(addr, s_val, s_val -= val);
}
static inline void _SDK_AtomicLocalSub4Byte(volatile uint32_t *addr, uint32_t val)
{
uint32_t s_val;
_SDK_ATOMIC_LOCAL_OPS_4BYTE(addr, s_val, s_val -= val);
}
static inline void _SDK_AtomicLocalSet1Byte(volatile uint8_t *addr, uint8_t bits)
{
uint8_t s_val;
_SDK_ATOMIC_LOCAL_OPS_1BYTE(addr, s_val, s_val |= bits);
}
static inline void _SDK_AtomicLocalSet2Byte(volatile uint16_t *addr, uint16_t bits)
{
uint16_t s_val;
_SDK_ATOMIC_LOCAL_OPS_2BYTE(addr, s_val, s_val |= bits);
}
static inline void _SDK_AtomicLocalSet4Byte(volatile uint32_t *addr, uint32_t bits)
{
uint32_t s_val;
_SDK_ATOMIC_LOCAL_OPS_4BYTE(addr, s_val, s_val |= bits);
}
static inline void _SDK_AtomicLocalClear1Byte(volatile uint8_t *addr, uint8_t bits)
{
uint8_t s_val;
_SDK_ATOMIC_LOCAL_OPS_1BYTE(addr, s_val, s_val &= ~bits);
}
static inline void _SDK_AtomicLocalClear2Byte(volatile uint16_t *addr, uint16_t bits)
{
uint16_t s_val;
_SDK_ATOMIC_LOCAL_OPS_2BYTE(addr, s_val, s_val &= ~bits);
}
static inline void _SDK_AtomicLocalClear4Byte(volatile uint32_t *addr, uint32_t bits)
{
uint32_t s_val;
_SDK_ATOMIC_LOCAL_OPS_4BYTE(addr, s_val, s_val &= ~bits);
}
static inline void _SDK_AtomicLocalToggle1Byte(volatile uint8_t *addr, uint8_t bits)
{
uint8_t s_val;
_SDK_ATOMIC_LOCAL_OPS_1BYTE(addr, s_val, s_val ^= bits);
}
static inline void _SDK_AtomicLocalToggle2Byte(volatile uint16_t *addr, uint16_t bits)
{
uint16_t s_val;
_SDK_ATOMIC_LOCAL_OPS_2BYTE(addr, s_val, s_val ^= bits);
}
static inline void _SDK_AtomicLocalToggle4Byte(volatile uint32_t *addr, uint32_t bits)
{
uint32_t s_val;
_SDK_ATOMIC_LOCAL_OPS_4BYTE(addr, s_val, s_val ^= bits);
}
static inline void _SDK_AtomicLocalClearAndSet1Byte(volatile uint8_t *addr, uint8_t clearBits, uint8_t setBits)
{
uint8_t s_val;
_SDK_ATOMIC_LOCAL_OPS_1BYTE(addr, s_val, s_val = (s_val & ~clearBits) | setBits);
}
static inline void _SDK_AtomicLocalClearAndSet2Byte(volatile uint16_t *addr, uint16_t clearBits, uint16_t setBits)
{
uint16_t s_val;
_SDK_ATOMIC_LOCAL_OPS_2BYTE(addr, s_val, s_val = (s_val & ~clearBits) | setBits);
}
static inline void _SDK_AtomicLocalClearAndSet4Byte(volatile uint32_t *addr, uint32_t clearBits, uint32_t setBits)
{
uint32_t s_val;
_SDK_ATOMIC_LOCAL_OPS_4BYTE(addr, s_val, s_val = (s_val & ~clearBits) | setBits);
}
#define SDK_ATOMIC_LOCAL_ADD(addr, val) \
((1UL == sizeof(*(addr))) ? _SDK_AtomicLocalAdd1Byte((volatile void*)(addr), (val)) : \
((2UL == sizeof(*(addr))) ? _SDK_AtomicLocalAdd2Byte((volatile void*)(addr), (val)) : \
_SDK_AtomicLocalAdd4Byte((volatile void*)(addr), (val))))
#define SDK_ATOMIC_LOCAL_SET(addr, bits) \
((1UL == sizeof(*(addr))) ? _SDK_AtomicLocalSet1Byte((volatile void*)(addr), (bits)) : \
((2UL == sizeof(*(addr))) ? _SDK_AtomicLocalSet2Byte((volatile void*)(addr), (bits)) : \
_SDK_AtomicLocalSet4Byte((volatile void*)(addr), (bits))))
#define SDK_ATOMIC_LOCAL_CLEAR(addr, bits) \
((1UL == sizeof(*(addr))) ? _SDK_AtomicLocalClear1Byte((volatile void*)(addr), (bits)) : \
((2UL == sizeof(*(addr))) ? _SDK_AtomicLocalClear2Byte((volatile void*)(addr), (bits)) : \
_SDK_AtomicLocalClear4Byte((volatile void*)(addr), (bits))))
#define SDK_ATOMIC_LOCAL_TOGGLE(addr, bits) \
((1UL == sizeof(*(addr))) ? _SDK_AtomicLocalToggle1Byte((volatile void*)(addr), (bits)) : \
((2UL == sizeof(*(addr))) ? _SDK_AtomicLocalToggle2Byte((volatile void*)(addr), (bits)) : \
_SDK_AtomicLocalToggle4Byte((volatile void*)(addr), (bits))))
#define SDK_ATOMIC_LOCAL_CLEAR_AND_SET(addr, clearBits, setBits) \
((1UL == sizeof(*(addr))) ? _SDK_AtomicLocalClearAndSet1Byte((volatile void*)(addr), (clearBits), (setBits)) : \
((2UL == sizeof(*(addr))) ? _SDK_AtomicLocalClearAndSet2Byte((volatile void*)(addr), (clearBits), (setBits)) : \
_SDK_AtomicLocalClearAndSet4Byte((volatile void*)(addr), (clearBits), (setBits))))
#else
#define SDK_ATOMIC_LOCAL_ADD(addr, val) \
do { \
uint32_t s_atomicOldInt; \
s_atomicOldInt = DisableGlobalIRQ(); \
*(addr) += (val); \
EnableGlobalIRQ(s_atomicOldInt); \
} while (0)
#define SDK_ATOMIC_LOCAL_SET(addr, bits) \
do { \
uint32_t s_atomicOldInt; \
s_atomicOldInt = DisableGlobalIRQ(); \
*(addr) |= (bits); \
EnableGlobalIRQ(s_atomicOldInt); \
} while (0)
#define SDK_ATOMIC_LOCAL_CLEAR(addr, bits) \
do { \
uint32_t s_atomicOldInt; \
s_atomicOldInt = DisableGlobalIRQ(); \
*(addr) &= ~(bits); \
EnableGlobalIRQ(s_atomicOldInt); \
} while (0)
#define SDK_ATOMIC_LOCAL_TOGGLE(addr, bits) \
do { \
uint32_t s_atomicOldInt; \
s_atomicOldInt = DisableGlobalIRQ(); \
*(addr) ^= (bits); \
EnableGlobalIRQ(s_atomicOldInt); \
} while (0)
#define SDK_ATOMIC_LOCAL_CLEAR_AND_SET(addr, clearBits, setBits) \
do { \
uint32_t s_atomicOldInt; \
s_atomicOldInt = DisableGlobalIRQ(); \
*(addr) = (*(addr) & ~(clearBits)) | (setBits); \
EnableGlobalIRQ(s_atomicOldInt); \
} while (0)
#endif
/* @} */
#if defined ( __ARMCC_VERSION ) && ( __ARMCC_VERSION >= 6010050 )
void DefaultISR(void);
#endif
/*
* The fsl_clock.h is included here because it needs MAKE_VERSION/MAKE_STATUS/status_t
* defined in previous of this file.
*/
#include "fsl_clock.h"
/*
* Chip level peripheral reset API, for MCUs that implement peripheral reset control external to a peripheral
*/
#if ((defined(FSL_FEATURE_SOC_SYSCON_COUNT) && (FSL_FEATURE_SOC_SYSCON_COUNT > 0)) || \
(defined(FSL_FEATURE_SOC_ASYNC_SYSCON_COUNT) && (FSL_FEATURE_SOC_ASYNC_SYSCON_COUNT > 0)))
#include "fsl_reset.h"
#endif
/*******************************************************************************
* API
******************************************************************************/
#if defined(__cplusplus)
extern "C"
{
#endif
/*!
* @brief Enable specific interrupt.
*
* Enable LEVEL1 interrupt. For some devices, there might be multiple interrupt
* levels. For example, there are NVIC and intmux. Here the interrupts connected
* to NVIC are the LEVEL1 interrupts, because they are routed to the core directly.
* The interrupts connected to intmux are the LEVEL2 interrupts, they are routed
* to NVIC first then routed to core.
*
* This function only enables the LEVEL1 interrupts. The number of LEVEL1 interrupts
* is indicated by the feature macro FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS.
*
* @param interrupt The IRQ number.
* @retval kStatus_Success Interrupt enabled successfully
* @retval kStatus_Fail Failed to enable the interrupt
*/
static inline status_t EnableIRQ(IRQn_Type interrupt)
{
status_t status = kStatus_Success;
if (NotAvail_IRQn == interrupt)
{
status = kStatus_Fail;
}
#if defined(FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS) && (FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS > 0)
else if ((int32_t)interrupt >= (int32_t)FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS)
{
status = kStatus_Fail;
}
#endif
else
{
#if defined(__GIC_PRIO_BITS)
GIC_EnableIRQ(interrupt);
#else
NVIC_EnableIRQ(interrupt);
#endif
}
return status;
}
/*!
* @brief Disable specific interrupt.
*
* Disable LEVEL1 interrupt. For some devices, there might be multiple interrupt
* levels. For example, there are NVIC and intmux. Here the interrupts connected
* to NVIC are the LEVEL1 interrupts, because they are routed to the core directly.
* The interrupts connected to intmux are the LEVEL2 interrupts, they are routed
* to NVIC first then routed to core.
*
* This function only disables the LEVEL1 interrupts. The number of LEVEL1 interrupts
* is indicated by the feature macro FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS.
*
* @param interrupt The IRQ number.
* @retval kStatus_Success Interrupt disabled successfully
* @retval kStatus_Fail Failed to disable the interrupt
*/
static inline status_t DisableIRQ(IRQn_Type interrupt)
{
status_t status = kStatus_Success;
if (NotAvail_IRQn == interrupt)
{
status = kStatus_Fail;
}
#if defined(FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS) && (FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS > 0)
else if ((int32_t)interrupt >= (int32_t)FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS)
{
status = kStatus_Fail;
}
#endif
else
{
#if defined(__GIC_PRIO_BITS)
GIC_DisableIRQ(interrupt);
#else
NVIC_DisableIRQ(interrupt);
#endif
}
return status;
}
/*!
* @brief Disable the global IRQ
*
* Disable the global interrupt and return the current primask register. User is required to provided the primask
* register for the EnableGlobalIRQ().
*
* @return Current primask value.
*/
static inline uint32_t DisableGlobalIRQ(void)
{
#if defined (__XCC__)
return 0;
#else
#if defined(CPSR_I_Msk)
uint32_t cpsr = __get_CPSR() & CPSR_I_Msk;
__disable_irq();
return cpsr;
#else
uint32_t regPrimask = __get_PRIMASK();
__disable_irq();
return regPrimask;
#endif
#endif
}
/*!
* @brief Enable the global IRQ
*
* Set the primask register with the provided primask value but not just enable the primask. The idea is for the
* convenience of integration of RTOS. some RTOS get its own management mechanism of primask. User is required to
* use the EnableGlobalIRQ() and DisableGlobalIRQ() in pair.
*
* @param primask value of primask register to be restored. The primask value is supposed to be provided by the
* DisableGlobalIRQ().
*/
static inline void EnableGlobalIRQ(uint32_t primask)
{
#if defined (__XCC__)
#else
#if defined(CPSR_I_Msk)
__set_CPSR((__get_CPSR() & ~CPSR_I_Msk) | primask);
#else
__set_PRIMASK(primask);
#endif
#endif
}
#if defined(ENABLE_RAM_VECTOR_TABLE)
/*!
* @brief install IRQ handler
*
* @param irq IRQ number
* @param irqHandler IRQ handler address
* @return The old IRQ handler address
*/
uint32_t InstallIRQHandler(IRQn_Type irq, uint32_t irqHandler);
#endif /* ENABLE_RAM_VECTOR_TABLE. */
#if (defined(FSL_FEATURE_SOC_SYSCON_COUNT) && (FSL_FEATURE_SOC_SYSCON_COUNT > 0))
/*
* When FSL_FEATURE_POWERLIB_EXTEND is defined to non-zero value,
* powerlib should be used instead of these functions.
*/
#if !(defined(FSL_FEATURE_POWERLIB_EXTEND) && (FSL_FEATURE_POWERLIB_EXTEND != 0))
/*!
* @brief Enable specific interrupt for wake-up from deep-sleep mode.
*
* Enable the interrupt for wake-up from deep sleep mode.
* Some interrupts are typically used in sleep mode only and will not occur during
* deep-sleep mode because relevant clocks are stopped. However, it is possible to enable
* those clocks (significantly increasing power consumption in the reduced power mode),
* making these wake-ups possible.
*
* @note This function also enables the interrupt in the NVIC (EnableIRQ() is called internaly).
*
* @param interrupt The IRQ number.
*/
void EnableDeepSleepIRQ(IRQn_Type interrupt);
/*!
* @brief Disable specific interrupt for wake-up from deep-sleep mode.
*
* Disable the interrupt for wake-up from deep sleep mode.
* Some interrupts are typically used in sleep mode only and will not occur during
* deep-sleep mode because relevant clocks are stopped. However, it is possible to enable
* those clocks (significantly increasing power consumption in the reduced power mode),
* making these wake-ups possible.
*
* @note This function also disables the interrupt in the NVIC (DisableIRQ() is called internaly).
*
* @param interrupt The IRQ number.
*/
void DisableDeepSleepIRQ(IRQn_Type interrupt);
#endif /* FSL_FEATURE_POWERLIB_EXTEND */
#endif /* FSL_FEATURE_SOC_SYSCON_COUNT */
/*!
* @brief Allocate memory with given alignment and aligned size.
*
* This is provided to support the dynamically allocated memory
* used in cache-able region.
* @param size The length required to malloc.
* @param alignbytes The alignment size.
* @retval The allocated memory.
*/
void *SDK_Malloc(size_t size, size_t alignbytes);
/*!
* @brief Free memory.
*
* @param ptr The memory to be release.
*/
void SDK_Free(void *ptr);
/*!
* @brief Delay at least for some time.
* Please note that, this API uses while loop for delay, different run-time environments make the time not precise,
* if precise delay count was needed, please implement a new delay function with hardware timer.
*
* @param delayTime_us Delay time in unit of microsecond.
* @param coreClock_Hz Core clock frequency with Hz.
*/
void SDK_DelayAtLeastUs(uint32_t delayTime_us, uint32_t coreClock_Hz);
#if defined(__cplusplus)
}
#endif
/*! @} */
#endif /* _FSL_COMMON_H_ */

577
drivers/fsl_ctimer.c Normal file
View File

@@ -0,0 +1,577 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* Copyright 2016-2020 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "fsl_ctimer.h"
/* Component ID definition, used by tools. */
#ifndef FSL_COMPONENT_ID
#define FSL_COMPONENT_ID "platform.drivers.ctimer"
#endif
/*******************************************************************************
* Prototypes
******************************************************************************/
/*!
* @brief Gets the instance from the base address
*
* @param base Ctimer peripheral base address
*
* @return The Timer instance
*/
static uint32_t CTIMER_GetInstance(CTIMER_Type *base);
/*!
* @brief CTIMER generic IRQ handle function.
*
* @param index FlexCAN peripheral instance index.
*/
static void CTIMER_GenericIRQHandler(uint32_t index);
/*******************************************************************************
* Variables
******************************************************************************/
/*! @brief Pointers to Timer bases for each instance. */
static CTIMER_Type *const s_ctimerBases[] = CTIMER_BASE_PTRS;
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
/*! @brief Pointers to Timer clocks for each instance. */
static const clock_ip_name_t s_ctimerClocks[] = CTIMER_CLOCKS;
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
#if !(defined(FSL_FEATURE_CTIMER_HAS_NO_RESET) && (FSL_FEATURE_CTIMER_HAS_NO_RESET))
#if !(defined(FSL_SDK_DISABLE_DRIVER_RESET_CONTROL) && FSL_SDK_DISABLE_DRIVER_RESET_CONTROL)
#if defined(FSL_FEATURE_CTIMER_WRITE_ZERO_ASSERT_RESET) && FSL_FEATURE_CTIMER_WRITE_ZERO_ASSERT_RESET
/*! @brief Pointers to Timer resets for each instance, writing a zero asserts the reset */
static const reset_ip_name_t s_ctimerResets[] = CTIMER_RSTS_N;
#else
/*! @brief Pointers to Timer resets for each instance, writing a one asserts the reset */
static const reset_ip_name_t s_ctimerResets[] = CTIMER_RSTS;
#endif
#endif
#endif /* FSL_SDK_DISABLE_DRIVER_RESET_CONTROL */
/*! @brief Pointers real ISRs installed by drivers for each instance. */
static ctimer_callback_t *s_ctimerCallback[sizeof(s_ctimerBases) / sizeof(s_ctimerBases[0])] = {0};
/*! @brief Callback type installed by drivers for each instance. */
static ctimer_callback_type_t ctimerCallbackType[sizeof(s_ctimerBases) / sizeof(s_ctimerBases[0])] = {
kCTIMER_SingleCallback};
/*! @brief Array to map timer instance to IRQ number. */
static const IRQn_Type s_ctimerIRQ[] = CTIMER_IRQS;
/*******************************************************************************
* Code
******************************************************************************/
static uint32_t CTIMER_GetInstance(CTIMER_Type *base)
{
uint32_t instance;
uint32_t ctimerArrayCount = (sizeof(s_ctimerBases) / sizeof(s_ctimerBases[0]));
/* Find the instance index from base address mappings. */
for (instance = 0; instance < ctimerArrayCount; instance++)
{
if (s_ctimerBases[instance] == base)
{
break;
}
}
assert(instance < ctimerArrayCount);
return instance;
}
/*!
* brief Ungates the clock and configures the peripheral for basic operation.
*
* note This API should be called at the beginning of the application before using the driver.
*
* param base Ctimer peripheral base address
* param config Pointer to the user configuration structure.
*/
void CTIMER_Init(CTIMER_Type *base, const ctimer_config_t *config)
{
assert(config != NULL);
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
/* Enable the timer clock*/
CLOCK_EnableClock(s_ctimerClocks[CTIMER_GetInstance(base)]);
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
#if !(defined(FSL_SDK_DISABLE_DRIVER_RESET_CONTROL) && FSL_SDK_DISABLE_DRIVER_RESET_CONTROL)
/* Reset the module. */
#if !(defined(FSL_FEATURE_CTIMER_HAS_NO_RESET) && (FSL_FEATURE_CTIMER_HAS_NO_RESET))
RESET_PeripheralReset(s_ctimerResets[CTIMER_GetInstance(base)]);
#endif
#endif /* FSL_SDK_DISABLE_DRIVER_RESET_CONTROL */
/* Setup the cimer mode and count select */
#if !(defined(FSL_FEATURE_CTIMER_HAS_NO_INPUT_CAPTURE) && (FSL_FEATURE_CTIMER_HAS_NO_INPUT_CAPTURE))
base->CTCR = CTIMER_CTCR_CTMODE(config->mode) | CTIMER_CTCR_CINSEL(config->input);
#endif
/* Setup the timer prescale value */
base->PR = CTIMER_PR_PRVAL(config->prescale);
}
/*!
* brief Gates the timer clock.
*
* param base Ctimer peripheral base address
*/
void CTIMER_Deinit(CTIMER_Type *base)
{
uint32_t index = CTIMER_GetInstance(base);
/* Stop the timer */
base->TCR &= ~CTIMER_TCR_CEN_MASK;
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
/* Disable the timer clock*/
CLOCK_DisableClock(s_ctimerClocks[index]);
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
/* Disable IRQ at NVIC Level */
(void)DisableIRQ(s_ctimerIRQ[index]);
}
/*!
* brief Fills in the timers configuration structure with the default settings.
*
* The default values are:
* code
* config->mode = kCTIMER_TimerMode;
* config->input = kCTIMER_Capture_0;
* config->prescale = 0;
* endcode
* param config Pointer to the user configuration structure.
*/
void CTIMER_GetDefaultConfig(ctimer_config_t *config)
{
assert(config != NULL);
/* Initializes the configure structure to zero. */
(void)memset(config, 0, sizeof(*config));
/* Run as a timer */
config->mode = kCTIMER_TimerMode;
/* This field is ignored when mode is timer */
config->input = kCTIMER_Capture_0;
/* Timer counter is incremented on every APB bus clock */
config->prescale = 0;
}
/*!
* brief Configures the PWM signal parameters.
*
* Enables PWM mode on the match channel passed in and will then setup the match value
* and other match parameters to generate a PWM signal.
* This function can manually assign the specified channel to set the PWM cycle.
*
* note When setting PWM output from multiple output pins, all should use the same PWM
* frequency. Please use CTIMER_SetupPwmPeriod to set up the PWM with high resolution.
*
* param base Ctimer peripheral base address
* param pwmPeriodChannel Specify the channel to control the PWM period
* param matchChannel Match pin to be used to output the PWM signal
* param dutyCyclePercent PWM pulse width; the value should be between 0 to 100
* param pwmFreq_Hz PWM signal frequency in Hz
* param srcClock_Hz Timer counter clock in Hz
* param enableInt Enable interrupt when the timer value reaches the match value of the PWM pulse,
* if it is 0 then no interrupt will be generated.
*
* return kStatus_Success on success
* kStatus_Fail If matchChannel is equal to pwmPeriodChannel; this channel is reserved to set the PWM cycle
*/
status_t CTIMER_SetupPwm(CTIMER_Type *base,
const ctimer_match_t pwmPeriodChannel,
ctimer_match_t matchChannel,
uint8_t dutyCyclePercent,
uint32_t pwmFreq_Hz,
uint32_t srcClock_Hz,
bool enableInt)
{
assert(pwmFreq_Hz > 0U);
uint32_t reg;
uint32_t period, pulsePeriod = 0;
uint32_t timerClock = srcClock_Hz / (base->PR + 1U);
uint32_t index = CTIMER_GetInstance(base);
if (matchChannel == pwmPeriodChannel)
{
return kStatus_Fail;
}
/* Enable PWM mode on the channel */
base->PWMC |= (1UL << (uint32_t)matchChannel);
/* Clear the stop, reset and interrupt bits for this channel */
reg = base->MCR;
reg &=
~(((uint32_t)((uint32_t)CTIMER_MCR_MR0R_MASK | (uint32_t)CTIMER_MCR_MR0S_MASK | (uint32_t)CTIMER_MCR_MR0I_MASK))
<< ((uint32_t)matchChannel * 3U));
/* If call back function is valid then enable match interrupt for the channel */
if (enableInt)
{
reg |= (((uint32_t)CTIMER_MCR_MR0I_MASK) << (CTIMER_MCR_MR0I_SHIFT + ((uint32_t)matchChannel * 3U)));
}
/* Reset the counter when match on channel 3 */
reg |= CTIMER_MCR_MR3R_MASK;
base->MCR = reg;
/* Calculate PWM period match value */
period = (timerClock / pwmFreq_Hz) - 1U;
/* Calculate pulse width match value */
if (dutyCyclePercent == 0U)
{
pulsePeriod = period + 1U;
}
else
{
pulsePeriod = (period * (100U - (uint32_t)dutyCyclePercent)) / 100U;
}
/* Specified channel pwmPeriodChannel will define the PWM period */
base->MR[pwmPeriodChannel] = period;
/* This will define the PWM pulse period */
base->MR[matchChannel] = pulsePeriod;
/* Clear status flags */
CTIMER_ClearStatusFlags(base, ((uint32_t)CTIMER_IR_MR0INT_MASK) << (uint32_t)matchChannel);
/* If call back function is valid then enable interrupt and update the call back function */
if (enableInt)
{
(void)EnableIRQ(s_ctimerIRQ[index]);
}
return kStatus_Success;
}
/*!
* brief Configures the PWM signal parameters.
*
* Enables PWM mode on the match channel passed in and will then setup the match value
* and other match parameters to generate a PWM signal.
* This function can manually assign the specified channel to set the PWM cycle.
*
* note When setting PWM output from multiple output pins, all should use the same PWM
* period
*
* param base Ctimer peripheral base address
* param pwmPeriodChannel Specify the channel to control the PWM period
* param matchChannel Match pin to be used to output the PWM signal
* param pwmPeriod PWM period match value
* param pulsePeriod Pulse width match value
* param enableInt Enable interrupt when the timer value reaches the match value of the PWM pulse,
* if it is 0 then no interrupt will be generated.
*
* return kStatus_Success on success
* kStatus_Fail If matchChannel is equal to pwmPeriodChannel; this channel is reserved to set the PWM period
*/
status_t CTIMER_SetupPwmPeriod(CTIMER_Type *base,
const ctimer_match_t pwmPeriodChannel,
ctimer_match_t matchChannel,
uint32_t pwmPeriod,
uint32_t pulsePeriod,
bool enableInt)
{
/* Some CTimers only have 16bits , so the value is limited*/
#if defined(FSL_FEATURE_SOC_CTIMER16B) && FSL_FEATURE_SOC_CTIMER16B
assert(!((FSL_FEATURE_CTIMER_BIT_SIZEn(base) < 32) && (pulsePeriod > 0xFFFFU)));
#endif
uint32_t reg;
uint32_t index = CTIMER_GetInstance(base);
if (matchChannel == pwmPeriodChannel)
{
return kStatus_Fail;
}
/* Enable PWM mode on PWM pulse channel */
base->PWMC |= (1UL << (uint32_t)matchChannel);
/* Clear the stop, reset and interrupt bits for PWM pulse channel */
reg = base->MCR;
reg &=
~((uint32_t)((uint32_t)CTIMER_MCR_MR0R_MASK | (uint32_t)CTIMER_MCR_MR0S_MASK | (uint32_t)CTIMER_MCR_MR0I_MASK)
<< ((uint32_t)matchChannel * 3U));
/* If call back function is valid then enable match interrupt for PWM pulse channel */
if (enableInt)
{
reg |= (((uint32_t)CTIMER_MCR_MR0I_MASK) << (CTIMER_MCR_MR0I_SHIFT + ((uint32_t)matchChannel * 3U)));
}
/* Reset the counter when match on PWM period channel (pwmPeriodChannel) */
reg |= ((uint32_t)((uint32_t)CTIMER_MCR_MR0R_MASK) << ((uint32_t)pwmPeriodChannel * 3U));
base->MCR = reg;
/* Specified channel pwmPeriodChannel will define the PWM period */
base->MR[pwmPeriodChannel] = pwmPeriod;
/* This will define the PWM pulse period */
base->MR[matchChannel] = pulsePeriod;
/* Clear status flags */
CTIMER_ClearStatusFlags(base, ((uint32_t)CTIMER_IR_MR0INT_MASK) << (uint32_t)matchChannel);
/* If call back function is valid then enable interrupt and update the call back function */
if (enableInt)
{
(void)EnableIRQ(s_ctimerIRQ[index]);
}
return kStatus_Success;
}
/*!
* brief Updates the duty cycle of an active PWM signal.
*
* note Please use CTIMER_SetupPwmPeriod to update the PWM with high resolution.
* This function can manually assign the specified channel to set the PWM cycle.
*
* param base Ctimer peripheral base address
* param pwmPeriodChannel Specify the channel to control the PWM period
* param matchChannel Match pin to be used to output the PWM signal
* param dutyCyclePercent New PWM pulse width; the value should be between 0 to 100
*/
void CTIMER_UpdatePwmDutycycle(CTIMER_Type *base,
const ctimer_match_t pwmPeriodChannel,
ctimer_match_t matchChannel,
uint8_t dutyCyclePercent)
{
uint32_t pulsePeriod = 0, period;
/* Specified channel pwmPeriodChannel defines the PWM period */
period = base->MR[pwmPeriodChannel];
/* For 0% dutycyle, make pulse period greater than period so the event will never occur */
if (dutyCyclePercent == 0U)
{
pulsePeriod = period + 1U;
}
else
{
pulsePeriod = (period * (100U - (uint32_t)dutyCyclePercent)) / 100U;
}
/* Update dutycycle */
base->MR[matchChannel] = pulsePeriod;
}
/*!
* brief Setup the match register.
*
* User configuration is used to setup the match value and action to be taken when a match occurs.
*
* param base Ctimer peripheral base address
* param matchChannel Match register to configure
* param config Pointer to the match configuration structure
*/
void CTIMER_SetupMatch(CTIMER_Type *base, ctimer_match_t matchChannel, const ctimer_match_config_t *config)
{
/* Some CTimers only have 16bits , so the value is limited*/
#if defined(FSL_FEATURE_SOC_CTIMER16B) && FSL_FEATURE_SOC_CTIMER16B
assert(!(FSL_FEATURE_CTIMER_BIT_SIZEn(base) < 32 && config->matchValue > 0xFFFFU));
#endif
uint32_t reg;
uint32_t index = CTIMER_GetInstance(base);
/* Set the counter operation when a match on this channel occurs */
reg = base->MCR;
reg &=
~((uint32_t)((uint32_t)CTIMER_MCR_MR0R_MASK | (uint32_t)CTIMER_MCR_MR0S_MASK | (uint32_t)CTIMER_MCR_MR0I_MASK)
<< ((uint32_t)matchChannel * 3U));
reg |= ((uint32_t)(config->enableCounterReset) << (CTIMER_MCR_MR0R_SHIFT + ((uint32_t)matchChannel * 3U)));
reg |= ((uint32_t)(config->enableCounterStop) << (CTIMER_MCR_MR0S_SHIFT + ((uint32_t)matchChannel * 3U)));
reg |= ((uint32_t)(config->enableInterrupt) << (CTIMER_MCR_MR0I_SHIFT + ((uint32_t)matchChannel * 3U)));
base->MCR = reg;
reg = base->EMR;
/* Set the match output operation when a match on this channel occurs */
reg &= ~(((uint32_t)CTIMER_EMR_EMC0_MASK) << ((uint32_t)matchChannel * 2U));
reg |= ((uint32_t)config->outControl) << (CTIMER_EMR_EMC0_SHIFT + ((uint32_t)matchChannel * 2U));
/* Set the initial state of the EM bit/output */
reg &= ~(((uint32_t)CTIMER_EMR_EM0_MASK) << (uint32_t)matchChannel);
reg |= ((uint32_t)config->outPinInitState) << (uint32_t)matchChannel;
base->EMR = reg;
/* Set the match value */
base->MR[matchChannel] = config->matchValue;
/* Clear status flags */
CTIMER_ClearStatusFlags(base, ((uint32_t)CTIMER_IR_MR0INT_MASK) << (uint32_t)matchChannel);
/* If interrupt is enabled then enable interrupt and update the call back function */
if (config->enableInterrupt)
{
(void)EnableIRQ(s_ctimerIRQ[index]);
}
}
/*!
* brief Get the status of output match.
*
* This function gets the status of output MAT, whether or not this output is connected to a pin.
* This status is driven to the MAT pins if the match function is selected via IOCON. 0 = LOW. 1 = HIGH.
*
* param base Ctimer peripheral base address
* param matchChannel External match channel, user can obtain the status of multiple match channels
* at the same time by using the logic of "|"
* enumeration ::ctimer_external_match_t
* return The mask of external match channel status flags. Users need to use the
* _ctimer_external_match type to decode the return variables.
*/
uint32_t CTIMER_GetOutputMatchStatus(CTIMER_Type *base, uint32_t matchChannel)
{
return (base->EMR & matchChannel);
}
#if !(defined(FSL_FEATURE_CTIMER_HAS_NO_INPUT_CAPTURE) && (FSL_FEATURE_CTIMER_HAS_NO_INPUT_CAPTURE))
/*!
* brief Setup the capture.
*
* param base Ctimer peripheral base address
* param capture Capture channel to configure
* param edge Edge on the channel that will trigger a capture
* param enableInt Flag to enable channel interrupts, if enabled then the registered call back
* is called upon capture
*/
void CTIMER_SetupCapture(CTIMER_Type *base,
ctimer_capture_channel_t capture,
ctimer_capture_edge_t edge,
bool enableInt)
{
uint32_t reg = base->CCR;
uint32_t index = CTIMER_GetInstance(base);
/* Set the capture edge */
reg &= ~((uint32_t)((uint32_t)CTIMER_CCR_CAP0RE_MASK | (uint32_t)CTIMER_CCR_CAP0FE_MASK |
(uint32_t)CTIMER_CCR_CAP0I_MASK)
<< ((uint32_t)capture * 3U));
reg |= ((uint32_t)edge) << (CTIMER_CCR_CAP0RE_SHIFT + ((uint32_t)capture * 3U));
/* Clear status flags */
CTIMER_ClearStatusFlags(base, (((uint32_t)kCTIMER_Capture0Flag) << (uint32_t)capture));
/* If call back function is valid then enable capture interrupt for the channel and update the call back function */
if (enableInt)
{
reg |= ((uint32_t)CTIMER_CCR_CAP0I_MASK) << ((uint32_t)capture * 3U);
(void)EnableIRQ(s_ctimerIRQ[index]);
}
base->CCR = reg;
}
#endif
/*!
* brief Register callback.
*
* param base Ctimer peripheral base address
* param cb_func callback function
* param cb_type callback function type, singular or multiple
*/
void CTIMER_RegisterCallBack(CTIMER_Type *base, ctimer_callback_t *cb_func, ctimer_callback_type_t cb_type)
{
uint32_t index = CTIMER_GetInstance(base);
s_ctimerCallback[index] = cb_func;
ctimerCallbackType[index] = cb_type;
}
/*!
* brief CTIMER generic IRQ handle function.
*
* param index FlexCAN peripheral instance index.
*/
static void CTIMER_GenericIRQHandler(uint32_t index)
{
uint32_t int_stat, i, mask;
/* Get Interrupt status flags */
int_stat = CTIMER_GetStatusFlags(s_ctimerBases[index]);
/* Clear the status flags that were set */
CTIMER_ClearStatusFlags(s_ctimerBases[index], int_stat);
if (ctimerCallbackType[index] == kCTIMER_SingleCallback)
{
if (s_ctimerCallback[index][0] != NULL)
{
s_ctimerCallback[index][0](int_stat);
}
}
else
{
#if defined(FSL_FEATURE_CTIMER_HAS_NO_INPUT_CAPTURE) && FSL_FEATURE_CTIMER_HAS_NO_INPUT_CAPTURE
for (i = 0; i <= CTIMER_IR_MR3INT_SHIFT; i++)
#else
#if defined(FSL_FEATURE_CTIMER_HAS_IR_CR3INT) && FSL_FEATURE_CTIMER_HAS_IR_CR3INT
for (i = 0; i <= CTIMER_IR_CR3INT_SHIFT; i++)
#else
#if !(defined(FSL_FEATURE_CTIMER_HAS_NO_IR_CR2INT) && FSL_FEATURE_CTIMER_HAS_NO_IR_CR2INT)
for (i = 0; i <= CTIMER_IR_CR2INT_SHIFT; i++)
#else
for (i = 0; i <= CTIMER_IR_CR1INT_SHIFT; i++)
#endif /* FSL_FEATURE_CTIMER_HAS_NO_IR_CR2INT */
#endif /* FSL_FEATURE_CTIMER_HAS_IR_CR3INT */
#endif
{
mask = 0x01UL << i;
/* For each status flag bit that was set call the callback function if it is valid */
if (((int_stat & mask) != 0U) && (s_ctimerCallback[index][i] != NULL))
{
s_ctimerCallback[index][i](int_stat);
}
}
}
SDK_ISR_EXIT_BARRIER;
}
/* IRQ handler functions overloading weak symbols in the startup */
#if defined(CTIMER0)
void CTIMER0_DriverIRQHandler(void);
void CTIMER0_DriverIRQHandler(void)
{
CTIMER_GenericIRQHandler(0);
SDK_ISR_EXIT_BARRIER;
}
#endif
#if defined(CTIMER1)
void CTIMER1_DriverIRQHandler(void);
void CTIMER1_DriverIRQHandler(void)
{
CTIMER_GenericIRQHandler(1);
SDK_ISR_EXIT_BARRIER;
}
#endif
#if defined(CTIMER2)
void CTIMER2_DriverIRQHandler(void);
void CTIMER2_DriverIRQHandler(void)
{
CTIMER_GenericIRQHandler(2);
SDK_ISR_EXIT_BARRIER;
}
#endif
#if defined(CTIMER3)
void CTIMER3_DriverIRQHandler(void);
void CTIMER3_DriverIRQHandler(void)
{
CTIMER_GenericIRQHandler(3);
SDK_ISR_EXIT_BARRIER;
}
#endif
#if defined(CTIMER4)
void CTIMER4_DriverIRQHandler(void);
void CTIMER4_DriverIRQHandler(void)
{
CTIMER_GenericIRQHandler(4);
SDK_ISR_EXIT_BARRIER;
}
#endif

533
drivers/fsl_ctimer.h Normal file
View File

@@ -0,0 +1,533 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* Copyright 2016-2020 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _FSL_CTIMER_H_
#define _FSL_CTIMER_H_
#include "fsl_common.h"
/*!
* @addtogroup ctimer
* @{
*/
/*! @file */
/*******************************************************************************
* Definitions
******************************************************************************/
/*! @name Driver version */
/*@{*/
#define FSL_CTIMER_DRIVER_VERSION (MAKE_VERSION(2, 2, 1)) /*!< Version 2.2.1 */
/*@}*/
/*! @brief List of Timer capture channels */
typedef enum _ctimer_capture_channel
{
kCTIMER_Capture_0 = 0U, /*!< Timer capture channel 0 */
kCTIMER_Capture_1, /*!< Timer capture channel 1 */
#if !(defined(FSL_FEATURE_CTIMER_HAS_NO_CCR_CAP2) && FSL_FEATURE_CTIMER_HAS_NO_CCR_CAP2)
kCTIMER_Capture_2, /*!< Timer capture channel 2 */
#endif /* FSL_FEATURE_CTIMER_HAS_NO_CCR_CAP2 */
#if defined(FSL_FEATURE_CTIMER_HAS_CCR_CAP3) && FSL_FEATURE_CTIMER_HAS_CCR_CAP3
kCTIMER_Capture_3 /*!< Timer capture channel 3 */
#endif /* FSL_FEATURE_CTIMER_HAS_CCR_CAP3 */
} ctimer_capture_channel_t;
/*! @brief List of capture edge options */
typedef enum _ctimer_capture_edge
{
kCTIMER_Capture_RiseEdge = 1U, /*!< Capture on rising edge */
kCTIMER_Capture_FallEdge = 2U, /*!< Capture on falling edge */
kCTIMER_Capture_BothEdge = 3U, /*!< Capture on rising and falling edge */
} ctimer_capture_edge_t;
/*! @brief List of Timer match registers */
typedef enum _ctimer_match
{
kCTIMER_Match_0 = 0U, /*!< Timer match register 0 */
kCTIMER_Match_1, /*!< Timer match register 1 */
kCTIMER_Match_2, /*!< Timer match register 2 */
kCTIMER_Match_3 /*!< Timer match register 3 */
} ctimer_match_t;
/*! @brief List of external match */
typedef enum _ctimer_external_match
{
kCTIMER_External_Match_0 = (1U << 0), /*!< External match 0 */
kCTIMER_External_Match_1 = (1U << 1), /*!< External match 1 */
kCTIMER_External_Match_2 = (1U << 2), /*!< External match 2 */
kCTIMER_External_Match_3 = (1U << 3) /*!< External match 3 */
} ctimer_external_match_t;
/*! @brief List of output control options */
typedef enum _ctimer_match_output_control
{
kCTIMER_Output_NoAction = 0U, /*!< No action is taken */
kCTIMER_Output_Clear, /*!< Clear the EM bit/output to 0 */
kCTIMER_Output_Set, /*!< Set the EM bit/output to 1 */
kCTIMER_Output_Toggle /*!< Toggle the EM bit/output */
} ctimer_match_output_control_t;
/*! @brief List of Timer modes */
typedef enum _ctimer_timer_mode
{
kCTIMER_TimerMode = 0U, /* TC is incremented every rising APB bus clock edge */
kCTIMER_IncreaseOnRiseEdge, /* TC is incremented on rising edge of input signal */
kCTIMER_IncreaseOnFallEdge, /* TC is incremented on falling edge of input signal */
kCTIMER_IncreaseOnBothEdge /* TC is incremented on both edges of input signal */
} ctimer_timer_mode_t;
/*! @brief List of Timer interrupts */
typedef enum _ctimer_interrupt_enable
{
kCTIMER_Match0InterruptEnable = CTIMER_MCR_MR0I_MASK, /*!< Match 0 interrupt */
kCTIMER_Match1InterruptEnable = CTIMER_MCR_MR1I_MASK, /*!< Match 1 interrupt */
kCTIMER_Match2InterruptEnable = CTIMER_MCR_MR2I_MASK, /*!< Match 2 interrupt */
kCTIMER_Match3InterruptEnable = CTIMER_MCR_MR3I_MASK, /*!< Match 3 interrupt */
#if !(defined(FSL_FEATURE_CTIMER_HAS_NO_INPUT_CAPTURE) && (FSL_FEATURE_CTIMER_HAS_NO_INPUT_CAPTURE))
kCTIMER_Capture0InterruptEnable = CTIMER_CCR_CAP0I_MASK, /*!< Capture 0 interrupt */
kCTIMER_Capture1InterruptEnable = CTIMER_CCR_CAP1I_MASK, /*!< Capture 1 interrupt */
#if !(defined(FSL_FEATURE_CTIMER_HAS_NO_CCR_CAP2) && FSL_FEATURE_CTIMER_HAS_NO_CCR_CAP2)
kCTIMER_Capture2InterruptEnable = CTIMER_CCR_CAP2I_MASK, /*!< Capture 2 interrupt */
#endif /* FSL_FEATURE_CTIMER_HAS_NO_CCR_CAP2 */
#if defined(FSL_FEATURE_CTIMER_HAS_CCR_CAP3) && FSL_FEATURE_CTIMER_HAS_CCR_CAP3
kCTIMER_Capture3InterruptEnable = CTIMER_CCR_CAP3I_MASK, /*!< Capture 3 interrupt */
#endif /* FSL_FEATURE_CTIMER_HAS_CCR_CAP3 */
#endif
} ctimer_interrupt_enable_t;
/*! @brief List of Timer flags */
typedef enum _ctimer_status_flags
{
kCTIMER_Match0Flag = CTIMER_IR_MR0INT_MASK, /*!< Match 0 interrupt flag */
kCTIMER_Match1Flag = CTIMER_IR_MR1INT_MASK, /*!< Match 1 interrupt flag */
kCTIMER_Match2Flag = CTIMER_IR_MR2INT_MASK, /*!< Match 2 interrupt flag */
kCTIMER_Match3Flag = CTIMER_IR_MR3INT_MASK, /*!< Match 3 interrupt flag */
#if !(defined(FSL_FEATURE_CTIMER_HAS_NO_INPUT_CAPTURE) && (FSL_FEATURE_CTIMER_HAS_NO_INPUT_CAPTURE))
kCTIMER_Capture0Flag = CTIMER_IR_CR0INT_MASK, /*!< Capture 0 interrupt flag */
kCTIMER_Capture1Flag = CTIMER_IR_CR1INT_MASK, /*!< Capture 1 interrupt flag */
#if !(defined(FSL_FEATURE_CTIMER_HAS_NO_IR_CR2INT) && FSL_FEATURE_CTIMER_HAS_NO_IR_CR2INT)
kCTIMER_Capture2Flag = CTIMER_IR_CR2INT_MASK, /*!< Capture 2 interrupt flag */
#endif /* FSL_FEATURE_CTIMER_HAS_NO_IR_CR2INT */
#if defined(FSL_FEATURE_CTIMER_HAS_IR_CR3INT) && FSL_FEATURE_CTIMER_HAS_IR_CR3INT
kCTIMER_Capture3Flag = CTIMER_IR_CR3INT_MASK, /*!< Capture 3 interrupt flag */
#endif /* FSL_FEATURE_CTIMER_HAS_IR_CR3INT */
#endif
} ctimer_status_flags_t;
typedef void (*ctimer_callback_t)(uint32_t flags);
/*! @brief Callback type when registering for a callback. When registering a callback
* an array of function pointers is passed the size could be 1 or 8, the callback
* type will tell that.
*/
typedef enum
{
kCTIMER_SingleCallback, /*!< Single Callback type where there is only one callback for the timer.
based on the status flags different channels needs to be handled differently */
kCTIMER_MultipleCallback /*!< Multiple Callback type where there can be 8 valid callbacks, one per channel.
for both match/capture */
} ctimer_callback_type_t;
/*!
* @brief Match configuration
*
* This structure holds the configuration settings for each match register.
*/
typedef struct _ctimer_match_config
{
uint32_t matchValue; /*!< This is stored in the match register */
bool enableCounterReset; /*!< true: Match will reset the counter
false: Match will not reser the counter */
bool enableCounterStop; /*!< true: Match will stop the counter
false: Match will not stop the counter */
ctimer_match_output_control_t outControl; /*!< Action to be taken on a match on the EM bit/output */
bool outPinInitState; /*!< Initial value of the EM bit/output */
bool enableInterrupt; /*!< true: Generate interrupt upon match
false: Do not generate interrupt on match */
} ctimer_match_config_t;
/*!
* @brief Timer configuration structure
*
* This structure holds the configuration settings for the Timer peripheral. To initialize this
* structure to reasonable defaults, call the CTIMER_GetDefaultConfig() function and pass a
* pointer to the configuration structure instance.
*
* The configuration structure can be made constant so as to reside in flash.
*/
typedef struct _ctimer_config
{
ctimer_timer_mode_t mode; /*!< Timer mode */
ctimer_capture_channel_t input; /*!< Input channel to increment the timer, used only in timer
modes that rely on this input signal to increment TC */
uint32_t prescale; /*!< Prescale value */
} ctimer_config_t;
/*******************************************************************************
* API
******************************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif
/*!
* @name Initialization and deinitialization
* @{
*/
/*!
* @brief Ungates the clock and configures the peripheral for basic operation.
*
* @note This API should be called at the beginning of the application before using the driver.
*
* @param base Ctimer peripheral base address
* @param config Pointer to the user configuration structure.
*/
void CTIMER_Init(CTIMER_Type *base, const ctimer_config_t *config);
/*!
* @brief Gates the timer clock.
*
* @param base Ctimer peripheral base address
*/
void CTIMER_Deinit(CTIMER_Type *base);
/*!
* @brief Fills in the timers configuration structure with the default settings.
*
* The default values are:
* @code
* config->mode = kCTIMER_TimerMode;
* config->input = kCTIMER_Capture_0;
* config->prescale = 0;
* @endcode
* @param config Pointer to the user configuration structure.
*/
void CTIMER_GetDefaultConfig(ctimer_config_t *config);
/*! @}*/
/*!
* @name PWM setup operations
* @{
*/
/*!
* @brief Configures the PWM signal parameters.
*
* Enables PWM mode on the match channel passed in and will then setup the match value
* and other match parameters to generate a PWM signal.
* This function can manually assign the specified channel to set the PWM cycle.
*
* @note When setting PWM output from multiple output pins, all should use the same PWM
* period
*
* @param base Ctimer peripheral base address
* @param pwmPeriodChannel Specify the channel to control the PWM period
* @param matchChannel Match pin to be used to output the PWM signal
* @param pwmPeriod PWM period match value
* @param pulsePeriod Pulse width match value
* @param enableInt Enable interrupt when the timer value reaches the match value of the PWM pulse,
* if it is 0 then no interrupt will be generated.
*/
status_t CTIMER_SetupPwmPeriod(CTIMER_Type *base,
const ctimer_match_t pwmPeriodChannel,
ctimer_match_t matchChannel,
uint32_t pwmPeriod,
uint32_t pulsePeriod,
bool enableInt);
/*!
* @brief Configures the PWM signal parameters.
*
* Enables PWM mode on the match channel passed in and will then setup the match value
* and other match parameters to generate a PWM signal.
* This function can manually assign the specified channel to set the PWM cycle.
*
* @note When setting PWM output from multiple output pins, all should use the same PWM
* frequency. Please use CTIMER_SetupPwmPeriod to set up the PWM with high resolution.
*
* @param base Ctimer peripheral base address
* @param pwmPeriodChannel Specify the channel to control the PWM period
* @param matchChannel Match pin to be used to output the PWM signal
* @param dutyCyclePercent PWM pulse width; the value should be between 0 to 100
* @param pwmFreq_Hz PWM signal frequency in Hz
* @param srcClock_Hz Timer counter clock in Hz
* @param enableInt Enable interrupt when the timer value reaches the match value of the PWM pulse,
* if it is 0 then no interrupt will be generated.
*/
status_t CTIMER_SetupPwm(CTIMER_Type *base,
const ctimer_match_t pwmPeriodChannel,
ctimer_match_t matchChannel,
uint8_t dutyCyclePercent,
uint32_t pwmFreq_Hz,
uint32_t srcClock_Hz,
bool enableInt);
/*!
* @brief Updates the pulse period of an active PWM signal.
*
* @param base Ctimer peripheral base address
* @param matchChannel Match pin to be used to output the PWM signal
* @param pulsePeriod New PWM pulse width match value
*/
static inline void CTIMER_UpdatePwmPulsePeriod(CTIMER_Type *base, ctimer_match_t matchChannel, uint32_t pulsePeriod)
{
/* Update PWM pulse period match value */
base->MR[matchChannel] = pulsePeriod;
}
/*!
* @brief Updates the duty cycle of an active PWM signal.
*
* @note Please use CTIMER_SetupPwmPeriod to update the PWM with high resolution.
* This function can manually assign the specified channel to set the PWM cycle.
*
* @param base Ctimer peripheral base address
* @param pwmPeriodChannel Specify the channel to control the PWM period
* @param matchChannel Match pin to be used to output the PWM signal
* @param dutyCyclePercent New PWM pulse width; the value should be between 0 to 100
*/
void CTIMER_UpdatePwmDutycycle(CTIMER_Type *base,
const ctimer_match_t pwmPeriodChannel,
ctimer_match_t matchChannel,
uint8_t dutyCyclePercent);
/*! @}*/
/*!
* @brief Setup the match register.
*
* User configuration is used to setup the match value and action to be taken when a match occurs.
*
* @param base Ctimer peripheral base address
* @param matchChannel Match register to configure
* @param config Pointer to the match configuration structure
*/
void CTIMER_SetupMatch(CTIMER_Type *base, ctimer_match_t matchChannel, const ctimer_match_config_t *config);
/*!
* @brief Get the status of output match.
*
* This function gets the status of output MAT, whether or not this output is connected to a pin.
* This status is driven to the MAT pins if the match function is selected via IOCON. 0 = LOW. 1 = HIGH.
*
* @param base Ctimer peripheral base address
* @param matchChannel External match channel, user can obtain the status of multiple match channels
* at the same time by using the logic of "|"
* enumeration ::ctimer_external_match_t
* @return The mask of external match channel status flags. Users need to use the
* _ctimer_external_match type to decode the return variables.
*/
uint32_t CTIMER_GetOutputMatchStatus(CTIMER_Type *base, uint32_t matchChannel);
/*!
* @brief Setup the capture.
*
* @param base Ctimer peripheral base address
* @param capture Capture channel to configure
* @param edge Edge on the channel that will trigger a capture
* @param enableInt Flag to enable channel interrupts, if enabled then the registered call back
* is called upon capture
*/
void CTIMER_SetupCapture(CTIMER_Type *base,
ctimer_capture_channel_t capture,
ctimer_capture_edge_t edge,
bool enableInt);
/*!
* @brief Get the timer count value from TC register.
*
* @param base Ctimer peripheral base address.
* @return return the timer count value.
*/
static inline uint32_t CTIMER_GetTimerCountValue(CTIMER_Type *base)
{
return (base->TC);
}
/*!
* @brief Register callback.
*
* @param base Ctimer peripheral base address
* @param cb_func callback function
* @param cb_type callback function type, singular or multiple
*/
void CTIMER_RegisterCallBack(CTIMER_Type *base, ctimer_callback_t *cb_func, ctimer_callback_type_t cb_type);
/*!
* @name Interrupt Interface
* @{
*/
/*!
* @brief Enables the selected Timer interrupts.
*
* @param base Ctimer peripheral base address
* @param mask The interrupts to enable. This is a logical OR of members of the
* enumeration ::ctimer_interrupt_enable_t
*/
static inline void CTIMER_EnableInterrupts(CTIMER_Type *base, uint32_t mask)
{
/* Enable match interrupts */
base->MCR |= mask & (CTIMER_MCR_MR0I_MASK | CTIMER_MCR_MR1I_MASK | CTIMER_MCR_MR2I_MASK | CTIMER_MCR_MR3I_MASK);
/* Enable capture interrupts */
#if !(defined(FSL_FEATURE_CTIMER_HAS_NO_INPUT_CAPTURE) && (FSL_FEATURE_CTIMER_HAS_NO_INPUT_CAPTURE))
base->CCR |= mask & (CTIMER_CCR_CAP0I_MASK | CTIMER_CCR_CAP1I_MASK
#if !(defined(FSL_FEATURE_CTIMER_HAS_NO_CCR_CAP2) && FSL_FEATURE_CTIMER_HAS_NO_CCR_CAP2)
| CTIMER_CCR_CAP2I_MASK
#endif /* FSL_FEATURE_CTIMER_HAS_NO_CCR_CAP2 */
#if defined(FSL_FEATURE_CTIMER_HAS_CCR_CAP3) && FSL_FEATURE_CTIMER_HAS_CCR_CAP3
| CTIMER_CCR_CAP3I_MASK
#endif /* FSL_FEATURE_CTIMER_HAS_CCR_CAP3 */
);
#endif
}
/*!
* @brief Disables the selected Timer interrupts.
*
* @param base Ctimer peripheral base address
* @param mask The interrupts to enable. This is a logical OR of members of the
* enumeration ::ctimer_interrupt_enable_t
*/
static inline void CTIMER_DisableInterrupts(CTIMER_Type *base, uint32_t mask)
{
/* Disable match interrupts */
base->MCR &= ~(mask & (CTIMER_MCR_MR0I_MASK | CTIMER_MCR_MR1I_MASK | CTIMER_MCR_MR2I_MASK | CTIMER_MCR_MR3I_MASK));
/* Disable capture interrupts */
#if !(defined(FSL_FEATURE_CTIMER_HAS_NO_INPUT_CAPTURE) && (FSL_FEATURE_CTIMER_HAS_NO_INPUT_CAPTURE))
base->CCR &= ~(mask & (CTIMER_CCR_CAP0I_MASK | CTIMER_CCR_CAP1I_MASK
#if !(defined(FSL_FEATURE_CTIMER_HAS_NO_CCR_CAP2) && FSL_FEATURE_CTIMER_HAS_NO_CCR_CAP2)
| CTIMER_CCR_CAP2I_MASK
#endif /* FSL_FEATURE_CTIMER_HAS_NO_CCR_CAP2 */
#if defined(FSL_FEATURE_CTIMER_HAS_CCR_CAP3) && FSL_FEATURE_CTIMER_HAS_CCR_CAP3
| CTIMER_CCR_CAP3I_MASK
#endif /* FSL_FEATURE_CTIMER_HAS_CCR_CAP3 */
));
#endif
}
/*!
* @brief Gets the enabled Timer interrupts.
*
* @param base Ctimer peripheral base address
*
* @return The enabled interrupts. This is the logical OR of members of the
* enumeration ::ctimer_interrupt_enable_t
*/
static inline uint32_t CTIMER_GetEnabledInterrupts(CTIMER_Type *base)
{
uint32_t enabledIntrs = 0;
/* Get all the match interrupts enabled */
enabledIntrs =
base->MCR & (CTIMER_MCR_MR0I_MASK | CTIMER_MCR_MR1I_MASK | CTIMER_MCR_MR2I_MASK | CTIMER_MCR_MR3I_MASK);
/* Get all the capture interrupts enabled */
#if !(defined(FSL_FEATURE_CTIMER_HAS_NO_INPUT_CAPTURE) && (FSL_FEATURE_CTIMER_HAS_NO_INPUT_CAPTURE))
enabledIntrs |= base->CCR & (CTIMER_CCR_CAP0I_MASK | CTIMER_CCR_CAP1I_MASK
#if !(defined(FSL_FEATURE_CTIMER_HAS_NO_CCR_CAP2) && FSL_FEATURE_CTIMER_HAS_NO_CCR_CAP2)
| CTIMER_CCR_CAP2I_MASK
#endif /* FSL_FEATURE_CTIMER_HAS_NO_CCR_CAP2 */
#if defined(FSL_FEATURE_CTIMER_HAS_CCR_CAP3) && FSL_FEATURE_CTIMER_HAS_CCR_CAP3
| CTIMER_CCR_CAP3I_MASK
#endif /* FSL_FEATURE_CTIMER_HAS_CCR_CAP3 */
);
#endif
return enabledIntrs;
}
/*! @}*/
/*!
* @name Status Interface
* @{
*/
/*!
* @brief Gets the Timer status flags.
*
* @param base Ctimer peripheral base address
*
* @return The status flags. This is the logical OR of members of the
* enumeration ::ctimer_status_flags_t
*/
static inline uint32_t CTIMER_GetStatusFlags(CTIMER_Type *base)
{
return base->IR;
}
/*!
* @brief Clears the Timer status flags.
*
* @param base Ctimer peripheral base address
* @param mask The status flags to clear. This is a logical OR of members of the
* enumeration ::ctimer_status_flags_t
*/
static inline void CTIMER_ClearStatusFlags(CTIMER_Type *base, uint32_t mask)
{
base->IR = mask;
}
/*! @}*/
/*!
* @name Counter Start and Stop
* @{
*/
/*!
* @brief Starts the Timer counter.
*
* @param base Ctimer peripheral base address
*/
static inline void CTIMER_StartTimer(CTIMER_Type *base)
{
base->TCR |= CTIMER_TCR_CEN_MASK;
}
/*!
* @brief Stops the Timer counter.
*
* @param base Ctimer peripheral base address
*/
static inline void CTIMER_StopTimer(CTIMER_Type *base)
{
base->TCR &= ~CTIMER_TCR_CEN_MASK;
}
/*! @}*/
/*!
* @brief Reset the counter.
*
* The timer counter and prescale counter are reset on the next positive edge of the APB clock.
*
* @param base Ctimer peripheral base address
*/
static inline void CTIMER_Reset(CTIMER_Type *base)
{
base->TCR |= CTIMER_TCR_CRST_MASK;
base->TCR &= ~CTIMER_TCR_CRST_MASK;
}
#if defined(__cplusplus)
}
#endif
/*! @}*/
#endif /* _FSL_CTIMER_H_ */

356
drivers/fsl_flexcomm.c Normal file
View File

@@ -0,0 +1,356 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* Copyright 2016-2019 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "fsl_common.h"
#include "fsl_flexcomm.h"
/*******************************************************************************
* Definitions
******************************************************************************/
/* Component ID definition, used by tools. */
#ifndef FSL_COMPONENT_ID
#define FSL_COMPONENT_ID "platform.drivers.flexcomm"
#endif
/*!
* @brief Used for conversion between `void*` and `uint32_t`.
*/
typedef union pvoid_to_u32
{
void *pvoid;
uint32_t u32;
} pvoid_to_u32_t;
/*******************************************************************************
* Prototypes
******************************************************************************/
/*! @brief Set the FLEXCOMM mode . */
static status_t FLEXCOMM_SetPeriph(FLEXCOMM_Type *base, FLEXCOMM_PERIPH_T periph, int lock);
/*! @brief check whether flexcomm supports peripheral type */
static bool FLEXCOMM_PeripheralIsPresent(FLEXCOMM_Type *base, FLEXCOMM_PERIPH_T periph);
/*******************************************************************************
* Variables
******************************************************************************/
/*! @brief Pointers to real IRQ handlers installed by drivers for each instance. */
static flexcomm_irq_handler_t s_flexcommIrqHandler[FSL_FEATURE_SOC_FLEXCOMM_COUNT];
/*! @brief Pointers to handles for each instance to provide context to interrupt routines */
static void *s_flexcommHandle[FSL_FEATURE_SOC_FLEXCOMM_COUNT];
/*! @brief Array to map FLEXCOMM instance number to IRQ number. */
IRQn_Type const kFlexcommIrqs[] = FLEXCOMM_IRQS;
/*! @brief Array to map FLEXCOMM instance number to base address. */
static const uint32_t s_flexcommBaseAddrs[FSL_FEATURE_SOC_FLEXCOMM_COUNT] = FLEXCOMM_BASE_ADDRS;
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
/*! @brief IDs of clock for each FLEXCOMM module */
static const clock_ip_name_t s_flexcommClocks[] = FLEXCOMM_CLOCKS;
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
#if !(defined(FSL_FEATURE_FLEXCOMM_HAS_NO_RESET) && FSL_FEATURE_FLEXCOMM_HAS_NO_RESET)
/*! @brief Pointers to FLEXCOMM resets for each instance. */
static const reset_ip_name_t s_flexcommResets[] = FLEXCOMM_RSTS;
#endif
/*******************************************************************************
* Code
******************************************************************************/
/* check whether flexcomm supports peripheral type */
static bool FLEXCOMM_PeripheralIsPresent(FLEXCOMM_Type *base, FLEXCOMM_PERIPH_T periph)
{
if (periph == FLEXCOMM_PERIPH_NONE)
{
return true;
}
else if (periph <= FLEXCOMM_PERIPH_I2S_TX)
{
return (base->PSELID & (1UL << ((uint32_t)periph + 3U))) > 0UL ? true : false;
}
else if (periph == FLEXCOMM_PERIPH_I2S_RX)
{
return (base->PSELID & (1U << 7U)) > (uint32_t)0U ? true : false;
}
else
{
return false;
}
}
/* Get the index corresponding to the FLEXCOMM */
/*! brief Returns instance number for FLEXCOMM module with given base address. */
uint32_t FLEXCOMM_GetInstance(void *base)
{
uint32_t i;
pvoid_to_u32_t BaseAddr;
BaseAddr.pvoid = base;
for (i = 0U; i < (uint32_t)FSL_FEATURE_SOC_FLEXCOMM_COUNT; i++)
{
if (BaseAddr.u32 == s_flexcommBaseAddrs[i])
{
break;
}
}
assert(i < (uint32_t)FSL_FEATURE_SOC_FLEXCOMM_COUNT);
return i;
}
/* Changes FLEXCOMM mode */
static status_t FLEXCOMM_SetPeriph(FLEXCOMM_Type *base, FLEXCOMM_PERIPH_T periph, int lock)
{
/* Check whether peripheral type is present */
if (!FLEXCOMM_PeripheralIsPresent(base, periph))
{
return kStatus_OutOfRange;
}
/* Flexcomm is locked to different peripheral type than expected */
if (((base->PSELID & FLEXCOMM_PSELID_LOCK_MASK) != 0U) &&
((base->PSELID & FLEXCOMM_PSELID_PERSEL_MASK) != (uint32_t)periph))
{
return kStatus_Fail;
}
/* Check if we are asked to lock */
if (lock != 0)
{
base->PSELID = (uint32_t)periph | FLEXCOMM_PSELID_LOCK_MASK;
}
else
{
base->PSELID = (uint32_t)periph;
}
return kStatus_Success;
}
/*! brief Initializes FLEXCOMM and selects peripheral mode according to the second parameter. */
status_t FLEXCOMM_Init(void *base, FLEXCOMM_PERIPH_T periph)
{
uint32_t idx = FLEXCOMM_GetInstance(base);
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
/* Enable the peripheral clock */
CLOCK_EnableClock(s_flexcommClocks[idx]);
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
#if !(defined(FSL_FEATURE_FLEXCOMM_HAS_NO_RESET) && FSL_FEATURE_FLEXCOMM_HAS_NO_RESET)
/* Reset the FLEXCOMM module */
RESET_PeripheralReset(s_flexcommResets[idx]);
#endif
/* Set the FLEXCOMM to given peripheral */
return FLEXCOMM_SetPeriph((FLEXCOMM_Type *)base, periph, 0);
}
/*! brief Sets IRQ handler for given FLEXCOMM module. It is used by drivers register IRQ handler according to FLEXCOMM
* mode */
void FLEXCOMM_SetIRQHandler(void *base, flexcomm_irq_handler_t handler, void *flexcommHandle)
{
uint32_t instance;
/* Look up instance number */
instance = FLEXCOMM_GetInstance(base);
/* Clear handler first to avoid execution of the handler with wrong handle */
s_flexcommIrqHandler[instance] = NULL;
s_flexcommHandle[instance] = flexcommHandle;
s_flexcommIrqHandler[instance] = handler;
SDK_ISR_EXIT_BARRIER;
}
/* IRQ handler functions overloading weak symbols in the startup */
#if defined(FLEXCOMM0)
void FLEXCOMM0_DriverIRQHandler(void);
void FLEXCOMM0_DriverIRQHandler(void)
{
assert(s_flexcommIrqHandler[0]);
s_flexcommIrqHandler[0]((uint32_t *)s_flexcommBaseAddrs[0], s_flexcommHandle[0]);
SDK_ISR_EXIT_BARRIER;
}
#endif
#if defined(FLEXCOMM1)
void FLEXCOMM1_DriverIRQHandler(void);
void FLEXCOMM1_DriverIRQHandler(void)
{
assert(s_flexcommIrqHandler[1]);
s_flexcommIrqHandler[1]((uint32_t *)s_flexcommBaseAddrs[1], s_flexcommHandle[1]);
SDK_ISR_EXIT_BARRIER;
}
#endif
#if defined(FLEXCOMM2)
void FLEXCOMM2_DriverIRQHandler(void);
void FLEXCOMM2_DriverIRQHandler(void)
{
assert(s_flexcommIrqHandler[2]);
s_flexcommIrqHandler[2]((uint32_t *)s_flexcommBaseAddrs[2], s_flexcommHandle[2]);
SDK_ISR_EXIT_BARRIER;
}
#endif
#if defined(FLEXCOMM3)
void FLEXCOMM3_DriverIRQHandler(void);
void FLEXCOMM3_DriverIRQHandler(void)
{
assert(s_flexcommIrqHandler[3]);
s_flexcommIrqHandler[3]((uint32_t *)s_flexcommBaseAddrs[3], s_flexcommHandle[3]);
SDK_ISR_EXIT_BARRIER;
}
#endif
#if defined(FLEXCOMM4)
void FLEXCOMM4_DriverIRQHandler(void);
void FLEXCOMM4_DriverIRQHandler(void)
{
assert(s_flexcommIrqHandler[4]);
s_flexcommIrqHandler[4]((uint32_t *)s_flexcommBaseAddrs[4], s_flexcommHandle[4]);
SDK_ISR_EXIT_BARRIER;
}
#endif
#if defined(FLEXCOMM5)
void FLEXCOMM5_DriverIRQHandler(void);
void FLEXCOMM5_DriverIRQHandler(void)
{
assert(s_flexcommIrqHandler[5]);
s_flexcommIrqHandler[5]((uint32_t *)s_flexcommBaseAddrs[5], s_flexcommHandle[5]);
SDK_ISR_EXIT_BARRIER;
}
#endif
#if defined(FLEXCOMM6)
void FLEXCOMM6_DriverIRQHandler(void);
void FLEXCOMM6_DriverIRQHandler(void)
{
assert(s_flexcommIrqHandler[6]);
s_flexcommIrqHandler[6]((uint32_t *)s_flexcommBaseAddrs[6], s_flexcommHandle[6]);
SDK_ISR_EXIT_BARRIER;
}
#endif
#if defined(FLEXCOMM7)
void FLEXCOMM7_DriverIRQHandler(void);
void FLEXCOMM7_DriverIRQHandler(void)
{
assert(s_flexcommIrqHandler[7]);
s_flexcommIrqHandler[7]((uint32_t *)s_flexcommBaseAddrs[7], s_flexcommHandle[7]);
SDK_ISR_EXIT_BARRIER;
}
#endif
#if defined(FLEXCOMM8)
void FLEXCOMM8_DriverIRQHandler(void);
void FLEXCOMM8_DriverIRQHandler(void)
{
assert(s_flexcommIrqHandler[8]);
s_flexcommIrqHandler[8]((uint32_t *)s_flexcommBaseAddrs[8], s_flexcommHandle[8]);
SDK_ISR_EXIT_BARRIER;
}
#endif
#if defined(FLEXCOMM9)
void FLEXCOMM9_DriverIRQHandler(void);
void FLEXCOMM9_DriverIRQHandler(void)
{
assert(s_flexcommIrqHandler[9]);
s_flexcommIrqHandler[9]((uint32_t *)s_flexcommBaseAddrs[9], s_flexcommHandle[9]);
SDK_ISR_EXIT_BARRIER;
}
#endif
#if defined(FLEXCOMM10)
void FLEXCOMM10_DriverIRQHandler(void);
void FLEXCOMM10_DriverIRQHandler(void)
{
assert(s_flexcommIrqHandler[10]);
s_flexcommIrqHandler[10]((uint32_t *)s_flexcommBaseAddrs[10], s_flexcommHandle[10]);
SDK_ISR_EXIT_BARRIER;
}
#endif
#if defined(FLEXCOMM11)
void FLEXCOMM11_DriverIRQHandler(void);
void FLEXCOMM11_DriverIRQHandler(void)
{
assert(s_flexcommIrqHandler[11]);
s_flexcommIrqHandler[11]((uint32_t *)s_flexcommBaseAddrs[11], s_flexcommHandle[11]);
SDK_ISR_EXIT_BARRIER;
}
#endif
#if defined(FLEXCOMM12)
void FLEXCOMM12_DriverIRQHandler(void);
void FLEXCOMM12_DriverIRQHandler(void)
{
assert(s_flexcommIrqHandler[12]);
s_flexcommIrqHandler[12]((uint32_t *)s_flexcommBaseAddrs[12], s_flexcommHandle[12]);
SDK_ISR_EXIT_BARRIER;
}
#endif
#if defined(FLEXCOMM13)
void FLEXCOMM13_DriverIRQHandler(void);
void FLEXCOMM13_DriverIRQHandler(void)
{
assert(s_flexcommIrqHandler[13]);
s_flexcommIrqHandler[13]((uint32_t *)s_flexcommBaseAddrs[13], s_flexcommHandle[13]);
SDK_ISR_EXIT_BARRIER;
}
#endif
#if defined(FLEXCOMM14)
void FLEXCOMM14_DriverIRQHandler(void);
void FLEXCOMM14_DriverIRQHandler(void)
{
uint32_t instance;
/* Look up instance number */
instance = FLEXCOMM_GetInstance(FLEXCOMM14);
assert(s_flexcommIrqHandler[instance]);
s_flexcommIrqHandler[instance]((uint32_t *)s_flexcommBaseAddrs[instance], s_flexcommHandle[instance]);
SDK_ISR_EXIT_BARRIER;
}
#endif
#if defined(FLEXCOMM15)
void FLEXCOMM15_DriverIRQHandler(void);
void FLEXCOMM15_DriverIRQHandler(void)
{
uint32_t instance;
/* Look up instance number */
instance = FLEXCOMM_GetInstance(FLEXCOMM15);
assert(s_flexcommIrqHandler[instance]);
s_flexcommIrqHandler[instance]((uint32_t *)s_flexcommBaseAddrs[instance], s_flexcommHandle[instance]);
SDK_ISR_EXIT_BARRIER;
}
#endif
#if defined(FLEXCOMM16)
void FLEXCOMM16_DriverIRQHandler(void);
void FLEXCOMM16_DriverIRQHandler(void)
{
uint32_t instance;
/* Look up instance number */
instance = FLEXCOMM_GetInstance(FLEXCOMM16);
assert(s_flexcommIrqHandler[instance]);
s_flexcommIrqHandler[instance]((uint32_t *)s_flexcommBaseAddrs[instance], s_flexcommHandle[instance]);
SDK_ISR_EXIT_BARRIER;
}
#endif

64
drivers/fsl_flexcomm.h Normal file
View File

@@ -0,0 +1,64 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* Copyright 2016-2019 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _FSL_FLEXCOMM_H_
#define _FSL_FLEXCOMM_H_
#include "fsl_common.h"
/*!
* @addtogroup flexcomm_driver
* @{
*/
/*! @name Driver version */
/*@{*/
/*! @brief FlexCOMM driver version 2.0.2. */
#define FSL_FLEXCOMM_DRIVER_VERSION (MAKE_VERSION(2, 0, 2))
/*@}*/
/*! @brief FLEXCOMM peripheral modes. */
typedef enum
{
FLEXCOMM_PERIPH_NONE, /*!< No peripheral */
FLEXCOMM_PERIPH_USART, /*!< USART peripheral */
FLEXCOMM_PERIPH_SPI, /*!< SPI Peripheral */
FLEXCOMM_PERIPH_I2C, /*!< I2C Peripheral */
FLEXCOMM_PERIPH_I2S_TX, /*!< I2S TX Peripheral */
FLEXCOMM_PERIPH_I2S_RX, /*!< I2S RX Peripheral */
} FLEXCOMM_PERIPH_T;
/*! @brief Typedef for interrupt handler. */
typedef void (*flexcomm_irq_handler_t)(void *base, void *handle);
/*! @brief Array with IRQ number for each FLEXCOMM module. */
extern IRQn_Type const kFlexcommIrqs[];
/*******************************************************************************
* API
******************************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif
/*! @brief Returns instance number for FLEXCOMM module with given base address. */
uint32_t FLEXCOMM_GetInstance(void *base);
/*! @brief Initializes FLEXCOMM and selects peripheral mode according to the second parameter. */
status_t FLEXCOMM_Init(void *base, FLEXCOMM_PERIPH_T periph);
/*! @brief Sets IRQ handler for given FLEXCOMM module. It is used by drivers register IRQ handler according to FLEXCOMM
* mode */
void FLEXCOMM_SetIRQHandler(void *base, flexcomm_irq_handler_t handler, void *flexcommHandle);
#if defined(__cplusplus)
}
#endif
/*@}*/
#endif /* _FSL_FLEXCOMM_H_*/

317
drivers/fsl_gpio.c Normal file
View File

@@ -0,0 +1,317 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* Copyright 2016-2020 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "fsl_gpio.h"
/* Component ID definition, used by tools. */
#ifndef FSL_COMPONENT_ID
#define FSL_COMPONENT_ID "platform.drivers.lpc_gpio"
#endif
/*******************************************************************************
* Variables
******************************************************************************/
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
/*! @brief Array to map FGPIO instance number to clock name. */
static const clock_ip_name_t s_gpioClockName[] = GPIO_CLOCKS;
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
#if !(defined(FSL_FEATURE_GPIO_HAS_NO_RESET) && FSL_FEATURE_GPIO_HAS_NO_RESET)
/*! @brief Pointers to GPIO resets for each instance. */
static const reset_ip_name_t s_gpioResets[] = GPIO_RSTS_N;
#endif
/*******************************************************************************
* Prototypes
************ ******************************************************************/
/*!
* @brief Enable GPIO port clock.
*
* @param base GPIO peripheral base pointer.
* @param port GPIO port number.
*/
static void GPIO_EnablePortClock(GPIO_Type *base, uint32_t port);
/*******************************************************************************
* Code
******************************************************************************/
static void GPIO_EnablePortClock(GPIO_Type *base, uint32_t port)
{
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
assert(port < ARRAY_SIZE(s_gpioClockName));
/* Upgate the GPIO clock */
CLOCK_EnableClock(s_gpioClockName[port]);
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
}
/*!
* brief Initializes the GPIO peripheral.
*
* This function ungates the GPIO clock.
*
* param base GPIO peripheral base pointer.
* param port GPIO port number.
*/
void GPIO_PortInit(GPIO_Type *base, uint32_t port)
{
GPIO_EnablePortClock(base, port);
#if !(defined(FSL_FEATURE_GPIO_HAS_NO_RESET) && FSL_FEATURE_GPIO_HAS_NO_RESET)
/* Reset the GPIO module */
RESET_PeripheralReset(s_gpioResets[port]);
#endif
}
/*!
* brief Initializes a GPIO pin used by the board.
*
* To initialize the GPIO, define a pin configuration, either input or output, in the user file.
* Then, call the GPIO_PinInit() function.
*
* This is an example to define an input pin or output pin configuration:
* code
* Define a digital input pin configuration,
* gpio_pin_config_t config =
* {
* kGPIO_DigitalInput,
* 0,
* }
* Define a digital output pin configuration,
* gpio_pin_config_t config =
* {
* kGPIO_DigitalOutput,
* 0,
* }
* endcode
*
* param base GPIO peripheral base pointer(Typically GPIO)
* param port GPIO port number
* param pin GPIO pin number
* param config GPIO pin configuration pointer
*/
void GPIO_PinInit(GPIO_Type *base, uint32_t port, uint32_t pin, const gpio_pin_config_t *config)
{
GPIO_EnablePortClock(base, port);
if (config->pinDirection == kGPIO_DigitalInput)
{
#if defined(FSL_FEATURE_GPIO_DIRSET_AND_DIRCLR) && (FSL_FEATURE_GPIO_DIRSET_AND_DIRCLR)
base->DIRCLR[port] = 1UL << pin;
#else
base->DIR[port] &= ~(1UL << pin);
#endif /*FSL_FEATURE_GPIO_DIRSET_AND_DIRCLR*/
}
else
{
/* Set default output value */
if (config->outputLogic == 0U)
{
base->CLR[port] = (1UL << pin);
}
else
{
base->SET[port] = (1UL << pin);
}
/* Set pin direction */
#if defined(FSL_FEATURE_GPIO_DIRSET_AND_DIRCLR) && (FSL_FEATURE_GPIO_DIRSET_AND_DIRCLR)
base->DIRSET[port] = 1UL << pin;
#else
base->DIR[port] |= 1UL << pin;
#endif /*FSL_FEATURE_GPIO_DIRSET_AND_DIRCLR*/
}
}
#if defined(FSL_FEATURE_GPIO_HAS_INTERRUPT) && FSL_FEATURE_GPIO_HAS_INTERRUPT
/*!
* @brief Set the configuration of pin interrupt.
*
* @param base GPIO base pointer.
* @param port GPIO port number
* @param pin GPIO pin number.
* @param config GPIO pin interrupt configuration..
*/
void GPIO_SetPinInterruptConfig(GPIO_Type *base, uint32_t port, uint32_t pin, gpio_interrupt_config_t *config)
{
base->INTEDG[port] = (base->INTEDG[port] & ~(1UL << pin)) | ((uint32_t)config->mode << pin);
base->INTPOL[port] = (base->INTPOL[port] & ~(1UL << pin)) | ((uint32_t)config->polarity << pin);
}
/*!
* @brief Enables multiple pins interrupt.
*
* @param base GPIO base pointer.
* @param port GPIO port number.
* @param index GPIO interrupt number.
* @param mask GPIO pin number macro.
*/
void GPIO_PortEnableInterrupts(GPIO_Type *base, uint32_t port, uint32_t index, uint32_t mask)
{
if ((uint32_t)kGPIO_InterruptA == index)
{
base->INTENA[port] = base->INTENA[port] | mask;
}
else if ((uint32_t)kGPIO_InterruptB == index)
{
base->INTENB[port] = base->INTENB[port] | mask;
}
else
{
/*Should not enter here*/
}
}
/*!
* @brief Disables multiple pins interrupt.
*
* @param base GPIO base pointer.
* @param port GPIO port number.
* @param index GPIO interrupt number.
* @param mask GPIO pin number macro.
*/
void GPIO_PortDisableInterrupts(GPIO_Type *base, uint32_t port, uint32_t index, uint32_t mask)
{
if ((uint32_t)kGPIO_InterruptA == index)
{
base->INTENA[port] = base->INTENA[port] & ~mask;
}
else if ((uint32_t)kGPIO_InterruptB == index)
{
base->INTENB[port] = base->INTENB[port] & ~mask;
}
else
{
/*Should not enter here*/
}
}
/*!
* @brief Clears multiple pins interrupt flag. Status flags are cleared by
* writing a 1 to the corresponding bit position.
*
* @param base GPIO base pointer.
* @param port GPIO port number.
* @param index GPIO interrupt number.
* @param mask GPIO pin number macro.
*/
void GPIO_PortClearInterruptFlags(GPIO_Type *base, uint32_t port, uint32_t index, uint32_t mask)
{
if ((uint32_t)kGPIO_InterruptA == index)
{
base->INTSTATA[port] = mask;
}
else if ((uint32_t)kGPIO_InterruptB == index)
{
base->INTSTATB[port] = mask;
}
else
{
/*Should not enter here*/
}
}
/*!
* @ Read port interrupt status.
*
* @param base GPIO base pointer.
* @param port GPIO port number
* @param index GPIO interrupt number.
* @retval masked GPIO status value
*/
uint32_t GPIO_PortGetInterruptStatus(GPIO_Type *base, uint32_t port, uint32_t index)
{
uint32_t status = 0U;
if ((uint32_t)kGPIO_InterruptA == index)
{
status = base->INTSTATA[port];
}
else if ((uint32_t)kGPIO_InterruptB == index)
{
status = base->INTSTATB[port];
}
else
{
/*Should not enter here*/
}
return status;
}
/*!
* @brief Enables the specific pin interrupt.
*
* @param base GPIO base pointer.
* @param port GPIO port number.
* @param pin GPIO pin number.
* @param index GPIO interrupt number.
*/
void GPIO_PinEnableInterrupt(GPIO_Type *base, uint32_t port, uint32_t pin, uint32_t index)
{
if ((uint32_t)kGPIO_InterruptA == index)
{
base->INTENA[port] = base->INTENA[port] | (1UL << pin);
}
else if ((uint32_t)kGPIO_InterruptB == index)
{
base->INTENB[port] = base->INTENB[port] | (1UL << pin);
}
else
{
/*Should not enter here*/
}
}
/*!
* @brief Disables the specific pin interrupt.
*
* @param base GPIO base pointer.
* @param port GPIO port number.
* @param pin GPIO pin number.
* @param index GPIO interrupt number.
*/
void GPIO_PinDisableInterrupt(GPIO_Type *base, uint32_t port, uint32_t pin, uint32_t index)
{
if ((uint32_t)kGPIO_InterruptA == index)
{
base->INTENA[port] = base->INTENA[port] & ~(1UL << pin);
}
else if ((uint32_t)kGPIO_InterruptB == index)
{
base->INTENB[port] = base->INTENB[port] & ~(1UL << pin);
}
else
{
/*Should not enter here*/
}
}
/*!
* @brief Clears the specific pin interrupt flag. Status flags are cleared by
* writing a 1 to the corresponding bit position.
*
* @param base GPIO base pointer.
* @param port GPIO port number.
* @param index GPIO interrupt number.
* @param mask GPIO pin number macro.
*/
void GPIO_PinClearInterruptFlag(GPIO_Type *base, uint32_t port, uint32_t pin, uint32_t index)
{
if ((uint32_t)kGPIO_InterruptA == index)
{
base->INTSTATA[port] = 1UL << pin;
}
else if ((uint32_t)kGPIO_InterruptB == index)
{
base->INTSTATB[port] = 1UL << pin;
}
else
{
/*Should not enter here*/
}
}
#endif /* FSL_FEATURE_GPIO_HAS_INTERRUPT */

364
drivers/fsl_gpio.h Normal file
View File

@@ -0,0 +1,364 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* Copyright 2016-2020 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _LPC_GPIO_H_
#define _LPC_GPIO_H_
#include "fsl_common.h"
/*!
* @addtogroup lpc_gpio
* @{
*/
/*! @file */
/*******************************************************************************
* Definitions
******************************************************************************/
/*! @name Driver version */
/*@{*/
/*! @brief LPC GPIO driver version. */
#define FSL_GPIO_DRIVER_VERSION (MAKE_VERSION(2, 1, 7))
/*@}*/
/*! @brief LPC GPIO direction definition */
typedef enum _gpio_pin_direction
{
kGPIO_DigitalInput = 0U, /*!< Set current pin as digital input*/
kGPIO_DigitalOutput = 1U, /*!< Set current pin as digital output*/
} gpio_pin_direction_t;
/*!
* @brief The GPIO pin configuration structure.
*
* Every pin can only be configured as either output pin or input pin at a time.
* If configured as a input pin, then leave the outputConfig unused.
*/
typedef struct _gpio_pin_config
{
gpio_pin_direction_t pinDirection; /*!< GPIO direction, input or output */
/* Output configurations, please ignore if configured as a input one */
uint8_t outputLogic; /*!< Set default output logic, no use in input */
} gpio_pin_config_t;
#if (defined(FSL_FEATURE_GPIO_HAS_INTERRUPT) && FSL_FEATURE_GPIO_HAS_INTERRUPT)
#define GPIO_PIN_INT_LEVEL 0x00U
#define GPIO_PIN_INT_EDGE 0x01U
#define PINT_PIN_INT_HIGH_OR_RISE_TRIGGER 0x00U
#define PINT_PIN_INT_LOW_OR_FALL_TRIGGER 0x01U
/*! @brief GPIO Pin Interrupt enable mode */
typedef enum _gpio_pin_enable_mode
{
kGPIO_PinIntEnableLevel = GPIO_PIN_INT_LEVEL, /*!< Generate Pin Interrupt on level mode */
kGPIO_PinIntEnableEdge = GPIO_PIN_INT_EDGE /*!< Generate Pin Interrupt on edge mode */
} gpio_pin_enable_mode_t;
/*! @brief GPIO Pin Interrupt enable polarity */
typedef enum _gpio_pin_enable_polarity
{
kGPIO_PinIntEnableHighOrRise =
PINT_PIN_INT_HIGH_OR_RISE_TRIGGER, /*!< Generate Pin Interrupt on high level or rising edge */
kGPIO_PinIntEnableLowOrFall =
PINT_PIN_INT_LOW_OR_FALL_TRIGGER /*!< Generate Pin Interrupt on low level or falling edge */
} gpio_pin_enable_polarity_t;
/*! @brief LPC GPIO interrupt index definition */
typedef enum _gpio_interrupt_index
{
kGPIO_InterruptA = 0U, /*!< Set current pin as interrupt A*/
kGPIO_InterruptB = 1U, /*!< Set current pin as interrupt B*/
} gpio_interrupt_index_t;
/*! @brief Configures the interrupt generation condition. */
typedef struct _gpio_interrupt_config
{
uint8_t mode; /* The trigger mode of GPIO interrupts */
uint8_t polarity; /* The polarity of GPIO interrupts */
} gpio_interrupt_config_t;
#endif
/*******************************************************************************
* API
******************************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif
/*! @name GPIO Configuration */
/*@{*/
/*!
* @brief Initializes the GPIO peripheral.
*
* This function ungates the GPIO clock.
*
* @param base GPIO peripheral base pointer.
* @param port GPIO port number.
*/
void GPIO_PortInit(GPIO_Type *base, uint32_t port);
/*!
* @brief Initializes a GPIO pin used by the board.
*
* To initialize the GPIO, define a pin configuration, either input or output, in the user file.
* Then, call the GPIO_PinInit() function.
*
* This is an example to define an input pin or output pin configuration:
* @code
* Define a digital input pin configuration,
* gpio_pin_config_t config =
* {
* kGPIO_DigitalInput,
* 0,
* }
* Define a digital output pin configuration,
* gpio_pin_config_t config =
* {
* kGPIO_DigitalOutput,
* 0,
* }
* @endcode
*
* @param base GPIO peripheral base pointer(Typically GPIO)
* @param port GPIO port number
* @param pin GPIO pin number
* @param config GPIO pin configuration pointer
*/
void GPIO_PinInit(GPIO_Type *base, uint32_t port, uint32_t pin, const gpio_pin_config_t *config);
/*@}*/
/*! @name GPIO Output Operations */
/*@{*/
/*!
* @brief Sets the output level of the one GPIO pin to the logic 1 or 0.
*
* @param base GPIO peripheral base pointer(Typically GPIO)
* @param port GPIO port number
* @param pin GPIO pin number
* @param output GPIO pin output logic level.
* - 0: corresponding pin output low-logic level.
* - 1: corresponding pin output high-logic level.
*/
static inline void GPIO_PinWrite(GPIO_Type *base, uint32_t port, uint32_t pin, uint8_t output)
{
base->B[port][pin] = output;
}
/*@}*/
/*! @name GPIO Input Operations */
/*@{*/
/*!
* @brief Reads the current input value of the GPIO PIN.
*
* @param base GPIO peripheral base pointer(Typically GPIO)
* @param port GPIO port number
* @param pin GPIO pin number
* @retval GPIO port input value
* - 0: corresponding pin input low-logic level.
* - 1: corresponding pin input high-logic level.
*/
static inline uint32_t GPIO_PinRead(GPIO_Type *base, uint32_t port, uint32_t pin)
{
return (uint32_t)base->B[port][pin];
}
/*@}*/
/*!
* @brief Sets the output level of the multiple GPIO pins to the logic 1.
*
* @param base GPIO peripheral base pointer(Typically GPIO)
* @param port GPIO port number
* @param mask GPIO pin number macro
*/
static inline void GPIO_PortSet(GPIO_Type *base, uint32_t port, uint32_t mask)
{
base->SET[port] = mask;
}
/*!
* @brief Sets the output level of the multiple GPIO pins to the logic 0.
*
* @param base GPIO peripheral base pointer(Typically GPIO)
* @param port GPIO port number
* @param mask GPIO pin number macro
*/
static inline void GPIO_PortClear(GPIO_Type *base, uint32_t port, uint32_t mask)
{
base->CLR[port] = mask;
}
/*!
* @brief Reverses current output logic of the multiple GPIO pins.
*
* @param base GPIO peripheral base pointer(Typically GPIO)
* @param port GPIO port number
* @param mask GPIO pin number macro
*/
static inline void GPIO_PortToggle(GPIO_Type *base, uint32_t port, uint32_t mask)
{
base->NOT[port] = mask;
}
/*@}*/
/*!
* @brief Reads the current input value of the whole GPIO port.
*
* @param base GPIO peripheral base pointer(Typically GPIO)
* @param port GPIO port number
*/
static inline uint32_t GPIO_PortRead(GPIO_Type *base, uint32_t port)
{
return (uint32_t)base->PIN[port];
}
/*@}*/
/*! @name GPIO Mask Operations */
/*@{*/
/*!
* @brief Sets port mask, 0 - enable pin, 1 - disable pin.
*
* @param base GPIO peripheral base pointer(Typically GPIO)
* @param port GPIO port number
* @param mask GPIO pin number macro
*/
static inline void GPIO_PortMaskedSet(GPIO_Type *base, uint32_t port, uint32_t mask)
{
base->MASK[port] = mask;
}
/*!
* @brief Sets the output level of the masked GPIO port. Only pins enabled by GPIO_SetPortMask() will be affected.
*
* @param base GPIO peripheral base pointer(Typically GPIO)
* @param port GPIO port number
* @param output GPIO port output value.
*/
static inline void GPIO_PortMaskedWrite(GPIO_Type *base, uint32_t port, uint32_t output)
{
base->MPIN[port] = output;
}
/*!
* @brief Reads the current input value of the masked GPIO port. Only pins enabled by GPIO_SetPortMask() will be
* affected.
*
* @param base GPIO peripheral base pointer(Typically GPIO)
* @param port GPIO port number
* @retval masked GPIO port value
*/
static inline uint32_t GPIO_PortMaskedRead(GPIO_Type *base, uint32_t port)
{
return (uint32_t)base->MPIN[port];
}
#if defined(FSL_FEATURE_GPIO_HAS_INTERRUPT) && FSL_FEATURE_GPIO_HAS_INTERRUPT
/*!
* @brief Set the configuration of pin interrupt.
*
* @param base GPIO base pointer.
* @param port GPIO port number
* @param pin GPIO pin number.
* @param config GPIO pin interrupt configuration..
*/
void GPIO_SetPinInterruptConfig(GPIO_Type *base, uint32_t port, uint32_t pin, gpio_interrupt_config_t *config);
/*!
* @brief Enables multiple pins interrupt.
*
* @param base GPIO base pointer.
* @param port GPIO port number.
* @param index GPIO interrupt number.
* @param mask GPIO pin number macro.
*/
void GPIO_PortEnableInterrupts(GPIO_Type *base, uint32_t port, uint32_t index, uint32_t mask);
/*!
* @brief Disables multiple pins interrupt.
*
* @param base GPIO base pointer.
* @param port GPIO port number.
* @param index GPIO interrupt number.
* @param mask GPIO pin number macro.
*/
void GPIO_PortDisableInterrupts(GPIO_Type *base, uint32_t port, uint32_t index, uint32_t mask);
/*!
* @brief Clears pin interrupt flag. Status flags are cleared by
* writing a 1 to the corresponding bit position.
*
* @param base GPIO base pointer.
* @param port GPIO port number.
* @param index GPIO interrupt number.
* @param mask GPIO pin number macro.
*/
void GPIO_PortClearInterruptFlags(GPIO_Type *base, uint32_t port, uint32_t index, uint32_t mask);
/*!
* @ Read port interrupt status.
*
* @param base GPIO base pointer.
* @param port GPIO port number
* @param index GPIO interrupt number.
* @retval masked GPIO status value
*/
uint32_t GPIO_PortGetInterruptStatus(GPIO_Type *base, uint32_t port, uint32_t index);
/*!
* @brief Enables the specific pin interrupt.
*
* @param base GPIO base pointer.
* @param port GPIO port number.
* @param pin GPIO pin number.
* @param index GPIO interrupt number.
*/
void GPIO_PinEnableInterrupt(GPIO_Type *base, uint32_t port, uint32_t pin, uint32_t index);
/*!
* @brief Disables the specific pin interrupt.
*
* @param base GPIO base pointer.
* @param port GPIO port number.
* @param pin GPIO pin number.
* @param index GPIO interrupt number.
*/
void GPIO_PinDisableInterrupt(GPIO_Type *base, uint32_t port, uint32_t pin, uint32_t index);
/*!
* @brief Clears the specific pin interrupt flag. Status flags are cleared by
* writing a 1 to the corresponding bit position.
*
* @param base GPIO base pointer.
* @param port GPIO port number.
* @param pin GPIO pin number.
* @param index GPIO interrupt number.
*/
void GPIO_PinClearInterruptFlag(GPIO_Type *base, uint32_t port, uint32_t pin, uint32_t index);
#endif /* FSL_FEATURE_GPIO_HAS_INTERRUPT */
/*@}*/
#if defined(__cplusplus)
}
#endif
/*!
* @}
*/
#endif /* _LPC_GPIO_H_*/

584
drivers/fsl_iap.c Normal file
View File

@@ -0,0 +1,584 @@
/*
* Copyright 2018-2020 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "fsl_iap.h"
/* Component ID definition, used by tools. */
#ifndef FSL_COMPONENT_ID
#define FSL_COMPONENT_ID "platform.drivers.iap"
#endif
#define HZ_TO_KHZ_DIV 1000U
/*******************************************************************************
* Definitions
******************************************************************************/
/*! @brief IAP_ENTRY API function type */
typedef void (*IAP_ENTRY_T)(uint32_t cmd[], uint32_t stat[]);
/*******************************************************************************
* Prototypes
******************************************************************************/
/*!
* @brief Translate the IAP return status.
*
* @param status IAP status return from the IAP function.
*
* @return sdk status code.
*/
static inline status_t translate_iap_status(uint32_t status);
/*!
* @brief IAP_ENTRY API function type.
*
* Wrapper for rom iap call.
*
* @param cmd_param IAP command and relevant parameter array.
* @param status_result IAP status result array.
*/
static inline void iap_entry(uint32_t *cmd_param, uint32_t *status_result);
/*******************************************************************************
* Variables
******************************************************************************/
/*******************************************************************************
* Code
******************************************************************************/
static inline status_t translate_iap_status(uint32_t status)
{
status_t ret = (status_t)status;
/* Translate IAP return code to sdk status code */
if (status != (uint32_t)kStatus_Success)
{
ret = MAKE_STATUS((int32_t)kStatusGroup_IAP, (int32_t)status);
}
return ret;
}
static inline void iap_entry(uint32_t *cmd_param, uint32_t *status_result)
{
__disable_irq();
((IAP_ENTRY_T)FSL_FEATURE_SYSCON_IAP_ENTRY_LOCATION)(cmd_param, status_result);
__enable_irq();
}
/*!
* @brief Read part identification number.
*
* This function is used to read the part identification number.
*
* @param partID Address to store the part identification number.
*
* @retval kStatus_IAP_Success Api has been executed successfully.
*/
status_t IAP_ReadPartID(uint32_t *partID)
{
uint32_t command[5] = {0x00U};
uint32_t result[5] = {0x00U};
command[0] = (uint32_t)kIapCmd_IAP_ReadPartId;
iap_entry(command, result);
*partID = result[1];
return translate_iap_status(result[0]);
}
/*!
* @brief Read boot code version number.
*
* This function is used to read the boot code version number.
*
* @param bootCodeVersion Address to store the boot code version.
*
* @retval kStatus_IAP_Success Api has been executed successfully.
*
* note Boot code version is two 32-bit words. Word 0 is the major version, word 1 is the minor version.
*/
status_t IAP_ReadBootCodeVersion(uint32_t *bootCodeVersion)
{
uint32_t command[5] = {0x00U};
uint32_t result[5] = {0x00U};
command[0] = (uint32_t)kIapCmd_IAP_Read_BootromVersion;
iap_entry(command, result);
bootCodeVersion[0] = result[1];
bootCodeVersion[1] = result[2];
return translate_iap_status(result[0]);
}
/*!
* @brief Reinvoke ISP.
*
* This function is used to invoke the boot loader in ISP mode. It maps boot vectors and configures the peripherals for
* ISP.
*
* @param ispTyoe ISP type selection.
* @param status store the possible status.
*
* @retval kStatus_IAP_ReinvokeISPConfig reinvoke configuration error.
*
* note The error response will be returned when IAP is disabled or an invalid ISP type selection appears. The call
* won't return unless an error occurs, so there can be no status code.
*/
void IAP_ReinvokeISP(uint8_t ispType, uint32_t *status)
{
uint32_t command[5] = {0x00U};
uint32_t result[5] = {0x00U};
uint8_t ispParameterArray[8];
command[0] = (uint32_t)kIapCmd_IAP_ReinvokeISP;
(void)memset(ispParameterArray, 0, sizeof(uint8_t) * 8U);
ispParameterArray[1] = ispType;
ispParameterArray[7] = ispParameterArray[0] ^ ispParameterArray[1] ^ ispParameterArray[2] ^ ispParameterArray[3] ^
ispParameterArray[4] ^ ispParameterArray[5] ^ ispParameterArray[6];
command[1] = (uint32_t)ispParameterArray;
iap_entry(command, result);
*status = (uint32_t)translate_iap_status(result[0]);
}
/*!
* @brief Read unique identification.
*
* This function is used to read the unique id.
*
* @param uniqueID store the uniqueID.
*
* @retval kStatus_IAP_Success Api has been executed successfully.
*/
status_t IAP_ReadUniqueID(uint32_t *uniqueID)
{
#if defined(FSL_FEATURE_IAP_READ_UNIQUE_ID_NOWORK) && FSL_FEATURE_IAP_READ_UNIQUE_ID_NOWORK
uint32_t *result = (uint32_t *)0x01000100;
uint8_t i = 0;
for (i = 0; i < 4; i++)
uniqueID[i] = result[i];
return kStatus_IAP_Success;
#else
uint32_t command[5] = {0x00U};
uint32_t result[5] = {0x00U};
command[0] = (uint32_t)kIapCmd_IAP_ReadUid;
iap_entry(command, result);
uniqueID[0] = result[1];
uniqueID[1] = result[2];
uniqueID[2] = result[3];
uniqueID[3] = result[4];
return translate_iap_status(result[0]);
#endif
}
#if defined(FLASH_CTRL_FLASHCFG_FLASHTIM_MASK)
/*!
* @brief Flash memory access time.
*
* This function is used to configure the access time to the flash memory.
*
* @param accessTime Flash memory access time FLASHTIM +1 is equal to the
* number of system clocks used for flash access.
*/
void IAP_ConfigAccessFlashTime(uint32_t accessTime)
{
uint32_t temp;
temp = FLASH_CTRL->FLASHCFG;
temp &= ~FLASH_CTRL_FLASHCFG_FLASHTIM_MASK;
FLASH_CTRL->FLASHCFG = temp | FLASH_CTRL_FLASHCFG_FLASHTIM(accessTime);
}
#endif
#if defined(FSL_FEATURE_IAP_HAS_READ_FACTORY_SETTINGS_FUNCTION) && FSL_FEATURE_IAP_HAS_READ_FACTORY_SETTINGS_FUNCTION
/*!
* @brief Read factory settings.
*
* This function reads the factory settings for calibration registers.
*
* @param dstRegAddr Address of the targeted calibration register.
* @param factoryValue Store the factory value
*
* @retval kStatus_IAP_Success Api has been executed successfully.
* @retval kStatus_IAP_ParamError Param0 is not one of the supported calibration registers.
*/
status_t IAP_ReadFactorySettings(uint32_t dstRegAddr, uint32_t *factoryValue)
{
uint32_t command[5] = {0x00U};
uint32_t result[5] = {0x00U};
command[0] = (uint32_t)kIapCmd_IAP_ReadFactorySettings;
command[1] = dstRegAddr;
iap_entry(command, result);
*factoryValue = result[1];
return translate_iap_status(result[0]);
}
#endif /* FSL_FEATURE_IAP_HAS_READ_FACTORY_SETTINGS_FUNCTION */
#if defined(FSL_FEATURE_IAP_HAS_FLASH_FUNCTION) && FSL_FEATURE_IAP_HAS_FLASH_FUNCTION
/*!
* @brief Prepare sector for write operation.
*
* This function prepares sector(s) for write/erase operation. This function must be called before calling the
* IAP_CopyRamToFlash() or IAP_EraseSector() or IAP_ErasePage() function. The end sector number must be greater than or
* equal to the start sector number.
*
* @param startSector Start sector number.
* @param endSector End sector number.
*
* @retval kStatus_IAP_Success Api has been executed successfully.
* @retval kStatus_IAP_NoPower Flash memory block is powered down.
* @retval kStatus_IAP_NoClock Flash memory block or controller is not clocked.
* @retval kStatus_IAP_InvalidSector Sector number is invalid or end sector number is greater than start sector number.
* @retval kStatus_IAP_Busy Flash programming hardware interface is busy.
*/
status_t IAP_PrepareSectorForWrite(uint32_t startSector, uint32_t endSector)
{
uint32_t command[5] = {0x00U};
uint32_t result[5] = {0x00U};
command[0] = (uint32_t)kIapCmd_IAP_PrepareSectorforWrite;
command[1] = startSector;
command[2] = endSector;
iap_entry(command, result);
return translate_iap_status(result[0]);
}
/*!
* @brief Copy RAM to flash.
*
* This function programs the flash memory. Corresponding sectors must be prepared via IAP_PrepareSectorForWrite before
* calling this function. The addresses should be a 256 byte boundary and the number of bytes should be 256 | 512 |
* 1024 | 4096.
*
* @param dstAddr Destination flash address where data bytes are to be written.
* @param srcAddr Source ram address from where data bytes are to be read.
* @param numOfBytes Number of bytes to be written.
* @param systemCoreClock SystemCoreClock in Hz. It is converted to KHz before calling the rom IAP function. When the
* flash controller has a fixed reference clock, this parameter is bypassed.
*
* @retval kStatus_IAP_Success Api has been executed successfully.
* @retval kStatus_IAP_NoPower Flash memory block is powered down.
* @retval kStatus_IAP_NoClock Flash memory block or controller is not clocked.
* @retval kStatus_IAP_SrcAddrError Source address is not on word boundary.
* @retval kStatus_IAP_DstAddrError Destination address is not on a correct boundary.
* @retval kStatus_IAP_SrcAddrNotMapped Source address is not mapped in the memory map.
* @retval kStatus_IAP_DstAddrNotMapped Destination address is not mapped in the memory map.
* @retval kStatus_IAP_CountError Byte count is not multiple of 4 or is not a permitted value.
* @retval kStatus_IAP_NotPrepared Command to prepare sector for write operation has not been executed.
* @retval kStatus_IAP_Busy Flash programming hardware interface is busy.
*/
status_t IAP_CopyRamToFlash(uint32_t dstAddr, uint32_t *srcAddr, uint32_t numOfBytes, uint32_t systemCoreClock)
{
uint32_t command[5] = {0x00U};
uint32_t result[5] = {0x00U};
command[0] = (uint32_t)kIapCmd_IAP_CopyRamToFlash;
command[1] = dstAddr;
command[2] = (uint32_t)srcAddr;
command[3] = numOfBytes;
#if !(defined(FSL_FEATURE_SYSCON_HAS_FLASH_REFERENCE_CLOCK) && FSL_FEATURE_SYSCON_HAS_FLASH_REFERENCE_CLOCK)
command[4] = systemCoreClock / HZ_TO_KHZ_DIV;
#endif /* FSL_FEATURE_SYSCON_HAS_FLASH_REFERENCE_CLOCK */
iap_entry(command, result);
return translate_iap_status(result[0]);
}
/*!
* @brief Erase sector.
*
* This function erases sector(s). The end sector number must be greater than or equal to the start sector number.
*
* @param startSector Start sector number.
* @param endSector End sector number.
* @param systemCoreClock SystemCoreClock in Hz. It is converted to KHz before calling the rom IAP function. When the
* flash controller has a fixed reference clock, this parameter is bypassed.
*
* @retval kStatus_IAP_Success Api has been executed successfully.
* @retval kStatus_IAP_NoPower Flash memory block is powered down.
* @retval kStatus_IAP_NoClock Flash memory block or controller is not clocked.
* @retval kStatus_IAP_InvalidSector Sector number is invalid or end sector number is greater than start sector number.
* @retval kStatus_IAP_NotPrepared Command to prepare sector for write operation has not been executed.
* @retval kStatus_IAP_Busy Flash programming hardware interface is busy.
*/
status_t IAP_EraseSector(uint32_t startSector, uint32_t endSector, uint32_t systemCoreClock)
{
uint32_t command[5] = {0x00U};
uint32_t result[5] = {0x00U};
command[0] = (uint32_t)kIapCmd_IAP_EraseSector;
command[1] = startSector;
command[2] = endSector;
#if !(defined(FSL_FEATURE_SYSCON_HAS_FLASH_REFERENCE_CLOCK) && FSL_FEATURE_SYSCON_HAS_FLASH_REFERENCE_CLOCK)
command[3] = systemCoreClock / HZ_TO_KHZ_DIV;
#endif /* FSL_FEATURE_SYSCON_HAS_FLASH_REFERENCE_CLOCK */
iap_entry(command, result);
return translate_iap_status(result[0]);
}
/*!
* @brief Erase page.
*
* This function erases page(s). The end page number must be greater than or equal to the start page number.
*
* @param startPage Start page number.
* @param endPage End page number.
* @param systemCoreClock SystemCoreClock in Hz. It is converted to KHz before calling the rom IAP function. When the
* flash controller has a fixed reference clock, this parameter is bypassed.
*
* @retval kStatus_IAP_Success Api has been executed successfully.
* @retval kStatus_IAP_NoPower Flash memory block is powered down.
* @retval kStatus_IAP_NoClock Flash memory block or controller is not clocked.
* @retval kStatus_IAP_InvalidSector Page number is invalid or end page number is greater than start page number.
* @retval kStatus_IAP_NotPrepared Command to prepare sector for write operation has not been executed.
* @retval kStatus_IAP_Busy Flash programming hardware interface is busy.
*/
status_t IAP_ErasePage(uint32_t startPage, uint32_t endPage, uint32_t systemCoreClock)
{
uint32_t command[5] = {0x00U};
uint32_t result[5] = {0x00U};
command[0] = (uint32_t)kIapCmd_IAP_ErasePage;
command[1] = startPage;
command[2] = endPage;
#if !(defined(FSL_FEATURE_SYSCON_HAS_FLASH_REFERENCE_CLOCK) && FSL_FEATURE_SYSCON_HAS_FLASH_REFERENCE_CLOCK)
command[3] = systemCoreClock / HZ_TO_KHZ_DIV;
#endif /* FSL_FEATURE_SYSCON_HAS_FLASH_REFERENCE_CLOCK */
iap_entry(command, result);
return translate_iap_status(result[0]);
}
/*!
* @brief Blank check sector(s)
*
* Blank check single or multiples sectors of flash memory. The end sector number must be greater than or equal to the
* start sector number. It can be used to verify the sector erasure after IAP_EraseSector call.
*
* @param startSector Start sector number.
* @param endSector End sector number.
* @retval kStatus_IAP_Success One or more sectors are in erased state.
* @retval kStatus_IAP_NoPower Flash memory block is powered down.
* @retval kStatus_IAP_NoClock Flash memory block or controller is not clocked.
* @retval kStatus_IAP_SectorNotblank One or more sectors are not blank.
*/
status_t IAP_BlankCheckSector(uint32_t startSector, uint32_t endSector)
{
uint32_t command[5] = {0x00U};
uint32_t result[5] = {0x00U};
command[0] = (uint32_t)kIapCmd_IAP_BlankCheckSector;
command[1] = startSector;
command[2] = endSector;
iap_entry(command, result);
return translate_iap_status(result[0]);
}
/*!
* @brief Compare memory contents of flash with ram.
*
* This function compares the contents of flash and ram. It can be used to verify the flash memory contents after
* IAP_CopyRamToFlash call.
*
* @param dstAddr Destination flash address.
* @param srcAddr Source ram address.
* @param numOfBytes Number of bytes to be compared.
*
* @retval kStatus_IAP_Success Contents of flash and ram match.
* @retval kStatus_IAP_NoPower Flash memory block is powered down.
* @retval kStatus_IAP_NoClock Flash memory block or controller is not clocked.
* @retval kStatus_IAP_AddrError Address is not on word boundary.
* @retval kStatus_IAP_AddrNotMapped Address is not mapped in the memory map.
* @retval kStatus_IAP_CountError Byte count is not multiple of 4 or is not a permitted value.
* @retval kStatus_IAP_CompareError Destination and source memory contents do not match.
*/
status_t IAP_Compare(uint32_t dstAddr, uint32_t *srcAddr, uint32_t numOfBytes)
{
uint32_t command[5] = {0x00U};
uint32_t result[5] = {0x00U};
command[0] = (uint32_t)kIapCmd_IAP_Compare;
command[1] = dstAddr;
command[2] = (uint32_t)srcAddr;
command[3] = numOfBytes;
iap_entry(command, result);
return translate_iap_status(result[0]);
}
#if defined(FSL_FEATURE_IAP_HAS_FLASH_EXTENDED_SIGNATURE_READ) && FSL_FEATURE_IAP_HAS_FLASH_EXTENDED_SIGNATURE_READ
/*!
* @brief Extended Read signature.
*
* This function calculates the signature value for one or more pages of on-chip flash memory.
*
* @param startPage Start page number.
* @param endPage End page number.
* @param numOfStates Number of wait states.
* @param signature Address to store the signature value.
*
* @retval kStatus_IAP_Success Api has been executed successfully.
*/
status_t IAP_ExtendedFlashSignatureRead(uint32_t startPage, uint32_t endPage, uint32_t numOfStates, uint32_t *signature)
{
uint32_t command[5] = {0x00U};
uint32_t result[5] = {0x00U};
command[0] = (uint32_t)kIapCmd_IAP_ExtendedReadSignature;
command[1] = startPage;
command[2] = endPage;
command[3] = numOfStates;
command[4] = 0;
iap_entry(command, result);
signature[0] = result[4];
signature[1] = result[3];
signature[2] = result[2];
signature[3] = result[1];
return translate_iap_status(result[0]);
}
#endif /* FSL_FEATURE_IAP_HAS_FLASH_EXTENDED_SIGNATURE_READ */
#if defined(FSL_FEATURE_IAP_HAS_FLASH_SIGNATURE_READ) && FSL_FEATURE_IAP_HAS_FLASH_SIGNATURE_READ
/*!
* @brief Read flash signature.
*
* This funtion is used to obtain a 32-bit signature value of the entire flash memory.
*
* @param signature Address to store the 32-bit generated signature value.
*
* @retval kStatus_IAP_Success Api has been executed successfully.
*/
status_t IAP_ReadFlashSignature(uint32_t *signature)
{
uint32_t command[5] = {0x00U};
uint32_t result[5] = {0x00U};
command[0] = (uint32_t)kIapCmd_IAP_ReadSignature;
iap_entry(command, result);
*signature = result[1];
return translate_iap_status(result[0]);
}
#endif /* FSL_FEATURE_IAP_HAS_FLASH_SIGNATURE_READ */
#endif /* FSL_FEATURE_IAP_HAS_FLASH_FUNCTION */
#if (defined(FSL_FEATURE_IAP_HAS_EEPROM_FUNCTION) && (FSL_FEATURE_IAP_HAS_EEPROM_FUNCTION == 1))
/*!
* @brief Read EEPROM page.
*
* This function is used to read given page of EEPROM into the memory provided.
*
* @param pageNumber EEPROM page number.
* @param dstAddr Memory address to store the value read from EEPROM.
* @param systemCoreClock Current core clock frequency in kHz.
*
* @retval kStatus_IAP_Success Api has been executed successfully.
* @retval kStatus_IAP_InvalidSector Sector number is invalid.
* @retval kStatus_IAP_DstAddrNotMapped Destination address is not mapped in the memory map.
*
* note Value 0xFFFFFFFF of systemCoreClock will retain the timing and clock settings for EEPROM.
*/
status_t IAP_ReadEEPROMPage(uint32_t pageNumber, uint32_t *dstAddr, uint32_t systemCoreClock)
{
uint32_t command[5] = {0x00U};
uint32_t result[5] = {0x00U};
command[0] = (uint32_t)kIapCmd_IAP_ReadEEPROMPage;
command[1] = pageNumber;
command[2] = (uint32_t)dstAddr;
command[3] = systemCoreClock / HZ_TO_KHZ_DIV;
iap_entry(command, result);
return translate_iap_status(result[0]);
}
/*!
* @brief Write EEPROM page.
*
* This function is used to write given data in the provided memory to a page of EEPROM.
*
* @param pageNumber EEPROM page number.
* @param srcAddr Memory address holding data to be stored on to EEPROM page.
* @param systemCoreClock Current core clock frequency in kHz.
*
* @retval kStatus_IAP_Success Api has been executed successfully.
* @retval kStatus_IAP_InvalidSector Sector number is invalid.
* @retval kStatus_IAP_SrcAddrNotMapped Source address is not mapped in the memory map.
*
* note Value 0xFFFFFFFF of systemCoreClock will retain the timing and clock settings for EEPROM
*/
status_t IAP_WriteEEPROMPage(uint32_t pageNumber, uint32_t *srcAddr, uint32_t systemCoreClock)
{
uint32_t command[5] = {0x00U};
uint32_t result[5] = {0x00U};
command[0] = (uint32_t)kIapCmd_IAP_WriteEEPROMPage;
command[1] = pageNumber;
command[2] = (uint32_t)srcAddr;
command[3] = systemCoreClock / HZ_TO_KHZ_DIV;
iap_entry(command, result);
return translate_iap_status(result[0]);
}
#endif /* FSL_FEATURE_IAP_HAS_EEPROM_FUNCTION */
#if defined(FSL_FEATURE_IAP_HAS_FAIM_FUNCTION) && FSL_FEATURE_IAP_HAS_FAIM_FUNCTION
/*!
* @brief Read FAIM page.
*
* This function is used to read given page of FAIM into the memory provided.
*
* @param pageNumber FAIM page number.
* @param dstAddr Memory address to store the value read from FAIM.
*
* @retval kStatus_IAP_Success Api has been executed successfully.
* @retval kStatus_IAP_DstAddrNotMapped Destination address is not mapped in the memory map.
*/
status_t IAP_ReadFAIMPage(uint32_t pageNumber, uint32_t *dstAddr)
{
uint32_t command[5] = {0x00U};
uint32_t result[5] = {0x00U};
command[0] = (uint32_t)kIapCmd_IAP_ReadFAIMPage;
command[1] = pageNumber;
command[2] = (uint32_t)dstAddr;
iap_entry(command, result);
return translate_iap_status(result[0]);
}
/*!
* @brief Write FAIM page.
*
* This function is used to write given data in the provided memory to a page of G.
*
* @param pageNumber FAIM page number.
* @param srcAddr Memory address holding data to be stored on to FAIM page.
*
* @retval kStatus_IAP_Success Api has been executed successfully.
* @retval kStatus_IAP_SrcAddrNotMapped Source address is not mapped in the memory map.
*/
status_t IAP_WriteFAIMPage(uint32_t pageNumber, uint32_t *srcAddr)
{
uint32_t command[5] = {0x00U};
uint32_t result[5] = {0x00U};
command[0] = (uint32_t)kIapCmd_IAP_WriteFAIMPage;
command[1] = pageNumber;
command[2] = (uint32_t)srcAddr;
iap_entry(command, result);
return translate_iap_status(result[0]);
}
#endif /* FSL_FEATURE_IAP_HAS_FAIM_FUNCTION */

435
drivers/fsl_iap.h Normal file
View File

@@ -0,0 +1,435 @@
/*
* Copyright 2018-2020 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _FSL_IAP_H_
#define _FSL_IAP_H_
#include "fsl_common.h"
/*!
* @addtogroup IAP_driver
* @{
*/
/*! @file */
/*******************************************************************************
* Definitions
******************************************************************************/
/*! @name Driver version */
/*@{*/
#define FSL_IAP_DRIVER_VERSION (MAKE_VERSION(2, 0, 5)) /*!< Version 2.0.5. */
/*@}*/
/*!
* @brief iap status codes.
*/
enum
{
kStatus_IAP_Success = kStatus_Success, /*!< Api is executed successfully */
kStatus_IAP_InvalidCommand = MAKE_STATUS(kStatusGroup_IAP, 1U), /*!< Invalid command */
kStatus_IAP_SrcAddrError = MAKE_STATUS(kStatusGroup_IAP, 2U), /*!< Source address is not on word boundary */
kStatus_IAP_DstAddrError =
MAKE_STATUS(kStatusGroup_IAP, 3U), /*!< Destination address is not on a correct boundary */
kStatus_IAP_SrcAddrNotMapped =
MAKE_STATUS(kStatusGroup_IAP, 4U), /*!< Source address is not mapped in the memory map */
kStatus_IAP_DstAddrNotMapped =
MAKE_STATUS(kStatusGroup_IAP, 5U), /*!< Destination address is not mapped in the memory map */
kStatus_IAP_CountError =
MAKE_STATUS(kStatusGroup_IAP, 6U), /*!< Byte count is not multiple of 4 or is not a permitted value */
kStatus_IAP_InvalidSector = MAKE_STATUS(
kStatusGroup_IAP,
7), /*!< Sector/page number is invalid or end sector/page number is greater than start sector/page number */
kStatus_IAP_SectorNotblank = MAKE_STATUS(kStatusGroup_IAP, 8U), /*!< One or more sectors are not blank */
kStatus_IAP_NotPrepared =
MAKE_STATUS(kStatusGroup_IAP, 9U), /*!< Command to prepare sector for write operation has not been executed */
kStatus_IAP_CompareError =
MAKE_STATUS(kStatusGroup_IAP, 10U), /*!< Destination and source memory contents do not match */
kStatus_IAP_Busy = MAKE_STATUS(kStatusGroup_IAP, 11U), /*!< Flash programming hardware interface is busy */
kStatus_IAP_ParamError =
MAKE_STATUS(kStatusGroup_IAP, 12U), /*!< Insufficient number of parameters or invalid parameter */
kStatus_IAP_AddrError = MAKE_STATUS(kStatusGroup_IAP, 13U), /*!< Address is not on word boundary */
kStatus_IAP_AddrNotMapped = MAKE_STATUS(kStatusGroup_IAP, 14U), /*!< Address is not mapped in the memory map */
kStatus_IAP_NoPower = MAKE_STATUS(kStatusGroup_IAP, 24U), /*!< Flash memory block is powered down */
kStatus_IAP_NoClock = MAKE_STATUS(kStatusGroup_IAP, 27U), /*!< Flash memory block or controller is not clocked */
kStatus_IAP_ReinvokeISPConfig = MAKE_STATUS(kStatusGroup_IAP, 0x1CU), /*!< Reinvoke configuration error */
};
/*!
* @brief iap command codes.
*/
enum _iap_commands
{
kIapCmd_IAP_ReadFactorySettings = 40U, /*!< Read the factory settings */
kIapCmd_IAP_PrepareSectorforWrite = 50U, /*!< Prepare Sector for write */
kIapCmd_IAP_CopyRamToFlash = 51U, /*!< Copy RAM to flash */
kIapCmd_IAP_EraseSector = 52U, /*!< Erase Sector */
kIapCmd_IAP_BlankCheckSector = 53U, /*!< Blank check sector */
kIapCmd_IAP_ReadPartId = 54U, /*!< Read part id */
kIapCmd_IAP_Read_BootromVersion = 55U, /*!< Read bootrom version */
kIapCmd_IAP_Compare = 56U, /*!< Compare */
kIapCmd_IAP_ReinvokeISP = 57U, /*!< Reinvoke ISP */
kIapCmd_IAP_ReadUid = 58U, /*!< Read Uid */
kIapCmd_IAP_ErasePage = 59U, /*!< Erase Page */
kIapCmd_IAP_ReadSignature = 70U, /*!< Read Signature */
kIapCmd_IAP_ExtendedReadSignature = 73U, /*!< Extended Read Signature */
#if defined(FSL_FEATURE_IAP_HAS_FAIM_FUNCTION) && FSL_FEATURE_IAP_HAS_FAIM_FUNCTION
kIapCmd_IAP_ReadFAIMPage = 80U, /*!< Read FAIM page */
kIapCmd_IAP_WriteFAIMPage = 81U, /*!< Write FAIM page */
#else
kIapCmd_IAP_ReadEEPROMPage = 80U, /*!< Read EEPROM page */
kIapCmd_IAP_WriteEEPROMPage = 81U, /*!< Write EEPROM page */
#endif /*FSL_FEATURE_IAP_HAS_FAIM_FUNCTION */
};
/*!
* @brief Flash memory access time.
*/
enum _flash_access_time
{
kFlash_IAP_OneSystemClockTime = 0U, /*! 1 system clock flash access time */
kFlash_IAP_TwoSystemClockTime = 1U, /*! 2 system clock flash access time */
kFlash_IAP_ThreeSystemClockTime = 2U, /*! 3 system clock flash access time */
};
/*******************************************************************************
* API
******************************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif
/*!
* @name Basic operations
* @{
*/
/*!
* @brief Read part identification number.
*
* This function is used to read the part identification number.
*
* @param partID Address to store the part identification number.
*
* @retval kStatus_IAP_Success Api has been executed successfully.
*/
status_t IAP_ReadPartID(uint32_t *partID);
/*!
* @brief Read boot code version number.
*
* This function is used to read the boot code version number.
*
* @param bootCodeVersion Address to store the boot code version.
*
* @retval kStatus_IAP_Success Api has been executed successfully.
*
* note Boot code version is two 32-bit words. Word 0 is the major version, word 1 is the minor version.
*/
status_t IAP_ReadBootCodeVersion(uint32_t *bootCodeVersion);
/*!
* @brief Reinvoke ISP.
*
* This function is used to invoke the boot loader in ISP mode. It maps boot vectors and configures the peripherals for
* ISP.
*
* @param ispType ISP type selection.
* @param status store the possible status.
*
* @retval kStatus_IAP_ReinvokeISPConfig reinvoke configuration error.
*
* note The error response will be returned when IAP is disabled or an invalid ISP type selection appears. The call
* won't return unless an error occurs, so there can be no status code.
*/
void IAP_ReinvokeISP(uint8_t ispType, uint32_t *status);
/*!
* @brief Read unique identification.
*
* This function is used to read the unique id.
*
* @param uniqueID store the uniqueID.
*
* @retval kStatus_IAP_Success Api has been executed successfully.
*/
status_t IAP_ReadUniqueID(uint32_t *uniqueID);
#if defined(FSL_FEATURE_IAP_HAS_READ_FACTORY_SETTINGS_FUNCTION) && FSL_FEATURE_IAP_HAS_READ_FACTORY_SETTINGS_FUNCTION
/*!
* @brief Read factory settings.
*
* This function reads the factory settings for calibration registers.
*
* @param dstRegAddr Address of the targeted calibration register.
* @param factoryValue Store the factory value
*
* @retval kStatus_IAP_Success Api has been executed successfully.
* @retval kStatus_IAP_ParamError Param0 is not one of the supported calibration registers.
*/
status_t IAP_ReadFactorySettings(uint32_t dstRegAddr, uint32_t *factoryValue);
#endif /* FSL_FEATURE_IAP_HAS_READ_FACTORY_SETTINGS_FUNCTION */
/*@}*/
#if defined(FSL_FEATURE_IAP_HAS_FLASH_FUNCTION) && FSL_FEATURE_IAP_HAS_FLASH_FUNCTION
/*!
* @name Flash operations
* @{
*/
#if defined(FLASH_CTRL_FLASHCFG_FLASHTIM_MASK)
/*!
* @brief Flash memory access time.
*
* This function is used to configure the access time to the flash memory.
*
* @param accessTime Flash memory access time FLASHTIM +1 is equal to the
* number of system clocks used for flash access.
*/
void IAP_ConfigAccessFlashTime(uint32_t accessTime);
#endif
/*!
* @brief Prepare sector for write operation.
*
* This function prepares sector(s) for write/erase operation. This function must be called before calling the
* IAP_CopyRamToFlash() or IAP_EraseSector() or IAP_ErasePage() function. The end sector number must be greater than or
* equal to the start sector number.
*
* @param startSector Start sector number.
* @param endSector End sector number.
*
* @retval kStatus_IAP_Success Api has been executed successfully.
* @retval kStatus_IAP_NoPower Flash memory block is powered down.
* @retval kStatus_IAP_NoClock Flash memory block or controller is not clocked.
* @retval kStatus_IAP_InvalidSector Sector number is invalid or end sector number is greater than start sector number.
* @retval kStatus_IAP_Busy Flash programming hardware interface is busy.
*/
status_t IAP_PrepareSectorForWrite(uint32_t startSector, uint32_t endSector);
/*!
* @brief Copy RAM to flash.
*
* This function programs the flash memory. Corresponding sectors must be prepared via IAP_PrepareSectorForWrite before
* calling this function. The addresses should be a 256 byte boundary and the number of bytes should be 256 | 512 |
* 1024 | 4096.
*
* @param dstAddr Destination flash address where data bytes are to be written.
* @param srcAddr Source ram address from where data bytes are to be read.
* @param numOfBytes Number of bytes to be written.
* @param systemCoreClock SystemCoreClock in Hz. It is converted to KHz before calling the rom IAP function. When the
* flash controller has a fixed reference clock, this parameter is bypassed.
*
* @retval kStatus_IAP_Success Api has been executed successfully.
* @retval kStatus_IAP_NoPower Flash memory block is powered down.
* @retval kStatus_IAP_NoClock Flash memory block or controller is not clocked.
* @retval kStatus_IAP_SrcAddrError Source address is not on word boundary.
* @retval kStatus_IAP_DstAddrError Destination address is not on a correct boundary.
* @retval kStatus_IAP_SrcAddrNotMapped Source address is not mapped in the memory map.
* @retval kStatus_IAP_DstAddrNotMapped Destination address is not mapped in the memory map.
* @retval kStatus_IAP_CountError Byte count is not multiple of 4 or is not a permitted value.
* @retval kStatus_IAP_NotPrepared Command to prepare sector for write operation has not been executed.
* @retval kStatus_IAP_Busy Flash programming hardware interface is busy.
*/
status_t IAP_CopyRamToFlash(uint32_t dstAddr, uint32_t *srcAddr, uint32_t numOfBytes, uint32_t systemCoreClock);
/*!
* @brief Erase sector.
*
* This function erases sector(s). The end sector number must be greater than or equal to the start sector number.
*
* @param startSector Start sector number.
* @param endSector End sector number.
* @param systemCoreClock SystemCoreClock in Hz. It is converted to KHz before calling the rom IAP function. When the
* flash controller has a fixed reference clock, this parameter is bypassed.
*
* @retval kStatus_IAP_Success Api has been executed successfully.
* @retval kStatus_IAP_NoPower Flash memory block is powered down.
* @retval kStatus_IAP_NoClock Flash memory block or controller is not clocked.
* @retval kStatus_IAP_InvalidSector Sector number is invalid or end sector number is greater than start sector number.
* @retval kStatus_IAP_NotPrepared Command to prepare sector for write operation has not been executed.
* @retval kStatus_IAP_Busy Flash programming hardware interface is busy.
*/
status_t IAP_EraseSector(uint32_t startSector, uint32_t endSector, uint32_t systemCoreClock);
/*!
* @brief Erase page.
*
* This function erases page(s). The end page number must be greater than or equal to the start page number.
*
* @param startPage Start page number.
* @param endPage End page number.
* @param systemCoreClock SystemCoreClock in Hz. It is converted to KHz before calling the rom IAP function. When the
* flash controller has a fixed reference clock, this parameter is bypassed.
*
* @retval kStatus_IAP_Success Api has been executed successfully.
* @retval kStatus_IAP_NoPower Flash memory block is powered down.
* @retval kStatus_IAP_NoClock Flash memory block or controller is not clocked.
* @retval kStatus_IAP_InvalidSector Page number is invalid or end page number is greater than start page number.
* @retval kStatus_IAP_NotPrepared Command to prepare sector for write operation has not been executed.
* @retval kStatus_IAP_Busy Flash programming hardware interface is busy.
*/
status_t IAP_ErasePage(uint32_t startPage, uint32_t endPage, uint32_t systemCoreClock);
/*!
* @brief Blank check sector(s)
*
* Blank check single or multiples sectors of flash memory. The end sector number must be greater than or equal to the
* start sector number. It can be used to verify the sector erasure after IAP_EraseSector call.
*
* @param startSector Start sector number.
* @param endSector End sector number.
* @retval kStatus_IAP_Success One or more sectors are in erased state.
* @retval kStatus_IAP_NoPower Flash memory block is powered down.
* @retval kStatus_IAP_NoClock Flash memory block or controller is not clocked.
* @retval kStatus_IAP_SectorNotblank One or more sectors are not blank.
*/
status_t IAP_BlankCheckSector(uint32_t startSector, uint32_t endSector);
/*!
* @brief Compare memory contents of flash with ram.
*
* This function compares the contents of flash and ram. It can be used to verify the flash memory contents after
* IAP_CopyRamToFlash call.
*
* @param dstAddr Destination flash address.
* @param srcAddr Source ram address.
* @param numOfBytes Number of bytes to be compared.
*
* @retval kStatus_IAP_Success Contents of flash and ram match.
* @retval kStatus_IAP_NoPower Flash memory block is powered down.
* @retval kStatus_IAP_NoClock Flash memory block or controller is not clocked.
* @retval kStatus_IAP_AddrError Address is not on word boundary.
* @retval kStatus_IAP_AddrNotMapped Address is not mapped in the memory map.
* @retval kStatus_IAP_CountError Byte count is not multiple of 4 or is not a permitted value.
* @retval kStatus_IAP_CompareError Destination and source memory contents do not match.
*/
status_t IAP_Compare(uint32_t dstAddr, uint32_t *srcAddr, uint32_t numOfBytes);
#if defined(FSL_FEATURE_IAP_HAS_FLASH_EXTENDED_SIGNATURE_READ) && FSL_FEATURE_IAP_HAS_FLASH_EXTENDED_SIGNATURE_READ
/*!
* @brief Extended Read signature.
*
* This function calculates the signature value for one or more pages of on-chip flash memory.
*
* @param startPage Start page number.
* @param endPage End page number.
* @param numOfStates Number of wait states.
* @param signature Address to store the signature value.
*
* @retval kStatus_IAP_Success Api has been executed successfully.
*/
status_t IAP_ExtendedFlashSignatureRead(uint32_t startPage,
uint32_t endPage,
uint32_t numOfStates,
uint32_t *signature);
#endif /* FSL_FEATURE_IAP_HAS_FLASH_EXTENDED_SIGNATURE_READ */
#if defined(FSL_FEATURE_IAP_HAS_FLASH_SIGNATURE_READ) && FSL_FEATURE_IAP_HAS_FLASH_SIGNATURE_READ
/*!
* @brief Read flash signature.
*
* This funtion is used to obtain a 32-bit signature value of the entire flash memory.
*
* @param signature Address to store the 32-bit generated signature value.
*
* @retval kStatus_IAP_Success Api has been executed successfully.
*/
status_t IAP_ReadFlashSignature(uint32_t *signature);
#endif /* FSL_FEATURE_IAP_HAS_FLASH_SIGNATURE_READ */
/*@}*/
#endif /* FSL_FEATURE_IAP_HAS_FLASH_FUNCTION */
#if (defined(FSL_FEATURE_IAP_HAS_EEPROM_FUNCTION) && (FSL_FEATURE_IAP_HAS_EEPROM_FUNCTION == 1))
/*!
* @name EEPROM operations
* @{
*/
/*!
* @brief Read EEPROM page.
*
* This function is used to read given page of EEPROM into the memory provided.
*
* @param pageNumber EEPROM page number.
* @param dstAddr Memory address to store the value read from EEPROM.
* @param systemCoreClock Current core clock frequency in kHz.
*
* @retval kStatus_IAP_Success Api has been executed successfully.
* @retval kStatus_IAP_InvalidSector Sector number is invalid.
* @retval kStatus_IAP_DstAddrNotMapped Destination address is not mapped in the memory map.
*
* note Value 0xFFFFFFFF of systemCoreClock will retain the timing and clock settings for EEPROM.
*/
status_t IAP_ReadEEPROMPage(uint32_t pageNumber, uint32_t *dstAddr, uint32_t systemCoreClock);
/*!
* @brief Write EEPROM page.
*
* This function is used to write given data in the provided memory to a page of EEPROM.
*
* @param pageNumber EEPROM page number.
* @param srcAddr Memory address holding data to be stored on to EEPROM page.
* @param systemCoreClock Current core clock frequency in kHz.
*
* @retval kStatus_IAP_Success Api has been executed successfully.
* @retval kStatus_IAP_InvalidSector Sector number is invalid.
* @retval kStatus_IAP_SrcAddrNotMapped Source address is not mapped in the memory map.
*
* note Value 0xFFFFFFFF of systemCoreClock will retain the timing and clock settings for EEPROM
*/
status_t IAP_WriteEEPROMPage(uint32_t pageNumber, uint32_t *srcAddr, uint32_t systemCoreClock);
/*@}*/
#endif /* FSL_FEATURE_IAP_HAS_EEPROM_FUNCTION */
#if defined(FSL_FEATURE_IAP_HAS_FAIM_FUNCTION) && FSL_FEATURE_IAP_HAS_FAIM_FUNCTION
/*!
* @name FAIM operations
* @{
*/
/*!
* @brief Read FAIM page.
*
* This function is used to read given page of FAIM into the memory provided.
*
* @param pageNumber FAIM page number.
* @param dstAddr Memory address to store the value read from FAIM.
*
* @retval kStatus_IAP_Success Api has been executed successfully.
* @retval kStatus_IAP_DstAddrNotMapped Destination address is not mapped in the memory map.
*/
status_t IAP_ReadFAIMPage(uint32_t pageNumber, uint32_t *dstAddr);
/*!
* @brief Write FAIM page.
*
* This function is used to write given data in the provided memory to a page of G.
*
* @param pageNumber FAIM page number.
* @param srcAddr Memory address holding data to be stored on to FAIM page.
*
* @retval kStatus_IAP_Success Api has been executed successfully.
* @retval kStatus_IAP_SrcAddrNotMapped Source address is not mapped in the memory map.
*/
status_t IAP_WriteFAIMPage(uint32_t pageNumber, uint32_t *srcAddr);
#endif /* FSL_FEATURE_IAP_HAS_FAIM_FUNCTION */
/*@}*/
#ifdef __cplusplus
}
#endif
/*@}*/
#endif /* _FSL_IAP_H_ */

135
drivers/fsl_inputmux.c Normal file
View File

@@ -0,0 +1,135 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* Copyright 2016-2020 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "fsl_inputmux.h"
/*******************************************************************************
* Definitions
******************************************************************************/
/* Component ID definition, used by tools. */
#ifndef FSL_COMPONENT_ID
#define FSL_COMPONENT_ID "platform.drivers.inputmux"
#endif
/*******************************************************************************
* Code
******************************************************************************/
/*!
* brief Initialize INPUTMUX peripheral.
* This function enables the INPUTMUX clock.
*
* param base Base address of the INPUTMUX peripheral.
*
* retval None.
*/
void INPUTMUX_Init(INPUTMUX_Type *base)
{
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
#if defined(FSL_FEATURE_INPUTMUX_HAS_NO_INPUTMUX_CLOCK_SOURCE) && FSL_FEATURE_INPUTMUX_HAS_NO_INPUTMUX_CLOCK_SOURCE
CLOCK_EnableClock(kCLOCK_Sct);
CLOCK_EnableClock(kCLOCK_Dma);
#else
CLOCK_EnableClock(kCLOCK_InputMux);
#endif /* FSL_FEATURE_INPUTMUX_HAS_NO_INPUTMUX_CLOCK_SOURCE */
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
}
/*!
* brief Attaches a signal
*
* This function gates the INPUTPMUX clock.
*
* param base Base address of the INPUTMUX peripheral.
* param index Destination peripheral to attach the signal to.
* param connection Selects connection.
*
* retval None.
*/
void INPUTMUX_AttachSignal(INPUTMUX_Type *base, uint32_t index, inputmux_connection_t connection)
{
uint32_t pmux_id;
uint32_t output_id;
/* extract pmux to be used */
pmux_id = ((uint32_t)(connection)) >> PMUX_SHIFT;
/* extract function number */
output_id = ((uint32_t)(connection)) & ((1UL << PMUX_SHIFT) - 1U);
/* programm signal */
*(volatile uint32_t *)(((uint32_t)base) + pmux_id + (index * 4U)) = output_id;
}
#if defined(FSL_FEATURE_INPUTMUX_HAS_SIGNAL_ENA)
/*!
* brief Enable/disable a signal
*
* This function gates the INPUTPMUX clock.
*
* param base Base address of the INPUTMUX peripheral.
* param signal Enable signal register id and bit offset.
* param enable Selects enable or disable.
*
* retval None.
*/
void INPUTMUX_EnableSignal(INPUTMUX_Type *base, inputmux_signal_t signal, bool enable)
{
uint32_t ena_id;
uint32_t ena_id_mask = (1UL << (32U - ENA_SHIFT)) - 1U;
uint32_t bit_offset;
#if defined(FSL_FEATURE_INPUTMUX_HAS_CHANNEL_MUX) && FSL_FEATURE_INPUTMUX_HAS_CHANNEL_MUX
uint32_t chmux_offset;
uint32_t chmux_value;
/* Only enable need to update channel mux */
if (enable && ((((uint32_t)signal) & (1UL << CHMUX_AVL_SHIFT)) != 0U))
{
chmux_offset = (((uint32_t)signal) >> CHMUX_OFF_SHIFT) & ((1U << (CHMUX_AVL_SHIFT - CHMUX_OFF_SHIFT)) - 1);
chmux_value = (((uint32_t)signal) >> CHMUX_VAL_SHIFT) & ((1U << (CHMUX_OFF_SHIFT - CHMUX_VAL_SHIFT)) - 1);
*(volatile uint32_t *)(((uint32_t)base) + chmux_offset) = chmux_value;
}
ena_id_mask = (1UL << (CHMUX_VAL_SHIFT - ENA_SHIFT)) - 1U;
#endif
/* extract enable register to be used */
ena_id = (((uint32_t)signal) >> ENA_SHIFT) & ena_id_mask;
/* extract enable bit offset */
bit_offset = ((uint32_t)signal) & ((1UL << ENA_SHIFT) - 1U);
/* set signal */
if (enable)
{
*(volatile uint32_t *)(((uint32_t)base) + ena_id) |= (1UL << bit_offset);
}
else
{
*(volatile uint32_t *)(((uint32_t)base) + ena_id) &= ~(1UL << bit_offset);
}
}
#endif
/*!
* brief Deinitialize INPUTMUX peripheral.
* This function disables the INPUTMUX clock.
*
* param base Base address of the INPUTMUX peripheral.
*
* retval None.
*/
void INPUTMUX_Deinit(INPUTMUX_Type *base)
{
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
#if defined(FSL_FEATURE_INPUTMUX_HAS_NO_INPUTMUX_CLOCK_SOURCE) && FSL_FEATURE_INPUTMUX_HAS_NO_INPUTMUX_CLOCK_SOURCE
CLOCK_DisableClock(kCLOCK_Sct);
CLOCK_DisableClock(kCLOCK_Dma);
#else
CLOCK_DisableClock(kCLOCK_InputMux);
#endif /* FSL_FEATURE_INPUTMUX_HAS_NO_INPUTMUX_CLOCK_SOURCE */
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
}

97
drivers/fsl_inputmux.h Normal file
View File

@@ -0,0 +1,97 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* Copyright 2016-2020 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _FSL_INPUTMUX_H_
#define _FSL_INPUTMUX_H_
#include "fsl_inputmux_connections.h"
#include "fsl_common.h"
/*!
* @addtogroup inputmux_driver
* @{
*/
/*! @file */
/*! @file fsl_inputmux_connections.h */
/*******************************************************************************
* Definitions
******************************************************************************/
/*! @name Driver version */
/*@{*/
/*! @brief Group interrupt driver version for SDK */
#define FSL_INPUTMUX_DRIVER_VERSION (MAKE_VERSION(2, 0, 3))
/*@}*/
/*******************************************************************************
* API
******************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif
/*!
* @brief Initialize INPUTMUX peripheral.
* This function enables the INPUTMUX clock.
*
* @param base Base address of the INPUTMUX peripheral.
*
* @retval None.
*/
void INPUTMUX_Init(INPUTMUX_Type *base);
/*!
* @brief Attaches a signal
*
* This function gates the INPUTPMUX clock.
*
* @param base Base address of the INPUTMUX peripheral.
* @param index Destination peripheral to attach the signal to.
* @param connection Selects connection.
*
* @retval None.
*/
void INPUTMUX_AttachSignal(INPUTMUX_Type *base, uint32_t index, inputmux_connection_t connection);
#if defined(FSL_FEATURE_INPUTMUX_HAS_SIGNAL_ENA)
/*!
* @brief Enable/disable a signal
*
* This function gates the INPUTPMUX clock.
*
* @param base Base address of the INPUTMUX peripheral.
* @param signal Enable signal register id and bit offset.
* @param enable Selects enable or disable.
*
* @retval None.
*/
void INPUTMUX_EnableSignal(INPUTMUX_Type *base, inputmux_signal_t signal, bool enable);
#endif
/*!
* @brief Deinitialize INPUTMUX peripheral.
* This function disables the INPUTMUX clock.
*
* @param base Base address of the INPUTMUX peripheral.
*
* @retval None.
*/
void INPUTMUX_Deinit(INPUTMUX_Type *base);
#ifdef __cplusplus
}
#endif
/*@}*/
#endif /* _FSL_INPUTMUX_H_ */

View File

@@ -0,0 +1,157 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* Copyright 2016, NXP
* All rights reserved.
*
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _FSL_INPUTMUX_CONNECTIONS_
#define _FSL_INPUTMUX_CONNECTIONS_
/*******************************************************************************
* Definitions
******************************************************************************/
/* Component ID definition, used by tools. */
#ifndef FSL_COMPONENT_ID
#define FSL_COMPONENT_ID "platform.drivers.inputmux_connections"
#endif
/*!
* @addtogroup inputmux_driver
* @{
*/
/*! @brief Periphinmux IDs */
#define PINTSEL_PMUX_ID 0xC0U
#define DMA_TRIG0_PMUX_ID 0xE0U
#define DMA_OTRIG_PMUX_ID 0x160U
#define FREQMEAS_PMUX_ID 0x180U
#define PMUX_SHIFT 20U
/*! @brief INPUTMUX connections type */
typedef enum _inputmux_connection_t
{
/*!< Frequency measure. */
kINPUTMUX_MainOscToFreqmeas = 0U + (FREQMEAS_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_Fro12MhzToFreqmeas = 1U + (FREQMEAS_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_WdtOscToFreqmeas = 2U + (FREQMEAS_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_32KhzOscToFreqmeas = 3U + (FREQMEAS_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_MainClkToFreqmeas = 4U + (FREQMEAS_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort0Pin4ToFreqmeas = 5U + (FREQMEAS_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort0Pin20ToFreqmeas = 6U + (FREQMEAS_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort0Pin24ToFreqmeas = 7U + (FREQMEAS_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort1Pin4ToFreqmeas = 8U + (FREQMEAS_PMUX_ID << PMUX_SHIFT),
/*!< Pin Interrupt. */
kINPUTMUX_GpioPort0Pin0ToPintsel = 0U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort0Pin1ToPintsel = 1U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort0Pin2ToPintsel = 2U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort0Pin3ToPintsel = 3U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort0Pin4ToPintsel = 4U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort0Pin5ToPintsel = 5U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort0Pin6ToPintsel = 6U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort0Pin7ToPintsel = 7U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort0Pin8ToPintsel = 8U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort0Pin9ToPintsel = 9U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort0Pin10ToPintsel = 10U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort0Pin11ToPintsel = 11U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort0Pin12ToPintsel = 12U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort0Pin13ToPintsel = 13U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort0Pin14ToPintsel = 14U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort0Pin15ToPintsel = 15U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort0Pin16ToPintsel = 16U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort0Pin17ToPintsel = 17U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort0Pin18ToPintsel = 18U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort0Pin19ToPintsel = 19U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort0Pin20ToPintsel = 20U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort0Pin21ToPintsel = 21U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort0Pin22ToPintsel = 22U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort0Pin23ToPintsel = 23U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort0Pin24ToPintsel = 24U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort0Pin25ToPintsel = 25U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort0Pin26ToPintsel = 26U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort0Pin27ToPintsel = 27U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort0Pin28ToPintsel = 28U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort0Pin29ToPintsel = 29U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort0Pin30ToPintsel = 30U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort0Pin31ToPintsel = 31U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort1Pin0ToPintsel = 32U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort1Pin1ToPintsel = 33U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort1Pin2ToPintsel = 34U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort1Pin3ToPintsel = 35U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort1Pin4ToPintsel = 36U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort1Pin5ToPintsel = 37U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort1Pin6ToPintsel = 38U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort1Pin7ToPintsel = 39U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort1Pin8ToPintsel = 40U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort1Pin9ToPintsel = 41U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort1Pin10ToPintsel = 42U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort1Pin11ToPintsel = 43U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort1Pin12ToPintsel = 44U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort1Pin13ToPintsel = 45U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort1Pin14ToPintsel = 46U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort1Pin15ToPintsel = 47U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort1Pin16ToPintsel = 48U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort1Pin17ToPintsel = 49U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort1Pin18ToPintsel = 50U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort1Pin19ToPintsel = 51U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort1Pin20ToPintsel = 52U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort1Pin21ToPintsel = 53U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort1Pin22ToPintsel = 54U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort1Pin23ToPintsel = 55U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort1Pin24ToPintsel = 56U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort1Pin25ToPintsel = 57U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort1Pin26ToPintsel = 58U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort1Pin27ToPintsel = 59U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort1Pin28ToPintsel = 60U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort1Pin29ToPintsel = 61U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort1Pin30ToPintsel = 62U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_GpioPort1Pin31ToPintsel = 63U + (PINTSEL_PMUX_ID << PMUX_SHIFT),
/*!< DMA ITRIG. */
kINPUTMUX_Adc0SeqaIrqToDma = 0U + (DMA_TRIG0_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_ADC0SeqbIrqToDma = 1U + (DMA_TRIG0_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_Sct0DmaReq0ToDma = 2U + (DMA_TRIG0_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_Sct0DmaReq1ToDma = 3U + (DMA_TRIG0_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_Ctimer0M0ToDma = 4U + (DMA_TRIG0_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_Ctimer0M1ToDma = 5U + (DMA_TRIG0_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_Ctimer1M0ToDma = 6U + (DMA_TRIG0_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_Ctimer2M0ToDma = 7U + (DMA_TRIG0_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_Ctimer2M1ToDma = 8U + (DMA_TRIG0_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_Ctimer3M0ToDma = 9U + (DMA_TRIG0_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_Ctimer4M0ToDma = 10U + (DMA_TRIG0_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_Ctimer4M1ToDma = 11U + (DMA_TRIG0_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_PinInt0ToDma = 12U + (DMA_TRIG0_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_PinInt1ToDma = 13U + (DMA_TRIG0_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_PinInt2ToDma = 14U + (DMA_TRIG0_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_PinInt3ToDma = 15U + (DMA_TRIG0_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_Otrig0ToDma = 16U + (DMA_TRIG0_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_Otrig1ToDma = 17U + (DMA_TRIG0_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_Otrig2ToDma = 18U + (DMA_TRIG0_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_Otrig3ToDma = 19U + (DMA_TRIG0_PMUX_ID << PMUX_SHIFT),
/*!< DMA OTRIG. */
kINPUTMUX_DmaFlexcomm0RxTrigoutToTriginChannels = 0U + (DMA_OTRIG_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_DmaFlexcomm0TxTrigoutToTriginChannels = 1U + (DMA_OTRIG_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_DmaFlexcomm1RxTrigoutToTriginChannels = 2U + (DMA_OTRIG_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_DmaFlexcomm1TxTrigoutToTriginChannels = 3U + (DMA_OTRIG_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_DmaFlexcomm2RxTrigoutToTriginChannels = 4U + (DMA_OTRIG_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_DmaFlexcomm2TxTrigoutToTriginChannels = 5U + (DMA_OTRIG_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_DmaFlexcomm3RxTrigoutToTriginChannels = 6U + (DMA_OTRIG_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_DmaFlexcomm3TxTrigoutToTriginChannels = 7U + (DMA_OTRIG_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_DmaFlexcomm4RxTrigoutToTriginChannels = 8U + (DMA_OTRIG_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_DmaFlexcomm4TxTrigoutToTriginChannels = 9U + (DMA_OTRIG_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_DmaFlexcomm5RxTrigoutToTriginChannels = 10U + (DMA_OTRIG_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_DmaFlexcomm5TxTrigoutToTriginChannels = 11U + (DMA_OTRIG_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_DmaFlexcomm6RxTrigoutToTriginChannels = 12U + (DMA_OTRIG_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_DmaFlexcomm6TxTrigoutToTriginChannels = 13U + (DMA_OTRIG_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_DmaFlexcomm7RxTrigoutToTriginChannels = 14U + (DMA_OTRIG_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_DmaFlexcomm7TxTrigoutToTriginChannels = 15U + (DMA_OTRIG_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_DmaDmic0Ch0TrigoutToTriginChannels = 16U + (DMA_OTRIG_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_Dmamic0Ch1TrigoutToTriginChannels = 17U + (DMA_OTRIG_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_DmaSpifi0TrigoutToTriginChannels = 18U + (DMA_OTRIG_PMUX_ID << PMUX_SHIFT),
kINPUTMUX_DmaChannel19_TrigoutToTriginChannels = 19U + (DMA_OTRIG_PMUX_ID << PMUX_SHIFT),
} inputmux_connection_t;
/*@}*/
#endif /* _FSL_INPUTMUX_CONNECTIONS_ */

288
drivers/fsl_iocon.h Normal file
View File

@@ -0,0 +1,288 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* Copyright 2016-2020 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _FSL_IOCON_H_
#define _FSL_IOCON_H_
#include "fsl_common.h"
/*!
* @addtogroup lpc_iocon
* @{
*/
/*! @file */
/*******************************************************************************
* Definitions
******************************************************************************/
/* Component ID definition, used by tools. */
#ifndef FSL_COMPONENT_ID
#define FSL_COMPONENT_ID "platform.drivers.lpc_iocon"
#endif
/*! @name Driver version */
/*@{*/
/*! @brief IOCON driver version. */
#define FSL_IOCON_DRIVER_VERSION (MAKE_VERSION(2, 1, 2))
/*@}*/
/**
* @brief Array of IOCON pin definitions passed to IOCON_SetPinMuxing() must be in this format
*/
typedef struct _iocon_group
{
uint8_t port; /* Pin port */
uint8_t pin; /* Pin number */
uint8_t ionumber; /* IO number */
uint16_t modefunc; /* Function and mode */
} iocon_group_t;
/**
* @brief IOCON function and mode selection definitions
* @note See the User Manual for specific modes and functions supported by the various pins.
*/
#if defined(FSL_FEATURE_IOCON_FUNC_FIELD_WIDTH) && (FSL_FEATURE_IOCON_FUNC_FIELD_WIDTH == 4)
#define IOCON_FUNC0 0x0 /*!< Selects pin function 0 */
#define IOCON_FUNC1 0x1 /*!< Selects pin function 1 */
#define IOCON_FUNC2 0x2 /*!< Selects pin function 2 */
#define IOCON_FUNC3 0x3 /*!< Selects pin function 3 */
#define IOCON_FUNC4 0x4 /*!< Selects pin function 4 */
#define IOCON_FUNC5 0x5 /*!< Selects pin function 5 */
#define IOCON_FUNC6 0x6 /*!< Selects pin function 6 */
#define IOCON_FUNC7 0x7 /*!< Selects pin function 7 */
#define IOCON_FUNC8 0x8 /*!< Selects pin function 8 */
#define IOCON_FUNC9 0x9 /*!< Selects pin function 9 */
#define IOCON_FUNC10 0xA /*!< Selects pin function 10 */
#define IOCON_FUNC11 0xB /*!< Selects pin function 11 */
#define IOCON_FUNC12 0xC /*!< Selects pin function 12 */
#define IOCON_FUNC13 0xD /*!< Selects pin function 13 */
#define IOCON_FUNC14 0xE /*!< Selects pin function 14 */
#define IOCON_FUNC15 0xF /*!< Selects pin function 15 */
#if defined(IOCON_PIO_MODE_SHIFT)
#define IOCON_MODE_INACT (0x0 << IOCON_PIO_MODE_SHIFT) /*!< No addition pin function */
#define IOCON_MODE_PULLDOWN (0x1 << IOCON_PIO_MODE_SHIFT) /*!< Selects pull-down function */
#define IOCON_MODE_PULLUP (0x2 << IOCON_PIO_MODE_SHIFT) /*!< Selects pull-up function */
#define IOCON_MODE_REPEATER (0x3 << IOCON_PIO_MODE_SHIFT) /*!< Selects pin repeater function */
#endif
#if defined(IOCON_PIO_I2CSLEW_SHIFT)
#define IOCON_GPIO_MODE (0x1 << IOCON_PIO_I2CSLEW_SHIFT) /*!< GPIO Mode */
#define IOCON_I2C_SLEW (0x0 << IOCON_PIO_I2CSLEW_SHIFT) /*!< I2C Slew Rate Control */
#endif
#if defined(IOCON_PIO_EGP_SHIFT)
#define IOCON_GPIO_MODE (0x1 << IOCON_PIO_EGP_SHIFT) /*!< GPIO Mode */
#define IOCON_I2C_SLEW (0x0 << IOCON_PIO_EGP_SHIFT) /*!< I2C Slew Rate Control */
#endif
#if defined(IOCON_PIO_SLEW_SHIFT)
#define IOCON_SLEW_STANDARD (0x0 << IOCON_PIO_SLEW_SHIFT) /*!< Driver Slew Rate Control */
#define IOCON_SLEW_FAST (0x1 << IOCON_PIO_SLEW_SHIFT) /*!< Driver Slew Rate Control */
#endif
#if defined(IOCON_PIO_INVERT_SHIFT)
#define IOCON_INV_EN (0x1 << IOCON_PIO_INVERT_SHIFT) /*!< Enables invert function on input */
#endif
#if defined(IOCON_PIO_DIGIMODE_SHIFT)
#define IOCON_ANALOG_EN (0x0 << IOCON_PIO_DIGIMODE_SHIFT) /*!< Enables analog function by setting 0 to bit 7 */
#define IOCON_DIGITAL_EN \
(0x1 << IOCON_PIO_DIGIMODE_SHIFT) /*!< Enables digital function by setting 1 to bit 7(default) */
#endif
#if defined(IOCON_PIO_FILTEROFF_SHIFT)
#define IOCON_INPFILT_OFF (0x1 << IOCON_PIO_FILTEROFF_SHIFT) /*!< Input filter Off for GPIO pins */
#define IOCON_INPFILT_ON (0x0 << IOCON_PIO_FILTEROFF_SHIFT) /*!< Input filter On for GPIO pins */
#endif
#if defined(IOCON_PIO_I2CDRIVE_SHIFT)
#define IOCON_I2C_LOWDRIVER (0x0 << IOCON_PIO_I2CDRIVE_SHIFT) /*!< Low drive, Output drive sink is 4 mA */
#define IOCON_I2C_HIGHDRIVER (0x1 << IOCON_PIO_I2CDRIVE_SHIFT) /*!< High drive, Output drive sink is 20 mA */
#endif
#if defined(IOCON_PIO_OD_SHIFT)
#define IOCON_OPENDRAIN_EN (0x1 << IOCON_PIO_OD_SHIFT) /*!< Enables open-drain function */
#endif
#if defined(IOCON_PIO_I2CFILTER_SHIFT)
#define IOCON_I2CFILTER_OFF (0x1 << IOCON_PIO_I2CFILTER_SHIFT) /*!< I2C 50 ns glitch filter enabled */
#define IOCON_I2CFILTER_ON (0x0 << IOCON_PIO_I2CFILTER_SHIFT) /*!< I2C 50 ns glitch filter not enabled, */
#endif
#if defined(IOCON_PIO_ASW_SHIFT)
#define IOCON_AWS_EN (0x1 << IOCON_PIO_ASW_SHIFT) /*!< Enables analog switch function */
#endif
#if defined(IOCON_PIO_SSEL_SHIFT)
#define IOCON_SSEL_3V3 (0x0 << IOCON_PIO_SSEL_SHIFT) /*!< 3V3 signaling in I2C mode */
#define IOCON_SSEL_1V8 (0x1 << IOCON_PIO_SSEL_SHIFT) /*!< 1V8 signaling in I2C mode */
#endif
#if defined(IOCON_PIO_ECS_SHIFT)
#define IOCON_ECS_OFF (0x0 << IOCON_PIO_ECS_SHIFT) /*!< IO is an open drain cell */
#define IOCON_ECS_ON (0x1 << IOCON_PIO_ECS_SHIFT) /*!< Pull-up resistor is connected */
#endif
#if defined(IOCON_PIO_S_MODE_SHIFT)
#define IOCON_S_MODE_0CLK (0x0 << IOCON_PIO_S_MODE_SHIFT) /*!< Bypass input filter */
#define IOCON_S_MODE_1CLK \
(0x1 << IOCON_PIO_S_MODE_SHIFT) /*!< Input pulses shorter than 1 filter clock are rejected \ \ \ \ \
*/
#define IOCON_S_MODE_2CLK \
(0x2 << IOCON_PIO_S_MODE_SHIFT) /*!< Input pulses shorter than 2 filter clock2 are rejected \ \ \ \ \
*/
#define IOCON_S_MODE_3CLK \
(0x3 << IOCON_PIO_S_MODE_SHIFT) /*!< Input pulses shorter than 3 filter clock2 are rejected \ \ \ \ \
*/
#define IOCON_S_MODE(clks) ((clks) << IOCON_PIO_S_MODE_SHIFT) /*!< Select clocks for digital input filter mode */
#endif
#if defined(IOCON_PIO_CLK_DIV_SHIFT)
#define IOCON_CLKDIV(div) \
((div) \
<< IOCON_PIO_CLK_DIV_SHIFT) /*!< Select peripheral clock divider for input filter sampling clock, 2^n, n=0-6 */
#endif
#else
#define IOCON_FUNC0 0x0 /*!< Selects pin function 0 */
#define IOCON_FUNC1 0x1 /*!< Selects pin function 1 */
#define IOCON_FUNC2 0x2 /*!< Selects pin function 2 */
#define IOCON_FUNC3 0x3 /*!< Selects pin function 3 */
#define IOCON_FUNC4 0x4 /*!< Selects pin function 4 */
#define IOCON_FUNC5 0x5 /*!< Selects pin function 5 */
#define IOCON_FUNC6 0x6 /*!< Selects pin function 6 */
#define IOCON_FUNC7 0x7 /*!< Selects pin function 7 */
#if defined(IOCON_PIO_MODE_SHIFT)
#define IOCON_MODE_INACT (0x0 << IOCON_PIO_MODE_SHIFT) /*!< No addition pin function */
#define IOCON_MODE_PULLDOWN (0x1 << IOCON_PIO_MODE_SHIFT) /*!< Selects pull-down function */
#define IOCON_MODE_PULLUP (0x2 << IOCON_PIO_MODE_SHIFT) /*!< Selects pull-up function */
#define IOCON_MODE_REPEATER (0x3 << IOCON_PIO_MODE_SHIFT) /*!< Selects pin repeater function */
#endif
#if defined(IOCON_PIO_I2CSLEW_SHIFT)
#define IOCON_GPIO_MODE (0x1 << IOCON_PIO_I2CSLEW_SHIFT) /*!< GPIO Mode */
#define IOCON_I2C_SLEW (0x0 << IOCON_PIO_I2CSLEW_SHIFT) /*!< I2C Slew Rate Control */
#endif
#if defined(IOCON_PIO_EGP_SHIFT)
#define IOCON_GPIO_MODE (0x1 << IOCON_PIO_EGP_SHIFT) /*!< GPIO Mode */
#define IOCON_I2C_SLEW (0x0 << IOCON_PIO_EGP_SHIFT) /*!< I2C Slew Rate Control */
#endif
#if defined(IOCON_PIO_INVERT_SHIFT)
#define IOCON_INV_EN (0x1 << IOCON_PIO_INVERT_SHIFT) /*!< Enables invert function on input */
#endif
#if defined(IOCON_PIO_DIGIMODE_SHIFT)
#define IOCON_ANALOG_EN (0x0 << IOCON_PIO_DIGIMODE_SHIFT) /*!< Enables analog function by setting 0 to bit 7 */
#define IOCON_DIGITAL_EN \
(0x1 << IOCON_PIO_DIGIMODE_SHIFT) /*!< Enables digital function by setting 1 to bit 7(default) */
#endif
#if defined(IOCON_PIO_FILTEROFF_SHIFT)
#define IOCON_INPFILT_OFF (0x1 << IOCON_PIO_FILTEROFF_SHIFT) /*!< Input filter Off for GPIO pins */
#define IOCON_INPFILT_ON (0x0 << IOCON_PIO_FILTEROFF_SHIFT) /*!< Input filter On for GPIO pins */
#endif
#if defined(IOCON_PIO_I2CDRIVE_SHIFT)
#define IOCON_I2C_LOWDRIVER (0x0 << IOCON_PIO_I2CDRIVE_SHIFT) /*!< Low drive, Output drive sink is 4 mA */
#define IOCON_I2C_HIGHDRIVER (0x1 << IOCON_PIO_I2CDRIVE_SHIFT) /*!< High drive, Output drive sink is 20 mA */
#endif
#if defined(IOCON_PIO_OD_SHIFT)
#define IOCON_OPENDRAIN_EN (0x1 << IOCON_PIO_OD_SHIFT) /*!< Enables open-drain function */
#endif
#if defined(IOCON_PIO_I2CFILTER_SHIFT)
#define IOCON_I2CFILTER_OFF (0x1 << IOCON_PIO_I2CFILTER_SHIFT) /*!< I2C 50 ns glitch filter enabled */
#define IOCON_I2CFILTER_ON (0x0 << IOCON_PIO_I2CFILTER_SHIFT) /*!< I2C 50 ns glitch filter not enabled */
#endif
#if defined(IOCON_PIO_S_MODE_SHIFT)
#define IOCON_S_MODE_0CLK (0x0 << IOCON_PIO_S_MODE_SHIFT) /*!< Bypass input filter */
#define IOCON_S_MODE_1CLK \
(0x1 << IOCON_PIO_S_MODE_SHIFT) /*!< Input pulses shorter than 1 filter clock are rejected \ \ \ \ \
*/
#define IOCON_S_MODE_2CLK \
(0x2 << IOCON_PIO_S_MODE_SHIFT) /*!< Input pulses shorter than 2 filter clock2 are rejected \ \ \ \ \
*/
#define IOCON_S_MODE_3CLK \
(0x3 << IOCON_PIO_S_MODE_SHIFT) /*!< Input pulses shorter than 3 filter clock2 are rejected \ \ \ \ \
*/
#define IOCON_S_MODE(clks) ((clks) << IOCON_PIO_S_MODE_SHIFT) /*!< Select clocks for digital input filter mode */
#endif
#if defined(IOCON_PIO_CLK_DIV_SHIFT)
#define IOCON_CLKDIV(div) \
((div) \
<< IOCON_PIO_CLK_DIV_SHIFT) /*!< Select peripheral clock divider for input filter sampling clock, 2^n, n=0-6 */
#endif
#endif
#if defined(__cplusplus)
extern "C" {
#endif
#if (defined(FSL_FEATURE_IOCON_ONE_DIMENSION) && (FSL_FEATURE_IOCON_ONE_DIMENSION == 1))
/**
* @brief Sets I/O Control pin mux
* @param base : The base of IOCON peripheral on the chip
* @param ionumber : GPIO number to mux
* @param modefunc : OR'ed values of type IOCON_*
* @return Nothing
*/
__STATIC_INLINE void IOCON_PinMuxSet(IOCON_Type *base, uint8_t ionumber, uint32_t modefunc)
{
base->PIO[ionumber] = modefunc;
}
#else
/**
* @brief Sets I/O Control pin mux
* @param base : The base of IOCON peripheral on the chip
* @param port : GPIO port to mux
* @param pin : GPIO pin to mux
* @param modefunc : OR'ed values of type IOCON_*
* @return Nothing
*/
__STATIC_INLINE void IOCON_PinMuxSet(IOCON_Type *base, uint8_t port, uint8_t pin, uint32_t modefunc)
{
base->PIO[port][pin] = modefunc;
}
#endif
/**
* @brief Set all I/O Control pin muxing
* @param base : The base of IOCON peripheral on the chip
* @param pinArray : Pointer to array of pin mux selections
* @param arrayLength : Number of entries in pinArray
* @return Nothing
*/
__STATIC_INLINE void IOCON_SetPinMuxing(IOCON_Type *base, const iocon_group_t *pinArray, uint32_t arrayLength)
{
uint32_t i;
for (i = 0; i < arrayLength; i++)
{
#if (defined(FSL_FEATURE_IOCON_ONE_DIMENSION) && (FSL_FEATURE_IOCON_ONE_DIMENSION == 1))
IOCON_PinMuxSet(base, pinArray[i].ionumber, pinArray[i].modefunc);
#else
IOCON_PinMuxSet(base, pinArray[i].port, pinArray[i].pin, pinArray[i].modefunc);
#endif /* FSL_FEATURE_IOCON_ONE_DIMENSION */
}
}
/* @} */
#if defined(__cplusplus)
}
#endif
#endif /* _FSL_IOCON_H_ */

185
drivers/fsl_reset.c Normal file
View File

@@ -0,0 +1,185 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* Copyright 2016, NXP
* All rights reserved.
*
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "fsl_common.h"
#include "fsl_reset.h"
/*******************************************************************************
* Definitions
******************************************************************************/
/* Component ID definition, used by tools. */
#ifndef FSL_COMPONENT_ID
#define FSL_COMPONENT_ID "platform.drivers.reset"
#endif
/*******************************************************************************
* Variables
******************************************************************************/
/*******************************************************************************
* Prototypes
******************************************************************************/
/*******************************************************************************
* Code
******************************************************************************/
#if ((defined(FSL_FEATURE_SOC_SYSCON_COUNT) && (FSL_FEATURE_SOC_SYSCON_COUNT > 0)) || \
(defined(FSL_FEATURE_SOC_ASYNC_SYSCON_COUNT) && (FSL_FEATURE_SOC_ASYNC_SYSCON_COUNT > 0)))
/*!
* brief Assert reset to peripheral.
*
* Asserts reset signal to specified peripheral module.
*
* param peripheral Assert reset to this peripheral. The enum argument contains encoding of reset register
* and reset bit position in the reset register.
*/
void RESET_SetPeripheralReset(reset_ip_name_t peripheral)
{
const uint32_t regIndex = ((uint32_t)peripheral & 0xFFFF0000u) >> 16;
const uint32_t bitPos = ((uint32_t)peripheral & 0x0000FFFFu);
const uint32_t bitMask = 1UL << bitPos;
assert(bitPos < 32UL);
/* ASYNC_SYSCON registers have offset 1024 */
if (regIndex >= SYSCON_PRESETCTRL_COUNT)
{
/* reset register is in ASYNC_SYSCON */
/* set bit */
ASYNC_SYSCON->ASYNCPRESETCTRLSET = bitMask;
/* wait until it reads 0b1 */
while (0u == (ASYNC_SYSCON->ASYNCPRESETCTRL & bitMask))
{
}
}
else
{
/* reset register is in SYSCON */
/* set bit */
SYSCON->PRESETCTRLSET[regIndex] = bitMask;
/* wait until it reads 0b1 */
while (0u == (SYSCON->PRESETCTRL[regIndex] & bitMask))
{
}
}
}
/*!
* brief Clear reset to peripheral.
*
* Clears reset signal to specified peripheral module, allows it to operate.
*
* param peripheral Clear reset to this peripheral. The enum argument contains encoding of reset register
* and reset bit position in the reset register.
*/
void RESET_ClearPeripheralReset(reset_ip_name_t peripheral)
{
const uint32_t regIndex = ((uint32_t)peripheral & 0xFFFF0000u) >> 16;
const uint32_t bitPos = ((uint32_t)peripheral & 0x0000FFFFu);
const uint32_t bitMask = 1UL << bitPos;
assert(bitPos < 32UL);
/* ASYNC_SYSCON registers have offset 1024 */
if (regIndex >= SYSCON_PRESETCTRL_COUNT)
{
/* reset register is in ASYNC_SYSCON */
/* clear bit */
ASYNC_SYSCON->ASYNCPRESETCTRLCLR = bitMask;
/* wait until it reads 0b0 */
while (bitMask == (ASYNC_SYSCON->ASYNCPRESETCTRL & bitMask))
{
}
}
else
{
/* reset register is in SYSCON */
/* clear bit */
SYSCON->PRESETCTRLCLR[regIndex] = bitMask;
/* wait until it reads 0b0 */
while (bitMask == (SYSCON->PRESETCTRL[regIndex] & bitMask))
{
}
}
}
/*!
* brief Reset peripheral module.
*
* Reset peripheral module.
*
* param peripheral Peripheral to reset. The enum argument contains encoding of reset register
* and reset bit position in the reset register.
*/
void RESET_PeripheralReset(reset_ip_name_t peripheral)
{
RESET_SetPeripheralReset(peripheral);
RESET_ClearPeripheralReset(peripheral);
}
/*!
* brief Set slave core to reset state and hold.
*/
void RESET_SetSlaveCoreReset(void)
{
uint32_t cpuctrl = (SYSCON->CPUCTRL & ~0x7F80U) | 0xC0C48000U;
/* CM4 is the master. */
if (SYSCON_CPUCTRL_MASTERCPU_MASK == (cpuctrl & SYSCON_CPUCTRL_MASTERCPU_MASK))
{
SYSCON->CPUCTRL = cpuctrl | SYSCON_CPUCTRL_CM0RSTEN_MASK;
}
/* CM0 is the master. */
else
{
SYSCON->CPUCTRL = cpuctrl | SYSCON_CPUCTRL_CM4RSTEN_MASK;
}
}
/*!
* brief Release slave core from reset state.
*/
void RESET_ClearSlaveCoreReset(void)
{
uint32_t cpuctrl = (SYSCON->CPUCTRL & ~0x7F80U) | 0xC0C48000U;
/* CM4 is the master. */
if (SYSCON_CPUCTRL_MASTERCPU_MASK == (cpuctrl & SYSCON_CPUCTRL_MASTERCPU_MASK))
{
SYSCON->CPUCTRL = cpuctrl & ~SYSCON_CPUCTRL_CM0RSTEN_MASK;
}
/* CM0 is the master. */
else
{
SYSCON->CPUCTRL = cpuctrl & ~SYSCON_CPUCTRL_CM4RSTEN_MASK;
}
}
/*!
* brief Reset slave core with the boot entry.
*/
void RESET_SlaveCoreReset(uint32_t bootAddr, uint32_t bootStackPointer)
{
volatile uint32_t i = 10U;
SYSCON->CPSTACK = bootStackPointer;
SYSCON->CPBOOT = bootAddr;
RESET_SetSlaveCoreReset();
while(0U != i--){}
RESET_ClearSlaveCoreReset();
}
#endif /* FSL_FEATURE_SOC_SYSCON_COUNT || FSL_FEATURE_SOC_ASYNC_SYSCON_COUNT */

205
drivers/fsl_reset.h Normal file
View File

@@ -0,0 +1,205 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* Copyright 2016, NXP
* All rights reserved.
*
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _FSL_RESET_H_
#define _FSL_RESET_H_
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "fsl_device_registers.h"
/*!
* @addtogroup reset
* @{
*/
/*******************************************************************************
* Definitions
******************************************************************************/
/*! @name Driver version */
/*@{*/
/*! @brief reset driver version 2.0.1. */
#define FSL_RESET_DRIVER_VERSION (MAKE_VERSION(2, 0, 1))
/*@}*/
/*!
* @brief Enumeration for peripheral reset control bits
*
* Defines the enumeration for peripheral reset control bits in PRESETCTRL/ASYNCPRESETCTRL registers
*/
typedef enum _SYSCON_RSTn
{
kFLASH_RST_SHIFT_RSTn = 0 | 7U, /**< Flash controller reset control */
kFMC_RST_SHIFT_RSTn = 0 | 8U, /**< Flash accelerator reset control */
kMUX_RST_SHIFT_RSTn = 0 | 11U, /**< Input mux reset control */
kIOCON_RST_SHIFT_RSTn = 0 | 13U, /**< IOCON reset control */
kGPIO0_RST_SHIFT_RSTn = 0 | 14U, /**< GPIO0 reset control */
kGPIO1_RST_SHIFT_RSTn = 0 | 15U, /**< GPIO1 reset control */
kPINT_RST_SHIFT_RSTn = 0 | 18U, /**< Pin interrupt (PINT) reset control */
kGINT_RST_SHIFT_RSTn = 0 | 19U, /**< Grouped interrupt (PINT) reset control. */
kDMA_RST_SHIFT_RSTn = 0 | 20U, /**< DMA reset control */
kCRC_RST_SHIFT_RSTn = 0 | 21U, /**< CRC reset control */
kWWDT_RST_SHIFT_RSTn = 0 | 22U, /**< Watchdog timer reset control */
kADC0_RST_SHIFT_RSTn = 0 | 27U, /**< ADC0 reset control */
kMRT_RST_SHIFT_RSTn = 65536 | 0U, /**< Multi-rate timer (MRT) reset control */
kSCT0_RST_SHIFT_RSTn = 65536 | 2U, /**< SCTimer/PWM 0 (SCT0) reset control */
kUTICK_RST_SHIFT_RSTn = 65536 | 10U, /**< Micro-tick timer reset control */
kFC0_RST_SHIFT_RSTn = 65536 | 11U, /**< Flexcomm Interface 0 reset control */
kFC1_RST_SHIFT_RSTn = 65536 | 12U, /**< Flexcomm Interface 1 reset control */
kFC2_RST_SHIFT_RSTn = 65536 | 13U, /**< Flexcomm Interface 2 reset control */
kFC3_RST_SHIFT_RSTn = 65536 | 14U, /**< Flexcomm Interface 3 reset control */
kFC4_RST_SHIFT_RSTn = 65536 | 15U, /**< Flexcomm Interface 4 reset control */
kFC5_RST_SHIFT_RSTn = 65536 | 16U, /**< Flexcomm Interface 5 reset control */
kFC6_RST_SHIFT_RSTn = 65536 | 17U, /**< Flexcomm Interface 6 reset control */
kFC7_RST_SHIFT_RSTn = 65536 | 18U, /**< Flexcomm Interface 7 reset control */
kDMIC_RST_SHIFT_RSTn = 65536 | 19U, /**< Digital microphone interface reset control */
kCT32B2_RST_SHIFT_RSTn = 65536 | 22U, /**< CT32B2 reset control */
kUSB_RST_SHIFT_RSTn = 65536 | 25U, /**< USB reset control */
kCT32B0_RST_SHIFT_RSTn = 65536 | 26U, /**< CT32B0 reset control */
kCT32B1_RST_SHIFT_RSTn = 65536 | 27U, /**< CT32B1 reset control */
kCT32B3_RST_SHIFT_RSTn = 67108864 | 13U, /**< CT32B3 reset control */
kCT32B4_RST_SHIFT_RSTn = 67108864 | 14U, /**< CT32B4 reset control */
} SYSCON_RSTn_t;
/** Array initializers with peripheral reset bits **/
#define ADC_RSTS \
{ \
kADC0_RST_SHIFT_RSTn \
} /* Reset bits for ADC peripheral */
#define CRC_RSTS \
{ \
kCRC_RST_SHIFT_RSTn \
} /* Reset bits for CRC peripheral */
#define DMA_RSTS_N \
{ \
kDMA_RST_SHIFT_RSTn \
} /* Reset bits for DMA peripheral */
#define DMIC_RSTS \
{ \
kDMIC_RST_SHIFT_RSTn \
} /* Reset bits for ADC peripheral */
#define FLEXCOMM_RSTS \
{ \
kFC0_RST_SHIFT_RSTn, kFC1_RST_SHIFT_RSTn, kFC2_RST_SHIFT_RSTn, kFC3_RST_SHIFT_RSTn, kFC4_RST_SHIFT_RSTn, \
kFC5_RST_SHIFT_RSTn, kFC6_RST_SHIFT_RSTn, kFC7_RST_SHIFT_RSTn \
} /* Reset bits for FLEXCOMM peripheral */
#define GINT_RSTS \
{ \
kGINT_RST_SHIFT_RSTn, kGINT_RST_SHIFT_RSTn \
} /* Reset bits for GINT peripheral. GINT0 & GINT1 share same slot */
#define GPIO_RSTS_N \
{ \
kGPIO0_RST_SHIFT_RSTn, kGPIO1_RST_SHIFT_RSTn \
} /* Reset bits for GPIO peripheral */
#define INPUTMUX_RSTS \
{ \
kMUX_RST_SHIFT_RSTn \
} /* Reset bits for INPUTMUX peripheral */
#define IOCON_RSTS \
{ \
kIOCON_RST_SHIFT_RSTn \
} /* Reset bits for IOCON peripheral */
#define FLASH_RSTS \
{ \
kFLASH_RST_SHIFT_RSTn, kFMC_RST_SHIFT_RSTn \
} /* Reset bits for Flash peripheral */
#define MRT_RSTS \
{ \
kMRT_RST_SHIFT_RSTn \
} /* Reset bits for MRT peripheral */
#define PINT_RSTS \
{ \
kPINT_RST_SHIFT_RSTn \
} /* Reset bits for PINT peripheral */
#define SCT_RSTS \
{ \
kSCT0_RST_SHIFT_RSTn \
} /* Reset bits for SCT peripheral */
#define CTIMER_RSTS \
{ \
kCT32B0_RST_SHIFT_RSTn, kCT32B1_RST_SHIFT_RSTn, kCT32B2_RST_SHIFT_RSTn, kCT32B3_RST_SHIFT_RSTn, \
kCT32B4_RST_SHIFT_RSTn \
} /* Reset bits for TIMER peripheral */
#define USB_RSTS \
{ \
kUSB_RST_SHIFT_RSTn \
} /* Reset bits for USB peripheral */
#define UTICK_RSTS \
{ \
kUTICK_RST_SHIFT_RSTn \
} /* Reset bits for UTICK peripheral */
#define WWDT_RSTS \
{ \
kWWDT_RST_SHIFT_RSTn \
} /* Reset bits for WWDT peripheral */
typedef SYSCON_RSTn_t reset_ip_name_t;
/*******************************************************************************
* API
******************************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif
/*!
* @brief Assert reset to peripheral.
*
* Asserts reset signal to specified peripheral module.
*
* @param peripheral Assert reset to this peripheral. The enum argument contains encoding of reset register
* and reset bit position in the reset register.
*/
void RESET_SetPeripheralReset(reset_ip_name_t peripheral);
/*!
* @brief Clear reset to peripheral.
*
* Clears reset signal to specified peripheral module, allows it to operate.
*
* @param peripheral Clear reset to this peripheral. The enum argument contains encoding of reset register
* and reset bit position in the reset register.
*/
void RESET_ClearPeripheralReset(reset_ip_name_t peripheral);
/*!
* @brief Reset peripheral module.
*
* Reset peripheral module.
*
* @param peripheral Peripheral to reset. The enum argument contains encoding of reset register
* and reset bit position in the reset register.
*/
void RESET_PeripheralReset(reset_ip_name_t peripheral);
/*!
* @brief Set slave core to reset state and hold.
*/
void RESET_SetSlaveCoreReset(void);
/*!
* @brief Release slave core from reset state.
*/
void RESET_ClearSlaveCoreReset(void);
/*!
* @brief Reset slave core with the boot entry.
*/
void RESET_SlaveCoreReset(uint32_t bootAddr, uint32_t bootStackPointer);
#if defined(__cplusplus)
}
#endif
/*! @} */
#endif /* _FSL_RESET_H_ */

803
drivers/fsl_sctimer.c Normal file
View File

@@ -0,0 +1,803 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* Copyright 2016-2020 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "fsl_sctimer.h"
/*******************************************************************************
* Definitions
******************************************************************************/
/* Component ID definition, used by tools. */
#ifndef FSL_COMPONENT_ID
#define FSL_COMPONENT_ID "platform.drivers.sctimer"
#endif
/*! @brief Typedef for interrupt handler. */
typedef void (*sctimer_isr_t)(SCT_Type *base);
/*******************************************************************************
* Prototypes
******************************************************************************/
/*!
* @brief Gets the instance from the base address
*
* @param base SCTimer peripheral base address
*
* @return The SCTimer instance
*/
static uint32_t SCTIMER_GetInstance(SCT_Type *base);
/*******************************************************************************
* Variables
******************************************************************************/
/*! @brief Pointers to SCT bases for each instance. */
static SCT_Type *const s_sctBases[] = SCT_BASE_PTRS;
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
/*! @brief Pointers to SCT clocks for each instance. */
static const clock_ip_name_t s_sctClocks[] = SCT_CLOCKS;
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
#if !(defined(FSL_SDK_DISABLE_DRIVER_RESET_CONTROL) && FSL_SDK_DISABLE_DRIVER_RESET_CONTROL)
#if defined(FSL_FEATURE_SCT_WRITE_ZERO_ASSERT_RESET) && FSL_FEATURE_SCT_WRITE_ZERO_ASSERT_RESET
/*! @brief Pointers to SCT resets for each instance, writing a zero asserts the reset */
static const reset_ip_name_t s_sctResets[] = SCT_RSTS_N;
#else
/*! @brief Pointers to SCT resets for each instance, writing a one asserts the reset */
static const reset_ip_name_t s_sctResets[] = SCT_RSTS;
#endif
#endif /* FSL_SDK_DISABLE_DRIVER_RESET_CONTROL */
/*!< @brief SCTimer event Callback function. */
static sctimer_event_callback_t s_eventCallback[FSL_FEATURE_SCT_NUMBER_OF_EVENTS];
/*!< @brief Keep track of SCTimer event number */
static uint32_t s_currentEvent;
/*!< @brief Keep track of SCTimer state number */
static uint32_t s_currentState;
/*!< @brief Keep track of SCTimer unify 32-bit or low 16-bit match/capture register number. */
static uint32_t s_currentMatch;
/*!< @brief Keep track of SCTimer high 16-bit match/capture register number. */
static uint32_t s_currentMatchhigh;
/*! @brief Pointer to SCTimer IRQ handler */
static sctimer_isr_t s_sctimerIsr;
/*******************************************************************************
* Code
******************************************************************************/
static uint32_t SCTIMER_GetInstance(SCT_Type *base)
{
uint32_t instance;
uint32_t sctArrayCount = (sizeof(s_sctBases) / sizeof(s_sctBases[0]));
/* Find the instance index from base address mappings. */
for (instance = 0; instance < sctArrayCount; instance++)
{
if (s_sctBases[instance] == base)
{
break;
}
}
assert(instance < sctArrayCount);
return instance;
}
/*!
* brief Ungates the SCTimer clock and configures the peripheral for basic operation.
*
* note This API should be called at the beginning of the application using the SCTimer driver.
*
* param base SCTimer peripheral base address
* param config Pointer to the user configuration structure.
*
* return kStatus_Success indicates success; Else indicates failure.
*/
status_t SCTIMER_Init(SCT_Type *base, const sctimer_config_t *config)
{
assert(NULL != config);
uint32_t i;
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
/* Enable the SCTimer clock*/
CLOCK_EnableClock(s_sctClocks[SCTIMER_GetInstance(base)]);
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
#if !(defined(FSL_SDK_DISABLE_DRIVER_RESET_CONTROL) && FSL_SDK_DISABLE_DRIVER_RESET_CONTROL)
/* Reset the module. */
RESET_PeripheralReset(s_sctResets[SCTIMER_GetInstance(base)]);
#endif /* FSL_SDK_DISABLE_DRIVER_RESET_CONTROL */
/* Setup the counter operation. For Current Driver interface SCTIMER_Init don't know detail
* frequency of input clock, but User know it. So the INSYNC have to set by user level. */
base->CONFIG = SCT_CONFIG_CKSEL(config->clockSelect) | SCT_CONFIG_CLKMODE(config->clockMode) |
SCT_CONFIG_UNIFY(config->enableCounterUnify) | SCT_CONFIG_INSYNC(config->inputsync);
/* Write to the control register, keep the counters halted. */
base->CTRL =
SCT_CTRL_BIDIR_L(config->enableBidirection_l) | SCT_CTRL_PRE_L(config->prescale_l) | SCT_CTRL_HALT_L_MASK;
/* Clear the counter after changing the PRE value. */
base->CTRL |= SCT_CTRL_CLRCTR_L_MASK;
if (!(config->enableCounterUnify))
{
base->CTRL |=
SCT_CTRL_BIDIR_H(config->enableBidirection_h) | SCT_CTRL_PRE_H(config->prescale_h) | SCT_CTRL_HALT_H_MASK;
base->CTRL |= SCT_CTRL_CLRCTR_H_MASK;
}
/* Initial state of channel output */
base->OUTPUT = config->outInitState;
/* Clear the global variables */
s_currentEvent = 0U;
s_currentState = 0U;
s_currentMatch = 0U;
s_currentMatchhigh = 0U;
/* Clear the callback array */
for (i = 0; i < (uint32_t)FSL_FEATURE_SCT_NUMBER_OF_EVENTS; i++)
{
s_eventCallback[i] = NULL;
}
/* Save interrupt handler */
s_sctimerIsr = SCTIMER_EventHandleIRQ;
return kStatus_Success;
}
/*!
* brief Gates the SCTimer clock.
*
* param base SCTimer peripheral base address
*/
void SCTIMER_Deinit(SCT_Type *base)
{
/* Halt the counters */
base->CTRL |= (SCT_CTRL_HALT_L_MASK | SCT_CTRL_HALT_H_MASK);
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
/* Disable the SCTimer clock*/
CLOCK_DisableClock(s_sctClocks[SCTIMER_GetInstance(base)]);
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
}
/*!
* brief Fills in the SCTimer configuration structure with the default settings.
*
* The default values are:
* code
* config->enableCounterUnify = true;
* config->clockMode = kSCTIMER_System_ClockMode;
* config->clockSelect = kSCTIMER_Clock_On_Rise_Input_0;
* config->enableBidirection_l = false;
* config->enableBidirection_h = false;
* config->prescale_l = 0U;
* config->prescale_h = 0U;
* config->outInitState = 0U;
* config->inputsync = 0xFU;
* endcode
* param config Pointer to the user configuration structure.
*/
void SCTIMER_GetDefaultConfig(sctimer_config_t *config)
{
assert(NULL != config);
/* Initializes the configure structure to zero. */
(void)memset(config, 0, sizeof(*config));
/* SCT operates as a unified 32-bit counter */
config->enableCounterUnify = true;
/* System clock clocks the entire SCT module */
config->clockMode = kSCTIMER_System_ClockMode;
/* This is used only by certain clock modes */
config->clockSelect = kSCTIMER_Clock_On_Rise_Input_0;
/* Up count mode only for the unified counter */
config->enableBidirection_l = false;
/* Up count mode only for Counte_H */
config->enableBidirection_h = false;
/* Prescale factor of 1 */
config->prescale_l = 0U;
/* Prescale factor of 1 for Counter_H*/
config->prescale_h = 0U;
/* Clear outputs */
config->outInitState = 0U;
/* Default value is 0xFU, it can be clear as 0 when speical conditions met.
* Condition can be clear as 0: (for all Clock Modes):
* (1) The corresponding input is already synchronous to the SCTimer/PWM clock.
* (2) The SCTimer/PWM clock frequency does not exceed 100 MHz.
* Note: The SCTimer/PWM clock is the bus/system clock for CKMODE 0-2 or asynchronous input
* clock for CKMODE3.
* Another condition can be clear as 0: (for CKMODE2 only)
* (1) The corresponding input is synchronous to the designated CKMODE2 input clock.
* (2) The CKMODE2 input clock frequency is less than one-third the frequency of the bus/system clock.
* Default value set as 0U, input0~input3 are set as bypasses. */
config->inputsync = 0xFU;
}
/*!
* brief Configures the PWM signal parameters.
*
* Call this function to configure the PWM signal period, mode, duty cycle, and edge. This
* function will create 2 events; one of the events will trigger on match with the pulse value
* and the other will trigger when the counter matches the PWM period. The PWM period event is
* also used as a limit event to reset the counter or change direction. Both events are enabled
* for the same state. The state number can be retrieved by calling the function
* SCTIMER_GetCurrentStateNumber().
* The counter is set to operate as one 32-bit counter (unify bit is set to 1).
* The counter operates in bi-directional mode when generating a center-aligned PWM.
*
* note When setting PWM output from multiple output pins, they all should use the same PWM mode
* i.e all PWM's should be either edge-aligned or center-aligned.
* When using this API, the PWM signal frequency of all the initialized channels must be the same.
* Otherwise all the initialized channels' PWM signal frequency is equal to the last call to the
* API's pwmFreq_Hz.
*
* param base SCTimer peripheral base address
* param pwmParams PWM parameters to configure the output
* param mode PWM operation mode, options available in enumeration ::sctimer_pwm_mode_t
* param pwmFreq_Hz PWM signal frequency in Hz
* param srcClock_Hz SCTimer counter clock in Hz
* param event Pointer to a variable where the PWM period event number is stored
*
* return kStatus_Success on success
* kStatus_Fail If we have hit the limit in terms of number of events created or if
* an incorrect PWM dutycylce is passed in.
*/
status_t SCTIMER_SetupPwm(SCT_Type *base,
const sctimer_pwm_signal_param_t *pwmParams,
sctimer_pwm_mode_t mode,
uint32_t pwmFreq_Hz,
uint32_t srcClock_Hz,
uint32_t *event)
{
assert(NULL != pwmParams);
assert(0U != srcClock_Hz);
assert(0U != pwmFreq_Hz);
assert((uint32_t)pwmParams->output < (uint32_t)FSL_FEATURE_SCT_NUMBER_OF_OUTPUTS);
assert(1U == (base->CONFIG & SCT_CONFIG_UNIFY_MASK));
/* If we do not have enough events available (this function will create two events),
* the function will return fail.
*/
status_t status = kStatus_Fail;
status_t status2;
uint32_t period, pulsePeriod = 0;
uint32_t sctClock = srcClock_Hz / (((base->CTRL & SCT_CTRL_PRE_L_MASK) >> SCT_CTRL_PRE_L_SHIFT) + 1U);
uint32_t periodEvent = 0, pulseEvent = 0;
uint32_t reg;
if ((s_currentEvent + 2U) <= (uint32_t)FSL_FEATURE_SCT_NUMBER_OF_EVENTS)
{
/* Use bi-directional mode for center-aligned PWM */
if (mode == kSCTIMER_CenterAlignedPwm)
{
base->CTRL |= SCT_CTRL_BIDIR_L_MASK;
}
/* Calculate PWM period match value */
if (mode == kSCTIMER_EdgeAlignedPwm)
{
period = (sctClock / pwmFreq_Hz) - 1U;
}
else
{
period = sctClock / (pwmFreq_Hz * 2U);
}
/* Calculate pulse width and period match value:
* For EdgeAlignedPwm, "pulsePeriod = 0" results in 0% dutycyle, "pulsePeriod = period - 1U" results in 100%
* dutycyle. For CenterAlignedPwm, , "pulsePeriod = 0" results in 0% dutycyle, "pulsePeriod = period + 2U"
* results in 100% dutycyle.
*/
pulsePeriod = (uint32_t)(((uint64_t)period * pwmParams->dutyCyclePercent) / 100U);
if (pwmParams->dutyCyclePercent >= 100U)
{
if (mode == kSCTIMER_EdgeAlignedPwm)
{
pulsePeriod = period + 2U;
}
else
{
pulsePeriod = period - 1U;
}
}
/* Schedule an event when we reach the PWM period */
status =
SCTIMER_CreateAndScheduleEvent(base, kSCTIMER_MatchEventOnly, period, 0, kSCTIMER_Counter_U, &periodEvent);
/* Schedule an event when we reach the pulse width */
status2 = SCTIMER_CreateAndScheduleEvent(base, kSCTIMER_MatchEventOnly, pulsePeriod, 0, kSCTIMER_Counter_U,
&pulseEvent);
if ((kStatus_Success == status) && (kStatus_Success == status2))
{
/* Reset the counter when we reach the PWM period */
SCTIMER_SetupCounterLimitAction(base, kSCTIMER_Counter_U, periodEvent);
/* Return the period event to the user */
*event = periodEvent;
/* For high-true level */
if ((uint32_t)pwmParams->level == (uint32_t)kSCTIMER_HighTrue)
{
/* Set the initial output level to low which is the inactive state */
base->OUTPUT &= ~(1UL << (uint32_t)pwmParams->output);
if (mode == kSCTIMER_EdgeAlignedPwm)
{
/* Set the output when we reach the PWM period */
SCTIMER_SetupOutputSetAction(base, (uint32_t)pwmParams->output, periodEvent);
/* Clear the output when we reach the PWM pulse value */
SCTIMER_SetupOutputClearAction(base, (uint32_t)pwmParams->output, pulseEvent);
}
else
{
/* Clear the output when we reach the PWM pulse event */
SCTIMER_SetupOutputClearAction(base, (uint32_t)pwmParams->output, pulseEvent);
/* Reverse output when down counting */
reg = base->OUTPUTDIRCTRL;
reg &= ~((uint32_t)SCT_OUTPUTDIRCTRL_SETCLR0_MASK << (2U * (uint32_t)pwmParams->output));
reg |= (1UL << (2U * (uint32_t)pwmParams->output));
base->OUTPUTDIRCTRL = reg;
}
}
/* For low-true level */
else
{
/* Set the initial output level to high which is the inactive state */
base->OUTPUT |= (1UL << (uint32_t)pwmParams->output);
if (mode == kSCTIMER_EdgeAlignedPwm)
{
/* Clear the output when we reach the PWM period */
SCTIMER_SetupOutputClearAction(base, (uint32_t)pwmParams->output, periodEvent);
/* Set the output when we reach the PWM pulse value */
SCTIMER_SetupOutputSetAction(base, (uint32_t)pwmParams->output, pulseEvent);
}
else
{
/* Set the output when we reach the PWM pulse event */
SCTIMER_SetupOutputSetAction(base, (uint32_t)pwmParams->output, pulseEvent);
/* Reverse output when down counting */
reg = base->OUTPUTDIRCTRL;
reg &= ~((uint32_t)SCT_OUTPUTDIRCTRL_SETCLR0_MASK << (2U * (uint32_t)pwmParams->output));
reg |= (1UL << (2U * (uint32_t)pwmParams->output));
base->OUTPUTDIRCTRL = reg;
}
}
}
else
{
status = kStatus_Fail;
}
}
return status;
}
/*!
* brief Updates the duty cycle of an active PWM signal.
*
* Before calling this function, the counter is set to operate as one 32-bit counter (unify bit is set to 1).
*
* param base SCTimer peripheral base address
* param output The output to configure
* param dutyCyclePercent New PWM pulse width; the value should be between 0 to 100
* param event Event number associated with this PWM signal. This was returned to the user by the
* function SCTIMER_SetupPwm().
*/
void SCTIMER_UpdatePwmDutycycle(SCT_Type *base, sctimer_out_t output, uint8_t dutyCyclePercent, uint32_t event)
{
assert(dutyCyclePercent <= 100U);
assert((uint32_t)output < (uint32_t)FSL_FEATURE_SCT_NUMBER_OF_OUTPUTS);
assert(1U == (base->CONFIG & SCT_CONFIG_UNIFY_MASK));
uint32_t periodMatchReg, pulseMatchReg;
uint32_t pulsePeriod = 0, period;
/* Retrieve the match register number for the PWM period */
periodMatchReg = base->EV[event].CTRL & SCT_EV_CTRL_MATCHSEL_MASK;
/* Retrieve the match register number for the PWM pulse period */
pulseMatchReg = base->EV[event + 1U].CTRL & SCT_EV_CTRL_MATCHSEL_MASK;
period = base->MATCH[periodMatchReg];
/* Calculate pulse width and period match value:
* For EdgeAlignedPwm, "pulsePeriod = 0" results in 0% dutycyle, "pulsePeriod = period - 1U" results in 100%
* dutycyle. For CenterAlignedPwm, , "pulsePeriod = 0" results in 0% dutycyle, "pulsePeriod = period + 2U"
* results in 100% dutycyle.
*/
pulsePeriod = (uint32_t)(((uint64_t)period * dutyCyclePercent) / 100U);
if (dutyCyclePercent == 100U)
{
if (0U == (base->CTRL & SCT_CTRL_BIDIR_L_MASK))
{
pulsePeriod = period + 2U;
}
else
{
pulsePeriod = period - 1U;
}
}
/* Stop the counter before updating match register */
SCTIMER_StopTimer(base, (uint32_t)kSCTIMER_Counter_U);
/* Update dutycycle */
base->MATCH[pulseMatchReg] = SCT_MATCH_MATCHn_L(pulsePeriod);
base->MATCHREL[pulseMatchReg] = SCT_MATCHREL_RELOADn_L(pulsePeriod);
/* Restart the counter */
SCTIMER_StartTimer(base, (uint32_t)kSCTIMER_Counter_U);
}
/*!
* brief Create an event that is triggered on a match or IO and schedule in current state.
*
* This function will configure an event using the options provided by the user. If the event type uses
* the counter match, then the function will set the user provided match value into a match register
* and put this match register number into the event control register.
* The event is enabled for the current state and the event number is increased by one at the end.
* The function returns the event number; this event number can be used to configure actions to be
* done when this event is triggered.
*
* param base SCTimer peripheral base address
* param howToMonitor Event type; options are available in the enumeration ::sctimer_interrupt_enable_t
* param matchValue The match value that will be programmed to a match register
* param whichIO The input or output that will be involved in event triggering. This field
* is ignored if the event type is "match only"
* param whichCounter SCTimer counter to use. In 16-bit mode, we can select Counter_L and Counter_H,
* In 32-bit mode, we can select Counter_U.
* param event Pointer to a variable where the new event number is stored
*
* return kStatus_Success on success
* kStatus_Error if we have hit the limit in terms of number of events created or
if we have reached the limit in terms of number of match registers
*/
status_t SCTIMER_CreateAndScheduleEvent(SCT_Type *base,
sctimer_event_t howToMonitor,
uint32_t matchValue,
uint32_t whichIO,
sctimer_counter_t whichCounter,
uint32_t *event)
{
uint32_t combMode = (((uint32_t)howToMonitor & SCT_EV_CTRL_COMBMODE_MASK) >> SCT_EV_CTRL_COMBMODE_SHIFT);
uint32_t currentCtrlVal = (uint32_t)howToMonitor;
status_t status = kStatus_Success;
if (s_currentEvent < (uint32_t)FSL_FEATURE_SCT_NUMBER_OF_EVENTS)
{
if (2U == combMode)
{
base->EV[s_currentEvent].CTRL = currentCtrlVal | SCT_EV_CTRL_IOSEL(whichIO);
}
else
{
if ((0U == combMode) || (3U == combMode))
{
currentCtrlVal |= SCT_EV_CTRL_IOSEL(whichIO);
}
if ((kSCTIMER_Counter_L == whichCounter) && (0U == (base->CONFIG & SCT_CONFIG_UNIFY_MASK)))
{
if (s_currentMatch < (uint32_t)FSL_FEATURE_SCT_NUMBER_OF_MATCH_CAPTURE)
{
currentCtrlVal |= SCT_EV_CTRL_MATCHSEL(s_currentMatch);
/* Use Counter_L bits if user wants to setup the Low counter */
base->MATCH_ACCESS16BIT[s_currentMatch].MATCHL = (uint16_t)matchValue;
base->MATCHREL_ACCESS16BIT[s_currentMatch].MATCHRELL = (uint16_t)matchValue;
base->EV[s_currentEvent].CTRL = currentCtrlVal;
/* Increment the match register number */
s_currentMatch++;
}
else
{
/* An error would occur if we have hit the limit in terms of number of match registers */
status = kStatus_Fail;
}
}
else if ((kSCTIMER_Counter_H == whichCounter) && (0U == (base->CONFIG & SCT_CONFIG_UNIFY_MASK)))
{
if (s_currentMatchhigh < (uint32_t)FSL_FEATURE_SCT_NUMBER_OF_MATCH_CAPTURE)
{
currentCtrlVal |= SCT_EV_CTRL_MATCHSEL(s_currentMatchhigh);
/* Use Counter_H bits if user wants to setup the High counter */
currentCtrlVal |= SCT_EV_CTRL_HEVENT(1U);
base->MATCH_ACCESS16BIT[s_currentMatchhigh].MATCHH = (uint16_t)matchValue;
base->MATCHREL_ACCESS16BIT[s_currentMatchhigh].MATCHRELH = (uint16_t)matchValue;
base->EV[s_currentEvent].CTRL = currentCtrlVal;
/* Increment the match register number */
s_currentMatchhigh++;
}
else
{
/* An error would occur if we have hit the limit in terms of number of match registers */
status = kStatus_Fail;
}
}
else if ((kSCTIMER_Counter_U == whichCounter) && (0U != (base->CONFIG & SCT_CONFIG_UNIFY_MASK)))
{
if (s_currentMatch < (uint32_t)FSL_FEATURE_SCT_NUMBER_OF_MATCH_CAPTURE)
{
/* Use Counter_L bits if counter is operating in 32-bit mode */
currentCtrlVal |= SCT_EV_CTRL_MATCHSEL(s_currentMatch);
base->MATCH[s_currentMatch] = matchValue;
base->MATCHREL[s_currentMatch] = matchValue;
base->EV[s_currentEvent].CTRL = currentCtrlVal;
/* Increment the match register number */
s_currentMatch++;
}
else
{
/* An error would occur if we have hit the limit in terms of number of match registers */
status = kStatus_Fail;
}
}
else
{
/* The used counter must match the CONFIG[UNIFY] bit selection */
status = kStatus_Fail;
}
}
if (kStatus_Success == status)
{
/* Enable the event in the current state */
base->EV[s_currentEvent].STATE = (1UL << s_currentState);
/* Return the event number */
*event = s_currentEvent;
/* Increment the event number */
s_currentEvent++;
}
}
else
{
/* An error would occur if we have hit the limit in terms of number of events created */
status = kStatus_Fail;
}
return status;
}
/*!
* brief Enable an event in the current state.
*
* This function will allow the event passed in to trigger in the current state. The event must
* be created earlier by either calling the function SCTIMER_SetupPwm() or function
* SCTIMER_CreateAndScheduleEvent() .
*
* param base SCTimer peripheral base address
* param event Event number to enable in the current state
*
*/
void SCTIMER_ScheduleEvent(SCT_Type *base, uint32_t event)
{
/* Enable event in the current state */
base->EV[event].STATE |= (1UL << s_currentState);
}
/*!
* brief Increase the state by 1
*
* All future events created by calling the function SCTIMER_ScheduleEvent() will be enabled in this new
* state.
*
* param base SCTimer peripheral base address
*
* return kStatus_Success on success
* kStatus_Error if we have hit the limit in terms of states used
*/
status_t SCTIMER_IncreaseState(SCT_Type *base)
{
status_t status = kStatus_Success;
/* Return an error if we have hit the limit in terms of states used */
if (s_currentState >= (uint32_t)FSL_FEATURE_SCT_NUMBER_OF_STATES)
{
status = kStatus_Fail;
}
else
{
s_currentState++;
}
return status;
}
/*!
* brief Provides the current state
*
* User can use this to set the next state by calling the function SCTIMER_SetupNextStateAction().
*
* param base SCTimer peripheral base address
*
* return The current state
*/
uint32_t SCTIMER_GetCurrentState(SCT_Type *base)
{
return s_currentState;
}
/*!
* brief Toggle the output level.
*
* This change in the output level is triggered by the event number that is passed in by the user.
*
* param base SCTimer peripheral base address
* param whichIO The output to toggle
* param event Event number that will trigger the output change
*/
void SCTIMER_SetupOutputToggleAction(SCT_Type *base, uint32_t whichIO, uint32_t event)
{
assert(whichIO < (uint32_t)FSL_FEATURE_SCT_NUMBER_OF_OUTPUTS);
uint32_t reg;
/* Set the same event to set and clear the output */
base->OUT[whichIO].CLR |= (1UL << event);
base->OUT[whichIO].SET |= (1UL << event);
/* Set the conflict resolution to toggle output */
reg = base->RES;
reg &= ~(((uint32_t)SCT_RES_O0RES_MASK) << (2U * whichIO));
reg |= ((uint32_t)(kSCTIMER_ResolveToggle)) << (2U * whichIO);
base->RES = reg;
}
/*!
* brief Setup capture of the counter value on trigger of a selected event
*
* param base SCTimer peripheral base address
* param whichCounter SCTimer counter to use. In 16-bit mode, we can select Counter_L and Counter_H,
* In 32-bit mode, we can select Counter_U.
* param captureRegister Pointer to a variable where the capture register number will be returned. User
* can read the captured value from this register when the specified event is triggered.
* param event Event number that will trigger the capture
*
* return kStatus_Success on success
* kStatus_Error if we have hit the limit in terms of number of match/capture registers available
*/
status_t SCTIMER_SetupCaptureAction(SCT_Type *base,
sctimer_counter_t whichCounter,
uint32_t *captureRegister,
uint32_t event)
{
status_t status;
if ((kSCTIMER_Counter_L == whichCounter) || (kSCTIMER_Counter_U == whichCounter))
{
if (s_currentMatch < (uint32_t)FSL_FEATURE_SCT_NUMBER_OF_MATCH_CAPTURE)
{
/* Set the bit to enable event */
base->CAPCTRL_ACCESS16BIT[s_currentMatch].CAPCTRLL |= SCT_CAPCTRLL_CAPCTRLL(1UL << event);
/* Set this resource to be a capture rather than match */
base->REGMODE_ACCESS16BIT.REGMODEL |= SCT_REGMODEL_REGMODEL(1UL << s_currentMatch);
/* Return the match register number */
*captureRegister = s_currentMatch;
/* Increase the match register number */
s_currentMatch++;
status = kStatus_Success;
}
else
{
/* Return an error if we have hit the limit in terms of number of capture/match registers used */
status = kStatus_Fail;
}
}
else
{
if (s_currentMatchhigh < (uint32_t)FSL_FEATURE_SCT_NUMBER_OF_MATCH_CAPTURE)
{
/* Set bit to enable event */
base->CAPCTRL_ACCESS16BIT[s_currentMatchhigh].CAPCTRLH |= SCT_CAPCTRLL_CAPCTRLL(1UL << event);
/* Set this resource to be a capture rather than match */
base->REGMODE_ACCESS16BIT.REGMODEH |= SCT_REGMODEL_REGMODEL(1UL << s_currentMatchhigh);
/* Return the match register number */
*captureRegister = s_currentMatchhigh;
/* Increase the match register number */
s_currentMatchhigh++;
status = kStatus_Success;
}
else
{
/* Return an error if we have hit the limit in terms of number of capture/match registers used */
status = kStatus_Fail;
}
}
return status;
}
/*!
* brief Receive noticification when the event trigger an interrupt.
*
* If the interrupt for the event is enabled by the user, then a callback can be registered
* which will be invoked when the event is triggered
*
* param base SCTimer peripheral base address
* param event Event number that will trigger the interrupt
* param callback Function to invoke when the event is triggered
*/
void SCTIMER_SetCallback(SCT_Type *base, sctimer_event_callback_t callback, uint32_t event)
{
s_eventCallback[event] = callback;
}
/*!
* brief SCTimer interrupt handler.
*
* param base SCTimer peripheral base address.
*/
void SCTIMER_EventHandleIRQ(SCT_Type *base)
{
uint32_t eventFlag = SCT0->EVFLAG;
/* Only clear the flags whose interrupt field is enabled */
uint32_t clearFlag = (eventFlag & SCT0->EVEN);
uint32_t mask = eventFlag;
uint32_t i;
/* Invoke the callback for certain events */
for (i = 0; i < (uint32_t)FSL_FEATURE_SCT_NUMBER_OF_EVENTS; i++)
{
if ((mask & 0x1U) != 0U)
{
if (s_eventCallback[i] != NULL)
{
s_eventCallback[i]();
}
}
mask >>= 1UL;
if (0U == mask)
{
/* All events have been handled. */
break;
}
}
/* Clear event interrupt flag */
SCT0->EVFLAG = clearFlag;
}
void SCT0_DriverIRQHandler(void);
void SCT0_DriverIRQHandler(void)
{
s_sctimerIsr(SCT0);
SDK_ISR_EXIT_BARRIER;
}

1258
drivers/fsl_sctimer.h Normal file

File diff suppressed because it is too large Load Diff

1072
drivers/fsl_spi.c Normal file

File diff suppressed because it is too large Load Diff

746
drivers/fsl_spi.h Normal file
View File

@@ -0,0 +1,746 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* Copyright 2016-2020 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _FSL_SPI_H_
#define _FSL_SPI_H_
#include "fsl_common.h"
#include "fsl_flexcomm.h"
/*!
* @addtogroup spi_driver
* @{
*/
/*! @file */
/*******************************************************************************
* Definitions
******************************************************************************/
/*! @name Driver version */
/*@{*/
/*! @brief SPI driver version. */
#define FSL_SPI_DRIVER_VERSION (MAKE_VERSION(2, 2, 1))
/*@}*/
/*! @brief Global variable for dummy data value setting. */
extern volatile uint8_t s_dummyData[];
#ifndef SPI_DUMMYDATA
/*! @brief SPI dummy transfer data, the data is sent while txBuff is NULL. */
#define SPI_DUMMYDATA (0xFFU)
#endif
/*! @brief Retry times for waiting flag. */
#ifndef SPI_RETRY_TIMES
#define SPI_RETRY_TIMES 0U /* Define to zero means keep waiting until the flag is assert/deassert. */
#endif
#define SPI_DATA(n) (((uint32_t)(n)) & 0xFFFFUL)
#define SPI_CTRLMASK (0xFFFF0000U)
#define SPI_ASSERTNUM_SSEL(n) ((~(1UL << ((n) + 16UL))) & 0xF0000UL)
#define SPI_DEASSERTNUM_SSEL(n) (1UL << ((n) + 16UL))
#define SPI_DEASSERT_ALL (0xF0000UL)
#define SPI_FIFOWR_FLAGS_MASK (~(SPI_DEASSERT_ALL | SPI_FIFOWR_TXDATA_MASK | SPI_FIFOWR_LEN_MASK))
#define SPI_FIFOTRIG_TXLVL_GET(base) (((base)->FIFOTRIG & SPI_FIFOTRIG_TXLVL_MASK) >> SPI_FIFOTRIG_TXLVL_SHIFT)
#define SPI_FIFOTRIG_RXLVL_GET(base) (((base)->FIFOTRIG & SPI_FIFOTRIG_RXLVL_MASK) >> SPI_FIFOTRIG_RXLVL_SHIFT)
/*! @brief SPI transfer option.*/
typedef enum _spi_xfer_option
{
kSPI_FrameDelay = (SPI_FIFOWR_EOF_MASK), /*!< A delay may be inserted, defined in the DLY register.*/
kSPI_FrameAssert = (SPI_FIFOWR_EOT_MASK), /*!< SSEL will be deasserted at the end of a transfer */
} spi_xfer_option_t;
/*! @brief SPI data shifter direction options.*/
typedef enum _spi_shift_direction
{
kSPI_MsbFirst = 0U, /*!< Data transfers start with most significant bit. */
kSPI_LsbFirst = 1U /*!< Data transfers start with least significant bit. */
} spi_shift_direction_t;
/*! @brief SPI clock polarity configuration.*/
typedef enum _spi_clock_polarity
{
kSPI_ClockPolarityActiveHigh = 0x0U, /*!< Active-high SPI clock (idles low). */
kSPI_ClockPolarityActiveLow /*!< Active-low SPI clock (idles high). */
} spi_clock_polarity_t;
/*! @brief SPI clock phase configuration.*/
typedef enum _spi_clock_phase
{
kSPI_ClockPhaseFirstEdge = 0x0U, /*!< First edge on SCK occurs at the middle of the first
* cycle of a data transfer. */
kSPI_ClockPhaseSecondEdge /*!< First edge on SCK occurs at the start of the
* first cycle of a data transfer. */
} spi_clock_phase_t;
/*! @brief txFIFO watermark values */
typedef enum _spi_txfifo_watermark
{
kSPI_TxFifo0 = 0, /*!< SPI tx watermark is empty */
kSPI_TxFifo1 = 1, /*!< SPI tx watermark at 1 item */
kSPI_TxFifo2 = 2, /*!< SPI tx watermark at 2 items */
kSPI_TxFifo3 = 3, /*!< SPI tx watermark at 3 items */
kSPI_TxFifo4 = 4, /*!< SPI tx watermark at 4 items */
kSPI_TxFifo5 = 5, /*!< SPI tx watermark at 5 items */
kSPI_TxFifo6 = 6, /*!< SPI tx watermark at 6 items */
kSPI_TxFifo7 = 7, /*!< SPI tx watermark at 7 items */
} spi_txfifo_watermark_t;
/*! @brief rxFIFO watermark values */
typedef enum _spi_rxfifo_watermark
{
kSPI_RxFifo1 = 0, /*!< SPI rx watermark at 1 item */
kSPI_RxFifo2 = 1, /*!< SPI rx watermark at 2 items */
kSPI_RxFifo3 = 2, /*!< SPI rx watermark at 3 items */
kSPI_RxFifo4 = 3, /*!< SPI rx watermark at 4 items */
kSPI_RxFifo5 = 4, /*!< SPI rx watermark at 5 items */
kSPI_RxFifo6 = 5, /*!< SPI rx watermark at 6 items */
kSPI_RxFifo7 = 6, /*!< SPI rx watermark at 7 items */
kSPI_RxFifo8 = 7, /*!< SPI rx watermark at 8 items */
} spi_rxfifo_watermark_t;
/*! @brief Transfer data width */
typedef enum _spi_data_width
{
kSPI_Data4Bits = 3, /*!< 4 bits data width */
kSPI_Data5Bits = 4, /*!< 5 bits data width */
kSPI_Data6Bits = 5, /*!< 6 bits data width */
kSPI_Data7Bits = 6, /*!< 7 bits data width */
kSPI_Data8Bits = 7, /*!< 8 bits data width */
kSPI_Data9Bits = 8, /*!< 9 bits data width */
kSPI_Data10Bits = 9, /*!< 10 bits data width */
kSPI_Data11Bits = 10, /*!< 11 bits data width */
kSPI_Data12Bits = 11, /*!< 12 bits data width */
kSPI_Data13Bits = 12, /*!< 13 bits data width */
kSPI_Data14Bits = 13, /*!< 14 bits data width */
kSPI_Data15Bits = 14, /*!< 15 bits data width */
kSPI_Data16Bits = 15, /*!< 16 bits data width */
} spi_data_width_t;
/*! @brief Slave select */
typedef enum _spi_ssel
{
kSPI_Ssel0 = 0, /*!< Slave select 0 */
kSPI_Ssel1 = 1, /*!< Slave select 1 */
kSPI_Ssel2 = 2, /*!< Slave select 2 */
kSPI_Ssel3 = 3, /*!< Slave select 3 */
} spi_ssel_t;
/*! @brief ssel polarity */
typedef enum _spi_spol
{
kSPI_Spol0ActiveHigh = SPI_CFG_SPOL0(1),
kSPI_Spol1ActiveHigh = SPI_CFG_SPOL1(1),
kSPI_Spol2ActiveHigh = SPI_CFG_SPOL2(1),
#if defined(FSL_FEATURE_SPI_IS_SSEL_PIN_COUNT_EQUAL_TO_THREE) && (FSL_FEATURE_SPI_IS_SSEL_PIN_COUNT_EQUAL_TO_THREE)
kSPI_SpolActiveAllHigh = (kSPI_Spol0ActiveHigh | kSPI_Spol1ActiveHigh | kSPI_Spol2ActiveHigh),
#else
kSPI_Spol3ActiveHigh = SPI_CFG_SPOL3(1),
kSPI_SpolActiveAllHigh =
(kSPI_Spol0ActiveHigh | kSPI_Spol1ActiveHigh | kSPI_Spol2ActiveHigh | kSPI_Spol3ActiveHigh),
#endif
kSPI_SpolActiveAllLow = 0,
} spi_spol_t;
/*!
* @brief SPI delay time configure structure.
* Note:
* The DLY register controls several programmable delays related to SPI signalling,
* it stands for how many SPI clock time will be inserted.
* The maxinun value of these delay time is 15.
*/
typedef struct _spi_delay_config
{
uint8_t preDelay; /*!< Delay between SSEL assertion and the beginning of transfer. */
uint8_t postDelay; /*!< Delay between the end of transfer and SSEL deassertion. */
uint8_t frameDelay; /*!< Delay between frame to frame. */
uint8_t transferDelay; /*!< Delay between transfer to transfer. */
} spi_delay_config_t;
/*! @brief SPI master user configure structure.*/
typedef struct _spi_master_config
{
bool enableLoopback; /*!< Enable loopback for test purpose */
bool enableMaster; /*!< Enable SPI at initialization time */
spi_clock_polarity_t polarity; /*!< Clock polarity */
spi_clock_phase_t phase; /*!< Clock phase */
spi_shift_direction_t direction; /*!< MSB or LSB */
uint32_t baudRate_Bps; /*!< Baud Rate for SPI in Hz */
spi_data_width_t dataWidth; /*!< Width of the data */
spi_ssel_t sselNum; /*!< Slave select number */
spi_spol_t sselPol; /*!< Configure active CS polarity */
uint8_t txWatermark; /*!< txFIFO watermark */
uint8_t rxWatermark; /*!< rxFIFO watermark */
spi_delay_config_t delayConfig; /*!< Delay configuration. */
} spi_master_config_t;
/*! @brief SPI slave user configure structure.*/
typedef struct _spi_slave_config
{
bool enableSlave; /*!< Enable SPI at initialization time */
spi_clock_polarity_t polarity; /*!< Clock polarity */
spi_clock_phase_t phase; /*!< Clock phase */
spi_shift_direction_t direction; /*!< MSB or LSB */
spi_data_width_t dataWidth; /*!< Width of the data */
spi_spol_t sselPol; /*!< Configure active CS polarity */
uint8_t txWatermark; /*!< txFIFO watermark */
uint8_t rxWatermark; /*!< rxFIFO watermark */
} spi_slave_config_t;
/*! @brief SPI transfer status.*/
enum
{
kStatus_SPI_Busy = MAKE_STATUS(kStatusGroup_LPC_SPI, 0), /*!< SPI bus is busy */
kStatus_SPI_Idle = MAKE_STATUS(kStatusGroup_LPC_SPI, 1), /*!< SPI is idle */
kStatus_SPI_Error = MAKE_STATUS(kStatusGroup_LPC_SPI, 2), /*!< SPI error */
kStatus_SPI_BaudrateNotSupport =
MAKE_STATUS(kStatusGroup_LPC_SPI, 3), /*!< Baudrate is not support in current clock source */
kStatus_SPI_Timeout = MAKE_STATUS(kStatusGroup_LPC_SPI, 4) /*!< SPI timeout polling status flags. */
};
/*! @brief SPI interrupt sources.*/
enum _spi_interrupt_enable
{
kSPI_RxLvlIrq = SPI_FIFOINTENSET_RXLVL_MASK, /*!< Rx level interrupt */
kSPI_TxLvlIrq = SPI_FIFOINTENSET_TXLVL_MASK, /*!< Tx level interrupt */
};
/*! @brief SPI status flags.*/
enum _spi_statusflags
{
kSPI_TxEmptyFlag = SPI_FIFOSTAT_TXEMPTY_MASK, /*!< txFifo is empty */
kSPI_TxNotFullFlag = SPI_FIFOSTAT_TXNOTFULL_MASK, /*!< txFifo is not full */
kSPI_RxNotEmptyFlag = SPI_FIFOSTAT_RXNOTEMPTY_MASK, /*!< rxFIFO is not empty */
kSPI_RxFullFlag = SPI_FIFOSTAT_RXFULL_MASK, /*!< rxFIFO is full */
};
/*! @brief SPI transfer structure */
typedef struct _spi_transfer
{
uint8_t *txData; /*!< Send buffer */
uint8_t *rxData; /*!< Receive buffer */
uint32_t configFlags; /*!< Additional option to control transfer, @ref spi_xfer_option_t. */
size_t dataSize; /*!< Transfer bytes */
} spi_transfer_t;
/*! @brief SPI half-duplex(master only) transfer structure */
typedef struct _spi_half_duplex_transfer
{
uint8_t *txData; /*!< Send buffer */
uint8_t *rxData; /*!< Receive buffer */
size_t txDataSize; /*!< Transfer bytes for transmit */
size_t rxDataSize; /*!< Transfer bytes */
uint32_t configFlags; /*!< Transfer configuration flags, @ref spi_xfer_option_t. */
bool isPcsAssertInTransfer; /*!< If PCS pin keep assert between transmit and receive. true for assert and false for
deassert. */
bool isTransmitFirst; /*!< True for transmit first and false for receive first. */
} spi_half_duplex_transfer_t;
/*! @brief Internal configuration structure used in 'spi' and 'spi_dma' driver */
typedef struct _spi_config
{
spi_data_width_t dataWidth;
spi_ssel_t sselNum;
} spi_config_t;
/*! @brief Master handle type */
typedef struct _spi_master_handle spi_master_handle_t;
/*! @brief Slave handle type */
typedef spi_master_handle_t spi_slave_handle_t;
/*! @brief SPI master callback for finished transmit */
typedef void (*spi_master_callback_t)(SPI_Type *base, spi_master_handle_t *handle, status_t status, void *userData);
/*! @brief SPI slave callback for finished transmit */
typedef void (*spi_slave_callback_t)(SPI_Type *base, spi_slave_handle_t *handle, status_t status, void *userData);
/*! @brief SPI transfer handle structure */
struct _spi_master_handle
{
uint8_t *volatile txData; /*!< Transfer buffer */
uint8_t *volatile rxData; /*!< Receive buffer */
volatile size_t txRemainingBytes; /*!< Number of data to be transmitted [in bytes] */
volatile size_t rxRemainingBytes; /*!< Number of data to be received [in bytes] */
volatile int8_t toReceiveCount; /*!< The number of data expected to receive in data width. Since the received count
and sent count should be the same to complete the transfer, if the sent count is
x and the received count is y, toReceiveCount is x-y. */
size_t totalByteCount; /*!< A number of transfer bytes */
volatile uint32_t state; /*!< SPI internal state */
spi_master_callback_t callback; /*!< SPI callback */
void *userData; /*!< Callback parameter */
uint8_t dataWidth; /*!< Width of the data [Valid values: 1 to 16] */
uint8_t sselNum; /*!< Slave select number to be asserted when transferring data [Valid values: 0 to 3] */
uint32_t configFlags; /*!< Additional option to control transfer */
uint8_t txWatermark; /*!< txFIFO watermark */
uint8_t rxWatermark; /*!< rxFIFO watermark */
};
/*! @brief Typedef for master interrupt handler. */
typedef void (*flexcomm_spi_master_irq_handler_t)(SPI_Type *base, spi_master_handle_t *handle);
/*! @brief Typedef for slave interrupt handler. */
typedef void (*flexcomm_spi_slave_irq_handler_t)(SPI_Type *base, spi_slave_handle_t *handle);
/*! @} */
/*******************************************************************************
* API
******************************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif
/*! @brief Returns instance number for SPI peripheral base address. */
uint32_t SPI_GetInstance(SPI_Type *base);
/*!
* @name Initialization and deinitialization
* @{
*/
/*!
* @brief Sets the SPI master configuration structure to default values.
*
* The purpose of this API is to get the configuration structure initialized for use in SPI_MasterInit().
* User may use the initialized structure unchanged in SPI_MasterInit(), or modify
* some fields of the structure before calling SPI_MasterInit(). After calling this API,
* the master is ready to transfer.
* Example:
@code
spi_master_config_t config;
SPI_MasterGetDefaultConfig(&config);
@endcode
*
* @param config pointer to master config structure
*/
void SPI_MasterGetDefaultConfig(spi_master_config_t *config);
/*!
* @brief Initializes the SPI with master configuration.
*
* The configuration structure can be filled by user from scratch, or be set with default
* values by SPI_MasterGetDefaultConfig(). After calling this API, the slave is ready to transfer.
* Example
@code
spi_master_config_t config = {
.baudRate_Bps = 400000,
...
};
SPI_MasterInit(SPI0, &config);
@endcode
*
* @param base SPI base pointer
* @param config pointer to master configuration structure
* @param srcClock_Hz Source clock frequency.
*/
status_t SPI_MasterInit(SPI_Type *base, const spi_master_config_t *config, uint32_t srcClock_Hz);
/*!
* @brief Sets the SPI slave configuration structure to default values.
*
* The purpose of this API is to get the configuration structure initialized for use in SPI_SlaveInit().
* Modify some fields of the structure before calling SPI_SlaveInit().
* Example:
@code
spi_slave_config_t config;
SPI_SlaveGetDefaultConfig(&config);
@endcode
*
* @param config pointer to slave configuration structure
*/
void SPI_SlaveGetDefaultConfig(spi_slave_config_t *config);
/*!
* @brief Initializes the SPI with slave configuration.
*
* The configuration structure can be filled by user from scratch or be set with
* default values by SPI_SlaveGetDefaultConfig().
* After calling this API, the slave is ready to transfer.
* Example
@code
spi_slave_config_t config = {
.polarity = flexSPIClockPolarity_ActiveHigh;
.phase = flexSPIClockPhase_FirstEdge;
.direction = flexSPIMsbFirst;
...
};
SPI_SlaveInit(SPI0, &config);
@endcode
*
* @param base SPI base pointer
* @param config pointer to slave configuration structure
*/
status_t SPI_SlaveInit(SPI_Type *base, const spi_slave_config_t *config);
/*!
* @brief De-initializes the SPI.
*
* Calling this API resets the SPI module, gates the SPI clock.
* The SPI module can't work unless calling the SPI_MasterInit/SPI_SlaveInit to initialize module.
*
* @param base SPI base pointer
*/
void SPI_Deinit(SPI_Type *base);
/*!
* @brief Enable or disable the SPI Master or Slave
* @param base SPI base pointer
* @param enable or disable ( true = enable, false = disable)
*/
static inline void SPI_Enable(SPI_Type *base, bool enable)
{
if (enable)
{
base->CFG |= SPI_CFG_ENABLE_MASK;
}
else
{
base->CFG &= ~SPI_CFG_ENABLE_MASK;
}
}
/*! @} */
/*!
* @name Status
* @{
*/
/*!
* @brief Gets the status flag.
*
* @param base SPI base pointer
* @return SPI Status, use status flag to AND @ref _spi_statusflags could get the related status.
*/
static inline uint32_t SPI_GetStatusFlags(SPI_Type *base)
{
assert(NULL != base);
return base->FIFOSTAT;
}
/*! @} */
/*!
* @name Interrupts
* @{
*/
/*!
* @brief Enables the interrupt for the SPI.
*
* @param base SPI base pointer
* @param irqs SPI interrupt source. The parameter can be any combination of the following values:
* @arg kSPI_RxLvlIrq
* @arg kSPI_TxLvlIrq
*/
static inline void SPI_EnableInterrupts(SPI_Type *base, uint32_t irqs)
{
assert(NULL != base);
base->FIFOINTENSET = irqs;
}
/*!
* @brief Disables the interrupt for the SPI.
*
* @param base SPI base pointer
* @param irqs SPI interrupt source. The parameter can be any combination of the following values:
* @arg kSPI_RxLvlIrq
* @arg kSPI_TxLvlIrq
*/
static inline void SPI_DisableInterrupts(SPI_Type *base, uint32_t irqs)
{
assert(NULL != base);
base->FIFOINTENCLR = irqs;
}
/*! @} */
/*!
* @name DMA Control
* @{
*/
/*!
* @brief Enables the DMA request from SPI txFIFO.
*
* @param base SPI base pointer
* @param enable True means enable DMA, false means disable DMA
*/
void SPI_EnableTxDMA(SPI_Type *base, bool enable);
/*!
* @brief Enables the DMA request from SPI rxFIFO.
*
* @param base SPI base pointer
* @param enable True means enable DMA, false means disable DMA
*/
void SPI_EnableRxDMA(SPI_Type *base, bool enable);
/*! @} */
/*!
* @name Bus Operations
* @{
*/
/*!
* @brief Returns the configurations.
*
* @param base SPI peripheral address.
* @return return configurations which contain datawidth and SSEL numbers.
* return data type is a pointer of spi_config_t.
*/
void *SPI_GetConfig(SPI_Type *base);
/*!
* @brief Sets the baud rate for SPI transfer. This is only used in master.
*
* @param base SPI base pointer
* @param baudrate_Bps baud rate needed in Hz.
* @param srcClock_Hz SPI source clock frequency in Hz.
*/
status_t SPI_MasterSetBaud(SPI_Type *base, uint32_t baudrate_Bps, uint32_t srcClock_Hz);
/*!
* @brief Writes a data into the SPI data register.
*
* @param base SPI base pointer
* @param data needs to be write.
* @param configFlags transfer configuration options @ref spi_xfer_option_t
*/
void SPI_WriteData(SPI_Type *base, uint16_t data, uint32_t configFlags);
/*!
* @brief Gets a data from the SPI data register.
*
* @param base SPI base pointer
* @return Data in the register.
*/
static inline uint32_t SPI_ReadData(SPI_Type *base)
{
assert(NULL != base);
return base->FIFORD;
}
/*!
* @brief Set delay time for transfer.
* the delay uint is SPI clock time, maximum value is 0xF.
* @param base SPI base pointer
* @param config configuration for delay option @ref spi_delay_config_t.
*/
static inline void SPI_SetTransferDelay(SPI_Type *base, const spi_delay_config_t *config)
{
assert(NULL != base);
assert(NULL != config);
base->DLY = (SPI_DLY_PRE_DELAY(config->preDelay) | SPI_DLY_POST_DELAY(config->postDelay) |
SPI_DLY_FRAME_DELAY(config->frameDelay) | SPI_DLY_TRANSFER_DELAY(config->transferDelay));
}
/*!
* @brief Set up the dummy data.
*
* @param base SPI peripheral address.
* @param dummyData Data to be transferred when tx buffer is NULL.
*/
void SPI_SetDummyData(SPI_Type *base, uint8_t dummyData);
/*! @} */
/*!
* @name Transactional
* @{
*/
/*!
* @brief Initializes the SPI master handle.
*
* This function initializes the SPI master handle which can be used for other SPI master transactional APIs. Usually,
* for a specified SPI instance, call this API once to get the initialized handle.
*
* @param base SPI peripheral base address.
* @param handle SPI handle pointer.
* @param callback Callback function.
* @param userData User data.
*/
status_t SPI_MasterTransferCreateHandle(SPI_Type *base,
spi_master_handle_t *handle,
spi_master_callback_t callback,
void *userData);
/*!
* @brief Transfers a block of data using a polling method.
*
* @param base SPI base pointer
* @param xfer pointer to spi_xfer_config_t structure
* @retval kStatus_Success Successfully start a transfer.
* @retval kStatus_InvalidArgument Input argument is invalid.
* @retval kStatus_SPI_Timeout The transfer timed out and was aborted.
*/
status_t SPI_MasterTransferBlocking(SPI_Type *base, spi_transfer_t *xfer);
/*!
* @brief Performs a non-blocking SPI interrupt transfer.
*
* @param base SPI peripheral base address.
* @param handle pointer to spi_master_handle_t structure which stores the transfer state
* @param xfer pointer to spi_xfer_config_t structure
* @retval kStatus_Success Successfully start a transfer.
* @retval kStatus_InvalidArgument Input argument is invalid.
* @retval kStatus_SPI_Busy SPI is not idle, is running another transfer.
*/
status_t SPI_MasterTransferNonBlocking(SPI_Type *base, spi_master_handle_t *handle, spi_transfer_t *xfer);
/*!
* @brief Transfers a block of data using a polling method.
*
* This function will do a half-duplex transfer for SPI master, This is a blocking function,
* which does not retuen until all transfer have been completed. And data transfer mechanism is half-duplex,
* users can set transmit first or receive first.
*
* @param base SPI base pointer
* @param xfer pointer to spi_half_duplex_transfer_t structure
* @return status of status_t.
*/
status_t SPI_MasterHalfDuplexTransferBlocking(SPI_Type *base, spi_half_duplex_transfer_t *xfer);
/*!
* @brief Performs a non-blocking SPI interrupt transfer.
*
* This function using polling way to do the first half transimission and using interrupts to
* do the second half transimission, the transfer mechanism is half-duplex.
* When do the second half transimission, code will return right away. When all data is transferred,
* the callback function is called.
*
* @param base SPI peripheral base address.
* @param handle pointer to spi_master_handle_t structure which stores the transfer state
* @param xfer pointer to spi_half_duplex_transfer_t structure
* @return status of status_t.
*/
status_t SPI_MasterHalfDuplexTransferNonBlocking(SPI_Type *base,
spi_master_handle_t *handle,
spi_half_duplex_transfer_t *xfer);
/*!
* @brief Gets the master transfer count.
*
* This function gets the master transfer count.
*
* @param base SPI peripheral base address.
* @param handle Pointer to the spi_master_handle_t structure which stores the transfer state.
* @param count The number of bytes transferred by using the non-blocking transaction.
* @return status of status_t.
*/
status_t SPI_MasterTransferGetCount(SPI_Type *base, spi_master_handle_t *handle, size_t *count);
/*!
* @brief SPI master aborts a transfer using an interrupt.
*
* This function aborts a transfer using an interrupt.
*
* @param base SPI peripheral base address.
* @param handle Pointer to the spi_master_handle_t structure which stores the transfer state.
*/
void SPI_MasterTransferAbort(SPI_Type *base, spi_master_handle_t *handle);
/*!
* @brief Interrupts the handler for the SPI.
*
* @param base SPI peripheral base address.
* @param handle pointer to spi_master_handle_t structure which stores the transfer state.
*/
void SPI_MasterTransferHandleIRQ(SPI_Type *base, spi_master_handle_t *handle);
/*!
* @brief Initializes the SPI slave handle.
*
* This function initializes the SPI slave handle which can be used for other SPI slave transactional APIs. Usually,
* for a specified SPI instance, call this API once to get the initialized handle.
*
* @param base SPI peripheral base address.
* @param handle SPI handle pointer.
* @param callback Callback function.
* @param userData User data.
*/
static inline status_t SPI_SlaveTransferCreateHandle(SPI_Type *base,
spi_slave_handle_t *handle,
spi_slave_callback_t callback,
void *userData)
{
return SPI_MasterTransferCreateHandle(base, handle, callback, userData);
}
/*!
* @brief Performs a non-blocking SPI slave interrupt transfer.
*
* @note The API returns immediately after the transfer initialization is finished.
*
* @param base SPI peripheral base address.
* @param handle pointer to spi_master_handle_t structure which stores the transfer state
* @param xfer pointer to spi_xfer_config_t structure
* @retval kStatus_Success Successfully start a transfer.
* @retval kStatus_InvalidArgument Input argument is invalid.
* @retval kStatus_SPI_Busy SPI is not idle, is running another transfer.
*/
static inline status_t SPI_SlaveTransferNonBlocking(SPI_Type *base, spi_slave_handle_t *handle, spi_transfer_t *xfer)
{
return SPI_MasterTransferNonBlocking(base, handle, xfer);
}
/*!
* @brief Gets the slave transfer count.
*
* This function gets the slave transfer count.
*
* @param base SPI peripheral base address.
* @param handle Pointer to the spi_master_handle_t structure which stores the transfer state.
* @param count The number of bytes transferred by using the non-blocking transaction.
* @return status of status_t.
*/
static inline status_t SPI_SlaveTransferGetCount(SPI_Type *base, spi_slave_handle_t *handle, size_t *count)
{
return SPI_MasterTransferGetCount(base, (spi_master_handle_t *)handle, count);
}
/*!
* @brief SPI slave aborts a transfer using an interrupt.
*
* This function aborts a transfer using an interrupt.
*
* @param base SPI peripheral base address.
* @param handle Pointer to the spi_slave_handle_t structure which stores the transfer state.
*/
static inline void SPI_SlaveTransferAbort(SPI_Type *base, spi_slave_handle_t *handle)
{
SPI_MasterTransferAbort(base, (spi_master_handle_t *)handle);
}
/*!
* @brief Interrupts a handler for the SPI slave.
*
* @param base SPI peripheral base address.
* @param handle pointer to spi_slave_handle_t structure which stores the transfer state
*/
static inline void SPI_SlaveTransferHandleIRQ(SPI_Type *base, spi_slave_handle_t *handle)
{
SPI_MasterTransferHandleIRQ(base, handle);
}
/*! @} */
#if defined(__cplusplus)
}
#endif
/*! @} */
#endif /* _FSL_SPI_H_*/

1160
drivers/fsl_usart.c Normal file

File diff suppressed because it is too large Load Diff

811
drivers/fsl_usart.h Normal file
View File

@@ -0,0 +1,811 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* Copyright 2016-2020 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _FSL_USART_H_
#define _FSL_USART_H_
#include "fsl_common.h"
/*!
* @addtogroup usart_driver
* @{
*/
/*******************************************************************************
* Definitions
******************************************************************************/
/*! @name Driver version */
/*@{*/
/*! @brief USART driver version. */
#define FSL_USART_DRIVER_VERSION (MAKE_VERSION(2, 4, 0))
/*@}*/
#define USART_FIFOTRIG_TXLVL_GET(base) (((base)->FIFOTRIG & USART_FIFOTRIG_TXLVL_MASK) >> USART_FIFOTRIG_TXLVL_SHIFT)
#define USART_FIFOTRIG_RXLVL_GET(base) (((base)->FIFOTRIG & USART_FIFOTRIG_RXLVL_MASK) >> USART_FIFOTRIG_RXLVL_SHIFT)
/*! @brief Retry times for waiting flag. */
#ifndef UART_RETRY_TIMES
#define UART_RETRY_TIMES 0U /* Defining to zero means to keep waiting for the flag until it is assert/deassert. */
#endif
/*! @brief Error codes for the USART driver. */
enum
{
kStatus_USART_TxBusy = MAKE_STATUS(kStatusGroup_LPC_USART, 0), /*!< Transmitter is busy. */
kStatus_USART_RxBusy = MAKE_STATUS(kStatusGroup_LPC_USART, 1), /*!< Receiver is busy. */
kStatus_USART_TxIdle = MAKE_STATUS(kStatusGroup_LPC_USART, 2), /*!< USART transmitter is idle. */
kStatus_USART_RxIdle = MAKE_STATUS(kStatusGroup_LPC_USART, 3), /*!< USART receiver is idle. */
kStatus_USART_TxError = MAKE_STATUS(kStatusGroup_LPC_USART, 7), /*!< Error happens on txFIFO. */
kStatus_USART_RxError = MAKE_STATUS(kStatusGroup_LPC_USART, 9), /*!< Error happens on rxFIFO. */
kStatus_USART_RxRingBufferOverrun = MAKE_STATUS(kStatusGroup_LPC_USART, 8), /*!< Error happens on rx ring buffer */
kStatus_USART_NoiseError = MAKE_STATUS(kStatusGroup_LPC_USART, 10), /*!< USART noise error. */
kStatus_USART_FramingError = MAKE_STATUS(kStatusGroup_LPC_USART, 11), /*!< USART framing error. */
kStatus_USART_ParityError = MAKE_STATUS(kStatusGroup_LPC_USART, 12), /*!< USART parity error. */
kStatus_USART_BaudrateNotSupport =
MAKE_STATUS(kStatusGroup_LPC_USART, 13), /*!< Baudrate is not support in current clock source */
kStatus_USART_Timeout = MAKE_STATUS(kStatusGroup_LPC_USART, 14), /*!< USART time out. */
};
/*! @brief USART synchronous mode. */
typedef enum _usart_sync_mode
{
kUSART_SyncModeDisabled = 0x0U, /*!< Asynchronous mode. */
kUSART_SyncModeSlave = 0x2U, /*!< Synchronous slave mode. */
kUSART_SyncModeMaster = 0x3U, /*!< Synchronous master mode. */
} usart_sync_mode_t;
/*! @brief USART parity mode. */
typedef enum _usart_parity_mode
{
kUSART_ParityDisabled = 0x0U, /*!< Parity disabled */
kUSART_ParityEven = 0x2U, /*!< Parity enabled, type even, bit setting: PE|PT = 10 */
kUSART_ParityOdd = 0x3U, /*!< Parity enabled, type odd, bit setting: PE|PT = 11 */
} usart_parity_mode_t;
/*! @brief USART stop bit count. */
typedef enum _usart_stop_bit_count
{
kUSART_OneStopBit = 0U, /*!< One stop bit */
kUSART_TwoStopBit = 1U, /*!< Two stop bits */
} usart_stop_bit_count_t;
/*! @brief USART data size. */
typedef enum _usart_data_len
{
kUSART_7BitsPerChar = 0U, /*!< Seven bit mode */
kUSART_8BitsPerChar = 1U, /*!< Eight bit mode */
} usart_data_len_t;
/*! @brief USART clock polarity configuration, used in sync mode.*/
typedef enum _usart_clock_polarity
{
kUSART_RxSampleOnFallingEdge = 0x0U, /*!< Un_RXD is sampled on the falling edge of SCLK. */
kUSART_RxSampleOnRisingEdge = 0x1U, /*!< Un_RXD is sampled on the rising edge of SCLK. */
} usart_clock_polarity_t;
/*! @brief txFIFO watermark values */
typedef enum _usart_txfifo_watermark
{
kUSART_TxFifo0 = 0, /*!< USART tx watermark is empty */
kUSART_TxFifo1 = 1, /*!< USART tx watermark at 1 item */
kUSART_TxFifo2 = 2, /*!< USART tx watermark at 2 items */
kUSART_TxFifo3 = 3, /*!< USART tx watermark at 3 items */
kUSART_TxFifo4 = 4, /*!< USART tx watermark at 4 items */
kUSART_TxFifo5 = 5, /*!< USART tx watermark at 5 items */
kUSART_TxFifo6 = 6, /*!< USART tx watermark at 6 items */
kUSART_TxFifo7 = 7, /*!< USART tx watermark at 7 items */
} usart_txfifo_watermark_t;
/*! @brief rxFIFO watermark values */
typedef enum _usart_rxfifo_watermark
{
kUSART_RxFifo1 = 0, /*!< USART rx watermark at 1 item */
kUSART_RxFifo2 = 1, /*!< USART rx watermark at 2 items */
kUSART_RxFifo3 = 2, /*!< USART rx watermark at 3 items */
kUSART_RxFifo4 = 3, /*!< USART rx watermark at 4 items */
kUSART_RxFifo5 = 4, /*!< USART rx watermark at 5 items */
kUSART_RxFifo6 = 5, /*!< USART rx watermark at 6 items */
kUSART_RxFifo7 = 6, /*!< USART rx watermark at 7 items */
kUSART_RxFifo8 = 7, /*!< USART rx watermark at 8 items */
} usart_rxfifo_watermark_t;
/*!
* @brief USART interrupt configuration structure, default settings all disabled.
*/
enum _usart_interrupt_enable
{
kUSART_TxErrorInterruptEnable = (USART_FIFOINTENSET_TXERR_MASK),
kUSART_RxErrorInterruptEnable = (USART_FIFOINTENSET_RXERR_MASK),
kUSART_TxLevelInterruptEnable = (USART_FIFOINTENSET_TXLVL_MASK),
kUSART_RxLevelInterruptEnable = (USART_FIFOINTENSET_RXLVL_MASK),
};
/*!
* @brief USART status flags.
*
* This provides constants for the USART status flags for use in the USART functions.
*/
enum _usart_flags
{
kUSART_TxError = (USART_FIFOSTAT_TXERR_MASK), /*!< TEERR bit, sets if TX buffer is error */
kUSART_RxError = (USART_FIFOSTAT_RXERR_MASK), /*!< RXERR bit, sets if RX buffer is error */
kUSART_TxFifoEmptyFlag = (USART_FIFOSTAT_TXEMPTY_MASK), /*!< TXEMPTY bit, sets if TX buffer is empty */
kUSART_TxFifoNotFullFlag = (USART_FIFOSTAT_TXNOTFULL_MASK), /*!< TXNOTFULL bit, sets if TX buffer is not full */
kUSART_RxFifoNotEmptyFlag = (USART_FIFOSTAT_RXNOTEMPTY_MASK), /*!< RXNOEMPTY bit, sets if RX buffer is not empty */
kUSART_RxFifoFullFlag = (USART_FIFOSTAT_RXFULL_MASK), /*!< RXFULL bit, sets if RX buffer is full */
};
/*! @brief USART configuration structure. */
typedef struct _usart_config
{
uint32_t baudRate_Bps; /*!< USART baud rate */
usart_parity_mode_t parityMode; /*!< Parity mode, disabled (default), even, odd */
usart_stop_bit_count_t stopBitCount; /*!< Number of stop bits, 1 stop bit (default) or 2 stop bits */
usart_data_len_t bitCountPerChar; /*!< Data length - 7 bit, 8 bit */
bool loopback; /*!< Enable peripheral loopback */
bool enableRx; /*!< Enable RX */
bool enableTx; /*!< Enable TX */
bool enableContinuousSCLK; /*!< USART continuous Clock generation enable in synchronous master mode. */
bool enableMode32k; /*!< USART uses 32 kHz clock from the RTC oscillator as the clock source. */
bool enableHardwareFlowControl; /*!< Enable hardware control RTS/CTS */
usart_txfifo_watermark_t txWatermark; /*!< txFIFO watermark */
usart_rxfifo_watermark_t rxWatermark; /*!< rxFIFO watermark */
usart_sync_mode_t syncMode; /*!< Transfer mode select - asynchronous, synchronous master, synchronous slave. */
usart_clock_polarity_t clockPolarity; /*!< Selects the clock polarity and sampling edge in synchronous mode. */
} usart_config_t;
/*! @brief USART transfer structure. */
typedef struct _usart_transfer
{
uint8_t *data; /*!< The buffer of data to be transfer.*/
size_t dataSize; /*!< The byte count to be transfer. */
} usart_transfer_t;
/* Forward declaration of the handle typedef. */
typedef struct _usart_handle usart_handle_t;
/*! @brief USART transfer callback function. */
typedef void (*usart_transfer_callback_t)(USART_Type *base, usart_handle_t *handle, status_t status, void *userData);
/*! @brief USART handle structure. */
struct _usart_handle
{
uint8_t *volatile txData; /*!< Address of remaining data to send. */
volatile size_t txDataSize; /*!< Size of the remaining data to send. */
size_t txDataSizeAll; /*!< Size of the data to send out. */
uint8_t *volatile rxData; /*!< Address of remaining data to receive. */
volatile size_t rxDataSize; /*!< Size of the remaining data to receive. */
size_t rxDataSizeAll; /*!< Size of the data to receive. */
uint8_t *rxRingBuffer; /*!< Start address of the receiver ring buffer. */
size_t rxRingBufferSize; /*!< Size of the ring buffer. */
volatile uint16_t rxRingBufferHead; /*!< Index for the driver to store received data into ring buffer. */
volatile uint16_t rxRingBufferTail; /*!< Index for the user to get data from the ring buffer. */
usart_transfer_callback_t callback; /*!< Callback function. */
void *userData; /*!< USART callback function parameter.*/
volatile uint8_t txState; /*!< TX transfer state. */
volatile uint8_t rxState; /*!< RX transfer state */
uint8_t txWatermark; /*!< txFIFO watermark */
uint8_t rxWatermark; /*!< rxFIFO watermark */
};
/*! @brief Typedef for usart interrupt handler. */
typedef void (*flexcomm_usart_irq_handler_t)(USART_Type *base, usart_handle_t *handle);
/*******************************************************************************
* API
******************************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif /* _cplusplus */
/*! @brief Returns instance number for USART peripheral base address. */
uint32_t USART_GetInstance(USART_Type *base);
/*!
* @name Initialization and deinitialization
* @{
*/
/*!
* @brief Initializes a USART instance with user configuration structure and peripheral clock.
*
* This function configures the USART module with the user-defined settings. The user can configure the configuration
* structure and also get the default configuration by using the USART_GetDefaultConfig() function.
* Example below shows how to use this API to configure USART.
* @code
* usart_config_t usartConfig;
* usartConfig.baudRate_Bps = 115200U;
* usartConfig.parityMode = kUSART_ParityDisabled;
* usartConfig.stopBitCount = kUSART_OneStopBit;
* USART_Init(USART1, &usartConfig, 20000000U);
* @endcode
*
* @param base USART peripheral base address.
* @param config Pointer to user-defined configuration structure.
* @param srcClock_Hz USART clock source frequency in HZ.
* @retval kStatus_USART_BaudrateNotSupport Baudrate is not support in current clock source.
* @retval kStatus_InvalidArgument USART base address is not valid
* @retval kStatus_Success Status USART initialize succeed
*/
status_t USART_Init(USART_Type *base, const usart_config_t *config, uint32_t srcClock_Hz);
/*!
* @brief Deinitializes a USART instance.
*
* This function waits for TX complete, disables TX and RX, and disables the USART clock.
*
* @param base USART peripheral base address.
*/
void USART_Deinit(USART_Type *base);
/*!
* @brief Gets the default configuration structure.
*
* This function initializes the USART configuration structure to a default value. The default
* values are:
* usartConfig->baudRate_Bps = 115200U;
* usartConfig->parityMode = kUSART_ParityDisabled;
* usartConfig->stopBitCount = kUSART_OneStopBit;
* usartConfig->bitCountPerChar = kUSART_8BitsPerChar;
* usartConfig->loopback = false;
* usartConfig->enableTx = false;
* usartConfig->enableRx = false;
*
* @param config Pointer to configuration structure.
*/
void USART_GetDefaultConfig(usart_config_t *config);
/*!
* @brief Sets the USART instance baud rate.
*
* This function configures the USART module baud rate. This function is used to update
* the USART module baud rate after the USART module is initialized by the USART_Init.
* @code
* USART_SetBaudRate(USART1, 115200U, 20000000U);
* @endcode
*
* @param base USART peripheral base address.
* @param baudrate_Bps USART baudrate to be set.
* @param srcClock_Hz USART clock source frequency in HZ.
* @retval kStatus_USART_BaudrateNotSupport Baudrate is not support in current clock source.
* @retval kStatus_Success Set baudrate succeed.
* @retval kStatus_InvalidArgument One or more arguments are invalid.
*/
status_t USART_SetBaudRate(USART_Type *base, uint32_t baudrate_Bps, uint32_t srcClock_Hz);
/*!
* @brief Enable 32 kHz mode which USART uses clock from the RTC oscillator as the clock source
*
* Please note that in order to use a 32 kHz clock to operate USART properly, the RTC oscillator
* and its 32 kHz output must be manully enabled by user, by calling RTC_Init and setting
* SYSCON_RTCOSCCTRL_EN bit to 1.
* And in 32kHz clocking mode the USART can only work at 9600 baudrate or at the baudrate that
* 9600 can evenly divide, eg: 4800, 3200.
*
* @param base USART peripheral base address.
* @param baudRate_Bps USART baudrate to be set..
* @param enableMode32k true is 32k mode, false is normal mode.
* @param srcClock_Hz USART clock source frequency in HZ.
* @retval kStatus_USART_BaudrateNotSupport Baudrate is not support in current clock source.
* @retval kStatus_Success Set baudrate succeed.
* @retval kStatus_InvalidArgument One or more arguments are invalid.
*/
status_t USART_Enable32kMode(USART_Type *base, uint32_t baudRate_Bps, bool enableMode32k, uint32_t srcClock_Hz);
/*!
* @brief Enable 9-bit data mode for USART.
*
* This function set the 9-bit mode for USART module. The 9th bit is not used for parity thus can be modified by user.
*
* @param base USART peripheral base address.
* @param enable true to enable, false to disable.
*/
void USART_Enable9bitMode(USART_Type *base, bool enable);
/*!
* @brief Set the USART slave address.
*
* This function configures the address for USART module that works as slave in 9-bit data mode. When the address
* detection is enabled, the frame it receices with MSB being 1 is considered as an address frame, otherwise it is
* considered as data frame. Once the address frame matches slave's own addresses, this slave is addressed. This
* address frame and its following data frames are stored in the receive buffer, otherwise the frames will be discarded.
* To un-address a slave, just send an address frame with unmatched address.
*
* @note Any USART instance joined in the multi-slave system can work as slave. The position of the address mark is the
* same as the parity bit when parity is enabled for 8 bit and 9 bit data formats.
*
* @param base USART peripheral base address.
* @param address USART slave address.
*/
static inline void USART_SetMatchAddress(USART_Type *base, uint8_t address)
{
/* Configure match address. */
base->ADDR = (uint32_t)address;
}
/*!
* @brief Enable the USART match address feature.
*
* @param base USART peripheral base address.
* @param match true to enable match address, false to disable.
*/
static inline void USART_EnableMatchAddress(USART_Type *base, bool match)
{
/* Configure match address enable bit. */
if (match)
{
base->CFG |= (uint32_t)USART_CFG_AUTOADDR_MASK;
base->CTL |= (uint32_t)USART_CTL_ADDRDET_MASK;
}
else
{
base->CFG &= ~(uint32_t)USART_CFG_AUTOADDR_MASK;
base->CTL &= ~(uint32_t)USART_CTL_ADDRDET_MASK;
}
}
/* @} */
/*!
* @name Status
* @{
*/
/*!
* @brief Get USART status flags.
*
* This function get all USART status flags, the flags are returned as the logical
* OR value of the enumerators @ref _usart_flags. To check a specific status,
* compare the return value with enumerators in @ref _usart_flags.
* For example, to check whether the TX is empty:
* @code
* if (kUSART_TxFifoNotFullFlag & USART_GetStatusFlags(USART1))
* {
* ...
* }
* @endcode
*
* @param base USART peripheral base address.
* @return USART status flags which are ORed by the enumerators in the _usart_flags.
*/
static inline uint32_t USART_GetStatusFlags(USART_Type *base)
{
return base->FIFOSTAT;
}
/*!
* @brief Clear USART status flags.
*
* This function clear supported USART status flags
* Flags that can be cleared or set are:
* kUSART_TxError
* kUSART_RxError
* For example:
* @code
* USART_ClearStatusFlags(USART1, kUSART_TxError | kUSART_RxError)
* @endcode
*
* @param base USART peripheral base address.
* @param mask status flags to be cleared.
*/
static inline void USART_ClearStatusFlags(USART_Type *base, uint32_t mask)
{
/* Only TXERR, RXERR fields support write. Remaining fields should be set to zero */
base->FIFOSTAT = mask & (USART_FIFOSTAT_TXERR_MASK | USART_FIFOSTAT_RXERR_MASK);
}
/* @} */
/*!
* @name Interrupts
* @{
*/
/*!
* @brief Enables USART interrupts according to the provided mask.
*
* This function enables the USART interrupts according to the provided mask. The mask
* is a logical OR of enumeration members. See @ref _usart_interrupt_enable.
* For example, to enable TX empty interrupt and RX full interrupt:
* @code
* USART_EnableInterrupts(USART1, kUSART_TxLevelInterruptEnable | kUSART_RxLevelInterruptEnable);
* @endcode
*
* @param base USART peripheral base address.
* @param mask The interrupts to enable. Logical OR of @ref _usart_interrupt_enable.
*/
static inline void USART_EnableInterrupts(USART_Type *base, uint32_t mask)
{
base->FIFOINTENSET = mask & 0xFUL;
}
/*!
* @brief Disables USART interrupts according to a provided mask.
*
* This function disables the USART interrupts according to a provided mask. The mask
* is a logical OR of enumeration members. See @ref _usart_interrupt_enable.
* This example shows how to disable the TX empty interrupt and RX full interrupt:
* @code
* USART_DisableInterrupts(USART1, kUSART_TxLevelInterruptEnable | kUSART_RxLevelInterruptEnable);
* @endcode
*
* @param base USART peripheral base address.
* @param mask The interrupts to disable. Logical OR of @ref _usart_interrupt_enable.
*/
static inline void USART_DisableInterrupts(USART_Type *base, uint32_t mask)
{
base->FIFOINTENCLR = mask & 0xFUL;
}
/*!
* @brief Returns enabled USART interrupts.
*
* This function returns the enabled USART interrupts.
*
* @param base USART peripheral base address.
*/
static inline uint32_t USART_GetEnabledInterrupts(USART_Type *base)
{
return base->FIFOINTENSET;
}
/*!
* @brief Enable DMA for Tx
*/
static inline void USART_EnableTxDMA(USART_Type *base, bool enable)
{
if (enable)
{
base->FIFOCFG |= USART_FIFOCFG_DMATX_MASK;
}
else
{
base->FIFOCFG &= ~(USART_FIFOCFG_DMATX_MASK);
}
}
/*!
* @brief Enable DMA for Rx
*/
static inline void USART_EnableRxDMA(USART_Type *base, bool enable)
{
if (enable)
{
base->FIFOCFG |= USART_FIFOCFG_DMARX_MASK;
}
else
{
base->FIFOCFG &= ~(USART_FIFOCFG_DMARX_MASK);
}
}
/*!
* @brief Enable CTS.
* This function will determine whether CTS is used for flow control.
*
* @param base USART peripheral base address.
* @param enable Enable CTS or not, true for enable and false for disable.
*/
static inline void USART_EnableCTS(USART_Type *base, bool enable)
{
if (enable)
{
base->CFG |= USART_CFG_CTSEN_MASK;
}
else
{
base->CFG &= ~USART_CFG_CTSEN_MASK;
}
}
/*!
* @brief Continuous Clock generation.
* By default, SCLK is only output while data is being transmitted in synchronous mode.
* Enable this funciton, SCLK will run continuously in synchronous mode, allowing
* characters to be received on Un_RxD independently from transmission on Un_TXD).
*
* @param base USART peripheral base address.
* @param enable Enable Continuous Clock generation mode or not, true for enable and false for disable.
*/
static inline void USART_EnableContinuousSCLK(USART_Type *base, bool enable)
{
if (enable)
{
base->CTL |= USART_CTL_CC_MASK;
}
else
{
base->CTL &= ~USART_CTL_CC_MASK;
}
}
/*!
* @brief Enable Continuous Clock generation bit auto clear.
* While enable this cuntion, the Continuous Clock bit is automatically cleared when a complete
* character has been received. This bit is cleared at the same time.
*
* @param base USART peripheral base address.
* @param enable Enable auto clear or not, true for enable and false for disable.
*/
static inline void USART_EnableAutoClearSCLK(USART_Type *base, bool enable)
{
if (enable)
{
base->CTL |= USART_CTL_CLRCCONRX_MASK;
}
else
{
base->CTL &= ~USART_CTL_CLRCCONRX_MASK;
}
}
/* @} */
/*!
* @name Bus Operations
* @{
*/
/*!
* @brief Writes to the FIFOWR register.
*
* This function writes data to the txFIFO directly. The upper layer must ensure
* that txFIFO has space for data to write before calling this function.
*
* @param base USART peripheral base address.
* @param data The byte to write.
*/
static inline void USART_WriteByte(USART_Type *base, uint8_t data)
{
base->FIFOWR = data;
}
/*!
* @brief Reads the FIFORD register directly.
*
* This function reads data from the rxFIFO directly. The upper layer must
* ensure that the rxFIFO is not empty before calling this function.
*
* @param base USART peripheral base address.
* @return The byte read from USART data register.
*/
static inline uint8_t USART_ReadByte(USART_Type *base)
{
return (uint8_t)base->FIFORD;
}
/*!
* @brief Transmit an address frame in 9-bit data mode.
*
* @param base USART peripheral base address.
* @param address USART slave address.
*/
void USART_SendAddress(USART_Type *base, uint8_t address);
/*!
* @brief Writes to the TX register using a blocking method.
*
* This function polls the TX register, waits for the TX register to be empty or for the TX FIFO
* to have room and writes data to the TX buffer.
*
* @param base USART peripheral base address.
* @param data Start address of the data to write.
* @param length Size of the data to write.
* @retval kStatus_USART_Timeout Transmission timed out and was aborted.
* @retval kStatus_InvalidArgument Invalid argument.
* @retval kStatus_Success Successfully wrote all data.
*/
status_t USART_WriteBlocking(USART_Type *base, const uint8_t *data, size_t length);
/*!
* @brief Read RX data register using a blocking method.
*
* This function polls the RX register, waits for the RX register to be full or for RX FIFO to
* have data and read data from the TX register.
*
* @param base USART peripheral base address.
* @param data Start address of the buffer to store the received data.
* @param length Size of the buffer.
* @retval kStatus_USART_FramingError Receiver overrun happened while receiving data.
* @retval kStatus_USART_ParityError Noise error happened while receiving data.
* @retval kStatus_USART_NoiseError Framing error happened while receiving data.
* @retval kStatus_USART_RxError Overflow or underflow rxFIFO happened.
* @retval kStatus_USART_Timeout Transmission timed out and was aborted.
* @retval kStatus_Success Successfully received all data.
*/
status_t USART_ReadBlocking(USART_Type *base, uint8_t *data, size_t length);
/* @} */
/*!
* @name Transactional
* @{
*/
/*!
* @brief Initializes the USART handle.
*
* This function initializes the USART handle which can be used for other USART
* transactional APIs. Usually, for a specified USART instance,
* call this API once to get the initialized handle.
*
* @param base USART peripheral base address.
* @param handle USART handle pointer.
* @param callback The callback function.
* @param userData The parameter of the callback function.
*/
status_t USART_TransferCreateHandle(USART_Type *base,
usart_handle_t *handle,
usart_transfer_callback_t callback,
void *userData);
/*!
* @brief Transmits a buffer of data using the interrupt method.
*
* This function sends data using an interrupt method. This is a non-blocking function, which
* returns directly without waiting for all data to be written to the TX register. When
* all data is written to the TX register in the IRQ handler, the USART driver calls the callback
* function and passes the @ref kStatus_USART_TxIdle as status parameter.
*
* @note The kStatus_USART_TxIdle is passed to the upper layer when all data is written
* to the TX register. However it does not ensure that all data are sent out. Before disabling the TX,
* check the kUSART_TransmissionCompleteFlag to ensure that the TX is finished.
*
* @param base USART peripheral base address.
* @param handle USART handle pointer.
* @param xfer USART transfer structure. See #usart_transfer_t.
* @retval kStatus_Success Successfully start the data transmission.
* @retval kStatus_USART_TxBusy Previous transmission still not finished, data not all written to TX register yet.
* @retval kStatus_InvalidArgument Invalid argument.
*/
status_t USART_TransferSendNonBlocking(USART_Type *base, usart_handle_t *handle, usart_transfer_t *xfer);
/*!
* @brief Sets up the RX ring buffer.
*
* This function sets up the RX ring buffer to a specific USART handle.
*
* When the RX ring buffer is used, data received are stored into the ring buffer even when the
* user doesn't call the USART_TransferReceiveNonBlocking() API. If there is already data received
* in the ring buffer, the user can get the received data from the ring buffer directly.
*
* @note When using the RX ring buffer, one byte is reserved for internal use. In other
* words, if @p ringBufferSize is 32, then only 31 bytes are used for saving data.
*
* @param base USART peripheral base address.
* @param handle USART handle pointer.
* @param ringBuffer Start address of the ring buffer for background receiving. Pass NULL to disable the ring buffer.
* @param ringBufferSize size of the ring buffer.
*/
void USART_TransferStartRingBuffer(USART_Type *base,
usart_handle_t *handle,
uint8_t *ringBuffer,
size_t ringBufferSize);
/*!
* @brief Aborts the background transfer and uninstalls the ring buffer.
*
* This function aborts the background transfer and uninstalls the ring buffer.
*
* @param base USART peripheral base address.
* @param handle USART handle pointer.
*/
void USART_TransferStopRingBuffer(USART_Type *base, usart_handle_t *handle);
/*!
* @brief Get the length of received data in RX ring buffer.
*
* @param handle USART handle pointer.
* @return Length of received data in RX ring buffer.
*/
size_t USART_TransferGetRxRingBufferLength(usart_handle_t *handle);
/*!
* @brief Aborts the interrupt-driven data transmit.
*
* This function aborts the interrupt driven data sending. The user can get the remainBtyes to find out
* how many bytes are still not sent out.
*
* @param base USART peripheral base address.
* @param handle USART handle pointer.
*/
void USART_TransferAbortSend(USART_Type *base, usart_handle_t *handle);
/*!
* @brief Get the number of bytes that have been sent out to bus.
*
* This function gets the number of bytes that have been sent out to bus by interrupt method.
*
* @param base USART peripheral base address.
* @param handle USART handle pointer.
* @param count Send bytes count.
* @retval kStatus_NoTransferInProgress No send in progress.
* @retval kStatus_InvalidArgument Parameter is invalid.
* @retval kStatus_Success Get successfully through the parameter \p count;
*/
status_t USART_TransferGetSendCount(USART_Type *base, usart_handle_t *handle, uint32_t *count);
/*!
* @brief Receives a buffer of data using an interrupt method.
*
* This function receives data using an interrupt method. This is a non-blocking function, which
* returns without waiting for all data to be received.
* If the RX ring buffer is used and not empty, the data in the ring buffer is copied and
* the parameter @p receivedBytes shows how many bytes are copied from the ring buffer.
* After copying, if the data in the ring buffer is not enough to read, the receive
* request is saved by the USART driver. When the new data arrives, the receive request
* is serviced first. When all data is received, the USART driver notifies the upper layer
* through a callback function and passes the status parameter @ref kStatus_USART_RxIdle.
* For example, the upper layer needs 10 bytes but there are only 5 bytes in the ring buffer.
* The 5 bytes are copied to the xfer->data and this function returns with the
* parameter @p receivedBytes set to 5. For the left 5 bytes, newly arrived data is
* saved from the xfer->data[5]. When 5 bytes are received, the USART driver notifies the upper layer.
* If the RX ring buffer is not enabled, this function enables the RX and RX interrupt
* to receive data to the xfer->data. When all data is received, the upper layer is notified.
*
* @param base USART peripheral base address.
* @param handle USART handle pointer.
* @param xfer USART transfer structure, see #usart_transfer_t.
* @param receivedBytes Bytes received from the ring buffer directly.
* @retval kStatus_Success Successfully queue the transfer into transmit queue.
* @retval kStatus_USART_RxBusy Previous receive request is not finished.
* @retval kStatus_InvalidArgument Invalid argument.
*/
status_t USART_TransferReceiveNonBlocking(USART_Type *base,
usart_handle_t *handle,
usart_transfer_t *xfer,
size_t *receivedBytes);
/*!
* @brief Aborts the interrupt-driven data receiving.
*
* This function aborts the interrupt-driven data receiving. The user can get the remainBytes to find out
* how many bytes not received yet.
*
* @param base USART peripheral base address.
* @param handle USART handle pointer.
*/
void USART_TransferAbortReceive(USART_Type *base, usart_handle_t *handle);
/*!
* @brief Get the number of bytes that have been received.
*
* This function gets the number of bytes that have been received.
*
* @param base USART peripheral base address.
* @param handle USART handle pointer.
* @param count Receive bytes count.
* @retval kStatus_NoTransferInProgress No receive in progress.
* @retval kStatus_InvalidArgument Parameter is invalid.
* @retval kStatus_Success Get successfully through the parameter \p count;
*/
status_t USART_TransferGetReceiveCount(USART_Type *base, usart_handle_t *handle, uint32_t *count);
/*!
* @brief USART IRQ handle function.
*
* This function handles the USART transmit and receive IRQ request.
*
* @param base USART peripheral base address.
* @param handle USART handle pointer.
*/
void USART_TransferHandleIRQ(USART_Type *base, usart_handle_t *handle);
/* @} */
#if defined(__cplusplus)
}
#endif
/*! @}*/
#endif /* _FSL_USART_H_ */