initial check in based on SVN revision 575
This commit is contained in:
619
drivers/fsl_adc.c
Normal file
619
drivers/fsl_adc.c
Normal 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
775
drivers/fsl_adc.h
Normal 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
1777
drivers/fsl_clock.c
Normal file
File diff suppressed because it is too large
Load Diff
876
drivers/fsl_clock.h
Normal file
876
drivers/fsl_clock.h
Normal 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
311
drivers/fsl_common.c
Normal 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
954
drivers/fsl_common.h
Normal 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
577
drivers/fsl_ctimer.c
Normal 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
533
drivers/fsl_ctimer.h
Normal 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
356
drivers/fsl_flexcomm.c
Normal 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
64
drivers/fsl_flexcomm.h
Normal 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
317
drivers/fsl_gpio.c
Normal 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
364
drivers/fsl_gpio.h
Normal 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
584
drivers/fsl_iap.c
Normal 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
435
drivers/fsl_iap.h
Normal 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
135
drivers/fsl_inputmux.c
Normal 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
97
drivers/fsl_inputmux.h
Normal 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_ */
|
||||
157
drivers/fsl_inputmux_connections.h
Normal file
157
drivers/fsl_inputmux_connections.h
Normal 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
288
drivers/fsl_iocon.h
Normal 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
185
drivers/fsl_reset.c
Normal 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
205
drivers/fsl_reset.h
Normal 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
803
drivers/fsl_sctimer.c
Normal 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
1258
drivers/fsl_sctimer.h
Normal file
File diff suppressed because it is too large
Load Diff
1072
drivers/fsl_spi.c
Normal file
1072
drivers/fsl_spi.c
Normal file
File diff suppressed because it is too large
Load Diff
746
drivers/fsl_spi.h
Normal file
746
drivers/fsl_spi.h
Normal 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
1160
drivers/fsl_usart.c
Normal file
File diff suppressed because it is too large
Load Diff
811
drivers/fsl_usart.h
Normal file
811
drivers/fsl_usart.h
Normal 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_ */
|
||||
Reference in New Issue
Block a user