Add mbed support for LPCXpresso54114 board

Signed-off-by: Mahadevan Mahesh <Mahesh.Mahadevan@nxp.com>
pull/4824/head
Mahadevan Mahesh 2016-12-15 15:02:00 -06:00 committed by Martin Kojtal
parent 605562f382
commit 7435b34bca
104 changed files with 34782 additions and 6 deletions

View File

@ -0,0 +1,107 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_PERIPHERALNAMES_H
#define MBED_PERIPHERALNAMES_H
#include "cmsis.h"
#include "PortNames.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
OSC32KCLK = 0,
} RTCName;
typedef enum {
UART_0 = Flexcomm0,
UART_1 = Flexcomm2
} UARTName;
#define STDIO_UART_TX USBTX
#define STDIO_UART_RX USBRX
#define STDIO_UART UART_0
typedef enum {
I2C_0 = Flexcomm1,
I2C_1 = Flexcomm4
} I2CName;
#define TPM_SHIFT 8
typedef enum {
PWM_1 = (0 << TPM_SHIFT) | (0), // FTM0 CH0
PWM_2 = (0 << TPM_SHIFT) | (1), // FTM0 CH1
PWM_3 = (0 << TPM_SHIFT) | (2), // FTM0 CH2
PWM_4 = (0 << TPM_SHIFT) | (3), // FTM0 CH3
PWM_5 = (0 << TPM_SHIFT) | (4), // FTM0 CH4
PWM_6 = (0 << TPM_SHIFT) | (5), // FTM0 CH5
PWM_7 = (0 << TPM_SHIFT) | (6), // FTM0 CH6
PWM_8 = (0 << TPM_SHIFT) | (7), // FTM0 CH7
PWM_9 = (1 << TPM_SHIFT) | (0), // FTM1 CH0
PWM_10 = (1 << TPM_SHIFT) | (1), // FTM1 CH1
PWM_11 = (1 << TPM_SHIFT) | (2), // FTM1 CH2
PWM_12 = (1 << TPM_SHIFT) | (3), // FTM1 CH3
PWM_13 = (1 << TPM_SHIFT) | (4), // FTM1 CH4
PWM_14 = (1 << TPM_SHIFT) | (5), // FTM1 CH5
PWM_15 = (1 << TPM_SHIFT) | (6), // FTM1 CH6
PWM_16 = (1 << TPM_SHIFT) | (7), // FTM1 CH7
PWM_17 = (2 << TPM_SHIFT) | (0), // FTM2 CH0
PWM_18 = (2 << TPM_SHIFT) | (1), // FTM2 CH1
PWM_19 = (2 << TPM_SHIFT) | (2), // FTM2 CH2
PWM_20 = (2 << TPM_SHIFT) | (3), // FTM2 CH3
PWM_21 = (2 << TPM_SHIFT) | (4), // FTM2 CH4
PWM_22 = (2 << TPM_SHIFT) | (5), // FTM2 CH5
PWM_23 = (2 << TPM_SHIFT) | (6), // FTM2 CH6
PWM_24 = (2 << TPM_SHIFT) | (7), // FTM2 CH7
PWM_25 = (3 << TPM_SHIFT) | (0), // FTM3 CH0
PWM_26 = (3 << TPM_SHIFT) | (1), // FTM3 CH1
PWM_27 = (3 << TPM_SHIFT) | (2), // FTM3 CH2
PWM_28 = (3 << TPM_SHIFT) | (3), // FTM3 CH3
PWM_29 = (3 << TPM_SHIFT) | (4), // FTM3 CH4
PWM_30 = (3 << TPM_SHIFT) | (5), // FTM3 CH5
PWM_31 = (3 << TPM_SHIFT) | (6), // FTM3 CH6
PWM_32 = (3 << TPM_SHIFT) | (7), // FTM3 CH7
} PWMName;
#define ADC_INSTANCE_SHIFT 8
#define ADC_B_CHANNEL_SHIFT 5
typedef enum {
ADC0_SE0 = 0,
ADC0_SE1 = 1,
ADC0_SE2 = 2,
ADC0_SE3 = 3,
ADC0_SE4 = 4,
ADC0_SE5 = 5,
ADC0_SE6 = 6,
ADC0_SE7 = 7,
ADC0_SE8 = 8,
ADC0_SE9 = 9,
ADC0_SE10 = 10,
ADC0_SE11 = 11,
} ADCName;
typedef enum {
SPI_0 = Flexcomm3,
SPI_1 = Flexcomm5
} SPIName;
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,101 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "PeripheralPins.h"
/************RTC***************/
const PinMap PinMap_RTC[] = {
{NC, OSC32KCLK, 0},
};
/************ADC***************/
const PinMap PinMap_ADC[] = {
{P0_30, ADC0_SE1, 0},
{P1_4, ADC0_SE7, 0},
{P1_5, ADC0_SE8, 0},
{P1_8, ADC0_SE11, 0},
{NC , NC , 0}
};
/************DAC***************/
const PinMap PinMap_DAC[] = {
{NC , NC , 0}
};
/************I2C***************/
const PinMap PinMap_I2C_SDA[] = {
{P0_24, I2C_0, 1},
{P0_26, I2C_1, 1},
{NC , NC , 0}
};
const PinMap PinMap_I2C_SCL[] = {
{P0_23, I2C_0, 1},
{P0_25, I2C_1, 1},
{NC , NC , 0}
};
/************UART***************/
const PinMap PinMap_UART_TX[] = {
{P0_1, UART_0, 1},
{P0_9, UART_1, 1},
{NC , NC , 0}
};
const PinMap PinMap_UART_RX[] = {
{P0_0, UART_0, 1},
{P0_8, UART_1, 1},
{NC , NC , 0}
};
const PinMap PinMap_UART_CTS[] = {
{NC , NC , 0}
};
const PinMap PinMap_UART_RTS[] = {
{NC , NC , 0}
};
/************SPI***************/
const PinMap PinMap_SPI_SCLK[] = {
{P0_11, SPI_0, 1},
{P0_19, SPI_1, 1},
{NC , NC , 0}
};
const PinMap PinMap_SPI_MOSI[] = {
{P0_12, SPI_0, 1},
{P0_20, SPI_1, 1},
{NC , NC , 0}
};
const PinMap PinMap_SPI_MISO[] = {
{P0_13, SPI_0, 1},
{P0_18, SPI_1, 1},
{NC , NC , 0}
};
const PinMap PinMap_SPI_SSEL[] = {
{P0_14, SPI_0, 1},
{P1_1, SPI_1, 4},
{P1_2, SPI_1, 4},
{NC , NC , 0}
};
/************PWM***************/
const PinMap PinMap_PWM[] = {
{NC , NC , 0}
};

View File

@ -0,0 +1,146 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_PINNAMES_H
#define MBED_PINNAMES_H
#include "cmsis.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
PIN_INPUT,
PIN_OUTPUT
} PinDirection;
#define PORT_SHIFT 5
typedef enum {
P0_0 = 0,
P0_1 = 1,
P0_2 = 2,
P0_3 = 3,
P0_4 = 4,
P0_5 = 5,
P0_6 = 6,
P0_7 = 7,
P0_8 = 8,
P0_9 = 9,
P0_10 = 10,
P0_11 = 11,
P0_12 = 12,
P0_13 = 13,
P0_14 = 14,
P0_15 = 15,
P0_16 = 16,
P0_17 = 17,
P0_18 = 18,
P0_19 = 19,
P0_20 = 20,
P0_21 = 21,
P0_22 = 22,
P0_23 = 23,
P0_24 = 24,
P0_25 = 25,
P0_26 = 26,
P0_29 = 29,
P0_30 = 30,
P0_31 = 31,
P1_0 = 32,
P1_1 = 33,
P1_2 = 34,
P1_3 = 35,
P1_4 = 36,
P1_5 = 37,
P1_6 = 38,
P1_7 = 39,
P1_8 = 40,
P1_9 = 41,
P1_10 = 42,
P1_11 = 43,
P1_12 = 44,
P1_13 = 45,
P1_14 = 46,
P1_15 = 47,
P1_16 = 48,
P1_17 = 49,
LED_RED = P0_29,
LED_GREEN = P1_10,
LED_BLUE = P1_9,
// mbed original LED naming
LED1 = LED_RED,
LED2 = LED_GREEN,
LED3 = LED_BLUE,
LED4 = LED_RED,
//Push buttons
SW1 = P0_24,
SW2 = P0_31,
SW3 = P0_4,
// USB Pins
USBTX = P0_1,
USBRX = P0_0,
// Arduino Headers
D0 = P0_8,
D1 = P0_9,
D2 = P0_10,
D3 = P1_12,
D4 = P1_13,
D5 = P0_29,
D6 = P1_0,
D7 = P1_14,
D8 = P1_16,
D9 = P1_15,
D10 = P1_1,
D11 = P0_20,
D12 = P0_18,
D13 = P0_19,
D14 = P0_26,
D15 = P0_25,
I2C_SCL = D15,
I2C_SDA = D14,
// Not connected
NC = (int)0xFFFFFFFF,
A0 = P0_30,
A1 = NC,
A2 = P1_8,
A3 = P1_10,
A4 = P1_4,
A5 = P1_5
} PinName;
typedef enum {
PullNone = 0,
PullDown = 1,
PullUp = 2,
PullDefault = PullUp
} PinMode;
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,184 @@
/*
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* How to set up clock using clock driver functions:
*
* 1. Setup clock sources.
*
* 2. Setup voltage for the fastest of the clock outputs
*
* 3. Set up wait states of the flash.
*
* 4. Set up all dividers.
*
* 5. Set up all selectors to provide selected clocks.
*/
/* TEXT BELOW IS USED AS SETTING FOR THE CLOCKS TOOL *****************************
!!ClocksProfile
product: Clocks v1.0
processor: LPC54114J256
package_id: LPC54114J256BD64
mcu_data: ksdk2_0
processor_version: 1.1.0
board: LPCXpresso54114
* BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR THE CLOCKS TOOL **/
#include "fsl_power.h"
#include "fsl_clock.h"
#include "clock_config.h"
/*******************************************************************************
* Definitions
******************************************************************************/
/*******************************************************************************
* Variables
******************************************************************************/
/* System clock frequency. */
extern uint32_t SystemCoreClock;
/*******************************************************************************
********************* Configuration BOARD_BootClockFRO12M ***********************
******************************************************************************/
/* TEXT BELOW IS USED AS SETTING FOR THE CLOCKS TOOL *****************************
!!Configuration
name: BOARD_BootClockFRO12M
outputs:
- {id: System_clock.outFreq, value: 12 MHz}
* BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR THE CLOCKS TOOL **/
/*******************************************************************************
* Variables for BOARD_BootClockFRO12M configuration
******************************************************************************/
/*******************************************************************************
* Code for BOARD_BootClockFRO12M configuration
******************************************************************************/
void BOARD_BootClockFRO12M(void)
{
/*!< Set up the clock sources */
/*!< Set up FRO */
POWER_DisablePD(kPDRUNCFG_PD_FRO_EN); /*!< Ensure FRO is on */
CLOCK_AttachClk(kFRO12M_to_MAIN_CLK); /*!< Switch to FRO 12MHz first to ensure we can change voltage without accidentally
being below the voltage for current speed */
CLOCK_SetupFROClocking(12000000U); /*!< Set up FRO to the 12 MHz, just for sure */
POWER_SetVoltageForFreq(12000000U); /*!< Set voltage for the one of the fastest clock outputs: System clock output */
CLOCK_SetFLASHAccessCyclesForFreq(12000000U); /*!< Set FLASH wait states for core */
/*!< Set up dividers */
CLOCK_SetClkDiv(kCLOCK_DivAhbClk, 1U, false); /*!< Set AHBCLKDIV divider to value 1 */
/*!< Set up clock selectors - Attach clocks to the peripheries */
CLOCK_AttachClk(kFRO12M_to_MAIN_CLK); /*!< Switch MAIN_CLK to FRO12M */
/*!< Set SystemCoreClock variable. */
SystemCoreClock = BOARD_BOOTCLOCKFRO12M_CORE_CLOCK;
}
/*******************************************************************************
********************** Configuration BOARD_BootClockFROHF48M ***********************
******************************************************************************/
/* TEXT BELOW IS USED AS SETTING FOR THE CLOCKS TOOL *****************************
!!Configuration
name: BOARD_BootClockFROHF48M
outputs:
- {id: System_clock.outFreq, value: 48 MHz}
settings:
- {id: SYSCON.MAINCLKSELA.sel, value: SYSCON.fro_hf}
* BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR THE CLOCKS TOOL **/
/*******************************************************************************
* Variables for BOARD_BootClockFROHF48M configuration
******************************************************************************/
/*******************************************************************************
* Code for BOARD_BootClockFROHF48M configuration
******************************************************************************/
void BOARD_BootClockFROHF48M(void)
{
/*!< Set up the clock sources */
/*!< Set up FRO */
POWER_DisablePD(kPDRUNCFG_PD_FRO_EN); /*!< Ensure FRO is on */
CLOCK_AttachClk(kFRO12M_to_MAIN_CLK); /*!< Switch to FRO 12MHz first to ensure we can change voltage without accidentally
being below the voltage for current speed */
POWER_SetVoltageForFreq(48000000U); /*!< Set voltage for the one of the fastest clock outputs: System clock output */
CLOCK_SetFLASHAccessCyclesForFreq(48000000U); /*!< Set FLASH wait states for core */
CLOCK_SetupFROClocking(48000000U); /*!< Set up high frequency FRO output to selected frequency */
/*!< Set up dividers */
CLOCK_SetClkDiv(kCLOCK_DivAhbClk, 1U, false); /*!< Set AHBCLKDIV divider to value 1 */
/*!< Set up clock selectors - Attach clocks to the peripheries */
CLOCK_AttachClk(kFRO_HF_to_MAIN_CLK); /*!< Switch MAIN_CLK to FRO_HF */
/*!< Set SystemCoreClock variable. */
SystemCoreClock = BOARD_BOOTCLOCKFROHF48M_CORE_CLOCK;
}
/*******************************************************************************
********************* Configuration BOARD_BootClockFROHF96M **********************
******************************************************************************/
/* TEXT BELOW IS USED AS SETTING FOR THE CLOCKS TOOL *****************************
!!Configuration
name: BOARD_BootClockFROHF96M
outputs:
- {id: System_clock.outFreq, value: 96 MHz}
settings:
- {id: SYSCON.MAINCLKSELA.sel, value: SYSCON.fro_hf}
sources:
- {id: SYSCON.fro_hf.outFreq, value: 96 MHz}
* BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR THE CLOCKS TOOL **/
/*******************************************************************************
* Variables for BOARD_BootClockFROHF96M configuration
******************************************************************************/
/*******************************************************************************
* Code for BOARD_BootClockFROHF96M configuration
******************************************************************************/
void BOARD_BootClockFROHF96M(void)
{
/*!< Set up the clock sources */
/*!< Set up FRO */
POWER_DisablePD(kPDRUNCFG_PD_FRO_EN); /*!< Ensure FRO is on */
CLOCK_AttachClk(kFRO12M_to_MAIN_CLK); /*!< Switch to FRO 12MHz first to ensure we can change voltage without accidentally
being below the voltage for current speed */
POWER_SetVoltageForFreq(96000000U); /*!< Set voltage for the one of the fastest clock outputs: System clock output */
CLOCK_SetFLASHAccessCyclesForFreq(96000000U); /*!< Set FLASH wait states for core */
CLOCK_SetupFROClocking(96000000U); /*!< Set up high frequency FRO output to selected frequency */
/*!< Set up dividers */
CLOCK_SetClkDiv(kCLOCK_DivAhbClk, 1U, false); /*!< Set AHBCLKDIV divider to value 1 */
/*!< Set up clock selectors - Attach clocks to the peripheries */
CLOCK_AttachClk(kFRO_HF_to_MAIN_CLK); /*!< Switch MAIN_CLK to FRO_HF */
/*!< Set SystemCoreClock variable. */
SystemCoreClock = BOARD_BOOTCLOCKFROHF96M_CORE_CLOCK;
}

View File

@ -0,0 +1,120 @@
/*
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _CLOCK_CONFIG_H_
#define _CLOCK_CONFIG_H_
#include "fsl_common.h"
/*******************************************************************************
* Definitions
******************************************************************************/
#define BOARD_XTAL0_CLK_HZ 12000000U /*!< Board xtal0 frequency in Hz */
#define BOARD_XTAL32K_CLK_HZ 32768U /*!< Board xtal32K frequency in Hz */
#define BOARD_BootClockRUN BOARD_BootClockFROHF48M
/*******************************************************************************
********************* Configuration BOARD_BootClockFRO12M ***********************
******************************************************************************/
/*******************************************************************************
* Definitions for BOARD_BootClockFRO12M configuration
******************************************************************************/
#define BOARD_BOOTCLOCKFRO12M_CORE_CLOCK 12000000U /*!< Core clock frequency: 12000000Hz */
/*******************************************************************************
* API for BOARD_BootClockFRO12M configuration
******************************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif /* __cplusplus*/
/*!
* @brief This function executes configuration of clocks.
*
*/
void BOARD_BootClockFRO12M(void);
#if defined(__cplusplus)
}
#endif /* __cplusplus*/
/*******************************************************************************
********************** Configuration BOARD_BootClockFROHF48M ***********************
******************************************************************************/
/*******************************************************************************
* Definitions for BOARD_BootClockFROHF48M configuration
******************************************************************************/
#define BOARD_BOOTCLOCKFROHF48M_CORE_CLOCK 48000000U /*!< Core clock frequency: 48000000Hz */
/*******************************************************************************
* API for BOARD_BootClockFROHF48M configuration
******************************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif /* __cplusplus*/
/*!
* @brief This function executes configuration of clocks.
*
*/
void BOARD_BootClockFROHF48M(void);
#if defined(__cplusplus)
}
#endif /* __cplusplus*/
/*******************************************************************************
********************* Configuration BOARD_BootClockFROHF96M **********************
******************************************************************************/
/*******************************************************************************
* Definitions for BOARD_BootClockFROHF96M configuration
******************************************************************************/
#define BOARD_BOOTCLOCKFROHF96M_CORE_CLOCK 96000000U /*!< Core clock frequency: 96000000Hz */
/*******************************************************************************
* API for BOARD_BootClockFROHF96M configuration
******************************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif /* __cplusplus*/
/*!
* @brief This function executes configuration of clocks.
*
*/
void BOARD_BootClockFROHF96M(void);
#if defined(__cplusplus)
}
#endif /* __cplusplus*/
#endif /* _CLOCK_CONFIG_H_ */

View File

@ -0,0 +1,40 @@
// The 'features' section in 'target.json' is now used to create the device's hardware preprocessor switches.
// Check the 'features' section of the target description in 'targets.json' for more details.
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_DEVICE_H
#define MBED_DEVICE_H
#if defined(TARGET_LPC54114_M4)
#define NUMBER_OF_GPIO_INTS 8
#elif defined(TARGET_LPC54114_M0)
#define NUMBER_OF_GPIO_INTS 4
#endif
#define APP_EXCLUDE_FROM_DEEPSLEEP \
(SYSCON_PDRUNCFG_PDEN_WDT_OSC_MASK | SYSCON_PDRUNCFG_PDEN_SRAMX_MASK | \
SYSCON_PDRUNCFG_PDEN_SRAM0_MASK | SYSCON_PDRUNCFG_PDEN_SRAM1_MASK | SYSCON_PDRUNCFG_PDEN_SRAM2_MASK)
#define DEVICE_ID_LENGTH 24
#include "objects.h"
#endif

View File

@ -0,0 +1,40 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "gpio_api.h"
#include "clock_config.h"
// called before main
void mbed_sdk_init()
{
BOARD_BootClockFROHF48M();
}
// Change the NMI pin to an input. This allows NMI pin to
// be used as a low power mode wakeup. The application will
// need to change the pin back to NMI_b or wakeup only occurs once!
void NMI_Handler(void)
{
//gpio_t gpio;
//gpio_init_in(&gpio, PTA4);
}
// Enable the RTC oscillator if available on the board
void rtc_setup_oscillator(void)
{
/* Enable the RTC 32K Oscillator */
SYSCON->RTCOSCCTRL |= SYSCON_RTCOSCCTRL_EN_MASK;
}

View File

@ -0,0 +1,134 @@
/*
** ###################################################################
** Version: rev. 1.0, 2016-05-09
** Build: b160802
**
** Abstract:
** Chip specific module features.
**
** Copyright (c) 2016 Freescale Semiconductor, Inc.
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without modification,
** are permitted provided that the following conditions are met:
**
** o Redistributions of source code must retain the above copyright notice, this list
** of conditions and the following disclaimer.
**
** o Redistributions in binary form must reproduce the above copyright notice, this
** list of conditions and the following disclaimer in the documentation and/or
** other materials provided with the distribution.
**
** o Neither the name of Freescale Semiconductor, Inc. nor the names of its
** contributors may be used to endorse or promote products derived from this
** software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
** ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
** ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
** http: www.freescale.com
** mail: support@freescale.com
**
** Revisions:
** - rev. 1.0 (2016-05-09)
** Initial version.
**
** ###################################################################
*/
#ifndef _LPC54114_cm4_FEATURES_H_
#define _LPC54114_cm4_FEATURES_H_
/* SOC module features */
/* @brief ADC availability on the SoC. */
#define FSL_FEATURE_SOC_ADC_COUNT (1)
/* @brief ASYNC_SYSCON availability on the SoC. */
#define FSL_FEATURE_SOC_ASYNC_SYSCON_COUNT (1)
/* @brief CRC availability on the SoC. */
#define FSL_FEATURE_SOC_CRC_COUNT (1)
/* @brief DMA availability on the SoC. */
#define FSL_FEATURE_SOC_DMA_COUNT (1)
/* @brief DMIC availability on the SoC. */
#define FSL_FEATURE_SOC_DMIC_COUNT (1)
/* @brief FLEXCOMM availability on the SoC. */
#define FSL_FEATURE_SOC_FLEXCOMM_COUNT (8)
/* @brief GINT availability on the SoC. */
#define FSL_FEATURE_SOC_GINT_COUNT (2)
/* @brief GPIO availability on the SoC. */
#define FSL_FEATURE_SOC_GPIO_COUNT (1)
/* @brief I2C availability on the SoC. */
#define FSL_FEATURE_SOC_I2C_COUNT (8)
/* @brief I2S availability on the SoC. */
#define FSL_FEATURE_SOC_I2S_COUNT (2)
/* @brief INPUTMUX availability on the SoC. */
#define FSL_FEATURE_SOC_INPUTMUX_COUNT (1)
/* @brief IOCON availability on the SoC. */
#define FSL_FEATURE_SOC_IOCON_COUNT (1)
/* @brief MAILBOX availability on the SoC. */
#define FSL_FEATURE_SOC_MAILBOX_COUNT (1)
/* @brief MRT availability on the SoC. */
#define FSL_FEATURE_SOC_MRT_COUNT (1)
/* @brief PINT availability on the SoC. */
#define FSL_FEATURE_SOC_PINT_COUNT (1)
/* @brief RTC availability on the SoC. */
#define FSL_FEATURE_SOC_RTC_COUNT (1)
/* @brief SCT availability on the SoC. */
#define FSL_FEATURE_SOC_SCT_COUNT (1)
/* @brief SPI availability on the SoC. */
#define FSL_FEATURE_SOC_SPI_COUNT (8)
/* @brief SPIFI availability on the SoC. */
#define FSL_FEATURE_SOC_SPIFI_COUNT (1)
/* @brief SYSCON availability on the SoC. */
#define FSL_FEATURE_SOC_SYSCON_COUNT (1)
/* @brief CTIMER availability on the SoC. */
#define FSL_FEATURE_SOC_CTIMER_COUNT (5)
/* @brief USART availability on the SoC. */
#define FSL_FEATURE_SOC_USART_COUNT (8)
/* @brief USB availability on the SoC. */
#define FSL_FEATURE_SOC_USB_COUNT (1)
/* @brief UTICK availability on the SoC. */
#define FSL_FEATURE_SOC_UTICK_COUNT (1)
/* @brief WWDT availability on the SoC. */
#define FSL_FEATURE_SOC_WWDT_COUNT (1)
/* DMA module features */
/* @brief Number of channels */
#define FSL_FEATURE_DMA_NUMBER_OF_CHANNELS (20)
/* PINT module features */
/* @brief Number of connected outputs */
#define FSL_FEATURE_PINT_NUMBER_OF_CONNECTED_OUTPUTS (8)
/* SCT module features */
/* @brief Number of events */
#define FSL_FEATURE_SCT_NUMBER_OF_EVENTS (10)
/* @brief Number of states */
#define FSL_FEATURE_SCT_NUMBER_OF_STATES (10)
/* @brief Number of match capture */
#define FSL_FEATURE_SCT_NUMBER_OF_MATCH_CAPTURE (10)
/* SYSCON module features */
/* @brief Pointer to ROM IAP entry functions */
#define FSL_FEATURE_SYSCON_IAP_ENTRY_LOCATION (0x03000205)
/* @brief Flash page size in bytes */
#define FSL_FEATURE_SYSCON_FLASH_PAGE_SIZE_BYTES (256)
/* @brief Flash sector size in bytes */
#define FSL_FEATURE_SYSCON_FLASH_SECTOR_SIZE_BYTES (32768)
/* @brief Flash size in bytes */
#define FSL_FEATURE_SYSCON_FLASH_SIZE_BYTES (262144)
#endif /* _LPC54114_cm4_FEATURES_H_ */

View File

@ -0,0 +1,129 @@
#! armcc -E
/*
** ###################################################################
** Processors: LPC54114J256BD64_cm4
** LPC54114J256UK49_cm4
**
** Compiler: Keil ARM C/C++ Compiler
** Reference manual: LPC5411x User manual Rev. 1.0 16 February 2016
** Version: rev. 1.0, 2016-04-29
** Build: b160526
**
** Abstract:
** Linker file for the Keil ARM C/C++ Compiler
**
** Copyright (c) 2016 Freescale Semiconductor, Inc.
** Copyright (c) 2016 NXP
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without modification,
** are permitted provided that the following conditions are met:
**
** o Redistributions of source code must retain the above copyright notice, this list
** of conditions and the following disclaimer.
**
** o Redistributions in binary form must reproduce the above copyright notice, this
** list of conditions and the following disclaimer in the documentation and/or
** other materials provided with the distribution.
**
** o Neither the name of copyright holder nor the names of its
** contributors may be used to endorse or promote products derived from this
** software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
** ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
** ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
** http: www.nxp.com
** mail: support@nxp.com
**
** ###################################################################
*/
#define __ram_vector_table__ 1
#if (defined(__ram_vector_table__))
#define __ram_vector_table_size__ 0x000000E0
#else
#define __ram_vector_table_size__ 0x00000000
#endif
#define m_interrupts_start 0x00000000
#define m_interrupts_size 0x000000E0
#define m_text_start 0x000000E0
#define m_text_size 0x0002FF20
#define m_core1_image_start 0x00030000
#define m_core1_image_size 0x00010000
#define m_interrupts_ram_start 0x20000000
#define m_interrupts_ram_size __ram_vector_table_size__
#define m_rpmsg_sh_mem_start 0x20026800
#define m_rpmsg_sh_mem_size 0x00001800
#define m_data_start (m_interrupts_ram_start + m_interrupts_ram_size)
#define m_data_size (0x00010000 - m_interrupts_ram_size)
#define m_sramx_start 0x04000000
#define m_sramx_size 0x00008000
/* Sizes */
#if (defined(__stack_size__))
#define Stack_Size __stack_size__
#else
#define Stack_Size 0x0400
#endif
#if (defined(__heap_size__))
#define Heap_Size __heap_size__
#else
#define Heap_Size 0x0400
#endif
LR_m_text m_interrupts_start m_text_start+m_text_size-m_interrupts_start { ; load region size_region
VECTOR_ROM m_interrupts_start m_interrupts_size { ; load address = execution address
* (RESET,+FIRST)
}
ER_m_text m_text_start m_text_size { ; load address = execution address
* (InRoot$$Sections)
.ANY (+RO)
}
ER_m_sramx m_sramx_start m_sramx_size { ; SRAMX memory
* (sramx)
}
#if (defined(__ram_vector_table__))
VECTOR_RAM m_interrupts_ram_start EMPTY m_interrupts_ram_size {
}
#else
VECTOR_RAM m_interrupts_start EMPTY 0 {
}
#endif
RW_m_data m_data_start m_data_size { ; RW data
.ANY (+RW +ZI)
}
RW_IRAM1 ((ImageLimit(RW_m_data) == m_data_start) ? ImageLimit(RW_m_data) : +0) EMPTY Heap_Size { ; Heap region growing up
}
ARM_LIB_STACK m_data_start+m_data_size EMPTY -Stack_Size { ; Stack region growing down
}
RPMSG_SH_MEM m_rpmsg_sh_mem_start UNINIT m_rpmsg_sh_mem_size { ; Shared memory used by RPMSG
* (rpmsg_sh_mem_section)
}
}
LR_CORE1_IMAGE m_core1_image_start {
CORE1_REGION m_core1_image_start m_core1_image_size {
*(M0CODE)
}
}

View File

@ -0,0 +1,625 @@
;/*****************************************************************************
; * @file: startup_LPC54114_cm4.s
; * @purpose: CMSIS Cortex-M4 Core Device Startup File for the
; * LPC54114_cm4
; * @version: 1.0
; * @date: 2016-4-29
; *
; * Copyright: 1997 - 2016 Freescale Semiconductor, Inc. All Rights Reserved.
; *
; * Redistribution and use in source and binary forms, with or without modification,
; * are permitted provided that the following conditions are met:
; *
; * o Redistributions of source code must retain the above copyright notice, this list
; * of conditions and the following disclaimer.
; *
; * o Redistributions in binary form must reproduce the above copyright notice, this
; * list of conditions and the following disclaimer in the documentation and/or
; * other materials provided with the distribution.
; *
; * o Neither the name of Freescale Semiconductor, Inc. nor the names of its
; * contributors may be used to endorse or promote products derived from this
; * software without specific prior written permission.
; *
; * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
; * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
; * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
; * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
; * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
; * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
; * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
; * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
; * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
; *
; *------- <<< Use Configuration Wizard in Context Menu >>> ------------------
; *
; *****************************************************************************/
PRESERVE8
THUMB
; Vector Table Mapped to Address 0 at Reset
AREA RESET, DATA, READONLY
EXPORT __Vectors
IMPORT |Image$$ARM_LIB_STACK$$ZI$$Limit|
__Vectors DCD |Image$$ARM_LIB_STACK$$ZI$$Limit| ; Top of Stack
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler
DCD HardFault_Handler
DCD MemManage_Handler
DCD BusFault_Handler
DCD UsageFault_Handler
__vector_table_0x1c
DCD 0 ; Checksum of the first 7 words
DCD 0
DCD 0 ; Enhanced image marker, set to 0x0 for legacy boot
DCD 0 ; Pointer to enhanced boot block, set to 0x0 for legacy boot
DCD SVC_Handler
DCD DebugMon_Handler
DCD 0
DCD PendSV_Handler
DCD SysTick_Handler
; External Interrupts
DCD WDT_BOD_IRQHandler ; Windowed watchdog timer, Brownout detect
DCD DMA0_IRQHandler ; DMA controller
DCD GINT0_IRQHandler ; GPIO group 0
DCD GINT1_IRQHandler ; GPIO group 1
DCD PIN_INT0_IRQHandler ; Pin interrupt 0 or pattern match engine slice 0
DCD PIN_INT1_IRQHandler ; Pin interrupt 1or pattern match engine slice 1
DCD PIN_INT2_IRQHandler ; Pin interrupt 2 or pattern match engine slice 2
DCD PIN_INT3_IRQHandler ; Pin interrupt 3 or pattern match engine slice 3
DCD UTICK0_IRQHandler ; Micro-tick Timer
DCD MRT0_IRQHandler ; Multi-rate timer
DCD CTIMER0_IRQHandler ; Standard counter/timer CTIMER0
DCD CTIMER1_IRQHandler ; Standard counter/timer CTIMER1
DCD SCT0_IRQHandler ; SCTimer/PWM
DCD CTIMER3_IRQHandler ; Standard counter/timer CTIMER3
DCD FLEXCOMM0_IRQHandler ; Flexcomm Interface 0 (USART, SPI, I2C)
DCD FLEXCOMM1_IRQHandler ; Flexcomm Interface 1 (USART, SPI, I2C)
DCD FLEXCOMM2_IRQHandler ; Flexcomm Interface 2 (USART, SPI, I2C)
DCD FLEXCOMM3_IRQHandler ; Flexcomm Interface 3 (USART, SPI, I2C)
DCD FLEXCOMM4_IRQHandler ; Flexcomm Interface 4 (USART, SPI, I2C)
DCD FLEXCOMM5_IRQHandler ; Flexcomm Interface 5 (USART, SPI, I2C)
DCD FLEXCOMM6_IRQHandler ; Flexcomm Interface 6 (USART, SPI, I2C, I2S)
DCD FLEXCOMM7_IRQHandler ; Flexcomm Interface 7 (USART, SPI, I2C, I2S)
DCD ADC0_SEQA_IRQHandler ; ADC0 sequence A completion.
DCD ADC0_SEQB_IRQHandler ; ADC0 sequence B completion.
DCD ADC0_THCMP_IRQHandler ; ADC0 threshold compare and error.
DCD DMIC0_IRQHandler ; Digital microphone and DMIC subsystem
DCD HWVAD0_IRQHandler ; Hardware Voice Activity Detector
DCD USB0_NEEDCLK_IRQHandler ; USB Activity Wake-up Interrupt
DCD USB0_IRQHandler ; USB device
DCD RTC_IRQHandler ; RTC alarm and wake-up interrupts
DCD IOH_IRQHandler ; IOH
DCD MAILBOX_IRQHandler ; Mailbox interrupt (present on selected devices)
DCD PIN_INT4_IRQHandler ; Pin interrupt 4 or pattern match engine slice 4 int
DCD PIN_INT5_IRQHandler ; Pin interrupt 5 or pattern match engine slice 5 int
DCD PIN_INT6_IRQHandler ; Pin interrupt 6 or pattern match engine slice 6 int
DCD PIN_INT7_IRQHandler ; Pin interrupt 7 or pattern match engine slice 7 int
DCD CTIMER2_IRQHandler ; Standard counter/timer CTIMER2
DCD CTIMER4_IRQHandler ; Standard counter/timer CTIMER4
DCD Reserved54_IRQHandler ; Reserved interrupt
DCD SPIFI0_IRQHandler ; SPI flash interface
; <h> Code Read Protection level (CRP)
; <o> CRP_Level:
; <0xFFFFFFFF=> Disabled
; <0x4E697370=> NO_ISP
; <0x12345678=> CRP1
; <0x87654321=> CRP2
; <0x43218765=> CRP3 (Are you sure?)
; </h>
CRP_Level EQU 0xFFFFFFFF
IF :LNOT::DEF:NO_CRP
AREA |.ARM.__at_0x02FC|, CODE, READONLY
CRP_Key DCD 0xFFFFFFFF
ENDIF
AREA |.text|, CODE, READONLY
cpu_id EQU 0xE000ED00
cpu_ctrl EQU 0x40000800
coproc_boot EQU 0x40000804
coproc_stack EQU 0x40000808
rel_vals
DCD cpu_id, cpu_ctrl, coproc_boot, coproc_stack
DCW 0xFFF, 0xC24
; Reset Handler - shared for both cores
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
IF :LNOT::DEF:SLAVEBOOT
; Both the M0+ and M4 core come via this shared startup code,
; but the M0+ and M4 core have different vector tables.
; Determine if the core executing this code is the master or
; the slave and handle each core state individually.
shared_boot_entry
LDR r6, =rel_vals
MOVS r4, #0 ; Flag for slave core (0)
MOVS r5, #1
; Determine which core (M0+ or M4) this code is running on
; r2 = (((*cpu_id) >> 4) & 0xFFF); (M4 core == 0xC24)
get_current_core_id
LDR r0, [r6, #0]
LDR r1, [r0] ; r1 = CPU ID status
LSRS r1, r1, #4 ; Right justify 12 CPU ID bits
LDRH r2, [r6, #16] ; Mask for CPU ID bits
ANDS r2, r1, r2 ; r2 = ARM COrtex CPU ID
LDRH r3, [r6, #18] ; Mask for CPU ID bits
CMP r3, r2 ; Core ID matches M4 identifier
BNE get_master_status
MOV r4, r5 ; Set flag for master core (1)
; Determine if M4 core is the master or slave
; r3 = ((*cpu_ctrl) & 1); (0 == m0+, 1 == M4)
get_master_status
LDR r0, [r6, #4]
LDR r3, [r0] ; r3 = SYSCON co-processor CPU control status
ANDS r3, r3, r5 ; r3 = (Bit 0: 1 = M4 is master, 0 = M4 is slave)
; Select boot based on selected master core and core ID
select_boot
EORS r3, r3, r4 ; r4 = (Bit 0: 0 = master, 1 = slave)
BNE slave_boot
B normal_boot
; Slave boot
slave_boot
LDR r0, [r6, #8]
LDR r2, [r0] ; r1 = SYSCON co-processor boot address
CMP r2, #0 ; Slave boot address = 0 (not set up)?
BEQ cpu_sleep
LDR r0, [r6, #12]
LDR r1, [r0] ; r5 = SYSCON co-processor stack address
MOV sp, r1 ; Update slave CPU stack pointer
; Be sure to update VTOR for the slave MCU to point to the
; slave vector table in boot memory
BX r2 ; Jump to slave boot address
; Slave isn't yet setup for system boot from the master
; so sleep until the master sets it up and then reboots it
cpu_sleep
MOV sp, r5 ; Will force exception if something happens
cpu_sleep_wfi
WFI ; Sleep forever until master reboots
B cpu_sleep_wfi
ENDIF
; Normal boot for master/slave
normal_boot
LDR r0, =SystemInit
BLX r0
LDR r0, =__main
BX r0
ENDP
; Dummy Exception Handlers (infinite loops which can be modified)
NMI_Handler PROC
EXPORT NMI_Handler [WEAK]
B .
ENDP
HardFault_Handler \
PROC
EXPORT HardFault_Handler [WEAK]
B .
ENDP
MemManage_Handler PROC
EXPORT MemManage_Handler [WEAK]
B .
ENDP
BusFault_Handler PROC
EXPORT BusFault_Handler [WEAK]
B .
ENDP
UsageFault_Handler PROC
EXPORT UsageFault_Handler [WEAK]
B .
ENDP
SVC_Handler PROC
EXPORT SVC_Handler [WEAK]
B .
ENDP
DebugMon_Handler PROC
EXPORT DebugMon_Handler [WEAK]
B .
ENDP
PendSV_Handler PROC
EXPORT PendSV_Handler [WEAK]
B .
ENDP
SysTick_Handler PROC
EXPORT SysTick_Handler [WEAK]
B .
ENDP
WDT_BOD_IRQHandler\
PROC
EXPORT WDT_BOD_IRQHandler [WEAK]
LDR R0, =WDT_BOD_DriverIRQHandler
BX R0
ENDP
DMA0_IRQHandler\
PROC
EXPORT DMA0_IRQHandler [WEAK]
LDR R0, =DMA0_DriverIRQHandler
BX R0
ENDP
GINT0_IRQHandler\
PROC
EXPORT GINT0_IRQHandler [WEAK]
LDR R0, =GINT0_DriverIRQHandler
BX R0
ENDP
GINT1_IRQHandler\
PROC
EXPORT GINT1_IRQHandler [WEAK]
LDR R0, =GINT1_DriverIRQHandler
BX R0
ENDP
PIN_INT0_IRQHandler\
PROC
EXPORT PIN_INT0_IRQHandler [WEAK]
LDR R0, =PIN_INT0_DriverIRQHandler
BX R0
ENDP
PIN_INT1_IRQHandler\
PROC
EXPORT PIN_INT1_IRQHandler [WEAK]
LDR R0, =PIN_INT1_DriverIRQHandler
BX R0
ENDP
PIN_INT2_IRQHandler\
PROC
EXPORT PIN_INT2_IRQHandler [WEAK]
LDR R0, =PIN_INT2_DriverIRQHandler
BX R0
ENDP
PIN_INT3_IRQHandler\
PROC
EXPORT PIN_INT3_IRQHandler [WEAK]
LDR R0, =PIN_INT3_DriverIRQHandler
BX R0
ENDP
UTICK0_IRQHandler\
PROC
EXPORT UTICK0_IRQHandler [WEAK]
LDR R0, =UTICK0_DriverIRQHandler
BX R0
ENDP
MRT0_IRQHandler\
PROC
EXPORT MRT0_IRQHandler [WEAK]
LDR R0, =MRT0_DriverIRQHandler
BX R0
ENDP
CTIMER0_IRQHandler\
PROC
EXPORT CTIMER0_IRQHandler [WEAK]
LDR R0, =CTIMER0_DriverIRQHandler
BX R0
ENDP
CTIMER1_IRQHandler\
PROC
EXPORT CTIMER1_IRQHandler [WEAK]
LDR R0, =CTIMER1_DriverIRQHandler
BX R0
ENDP
SCT0_IRQHandler\
PROC
EXPORT SCT0_IRQHandler [WEAK]
LDR R0, =SCT0_DriverIRQHandler
BX R0
ENDP
CTIMER3_IRQHandler\
PROC
EXPORT CTIMER3_IRQHandler [WEAK]
LDR R0, =CTIMER3_DriverIRQHandler
BX R0
ENDP
FLEXCOMM0_IRQHandler\
PROC
EXPORT FLEXCOMM0_IRQHandler [WEAK]
LDR R0, =FLEXCOMM0_DriverIRQHandler
BX R0
ENDP
FLEXCOMM1_IRQHandler\
PROC
EXPORT FLEXCOMM1_IRQHandler [WEAK]
LDR R0, =FLEXCOMM1_DriverIRQHandler
BX R0
ENDP
FLEXCOMM2_IRQHandler\
PROC
EXPORT FLEXCOMM2_IRQHandler [WEAK]
LDR R0, =FLEXCOMM2_DriverIRQHandler
BX R0
ENDP
FLEXCOMM3_IRQHandler\
PROC
EXPORT FLEXCOMM3_IRQHandler [WEAK]
LDR R0, =FLEXCOMM3_DriverIRQHandler
BX R0
ENDP
FLEXCOMM4_IRQHandler\
PROC
EXPORT FLEXCOMM4_IRQHandler [WEAK]
LDR R0, =FLEXCOMM4_DriverIRQHandler
BX R0
ENDP
FLEXCOMM5_IRQHandler\
PROC
EXPORT FLEXCOMM5_IRQHandler [WEAK]
LDR R0, =FLEXCOMM5_DriverIRQHandler
BX R0
ENDP
FLEXCOMM6_IRQHandler\
PROC
EXPORT FLEXCOMM6_IRQHandler [WEAK]
LDR R0, =FLEXCOMM6_DriverIRQHandler
BX R0
ENDP
FLEXCOMM7_IRQHandler\
PROC
EXPORT FLEXCOMM7_IRQHandler [WEAK]
LDR R0, =FLEXCOMM7_DriverIRQHandler
BX R0
ENDP
ADC0_SEQA_IRQHandler\
PROC
EXPORT ADC0_SEQA_IRQHandler [WEAK]
LDR R0, =ADC0_SEQA_DriverIRQHandler
BX R0
ENDP
ADC0_SEQB_IRQHandler\
PROC
EXPORT ADC0_SEQB_IRQHandler [WEAK]
LDR R0, =ADC0_SEQB_DriverIRQHandler
BX R0
ENDP
ADC0_THCMP_IRQHandler\
PROC
EXPORT ADC0_THCMP_IRQHandler [WEAK]
LDR R0, =ADC0_THCMP_DriverIRQHandler
BX R0
ENDP
DMIC0_IRQHandler\
PROC
EXPORT DMIC0_IRQHandler [WEAK]
LDR R0, =DMIC0_DriverIRQHandler
BX R0
ENDP
HWVAD0_IRQHandler\
PROC
EXPORT HWVAD0_IRQHandler [WEAK]
LDR R0, =HWVAD0_DriverIRQHandler
BX R0
ENDP
USB0_NEEDCLK_IRQHandler\
PROC
EXPORT USB0_NEEDCLK_IRQHandler [WEAK]
LDR R0, =USB0_NEEDCLK_DriverIRQHandler
BX R0
ENDP
USB0_IRQHandler\
PROC
EXPORT USB0_IRQHandler [WEAK]
LDR R0, =USB0_DriverIRQHandler
BX R0
ENDP
RTC_IRQHandler\
PROC
EXPORT RTC_IRQHandler [WEAK]
LDR R0, =RTC_DriverIRQHandler
BX R0
ENDP
IOH_IRQHandler\
PROC
EXPORT IOH_IRQHandler [WEAK]
LDR R0, =IOH_DriverIRQHandler
BX R0
ENDP
MAILBOX_IRQHandler\
PROC
EXPORT MAILBOX_IRQHandler [WEAK]
LDR R0, =MAILBOX_DriverIRQHandler
BX R0
ENDP
PIN_INT4_IRQHandler\
PROC
EXPORT PIN_INT4_IRQHandler [WEAK]
LDR R0, =PIN_INT4_DriverIRQHandler
BX R0
ENDP
PIN_INT5_IRQHandler\
PROC
EXPORT PIN_INT5_IRQHandler [WEAK]
LDR R0, =PIN_INT5_DriverIRQHandler
BX R0
ENDP
PIN_INT6_IRQHandler\
PROC
EXPORT PIN_INT6_IRQHandler [WEAK]
LDR R0, =PIN_INT6_DriverIRQHandler
BX R0
ENDP
PIN_INT7_IRQHandler\
PROC
EXPORT PIN_INT7_IRQHandler [WEAK]
LDR R0, =PIN_INT7_DriverIRQHandler
BX R0
ENDP
CTIMER2_IRQHandler\
PROC
EXPORT CTIMER2_IRQHandler [WEAK]
LDR R0, =CTIMER2_DriverIRQHandler
BX R0
ENDP
CTIMER4_IRQHandler\
PROC
EXPORT CTIMER4_IRQHandler [WEAK]
LDR R0, =CTIMER4_DriverIRQHandler
BX R0
ENDP
Reserved54_IRQHandler\
PROC
EXPORT Reserved54_IRQHandler [WEAK]
LDR R0, =Reserved54_DriverIRQHandler
BX R0
ENDP
SPIFI0_IRQHandler\
PROC
EXPORT SPIFI0_IRQHandler [WEAK]
LDR R0, =SPIFI0_DriverIRQHandler
BX R0
ENDP
Default_Handler PROC
EXPORT WDT_BOD_DriverIRQHandler [WEAK]
EXPORT DMA0_DriverIRQHandler [WEAK]
EXPORT GINT0_DriverIRQHandler [WEAK]
EXPORT GINT1_DriverIRQHandler [WEAK]
EXPORT PIN_INT0_DriverIRQHandler [WEAK]
EXPORT PIN_INT1_DriverIRQHandler [WEAK]
EXPORT PIN_INT2_DriverIRQHandler [WEAK]
EXPORT PIN_INT3_DriverIRQHandler [WEAK]
EXPORT UTICK0_DriverIRQHandler [WEAK]
EXPORT MRT0_DriverIRQHandler [WEAK]
EXPORT CTIMER0_DriverIRQHandler [WEAK]
EXPORT CTIMER1_DriverIRQHandler [WEAK]
EXPORT SCT0_DriverIRQHandler [WEAK]
EXPORT CTIMER3_DriverIRQHandler [WEAK]
EXPORT FLEXCOMM0_DriverIRQHandler [WEAK]
EXPORT FLEXCOMM1_DriverIRQHandler [WEAK]
EXPORT FLEXCOMM2_DriverIRQHandler [WEAK]
EXPORT FLEXCOMM3_DriverIRQHandler [WEAK]
EXPORT FLEXCOMM4_DriverIRQHandler [WEAK]
EXPORT FLEXCOMM5_DriverIRQHandler [WEAK]
EXPORT FLEXCOMM6_DriverIRQHandler [WEAK]
EXPORT FLEXCOMM7_DriverIRQHandler [WEAK]
EXPORT ADC0_SEQA_DriverIRQHandler [WEAK]
EXPORT ADC0_SEQB_DriverIRQHandler [WEAK]
EXPORT ADC0_THCMP_DriverIRQHandler [WEAK]
EXPORT DMIC0_DriverIRQHandler [WEAK]
EXPORT HWVAD0_DriverIRQHandler [WEAK]
EXPORT USB0_NEEDCLK_DriverIRQHandler [WEAK]
EXPORT USB0_DriverIRQHandler [WEAK]
EXPORT RTC_DriverIRQHandler [WEAK]
EXPORT IOH_DriverIRQHandler [WEAK]
EXPORT MAILBOX_DriverIRQHandler [WEAK]
EXPORT PIN_INT4_DriverIRQHandler [WEAK]
EXPORT PIN_INT5_DriverIRQHandler [WEAK]
EXPORT PIN_INT6_DriverIRQHandler [WEAK]
EXPORT PIN_INT7_DriverIRQHandler [WEAK]
EXPORT CTIMER2_DriverIRQHandler [WEAK]
EXPORT CTIMER4_DriverIRQHandler [WEAK]
EXPORT Reserved54_DriverIRQHandler [WEAK]
EXPORT SPIFI0_DriverIRQHandler [WEAK]
WDT_BOD_DriverIRQHandler
DMA0_DriverIRQHandler
GINT0_DriverIRQHandler
GINT1_DriverIRQHandler
PIN_INT0_DriverIRQHandler
PIN_INT1_DriverIRQHandler
PIN_INT2_DriverIRQHandler
PIN_INT3_DriverIRQHandler
UTICK0_DriverIRQHandler
MRT0_DriverIRQHandler
CTIMER0_DriverIRQHandler
CTIMER1_DriverIRQHandler
SCT0_DriverIRQHandler
CTIMER3_DriverIRQHandler
FLEXCOMM0_DriverIRQHandler
FLEXCOMM1_DriverIRQHandler
FLEXCOMM2_DriverIRQHandler
FLEXCOMM3_DriverIRQHandler
FLEXCOMM4_DriverIRQHandler
FLEXCOMM5_DriverIRQHandler
FLEXCOMM6_DriverIRQHandler
FLEXCOMM7_DriverIRQHandler
ADC0_SEQA_DriverIRQHandler
ADC0_SEQB_DriverIRQHandler
ADC0_THCMP_DriverIRQHandler
DMIC0_DriverIRQHandler
HWVAD0_DriverIRQHandler
USB0_NEEDCLK_DriverIRQHandler
USB0_DriverIRQHandler
RTC_DriverIRQHandler
IOH_DriverIRQHandler
MAILBOX_DriverIRQHandler
PIN_INT4_DriverIRQHandler
PIN_INT5_DriverIRQHandler
PIN_INT6_DriverIRQHandler
PIN_INT7_DriverIRQHandler
CTIMER2_DriverIRQHandler
CTIMER4_DriverIRQHandler
Reserved54_DriverIRQHandler
SPIFI0_DriverIRQHandler
B .
ENDP
ALIGN
END

View File

@ -0,0 +1,31 @@
/* mbed Microcontroller Library - stackheap
* Copyright (C) 2009-2011 ARM Limited. All rights reserved.
*
* Setup a fixed single stack/heap memory model,
* between the top of the RW/ZI region and the stackpointer
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <rt_misc.h>
#include <stdint.h>
extern char Image$$RW_IRAM1$$ZI$$Limit[];
extern __value_in_regs struct __initial_stackheap __user_setup_stackheap(uint32_t R0, uint32_t R1, uint32_t R2, uint32_t R3) {
uint32_t zi_limit = (uint32_t)Image$$RW_IRAM1$$ZI$$Limit;
uint32_t sp_limit = __current_sp();
zi_limit = (zi_limit + 7) & ~0x7; // ensure zi_limit is 8-byte aligned
struct __initial_stackheap r;
r.heap_base = zi_limit;
r.heap_limit = sp_limit;
return r;
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,292 @@
/*
** ###################################################################
** Processors: LPC54114J256_cm4
**
** Compiler: GNU C Compiler
** Reference manual: LPC54114 Series Reference Manual, Rev. 0 , 11/2016
** Version: rev. 1.0, 2016-11-02
** Build: b161214
**
** Abstract:
** Linker file for the GNU C Compiler
**
** Copyright (c) 2016 Freescale Semiconductor, Inc.
** Copyright (c) 2016 - 2017 , NXP
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without modification,
** are permitted provided that the following conditions are met:
**
** o Redistributions of source code must retain the above copyright notice, this list
** of conditions and the following disclaimer.
**
** o Redistributions in binary form must reproduce the above copyright notice, this
** list of conditions and the following disclaimer in the documentation and/or
** other materials provided with the distribution.
**
** o Neither the name of copyright holder nor the names of its
** contributors may be used to endorse or promote products derived from this
** software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
** ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
** ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
** http: www.freescale.com
** mail: support@freescale.com
**
** Copyright (c) 2016 NXP Semiconductors, Inc.
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without modification,
** are permitted provided that the following conditions are met:
**
** o Redistributions of source code must retain the above copyright notice, this list
** of conditions and the following disclaimer.
**
** o Redistributions in binary form must reproduce the above copyright notice, this
** list of conditions and the following disclaimer in the documentation and/or
** other materials provided with the distribution.
**
** o Neither the name of NXP Semiconductors, Inc. nor the names of its
** contributors may be used to endorse or promote products derived from this
** software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
** ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
** ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
** http: www.nxp.com
** mail: support@nxp.com
**
** ###################################################################
*/
/* Entry Point */
ENTRY(Reset_Handler)
__ram_vector_table__ = 1;
__stack_size__ = 0x2000;
__heap_size__ = 0x4000;
HEAP_SIZE = DEFINED(__heap_size__) ? __heap_size__ : 0x0400;
STACK_SIZE = DEFINED(__stack_size__) ? __stack_size__ : 0x0800;
M_VECTOR_RAM_SIZE = DEFINED(__ram_vector_table__) ? 0xE4 : 0x0;
RPMSG_SHMEM_SIZE = DEFINED(__use_shmem__) ? 0x1800 : 0;
/* Specify the memory areas */
MEMORY
{
m_interrupts (RX) : ORIGIN = 0x00000000, LENGTH = 0x000000E4
m_text (RX) : ORIGIN = 0x000000E4, LENGTH = 0x0002FF1C
m_core1_image (RX) : ORIGIN = 0x00030000, LENGTH = 0x00010000
m_data (RW) : ORIGIN = 0x20000000, LENGTH = 0x00010000
rpmsg_sh_mem (RW) : ORIGIN = 0x20026800, LENGTH = RPMSG_SHMEM_SIZE
}
/* Define output sections */
SECTIONS
{
/* section for storing the secondary core image */
.m0code :
{
. = ALIGN(4) ;
KEEP (*(.m0code))
*(.m0code*)
. = ALIGN(4) ;
} > m_core1_image
/* NOINIT section for rpmsg_sh_mem */
.noinit_rpmsg_sh_mem (NOLOAD) : ALIGN(4)
{
*(.noinit.$rpmsg_sh_mem*)
. = ALIGN(4) ;
} > rpmsg_sh_mem
/* The startup code goes first into internal flash */
.interrupts :
{
__VECTOR_TABLE = .;
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} > m_interrupts
/* The program code and other data goes into internal flash */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
} > m_text
.ARM.extab :
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} > m_text
.ARM :
{
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} > m_text
.ctors :
{
__CTOR_LIST__ = .;
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
from the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
__CTOR_END__ = .;
} > m_text
.dtors :
{
__DTOR_LIST__ = .;
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
__DTOR_END__ = .;
} > m_text
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} > m_text
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} > m_text
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
} > m_text
__etext = .; /* define a global symbol at end of code */
__DATA_ROM = .; /* Symbol is used by startup for data initialization */
.interrupts_ram :
{
. = ALIGN(4);
__VECTOR_RAM__ = .;
__interrupts_ram_start__ = .; /* Create a global symbol at data start */
*(.m_interrupts_ram) /* This is a user defined section */
. += M_VECTOR_RAM_SIZE;
. = ALIGN(4);
__interrupts_ram_end__ = .; /* Define a global symbol at data end */
} > m_data
__VECTOR_RAM = DEFINED(__ram_vector_table__) ? __VECTOR_RAM__ : ORIGIN(m_interrupts);
__RAM_VECTOR_TABLE_SIZE_BYTES = DEFINED(__ram_vector_table__) ? (__interrupts_ram_end__ - __interrupts_ram_start__) : 0x0;
.data : AT(__DATA_ROM)
{
. = ALIGN(4);
__DATA_RAM = .;
__data_start__ = .; /* create a global symbol at data start */
*(.ramfunc*) /* for functions in ram */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
KEEP(*(.jcr*))
. = ALIGN(4);
__data_end__ = .; /* define a global symbol at data end */
} > m_data
__DATA_END = __DATA_ROM + (__data_end__ - __data_start__);
text_end = ORIGIN(m_text) + LENGTH(m_text);
ASSERT(__DATA_END <= text_end, "region m_text overflowed with text and data")
/* Uninitialized data section */
.bss :
{
/* This is used by the startup in order to initialize the .bss section */
. = ALIGN(4);
__START_BSS = .;
__bss_start__ = .;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
__bss_end__ = .;
__END_BSS = .;
} > m_data
.heap :
{
. = ALIGN(8);
__end__ = .;
PROVIDE(end = .);
__HeapBase = .;
. += HEAP_SIZE;
__HeapLimit = .;
__heap_limit = .; /* Add for _sbrk */
} > m_data
.stack :
{
. = ALIGN(8);
. += STACK_SIZE;
} > m_data
/* Initializes stack on the end of block */
__StackTop = ORIGIN(m_data) + LENGTH(m_data);
__StackLimit = __StackTop - STACK_SIZE;
PROVIDE(__stack = __StackTop);
.ARM.attributes 0 : { *(.ARM.attributes) }
ASSERT(__StackLimit >= __HeapLimit, "region m_data overflowed with stack and heap")
}

View File

@ -0,0 +1,791 @@
/* ---------------------------------------------------------------------------------------*/
/* @file: startup_LPC54114_cm4.S */
/* @purpose: CMSIS Cortex-M4 Core Device Startup File */
/* LPC54114_cm4 */
/* @version: 1.0 */
/* @date: 2016-11-2 */
/* @build: b161214 */
/* ---------------------------------------------------------------------------------------*/
/* */
/* Copyright (c) 1997 - 2016 , Freescale Semiconductor, Inc. */
/* Copyright (c) 2016 - 2017 , NXP */
/* */
/* Redistribution and use in source and binary forms, with or without modification, */
/* are permitted provided that the following conditions are met: */
/* */
/* o Redistributions of source code must retain the above copyright notice, this list */
/* of conditions and the following disclaimer. */
/* */
/* o Redistributions in binary form must reproduce the above copyright notice, this */
/* list of conditions and the following disclaimer in the documentation and/or */
/* other materials provided with the distribution. */
/* */
/* o Neither the name of copyright holder nor the names of its */
/* contributors may be used to endorse or promote products derived from this */
/* software without specific prior written permission. */
/* */
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND */
/* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */
/* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */
/* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR */
/* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */
/* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */
/* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */
/* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
/* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
/* */
/* Copyright (c) 2016 , NXP Semiconductors, Inc. */
/* All rights reserved. */
/* */
/* Redistribution and use in source and binary forms, with or without modification, */
/* are permitted provided that the following conditions are met: */
/* */
/* o Redistributions of source code must retain the above copyright notice, this list */
/* of conditions and the following disclaimer. */
/* */
/* o Redistributions in binary form must reproduce the above copyright notice, this */
/* list of conditions and the following disclaimer in the documentation and/or */
/* other materials provided with the distribution. */
/* */
/* o Neither the name of NXP Semiconductors, Inc. nor the names of its */
/* contributors may be used to endorse or promote products derived from this */
/* software without specific prior written permission. */
/* */
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND */
/* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */
/* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */
/* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR */
/* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */
/* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */
/* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */
/* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
/* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
/*****************************************************************************/
/* Version: GCC for ARM Embedded Processors */
/*****************************************************************************/
.syntax unified
.arch armv7-m
.section .isr_vector, "a"
.align 2
.globl __Vectors
__Vectors:
.long __StackTop /* Top of Stack */
.long Reset_Handler /* Reset Handler */
.long NMI_Handler /* NMI Handler*/
.long HardFault_Handler /* Hard Fault Handler*/
.long MemManage_Handler /* MPU Fault Handler*/
.long BusFault_Handler /* Bus Fault Handler*/
.long UsageFault_Handler /* Usage Fault Handler*/
.long 0 /* Reserved*/
.long 0 /* Reserved*/
.long 0 /* Reserved*/
.long 0 /* Reserved*/
.long SVC_Handler /* SVCall Handler*/
.long DebugMon_Handler /* Debug Monitor Handler*/
.long 0 /* Reserved*/
.long PendSV_Handler /* PendSV Handler*/
.long SysTick_Handler /* SysTick Handler*/
/* External Interrupts*/
.long WDT_BOD_IRQHandler /* Watchdog Timer, Brownout detect */
.long DMA0_IRQHandler /* DMA controller interrupt */
.long GINT0_IRQHandler /* GPIO group 0 */
.long GINT1_IRQHandler /* GPIO group 1 */
.long PIN_INT0_IRQHandler /* Pin interrupt 0 or pattern match engine slice 0 */
.long PIN_INT1_IRQHandler /* Pin interrupt 1 or pattern match engine slice 1 */
.long PIN_INT2_IRQHandler /* Pin interrupt 2 or pattern match engine slice 2 */
.long PIN_INT3_IRQHandler /* Pin interrupt 3 or pattern match engine slice 3 */
.long UTICK0_IRQHandler /* Micro-tick Timer */
.long MRT0_IRQHandler /* Multi-rate timer */
.long CTIMER0_IRQHandler /* Standard counter/timer CTIMER0 */
.long CTIMER1_IRQHandler /* Standard counter/timer CTIMER1 */
.long SCT0_IRQHandler /* SCTimer/PWM */
.long CTIMER3_IRQHandler /* Standard counter/timer CTIMER3 */
.long FLEXCOMM0_IRQHandler /* Flexcomm Interface 0 (USART, SPI, I2C, FLEXCOMM) */
.long FLEXCOMM1_IRQHandler /* Flexcomm Interface 1 (USART, SPI, I2C, FLEXCOMM) */
.long FLEXCOMM2_IRQHandler /* Flexcomm Interface 2 (USART, SPI, I2C, FLEXCOMM) */
.long FLEXCOMM3_IRQHandler /* Flexcomm Interface 3 (USART, SPI, I2C, FLEXCOMM) */
.long FLEXCOMM4_IRQHandler /* Flexcomm Interface 4 (USART, SPI, I2C, FLEXCOMM) */
.long FLEXCOMM5_IRQHandler /* Flexcomm Interface 5 (USART, SPI, I2C, FLEXCOMM) */
.long FLEXCOMM6_IRQHandler /* Flexcomm Interface 6 (USART, SPI, I2C, FLEXCOMM) */
.long FLEXCOMM7_IRQHandler /* Flexcomm Interface 7 (USART, SPI, I2C, FLEXCOMM) */
.long ADC0_SEQA_IRQHandler /* ADC0 sequence A completion */
.long ADC0_SEQB_IRQHandler /* ADC0 sequence B completion */
.long ADC0_THCMP_IRQHandler /* ADC0 threshold compare and error. */
.long DMIC0_IRQHandler /* RTC alarm and wake-up interrupts */
.long HWVAD0_IRQHandler /* Hardware Voice Activity Detector */
.long USB0_NEEDCLK_IRQHandler /* USB Activity Wake-up Interrupt */
.long USB0_IRQHandler /* USB device */
.long RTC_IRQHandler /* RTC alarm and wake-up interrupts */
.long IOH_IRQHandler /* IOH interrupt */
.long MAILBOX_IRQHandler /* Mailbox interrupt */
.long PIN_INT4_IRQHandler /* Pin interrupt 4 or pattern match engine slice 4 int */
.long PIN_INT5_IRQHandler /* Pin interrupt 5 or pattern match engine slice 5 int */
.long PIN_INT6_IRQHandler /* Pin interrupt 6 or pattern match engine slice 6 int */
.long PIN_INT7_IRQHandler /* Pin interrupt 7 or pattern match engine slice 7 int */
.long CTIMER2_IRQHandler /* Standard counter/timer CTIMER2 */
.long CTIMER4_IRQHandler /* Standard counter/timer CTIMER4 */
.long 0 /* Reserved interrupt */
.long SPIFI0_IRQHandler /* SPI flash interface */
.size __Vectors, . - __Vectors
.text
.thumb
#ifndef SLAVEBOOT
rel_vals:
.long 0xE000ED00 /* cpu_id */
.long 0x40000800 /* cpu_ctrl */
.long 0x40000804 /* coproc_boot */
.long 0x40000808 /* coproc_stack */
.short 0x0FFF
.short 0x0C24
#endif
/* Reset Handler */
.thumb_func
.align 2
.globl Reset_Handler
.weak Reset_Handler
.type Reset_Handler, %function
Reset_Handler:
#ifndef SLAVEBOOT
/* Both the M0+ and M4 core come via this shared startup code,
* but the M0+ and M4 core have different vector tables.
* Determine if the core executing this code is the master or
* the slave and handle each core state individually. */
shared_boot_entry:
ldr r6, =rel_vals
/* Flag for slave core (0) */
movs r4, 0
movs r5, 1
/* Determine which core (M0+ or M4) this code is running on */
/* r2 = (((*cpu_id) >> 4) & 0xFFF); (M4 core == 0xC24) */
get_current_core_id:
ldr r0, [r6, #0]
ldr r1, [r0] /* r1 = CPU ID status */
lsrs r1, r1, #4 /* Right justify 12 CPU ID bits */
ldrh r2, [r6, #16] /* Mask for CPU ID bits */
ands r2, r1, r2 /* r2 = ARM COrtex CPU ID */
ldrh r3, [r6, #18] /* Mask for CPU ID bits */
cmp r3, r2 /* Core ID matches M4 identifier */
bne get_master_status
mov r4, r5 /* Set flag for master core (1) */
/* Determine if M4 core is the master or slave */
/* r3 = ((*cpu_ctrl) & 1); (0 == m0+, 1 == M4) */
get_master_status:
ldr r0, [r6, #4]
ldr r3, [r0] /* r3 = SYSCON co-processor CPU control status */
ands r3, r3, r5 /* r3 = (Bit 0: 1 = M4 is master, 0 = M4 is slave) */
/* Select boot based on selected master core and core ID */
select_boot:
eors r3, r3, r4 /* r4 = (Bit 0: 0 = master, 1 = slave) */
bne slave_boot
b normal_boot
/* Slave boot */
slave_boot:
ldr r0, [r6, #8]
ldr r2, [r0] /* r1 = SYSCON co-processor boot address */
cmp r2, #0 /* Slave boot address = 0 (not set up)? */
beq cpu_sleep
ldr r0, [r6, #12]
ldr r1, [r0] /* r5 = SYSCON co-processor stack address */
mov sp, r1 /* Update slave CPU stack pointer */
/* Be sure to update VTOR for the slave MCU to point to the */
/* slave vector table in boot memory */
bx r2 /* Jump to slave boot address */
/* Slave isn't yet setup for system boot from the master */
/* so sleep until the master sets it up and then reboots it */
cpu_sleep:
mov sp, r5 /* Will force exception if something happens */
cpu_sleep_wfi:
wfi /* Sleep forever until master reboots */
b cpu_sleep_wfi
#endif /* defined(SLAVEBOOT) */
#ifndef __START
#define __START _start
#endif
#ifndef __ATOLLIC__
normal_boot:
#ifndef __NO_SYSTEM_INIT
ldr r0,=SystemInit
blx r0
#endif
/* Loop to copy data from read only memory to RAM. The ranges
* of copy from/to are specified by following symbols evaluated in
* linker script.
* __etext: End of code section, i.e., begin of data sections to copy from.
* __data_start__/__data_end__: RAM address range that data should be
* copied to. Both must be aligned to 4 bytes boundary. */
ldr r1, =__etext
ldr r2, =__data_start__
ldr r3, =__data_end__
#if 1
/* Here are two copies of loop implemenations. First one favors code size
* and the second one favors performance. Default uses the first one.
* Change to "#if 0" to use the second one */
.LC0:
cmp r2, r3
ittt lt
ldrlt r0, [r1], #4
strlt r0, [r2], #4
blt .LC0
#else
subs r3, r2
ble .LC1
.LC0:
subs r3, #4
ldr r0, [r1, r3]
str r0, [r2, r3]
bgt .LC0
.LC1:
#endif
#ifdef __STARTUP_CLEAR_BSS
/* This part of work usually is done in C library startup code. Otherwise,
* define this macro to enable it in this startup.
*
* Loop to zero out BSS section, which uses following symbols
* in linker script:
* __bss_start__: start of BSS section. Must align to 4
* __bss_end__: end of BSS section. Must align to 4
*/
ldr r1, =__bss_start__
ldr r2, =__bss_end__
movs r0, 0
.LC2:
cmp r1, r2
itt lt
strlt r0, [r1], #4
blt .LC2
#endif /* __STARTUP_CLEAR_BSS */
ldr r0,=__START
blx r0
#else
ldr r0,=__libc_init_array
blx r0
ldr r0,=main
bx r0
#endif
.pool
.size Reset_Handler, . - Reset_Handler
.align 1
.thumb_func
.weak DefaultISR
.type DefaultISR, %function
DefaultISR:
b DefaultISR
.size DefaultISR, . - DefaultISR
.align 1
.thumb_func
.weak NMI_Handler
.type NMI_Handler, %function
NMI_Handler:
ldr r0,=NMI_Handler
bx r0
.size NMI_Handler, . - NMI_Handler
.align 1
.thumb_func
.weak HardFault_Handler
.type HardFault_Handler, %function
HardFault_Handler:
ldr r0,=HardFault_Handler
bx r0
.size HardFault_Handler, . - HardFault_Handler
.align 1
.thumb_func
.weak MemManage_Handler
.type MemManage_Handler, %function
MemManage_Handler:
ldr r0,=MemManage_Handler
bx r0
.size MemManage_Handler, . - MemManage_Handler
.align 1
.thumb_func
.weak BusFault_Handler
.type BusFault_Handler, %function
BusFault_Handler:
ldr r0,=BusFault_Handler
bx r0
.size BusFault_Handler, . - BusFault_Handler
.align 1
.thumb_func
.weak UsageFault_Handler
.type UsageFault_Handler, %function
UsageFault_Handler:
ldr r0,=UsageFault_Handler
bx r0
.size UsageFault_Handler, . - UsageFault_Handler
.align 1
.thumb_func
.weak SVC_Handler
.type SVC_Handler, %function
SVC_Handler:
ldr r0,=SVC_Handler
bx r0
.size SVC_Handler, . - SVC_Handler
.align 1
.thumb_func
.weak DebugMon_Handler
.type DebugMon_Handler, %function
DebugMon_Handler:
ldr r0,=DebugMon_Handler
bx r0
.size DebugMon_Handler, . - DebugMon_Handler
.align 1
.thumb_func
.weak PendSV_Handler
.type PendSV_Handler, %function
PendSV_Handler:
ldr r0,=PendSV_Handler
bx r0
.size PendSV_Handler, . - PendSV_Handler
.align 1
.thumb_func
.weak SysTick_Handler
.type SysTick_Handler, %function
SysTick_Handler:
ldr r0,=SysTick_Handler
bx r0
.size SysTick_Handler, . - SysTick_Handler
.align 1
.thumb_func
.weak WDT_BOD_IRQHandler
.type WDT_BOD_IRQHandler, %function
WDT_BOD_IRQHandler:
ldr r0,=WDT_BOD_DriverIRQHandler
bx r0
.size WDT_BOD_IRQHandler, . - WDT_BOD_IRQHandler
.align 1
.thumb_func
.weak DMA0_IRQHandler
.type DMA0_IRQHandler, %function
DMA0_IRQHandler:
ldr r0,=DMA0_DriverIRQHandler
bx r0
.size DMA0_IRQHandler, . - DMA0_IRQHandler
.align 1
.thumb_func
.weak GINT0_IRQHandler
.type GINT0_IRQHandler, %function
GINT0_IRQHandler:
ldr r0,=GINT0_DriverIRQHandler
bx r0
.size GINT0_IRQHandler, . - GINT0_IRQHandler
.align 1
.thumb_func
.weak GINT1_IRQHandler
.type GINT1_IRQHandler, %function
GINT1_IRQHandler:
ldr r0,=GINT1_DriverIRQHandler
bx r0
.size GINT1_IRQHandler, . - GINT1_IRQHandler
.align 1
.thumb_func
.weak PIN_INT0_IRQHandler
.type PIN_INT0_IRQHandler, %function
PIN_INT0_IRQHandler:
ldr r0,=PIN_INT0_DriverIRQHandler
bx r0
.size PIN_INT0_IRQHandler, . - PIN_INT0_IRQHandler
.align 1
.thumb_func
.weak PIN_INT1_IRQHandler
.type PIN_INT1_IRQHandler, %function
PIN_INT1_IRQHandler:
ldr r0,=PIN_INT1_DriverIRQHandler
bx r0
.size PIN_INT1_IRQHandler, . - PIN_INT1_IRQHandler
.align 1
.thumb_func
.weak PIN_INT2_IRQHandler
.type PIN_INT2_IRQHandler, %function
PIN_INT2_IRQHandler:
ldr r0,=PIN_INT2_DriverIRQHandler
bx r0
.size PIN_INT2_IRQHandler, . - PIN_INT2_IRQHandler
.align 1
.thumb_func
.weak PIN_INT3_IRQHandler
.type PIN_INT3_IRQHandler, %function
PIN_INT3_IRQHandler:
ldr r0,=PIN_INT3_DriverIRQHandler
bx r0
.size PIN_INT3_IRQHandler, . - PIN_INT3_IRQHandler
.align 1
.thumb_func
.weak UTICK0_IRQHandler
.type UTICK0_IRQHandler, %function
UTICK0_IRQHandler:
ldr r0,=UTICK0_DriverIRQHandler
bx r0
.size UTICK0_IRQHandler, . - UTICK0_IRQHandler
.align 1
.thumb_func
.weak MRT0_IRQHandler
.type MRT0_IRQHandler, %function
MRT0_IRQHandler:
ldr r0,=MRT0_DriverIRQHandler
bx r0
.size MRT0_IRQHandler, . - MRT0_IRQHandler
.align 1
.thumb_func
.weak CTIMER0_IRQHandler
.type CTIMER0_IRQHandler, %function
CTIMER0_IRQHandler:
ldr r0,=CTIMER0_DriverIRQHandler
bx r0
.size CTIMER0_IRQHandler, . - CTIMER0_IRQHandler
.align 1
.thumb_func
.weak CTIMER1_IRQHandler
.type CTIMER1_IRQHandler, %function
CTIMER1_IRQHandler:
ldr r0,=CTIMER1_DriverIRQHandler
bx r0
.size CTIMER1_IRQHandler, . - CTIMER1_IRQHandler
.align 1
.thumb_func
.weak SCT0_IRQHandler
.type SCT0_IRQHandler, %function
SCT0_IRQHandler:
ldr r0,=SCT0_DriverIRQHandler
bx r0
.size SCT0_IRQHandler, . - SCT0_IRQHandler
.align 1
.thumb_func
.weak CTIMER3_IRQHandler
.type CTIMER3_IRQHandler, %function
CTIMER3_IRQHandler:
ldr r0,=CTIMER3_DriverIRQHandler
bx r0
.size CTIMER3_IRQHandler, . - CTIMER3_IRQHandler
.align 1
.thumb_func
.weak FLEXCOMM0_IRQHandler
.type FLEXCOMM0_IRQHandler, %function
FLEXCOMM0_IRQHandler:
ldr r0,=FLEXCOMM0_DriverIRQHandler
bx r0
.size FLEXCOMM0_IRQHandler, . - FLEXCOMM0_IRQHandler
.align 1
.thumb_func
.weak FLEXCOMM1_IRQHandler
.type FLEXCOMM1_IRQHandler, %function
FLEXCOMM1_IRQHandler:
ldr r0,=FLEXCOMM1_DriverIRQHandler
bx r0
.size FLEXCOMM1_IRQHandler, . - FLEXCOMM1_IRQHandler
.align 1
.thumb_func
.weak FLEXCOMM2_IRQHandler
.type FLEXCOMM2_IRQHandler, %function
FLEXCOMM2_IRQHandler:
ldr r0,=FLEXCOMM2_DriverIRQHandler
bx r0
.size FLEXCOMM2_IRQHandler, . - FLEXCOMM2_IRQHandler
.align 1
.thumb_func
.weak FLEXCOMM3_IRQHandler
.type FLEXCOMM3_IRQHandler, %function
FLEXCOMM3_IRQHandler:
ldr r0,=FLEXCOMM3_DriverIRQHandler
bx r0
.size FLEXCOMM3_IRQHandler, . - FLEXCOMM3_IRQHandler
.align 1
.thumb_func
.weak FLEXCOMM4_IRQHandler
.type FLEXCOMM4_IRQHandler, %function
FLEXCOMM4_IRQHandler:
ldr r0,=FLEXCOMM4_DriverIRQHandler
bx r0
.size FLEXCOMM4_IRQHandler, . - FLEXCOMM4_IRQHandler
.align 1
.thumb_func
.weak FLEXCOMM5_IRQHandler
.type FLEXCOMM5_IRQHandler, %function
FLEXCOMM5_IRQHandler:
ldr r0,=FLEXCOMM5_DriverIRQHandler
bx r0
.size FLEXCOMM5_IRQHandler, . - FLEXCOMM5_IRQHandler
.align 1
.thumb_func
.weak FLEXCOMM6_IRQHandler
.type FLEXCOMM6_IRQHandler, %function
FLEXCOMM6_IRQHandler:
ldr r0,=FLEXCOMM6_DriverIRQHandler
bx r0
.size FLEXCOMM6_IRQHandler, . - FLEXCOMM6_IRQHandler
.align 1
.thumb_func
.weak FLEXCOMM7_IRQHandler
.type FLEXCOMM7_IRQHandler, %function
FLEXCOMM7_IRQHandler:
ldr r0,=FLEXCOMM7_DriverIRQHandler
bx r0
.size FLEXCOMM7_IRQHandler, . - FLEXCOMM7_IRQHandler
.align 1
.thumb_func
.weak ADC0_SEQA_IRQHandler
.type ADC0_SEQA_IRQHandler, %function
ADC0_SEQA_IRQHandler:
ldr r0,=ADC0_SEQA_DriverIRQHandler
bx r0
.size ADC0_SEQA_IRQHandler, . - ADC0_SEQA_IRQHandler
.align 1
.thumb_func
.weak ADC0_SEQB_IRQHandler
.type ADC0_SEQB_IRQHandler, %function
ADC0_SEQB_IRQHandler:
ldr r0,=ADC0_SEQB_DriverIRQHandler
bx r0
.size ADC0_SEQB_IRQHandler, . - ADC0_SEQB_IRQHandler
.align 1
.thumb_func
.weak ADC0_THCMP_IRQHandler
.type ADC0_THCMP_IRQHandler, %function
ADC0_THCMP_IRQHandler:
ldr r0,=ADC0_THCMP_DriverIRQHandler
bx r0
.size ADC0_THCMP_IRQHandler, . - ADC0_THCMP_IRQHandler
.align 1
.thumb_func
.weak DMIC0_IRQHandler
.type DMIC0_IRQHandler, %function
DMIC0_IRQHandler:
ldr r0,=DMIC0_DriverIRQHandler
bx r0
.size DMIC0_IRQHandler, . - DMIC0_IRQHandler
.align 1
.thumb_func
.weak HWVAD0_IRQHandler
.type HWVAD0_IRQHandler, %function
HWVAD0_IRQHandler:
ldr r0,=HWVAD0_DriverIRQHandler
bx r0
.size HWVAD0_IRQHandler, . - HWVAD0_IRQHandler
.align 1
.thumb_func
.weak USB0_NEEDCLK_IRQHandler
.type USB0_NEEDCLK_IRQHandler, %function
USB0_NEEDCLK_IRQHandler:
ldr r0,=USB0_NEEDCLK_DriverIRQHandler
bx r0
.size USB0_NEEDCLK_IRQHandler, . - USB0_NEEDCLK_IRQHandler
.align 1
.thumb_func
.weak USB0_IRQHandler
.type USB0_IRQHandler, %function
USB0_IRQHandler:
ldr r0,=USB0_DriverIRQHandler
bx r0
.size USB0_IRQHandler, . - USB0_IRQHandler
.align 1
.thumb_func
.weak RTC_IRQHandler
.type RTC_IRQHandler, %function
RTC_IRQHandler:
ldr r0,=RTC_DriverIRQHandler
bx r0
.size RTC_IRQHandler, . - RTC_IRQHandler
.align 1
.thumb_func
.weak IOH_IRQHandler
.type IOH_IRQHandler, %function
IOH_IRQHandler:
ldr r0,=IOH_DriverIRQHandler
bx r0
.size IOH_IRQHandler, . - IOH_IRQHandler
.align 1
.thumb_func
.weak MAILBOX_IRQHandler
.type MAILBOX_IRQHandler, %function
MAILBOX_IRQHandler:
ldr r0,=MAILBOX_DriverIRQHandler
bx r0
.size MAILBOX_IRQHandler, . - MAILBOX_IRQHandler
.align 1
.thumb_func
.weak PIN_INT4_IRQHandler
.type PIN_INT4_IRQHandler, %function
PIN_INT4_IRQHandler:
ldr r0,=PIN_INT4_DriverIRQHandler
bx r0
.size PIN_INT4_IRQHandler, . - PIN_INT4_IRQHandler
.align 1
.thumb_func
.weak PIN_INT5_IRQHandler
.type PIN_INT5_IRQHandler, %function
PIN_INT5_IRQHandler:
ldr r0,=PIN_INT5_DriverIRQHandler
bx r0
.size PIN_INT5_IRQHandler, . - PIN_INT5_IRQHandler
.align 1
.thumb_func
.weak PIN_INT6_IRQHandler
.type PIN_INT6_IRQHandler, %function
PIN_INT6_IRQHandler:
ldr r0,=PIN_INT6_DriverIRQHandler
bx r0
.size PIN_INT6_IRQHandler, . - PIN_INT6_IRQHandler
.align 1
.thumb_func
.weak PIN_INT7_IRQHandler
.type PIN_INT7_IRQHandler, %function
PIN_INT7_IRQHandler:
ldr r0,=PIN_INT7_DriverIRQHandler
bx r0
.size PIN_INT7_IRQHandler, . - PIN_INT7_IRQHandler
.align 1
.thumb_func
.weak CTIMER2_IRQHandler
.type CTIMER2_IRQHandler, %function
CTIMER2_IRQHandler:
ldr r0,=CTIMER2_DriverIRQHandler
bx r0
.size CTIMER2_IRQHandler, . - CTIMER2_IRQHandler
.align 1
.thumb_func
.weak CTIMER4_IRQHandler
.type CTIMER4_IRQHandler, %function
CTIMER4_IRQHandler:
ldr r0,=CTIMER4_DriverIRQHandler
bx r0
.size CTIMER4_IRQHandler, . - CTIMER4_IRQHandler
.align 1
.thumb_func
.weak SPIFI0_IRQHandler
.type SPIFI0_IRQHandler, %function
SPIFI0_IRQHandler:
ldr r0,=SPIFI0_DriverIRQHandler
bx r0
.size SPIFI0_IRQHandler, . - SPIFI0_IRQHandler
/* Macro to define default handlers. Default handler
* will be weak symbol and just dead loops. They can be
* overwritten by other handlers */
.macro def_irq_handler handler_name
.weak \handler_name
.set \handler_name, DefaultISR
.endm
/* Exception Handlers */
def_irq_handler WDT_BOD_DriverIRQHandler /* Windowed watchdog timer, Brownout detect */
def_irq_handler DMA0_DriverIRQHandler /* DMA controller */
def_irq_handler GINT0_DriverIRQHandler /* GPIO group 0 */
def_irq_handler GINT1_DriverIRQHandler /* GPIO group 1 */
def_irq_handler PIN_INT0_DriverIRQHandler /* Pin interrupt 0 or pattern match engine slice 0 */
def_irq_handler PIN_INT1_DriverIRQHandler /* Pin interrupt 1or pattern match engine slice 1 */
def_irq_handler PIN_INT2_DriverIRQHandler /* Pin interrupt 2 or pattern match engine slice 2 */
def_irq_handler PIN_INT3_DriverIRQHandler /* Pin interrupt 3 or pattern match engine slice 3 */
def_irq_handler UTICK0_DriverIRQHandler /* Micro-tick Timer */
def_irq_handler MRT0_DriverIRQHandler /* Multi-rate timer */
def_irq_handler CTIMER0_DriverIRQHandler /* Standard counter/timer CTIMER0 */
def_irq_handler CTIMER1_DriverIRQHandler /* Standard counter/timer CTIMER1 */
def_irq_handler SCT0_DriverIRQHandler /* SCTimer/PWM */
def_irq_handler CTIMER3_DriverIRQHandler /* Standard counter/timer CTIMER3 */
def_irq_handler FLEXCOMM0_DriverIRQHandler /* Flexcomm Interface 0 (USART, SPI, I2C) */
def_irq_handler FLEXCOMM1_DriverIRQHandler /* Flexcomm Interface 1 (USART, SPI, I2C) */
def_irq_handler FLEXCOMM2_DriverIRQHandler /* Flexcomm Interface 2 (USART, SPI, I2C) */
def_irq_handler FLEXCOMM3_DriverIRQHandler /* Flexcomm Interface 3 (USART, SPI, I2C) */
def_irq_handler FLEXCOMM4_DriverIRQHandler /* Flexcomm Interface 4 (USART, SPI, I2C) */
def_irq_handler FLEXCOMM5_DriverIRQHandler /* Flexcomm Interface 5 (USART, SPI, I2C) */
def_irq_handler FLEXCOMM6_DriverIRQHandler /* Flexcomm Interface 6 (USART, SPI, I2C, I2S) */
def_irq_handler FLEXCOMM7_DriverIRQHandler /* Flexcomm Interface 7 (USART, SPI, I2C, I2S) */
def_irq_handler ADC0_SEQA_DriverIRQHandler /* ADC0 sequence A completion. */
def_irq_handler ADC0_SEQB_DriverIRQHandler /* ADC0 sequence B completion. */
def_irq_handler ADC0_THCMP_DriverIRQHandler /* ADC0 threshold compare and error. */
def_irq_handler DMIC0_DriverIRQHandler /* Digital microphone and DMIC subsystem */
def_irq_handler HWVAD0_DriverIRQHandler /* Hardware Voice Activity Detector */
def_irq_handler USB0_NEEDCLK_DriverIRQHandler /* USB Activity Wake-up Interrupt */
def_irq_handler USB0_DriverIRQHandler /* USB device */
def_irq_handler RTC_DriverIRQHandler /* RTC alarm and wake-up interrupts */
def_irq_handler IOH_DriverIRQHandler /* IOH */
def_irq_handler MAILBOX_DriverIRQHandler /* Mailbox interrupt (present on selected devices) */
def_irq_handler PIN_INT4_DriverIRQHandler /* Pin interrupt 4 or pattern match engine slice 4 int */
def_irq_handler PIN_INT5_DriverIRQHandler /* Pin interrupt 5 or pattern match engine slice 5 int */
def_irq_handler PIN_INT6_DriverIRQHandler /* Pin interrupt 6 or pattern match engine slice 6 int */
def_irq_handler PIN_INT7_DriverIRQHandler /* Pin interrupt 7 or pattern match engine slice 7 int */
def_irq_handler CTIMER2_DriverIRQHandler /* Standard counter/timer CTIMER2 */
def_irq_handler CTIMER4_DriverIRQHandler /* Standard counter/timer CTIMER4 */
def_irq_handler SPIFI0_DriverIRQHandler /* SPI flash interface */
.end

View File

@ -0,0 +1,142 @@
/*
** ###################################################################
** Processors: LPC54114J256BD64_M4
** LPC54114J256UK49_M4
**
** Compiler: IAR ANSI C/C++ Compiler for ARM
** Reference manual: LPC5411x User manual Rev. 1.1 25 May 2016
** Version: rev. 1.0, 2016-04-29
** Build: b161227
**
** Abstract:
** Linker file for the IAR ANSI C/C++ Compiler for ARM
**
** Copyright (c) 2016 Freescale Semiconductor, Inc.
** Copyright 2016 - 2017 NXP
** Redistribution and use in source and binary forms, with or without modification,
** are permitted provided that the following conditions are met:
**
** o Redistributions of source code must retain the above copyright notice, this list
** of conditions and the following disclaimer.
**
** o Redistributions in binary form must reproduce the above copyright notice, this
** list of conditions and the following disclaimer in the documentation and/or
** other materials provided with the distribution.
**
** o Neither the name of the copyright holder nor the names of its
** contributors may be used to endorse or promote products derived from this
** software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
** ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
** ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
** http: www.nxp.com
** mail: support@nxp.com
**
** ###################################################################
*/
define symbol __ram_vector_table__ = 1;
/* Heap 1/4 of ram and stack 1/8 */
define symbol __stack_size__=0x2000;
define symbol __heap_size__=0x4000;
define symbol __ram_vector_table_size__ = isdefinedsymbol(__ram_vector_table__) ? 0x000000E0 : 0;
define symbol __ram_vector_table_offset__ = isdefinedsymbol(__ram_vector_table__) ? 0x000000DF : 0;
define symbol m_interrupts_start = 0x00000000;
define symbol m_interrupts_end = 0x000000DF;
define symbol m_text_start = 0x000000E0;
define symbol m_text_end = 0x0002FFFF;
define symbol m_interrupts_ram_start = 0x20000000;
define symbol m_interrupts_ram_end = 0x20000000 + __ram_vector_table_offset__;
define symbol m_data_start = m_interrupts_ram_start + __ram_vector_table_size__;
define symbol m_data_end = 0x2000FFFF;
define exported symbol rpmsg_sh_mem_start = 0x20026800;
define exported symbol rpmsg_sh_mem_end = 0x20027FFF;
define symbol m_sramx_start = 0x04000000;
define symbol m_sramx_end = 0x04007FFF;
define exported symbol core1_image_start = 0x00030000;
define exported symbol core1_image_end = 0x0003FFFF;
define symbol __crp_start__ = 0x000002FC;
define symbol __crp_end__ = 0x000002FF;
define symbol __ram_iap_start__ = 0x2000FFE0;
define symbol __ram_iap_end__ = 0x2000FFFF;
/* Sizes */
if (isdefinedsymbol(__stack_size__)) {
define symbol __size_cstack__ = __stack_size__;
} else {
define symbol __size_cstack__ = 0x0400;
}
if (isdefinedsymbol(__heap_size__)) {
define symbol __size_heap__ = __heap_size__;
} else {
define symbol __size_heap__ = 0x0800;
}
define exported symbol __VECTOR_TABLE = m_interrupts_start;
define exported symbol __VECTOR_RAM = isdefinedsymbol(__ram_vector_table__) ? m_interrupts_ram_start : m_interrupts_start;
define exported symbol __RAM_VECTOR_TABLE_SIZE = __ram_vector_table_size__;
define memory mem with size = 4G;
define region TEXT_region = mem:[from m_interrupts_start to m_interrupts_end]
| mem:[from m_text_start to m_text_end]
- mem:[from __crp_start__ to __crp_end__];
define region DATA_region = mem:[from m_data_start to m_data_end]
- mem:[from __ram_iap_start__-__size_cstack__ to __ram_iap_end__];
define region CSTACK_region = mem:[from __ram_iap_start__-__size_cstack__ to __ram_iap_start__-1];
define region SRAMX_region = mem:[from m_sramx_start to m_sramx_end];
define region CRP_region = mem:[from __crp_start__ to __crp_end__];
define region m_interrupts_ram_region = mem:[from m_interrupts_ram_start to m_interrupts_ram_end];
define region rpmsg_sh_mem_region = mem:[from rpmsg_sh_mem_start to rpmsg_sh_mem_end];
define block CSTACK with alignment = 8, size = __size_cstack__ { };
define block HEAP with alignment = 8, size = __size_heap__ { };
define block RW { readwrite };
define block ZI { zi };
define region core1_region = mem:[from core1_image_start to core1_image_end];
define block SEC_CORE_IMAGE_WBLOCK { section __sec_core };
initialize by copy { readwrite };
if (isdefinedsymbol(__USE_DLIB_PERTHREAD))
{
// Required in a multi-threaded application
initialize by copy with packing = none { section __DLIB_PERTHREAD };
}
do not initialize { section .noinit };
do not initialize { section rpmsg_sh_mem_section };
place at address mem: m_interrupts_start { readonly section .intvec };
place in TEXT_region { readonly };
place in DATA_region { block RW };
place in DATA_region { block ZI };
place in DATA_region { last block HEAP };
place in SRAMX_region { section sramx };
place in CSTACK_region { block CSTACK };
place in CRP_region { section .crp };
place in m_interrupts_ram_region { section m_interrupts_ram };
place in rpmsg_sh_mem_region { section rpmsg_sh_mem_section };
place in core1_region { block SEC_CORE_IMAGE_WBLOCK };

View File

@ -0,0 +1,567 @@
;/*****************************************************************************
; * @file: startup_LPC54114_cm4.s
; * @purpose: CMSIS Cortex-M4 Core Device Startup File
; * LPC54114_cm4
; * @version: 1.0
; * @date: 2016-4-29
; *----------------------------------------------------------------------------
; *
; * Copyright: 1997 - 2016 Freescale Semiconductor,
; *
; All rights reserved.
;
; Redistribution and use in source and binary forms, with or without modification,
; are permitted provided that the following conditions are met:
;
; o Redistributions of source code must retain the above copyright notice, this list
; of conditions and the following disclaimer.
;
; o Redistributions in binary form must reproduce the above copyright notice, this
; list of conditions and the following disclaimer in the documentation and/or
; other materials provided with the distribution.
;
; o Neither the name of Freescale Semiconductor, Inc. nor the names of its
; contributors may be used to endorse or promote products derived from this
; software without specific prior written permission.
;
; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
; ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
;
; The modules in this file are included in the libraries, and may be replaced
; by any user-defined modules that define the PUBLIC symbol _program_start or
; a user defined start symbol.
; To override the cstartup defined in the library, simply add your modified
; version to the workbench project.
;
; The vector table is normally located at address 0.
; When debugging in RAM, it can be located in RAM, aligned to at least 2^6.
; The name "__vector_table" has special meaning for C-SPY:
; it is where the SP start value is found, and the NVIC vector
; table register (VTOR) is initialized to this address if != 0.
;
; Cortex-M version
;
MODULE ?cstartup
;; Forward declaration of sections.
SECTION CSTACK:DATA:NOROOT(3)
SECTION .intvec:CODE:NOROOT(2)
EXTERN __iar_program_start
EXTERN SystemInit
PUBLIC __vector_table
PUBLIC __vector_table_0x1c
PUBLIC __Vectors
PUBLIC __Vectors_End
PUBLIC __Vectors_Size
DATA
__vector_table
DCD sfe(CSTACK)
DCD Reset_Handler
DCD NMI_Handler
DCD HardFault_Handler
DCD MemManage_Handler
DCD BusFault_Handler
DCD UsageFault_Handler
__vector_table_0x1c
DCD 0
DCD 0
DCD 0
DCD 0
DCD SVC_Handler
DCD DebugMon_Handler
DCD 0
DCD PendSV_Handler
DCD SysTick_Handler
; External Interrupts
DCD WDT_BOD_IRQHandler ; Windowed watchdog timer, Brownout detect
DCD DMA0_IRQHandler ; DMA controller
DCD GINT0_IRQHandler ; GPIO group 0
DCD GINT1_IRQHandler ; GPIO group 1
DCD PIN_INT0_IRQHandler ; Pin interrupt 0 or pattern match engine slice 0
DCD PIN_INT1_IRQHandler ; Pin interrupt 1or pattern match engine slice 1
DCD PIN_INT2_IRQHandler ; Pin interrupt 2 or pattern match engine slice 2
DCD PIN_INT3_IRQHandler ; Pin interrupt 3 or pattern match engine slice 3
DCD UTICK0_IRQHandler ; Micro-tick Timer
DCD MRT0_IRQHandler ; Multi-rate timer
DCD CTIMER0_IRQHandler ; Standard counter/timer CTIMER0
DCD CTIMER1_IRQHandler ; Standard counter/timer CTIMER1
DCD SCT0_IRQHandler ; SCTimer/PWM
DCD CTIMER3_IRQHandler ; Standard counter/timer CTIMER3
DCD FLEXCOMM0_IRQHandler ; Flexcomm Interface 0 (USART, SPI, I2C)
DCD FLEXCOMM1_IRQHandler ; Flexcomm Interface 1 (USART, SPI, I2C)
DCD FLEXCOMM2_IRQHandler ; Flexcomm Interface 2 (USART, SPI, I2C)
DCD FLEXCOMM3_IRQHandler ; Flexcomm Interface 3 (USART, SPI, I2C)
DCD FLEXCOMM4_IRQHandler ; Flexcomm Interface 4 (USART, SPI, I2C)
DCD FLEXCOMM5_IRQHandler ; Flexcomm Interface 5 (USART, SPI, I2C)
DCD FLEXCOMM6_IRQHandler ; Flexcomm Interface 6 (USART, SPI, I2C, I2S)
DCD FLEXCOMM7_IRQHandler ; Flexcomm Interface 7 (USART, SPI, I2C, I2S)
DCD ADC0_SEQA_IRQHandler ; ADC0 sequence A completion.
DCD ADC0_SEQB_IRQHandler ; ADC0 sequence B completion.
DCD ADC0_THCMP_IRQHandler ; ADC0 threshold compare and error.
DCD DMIC0_IRQHandler ; Digital microphone and DMIC subsystem
DCD HWVAD0_IRQHandler ; Hardware Voice Activity Detector
DCD USB0_NEEDCLK_IRQHandler ; USB Activity Wake-up Interrupt
DCD USB0_IRQHandler ; USB device
DCD RTC_IRQHandler ; RTC alarm and wake-up interrupts
DCD IOH_IRQHandler ; IOH
DCD MAILBOX_IRQHandler ; Mailbox interrupt (present on selected devices)
DCD PIN_INT4_IRQHandler ; Pin interrupt 4 or pattern match engine slice 4 int
DCD PIN_INT5_IRQHandler ; Pin interrupt 5 or pattern match engine slice 5 int
DCD PIN_INT6_IRQHandler ; Pin interrupt 6 or pattern match engine slice 6 int
DCD PIN_INT7_IRQHandler ; Pin interrupt 7 or pattern match engine slice 7 int
DCD CTIMER2_IRQHandler ; Standard counter/timer CTIMER2
DCD CTIMER4_IRQHandler ; Standard counter/timer CTIMER4
DCD Reserved54_IRQHandler ; Reserved interrupt
DCD SPIFI0_IRQHandler ; SPI flash interface
__Vectors_End
; Code Read Protection Level (CRP)
; <0xFFFFFFFF=> Disabled
; <0x4E697370=> NO_ISP
; <0x12345678=> CRP1
; <0x87654321=> CRP2
; <0x43218765=> CRP3
#if !defined NO_CRP
SECTION .crp:CODE
__CRP
DCD 0xFFFFFFFF
__CRP_End
#endif
__Vectors EQU __vector_table
__Vectors_Size EQU __Vectors_End - __Vectors
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Default interrupt handlers.
;;
SECTION .intvec:CODE:NOROOT(2)
#if !defined(SLAVEBOOT)
DATA
cpu_id EQU 0xE000ED00 ; CPUID Base Register (System control block register)
cpu_ctrl EQU 0x40000800
coproc_boot EQU 0x40000804
coproc_stack EQU 0x40000808
rel_vals
DC32 cpu_id, cpu_ctrl, coproc_boot, coproc_stack
DC16 0xFFF, 0xC24
#endif
THUMB
PUBWEAK Reset_Handler
SECTION .text:CODE:REORDER:NOROOT(2)
; Reset Handler - shared for both cores
Reset_Handler
#if !defined(SLAVEBOOT)
; Both the M0+ and M4 core come via this shared startup code,
; but the M0+ and M4 core have different vector tables.
; Determine if the core executing this code is the master or
; the slave and handle each core state individually.
shared_boot_entry
LDR r6, =rel_vals
MOVS r4, #0 ; Flag for slave core (0)
MOVS r5, #1
; Determine which core (M0+ or M4) this code is running on
; r2 = (((*cpu_id) >> 4) & 0xFFF); (M4 core == 0xC24)
get_current_core_id
LDR r0, [r6, #0]
LDR r1, [r0] ; r1 = CPU ID status
LSRS r1, r1, #4 ; Right justify 12 CPU ID bits
LDRH r2, [r6, #16] ; Mask for CPU ID bits
ANDS r2, r1, r2 ; r2 = ARM COrtex CPU ID
LDRH r3, [r6, #18] ; Mask for CPU ID bits
CMP r3, r2 ; Core ID matches M4 identifier
BNE get_master_status
MOV r4, r5 ; Set flag for master core (1)
; Determine if M4 core is the master or slave
; r3 = ((*cpu_ctrl) & 1); (0 == m0+, 1 == M4)
get_master_status
LDR r0, [r6, #4]
LDR r3, [r0] ; r3 = SYSCON co-processor CPU control status
ANDS r3, r3, r5 ; r3 = (Bit 0: 1 = M4 is master, 0 = M4 is slave)
; Select boot based on selected master core and core ID
select_boot
EORS r3, r3, r4 ; r4 = (Bit 0: 0 = master, 1 = slave)
BNE slave_boot
B normal_boot
; Slave boot
slave_boot
LDR r0, [r6, #8]
LDR r2, [r0] ; r1 = SYSCON co-processor boot address
CMP r2, #0 ; Slave boot address = 0 (not set up)?
BEQ cpu_sleep
LDR r0, [r6, #12]
LDR r1, [r0] ; r5 = SYSCON co-processor stack address
MOV sp, r1 ; Update slave CPU stack pointer
; Be sure to update VTOR for the slave MCU to point to the
; slave vector table in boot memory
BX r2 ; Jump to slave boot address
; Slave isn't yet setup for system boot from the master
; so sleep until the master sets it up and then reboots it
cpu_sleep
MOV sp, r5 ; Will force exception if something happens
cpu_sleep_wfi
WFI ; Sleep forever until master reboots
B cpu_sleep_wfi
#endif ; defined(SLAVEBOOT)
; Normal boot for master/slave
normal_boot
LDR r0, =SystemInit
BLX r0
LDR r0, =__iar_program_start
BX r0
PUBWEAK NMI_Handler
SECTION .text:CODE:REORDER:NOROOT(1)
NMI_Handler
B .
PUBWEAK HardFault_Handler
SECTION .text:CODE:REORDER:NOROOT(1)
HardFault_Handler
B .
PUBWEAK MemManage_Handler
SECTION .text:CODE:REORDER:NOROOT(1)
MemManage_Handler
B .
PUBWEAK BusFault_Handler
SECTION .text:CODE:REORDER:NOROOT(1)
BusFault_Handler
B .
PUBWEAK UsageFault_Handler
SECTION .text:CODE:REORDER:NOROOT(1)
UsageFault_Handler
B .
PUBWEAK SVC_Handler
SECTION .text:CODE:REORDER:NOROOT(1)
SVC_Handler
B .
PUBWEAK DebugMon_Handler
SECTION .text:CODE:REORDER:NOROOT(1)
DebugMon_Handler
B .
PUBWEAK PendSV_Handler
SECTION .text:CODE:REORDER:NOROOT(1)
PendSV_Handler
B .
PUBWEAK SysTick_Handler
SECTION .text:CODE:REORDER:NOROOT(1)
SysTick_Handler
B .
PUBWEAK WDT_BOD_IRQHandler
PUBWEAK WDT_BOD_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
WDT_BOD_IRQHandler
LDR R0, =WDT_BOD_DriverIRQHandler
BX R0
PUBWEAK DMA0_IRQHandler
PUBWEAK DMA0_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
DMA0_IRQHandler
LDR R0, =DMA0_DriverIRQHandler
BX R0
PUBWEAK GINT0_IRQHandler
PUBWEAK GINT0_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
GINT0_IRQHandler
LDR R0, =GINT0_DriverIRQHandler
BX R0
PUBWEAK GINT1_IRQHandler
PUBWEAK GINT1_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
GINT1_IRQHandler
LDR R0, =GINT1_DriverIRQHandler
BX R0
PUBWEAK PIN_INT0_IRQHandler
PUBWEAK PIN_INT0_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
PIN_INT0_IRQHandler
LDR R0, =PIN_INT0_DriverIRQHandler
BX R0
PUBWEAK PIN_INT1_IRQHandler
PUBWEAK PIN_INT1_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
PIN_INT1_IRQHandler
LDR R0, =PIN_INT1_DriverIRQHandler
BX R0
PUBWEAK PIN_INT2_IRQHandler
PUBWEAK PIN_INT2_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
PIN_INT2_IRQHandler
LDR R0, =PIN_INT2_DriverIRQHandler
BX R0
PUBWEAK PIN_INT3_IRQHandler
PUBWEAK PIN_INT3_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
PIN_INT3_IRQHandler
LDR R0, =PIN_INT3_DriverIRQHandler
BX R0
PUBWEAK UTICK0_IRQHandler
PUBWEAK UTICK0_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
UTICK0_IRQHandler
LDR R0, =UTICK0_DriverIRQHandler
BX R0
PUBWEAK MRT0_IRQHandler
PUBWEAK MRT0_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
MRT0_IRQHandler
LDR R0, =MRT0_DriverIRQHandler
BX R0
PUBWEAK CTIMER0_IRQHandler
PUBWEAK CTIMER0_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
CTIMER0_IRQHandler
LDR R0, =CTIMER0_DriverIRQHandler
BX R0
PUBWEAK CTIMER1_IRQHandler
PUBWEAK CTIMER1_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
CTIMER1_IRQHandler
LDR R0, =CTIMER1_DriverIRQHandler
BX R0
PUBWEAK SCT0_IRQHandler
PUBWEAK SCT0_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
SCT0_IRQHandler
LDR R0, =SCT0_DriverIRQHandler
BX R0
PUBWEAK CTIMER3_IRQHandler
PUBWEAK CTIMER3_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
CTIMER3_IRQHandler
LDR R0, =CTIMER3_DriverIRQHandler
BX R0
PUBWEAK FLEXCOMM0_IRQHandler
PUBWEAK FLEXCOMM0_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
FLEXCOMM0_IRQHandler
LDR R0, =FLEXCOMM0_DriverIRQHandler
BX R0
PUBWEAK FLEXCOMM1_IRQHandler
PUBWEAK FLEXCOMM1_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
FLEXCOMM1_IRQHandler
LDR R0, =FLEXCOMM1_DriverIRQHandler
BX R0
PUBWEAK FLEXCOMM2_IRQHandler
PUBWEAK FLEXCOMM2_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
FLEXCOMM2_IRQHandler
LDR R0, =FLEXCOMM2_DriverIRQHandler
BX R0
PUBWEAK FLEXCOMM3_IRQHandler
PUBWEAK FLEXCOMM3_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
FLEXCOMM3_IRQHandler
LDR R0, =FLEXCOMM3_DriverIRQHandler
BX R0
PUBWEAK FLEXCOMM4_IRQHandler
PUBWEAK FLEXCOMM4_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
FLEXCOMM4_IRQHandler
LDR R0, =FLEXCOMM4_DriverIRQHandler
BX R0
PUBWEAK FLEXCOMM5_IRQHandler
PUBWEAK FLEXCOMM5_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
FLEXCOMM5_IRQHandler
LDR R0, =FLEXCOMM5_DriverIRQHandler
BX R0
PUBWEAK FLEXCOMM6_IRQHandler
PUBWEAK FLEXCOMM6_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
FLEXCOMM6_IRQHandler
LDR R0, =FLEXCOMM6_DriverIRQHandler
BX R0
PUBWEAK FLEXCOMM7_IRQHandler
PUBWEAK FLEXCOMM7_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
FLEXCOMM7_IRQHandler
LDR R0, =FLEXCOMM7_DriverIRQHandler
BX R0
PUBWEAK ADC0_SEQA_IRQHandler
PUBWEAK ADC0_SEQA_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
ADC0_SEQA_IRQHandler
LDR R0, =ADC0_SEQA_DriverIRQHandler
BX R0
PUBWEAK ADC0_SEQB_IRQHandler
PUBWEAK ADC0_SEQB_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
ADC0_SEQB_IRQHandler
LDR R0, =ADC0_SEQB_DriverIRQHandler
BX R0
PUBWEAK ADC0_THCMP_IRQHandler
PUBWEAK ADC0_THCMP_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
ADC0_THCMP_IRQHandler
LDR R0, =ADC0_THCMP_DriverIRQHandler
BX R0
PUBWEAK DMIC0_IRQHandler
PUBWEAK DMIC0_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
DMIC0_IRQHandler
LDR R0, =DMIC0_DriverIRQHandler
BX R0
PUBWEAK HWVAD0_IRQHandler
PUBWEAK HWVAD0_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
HWVAD0_IRQHandler
LDR R0, =HWVAD0_DriverIRQHandler
BX R0
PUBWEAK USB0_NEEDCLK_IRQHandler
PUBWEAK USB0_NEEDCLK_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
USB0_NEEDCLK_IRQHandler
LDR R0, =USB0_NEEDCLK_DriverIRQHandler
BX R0
PUBWEAK USB0_IRQHandler
PUBWEAK USB0_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
USB0_IRQHandler
LDR R0, =USB0_DriverIRQHandler
BX R0
PUBWEAK RTC_IRQHandler
PUBWEAK RTC_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
RTC_IRQHandler
LDR R0, =RTC_DriverIRQHandler
BX R0
PUBWEAK IOH_IRQHandler
PUBWEAK IOH_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
IOH_IRQHandler
LDR R0, =IOH_DriverIRQHandler
BX R0
PUBWEAK MAILBOX_IRQHandler
PUBWEAK MAILBOX_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
MAILBOX_IRQHandler
LDR R0, =MAILBOX_DriverIRQHandler
BX R0
PUBWEAK PIN_INT4_IRQHandler
PUBWEAK PIN_INT4_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
PIN_INT4_IRQHandler
LDR R0, =PIN_INT4_DriverIRQHandler
BX R0
PUBWEAK PIN_INT5_IRQHandler
PUBWEAK PIN_INT5_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
PIN_INT5_IRQHandler
LDR R0, =PIN_INT5_DriverIRQHandler
BX R0
PUBWEAK PIN_INT6_IRQHandler
PUBWEAK PIN_INT6_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
PIN_INT6_IRQHandler
LDR R0, =PIN_INT6_DriverIRQHandler
BX R0
PUBWEAK PIN_INT7_IRQHandler
PUBWEAK PIN_INT7_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
PIN_INT7_IRQHandler
LDR R0, =PIN_INT7_DriverIRQHandler
BX R0
PUBWEAK CTIMER2_IRQHandler
PUBWEAK CTIMER2_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
CTIMER2_IRQHandler
LDR R0, =CTIMER2_DriverIRQHandler
BX R0
PUBWEAK CTIMER4_IRQHandler
PUBWEAK CTIMER4_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
CTIMER4_IRQHandler
LDR R0, =CTIMER4_DriverIRQHandler
BX R0
PUBWEAK Reserved54_IRQHandler
PUBWEAK Reserved54_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
Reserved54_IRQHandler
LDR R0, =Reserved54_DriverIRQHandler
BX R0
PUBWEAK SPIFI0_IRQHandler
PUBWEAK SPIFI0_DriverIRQHandler
SECTION .text:CODE:REORDER:NOROOT(2)
SPIFI0_IRQHandler
LDR R0, =SPIFI0_DriverIRQHandler
BX R0
WDT_BOD_DriverIRQHandler
DMA0_DriverIRQHandler
GINT0_DriverIRQHandler
GINT1_DriverIRQHandler
PIN_INT0_DriverIRQHandler
PIN_INT1_DriverIRQHandler
PIN_INT2_DriverIRQHandler
PIN_INT3_DriverIRQHandler
UTICK0_DriverIRQHandler
MRT0_DriverIRQHandler
CTIMER0_DriverIRQHandler
CTIMER1_DriverIRQHandler
SCT0_DriverIRQHandler
CTIMER3_DriverIRQHandler
FLEXCOMM0_DriverIRQHandler
FLEXCOMM1_DriverIRQHandler
FLEXCOMM2_DriverIRQHandler
FLEXCOMM3_DriverIRQHandler
FLEXCOMM4_DriverIRQHandler
FLEXCOMM5_DriverIRQHandler
FLEXCOMM6_DriverIRQHandler
FLEXCOMM7_DriverIRQHandler
ADC0_SEQA_DriverIRQHandler
ADC0_SEQB_DriverIRQHandler
ADC0_THCMP_DriverIRQHandler
DMIC0_DriverIRQHandler
HWVAD0_DriverIRQHandler
USB0_NEEDCLK_DriverIRQHandler
USB0_DriverIRQHandler
RTC_DriverIRQHandler
IOH_DriverIRQHandler
MAILBOX_DriverIRQHandler
PIN_INT4_DriverIRQHandler
PIN_INT5_DriverIRQHandler
PIN_INT6_DriverIRQHandler
PIN_INT7_DriverIRQHandler
CTIMER2_DriverIRQHandler
CTIMER4_DriverIRQHandler
Reserved54_DriverIRQHandler
SPIFI0_DriverIRQHandler
DefaultISR
B .
END

View File

@ -0,0 +1,46 @@
/* mbed Microcontroller Library
* CMSIS-style functionality to support dynamic vectors
*******************************************************************************
* Copyright (c) 2011 ARM Limited. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of ARM Limited nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************
*/
#ifndef MBED_CMSIS_NVIC_H
#define MBED_CMSIS_NVIC_H
#if defined(__CC_ARM)
extern uint32_t Image$$VECTOR_RAM$$Base[];
#define __VECTOR_RAM Image$$VECTOR_RAM$$Base
#else
extern uint32_t __VECTOR_RAM[];
#endif
/* Symbols defined by the linker script */
#define NVIC_NUM_VECTORS (16 + 40) // CORE + MCU Peripherals
#define NVIC_RAM_VECTOR_ADDRESS (__VECTOR_RAM) // Vectors positioned at start of RAM
#endif

View File

@ -0,0 +1,359 @@
/*
** ###################################################################
** Processors: LPC54114J256BD64_cm4
** LPC54114J256UK49_cm4
**
** Compilers: Keil ARM C/C++ Compiler
** GNU C Compiler
** IAR ANSI C/C++ Compiler for ARM
**
** Reference manual: LPC5411x User manual Rev. 1.0 16 February 2016
** Version: rev. 1.0, 2016-04-29
** Build: b160525
**
** Abstract:
** Provides a system configuration function and a global variable that
** contains the system frequency. It configures the device and initializes
** the oscillator (PLL) that is part of the microcontroller device.
**
** Copyright (c) 2016 Freescale Semiconductor, Inc.
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without modification,
** are permitted provided that the following conditions are met:
**
** o Redistributions of source code must retain the above copyright notice, this list
** of conditions and the following disclaimer.
**
** o Redistributions in binary form must reproduce the above copyright notice, this
** list of conditions and the following disclaimer in the documentation and/or
** other materials provided with the distribution.
**
** o Neither the name of Freescale Semiconductor, Inc. nor the names of its
** contributors may be used to endorse or promote products derived from this
** software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
** ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
** ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
** http: www.freescale.com
** mail: support@freescale.com
**
** Revisions:
** - rev. 1.0 (2016-04-29)
** Initial version.
**
** ###################################################################
*/
/*!
* @file LPC54114_cm4
* @version 1.0
* @date 2016-04-29
* @brief Device specific configuration file for LPC54114_cm4 (implementation
* file)
*
* Provides a system configuration function and a global variable that contains
* the system frequency. It configures the device and initializes the oscillator
* (PLL) that is part of the microcontroller device.
*/
#include <stdint.h>
#include "fsl_device_registers.h"
#define NVALMAX (0x100)
#define PVALMAX (0x20)
#define MVALMAX (0x8000)
#define PLL_SSCG0_MDEC_VAL_P (0) /* MDEC is in bits 16 downto 0 */
#define PLL_SSCG0_MDEC_VAL_M (0x1FFFFUL << PLL_SSCG0_MDEC_VAL_P) /* NDEC is in bits 9 downto 0 */
#define PLL_NDEC_VAL_P (0) /* NDEC is in bits 9:0 */
#define PLL_NDEC_VAL_M (0x3FFUL << PLL_NDEC_VAL_P)
#define PLL_PDEC_VAL_P (0) /* PDEC is in bits 6:0 */
#define PLL_PDEC_VAL_M (0x3FFUL << PLL_PDEC_VAL_P)
extern void *__Vectors;
/* ----------------------------------------------------------------------------
-- Core clock
---------------------------------------------------------------------------- */
uint32_t SystemCoreClock = DEFAULT_SYSTEM_CLOCK;
static const uint8_t wdtFreqLookup[32] = {0, 8, 12, 15, 18, 20, 24, 26, 28, 30, 32, 34, 36, 38, 40, 41, 42, 44, 45, 46,
48, 49, 50, 52, 53, 54, 56, 57, 58, 59, 60, 61};
static uint32_t GetWdtOscFreq(void)
{
uint8_t freq_sel, div_sel;
div_sel = ((SYSCON->WDTOSCCTRL & SYSCON_WDTOSCCTRL_DIVSEL_MASK) + 1) << 1;
freq_sel = wdtFreqLookup[((SYSCON->WDTOSCCTRL & SYSCON_WDTOSCCTRL_FREQSEL_MASK) >> SYSCON_WDTOSCCTRL_FREQSEL_SHIFT)];
return ((uint32_t) freq_sel * 50000U)/((uint32_t)div_sel);
}
/* Find decoded N value for raw NDEC value */
static uint32_t pllDecodeN(uint32_t NDEC)
{
uint32_t n, x, i;
/* Find NDec */
switch (NDEC)
{
case 0xFFF:
n = 0;
break;
case 0x302:
n = 1;
break;
case 0x202:
n = 2;
break;
default:
x = 0x080;
n = 0xFFFFFFFF;
for (i = NVALMAX; ((i >= 3) && (n == 0xFFFFFFFF)); i--)
{
x = (((x ^ (x >> 2) ^ (x >> 3) ^ (x >> 4)) & 1) << 7) | ((x >> 1) & 0x7F);
if ((x & (PLL_NDEC_VAL_M >> PLL_NDEC_VAL_P)) == NDEC)
{
/* Decoded value of NDEC */
n = i;
}
}
break;
}
return n;
}
/* Find decoded P value for raw PDEC value */
static uint32_t pllDecodeP(uint32_t PDEC)
{
uint32_t p, x, i;
/* Find PDec */
switch (PDEC)
{
case 0xFF:
p = 0;
break;
case 0x62:
p = 1;
break;
case 0x42:
p = 2;
break;
default:
x = 0x10;
p = 0xFFFFFFFF;
for (i = PVALMAX; ((i >= 3) && (p == 0xFFFFFFFF)); i--)
{
x = (((x ^ (x >> 2)) & 1) << 4) | ((x >> 1) & 0xF);
if ((x & (PLL_PDEC_VAL_M >> PLL_PDEC_VAL_P)) == PDEC)
{
/* Decoded value of PDEC */
p = i;
}
}
break;
}
return p;
}
/* Find decoded M value for raw MDEC value */
static uint32_t pllDecodeM(uint32_t MDEC)
{
uint32_t m, i, x;
/* Find MDec */
switch (MDEC)
{
case 0xFFFFF:
m = 0;
break;
case 0x18003:
m = 1;
break;
case 0x10003:
m = 2;
break;
default:
x = 0x04000;
m = 0xFFFFFFFF;
for (i = MVALMAX; ((i >= 3) && (m == 0xFFFFFFFF)); i--)
{
x = (((x ^ (x >> 1)) & 1) << 14) | ((x >> 1) & 0x3FFF);
if ((x & (PLL_SSCG0_MDEC_VAL_M >> PLL_SSCG0_MDEC_VAL_P)) == MDEC)
{
/* Decoded value of MDEC */
m = i;
}
}
break;
}
return m;
}
/* Get predivider (N) from PLL NDEC setting */
static uint32_t findPllPreDiv(uint32_t ctrlReg, uint32_t nDecReg)
{
uint32_t preDiv = 1;
/* Direct input is not used? */
if ((ctrlReg & SYSCON_SYSPLLCTRL_DIRECTI_MASK) == 0)
{
/* Decode NDEC value to get (N) pre divider */
preDiv = pllDecodeN(nDecReg & 0x3FF);
if (preDiv == 0)
{
preDiv = 1;
}
}
/* Adjusted by 1, directi is used to bypass */
return preDiv;
}
/* Get postdivider (P) from PLL PDEC setting */
static uint32_t findPllPostDiv(uint32_t ctrlReg, uint32_t pDecReg)
{
uint32_t postDiv = 1;
/* Direct input is not used? */
if ((ctrlReg & SYSCON_SYSPLLCTRL_DIRECTO_MASK) == 0)
{
/* Decode PDEC value to get (P) post divider */
postDiv = 2 * pllDecodeP(pDecReg & 0x7F);
if (postDiv == 0)
{
postDiv = 2;
}
}
/* Adjusted by 1, directo is used to bypass */
return postDiv;
}
/* Get multiplier (M) from PLL MDEC and BYPASS_FBDIV2 settings */
static uint32_t findPllMMult(uint32_t ctrlReg, uint32_t mDecReg)
{
uint32_t mMult = 1;
/* Decode MDEC value to get (M) multiplier */
mMult = pllDecodeM(mDecReg & 0x1FFFF);
/* Extra multiply by 2 needed? */
if ((ctrlReg & SYSCON_SYSPLLCTRL_BYPASSCCODIV2_MASK) == 0)
{
mMult = mMult << 1;
}
if (mMult == 0)
{
mMult = 1;
}
return mMult;
}
/* ----------------------------------------------------------------------------
-- SystemInit()
---------------------------------------------------------------------------- */
void SystemInit(void)
{
#if ((__FPU_PRESENT == 1) && (__FPU_USED == 1)) || (defined(__VFP_FP__) && !defined(__SOFTFP__))
SCB->CPACR |= ((3UL << 10 * 2) | (3UL << 11 * 2)); /* set CP10, CP11 Full Access */
#endif /* ((__FPU_PRESENT == 1) && (__FPU_USED == 1)) */
SCB->VTOR = (uint32_t)&__Vectors;
/* Optionally enable RAM banks that may be off by default at reset */
#if !defined(DONT_ENABLE_DISABLED_RAMBANKS)
SYSCON->AHBCLKCTRLSET[0] = SYSCON_AHBCLKCTRL_SRAM2_MASK;
#endif
}
/* ----------------------------------------------------------------------------
-- SystemCoreClockUpdate()
---------------------------------------------------------------------------- */
void SystemCoreClockUpdate(void)
{
uint32_t clkRate = 0;
uint32_t prediv, postdiv;
uint64_t workRate;
switch (SYSCON->MAINCLKSELB & SYSCON_MAINCLKSELB_SEL_MASK)
{
case 0x00: /* MAINCLKSELA clock (main_clk_a)*/
switch (SYSCON->MAINCLKSELA & SYSCON_MAINCLKSELA_SEL_MASK)
{
case 0x00: /* FRO 12 MHz (fro_12m) */
clkRate = CLK_FRO_12MHZ;
break;
case 0x01: /* CLKIN (clk_in) */
clkRate = CLK_CLK_IN;
break;
case 0x02: /* Watchdog oscillator (wdt_clk) */
clkRate = GetWdtOscFreq();
break;
default: /* = 0x03 = FRO 96 or 48 MHz (fro_hf) */
if (SYSCON->FROCTRL & SYSCON_FROCTRL_SEL_MASK)
{
clkRate = CLK_FRO_96MHZ;
}
else
{
clkRate = CLK_FRO_48MHZ;
}
break;
}
break;
case 0x02: /* System PLL clock (pll_clk)*/
switch (SYSCON->SYSPLLCLKSEL & SYSCON_SYSPLLCLKSEL_SEL_MASK)
{
case 0x00: /* FRO 12 MHz (fro_12m) */
clkRate = CLK_FRO_12MHZ;
break;
case 0x01: /* CLKIN (clk_in) */
clkRate = CLK_CLK_IN;
break;
case 0x02: /* Watchdog oscillator (wdt_clk) */
clkRate = GetWdtOscFreq();
break;
case 0x03: /* RTC oscillator 32 kHz output (32k_clk) */
clkRate = CLK_RTC_32K_CLK;
break;
default:
break;
}
if ((SYSCON->SYSPLLCTRL & SYSCON_SYSPLLCTRL_BYPASS_MASK) == 0)
{
/* PLL is not in bypass mode, get pre-divider, post-divider, and M divider */
prediv = findPllPreDiv(SYSCON->SYSPLLCTRL, SYSCON->SYSPLLNDEC);
postdiv = findPllPostDiv(SYSCON->SYSPLLCTRL, SYSCON->SYSPLLPDEC);
/* Adjust input clock */
clkRate = clkRate / prediv;
/* If using the SS, use the multiplier */
if (SYSCON->SYSPLLSSCTRL1 & SYSCON_SYSPLLSSCTRL1_PD_MASK)
{
/* MDEC used for rate */
workRate = (uint64_t)clkRate * (uint64_t)findPllMMult(SYSCON->SYSPLLCTRL, SYSCON->SYSPLLSSCTRL0);
}
else
{
/* SS multipler used for rate */
workRate = 0;
/* Adjust by fractional */
workRate = workRate + ((clkRate * (uint64_t)((SYSCON->SYSPLLSSCTRL1 & 0x7FF) >> 0)) / 0x800);
}
clkRate = workRate / ((uint64_t)postdiv);
}
break;
case 0x03: /* RTC oscillator 32 kHz output (32k_clk) */
clkRate = CLK_RTC_32K_CLK;
break;
default:
break;
}
SystemCoreClock = clkRate / ((SYSCON->AHBCLKDIV & 0xFF) + 1);
}

View File

@ -0,0 +1,119 @@
/*
** ###################################################################
** Processors: LPC54114J256BD64_cm4
** LPC54114J256UK49_cm4
**
** Compilers: Keil ARM C/C++ Compiler
** GNU C Compiler
** IAR ANSI C/C++ Compiler for ARM
**
** Reference manual: LPC5411x User manual Rev. 1.0 16 February 2016
** Version: rev. 1.0, 2016-04-29
** Build: b160525
**
** Abstract:
** Provides a system configuration function and a global variable that
** contains the system frequency. It configures the device and initializes
** the oscillator (PLL) that is part of the microcontroller device.
**
** Copyright (c) 2016 Freescale Semiconductor, Inc.
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without modification,
** are permitted provided that the following conditions are met:
**
** o Redistributions of source code must retain the above copyright notice, this list
** of conditions and the following disclaimer.
**
** o Redistributions in binary form must reproduce the above copyright notice, this
** list of conditions and the following disclaimer in the documentation and/or
** other materials provided with the distribution.
**
** o Neither the name of Freescale Semiconductor, Inc. nor the names of its
** contributors may be used to endorse or promote products derived from this
** software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
** ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
** ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
** http: www.freescale.com
** mail: support@freescale.com
**
** Revisions:
** - rev. 1.0 (2016-04-29)
** Initial version.
**
** ###################################################################
*/
/*!
* @file LPC54114_cm4
* @version 1.0
* @date 2016-04-29
* @brief Device specific configuration file for LPC54114_cm4 (header file)
*
* Provides a system configuration function and a global variable that contains
* the system frequency. It configures the device and initializes the oscillator
* (PLL) that is part of the microcontroller device.
*/
#ifndef _SYSTEM_LPC54114_cm4_H_
#define _SYSTEM_LPC54114_cm4_H_ /**< Symbol preventing repeated inclusion */
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#define DEFAULT_SYSTEM_CLOCK 12000000u /* Default System clock value */
#define CLK_RTC_32K_CLK 32768u /* RTC oscillator 32 kHz output (32k_clk */
#define CLK_FRO_12MHZ 12000000u /* FRO 12 MHz (fro_12m) */
#define CLK_FRO_48MHZ 48000000u /* FRO 48 MHz (fro_48m) */
#define CLK_FRO_96MHZ 96000000u /* FRO 96 MHz (fro_96m) */
#define CLK_CLK_IN 0u /* Default CLK_IN pin clock */
/**
* @brief System clock frequency (core clock)
*
* The system clock frequency supplied to the SysTick timer and the processor
* core clock. This variable can be used by the user application to setup the
* SysTick timer or configure other parameters. It may also be used by debugger to
* query the frequency of the debug timer or configure the trace clock speed
* SystemCoreClock is initialized with a correct predefined value.
*/
extern uint32_t SystemCoreClock;
/**
* @brief Setup the microcontroller system.
*
* Typically this function configures the oscillator (PLL) that is part of the
* microcontroller device. For systems with variable clock speed it also updates
* the variable SystemCoreClock. SystemInit is called from startup_device file.
*/
void SystemInit (void);
/**
* @brief Updates the SystemCoreClock variable.
*
* It must be called whenever the core clock is changed during program
* execution. SystemCoreClockUpdate() evaluates the clock register settings and calculates
* the current core clock.
*/
void SystemCoreClockUpdate (void);
#ifdef __cplusplus
}
#endif
#endif /* _SYSTEM_LPC54114_cm4_H_ */

View File

@ -0,0 +1,13 @@
/* mbed Microcontroller Library - CMSIS
* Copyright (C) 2009-2011 ARM Limited. All rights reserved.
*
* A generic CMSIS include header, pulling in LPC54114 specifics
*/
#ifndef MBED_CMSIS_H
#define MBED_CMSIS_H
#include "fsl_device_registers.h"
#include "cmsis_nvic.h"
#endif

View File

@ -0,0 +1,65 @@
/*
* Copyright (c) 2014 - 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __FSL_DEVICE_REGISTERS_H__
#define __FSL_DEVICE_REGISTERS_H__
/*
* Include the cpu specific register header files.
*
* The CPU macro should be declared in the project or makefile.
*/
#if (defined(CPU_LPC54114J256BD64_cm4) || defined(CPU_LPC54114J256UK49_cm4))
#define LPC54114_cm4_SERIES
/* CMSIS-style register definitions */
#include "LPC54114_cm4.h"
/* CPU specific feature definitions */
#include "LPC54114_cm4_features.h"
#elif (defined(CPU_LPC54114J256BD64_cm0plus) || defined(CPU_LPC54114J256UK49_cm0plus))
#define LPC54114_cm0plus_SERIES
/* CMSIS-style register definitions */
#include "LPC54114_cm0plus.h"
/* CPU specific feature definitions */
#include "LPC54114_cm0plus_features.h"
#else
#error "No valid CPU defined!"
#endif
#endif /* __FSL_DEVICE_REGISTERS_H__ */
/*******************************************************************************
* EOF
******************************************************************************/

View File

@ -0,0 +1,310 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "fsl_adc.h"
#include "fsl_clock.h"
static ADC_Type *const s_adcBases[] = ADC_BASE_PTRS;
static const clock_ip_name_t s_adcClocks[] = ADC_CLOCKS;
static uint32_t ADC_GetInstance(ADC_Type *base)
{
uint32_t instance;
/* Find the instance index from base address mappings. */
for (instance = 0; instance < FSL_FEATURE_SOC_ADC_COUNT; instance++)
{
if (s_adcBases[instance] == base)
{
break;
}
}
assert(instance < FSL_FEATURE_SOC_ADC_COUNT);
return instance;
}
void ADC_Init(ADC_Type *base, const adc_config_t *config)
{
assert(config != NULL);
uint32_t tmp32 = 0U;
/* Enable clock. */
CLOCK_EnableClock(s_adcClocks[ADC_GetInstance(base)]);
/* Disable the interrupts. */
base->INTEN = 0U; /* Quickly disable all the interrupts. */
/* Configure the ADC block. */
tmp32 = ADC_CTRL_CLKDIV(config->clockDividerNumber);
/* Async or Sync clock mode. */
switch (config->clockMode)
{
case kADC_ClockAsynchronousMode:
tmp32 |= ADC_CTRL_ASYNMODE_MASK;
break;
default: /* kADC_ClockSynchronousMode */
break;
}
/* Resolution. */
tmp32 |= ADC_CTRL_RESOL(config->resolution);
/* Bypass calibration. */
if (config->enableBypassCalibration)
{
tmp32 |= ADC_CTRL_BYPASSCAL_MASK;
}
/* Sample time clock count. */
tmp32 |= ADC_CTRL_TSAMP(config->sampleTimeNumber);
base->CTRL = tmp32;
}
void ADC_GetDefaultConfig(adc_config_t *config)
{
config->clockMode = kADC_ClockSynchronousMode;
config->clockDividerNumber = 0U;
config->resolution = kADC_Resolution12bit;
config->enableBypassCalibration = false;
config->sampleTimeNumber = 0U;
}
void ADC_Deinit(ADC_Type *base)
{
/* Disable the clock. */
CLOCK_DisableClock(s_adcClocks[ADC_GetInstance(base)]);
}
bool ADC_DoSelfCalibration(ADC_Type *base)
{
uint32_t i;
/* Enable the converter. */
/* This bit acn 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;
for (i = 0U; i < 0x10; i++) /* Wait a few clocks to startup up. */
{
__ASM("NOP");
}
if (!(base->STARTUP & ADC_STARTUP_ADC_ENA_MASK))
{
return false; /* ADC is not powered up. */
}
/* 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)))
{
/* Calibration is needed, do it now. */
base->CALIB = ADC_CALIB_CALIB_MASK;
i = 0xF0000;
while ((ADC_CALIB_CALIB_MASK == (base->CALIB & ADC_CALIB_CALIB_MASK)) && (--i))
{
}
if (i == 0U)
{
return false; /* Calibration timeout. */
}
}
/* A dummy conversion cycle will be performed. */
base->STARTUP |= ADC_STARTUP_ADC_INIT_MASK;
i = 0x7FFFF;
while ((ADC_STARTUP_ADC_INIT_MASK == (base->STARTUP & ADC_STARTUP_ADC_INIT_MASK)) && (--i))
{
}
if (i == 0U)
{
return false;
}
return true;
}
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;
}
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;
}
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. */
if (0U == (ADC_SEQ_GDAT_DATAVALID_MASK & tmp32))
{
return false;
}
info->result = (tmp32 & ADC_SEQ_GDAT_RESULT_MASK) >> ADC_SEQ_GDAT_RESULT_SHIFT;
info->thresholdCompareStatus =
(adc_threshold_compare_status_t)((tmp32 & ADC_SEQ_GDAT_THCMPRANGE_MASK) >> ADC_SEQ_GDAT_THCMPRANGE_SHIFT);
info->thresholdCorssingStatus =
(adc_threshold_crossing_status_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 true;
}
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. */
if (0U == (ADC_SEQ_GDAT_DATAVALID_MASK & tmp32))
{
return false;
}
info->result = (tmp32 & ADC_SEQ_GDAT_RESULT_MASK) >> ADC_SEQ_GDAT_RESULT_SHIFT;
info->thresholdCompareStatus =
(adc_threshold_compare_status_t)((tmp32 & ADC_SEQ_GDAT_THCMPRANGE_MASK) >> ADC_SEQ_GDAT_THCMPRANGE_SHIFT);
info->thresholdCorssingStatus =
(adc_threshold_crossing_status_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 true;
}
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. */
if (0U == (ADC_DAT_DATAVALID_MASK & tmp32))
{
return false;
}
info->result = (tmp32 & ADC_DAT_RESULT_MASK) >> ADC_DAT_RESULT_SHIFT;
info->thresholdCompareStatus =
(adc_threshold_compare_status_t)((tmp32 & ADC_DAT_THCMPRANGE_MASK) >> ADC_DAT_THCMPRANGE_SHIFT);
info->thresholdCorssingStatus =
(adc_threshold_crossing_status_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 true;
}

View File

@ -0,0 +1,664 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __FSL_ADC_H__
#define __FSL_ADC_H__
#include "fsl_common.h"
/*!
* @addtogroup lpc_adc
* @{
*/
/*! @file */
/*******************************************************************************
* Definitions
******************************************************************************/
/*! @name Driver version */
/*@{*/
/*! @brief ADC driver version 1.0.0. */
#define LPC_ADC_DRIVER_VERSION (MAKE_VERSION(2, 0, 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 = 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. */
kADC_ConvSeqBInterruptEnable = ADC_INTEN_SEQB_INTEN_MASK, /*!< Enable interrupt upon completion of each individual
conversion in sequence B, or entire sequence. */
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. */
};
/*!
* @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;
/*!
* @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;
/*!
* @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 is 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 structure for configuring the block.
*/
typedef struct _adc_config
{
adc_clock_mode_t clockMode; /*!< Select the clock mode for ADC converter. */
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. */
adc_resolution_t resolution; /*!< Select the conversion bits. */
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. */
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.*/
} 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 lauch 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; /*!< Keey 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);
/*!
* @brief Do the self hardware calibration.
*
* @param base ADC peripheral base address.
* @retval true Calibration succeed.
* @retval false Calibration failed.
*/
bool ADC_DoSelfCalibration(ADC_Type *base);
/*!
* @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.
*/
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);
}
}
/* @} */
/*!
* @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;
}
}
/*!
* @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;
}
/* @} */
/*!
* @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;
}
/* @} */
/*!
* @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);
/*!
* @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);
/*!
* @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 |= (0x7 & 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 &= ~(0x7 & mask);
}
/*!
* @brief Enable the interrupt of shreshold 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_EnableShresholdCompareInterrupt(ADC_Type *base,
uint32_t channel,
adc_threshold_interrupt_mode_t mode)
{
base->INTEN = (base->INTEN & ~(0x3U << ((channel << 1U) + 3U))) | ((uint32_t)(mode) << ((channel << 1U) + 3U));
}
/* @} */
/*!
* @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__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,857 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FSL_CLOCK_H_
#define _FSL_CLOCK_H_
#include "fsl_device_registers.h"
#include <stdint.h>
#include <stdbool.h>
#include <assert.h>
/*! @addtogroup clock */
/*! @{ */
/*! @file */
/*******************************************************************************
* Definitions
*****************************************************************************/
/*! @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_Dmic, /*!< Digital Mic clock */
kCLOCK_AsyncApbClk, /*!< Async APB clock */
kCLOCK_FlexI2S, /*!< FlexI2S clock */
kCLOCK_Flexcomm0, /*!< Flexcomm0Clock */
kCLOCK_Flexcomm1, /*!< Flexcomm1Clock */
kCLOCK_Flexcomm2, /*!< Flexcomm2Clock */
kCLOCK_Flexcomm3, /*!< Flexcomm3Clock */
kCLOCK_Flexcomm4, /*!< Flexcomm4Clock */
kCLOCK_Flexcomm5, /*!< Flexcomm5Clock */
kCLOCK_Flexcomm6, /*!< Flexcomm6Clock */
kCLOCK_Flexcomm7, /*!< Flexcomm7Clock */
} 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 64bits wide
* starting from LSB upwards
*
* [4 bits for choice, where 1 is A, 2 is B, 3 is C and 4 is D, 0 means end of descriptor] [8 bits mux ID]*
*
*/
#define MUX_A(m, choice) (((m) << 0) | ((choice + 1) << 8))
#define MUX_B(m, choice) (((m) << 12) | ((choice + 1) << 20))
#define MUX_C(m, choice) (((m) << 24) | ((choice + 1) << 32))
#define MUX_D(m, choice) (((m) << 36) | ((choice + 1) << 44))
#define MUX_E(m, choice) (((m) << 48) | ((choice + 1) << 56))
#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 28
typedef enum _clock_attach_id
{
kFRO12M_to_MAIN_CLK = MUX_A(CM_MAINCLKSELA, 0) | MUX_B(CM_MAINCLKSELB, 0),
kEXT_CLK_to_MAIN_CLK = MUX_A(CM_MAINCLKSELA, 1) | MUX_B(CM_MAINCLKSELB, 0),
kWDT_OSC_to_MAIN_CLK = MUX_A(CM_MAINCLKSELA, 2) | MUX_B(CM_MAINCLKSELB, 0),
kFRO_HF_to_MAIN_CLK = MUX_A(CM_MAINCLKSELA, 3) | MUX_B(CM_MAINCLKSELB, 0),
kSYS_PLL_to_MAIN_CLK = MUX_A(CM_MAINCLKSELB, 2),
kOSC32K_to_MAIN_CLK = MUX_A(CM_MAINCLKSELB, 3),
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),
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),
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 = 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 < 2)
{
SYSCON->AHBCLKCTRLSET[index] = (1U << CLK_GATE_ABSTRACT_BITS_SHIFT(clk));
}
else
{
ASYNC_SYSCON->ASYNCAPBCLKCTRLSET = (1U << 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 < 2)
{
SYSCON->AHBCLKCTRLCLR[index] = (1U << CLK_GATE_ABSTRACT_BITS_SHIFT(clk));
}
else
{
ASYNC_SYSCON->ASYNCAPBCLKCTRLCLR = (1U << 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 */
kCLOCK_Flash8Cycle /*!< Flash accesses use 8 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 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 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 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 Asynchronous APB Clock source
* @return Asynchronous APB CLock source
*/
__STATIC_INLINE async_clock_src_t CLOCK_GetAsyncApbClkSrc(void)
{
return (async_clock_src_t)(ASYNC_SYSCON->ASYNCAPBCLKSELA & 0x3);
}
/*! @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) != 0);
}
/*! @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 (1 << 0) /*!< Flag to use InputRate in PLL configuration structure for setup */
#define PLL_CONFIGFLAG_FORCENOFRACT \
(1 \
<< 2) /*!< 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 (1 << 0) /*!< Setup will power on the PLL after setup */
#define PLL_SETUPFLAG_WAITLOCK (1 << 1) /*!< Setup will wait for PLL lock, implies the PLL will be pwoered on */
#define PLL_SETUPFLAG_ADGVOLT (1 << 2) /*!< Optimize system voltage for the new PLL rate */
/*! @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_ */

View File

@ -0,0 +1,161 @@
/*
* Copyright (c) 2015-2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "fsl_common.h"
/* This is not needed for mbed */
#if 0
#include "fsl_debug_console.h"
#ifndef NDEBUG
#if (defined(__CC_ARM)) || (defined(__ICCARM__))
void __aeabi_assert(const char *failedExpr, const char *file, int line)
{
PRINTF("ASSERT ERROR \" %s \": file \"%s\" Line \"%d\" \n", failedExpr, file, line);
for (;;)
{
__asm("bkpt #0");
}
}
#elif(defined(__GNUC__))
void __assert_func(const char *file, int line, const char *func, const char *failedExpr)
{
PRINTF("ASSERT ERROR \" %s \": file \"%s\" Line \"%d\" function name \"%s\" \n", failedExpr, file, line, func);
for (;;)
{
__asm("bkpt #0");
}
}
#endif /* (defined(__CC_ARM)) || (defined (__ICCARM__)) */
#endif /* NDEBUG */
#endif
void InstallIRQHandler(IRQn_Type irq, uint32_t irqHandler)
{
/* Addresses for VECTOR_TABLE and VECTOR_RAM come from the linker file */
#if defined(__CC_ARM)
extern uint32_t Image$$VECTOR_ROM$$Base[];
extern uint32_t Image$$VECTOR_RAM$$Base[];
extern uint32_t Image$$RW_m_data$$Base[];
#define __VECTOR_TABLE Image$$VECTOR_ROM$$Base
#define __VECTOR_RAM Image$$VECTOR_RAM$$Base
#define __RAM_VECTOR_TABLE_SIZE (((uint32_t)Image$$RW_m_data$$Base - (uint32_t)Image$$VECTOR_RAM$$Base))
#elif defined(__ICCARM__)
extern uint32_t __RAM_VECTOR_TABLE_SIZE[];
extern uint32_t __VECTOR_TABLE[];
extern uint32_t __VECTOR_RAM[];
#elif defined(__GNUC__)
extern uint32_t __VECTOR_TABLE[];
extern uint32_t __VECTOR_RAM[];
extern uint32_t __RAM_VECTOR_TABLE_SIZE_BYTES[];
uint32_t __RAM_VECTOR_TABLE_SIZE = (uint32_t)(__RAM_VECTOR_TABLE_SIZE_BYTES);
#endif /* defined(__CC_ARM) */
uint32_t n;
uint32_t interrupts_disabled;
interrupts_disabled = __get_PRIMASK();
__disable_irq();
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;
}
/* make sure the __VECTOR_RAM is noncachable */
__VECTOR_RAM[irq + 16] = irqHandler;
if (!interrupts_disabled) {
__enable_irq();
}
}
#ifndef CPU_QN908X
#if (defined(FSL_FEATURE_SOC_SYSCON_COUNT) && (FSL_FEATURE_SOC_SYSCON_COUNT > 0))
void EnableDeepSleepIRQ(IRQn_Type interrupt)
{
uint32_t index = 0;
uint32_t intNumber = (uint32_t)interrupt;
while (intNumber >= 32u)
{
index++;
intNumber -= 32u;
}
SYSCON->STARTERSET[index] = 1u << intNumber;
EnableIRQ(interrupt); /* also enable interrupt at NVIC */
}
void DisableDeepSleepIRQ(IRQn_Type interrupt)
{
uint32_t index = 0;
uint32_t intNumber = (uint32_t)interrupt;
while (intNumber >= 32u)
{
index++;
intNumber -= 32u;
}
DisableIRQ(interrupt); /* also disable interrupt at NVIC */
SYSCON->STARTERCLR[index] = 1u << intNumber;
}
#endif /* FSL_FEATURE_SOC_SYSCON_COUNT */
#else
void EnableDeepSleepIRQ(IRQn_Type interrupt)
{
uint32_t index = 0;
uint32_t intNumber = (uint32_t)interrupt;
while (intNumber >= 32u)
{
index++;
intNumber -= 32u;
}
/* SYSCON->STARTERSET[index] = 1u << intNumber; */
EnableIRQ(interrupt); /* also enable interrupt at NVIC */
}
void DisableDeepSleepIRQ(IRQn_Type interrupt)
{
uint32_t index = 0;
uint32_t intNumber = (uint32_t)interrupt;
while (intNumber >= 32u)
{
index++;
intNumber -= 32u;
}
DisableIRQ(interrupt); /* also disable interrupt at NVIC */
/* SYSCON->STARTERCLR[index] = 1u << intNumber; */
}
#endif /*CPU_QN908X */

View File

@ -0,0 +1,310 @@
/*
* Copyright (c) 2015-2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FSL_COMMON_H_
#define _FSL_COMMON_H_
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#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))
/* Debug console type definition. */
#define DEBUG_CONSOLE_DEVICE_TYPE_NONE 0U /*!< No debug console. */
#define DEBUG_CONSOLE_DEVICE_TYPE_UART 1U /*!< Debug console base on UART. */
#define DEBUG_CONSOLE_DEVICE_TYPE_LPUART 2U /*!< Debug console base on LPUART. */
#define DEBUG_CONSOLE_DEVICE_TYPE_LPSCI 3U /*!< Debug console base on LPSCI. */
#define DEBUG_CONSOLE_DEVICE_TYPE_USBCDC 4U /*!< Debug console base on USBCDC. */
#define DEBUG_CONSOLE_DEVICE_TYPE_FLEXCOMM 5U /*!< Debug console base on USBCDC. */
/*! @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_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_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_NOTIFIER = 98, /*!< Group number for NOTIFIER status codes. */
kStatusGroup_DebugConsole = 99, /*!< Group number for debug console status codes. */
kStatusGroup_ApplicationRangeStart = 100, /*!< Starting number for application groups. */
};
/*! @brief Generic status return codes. */
enum _generic_status
{
kStatus_Success = MAKE_STATUS(kStatusGroup_Generic, 0),
kStatus_Fail = MAKE_STATUS(kStatusGroup_Generic, 1),
kStatus_ReadOnly = MAKE_STATUS(kStatusGroup_Generic, 2),
kStatus_OutOfRange = MAKE_STATUS(kStatusGroup_Generic, 3),
kStatus_InvalidArgument = MAKE_STATUS(kStatusGroup_Generic, 4),
kStatus_Timeout = MAKE_STATUS(kStatusGroup_Generic, 5),
kStatus_NoTransferInProgress = MAKE_STATUS(kStatusGroup_Generic, 6),
};
/*! @brief Type used for all status and error return values. */
typedef int32_t status_t;
/*
* 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
/*! @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. */
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
/*! @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)
/* @} */
/*******************************************************************************
* API
******************************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif
/*!
* @brief Enable specific interrupt.
*
* Enable the interrupt not routed from intmux.
*
* @param interrupt The IRQ number.
*/
static inline void EnableIRQ(IRQn_Type interrupt)
{
if (NotAvail_IRQn == interrupt)
{
return;
}
#if defined(FSL_FEATURE_SOC_INTMUX_COUNT) && (FSL_FEATURE_SOC_INTMUX_COUNT > 0)
if (interrupt < FSL_FEATURE_INTMUX_IRQ_START_INDEX)
#endif
{
NVIC_EnableIRQ(interrupt);
}
}
/*!
* @brief Disable specific interrupt.
*
* Disable the interrupt not routed from intmux.
*
* @param interrupt The IRQ number.
*/
static inline void DisableIRQ(IRQn_Type interrupt)
{
if (NotAvail_IRQn == interrupt)
{
return;
}
#if defined(FSL_FEATURE_SOC_INTMUX_COUNT) && (FSL_FEATURE_SOC_INTMUX_COUNT > 0)
if (interrupt < FSL_FEATURE_INTMUX_IRQ_START_INDEX)
#endif
{
NVIC_DisableIRQ(interrupt);
}
}
/*!
* @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)
{
uint32_t regPrimask = __get_PRIMASK();
__disable_irq();
return regPrimask;
}
/*!
* @brief Enaable the global IRQ
*
* Set the primask register with the provided primask value but not just enable the primask. The idea is for the
* convinience 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)
{
__set_PRIMASK(primask);
}
/*!
* @brief install IRQ handler
*
* @param irq IRQ number
* @param irqHandler IRQ handler address
*/
void InstallIRQHandler(IRQn_Type irq, uint32_t irqHandler);
#if (defined(FSL_FEATURE_SOC_SYSCON_COUNT) && (FSL_FEATURE_SOC_SYSCON_COUNT > 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 internally).
*
* @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 internally).
*
* @param interrupt The IRQ number.
*/
void DisableDeepSleepIRQ(IRQn_Type interrupt);
#endif /* FSL_FEATURE_SOC_SYSCON_COUNT */
#if defined(__cplusplus)
}
#endif
/*! @} */
#endif /* _FSL_COMMON_H_ */

View File

@ -0,0 +1,139 @@
/*
* Copyright (c) 2015-2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "fsl_crc.h"
/*******************************************************************************
* Definitions
******************************************************************************/
#if defined(CRC_DRIVER_USE_CRC16_CCITT_FALSE_AS_DEFAULT) && CRC_DRIVER_USE_CRC16_CCITT_FALSE_AS_DEFAULT
/* @brief Default user configuration structure for CRC-CCITT */
#define CRC_DRIVER_DEFAULT_POLYNOMIAL kCRC_Polynomial_CRC_CCITT
/*< CRC-CCIT polynomial x^16 + x^12 + x^5 + x^0 */
#define CRC_DRIVER_DEFAULT_REVERSE_IN false
/*< Default is no bit reverse */
#define CRC_DRIVER_DEFAULT_COMPLEMENT_IN false
/*< Default is without complement of written data */
#define CRC_DRIVER_DEFAULT_REVERSE_OUT false
/*< Default is no bit reverse */
#define CRC_DRIVER_DEFAULT_COMPLEMENT_OUT false
/*< Default is without complement of CRC data register read data */
#define CRC_DRIVER_DEFAULT_SEED 0xFFFFU
/*< Default initial checksum */
#endif /* CRC_DRIVER_USE_CRC16_CCITT_FALSE_AS_DEFAULT */
/*******************************************************************************
* Code
******************************************************************************/
void CRC_Init(CRC_Type *base, const crc_config_t *config)
{
/* enable clock to CRC */
CLOCK_EnableClock(kCLOCK_Crc);
/* configure CRC module and write the seed */
base->MODE = 0 | CRC_MODE_CRC_POLY(config->polynomial) | CRC_MODE_BIT_RVS_WR(config->reverseIn) |
CRC_MODE_CMPL_WR(config->complementIn) | CRC_MODE_BIT_RVS_SUM(config->reverseOut) |
CRC_MODE_CMPL_SUM(config->complementOut);
base->SEED = config->seed;
}
void CRC_GetDefaultConfig(crc_config_t *config)
{
static const crc_config_t default_config = {CRC_DRIVER_DEFAULT_POLYNOMIAL, CRC_DRIVER_DEFAULT_REVERSE_IN,
CRC_DRIVER_DEFAULT_COMPLEMENT_IN, CRC_DRIVER_DEFAULT_REVERSE_OUT,
CRC_DRIVER_DEFAULT_COMPLEMENT_OUT, CRC_DRIVER_DEFAULT_SEED};
*config = default_config;
}
void CRC_Reset(CRC_Type *base)
{
/* TODO - HW reset currently not exposed in API and they don't want
* dependencies to other modules anyway, so use SW reset temporarily. */
/* SYSCON_PeriphReset(RESET_CRC); */
crc_config_t config;
CRC_GetDefaultConfig(&config);
CRC_Init(base, &config);
}
void CRC_GetConfig(CRC_Type *base, crc_config_t *config)
{
/* extract CRC mode settings */
uint32_t mode = base->MODE;
config->polynomial = (crc_polynomial_t)((mode & CRC_MODE_CRC_POLY_MASK) >> CRC_MODE_CRC_POLY_SHIFT);
config->reverseIn = (bool)(mode & CRC_MODE_BIT_RVS_WR_MASK);
config->complementIn = (bool)(mode & CRC_MODE_CMPL_WR_MASK);
config->reverseOut = (bool)(mode & CRC_MODE_BIT_RVS_SUM_MASK);
config->complementOut = (bool)(mode & CRC_MODE_CMPL_SUM_MASK);
/* reset CRC sum bit reverse and 1's complement setting, so its value can be used as a seed */
base->MODE = mode & ~((1U << CRC_MODE_BIT_RVS_SUM_SHIFT) | (1U << CRC_MODE_CMPL_SUM_SHIFT));
/* now we can obtain intermediate raw CRC sum value */
config->seed = base->SUM;
/* restore original CRC sum bit reverse and 1's complement setting */
base->MODE = mode;
}
void CRC_WriteData(CRC_Type *base, const uint8_t *data, size_t dataSize)
{
const uint32_t *data32;
/* 8-bit reads and writes till source address is aligned 4 bytes */
while ((dataSize) && ((uint32_t)data & 3U))
{
*((__O uint8_t *)&(base->WR_DATA)) = *data;
data++;
dataSize--;
}
/* use 32-bit reads and writes as long as possible */
data32 = (const uint32_t *)data;
while (dataSize >= sizeof(uint32_t))
{
base->WR_DATA = *data32;
data32++;
dataSize -= sizeof(uint32_t);
}
data = (const uint8_t *)data32;
/* 8-bit reads and writes till end of data buffer */
while (dataSize)
{
*((__O uint8_t *)&(base->WR_DATA)) = *data;
data++;
dataSize--;
}
}

View File

@ -0,0 +1,199 @@
/*
* Copyright (c) 2015-2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FSL_CRC_H_
#define _FSL_CRC_H_
#include "fsl_common.h"
/*!
* @addtogroup crc
* @{
*/
/*! @file */
/*******************************************************************************
* Definitions
******************************************************************************/
/*! @name Driver version */
/*@{*/
/*! @brief CRC driver version. Version 2.0.0.
*
* Current version: 2.0.0
*
* Change log:
* - Version 2.0.0
* - initial version
*/
#define FSL_CRC_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
/*@}*/
#ifndef CRC_DRIVER_CUSTOM_DEFAULTS
/*! @brief Default configuration structure filled by CRC_GetDefaultConfig(). Uses CRC-16/CCITT-FALSE as default. */
#define CRC_DRIVER_USE_CRC16_CCITT_FALSE_AS_DEFAULT 1
#endif
/*! @brief CRC polynomials to use. */
typedef enum _crc_polynomial
{
kCRC_Polynomial_CRC_CCITT = 0U, /*!< x^16+x^12+x^5+1 */
kCRC_Polynomial_CRC_16 = 1U, /*!< x^16+x^15+x^2+1 */
kCRC_Polynomial_CRC_32 = 2U /*!< x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1 */
} crc_polynomial_t;
/*!
* @brief CRC protocol configuration.
*
* This structure holds the configuration for the CRC protocol.
*
*/
typedef struct _crc_config
{
crc_polynomial_t polynomial; /*!< CRC polynomial. */
bool reverseIn; /*!< Reverse bits on input. */
bool complementIn; /*!< Perform 1's complement on input. */
bool reverseOut; /*!< Reverse bits on output. */
bool complementOut; /*!< Perform 1's complement on output. */
uint32_t seed; /*!< Starting checksum value. */
} crc_config_t;
/*******************************************************************************
* API
******************************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif
/*!
* @brief Enables and configures the CRC peripheral module.
*
* This functions enables the CRC peripheral clock in the LPC SYSCON block.
* It also configures the CRC engine and starts checksum computation by writing the seed.
*
* @param base CRC peripheral address.
* @param config CRC module configuration structure.
*/
void CRC_Init(CRC_Type *base, const crc_config_t *config);
/*!
* @brief Disables the CRC peripheral module.
*
* This functions disables the CRC peripheral clock in the LPC SYSCON block.
*
* @param base CRC peripheral address.
*/
static inline void CRC_Deinit(CRC_Type *base)
{
/* disable clock to CRC */
CLOCK_DisableClock(kCLOCK_Crc);
}
/*!
* @brief resets CRC peripheral module.
*
* @param base CRC peripheral address, currently not used.
*/
void CRC_Reset(CRC_Type *base);
/*!
* @brief Loads default values to CRC protocol configuration structure.
*
* Loads default values to CRC protocol configuration structure. The default values are:
* @code
* config->polynomial = kCRC_Polynomial_CRC_CCITT;
* config->reverseIn = false;
* config->complementIn = false;
* config->reverseOut = false;
* config->complementOut = false;
* config->seed = 0xFFFFU;
* @endcode
*
* @param config CRC protocol configuration structure
*/
void CRC_GetDefaultConfig(crc_config_t *config);
/*!
* @brief Loads actual values configured in CRC peripheral to CRC protocol configuration structure.
*
* The values, including seed, can be used to resume CRC calculation later.
* @param base CRC peripheral address.
* @param config CRC protocol configuration structure
*/
void CRC_GetConfig(CRC_Type *base, crc_config_t *config);
/*!
* @brief Writes data to the CRC module.
*
* Writes input data buffer bytes to CRC data register.
*
* @param base CRC peripheral address.
* @param data Input data stream, MSByte in data[0].
* @param dataSize Size of the input data buffer in bytes.
*/
void CRC_WriteData(CRC_Type *base, const uint8_t *data, size_t dataSize);
/*!
* @brief Reads 32-bit checksum from the CRC module.
*
* Reads CRC data register.
*
* @param base CRC peripheral address.
* @return final 32-bit checksum, after configured bit reverse and complement operations.
*/
static inline uint32_t CRC_Get32bitResult(CRC_Type *base)
{
return base->SUM;
}
/*!
* @brief Reads 16-bit checksum from the CRC module.
*
* Reads CRC data register.
*
* @param base CRC peripheral address.
* @return final 16-bit checksum, after configured bit reverse and complement operations.
*/
static inline uint16_t CRC_Get16bitResult(CRC_Type *base)
{
return (uint16_t)base->SUM;
}
#if defined(__cplusplus)
}
#endif
/*!
*@}
*/
#endif /* _FSL_CRC_H_ */

View File

@ -0,0 +1,346 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "fsl_ctimer.h"
/*******************************************************************************
* 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);
/*******************************************************************************
* Variables
******************************************************************************/
/*! @brief Pointers to Timer bases for each instance. */
static CTIMER_Type *const s_ctimerBases[] = CTIMER_BASE_PTRS;
/*! @brief Pointers to Timer clocks for each instance. */
static const clock_ip_name_t s_ctimerClocks[] = CTIMER_CLOCKS;
/*! @brief Pointers to Timer resets for each instance. */
static const reset_ip_name_t s_ctimerResets[] = CTIMER_RSTS;
/*! @brief Pointers real ISRs installed by drivers for each instance. */
static ctimer_callback_t *s_ctimerCallback[FSL_FEATURE_SOC_CTIMER_COUNT] = {0};
/*! @brief Callback type installed by drivers for each instance. */
static ctimer_callback_type_t ctimerCallbackType[FSL_FEATURE_SOC_CTIMER_COUNT] = {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;
}
void CTIMER_Init(CTIMER_Type *base, const ctimer_config_t *config)
{
assert(config);
/* Enable the timer clock*/
CLOCK_EnableClock(s_ctimerClocks[CTIMER_GetInstance(base)]);
/* Reset the module */
RESET_PeripheralReset(s_ctimerResets[CTIMER_GetInstance(base)]);
/* Setup the cimer mode and count select */
base->CTCR = CTIMER_CTCR_CTMODE(config->mode) | CTIMER_CTCR_CINSEL(config->input);
/* Setup the timer prescale value */
base->PR = CTIMER_PR_PRVAL(config->prescale);
}
void CTIMER_Deinit(CTIMER_Type *base)
{
uint32_t index = CTIMER_GetInstance(base);
/* Stop the timer */
base->TCR &= ~CTIMER_TCR_CEN_MASK;
/* Disable the timer clock*/
CLOCK_DisableClock(s_ctimerClocks[index]);
/* Disable IRQ at NVIC Level */
DisableIRQ(s_ctimerIRQ[index]);
}
void CTIMER_GetDefaultConfig(ctimer_config_t *config)
{
assert(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;
}
status_t CTIMER_SetupPwm(CTIMER_Type *base,
ctimer_match_t matchChannel,
uint8_t dutyCyclePercent,
uint32_t pwmFreq_Hz,
uint32_t srcClock_Hz,
bool enableInt)
{
assert(pwmFreq_Hz > 0);
uint32_t reg;
uint32_t period, pulsePeriod = 0;
uint32_t timerClock = srcClock_Hz / (base->PR + 1);
uint32_t index = CTIMER_GetInstance(base);
if (matchChannel == kCTIMER_Match_3)
{
return kStatus_Fail;
}
/* Enable PWM mode on the channel */
base->PWMC |= (1U << matchChannel);
/* Clear the stop, reset and interrupt bits for this channel */
reg = base->MCR;
reg &= ~((CTIMER_MCR_MR0R_MASK | CTIMER_MCR_MR0S_MASK | CTIMER_MCR_MR0I_MASK) << (matchChannel * 3));
/* If call back function is valid then enable match interrupt for the channel */
if (enableInt)
{
reg |= (CTIMER_MCR_MR0I_MASK << (CTIMER_MCR_MR0I_SHIFT + (matchChannel * 3)));
}
/* 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) - 1;
/* Calculate pulse width match value */
if (dutyCyclePercent == 0)
{
pulsePeriod = period + 1;
}
else
{
pulsePeriod = (period * (100 - dutyCyclePercent)) / 100;
}
/* Match on channel 3 will define the PWM period */
base->MR[kCTIMER_Match_3] = period;
/* This will define the PWM pulse period */
base->MR[matchChannel] = pulsePeriod;
/* Clear status flags */
CTIMER_ClearStatusFlags(base, CTIMER_IR_MR0INT_MASK << matchChannel);
/* If call back function is valid then enable interrupt and update the call back function */
if (enableInt)
{
EnableIRQ(s_ctimerIRQ[index]);
}
return kStatus_Success;
}
void CTIMER_UpdatePwmDutycycle(CTIMER_Type *base, ctimer_match_t matchChannel, uint8_t dutyCyclePercent)
{
uint32_t pulsePeriod = 0, period;
/* Match channel 3 defines the PWM period */
period = base->MR[kCTIMER_Match_3];
/* Calculate pulse width match value */
pulsePeriod = (period * dutyCyclePercent) / 100;
/* For 0% dutycyle, make pulse period greater than period so the event will never occur */
if (dutyCyclePercent == 0)
{
pulsePeriod = period + 1;
}
else
{
pulsePeriod = (period * (100 - dutyCyclePercent)) / 100;
}
/* Update dutycycle */
base->MR[matchChannel] = pulsePeriod;
}
void CTIMER_SetupMatch(CTIMER_Type *base, ctimer_match_t matchChannel, const ctimer_match_config_t *config)
{
uint32_t reg;
uint32_t index = CTIMER_GetInstance(base);
/* Set the counter operation when a match on this channel occurs */
reg = base->MCR;
reg &= ~((CTIMER_MCR_MR0R_MASK | CTIMER_MCR_MR0S_MASK | CTIMER_MCR_MR0I_MASK) << (matchChannel * 3));
reg |= (uint32_t)((uint32_t)(config->enableCounterReset) << (CTIMER_MCR_MR0R_SHIFT + (matchChannel * 3)));
reg |= (uint32_t)((uint32_t)(config->enableCounterStop) << (CTIMER_MCR_MR0S_SHIFT + (matchChannel * 3)));
reg |= (uint32_t)((uint32_t)(config->enableInterrupt) << (CTIMER_MCR_MR0I_SHIFT + (matchChannel * 3)));
base->MCR = reg;
reg = base->EMR;
/* Set the match output operation when a match on this channel occurs */
reg &= ~(CTIMER_EMR_EMC0_MASK << (matchChannel * 2));
reg |= (uint32_t)config->outControl << (CTIMER_EMR_EMC0_SHIFT + (matchChannel * 2));
/* Set the initial state of the EM bit/output */
reg &= ~(CTIMER_EMR_EM0_MASK << matchChannel);
reg |= (uint32_t)config->outPinInitState << matchChannel;
base->EMR = reg;
/* Set the match value */
base->MR[matchChannel] = config->matchValue;
/* Clear status flags */
CTIMER_ClearStatusFlags(base, CTIMER_IR_MR0INT_MASK << matchChannel);
/* If interrupt is enabled then enable interrupt and update the call back function */
if (config->enableInterrupt)
{
EnableIRQ(s_ctimerIRQ[index]);
}
}
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 &= ~((CTIMER_CCR_CAP0RE_MASK | CTIMER_CCR_CAP0FE_MASK | CTIMER_CCR_CAP0I_MASK) << (capture * 3));
reg |= (uint32_t)edge << (CTIMER_CCR_CAP0RE_SHIFT + (capture * 3));
/* Clear status flags */
CTIMER_ClearStatusFlags(base, (kCTIMER_Capture0Flag << capture));
/* If call back function is valid then enable capture interrupt for the channel and update the call back function */
if (enableInt)
{
reg |= CTIMER_CCR_CAP0I_MASK << (capture * 3);
EnableIRQ(s_ctimerIRQ[index]);
}
base->CCR = reg;
}
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;
}
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])
{
s_ctimerCallback[index][0](int_stat);
}
}
else
{
for (i = 0; i <= CTIMER_IR_CR3INT_SHIFT; i++)
{
mask = 0x01 << i;
/* For each status flag bit that was set call the callback function if it is valid */
if ((int_stat & mask) && (s_ctimerCallback[index][i]))
{
s_ctimerCallback[index][i](int_stat);
}
}
}
}
#if (FSL_FEATURE_SOC_CTIMER_COUNT > 0U)
/* IRQ handler functions overloading weak symbols in the startup */
void CTIMER0_DriverIRQHandler(void)
{
CTIMER_GenericIRQHandler(0);
}
#endif
#if (FSL_FEATURE_SOC_CTIMER_COUNT > 1U)
void CTIMER1_DriverIRQHandler(void)
{
CTIMER_GenericIRQHandler(1);
}
#endif
#if (FSL_FEATURE_SOC_CTIMER_COUNT > 2U)
void CTIMER2_DriverIRQHandler(void)
{
CTIMER_GenericIRQHandler(2);
}
#endif
#if (FSL_FEATURE_SOC_CTIMER_COUNT > 3U)
void CTIMER3_DriverIRQHandler(void)
{
CTIMER_GenericIRQHandler(3);
}
#endif
#if (FSL_FEATURE_SOC_CTIMER_COUNT > 4U)
void CTIMER4_DriverIRQHandler(void)
{
CTIMER_GenericIRQHandler(4);
}
#endif

View File

@ -0,0 +1,434 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#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, 0, 0)) /*!< Version 2.0.0 */
/*@}*/
/*! @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 */
kCTIMER_Capture_2, /*!< Timer capture channel 2 */
kCTIMER_Capture_3 /*!< Timer capture channel 3 */
} 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 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 */
kCTIMER_Capture0InterruptEnable = CTIMER_CCR_CAP0I_MASK, /*!< Capture 0 interrupt */
kCTIMER_Capture1InterruptEnable = CTIMER_CCR_CAP1I_MASK, /*!< Capture 1 interrupt */
kCTIMER_Capture2InterruptEnable = CTIMER_CCR_CAP2I_MASK, /*!< Capture 2 interrupt */
kCTIMER_Capture3InterruptEnable = CTIMER_CCR_CAP3I_MASK, /*!< Capture 3 interrupt */
} 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 */
kCTIMER_Capture0Flag = CTIMER_IR_CR0INT_MASK, /*!< Capture 0 interrupt flag */
kCTIMER_Capture1Flag = CTIMER_IR_CR1INT_MASK, /*!< Capture 1 interrupt flag */
kCTIMER_Capture2Flag = CTIMER_IR_CR2INT_MASK, /*!< Capture 2 interrupt flag */
kCTIMER_Capture3Flag = CTIMER_IR_CR3INT_MASK, /*!< Capture 3 interrupt flag */
} 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 will assign match channel 3 to set the PWM cycle.
*
* @note When setting PWM output from multiple output pins, all should use the same PWM
* frequency
*
* @param base Ctimer peripheral base address
* @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 is generated
*
* @return kStatus_Success on success
* kStatus_Fail If matchChannel passed in is 3; this channel is reserved to set the PWM cycle
*/
status_t CTIMER_SetupPwm(CTIMER_Type *base,
ctimer_match_t matchChannel,
uint8_t dutyCyclePercent,
uint32_t pwmFreq_Hz,
uint32_t srcClock_Hz,
bool enableInt);
/*!
* @brief Updates the duty cycle of an active PWM signal.
*
* @param base Ctimer peripheral base address
* @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, 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 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 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;
/* Enable capture interrupts */
base->CCR |= mask;
}
/*!
* @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;
/* Disable capture interrupts */
base->CCR &= ~mask;
}
/*!
* @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_SHIFT | CTIMER_MCR_MR1I_SHIFT | CTIMER_MCR_MR2I_SHIFT | CTIMER_MCR_MR3I_SHIFT);
/* Get all the capture interrupts enabled */
enabledIntrs |=
base->CCR & (CTIMER_CCR_CAP0I_SHIFT | CTIMER_CCR_CAP1I_SHIFT | CTIMER_CCR_CAP2I_SHIFT | CTIMER_CCR_CAP3I_SHIFT);
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_ */

View File

@ -0,0 +1,417 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "fsl_dma.h"
/*******************************************************************************
* Definitions
******************************************************************************/
/*******************************************************************************
* Prototypes
******************************************************************************/
/*!
* @brief Get instance number for DMA.
*
* @param base DMA peripheral base address.
*/
static int32_t DMA_GetInstance(DMA_Type *base);
/*******************************************************************************
* Variables
******************************************************************************/
/*! @brief Array to map DMA instance number to base pointer. */
static DMA_Type *const s_dmaBases[] = DMA_BASE_PTRS;
/*! @brief Array to map DMA instance number to IRQ number. */
static const IRQn_Type s_dmaIRQNumber[] = DMA_IRQS;
/*! @brief Pointers to transfer handle for each DMA channel. */
static dma_handle_t *s_DMAHandle[FSL_FEATURE_DMA_NUMBER_OF_CHANNELS];
/*! @brief Static table of descriptors */
#if defined(__ICCARM__)
#pragma data_alignment = 512
dma_descriptor_t s_dma_descriptor_table[FSL_FEATURE_DMA_NUMBER_OF_CHANNELS] = {0};
#elif defined(__CC_ARM)
__attribute__((aligned(512))) dma_descriptor_t s_dma_descriptor_table[FSL_FEATURE_DMA_NUMBER_OF_CHANNELS] = {0};
#elif defined(__GNUC__)
__attribute__((aligned(512))) dma_descriptor_t s_dma_descriptor_table[FSL_FEATURE_DMA_NUMBER_OF_CHANNELS] = {0};
#endif
/*******************************************************************************
* Code
******************************************************************************/
static int32_t DMA_GetInstance(DMA_Type *base)
{
int32_t instance;
/* Find the instance index from base address mappings. */
for (instance = 0; instance < FSL_FEATURE_SOC_DMA_COUNT; instance++)
{
if (s_dmaBases[instance] == base)
{
break;
}
}
assert(instance < FSL_FEATURE_SOC_DMA_COUNT);
return instance < FSL_FEATURE_SOC_DMA_COUNT ? instance : -1;
}
void DMA_Init(DMA_Type *base)
{
/* enable dma clock gate */
CLOCK_EnableClock(kCLOCK_Dma);
/* set descriptor table */
base->SRAMBASE = (uint32_t)s_dma_descriptor_table;
/* enable dma peripheral */
base->CTRL |= DMA_CTRL_ENABLE_MASK;
}
void DMA_Deinit(DMA_Type *base)
{
/* Disable DMA peripheral */
base->CTRL &= ~(DMA_CTRL_ENABLE_MASK);
}
void DMA_ConfigureChannelTrigger(DMA_Type *base, uint32_t channel, dma_channel_trigger_t *trigger)
{
assert((channel < FSL_FEATURE_DMA_NUMBER_OF_CHANNELS) && (NULL != trigger));
uint32_t tmp = (
DMA_CHANNEL_CFG_HWTRIGEN_MASK | DMA_CHANNEL_CFG_TRIGPOL_MASK | DMA_CHANNEL_CFG_TRIGTYPE_MASK |
DMA_CHANNEL_CFG_TRIGBURST_MASK | DMA_CHANNEL_CFG_BURSTPOWER_MASK | DMA_CHANNEL_CFG_SRCBURSTWRAP_MASK |
DMA_CHANNEL_CFG_DSTBURSTWRAP_MASK
);
tmp = base->CHANNEL[channel].CFG & (~tmp);
tmp |= (uint32_t)(trigger->type) | (uint32_t)(trigger->burst) | (uint32_t)(trigger->wrap);
base->CHANNEL[channel].CFG = tmp;
}
/*!
* @brief Gets the remaining bytes of the current DMA descriptor transfer.
*
* @param base DMA peripheral base address.
* @param channel DMA channel number.
* @return The number of bytes which have not been transferred yet.
*/
uint32_t DMA_GetRemainingBytes(DMA_Type *base, uint32_t channel)
{
assert(channel < FSL_FEATURE_DMA_NUMBER_OF_CHANNELS);
/* NOTE: when descriptors are chained, ACTIVE bit is set for whole chain. It makes
* impossible to distinguish between:
* - transfer finishes (represented by value '0x3FF')
* - and remaining 1024 bytes to transfer (value 0x3FF)
* for all descriptor in chain, except the last one.
* If you decide to use this function, please use 1023 transfers as maximal value */
/* Channel not active (transfer finished) and value is 0x3FF - nothing to transfer */
if (
(!(base->COMMON[DMA_CHANNEL_GROUP(channel)].ACTIVE & (1U << (DMA_CHANNEL_INDEX(channel))))) &&
(0x3FF == ((base->CHANNEL[channel].XFERCFG & DMA_CHANNEL_XFERCFG_XFERCOUNT_MASK) >> DMA_CHANNEL_XFERCFG_XFERCOUNT_SHIFT))
)
{
return 0;
}
return base->CHANNEL[channel].XFERCFG + 1;
}
static void DMA_SetupDescriptor(
dma_descriptor_t *desc,
uint32_t xfercfg,
void *srcEndAddr,
void *dstEndAddr,
void *nextDesc
)
{
desc->xfercfg = xfercfg;
desc->srcEndAddr = srcEndAddr;
desc->dstEndAddr = dstEndAddr;
desc->linkToNextDesc = nextDesc;
}
/* Verify and convert dma_xfercfg_t to XFERCFG register */
static void DMA_SetupXferCFG(
dma_xfercfg_t *xfercfg,
uint32_t *xfercfg_addr
)
{
assert(xfercfg != NULL);
/* check source increment */
assert((xfercfg->srcInc == 0) || (xfercfg->srcInc == 1) || (xfercfg->srcInc == 2) || (xfercfg->srcInc == 4));
/* check destination increment */
assert((xfercfg->dstInc == 0) || (xfercfg->dstInc == 1) || (xfercfg->dstInc == 2) || (xfercfg->dstInc == 4));
/* check data width */
assert((xfercfg->byteWidth == 1) || (xfercfg->byteWidth == 2) || (xfercfg->byteWidth == 4));
/* check transfer count */
assert(xfercfg->transferCount <= DMA_MAX_TRANSFER_COUNT);
uint32_t xfer = 0, tmp;
/* set valid flag - descriptor is ready now */
xfer |= DMA_CHANNEL_XFERCFG_CFGVALID(xfercfg->valid ? 1 : 0);
/* set reload - allow link to next descriptor */
xfer |= DMA_CHANNEL_XFERCFG_RELOAD(xfercfg->reload ? 1 : 0);
/* set swtrig flag - start transfer */
xfer |= DMA_CHANNEL_XFERCFG_SWTRIG(xfercfg->swtrig? 1 : 0);
/* set transfer count */
xfer |= DMA_CHANNEL_XFERCFG_CLRTRIG(xfercfg->clrtrig? 1 : 0);
/* set INTA */
xfer |= DMA_CHANNEL_XFERCFG_SETINTA(xfercfg->intA ? 1 : 0);
/* set INTB */
xfer |= DMA_CHANNEL_XFERCFG_SETINTB(xfercfg->intB ? 1 : 0);
/* set data width */
tmp = xfercfg->byteWidth == 4 ? 2 : xfercfg->byteWidth - 1;
xfer |= DMA_CHANNEL_XFERCFG_WIDTH(tmp);
/* set source increment value */
tmp = xfercfg->srcInc == 4 ? 3 : xfercfg->srcInc;
xfer |= DMA_CHANNEL_XFERCFG_SRCINC(tmp);
/* set destination increment value */
tmp = xfercfg->dstInc == 4 ? 3 : xfercfg->dstInc;
xfer |= DMA_CHANNEL_XFERCFG_DSTINC(tmp);
/* set transfer count */
xfer |= DMA_CHANNEL_XFERCFG_XFERCOUNT(xfercfg->transferCount - 1);
/* store xferCFG */
*xfercfg_addr = xfer;
}
void DMA_CreateDescriptor(
dma_descriptor_t *desc,
dma_xfercfg_t *xfercfg,
void *srcAddr,
void *dstAddr,
void *nextDesc
)
{
uint32_t xfercfg_reg = 0;
assert((NULL != desc) && (0 == (uint32_t)desc % 16) && (NULL != xfercfg));
assert((NULL != srcAddr) && (0 == (uint32_t)srcAddr % xfercfg->byteWidth));
assert((NULL != dstAddr) && (0 == (uint32_t)dstAddr % xfercfg->byteWidth));
assert((NULL == nextDesc) || (0 == (uint32_t)nextDesc % 16));
/* Setup channel configuration */
DMA_SetupXferCFG(xfercfg, &xfercfg_reg);
/* Set descriptor structure */
DMA_SetupDescriptor(desc, xfercfg_reg,
(uint8_t*)srcAddr + (xfercfg->srcInc * xfercfg->byteWidth * (xfercfg->transferCount - 1)),
(uint8_t*)dstAddr + (xfercfg->dstInc * xfercfg->byteWidth * (xfercfg->transferCount - 1)),
nextDesc
);
}
void DMA_AbortTransfer(dma_handle_t *handle)
{
assert(NULL != handle);
DMA_DisableChannel(handle->base, handle->channel);
while (handle->base->COMMON[DMA_CHANNEL_GROUP(handle->channel)].BUSY & (1U << DMA_CHANNEL_INDEX(handle->channel)))
{ }
handle->base->COMMON[DMA_CHANNEL_GROUP(handle->channel)].ABORT |= 1U << DMA_CHANNEL_INDEX(handle->channel);
DMA_EnableChannel(handle->base, handle->channel);
}
void DMA_CreateHandle(dma_handle_t *handle, DMA_Type *base, uint32_t channel)
{
int32_t dmaInstance;
assert((NULL != handle) && (channel < FSL_FEATURE_DMA_NUMBER_OF_CHANNELS));
/* base address is invalid DMA instance */
dmaInstance = DMA_GetInstance(base);
memset(handle, 0, sizeof(*handle));
handle->base = base;
handle->channel = channel;
s_DMAHandle[channel] = handle;
/* Enable NVIC interrupt */
EnableIRQ(s_dmaIRQNumber[dmaInstance]);
}
void DMA_SetCallback(dma_handle_t *handle, dma_callback callback, void *userData)
{
assert(handle != NULL);
handle->callback = callback;
handle->userData = userData;
}
void DMA_PrepareTransfer(dma_transfer_config_t *config,
void *srcAddr,
void *dstAddr,
uint32_t byteWidth,
uint32_t transferBytes,
dma_transfer_type_t type,
void *nextDesc)
{
uint32_t xfer_count;
assert((NULL != config) && (NULL != srcAddr) && (NULL != dstAddr));
assert((byteWidth == 1) || (byteWidth == 2) || (byteWidth == 4));
/* check max */
xfer_count = transferBytes / byteWidth;
assert((xfer_count <= DMA_MAX_TRANSFER_COUNT) && (0 == transferBytes % byteWidth));
memset(config, 0, sizeof(*config));
switch (type)
{
case kDMA_MemoryToMemory:
config->xfercfg.srcInc = 1;
config->xfercfg.dstInc = 1;
config->isPeriph = false;
break;
case kDMA_PeripheralToMemory:
/* Peripheral register - source doesn't increment */
config->xfercfg.srcInc = 0;
config->xfercfg.dstInc = 1;
config->isPeriph = true;
break;
case kDMA_MemoryToPeripheral:
/* Peripheral register - destination doesn't increment */
config->xfercfg.srcInc = 1;
config->xfercfg.dstInc = 0;
config->isPeriph = true;
break;
case kDMA_StaticToStatic:
config->xfercfg.srcInc = 0;
config->xfercfg.dstInc = 0;
config->isPeriph = true;
break;
default:
return;
}
config->dstAddr = (uint8_t*)dstAddr;
config->srcAddr = (uint8_t*)srcAddr;
config->nextDesc = (uint8_t*)nextDesc;
config->xfercfg.transferCount = xfer_count;
config->xfercfg.byteWidth = byteWidth;
config->xfercfg.intA = true;
config->xfercfg.reload = nextDesc != NULL;
config->xfercfg.valid = true;
}
status_t DMA_SubmitTransfer(dma_handle_t *handle, dma_transfer_config_t *config)
{
assert((NULL != handle) && (NULL != config));
/* Previous transfer has not finished */
if (DMA_ChannelIsActive(handle->base, handle->channel))
{
return kStatus_DMA_Busy;
}
/* enable/disable peripheral request */
if (config->isPeriph)
{
DMA_EnableChannelPeriphRq(handle->base, handle->channel);
}
else
{
DMA_DisableChannelPeriphRq(handle->base, handle->channel);
}
DMA_CreateDescriptor(
&s_dma_descriptor_table[ handle->channel ], &config->xfercfg,
config->srcAddr, config->dstAddr, config->nextDesc
);
return kStatus_Success;
}
void DMA_StartTransfer(dma_handle_t *handle)
{
assert(NULL != handle);
/* Enable channel interrupt */
handle->base->COMMON[DMA_CHANNEL_GROUP(handle->channel)].INTENSET |= 1U << DMA_CHANNEL_INDEX(handle->channel);
/* If HW trigger is enabled - disable SW trigger */
if (handle->base->CHANNEL[handle->channel].CFG & DMA_CHANNEL_CFG_HWTRIGEN_MASK)
{
s_dma_descriptor_table[ handle->channel ].xfercfg &= ~(DMA_CHANNEL_XFERCFG_SWTRIG_MASK);
}
/* Otherwise enable SW trigger */
else
{
s_dma_descriptor_table[ handle->channel ].xfercfg |= DMA_CHANNEL_XFERCFG_SWTRIG_MASK;
}
/* Set channel XFERCFG register according first channel descriptor. */
handle->base->CHANNEL[handle->channel].XFERCFG = s_dma_descriptor_table[ handle->channel ].xfercfg;
/* At this moment, the channel ACTIVE bit is set and application cannot modify
* or start another transfer using this channel. Channel ACTIVE bit is cleared by
* 'AbortTransfer' function or when the transfer finishes */
}
void DMA0_DriverIRQHandler(void)
{
dma_handle_t *handle;
int32_t channel_group;
int32_t channel_index;
/* Find channels that have completed transfer */
for (int i = 0; i < FSL_FEATURE_DMA_NUMBER_OF_CHANNELS; i++)
{
handle = s_DMAHandle[i];
/* Handle is not present */
if (NULL == handle)
{
continue;
}
channel_group = DMA_CHANNEL_GROUP(handle->channel);
channel_index = DMA_CHANNEL_INDEX(handle->channel);
/* Channel uses INTA flag */
if (handle->base->COMMON[channel_group].INTA & (1U << channel_index))
{
/* Clear INTA flag */
handle->base->COMMON[channel_group].INTA = 1U << channel_index;
if (handle->callback)
{
(handle->callback)(handle, handle->userData, true, kDMA_IntA);
}
}
/* Channel uses INTB flag */
if (handle->base->COMMON[channel_group].INTB & (1U << channel_index))
{
/* Clear INTB flag */
handle->base->COMMON[channel_group].INTB = 1U << channel_index;
if (handle->callback)
{
(handle->callback)(handle, handle->userData, true, kDMA_IntB);
}
}
}
}

View File

@ -0,0 +1,476 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FSL_DMA_H_
#define _FSL_DMA_H_
#include "fsl_common.h"
/*!
* @addtogroup dma
* @{
*/
/*! @file */
/*******************************************************************************
* Definitions
******************************************************************************/
/*! @name Driver version */
/*@{*/
/*! @brief DMA driver version */
#define FSL_DMA_DRIVER_VERSION (MAKE_VERSION(2, 0, 0)) /*!< Version 2.0.0. */
/*@}*/
#define DMA_MAX_TRANSFER_COUNT 0x400
/* Channel group consists of 32 channels. channel_group = (channel / 32) */
#define DMA_CHANNEL_GROUP(channel) (((uint8_t)channel) >> 5U)
/* Channel index in channel group. channel_index = (channel % 32) */
#define DMA_CHANNEL_INDEX(channel) (((uint8_t)channel) & 0x1F)
/*! @brief DMA descriptor structure */
typedef struct _dma_descriptor {
uint32_t xfercfg; /*!< Transfer configuration */
void *srcEndAddr; /*!< Last source address of DMA transfer */
void *dstEndAddr; /*!< Last destination address of DMA transfer */
void *linkToNextDesc; /*!< Address of next DMA descriptor in chain */
} dma_descriptor_t;
/*! @brief DMA transfer configuration */
typedef struct _dma_xfercfg {
bool valid; /*!< Descriptor is ready to transfer */
bool reload; /*!< Reload channel configuration register after
current descriptor is exhausted */
bool swtrig; /*!< Perform software trigger. Transfer if fired
when 'valid' is set */
bool clrtrig; /*!< Clear trigger */
bool intA; /*!< Raises IRQ when transfer is done and set IRQA status register flag */
bool intB; /*!< Raises IRQ when transfer is done and set IRQB status register flag */
uint8_t byteWidth; /*!< Byte width of data to transfer */
uint8_t srcInc; /*!< Increment source address by 'srcInc' x 'byteWidth' */
uint8_t dstInc; /*!< Increment destination address by 'dstInc' x 'byteWidth' */
uint16_t transferCount; /*!< Number of transfers */
} dma_xfercfg_t;
/*! @brief DMA channel priority */
typedef enum _dma_priority {
kDMA_ChannelPriority0 = 0, /*!< Highest channel priority - priority 0 */
kDMA_ChannelPriority1, /*!< Channel priority 1 */
kDMA_ChannelPriority2, /*!< Channel priority 2 */
kDMA_ChannelPriority3, /*!< Channel priority 3 */
kDMA_ChannelPriority4, /*!< Channel priority 4 */
kDMA_ChannelPriority5, /*!< Channel priority 5 */
kDMA_ChannelPriority6, /*!< Channel priority 6 */
kDMA_ChannelPriority7, /*!< Lowest channel priority - priority 7 */
} dma_priority_t;
/*! @brief DMA interrupt flags */
typedef enum _dma_int {
kDMA_IntA, /*!< DMA interrupt flag A */
kDMA_IntB, /*!< DMA interrupt flag B */
} dma_irq_t;
/*! @brief DMA trigger type*/
typedef enum _dma_trigger_type {
kDMA_NoTrigger = 0, /*!< Trigger is disabled */
kDMA_LowLevelTrigger = DMA_CHANNEL_CFG_HWTRIGEN(1) | DMA_CHANNEL_CFG_TRIGTYPE(1), /*!< Low level active trigger */
kDMA_HighLevelTrigger = DMA_CHANNEL_CFG_HWTRIGEN(1) | DMA_CHANNEL_CFG_TRIGTYPE(1) | DMA_CHANNEL_CFG_TRIGPOL(1), /*!< High level active trigger */
kDMA_FallingEdgeTrigger = DMA_CHANNEL_CFG_HWTRIGEN(1), /*!< Falling edge active trigger */
kDMA_RisingEdgeTrigger = DMA_CHANNEL_CFG_HWTRIGEN(1) | DMA_CHANNEL_CFG_TRIGPOL(1), /*!< Rising edge active trigger */
} dma_trigger_type_t;
/*! @brief DMA trigger burst */
typedef enum _dma_trigger_burst {
kDMA_SingleTransfer = 0, /*!< Single transfer */
kDMA_LevelBurstTransfer = DMA_CHANNEL_CFG_TRIGBURST(1), /*!< Burst transfer driven by level trigger */
kDMA_EdgeBurstTransfer1 = DMA_CHANNEL_CFG_TRIGBURST(1), /*!< Perform 1 transfer by edge trigger */
kDMA_EdgeBurstTransfer2 = DMA_CHANNEL_CFG_TRIGBURST(1) | DMA_CHANNEL_CFG_BURSTPOWER(1), /*!< Perform 2 transfers by edge trigger */
kDMA_EdgeBurstTransfer4 = DMA_CHANNEL_CFG_TRIGBURST(1) | DMA_CHANNEL_CFG_BURSTPOWER(2), /*!< Perform 4 transfers by edge trigger */
kDMA_EdgeBurstTransfer8 = DMA_CHANNEL_CFG_TRIGBURST(1) | DMA_CHANNEL_CFG_BURSTPOWER(3), /*!< Perform 8 transfers by edge trigger */
kDMA_EdgeBurstTransfer16 = DMA_CHANNEL_CFG_TRIGBURST(1) | DMA_CHANNEL_CFG_BURSTPOWER(4), /*!< Perform 16 transfers by edge trigger */
kDMA_EdgeBurstTransfer32 = DMA_CHANNEL_CFG_TRIGBURST(1) | DMA_CHANNEL_CFG_BURSTPOWER(5), /*!< Perform 32 transfers by edge trigger */
kDMA_EdgeBurstTransfer64 = DMA_CHANNEL_CFG_TRIGBURST(1) | DMA_CHANNEL_CFG_BURSTPOWER(6), /*!< Perform 64 transfers by edge trigger */
kDMA_EdgeBurstTransfer128 = DMA_CHANNEL_CFG_TRIGBURST(1) | DMA_CHANNEL_CFG_BURSTPOWER(7), /*!< Perform 128 transfers by edge trigger */
kDMA_EdgeBurstTransfer256 = DMA_CHANNEL_CFG_TRIGBURST(1) | DMA_CHANNEL_CFG_BURSTPOWER(8), /*!< Perform 256 transfers by edge trigger */
kDMA_EdgeBurstTransfer512 = DMA_CHANNEL_CFG_TRIGBURST(1) | DMA_CHANNEL_CFG_BURSTPOWER(9), /*!< Perform 512 transfers by edge trigger */
kDMA_EdgeBurstTransfer1024 = DMA_CHANNEL_CFG_TRIGBURST(1) | DMA_CHANNEL_CFG_BURSTPOWER(10), /*!< Perform 1024 transfers by edge trigger */
} dma_trigger_burst_t;
/*! @brief DMA burst wrapping */
typedef enum _dma_burst_wrap {
kDMA_NoWrap = 0, /*!< Wrapping is disabled */
kDMA_SrcWrap = DMA_CHANNEL_CFG_SRCBURSTWRAP(1), /*!< Wrapping is enabled for source */
kDMA_DstWrap = DMA_CHANNEL_CFG_DSTBURSTWRAP(1), /*!< Wrapping is enabled for destination */
kDMA_SrcAndDstWrap = DMA_CHANNEL_CFG_SRCBURSTWRAP(1) | DMA_CHANNEL_CFG_DSTBURSTWRAP(1), /*!< Wrapping is enabled for source and destination */
} dma_burst_wrap_t;
/*! @brief DMA transfer type */
typedef enum _dma_transfer_type
{
kDMA_MemoryToMemory = 0x0U, /*!< Transfer from memory to memory (increment source and destination) */
kDMA_PeripheralToMemory, /*!< Transfer from peripheral to memory (increment only destination) */
kDMA_MemoryToPeripheral, /*!< Transfer from memory to peripheral (increment only source)*/
kDMA_StaticToStatic, /*!< Peripheral to static memory (do not increment source or destination) */
} dma_transfer_type_t;
/*! @brief DMA channel trigger */
typedef struct _dma_channel_trigger {
dma_trigger_type_t type;
dma_trigger_burst_t burst;
dma_burst_wrap_t wrap;
} dma_channel_trigger_t;
/*! @brief DMA transfer status */
enum _dma_transfer_status
{
kStatus_DMA_Busy = MAKE_STATUS(kStatusGroup_DMA, 0), /*!< Channel is busy and can't handle the
transfer request. */
};
/*! @brief DMA transfer configuration */
typedef struct _dma_transfer_config
{
uint8_t *srcAddr; /*!< Source data address */
uint8_t *dstAddr; /*!< Destination data address */
uint8_t *nextDesc; /*!< Chain custom descriptor */
dma_xfercfg_t xfercfg; /*!< Transfer options */
bool isPeriph; /*!< DMA transfer is driven by peripheral */
} dma_transfer_config_t;
/*! @brief Callback for DMA */
struct _dma_handle;
/*! @brief Define Callback function for DMA. */
typedef void (*dma_callback)(struct _dma_handle *handle, void *userData, bool transferDone, uint32_t intmode);
/*! @brief DMA transfer handle structure */
typedef struct _dma_handle
{
dma_callback callback; /*!< Callback function. Invoked when transfer
of descriptor with interrupt flag finishes */
void *userData; /*!< Callback function parameter */
DMA_Type *base; /*!< DMA peripheral base address */
uint8_t channel; /*!< DMA channel number */
} dma_handle_t;
/*******************************************************************************
* APIs
******************************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif /* __cplusplus */
/*!
* @name DMA initialization and De-initialization
* @{
*/
/*!
* @brief Initializes DMA peripheral.
*
* This function enable the DMA clock, set descriptor table and
* enable DMA peripheral.
*
* @param base DMA peripheral base address.
*/
void DMA_Init(DMA_Type *base);
/*!
* @brief Deinitializes DMA peripheral.
*
* This function gates the DMA clock.
*
* @param base DMA peripheral base address.
*/
void DMA_Deinit(DMA_Type *base);
/* @} */
/*!
* @name DMA Channel Operation
* @{
*/
/*!
* @brief Return whether DMA channel is processing transfer
*
* @param base DMA peripheral base address.
* @param channel DMA channel number.
* @return True for active state, false otherwise.
*/
static inline bool DMA_ChannelIsActive(DMA_Type *base, uint32_t channel)
{
assert(channel < FSL_FEATURE_DMA_NUMBER_OF_CHANNELS);
return (base->COMMON[DMA_CHANNEL_GROUP(channel)].ACTIVE & (1U << DMA_CHANNEL_INDEX(channel))) ? true : false;
}
/*!
* @brief Enables the interrupt source for the DMA transfer.
*
* @param base DMA peripheral base address.
* @param channel DMA channel number.
*/
static inline void DMA_EnableChannelInterrupts(DMA_Type *base, uint32_t channel)
{
assert(channel < FSL_FEATURE_DMA_NUMBER_OF_CHANNELS);
base->COMMON[DMA_CHANNEL_GROUP(channel)].INTENSET |= 1U << DMA_CHANNEL_INDEX(channel);
}
/*!
* @brief Disables the interrupt source for the DMA transfer.
*
* @param base DMA peripheral base address.
* @param channel DMA channel number.
*/
static inline void DMA_DisableChannelInterrupts(DMA_Type *base, uint32_t channel)
{
assert(channel < FSL_FEATURE_DMA_NUMBER_OF_CHANNELS);
base->COMMON[DMA_CHANNEL_GROUP(channel)].INTENCLR |= 1U << DMA_CHANNEL_INDEX(channel);
}
/*!
* @brief Enable DMA channel.
*
* @param base DMA peripheral base address.
* @param channel DMA channel number.
*/
static inline void DMA_EnableChannel(DMA_Type *base, uint32_t channel)
{
assert(channel < FSL_FEATURE_DMA_NUMBER_OF_CHANNELS);
base->COMMON[DMA_CHANNEL_GROUP(channel)].ENABLESET |= 1U << DMA_CHANNEL_INDEX(channel);
}
/*!
* @brief Disable DMA channel.
*
* @param base DMA peripheral base address.
* @param channel DMA channel number.
*/
static inline void DMA_DisableChannel(DMA_Type *base, uint32_t channel)
{
assert(channel < FSL_FEATURE_DMA_NUMBER_OF_CHANNELS);
base->COMMON[DMA_CHANNEL_GROUP(channel)].ENABLECLR |= 1U << DMA_CHANNEL_INDEX(channel);
}
/*!
* @brief Set PERIPHREQEN of channel configuration register.
*
* @param base DMA peripheral base address.
* @param channel DMA channel number.
*/
static inline void DMA_EnableChannelPeriphRq(DMA_Type *base, uint32_t channel)
{
assert(channel < FSL_FEATURE_DMA_NUMBER_OF_CHANNELS);
base->CHANNEL[channel].CFG |= DMA_CHANNEL_CFG_PERIPHREQEN_MASK;
}
/*!
* @brief Get PERIPHREQEN value of channel configuration register.
*
* @param base DMA peripheral base address.
* @param channel DMA channel number.
* @return True for enabled PeriphRq, false for disabled.
*/
static inline void DMA_DisableChannelPeriphRq(DMA_Type *base, uint32_t channel)
{
assert(channel < FSL_FEATURE_DMA_NUMBER_OF_CHANNELS);
base->CHANNEL[channel].CFG &= ~DMA_CHANNEL_CFG_PERIPHREQEN_MASK;
}
/*!
* @brief Set trigger settings of DMA channel.
*
* @param base DMA peripheral base address.
* @param channel DMA channel number.
* @param trigger trigger configuration.
*/
void DMA_ConfigureChannelTrigger(DMA_Type *base, uint32_t channel, dma_channel_trigger_t *trigger);
/*!
* @brief Gets the remaining bytes of the current DMA descriptor transfer.
*
* @param base DMA peripheral base address.
* @param channel DMA channel number.
* @return The number of bytes which have not been transferred yet.
*/
uint32_t DMA_GetRemainingBytes(DMA_Type *base, uint32_t channel);
/*!
* @brief Set priority of channel configuration register.
*
* @param base DMA peripheral base address.
* @param channel DMA channel number.
* @param priority Channel priority value.
*/
static inline void DMA_SetChannelPriority(DMA_Type *base, uint32_t channel, dma_priority_t priority)
{
assert(channel < FSL_FEATURE_DMA_NUMBER_OF_CHANNELS);
base->CHANNEL[channel].CFG = (base->CHANNEL[channel].CFG & (~(DMA_CHANNEL_CFG_CHPRIORITY_MASK))) | DMA_CHANNEL_CFG_CHPRIORITY(priority);
}
/*!
* @brief Get priority of channel configuration register.
*
* @param base DMA peripheral base address.
* @param channel DMA channel number.
* @return Channel priority value.
*/
static inline dma_priority_t DMA_GetChannelPriority(DMA_Type *base, uint32_t channel)
{
assert(channel < FSL_FEATURE_DMA_NUMBER_OF_CHANNELS);
return (dma_priority_t)((base->CHANNEL[channel].CFG & DMA_CHANNEL_CFG_CHPRIORITY_MASK) >> DMA_CHANNEL_CFG_CHPRIORITY_SHIFT);
}
/*!
* @brief Create application specific DMA descriptor
* to be used in a chain in transfer
*
* @param desc DMA descriptor address.
* @param xfercfg Transfer configuration for DMA descriptor.
* @param srcAddr Address of last item to transmit
* @param dstAddr Address of last item to receive.
* @param nextDesc Address of next descriptor in chain.
*/
void DMA_CreateDescriptor(
dma_descriptor_t *desc,
dma_xfercfg_t *xfercfg,
void *srcAddr,
void *dstAddr,
void *nextDesc
);
/* @} */
/*!
* @name DMA Transactional Operation
* @{
*/
/*!
* @brief Abort running transfer by handle.
*
* This function aborts DMA transfer specified by handle.
*
* @param handle DMA handle pointer.
*/
void DMA_AbortTransfer(dma_handle_t *handle);
/*!
* @brief Creates the DMA handle.
*
* This function is called if using transaction API for DMA. This function
* initializes the internal state of DMA handle.
*
* @param handle DMA handle pointer. The DMA handle stores callback function and
* parameters.
* @param base DMA peripheral base address.
* @param channel DMA channel number.
*/
void DMA_CreateHandle(dma_handle_t *handle, DMA_Type *base, uint32_t channel);
/*!
* @brief Installs a callback function for the DMA transfer.
*
* This callback is called in DMA IRQ handler. Use the callback to do something after
* the current major loop transfer completes.
*
* @param handle DMA handle pointer.
* @param callback DMA callback function pointer.
* @param userData Parameter for callback function.
*/
void DMA_SetCallback(dma_handle_t *handle, dma_callback callback, void *userData);
/*!
* @brief Prepares the DMA transfer structure.
*
* This function prepares the transfer configuration structure according to the user input.
*
* @param config The user configuration structure of type dma_transfer_t.
* @param srcAddr DMA transfer source address.
* @param dstAddr DMA transfer destination address.
* @param byteWidth DMA transfer destination address width(bytes).
* @param transferBytes DMA transfer bytes to be transferred.
* @param type DMA transfer type.
* @param nextDesc Chain custom descriptor to transfer.
* @note The data address and the data width must be consistent. For example, if the SRC
* is 4 bytes, so the source address must be 4 bytes aligned, or it shall result in
* source address error(SAE).
*/
void DMA_PrepareTransfer(dma_transfer_config_t *config,
void *srcAddr,
void *dstAddr,
uint32_t byteWidth,
uint32_t transferBytes,
dma_transfer_type_t type,
void *nextDesc);
/*!
* @brief Submits the DMA transfer request.
*
* This function submits the DMA transfer request according to the transfer configuration structure.
* If the user submits the transfer request repeatedly, this function packs an unprocessed request as
* a TCD and enables scatter/gather feature to process it in the next time.
*
* @param handle DMA handle pointer.
* @param config Pointer to DMA transfer configuration structure.
* @retval kStatus_DMA_Success It means submit transfer request succeed.
* @retval kStatus_DMA_QueueFull It means TCD queue is full. Submit transfer request is not allowed.
* @retval kStatus_DMA_Busy It means the given channel is busy, need to submit request later.
*/
status_t DMA_SubmitTransfer(dma_handle_t *handle, dma_transfer_config_t *config);
/*!
* @brief DMA start transfer.
*
* This function enables the channel request. User can call this function after submitting the transfer request
* or before submitting the transfer request.
*
* @param handle DMA handle pointer.
*/
void DMA_StartTransfer(dma_handle_t *handle);
/*!
* @brief DMA IRQ handler for descriptor transfer complete.
*
* This function clears the channel major interrupt flag and call
* the callback function if it is not NULL.
*/
void DMA_HandleIRQ(void);
/* @} */
#if defined(__cplusplus)
}
#endif /* __cplusplus */
/* @} */
#endif /*_FSL_DMA_H_*/

View File

@ -0,0 +1,235 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "fsl_dmic.h"
/*******************************************************************************
* Variables
******************************************************************************/
/* Array of DMIC peripheral base address. */
static DMIC_Type *const s_dmicBases[FSL_FEATURE_SOC_DMIC_COUNT] = DMIC_BASE_PTRS;
/* Array of DMIC clock name. */
static const clock_ip_name_t s_dmicClock[FSL_FEATURE_SOC_DMIC_COUNT] = DMIC_CLOCKS;
/* Array of DMIC IRQ number. */
static const IRQn_Type s_dmicIRQ[FSL_FEATURE_SOC_DMIC_COUNT] = DMIC_IRQS;
/*! @brief Callback function array for DMIC(s). */
static dmic_callback_t s_dmicCallback[FSL_FEATURE_SOC_DMIC_COUNT];
/* Array of HWVAD IRQ number. */
static const IRQn_Type s_dmicHwvadIRQ[FSL_FEATURE_SOC_DMIC_COUNT] = DMIC_HWVAD_IRQS;
/*! @brief Callback function array for HWVAD(s). */
static dmic_hwvad_callback_t s_dmicHwvadCallback[FSL_FEATURE_SOC_DMIC_COUNT];
/*******************************************************************************
* Prototypes
******************************************************************************/
/*!
* @brief Get the DMIC instance from peripheral base address.
*
* @param base DMIC peripheral base address.
* @return DMIC instance.
*/
uint32_t DMIC_GetInstance(DMIC_Type *base)
{
uint32_t instance;
/* Find the instance index from base address mappings. */
for (instance = 0; instance < FSL_FEATURE_SOC_DMIC_COUNT; instance++)
{
if (s_dmicBases[instance] == base)
{
break;
}
}
assert(instance < FSL_FEATURE_SOC_DMIC_COUNT);
return instance;
}
void DMIC_Init(DMIC_Type *base)
{
assert(base);
/* Enable the clock to the register interface */
CLOCK_EnableClock(s_dmicClock[DMIC_GetInstance(base)]);
/* Reset the peripheral */
RESET_PeripheralReset(kDMIC_RST_SHIFT_RSTn);
/* Disable DMA request*/
base->CHANNEL[0].FIFO_CTRL &= ~DMIC_CHANNEL_FIFO_CTRL_DMAEN(1);
base->CHANNEL[1].FIFO_CTRL &= ~DMIC_CHANNEL_FIFO_CTRL_DMAEN(1);
/* Disable DMIC interrupt. */
base->CHANNEL[0].FIFO_CTRL &= ~DMIC_CHANNEL_FIFO_CTRL_INTEN(1);
base->CHANNEL[1].FIFO_CTRL &= ~DMIC_CHANNEL_FIFO_CTRL_INTEN(1);
}
void DMIC_DeInit(DMIC_Type *base)
{
assert(base);
/* Disable the clock to the register interface */
CLOCK_DisableClock(s_dmicClock[DMIC_GetInstance(base)]);
}
void DMIC_ConfigIO(DMIC_Type *base, dmic_io_t config)
{
base->IOCFG = config;
}
void DMIC_SetOperationMode(DMIC_Type *base, operation_mode_t mode)
{
if (mode == kDMIC_OperationModeInterrupt)
{
/* Enable DMIC interrupt. */
base->CHANNEL[0].FIFO_CTRL |= DMIC_CHANNEL_FIFO_CTRL_INTEN(1);
base->CHANNEL[1].FIFO_CTRL |= DMIC_CHANNEL_FIFO_CTRL_INTEN(1);
}
if (mode == kDMIC_OperationModeDma)
{
/* enable DMA request*/
base->CHANNEL[0].FIFO_CTRL |= DMIC_CHANNEL_FIFO_CTRL_DMAEN(1);
base->CHANNEL[1].FIFO_CTRL |= DMIC_CHANNEL_FIFO_CTRL_DMAEN(1);
}
}
void DMIC_ConfigChannel(DMIC_Type *base,
dmic_channel_t channel,
stereo_side_t side,
dmic_channel_config_t *channel_config)
{
base->CHANNEL[channel].DIVHFCLK = channel_config->divhfclk;
base->CHANNEL[channel].OSR = channel_config->osr;
base->CHANNEL[channel].GAINSHIFT = channel_config->gainshft;
base->CHANNEL[channel].PREAC2FSCOEF = channel_config->preac2coef;
base->CHANNEL[channel].PREAC4FSCOEF = channel_config->preac4coef;
base->CHANNEL[channel].PHY_CTRL =
DMIC_CHANNEL_PHY_CTRL_PHY_FALL(side) | DMIC_CHANNEL_PHY_CTRL_PHY_HALF(channel_config->sample_rate);
base->CHANNEL[channel].DC_CTRL = DMIC_CHANNEL_DC_CTRL_DCPOLE(channel_config->dc_cut_level) |
DMIC_CHANNEL_DC_CTRL_DCGAIN(channel_config->post_dc_gain_reduce) |
DMIC_CHANNEL_DC_CTRL_SATURATEAT16BIT(channel_config->saturate16bit);
}
void DMIC_CfgChannelDc(DMIC_Type *base,
dmic_channel_t channel,
dc_removal_t dc_cut_level,
uint32_t post_dc_gain_reduce,
bool saturate16bit)
{
base->CHANNEL[channel].DC_CTRL = DMIC_CHANNEL_DC_CTRL_DCPOLE(dc_cut_level) |
DMIC_CHANNEL_DC_CTRL_DCGAIN(post_dc_gain_reduce) |
DMIC_CHANNEL_DC_CTRL_SATURATEAT16BIT(saturate16bit);
}
void DMIC_Use2fs(DMIC_Type *base, bool use2fs)
{
base->USE2FS = (use2fs) ? 0x1 : 0x0;
}
void DMIC_EnableChannnel(DMIC_Type *base, uint32_t channelmask)
{
base->CHANEN = channelmask;
}
void DMIC_FifoChannel(DMIC_Type *base, uint32_t channel, uint32_t trig_level, uint32_t enable, uint32_t resetn)
{
base->CHANNEL[channel].FIFO_CTRL |=
(base->CHANNEL[channel].FIFO_CTRL & (DMIC_CHANNEL_FIFO_CTRL_INTEN_MASK | DMIC_CHANNEL_FIFO_CTRL_DMAEN_MASK)) |
DMIC_CHANNEL_FIFO_CTRL_TRIGLVL(trig_level) | DMIC_CHANNEL_FIFO_CTRL_ENABLE(enable) |
DMIC_CHANNEL_FIFO_CTRL_RESETN(resetn);
}
void DMIC_EnableIntCallback(DMIC_Type *base, dmic_callback_t cb)
{
uint32_t instance;
instance = DMIC_GetInstance(base);
NVIC_ClearPendingIRQ(s_dmicIRQ[instance]);
/* Save callback pointer */
s_dmicCallback[instance] = cb;
EnableIRQ(s_dmicIRQ[instance]);
}
void DMIC_DisableIntCallback(DMIC_Type *base, dmic_callback_t cb)
{
uint32_t instance;
instance = DMIC_GetInstance(base);
DisableIRQ(s_dmicIRQ[instance]);
s_dmicCallback[instance] = NULL;
NVIC_ClearPendingIRQ(s_dmicIRQ[instance]);
}
void DMIC_HwvadEnableIntCallback(DMIC_Type *base, dmic_hwvad_callback_t vadcb)
{
uint32_t instance;
instance = DMIC_GetInstance(base);
NVIC_ClearPendingIRQ(s_dmicHwvadIRQ[instance]);
/* Save callback pointer */
s_dmicHwvadCallback[instance] = vadcb;
EnableIRQ(s_dmicHwvadIRQ[instance]);
}
void DMIC_HwvadDisableIntCallback(DMIC_Type *base, dmic_hwvad_callback_t vadcb)
{
uint32_t instance;
instance = DMIC_GetInstance(base);
DisableIRQ(s_dmicHwvadIRQ[instance]);
s_dmicHwvadCallback[instance] = NULL;
NVIC_ClearPendingIRQ(s_dmicHwvadIRQ[instance]);
}
/* IRQ handler functions overloading weak symbols in the startup */
#if defined(DMIC0)
/*DMIC0 IRQ handler */
void DMIC0_DriverIRQHandler(void)
{
if (s_dmicCallback[0] != NULL)
{
s_dmicCallback[0]();
}
}
/*DMIC0 HWVAD IRQ handler */
void HWVAD0_IRQHandler(void)
{
if (s_dmicHwvadCallback[0] != NULL)
{
s_dmicHwvadCallback[0]();
}
}
#endif

View File

@ -0,0 +1,439 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FSL_DMIC_H_
#define _FSL_DMIC_H_
#include "fsl_common.h"
/*!
* @addtogroup dmic_driver
* @{
*/
/*! @file*/
/*******************************************************************************
* Definitions
******************************************************************************/
/*!
* @name DMIC version
* @{
*/
/*! @brief DMIC driver version 2.0.0. */
#define FSL_DMIC_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
/*@}*/
/*! @brief DMIC different operation modes. */
typedef enum _operation_mode
{
kDMIC_OperationModePoll = 0U, /*!< Polling mode */
kDMIC_OperationModeInterrupt = 1U, /*!< Interrupt mode */
kDMIC_OperationModeDma = 2U, /*!< DMA mode */
} operation_mode_t;
/*! @brief DMIC left/right values. */
typedef enum _stereo_side
{
kDMIC_Left = 0U, /*!< Left Stereo channel */
kDMIC_Right = 1U, /*!< Right Stereo channel */
} stereo_side_t;
/*! @brief DMIC Clock pre-divider values. */
typedef enum
{
kDMIC_PdmDiv1 = 0U, /*!< DMIC pre-divider set in divide by 1 */
kDMIC_PdmDiv2 = 1U, /*!< DMIC pre-divider set in divide by 2 */
kDMIC_PdmDiv3 = 2U, /*!< DMIC pre-divider set in divide by 3 */
kDMIC_PdmDiv4 = 3U, /*!< DMIC pre-divider set in divide by 4 */
kDMIC_PdmDiv6 = 4U, /*!< DMIC pre-divider set in divide by 6 */
kDMIC_PdmDiv8 = 5U, /*!< DMIC pre-divider set in divide by 8 */
kDMIC_PdmDiv12 = 6U, /*!< DMIC pre-divider set in divide by 12 */
kDMIC_PdmDiv16 = 7U, /*!< DMIC pre-divider set in divide by 16*/
kDMIC_PdmDiv24 = 8U, /*!< DMIC pre-divider set in divide by 24*/
kDMIC_PdmDiv32 = 9U, /*!< DMIC pre-divider set in divide by 32 */
kDMIC_PdmDiv48 = 10U, /*!< DMIC pre-divider set in divide by 48 */
kDMIC_PdmDiv64 = 11U, /*!< DMIC pre-divider set in divide by 64*/
kDMIC_PdmDiv96 = 12U, /*!< DMIC pre-divider set in divide by 96*/
kDMIC_PdmDiv128 = 13U, /*!< DMIC pre-divider set in divide by 128 */
} pdm_div_t;
/*! @brief Pre-emphasis Filter coefficient value for 2FS and 4FS modes. */
typedef enum _compensation
{
kDMIC_CompValueZero = 0U, /*!< Compensation 0 */
kDMIC_CompValueNegativePoint16 = 1U, /*!< Compensation -0.16 */
kDMIC_CompValueNegativePoint15 = 2U, /*!< Compensation -0.15 */
kDMIC_CompValueNegativePoint13 = 3U, /*!< Compensation -0.13 */
} compensation_t;
/*! @brief DMIC DC filter control values. */
typedef enum _dc_removal
{
kDMIC_DcNoRemove = 0U, /*!< Flat response no filter */
kDMIC_DcCut155 = 1U, /*!< Cut off Frequency is 155 Hz */
kDMIC_DcCut78 = 2U, /*!< Cut off Frequency is 78 Hz */
kDMIC_DcCut39 = 3U, /*!< Cut off Frequency is 39 Hz */
} dc_removal_t;
/*! @brief DMIC IO configiration. */
typedef enum _dmic_io
{
kDMIC_PdmDual = 0U, /*!< Two separate pairs of PDM wires */
kDMIC_PdmStereo = 4U, /*!< Stereo Mic */
kDMIC_PdmBypass = 3U, /*!< Clk Bypass clocks both channels */
kDMIC_PdmBypassClk0 = 1U, /*!< Clk Bypass clocks only channel0 */
kDMIC_PdmBypassClk1 = 2U, /*!< Clk Bypas clocks only channel1 */
} dmic_io_t;
/*! @brief DMIC Channel number. */
typedef enum _dmic_channel
{
kDMIC_Channel0 = 0U, /*!< DMIC channel 0 */
kDMIC_Channel1 = 1U, /*!< DMIC channel 1 */
} dmic_channel_t;
/*! @brief DMIC and decimator sample rates. */
typedef enum _dmic_phy_sample_rate
{
kDMIC_PhyFullSpeed = 0U, /*!< Decimator gets one sample per each chosen clock edge of PDM interface */
kDMIC_PhyHalfSpeed = 1U, /*!< PDM clock to Microphone is halved, decimator receives each sample twice */
} dmic_phy_sample_rate_t;
/*! @brief DMIC transfer status.*/
enum _dmic_status
{
kStatus_DMIC_Busy = MAKE_STATUS(kStatusGroup_DMIC, 0), /*!< DMIC is busy */
kStatus_DMIC_Idle = MAKE_STATUS(kStatusGroup_DMIC, 1), /*!< DMIC is idle */
kStatus_DMIC_OverRunError = MAKE_STATUS(kStatusGroup_DMIC, 2), /*!< DMIC over run Error */
kStatus_DMIC_UnderRunError = MAKE_STATUS(kStatusGroup_DMIC, 3), /*!< DMIC under run Error */
};
/*! @brief DMIC Channel configuration structure. */
typedef struct _dmic_channel_config
{
pdm_div_t divhfclk; /*!< DMIC Clock pre-divider values */
uint32_t osr; /*!< oversampling rate(CIC decimation rate) for PCM */
int32_t gainshft; /*!< 4FS PCM data gain control */
compensation_t preac2coef; /*!< Pre-emphasis Filter coefficient value for 2FS */
compensation_t preac4coef; /*!< Pre-emphasis Filter coefficient value for 4FS */
dc_removal_t dc_cut_level; /*!< DMIC DC filter control values. */
uint32_t post_dc_gain_reduce; /*!< Fine gain adjustment in the form of a number of bits to downshift */
dmic_phy_sample_rate_t sample_rate; /*!< DMIC and decimator sample rates */
bool saturate16bit; /*!< Selects 16-bit saturation. 0 means results roll over if out range and do not saturate.
1 means if the result overflows, it saturates at 0xFFFF for positive overflow and
0x8000 for negative overflow.*/
} dmic_channel_config_t;
/*! @brief DMIC Callback function. */
typedef void (*dmic_callback_t)(void);
/*! @brief HWVAD Callback function. */
typedef void (*dmic_hwvad_callback_t)(void);
/*******************************************************************************
* Definitions
******************************************************************************/
/*******************************************************************************
* API
******************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif
/*!
* @brief Get the DMIC instance from peripheral base address.
*
* @param base DMIC peripheral base address.
* @return DMIC instance.
*/
uint32_t DMIC_GetInstance(DMIC_Type *base);
/*!
* @brief Turns DMIC Clock on
* @param base : DMIC base
* @return Nothing
*/
void DMIC_Init(DMIC_Type *base);
/*!
* @brief Turns DMIC Clock off
* @param base : DMIC base
* @return Nothing
*/
void DMIC_DeInit(DMIC_Type *base);
/*!
* @brief Configure DMIC io
* @param base : The base address of DMIC interface
* @param config : DMIC io configuration
* @return Nothing
*/
void DMIC_ConfigIO(DMIC_Type *base, dmic_io_t config);
/*!
* @brief Set DMIC operating mode
* @param base : The base address of DMIC interface
* @param mode : DMIC mode
* @return Nothing
*/
void DMIC_SetOperationMode(DMIC_Type *base, operation_mode_t mode);
/*!
* @brief Configure DMIC channel
* @param base : The base address of DMIC interface
* @param channel : DMIC channel
* @param side : stereo_side_t, choice of left or right
* @param channel_config : Channel configuration
* @return Nothing
*/
void DMIC_ConfigChannel(DMIC_Type *base,
dmic_channel_t channel,
stereo_side_t side,
dmic_channel_config_t *channel_config);
/*!
* @brief Configure Clock scaling
* @param base : The base address of DMIC interface
* @param use2fs : clock scaling
* @return Nothing
*/
void DMIC_Use2fs(DMIC_Type *base, bool use2fs);
/*!
* @brief Enable a particualr channel
* @param base : The base address of DMIC interface
* @param channelmask : Channel selection
* @return Nothing
*/
void DMIC_EnableChannnel(DMIC_Type *base, uint32_t channelmask);
/*!
* @brief Configure fifo settings for DMIC channel
* @param base : The base address of DMIC interface
* @param channel : DMIC channel
* @param trig_level : FIFO trigger level
* @param enable : FIFO level
* @param resetn : FIFO reset
* @return Nothing
*/
void DMIC_FifoChannel(DMIC_Type *base, uint32_t channel, uint32_t trig_level, uint32_t enable, uint32_t resetn);
/*!
* @brief Get FIFO status
* @param base : The base address of DMIC interface
* @param channel : DMIC channel
* @return FIFO status
*/
static inline uint32_t DMIC_FifoGetStatus(DMIC_Type *base, uint32_t channel)
{
return base->CHANNEL[channel].FIFO_STATUS;
}
/*!
* @brief Clear FIFO status
* @param base : The base address of DMIC interface
* @param channel : DMIC channel
* @param mask : Bits to be cleared
* @return FIFO status
*/
static inline void DMIC_FifoClearStatus(DMIC_Type *base, uint32_t channel, uint32_t mask)
{
base->CHANNEL[channel].FIFO_STATUS = mask;
}
/*!
* @brief Get FIFO data
* @param base : The base address of DMIC interface
* @param channel : DMIC channel
* @return FIFO data
*/
static inline uint32_t DMIC_FifoGetData(DMIC_Type *base, uint32_t channel)
{
return base->CHANNEL[channel].FIFO_DATA;
}
/*!
* @brief Enable callback.
* This function enables the interrupt for the selected DMIC peripheral.
* The callback function is not enabled until this function is called.
*
* @param base Base address of the DMIC peripheral.
* @param cb callback Pointer to store callback function.
* @retval None.
*/
void DMIC_EnableIntCallback(DMIC_Type *base, dmic_callback_t cb);
/*!
* @brief Disable callback.
* This function disables the interrupt for the selected DMIC peripheral.
*
* @param base Base address of the DMIC peripheral.
* @param cb callback Pointer to store callback function..
* @retval None.
*/
void DMIC_DisableIntCallback(DMIC_Type *base, dmic_callback_t cb);
/**
* @}
*/
/*!
* @name hwvad
* @{
*/
/*!
* @brief Sets the gain value for the noise estimator.
*
* @param base DMIC base pointer
* @param value gain value for the noise estimator.
* @retval None.
*/
static inline void DMIC_SetGainNoiseEstHwvad(DMIC_Type *base, uint32_t value)
{
assert(NULL != base);
base->HWVADTHGN = value & 0xFu;
}
/*!
* @brief Sets the gain value for the signal estimator.
*
* @param base DMIC base pointer
* @param value gain value for the signal estimator.
* @retval None.
*/
static inline void DMIC_SetGainSignalEstHwvad(DMIC_Type *base, uint32_t value)
{
assert(NULL != base);
base->HWVADTHGS = value & 0xFu;
}
/*!
* @brief Sets the hwvad filter cutoff frequency parameter.
*
* @param base DMIC base pointer
* @param value cut off frequency value.
* @retval None.
*/
static inline void DMIC_SetFilterCtrlHwvad(DMIC_Type *base, uint32_t value)
{
assert(NULL != base);
base->HWVADHPFS = value & 0x3u;
}
/*!
* @brief Sets the input gain of hwvad.
*
* @param base DMIC base pointer
* @param value input gain value for hwvad.
* @retval None.
*/
static inline void DMIC_SetInputGainHwvad(DMIC_Type *base, uint32_t value)
{
assert(NULL != base);
base->HWVADGAIN = value & 0xFu;
}
/*!
* @brief Clears hwvad internal interrupt flag.
*
* @param base DMIC base pointer
* @param st10 bit value.
* @retval None.
*/
static inline void DMIC_CtrlClrIntrHwvad(DMIC_Type *base, bool st10)
{
assert(NULL != base);
base->HWVADST10 = (st10) ? 0x1 : 0x0;
}
/*!
* @brief Resets hwvad filters.
*
* @param base DMIC base pointer
* @param rstt Reset bit value.
* @retval None.
*/
static inline void DMIC_FilterResetHwvad(DMIC_Type *base, bool rstt)
{
assert(NULL != base);
base->HWVADRSTT = (rstt) ? 0x1 : 0x0;
}
/*!
* @brief Gets the value from output of the filter z7.
*
* @param base DMIC base pointer
* @retval output of filter z7.
*/
static inline uint16_t DMIC_GetNoiseEnvlpEst(DMIC_Type *base)
{
assert(NULL != base);
return (base->HWVADLOWZ & 0xFFFFu);
}
/*!
* @brief Enable hwvad callback.
* This function enables the hwvad interrupt for the selected DMIC peripheral.
* The callback function is not enabled until this function is called.
*
* @param base Base address of the DMIC peripheral.
* @param vadcb callback Pointer to store callback function.
* @retval None.
*/
void DMIC_HwvadEnableIntCallback(DMIC_Type *base, dmic_hwvad_callback_t vadcb);
/*!
* @brief Disable callback.
* This function disables the hwvad interrupt for the selected DMIC peripheral.
*
* @param base Base address of the DMIC peripheral.
* @param vadcb callback Pointer to store callback function..
* @retval None.
*/
void DMIC_HwvadDisableIntCallback(DMIC_Type *base, dmic_hwvad_callback_t vadcb);
/*! @} */
#ifdef __cplusplus
}
#endif
/*! @}*/
#endif /* __FSL_DMIC_H */

View File

@ -0,0 +1,197 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "fsl_dmic_dma.h"
#include "fsl_dmic.h"
/*******************************************************************************
* Definitions
******************************************************************************/
#define DMIC_HANDLE_ARRAY_SIZE 1
/*<! Structure definition for dmic_dma_handle_t. The structure is private. */
typedef struct _dmic_dma_private_handle
{
DMIC_Type *base;
dmic_dma_handle_t *handle;
} dmic_dma_private_handle_t;
/*! @brief DMIC transfer state, which is used for DMIC transactiaonl APIs' internal state. */
enum _dmic_dma_states_t
{
kDMIC_Idle = 0x0, /*!< DMIC is idle state */
kDMIC_Busy /*!< DMIC is busy tranferring data. */
};
/*******************************************************************************
* Prototypes
******************************************************************************/
/*!
* @brief Get the DMIC instance from peripheral base address.
*
* @param base DMIC peripheral base address.
* @return DMIC instance.
*/
extern uint32_t DMIC_GetInstance(DMIC_Type *base);
/*******************************************************************************
* Variables
******************************************************************************/
/*<! Private handle only used for internally. */
static dmic_dma_private_handle_t s_dmaPrivateHandle[DMIC_HANDLE_ARRAY_SIZE];
/*******************************************************************************
* Code
********************************************************************************/
static void DMIC_TransferReceiveDMACallback(dma_handle_t *handle, void *param, bool transferDone, uint32_t intmode)
{
assert(handle);
assert(param);
dmic_dma_private_handle_t *dmicPrivateHandle = (dmic_dma_private_handle_t *)param;
dmicPrivateHandle->handle->state = kDMIC_Idle;
if (dmicPrivateHandle->handle->callback)
{
dmicPrivateHandle->handle->callback(dmicPrivateHandle->base, dmicPrivateHandle->handle, kStatus_DMIC_Idle,
dmicPrivateHandle->handle->userData);
}
}
status_t DMIC_TransferCreateHandleDMA(DMIC_Type *base,
dmic_dma_handle_t *handle,
dmic_dma_transfer_callback_t callback,
void *userData,
dma_handle_t *rxDmaHandle)
{
int32_t instance = 0;
/* check 'base' */
assert(!(NULL == base));
if (NULL == base)
{
return kStatus_InvalidArgument;
}
/* check 'handle' */
assert(!(NULL == handle));
if (NULL == handle)
{
return kStatus_InvalidArgument;
}
/* check DMIC instance by 'base'*/
instance = DMIC_GetInstance(base);
assert(!(instance < 0));
if (instance < 0)
{
return kStatus_InvalidArgument;
}
memset(handle, 0, sizeof(*handle));
/* assign 'base' and 'handle' */
s_dmaPrivateHandle[instance].base = base;
s_dmaPrivateHandle[instance].handle = handle;
handle->callback = callback;
handle->userData = userData;
handle->rxDmaHandle = rxDmaHandle;
/* Set DMIC state to idle */
handle->state = kDMIC_Idle;
/* Configure RX. */
if (rxDmaHandle)
{
DMA_SetCallback(rxDmaHandle, DMIC_TransferReceiveDMACallback, &s_dmaPrivateHandle[instance]);
}
return kStatus_Success;
}
status_t DMIC_TransferReceiveDMA(DMIC_Type *base,
dmic_dma_handle_t *handle,
dmic_transfer_t *xfer,
uint32_t dmic_channel)
{
assert(handle);
assert(handle->rxDmaHandle);
assert(xfer);
assert(xfer->data);
assert(xfer->dataSize);
dma_transfer_config_t xferConfig;
status_t status;
/* Check if the device is busy. If previous RX not finished.*/
if (handle->state == kDMIC_Busy)
{
status = kStatus_DMIC_Busy;
}
else
{
handle->state = kDMIC_Busy;
handle->transferSize = xfer->dataSize;
/* Prepare transfer. */
DMA_PrepareTransfer(&xferConfig, (void *)&base->CHANNEL[dmic_channel].FIFO_DATA, xfer->data, sizeof(uint16_t),
xfer->dataSize, kDMA_PeripheralToMemory, NULL);
/* Submit transfer. */
DMA_SubmitTransfer(handle->rxDmaHandle, &xferConfig);
DMA_StartTransfer(handle->rxDmaHandle);
status = kStatus_Success;
}
return status;
}
void DMIC_TransferAbortReceiveDMA(DMIC_Type *base, dmic_dma_handle_t *handle)
{
assert(NULL != handle);
assert(NULL != handle->rxDmaHandle);
/* Stop transfer. */
DMA_AbortTransfer(handle->rxDmaHandle);
handle->state = kDMIC_Idle;
}
status_t DMIC_TransferGetReceiveCountDMA(DMIC_Type *base, dmic_dma_handle_t *handle, uint32_t *count)
{
assert(handle);
assert(handle->rxDmaHandle);
assert(count);
if (kDMIC_Idle == handle->state)
{
return kStatus_NoTransferInProgress;
}
*count = handle->transferSize - DMA_GetRemainingBytes(handle->rxDmaHandle->base, handle->rxDmaHandle->channel);
return kStatus_Success;
}

View File

@ -0,0 +1,152 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FSL_DMIC_DMA_H_
#define _FSL_DMIC_DMA_H_
#include "fsl_common.h"
#include "fsl_dma.h"
/*!
* @addtogroup dmic_dma_driver
* @{
*/
/*! @file */
/*******************************************************************************
* Definitions
******************************************************************************/
/*! @brief DMIC transfer structure. */
typedef struct _dmic_transfer
{
uint16_t *data; /*!< The buffer of data to be transfer.*/
size_t dataSize; /*!< The byte count to be transfer. */
} dmic_transfer_t;
/* Forward declaration of the handle typedef. */
typedef struct _dmic_dma_handle dmic_dma_handle_t;
/*! @brief DMIC transfer callback function. */
typedef void (*dmic_dma_transfer_callback_t)(DMIC_Type *base,
dmic_dma_handle_t *handle,
status_t status,
void *userData);
/*!
* @brief DMIC DMA handle
*/
struct _dmic_dma_handle
{
DMIC_Type *base; /*!< DMIC peripheral base address. */
dma_handle_t *rxDmaHandle; /*!< The DMA RX channel used. */
dmic_dma_transfer_callback_t callback; /*!< Callback function. */
void *userData; /*!< DMIC callback function parameter.*/
size_t transferSize; /*!< Size of the data to receive. */
volatile uint8_t state; /*!< Internal state of DMIC DMA transfer */
};
/*******************************************************************************
* API
******************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif /* _cplusplus */
/*!
* @name DMA transactional
* @{
*/
/*!
* @brief Initializes the DMIC handle which is used in transactional functions.
* @param base DMIC peripheral base address.
* @param handle Pointer to dmic_dma_handle_t structure.
* @param callback Callback function.
* @param userData User data.
* @param rxDmaHandle User-requested DMA handle for RX DMA transfer.
*/
status_t DMIC_TransferCreateHandleDMA(DMIC_Type *base,
dmic_dma_handle_t *handle,
dmic_dma_transfer_callback_t callback,
void *userData,
dma_handle_t *rxDmaHandle);
/*!
* @brief Receives data using DMA.
*
* This function receives data using DMA. This is a non-blocking function, which returns
* right away. When all data is received, the receive callback function is called.
*
* @param base USART peripheral base address.
* @param handle Pointer to usart_dma_handle_t structure.
* @param xfer DMIC DMA transfer structure. See #dmic_transfer_t.
* @param dmic_channel DMIC channel
* @retval kStatus_Success
*/
status_t DMIC_TransferReceiveDMA(DMIC_Type *base,
dmic_dma_handle_t *handle,
dmic_transfer_t *xfer,
uint32_t dmic_channel);
/*!
* @brief Aborts the received data using DMA.
*
* This function aborts the received data using DMA.
*
* @param base DMIC peripheral base address
* @param handle Pointer to dmic_dma_handle_t structure
*/
void DMIC_TransferAbortReceiveDMA(DMIC_Type *base, dmic_dma_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 DMIC peripheral base address.
* @param handle DMIC 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 count;
*/
status_t DMIC_TransferGetReceiveCountDMA(DMIC_Type *base, dmic_dma_handle_t *handle, uint32_t *count);
/* @} */
#if defined(__cplusplus)
}
#endif
/*! @}*/
#endif /* _FSL_DMIC_DMA_H_ */

View File

@ -0,0 +1,127 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "fsl_flashiap.h"
#define HZ_TO_KHZ_DIV 1000
/*******************************************************************************
* Code
******************************************************************************/
static status_t translate_iap_status(uint32_t status)
{
/* Translate IAP return code to sdk status code */
if (status == kStatus_Success)
{
return status;
}
else
{
return MAKE_STATUS(kStatusGroup_FLASHIAP, status);
}
}
status_t FLASHIAP_PrepareSectorForWrite(uint32_t startSector, uint32_t endSector)
{
uint32_t command[5], result[4];
command[0] = kIapCmd_FLASHIAP_PrepareSectorforWrite;
command[1] = startSector;
command[2] = endSector;
iap_entry(command, result);
return translate_iap_status(result[0]);
}
status_t FLASHIAP_CopyRamToFlash(uint32_t dstAddr, uint32_t *srcAddr, uint32_t numOfBytes, uint32_t systemCoreClock)
{
uint32_t command[5], result[4];
command[0] = kIapCmd_FLASHIAP_CopyRamToFlash;
command[1] = dstAddr;
command[2] = (uint32_t)srcAddr;
command[3] = numOfBytes;
command[4] = systemCoreClock / HZ_TO_KHZ_DIV;
iap_entry(command, result);
return translate_iap_status(result[0]);
}
status_t FLASHIAP_EraseSector(uint32_t startSector, uint32_t endSector, uint32_t systemCoreClock)
{
uint32_t command[5], result[4];
command[0] = kIapCmd_FLASHIAP_EraseSector;
command[1] = startSector;
command[2] = endSector;
command[3] = systemCoreClock / HZ_TO_KHZ_DIV;
iap_entry(command, result);
return translate_iap_status(result[0]);
}
status_t FLASHIAP_ErasePage(uint32_t startPage, uint32_t endPage, uint32_t systemCoreClock)
{
uint32_t command[5], result[4];
command[0] = kIapCmd_FLASHIAP_ErasePage;
command[1] = startPage;
command[2] = endPage;
command[3] = systemCoreClock / HZ_TO_KHZ_DIV;
iap_entry(command, result);
return translate_iap_status(result[0]);
}
status_t FLASHIAP_BlankCheckSector(uint32_t startSector, uint32_t endSector)
{
uint32_t command[5], result[4];
command[0] = kIapCmd_FLASHIAP_BlankCheckSector;
command[1] = startSector;
command[2] = endSector;
iap_entry(command, result);
return translate_iap_status(result[0]);
}
status_t FLASHIAP_Compare(uint32_t dstAddr, uint32_t *srcAddr, uint32_t numOfBytes)
{
uint32_t command[5], result[4];
command[0] = kIapCmd_FLASHIAP_Compare;
command[1] = dstAddr;
command[2] = (uint32_t)srcAddr;
command[3] = numOfBytes;
iap_entry(command, result);
return translate_iap_status(result[0]);
}

View File

@ -0,0 +1,264 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FSL_FLASHIAP_H_
#define _FSL_FLASHIAP_H_
#include "fsl_common.h"
/*!
* @addtogroup flashiap_driver
* @{
*/
/*! @file */
/*******************************************************************************
* Definitions
******************************************************************************/
/*! @name Driver version */
/*@{*/
#define FSL_FLASHIAP_DRIVER_VERSION (MAKE_VERSION(2, 0, 0)) /*!< Version 2.0.0. */
/*@}*/
/*!
* @brief Flashiap status codes.
*/
enum _flashiap_status
{
kStatus_FLASHIAP_Success = kStatus_Success, /*!< Api is executed successfully */
kStatus_FLASHIAP_InvalidCommand = MAKE_STATUS(kStatusGroup_FLASHIAP, 1U), /*!< Invalid command */
kStatus_FLASHIAP_SrcAddrError =
MAKE_STATUS(kStatusGroup_FLASHIAP, 2U), /*!< Source address is not on word boundary */
kStatus_FLASHIAP_DstAddrError =
MAKE_STATUS(kStatusGroup_FLASHIAP, 3U), /*!< Destination address is not on a correct boundary */
kStatus_FLASHIAP_SrcAddrNotMapped =
MAKE_STATUS(kStatusGroup_FLASHIAP, 4U), /*!< Source address is not mapped in the memory map */
kStatus_FLASHIAP_DstAddrNotMapped =
MAKE_STATUS(kStatusGroup_FLASHIAP, 5U), /*!< Destination address is not mapped in the memory map */
kStatus_FLASHIAP_CountError =
MAKE_STATUS(kStatusGroup_FLASHIAP, 6U), /*!< Byte count is not multiple of 4 or is not a permitted value */
kStatus_FLASHIAP_InvalidSector =
MAKE_STATUS(kStatusGroup_FLASHIAP,
7), /*!< Sector number is invalid or end sector number is greater than start sector number */
kStatus_FLASHIAP_SectorNotblank = MAKE_STATUS(kStatusGroup_FLASHIAP, 8U), /*!< One or more sectors are not blank */
kStatus_FLASHIAP_NotPrepared =
MAKE_STATUS(kStatusGroup_FLASHIAP, 9U), /*!< Command to prepare sector for write operation was not executed */
kStatus_FLASHIAP_CompareError =
MAKE_STATUS(kStatusGroup_FLASHIAP, 10U), /*!< Destination and source memory contents do not match */
kStatus_FLASHIAP_Busy =
MAKE_STATUS(kStatusGroup_FLASHIAP, 11U), /*!< Flash programming hardware interface is busy */
kStatus_FLASHIAP_ParamError =
MAKE_STATUS(kStatusGroup_FLASHIAP, 12U), /*!< Insufficient number of parameters or invalid parameter */
kStatus_FLASHIAP_AddrError = MAKE_STATUS(kStatusGroup_FLASHIAP, 13U), /*!< Address is not on word boundary */
kStatus_FLASHIAP_AddrNotMapped =
MAKE_STATUS(kStatusGroup_FLASHIAP, 14U), /*!< Address is not mapped in the memory map */
kStatus_FLASHIAP_NoPower = MAKE_STATUS(kStatusGroup_FLASHIAP, 24U), /*!< Flash memory block is powered down */
kStatus_FLASHIAP_NoClock =
MAKE_STATUS(kStatusGroup_FLASHIAP, 27U), /*!< Flash memory block or controller is not clocked */
};
/*!
* @brief Flashiap command codes.
*/
enum _flashiap_commands
{
kIapCmd_FLASHIAP_PrepareSectorforWrite = 50U, /*!< Prepare Sector for write */
kIapCmd_FLASHIAP_CopyRamToFlash = 51U, /*!< Copy RAM to flash */
kIapCmd_FLASHIAP_EraseSector = 52U, /*!< Erase Sector */
kIapCmd_FLASHIAP_BlankCheckSector = 53U, /*!< Blank check sector */
kIapCmd_FLASHIAP_ReadPartId = 54U, /*!< Read part id */
kIapCmd_FLASHIAP_Read_BootromVersion = 55U, /*!< Read bootrom version */
kIapCmd_FLASHIAP_Compare = 56U, /*!< Compare */
kIapCmd_FLASHIAP_ReinvokeISP = 57U, /*!< Reinvoke ISP */
kIapCmd_FLASHIAP_ReadUid = 58U, /*!< Read Uid isp */
kIapCmd_FLASHIAP_ErasePage = 59U, /*!< Erase Page */
kIapCmd_FLASHIAP_ReadMisr = 70U, /*!< Read Misr */
kIapCmd_FLASHIAP_ReinvokeI2cSpiISP = 71U /*!< Reinvoke I2C/SPI isp */
};
/*! @brief IAP_ENTRY API function type */
typedef void (*IAP_ENTRY_T)(uint32_t cmd[5], uint32_t stat[4]);
/*******************************************************************************
* API
******************************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif
/*!
* @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.
*
* @retval None. Status/Result is returned via status_result array.
*/
static inline void iap_entry(uint32_t *cmd_param, uint32_t *status_result)
{
((IAP_ENTRY_T)FSL_FEATURE_SYSCON_IAP_ENTRY_LOCATION)(cmd_param, status_result);
}
/*!
* @brief Prepare sector for write operation
* This function prepares sector(s) for write/erase operation. This function must be
* called before calling the FLASHIAP_CopyRamToFlash() or FLASHIAP_EraseSector() or
* FLASHIAP_ErasePage() function. The end sector must be greater than or equal to
* start sector number.
*
* @param startSector Start sector number.
* @param endSector End sector number.
*
* @retval #kStatus_FLASHIAP_Success Api was executed successfully.
* @retval #kStatus_FLASHIAP_NoPower Flash memory block is powered down.
* @retval #kStatus_FLASHIAP_NoClock Flash memory block or controller is not clocked.
* @retval #kStatus_FLASHIAP_InvalidSector Sector number is invalid or end sector number
* is greater than start sector number.
* @retval #kStatus_FLASHIAP_Busy Flash programming hardware interface is busy.
*/
status_t FLASHIAP_PrepareSectorForWrite(uint32_t startSector, uint32_t endSector);
/*!
* @brief Copy RAM to flash.
* This function programs the flash memory. Corresponding sectors must be prepared
* via FLASHIAP_PrepareSectorForWrite before calling 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.
*
* @retval #kStatus_FLASHIAP_Success Api was executed successfully.
* @retval #kStatus_FLASHIAP_NoPower Flash memory block is powered down.
* @retval #kStatus_FLASHIAP_NoClock Flash memory block or controller is not clocked.
* @retval #kStatus_FLASHIAP_SrcAddrError Source address is not on word boundary.
* @retval #kStatus_FLASHIAP_DstAddrError Destination address is not on a correct boundary.
* @retval #kStatus_FLASHIAP_SrcAddrNotMapped Source address is not mapped in the memory map.
* @retval #kStatus_FLASHIAP_DstAddrNotMapped Destination address is not mapped in the memory map.
* @retval #kStatus_FLASHIAP_CountError Byte count is not multiple of 4 or is not a permitted value.
* @retval #kStatus_FLASHIAP_NotPrepared Command to prepare sector for write operation was not executed.
* @retval #kStatus_FLASHIAP_Busy Flash programming hardware interface is busy.
*/
status_t FLASHIAP_CopyRamToFlash(uint32_t dstAddr, uint32_t *srcAddr, uint32_t numOfBytes, uint32_t systemCoreClock);
/*!
* @brief Erase sector
* This function erases sector(s). The end sector must be greater than or equal to
* start sector number. FLASHIAP_PrepareSectorForWrite must be called before
* calling this function.
*
* @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.
*
* @retval #kStatus_FLASHIAP_Success Api was executed successfully.
* @retval #kStatus_FLASHIAP_NoPower Flash memory block is powered down.
* @retval #kStatus_FLASHIAP_NoClock Flash memory block or controller is not clocked.
* @retval #kStatus_FLASHIAP_InvalidSector Sector number is invalid or end sector number
* is greater than start sector number.
* @retval #kStatus_FLASHIAP_NotPrepared Command to prepare sector for write operation was not executed.
* @retval #kStatus_FLASHIAP_Busy Flash programming hardware interface is busy.
*/
status_t FLASHIAP_EraseSector(uint32_t startSector, uint32_t endSector, uint32_t systemCoreClock);
/*!
* This function erases page(s). The end page must be greater than or equal to
* start page number. Corresponding sectors must be prepared via FLASHIAP_PrepareSectorForWrite
* before calling calling this function.
*
* @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.
*
* @retval #kStatus_FLASHIAP_Success Api was executed successfully.
* @retval #kStatus_FLASHIAP_NoPower Flash memory block is powered down.
* @retval #kStatus_FLASHIAP_NoClock Flash memory block or controller is not clocked.
* @retval #kStatus_FLASHIAP_InvalidSector Page number is invalid or end page number
* is greater than start page number
* @retval #kStatus_FLASHIAP_NotPrepared Command to prepare sector for write operation was not executed.
* @retval #kStatus_FLASHIAP_Busy Flash programming hardware interface is busy.
*/
status_t FLASHIAP_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 must be greater than or equal to
* start sector number. It can be used to verify the sector eraseure after FLASHIAP_EraseSector call.
*
* @param startSector : Start sector number. Must be greater than or equal to start sector number
* @param endSector : End sector number
* @retval #kStatus_FLASHIAP_Success One or more sectors are in erased state.
* @retval #kStatus_FLASHIAP_NoPower Flash memory block is powered down.
* @retval #kStatus_FLASHIAP_NoClock Flash memory block or controller is not clocked.
* @retval #kStatus_FLASHIAP_SectorNotblank One or more sectors are not blank.
*/
status_t FLASHIAP_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 FLASHIAP_CopyRamToFlash call.
*
* @param dstAddr Destination flash address.
* @param srcAddr Source ram address.
* @param numOfBytes Number of bytes to be compared.
*
* @retval #kStatus_FLASHIAP_Success Contents of flash and ram match.
* @retval #kStatus_FLASHIAP_NoPower Flash memory block is powered down.
* @retval #kStatus_FLASHIAP_NoClock Flash memory block or controller is not clocked.
* @retval #kStatus_FLASHIAP_AddrError Address is not on word boundary.
* @retval #kStatus_FLASHIAP_AddrNotMapped Address is not mapped in the memory map.
* @retval #kStatus_FLASHIAP_CountError Byte count is not multiple of 4 or is not a permitted value.
* @retval #kStatus_FLASHIAP_CompareError Destination and source memory contents do not match.
*/
status_t FLASHIAP_Compare(uint32_t dstAddr, uint32_t *srcAddr, uint32_t numOfBytes);
#ifdef __cplusplus
}
#endif
/*@}*/
#endif /* _FSL_FLASHIAP_H_ */

View File

@ -0,0 +1,218 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "fsl_common.h"
#include "fsl_flexcomm.h"
/*******************************************************************************
* Definitions
******************************************************************************/
/*******************************************************************************
* 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[] = USART_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;
/*! @brief IDs of clock for each FLEXCOMM module */
static const clock_ip_name_t s_flexcommClocks[] = FLEXCOMM_CLOCKS;
/*******************************************************************************
* 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_USART) && (periph <= FLEXCOMM_PERIPH_I2S_TX))
{
return (base->PSELID & (uint32_t)(1 << ((uint32_t)periph + 3))) > 0 ? true : false;
}
else if (periph == FLEXCOMM_PERIPH_I2S_RX)
{
return (base->PSELID & (1 << 7)) > 0 ? true : false;
}
else
{
return false;
}
}
/* Get the index corresponding to the FLEXCOMM */
uint32_t FLEXCOMM_GetInstance(void *base)
{
int i;
for (i = 0; i < FSL_FEATURE_SOC_FLEXCOMM_COUNT; i++)
{
if ((uint32_t)base == s_flexcommBaseAddrs[i])
{
return i;
}
}
assert(false);
return 0;
}
/* Changes FLEXCOMM mode */
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) && ((base->PSELID & FLEXCOMM_PSELID_PERSEL_MASK) != periph))
{
return kStatus_Fail;
}
/* Check if we are asked to lock */
if (lock)
{
base->PSELID = (uint32_t)periph | FLEXCOMM_PSELID_LOCK_MASK;
}
else
{
base->PSELID = (uint32_t)periph;
}
return kStatus_Success;
}
status_t FLEXCOMM_Init(void *base, FLEXCOMM_PERIPH_T periph)
{
int idx = FLEXCOMM_GetInstance(base);
if (idx < 0)
{
return kStatus_InvalidArgument;
}
/* Enable the peripheral clock */
CLOCK_EnableClock(s_flexcommClocks[idx]);
/* Set the FLEXCOMM to given peripheral */
return FLEXCOMM_SetPeriph((FLEXCOMM_Type *)base, periph, 0);
}
void FLEXCOMM_SetIRQHandler(void *base, flexcomm_irq_handler_t handler, void *handle)
{
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] = handle;
s_flexcommIrqHandler[instance] = handler;
}
/* IRQ handler functions overloading weak symbols in the startup */
void FLEXCOMM0_DriverIRQHandler(void)
{
assert(s_flexcommIrqHandler[0]);
s_flexcommIrqHandler[0]((void *)s_flexcommBaseAddrs[0], s_flexcommHandle[0]);
}
#if (FSL_FEATURE_SOC_FLEXCOMM_COUNT > 1U)
void FLEXCOMM1_DriverIRQHandler(void)
{
assert(s_flexcommIrqHandler[1]);
s_flexcommIrqHandler[1]((void *)s_flexcommBaseAddrs[1], s_flexcommHandle[1]);
}
#endif
#if (FSL_FEATURE_SOC_FLEXCOMM_COUNT > 2U)
void FLEXCOMM2_DriverIRQHandler(void)
{
assert(s_flexcommIrqHandler[2]);
s_flexcommIrqHandler[2]((void *)s_flexcommBaseAddrs[2], s_flexcommHandle[2]);
}
#endif
#if (FSL_FEATURE_SOC_FLEXCOMM_COUNT > 3U)
void FLEXCOMM3_DriverIRQHandler(void)
{
assert(s_flexcommIrqHandler[3]);
s_flexcommIrqHandler[3]((void *)s_flexcommBaseAddrs[3], s_flexcommHandle[3]);
}
#endif
#if (FSL_FEATURE_SOC_FLEXCOMM_COUNT > 4U)
void FLEXCOMM4_DriverIRQHandler(void)
{
assert(s_flexcommIrqHandler[4]);
s_flexcommIrqHandler[4]((void *)s_flexcommBaseAddrs[4], s_flexcommHandle[4]);
}
#endif
#if (FSL_FEATURE_SOC_FLEXCOMM_COUNT > 5U)
void FLEXCOMM5_DriverIRQHandler(void)
{
assert(s_flexcommIrqHandler[5]);
s_flexcommIrqHandler[5]((void *)s_flexcommBaseAddrs[5], s_flexcommHandle[5]);
}
#endif
#if (FSL_FEATURE_SOC_FLEXCOMM_COUNT > 6U)
void FLEXCOMM6_DriverIRQHandler(void)
{
assert(s_flexcommIrqHandler[6]);
s_flexcommIrqHandler[6]((void *)s_flexcommBaseAddrs[6], s_flexcommHandle[6]);
}
#endif
#if (FSL_FEATURE_SOC_FLEXCOMM_COUNT > 7U)
void FLEXCOMM7_DriverIRQHandler(void)
{
assert(s_flexcommIrqHandler[7]);
s_flexcommIrqHandler[7]((void *)s_flexcommBaseAddrs[7], s_flexcommHandle[7]);
}
#endif

View File

@ -0,0 +1,69 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FSL_FLEXCOMM_H_
#define _FSL_FLEXCOMM_H_
#include "fsl_common.h"
/*!
* @addtogroup flexcomm_driver
* @{
*/
/*! @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[];
/*! @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 *handle);
/*@}*/
#endif /* _FSL_FLEXCOMM_H_*/

View File

@ -0,0 +1,61 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "fsl_fmeas.h"
/*******************************************************************************
* Definitions
*******************************************************************************/
/*! @brief Target clock counter value.
* According to user manual, 2 has to be subtracted from captured value (CAPVAL). */
#define TARGET_CLOCK_COUNT(base) \
((uint32_t)( \
((((SYSCON_Type *)base)->FREQMECTRL & SYSCON_FREQMECTRL_CAPVAL_MASK) >> SYSCON_FREQMECTRL_CAPVAL_SHIFT) - 2))
/*! @brief Reference clock counter value. */
#define REFERENCE_CLOCK_COUNT ((uint32_t)((SYSCON_FREQMECTRL_CAPVAL_MASK >> SYSCON_FREQMECTRL_CAPVAL_SHIFT) + 1))
/*******************************************************************************
* Code
******************************************************************************/
uint32_t FMEAS_GetFrequency(SYSCON_Type *base, uint32_t refClockRate)
{
uint32_t targetClockCount = TARGET_CLOCK_COUNT(base);
uint64_t clkrate = 0;
if (targetClockCount > 0)
{
clkrate = (((uint64_t)targetClockCount) * (uint64_t)refClockRate) / REFERENCE_CLOCK_COUNT;
}
return (uint32_t)clkrate;
}

View File

@ -0,0 +1,110 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FSL_FMEAS_H_
#define _FSL_FMEAS_H_
#include "fsl_common.h"
/*!
* @addtogroup fmeas
* @{
*/
/*! @file */
/*******************************************************************************
* Definitions
*******************************************************************************/
/*! @name Driver version */
/*@{*/
/*! @brief Defines LPC Frequency Measure driver version 2.0.0.
*
* Change log:
* - Version 2.0.0
* - initial version
*/
#define FSL_FMEAS_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
/*@}*/
/*******************************************************************************
* API
*******************************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif /* __cplusplus */
/*!
* @name FMEAS Functional Operation
* @{
*/
/*!
* @brief Starts a frequency measurement cycle.
*
* @param base : SYSCON peripheral base address.
*/
static inline void FMEAS_StartMeasure(SYSCON_Type *base)
{
base->FREQMECTRL = 0;
base->FREQMECTRL = (1UL << 31);
}
/*!
* @brief Indicates when a frequency measurement cycle is complete.
*
* @param base : SYSCON peripheral base address.
* @return true if a measurement cycle is active, otherwise false.
*/
static inline bool FMEAS_IsMeasureComplete(SYSCON_Type *base)
{
return (bool)((base->FREQMECTRL & (1UL << 31)) == 0);
}
/*!
* @brief Returns the computed value for a frequency measurement cycle
*
* @param base : SYSCON peripheral base address.
* @param refClockRate : Reference clock rate used during the frequency measurement cycle.
*
* @return Frequency in Hz.
*/
uint32_t FMEAS_GetFrequency(SYSCON_Type *base, uint32_t refClockRate);
/*@}*/
#if defined(__cplusplus)
}
#endif /* __cplusplus */
/*! @}*/
#endif /* _FSL_FMEAS_H_ */

View File

@ -0,0 +1,263 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "fsl_gint.h"
/*******************************************************************************
* Variables
******************************************************************************/
/*! @brief Pointers to GINT bases for each instance. */
static GINT_Type *const s_gintBases[FSL_FEATURE_SOC_GINT_COUNT] = GINT_BASE_PTRS;
/*! @brief Clocks for each instance. */
static const clock_ip_name_t s_gintClocks[FSL_FEATURE_SOC_GINT_COUNT] = GINT_CLOCKS;
/*! @brief Resets for each instance. */
static const reset_ip_name_t s_gintResets[FSL_FEATURE_SOC_GINT_COUNT] = GINT_RSTS;
/* @brief Irq number for each instance */
static const IRQn_Type s_gintIRQ[FSL_FEATURE_SOC_GINT_COUNT] = GINT_IRQS;
/*! @brief Callback function array for GINT(s). */
static gint_cb_t s_gintCallback[FSL_FEATURE_SOC_GINT_COUNT];
/*******************************************************************************
* Code
******************************************************************************/
static uint32_t GINT_GetInstance(GINT_Type *base)
{
uint32_t instance;
/* Find the instance index from base address mappings. */
for (instance = 0; instance < FSL_FEATURE_SOC_GINT_COUNT; instance++)
{
if (s_gintBases[instance] == base)
{
break;
}
}
assert(instance < FSL_FEATURE_SOC_GINT_COUNT);
return instance;
}
void GINT_Init(GINT_Type *base)
{
uint32_t instance;
instance = GINT_GetInstance(base);
s_gintCallback[instance] = NULL;
/* Enable the peripheral clock */
CLOCK_EnableClock(s_gintClocks[instance]);
/* Reset the peripheral */
RESET_PeripheralReset(s_gintResets[instance]);
}
void GINT_SetCtrl(GINT_Type *base, gint_comb_t comb, gint_trig_t trig, gint_cb_t callback)
{
uint32_t instance;
instance = GINT_GetInstance(base);
base->CTRL = (GINT_CTRL_COMB(comb) | GINT_CTRL_TRIG(trig));
/* Save callback pointer */
s_gintCallback[instance] = callback;
}
void GINT_GetCtrl(GINT_Type *base, gint_comb_t *comb, gint_trig_t *trig, gint_cb_t *callback)
{
uint32_t instance;
instance = GINT_GetInstance(base);
*comb = (gint_comb_t)((base->CTRL & GINT_CTRL_COMB_MASK) >> GINT_CTRL_COMB_SHIFT);
*trig = (gint_trig_t)((base->CTRL & GINT_CTRL_TRIG_MASK) >> GINT_CTRL_TRIG_SHIFT);
*callback = s_gintCallback[instance];
}
void GINT_ConfigPins(GINT_Type *base, gint_port_t port, uint32_t polarityMask, uint32_t enableMask)
{
base->PORT_POL[port] = polarityMask;
base->PORT_ENA[port] = enableMask;
}
void GINT_GetConfigPins(GINT_Type *base, gint_port_t port, uint32_t *polarityMask, uint32_t *enableMask)
{
*polarityMask = base->PORT_POL[port];
*enableMask = base->PORT_ENA[port];
}
void GINT_EnableCallback(GINT_Type *base)
{
uint32_t instance;
instance = GINT_GetInstance(base);
/* If GINT is configured in "AND" mode a spurious interrupt is generated.
Clear status and pending interrupt before enabling the irq in NVIC. */
GINT_ClrStatus(base);
NVIC_ClearPendingIRQ(s_gintIRQ[instance]);
EnableIRQ(s_gintIRQ[instance]);
}
void GINT_DisableCallback(GINT_Type *base)
{
uint32_t instance;
instance = GINT_GetInstance(base);
DisableIRQ(s_gintIRQ[instance]);
GINT_ClrStatus(base);
NVIC_ClearPendingIRQ(s_gintIRQ[instance]);
}
void GINT_Deinit(GINT_Type *base)
{
uint32_t instance;
instance = GINT_GetInstance(base);
/* Cleanup */
GINT_DisableCallback(base);
s_gintCallback[instance] = NULL;
/* Reset the peripheral */
RESET_PeripheralReset(s_gintResets[instance]);
/* Disable the peripheral clock */
CLOCK_DisableClock(s_gintClocks[instance]);
}
/* IRQ handler functions overloading weak symbols in the startup */
void GINT0_DriverIRQHandler(void)
{
/* Clear interrupt before callback */
s_gintBases[0]->CTRL |= GINT_CTRL_INT_MASK;
/* Call user function */
if (s_gintCallback[0] != NULL)
{
s_gintCallback[0]();
}
}
#if (FSL_FEATURE_SOC_GINT_COUNT > 1U)
void GINT1_DriverIRQHandler(void)
{
/* Clear interrupt before callback */
s_gintBases[1]->CTRL |= GINT_CTRL_INT_MASK;
/* Call user function */
if (s_gintCallback[1] != NULL)
{
s_gintCallback[1]();
}
}
#endif
#if (FSL_FEATURE_SOC_GINT_COUNT > 2U)
void GINT2_DriverIRQHandler(void)
{
/* Clear interrupt before callback */
s_gintBases[2]->CTRL |= GINT_CTRL_INT_MASK;
/* Call user function */
if (s_gintCallback[2] != NULL)
{
s_gintCallback[2]();
}
}
#endif
#if (FSL_FEATURE_SOC_GINT_COUNT > 3U)
void GINT3_DriverIRQHandler(void)
{
/* Clear interrupt before callback */
s_gintBases[3]->CTRL |= GINT_CTRL_INT_MASK;
/* Call user function */
if (s_gintCallback[3] != NULL)
{
s_gintCallback[3]();
}
}
#endif
#if (FSL_FEATURE_SOC_GINT_COUNT > 4U)
void GINT4_DriverIRQHandler(void)
{
/* Clear interrupt before callback */
s_gintBases[4]->CTRL |= GINT_CTRL_INT_MASK;
/* Call user function */
if (s_gintCallback[4] != NULL)
{
s_gintCallback[4]();
}
}
#endif
#if (FSL_FEATURE_SOC_GINT_COUNT > 5U)
void GINT5_DriverIRQHandler(void)
{
/* Clear interrupt before callback */
s_gintBases[5]->CTRL |= GINT_CTRL_INT_MASK;
/* Call user function */
if (s_gintCallback[5] != NULL)
{
s_gintCallback[5]();
}
}
#endif
#if (FSL_FEATURE_SOC_GINT_COUNT > 6U)
void GINT6_DriverIRQHandler(void)
{
/* Clear interrupt before callback */
s_gintBases[6]->CTRL |= GINT_CTRL_INT_MASK;
/* Call user function */
if (s_gintCallback[6] != NULL)
{
s_gintCallback[6]();
}
}
#endif
#if (FSL_FEATURE_SOC_GINT_COUNT > 7U)
void GINT7_DriverIRQHandler(void)
{
/* Clear interrupt before callback */
s_gintBases[7]->CTRL |= GINT_CTRL_INT_MASK;
/* Call user function */
if (s_gintCallback[7] != NULL)
{
s_gintCallback[7]();
}
}
#endif

View File

@ -0,0 +1,244 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FSL_GINT_H_
#define _FSL_GINT_H_
#include "fsl_common.h"
/*!
* @addtogroup gint_driver
* @{
*/
/*! @file */
/*******************************************************************************
* Definitions
******************************************************************************/
/*! @name Driver version */
/*@{*/
#define FSL_GINT_DRIVER_VERSION (MAKE_VERSION(2, 0, 0)) /*!< Version 2.0.0. */
/*@}*/
/*! @brief GINT combine inputs type */
typedef enum _gint_comb
{
kGINT_CombineOr = 0U, /*!< A grouped interrupt is generated when any one of the enabled inputs is active */
kGINT_CombineAnd = 1U /*!< A grouped interrupt is generated when all enabled inputs are active */
} gint_comb_t;
/*! @brief GINT trigger type */
typedef enum _gint_trig
{
kGINT_TrigEdge = 0U, /*!< Edge triggered based on polarity */
kGINT_TrigLevel = 1U /*!< Level triggered based on polarity */
} gint_trig_t;
/* @brief GINT port type */
typedef enum _gint_port
{
kGINT_Port0 = 0U,
kGINT_Port1 = 1U,
#if defined(FSL_FEATURE_GINT_PORT_COUNT) && (FSL_FEATURE_GINT_PORT_COUNT > 2U)
kGINT_Port2 = 2U,
#endif
#if defined(FSL_FEATURE_GINT_PORT_COUNT) && (FSL_FEATURE_GINT_PORT_COUNT > 3U)
kGINT_Port3 = 3U,
#endif
#if defined(FSL_FEATURE_GINT_PORT_COUNT) && (FSL_FEATURE_GINT_PORT_COUNT > 4U)
kGINT_Port4 = 4U,
#endif
#if defined(FSL_FEATURE_GINT_PORT_COUNT) && (FSL_FEATURE_GINT_PORT_COUNT > 5U)
kGINT_Port5 = 5U,
#endif
#if defined(FSL_FEATURE_GINT_PORT_COUNT) && (FSL_FEATURE_GINT_PORT_COUNT > 6U)
kGINT_Port6 = 6U,
#endif
#if defined(FSL_FEATURE_GINT_PORT_COUNT) && (FSL_FEATURE_GINT_PORT_COUNT > 7U)
kGINT_Port7 = 7U,
#endif
} gint_port_t;
/*! @brief GINT Callback function. */
typedef void (*gint_cb_t)(void);
/*******************************************************************************
* API
******************************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif
/*!
* @brief Initialize GINT peripheral.
* This function initializes the GINT peripheral and enables the clock.
*
* @param base Base address of the GINT peripheral.
*
* @retval None.
*/
void GINT_Init(GINT_Type *base);
/*!
* @brief Setup GINT peripheral control parameters.
* This function sets the control parameters of GINT peripheral.
*
* @param base Base address of the GINT peripheral.
* @param comb Controls if the enabled inputs are logically ORed or ANDed for interrupt generation.
* @param trig Controls if the enabled inputs are level or edge sensitive based on polarity.
* @param callback This function is called when configured group interrupt is generated.
*
* @retval None.
*/
void GINT_SetCtrl(GINT_Type *base, gint_comb_t comb, gint_trig_t trig, gint_cb_t callback);
/*!
* @brief Get GINT peripheral control parameters.
* This function returns the control parameters of GINT peripheral.
*
* @param base Base address of the GINT peripheral.
* @param comb Pointer to store combine input value.
* @param trig Pointer to store trigger value.
* @param callback Pointer to store callback function.
*
* @retval None.
*/
void GINT_GetCtrl(GINT_Type *base, gint_comb_t *comb, gint_trig_t *trig, gint_cb_t *callback);
/*!
* @brief Configure GINT peripheral pins.
* This function enables and controls the polarity of enabled pin(s) of a given port.
*
* @param base Base address of the GINT peripheral.
* @param port Port number.
* @param polarityMask Each bit position selects the polarity of the corresponding enabled pin.
* 0 = The pin is active LOW. 1 = The pin is active HIGH.
* @param enableMask Each bit position selects if the corresponding pin is enabled or not.
* 0 = The pin is disabled. 1 = The pin is enabled.
*
* @retval None.
*/
void GINT_ConfigPins(GINT_Type *base, gint_port_t port, uint32_t polarityMask, uint32_t enableMask);
/*!
* @brief Get GINT peripheral pin configuration.
* This function returns the pin configuration of a given port.
*
* @param base Base address of the GINT peripheral.
* @param port Port number.
* @param polarityMask Pointer to store the polarity mask Each bit position indicates the polarity of the corresponding
enabled pin.
* 0 = The pin is active LOW. 1 = The pin is active HIGH.
* @param enableMask Pointer to store the enable mask. Each bit position indicates if the corresponding pin is enabled
or not.
* 0 = The pin is disabled. 1 = The pin is enabled.
*
* @retval None.
*/
void GINT_GetConfigPins(GINT_Type *base, gint_port_t port, uint32_t *polarityMask, uint32_t *enableMask);
/*!
* @brief Enable callback.
* This function enables the interrupt for the selected GINT peripheral. Although the pin(s) are monitored
* as soon as they are enabled, the callback function is not enabled until this function is called.
*
* @param base Base address of the GINT peripheral.
*
* @retval None.
*/
void GINT_EnableCallback(GINT_Type *base);
/*!
* @brief Disable callback.
* This function disables the interrupt for the selected GINT peripheral. Although the pins are still
* being monitored but the callback function is not called.
*
* @param base Base address of the peripheral.
*
* @retval None.
*/
void GINT_DisableCallback(GINT_Type *base);
/*!
* @brief Clear GINT status.
* This function clears the GINT status bit.
*
* @param base Base address of the GINT peripheral.
*
* @retval None.
*/
static inline void GINT_ClrStatus(GINT_Type *base)
{
base->CTRL |= GINT_CTRL_INT_MASK;
}
/*!
* @brief Get GINT status.
* This function returns the GINT status.
*
* @param base Base address of the GINT peripheral.
*
* @retval status = 0 No group interrupt request. = 1 Group interrupt request active.
*/
static inline uint32_t GINT_GetStatus(GINT_Type *base)
{
return (base->CTRL & GINT_CTRL_INT_MASK);
}
/*!
* @brief Deinitialize GINT peripheral.
* This function disables the GINT clock.
*
* @param base Base address of the GINT peripheral.
*
* @retval None.
*/
void GINT_Deinit(GINT_Type *base);
#ifdef __cplusplus
}
#endif
/*@}*/
#endif /* _FSL_GINT_H_ */

View File

@ -0,0 +1,64 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "fsl_gpio.h"
/*******************************************************************************
* Variables
******************************************************************************/
/*******************************************************************************
* Prototypes
************ ******************************************************************/
/*******************************************************************************
* Code
******************************************************************************/
void GPIO_PinInit(GPIO_Type *base, uint32_t port, uint32_t pin, const gpio_pin_config_t *config)
{
if (config->pinDirection == kGPIO_DigitalInput)
{
base->DIR[port] &= ~(1U << pin);
}
else
{
base->DIR[port] |= 1U << pin;
/* Set default output value */
if (config->outputLogic == 0U)
{
base->CLR[port] = (1U << pin);
}
else
{
base->PIN[port] = (1U << pin);
}
}
}

View File

@ -0,0 +1,250 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SDRVL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#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 1.0.0. */
#define FSL_GPIO_DRIVER_VERSION (MAKE_VERSION(1, 0, 0))
/*@}*/
/*! @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;
/*******************************************************************************
* API
******************************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif
/*! @name GPIO Configuration */
/*@{*/
/*!
* @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_WritePinOutput(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_ReadPinInput(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_SetPinsOutput(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_ClearPinsOutput(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_TogglePinsOutput(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_ReadPinsInput(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_SetPortMask(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_WriteMPort(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_ReadMPort(GPIO_Type *base, uint32_t port)
{
return (uint32_t)base->MPIN[port];
}
/*@}*/
#if defined(__cplusplus)
}
#endif
/*!
* @}
*/
#endif /* _LPC_GPIO_H_*/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,539 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "fsl_i2c_dma.h"
#include "fsl_flexcomm.h"
/*******************************************************************************
* Definitions
******************************************************************************/
/*<! @brief Structure definition for i2c_master_dma_handle_t. The structure is private. */
typedef struct _i2c_master_dma_private_handle
{
I2C_Type *base;
i2c_master_dma_handle_t *handle;
} i2c_master_dma_private_handle_t;
/*******************************************************************************
* Prototypes
******************************************************************************/
/*!
* @brief DMA callback for I2C master DMA driver.
*
* @param handle DMA handler for I2C master DMA driver
* @param userData user param passed to the callback function
*/
static void I2C_MasterTransferCallbackDMA(dma_handle_t *handle, void *userData);
/*!
* @brief Set up master transfer, send slave address and sub address(if any), wait until the
* wait until address sent status return.
*
* @param base I2C peripheral base address.
* @param handle pointer to i2c_master_dma_handle_t structure which stores the transfer state.
* @param xfer pointer to i2c_master_transfer_t structure.
*/
static status_t I2C_InitTransferStateMachineDMA(I2C_Type *base,
i2c_master_dma_handle_t *handle,
i2c_master_transfer_t *xfer);
/*!
* @brief Get the I2C instance from peripheral base address.
*
* @param base I2C peripheral base address.
* @return I2C instance.
*/
extern uint32_t I2C_GetInstance(I2C_Type *base);
/*******************************************************************************
* Variables
******************************************************************************/
/*<! Private handle only used for internally. */
static i2c_master_dma_private_handle_t s_dmaPrivateHandle[FSL_FEATURE_SOC_FLEXCOMM_COUNT];
/*******************************************************************************
* Codes
******************************************************************************/
/*!
* @brief Prepares the transfer state machine and fills in the command buffer.
* @param handle Master nonblocking driver handle.
*/
static status_t I2C_InitTransferStateMachineDMA(I2C_Type *base,
i2c_master_dma_handle_t *handle,
i2c_master_transfer_t *xfer)
{
struct _i2c_master_transfer *transfer;
handle->transfer = *xfer;
transfer = &(handle->transfer);
handle->transferCount = 0;
handle->remainingBytesDMA = 0;
handle->buf = (uint8_t *)transfer->data;
handle->remainingSubaddr = 0;
if (transfer->flags & kI2C_TransferNoStartFlag)
{
/* Start condition shall be ommited, switch directly to next phase */
if (transfer->dataSize == 0)
{
handle->state = kStopState;
}
else if (handle->transfer.direction == kI2C_Write)
{
handle->state = xfer->dataSize = kTransmitDataState;
}
else if (handle->transfer.direction == kI2C_Read)
{
handle->state = (xfer->dataSize == 1) ? kReceiveLastDataState : kReceiveDataState;
}
else
{
return kStatus_I2C_InvalidParameter;
}
}
else
{
if (transfer->subaddressSize != 0)
{
int i;
uint32_t subaddress;
if (transfer->subaddressSize > sizeof(handle->subaddrBuf))
{
return kStatus_I2C_InvalidParameter;
}
/* Prepare subaddress transmit buffer, most significant byte is stored at the lowest address */
subaddress = xfer->subaddress;
for (i = xfer->subaddressSize - 1; i >= 0; i--)
{
handle->subaddrBuf[i] = subaddress & 0xff;
subaddress >>= 8;
}
handle->remainingSubaddr = transfer->subaddressSize;
}
handle->state = kStartState;
}
return kStatus_Success;
}
static void I2C_RunDMATransfer(I2C_Type *base, i2c_master_dma_handle_t *handle)
{
int transfer_size;
dma_transfer_config_t xferConfig;
/* Update transfer count */
handle->transferCount = handle->buf - (uint8_t *)handle->transfer.data;
/* Check if there is anything to be transferred at all */
if (handle->remainingBytesDMA == 0)
{
/* No data to be transferrred, disable DMA */
base->MSTCTL = 0;
return;
}
/* Calculate transfer size */
transfer_size = handle->remainingBytesDMA;
if (transfer_size > I2C_MAX_DMA_TRANSFER_COUNT)
{
transfer_size = I2C_MAX_DMA_TRANSFER_COUNT;
}
switch (handle->transfer.direction)
{
case kI2C_Write:
DMA_PrepareTransfer(&xferConfig, handle->buf, (void *)&base->MSTDAT, sizeof(uint8_t), transfer_size,
kDMA_MemoryToPeripheral, NULL);
break;
case kI2C_Read:
DMA_PrepareTransfer(&xferConfig, (void *)&base->MSTDAT, handle->buf, sizeof(uint8_t), transfer_size,
kDMA_PeripheralToMemory, NULL);
break;
default:
/* This should never happen */
assert(0);
break;
}
DMA_SubmitTransfer(handle->dmaHandle, &xferConfig);
DMA_StartTransfer(handle->dmaHandle);
handle->remainingBytesDMA -= transfer_size;
handle->buf += transfer_size;
}
/*!
* @brief Execute states until the transfer is done.
* @param handle Master nonblocking driver handle.
* @param[out] isDone Set to true if the transfer has completed.
* @retval #kStatus_Success
* @retval #kStatus_I2C_ArbitrationLost
* @retval #kStatus_I2C_Nak
*/
static status_t I2C_RunTransferStateMachineDMA(I2C_Type *base, i2c_master_dma_handle_t *handle, bool *isDone)
{
uint32_t status;
uint32_t master_state;
struct _i2c_master_transfer *transfer;
dma_transfer_config_t xferConfig;
status_t err;
uint32_t start_flag = 0;
transfer = &(handle->transfer);
*isDone = false;
status = I2C_GetStatusFlags(base);
if (status & I2C_STAT_MSTARBLOSS_MASK)
{
I2C_MasterClearStatusFlags(base, I2C_STAT_MSTARBLOSS_MASK);
DMA_AbortTransfer(handle->dmaHandle);
base->MSTCTL = 0;
return kStatus_I2C_ArbitrationLost;
}
if (status & I2C_STAT_MSTSTSTPERR_MASK)
{
I2C_MasterClearStatusFlags(base, I2C_STAT_MSTSTSTPERR_MASK);
DMA_AbortTransfer(handle->dmaHandle);
base->MSTCTL = 0;
return kStatus_I2C_StartStopError;
}
if ((status & I2C_STAT_MSTPENDING_MASK) == 0)
{
return kStatus_I2C_Busy;
}
/* Get the state of the I2C module */
master_state = (status & I2C_STAT_MSTSTATE_MASK) >> I2C_STAT_MSTSTATE_SHIFT;
if ((master_state == I2C_STAT_MSTCODE_NACKADR) || (master_state == I2C_STAT_MSTCODE_NACKDAT))
{
/* Slave NACKed last byte, issue stop and return error */
DMA_AbortTransfer(handle->dmaHandle);
base->MSTCTL = I2C_MSTCTL_MSTSTOP_MASK;
handle->state = kWaitForCompletionState;
return kStatus_I2C_Nak;
}
err = kStatus_Success;
if (handle->state == kStartState)
{
/* set start flag for later use */
start_flag = I2C_MSTCTL_MSTSTART_MASK;
if (handle->remainingSubaddr)
{
base->MSTDAT = (uint32_t)transfer->slaveAddress << 1;
handle->state = kTransmitSubaddrState;
}
else if (transfer->direction == kI2C_Write)
{
base->MSTDAT = (uint32_t)transfer->slaveAddress << 1;
if (transfer->dataSize == 0)
{
/* No data to be transferred, initiate start and schedule stop */
base->MSTCTL = I2C_MSTCTL_MSTSTART_MASK;
handle->state = kStopState;
return err;
}
handle->state = kTransmitDataState;
}
else if ((transfer->direction == kI2C_Read) && (transfer->dataSize > 0))
{
base->MSTDAT = ((uint32_t)transfer->slaveAddress << 1) | 1u;
if (transfer->dataSize == 1)
{
/* The very last byte is always received by means of SW */
base->MSTCTL = I2C_MSTCTL_MSTSTART_MASK;
handle->state = kReceiveLastDataState;
return err;
}
handle->state = kReceiveDataState;
}
else
{
handle->state = kIdleState;
err = kStatus_I2C_UnexpectedState;
return err;
}
}
switch (handle->state)
{
case kTransmitSubaddrState:
if ((master_state != I2C_STAT_MSTCODE_TXREADY) && (!start_flag))
{
return kStatus_I2C_UnexpectedState;
}
base->MSTCTL = start_flag | I2C_MSTCTL_MSTDMA_MASK;
/* Prepare and submit DMA transfer. */
DMA_PrepareTransfer(&xferConfig, handle->subaddrBuf, (void *)&base->MSTDAT, sizeof(uint8_t),
handle->remainingSubaddr, kDMA_MemoryToPeripheral, NULL);
DMA_SubmitTransfer(handle->dmaHandle, &xferConfig);
handle->remainingSubaddr = 0;
if (transfer->dataSize)
{
/* There is data to be transferred, if there is write to read turnaround it is necessary to perform
* repeated start */
handle->state = (transfer->direction == kI2C_Read) ? kStartState : kTransmitDataState;
}
else
{
/* No more data, schedule stop condition */
handle->state = kStopState;
}
break;
case kTransmitDataState:
if ((master_state != I2C_STAT_MSTCODE_TXREADY) && (!start_flag))
{
return kStatus_I2C_UnexpectedState;
}
base->MSTCTL = start_flag | I2C_MSTCTL_MSTDMA_MASK;
handle->remainingBytesDMA = handle->transfer.dataSize;
I2C_RunDMATransfer(base, handle);
/* Schedule stop condition */
handle->state = kStopState;
break;
case kReceiveDataState:
if ((master_state != I2C_STAT_MSTCODE_RXREADY) && (!start_flag))
{
return kStatus_I2C_UnexpectedState;
}
base->MSTCTL = start_flag | I2C_MSTCTL_MSTDMA_MASK;
handle->remainingBytesDMA = handle->transfer.dataSize - 1;
I2C_RunDMATransfer(base, handle);
/* Schedule reception of last data byte */
handle->state = kReceiveLastDataState;
break;
case kReceiveLastDataState:
if (master_state != I2C_STAT_MSTCODE_RXREADY)
{
return kStatus_I2C_UnexpectedState;
}
((uint8_t *)transfer->data)[transfer->dataSize - 1] = base->MSTDAT;
handle->transferCount++;
/* No more data expected, issue NACK and STOP right away */
base->MSTCTL = I2C_MSTCTL_MSTSTOP_MASK;
handle->state = kWaitForCompletionState;
break;
case kStopState:
if (transfer->flags & kI2C_TransferNoStopFlag)
{
/* Stop condition is omitted, we are done */
*isDone = true;
handle->state = kIdleState;
break;
}
/* Send stop condition */
base->MSTCTL = I2C_MSTCTL_MSTSTOP_MASK;
handle->state = kWaitForCompletionState;
break;
case kWaitForCompletionState:
*isDone = true;
handle->state = kIdleState;
break;
case kStartState:
case kIdleState:
default:
/* State machine shall not be invoked again once it enters the idle state */
err = kStatus_I2C_UnexpectedState;
break;
}
return err;
}
void I2C_MasterTransferDMAHandleIRQ(I2C_Type *base, i2c_master_dma_handle_t *handle)
{
bool isDone;
status_t result;
/* Don't do anything if we don't have a valid handle. */
if (!handle)
{
return;
}
result = I2C_RunTransferStateMachineDMA(base, handle, &isDone);
if (isDone || (result != kStatus_Success))
{
/* Disable internal IRQ enables. */
I2C_DisableInterrupts(base,
I2C_INTSTAT_MSTPENDING_MASK | I2C_INTSTAT_MSTARBLOSS_MASK | I2C_INTSTAT_MSTSTSTPERR_MASK);
/* Invoke callback. */
if (handle->completionCallback)
{
handle->completionCallback(base, handle, result, handle->userData);
}
}
}
static void I2C_MasterTransferCallbackDMA(dma_handle_t *handle, void *userData)
{
i2c_master_dma_private_handle_t *dmaPrivateHandle;
/* Don't do anything if we don't have a valid handle. */
if (!handle)
{
return;
}
dmaPrivateHandle = (i2c_master_dma_private_handle_t *)userData;
I2C_RunDMATransfer(dmaPrivateHandle->base, dmaPrivateHandle->handle);
}
void I2C_MasterTransferCreateHandleDMA(I2C_Type *base,
i2c_master_dma_handle_t *handle,
i2c_master_dma_transfer_callback_t callback,
void *userData,
dma_handle_t *dmaHandle)
{
uint32_t instance;
assert(handle);
assert(dmaHandle);
/* Zero handle. */
memset(handle, 0, sizeof(*handle));
/* Look up instance number */
instance = I2C_GetInstance(base);
/* Set the user callback and userData. */
handle->completionCallback = callback;
handle->userData = userData;
FLEXCOMM_SetIRQHandler(base, (flexcomm_irq_handler_t)(uintptr_t)I2C_MasterTransferDMAHandleIRQ, handle);
/* Clear internal IRQ enables and enable NVIC IRQ. */
I2C_DisableInterrupts(base,
I2C_INTSTAT_MSTPENDING_MASK | I2C_INTSTAT_MSTARBLOSS_MASK | I2C_INTSTAT_MSTSTSTPERR_MASK);
EnableIRQ(kFlexcommIrqs[instance]);
/* Set the handle for DMA. */
handle->dmaHandle = dmaHandle;
s_dmaPrivateHandle[instance].base = base;
s_dmaPrivateHandle[instance].handle = handle;
DMA_SetCallback(dmaHandle, (dma_callback)(uintptr_t)I2C_MasterTransferCallbackDMA, &s_dmaPrivateHandle[instance]);
}
status_t I2C_MasterTransferDMA(I2C_Type *base, i2c_master_dma_handle_t *handle, i2c_master_transfer_t *xfer)
{
status_t result;
assert(handle);
assert(xfer);
assert(xfer->subaddressSize <= sizeof(xfer->subaddress));
/* Return busy if another transaction is in progress. */
if (handle->state != kIdleState)
{
return kStatus_I2C_Busy;
}
/* Prepare transfer state machine. */
result = I2C_InitTransferStateMachineDMA(base, handle, xfer);
/* Clear error flags. */
I2C_MasterClearStatusFlags(base, I2C_STAT_MSTARBLOSS_MASK | I2C_STAT_MSTSTSTPERR_MASK);
/* Enable I2C internal IRQ sources */
I2C_EnableInterrupts(base,
I2C_INTSTAT_MSTARBLOSS_MASK | I2C_INTSTAT_MSTSTSTPERR_MASK | I2C_INTSTAT_MSTPENDING_MASK);
return result;
}
status_t I2C_MasterTransferGetCountDMA(I2C_Type *base, i2c_master_dma_handle_t *handle, size_t *count)
{
assert(handle);
if (!count)
{
return kStatus_InvalidArgument;
}
/* Catch when there is not an active transfer. */
if (handle->state == kIdleState)
{
*count = 0;
return kStatus_NoTransferInProgress;
}
/* There is no necessity to disable interrupts as we read a single integer value */
*count = handle->transferCount;
return kStatus_Success;
}
void I2C_MasterTransferAbortDMA(I2C_Type *base, i2c_master_dma_handle_t *handle)
{
DMA_AbortTransfer(handle->dmaHandle);
/* Disable DMA */
base->MSTCTL = 0;
/* Reset the state to idle. */
handle->state = kIdleState;
}

View File

@ -0,0 +1,136 @@
/*
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FSL_I2C_DMA_H_
#define _FSL_I2C_DMA_H_
#include "fsl_i2c.h"
#include "fsl_dma.h"
/*!
* @addtogroup i2c_dma_driver
* @{
*/
/*******************************************************************************
* Definitions
******************************************************************************/
/*! @brief Maximum lenght of single DMA transfer (determined by capability of the DMA engine) */
#define I2C_MAX_DMA_TRANSFER_COUNT 1024
/*! @brief I2C master dma handle typedef. */
typedef struct _i2c_master_dma_handle i2c_master_dma_handle_t;
/*! @brief I2C master dma transfer callback typedef. */
typedef void (*i2c_master_dma_transfer_callback_t)(I2C_Type *base,
i2c_master_dma_handle_t *handle,
status_t status,
void *userData);
/*! @brief I2C master dma transfer structure. */
struct _i2c_master_dma_handle
{
uint8_t state; /*!< Transfer state machine current state. */
uint32_t transferCount; /*!< Indicates progress of the transfer */
uint32_t remainingBytesDMA; /*!< Remaining byte count to be transferred using DMA. */
uint8_t *buf; /*!< Buffer pointer for current state. */
uint32_t remainingSubaddr;
uint8_t subaddrBuf[4];
dma_handle_t *dmaHandle; /*!< The DMA handler used. */
i2c_master_transfer_t transfer; /*!< Copy of the current transfer info. */
i2c_master_dma_transfer_callback_t completionCallback; /*!< Callback function called after dma transfer finished. */
void *userData; /*!< Callback parameter passed to callback function. */
};
/*******************************************************************************
* API
******************************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif /*_cplusplus. */
/*!
* @name I2C Block DMA Transfer Operation
* @{
*/
/*!
* @brief Init the I2C handle which is used in transcational functions
*
* @param base I2C peripheral base address
* @param handle pointer to i2c_master_dma_handle_t structure
* @param callback pointer to user callback function
* @param userData user param passed to the callback function
* @param dmaHandle DMA handle pointer
*/
void I2C_MasterTransferCreateHandleDMA(I2C_Type *base,
i2c_master_dma_handle_t *handle,
i2c_master_dma_transfer_callback_t callback,
void *userData,
dma_handle_t *dmaHandle);
/*!
* @brief Performs a master dma non-blocking transfer on the I2C bus
*
* @param base I2C peripheral base address
* @param handle pointer to i2c_master_dma_handle_t structure
* @param xfer pointer to transfer structure of i2c_master_transfer_t
* @retval kStatus_Success Sucessully complete the data transmission.
* @retval kStatus_I2C_Busy Previous transmission still not finished.
* @retval kStatus_I2C_Timeout Transfer error, wait signal timeout.
* @retval kStatus_I2C_ArbitrationLost Transfer error, arbitration lost.
* @retval kStataus_I2C_Nak Transfer error, receive Nak during transfer.
*/
status_t I2C_MasterTransferDMA(I2C_Type *base, i2c_master_dma_handle_t *handle, i2c_master_transfer_t *xfer);
/*!
* @brief Get master transfer status during a dma non-blocking transfer
*
* @param base I2C peripheral base address
* @param handle pointer to i2c_master_dma_handle_t structure
* @param count Number of bytes transferred so far by the non-blocking transaction.
*/
status_t I2C_MasterTransferGetCountDMA(I2C_Type *base, i2c_master_dma_handle_t *handle, size_t *count);
/*!
* @brief Abort a master dma non-blocking transfer in a early time
*
* @param base I2C peripheral base address
* @param handle pointer to i2c_master_dma_handle_t structure
*/
void I2C_MasterTransferAbortDMA(I2C_Type *base, i2c_master_dma_handle_t *handle);
/* @} */
#if defined(__cplusplus)
}
#endif /*_cplusplus. */
/*@}*/
#endif /*_FSL_I2C_DMA_H_*/

View File

@ -0,0 +1,824 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "fsl_i2s.h"
#include "fsl_flexcomm.h"
#include <string.h>
/*******************************************************************************
* Definitions
******************************************************************************/
/* TODO - absent in device header files, should be there */
#define I2S_FIFOCFG_TXI2SE0_MASK (0x4U)
#define I2S_FIFOCFG_TXI2SE0_SHIFT (2U)
#define I2S_FIFOCFG_TXI2SE0(x) (((uint32_t)(((uint32_t)(x)) << I2S_FIFOCFG_TXI2SE0_SHIFT)) & I2S_FIFOCFG_TXI2SE0_MASK)
#define I2S_FIFOCFG_PACK48_MASK (0x8U)
#define I2S_FIFOCFG_PACK48_SHIFT (3U)
#define I2S_FIFOCFG_PACK48(x) (((uint32_t)(((uint32_t)(x)) << I2S_FIFOCFG_PACK48_SHIFT)) & I2S_FIFOCFG_PACK48_MASK)
/*! @brief I2S states. */
enum _i2s_state
{
kI2S_StateIdle = 0x0, /*!< Not performing transfer */
kI2S_StateTx, /*!< Performing transmit */
kI2S_StateTxWaitToWriteDummyData, /*!< Wait on FIFO in order to write final dummy data there */
kI2S_StateTxWaitForEmptyFifo, /*!< Wait for FIFO to be flushed */
kI2S_StateRx, /*!< Performing receive */
};
/*******************************************************************************
* Prototypes
******************************************************************************/
static void I2S_Config(I2S_Type *base, const i2s_config_t *config);
static status_t I2S_ValidateBuffer(i2s_handle_t *handle, i2s_transfer_t *transfer);
/*******************************************************************************
* Code
******************************************************************************/
void I2S_TxInit(I2S_Type *base, const i2s_config_t *config)
{
uint32_t cfg = 0U;
uint32_t trig = 0U;
FLEXCOMM_Init(base, FLEXCOMM_PERIPH_I2S_TX);
I2S_Config(base, config);
/* Configure FIFO */
cfg |= I2S_FIFOCFG_ENABLETX(1U); /* enable TX FIFO */
cfg |= I2S_FIFOCFG_EMPTYTX(1U); /* empty TX FIFO */
cfg |= I2S_FIFOCFG_TXI2SE0(config->txEmptyZero); /* transmit zero when buffer becomes empty or last item */
cfg |= I2S_FIFOCFG_PACK48(config->pack48); /* set pack 48-bit format or not */
trig |= I2S_FIFOTRIG_TXLVLENA(1U); /* enable TX FIFO trigger */
trig |= I2S_FIFOTRIG_TXLVL(config->watermark); /* set TX FIFO trigger level */
base->FIFOCFG = cfg;
base->FIFOTRIG = trig;
}
void I2S_RxInit(I2S_Type *base, const i2s_config_t *config)
{
uint32_t cfg = 0U;
uint32_t trig = 0U;
FLEXCOMM_Init(base, FLEXCOMM_PERIPH_I2S_RX);
I2S_Config(base, config);
/* Configure FIFO */
cfg |= I2S_FIFOCFG_ENABLERX(1U); /* enable RX FIFO */
cfg |= I2S_FIFOCFG_EMPTYRX(1U); /* empty RX FIFO */
cfg |= I2S_FIFOCFG_PACK48(config->pack48); /* set pack 48-bit format or not */
trig |= I2S_FIFOTRIG_RXLVLENA(1U); /* enable RX FIFO trigger */
trig |= I2S_FIFOTRIG_RXLVL(config->watermark); /* set RX FIFO trigger level */
base->FIFOCFG = cfg;
base->FIFOTRIG = trig;
}
void I2S_TxGetDefaultConfig(i2s_config_t *config)
{
config->masterSlave = kI2S_MasterSlaveNormalMaster;
config->mode = kI2S_ModeI2sClassic;
config->rightLow = false;
config->leftJust = false;
config->pdmData = false;
config->sckPol = false;
config->wsPol = false;
config->divider = 1U;
config->oneChannel = false;
config->dataLength = 16U;
config->frameLength = 32U;
config->position = 0U;
config->watermark = 4U;
config->txEmptyZero = true;
config->pack48 = false;
}
void I2S_RxGetDefaultConfig(i2s_config_t *config)
{
config->masterSlave = kI2S_MasterSlaveNormalSlave;
config->mode = kI2S_ModeI2sClassic;
config->rightLow = false;
config->leftJust = false;
config->pdmData = false;
config->sckPol = false;
config->wsPol = false;
config->divider = 1U;
config->oneChannel = false;
config->dataLength = 16U;
config->frameLength = 32U;
config->position = 0U;
config->watermark = 4U;
config->txEmptyZero = false;
config->pack48 = false;
}
static void I2S_Config(I2S_Type *base, const i2s_config_t *config)
{
assert(config);
uint32_t cfg1 = 0U;
uint32_t cfg2 = 0U;
/* set master/slave configuration */
cfg1 |= I2S_CFG1_MSTSLVCFG(config->masterSlave);
/* set I2S mode */
cfg1 |= I2S_CFG1_MODE(config->mode);
/* set right low (channel swap) */
cfg1 |= I2S_CFG1_RIGHTLOW(config->rightLow);
/* set data justification */
cfg1 |= I2S_CFG1_LEFTJUST(config->leftJust);
/* set source to PDM dmic */
cfg1 |= I2S_CFG1_PDMDATA(config->pdmData);
/* set SCLK polarity */
cfg1 |= I2S_CFG1_SCK_POL(config->sckPol);
/* set WS polarity */
cfg1 |= I2S_CFG1_WS_POL(config->wsPol);
/* set mono mode */
cfg1 |= I2S_CFG1_ONECHANNEL(config->oneChannel);
/* set data length */
cfg1 |= I2S_CFG1_DATALEN(config->dataLength - 1U);
/* set frame length */
cfg2 |= I2S_CFG2_FRAMELEN(config->frameLength - 1U);
/* set data position of this channel pair within the frame */
cfg2 |= I2S_CFG2_POSITION(config->position);
/* write to registers */
base->CFG1 = cfg1;
base->CFG2 = cfg2;
/* set the clock divider */
base->DIV = I2S_DIV_DIV(config->divider - 1U);
}
void I2S_Deinit(I2S_Type *base)
{
/* TODO gate FLEXCOMM clock via FLEXCOMM driver */
}
void I2S_TxEnable(I2S_Type *base, bool enable)
{
if (enable)
{
I2S_EnableInterrupts(base, kI2S_TxErrorFlag | kI2S_TxLevelFlag);
I2S_Enable(base);
}
else
{
I2S_DisableInterrupts(base, kI2S_TxErrorFlag | kI2S_TxLevelFlag);
I2S_Disable(base);
base->FIFOCFG |= I2S_FIFOCFG_EMPTYTX_MASK;
}
}
void I2S_RxEnable(I2S_Type *base, bool enable)
{
if (enable)
{
I2S_EnableInterrupts(base, kI2S_RxErrorFlag | kI2S_RxLevelFlag);
I2S_Enable(base);
}
else
{
I2S_DisableInterrupts(base, kI2S_RxErrorFlag | kI2S_RxLevelFlag);
I2S_Disable(base);
base->FIFOCFG |= I2S_FIFOCFG_EMPTYRX_MASK;
}
}
static status_t I2S_ValidateBuffer(i2s_handle_t *handle, i2s_transfer_t *transfer)
{
assert(transfer->data);
if (!transfer->data)
{
return kStatus_InvalidArgument;
}
assert(transfer->dataSize > 0U);
if (transfer->dataSize <= 0U)
{
return kStatus_InvalidArgument;
}
if (handle->dataLength == 4U)
{
/* No alignment and data length requirements */
}
else if ((handle->dataLength >= 5U) && (handle->dataLength <= 8U))
{
assert((((uint32_t)transfer->data) % 2U) == 0U);
if ((((uint32_t)transfer->data) % 2U) != 0U)
{
/* Data not 2-bytes aligned */
return kStatus_InvalidArgument;
}
assert((transfer->dataSize % 2U) == 0U);
if ((transfer->dataSize % 2U) != 0U)
{
/* Data not in pairs of left/right channel bytes */
return kStatus_InvalidArgument;
}
}
else if ((handle->dataLength >= 9U) && (handle->dataLength <= 16U))
{
assert((((uint32_t)transfer->data) % 4U) == 0U);
if ((((uint32_t)transfer->data) % 4U) != 0U)
{
/* Data not 4-bytes aligned */
return kStatus_InvalidArgument;
}
assert((transfer->dataSize % 4U) == 0U);
if ((transfer->dataSize % 4U) != 0U)
{
/* Data lenght not multiply of 4 */
return kStatus_InvalidArgument;
}
}
else if ((handle->dataLength >= 17U) && (handle->dataLength <= 24U))
{
assert((transfer->dataSize % 6U) == 0U);
if ((transfer->dataSize % 6U) != 0U)
{
/* Data lenght not multiply of 6 */
return kStatus_InvalidArgument;
}
assert(!((handle->pack48) && ((((uint32_t)transfer->data) % 4U) != 0U)));
if ((handle->pack48) && ((((uint32_t)transfer->data) % 4U) != 0U))
{
/* Data not 4-bytes aligned */
return kStatus_InvalidArgument;
}
}
else /* if (handle->dataLength >= 25U) */
{
assert((((uint32_t)transfer->data) % 4U) == 0U);
if ((((uint32_t)transfer->data) % 4U) != 0U)
{
/* Data not 4-bytes aligned */
return kStatus_InvalidArgument;
}
if (handle->oneChannel)
{
assert((transfer->dataSize % 4U) == 0U);
if ((transfer->dataSize % 4U) != 0U)
{
/* Data lenght not multiply of 4 */
return kStatus_InvalidArgument;
}
}
else
{
assert((transfer->dataSize % 8U) == 0U);
if ((transfer->dataSize % 8U) != 0U)
{
/* Data lenght not multiply of 8 */
return kStatus_InvalidArgument;
}
}
}
return kStatus_Success;
}
void I2S_TxTransferCreateHandle(I2S_Type *base, i2s_handle_t *handle, i2s_transfer_callback_t callback, void *userData)
{
assert(handle);
/* Clear out the handle */
memset(handle, 0U, sizeof(*handle));
/* Save callback and user data */
handle->completionCallback = callback;
handle->userData = userData;
/* Remember some items set previously by configuration */
handle->watermark = ((base->FIFOTRIG & I2S_FIFOTRIG_TXLVL_MASK) >> I2S_FIFOTRIG_TXLVL_SHIFT);
handle->oneChannel = ((base->CFG1 & I2S_CFG1_ONECHANNEL_MASK) >> I2S_CFG1_ONECHANNEL_SHIFT);
handle->dataLength = ((base->CFG1 & I2S_CFG1_DATALEN_MASK) >> I2S_CFG1_DATALEN_SHIFT) + 1U;
handle->pack48 = ((base->FIFOCFG & I2S_FIFOCFG_PACK48_MASK) >> I2S_FIFOCFG_PACK48_SHIFT);
handle->useFifo48H = false;
/* Register IRQ handling */
FLEXCOMM_SetIRQHandler(base, (flexcomm_irq_handler_t)(uintptr_t)I2S_TxHandleIRQ, handle);
}
status_t I2S_TxTransferNonBlocking(I2S_Type *base, i2s_handle_t *handle, i2s_transfer_t transfer)
{
assert(handle);
if (!handle)
{
return kStatus_InvalidArgument;
}
status_t result;
result = I2S_ValidateBuffer(handle, &transfer);
if (result != kStatus_Success)
{
return result;
}
if (handle->i2sQueue[handle->queueUser].dataSize)
{
/* Previously prepared buffers not processed yet */
return kStatus_I2S_Busy;
}
handle->state = kI2S_StateTx;
handle->i2sQueue[handle->queueUser].data = transfer.data;
handle->i2sQueue[handle->queueUser].dataSize = transfer.dataSize;
handle->queueUser = (handle->queueUser + 1U) % I2S_NUM_BUFFERS;
base->FIFOTRIG = (base->FIFOTRIG & (~I2S_FIFOTRIG_TXLVL_MASK)) | I2S_FIFOTRIG_TXLVL(handle->watermark);
I2S_TxEnable(base, true);
return kStatus_Success;
}
void I2S_TxTransferAbort(I2S_Type *base, i2s_handle_t *handle)
{
assert(handle);
/* Disable I2S operation and interrupts */
I2S_TxEnable(base, false);
/* Reset state */
handle->state = kI2S_StateIdle;
/* Clear transfer queue */
memset((void *)&handle->i2sQueue, 0U, sizeof(i2s_transfer_t) * I2S_NUM_BUFFERS);
handle->queueDriver = 0U;
handle->queueUser = 0U;
}
void I2S_RxTransferCreateHandle(I2S_Type *base, i2s_handle_t *handle, i2s_transfer_callback_t callback, void *userData)
{
assert(handle);
/* Clear out the handle */
memset(handle, 0U, sizeof(*handle));
/* Save callback and user data */
handle->completionCallback = callback;
handle->userData = userData;
/* Remember some items set previously by configuration */
handle->watermark = ((base->FIFOTRIG & I2S_FIFOTRIG_RXLVL_MASK) >> I2S_FIFOTRIG_RXLVL_SHIFT);
handle->oneChannel = ((base->CFG1 & I2S_CFG1_ONECHANNEL_MASK) >> I2S_CFG1_ONECHANNEL_SHIFT);
handle->dataLength = ((base->CFG1 & I2S_CFG1_DATALEN_MASK) >> I2S_CFG1_DATALEN_SHIFT) + 1U;
handle->pack48 = ((base->FIFOCFG & I2S_FIFOCFG_PACK48_MASK) >> I2S_FIFOCFG_PACK48_SHIFT);
handle->useFifo48H = false;
/* Register IRQ handling */
FLEXCOMM_SetIRQHandler(base, (flexcomm_irq_handler_t)(uintptr_t)I2S_RxHandleIRQ, handle);
}
status_t I2S_RxTransferNonBlocking(I2S_Type *base, i2s_handle_t *handle, i2s_transfer_t transfer)
{
assert(handle);
if (!handle)
{
return kStatus_InvalidArgument;
}
status_t result;
result = I2S_ValidateBuffer(handle, &transfer);
if (result != kStatus_Success)
{
return result;
}
if (handle->i2sQueue[handle->queueUser].dataSize)
{
/* Previously prepared buffers not processed yet */
return kStatus_I2S_Busy;
}
handle->state = kI2S_StateRx;
handle->i2sQueue[handle->queueUser].data = transfer.data;
handle->i2sQueue[handle->queueUser].dataSize = transfer.dataSize;
handle->queueUser = (handle->queueUser + 1U) % I2S_NUM_BUFFERS;
base->FIFOTRIG = (base->FIFOTRIG & (~I2S_FIFOTRIG_RXLVL_MASK)) | I2S_FIFOTRIG_RXLVL(handle->watermark);
I2S_RxEnable(base, true);
return kStatus_Success;
}
void I2S_RxTransferAbort(I2S_Type *base, i2s_handle_t *handle)
{
assert(handle);
/* Disable I2S operation and interrupts */
I2S_RxEnable(base, false);
/* Reset state */
handle->state = kI2S_StateIdle;
/* Clear transfer queue */
memset((void *)&handle->i2sQueue, 0U, sizeof(i2s_transfer_t) * I2S_NUM_BUFFERS);
handle->queueDriver = 0U;
handle->queueUser = 0U;
}
status_t I2S_TransferGetCount(I2S_Type *base, i2s_handle_t *handle, size_t *count)
{
assert(handle);
if (!handle)
{
return kStatus_InvalidArgument;
}
assert(count);
if (!count)
{
return kStatus_InvalidArgument;
}
if (handle->state == kI2S_StateIdle)
{
return kStatus_NoTransferInProgress;
}
*count = handle->transferCount;
return kStatus_Success;
}
status_t I2S_TransferGetErrorCount(I2S_Type *base, i2s_handle_t *handle, size_t *count)
{
assert(handle);
if (!handle)
{
return kStatus_InvalidArgument;
}
assert(count);
if (!count)
{
return kStatus_InvalidArgument;
}
if (handle->state == kI2S_StateIdle)
{
return kStatus_NoTransferInProgress;
}
*count = handle->errorCount;
return kStatus_Success;
}
void I2S_TxHandleIRQ(I2S_Type *base, i2s_handle_t *handle)
{
uint32_t intstat = base->FIFOINTSTAT;
uint32_t data;
if (intstat & I2S_FIFOINTSTAT_TXERR_MASK)
{
handle->errorCount++;
/* Clear TX error interrupt flag */
base->FIFOSTAT = I2S_FIFOSTAT_TXERR(1U);
}
if (intstat & I2S_FIFOINTSTAT_TXLVL_MASK)
{
if (handle->state == kI2S_StateTx)
{
/* Send data */
while ((base->FIFOSTAT & I2S_FIFOSTAT_TXNOTFULL_MASK) &&
(handle->i2sQueue[handle->queueDriver].dataSize > 0U))
{
/* Write output data */
if (handle->dataLength == 4U)
{
data = *(handle->i2sQueue[handle->queueDriver].data);
base->FIFOWR = ((data & 0xF0U) << 12U) | (data & 0xFU);
handle->i2sQueue[handle->queueDriver].data++;
handle->transferCount++;
handle->i2sQueue[handle->queueDriver].dataSize--;
}
else if (handle->dataLength <= 8U)
{
data = *((uint16_t *)handle->i2sQueue[handle->queueDriver].data);
base->FIFOWR = ((data & 0xFF00U) << 8U) | (data & 0xFFU);
handle->i2sQueue[handle->queueDriver].data += sizeof(uint16_t);
handle->transferCount += sizeof(uint16_t);
handle->i2sQueue[handle->queueDriver].dataSize -= sizeof(uint16_t);
}
else if (handle->dataLength <= 16U)
{
base->FIFOWR = *((uint32_t *)(handle->i2sQueue[handle->queueDriver].data));
handle->i2sQueue[handle->queueDriver].data += sizeof(uint32_t);
handle->transferCount += sizeof(uint32_t);
handle->i2sQueue[handle->queueDriver].dataSize -= sizeof(uint32_t);
}
else if (handle->dataLength <= 24U)
{
if (handle->pack48)
{
if (handle->useFifo48H)
{
base->FIFOWR48H = *((uint16_t *)(handle->i2sQueue[handle->queueDriver].data));
handle->i2sQueue[handle->queueDriver].data += sizeof(uint16_t);
handle->transferCount += sizeof(uint16_t);
handle->i2sQueue[handle->queueDriver].dataSize -= sizeof(uint16_t);
handle->useFifo48H = false;
}
else
{
base->FIFOWR = *((uint32_t *)(handle->i2sQueue[handle->queueDriver].data));
handle->i2sQueue[handle->queueDriver].data += sizeof(uint32_t);
handle->transferCount += sizeof(uint32_t);
handle->i2sQueue[handle->queueDriver].dataSize -= sizeof(uint32_t);
handle->useFifo48H = true;
}
}
else
{
data = (uint32_t)(*(handle->i2sQueue[handle->queueDriver].data++));
data |= ((uint32_t)(*(handle->i2sQueue[handle->queueDriver].data++))) << 8U;
data |= ((uint32_t)(*(handle->i2sQueue[handle->queueDriver].data++))) << 16U;
if (handle->useFifo48H)
{
base->FIFOWR48H = data;
handle->useFifo48H = false;
}
else
{
base->FIFOWR = data;
handle->useFifo48H = true;
}
handle->transferCount += 3U;
handle->i2sQueue[handle->queueDriver].dataSize -= 3U;
}
}
else /* if (handle->dataLength <= 32U) */
{
base->FIFOWR = *((uint32_t *)(handle->i2sQueue[handle->queueDriver].data));
handle->i2sQueue[handle->queueDriver].data += sizeof(uint32_t);
handle->transferCount += sizeof(uint32_t);
handle->i2sQueue[handle->queueDriver].dataSize -= sizeof(uint32_t);
}
if (handle->i2sQueue[handle->queueDriver].dataSize == 0U)
{
/* Actual data buffer sent out, switch to a next one */
handle->queueDriver = (handle->queueDriver + 1U) % I2S_NUM_BUFFERS;
/* Notify user */
if (handle->completionCallback)
{
handle->completionCallback(base, handle, kStatus_I2S_BufferComplete, handle->userData);
}
/* Check if the next buffer contains anything to send */
if (handle->i2sQueue[handle->queueDriver].dataSize == 0U)
{
/* Everything has been written to FIFO */
handle->state = kI2S_StateTxWaitToWriteDummyData;
break;
}
}
}
}
else if (handle->state == kI2S_StateTxWaitToWriteDummyData)
{
/* Write dummy data */
if ((handle->dataLength > 16U) && (handle->dataLength < 25U))
{
if (handle->useFifo48H)
{
base->FIFOWR48H = 0U;
handle->useFifo48H = false;
}
else
{
base->FIFOWR = 0U;
base->FIFOWR48H = 0U;
}
}
else
{
base->FIFOWR = 0U;
}
/* Next time invoke this handler when FIFO becomes empty (TX level 0) */
base->FIFOTRIG &= ~I2S_FIFOTRIG_TXLVL_MASK;
handle->state = kI2S_StateTxWaitForEmptyFifo;
}
else if (handle->state == kI2S_StateTxWaitForEmptyFifo)
{
/* FIFO, including additional dummy data, has been emptied now,
* all relevant data should have been output from peripheral */
/* Stop transfer */
I2S_Disable(base);
I2S_DisableInterrupts(base, kI2S_TxErrorFlag | kI2S_TxLevelFlag);
base->FIFOCFG |= I2S_FIFOCFG_EMPTYTX_MASK;
/* Reset state */
handle->state = kI2S_StateIdle;
/* Notify user */
if (handle->completionCallback)
{
handle->completionCallback(base, handle, kStatus_I2S_Done, handle->userData);
}
}
else
{
/* Do nothing */
}
/* Clear TX level interrupt flag */
base->FIFOSTAT = I2S_FIFOSTAT_TXLVL(1U);
}
}
void I2S_RxHandleIRQ(I2S_Type *base, i2s_handle_t *handle)
{
uint32_t intstat = base->FIFOINTSTAT;
uint32_t data;
if (intstat & I2S_FIFOINTSTAT_RXERR_MASK)
{
handle->errorCount++;
/* Clear RX error interrupt flag */
base->FIFOSTAT = I2S_FIFOSTAT_RXERR(1U);
}
if (intstat & I2S_FIFOINTSTAT_RXLVL_MASK)
{
while ((base->FIFOSTAT & I2S_FIFOSTAT_RXNOTEMPTY_MASK) && (handle->i2sQueue[handle->queueDriver].dataSize > 0U))
{
/* Read input data */
if (handle->dataLength == 4U)
{
data = base->FIFORD;
*(handle->i2sQueue[handle->queueDriver].data) = ((data & 0x000F0000U) >> 12U) | (data & 0x0000000FU);
handle->i2sQueue[handle->queueDriver].data++;
handle->transferCount++;
handle->i2sQueue[handle->queueDriver].dataSize--;
}
else if (handle->dataLength <= 8U)
{
data = base->FIFORD;
*((uint16_t *)handle->i2sQueue[handle->queueDriver].data) = ((data >> 8U) & 0xFF00U) | (data & 0xFFU);
handle->i2sQueue[handle->queueDriver].data += sizeof(uint16_t);
handle->transferCount += sizeof(uint16_t);
handle->i2sQueue[handle->queueDriver].dataSize -= sizeof(uint16_t);
}
else if (handle->dataLength <= 16U)
{
data = base->FIFORD;
*((uint32_t *)handle->i2sQueue[handle->queueDriver].data) = data;
handle->i2sQueue[handle->queueDriver].data += sizeof(uint32_t);
handle->transferCount += sizeof(uint32_t);
handle->i2sQueue[handle->queueDriver].dataSize -= sizeof(uint32_t);
}
else if (handle->dataLength <= 24U)
{
if (handle->pack48)
{
if (handle->useFifo48H)
{
data = base->FIFORD48H;
handle->useFifo48H = false;
*((uint16_t *)handle->i2sQueue[handle->queueDriver].data) = data;
handle->i2sQueue[handle->queueDriver].data += sizeof(uint16_t);
handle->transferCount += sizeof(uint16_t);
handle->i2sQueue[handle->queueDriver].dataSize -= sizeof(uint16_t);
}
else
{
data = base->FIFORD;
handle->useFifo48H = true;
*((uint32_t *)handle->i2sQueue[handle->queueDriver].data) = data;
handle->i2sQueue[handle->queueDriver].data += sizeof(uint32_t);
handle->transferCount += sizeof(uint32_t);
handle->i2sQueue[handle->queueDriver].dataSize -= sizeof(uint32_t);
}
}
else
{
if (handle->useFifo48H)
{
data = base->FIFORD48H;
handle->useFifo48H = false;
}
else
{
data = base->FIFORD;
handle->useFifo48H = true;
}
*(handle->i2sQueue[handle->queueDriver].data++) = data & 0xFFU;
*(handle->i2sQueue[handle->queueDriver].data++) = (data >> 8U) & 0xFFU;
*(handle->i2sQueue[handle->queueDriver].data++) = (data >> 16U) & 0xFFU;
handle->transferCount += 3U;
handle->i2sQueue[handle->queueDriver].dataSize -= 3U;
}
}
else /* if (handle->dataLength <= 32U) */
{
data = base->FIFORD;
*((uint32_t *)handle->i2sQueue[handle->queueDriver].data) = data;
handle->i2sQueue[handle->queueDriver].data += sizeof(uint32_t);
handle->transferCount += sizeof(uint32_t);
handle->i2sQueue[handle->queueDriver].dataSize -= sizeof(uint32_t);
}
if (handle->i2sQueue[handle->queueDriver].dataSize == 0U)
{
/* Actual data buffer filled with input data, switch to a next one */
handle->queueDriver = (handle->queueDriver + 1U) % I2S_NUM_BUFFERS;
/* Notify user */
if (handle->completionCallback)
{
handle->completionCallback(base, handle, kStatus_I2S_BufferComplete, handle->userData);
}
if (handle->i2sQueue[handle->queueDriver].dataSize == 0U)
{
/* No other buffer prepared to receive data into */
/* Disable I2S operation and interrupts */
I2S_Disable(base);
I2S_DisableInterrupts(base, kI2S_RxErrorFlag | kI2S_RxLevelFlag);
base->FIFOCFG |= I2S_FIFOCFG_EMPTYRX_MASK;
/* Reset state */
handle->state = kI2S_StateIdle;
/* Notify user */
if (handle->completionCallback)
{
handle->completionCallback(base, handle, kStatus_I2S_Done, handle->userData);
}
/* Clear RX level interrupt flag */
base->FIFOSTAT = I2S_FIFOSTAT_RXLVL(1U);
return;
}
}
}
/* Clear RX level interrupt flag */
base->FIFOSTAT = I2S_FIFOSTAT_RXLVL(1U);
}
}

View File

@ -0,0 +1,483 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FSL_I2S_H_
#define _FSL_I2S_H_
#include "fsl_device_registers.h"
#include "fsl_common.h"
#include "fsl_flexcomm.h"
/*******************************************************************************
* Definitions
******************************************************************************/
/*!
* @addtogroup i2s_driver
* @{
*/
/*! @file */
/*! @name Driver version */
/*@{*/
/*! @brief I2S driver version 2.0.0.
*
* Current version: 2.0.0
*
* Change log:
* - Version 2.0.0
* - initial version
*/
#define FSL_I2S_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
/*@}*/
#ifndef I2S_NUM_BUFFERS
/*! @brief Number of buffers . */
#define I2S_NUM_BUFFERS (4)
#endif
/*! @brief I2S status codes. */
enum _i2s_status
{
kStatus_I2S_BufferComplete =
MAKE_STATUS(kStatusGroup_I2S, 0), /*!< Transfer from/into a single buffer has completed */
kStatus_I2S_Done = MAKE_STATUS(kStatusGroup_I2S, 1), /*!< All buffers transfers have completed */
kStatus_I2S_Busy =
MAKE_STATUS(kStatusGroup_I2S, 2), /*!< Already performing a transfer and cannot queue another buffer */
};
/*!
* @brief I2S flags.
*
* @note These enums are meant to be OR'd together to form a bit mask.
*/
typedef enum _i2s_flags
{
kI2S_TxErrorFlag = I2S_FIFOINTENSET_TXERR_MASK, /*!< TX error interrupt */
kI2S_TxLevelFlag = I2S_FIFOINTENSET_TXLVL_MASK, /*!< TX level interrupt */
kI2S_RxErrorFlag = I2S_FIFOINTENSET_RXERR_MASK, /*!< RX error interrupt */
kI2S_RxLevelFlag = I2S_FIFOINTENSET_RXLVL_MASK /*!< RX level interrupt */
} i2s_flags_t;
/*! @brief Master / slave mode. */
typedef enum _i2s_master_slave
{
kI2S_MasterSlaveNormalSlave = 0x0, /*!< Normal slave */
kI2S_MasterSlaveWsSyncMaster = 0x1, /*!< WS synchronized master */
kI2S_MasterSlaveExtSckMaster = 0x2, /*!< Master using existing SCK */
kI2S_MasterSlaveNormalMaster = 0x3 /*!< Normal master */
} i2s_master_slave_t;
/*! @brief I2S mode. */
typedef enum _i2s_mode
{
kI2S_ModeI2sClassic = 0x0, /*!< I2S classic mode */
kI2S_ModeDspWs50 = 0x1, /*!< DSP mode, WS having 50% duty cycle */
kI2S_ModeDspWsShort = 0x2, /*!< DSP mode, WS having one clock long pulse */
kI2S_ModeDspWsLong = 0x3 /*!< DSP mode, WS having one data slot long pulse */
} i2s_mode_t;
/*! @brief I2S configuration structure. */
typedef struct _i2s_config
{
i2s_master_slave_t masterSlave; /*!< Master / slave configuration */
i2s_mode_t mode; /*!< I2S mode */
bool rightLow; /*!< Right channel data in low portion of FIFO */
bool leftJust; /*!< Left justify data in FIFO */
bool pdmData; /*!< Data source is the D-Mic subsystem */
bool sckPol; /*!< SCK polarity */
bool wsPol; /*!< WS polarity */
uint16_t divider; /*!< Flexcomm function clock divider (1 - 4096) */
bool oneChannel; /*!< true mono, false stereo */
uint8_t dataLength; /*!< Data length (4 - 32) */
uint16_t frameLength; /*!< Frame width (4 - 512) */
uint16_t position; /*!< Data position in the frame */
uint8_t watermark; /*!< FIFO trigger level */
bool txEmptyZero; /*!< Transmit zero when buffer becomes empty or last item */
bool pack48; /*!< Packing format for 48-bit data (false - 24 bit values, true - alternating 32-bit and 16-bit
values) */
} i2s_config_t;
/*! @brief Buffer to transfer from or receive audio data into. */
typedef struct _i2s_transfer
{
volatile uint8_t *data; /*!< Pointer to data buffer. */
volatile size_t dataSize; /*!< Buffer size in bytes. */
} i2s_transfer_t;
/*! @brief Transactional state of the intialized transfer or receive I2S operation. */
typedef struct _i2s_handle i2s_handle_t;
/*!
* @brief Callback function invoked from transactional API
* on completion of a single buffer transfer.
*
* @param base I2S base pointer.
* @param handle pointer to I2S transaction.
* @param completionStatus status of the transaction.
* @param userData optional pointer to user arguments data.
*/
typedef void (*i2s_transfer_callback_t)(I2S_Type *base,
i2s_handle_t *handle,
status_t completionStatus,
void *userData);
/*! @brief Members not to be accessed / modified outside of the driver. */
struct _i2s_handle
{
uint32_t state; /*!< State of transfer */
i2s_transfer_callback_t completionCallback; /*!< Callback function pointer */
void *userData; /*!< Application data passed to callback */
bool oneChannel; /*!< true mono, false stereo */
uint8_t dataLength; /*!< Data length (4 - 32) */
bool pack48; /*!< Packing format for 48-bit data (false - 24 bit values, true - alternating 32-bit and 16-bit
values) */
bool useFifo48H; /*!< When dataLength 17-24: true use FIFOWR48H, false use FIFOWR */
volatile i2s_transfer_t i2sQueue[I2S_NUM_BUFFERS]; /*!< Transfer queue storing transfer buffers */
volatile uint8_t queueUser; /*!< Queue index where user's next transfer will be stored */
volatile uint8_t queueDriver; /*!< Queue index of buffer actually used by the driver */
volatile uint32_t errorCount; /*!< Number of buffer underruns/overruns */
volatile uint32_t transferCount; /*!< Number of bytes transferred */
volatile uint8_t watermark; /*!< FIFO trigger level */
};
/*******************************************************************************
* API
******************************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif
/*!
* @name Initialization and deinitialization
* @{
*/
/*!
* @brief Initializes the FLEXCOMM peripheral for I2S transmit functionality.
*
* Ungates the FLEXCOMM clock and configures the module
* for I2S transmission using a configuration structure.
* The configuration structure can be custom filled or set with default values by
* I2S_TxGetDefaultConfig().
*
* @note This API should be called at the beginning of the application to use
* the I2S driver.
*
* @param base I2S base pointer.
* @param config pointer to I2S configuration structure.
*/
void I2S_TxInit(I2S_Type *base, const i2s_config_t *config);
/*!
* @brief Initializes the FLEXCOMM peripheral for I2S receive functionality.
*
* Ungates the FLEXCOMM clock and configures the module
* for I2S receive using a configuration structure.
* The configuration structure can be custom filled or set with default values by
* I2S_RxGetDefaultConfig().
*
* @note This API should be called at the beginning of the application to use
* the I2S driver.
*
* @param base I2S base pointer.
* @param config pointer to I2S configuration structure.
*/
void I2S_RxInit(I2S_Type *base, const i2s_config_t *config);
/*!
* @brief Sets the I2S Tx configuration structure to default values.
*
* This API initializes the configuration structure for use in I2S_TxInit().
* The initialized structure can remain unchanged in I2S_TxInit(), or it can be modified
* before calling I2S_TxInit().
* Example:
@code
i2s_config_t config;
I2S_TxGetDefaultConfig(&config);
@endcode
*
* Default values:
* @code
* config->masterSlave = kI2S_MasterSlaveNormalMaster;
* config->mode = kI2S_ModeI2sClassic;
* config->rightLow = false;
* config->leftJust = false;
* config->pdmData = false;
* config->sckPol = false;
* config->wsPol = false;
* config->divider = 1;
* config->oneChannel = false;
* config->dataLength = 16;
* config->frameLength = 32;
* config->position = 0;
* config->watermark = 4;
* config->txEmptyZero = true;
* config->pack48 = false;
* @endcode
*
* @param config pointer to I2S configuration structure.
*/
void I2S_TxGetDefaultConfig(i2s_config_t *config);
/*!
* @brief Sets the I2S Rx configuration structure to default values.
*
* This API initializes the configuration structure for use in I2S_RxInit().
* The initialized structure can remain unchanged in I2S_RxInit(), or it can be modified
* before calling I2S_RxInit().
* Example:
@code
i2s_config_t config;
I2S_RxGetDefaultConfig(&config);
@endcode
*
* Default values:
* @code
* config->masterSlave = kI2S_MasterSlaveNormalSlave;
* config->mode = kI2S_ModeI2sClassic;
* config->rightLow = false;
* config->leftJust = false;
* config->pdmData = false;
* config->sckPol = false;
* config->wsPol = false;
* config->divider = 1;
* config->oneChannel = false;
* config->dataLength = 16;
* config->frameLength = 32;
* config->position = 0;
* config->watermark = 4;
* config->txEmptyZero = false;
* config->pack48 = false;
* @endcode
*
* @param config pointer to I2S configuration structure.
*/
void I2S_RxGetDefaultConfig(i2s_config_t *config);
/*!
* @brief De-initializes the I2S peripheral.
*
* This API gates the FLEXCOMM clock. The I2S module can't operate unless I2S_TxInit
* or I2S_RxInit is called to enable the clock.
*
* @param base I2S base pointer.
*/
void I2S_Deinit(I2S_Type *base);
/*! @} */
/*!
* @name Non-blocking API
* @{
*/
/*!
* @brief Initializes handle for transfer of audio data.
*
* @param base I2S base pointer.
* @param handle pointer to handle structure.
* @param callback function to be called back when transfer is done or fails.
* @param userData pointer to data passed to callback.
*/
void I2S_TxTransferCreateHandle(I2S_Type *base, i2s_handle_t *handle, i2s_transfer_callback_t callback, void *userData);
/*!
* @brief Begins or queue sending of the given data.
*
* @param base I2S base pointer.
* @param handle pointer to handle structure.
* @param transfer data buffer.
*
* @retval kStatus_Success
* @retval kStatus_I2S_Busy if all queue slots are occupied with unsent buffers.
*/
status_t I2S_TxTransferNonBlocking(I2S_Type *base, i2s_handle_t *handle, i2s_transfer_t transfer);
/*!
* @brief Aborts sending of data.
*
* @param base I2S base pointer.
* @param handle pointer to handle structure.
*/
void I2S_TxTransferAbort(I2S_Type *base, i2s_handle_t *handle);
/*!
* @brief Initializes handle for reception of audio data.
*
* @param base I2S base pointer.
* @param handle pointer to handle structure.
* @param callback function to be called back when transfer is done or fails.
* @param userData pointer to data passed to callback.
*/
void I2S_RxTransferCreateHandle(I2S_Type *base, i2s_handle_t *handle, i2s_transfer_callback_t callback, void *userData);
/*!
* @brief Begins or queue reception of data into given buffer.
*
* @param base I2S base pointer.
* @param handle pointer to handle structure.
* @param transfer data buffer.
*
* @retval kStatus_Success
* @retval kStatus_I2S_Busy if all queue slots are occupied with buffers which are not full.
*/
status_t I2S_RxTransferNonBlocking(I2S_Type *base, i2s_handle_t *handle, i2s_transfer_t transfer);
/*!
* @brief Aborts receiving of data.
*
* @param base I2S base pointer.
* @param handle pointer to handle structure.
*/
void I2S_RxTransferAbort(I2S_Type *base, i2s_handle_t *handle);
/*!
* @brief Returns number of bytes transferred so far.
*
* @param base I2S base pointer.
* @param handle pointer to handle structure.
* @param[out] count number of bytes transferred so far by the non-blocking transaction.
*
* @retval kStatus_Success
* @retval kStatus_NoTransferInProgress there is no non-blocking transaction currently in progress.
*/
status_t I2S_TransferGetCount(I2S_Type *base, i2s_handle_t *handle, size_t *count);
/*!
* @brief Returns number of buffer underruns or overruns.
*
* @param base I2S base pointer.
* @param handle pointer to handle structure.
* @param[out] count number of transmit errors encountered so far by the non-blocking transaction.
*
* @retval kStatus_Success
* @retval kStatus_NoTransferInProgress there is no non-blocking transaction currently in progress.
*/
status_t I2S_TransferGetErrorCount(I2S_Type *base, i2s_handle_t *handle, size_t *count);
/*! @} */
/*!
* @name Enable / disable
* @{
*/
/*!
* @brief Enables I2S operation.
*
* @param base I2S base pointer.
*/
static inline void I2S_Enable(I2S_Type *base)
{
base->CFG1 |= I2S_CFG1_MAINENABLE(1U);
}
/*!
* @brief Disables I2S operation.
*
* @param base I2S base pointer.
*/
static inline void I2S_Disable(I2S_Type *base)
{
base->CFG1 &= (~I2S_CFG1_MAINENABLE(1U));
}
/*! @} */
/*!
* @name Interrupts
* @{
*/
/*!
* @brief Enables I2S FIFO interrupts.
*
* @param base I2S base pointer.
* @param interruptMask bit mask of interrupts to enable. See #i2s_flags_t for the set
* of constants that should be OR'd together to form the bit mask.
*/
static inline void I2S_EnableInterrupts(I2S_Type *base, uint32_t interruptMask)
{
base->FIFOINTENSET = interruptMask;
}
/*!
* @brief Disables I2S FIFO interrupts.
*
* @param base I2S base pointer.
* @param interruptMask bit mask of interrupts to enable. See #i2s_flags_t for the set
* of constants that should be OR'd together to form the bit mask.
*/
static inline void I2S_DisableInterrupts(I2S_Type *base, uint32_t interruptMask)
{
base->FIFOINTENCLR = interruptMask;
}
/*!
* @brief Returns the set of currently enabled I2S FIFO interrupts.
*
* @param base I2S base pointer.
*
* @return A bitmask composed of #i2s_flags_t enumerators OR'd together
* to indicate the set of enabled interrupts.
*/
static inline uint32_t I2S_GetEnabledInterrupts(I2S_Type *base)
{
return base->FIFOINTENSET;
}
/*!
* @brief Invoked from interrupt handler when transmit FIFO level decreases.
*
* @param base I2S base pointer.
* @param handle pointer to handle structure.
*/
void I2S_TxHandleIRQ(I2S_Type *base, i2s_handle_t *handle);
/*!
* @brief Invoked from interrupt handler when receive FIFO level decreases.
*
* @param base I2S base pointer.
* @param handle pointer to handle structure.
*/
void I2S_RxHandleIRQ(I2S_Type *base, i2s_handle_t *handle);
/*! @} */
/*! @} */
#if defined(__cplusplus)
}
#endif
#endif /* _FSL_I2S_H_ */

View File

@ -0,0 +1,603 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "fsl_dma.h"
#include "fsl_i2s_dma.h"
#include "fsl_flexcomm.h"
#include <string.h>
/*******************************************************************************
* Definitions
******************************************************************************/
#define DMA_MAX_TRANSFER_BYTES (DMA_MAX_TRANSFER_COUNT * sizeof(uint32_t))
#define DMA_DESCRIPTORS (2U)
#define ENQUEUED_BYTES_BUFFER_SIZE (DMA_DESCRIPTORS + 1U)
#define I2S_FIFO_DEPTH (8U)
/*<! @brief Structure for statically allocated private data. */
typedef struct _i2s_dma_private_handle
{
I2S_Type *base; /*!< I2S base address */
i2s_dma_handle_t *handle; /*!< I2S handle */
volatile uint16_t
enqueuedBytes[ENQUEUED_BYTES_BUFFER_SIZE]; /*!< Number of bytes being transferred by DMA descriptors */
volatile uint8_t enqueuedBytesStart; /*!< First item in enqueuedBytes (for reading) */
volatile uint8_t enqueuedBytesEnd; /*!< Last item in enqueuedBytes (for adding) */
volatile bool initialDescriptor; /*!< Initial DMA descriptor transfer not finished yet */
volatile uint8_t
dmaDescriptorsUsed; /*!< Number of DMA descriptors with valid data (in queue, excluding initial descriptor) */
volatile uint8_t descriptor; /*!< Index of next descriptor to be configured with data */
volatile uint8_t queueDescriptor; /*!< Queue index of buffer to be actually consumed by DMA */
volatile i2s_transfer_t descriptorQueue[I2S_NUM_BUFFERS]; /*!< Transfer data as queued to descriptors for DMA */
} i2s_dma_private_handle_t;
/*! @brief I2S DMA transfer private state. */
enum _i2s_dma_state
{
kI2S_DmaStateIdle = 0x0U, /*!< I2S is in idle state */
kI2S_DmaStateTx, /*!< I2S is busy transmitting data */
kI2S_DmaStateRx, /*!< I2S is busy receiving data */
};
/*******************************************************************************
* Prototypes
******************************************************************************/
static status_t I2S_EnqueueUserBuffer(I2S_Type *base, i2s_dma_handle_t *handle, i2s_transfer_t transfer);
static uint32_t I2S_GetInstance(I2S_Type *base);
static void I2S_TxEnableDMA(I2S_Type *base, bool enable);
static void I2S_RxEnableDMA(I2S_Type *base, bool enable);
static status_t I2S_StartTransferDMA(I2S_Type *base, i2s_dma_handle_t *handle);
static status_t I2S_AddTransferDMA(I2S_Type *base, i2s_dma_handle_t *handle, const uint16_t maxSize);
/*******************************************************************************
* Variables
******************************************************************************/
/*<! @brief DMA transfer descriptors. */
#if defined(__ICCARM__)
#pragma data_alignment = 16
static dma_descriptor_t s_DmaDescriptors[DMA_DESCRIPTORS * FSL_FEATURE_SOC_I2S_COUNT];
#elif defined(__CC_ARM)
__attribute__((aligned(16))) static dma_descriptor_t s_DmaDescriptors[DMA_DESCRIPTORS * FSL_FEATURE_SOC_I2S_COUNT];
#elif defined(__GNUC__)
__attribute__((aligned(16))) static dma_descriptor_t s_DmaDescriptors[DMA_DESCRIPTORS * FSL_FEATURE_SOC_I2S_COUNT];
#endif
/*<! @brief Buffer with dummy TX data. */
#if defined(__ICCARM__)
#pragma data_alignment = 4
static uint32_t s_DummyBufferTx = 0U;
#elif defined(__CC_ARM)
__attribute__((aligned(4))) static uint32_t s_DummyBufferTx = 0U;
#elif defined(__GNUC__)
__attribute__((aligned(4))) static uint32_t s_DummyBufferTx = 0U;
#endif
/*<! @brief Buffer to fill with RX data. */
#if defined(__ICCARM__)
#pragma data_alignment = 4
static uint32_t s_DummyBufferRx = 0U;
#elif defined(__CC_ARM)
__attribute__((aligned(4))) static uint32_t s_DummyBufferRx = 0U;
#elif defined(__GNUC__)
__attribute__((aligned(4))) static uint32_t s_DummyBufferRx = 0U;
#endif
/*<! @brief Private array of data associated with available I2S peripherals. */
static i2s_dma_private_handle_t s_DmaPrivateHandle[FSL_FEATURE_SOC_I2S_COUNT];
/*<! @brief Base addresses of available I2S peripherals. */
static const uint32_t s_I2sBaseAddrs[FSL_FEATURE_SOC_I2S_COUNT] = I2S_BASE_ADDRS;
/*******************************************************************************
* Code
******************************************************************************/
static status_t I2S_EnqueueUserBuffer(I2S_Type *base, i2s_dma_handle_t *handle, i2s_transfer_t transfer)
{
uint32_t instance = I2S_GetInstance(base);
i2s_dma_private_handle_t *privateHandle = &(s_DmaPrivateHandle[instance]);
/* Validate input data and tranfer buffer */
assert(handle);
if (!handle)
{
return kStatus_InvalidArgument;
}
assert((((uint32_t)transfer.data) % 4U) == 0U);
if ((((uint32_t)transfer.data) % 4U) != 0U)
{
/* Data not 4-bytes aligned */
return kStatus_InvalidArgument;
}
assert(transfer.dataSize != 0U);
if (transfer.dataSize == 0U)
{
/* No data to send or receive */
return kStatus_InvalidArgument;
}
assert((transfer.dataSize % 4U) == 0U);
if ((transfer.dataSize % 4U) != 0U)
{
/* Data length not multiply of 4 bytes */
return kStatus_InvalidArgument;
}
if (handle->i2sQueue[handle->queueUser].dataSize)
{
/* Previously prepared buffers not processed yet, reject request */
return kStatus_I2S_Busy;
}
/* Enqueue data */
privateHandle->descriptorQueue[handle->queueUser].data = transfer.data;
privateHandle->descriptorQueue[handle->queueUser].dataSize = transfer.dataSize;
handle->i2sQueue[handle->queueUser].data = transfer.data;
handle->i2sQueue[handle->queueUser].dataSize = transfer.dataSize;
handle->queueUser = (handle->queueUser + 1U) % I2S_NUM_BUFFERS;
return kStatus_Success;
}
static uint32_t I2S_GetInstance(I2S_Type *base)
{
uint32_t i;
for (i = 0U; i < FSL_FEATURE_SOC_I2S_COUNT; i++)
{
if ((uint32_t)base == s_I2sBaseAddrs[i])
{
return i;
}
}
assert(false);
return 0U;
}
void I2S_TxTransferCreateHandleDMA(I2S_Type *base,
i2s_dma_handle_t *handle,
dma_handle_t *dmaHandle,
i2s_dma_transfer_callback_t callback,
void *userData)
{
assert(handle);
assert(dmaHandle);
uint32_t instance = I2S_GetInstance(base);
i2s_dma_private_handle_t *privateHandle = &(s_DmaPrivateHandle[instance]);
memset(handle, 0U, sizeof(*handle));
handle->state = kI2S_DmaStateIdle;
handle->dmaHandle = dmaHandle;
handle->completionCallback = callback;
handle->userData = userData;
memset(privateHandle, 0U, sizeof(*privateHandle));
privateHandle->base = base;
privateHandle->handle = handle;
privateHandle->initialDescriptor = false;
DMA_SetCallback(dmaHandle, I2S_DMACallback, privateHandle);
}
status_t I2S_TxTransferSendDMA(I2S_Type *base, i2s_dma_handle_t *handle, i2s_transfer_t transfer)
{
/* Enqueue transfer buffer */
status_t status = I2S_EnqueueUserBuffer(base, handle, transfer);
if (status != kStatus_Success)
{
return status;
}
/* Initialize DMA transfer */
if (handle->state == kI2S_DmaStateIdle)
{
handle->state = kI2S_DmaStateTx;
return I2S_StartTransferDMA(base, handle);
}
return kStatus_Success;
}
void I2S_TransferAbortDMA(I2S_Type *base, i2s_dma_handle_t *handle)
{
assert(handle);
assert(handle->dmaHandle);
uint32_t instance = I2S_GetInstance(base);
i2s_dma_private_handle_t *privateHandle = &(s_DmaPrivateHandle[instance]);
/* Abort operation */
DMA_AbortTransfer(handle->dmaHandle);
if (handle->state == kI2S_DmaStateTx)
{
I2S_TxEnableDMA(base, false);
}
else
{
I2S_RxEnableDMA(base, false);
}
I2S_Disable(base);
/* Reset state */
handle->state = kI2S_DmaStateIdle;
/* Clear transfer queue */
memset((void *)&(handle->i2sQueue), 0U, sizeof(handle->i2sQueue));
handle->queueDriver = 0U;
handle->queueUser = 0U;
/* Clear internal state */
memset((void *)&(privateHandle->descriptorQueue), 0U, sizeof(privateHandle->descriptorQueue));
memset((void *)&(privateHandle->enqueuedBytes), 0U, sizeof(privateHandle->enqueuedBytes));
privateHandle->enqueuedBytesStart = 0U;
privateHandle->enqueuedBytesEnd = 0U;
privateHandle->initialDescriptor = false;
privateHandle->dmaDescriptorsUsed = 0U;
privateHandle->descriptor = 0U;
privateHandle->queueDescriptor = 0U;
}
void I2S_RxTransferCreateHandleDMA(I2S_Type *base,
i2s_dma_handle_t *handle,
dma_handle_t *dmaHandle,
i2s_dma_transfer_callback_t callback,
void *userData)
{
I2S_TxTransferCreateHandleDMA(base, handle, dmaHandle, callback, userData);
}
status_t I2S_RxTransferReceiveDMA(I2S_Type *base, i2s_dma_handle_t *handle, i2s_transfer_t transfer)
{
/* Enqueue transfer buffer */
status_t status = I2S_EnqueueUserBuffer(base, handle, transfer);
if (status != kStatus_Success)
{
return status;
}
/* Initialize DMA transfer */
if (handle->state == kI2S_DmaStateIdle)
{
handle->state = kI2S_DmaStateRx;
return I2S_StartTransferDMA(base, handle);
}
return kStatus_Success;
}
static void I2S_TxEnableDMA(I2S_Type *base, bool enable)
{
if (enable)
{
base->FIFOCFG |= I2S_FIFOCFG_DMATX_MASK;
}
else
{
base->FIFOCFG &= (~I2S_FIFOCFG_DMATX_MASK);
base->FIFOCFG |= I2S_FIFOCFG_EMPTYTX_MASK;
}
}
static void I2S_RxEnableDMA(I2S_Type *base, bool enable)
{
if (enable)
{
base->FIFOCFG |= I2S_FIFOCFG_DMARX_MASK;
}
else
{
base->FIFOCFG &= (~I2S_FIFOCFG_DMARX_MASK);
base->FIFOCFG |= I2S_FIFOCFG_EMPTYRX_MASK;
}
}
static status_t I2S_StartTransferDMA(I2S_Type *base, i2s_dma_handle_t *handle)
{
status_t status;
dma_transfer_config_t xferConfig = {0};
i2s_dma_private_handle_t *privateHandle;
i2s_transfer_t volatile *transfer;
uint16_t transferBytes;
uint32_t instance;
uint32_t i;
instance = I2S_GetInstance(base);
privateHandle = &(s_DmaPrivateHandle[instance]);
transfer = &(privateHandle->descriptorQueue[privateHandle->queueDescriptor]);
/*
* Divide first buffer between initial DMA descriptor and chained DMA descriptors.
* This allows to enqueue more data before entire buffer is processed
* and thus could prevent audio drop-outs due to requeing.
* But user is expected to enqueue more data in order for this to work.
*/
transferBytes = (transfer->dataSize / (DMA_DESCRIPTORS + 1U));
if (transferBytes > DMA_MAX_TRANSFER_BYTES)
{
transferBytes = DMA_MAX_TRANSFER_BYTES;
}
if ((transferBytes % 4U) != 0U)
{
transferBytes -= (transferBytes % 4U);
}
assert(transferBytes > 0U);
if (transferBytes == 0U)
{
/*
* TODO buffer too small to be divided for multiple descriptors
* return invalid argument status for now
*/
return kStatus_InvalidArgument;
}
/* Prepare transfer of data via initial DMA transfer descriptor */
DMA_PrepareTransfer(
&xferConfig, (handle->state == kI2S_DmaStateTx) ? (void *)transfer->data : (void *)&(base->FIFORD),
(handle->state == kI2S_DmaStateTx) ? (void *)&(base->FIFOWR) : (void *)transfer->data, sizeof(uint32_t),
transferBytes, (handle->state == kI2S_DmaStateTx) ? kDMA_MemoryToPeripheral : kDMA_PeripheralToMemory,
(void *)&(s_DmaDescriptors[(instance * FSL_FEATURE_SOC_I2S_COUNT) + 0U]));
privateHandle->initialDescriptor = true; /* For IRQ handler to know that it will be fired for first descriptor */
privateHandle->enqueuedBytes[privateHandle->enqueuedBytesEnd] = transferBytes;
privateHandle->enqueuedBytesEnd = (privateHandle->enqueuedBytesEnd + 1U) % ENQUEUED_BYTES_BUFFER_SIZE;
transfer->dataSize -= transferBytes;
transfer->data += transferBytes;
if (transfer->dataSize == 0U)
{
transfer->data = NULL;
privateHandle->queueDescriptor = (privateHandle->queueDescriptor + 1U) % I2S_NUM_BUFFERS;
}
/* Prepare chained descriptors to transfer 2nd and 3rd part of initial data */
for (i = 0; i < DMA_DESCRIPTORS; i++)
{
if (i == (DMA_DESCRIPTORS - 1))
{
/* Last buffer will take the rest of data (because of possible truncating by division) */
transferBytes = transfer->dataSize;
if (transferBytes > DMA_MAX_TRANSFER_BYTES)
{
transferBytes = DMA_MAX_TRANSFER_BYTES;
}
}
I2S_AddTransferDMA(base, handle, transferBytes);
}
/* Submit and start initial DMA transfer */
if (handle->state == kI2S_DmaStateTx)
{
I2S_TxEnableDMA(base, true);
}
else
{
I2S_RxEnableDMA(base, true);
}
status = DMA_SubmitTransfer(handle->dmaHandle, &xferConfig);
if (status != kStatus_Success)
{
return status;
}
DMA_StartTransfer(handle->dmaHandle);
I2S_Enable(base);
return kStatus_Success;
}
static status_t I2S_AddTransferDMA(I2S_Type *base, i2s_dma_handle_t *handle, const uint16_t maxSize)
{
dma_xfercfg_t xfercfg;
i2s_transfer_t volatile *transfer;
uint16_t transferBytes;
uint32_t instance;
i2s_dma_private_handle_t *privateHandle;
dma_descriptor_t *descriptor;
dma_descriptor_t *nextDescriptor;
instance = I2S_GetInstance(base);
privateHandle = &(s_DmaPrivateHandle[instance]);
if (privateHandle->dmaDescriptorsUsed >= DMA_DESCRIPTORS)
{
/* No unprocessed DMA transfer descriptor */
return kStatus_I2S_Busy;
}
transfer = &(privateHandle->descriptorQueue[privateHandle->queueDescriptor]);
/* Determine currently configured descriptor and the other which it will link to */
descriptor = &(s_DmaDescriptors[(instance * FSL_FEATURE_SOC_I2S_COUNT) + privateHandle->descriptor]);
privateHandle->descriptor = (privateHandle->descriptor + 1U) % DMA_DESCRIPTORS;
nextDescriptor = &(s_DmaDescriptors[(instance * FSL_FEATURE_SOC_I2S_COUNT) + privateHandle->descriptor]);
if (transfer->dataSize == 0U)
{
/* Currently nothing to enqueue, use dummy buffer instead */
xfercfg.valid = false;
xfercfg.reload = true;
xfercfg.swtrig = false;
xfercfg.clrtrig = false;
xfercfg.intA = true;
xfercfg.intB = false;
xfercfg.byteWidth = sizeof(uint32_t);
xfercfg.srcInc = 0U;
xfercfg.dstInc = 0U;
xfercfg.transferCount = I2S_FIFO_DEPTH + 1U;
DMA_CreateDescriptor(descriptor, &xfercfg,
(handle->state == kI2S_DmaStateTx) ? (void *)&s_DummyBufferTx : (void *)&(base->FIFORD),
(handle->state == kI2S_DmaStateTx) ? (void *)&(base->FIFOWR) : (void *)&s_DummyBufferRx,
(void *)nextDescriptor);
/* TODO use API for this once it is available in DMA driver */
descriptor->xfercfg |= DMA_CHANNEL_XFERCFG_CFGVALID(1U);
handle->dmaHandle->base->COMMON->SETVALID = (1U << (handle->dmaHandle->channel));
return kStatus_Success;
}
else if (transfer->dataSize > maxSize)
{
/* Take part of data - DMA transfer limitation */
transferBytes = maxSize;
}
else
{
/* Entire buffer can fit into a single descriptor */
transferBytes = transfer->dataSize;
privateHandle->queueDescriptor = (privateHandle->queueDescriptor + 1U) % I2S_NUM_BUFFERS;
}
privateHandle->enqueuedBytes[privateHandle->enqueuedBytesEnd] = transferBytes;
privateHandle->enqueuedBytesEnd = (privateHandle->enqueuedBytesEnd + 1U) % ENQUEUED_BYTES_BUFFER_SIZE;
/* Configure descriptor */
xfercfg.valid = false;
xfercfg.reload = true;
xfercfg.swtrig = false;
xfercfg.clrtrig = false;
xfercfg.intA = true;
xfercfg.intB = false;
xfercfg.byteWidth = sizeof(uint32_t);
xfercfg.srcInc = (handle->state == kI2S_DmaStateTx) ? 1U : 0U;
xfercfg.dstInc = (handle->state == kI2S_DmaStateTx) ? 0U : 1U;
xfercfg.transferCount = transferBytes / sizeof(uint32_t);
DMA_CreateDescriptor(
descriptor, &xfercfg, (handle->state == kI2S_DmaStateTx) ? (void *)transfer->data : (void *)&(base->FIFORD),
(handle->state == kI2S_DmaStateTx) ? (void *)&(base->FIFOWR) : (void *)transfer->data, (void *)nextDescriptor);
/* TODO use API for this once it is available in DMA driver */
descriptor->xfercfg |= DMA_CHANNEL_XFERCFG_CFGVALID(1U);
handle->dmaHandle->base->COMMON->SETVALID = (1U << (handle->dmaHandle->channel));
/* Advance internal state */
privateHandle->dmaDescriptorsUsed++;
transfer->dataSize -= transferBytes;
transfer->data += transferBytes;
return kStatus_Success;
}
void I2S_DMACallback(dma_handle_t *handle, void *userData, bool transferDone, uint32_t tcds)
{
i2s_dma_private_handle_t *privateHandle = (i2s_dma_private_handle_t *)userData;
i2s_dma_handle_t *i2sHandle = privateHandle->handle;
I2S_Type *base = privateHandle->base;
if (!transferDone)
{
return;
}
if (i2sHandle->i2sQueue[i2sHandle->queueDriver].dataSize == 0U)
{
/*
* All user buffers processed before, dataSize already zero,
* this means at least one dummy buffer sent/received
* and no new buffer enqueued by user meanwhile.
*/
I2S_TransferAbortDMA(base, i2sHandle);
/* Notify user about completion of the final buffer */
if (i2sHandle->completionCallback)
{
(i2sHandle->completionCallback)(base, i2sHandle, kStatus_I2S_Done, i2sHandle->userData);
}
return;
}
if (privateHandle->initialDescriptor)
{
/* Initial descriptor finished, decrease amount of data to be processed */
assert(privateHandle->enqueuedBytes[privateHandle->enqueuedBytesStart] > 0U);
i2sHandle->i2sQueue[i2sHandle->queueDriver].dataSize -=
privateHandle->enqueuedBytes[privateHandle->enqueuedBytesStart];
i2sHandle->i2sQueue[i2sHandle->queueDriver].data +=
privateHandle->enqueuedBytes[privateHandle->enqueuedBytesStart];
privateHandle->enqueuedBytes[privateHandle->enqueuedBytesStart] = 0U;
privateHandle->enqueuedBytesStart = (privateHandle->enqueuedBytesStart + 1U) % ENQUEUED_BYTES_BUFFER_SIZE;
privateHandle->initialDescriptor = false;
}
else
{
if (privateHandle->dmaDescriptorsUsed > 0U)
{
/* Finished one of chained descriptors, decrease amount of data to be processed */
assert(privateHandle->enqueuedBytes[privateHandle->enqueuedBytesStart] > 0U);
i2sHandle->i2sQueue[i2sHandle->queueDriver].dataSize -=
privateHandle->enqueuedBytes[privateHandle->enqueuedBytesStart];
i2sHandle->i2sQueue[i2sHandle->queueDriver].data +=
privateHandle->enqueuedBytes[privateHandle->enqueuedBytesStart];
privateHandle->enqueuedBytes[privateHandle->enqueuedBytesStart] = 0U;
privateHandle->enqueuedBytesStart = (privateHandle->enqueuedBytesStart + 1U) % ENQUEUED_BYTES_BUFFER_SIZE;
privateHandle->dmaDescriptorsUsed--;
}
}
if (i2sHandle->i2sQueue[i2sHandle->queueDriver].dataSize == 0U)
{
/* Entire user buffer sent or received - advance to next one */
i2sHandle->i2sQueue[i2sHandle->queueDriver].data = NULL;
i2sHandle->queueDriver = (i2sHandle->queueDriver + 1U) % I2S_NUM_BUFFERS;
/* Notify user about buffer completion */
if (i2sHandle->completionCallback)
{
(i2sHandle->completionCallback)(base, i2sHandle, kStatus_I2S_BufferComplete, i2sHandle->userData);
}
}
/* Enqueue new chunk of data to DMA (if any) */
I2S_AddTransferDMA(base, i2sHandle, DMA_MAX_TRANSFER_BYTES);
}

View File

@ -0,0 +1,191 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FSL_I2S_DMA_H_
#define _FSL_I2S_DMA_H_
#include "fsl_device_registers.h"
#include "fsl_common.h"
#include "fsl_flexcomm.h"
#include "fsl_dma.h"
#include "fsl_i2s.h"
/*******************************************************************************
* Definitions
******************************************************************************/
/*!
* @addtogroup i2s_dma_driver
* @{
*/
/*! @file */
/*! @name Driver version */
/*@{*/
/*! @brief I2S DMA driver version 2.0.0.
*
* Current version: 2.0.0
*
* Change log:
* - Version 2.0.0
* - initial version
*/
#define FSL_I2S_DMA_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
/*@}*/
/*! @brief Members not to be accessed / modified outside of the driver. */
typedef struct _i2s_dma_handle i2s_dma_handle_t;
/*!
* @brief Callback function invoked from DMA API on completion.
*
* @param base I2S base pointer.
* @param handle pointer to I2S transaction.
* @param completionStatus status of the transaction.
* @param userData optional pointer to user arguments data.
*/
typedef void (*i2s_dma_transfer_callback_t)(I2S_Type *base,
i2s_dma_handle_t *handle,
status_t completionStatus,
void *userData);
struct _i2s_dma_handle
{
uint32_t state; /*!< Internal state of I2S DMA transfer */
i2s_dma_transfer_callback_t completionCallback; /*!< Callback function pointer */
void *userData; /*!< Application data passed to callback */
dma_handle_t *dmaHandle; /*!< DMA handle */
volatile i2s_transfer_t i2sQueue[I2S_NUM_BUFFERS]; /*!< Transfer queue storing transfer buffers */
volatile uint8_t queueUser; /*!< Queue index where user's next transfer will be stored */
volatile uint8_t queueDriver; /*!< Queue index of buffer actually used by the driver */
};
/*******************************************************************************
* API
******************************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif
/*!
* @name Initialization and deinitialization
* @{
*/
/*! @} */
/*!
* @name DMA API
* @{
*/
/*!
* @brief Initializes handle for transfer of audio data.
*
* @param base I2S base pointer.
* @param handle pointer to handle structure.
* @param dmaHandle pointer to dma handle structure.
* @param callback function to be called back when transfer is done or fails.
* @param userData pointer to data passed to callback.
*/
void I2S_TxTransferCreateHandleDMA(I2S_Type *base,
i2s_dma_handle_t *handle,
dma_handle_t *dmaHandle,
i2s_dma_transfer_callback_t callback,
void *userData);
/*!
* @brief Begins or queue sending of the given data.
*
* @param base I2S base pointer.
* @param handle pointer to handle structure.
* @param transfer data buffer.
*
* @retval kStatus_Success
* @retval kStatus_I2S_Busy if all queue slots are occupied with unsent buffers.
*/
status_t I2S_TxTransferSendDMA(I2S_Type *base, i2s_dma_handle_t *handle, i2s_transfer_t transfer);
/*!
* @brief Aborts transfer of data.
*
* @param base I2S base pointer.
* @param handle pointer to handle structure.
*/
void I2S_TransferAbortDMA(I2S_Type *base, i2s_dma_handle_t *handle);
/*!
* @brief Initializes handle for reception of audio data.
*
* @param base I2S base pointer.
* @param handle pointer to handle structure.
* @param dmaHandle pointer to dma handle structure.
* @param callback function to be called back when transfer is done or fails.
* @param userData pointer to data passed to callback.
*/
void I2S_RxTransferCreateHandleDMA(I2S_Type *base,
i2s_dma_handle_t *handle,
dma_handle_t *dmaHandle,
i2s_dma_transfer_callback_t callback,
void *userData);
/*!
* @brief Begins or queue reception of data into given buffer.
*
* @param base I2S base pointer.
* @param handle pointer to handle structure.
* @param transfer data buffer.
*
* @retval kStatus_Success
* @retval kStatus_I2S_Busy if all queue slots are occupied with buffers
* which are not full.
*/
status_t I2S_RxTransferReceiveDMA(I2S_Type *base, i2s_dma_handle_t *handle, i2s_transfer_t transfer);
/*!
* @brief Invoked from DMA interrupt handler.
*
* @param handle pointer to DMA handle structure.
* @param userData argument for user callback.
* @param transferDone if transfer was done.
* @param tcds
*/
void I2S_DMACallback(dma_handle_t *handle, void *userData, bool transferDone, uint32_t tcds);
/*! @} */
/*! @} */
#if defined(__cplusplus)
}
#endif
#endif /* _FSL_I2S_DMA_H_ */

View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "fsl_inputmux.h"
/*******************************************************************************
* Definitions
******************************************************************************/
/*******************************************************************************
* Code
******************************************************************************/
void INPUTMUX_Init(INPUTMUX_Type *base)
{
CLOCK_EnableClock(kCLOCK_InputMux);
}
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)) & 0xffffU;
/* programm signal */
*(volatile uint32_t *)(((uint32_t)base) + pmux_id + (index * 4)) = output_id;
}
void INPUTMUX_Deinit(INPUTMUX_Type *base)
{
CLOCK_DisableClock(kCLOCK_InputMux);
}

View File

@ -0,0 +1,104 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#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, 0)) /*!< Version 2.0.0. */
/*@}*/
/*******************************************************************************
* 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);
/*!
* @brief Deinitialize INPUTMUX peripheral.
* This function disables the INPUTMUX clock.
*
* @param base Base address of the INPUTMUX peripheral.
*
* @retval None.
*/
void INPUTMUX_Deinit(INPUTMUX_Type *base);
#ifdef __cplusplus
}
#endif
/*@}*/
#endif /* _FSL_INPUTMUX_H_ */

View File

@ -0,0 +1,174 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FSL_INPUTMUX_CONNECTIONS_
#define _FSL_INPUTMUX_CONNECTIONS_
/*******************************************************************************
* Definitions
******************************************************************************/
/*!
* @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_ */

View File

@ -0,0 +1,138 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FSL_IOCON_H_
#define _FSL_IOCON_H_
#include "fsl_common.h"
/*!
* @addtogroup lpc_iocon
* @{
*/
/*! @file */
/*******************************************************************************
* Definitions
******************************************************************************/
/*! @name Driver version */
/*@{*/
/*! @brief IOCON driver version 2.0.0. */
#define LPC_IOCON_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
/*@}*/
/**
* @brief Array of IOCON pin definitions passed to IOCON_SetPinMuxing() must be in this format
*/
typedef struct _iocon_group
{
uint32_t port : 8; /* Pin port */
uint32_t pin : 8; /* Pin number */
uint32_t modefunc : 16; /* 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.
*/
#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_MODE_INACT (0x0 << 3) /*!< No addition pin function */
#define IOCON_MODE_PULLDOWN (0x1 << 3) /*!< Selects pull-down function */
#define IOCON_MODE_PULLUP (0x2 << 3) /*!< Selects pull-up function */
#define IOCON_MODE_REPEATER (0x3 << 3) /*!< Selects pin repeater function */
#define IOCON_HYS_EN (0x1 << 5) /*!< Enables hysteresis */
#define IOCON_GPIO_MODE (0x1 << 5) /*!< GPIO Mode */
#define IOCON_I2C_SLEW (0x1 << 5) /*!< I2C Slew Rate Control */
#define IOCON_INV_EN (0x1 << 6) /*!< Enables invert function on input */
#define IOCON_ANALOG_EN (0x0 << 7) /*!< Enables analog function by setting 0 to bit 7 */
#define IOCON_DIGITAL_EN (0x1 << 7) /*!< Enables digital function by setting 1 to bit 7(default) */
#define IOCON_STDI2C_EN (0x1 << 8) /*!< I2C standard mode/fast-mode */
#define IOCON_FASTI2C_EN (0x3 << 8) /*!< I2C Fast-mode Plus and high-speed slave */
#define IOCON_INPFILT_OFF (0x1 << 8) /*!< Input filter Off for GPIO pins */
#define IOCON_INPFILT_ON (0x0 << 8) /*!< Input filter On for GPIO pins */
#define IOCON_OPENDRAIN_EN (0x1 << 10) /*!< Enables open-drain function */
#define IOCON_S_MODE_0CLK (0x0 << 11) /*!< Bypass input filter */
#define IOCON_S_MODE_1CLK (0x1 << 11) /*!< Input pulses shorter than 1 filter clock are rejected */
#define IOCON_S_MODE_2CLK (0x2 << 11) /*!< Input pulses shorter than 2 filter clock2 are rejected */
#define IOCON_S_MODE_3CLK (0x3 << 11) /*!< Input pulses shorter than 3 filter clock2 are rejected */
#define IOCON_S_MODE(clks) ((clks) << 11) /*!< Select clocks for digital input filter mode */
#define IOCON_CLKDIV(div) \
((div) << 13) /*!< Select peripheral clock divider for input filter sampling clock, 2^n, n=0-6 */
#if defined(__cplusplus)
extern "C" {
#endif
/**
* @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;
}
/**
* @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++)
{
IOCON_PinMuxSet(base, pinArray[i].port, pinArray[i].pin, pinArray[i].modefunc);
}
}
/* @} */
#if defined(__cplusplus)
}
#endif
#endif /* _FSL_IOCON_H_ */

View File

@ -0,0 +1,196 @@
/*
* Copyright(C) NXP Semiconductors, 2014
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FSL_MAILBOX_H_
#define _FSL_MAILBOX_H_
#include "fsl_common.h"
/*!
* @addtogroup mailbox
* @{
*/
/*! @file */
/******************************************************************************
* Definitions
*****************************************************************************/
/*! @name Driver version */
/*@{*/
/*! @brief MAILBOX driver version 2.0.0. */
#define FSL_MAILBOX_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
/*@}*/
/*!
* @brief CPU ID.
*/
typedef enum _mailbox_cpu_id
{
kMAILBOX_CM0Plus = 0,
kMAILBOX_CM4
} mailbox_cpu_id_t;
/*******************************************************************************
* API
******************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif
/*!
* @name MAILBOX initialization
* @{
*/
/*!
* @brief Initializes the MAILBOX module.
*
* This function enables the MAILBOX clock only.
*
* @param base MAILBOX peripheral base address.
*/
static inline void MAILBOX_Init(MAILBOX_Type *base)
{
CLOCK_EnableClock(kCLOCK_Mailbox);
}
/*!
* @brief De-initializes the MAILBOX module.
*
* This function disables the MAILBOX clock only.
*
* @param base MAILBOX peripheral base address.
*/
static inline void MAILBOX_Deinit(MAILBOX_Type *base)
{
CLOCK_DisableClock(kCLOCK_Mailbox);
}
/* @} */
/*!
* @brief Set data value in the mailbox based on the CPU ID.
*
* @param base MAILBOX peripheral base address.
* @param cpu_id CPU id, kMAILBOX_CM0Plus is M0+ or kMAILBOX_CM4 is M4.
* @param mboxData Data to send in the mailbox.
*
* @note Sets a data value to send via the MAILBOX to the other core.
*/
static inline void MAILBOX_SetValue(MAILBOX_Type *base, mailbox_cpu_id_t cpu_id, uint32_t mboxData)
{
assert((cpu_id == kMAILBOX_CM0Plus) || (cpu_id == kMAILBOX_CM4));
base->MBOXIRQ[cpu_id].IRQ = mboxData;
}
/*!
* @brief Get data in the mailbox based on the CPU ID.
*
* @param base MAILBOX peripheral base address.
* @param cpu_id CPU id, kMAILBOX_CM0Plus is M0+ or kMAILBOX_CM4 is M4.
*
* @return Current mailbox data.
*/
static inline uint32_t MAILBOX_GetValue(MAILBOX_Type *base, mailbox_cpu_id_t cpu_id)
{
assert((cpu_id == kMAILBOX_CM0Plus) || (cpu_id == kMAILBOX_CM4));
return base->MBOXIRQ[cpu_id].IRQ;
}
/*!
* @brief Set data bits in the mailbox based on the CPU ID.
*
* @param base MAILBOX peripheral base address.
* @param cpu_id CPU id, kMAILBOX_CM0Plus is M0+ or kMAILBOX_CM4 is M4.
* @param mboxSetBits Data bits to set in the mailbox.
*
* @note Sets data bits to send via the MAILBOX to the other core. A value of 0 will
* do nothing. Only sets bits selected with a 1 in it's bit position.
*/
static inline void MAILBOX_SetValueBits(MAILBOX_Type *base, mailbox_cpu_id_t cpu_id, uint32_t mboxSetBits)
{
assert((cpu_id == kMAILBOX_CM0Plus) || (cpu_id == kMAILBOX_CM4));
base->MBOXIRQ[cpu_id].IRQSET = mboxSetBits;
}
/*!
* @brief Clear data bits in the mailbox based on the CPU ID.
*
* @param base MAILBOX peripheral base address.
* @param cpu_id CPU id, kMAILBOX_CM0Plus is M0+ or kMAILBOX_CM4 is M4.
* @param mboxClrBits Data bits to clear in the mailbox.
*
* @note Clear data bits to send via the MAILBOX to the other core. A value of 0 will
* do nothing. Only clears bits selected with a 1 in it's bit position.
*/
static inline void MAILBOX_ClearValueBits(MAILBOX_Type *base, mailbox_cpu_id_t cpu_id, uint32_t mboxClrBits)
{
assert((cpu_id == kMAILBOX_CM0Plus) || (cpu_id == kMAILBOX_CM4));
base->MBOXIRQ[cpu_id].IRQCLR = mboxClrBits;
}
/*!
* @brief Get MUTEX state and lock mutex
*
* @param base MAILBOX peripheral base address.
*
* @return See note
*
* @note Returns '1' if the mutex was taken or '0' if another resources has the
* mutex locked. Once a mutex is taken, it can be returned with the MAILBOX_SetMutex()
* function.
*/
static inline uint32_t MAILBOX_GetMutex(MAILBOX_Type *base)
{
return (base->MUTEX & MAILBOX_MUTEX_EX_MASK);
}
/*!
* @brief Set MUTEX state
*
* @param base MAILBOX peripheral base address.
*
* @note Sets mutex state to '1' and allows other resources to get the mutex.
*/
static inline void MAILBOX_SetMutex(MAILBOX_Type *base)
{
base->MUTEX = MAILBOX_MUTEX_EX_MASK;
}
#if defined(__cplusplus)
}
#endif /*_cplusplus*/
/*@}*/
#endif /* _FSL_MAILBOX_H_ */

View File

@ -0,0 +1,116 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "fsl_mrt.h"
/*******************************************************************************
* Prototypes
******************************************************************************/
/*!
* @brief Gets the instance from the base address
*
* @param base Multi-Rate timer peripheral base address
*
* @return The MRT instance
*/
static uint32_t MRT_GetInstance(MRT_Type *base);
/*******************************************************************************
* Variables
******************************************************************************/
/*! @brief Pointers to MRT bases for each instance. */
static MRT_Type *const s_mrtBases[] = MRT_BASE_PTRS;
/*! @brief Pointers to MRT clocks for each instance. */
static const clock_ip_name_t s_mrtClocks[] = MRT_CLOCKS;
/*! @brief Pointers to MRT resets for each instance. */
static const reset_ip_name_t s_mrtResets[] = MRT_RSTS;
/*******************************************************************************
* Code
******************************************************************************/
static uint32_t MRT_GetInstance(MRT_Type *base)
{
uint32_t instance;
uint32_t mrtArrayCount = (sizeof(s_mrtBases) / sizeof(s_mrtBases[0]));
/* Find the instance index from base address mappings. */
for (instance = 0; instance < mrtArrayCount; instance++)
{
if (s_mrtBases[instance] == base)
{
break;
}
}
assert(instance < mrtArrayCount);
return instance;
}
void MRT_Init(MRT_Type *base, const mrt_config_t *config)
{
assert(config);
/* Ungate the MRT clock */
CLOCK_EnableClock(s_mrtClocks[MRT_GetInstance(base)]);
/* Reset the module */
RESET_PeripheralReset(s_mrtResets[MRT_GetInstance(base)]);
/* Set timer operating mode */
base->MODCFG = MRT_MODCFG_MULTITASK(config->enableMultiTask);
}
void MRT_Deinit(MRT_Type *base)
{
/* Stop all the timers */
MRT_StopTimer(base, kMRT_Channel_0);
MRT_StopTimer(base, kMRT_Channel_1);
MRT_StopTimer(base, kMRT_Channel_2);
MRT_StopTimer(base, kMRT_Channel_3);
/* Gate the MRT clock*/
CLOCK_DisableClock(s_mrtClocks[MRT_GetInstance(base)]);
}
void MRT_UpdateTimerPeriod(MRT_Type *base, mrt_chnl_t channel, uint32_t count, bool immediateLoad)
{
uint32_t newValue = count;
if (((base->CHANNEL[channel].CTRL & MRT_CHANNEL_CTRL_MODE_MASK) == kMRT_OneShotMode) || (immediateLoad))
{
/* For one-shot interrupt mode, load the new value immediately even if user forgot to enable */
newValue |= MRT_CHANNEL_INTVAL_LOAD_MASK;
}
/* Update the timer interval value */
base->CHANNEL[channel].INTVAL = newValue;
}

View File

@ -0,0 +1,371 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FSL_MRT_H_
#define _FSL_MRT_H_
#include "fsl_common.h"
/*!
* @addtogroup mrt
* @{
*/
/*! @file */
/*******************************************************************************
* Definitions
******************************************************************************/
/*! @name Driver version */
/*@{*/
#define FSL_MRT_DRIVER_VERSION (MAKE_VERSION(2, 0, 0)) /*!< Version 2.0.0 */
/*@}*/
/*! @brief List of MRT channels */
typedef enum _mrt_chnl
{
kMRT_Channel_0 = 0U, /*!< MRT channel number 0*/
kMRT_Channel_1, /*!< MRT channel number 1 */
kMRT_Channel_2, /*!< MRT channel number 2 */
kMRT_Channel_3 /*!< MRT channel number 3 */
} mrt_chnl_t;
/*! @brief List of MRT timer modes */
typedef enum _mrt_timer_mode
{
kMRT_RepeatMode = (0 << MRT_CHANNEL_CTRL_MODE_SHIFT), /*!< Repeat Interrupt mode */
kMRT_OneShotMode = (1 << MRT_CHANNEL_CTRL_MODE_SHIFT), /*!< One-shot Interrupt mode */
kMRT_OneShotStallMode = (2 << MRT_CHANNEL_CTRL_MODE_SHIFT) /*!< One-shot stall mode */
} mrt_timer_mode_t;
/*! @brief List of MRT interrupts */
typedef enum _mrt_interrupt_enable
{
kMRT_TimerInterruptEnable = MRT_CHANNEL_CTRL_INTEN_MASK /*!< Timer interrupt enable*/
} mrt_interrupt_enable_t;
/*! @brief List of MRT status flags */
typedef enum _mrt_status_flags
{
kMRT_TimerInterruptFlag = MRT_CHANNEL_STAT_INTFLAG_MASK, /*!< Timer interrupt flag */
kMRT_TimerRunFlag = MRT_CHANNEL_STAT_RUN_MASK, /*!< Indicates state of the timer */
} mrt_status_flags_t;
/*!
* @brief MRT configuration structure
*
* This structure holds the configuration settings for the MRT peripheral. To initialize this
* structure to reasonable defaults, call the MRT_GetDefaultConfig() function and pass a
* pointer to your config structure instance.
*
* The config struct can be made const so it resides in flash
*/
typedef struct _mrt_config
{
bool enableMultiTask; /*!< true: Timers run in multi-task mode; false: Timers run in hardware status mode */
} mrt_config_t;
/*******************************************************************************
* API
******************************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif
/*!
* @name Initialization and deinitialization
* @{
*/
/*!
* @brief Ungates the MRT clock and configures the peripheral for basic operation.
*
* @note This API should be called at the beginning of the application using the MRT driver.
*
* @param base Multi-Rate timer peripheral base address
* @param config Pointer to user's MRT config structure
*/
void MRT_Init(MRT_Type *base, const mrt_config_t *config);
/*!
* @brief Gate the MRT clock
*
* @param base Multi-Rate timer peripheral base address
*/
void MRT_Deinit(MRT_Type *base);
/*!
* @brief Fill in the MRT config struct with the default settings
*
* The default values are:
* @code
* config->enableMultiTask = false;
* @endcode
* @param config Pointer to user's MRT config structure.
*/
static inline void MRT_GetDefaultConfig(mrt_config_t *config)
{
assert(config);
/* Use hardware status operating mode */
config->enableMultiTask = false;
}
/*!
* @brief Sets up an MRT channel mode.
*
* @param base Multi-Rate timer peripheral base address
* @param channel Channel that is being configured.
* @param mode Timer mode to use for the channel.
*/
static inline void MRT_SetupChannelMode(MRT_Type *base, mrt_chnl_t channel, const mrt_timer_mode_t mode)
{
uint32_t reg = base->CHANNEL[channel].CTRL;
/* Clear old value */
reg &= ~MRT_CHANNEL_CTRL_MODE_MASK;
/* Add the new mode */
reg |= mode;
base->CHANNEL[channel].CTRL = reg;
}
/*! @}*/
/*!
* @name Interrupt Interface
* @{
*/
/*!
* @brief Enables the MRT interrupt.
*
* @param base Multi-Rate timer peripheral base address
* @param channel Timer channel number
* @param mask The interrupts to enable. This is a logical OR of members of the
* enumeration ::mrt_interrupt_enable_t
*/
static inline void MRT_EnableInterrupts(MRT_Type *base, mrt_chnl_t channel, uint32_t mask)
{
base->CHANNEL[channel].CTRL |= mask;
}
/*!
* @brief Disables the selected MRT interrupt.
*
* @param base Multi-Rate timer peripheral base address
* @param channel Timer channel number
* @param mask The interrupts to disable. This is a logical OR of members of the
* enumeration ::mrt_interrupt_enable_t
*/
static inline void MRT_DisableInterrupts(MRT_Type *base, mrt_chnl_t channel, uint32_t mask)
{
base->CHANNEL[channel].CTRL &= ~mask;
}
/*!
* @brief Gets the enabled MRT interrupts.
*
* @param base Multi-Rate timer peripheral base address
* @param channel Timer channel number
*
* @return The enabled interrupts. This is the logical OR of members of the
* enumeration ::mrt_interrupt_enable_t
*/
static inline uint32_t MRT_GetEnabledInterrupts(MRT_Type *base, mrt_chnl_t channel)
{
return (base->CHANNEL[channel].CTRL & MRT_CHANNEL_CTRL_INTEN_MASK);
}
/*! @}*/
/*!
* @name Status Interface
* @{
*/
/*!
* @brief Gets the MRT status flags
*
* @param base Multi-Rate timer peripheral base address
* @param channel Timer channel number
*
* @return The status flags. This is the logical OR of members of the
* enumeration ::mrt_status_flags_t
*/
static inline uint32_t MRT_GetStatusFlags(MRT_Type *base, mrt_chnl_t channel)
{
return (base->CHANNEL[channel].STAT & (MRT_CHANNEL_STAT_INTFLAG_MASK | MRT_CHANNEL_STAT_RUN_MASK));
}
/*!
* @brief Clears the MRT status flags.
*
* @param base Multi-Rate timer peripheral base address
* @param channel Timer channel number
* @param mask The status flags to clear. This is a logical OR of members of the
* enumeration ::mrt_status_flags_t
*/
static inline void MRT_ClearStatusFlags(MRT_Type *base, mrt_chnl_t channel, uint32_t mask)
{
base->CHANNEL[channel].STAT = (mask & MRT_CHANNEL_STAT_INTFLAG_MASK);
}
/*! @}*/
/*!
* @name Read and Write the timer period
* @{
*/
/*!
* @brief Used to update the timer period in units of count.
*
* The new value will be immediately loaded or will be loaded at the end of the current time
* interval. For one-shot interrupt mode the new value will be immediately loaded.
*
* @note User can call the utility macros provided in fsl_common.h to convert to ticks
*
* @param base Multi-Rate timer peripheral base address
* @param channel Timer channel number
* @param count Timer period in units of ticks
* @param immediateLoad true: Load the new value immediately into the TIMER register;
* false: Load the new value at the end of current timer interval
*/
void MRT_UpdateTimerPeriod(MRT_Type *base, mrt_chnl_t channel, uint32_t count, bool immediateLoad);
/*!
* @brief Reads the current timer counting value.
*
* This function returns the real-time timer counting value, in a range from 0 to a
* timer period.
*
* @note User can call the utility macros provided in fsl_common.h to convert ticks to usec or msec
*
* @param base Multi-Rate timer peripheral base address
* @param channel Timer channel number
*
* @return Current timer counting value in ticks
*/
static inline uint32_t MRT_GetCurrentTimerCount(MRT_Type *base, mrt_chnl_t channel)
{
return base->CHANNEL[channel].TIMER;
}
/*! @}*/
/*!
* @name Timer Start and Stop
* @{
*/
/*!
* @brief Starts the timer counting.
*
* After calling this function, timers load period value, counts down to 0 and
* depending on the timer mode it will either load the respective start value again or stop.
*
* @note User can call the utility macros provided in fsl_common.h to convert to ticks
*
* @param base Multi-Rate timer peripheral base address
* @param channel Timer channel number.
* @param count Timer period in units of ticks
*/
static inline void MRT_StartTimer(MRT_Type *base, mrt_chnl_t channel, uint32_t count)
{
/* Write the timer interval value */
base->CHANNEL[channel].INTVAL = count;
}
/*!
* @brief Stops the timer counting.
*
* This function stops the timer from counting.
*
* @param base Multi-Rate timer peripheral base address
* @param channel Timer channel number.
*/
static inline void MRT_StopTimer(MRT_Type *base, mrt_chnl_t channel)
{
/* Stop the timer immediately */
base->CHANNEL[channel].INTVAL = MRT_CHANNEL_INTVAL_LOAD_MASK;
}
/*! @}*/
/*!
* @name Get & release channel
* @{
*/
/*!
* @brief Find the available channel.
*
* This function returns the lowest available channel number.
*
* @param base Multi-Rate timer peripheral base address
*/
static inline uint32_t MRT_GetIdleChannel(MRT_Type *base)
{
return base->IDLE_CH;
}
/*!
* @brief Release the channel when the timer is using the multi-task mode.
*
* In multi-task mode, the INUSE flags allow more control over when MRT channels are released for
* further use. The user can hold on to a channel acquired by calling MRT_GetIdleChannel() for as
* long as it is needed and release it by calling this function. This removes the need to ask for
* an available channel for every use.
*
* @param base Multi-Rate timer peripheral base address
* @param channel Timer channel number.
*/
static inline void MRT_ReleaseChannel(MRT_Type *base, mrt_chnl_t channel)
{
uint32_t reg = base->CHANNEL[channel].STAT;
/* Clear flag bits to prevent accidentally clearing anything when writing back */
reg = ~MRT_CHANNEL_STAT_INTFLAG_MASK;
reg |= MRT_CHANNEL_STAT_INUSE_MASK;
base->CHANNEL[channel].STAT = reg;
}
/*! @}*/
#if defined(__cplusplus)
}
#endif
/*! @}*/
#endif /* _FSL_MRT_H_ */

View File

@ -0,0 +1,411 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "fsl_pint.h"
/*******************************************************************************
* Variables
******************************************************************************/
/*! @brief Irq number array */
static const IRQn_Type s_pintIRQ[FSL_FEATURE_PINT_NUMBER_OF_CONNECTED_OUTPUTS] = PINT_IRQS;
/*! @brief Callback function array for PINT(s). */
static pint_cb_t s_pintCallback[FSL_FEATURE_PINT_NUMBER_OF_CONNECTED_OUTPUTS];
/*******************************************************************************
* Code
******************************************************************************/
void PINT_Init(PINT_Type *base)
{
uint32_t i;
uint32_t pmcfg;
assert(base);
pmcfg = 0;
for (i = 0; i < FSL_FEATURE_PINT_NUMBER_OF_CONNECTED_OUTPUTS; i++)
{
s_pintCallback[i] = NULL;
}
/* Disable all bit slices */
for (i = 0; i < PINT_PIN_INT_COUNT; i++)
{
pmcfg = pmcfg | (kPINT_PatternMatchNever << (PININT_BITSLICE_CFG_START + (i * 3U)));
}
/* Enable the peripheral clock */
CLOCK_EnableClock(kCLOCK_Pint);
/* Reset the peripheral */
RESET_PeripheralReset(kPINT_RST_SHIFT_RSTn);
/* Disable all pattern match bit slices */
base->PMCFG = pmcfg;
}
void PINT_PinInterruptConfig(PINT_Type *base, pint_pin_int_t intr, pint_pin_enable_t enable, pint_cb_t callback)
{
assert(base);
/* Clear Rise and Fall flags first */
PINT_PinInterruptClrRiseFlag(base, intr);
PINT_PinInterruptClrFallFlag(base, intr);
/* select level or edge sensitive */
base->ISEL = (base->ISEL & ~(1U << intr)) | ((enable & PINT_PIN_INT_LEVEL) ? (1U << intr) : 0U);
/* enable rising or level interrupt */
if (enable & (PINT_PIN_INT_LEVEL | PINT_PIN_INT_RISE))
{
base->SIENR = 1U << intr;
}
else
{
base->CIENR = 1U << intr;
}
/* Enable falling or select high level */
if (enable & PINT_PIN_INT_FALL_OR_HIGH_LEVEL)
{
base->SIENF = 1U << intr;
}
else
{
base->CIENF = 1U << intr;
}
s_pintCallback[intr] = callback;
}
void PINT_PinInterruptGetConfig(PINT_Type *base, pint_pin_int_t pintr, pint_pin_enable_t *enable, pint_cb_t *callback)
{
uint32_t mask;
bool level;
assert(base);
*enable = kPINT_PinIntEnableNone;
level = false;
mask = 1U << pintr;
if (base->ISEL & mask)
{
/* Pin interrupt is level sensitive */
level = true;
}
if (base->IENR & mask)
{
if (level)
{
/* Level interrupt is enabled */
*enable = kPINT_PinIntEnableLowLevel;
}
else
{
/* Rising edge interrupt */
*enable = kPINT_PinIntEnableRiseEdge;
}
}
if (base->IENF & mask)
{
if (level)
{
/* Level interrupt is active high */
*enable = kPINT_PinIntEnableHighLevel;
}
else
{
/* Either falling or both edge */
if (*enable == kPINT_PinIntEnableRiseEdge)
{
/* Rising and faling edge */
*enable = kPINT_PinIntEnableBothEdges;
}
else
{
/* Falling edge */
*enable = kPINT_PinIntEnableFallEdge;
}
}
}
*callback = s_pintCallback[pintr];
}
void PINT_PatternMatchConfig(PINT_Type *base, pint_pmatch_bslice_t bslice, pint_pmatch_cfg_t *cfg)
{
uint32_t src_shift;
uint32_t cfg_shift;
uint32_t pmcfg;
assert(base);
src_shift = PININT_BITSLICE_SRC_START + (bslice * 3U);
cfg_shift = PININT_BITSLICE_CFG_START + (bslice * 3U);
/* Input source selection for selected bit slice */
base->PMSRC = (base->PMSRC & ~(PININT_BITSLICE_SRC_MASK << src_shift)) | (cfg->bs_src << src_shift);
/* Bit slice configuration */
pmcfg = base->PMCFG;
pmcfg = (pmcfg & ~(PININT_BITSLICE_CFG_MASK << cfg_shift)) | (cfg->bs_cfg << cfg_shift);
/* If end point is true, enable the bits */
if (bslice != 7U)
{
if (cfg->end_point)
{
pmcfg |= (0x1U << bslice);
}
else
{
pmcfg &= ~(0x1U << bslice);
}
}
base->PMCFG = pmcfg;
/* Save callback pointer */
s_pintCallback[bslice] = cfg->callback;
}
void PINT_PatternMatchGetConfig(PINT_Type *base, pint_pmatch_bslice_t bslice, pint_pmatch_cfg_t *cfg)
{
uint32_t src_shift;
uint32_t cfg_shift;
assert(base);
src_shift = PININT_BITSLICE_SRC_START + (bslice * 3U);
cfg_shift = PININT_BITSLICE_CFG_START + (bslice * 3U);
cfg->bs_src = (pint_pmatch_input_src_t)((base->PMSRC & (PININT_BITSLICE_SRC_MASK << src_shift)) >> src_shift);
cfg->bs_cfg = (pint_pmatch_bslice_cfg_t)((base->PMCFG & (PININT_BITSLICE_CFG_MASK << cfg_shift)) >> cfg_shift);
if (bslice == 7U)
{
cfg->end_point = true;
}
else
{
cfg->end_point = (base->PMCFG & (0x1U << bslice)) >> bslice;
}
cfg->callback = s_pintCallback[bslice];
}
uint32_t PINT_PatternMatchResetDetectLogic(PINT_Type *base)
{
uint32_t pmctrl;
uint32_t pmstatus;
uint32_t pmsrc;
pmctrl = PINT->PMCTRL;
pmstatus = pmctrl >> PINT_PMCTRL_PMAT_SHIFT;
if (pmstatus)
{
/* Reset Pattern match engine detection logic */
pmsrc = base->PMSRC;
base->PMSRC = pmsrc;
}
return (pmstatus);
}
void PINT_EnableCallback(PINT_Type *base)
{
uint32_t i;
assert(base);
PINT_PinInterruptClrStatusAll(base);
for (i = 0; i < FSL_FEATURE_PINT_NUMBER_OF_CONNECTED_OUTPUTS; i++)
{
NVIC_ClearPendingIRQ(s_pintIRQ[i]);
PINT_PinInterruptClrStatus(base, (pint_pin_int_t)i);
EnableIRQ(s_pintIRQ[i]);
}
}
void PINT_DisableCallback(PINT_Type *base)
{
uint32_t i;
assert(base);
for (i = 0; i < FSL_FEATURE_PINT_NUMBER_OF_CONNECTED_OUTPUTS; i++)
{
DisableIRQ(s_pintIRQ[i]);
PINT_PinInterruptClrStatus(base, (pint_pin_int_t)i);
NVIC_ClearPendingIRQ(s_pintIRQ[i]);
}
}
void PINT_Deinit(PINT_Type *base)
{
uint32_t i;
assert(base);
/* Cleanup */
PINT_DisableCallback(base);
for (i = 0; i < FSL_FEATURE_PINT_NUMBER_OF_CONNECTED_OUTPUTS; i++)
{
s_pintCallback[i] = NULL;
}
/* Reset the peripheral */
RESET_PeripheralReset(kPINT_RST_SHIFT_RSTn);
/* Disable the peripheral clock */
CLOCK_DisableClock(kCLOCK_Pint);
}
/* IRQ handler functions overloading weak symbols in the startup */
void PIN_INT0_DriverIRQHandler(void)
{
uint32_t pmstatus;
/* Reset pattern match detection */
pmstatus = PINT_PatternMatchResetDetectLogic(PINT);
/* Call user function */
if (s_pintCallback[kPINT_PinInt0] != NULL)
{
s_pintCallback[kPINT_PinInt0](kPINT_PinInt0, pmstatus);
}
}
#if (FSL_FEATURE_PINT_NUMBER_OF_CONNECTED_OUTPUTS > 1U)
void PIN_INT1_DriverIRQHandler(void)
{
uint32_t pmstatus;
/* Reset pattern match detection */
pmstatus = PINT_PatternMatchResetDetectLogic(PINT);
/* Call user function */
if (s_pintCallback[kPINT_PinInt1] != NULL)
{
s_pintCallback[kPINT_PinInt1](kPINT_PinInt1, pmstatus);
}
}
#endif
#if (FSL_FEATURE_PINT_NUMBER_OF_CONNECTED_OUTPUTS > 2U)
void PIN_INT2_DriverIRQHandler(void)
{
uint32_t pmstatus;
/* Reset pattern match detection */
pmstatus = PINT_PatternMatchResetDetectLogic(PINT);
/* Call user function */
if (s_pintCallback[kPINT_PinInt2] != NULL)
{
s_pintCallback[kPINT_PinInt2](kPINT_PinInt2, pmstatus);
}
}
#endif
#if (FSL_FEATURE_PINT_NUMBER_OF_CONNECTED_OUTPUTS > 3U)
void PIN_INT3_DriverIRQHandler(void)
{
uint32_t pmstatus;
/* Reset pattern match detection */
pmstatus = PINT_PatternMatchResetDetectLogic(PINT);
/* Call user function */
if (s_pintCallback[kPINT_PinInt3] != NULL)
{
s_pintCallback[kPINT_PinInt3](kPINT_PinInt3, pmstatus);
}
}
#endif
#if (FSL_FEATURE_PINT_NUMBER_OF_CONNECTED_OUTPUTS > 4U)
void PIN_INT4_DriverIRQHandler(void)
{
uint32_t pmstatus;
/* Reset pattern match detection */
pmstatus = PINT_PatternMatchResetDetectLogic(PINT);
/* Call user function */
if (s_pintCallback[kPINT_PinInt4] != NULL)
{
s_pintCallback[kPINT_PinInt4](kPINT_PinInt4, pmstatus);
}
}
#endif
#if (FSL_FEATURE_PINT_NUMBER_OF_CONNECTED_OUTPUTS > 5U)
void PIN_INT5_DriverIRQHandler(void)
{
uint32_t pmstatus;
/* Reset pattern match detection */
pmstatus = PINT_PatternMatchResetDetectLogic(PINT);
/* Call user function */
if (s_pintCallback[kPINT_PinInt5] != NULL)
{
s_pintCallback[kPINT_PinInt5](kPINT_PinInt5, pmstatus);
}
}
#endif
#if (FSL_FEATURE_PINT_NUMBER_OF_CONNECTED_OUTPUTS > 6U)
void PIN_INT6_DriverIRQHandler(void)
{
uint32_t pmstatus;
/* Reset pattern match detection */
pmstatus = PINT_PatternMatchResetDetectLogic(PINT);
/* Call user function */
if (s_pintCallback[kPINT_PinInt6] != NULL)
{
s_pintCallback[kPINT_PinInt6](kPINT_PinInt6, pmstatus);
}
}
#endif
#if (FSL_FEATURE_PINT_NUMBER_OF_CONNECTED_OUTPUTS > 7U)
void PIN_INT7_DriverIRQHandler(void)
{
uint32_t pmstatus;
/* Reset pattern match detection */
pmstatus = PINT_PatternMatchResetDetectLogic(PINT);
/* Call user function */
if (s_pintCallback[kPINT_PinInt7] != NULL)
{
s_pintCallback[kPINT_PinInt7](kPINT_PinInt7, pmstatus);
}
}
#endif

View File

@ -0,0 +1,568 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FSL_PINT_H_
#define _FSL_PINT_H_
#include "fsl_common.h"
/*!
* @addtogroup pint_driver
* @{
*/
/*! @file */
/*******************************************************************************
* Definitions
******************************************************************************/
/*! @name Driver version */
/*@{*/
#define FSL_PINT_DRIVER_VERSION (MAKE_VERSION(2, 0, 0)) /*!< Version 2.0.0 */
/*@}*/
/* Number of interrupt line supported by PINT */
#define PINT_PIN_INT_COUNT 8U
/* Number of input sources supported by PINT */
#define PINT_INPUT_COUNT 8U
/* PININT Bit slice source register bits */
#define PININT_BITSLICE_SRC_START 8U
#define PININT_BITSLICE_SRC_MASK 7U
/* PININT Bit slice configuration register bits */
#define PININT_BITSLICE_CFG_START 8U
#define PININT_BITSLICE_CFG_MASK 7U
#define PININT_BITSLICE_ENDP_MASK 7U
#define PINT_PIN_INT_LEVEL 0x10U
#define PINT_PIN_INT_EDGE 0x00U
#define PINT_PIN_INT_FALL_OR_HIGH_LEVEL 0x02U
#define PINT_PIN_INT_RISE 0x01U
#define PINT_PIN_RISE_EDGE (PINT_PIN_INT_EDGE | PINT_PIN_INT_RISE)
#define PINT_PIN_FALL_EDGE (PINT_PIN_INT_EDGE | PINT_PIN_INT_FALL_OR_HIGH_LEVEL)
#define PINT_PIN_BOTH_EDGE (PINT_PIN_INT_EDGE | PINT_PIN_INT_RISE | PINT_PIN_INT_FALL_OR_HIGH_LEVEL)
#define PINT_PIN_LOW_LEVEL (PINT_PIN_INT_LEVEL)
#define PINT_PIN_HIGH_LEVEL (PINT_PIN_INT_LEVEL | PINT_PIN_INT_FALL_OR_HIGH_LEVEL)
/*! @brief PINT Pin Interrupt enable type */
typedef enum _pint_pin_enable
{
kPINT_PinIntEnableNone = 0U, /*!< Do not generate Pin Interrupt */
kPINT_PinIntEnableRiseEdge = PINT_PIN_RISE_EDGE, /*!< Generate Pin Interrupt on rising edge */
kPINT_PinIntEnableFallEdge = PINT_PIN_FALL_EDGE, /*!< Generate Pin Interrupt on falling edge */
kPINT_PinIntEnableBothEdges = PINT_PIN_BOTH_EDGE, /*!< Generate Pin Interrupt on both edges */
kPINT_PinIntEnableLowLevel = PINT_PIN_LOW_LEVEL, /*!< Generate Pin Interrupt on low level */
kPINT_PinIntEnableHighLevel = PINT_PIN_HIGH_LEVEL /*!< Generate Pin Interrupt on high level */
} pint_pin_enable_t;
/*! @brief PINT Pin Interrupt type */
typedef enum _pint_int
{
kPINT_PinInt0 = 0U, /*!< Pin Interrupt 0 */
#if (FSL_FEATURE_PINT_NUMBER_OF_CONNECTED_OUTPUTS > 1U)
kPINT_PinInt1 = 1U, /*!< Pin Interrupt 1 */
#endif
#if (FSL_FEATURE_PINT_NUMBER_OF_CONNECTED_OUTPUTS > 2U)
kPINT_PinInt2 = 2U, /*!< Pin Interrupt 2 */
#endif
#if (FSL_FEATURE_PINT_NUMBER_OF_CONNECTED_OUTPUTS > 3U)
kPINT_PinInt3 = 3U, /*!< Pin Interrupt 3 */
#endif
#if (FSL_FEATURE_PINT_NUMBER_OF_CONNECTED_OUTPUTS > 4U)
kPINT_PinInt4 = 4U, /*!< Pin Interrupt 4 */
#endif
#if (FSL_FEATURE_PINT_NUMBER_OF_CONNECTED_OUTPUTS > 5U)
kPINT_PinInt5 = 5U, /*!< Pin Interrupt 5 */
#endif
#if (FSL_FEATURE_PINT_NUMBER_OF_CONNECTED_OUTPUTS > 6U)
kPINT_PinInt6 = 6U, /*!< Pin Interrupt 6 */
#endif
#if (FSL_FEATURE_PINT_NUMBER_OF_CONNECTED_OUTPUTS > 7U)
kPINT_PinInt7 = 7U, /*!< Pin Interrupt 7 */
#endif
} pint_pin_int_t;
/*! @brief PINT Pattern Match bit slice input source type */
typedef enum _pint_pmatch_input_src
{
kPINT_PatternMatchInp0Src = 0U, /*!< Input source 0 */
kPINT_PatternMatchInp1Src = 1U, /*!< Input source 1 */
kPINT_PatternMatchInp2Src = 2U, /*!< Input source 2 */
kPINT_PatternMatchInp3Src = 3U, /*!< Input source 3 */
kPINT_PatternMatchInp4Src = 4U, /*!< Input source 4 */
kPINT_PatternMatchInp5Src = 5U, /*!< Input source 5 */
kPINT_PatternMatchInp6Src = 6U, /*!< Input source 6 */
kPINT_PatternMatchInp7Src = 7U, /*!< Input source 7 */
} pint_pmatch_input_src_t;
/*! @brief PINT Pattern Match bit slice type */
typedef enum _pint_pmatch_bslice
{
kPINT_PatternMatchBSlice0 = 0U, /*!< Bit slice 0 */
#if (FSL_FEATURE_PINT_NUMBER_OF_CONNECTED_OUTPUTS > 1U)
kPINT_PatternMatchBSlice1 = 1U, /*!< Bit slice 1 */
#endif
#if (FSL_FEATURE_PINT_NUMBER_OF_CONNECTED_OUTPUTS > 2U)
kPINT_PatternMatchBSlice2 = 2U, /*!< Bit slice 2 */
#endif
#if (FSL_FEATURE_PINT_NUMBER_OF_CONNECTED_OUTPUTS > 3U)
kPINT_PatternMatchBSlice3 = 3U, /*!< Bit slice 3 */
#endif
#if (FSL_FEATURE_PINT_NUMBER_OF_CONNECTED_OUTPUTS > 4U)
kPINT_PatternMatchBSlice4 = 4U, /*!< Bit slice 4 */
#endif
#if (FSL_FEATURE_PINT_NUMBER_OF_CONNECTED_OUTPUTS > 5U)
kPINT_PatternMatchBSlice5 = 5U, /*!< Bit slice 5 */
#endif
#if (FSL_FEATURE_PINT_NUMBER_OF_CONNECTED_OUTPUTS > 6U)
kPINT_PatternMatchBSlice6 = 6U, /*!< Bit slice 6 */
#endif
#if (FSL_FEATURE_PINT_NUMBER_OF_CONNECTED_OUTPUTS > 7U)
kPINT_PatternMatchBSlice7 = 7U, /*!< Bit slice 7 */
#endif
} pint_pmatch_bslice_t;
/*! @brief PINT Pattern Match configuration type */
typedef enum _pint_pmatch_bslice_cfg
{
kPINT_PatternMatchAlways = 0U, /*!< Always Contributes to product term match */
kPINT_PatternMatchStickyRise = 1U, /*!< Sticky Rising edge */
kPINT_PatternMatchStickyFall = 2U, /*!< Sticky Falling edge */
kPINT_PatternMatchStickyBothEdges = 3U, /*!< Sticky Rising or Falling edge */
kPINT_PatternMatchHigh = 4U, /*!< High level */
kPINT_PatternMatchLow = 5U, /*!< Low level */
kPINT_PatternMatchNever = 6U, /*!< Never contributes to product term match */
kPINT_PatternMatchBothEdges = 7U, /*!< Either rising or falling edge */
} pint_pmatch_bslice_cfg_t;
/*! @brief PINT Callback function. */
typedef void (*pint_cb_t)(pint_pin_int_t pintr, uint32_t pmatch_status);
typedef struct _pint_pmatch_cfg
{
pint_pmatch_input_src_t bs_src;
pint_pmatch_bslice_cfg_t bs_cfg;
bool end_point;
pint_cb_t callback;
} pint_pmatch_cfg_t;
/*******************************************************************************
* API
******************************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif
/*!
* @brief Initialize PINT peripheral.
* This function initializes the PINT peripheral and enables the clock.
*
* @param base Base address of the PINT peripheral.
*
* @retval None.
*/
void PINT_Init(PINT_Type *base);
/*!
* @brief Configure PINT peripheral pin interrupt.
* This function configures a given pin interrupt.
*
* @param base Base address of the PINT peripheral.
* @param intr Pin interrupt.
* @param enable Selects detection logic.
* @param callback Callback.
*
* @retval None.
*/
void PINT_PinInterruptConfig(PINT_Type *base, pint_pin_int_t intr, pint_pin_enable_t enable, pint_cb_t callback);
/*!
* @brief Get PINT peripheral pin interrupt configuration.
* This function returns the configuration of a given pin interrupt.
*
* @param base Base address of the PINT peripheral.
* @param pintr Pin interrupt.
* @param enable Pointer to store the detection logic.
* @param callback Callback.
*
* @retval None.
*/
void PINT_PinInterruptGetConfig(PINT_Type *base, pint_pin_int_t pintr, pint_pin_enable_t *enable, pint_cb_t *callback);
/*!
* @brief Clear Selected pin interrupt status.
* This function clears the selected pin interrupt status.
*
* @param base Base address of the PINT peripheral.
* @param pintr Pin interrupt.
*
* @retval None.
*/
static inline void PINT_PinInterruptClrStatus(PINT_Type *base, pint_pin_int_t pintr)
{
base->IST = (1U << pintr);
}
/*!
* @brief Get Selected pin interrupt status.
* This function returns the selected pin interrupt status.
*
* @param base Base address of the PINT peripheral.
* @param pintr Pin interrupt.
*
* @retval status = 0 No pin interrupt request. = 1 Selected Pin interrupt request active.
*/
static inline uint32_t PINT_PinInterruptGetStatus(PINT_Type *base, pint_pin_int_t pintr)
{
return ((base->IST & (1U << pintr)) ? 1U : 0U);
}
/*!
* @brief Clear all pin interrupts status.
* This function clears the status of all pin interrupts.
*
* @param base Base address of the PINT peripheral.
*
* @retval None.
*/
static inline void PINT_PinInterruptClrStatusAll(PINT_Type *base)
{
base->IST = PINT_IST_PSTAT_MASK;
}
/*!
* @brief Get all pin interrupts status.
* This function returns the status of all pin interrupts.
*
* @param base Base address of the PINT peripheral.
*
* @retval status Each bit position indicates the status of corresponding pin interrupt.
* = 0 No pin interrupt request. = 1 Pin interrupt request active.
*/
static inline uint32_t PINT_PinInterruptGetStatusAll(PINT_Type *base)
{
return (base->IST);
}
/*!
* @brief Clear Selected pin interrupt fall flag.
* This function clears the selected pin interrupt fall flag.
*
* @param base Base address of the PINT peripheral.
* @param pintr Pin interrupt.
*
* @retval None.
*/
static inline void PINT_PinInterruptClrFallFlag(PINT_Type *base, pint_pin_int_t pintr)
{
base->FALL = (1U << pintr);
}
/*!
* @brief Get selected pin interrupt fall flag.
* This function returns the selected pin interrupt fall flag.
*
* @param base Base address of the PINT peripheral.
* @param pintr Pin interrupt.
*
* @retval flag = 0 Falling edge has not been detected. = 1 Falling edge has been detected.
*/
static inline uint32_t PINT_PinInterruptGetFallFlag(PINT_Type *base, pint_pin_int_t pintr)
{
return ((base->FALL & (1U << pintr)) ? 1U : 0U);
}
/*!
* @brief Clear all pin interrupt fall flags.
* This function clears the fall flag for all pin interrupts.
*
* @param base Base address of the PINT peripheral.
*
* @retval None.
*/
static inline void PINT_PinInterruptClrFallFlagAll(PINT_Type *base)
{
base->FALL = PINT_FALL_FDET_MASK;
}
/*!
* @brief Get all pin interrupt fall flags.
* This function returns the fall flag of all pin interrupts.
*
* @param base Base address of the PINT peripheral.
*
* @retval flags Each bit position indicates the falling edge detection of the corresponding pin interrupt.
* 0 Falling edge has not been detected. = 1 Falling edge has been detected.
*/
static inline uint32_t PINT_PinInterruptGetFallFlagAll(PINT_Type *base)
{
return (base->FALL);
}
/*!
* @brief Clear Selected pin interrupt rise flag.
* This function clears the selected pin interrupt rise flag.
*
* @param base Base address of the PINT peripheral.
* @param pintr Pin interrupt.
*
* @retval None.
*/
static inline void PINT_PinInterruptClrRiseFlag(PINT_Type *base, pint_pin_int_t pintr)
{
base->RISE = (1U << pintr);
}
/*!
* @brief Get selected pin interrupt rise flag.
* This function returns the selected pin interrupt rise flag.
*
* @param base Base address of the PINT peripheral.
* @param pintr Pin interrupt.
*
* @retval flag = 0 Rising edge has not been detected. = 1 Rising edge has been detected.
*/
static inline uint32_t PINT_PinInterruptGetRiseFlag(PINT_Type *base, pint_pin_int_t pintr)
{
return ((base->RISE & (1U << pintr)) ? 1U : 0U);
}
/*!
* @brief Clear all pin interrupt rise flags.
* This function clears the rise flag for all pin interrupts.
*
* @param base Base address of the PINT peripheral.
*
* @retval None.
*/
static inline void PINT_PinInterruptClrRiseFlagAll(PINT_Type *base)
{
base->RISE = PINT_RISE_RDET_MASK;
}
/*!
* @brief Get all pin interrupt rise flags.
* This function returns the rise flag of all pin interrupts.
*
* @param base Base address of the PINT peripheral.
*
* @retval flags Each bit position indicates the rising edge detection of the corresponding pin interrupt.
* 0 Rising edge has not been detected. = 1 Rising edge has been detected.
*/
static inline uint32_t PINT_PinInterruptGetRiseFlagAll(PINT_Type *base)
{
return (base->RISE);
}
/*!
* @brief Configure PINT pattern match.
* This function configures a given pattern match bit slice.
*
* @param base Base address of the PINT peripheral.
* @param bslice Pattern match bit slice number.
* @param cfg Pointer to bit slice configuration.
*
* @retval None.
*/
void PINT_PatternMatchConfig(PINT_Type *base, pint_pmatch_bslice_t bslice, pint_pmatch_cfg_t *cfg);
/*!
* @brief Get PINT pattern match configuration.
* This function returns the configuration of a given pattern match bit slice.
*
* @param base Base address of the PINT peripheral.
* @param bslice Pattern match bit slice number.
* @param cfg Pointer to bit slice configuration.
*
* @retval None.
*/
void PINT_PatternMatchGetConfig(PINT_Type *base, pint_pmatch_bslice_t bslice, pint_pmatch_cfg_t *cfg);
/*!
* @brief Get pattern match bit slice status.
* This function returns the status of selected bit slice.
*
* @param base Base address of the PINT peripheral.
* @param bslice Pattern match bit slice number.
*
* @retval status = 0 Match has not been detected. = 1 Match has been detected.
*/
static inline uint32_t PINT_PatternMatchGetStatus(PINT_Type *base, pint_pmatch_bslice_t bslice)
{
return ((base->PMCTRL >> PINT_PMCTRL_PMAT_SHIFT) & (0x1U << bslice)) >> bslice;
}
/*!
* @brief Get status of all pattern match bit slices.
* This function returns the status of all bit slices.
*
* @param base Base address of the PINT peripheral.
*
* @retval status Each bit position indicates the match status of corresponding bit slice.
* = 0 Match has not been detected. = 1 Match has been detected.
*/
static inline uint32_t PINT_PatternMatchGetStatusAll(PINT_Type *base)
{
return base->PMCTRL >> PINT_PMCTRL_PMAT_SHIFT;
}
/*!
* @brief Reset pattern match detection logic.
* This function resets the pattern match detection logic if any of the product term is matching.
*
* @param base Base address of the PINT peripheral.
*
* @retval pmstatus Each bit position indicates the match status of corresponding bit slice.
* = 0 Match was detected. = 1 Match was not detected.
*/
uint32_t PINT_PatternMatchResetDetectLogic(PINT_Type *base);
/*!
* @brief Enable pattern match function.
* This function enables the pattern match function.
*
* @param base Base address of the PINT peripheral.
*
* @retval None.
*/
static inline void PINT_PatternMatchEnable(PINT_Type *base)
{
base->PMCTRL = (base->PMCTRL & PINT_PMCTRL_ENA_RXEV_MASK) | PINT_PMCTRL_SEL_PMATCH_MASK;
}
/*!
* @brief Disable pattern match function.
* This function disables the pattern match function.
*
* @param base Base address of the PINT peripheral.
*
* @retval None.
*/
static inline void PINT_PatternMatchDisable(PINT_Type *base)
{
base->PMCTRL = (base->PMCTRL & PINT_PMCTRL_ENA_RXEV_MASK) & ~PINT_PMCTRL_SEL_PMATCH_MASK;
}
/*!
* @brief Enable RXEV output.
* This function enables the pattern match RXEV output.
*
* @param base Base address of the PINT peripheral.
*
* @retval None.
*/
static inline void PINT_PatternMatchEnableRXEV(PINT_Type *base)
{
base->PMCTRL = (base->PMCTRL & PINT_PMCTRL_SEL_PMATCH_MASK) | PINT_PMCTRL_ENA_RXEV_MASK;
}
/*!
* @brief Disable RXEV output.
* This function disables the pattern match RXEV output.
*
* @param base Base address of the PINT peripheral.
*
* @retval None.
*/
static inline void PINT_PatternMatchDisableRXEV(PINT_Type *base)
{
base->PMCTRL = (base->PMCTRL & PINT_PMCTRL_SEL_PMATCH_MASK) & ~PINT_PMCTRL_ENA_RXEV_MASK;
}
/*!
* @brief Enable callback.
* This function enables the interrupt for the selected PINT peripheral. Although the pin(s) are monitored
* as soon as they are enabled, the callback function is not enabled until this function is called.
*
* @param base Base address of the PINT peripheral.
*
* @retval None.
*/
void PINT_EnableCallback(PINT_Type *base);
/*!
* @brief Disable callback.
* This function disables the interrupt for the selected PINT peripheral. Although the pins are still
* being monitored but the callback function is not called.
*
* @param base Base address of the peripheral.
*
* @retval None.
*/
void PINT_DisableCallback(PINT_Type *base);
/*!
* @brief Deinitialize PINT peripheral.
* This function disables the PINT clock.
*
* @param base Base address of the PINT peripheral.
*
* @retval None.
*/
void PINT_Deinit(PINT_Type *base);
#ifdef __cplusplus
}
#endif
/*@}*/
#endif /* _FSL_PINT_H_ */

View File

@ -0,0 +1,37 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "fsl_common.h"
#include "fsl_power.h"
/*******************************************************************************
* Code
******************************************************************************/
/* Empty file since implementation is in header file and power library */

View File

@ -0,0 +1,215 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FSL_POWER_H_
#define _FSL_POWER_H_
#include "fsl_common.h"
/*! @addtogroup power */
/*! @{ */
/*! @file */
/*******************************************************************************
* Definitions
******************************************************************************/
#define MAKE_PD_BITS(reg, slot) ((reg << 8) | slot)
#define PDRCFG0 0x0U
#define PDRCFG1 0x1U
typedef enum pd_bits
{
kPDRUNCFG_PD_FRO_EN = MAKE_PD_BITS(PDRCFG0, 4U),
kPDRUNCFG_PD_FLASH = MAKE_PD_BITS(PDRCFG0, 5U),
kPDRUNCFG_PD_TEMPS = MAKE_PD_BITS(PDRCFG0, 6U),
kPDRUNCFG_PD_BOD_RESET = MAKE_PD_BITS(PDRCFG0, 7U),
kPDRUNCFG_PD_BOD_INTR = MAKE_PD_BITS(PDRCFG0, 8U),
kPDRUNCFG_PD_ADC0 = MAKE_PD_BITS(PDRCFG0, 10U),
kPDRUNCFG_PD_VDDFLASH = MAKE_PD_BITS(PDRCFG0, 11U),
kPDRUNCFG_LP_VDDFLASH = MAKE_PD_BITS(PDRCFG0, 12U),
kPDRUNCFG_PD_RAM0 = MAKE_PD_BITS(PDRCFG0, 13U),
kPDRUNCFG_PD_RAM1 = MAKE_PD_BITS(PDRCFG0, 14U),
kPDRUNCFG_PD_RAM2 = MAKE_PD_BITS(PDRCFG0, 15U),
kPDRUNCFG_PD_RAMX = MAKE_PD_BITS(PDRCFG0, 16U),
kPDRUNCFG_PD_ROM = MAKE_PD_BITS(PDRCFG0, 17U),
kPDRUNCFG_PD_VDDHV_ENA = MAKE_PD_BITS(PDRCFG0, 18U),
kPDRUNCFG_PD_VD7_ENA = MAKE_PD_BITS(PDRCFG0, 19U),
kPDRUNCFG_PD_WDT_OSC = MAKE_PD_BITS(PDRCFG0, 20U),
kPDRUNCFG_PD_USB0_PHY = MAKE_PD_BITS(PDRCFG0, 21U),
kPDRUNCFG_PD_SYS_PLL0 = MAKE_PD_BITS(PDRCFG0, 22U),
kPDRUNCFG_PD_VREFP_SW = MAKE_PD_BITS(PDRCFG0, 23U),
kPDRUNCFG_PD_FLASH_BG = MAKE_PD_BITS(PDRCFG0, 25U),
kPDRUNCFG_PD_ALT_FLASH_IBG = MAKE_PD_BITS(PDRCFG1, 28U),
kPDRUNCFG_SEL_ALT_FLASH_IBG = MAKE_PD_BITS(PDRCFG1, 29U),
kPDRUNCFG_ForceUnsigned = 0x80000000U
} pd_bit_t;
/*******************************************************************************
* API
******************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif
/*!
* @name Power Configuration
* @{
*/
/*!
* @brief API to enable PDRUNCFG bit in the Syscon. Note that enabling the bit powers down the peripheral
*
* @param en peripheral for which to enable the PDRUNCFG bit
* @return none
*/
static inline void POWER_EnablePD(pd_bit_t en)
{
/* PDRUNCFGSET */
SYSCON->PDRUNCFGSET[(en >> 8UL)] = (1UL << (en & 0xffU));
}
/*!
* @brief API to disable PDRUNCFG bit in the Syscon. Note that disabling the bit powers up the peripheral
*
* @param en peripheral for which to disable the PDRUNCFG bit
* @return none
*/
static inline void POWER_DisablePD(pd_bit_t en)
{
/* PDRUNCFGCLR */
SYSCON->PDRUNCFGCLR[(en >> 8UL)] = (1UL << (en & 0xffU));
}
/*!
* @brief API to enable deep sleep bit in the ARM Core.
*
* @return none
*/
static inline void POWER_EnableDeepSleep(void)
{
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
}
/*!
* @brief API to disable deep sleep bit in the ARM Core.
*
* @return none
*/
static inline void POWER_DisableDeepSleep(void)
{
SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
}
/*!
* @brief API to power down flash controller.
*
* @return none
*/
static inline void POWER_PowerDownFlash(void)
{
/* note, we retain flash trim to make waking back up faster */
SYSCON->PDRUNCFGSET[0] = SYSCON_PDRUNCFG_LP_VDDFLASH_MASK | SYSCON_PDRUNCFG_PD_VDDHV_ENA_MASK | SYSCON_PDRUNCFG_PD_FLASH_BG_MASK;
/* TURN OFF clock for Flash Controller (only needed for FLASH programming, will be turned on by ROM API) */
CLOCK_DisableClock(kCLOCK_Flash);
/* TURN OFF clock for Flash Accelerator */
CLOCK_DisableClock(kCLOCK_Fmc);
}
/*!
* @brief API to power up flash controller.
*
* @return none
*/
static inline void POWER_PowerUpFlash(void)
{
SYSCON->PDRUNCFGCLR[0] = SYSCON_PDRUNCFG_LP_VDDFLASH_MASK | SYSCON_PDRUNCFG_PD_VDDHV_ENA_MASK;
/* TURN ON clock for flash controller */
CLOCK_EnableClock(kCLOCK_Fmc);
}
/*!
* @brief Power Library API to enter deep sleep mode.
*
* @param exclude_from_pd Bit mask of the PDRUNCFG bits that needs to be powered on during deep sleep
* @return none
*/
void POWER_EnterDeepSleep(uint32_t exclude_from_pd);
/*!
* @brief Power Library API to enter deep power down mode.
*
* @param exclude_from_pd Bit mask of the PDRUNCFG bits that needs to be powered on during deep power down mode,
* but this is has no effect as the voltages are cut off.
* @return none
*/
void POWER_EnterDeepPowerDown(uint32_t exclude_from_pd);
/*!
* @brief Power Library API to choose normal regulation and set the voltage for the desired operating frequency.
*
* @param freq - The desired frequency at which the part would like to operate,
* note that the voltage and flash wait states should be set before changing frequency
* @return none
*/
void POWER_SetVoltageForFreq(uint32_t freq);
/*!
* @brief Power Library API to choose low power regulation and set the voltage for the desired operating frequency.
*
* @param freq - The desired frequency at which the part would like to operate,
* note only 12MHz and 48Mhz are supported
* @return none
*/
void POWER_SetLowPowerVoltageForFreq(uint32_t freq);
/*!
* @brief Power Library API to return the library version.
*
* @return version number of the power library
*/
uint32_t POWER_GetLibVersion(void);
/* @} */
#ifdef __cplusplus
}
#endif
/*! @} */
#endif /* _FSL_POWER_H_ */

View File

@ -0,0 +1,125 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "fsl_common.h"
#include "fsl_reset.h"
/*******************************************************************************
* Definitions
******************************************************************************/
/*******************************************************************************
* 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)))
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 = 1u << bitPos;
assert(bitPos < 32u);
/* 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))
{
}
}
}
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 = 1u << bitPos;
assert(bitPos < 32u);
/* 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))
{
}
}
}
void RESET_PeripheralReset(reset_ip_name_t peripheral)
{
RESET_SetPeripheralReset(peripheral);
RESET_ClearPeripheralReset(peripheral);
}
#endif /* FSL_FEATURE_SOC_SYSCON_COUNT || FSL_FEATURE_SOC_ASYNC_SYSCON_COUNT */

View File

@ -0,0 +1,205 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#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 ksdk_common
* @{
*/
/*******************************************************************************
* Definitions
******************************************************************************/
/*!
* @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 \
{ \
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 \
{ \
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);
#if defined(__cplusplus)
}
#endif
/*! @} */
#endif /* _FSL_RESET_H_ */

View File

@ -0,0 +1,286 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "fsl_rtc.h"
/*******************************************************************************
* Definitions
******************************************************************************/
#define SECONDS_IN_A_DAY (86400U)
#define SECONDS_IN_A_HOUR (3600U)
#define SECONDS_IN_A_MINUTE (60U)
#define DAYS_IN_A_YEAR (365U)
#define YEAR_RANGE_START (1970U)
#define YEAR_RANGE_END (2099U)
/*******************************************************************************
* Prototypes
******************************************************************************/
/*!
* @brief Checks whether the date and time passed in is valid
*
* @param datetime Pointer to structure where the date and time details are stored
*
* @return Returns false if the date & time details are out of range; true if in range
*/
static bool RTC_CheckDatetimeFormat(const rtc_datetime_t *datetime);
/*!
* @brief Converts time data from datetime to seconds
*
* @param datetime Pointer to datetime structure where the date and time details are stored
*
* @return The result of the conversion in seconds
*/
static uint32_t RTC_ConvertDatetimeToSeconds(const rtc_datetime_t *datetime);
/*!
* @brief Converts time data from seconds to a datetime structure
*
* @param seconds Seconds value that needs to be converted to datetime format
* @param datetime Pointer to the datetime structure where the result of the conversion is stored
*/
static void RTC_ConvertSecondsToDatetime(uint32_t seconds, rtc_datetime_t *datetime);
/*******************************************************************************
* Code
******************************************************************************/
static bool RTC_CheckDatetimeFormat(const rtc_datetime_t *datetime)
{
assert(datetime);
/* Table of days in a month for a non leap year. First entry in the table is not used,
* valid months start from 1
*/
uint8_t daysPerMonth[] = {0U, 31U, 28U, 31U, 30U, 31U, 30U, 31U, 31U, 30U, 31U, 30U, 31U};
/* Check year, month, hour, minute, seconds */
if ((datetime->year < YEAR_RANGE_START) || (datetime->year > YEAR_RANGE_END) || (datetime->month > 12U) ||
(datetime->month < 1U) || (datetime->hour >= 24U) || (datetime->minute >= 60U) || (datetime->second >= 60U))
{
/* If not correct then error*/
return false;
}
/* Adjust the days in February for a leap year */
if ((((datetime->year & 3U) == 0) && (datetime->year % 100 != 0)) || (datetime->year % 400 == 0))
{
daysPerMonth[2] = 29U;
}
/* Check the validity of the day */
if ((datetime->day > daysPerMonth[datetime->month]) || (datetime->day < 1U))
{
return false;
}
return true;
}
static uint32_t RTC_ConvertDatetimeToSeconds(const rtc_datetime_t *datetime)
{
assert(datetime);
/* Number of days from begin of the non Leap-year*/
/* Number of days from begin of the non Leap-year*/
uint16_t monthDays[] = {0U, 0U, 31U, 59U, 90U, 120U, 151U, 181U, 212U, 243U, 273U, 304U, 334U};
uint32_t seconds;
/* Compute number of days from 1970 till given year*/
seconds = (datetime->year - 1970U) * DAYS_IN_A_YEAR;
/* Add leap year days */
seconds += ((datetime->year / 4) - (1970U / 4));
/* Add number of days till given month*/
seconds += monthDays[datetime->month];
/* Add days in given month. We subtract the current day as it is
* represented in the hours, minutes and seconds field*/
seconds += (datetime->day - 1);
/* For leap year if month less than or equal to Febraury, decrement day counter*/
if ((!(datetime->year & 3U)) && (datetime->month <= 2U))
{
seconds--;
}
seconds = (seconds * SECONDS_IN_A_DAY) + (datetime->hour * SECONDS_IN_A_HOUR) +
(datetime->minute * SECONDS_IN_A_MINUTE) + datetime->second;
return seconds;
}
static void RTC_ConvertSecondsToDatetime(uint32_t seconds, rtc_datetime_t *datetime)
{
assert(datetime);
uint32_t x;
uint32_t secondsRemaining, days;
uint16_t daysInYear;
/* Table of days in a month for a non leap year. First entry in the table is not used,
* valid months start from 1
*/
uint8_t daysPerMonth[] = {0U, 31U, 28U, 31U, 30U, 31U, 30U, 31U, 31U, 30U, 31U, 30U, 31U};
/* Start with the seconds value that is passed in to be converted to date time format */
secondsRemaining = seconds;
/* Calcuate the number of days, we add 1 for the current day which is represented in the
* hours and seconds field
*/
days = secondsRemaining / SECONDS_IN_A_DAY + 1;
/* Update seconds left*/
secondsRemaining = secondsRemaining % SECONDS_IN_A_DAY;
/* Calculate the datetime hour, minute and second fields */
datetime->hour = secondsRemaining / SECONDS_IN_A_HOUR;
secondsRemaining = secondsRemaining % SECONDS_IN_A_HOUR;
datetime->minute = secondsRemaining / 60U;
datetime->second = secondsRemaining % SECONDS_IN_A_MINUTE;
/* Calculate year */
daysInYear = DAYS_IN_A_YEAR;
datetime->year = YEAR_RANGE_START;
while (days > daysInYear)
{
/* Decrease day count by a year and increment year by 1 */
days -= daysInYear;
datetime->year++;
/* Adjust the number of days for a leap year */
if (datetime->year & 3U)
{
daysInYear = DAYS_IN_A_YEAR;
}
else
{
daysInYear = DAYS_IN_A_YEAR + 1;
}
}
/* Adjust the days in February for a leap year */
if (!(datetime->year & 3U))
{
daysPerMonth[2] = 29U;
}
for (x = 1U; x <= 12U; x++)
{
if (days <= daysPerMonth[x])
{
datetime->month = x;
break;
}
else
{
days -= daysPerMonth[x];
}
}
datetime->day = days;
}
void RTC_Init(RTC_Type *base)
{
/* Enable the RTC peripheral clock */
CLOCK_EnableClock(kCLOCK_Rtc);
/* Make sure the reset bit is cleared */
base->CTRL &= ~RTC_CTRL_SWRESET_MASK;
/* Make sure the RTC OSC is powered up */
base->CTRL &= ~RTC_CTRL_RTC_OSC_PD_MASK;
}
status_t RTC_SetDatetime(RTC_Type *base, const rtc_datetime_t *datetime)
{
assert(datetime);
/* Return error if the time provided is not valid */
if (!(RTC_CheckDatetimeFormat(datetime)))
{
return kStatus_InvalidArgument;
}
/* Set time in seconds */
base->COUNT = RTC_ConvertDatetimeToSeconds(datetime);
return kStatus_Success;
}
void RTC_GetDatetime(RTC_Type *base, rtc_datetime_t *datetime)
{
assert(datetime);
uint32_t seconds = 0;
seconds = base->COUNT;
RTC_ConvertSecondsToDatetime(seconds, datetime);
}
status_t RTC_SetAlarm(RTC_Type *base, const rtc_datetime_t *alarmTime)
{
assert(alarmTime);
uint32_t alarmSeconds = 0;
uint32_t currSeconds = 0;
/* Return error if the alarm time provided is not valid */
if (!(RTC_CheckDatetimeFormat(alarmTime)))
{
return kStatus_InvalidArgument;
}
alarmSeconds = RTC_ConvertDatetimeToSeconds(alarmTime);
/* Get the current time */
currSeconds = base->COUNT;
/* Return error if the alarm time has passed */
if (alarmSeconds < currSeconds)
{
return kStatus_Fail;
}
/* Set alarm in seconds*/
base->MATCH = alarmSeconds;
return kStatus_Success;
}
void RTC_GetAlarm(RTC_Type *base, rtc_datetime_t *datetime)
{
assert(datetime);
uint32_t alarmSeconds = 0;
/* Get alarm in seconds */
alarmSeconds = base->MATCH;
RTC_ConvertSecondsToDatetime(alarmSeconds, datetime);
}

View File

@ -0,0 +1,338 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FSL_RTC_H_
#define _FSL_RTC_H_
#include "fsl_common.h"
/*!
* @addtogroup rtc
* @{
*/
/*! @file */
/*******************************************************************************
* Definitions
******************************************************************************/
/*! @name Driver version */
/*@{*/
#define FSL_RTC_DRIVER_VERSION (MAKE_VERSION(2, 0, 0)) /*!< Version 2.0.0 */
/*@}*/
/*! @brief List of RTC interrupts */
typedef enum _rtc_interrupt_enable
{
kRTC_AlarmInterruptEnable = RTC_CTRL_ALARMDPD_EN_MASK, /*!< Alarm interrupt.*/
kRTC_WakeupInterruptEnable = RTC_CTRL_WAKEDPD_EN_MASK /*!< Wake-up interrupt.*/
} rtc_interrupt_enable_t;
/*! @brief List of RTC flags */
typedef enum _rtc_status_flags
{
kRTC_AlarmFlag = RTC_CTRL_ALARM1HZ_MASK, /*!< Alarm flag*/
kRTC_WakeupFlag = RTC_CTRL_WAKE1KHZ_MASK /*!< 1kHz wake-up timer flag*/
} rtc_status_flags_t;
/*! @brief Structure is used to hold the date and time */
typedef struct _rtc_datetime
{
uint16_t year; /*!< Range from 1970 to 2099.*/
uint8_t month; /*!< Range from 1 to 12.*/
uint8_t day; /*!< Range from 1 to 31 (depending on month).*/
uint8_t hour; /*!< Range from 0 to 23.*/
uint8_t minute; /*!< Range from 0 to 59.*/
uint8_t second; /*!< Range from 0 to 59.*/
} rtc_datetime_t;
/*******************************************************************************
* API
******************************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif
/*!
* @name Initialization and deinitialization
* @{
*/
/*!
* @brief Ungates the RTC clock and enables the RTC oscillator.
*
* @note This API should be called at the beginning of the application using the RTC driver.
*
* @param base RTC peripheral base address
*/
void RTC_Init(RTC_Type *base);
/*!
* @brief Stop the timer and gate the RTC clock
*
* @param base RTC peripheral base address
*/
static inline void RTC_Deinit(RTC_Type *base)
{
/* Stop the RTC timer */
base->CTRL &= ~RTC_CTRL_RTC_EN_MASK;
/* Gate the module clock */
CLOCK_DisableClock(kCLOCK_Rtc);
}
/*! @}*/
/*!
* @name Current Time & Alarm
* @{
*/
/*!
* @brief Sets the RTC date and time according to the given time structure.
*
* The RTC counter must be stopped prior to calling this function as writes to the RTC
* seconds register will fail if the RTC counter is running.
*
* @param base RTC peripheral base address
* @param datetime Pointer to structure where the date and time details to set are stored
*
* @return kStatus_Success: Success in setting the time and starting the RTC
* kStatus_InvalidArgument: Error because the datetime format is incorrect
*/
status_t RTC_SetDatetime(RTC_Type *base, const rtc_datetime_t *datetime);
/*!
* @brief Gets the RTC time and stores it in the given time structure.
*
* @param base RTC peripheral base address
* @param datetime Pointer to structure where the date and time details are stored.
*/
void RTC_GetDatetime(RTC_Type *base, rtc_datetime_t *datetime);
/*!
* @brief Sets the RTC alarm time
*
* The function checks whether the specified alarm time is greater than the present
* time. If not, the function does not set the alarm and returns an error.
*
* @param base RTC peripheral base address
* @param alarmTime Pointer to structure where the alarm time is stored.
*
* @return kStatus_Success: success in setting the RTC alarm
* kStatus_InvalidArgument: Error because the alarm datetime format is incorrect
* kStatus_Fail: Error because the alarm time has already passed
*/
status_t RTC_SetAlarm(RTC_Type *base, const rtc_datetime_t *alarmTime);
/*!
* @brief Returns the RTC alarm time.
*
* @param base RTC peripheral base address
* @param datetime Pointer to structure where the alarm date and time details are stored.
*/
void RTC_GetAlarm(RTC_Type *base, rtc_datetime_t *datetime);
/*! @}*/
/*!
* @brief Enable the RTC high resolution timer and set the wake-up time.
*
* @param base RTC peripheral base address
* @param wakeupValue The value to be loaded into the RTC WAKE register
*/
static inline void RTC_SetWakeupCount(RTC_Type *base, uint16_t wakeupValue)
{
/* Enable the 1kHz RTC timer */
base->CTRL |= RTC_CTRL_RTC1KHZ_EN_MASK;
/* Set the start count value into the wake-up timer */
base->WAKE = wakeupValue;
}
/*!
* @brief Read actual RTC counter value.
*
* @param base RTC peripheral base address
*/
static inline uint16_t RTC_GetWakeupCount(RTC_Type *base)
{
/* Read wake-up counter */
return RTC_WAKE_VAL(base->WAKE);
}
/*!
* @name Interrupt Interface
* @{
*/
/*!
* @brief Enables the selected RTC interrupts.
*
* @param base RTC peripheral base address
* @param mask The interrupts to enable. This is a logical OR of members of the
* enumeration ::rtc_interrupt_enable_t
*/
static inline void RTC_EnableInterrupts(RTC_Type *base, uint32_t mask)
{
uint32_t reg = base->CTRL;
/* Clear flag bits to prevent accidentally clearing anything when writing back */
reg &= ~(RTC_CTRL_ALARM1HZ_MASK | RTC_CTRL_WAKE1KHZ_MASK);
reg |= mask;
base->CTRL = reg;
}
/*!
* @brief Disables the selected RTC interrupts.
*
* @param base RTC peripheral base address
* @param mask The interrupts to enable. This is a logical OR of members of the
* enumeration ::rtc_interrupt_enable_t
*/
static inline void RTC_DisableInterrupts(RTC_Type *base, uint32_t mask)
{
uint32_t reg = base->CTRL;
/* Clear flag bits to prevent accidentally clearing anything when writing back */
reg &= ~(RTC_CTRL_ALARM1HZ_MASK | RTC_CTRL_WAKE1KHZ_MASK | mask);
base->CTRL = reg;
}
/*!
* @brief Gets the enabled RTC interrupts.
*
* @param base RTC peripheral base address
*
* @return The enabled interrupts. This is the logical OR of members of the
* enumeration ::rtc_interrupt_enable_t
*/
static inline uint32_t RTC_GetEnabledInterrupts(RTC_Type *base)
{
return (base->CTRL & (RTC_CTRL_ALARMDPD_EN_MASK | RTC_CTRL_WAKEDPD_EN_MASK));
}
/*! @}*/
/*!
* @name Status Interface
* @{
*/
/*!
* @brief Gets the RTC status flags
*
* @param base RTC peripheral base address
*
* @return The status flags. This is the logical OR of members of the
* enumeration ::rtc_status_flags_t
*/
static inline uint32_t RTC_GetStatusFlags(RTC_Type *base)
{
return (base->CTRL & (RTC_CTRL_ALARM1HZ_MASK | RTC_CTRL_WAKE1KHZ_MASK));
}
/*!
* @brief Clears the RTC status flags.
*
* @param base RTC peripheral base address
* @param mask The status flags to clear. This is a logical OR of members of the
* enumeration ::rtc_status_flags_t
*/
static inline void RTC_ClearStatusFlags(RTC_Type *base, uint32_t mask)
{
uint32_t reg = base->CTRL;
/* Clear flag bits to prevent accidentally clearing anything when writing back */
reg &= ~(RTC_CTRL_ALARM1HZ_MASK | RTC_CTRL_WAKE1KHZ_MASK);
/* Write 1 to the flags we wish to clear */
reg |= mask;
base->CTRL = reg;
}
/*! @}*/
/*!
* @name Timer Start and Stop
* @{
*/
/*!
* @brief Starts the RTC time counter.
*
* After calling this function, the timer counter increments once a second provided SR[TOF] or
* SR[TIF] are not set.
*
* @param base RTC peripheral base address
*/
static inline void RTC_StartTimer(RTC_Type *base)
{
base->CTRL |= RTC_CTRL_RTC_EN_MASK;
}
/*!
* @brief Stops the RTC time counter.
*
* RTC's seconds register can be written to only when the timer is stopped.
*
* @param base RTC peripheral base address
*/
static inline void RTC_StopTimer(RTC_Type *base)
{
base->CTRL &= ~RTC_CTRL_RTC_EN_MASK;
}
/*! @}*/
/*!
* @brief Performs a software reset on the RTC module.
*
* This resets all RTC registers to their reset value. The bit is cleared by software explicitly clearing it.
*
* @param base RTC peripheral base address
*/
static inline void RTC_Reset(RTC_Type *base)
{
base->CTRL |= RTC_CTRL_SWRESET_MASK;
base->CTRL &= ~RTC_CTRL_SWRESET_MASK;
}
#if defined(__cplusplus)
}
#endif
/*! @}*/
#endif /* _FSL_RTC_H_ */

View File

@ -0,0 +1,529 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "fsl_sctimer.h"
/*******************************************************************************
* Definitions
******************************************************************************/
/*! @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;
/*! @brief Pointers to SCT clocks for each instance. */
static const clock_ip_name_t s_sctClocks[] = SCT_CLOCKS;
/*! @brief Pointers to SCT resets for each instance. */
static const reset_ip_name_t s_sctResets[] = SCT_RSTS;
/*!< @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 match/capture register number */
static uint32_t s_currentMatch;
/*! @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;
}
status_t SCTIMER_Init(SCT_Type *base, const sctimer_config_t *config)
{
assert(config);
uint32_t i;
/* Enable the SCTimer clock*/
CLOCK_EnableClock(s_sctClocks[SCTIMER_GetInstance(base)]);
/* Reset the module */
RESET_PeripheralReset(s_sctResets[SCTIMER_GetInstance(base)]);
/* Setup the counter operation */
base->CONFIG = SCT_CONFIG_CKSEL(config->clockSelect) | SCT_CONFIG_CLKMODE(config->clockMode) |
SCT_CONFIG_UNIFY(config->enableCounterUnify);
/* Write to the control register, clear the counter and keep the counters halted */
base->CTRL = SCT_CTRL_BIDIR_L(config->enableBidirection_l) | SCT_CTRL_PRE_L(config->prescale_l) |
SCT_CTRL_CLRCTR_L_MASK | SCT_CTRL_HALT_L_MASK;
if (!(config->enableCounterUnify))
{
base->CTRL |= SCT_CTRL_BIDIR_H(config->enableBidirection_h) | SCT_CTRL_PRE_H(config->prescale_h) |
SCT_CTRL_CLRCTR_H_MASK | SCT_CTRL_HALT_H_MASK;
}
/* Initial state of channel output */
base->OUTPUT = config->outInitState;
/* Clear the global variables */
s_currentEvent = 0;
s_currentState = 0;
s_currentMatch = 0;
/* Clear the callback array */
for (i = 0; i < FSL_FEATURE_SCT_NUMBER_OF_EVENTS; i++)
{
s_eventCallback[i] = NULL;
}
/* Save interrupt handler */
s_sctimerIsr = SCTIMER_EventHandleIRQ;
return kStatus_Success;
}
void SCTIMER_Deinit(SCT_Type *base)
{
/* Halt the counters */
base->CTRL |= (SCT_CTRL_HALT_L_MASK | SCT_CTRL_HALT_H_MASK);
/* Disable the SCTimer clock*/
CLOCK_DisableClock(s_sctClocks[SCTIMER_GetInstance(base)]);
}
void SCTIMER_GetDefaultConfig(sctimer_config_t *config)
{
assert(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 = 0;
/* Prescale factor of 1 for Counter_H*/
config->prescale_h = 0;
/* Clear outputs */
config->outInitState = 0;
}
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(pwmParams);
assert(srcClock_Hz);
assert(pwmFreq_Hz);
uint32_t period, pulsePeriod = 0;
uint32_t sctClock = srcClock_Hz / (((base->CTRL & SCT_CTRL_PRE_L_MASK) >> SCT_CTRL_PRE_L_SHIFT) + 1);
uint32_t periodEvent, pulseEvent;
uint32_t reg;
/* This function will create 2 events, return an error if we do not have enough events available */
if ((s_currentEvent + 2) > FSL_FEATURE_SCT_NUMBER_OF_EVENTS)
{
return kStatus_Fail;
}
if (pwmParams->dutyCyclePercent == 0)
{
return kStatus_Fail;
}
/* Set unify bit to operate in 32-bit counter mode */
base->CONFIG |= SCT_CONFIG_UNIFY_MASK;
/* 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) - 1;
}
else
{
period = sctClock / (pwmFreq_Hz * 2);
}
/* Calculate pulse width match value */
pulsePeriod = (period * pwmParams->dutyCyclePercent) / 100;
/* For 100% dutycyle, make pulse period greater than period so the event will never occur */
if (pwmParams->dutyCyclePercent >= 100)
{
pulsePeriod = period + 2;
}
/* Schedule an event when we reach the PWM period */
SCTIMER_CreateAndScheduleEvent(base, kSCTIMER_MatchEventOnly, period, 0, kSCTIMER_Counter_L, &periodEvent);
/* Schedule an event when we reach the pulse width */
SCTIMER_CreateAndScheduleEvent(base, kSCTIMER_MatchEventOnly, pulsePeriod, 0, kSCTIMER_Counter_L, &pulseEvent);
/* Reset the counter when we reach the PWM period */
SCTIMER_SetupCounterLimitAction(base, kSCTIMER_Counter_L, periodEvent);
/* Return the period event to the user */
*event = periodEvent;
/* For high-true level */
if (pwmParams->level == kSCTIMER_HighTrue)
{
/* Set the initial output level to low which is the inactive state */
base->OUTPUT &= ~(1U << pwmParams->output);
if (mode == kSCTIMER_EdgeAlignedPwm)
{
/* Set the output when we reach the PWM period */
SCTIMER_SetupOutputSetAction(base, pwmParams->output, periodEvent);
/* Clear the output when we reach the PWM pulse value */
SCTIMER_SetupOutputClearAction(base, pwmParams->output, pulseEvent);
}
else
{
/* Clear the output when we reach the PWM pulse event */
SCTIMER_SetupOutputClearAction(base, pwmParams->output, pulseEvent);
/* Reverse output when down counting */
reg = base->OUTPUTDIRCTRL;
reg &= ~(SCT_OUTPUTDIRCTRL_SETCLR0_MASK << (2 * pwmParams->output));
reg |= (1U << (2 * pwmParams->output));
base->OUTPUTDIRCTRL = reg;
}
}
/* For low-true level */
else
{
/* Set the initial output level to high which is the inactive state */
base->OUTPUT |= (1U << pwmParams->output);
if (mode == kSCTIMER_EdgeAlignedPwm)
{
/* Clear the output when we reach the PWM period */
SCTIMER_SetupOutputClearAction(base, pwmParams->output, periodEvent);
/* Set the output when we reach the PWM pulse value */
SCTIMER_SetupOutputSetAction(base, pwmParams->output, pulseEvent);
}
else
{
/* Set the output when we reach the PWM pulse event */
SCTIMER_SetupOutputSetAction(base, pwmParams->output, pulseEvent);
/* Reverse output when down counting */
reg = base->OUTPUTDIRCTRL;
reg &= ~(SCT_OUTPUTDIRCTRL_SETCLR0_MASK << (2 * pwmParams->output));
reg |= (1U << (2 * pwmParams->output));
base->OUTPUTDIRCTRL = reg;
}
}
return kStatus_Success;
}
void SCTIMER_UpdatePwmDutycycle(SCT_Type *base, sctimer_out_t output, uint8_t dutyCyclePercent, uint32_t event)
{
assert(dutyCyclePercent > 0);
uint32_t periodMatchReg, pulseMatchReg;
uint32_t pulsePeriod = 0, period;
/* Retrieve the match register number for the PWM period */
periodMatchReg = base->EVENT[event].CTRL & SCT_EVENT_CTRL_MATCHSEL_MASK;
/* Retrieve the match register number for the PWM pulse period */
pulseMatchReg = base->EVENT[event + 1].CTRL & SCT_EVENT_CTRL_MATCHSEL_MASK;
period = base->SCTMATCH[periodMatchReg];
/* Calculate pulse width match value */
pulsePeriod = (period * dutyCyclePercent) / 100;
/* For 100% dutycyle, make pulse period greater than period so the event will never occur */
if (dutyCyclePercent >= 100)
{
pulsePeriod = period + 2;
}
/* Stop the counter before updating match register */
SCTIMER_StopTimer(base, kSCTIMER_Counter_L);
/* Update dutycycle */
base->SCTMATCH[pulseMatchReg] = SCT_SCTMATCH_MATCHn_L(pulsePeriod);
base->SCTMATCHREL[pulseMatchReg] = SCT_SCTMATCHREL_RELOADn_L(pulsePeriod);
/* Restart the counter */
SCTIMER_StartTimer(base, kSCTIMER_Counter_L);
}
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_EVENT_CTRL_COMBMODE_MASK) >> SCT_EVENT_CTRL_COMBMODE_SHIFT);
uint32_t currentCtrlVal = howToMonitor;
/* Return an error if we have hit the limit in terms of number of events created */
if (s_currentEvent >= FSL_FEATURE_SCT_NUMBER_OF_EVENTS)
{
return kStatus_Fail;
}
/* IO only mode */
if (combMode == 0x2U)
{
base->EVENT[s_currentEvent].CTRL = currentCtrlVal | SCT_EVENT_CTRL_IOSEL(whichIO);
}
/* Match mode only */
else if (combMode == 0x1U)
{
/* Return an error if we have hit the limit in terms of number of number of match registers */
if (s_currentMatch >= FSL_FEATURE_SCT_NUMBER_OF_MATCH_CAPTURE)
{
return kStatus_Fail;
}
currentCtrlVal |= SCT_EVENT_CTRL_MATCHSEL(s_currentMatch);
/* Use Counter_L bits if counter is operating in 32-bit mode or user wants to setup the L counter */
if ((base->CONFIG & SCT_CONFIG_UNIFY_MASK) || (whichCounter == kSCTIMER_Counter_L))
{
base->SCTMATCH[s_currentMatch] = SCT_SCTMATCH_MATCHn_L(matchValue);
base->SCTMATCHREL[s_currentMatch] = SCT_SCTMATCHREL_RELOADn_L(matchValue);
}
else
{
/* Select the counter, no need for this if operating in 32-bit mode */
currentCtrlVal |= SCT_EVENT_CTRL_HEVENT(whichCounter);
base->SCTMATCH[s_currentMatch] = SCT_SCTMATCH_MATCHn_H(matchValue);
base->SCTMATCHREL[s_currentMatch] = SCT_SCTMATCHREL_RELOADn_H(matchValue);
}
base->EVENT[s_currentEvent].CTRL = currentCtrlVal;
/* Increment the match register number */
s_currentMatch++;
}
/* Use both Match & IO */
else
{
/* Return an error if we have hit the limit in terms of number of number of match registers */
if (s_currentMatch >= FSL_FEATURE_SCT_NUMBER_OF_MATCH_CAPTURE)
{
return kStatus_Fail;
}
currentCtrlVal |= SCT_EVENT_CTRL_MATCHSEL(s_currentMatch) | SCT_EVENT_CTRL_IOSEL(whichIO);
/* Use Counter_L bits if counter is operating in 32-bit mode or user wants to setup the L counter */
if ((base->CONFIG & SCT_CONFIG_UNIFY_MASK) || (whichCounter == kSCTIMER_Counter_L))
{
base->SCTMATCH[s_currentMatch] = SCT_SCTMATCH_MATCHn_L(matchValue);
base->SCTMATCHREL[s_currentMatch] = SCT_SCTMATCHREL_RELOADn_L(matchValue);
}
else
{
/* Select the counter, no need for this if operating in 32-bit mode */
currentCtrlVal |= SCT_EVENT_CTRL_HEVENT(whichCounter);
base->SCTMATCH[s_currentMatch] = SCT_SCTMATCH_MATCHn_H(matchValue);
base->SCTMATCHREL[s_currentMatch] = SCT_SCTMATCHREL_RELOADn_H(matchValue);
}
base->EVENT[s_currentEvent].CTRL = currentCtrlVal;
/* Increment the match register number */
s_currentMatch++;
}
/* Enable the event in the current state */
base->EVENT[s_currentEvent].STATE = (1U << s_currentState);
/* Return the event number */
*event = s_currentEvent;
/* Increment the event number */
s_currentEvent++;
return kStatus_Success;
}
void SCTIMER_ScheduleEvent(SCT_Type *base, uint32_t event)
{
/* Enable event in the current state */
base->EVENT[event].STATE |= (1U << s_currentState);
}
status_t SCTIMER_IncreaseState(SCT_Type *base)
{
/* Return an error if we have hit the limit in terms of states used */
if (s_currentState >= FSL_FEATURE_SCT_NUMBER_OF_STATES)
{
return kStatus_Fail;
}
s_currentState++;
return kStatus_Success;
}
uint32_t SCTIMER_GetCurrentState(SCT_Type *base)
{
return s_currentState;
}
void SCTIMER_SetupOutputToggleAction(SCT_Type *base, uint32_t whichIO, uint32_t event)
{
uint32_t reg;
/* Set the same event to set and clear the output */
base->OUT[whichIO].CLR |= (1U << event);
base->OUT[whichIO].SET |= (1U << event);
/* Set the conflict resolution to toggle output */
reg = base->RES;
reg &= ~(SCT_RES_O0RES_MASK << (2 * whichIO));
reg |= (uint32_t)(kSCTIMER_ResolveToggle << (2 * whichIO));
base->RES = reg;
}
status_t SCTIMER_SetupCaptureAction(SCT_Type *base,
sctimer_counter_t whichCounter,
uint32_t *captureRegister,
uint32_t event)
{
/* Return an error if we have hit the limit in terms of number of capture/match registers used */
if (s_currentMatch >= FSL_FEATURE_SCT_NUMBER_OF_MATCH_CAPTURE)
{
return kStatus_Fail;
}
/* Use Counter_L bits if counter is operating in 32-bit mode or user wants to setup the L counter */
if ((base->CONFIG & SCT_CONFIG_UNIFY_MASK) || (whichCounter == kSCTIMER_Counter_L))
{
/* Set the bit to enable event */
base->SCTCAPCTRL[s_currentMatch] |= SCT_SCTCAPCTRL_CAPCONn_L(1 << event);
/* Set this resource to be a capture rather than match */
base->REGMODE |= SCT_REGMODE_REGMOD_L(1 << s_currentMatch);
}
else
{
/* Set bit to enable event */
base->SCTCAPCTRL[s_currentMatch] |= SCT_SCTCAPCTRL_CAPCONn_H(1 << event);
/* Set this resource to be a capture rather than match */
base->REGMODE |= SCT_REGMODE_REGMOD_H(1 << s_currentMatch);
}
/* Return the match register number */
*captureRegister = s_currentMatch;
/* Increase the match register number */
s_currentMatch++;
return kStatus_Success;
}
void SCTIMER_SetCallback(SCT_Type *base, sctimer_event_callback_t callback, uint32_t event)
{
s_eventCallback[event] = callback;
}
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;
int i = 0;
/* Invoke the callback for certain events */
for (i = 0; (i < FSL_FEATURE_SCT_NUMBER_OF_EVENTS) && (mask != 0); i++)
{
if (mask & 0x1)
{
if (s_eventCallback[i] != NULL)
{
s_eventCallback[i]();
}
}
mask >>= 1;
}
/* Clear event interrupt flag */
SCT0->EVFLAG = clearFlag;
}
void SCT0_IRQHandler(void)
{
s_sctimerIsr(SCT0);
}

View File

@ -0,0 +1,819 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FSL_SCTIMER_H_
#define _FSL_SCTIMER_H_
#include "fsl_common.h"
/*!
* @addtogroup sctimer
* @{
*/
/*! @file */
/*******************************************************************************
* Definitions
******************************************************************************/
/*! @name Driver version */
/*@{*/
#define FSL_SCTIMER_DRIVER_VERSION (MAKE_VERSION(2, 0, 0)) /*!< Version 2.0.0 */
/*@}*/
/*! @brief SCTimer PWM operation modes */
typedef enum _sctimer_pwm_mode
{
kSCTIMER_EdgeAlignedPwm = 0U, /*!< Edge-aligned PWM */
kSCTIMER_CenterAlignedPwm /*!< Center-aligned PWM */
} sctimer_pwm_mode_t;
/*! @brief SCTimer counters when working as two independent 16-bit counters */
typedef enum _sctimer_counter
{
kSCTIMER_Counter_L = 0U, /*!< Counter L */
kSCTIMER_Counter_H /*!< Counter H */
} sctimer_counter_t;
/*! @brief List of SCTimer input pins */
typedef enum _sctimer_input
{
kSCTIMER_Input_0 = 0U, /*!< SCTIMER input 0 */
kSCTIMER_Input_1, /*!< SCTIMER input 1 */
kSCTIMER_Input_2, /*!< SCTIMER input 2 */
kSCTIMER_Input_3, /*!< SCTIMER input 3 */
kSCTIMER_Input_4, /*!< SCTIMER input 4 */
kSCTIMER_Input_5, /*!< SCTIMER input 5 */
kSCTIMER_Input_6, /*!< SCTIMER input 6 */
kSCTIMER_Input_7 /*!< SCTIMER input 7 */
} sctimer_input_t;
/*! @brief List of SCTimer output pins */
typedef enum _sctimer_out
{
kSCTIMER_Out_0 = 0U, /*!< SCTIMER output 0*/
kSCTIMER_Out_1, /*!< SCTIMER output 1 */
kSCTIMER_Out_2, /*!< SCTIMER output 2 */
kSCTIMER_Out_3, /*!< SCTIMER output 3 */
kSCTIMER_Out_4, /*!< SCTIMER output 4 */
kSCTIMER_Out_5, /*!< SCTIMER output 5 */
kSCTIMER_Out_6, /*!< SCTIMER output 6 */
kSCTIMER_Out_7 /*!< SCTIMER output 7 */
} sctimer_out_t;
/*! @brief SCTimer PWM output pulse mode: high-true, low-true or no output */
typedef enum _sctimer_pwm_level_select
{
kSCTIMER_LowTrue = 0U, /*!< Low true pulses */
kSCTIMER_HighTrue /*!< High true pulses */
} sctimer_pwm_level_select_t;
/*! @brief Options to configure a SCTimer PWM signal */
typedef struct _sctimer_pwm_signal_param
{
sctimer_out_t output; /*!< The output pin to use to generate the PWM signal */
sctimer_pwm_level_select_t level; /*!< PWM output active level select. */
uint8_t dutyCyclePercent; /*!< PWM pulse width, value should be between 1 to 100
100 = always active signal (100% duty cycle).*/
} sctimer_pwm_signal_param_t;
/*! @brief SCTimer clock mode options */
typedef enum _sctimer_clock_mode
{
kSCTIMER_System_ClockMode = 0U, /*!< System Clock Mode */
kSCTIMER_Sampled_ClockMode, /*!< Sampled System Clock Mode */
kSCTIMER_Input_ClockMode, /*!< SCT Input Clock Mode */
kSCTIMER_Asynchronous_ClockMode /*!< Asynchronous Mode */
} sctimer_clock_mode_t;
/*! @brief SCTimer clock select options */
typedef enum _sctimer_clock_select
{
kSCTIMER_Clock_On_Rise_Input_0 = 0U, /*!< Rising edges on input 0 */
kSCTIMER_Clock_On_Fall_Input_0, /*!< Falling edges on input 0 */
kSCTIMER_Clock_On_Rise_Input_1, /*!< Rising edges on input 1 */
kSCTIMER_Clock_On_Fall_Input_1, /*!< Falling edges on input 1 */
kSCTIMER_Clock_On_Rise_Input_2, /*!< Rising edges on input 2 */
kSCTIMER_Clock_On_Fall_Input_2, /*!< Falling edges on input 2 */
kSCTIMER_Clock_On_Rise_Input_3, /*!< Rising edges on input 3 */
kSCTIMER_Clock_On_Fall_Input_3, /*!< Falling edges on input 3 */
kSCTIMER_Clock_On_Rise_Input_4, /*!< Rising edges on input 4 */
kSCTIMER_Clock_On_Fall_Input_4, /*!< Falling edges on input 4 */
kSCTIMER_Clock_On_Rise_Input_5, /*!< Rising edges on input 5 */
kSCTIMER_Clock_On_Fall_Input_5, /*!< Falling edges on input 5 */
kSCTIMER_Clock_On_Rise_Input_6, /*!< Rising edges on input 6 */
kSCTIMER_Clock_On_Fall_Input_6, /*!< Falling edges on input 6 */
kSCTIMER_Clock_On_Rise_Input_7, /*!< Rising edges on input 7 */
kSCTIMER_Clock_On_Fall_Input_7 /*!< Falling edges on input 7 */
} sctimer_clock_select_t;
/*!
* @brief SCTimer output conflict resolution options.
*
* Specifies what action should be taken if multiple events dictate that a given output should be
* both set and cleared at the same time
*/
typedef enum _sctimer_conflict_resolution
{
kSCTIMER_ResolveNone = 0U, /*!< No change */
kSCTIMER_ResolveSet, /*!< Set output */
kSCTIMER_ResolveClear, /*!< Clear output */
kSCTIMER_ResolveToggle /*!< Toggle output */
} sctimer_conflict_resolution_t;
/*! @brief List of SCTimer event types */
typedef enum _sctimer_event
{
kSCTIMER_InputLowOrMatchEvent =
(0 << SCT_EVENT_CTRL_COMBMODE_SHIFT) + (0 << SCT_EVENT_CTRL_IOCOND_SHIFT) + (0 << SCT_EVENT_CTRL_OUTSEL_SHIFT),
kSCTIMER_InputRiseOrMatchEvent =
(0 << SCT_EVENT_CTRL_COMBMODE_SHIFT) + (1 << SCT_EVENT_CTRL_IOCOND_SHIFT) + (0 << SCT_EVENT_CTRL_OUTSEL_SHIFT),
kSCTIMER_InputFallOrMatchEvent =
(0 << SCT_EVENT_CTRL_COMBMODE_SHIFT) + (2 << SCT_EVENT_CTRL_IOCOND_SHIFT) + (0 << SCT_EVENT_CTRL_OUTSEL_SHIFT),
kSCTIMER_InputHighOrMatchEvent =
(0 << SCT_EVENT_CTRL_COMBMODE_SHIFT) + (3 << SCT_EVENT_CTRL_IOCOND_SHIFT) + (0 << SCT_EVENT_CTRL_OUTSEL_SHIFT),
kSCTIMER_MatchEventOnly =
(1 << SCT_EVENT_CTRL_COMBMODE_SHIFT) + (0 << SCT_EVENT_CTRL_IOCOND_SHIFT) + (0 << SCT_EVENT_CTRL_OUTSEL_SHIFT),
kSCTIMER_InputLowEvent =
(2 << SCT_EVENT_CTRL_COMBMODE_SHIFT) + (0 << SCT_EVENT_CTRL_IOCOND_SHIFT) + (0 << SCT_EVENT_CTRL_OUTSEL_SHIFT),
kSCTIMER_InputRiseEvent =
(2 << SCT_EVENT_CTRL_COMBMODE_SHIFT) + (1 << SCT_EVENT_CTRL_IOCOND_SHIFT) + (0 << SCT_EVENT_CTRL_OUTSEL_SHIFT),
kSCTIMER_InputFallEvent =
(2 << SCT_EVENT_CTRL_COMBMODE_SHIFT) + (2 << SCT_EVENT_CTRL_IOCOND_SHIFT) + (0 << SCT_EVENT_CTRL_OUTSEL_SHIFT),
kSCTIMER_InputHighEvent =
(2 << SCT_EVENT_CTRL_COMBMODE_SHIFT) + (3 << SCT_EVENT_CTRL_IOCOND_SHIFT) + (0 << SCT_EVENT_CTRL_OUTSEL_SHIFT),
kSCTIMER_InputLowAndMatchEvent =
(3 << SCT_EVENT_CTRL_COMBMODE_SHIFT) + (0 << SCT_EVENT_CTRL_IOCOND_SHIFT) + (0 << SCT_EVENT_CTRL_OUTSEL_SHIFT),
kSCTIMER_InputRiseAndMatchEvent =
(3 << SCT_EVENT_CTRL_COMBMODE_SHIFT) + (1 << SCT_EVENT_CTRL_IOCOND_SHIFT) + (0 << SCT_EVENT_CTRL_OUTSEL_SHIFT),
kSCTIMER_InputFallAndMatchEvent =
(3 << SCT_EVENT_CTRL_COMBMODE_SHIFT) + (2 << SCT_EVENT_CTRL_IOCOND_SHIFT) + (0 << SCT_EVENT_CTRL_OUTSEL_SHIFT),
kSCTIMER_InputHighAndMatchEvent =
(3 << SCT_EVENT_CTRL_COMBMODE_SHIFT) + (3 << SCT_EVENT_CTRL_IOCOND_SHIFT) + (0 << SCT_EVENT_CTRL_OUTSEL_SHIFT),
kSCTIMER_OutputLowOrMatchEvent =
(0 << SCT_EVENT_CTRL_COMBMODE_SHIFT) + (0 << SCT_EVENT_CTRL_IOCOND_SHIFT) + (1 << SCT_EVENT_CTRL_OUTSEL_SHIFT),
kSCTIMER_OutputRiseOrMatchEvent =
(0 << SCT_EVENT_CTRL_COMBMODE_SHIFT) + (1 << SCT_EVENT_CTRL_IOCOND_SHIFT) + (1 << SCT_EVENT_CTRL_OUTSEL_SHIFT),
kSCTIMER_OutputFallOrMatchEvent =
(0 << SCT_EVENT_CTRL_COMBMODE_SHIFT) + (2 << SCT_EVENT_CTRL_IOCOND_SHIFT) + (1 << SCT_EVENT_CTRL_OUTSEL_SHIFT),
kSCTIMER_OutputHighOrMatchEvent =
(0 << SCT_EVENT_CTRL_COMBMODE_SHIFT) + (3 << SCT_EVENT_CTRL_IOCOND_SHIFT) + (1 << SCT_EVENT_CTRL_OUTSEL_SHIFT),
kSCTIMER_OutputLowEvent =
(2 << SCT_EVENT_CTRL_COMBMODE_SHIFT) + (0 << SCT_EVENT_CTRL_IOCOND_SHIFT) + (1 << SCT_EVENT_CTRL_OUTSEL_SHIFT),
kSCTIMER_OutputRiseEvent =
(2 << SCT_EVENT_CTRL_COMBMODE_SHIFT) + (1 << SCT_EVENT_CTRL_IOCOND_SHIFT) + (1 << SCT_EVENT_CTRL_OUTSEL_SHIFT),
kSCTIMER_OutputFallEvent =
(2 << SCT_EVENT_CTRL_COMBMODE_SHIFT) + (2 << SCT_EVENT_CTRL_IOCOND_SHIFT) + (1 << SCT_EVENT_CTRL_OUTSEL_SHIFT),
kSCTIMER_OutputHighEvent =
(2 << SCT_EVENT_CTRL_COMBMODE_SHIFT) + (3 << SCT_EVENT_CTRL_IOCOND_SHIFT) + (1 << SCT_EVENT_CTRL_OUTSEL_SHIFT),
kSCTIMER_OutputLowAndMatchEvent =
(3 << SCT_EVENT_CTRL_COMBMODE_SHIFT) + (0 << SCT_EVENT_CTRL_IOCOND_SHIFT) + (1 << SCT_EVENT_CTRL_OUTSEL_SHIFT),
kSCTIMER_OutputRiseAndMatchEvent =
(3 << SCT_EVENT_CTRL_COMBMODE_SHIFT) + (1 << SCT_EVENT_CTRL_IOCOND_SHIFT) + (1 << SCT_EVENT_CTRL_OUTSEL_SHIFT),
kSCTIMER_OutputFallAndMatchEvent =
(3 << SCT_EVENT_CTRL_COMBMODE_SHIFT) + (2 << SCT_EVENT_CTRL_IOCOND_SHIFT) + (1 << SCT_EVENT_CTRL_OUTSEL_SHIFT),
kSCTIMER_OutputHighAndMatchEvent =
(3 << SCT_EVENT_CTRL_COMBMODE_SHIFT) + (3 << SCT_EVENT_CTRL_IOCOND_SHIFT) + (1 << SCT_EVENT_CTRL_OUTSEL_SHIFT)
} sctimer_event_t;
/*! @brief SCTimer callback typedef. */
typedef void (*sctimer_event_callback_t)(void);
/*! @brief List of SCTimer interrupts */
typedef enum _sctimer_interrupt_enable
{
kSCTIMER_Event0InterruptEnable = (1U << 0), /*!< Event 0 interrupt */
kSCTIMER_Event1InterruptEnable = (1U << 1), /*!< Event 1 interrupt */
kSCTIMER_Event2InterruptEnable = (1U << 2), /*!< Event 2 interrupt */
kSCTIMER_Event3InterruptEnable = (1U << 3), /*!< Event 3 interrupt */
kSCTIMER_Event4InterruptEnable = (1U << 4), /*!< Event 4 interrupt */
kSCTIMER_Event5InterruptEnable = (1U << 5), /*!< Event 5 interrupt */
kSCTIMER_Event6InterruptEnable = (1U << 6), /*!< Event 6 interrupt */
kSCTIMER_Event7InterruptEnable = (1U << 7), /*!< Event 7 interrupt */
kSCTIMER_Event8InterruptEnable = (1U << 8), /*!< Event 8 interrupt */
kSCTIMER_Event9InterruptEnable = (1U << 9), /*!< Event 9 interrupt */
kSCTIMER_Event10InterruptEnable = (1U << 10), /*!< Event 10 interrupt */
kSCTIMER_Event11InterruptEnable = (1U << 11), /*!< Event 11 interrupt */
kSCTIMER_Event12InterruptEnable = (1U << 12), /*!< Event 12 interrupt */
} sctimer_interrupt_enable_t;
/*! @brief List of SCTimer flags */
typedef enum _sctimer_status_flags
{
kSCTIMER_Event0Flag = (1U << 0), /*!< Event 0 Flag */
kSCTIMER_Event1Flag = (1U << 1), /*!< Event 1 Flag */
kSCTIMER_Event2Flag = (1U << 2), /*!< Event 2 Flag */
kSCTIMER_Event3Flag = (1U << 3), /*!< Event 3 Flag */
kSCTIMER_Event4Flag = (1U << 4), /*!< Event 4 Flag */
kSCTIMER_Event5Flag = (1U << 5), /*!< Event 5 Flag */
kSCTIMER_Event6Flag = (1U << 6), /*!< Event 6 Flag */
kSCTIMER_Event7Flag = (1U << 7), /*!< Event 7 Flag */
kSCTIMER_Event8Flag = (1U << 8), /*!< Event 8 Flag */
kSCTIMER_Event9Flag = (1U << 9), /*!< Event 9 Flag */
kSCTIMER_Event10Flag = (1U << 10), /*!< Event 10 Flag */
kSCTIMER_Event11Flag = (1U << 11), /*!< Event 11 Flag */
kSCTIMER_Event12Flag = (1U << 12), /*!< Event 12 Flag */
kSCTIMER_BusErrorLFlag =
(1U << SCT_CONFLAG_BUSERRL_SHIFT), /*!< Bus error due to write when L counter was not halted */
kSCTIMER_BusErrorHFlag =
(1U << SCT_CONFLAG_BUSERRH_SHIFT) /*!< Bus error due to write when H counter was not halted */
} sctimer_status_flags_t;
/*!
* @brief SCTimer configuration structure
*
* This structure holds the configuration settings for the SCTimer peripheral. To initialize this
* structure to reasonable defaults, call the SCTMR_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 _sctimer_config
{
bool enableCounterUnify; /*!< true: SCT operates as a unified 32-bit counter;
false: SCT operates as two 16-bit counters */
sctimer_clock_mode_t clockMode; /*!< SCT clock mode value */
sctimer_clock_select_t clockSelect; /*!< SCT clock select value */
bool enableBidirection_l; /*!< true: Up-down count mode for the L or unified counter
false: Up count mode only for the L or unified counter */
bool enableBidirection_h; /*!< true: Up-down count mode for the H or unified counter
false: Up count mode only for the H or unified counter.
This field is used only if the enableCounterUnify is set
to false */
uint8_t prescale_l; /*!< Prescale value to produce the L or unified counter clock */
uint8_t prescale_h; /*!< Prescale value to produce the H counter clock.
This field is used only if the enableCounterUnify is set
to false */
uint8_t outInitState; /*!< Defines the initial output value */
} sctimer_config_t;
/*******************************************************************************
* API
******************************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif
/*!
* @name Initialization and deinitialization
* @{
*/
/*!
* @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);
/*!
* @brief Gates the SCTimer clock.
*
* @param base SCTimer peripheral base address
*/
void SCTIMER_Deinit(SCT_Type *base);
/*!
* @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 = 0;
* config->prescale_h = 0;
* config->outInitState = 0;
* @endcode
* @param config Pointer to the user configuration structure.
*/
void SCTIMER_GetDefaultConfig(sctimer_config_t *config);
/*! @}*/
/*!
* @name PWM setup operations
* @{
*/
/*!
* @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.
*
* @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);
/*!
* @brief Updates the duty cycle of an active PWM signal.
*
* @param base SCTimer peripheral base address
* @param output The output to configure
* @param dutyCyclePercent New PWM pulse width; the value should be between 1 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);
/*!
* @name Interrupt Interface
* @{
*/
/*!
* @brief Enables the selected SCTimer interrupts.
*
* @param base SCTimer peripheral base address
* @param mask The interrupts to enable. This is a logical OR of members of the
* enumeration ::sctimer_interrupt_enable_t
*/
static inline void SCTIMER_EnableInterrupts(SCT_Type *base, uint32_t mask)
{
base->EVEN |= mask;
}
/*!
* @brief Disables the selected SCTimer interrupts.
*
* @param base SCTimer peripheral base address
* @param mask The interrupts to enable. This is a logical OR of members of the
* enumeration ::sctimer_interrupt_enable_t
*/
static inline void SCTIMER_DisableInterrupts(SCT_Type *base, uint32_t mask)
{
base->EVEN &= ~mask;
}
/*!
* @brief Gets the enabled SCTimer interrupts.
*
* @param base SCTimer peripheral base address
*
* @return The enabled interrupts. This is the logical OR of members of the
* enumeration ::sctimer_interrupt_enable_t
*/
static inline uint32_t SCTIMER_GetEnabledInterrupts(SCT_Type *base)
{
return (base->EVEN & 0xFFFFU);
}
/*! @}*/
/*!
* @name Status Interface
* @{
*/
/*!
* @brief Gets the SCTimer status flags.
*
* @param base SCTimer peripheral base address
*
* @return The status flags. This is the logical OR of members of the
* enumeration ::sctimer_status_flags_t
*/
static inline uint32_t SCTIMER_GetStatusFlags(SCT_Type *base)
{
uint32_t statusFlags = 0;
/* Add the recorded events */
statusFlags = (base->EVFLAG & 0xFFFFU);
/* Add bus error flags */
statusFlags |= (base->CONFLAG & (SCT_CONFLAG_BUSERRL_MASK | SCT_CONFLAG_BUSERRH_MASK));
return statusFlags;
}
/*!
* @brief Clears the SCTimer status flags.
*
* @param base SCTimer peripheral base address
* @param mask The status flags to clear. This is a logical OR of members of the
* enumeration ::sctimer_status_flags_t
*/
static inline void SCTIMER_ClearStatusFlags(SCT_Type *base, uint32_t mask)
{
/* Write to the flag registers */
base->EVFLAG = (mask & 0xFFFFU);
base->CONFLAG = (mask & (SCT_CONFLAG_BUSERRL_MASK | SCT_CONFLAG_BUSERRH_MASK));
}
/*! @}*/
/*!
* @name Counter Start and Stop
* @{
*/
/*!
* @brief Starts the SCTimer counter.
*
* @param base SCTimer peripheral base address
* @param countertoStart SCTimer counter to start; if unify mode is set then function always
* writes to HALT_L bit
*/
static inline void SCTIMER_StartTimer(SCT_Type *base, sctimer_counter_t countertoStart)
{
/* Clear HALT_L bit if counter is operating in 32-bit mode or user wants to start L counter */
if ((base->CONFIG & SCT_CONFIG_UNIFY_MASK) || (countertoStart == kSCTIMER_Counter_L))
{
base->CTRL &= ~(SCT_CTRL_HALT_L_MASK);
}
else
{
/* Start H counter */
base->CTRL &= ~(SCT_CTRL_HALT_H_MASK);
}
}
/*!
* @brief Halts the SCTimer counter.
*
* @param base SCTimer peripheral base address
* @param countertoStop SCTimer counter to stop; if unify mode is set then function always
* writes to HALT_L bit
*/
static inline void SCTIMER_StopTimer(SCT_Type *base, sctimer_counter_t countertoStop)
{
/* Set HALT_L bit if counter is operating in 32-bit mode or user wants to stop L counter */
if ((base->CONFIG & SCT_CONFIG_UNIFY_MASK) || (countertoStop == kSCTIMER_Counter_L))
{
base->CTRL |= (SCT_CTRL_HALT_L_MASK);
}
else
{
/* Stop H counter */
base->CTRL |= (SCT_CTRL_HALT_H_MASK);
}
}
/*! @}*/
/*!
* @name Functions to create a new event and manage the state logic
* @{
*/
/*!
* @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 when operating in 16-bit mode. In 32-bit mode, this
* field has no meaning as we have only 1 unified counter; hence ignored.
* @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);
/*!
* @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);
/*!
* @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);
/*!
* @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);
/*! @}*/
/*!
* @name Actions to take in response to an event
* @{
*/
/*!
* @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 when operating in 16-bit mode. In 32-bit mode, this
* field has no meaning as only the Counter_L bits are used.
* @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);
/*!
* @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);
/*!
* @brief Transition to the specified state.
*
* This transition will be triggered by the event number that is passed in by the user.
*
* @param base SCTimer peripheral base address
* @param nextState The next state SCTimer will transition to
* @param event Event number that will trigger the state transition
*/
static inline void SCTIMER_SetupNextStateAction(SCT_Type *base, uint32_t nextState, uint32_t event)
{
uint32_t reg = base->EVENT[event].CTRL;
reg &= ~(SCT_EVENT_CTRL_STATEV_MASK);
/* Load the STATEV value when the event occurs to be the next state */
reg |= SCT_EVENT_CTRL_STATEV(nextState) | SCT_EVENT_CTRL_STATELD_MASK;
base->EVENT[event].CTRL = reg;
}
/*!
* @brief Set the Output.
*
* This output will be set when the event number that is passed in by the user is triggered.
*
* @param base SCTimer peripheral base address
* @param whichIO The output to set
* @param event Event number that will trigger the output change
*/
static inline void SCTIMER_SetupOutputSetAction(SCT_Type *base, uint32_t whichIO, uint32_t event)
{
base->OUT[whichIO].SET |= (1U << event);
}
/*!
* @brief Clear the Output.
*
* This output will be cleared when the event number that is passed in by the user is triggered.
*
* @param base SCTimer peripheral base address
* @param whichIO The output to clear
* @param event Event number that will trigger the output change
*/
static inline void SCTIMER_SetupOutputClearAction(SCT_Type *base, uint32_t whichIO, uint32_t event)
{
base->OUT[whichIO].CLR |= (1U << event);
}
/*!
* @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);
/*!
* @brief Limit the running counter.
*
* The counter is limited when the event number that is passed in by the user is triggered.
*
* @param base SCTimer peripheral base address
* @param whichCounter SCTimer counter to use when operating in 16-bit mode. In 32-bit mode, this
* field has no meaning as only the Counter_L bits are used.
* @param event Event number that will trigger the counter to be limited
*/
static inline void SCTIMER_SetupCounterLimitAction(SCT_Type *base, sctimer_counter_t whichCounter, uint32_t event)
{
/* Use Counter_L bits if counter is operating in 32-bit mode or user wants to setup the L counter */
if ((base->CONFIG & SCT_CONFIG_UNIFY_MASK) || (whichCounter == kSCTIMER_Counter_L))
{
base->LIMIT |= SCT_LIMIT_LIMMSK_L(1U << event);
}
else
{
base->LIMIT |= SCT_LIMIT_LIMMSK_H(1U << event);
}
}
/*!
* @brief Stop the running counter.
*
* The counter is stopped when the event number that is passed in by the user is triggered.
*
* @param base SCTimer peripheral base address
* @param whichCounter SCTimer counter to use when operating in 16-bit mode. In 32-bit mode, this
* field has no meaning as only the Counter_L bits are used.
* @param event Event number that will trigger the counter to be stopped
*/
static inline void SCTIMER_SetupCounterStopAction(SCT_Type *base, sctimer_counter_t whichCounter, uint32_t event)
{
/* Use Counter_L bits if counter is operating in 32-bit mode or user wants to setup the L counter */
if ((base->CONFIG & SCT_CONFIG_UNIFY_MASK) || (whichCounter == kSCTIMER_Counter_L))
{
base->STOP |= SCT_STOP_STOPMSK_L(1U << event);
}
else
{
base->STOP |= SCT_STOP_STOPMSK_H(1U << event);
}
}
/*!
* @brief Re-start the stopped counter.
*
* The counter will re-start when the event number that is passed in by the user is triggered.
*
* @param base SCTimer peripheral base address
* @param whichCounter SCTimer counter to use when operating in 16-bit mode. In 32-bit mode, this
* field has no meaning as only the Counter_L bits are used.
* @param event Event number that will trigger the counter to re-start
*/
static inline void SCTIMER_SetupCounterStartAction(SCT_Type *base, sctimer_counter_t whichCounter, uint32_t event)
{
/* Use Counter_L bits if counter is operating in 32-bit mode or user wants to setup the L counter */
if ((base->CONFIG & SCT_CONFIG_UNIFY_MASK) || (whichCounter == kSCTIMER_Counter_L))
{
base->START |= SCT_START_STARTMSK_L(1U << event);
}
else
{
base->START |= SCT_START_STARTMSK_H(1U << event);
}
}
/*!
* @brief Halt the running counter.
*
* The counter is disabled (halted) when the event number that is passed in by the user is
* triggered. When the counter is halted, all further events are disabled. The HALT condition
* can only be removed by calling the SCTIMER_StartTimer() function.
*
* @param base SCTimer peripheral base address
* @param whichCounter SCTimer counter to use when operating in 16-bit mode. In 32-bit mode, this
* field has no meaning as only the Counter_L bits are used.
* @param event Event number that will trigger the counter to be halted
*/
static inline void SCTIMER_SetupCounterHaltAction(SCT_Type *base, sctimer_counter_t whichCounter, uint32_t event)
{
/* Use Counter_L bits if counter is operating in 32-bit mode or user wants to setup the L counter */
if ((base->CONFIG & SCT_CONFIG_UNIFY_MASK) || (whichCounter == kSCTIMER_Counter_L))
{
base->HALT |= SCT_HALT_HALTMSK_L(1U << event);
}
else
{
base->HALT |= SCT_HALT_HALTMSK_H(1U << event);
}
}
/*!
* @brief Generate a DMA request.
*
* DMA request will be triggered by the event number that is passed in by the user.
*
* @param base SCTimer peripheral base address
* @param dmaNumber The DMA request to generate
* @param event Event number that will trigger the DMA request
*/
static inline void SCTIMER_SetupDmaTriggerAction(SCT_Type *base, uint32_t dmaNumber, uint32_t event)
{
if (dmaNumber == 0)
{
base->DMA0REQUEST |= (1U << event);
}
else
{
base->DMA1REQUEST |= (1U << event);
}
}
/*!
* @brief SCTimer interrupt handler.
*
* @param base SCTimer peripheral base address.
*/
void SCTIMER_EventHandleIRQ(SCT_Type *base);
/*! @}*/
#if defined(__cplusplus)
}
#endif
/*! @}*/
#endif /* _FSL_SCTIMER_H_ */

View File

@ -0,0 +1,688 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "fsl_spi.h"
#include "fsl_flexcomm.h"
/*******************************************************************************
* Definitons
******************************************************************************/
/* Note: FIFOCFG[SIZE] has always value 1 = 8 items depth */
#define SPI_FIFO_DEPTH(base) ((((base)->FIFOCFG & SPI_FIFOCFG_SIZE_MASK) >> SPI_FIFOCFG_SIZE_SHIFT) << 3)
/* Convert transfer count to transfer bytes. dataWidth is a
* range <0,15>. Range <8,15> represents 2B transfer */
#define SPI_COUNT_TO_BYTES(dataWidth, count) ((count) << ((dataWidth) >> 3U))
#define SPI_BYTES_TO_COUNT(dataWidth, bytes) ((bytes) >> ((dataWidth) >> 3U))
/*******************************************************************************
* Variables
******************************************************************************/
/*! @brief internal SPI config array */
static spi_config_t g_configs[FSL_FEATURE_SOC_SPI_COUNT] = {(spi_data_width_t)0};
/*! @brief IRQ name array */
static const IRQn_Type s_spiIRQ[] = SPI_IRQS;
/*******************************************************************************
* Code
******************************************************************************/
void *SPI_GetConfig(SPI_Type *base)
{
int32_t instance;
instance = FLEXCOMM_GetInstance(base);
if (instance < 0)
{
return NULL;
}
return &g_configs[instance];
}
void SPI_MasterGetDefaultConfig(spi_master_config_t *config)
{
assert(NULL != config);
config->enableLoopback = false;
config->enableMaster = true;
config->polarity = kSPI_ClockPolarityActiveHigh;
config->phase = kSPI_ClockPhaseFirstEdge;
config->direction = kSPI_MsbFirst;
config->baudRate_Bps = 500000U;
config->dataWidth = kSPI_Data8Bits;
config->sselNum = kSPI_Ssel0;
config->txWatermark = kSPI_TxFifo0;
config->rxWatermark = kSPI_RxFifo1;
}
status_t SPI_MasterInit(SPI_Type *base, const spi_master_config_t *config, uint32_t srcClock_Hz)
{
int32_t result = 0, instance = 0;
uint32_t tmp;
/* assert params */
assert(!((NULL == base) || (NULL == config) || (0 == srcClock_Hz)));
if ((NULL == base) || (NULL == config) || (0 == srcClock_Hz))
{
return kStatus_InvalidArgument;
}
/* initialize flexcomm to SPI mode */
result = FLEXCOMM_Init(base, FLEXCOMM_PERIPH_SPI);
assert(kStatus_Success == result);
if (kStatus_Success != result)
{
return result;
}
/* set divider */
result = SPI_MasterSetBaud(base, config->baudRate_Bps, srcClock_Hz);
if (kStatus_Success != result)
{
return result;
}
/* get instance number */
instance = FLEXCOMM_GetInstance(base);
assert(instance >= 0);
/* store configuration */
g_configs[instance].dataWidth = config->dataWidth;
g_configs[instance].sselNum = config->sselNum;
/* enable FIFOs */
base->FIFOCFG |= SPI_FIFOCFG_EMPTYTX_MASK | SPI_FIFOCFG_EMPTYRX_MASK;
base->FIFOCFG |= SPI_FIFOCFG_ENABLETX_MASK | SPI_FIFOCFG_ENABLERX_MASK;
/* trigger level - empty txFIFO, one item in rxFIFO */
tmp = base->FIFOTRIG & (~(SPI_FIFOTRIG_RXLVL_MASK | SPI_FIFOTRIG_TXLVL_MASK));
tmp |= SPI_FIFOTRIG_TXLVL(config->txWatermark) | SPI_FIFOTRIG_RXLVL(config->rxWatermark);
/* enable generating interrupts for FIFOTRIG levels */
tmp |= SPI_FIFOTRIG_TXLVLENA_MASK | SPI_FIFOTRIG_RXLVLENA_MASK;
/* set FIFOTRIG */
base->FIFOTRIG = tmp;
/* configure SPI mode */
tmp = base->CFG;
tmp &= ~(SPI_CFG_MASTER_MASK | SPI_CFG_LSBF_MASK | SPI_CFG_CPHA_MASK | SPI_CFG_CPOL_MASK | SPI_CFG_LOOP_MASK);
/* phase */
tmp |= SPI_CFG_CPHA(config->phase);
/* polarity */
tmp |= SPI_CFG_CPOL(config->polarity);
/* direction */
tmp |= SPI_CFG_LSBF(config->direction);
/* master mode */
tmp |= SPI_CFG_MASTER(1);
/* loopback */
tmp |= SPI_CFG_LOOP(config->enableLoopback);
base->CFG = tmp;
SPI_Enable(base, config->enableMaster);
return kStatus_Success;
}
void SPI_SlaveGetDefaultConfig(spi_slave_config_t *config)
{
assert(NULL != config);
config->enableSlave = true;
config->polarity = kSPI_ClockPolarityActiveHigh;
config->phase = kSPI_ClockPhaseFirstEdge;
config->direction = kSPI_MsbFirst;
config->dataWidth = kSPI_Data8Bits;
config->txWatermark = kSPI_TxFifo0;
config->rxWatermark = kSPI_RxFifo1;
}
status_t SPI_SlaveInit(SPI_Type *base, const spi_slave_config_t *config)
{
int32_t result = 0, instance;
uint32_t tmp;
/* assert params */
assert(!((NULL == base) || (NULL == config)));
if ((NULL == base) || (NULL == config))
{
return kStatus_InvalidArgument;
}
/* configure flexcomm to SPI, enable clock gate */
result = FLEXCOMM_Init(base, FLEXCOMM_PERIPH_SPI);
assert(kStatus_Success == result);
if (kStatus_Success != result)
{
return result;
}
instance = FLEXCOMM_GetInstance(base);
/* store configuration */
g_configs[instance].dataWidth = config->dataWidth;
/* empty and enable FIFOs */
base->FIFOCFG |= SPI_FIFOCFG_EMPTYTX_MASK | SPI_FIFOCFG_EMPTYRX_MASK;
base->FIFOCFG |= SPI_FIFOCFG_ENABLETX_MASK | SPI_FIFOCFG_ENABLERX_MASK;
/* trigger level - empty txFIFO, one item in rxFIFO */
tmp = base->FIFOTRIG & (~(SPI_FIFOTRIG_RXLVL_MASK | SPI_FIFOTRIG_TXLVL_MASK));
tmp |= SPI_FIFOTRIG_TXLVL(config->txWatermark) | SPI_FIFOTRIG_RXLVL(config->rxWatermark);
/* enable generating interrupts for FIFOTRIG levels */
tmp |= SPI_FIFOTRIG_TXLVLENA_MASK | SPI_FIFOTRIG_RXLVLENA_MASK;
/* set FIFOTRIG */
base->FIFOTRIG = tmp;
/* configure SPI mode */
tmp = base->CFG;
tmp &= ~(SPI_CFG_MASTER_MASK | SPI_CFG_LSBF_MASK | SPI_CFG_CPHA_MASK | SPI_CFG_CPOL_MASK);
/* phase */
tmp |= SPI_CFG_CPHA(config->phase);
/* polarity */
tmp |= SPI_CFG_CPOL(config->polarity);
/* direction */
tmp |= SPI_CFG_LSBF(config->direction);
base->CFG = tmp;
SPI_Enable(base, config->enableSlave);
return kStatus_Success;
}
void SPI_Deinit(SPI_Type *base)
{
/* Assert arguments */
assert(NULL != base);
/* Disable interrupts, disable dma requests, disable peripheral */
base->FIFOINTENCLR = SPI_FIFOINTENCLR_TXERR_MASK | SPI_FIFOINTENCLR_RXERR_MASK | SPI_FIFOINTENCLR_TXLVL_MASK |
SPI_FIFOINTENCLR_RXLVL_MASK;
base->FIFOCFG &= ~(SPI_FIFOCFG_DMATX_MASK | SPI_FIFOCFG_DMARX_MASK);
base->CFG &= ~(SPI_CFG_ENABLE_MASK);
}
void SPI_EnableTxDMA(SPI_Type *base, bool enable)
{
if (enable)
{
base->FIFOCFG |= SPI_FIFOCFG_DMATX_MASK;
}
else
{
base->FIFOCFG &= ~SPI_FIFOCFG_DMATX_MASK;
}
}
void SPI_EnableRxDMA(SPI_Type *base, bool enable)
{
if (enable)
{
base->FIFOCFG |= SPI_FIFOCFG_DMARX_MASK;
}
else
{
base->FIFOCFG &= ~SPI_FIFOCFG_DMARX_MASK;
}
}
status_t SPI_MasterSetBaud(SPI_Type *base, uint32_t baudrate_Bps, uint32_t srcClock_Hz)
{
uint32_t tmp;
/* assert params */
assert(!((NULL == base) || (0 == baudrate_Bps) || (0 == srcClock_Hz)));
if ((NULL == base) || (0 == baudrate_Bps) || (0 == srcClock_Hz))
{
return kStatus_InvalidArgument;
}
/* calculate baudrate */
tmp = (srcClock_Hz / baudrate_Bps) - 1;
if (tmp > 0xFFFF)
{
return kStatus_SPI_BaudrateNotSupport;
}
base->DIV &= ~SPI_DIV_DIVVAL_MASK;
base->DIV |= SPI_DIV_DIVVAL(tmp);
return kStatus_Success;
}
void SPI_WriteData(SPI_Type *base, uint16_t data, uint32_t configFlags)
{
uint32_t control = 0;
int32_t instance;
/* check params */
assert(NULL != base);
/* get and check instance */
instance = FLEXCOMM_GetInstance(base);
assert(!(instance < 0));
if (instance < 0)
{
return;
}
/* set data width */
control |= SPI_FIFOWR_LEN(g_configs[instance].dataWidth);
/* set sssel */
control |= (SPI_DEASSERT_ALL & (~SPI_DEASSERTNUM_SSEL(g_configs[instance].sselNum)));
/* mask configFlags */
control |= (configFlags & SPI_FIFOWR_FLAGS_MASK);
/* control should not affect lower 16 bits */
assert(!(control & 0xFFFF));
base->FIFOWR = data | control;
}
status_t SPI_MasterTransferCreateHandle(SPI_Type *base,
spi_master_handle_t *handle,
spi_master_callback_t callback,
void *userData)
{
int32_t instance = 0;
/* check 'base' */
assert(!(NULL == base));
if (NULL == base)
{
return kStatus_InvalidArgument;
}
/* check 'handle' */
assert(!(NULL == handle));
if (NULL == handle)
{
return kStatus_InvalidArgument;
}
/* get flexcomm instance by 'base' param */
instance = FLEXCOMM_GetInstance(base);
assert(!(instance < 0));
if (instance < 0)
{
return kStatus_InvalidArgument;
}
memset(handle, 0, sizeof(*handle));
/* Initialize the handle */
if (base->CFG & SPI_CFG_MASTER_MASK)
{
FLEXCOMM_SetIRQHandler(base, (flexcomm_irq_handler_t)(uintptr_t)SPI_MasterTransferHandleIRQ, handle);
}
else
{
FLEXCOMM_SetIRQHandler(base, (flexcomm_irq_handler_t)(uintptr_t)SPI_SlaveTransferHandleIRQ, handle);
}
handle->dataWidth = g_configs[instance].dataWidth;
/* in slave mode, the sselNum is not important */
handle->sselNum = g_configs[instance].sselNum;
handle->txWatermark = (spi_txfifo_watermark_t)SPI_FIFOTRIG_TXLVL_GET(base);
handle->rxWatermark = (spi_rxfifo_watermark_t)SPI_FIFOTRIG_RXLVL_GET(base);
handle->callback = callback;
handle->userData = userData;
/* Enable SPI NVIC */
EnableIRQ(s_spiIRQ[instance]);
return kStatus_Success;
}
status_t SPI_MasterTransferBlocking(SPI_Type *base, spi_transfer_t *xfer)
{
int32_t instance;
uint32_t tx_ctrl = 0, last_ctrl = 0;
uint32_t tmp32, rxRemainingBytes, txRemainingBytes, dataWidth;
uint32_t toReceiveCount = 0;
uint8_t *txData, *rxData;
uint32_t fifoDepth;
/* check params */
assert(!((NULL == base) || (NULL == xfer) || ((NULL == xfer->txData) && (NULL == xfer->rxData))));
if ((NULL == base) || (NULL == xfer) || ((NULL == xfer->txData) && (NULL == xfer->rxData)))
{
return kStatus_InvalidArgument;
}
fifoDepth = SPI_FIFO_DEPTH(base);
txData = xfer->txData;
rxData = xfer->rxData;
txRemainingBytes = txData ? xfer->dataSize : 0;
rxRemainingBytes = rxData ? xfer->dataSize : 0;
instance = FLEXCOMM_GetInstance(base);
assert(instance >= 0);
dataWidth = g_configs[instance].dataWidth;
/* dataSize (in bytes) is not aligned to 16bit (2B) transfer */
assert(!((dataWidth > kSPI_Data8Bits) && (xfer->dataSize & 0x1)));
if ((dataWidth > kSPI_Data8Bits) && (xfer->dataSize & 0x1))
{
return kStatus_InvalidArgument;
}
/* clear tx/rx errors and empty FIFOs */
base->FIFOCFG |= SPI_FIFOCFG_EMPTYTX_MASK | SPI_FIFOCFG_EMPTYRX_MASK;
base->FIFOSTAT |= SPI_FIFOSTAT_TXERR_MASK | SPI_FIFOSTAT_RXERR_MASK;
/* select slave to talk with */
tx_ctrl |= (SPI_DEASSERT_ALL & (~SPI_DEASSERTNUM_SSEL(g_configs[instance].sselNum)));
/* set width of data - range asserted at entry */
tx_ctrl |= SPI_FIFOWR_LEN(dataWidth);
/* end of transfer */
last_ctrl |= (xfer->configFlags & (uint32_t)kSPI_FrameAssert) ? (uint32_t)kSPI_FrameAssert : 0;
/* delay end of transfer */
last_ctrl |= (xfer->configFlags & (uint32_t)kSPI_FrameDelay) ? (uint32_t)kSPI_FrameDelay : 0;
/* last index of loop */
while (txRemainingBytes || rxRemainingBytes || toReceiveCount)
{
/* if rxFIFO is not empty */
if (base->FIFOSTAT & SPI_FIFOSTAT_RXNOTEMPTY_MASK)
{
tmp32 = base->FIFORD;
/* rxBuffer is not empty */
if (rxRemainingBytes)
{
*(rxData++) = tmp32;
rxRemainingBytes--;
/* read 16 bits at once */
if (dataWidth > 8)
{
*(rxData++) = tmp32 >> 8;
rxRemainingBytes--;
}
}
/* decrease number of data expected to receive */
toReceiveCount -= 1;
}
/* transmit if txFIFO is not full and data to receive does not exceed FIFO depth */
if ((base->FIFOSTAT & SPI_FIFOSTAT_TXNOTFULL_MASK) && (toReceiveCount < fifoDepth) &&
((txRemainingBytes) || (rxRemainingBytes >= SPI_COUNT_TO_BYTES(dataWidth, toReceiveCount + 1))))
{
/* txBuffer is not empty */
if (txRemainingBytes)
{
tmp32 = *(txData++);
txRemainingBytes--;
/* write 16 bit at once */
if (dataWidth > 8)
{
tmp32 |= ((uint32_t)(*(txData++))) << 8U;
txRemainingBytes--;
}
if (!txRemainingBytes)
{
tx_ctrl |= last_ctrl;
}
}
else
{
tmp32 = SPI_DUMMYDATA;
/* last transfer */
if (rxRemainingBytes == SPI_COUNT_TO_BYTES(dataWidth, toReceiveCount + 1))
{
tx_ctrl |= last_ctrl;
}
}
/* send data */
tmp32 = tx_ctrl | tmp32;
base->FIFOWR = tmp32;
toReceiveCount += 1;
}
}
/* wait if TX FIFO of previous transfer is not empty */
while (!(base->FIFOSTAT & SPI_FIFOSTAT_TXEMPTY_MASK))
{
}
return kStatus_Success;
}
status_t SPI_MasterTransferNonBlocking(SPI_Type *base, spi_master_handle_t *handle, spi_transfer_t *xfer)
{
/* check params */
assert(
!((NULL == base) || (NULL == handle) || (NULL == xfer) || ((NULL == xfer->txData) && (NULL == xfer->rxData))));
if ((NULL == base) || (NULL == handle) || (NULL == xfer) || ((NULL == xfer->txData) && (NULL == xfer->rxData)))
{
return kStatus_InvalidArgument;
}
/* dataSize (in bytes) is not aligned to 16bit (2B) transfer */
assert(!((handle->dataWidth > kSPI_Data8Bits) && (xfer->dataSize & 0x1)));
if ((handle->dataWidth > kSPI_Data8Bits) && (xfer->dataSize & 0x1))
{
return kStatus_InvalidArgument;
}
/* Check if SPI is busy */
if (handle->state == kStatus_SPI_Busy)
{
return kStatus_SPI_Busy;
}
/* Set the handle information */
handle->txData = xfer->txData;
handle->rxData = xfer->rxData;
/* set count */
handle->txRemainingBytes = xfer->txData ? xfer->dataSize : 0;
handle->rxRemainingBytes = xfer->rxData ? xfer->dataSize : 0;
handle->totalByteCount = xfer->dataSize;
/* other options */
handle->toReceiveCount = 0;
handle->configFlags = xfer->configFlags;
/* Set the SPI state to busy */
handle->state = kStatus_SPI_Busy;
/* clear FIFOs when transfer starts */
base->FIFOCFG |= SPI_FIFOCFG_EMPTYTX_MASK | SPI_FIFOCFG_EMPTYRX_MASK;
base->FIFOSTAT |= SPI_FIFOSTAT_TXERR_MASK | SPI_FIFOSTAT_RXERR_MASK;
/* enable generating txIRQ and rxIRQ, first transfer is fired by empty txFIFO */
base->FIFOINTENSET |= SPI_FIFOINTENSET_TXLVL_MASK | SPI_FIFOINTENSET_RXLVL_MASK;
return kStatus_Success;
}
status_t SPI_MasterTransferGetCount(SPI_Type *base, spi_master_handle_t *handle, size_t *count)
{
assert(NULL != handle);
if (!count)
{
return kStatus_InvalidArgument;
}
/* Catch when there is not an active transfer. */
if (handle->state != kStatus_SPI_Busy)
{
*count = 0;
return kStatus_NoTransferInProgress;
}
*count = handle->totalByteCount - handle->rxRemainingBytes;
return kStatus_Success;
}
void SPI_MasterTransferAbort(SPI_Type *base, spi_master_handle_t *handle)
{
assert(NULL != handle);
/* Disable interrupt requests*/
base->FIFOINTENSET &= ~(SPI_FIFOINTENSET_TXLVL_MASK | SPI_FIFOINTENSET_RXLVL_MASK);
/* Empty FIFOs */
base->FIFOCFG |= SPI_FIFOCFG_EMPTYTX_MASK | SPI_FIFOCFG_EMPTYRX_MASK;
handle->state = kStatus_SPI_Idle;
handle->txRemainingBytes = 0;
handle->rxRemainingBytes = 0;
}
static void SPI_TransferHandleIRQInternal(SPI_Type *base, spi_master_handle_t *handle)
{
uint32_t tx_ctrl = 0, last_ctrl = 0, tmp32;
bool loopContinue;
uint32_t fifoDepth;
/* check params */
assert((NULL != base) && (NULL != handle) && ((NULL != handle->txData) || (NULL != handle->rxData)));
fifoDepth = SPI_FIFO_DEPTH(base);
/* select slave to talk with */
tx_ctrl |= (SPI_DEASSERT_ALL & SPI_ASSERTNUM_SSEL(handle->sselNum));
/* set width of data */
tx_ctrl |= SPI_FIFOWR_LEN(handle->dataWidth);
/* end of transfer */
last_ctrl |= (handle->configFlags & (uint32_t)kSPI_FrameAssert) ? (uint32_t)kSPI_FrameAssert : 0;
/* delay end of transfer */
last_ctrl |= (handle->configFlags & (uint32_t)kSPI_FrameDelay) ? (uint32_t)kSPI_FrameDelay : 0;
do
{
loopContinue = false;
/* rxFIFO is not empty */
if (base->FIFOSTAT & SPI_FIFOSTAT_RXNOTEMPTY_MASK)
{
tmp32 = base->FIFORD;
/* rxBuffer is not empty */
if (handle->rxRemainingBytes)
{
/* low byte must go first */
*(handle->rxData++) = tmp32;
handle->rxRemainingBytes--;
/* read 16 bits at once */
if (handle->dataWidth > kSPI_Data8Bits)
{
*(handle->rxData++) = tmp32 >> 8;
handle->rxRemainingBytes--;
}
}
/* decrease number of data expected to receive */
handle->toReceiveCount -= 1;
loopContinue = true;
}
/* - txFIFO is not full
* - we cannot cause rxFIFO overflow by sending more data than is the depth of FIFO
* - txBuffer is not empty or the next 'toReceiveCount' data can fit into rxBuffer
*/
if ((base->FIFOSTAT & SPI_FIFOSTAT_TXNOTFULL_MASK) && (handle->toReceiveCount < fifoDepth) &&
((handle->txRemainingBytes) ||
(handle->rxRemainingBytes >= SPI_COUNT_TO_BYTES(handle->dataWidth, handle->toReceiveCount + 1))))
{
/* txBuffer is not empty */
if (handle->txRemainingBytes)
{
/* low byte must go first */
tmp32 = *(handle->txData++);
handle->txRemainingBytes--;
/* write 16 bit at once */
if (handle->dataWidth > kSPI_Data8Bits)
{
tmp32 |= ((uint32_t)(*(handle->txData++))) << 8U;
handle->txRemainingBytes--;
}
/* last transfer */
if (!handle->txRemainingBytes)
{
tx_ctrl |= last_ctrl;
}
}
else
{
tmp32 = SPI_DUMMYDATA;
/* last transfer */
if (handle->rxRemainingBytes == SPI_COUNT_TO_BYTES(handle->dataWidth, handle->toReceiveCount + 1))
{
tx_ctrl |= last_ctrl;
}
}
/* send data */
tmp32 = tx_ctrl | tmp32;
base->FIFOWR = tmp32;
/* increase number of expected data to receive */
handle->toReceiveCount += 1;
loopContinue = true;
}
} while (loopContinue);
}
void SPI_MasterTransferHandleIRQ(SPI_Type *base, spi_master_handle_t *handle)
{
assert((NULL != base) && (NULL != handle));
/* IRQ behaviour:
* - first interrupt is triggered by empty txFIFO. The transfer function
* then tries empty rxFIFO and fill txFIFO interleaved that results to
* strategy to process as many items as possible.
* - the next IRQs can be:
* rxIRQ from nonempty rxFIFO which requires to empty rxFIFO.
* txIRQ from empty txFIFO which requires to refill txFIFO.
* - last interrupt is triggered by empty txFIFO. The last state is
* known by empty rxBuffer and txBuffer. If there is nothing to receive
* or send - both operations have been finished and interrupts can be
* disabled.
*/
/* Data to send or read or expected to receive */
if ((handle->txRemainingBytes) || (handle->rxRemainingBytes) || (handle->toReceiveCount))
{
/* Transmit or receive data */
SPI_TransferHandleIRQInternal(base, handle);
/* No data to send or read or receive. Transfer ends. Set txTrigger to 0 level and
* enable txIRQ to confirm when txFIFO becomes empty */
if ((!handle->txRemainingBytes) && (!handle->rxRemainingBytes) && (!handle->toReceiveCount))
{
base->FIFOTRIG = base->FIFOTRIG & (~SPI_FIFOTRIG_TXLVL_MASK);
base->FIFOINTENSET |= SPI_FIFOINTENSET_TXLVL_MASK;
}
else
{
uint32_t rxRemainingCount = SPI_BYTES_TO_COUNT(handle->dataWidth, handle->rxRemainingBytes);
/* If, there are no data to send or rxFIFO is already filled with necessary number of dummy data,
* disable txIRQ. From this point only rxIRQ is used to receive data without any transmission */
if ((!handle->txRemainingBytes) && (rxRemainingCount <= handle->toReceiveCount))
{
base->FIFOINTENCLR = SPI_FIFOINTENCLR_TXLVL_MASK;
}
/* Nothing to receive or transmit, but we still have pending data which are bellow rxLevel.
* Cannot clear rxFIFO, txFIFO might be still active */
if (rxRemainingCount == 0)
{
if ((handle->txRemainingBytes == 0) && (handle->toReceiveCount != 0) &&
(handle->toReceiveCount < SPI_FIFOTRIG_RXLVL_GET(base) + 1))
{
base->FIFOTRIG =
(base->FIFOTRIG & (~SPI_FIFOTRIG_RXLVL_MASK)) | SPI_FIFOTRIG_RXLVL(handle->toReceiveCount - 1);
}
}
/* Expected to receive less data than rxLevel value, we have to update rxLevel */
else
{
if (rxRemainingCount < (SPI_FIFOTRIG_RXLVL_GET(base) + 1))
{
base->FIFOTRIG =
(base->FIFOTRIG & (~SPI_FIFOTRIG_RXLVL_MASK)) | SPI_FIFOTRIG_RXLVL(rxRemainingCount - 1);
}
}
}
}
else
{
/* Empty txFIFO is confirmed. Disable IRQs and restore triggers values */
base->FIFOINTENCLR = SPI_FIFOINTENCLR_RXLVL_MASK | SPI_FIFOINTENCLR_TXLVL_MASK;
base->FIFOTRIG = (base->FIFOTRIG & (~(SPI_FIFOTRIG_RXLVL_MASK | SPI_FIFOTRIG_RXLVL_MASK))) |
SPI_FIFOTRIG_RXLVL(handle->rxWatermark) | SPI_FIFOTRIG_TXLVL(handle->txWatermark);
/* set idle state and call user callback */
handle->state = kStatus_SPI_Idle;
if (handle->callback)
{
(handle->callback)(base, handle, handle->state, handle->userData);
}
}
}

View File

@ -0,0 +1,625 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used tom endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#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 USART driver version 2.0.0. */
#define FSL_SPI_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
/*@}*/
#define SPI_DUMMYDATA (0xFFFF)
#define SPI_DATA(n) (((uint32_t)(n)) & 0xFFFF)
#define SPI_CTRLMASK (0xFFFF0000)
#define SPI_ASSERTNUM_SSEL(n) ((~(1U << ((n) + 16))) & 0xF0000)
#define SPI_DEASSERTNUM_SSEL(n) (1U << ((n) + 16))
#define SPI_DEASSERT_ALL (0xF0000)
#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), /*!< Delay chip select */
kSPI_FrameAssert = (SPI_FIFOWR_EOT_MASK), /*!< When transfer ends, assert chip select */
} 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 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_txfifo_watermark_t txWatermark; /*!< txFIFO watermark */
spi_rxfifo_watermark_t rxWatermark; /*!< rxFIFO watermark */
} 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_txfifo_watermark_t txWatermark; /*!< txFIFO watermark */
spi_rxfifo_watermark_t rxWatermark; /*!< rxFIFO watermark */
} spi_slave_config_t;
/*! @brief SPI transfer status.*/
enum _spi_status
{
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 */
};
/*! @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 */
size_t dataSize; /*!< Transfer bytes */
} spi_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 size_t toReceiveCount; /*!< Receive data remaining in bytes */
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 */
spi_txfifo_watermark_t txWatermark; /*!< txFIFO watermark */
spi_rxfifo_watermark_t rxWatermark; /*!< rxFIFO watermark */
};
#if defined(__cplusplus)
extern "C" {
#endif
/*******************************************************************************
* API
******************************************************************************/
/*!
* @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 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;
}
/*! @} */
/*!
* @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.
*/
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 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_*/

View File

@ -0,0 +1,396 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "fsl_spi_dma.h"
/*******************************************************************************
* Definitons
******************************************************************************/
/*<! Structure definition for spi_dma_private_handle_t. The structure is private. */
typedef struct _spi_dma_private_handle
{
SPI_Type *base;
spi_dma_handle_t *handle;
} spi_dma_private_handle_t;
/*! @brief SPI transfer state, which is used for SPI transactiaonl APIs' internal state. */
enum _spi_dma_states_t
{
kSPI_Idle = 0x0, /*!< SPI is idle state */
kSPI_Busy /*!< SPI is busy tranferring data. */
};
typedef struct _spi_dma_txdummy
{
uint32_t lastWord;
uint32_t word;
} spi_dma_txdummy_t;
/*<! Private handle only used for internally. */
static spi_dma_private_handle_t s_dmaPrivateHandle[FSL_FEATURE_SOC_SPI_COUNT];
/*******************************************************************************
* Prototypes
******************************************************************************/
/*!
* @brief SPI private function to return SPI configuration
*
* @param base SPI base address.
*/
void *SPI_GetConfig(SPI_Type *base);
/*!
* @brief DMA callback function for SPI send transfer.
*
* @param handle DMA handle pointer.
* @param userData User data for DMA callback function.
*/
static void SPI_TxDMACallback(dma_handle_t *handle, void *userData, bool transferDone, uint32_t intmode);
/*!
* @brief DMA callback function for SPI receive transfer.
*
* @param handle DMA handle pointer.
* @param userData User data for DMA callback function.
*/
static void SPI_RxDMACallback(dma_handle_t *handle, void *userData, bool transferDone, uint32_t intmode);
/*******************************************************************************
* Variables
******************************************************************************/
static spi_dma_txdummy_t s_txDummy[FSL_FEATURE_SOC_SPI_COUNT] = {0};
static uint16_t s_rxDummy;
#if defined(__ICCARM__)
#pragma data_alignment = 16
static dma_descriptor_t s_spi_descriptor_table[FSL_FEATURE_SOC_SPI_COUNT] = {0};
#elif defined(__CC_ARM)
__attribute__((aligned(16))) static dma_descriptor_t s_spi_descriptor_table[FSL_FEATURE_SOC_SPI_COUNT] = {0};
#elif defined(__GNUC__)
__attribute__((aligned(16))) static dma_descriptor_t s_spi_descriptor_table[FSL_FEATURE_SOC_SPI_COUNT] = {0};
#endif
/*******************************************************************************
* Code
******************************************************************************/
static void XferToFifoWR(spi_transfer_t *xfer, uint32_t *fifowr)
{
*fifowr |= xfer->configFlags & (uint32_t)kSPI_FrameDelay ? (uint32_t)kSPI_FrameDelay : 0;
*fifowr |= xfer->configFlags & (uint32_t)kSPI_FrameAssert ? (uint32_t)kSPI_FrameAssert : 0;
}
static void SpiConfigToFifoWR(spi_config_t *config, uint32_t *fifowr)
{
*fifowr |= (SPI_DEASSERT_ALL & (~SPI_DEASSERTNUM_SSEL(config->sselNum)));
/* set width of data - range asserted at entry */
*fifowr |= SPI_FIFOWR_LEN(config->dataWidth);
}
static void PrepareTxFIFO(uint32_t *fifo, uint32_t count, uint32_t ctrl)
{
assert(!(fifo == NULL));
if (fifo == NULL)
{
return;
}
/* CS deassert and CS delay are relevant only for last word */
uint32_t tx_ctrl = ctrl & (~(SPI_FIFOWR_EOT_MASK | SPI_FIFOWR_EOF_MASK));
uint32_t i = 0;
for (; i + 1 < count; i++)
{
fifo[i] = (fifo[i] & 0xFFFFU) | (tx_ctrl & 0xFFFF0000U);
}
if (i < count)
{
fifo[i] = (fifo[i] & 0xFFFFU) | (ctrl & 0xFFFF0000U);
}
}
static void SPI_SetupDummy(uint32_t *dummy, spi_transfer_t *xfer, spi_config_t *spi_config_p)
{
*dummy = SPI_DUMMYDATA;
XferToFifoWR(xfer, dummy);
SpiConfigToFifoWR(spi_config_p, dummy);
}
status_t SPI_MasterTransferCreateHandleDMA(SPI_Type *base,
spi_dma_handle_t *handle,
spi_dma_callback_t callback,
void *userData,
dma_handle_t *txHandle,
dma_handle_t *rxHandle)
{
int32_t instance = 0;
/* check 'base' */
assert(!(NULL == base));
if (NULL == base)
{
return kStatus_InvalidArgument;
}
/* check 'handle' */
assert(!(NULL == handle));
if (NULL == handle)
{
return kStatus_InvalidArgument;
}
instance = FLEXCOMM_GetInstance(base);
memset(handle, 0, sizeof(*handle));
/* Set spi base to handle */
handle->txHandle = txHandle;
handle->rxHandle = rxHandle;
handle->callback = callback;
handle->userData = userData;
/* Set SPI state to idle */
handle->state = kSPI_Idle;
/* Set handle to global state */
s_dmaPrivateHandle[instance].base = base;
s_dmaPrivateHandle[instance].handle = handle;
/* Install callback for Tx dma channel */
DMA_SetCallback(handle->txHandle, SPI_TxDMACallback, &s_dmaPrivateHandle[instance]);
DMA_SetCallback(handle->rxHandle, SPI_RxDMACallback, &s_dmaPrivateHandle[instance]);
return kStatus_Success;
}
status_t SPI_MasterTransferDMA(SPI_Type *base, spi_dma_handle_t *handle, spi_transfer_t *xfer)
{
int32_t instance;
status_t result = kStatus_Success;
spi_config_t *spi_config_p;
assert(!((NULL == handle) || (NULL == xfer)));
if ((NULL == handle) || (NULL == xfer))
{
return kStatus_InvalidArgument;
}
/* txData set and not aligned to sizeof(uint32_t) */
assert(!((NULL != xfer->txData) && ((uint32_t)xfer->txData % sizeof(uint32_t))));
if ((NULL != xfer->txData) && ((uint32_t)xfer->txData % sizeof(uint32_t)))
{
return kStatus_InvalidArgument;
}
/* rxData set and not aligned to sizeof(uint32_t) */
assert(!((NULL != xfer->rxData) && ((uint32_t)xfer->rxData % sizeof(uint32_t))));
if ((NULL != xfer->rxData) && ((uint32_t)xfer->rxData % sizeof(uint32_t)))
{
return kStatus_InvalidArgument;
}
/* byte size is zero or not aligned to sizeof(uint32_t) */
assert(!((xfer->dataSize == 0) || (xfer->dataSize % sizeof(uint32_t))));
if ((xfer->dataSize == 0) || (xfer->dataSize % sizeof(uint32_t)))
{
return kStatus_InvalidArgument;
}
/* cannot get instance from base address */
instance = FLEXCOMM_GetInstance(base);
assert(!(instance < 0));
if (instance < 0)
{
return kStatus_InvalidArgument;
}
/* Check if the device is busy */
if (handle->state == kSPI_Busy)
{
return kStatus_SPI_Busy;
}
else
{
uint32_t tmp;
dma_transfer_config_t xferConfig = {0};
spi_config_p = (spi_config_t *)SPI_GetConfig(base);
handle->state = kStatus_SPI_Busy;
handle->transferSize = xfer->dataSize;
/* receive */
SPI_EnableRxDMA(base, true);
if (xfer->rxData)
{
DMA_PrepareTransfer(&xferConfig, (void *)&base->FIFORD, xfer->rxData, sizeof(uint32_t), xfer->dataSize,
kDMA_PeripheralToMemory, NULL);
}
else
{
DMA_PrepareTransfer(&xferConfig, (void *)&base->FIFORD, &s_rxDummy, sizeof(uint32_t), xfer->dataSize,
kDMA_StaticToStatic, NULL);
}
DMA_SubmitTransfer(handle->rxHandle, &xferConfig);
handle->rxInProgress = true;
DMA_StartTransfer(handle->rxHandle);
/* transmit */
SPI_EnableTxDMA(base, true);
if (xfer->txData)
{
tmp = 0;
XferToFifoWR(xfer, &tmp);
SpiConfigToFifoWR(spi_config_p, &tmp);
PrepareTxFIFO((uint32_t *)xfer->txData, xfer->dataSize / sizeof(uint32_t), tmp);
DMA_PrepareTransfer(&xferConfig, xfer->txData, (void *)&base->FIFOWR, sizeof(uint32_t), xfer->dataSize,
kDMA_MemoryToPeripheral, NULL);
DMA_SubmitTransfer(handle->txHandle, &xferConfig);
}
else
{
if ((xfer->configFlags & kSPI_FrameAssert) && (xfer->dataSize > sizeof(uint32_t)))
{
dma_xfercfg_t tmp_xfercfg = { 0 };
tmp_xfercfg.valid = true;
tmp_xfercfg.swtrig = true;
tmp_xfercfg.intA = true;
tmp_xfercfg.byteWidth = sizeof(uint32_t);
tmp_xfercfg.srcInc = 0;
tmp_xfercfg.dstInc = 0;
tmp_xfercfg.transferCount = 1;
/* create chained descriptor to transmit last word */
SPI_SetupDummy(&s_txDummy[instance].lastWord, xfer, spi_config_p);
DMA_CreateDescriptor(&s_spi_descriptor_table[instance], &tmp_xfercfg, &s_txDummy[instance].lastWord,
(uint32_t *)&base->FIFOWR, NULL);
/* use common API to setup first descriptor */
SPI_SetupDummy(&s_txDummy[instance].word, NULL, spi_config_p);
DMA_PrepareTransfer(&xferConfig, &s_txDummy[instance].word, (void *)&base->FIFOWR, sizeof(uint32_t),
xfer->dataSize - sizeof(uint32_t), kDMA_StaticToStatic,
&s_spi_descriptor_table[instance]);
/* disable interrupts for first descriptor
* to avoid calling callback twice */
xferConfig.xfercfg.intA = false;
xferConfig.xfercfg.intB = false;
result = DMA_SubmitTransfer(handle->txHandle, &xferConfig);
if (result != kStatus_Success)
{
return result;
}
}
else
{
SPI_SetupDummy(&s_txDummy[instance].word, xfer, spi_config_p);
DMA_PrepareTransfer(&xferConfig, &s_txDummy[instance].word, (void *)&base->FIFOWR, sizeof(uint32_t),
xfer->dataSize, kDMA_StaticToStatic, NULL);
result = DMA_SubmitTransfer(handle->txHandle, &xferConfig);
if (result != kStatus_Success)
{
return result;
}
}
}
handle->txInProgress = true;
DMA_StartTransfer(handle->txHandle);
}
return result;
}
static void SPI_RxDMACallback(dma_handle_t *handle, void *userData, bool transferDone, uint32_t intmode)
{
spi_dma_private_handle_t *privHandle = (spi_dma_private_handle_t *)userData;
spi_dma_handle_t *spiHandle = privHandle->handle;
SPI_Type *base = privHandle->base;
/* change the state */
spiHandle->rxInProgress = false;
/* All finished, call the callback */
if ((spiHandle->txInProgress == false) && (spiHandle->rxInProgress == false))
{
spiHandle->state = kSPI_Idle;
if (spiHandle->callback)
{
(spiHandle->callback)(base, spiHandle, kStatus_Success, spiHandle->userData);
}
}
}
static void SPI_TxDMACallback(dma_handle_t *handle, void *userData, bool transferDone, uint32_t intmode)
{
spi_dma_private_handle_t *privHandle = (spi_dma_private_handle_t *)userData;
spi_dma_handle_t *spiHandle = privHandle->handle;
SPI_Type *base = privHandle->base;
/* change the state */
spiHandle->txInProgress = false;
/* All finished, call the callback */
if ((spiHandle->txInProgress == false) && (spiHandle->rxInProgress == false))
{
spiHandle->state = kSPI_Idle;
if (spiHandle->callback)
{
(spiHandle->callback)(base, spiHandle, kStatus_Success, spiHandle->userData);
}
}
}
void SPI_MasterTransferAbortDMA(SPI_Type *base, spi_dma_handle_t *handle)
{
assert(NULL != handle);
/* Stop tx transfer first */
DMA_AbortTransfer(handle->txHandle);
/* Then rx transfer */
DMA_AbortTransfer(handle->rxHandle);
/* Set the handle state */
handle->txInProgress = false;
handle->rxInProgress = false;
handle->state = kSPI_Idle;
}
status_t SPI_MasterTransferGetCountDMA(SPI_Type *base, spi_dma_handle_t *handle, size_t *count)
{
assert(handle);
if (!count)
{
return kStatus_InvalidArgument;
}
/* Catch when there is not an active transfer. */
if (handle->state != kSPI_Busy)
{
*count = 0;
return kStatus_NoTransferInProgress;
}
size_t bytes;
bytes = DMA_GetRemainingBytes(handle->rxHandle->base, handle->rxHandle->channel);
*count = handle->transferSize - bytes;
return kStatus_Success;
}

View File

@ -0,0 +1,209 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used tom endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FSL_SPI_DMA_H_
#define _FSL_SPI_DMA_H_
#include "fsl_dma.h"
#include "fsl_spi.h"
/*!
* @addtogroup spi_dma_driver
* @{
*/
/*! @file */
/*******************************************************************************
* Definitions
******************************************************************************/
typedef struct _spi_dma_handle spi_dma_handle_t;
/*! @brief SPI DMA callback called at the end of transfer. */
typedef void (*spi_dma_callback_t)(SPI_Type *base, spi_dma_handle_t *handle, status_t status, void *userData);
/*! @brief SPI DMA transfer handle, users should not touch the content of the handle.*/
struct _spi_dma_handle
{
volatile bool txInProgress; /*!< Send transfer finished */
volatile bool rxInProgress; /*!< Receive transfer finished */
dma_handle_t *txHandle; /*!< DMA handler for SPI send */
dma_handle_t *rxHandle; /*!< DMA handler for SPI receive */
uint8_t bytesPerFrame; /*!< Bytes in a frame for SPI tranfer */
spi_dma_callback_t callback; /*!< Callback for SPI DMA transfer */
void *userData; /*!< User Data for SPI DMA callback */
uint32_t state; /*!< Internal state of SPI DMA transfer */
size_t transferSize; /*!< Bytes need to be transfer */
};
/*******************************************************************************
* APIs
******************************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif
/*!
* @name DMA Transactional
* @{
*/
/*!
* @brief Initialize the SPI master DMA handle.
*
* This function initializes the SPI master DMA handle which can be used for other SPI master transactional APIs.
* Usually, for a specified SPI instance, user need only call this API once to get the initialized handle.
*
* @param base SPI peripheral base address.
* @param handle SPI handle pointer.
* @param callback User callback function called at the end of a transfer.
* @param userData User data for callback.
* @param txHandle DMA handle pointer for SPI Tx, the handle shall be static allocated by users.
* @param rxHandle DMA handle pointer for SPI Rx, the handle shall be static allocated by users.
*/
status_t SPI_MasterTransferCreateHandleDMA(SPI_Type *base,
spi_dma_handle_t *handle,
spi_dma_callback_t callback,
void *userData,
dma_handle_t *txHandle,
dma_handle_t *rxHandle);
/*!
* @brief Perform a non-blocking SPI transfer using DMA.
*
* @note This interface returned immediately after transfer initiates, users should call
* SPI_GetTransferStatus to poll the transfer status to check whether SPI transfer finished.
*
* @param base SPI peripheral base address.
* @param handle SPI DMA handle pointer.
* @param xfer Pointer to dma transfer 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_MasterTransferDMA(SPI_Type *base, spi_dma_handle_t *handle, spi_transfer_t *xfer);
/*!
* @brief Initialize the SPI slave DMA handle.
*
* This function initializes the SPI slave DMA handle which can be used for other SPI master transactional APIs.
* Usually, for a specified SPI instance, user need only call this API once to get the initialized handle.
*
* @param base SPI peripheral base address.
* @param handle SPI handle pointer.
* @param callback User callback function called at the end of a transfer.
* @param userData User data for callback.
* @param txHandle DMA handle pointer for SPI Tx, the handle shall be static allocated by users.
* @param rxHandle DMA handle pointer for SPI Rx, the handle shall be static allocated by users.
*/
static inline status_t SPI_SlaveTransferCreateHandleDMA(SPI_Type *base,
spi_dma_handle_t *handle,
spi_dma_callback_t callback,
void *userData,
dma_handle_t *txHandle,
dma_handle_t *rxHandle)
{
return SPI_MasterTransferCreateHandleDMA(base, handle, callback, userData, txHandle, rxHandle);
}
/*!
* @brief Perform a non-blocking SPI transfer using DMA.
*
* @note This interface returned immediately after transfer initiates, users should call
* SPI_GetTransferStatus to poll the transfer status to check whether SPI transfer finished.
*
* @param base SPI peripheral base address.
* @param handle SPI DMA handle pointer.
* @param xfer Pointer to dma transfer 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_SlaveTransferDMA(SPI_Type *base, spi_dma_handle_t *handle, spi_transfer_t *xfer)
{
return SPI_MasterTransferDMA(base, handle, xfer);
}
/*!
* @brief Abort a SPI transfer using DMA.
*
* @param base SPI peripheral base address.
* @param handle SPI DMA handle pointer.
*/
void SPI_MasterTransferAbortDMA(SPI_Type *base, spi_dma_handle_t *handle);
/*!
* @brief Gets the master DMA transfer remaining bytes.
*
* This function gets the master DMA transfer remaining bytes.
*
* @param base SPI peripheral base address.
* @param handle A pointer to the spi_dma_handle_t structure which stores the transfer state.
* @param count A number of bytes transferred by the non-blocking transaction.
* @return status of status_t.
*/
status_t SPI_MasterTransferGetCountDMA(SPI_Type *base, spi_dma_handle_t *handle, size_t *count);
/*!
* @brief Abort a SPI transfer using DMA.
*
* @param base SPI peripheral base address.
* @param handle SPI DMA handle pointer.
*/
static inline void SPI_SlaveTransferAbortDMA(SPI_Type *base, spi_dma_handle_t *handle)
{
SPI_MasterTransferAbortDMA(base, handle);
}
/*!
* @brief Gets the slave DMA transfer remaining bytes.
*
* This function gets the slave DMA transfer remaining bytes.
*
* @param base SPI peripheral base address.
* @param handle A pointer to the spi_dma_handle_t structure which stores the transfer state.
* @param count A number of bytes transferred by the non-blocking transaction.
* @return status of status_t.
*/
static inline status_t SPI_SlaveTransferGetCountDMA(SPI_Type *base, spi_dma_handle_t *handle, size_t *count)
{
return SPI_MasterTransferGetCountDMA(base, handle, count);
}
/*! @} */
#if defined(__cplusplus)
}
#endif
/*! @} */
#endif /* _FSL_SPI_DMA_H_*/

View File

@ -0,0 +1,667 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "fsl_usart.h"
#include "fsl_device_registers.h"
#include "fsl_flexcomm.h"
enum _usart_transfer_states
{
kUSART_TxIdle, /* TX idle. */
kUSART_TxBusy, /* TX busy. */
kUSART_RxIdle, /* RX idle. */
kUSART_RxBusy /* RX busy. */
};
/* Array of UART IRQ number. */
static const IRQn_Type s_usartIRQ[] = USART_IRQS;
/*******************************************************************************
* Code
******************************************************************************/
static size_t USART_TransferGetRxRingBufferLength(usart_handle_t *handle)
{
size_t size;
/* Check arguments */
assert(NULL != handle);
if (handle->rxRingBufferTail > handle->rxRingBufferHead)
{
size = (size_t)(handle->rxRingBufferHead + handle->rxRingBufferSize - handle->rxRingBufferTail);
}
else
{
size = (size_t)(handle->rxRingBufferHead - handle->rxRingBufferTail);
}
return size;
}
static bool USART_TransferIsRxRingBufferFull(usart_handle_t *handle)
{
bool full;
/* Check arguments */
assert(NULL != handle);
if (USART_TransferGetRxRingBufferLength(handle) == (handle->rxRingBufferSize - 1U))
{
full = true;
}
else
{
full = false;
}
return full;
}
void USART_TransferStartRingBuffer(USART_Type *base, usart_handle_t *handle, uint8_t *ringBuffer, size_t ringBufferSize)
{
/* Check arguments */
assert(NULL != base);
assert(NULL != handle);
assert(NULL != ringBuffer);
/* Setup the ringbuffer address */
handle->rxRingBuffer = ringBuffer;
handle->rxRingBufferSize = ringBufferSize;
handle->rxRingBufferHead = 0U;
handle->rxRingBufferTail = 0U;
/* ring buffer is ready we can start receiving data */
base->FIFOINTENSET |= USART_FIFOINTENSET_RXLVL_MASK | USART_FIFOINTENSET_RXERR_MASK;
}
void USART_TransferStopRingBuffer(USART_Type *base, usart_handle_t *handle)
{
/* Check arguments */
assert(NULL != base);
assert(NULL != handle);
if (handle->rxState == kUSART_RxIdle)
{
base->FIFOINTENCLR = USART_FIFOINTENCLR_RXLVL_MASK | USART_FIFOINTENCLR_RXERR_MASK;
}
handle->rxRingBuffer = NULL;
handle->rxRingBufferSize = 0U;
handle->rxRingBufferHead = 0U;
handle->rxRingBufferTail = 0U;
}
status_t USART_Init(USART_Type *base, const usart_config_t *config, uint32_t srcClock_Hz)
{
int result;
/* check arguments */
assert(!((NULL == base) || (NULL == config) || (0 == srcClock_Hz)));
if ((NULL == base) || (NULL == config) || (0 == srcClock_Hz))
{
return kStatus_InvalidArgument;
}
/* initialize flexcomm to USART mode */
result = FLEXCOMM_Init(base, FLEXCOMM_PERIPH_USART);
if (kStatus_Success != result)
{
return result;
}
/* setup baudrate */
result = USART_SetBaudRate(base, config->baudRate_Bps, srcClock_Hz);
if (kStatus_Success != result)
{
return result;
}
if (config->enableTx)
{
/* empty and enable txFIFO */
base->FIFOCFG |= USART_FIFOCFG_EMPTYTX_MASK | USART_FIFOCFG_ENABLETX_MASK;
/* setup trigger level */
base->FIFOTRIG &= ~(USART_FIFOTRIG_TXLVL_MASK);
base->FIFOTRIG |= USART_FIFOTRIG_TXLVL(config->txWatermark);
/* enable trigger interrupt */
base->FIFOTRIG |= USART_FIFOTRIG_TXLVLENA_MASK;
}
/* empty and enable rxFIFO */
if (config->enableRx)
{
base->FIFOCFG |= USART_FIFOCFG_EMPTYRX_MASK | USART_FIFOCFG_ENABLERX_MASK;
/* setup trigger level */
base->FIFOTRIG &= ~(USART_FIFOTRIG_RXLVL_MASK);
base->FIFOTRIG |= USART_FIFOTRIG_RXLVL(config->rxWatermark);
/* enable trigger interrupt */
base->FIFOTRIG |= USART_FIFOTRIG_RXLVLENA_MASK;
}
/* setup configuration and enable USART */
base->CFG = USART_CFG_PARITYSEL(config->parityMode) | USART_CFG_STOPLEN(config->stopBitCount) |
USART_CFG_DATALEN(config->bitCountPerChar) | USART_CFG_LOOP(config->loopback) | USART_CFG_ENABLE_MASK;
return kStatus_Success;
}
void USART_Deinit(USART_Type *base)
{
/* Check arguments */
assert(NULL != base);
/* Disable interrupts, disable dma requests, disable peripheral */
base->FIFOINTENCLR = USART_FIFOINTENCLR_TXERR_MASK | USART_FIFOINTENCLR_RXERR_MASK | USART_FIFOINTENCLR_TXLVL_MASK | USART_FIFOINTENCLR_RXLVL_MASK;
base->FIFOCFG &= ~(USART_FIFOCFG_DMATX_MASK | USART_FIFOCFG_DMARX_MASK);
base->CFG &= ~(USART_CFG_ENABLE_MASK);
}
void USART_GetDefaultConfig(usart_config_t *config)
{
/* Check arguments */
assert(NULL != config);
/* Set always all members ! */
config->baudRate_Bps = 115200U;
config->parityMode = kUSART_ParityDisabled;
config->stopBitCount = kUSART_OneStopBit;
config->bitCountPerChar = kUSART_8BitsPerChar;
config->loopback = false;
config->enableRx = false;
config->enableTx = false;
config->txWatermark = kUSART_TxFifo0;
config->rxWatermark = kUSART_RxFifo1;
}
status_t USART_SetBaudRate(USART_Type *base, uint32_t baudrate_Bps, uint32_t srcClock_Hz)
{
uint32_t best_diff = (uint32_t)-1, best_osrval = 0xf, best_brgval = (uint32_t)-1;
uint32_t osrval, brgval, diff, baudrate;
/* check arguments */
assert(!((NULL == base) || (0 == baudrate_Bps) || (0 == srcClock_Hz)));
if ((NULL == base) || (0 == baudrate_Bps) || (0 == srcClock_Hz))
{
return kStatus_InvalidArgument;
}
for (osrval = best_osrval; osrval >= 4; osrval--)
{
brgval = (srcClock_Hz / ((osrval + 1) * baudrate_Bps)) - 1;
if (brgval > 0xFFFF)
{
continue;
}
baudrate = srcClock_Hz / ((osrval + 1) * (brgval + 1));
diff = baudrate_Bps < baudrate ? baudrate - baudrate_Bps : baudrate_Bps - baudrate;
if (diff < best_diff)
{
best_diff = diff;
best_osrval = osrval;
best_brgval = brgval;
}
}
/* value over range */
if (best_brgval > 0xFFFF)
{
return kStatus_USART_BaudrateNotSupport;
}
base->OSR = best_osrval;
base->BRG = best_brgval;
return kStatus_Success;
}
void USART_WriteBlocking(USART_Type *base, const uint8_t *data, size_t length)
{
/* Check arguments */
assert(!((NULL == base) || (NULL == data)));
if ((NULL == base) || (NULL == data))
{
return;
}
/* Check whether txFIFO is enabled */
if (!(base->FIFOCFG & USART_FIFOCFG_ENABLETX_MASK))
{
return;
}
for (; length > 0; length--)
{
/* Loop until txFIFO get some space for new data */
while (!(base->FIFOSTAT & USART_FIFOSTAT_TXNOTFULL_MASK))
{
}
base->FIFOWR = *data;
data++;
}
/* Wait to finish transfer */
while (!(base->FIFOSTAT & USART_FIFOSTAT_TXEMPTY_MASK))
{
}
}
status_t USART_ReadBlocking(USART_Type *base, uint8_t *data, size_t length)
{
uint32_t status;
/* check arguments */
assert(!((NULL == base) || (NULL == data)));
if ((NULL == base) || (NULL == data))
{
return kStatus_InvalidArgument;
}
/* Check whether rxFIFO is enabled */
if (!(base->FIFOCFG & USART_FIFOCFG_ENABLERX_MASK))
{
return kStatus_Fail;
}
for (; length > 0; length--)
{
/* loop until rxFIFO have some data to read */
while (!(base->FIFOSTAT & USART_FIFOSTAT_RXNOTEMPTY_MASK))
{
}
/* check receive status */
status = base->STAT;
if (status & USART_STAT_FRAMERRINT_MASK)
{
return kStatus_USART_FramingError;
}
if (status & USART_STAT_PARITYERRINT_MASK)
{
return kStatus_USART_ParityError;
}
if (status & USART_STAT_RXNOISEINT_MASK)
{
return kStatus_USART_NoiseError;
}
/* check rxFIFO status */
if (base->FIFOSTAT & USART_FIFOSTAT_RXERR_MASK)
{
return kStatus_USART_RxError;
}
*data = base->FIFORD;
data++;
}
return kStatus_Success;
}
status_t USART_TransferCreateHandle(USART_Type *base,
usart_handle_t *handle,
usart_transfer_callback_t callback,
void *userData)
{
int32_t instance = 0;
/* Check 'base' */
assert(!((NULL == base) || (NULL == handle)));
if ((NULL == base) || (NULL == handle))
{
return kStatus_InvalidArgument;
}
instance = FLEXCOMM_GetInstance(base);
memset(handle, 0, sizeof(*handle));
/* Set the TX/RX state. */
handle->rxState = kUSART_RxIdle;
handle->txState = kUSART_TxIdle;
/* Set the callback and user data. */
handle->callback = callback;
handle->userData = userData;
handle->rxWatermark = (usart_rxfifo_watermark_t)USART_FIFOTRIG_RXLVL_GET(base);
handle->txWatermark = (usart_txfifo_watermark_t)USART_FIFOTRIG_TXLVL_GET(base);
FLEXCOMM_SetIRQHandler(base, (flexcomm_irq_handler_t)(uintptr_t)USART_TransferHandleIRQ, handle);
/* Enable interrupt in NVIC. */
EnableIRQ(s_usartIRQ[instance]);
return kStatus_Success;
}
status_t USART_TransferSendNonBlocking(USART_Type *base, usart_handle_t *handle, usart_transfer_t *xfer)
{
/* Check arguments */
assert(!((NULL == base) || (NULL == handle) || (NULL == xfer)));
if ((NULL == base) || (NULL == handle) || (NULL == xfer))
{
return kStatus_InvalidArgument;
}
/* Check xfer members */
assert(!((0 == xfer->dataSize) || (NULL == xfer->data)));
if ((0 == xfer->dataSize) || (NULL == xfer->data))
{
return kStatus_InvalidArgument;
}
/* Return error if current TX busy. */
if (kUSART_TxBusy == handle->txState)
{
return kStatus_USART_TxBusy;
}
else
{
handle->txData = xfer->data;
handle->txDataSize = xfer->dataSize;
handle->txDataSizeAll = xfer->dataSize;
handle->txState = kUSART_TxBusy;
/* Enable transmiter interrupt. */
base->FIFOINTENSET |= USART_FIFOINTENSET_TXLVL_MASK;
}
return kStatus_Success;
}
void USART_TransferAbortSend(USART_Type *base, usart_handle_t *handle)
{
assert(NULL != handle);
/* Disable interrupts */
base->FIFOINTENSET &= ~USART_FIFOINTENSET_TXLVL_MASK;
/* Empty txFIFO */
base->FIFOCFG |= USART_FIFOCFG_EMPTYTX_MASK;
handle->txDataSize = 0;
handle->txState = kUSART_TxIdle;
}
status_t USART_TransferGetSendCount(USART_Type *base, usart_handle_t *handle, uint32_t *count)
{
assert(NULL != handle);
assert(NULL != count);
if (kUSART_TxIdle == handle->txState)
{
return kStatus_NoTransferInProgress;
}
*count = handle->txDataSizeAll - handle->txDataSize;
return kStatus_Success;
}
status_t USART_TransferReceiveNonBlocking(USART_Type *base,
usart_handle_t *handle,
usart_transfer_t *xfer,
size_t *receivedBytes)
{
uint32_t i;
/* How many bytes to copy from ring buffer to user memory. */
size_t bytesToCopy = 0U;
/* How many bytes to receive. */
size_t bytesToReceive;
/* How many bytes currently have received. */
size_t bytesCurrentReceived;
uint32_t regPrimask = 0U;
/* Check arguments */
assert(!((NULL == base) || (NULL == handle) || (NULL == xfer)));
if ((NULL == base) || (NULL == handle) || (NULL == xfer))
{
return kStatus_InvalidArgument;
}
/* Check xfer members */
assert(!((0 == xfer->dataSize) || (NULL == xfer->data)));
if ((0 == xfer->dataSize) || (NULL == xfer->data))
{
return kStatus_InvalidArgument;
}
/* How to get data:
1. If RX ring buffer is not enabled, then save xfer->data and xfer->dataSize
to uart handle, enable interrupt to store received data to xfer->data. When
all data received, trigger callback.
2. If RX ring buffer is enabled and not empty, get data from ring buffer first.
If there are enough data in ring buffer, copy them to xfer->data and return.
If there are not enough data in ring buffer, copy all of them to xfer->data,
save the xfer->data remained empty space to uart handle, receive data
to this empty space and trigger callback when finished. */
if (kUSART_RxBusy == handle->rxState)
{
return kStatus_USART_RxBusy;
}
else
{
bytesToReceive = xfer->dataSize;
bytesCurrentReceived = 0U;
/* If RX ring buffer is used. */
if (handle->rxRingBuffer)
{
/* Disable IRQ, protect ring buffer. */
regPrimask = DisableGlobalIRQ();
/* How many bytes in RX ring buffer currently. */
bytesToCopy = USART_TransferGetRxRingBufferLength(handle);
if (bytesToCopy)
{
bytesToCopy = MIN(bytesToReceive, bytesToCopy);
bytesToReceive -= bytesToCopy;
/* Copy data from ring buffer to user memory. */
for (i = 0U; i < bytesToCopy; i++)
{
xfer->data[bytesCurrentReceived++] = handle->rxRingBuffer[handle->rxRingBufferTail];
/* Wrap to 0. Not use modulo (%) because it might be large and slow. */
if (handle->rxRingBufferTail + 1U == handle->rxRingBufferSize)
{
handle->rxRingBufferTail = 0U;
}
else
{
handle->rxRingBufferTail++;
}
}
}
/* If ring buffer does not have enough data, still need to read more data. */
if (bytesToReceive)
{
/* No data in ring buffer, save the request to UART handle. */
handle->rxData = xfer->data + bytesCurrentReceived;
handle->rxDataSize = bytesToReceive;
handle->rxDataSizeAll = bytesToReceive;
handle->rxState = kUSART_RxBusy;
}
/* Enable IRQ if previously enabled. */
EnableGlobalIRQ(regPrimask);
/* Call user callback since all data are received. */
if (0 == bytesToReceive)
{
if (handle->callback)
{
handle->callback(base, handle, kStatus_USART_RxIdle, handle->userData);
}
}
}
/* Ring buffer not used. */
else
{
handle->rxData = xfer->data + bytesCurrentReceived;
handle->rxDataSize = bytesToReceive;
handle->rxDataSizeAll = bytesToReceive;
handle->rxState = kUSART_RxBusy;
/* Enable RX interrupt. */
base->FIFOINTENSET |= USART_FIFOINTENSET_RXLVL_MASK;
}
/* Return the how many bytes have read. */
if (receivedBytes)
{
*receivedBytes = bytesCurrentReceived;
}
}
return kStatus_Success;
}
void USART_TransferAbortReceive(USART_Type *base, usart_handle_t *handle)
{
assert(NULL != handle);
/* Only abort the receive to handle->rxData, the RX ring buffer is still working. */
if (!handle->rxRingBuffer)
{
/* Disable interrupts */
base->FIFOINTENSET &= ~USART_FIFOINTENSET_RXLVL_MASK;
/* Empty rxFIFO */
base->FIFOCFG |= USART_FIFOCFG_EMPTYRX_MASK;
}
handle->rxDataSize = 0U;
handle->rxState = kUSART_RxIdle;
}
status_t USART_TransferGetReceiveCount(USART_Type *base, usart_handle_t *handle, uint32_t *count)
{
assert(NULL != handle);
assert(NULL != count);
if (kUSART_RxIdle == handle->rxState)
{
return kStatus_NoTransferInProgress;
}
*count = handle->rxDataSizeAll - handle->rxDataSize;
return kStatus_Success;
}
void USART_TransferHandleIRQ(USART_Type *base, usart_handle_t *handle)
{
/* Check arguments */
assert((NULL != base) && (NULL != handle));
bool receiveEnabled = (handle->rxDataSize) || (handle->rxRingBuffer);
bool sendEnabled = handle->txDataSize;
/* If RX overrun. */
if (base->FIFOSTAT & USART_FIFOSTAT_RXERR_MASK)
{
/* Clear rx error state. */
base->FIFOSTAT |= USART_FIFOSTAT_RXERR_MASK;
/* clear rxFIFO */
base->FIFOCFG |= USART_FIFOCFG_EMPTYRX_MASK;
/* Trigger callback. */
if (handle->callback)
{
handle->callback(base, handle, kStatus_USART_RxError, handle->userData);
}
}
while ((receiveEnabled && (base->FIFOSTAT & USART_FIFOSTAT_RXNOTEMPTY_MASK)) ||
(sendEnabled && (base->FIFOSTAT & USART_FIFOSTAT_TXNOTFULL_MASK)))
{
/* Receive data */
if (receiveEnabled && (base->FIFOSTAT & USART_FIFOSTAT_RXNOTEMPTY_MASK))
{
/* Receive to app bufffer if app buffer is present */
if (handle->rxDataSize)
{
*handle->rxData = base->FIFORD;
handle->rxDataSize--;
handle->rxData++;
receiveEnabled = ((handle->rxDataSize != 0) || (handle->rxRingBuffer));
if (!handle->rxDataSize)
{
if (!handle->rxRingBuffer)
{
base->FIFOINTENCLR = USART_FIFOINTENCLR_RXLVL_MASK | USART_FIFOINTENSET_RXERR_MASK;
}
handle->rxState = kUSART_RxIdle;
if (handle->callback)
{
handle->callback(base, handle, kStatus_USART_RxIdle, handle->userData);
}
}
}
/* Otherwise receive to ring buffer if ring buffer is present */
else
{
if (handle->rxRingBuffer)
{
/* If RX ring buffer is full, trigger callback to notify over run. */
if (USART_TransferIsRxRingBufferFull(handle))
{
if (handle->callback)
{
handle->callback(base, handle, kStatus_USART_RxRingBufferOverrun, handle->userData);
}
}
/* If ring buffer is still full after callback function, the oldest data is overrided. */
if (USART_TransferIsRxRingBufferFull(handle))
{
/* Increase handle->rxRingBufferTail to make room for new data. */
if (handle->rxRingBufferTail + 1U == handle->rxRingBufferSize)
{
handle->rxRingBufferTail = 0U;
}
else
{
handle->rxRingBufferTail++;
}
}
/* Read data. */
handle->rxRingBuffer[handle->rxRingBufferHead] = base->FIFORD;
/* Increase handle->rxRingBufferHead. */
if (handle->rxRingBufferHead + 1U == handle->rxRingBufferSize)
{
handle->rxRingBufferHead = 0U;
}
else
{
handle->rxRingBufferHead++;
}
}
}
}
/* Send data */
if (sendEnabled && (base->FIFOSTAT & USART_FIFOSTAT_TXNOTFULL_MASK))
{
base->FIFOWR = *handle->txData;
handle->txDataSize--;
handle->txData++;
sendEnabled = handle->txDataSize != 0;
if (!sendEnabled)
{
base->FIFOINTENCLR = USART_FIFOINTENCLR_TXLVL_MASK;
handle->txState = kUSART_TxIdle;
if (handle->callback)
{
handle->callback(base, handle, kStatus_USART_TxIdle, handle->userData);
}
}
}
}
/* ring buffer is not used */
if (NULL == handle->rxRingBuffer)
{
/* restore if rx transfer ends and rxLevel is different from default value */
if ((handle->rxDataSize == 0) && (USART_FIFOTRIG_RXLVL_GET(base) != handle->rxWatermark))
{
base->FIFOTRIG = (base->FIFOTRIG & (~USART_FIFOTRIG_RXLVL_MASK)) | USART_FIFOTRIG_RXLVL(handle->rxWatermark);
}
/* decrease level if rx transfer is bellow */
if ((handle->rxDataSize != 0) && (handle->rxDataSize < (USART_FIFOTRIG_RXLVL_GET(base) + 1)))
{
base->FIFOTRIG = (base->FIFOTRIG & (~USART_FIFOTRIG_RXLVL_MASK)) | (USART_FIFOTRIG_RXLVL(handle->rxDataSize - 1));
}
}
}

View File

@ -0,0 +1,614 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FSL_USART_H_
#define _FSL_USART_H_
#include "fsl_common.h"
/*!
* @addtogroup usart_driver
* @{
*/
/*******************************************************************************
* Definitions
******************************************************************************/
/*! @name Driver version */
/*@{*/
/*! @brief USART driver version 2.0.0. */
#define FSL_USART_DRIVER_VERSION (MAKE_VERSION(2, 0, 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 Error codes for the USART driver. */
enum _usart_status
{
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 txFIFO. */
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 */
};
/*! @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 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), /*!< TXEMPT bit, sets if TX buffer is empty */
kUSART_RxError = (USART_FIFOSTAT_RXERR_MASK), /*!< TXEMPT bit, sets if TX buffer is empty */
kUSART_TxFifoEmptyFlag = (USART_FIFOSTAT_TXEMPTY_MASK), /*!< TXEMPT bit, sets if TX buffer is empty */
kUSART_TxFifoNotFullFlag = (USART_FIFOSTAT_TXNOTFULL_MASK), /*!< TXEMPT bit, sets if TX buffer is not full */
kUSART_RxFifoNotEmptyFlag = (USART_FIFOSTAT_RXNOTEMPTY_MASK), /*!< RXEMPT bit, sets if RX buffer is not empty */
kUSART_RxFifoFullFlag = (USART_FIFOSTAT_RXFULL_MASK), /*!< RXEMPT 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 */
usart_txfifo_watermark_t txWatermark;/*!< txFIFO watermark */
usart_rxfifo_watermark_t rxWatermark;/*!< rxFIFO watermark */
} 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 */
usart_txfifo_watermark_t txWatermark; /*!< txFIFO watermark */
usart_rxfifo_watermark_t rxWatermark; /*!< rxFIFO watermark */
};
/*******************************************************************************
* API
******************************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif /* _cplusplus */
/*!
* @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 freqency 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);
/* @} */
/*!
* @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;
}
/* @} */
/*!
* @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 & 0xF;
}
/*!
* @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->FIFOINTENSET = ~(mask & 0xF);
}
/*!
* @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);
}
}
/* @} */
/*!
* @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 base->FIFORD;
}
/*!
* @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.
*/
void 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_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 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 written to USART TX register.
*
* This function gets the number of bytes that have been written to USART TX
* register 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_ */

View File

@ -0,0 +1,263 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "fsl_usart.h"
#include "fsl_device_registers.h"
#include "fsl_dma.h"
#include "fsl_flexcomm.h"
#include "fsl_usart_dma.h"
#define USART_HANDLE_ARRAY_SIZE 7
/*<! Structure definition for uart_dma_handle_t. The structure is private. */
typedef struct _usart_dma_private_handle
{
USART_Type *base;
usart_dma_handle_t *handle;
} usart_dma_private_handle_t;
enum _usart_transfer_states
{
kUSART_TxIdle, /* TX idle. */
kUSART_TxBusy, /* TX busy. */
kUSART_RxIdle, /* RX idle. */
kUSART_RxBusy /* RX busy. */
};
/*<! Private handle only used for internally. */
static usart_dma_private_handle_t s_dmaPrivateHandle[USART_HANDLE_ARRAY_SIZE];
/*******************************************************************************
* Prototypes
******************************************************************************/
static void USART_TransferSendDMACallback(dma_handle_t *handle, void *param, bool transferDone, uint32_t intmode)
{
assert(handle);
assert(param);
usart_dma_private_handle_t *usartPrivateHandle = (usart_dma_private_handle_t *)param;
/* Disable UART TX DMA. */
USART_EnableTxDMA(usartPrivateHandle->base, false);
usartPrivateHandle->handle->txState = kUSART_TxIdle;
if (usartPrivateHandle->handle->callback)
{
usartPrivateHandle->handle->callback(usartPrivateHandle->base, usartPrivateHandle->handle, kStatus_USART_TxIdle,
usartPrivateHandle->handle->userData);
}
}
static void USART_TransferReceiveDMACallback(dma_handle_t *handle, void *param, bool transferDone, uint32_t intmode)
{
assert(handle);
assert(param);
usart_dma_private_handle_t *usartPrivateHandle = (usart_dma_private_handle_t *)param;
/* Disable UART RX DMA. */
USART_EnableRxDMA(usartPrivateHandle->base, false);
usartPrivateHandle->handle->rxState = kUSART_RxIdle;
if (usartPrivateHandle->handle->callback)
{
usartPrivateHandle->handle->callback(usartPrivateHandle->base, usartPrivateHandle->handle, kStatus_USART_RxIdle,
usartPrivateHandle->handle->userData);
}
}
status_t USART_TransferCreateHandleDMA(USART_Type *base,
usart_dma_handle_t *handle,
usart_dma_transfer_callback_t callback,
void *userData,
dma_handle_t *txDmaHandle,
dma_handle_t *rxDmaHandle)
{
int32_t instance = 0;
/* check 'base' */
assert(!(NULL == base));
if (NULL == base)
{
return kStatus_InvalidArgument;
}
/* check 'handle' */
assert(!(NULL == handle));
if (NULL == handle)
{
return kStatus_InvalidArgument;
}
instance = FLEXCOMM_GetInstance(base);
memset(handle, 0, sizeof(*handle));
/* assign 'base' and 'handle' */
s_dmaPrivateHandle[instance].base = base;
s_dmaPrivateHandle[instance].handle = handle;
/* set tx/rx 'idle' state */
handle->rxState = kUSART_RxIdle;
handle->txState = kUSART_TxIdle;
handle->callback = callback;
handle->userData = userData;
handle->rxDmaHandle = rxDmaHandle;
handle->txDmaHandle = txDmaHandle;
/* Configure TX. */
if (txDmaHandle)
{
DMA_SetCallback(txDmaHandle, USART_TransferSendDMACallback, &s_dmaPrivateHandle[instance]);
}
/* Configure RX. */
if (rxDmaHandle)
{
DMA_SetCallback(rxDmaHandle, USART_TransferReceiveDMACallback, &s_dmaPrivateHandle[instance]);
}
return kStatus_Success;
}
status_t USART_TransferSendDMA(USART_Type *base, usart_dma_handle_t *handle, usart_transfer_t *xfer)
{
assert(handle);
assert(handle->txDmaHandle);
assert(xfer);
assert(xfer->data);
assert(xfer->dataSize);
dma_transfer_config_t xferConfig;
status_t status;
/* If previous TX not finished. */
if (kUSART_TxBusy == handle->txState)
{
status = kStatus_USART_TxBusy;
}
else
{
handle->txState = kUSART_TxBusy;
handle->txDataSizeAll = xfer->dataSize;
/* Enable DMA request from txFIFO */
USART_EnableTxDMA(base, true);
/* Prepare transfer. */
DMA_PrepareTransfer(&xferConfig, xfer->data, (void *)&base->FIFOWR, sizeof(uint8_t), xfer->dataSize,
kDMA_MemoryToPeripheral, NULL);
/* Submit transfer. */
DMA_SubmitTransfer(handle->txDmaHandle, &xferConfig);
DMA_StartTransfer(handle->txDmaHandle);
status = kStatus_Success;
}
return status;
}
status_t USART_TransferReceiveDMA(USART_Type *base, usart_dma_handle_t *handle, usart_transfer_t *xfer)
{
assert(handle);
assert(handle->rxDmaHandle);
assert(xfer);
assert(xfer->data);
assert(xfer->dataSize);
dma_transfer_config_t xferConfig;
status_t status;
/* If previous RX not finished. */
if (kUSART_RxBusy == handle->rxState)
{
status = kStatus_USART_RxBusy;
}
else
{
handle->rxState = kUSART_RxBusy;
handle->rxDataSizeAll = xfer->dataSize;
/* Enable DMA request from rxFIFO */
USART_EnableRxDMA(base, true);
/* Prepare transfer. */
DMA_PrepareTransfer(&xferConfig, (void *)&base->FIFORD, xfer->data, sizeof(uint8_t), xfer->dataSize,
kDMA_PeripheralToMemory, NULL);
/* Submit transfer. */
DMA_SubmitTransfer(handle->rxDmaHandle, &xferConfig);
DMA_StartTransfer(handle->rxDmaHandle);
status = kStatus_Success;
}
return status;
}
void USART_TransferAbortSendDMA(USART_Type *base, usart_dma_handle_t *handle)
{
assert(NULL != handle);
assert(NULL != handle->txDmaHandle);
/* Stop transfer. */
DMA_AbortTransfer(handle->txDmaHandle);
handle->txState = kUSART_TxIdle;
}
void USART_TransferAbortReceiveDMA(USART_Type *base, usart_dma_handle_t *handle)
{
assert(NULL != handle);
assert(NULL != handle->rxDmaHandle);
/* Stop transfer. */
DMA_AbortTransfer(handle->rxDmaHandle);
handle->rxState = kUSART_RxIdle;
}
status_t USART_TransferGetReceiveCountDMA(USART_Type *base, usart_dma_handle_t *handle, uint32_t *count)
{
assert(handle);
assert(handle->rxDmaHandle);
assert(count);
if (kUSART_RxIdle == handle->rxState)
{
return kStatus_NoTransferInProgress;
}
*count = handle->rxDataSizeAll - DMA_GetRemainingBytes(handle->rxDmaHandle->base, handle->rxDmaHandle->channel);
return kStatus_Success;
}

View File

@ -0,0 +1,177 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FSL_USART_DMA_H_
#define _FSL_USART_DMA_H_
#include "fsl_common.h"
#include "fsl_dma.h"
#include "fsl_usart.h"
/*!
* @addtogroup usart_dma_driver
* @{
*/
/*! @file */
/*******************************************************************************
* Definitions
******************************************************************************/
/* Forward declaration of the handle typedef. */
typedef struct _usart_dma_handle usart_dma_handle_t;
/*! @brief UART transfer callback function. */
typedef void (*usart_dma_transfer_callback_t)(USART_Type *base,
usart_dma_handle_t *handle,
status_t status,
void *userData);
/*!
* @brief UART DMA handle
*/
struct _usart_dma_handle
{
USART_Type *base; /*!< UART peripheral base address. */
usart_dma_transfer_callback_t callback; /*!< Callback function. */
void *userData; /*!< UART callback function parameter.*/
size_t rxDataSizeAll; /*!< Size of the data to receive. */
size_t txDataSizeAll; /*!< Size of the data to send out. */
dma_handle_t *txDmaHandle; /*!< The DMA TX channel used. */
dma_handle_t *rxDmaHandle; /*!< The DMA RX channel used. */
volatile uint8_t txState; /*!< TX transfer state. */
volatile uint8_t rxState; /*!< RX transfer state */
};
/*******************************************************************************
* API
******************************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif /* _cplusplus */
/*!
* @name DMA transactional
* @{
*/
/*!
* @brief Initializes the USART handle which is used in transactional functions.
* @param base USART peripheral base address.
* @param handle Pointer to usart_dma_handle_t structure.
* @param callback Callback function.
* @param userData User data.
* @param txDmaHandle User-requested DMA handle for TX DMA transfer.
* @param rxDmaHandle User-requested DMA handle for RX DMA transfer.
*/
status_t USART_TransferCreateHandleDMA(USART_Type *base,
usart_dma_handle_t *handle,
usart_dma_transfer_callback_t callback,
void *userData,
dma_handle_t *txDmaHandle,
dma_handle_t *rxDmaHandle);
/*!
* @brief Sends data using DMA.
*
* This function sends data using DMA. This is a non-blocking function, which returns
* right away. When all data is sent, the send callback function is called.
*
* @param base USART peripheral base address.
* @param handle USART handle pointer.
* @param xfer USART DMA transfer structure. See #usart_transfer_t.
* @retval kStatus_Success if succeed, others failed.
* @retval kStatus_USART_TxBusy Previous transfer on going.
* @retval kStatus_InvalidArgument Invalid argument.
*/
status_t USART_TransferSendDMA(USART_Type *base, usart_dma_handle_t *handle, usart_transfer_t *xfer);
/*!
* @brief Receives data using DMA.
*
* This function receives data using DMA. This is a non-blocking function, which returns
* right away. When all data is received, the receive callback function is called.
*
* @param base USART peripheral base address.
* @param handle Pointer to usart_dma_handle_t structure.
* @param xfer USART DMA transfer structure. See #usart_transfer_t.
* @retval kStatus_Success if succeed, others failed.
* @retval kStatus_USART_RxBusy Previous transfer on going.
* @retval kStatus_InvalidArgument Invalid argument.
*/
status_t USART_TransferReceiveDMA(USART_Type *base, usart_dma_handle_t *handle, usart_transfer_t *xfer);
/*!
* @brief Aborts the sent data using DMA.
*
* This function aborts send data using DMA.
*
* @param base USART peripheral base address
* @param handle Pointer to usart_dma_handle_t structure
*/
void USART_TransferAbortSendDMA(USART_Type *base, usart_dma_handle_t *handle);
/*!
* @brief Aborts the received data using DMA.
*
* This function aborts the received data using DMA.
*
* @param base USART peripheral base address
* @param handle Pointer to usart_dma_handle_t structure
*/
void USART_TransferAbortReceiveDMA(USART_Type *base, usart_dma_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_TransferGetReceiveCountDMA(USART_Type *base, usart_dma_handle_t *handle, uint32_t *count);
/* @} */
#if defined(__cplusplus)
}
#endif
/*! @}*/
#endif /* _FSL_USART_DMA_H_ */

View File

@ -0,0 +1,153 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "fsl_utick.h"
#include "fsl_power.h"
/*******************************************************************************
* Definitions
******************************************************************************/
/* Typedef for interrupt handler. */
typedef void (*utick_isr_t)(UTICK_Type *base, utick_callback_t cb);
/*******************************************************************************
* Prototypes
******************************************************************************/
/*!
* @brief Gets the instance from the base address
*
* @param base UTICK peripheral base address
*
* @return The UTICK instance
*/
static uint32_t UTICK_GetInstance(UTICK_Type *base);
/*******************************************************************************
* Variables
******************************************************************************/
/* Array of UTICK handle. */
static utick_callback_t s_utickHandle[FSL_FEATURE_SOC_UTICK_COUNT];
/* Array of UTICK peripheral base address. */
static UTICK_Type *const s_utickBases[] = UTICK_BASE_PTRS;
/* Array of UTICK IRQ number. */
static const IRQn_Type s_utickIRQ[] = UTICK_IRQS;
/* Array of UTICK clock name. */
static const clock_ip_name_t s_utickClock[] = UTICK_CLOCKS;
/* UTICK ISR for transactional APIs. */
static utick_isr_t s_utickIsr;
/*******************************************************************************
* Code
******************************************************************************/
static uint32_t UTICK_GetInstance(UTICK_Type *base)
{
uint32_t instance;
/* Find the instance index from base address mappings. */
for (instance = 0; instance < FSL_FEATURE_SOC_UTICK_COUNT; instance++)
{
if (s_utickBases[instance] == base)
{
break;
}
}
assert(instance < FSL_FEATURE_SOC_UTICK_COUNT);
return instance;
}
void UTICK_SetTick(UTICK_Type *base, utick_mode_t mode, uint32_t count, utick_callback_t cb)
{
uint32_t instance;
/* Get instance from peripheral base address. */
instance = UTICK_GetInstance(base);
/* Save the handle in global variables to support the double weak mechanism. */
s_utickHandle[instance] = cb;
EnableDeepSleepIRQ(s_utickIRQ[instance]);
base->CTRL = count | UTICK_CTRL_REPEAT(mode);
}
void UTICK_Init(UTICK_Type *base)
{
/* Enable utick clock */
CLOCK_EnableClock(s_utickClock[UTICK_GetInstance(base)]);
/* Power up Watchdog oscillator*/
POWER_DisablePD(kPDRUNCFG_PD_WDT_OSC);
s_utickIsr = UTICK_HandleIRQ;
}
void UTICK_Deinit(UTICK_Type *base)
{
/* Turn off utick */
base->CTRL = 0;
/* Disable utick clock */
CLOCK_DisableClock(s_utickClock[UTICK_GetInstance(base)]);
}
uint32_t UTICK_GetStatusFlags(UTICK_Type *base)
{
return (base->STAT);
}
void UTICK_ClearStatusFlags(UTICK_Type *base)
{
base->STAT = UTICK_STAT_INTR_MASK;
}
void UTICK_HandleIRQ(UTICK_Type *base, utick_callback_t cb)
{
UTICK_ClearStatusFlags(base);
if (cb)
{
cb();
}
}
#if defined(UTICK0)
void UTICK0_DriverIRQHandler(void)
{
s_utickIsr(UTICK0, s_utickHandle[0]);
}
#endif
#if defined(UTICK1)
void UTICK1_DriverIRQHandler(void)
{
s_utickIsr(UTICK1, s_utickHandle[1]);
}
#endif
#if defined(UTICK2)
void UTICK2_DriverIRQHandler(void)
{
s_utickIsr(UTICK2, s_utickHandle[2]);
}
#endif

View File

@ -0,0 +1,140 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FSL_UTICK_H_
#define _FSL_UTICK_H_
#include "fsl_common.h"
/*!
* @addtogroup utick
* @{
*/
/*! @file*/
/*******************************************************************************
* Definitions
******************************************************************************/
/*! @name Driver version */
/*@{*/
/*! @brief UTICK driver version 2.0.0. */
#define FSL_UTICK_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
/*@}*/
/*! @brief UTICK timer operational mode. */
typedef enum _utick_mode
{
kUTICK_Onetime = 0x0U, /*!< Trigger once*/
kUTICK_Repeat = 0x1U, /*!< Trigger repeatedly */
} utick_mode_t;
/*! @brief UTICK callback function. */
typedef void (*utick_callback_t)(void);
/*******************************************************************************
* API
******************************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif /* _cplusplus */
/*!
* @name Initialization and deinitialization
* @{
*/
/*!
* @brief Initializes an UTICK by turning its bus clock on
*
*/
void UTICK_Init(UTICK_Type *base);
/*!
* @brief Deinitializes a UTICK instance.
*
* This function shuts down Utick bus clock
*
* @param base UTICK peripheral base address.
*/
void UTICK_Deinit(UTICK_Type *base);
/*!
* @brief Get Status Flags.
*
* This returns the status flag
*
* @param base UTICK peripheral base address.
* @return status register value
*/
uint32_t UTICK_GetStatusFlags(UTICK_Type *base);
/*!
* @brief Clear Status Interrupt Flags.
*
* This clears intr status flag
*
* @param base UTICK peripheral base address.
* @return none
*/
void UTICK_ClearStatusFlags(UTICK_Type *base);
/*!
* @brief Starts UTICK.
*
* This function starts a repeat/onetime countdown with an optional callback
*
* @param base UTICK peripheral base address.
* @param mode UTICK timer mode (ie kUTICK_onetime or kUTICK_repeat)
* @param count UTICK timer mode (ie kUTICK_onetime or kUTICK_repeat)
* @param cb UTICK callback (can be left as NULL if none, otherwise should be a void func(void))
* @return none
*/
void UTICK_SetTick(UTICK_Type *base, utick_mode_t mode, uint32_t count, utick_callback_t cb);
/*!
* @brief UTICK Interrupt Service Handler.
*
* This function handles the interrupt and refers to the callback array in the driver to callback user (as per request
* in UTICK_SetTick()).
* if no user callback is scheduled, the interrupt will simply be cleared.
*
* @param base UTICK peripheral base address.
* @param cb callback scheduled for this instance of UTICK
* @return none
*/
void UTICK_HandleIRQ(UTICK_Type *base, utick_callback_t cb);
/* @} */
#if defined(__cplusplus)
}
#endif
/*! @}*/
#endif /* _FSL_UTICK_H_ */

View File

@ -0,0 +1,162 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "fsl_wwdt.h"
/*******************************************************************************
* Prototypes
******************************************************************************/
/*!
* @brief Gets the instance from the base address
*
* @param base WWDT peripheral base address
*
* @return The WWDT instance
*/
static uint32_t WWDT_GetInstance(WWDT_Type *base);
/*******************************************************************************
* Variables
******************************************************************************/
/*! @brief Pointers to WWDT bases for each instance. */
static WWDT_Type *const s_wwdtBases[] = WWDT_BASE_PTRS;
/*! @brief Pointers to WWDT clocks for each instance. */
static const clock_ip_name_t s_wwdtClocks[] = WWDT_CLOCKS;
/*! @brief Pointers to WWDT resets for each instance. */
static const reset_ip_name_t s_wwdtResets[] = WWDT_RSTS;
/*******************************************************************************
* Code
******************************************************************************/
static uint32_t WWDT_GetInstance(WWDT_Type *base)
{
uint32_t instance;
uint32_t wwdtArrayCount = (sizeof(s_wwdtBases) / sizeof(s_wwdtBases[0]));
/* Find the instance index from base address mappings. */
for (instance = 0; instance < wwdtArrayCount; instance++)
{
if (s_wwdtBases[instance] == base)
{
break;
}
}
assert(instance < wwdtArrayCount);
return instance;
}
/*******************************************************************************
* Code
******************************************************************************/
void WWDT_GetDefaultConfig(wwdt_config_t *config)
{
assert(config);
/* Enable the watch dog */
config->enableWwdt = true;
/* Disable the watchdog timeout reset */
config->enableWatchdogReset = false;
/* Disable the watchdog protection for updating the timeout value */
config->enableWatchdogProtect = false;
/* Do not lock the watchdog oscillator */
config->enableLockOscillator = false;
/* Windowing is not in effect */
config->windowValue = 0xFFFFFFU;
/* Set the timeout value to the max */
config->timeoutValue = 0xFFFFFFU;
/* No warning is provided */
config->warningValue = 0;
}
void WWDT_Init(WWDT_Type *base, const wwdt_config_t *config)
{
assert(config);
uint32_t value = 0U;
/* Enable the WWDT clock */
CLOCK_EnableClock(s_wwdtClocks[WWDT_GetInstance(base)]);
/* Reset the WWDT module */
RESET_PeripheralReset(s_wwdtResets[WWDT_GetInstance(base)]);
value = WWDT_MOD_WDEN(config->enableWwdt) | WWDT_MOD_WDRESET(config->enableWatchdogReset) |
WWDT_MOD_WDPROTECT(config->enableWatchdogProtect) | WWDT_MOD_LOCK(config->enableLockOscillator);
/* Set configruation */
base->WINDOW = WWDT_WINDOW_WINDOW(config->windowValue);
base->TC = WWDT_TC_COUNT(config->timeoutValue);
base->WARNINT = WWDT_WARNINT_WARNINT(config->warningValue);
base->MOD = value;
}
void WWDT_Deinit(WWDT_Type *base)
{
WWDT_Disable(base);
/* Disable the WWDT clock */
CLOCK_DisableClock(s_wwdtClocks[WWDT_GetInstance(base)]);
}
void WWDT_Refresh(WWDT_Type *base)
{
uint32_t primaskValue = 0U;
/* Disable the global interrupt to protect refresh sequence */
primaskValue = DisableGlobalIRQ();
base->FEED = WWDT_FIRST_WORD_OF_REFRESH;
base->FEED = WWDT_SECOND_WORD_OF_REFRESH;
EnableGlobalIRQ(primaskValue);
}
void WWDT_ClearStatusFlags(WWDT_Type *base, uint32_t mask)
{
/* Clear the WDINT bit so that we don't accidentally clear it */
uint32_t reg = (base->MOD & (~WWDT_MOD_WDINT_MASK));
/* Clear timeout by writing a zero */
if (mask & kWWDT_TimeoutFlag)
{
reg &= ~WWDT_MOD_WDTOF_MASK;
}
/* Clear warning interrupt flag by writing a one */
if (mask & kWWDT_WarningFlag)
{
reg |= WWDT_MOD_WDINT_MASK;
}
base->MOD = reg;
}

View File

@ -0,0 +1,283 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FSL_WWDT_H_
#define _FSL_WWDT_H_
#include "fsl_common.h"
/*!
* @addtogroup wwdt
* @{
*/
/*! @file */
/*******************************************************************************
* Definitions
*******************************************************************************/
/*! @name Driver version */
/*@{*/
/*! @brief Defines WWDT driver version 2.0.0. */
#define FSL_WWDT_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
/*@}*/
/*! @name Refresh sequence */
/*@{*/
#define WWDT_FIRST_WORD_OF_REFRESH (0xAAU) /*!< First word of refresh sequence */
#define WWDT_SECOND_WORD_OF_REFRESH (0x55U) /*!< Second word of refresh sequence */
/*@}*/
/*! @brief Describes WWDT configuration structure. */
typedef struct _wwdt_config
{
bool enableWwdt; /*!< Enables or disables WWDT */
bool enableWatchdogReset; /*!< true: Watchdog timeout will cause a chip reset
false: Watchdog timeout will not cause a chip reset */
bool enableWatchdogProtect; /*!< true: Enable watchdog protect i.e timeout value can only be
changed after counter is below warning & window values
false: Disable watchdog protect; timeout value can be changed
at any time */
bool enableLockOscillator; /*!< true: Disabling or powering down the watchdog oscillator is prevented
Once set, this bit can only be cleared by a reset
false: Do not lock oscillator */
uint32_t windowValue; /*!< Window value, set this to 0xFFFFFF if windowing is not in effect */
uint32_t timeoutValue; /*!< Timeout value */
uint32_t warningValue; /*!< Watchdog time counter value that will generate a
warning interrupt. Set this to 0 for no warning */
} wwdt_config_t;
/*!
* @brief WWDT status flags.
*
* This structure contains the WWDT status flags for use in the WWDT functions.
*/
enum _wwdt_status_flags_t
{
kWWDT_TimeoutFlag = WWDT_MOD_WDTOF_MASK, /*!< Time-out flag, set when the timer times out */
kWWDT_WarningFlag = WWDT_MOD_WDINT_MASK /*!< Warning interrupt flag, set when timer is below the value WDWARNINT */
};
/*******************************************************************************
* API
*******************************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif /* __cplusplus */
/*!
* @name WWDT Initialization and De-initialization
* @{
*/
/*!
* @brief Initializes WWDT configure sturcture.
*
* This function initializes the WWDT configure structure to default value. The default
* value are:
* @code
* config->enableWwdt = true;
* config->enableWatchdogReset = false;
* config->enableWatchdogProtect = false;
* config->enableLockOscillator = false;
* config->windowValue = 0xFFFFFFU;
* config->timeoutValue = 0xFFFFFFU;
* config->warningValue = 0;
* @endcode
*
* @param config Pointer to WWDT config structure.
* @see wwdt_config_t
*/
void WWDT_GetDefaultConfig(wwdt_config_t *config);
/*!
* @brief Initializes the WWDT.
*
* This function initializes the WWDT. When called, the WWDT runs according to the configuration.
*
* Example:
* @code
* wwdt_config_t config;
* WWDT_GetDefaultConfig(&config);
* config.timeoutValue = 0x7ffU;
* WWDT_Init(wwdt_base,&config);
* @endcode
*
* @param base WWDT peripheral base address
* @param config The configuration of WWDT
*/
void WWDT_Init(WWDT_Type *base, const wwdt_config_t *config);
/*!
* @brief Shuts down the WWDT.
*
* This function shuts down the WWDT.
*
* @param base WWDT peripheral base address
*/
void WWDT_Deinit(WWDT_Type *base);
/* @} */
/*!
* @name WWDT Functional Operation
* @{
*/
/*!
* @brief Enables the WWDT module.
*
* This function write value into WWDT_MOD register to enable the WWDT, it is a write-once bit;
* once this bit is set to one and a watchdog feed is performed, the watchdog timer will run
* permanently.
*
* @param base WWDT peripheral base address
*/
static inline void WWDT_Enable(WWDT_Type *base)
{
base->MOD |= WWDT_MOD_WDEN_MASK;
}
/*!
* @brief Disables the WWDT module.
*
* This function write value into WWDT_MOD register to disable the WWDT.
*
* @param base WWDT peripheral base address
*/
static inline void WWDT_Disable(WWDT_Type *base)
{
base->MOD &= ~WWDT_MOD_WDEN_MASK;
}
/*!
* @brief Gets all WWDT status flags.
*
* This function gets all status flags.
*
* Example for getting Timeout Flag:
* @code
* uint32_t status;
* status = WWDT_GetStatusFlags(wwdt_base) & kWWDT_TimeoutFlag;
* @endcode
* @param base WWDT peripheral base address
* @return The status flags. This is the logical OR of members of the
* enumeration ::_wwdt_status_flags_t
*/
static inline uint32_t WWDT_GetStatusFlags(WWDT_Type *base)
{
return (base->MOD & (WWDT_MOD_WDTOF_MASK | WWDT_MOD_WDINT_MASK));
}
/*!
* @brief Clear WWDT flag.
*
* This function clears WWDT status flag.
*
* Example for clearing warning flag:
* @code
* WWDT_ClearStatusFlags(wwdt_base, kWWDT_WarningFlag);
* @endcode
* @param base WWDT peripheral base address
* @param mask The status flags to clear. This is a logical OR of members of the
* enumeration ::_wwdt_status_flags_t
*/
void WWDT_ClearStatusFlags(WWDT_Type *base, uint32_t mask);
/*!
* @brief Set the WWDT warning value.
*
* The WDWARNINT register determines the watchdog timer counter value that will generate a watchdog
* interrupt. When the watchdog timer counter is no longer greater than the value defined by
* WARNINT, an interrupt will be generated after the subsequent WDCLK.
*
* @param base WWDT peripheral base address
* @param warningValue WWDT warning value.
*/
static inline void WWDT_SetWarningValue(WWDT_Type *base, uint32_t warningValue)
{
base->WARNINT = WWDT_WARNINT_WARNINT(warningValue);
}
/*!
* @brief Set the WWDT timeout value.
*
* This function sets the timeout value. Every time a feed sequence occurs the value in the TC
* register is loaded into the Watchdog timer. Writing a value below 0xFF will cause 0xFF to be
* loaded into the TC register. Thus the minimum time-out interval is TWDCLK*256*4.
* If enableWatchdogProtect flag is true in wwdt_config_t config structure, any attempt to change
* the timeout value before the watchdog counter is below the warning and window values
* will cause a watchdog reset and set the WDTOF flag.
*
* @param base WWDT peripheral base address
* @param timeoutCount WWDT timeout value, count of WWDT clock tick.
*/
static inline void WWDT_SetTimeoutValue(WWDT_Type *base, uint32_t timeoutCount)
{
base->TC = WWDT_TC_COUNT(timeoutCount);
}
/*!
* @brief Sets the WWDT window value.
*
* The WINDOW register determines the highest TV value allowed when a watchdog feed is performed.
* If a feed sequence occurs when timer value is greater than the value in WINDOW, a watchdog
* event will occur. To disable windowing, set windowValue to 0xFFFFFF (maximum possible timer
* value) so windowing is not in effect.
*
* @param base WWDT peripheral base address
* @param windowValue WWDT window value.
*/
static inline void WWDT_SetWindowValue(WWDT_Type *base, uint32_t windowValue)
{
base->WINDOW = WWDT_WINDOW_WINDOW(windowValue);
}
/*!
* @brief Refreshes the WWDT timer.
*
* This function feeds the WWDT.
* This function should be called before WWDT timer is in timeout. Otherwise, a reset is asserted.
*
* @param base WWDT peripheral base address
*/
void WWDT_Refresh(WWDT_Type *base);
/*@}*/
#if defined(__cplusplus)
}
#endif /* __cplusplus */
/*! @}*/
#endif /* _FSL_WWDT_H_ */

View File

@ -0,0 +1,47 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_PERIPHERALPINS_H
#define MBED_PERIPHERALPINS_H
#include "pinmap.h"
#include "PeripheralNames.h"
/************RTC***************/
extern const PinMap PinMap_RTC[];
/************ADC***************/
extern const PinMap PinMap_ADC[];
/************I2C***************/
extern const PinMap PinMap_I2C_SDA[];
extern const PinMap PinMap_I2C_SCL[];
/************UART***************/
extern const PinMap PinMap_UART_TX[];
extern const PinMap PinMap_UART_RX[];
extern const PinMap PinMap_UART_CTS[];
extern const PinMap PinMap_UART_RTS[];
/************SPI***************/
extern const PinMap PinMap_SPI_SCLK[];
extern const PinMap PinMap_SPI_MOSI[];
extern const PinMap PinMap_SPI_MISO[];
extern const PinMap PinMap_SPI_SSEL[];
/************PWM***************/
extern const PinMap PinMap_PWM[];
#endif

View File

@ -0,0 +1,45 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_PORTNAMES_H
#define MBED_PORTNAMES_H
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
Port0 = 0,
Port1 = 1
} PortName;
typedef enum {
Flexcomm0 = 0,
Flexcomm1 = 1,
Flexcomm2 = 2,
Flexcomm3 = 3,
Flexcomm4 = 4,
Flexcomm5 = 5,
Flexcomm6 = 6,
Flexcomm7 = 7,
Flexcomm8 = 8,
Flexcomm9 = 9
} FlexcommName;
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,94 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "mbed_assert.h"
#include "analogin_api.h"
#if DEVICE_ANALOGIN
#include "cmsis.h"
#include "pinmap.h"
#include "PeripheralNames.h"
#include "fsl_adc.h"
#include "fsl_power.h"
#include "PeripheralPins.h"
/* Array of ADC peripheral base address. */
static ADC_Type *const adc_addrs[] = ADC_BASE_PTRS;
#define MAX_FADC 6000000
void analogin_init(analogin_t *obj, PinName pin)
{
obj->adc = (ADCName)pinmap_peripheral(pin, PinMap_ADC);
MBED_ASSERT(obj->adc != (ADCName)NC);
uint32_t instance = obj->adc >> ADC_INSTANCE_SHIFT;
adc_config_t adc_config;
/* SYSCON power. */
POWER_DisablePD(kPDRUNCFG_PD_ADC0); /* Power on the ADC converter. */
POWER_DisablePD(kPDRUNCFG_PD_VD7_ENA); /* Power on the analog power supply. */
POWER_DisablePD(kPDRUNCFG_PD_VREFP_SW); /* Power on the reference voltage source. */
POWER_DisablePD(kPDRUNCFG_PD_TEMPS); /* Power on the temperature sensor. */
/* Enable the clock. */
CLOCK_AttachClk(kFRO12M_to_MAIN_CLK);
CLOCK_EnableClock(kCLOCK_Adc0);
/* Calibration after power up. */
if (!(ADC_DoSelfCalibration(adc_addrs[instance]))) {
/* Calibration failed */
return;
}
ADC_GetDefaultConfig(&adc_config);
adc_config.clockDividerNumber = 1;
ADC_Init(adc_addrs[instance], &adc_config);
pinmap_pinout(pin, PinMap_ADC);
}
uint16_t analogin_read_u16(analogin_t *obj)
{
uint32_t instance = obj->adc >> ADC_INSTANCE_SHIFT;
uint32_t channel = obj->adc & 0xF;
adc_conv_seq_config_t adcConvSeqConfigStruct;
adc_result_info_t adcResultInfoStruct;
adcConvSeqConfigStruct.channelMask = (1U << channel);
adcConvSeqConfigStruct.triggerMask = 0U;
adcConvSeqConfigStruct.triggerPolarity = kADC_TriggerPolarityNegativeEdge;
adcConvSeqConfigStruct.enableSingleStep = false;
adcConvSeqConfigStruct.enableSyncBypass = false;
adcConvSeqConfigStruct.interruptMode = kADC_InterruptForEachSequence;
ADC_SetConvSeqAConfig(adc_addrs[instance], &adcConvSeqConfigStruct);
ADC_DoSoftwareTriggerConvSeqA(adc_addrs[instance]);
/* Wait for the converter to be done. */
while (!ADC_GetChannelConversionResult(adc_addrs[instance], channel, &adcResultInfoStruct)) {
}
return adcResultInfoStruct.result;
}
float analogin_read(analogin_t *obj)
{
uint16_t value = analogin_read_u16(obj);
return (float)value * (1.0f / (float)0xFFFF);
}
#endif

View File

@ -0,0 +1,75 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "mbed_assert.h"
#include "gpio_api.h"
#include "pinmap.h"
#include "fsl_gpio.h"
uint32_t gpio_set(PinName pin)
{
MBED_ASSERT(pin != (PinName)NC);
pin_function(pin, 0);
return (1 << ((int)pin & 0x1F));
}
void gpio_init(gpio_t *obj, PinName pin)
{
obj->pin = pin;
if (pin == (PinName)NC)
return;
pin_function(pin, 0);
}
void gpio_mode(gpio_t *obj, PinMode mode)
{
pin_mode(obj->pin, mode);
}
void gpio_dir(gpio_t *obj, PinDirection direction)
{
MBED_ASSERT(obj->pin != (PinName)NC);
uint32_t pin_number = obj->pin & 0x1F;
uint8_t port_number = obj->pin / 32;
switch (direction) {
case PIN_INPUT:
GPIO->DIR[port_number] &= ~(1U << pin_number);
break;
case PIN_OUTPUT:
GPIO->DIR[port_number] |= (1U << pin_number);
break;
}
}
void gpio_write(gpio_t *obj, int value)
{
MBED_ASSERT(obj->pin != (PinName)NC);
uint32_t pin_number = obj->pin & 0x1F;
uint8_t port_number = obj->pin / 32;
GPIO_WritePinOutput(GPIO, port_number, pin_number, value);
}
int gpio_read(gpio_t *obj)
{
MBED_ASSERT(obj->pin != (PinName)NC);
uint32_t pin_number = obj->pin & 0x1F;
uint8_t port_number = obj->pin / 32;
return (int)GPIO_ReadPinInput(GPIO, port_number, pin_number);
}

View File

@ -0,0 +1,150 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stddef.h>
#include "cmsis.h"
#include "gpio_irq_api.h"
#if DEVICE_INTERRUPTIN
#include "gpio_api.h"
#include "fsl_inputmux.h"
#include "fsl_pint.h"
#include "mbed_error.h"
static uint32_t channel_ids[NUMBER_OF_GPIO_INTS] = {0};
static gpio_irq_handler irq_handler;
/* Array of PORT IRQ number. */
static const IRQn_Type pint_irqs[] = PINT_IRQS;
void pint_intr_callback(pint_pin_int_t pintr, uint32_t pmatch_status)
{
uint32_t ch_bit = (1 << pintr);
// Return immediately if:
// * The interrupt was already served
// * There is no user handler
// * It is a level interrupt, not an edge interrupt
if (((PINT->IST & ch_bit) == 0) ||
(channel_ids[pintr] == 0) ||
(PINT->ISEL & ch_bit)) {
return;
}
if ((PINT->IENR & ch_bit) && (PINT->RISE & ch_bit)){
irq_handler(channel_ids[pintr], IRQ_RISE);
PINT->RISE = ch_bit;
}
if ((PINT->IENF & ch_bit) && (PINT->FALL & ch_bit)) {
irq_handler(channel_ids[pintr], IRQ_FALL);
PINT->FALL = ch_bit;
}
PINT_PinInterruptClrStatus(PINT, pintr);
}
int gpio_irq_init(gpio_irq_t *obj, PinName pin, gpio_irq_handler handler, uint32_t id)
{
int found_free_channel = 0;
int i = 0;
if (pin == NC) {
return -1;
}
irq_handler = handler;
for (i = 0; i < NUMBER_OF_GPIO_INTS; i++) {
if (channel_ids[i] == 0) {
channel_ids[i] = id;
obj->ch = i;
found_free_channel = 1;
break;
}
}
if (!found_free_channel) {
return -1;
}
obj->pin = pin & 0x1F;
obj->port = pin / 32;
/* Connect trigger sources to PINT */
INPUTMUX_Init(INPUTMUX);
INPUTMUX->PINTSEL[obj->ch] = pin;
/* Turnoff clock to inputmux to save power. Clock is only needed to make changes */
INPUTMUX_Deinit(INPUTMUX);
/* Initialize PINT */
PINT_Init(PINT);
NVIC_EnableIRQ(pint_irqs[obj->ch]);
return 0;
}
void gpio_irq_free(gpio_irq_t *obj)
{
channel_ids[obj->ch] = 0;
}
void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable)
{
unsigned int ch_bit = (1 << obj->ch);
// Clear interrupt
if (!(PINT->ISEL & ch_bit))
PINT->IST = ch_bit;
// Edge trigger
PINT->ISEL &= ~ch_bit;
/* Setup Pin Interrupt for rising or falling edge */
if (enable) {
if (event == IRQ_RISE) {
/* Checking if falling edge interrupt is already enabled on this pin */
if (PINT->IENF & (1U << obj->ch)) {
PINT_PinInterruptConfig(PINT, (pint_pin_int_t)obj->ch, kPINT_PinIntEnableBothEdges, pint_intr_callback);
} else {
PINT_PinInterruptConfig(PINT, (pint_pin_int_t)obj->ch, kPINT_PinIntEnableRiseEdge, pint_intr_callback);
}
} else {
/* Checking if rising edge interrupt is already enabled on this pin */
if (PINT->IENR & (1U << obj->ch)) {
PINT_PinInterruptConfig(PINT, (pint_pin_int_t)obj->ch, kPINT_PinIntEnableBothEdges, pint_intr_callback);
} else {
PINT_PinInterruptConfig(PINT, (pint_pin_int_t)obj->ch, kPINT_PinIntEnableFallEdge, pint_intr_callback);
}
}
} else {
PINT_PinInterruptConfig(PINT, (pint_pin_int_t)obj->ch, kPINT_PinIntEnableNone, NULL);
}
}
void gpio_irq_enable(gpio_irq_t *obj)
{
NVIC_EnableIRQ(pint_irqs[obj->ch]);
}
void gpio_irq_disable(gpio_irq_t *obj)
{
NVIC_DisableIRQ(pint_irqs[obj->ch]);
}
#endif

View File

@ -0,0 +1,36 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_GPIO_OBJECT_H
#define MBED_GPIO_OBJECT_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
PinName pin;
} gpio_t;
static inline int gpio_is_connected(const gpio_t *obj)
{
return obj->pin != (PinName)NC;
}
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,287 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "mbed_assert.h"
#include "i2c_api.h"
#if DEVICE_I2C
#include "cmsis.h"
#include "pinmap.h"
#include "fsl_i2c.h"
#include "PeripheralPins.h"
/* 7 bit IIC addr - R/W flag not included */
static int i2c_address = 0;
/* Array of I2C peripheral base address. */
static I2C_Type *const i2c_addrs[] = I2C_BASE_PTRS;
void i2c_init(i2c_t *obj, PinName sda, PinName scl)
{
uint32_t i2c_sda = pinmap_peripheral(sda, PinMap_I2C_SDA);
uint32_t i2c_scl = pinmap_peripheral(scl, PinMap_I2C_SCL);
obj->instance = pinmap_merge(i2c_sda, i2c_scl);
obj->next_repeated_start = 0;
MBED_ASSERT((int)obj->instance != NC);
i2c_master_config_t master_config;
switch (obj->instance) {
case 0:
CLOCK_AttachClk(kFRO12M_to_FLEXCOMM0);
RESET_PeripheralReset(kFC0_RST_SHIFT_RSTn);
break;
case 1:
CLOCK_AttachClk(kFRO12M_to_FLEXCOMM1);
RESET_PeripheralReset(kFC1_RST_SHIFT_RSTn);
break;
case 2:
CLOCK_AttachClk(kFRO12M_to_FLEXCOMM2);
RESET_PeripheralReset(kFC2_RST_SHIFT_RSTn);
break;
case 3:
CLOCK_AttachClk(kFRO12M_to_FLEXCOMM3);
RESET_PeripheralReset(kFC3_RST_SHIFT_RSTn);
break;
case 4:
CLOCK_AttachClk(kFRO12M_to_FLEXCOMM4);
RESET_PeripheralReset(kFC4_RST_SHIFT_RSTn);
break;
case 5:
CLOCK_AttachClk(kFRO12M_to_FLEXCOMM5);
RESET_PeripheralReset(kFC5_RST_SHIFT_RSTn);
break;
case 6:
CLOCK_AttachClk(kFRO12M_to_FLEXCOMM6);
RESET_PeripheralReset(kFC6_RST_SHIFT_RSTn);
break;
case 7:
CLOCK_AttachClk(kFRO12M_to_FLEXCOMM7);
RESET_PeripheralReset(kFC7_RST_SHIFT_RSTn);
break;
}
I2C_MasterGetDefaultConfig(&master_config);
I2C_MasterInit(i2c_addrs[obj->instance], &master_config, 12000000);
pinmap_pinout(sda, PinMap_I2C_SDA);
pinmap_pinout(scl, PinMap_I2C_SCL);
}
int i2c_start(i2c_t *obj)
{
I2C_Type *base = i2c_addrs[obj->instance];
uint32_t status;
do
{
status = I2C_GetStatusFlags(base);
} while ((status & I2C_STAT_MSTPENDING_MASK) == 0);
/* Clear controller state. */
I2C_MasterClearStatusFlags(base, I2C_STAT_MSTARBLOSS_MASK | I2C_STAT_MSTSTSTPERR_MASK);
/* Start the transfer */
base->MSTCTL = I2C_MSTCTL_MSTSTART_MASK;
return 0;
}
int i2c_stop(i2c_t *obj)
{
I2C_Type *base = i2c_addrs[obj->instance];
uint32_t status;
do
{
status = I2C_GetStatusFlags(base);
} while ((status & I2C_STAT_MSTPENDING_MASK) == 0);
/* Clear controller state. */
I2C_MasterClearStatusFlags(base, I2C_STAT_MSTARBLOSS_MASK | I2C_STAT_MSTSTSTPERR_MASK);
base->MSTCTL = I2C_MSTCTL_MSTSTOP_MASK;
return 0;
}
void i2c_frequency(i2c_t *obj, int hz)
{
I2C_MasterSetBaudRate(i2c_addrs[obj->instance], hz, 12000000);
}
int i2c_read(i2c_t *obj, int address, char *data, int length, int stop)
{
I2C_Type *base = i2c_addrs[obj->instance];
i2c_master_transfer_t master_xfer;
i2c_address = address >> 1;
memset(&master_xfer, 0, sizeof(master_xfer));
master_xfer.slaveAddress = address >> 1;
master_xfer.direction = kI2C_Read;
master_xfer.data = (uint8_t *)data;
master_xfer.dataSize = length;
if (obj->next_repeated_start) {
master_xfer.flags |= kI2C_TransferRepeatedStartFlag;
}
if (!stop) {
master_xfer.flags |= kI2C_TransferNoStopFlag;
}
obj->next_repeated_start = master_xfer.flags & kI2C_TransferNoStopFlag ? 1 : 0;
/* The below function will issue a STOP signal at the end of the transfer.
* This is required by the hardware in order to receive the last byte
*/
if (I2C_MasterTransferBlocking(base, &master_xfer) != kStatus_Success) {
return I2C_ERROR_NO_SLAVE;
}
return length;
}
int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop)
{
I2C_Type *base = i2c_addrs[obj->instance];
i2c_master_transfer_t master_xfer;
if (length == 0) {
if (I2C_MasterStart(base, address >> 1, kI2C_Write) != kStatus_Success) {
return I2C_ERROR_NO_SLAVE;
}
if (((I2C_GetStatusFlags(base) & I2C_STAT_MSTSTATE_MASK) >> I2C_STAT_MSTSTATE_SHIFT) == I2C_STAT_MSTCODE_NACKADR) {
i2c_stop(obj);
return I2C_ERROR_NO_SLAVE;
} else {
i2c_stop(obj);
return length;
}
}
memset(&master_xfer, 0, sizeof(master_xfer));
master_xfer.slaveAddress = address >> 1;
master_xfer.direction = kI2C_Write;
master_xfer.data = (uint8_t *)data;
master_xfer.dataSize = length;
if (obj->next_repeated_start) {
master_xfer.flags |= kI2C_TransferRepeatedStartFlag;
}
if (!stop) {
master_xfer.flags |= kI2C_TransferNoStopFlag;
}
obj->next_repeated_start = master_xfer.flags & kI2C_TransferNoStopFlag ? 1 : 0;
if (I2C_MasterTransferBlocking(base, &master_xfer) != kStatus_Success) {
return I2C_ERROR_NO_SLAVE;
}
return length;
}
void i2c_reset(i2c_t *obj)
{
i2c_stop(obj);
}
int i2c_byte_read(i2c_t *obj, int last)
{
uint8_t data;
I2C_Type *base = i2c_addrs[obj->instance];
i2c_master_transfer_t master_xfer;
memset(&master_xfer, 0, sizeof(master_xfer));
master_xfer.slaveAddress = i2c_address;
master_xfer.direction = kI2C_Read;
master_xfer.data = &data;
master_xfer.dataSize = 1;
if (I2C_MasterTransferBlocking(base, &master_xfer) != kStatus_Success) {
return I2C_ERROR_NO_SLAVE;
}
return data;
}
int i2c_byte_write(i2c_t *obj, int data)
{
status_t ret_value;
ret_value = I2C_MasterWriteBlocking(i2c_addrs[obj->instance], (uint8_t *)(&data), 1, kI2C_TransferNoStopFlag);
if (ret_value == kStatus_Success) {
return 1;
} else if (ret_value == kStatus_I2C_Nak) {
return 0;
} else {
return 2;
}
}
#if DEVICE_I2CSLAVE
void i2c_slave_mode(i2c_t *obj, int enable_slave)
{
i2c_slave_config_t slave_config;
I2C_SlaveGetDefaultConfig(&slave_config);
slave_config.enableSlave = (bool)enable_slave;
I2C_SlaveInit(i2c_addrs[obj->instance], &slave_config, 12000000);
}
int i2c_slave_receive(i2c_t *obj)
{
uint32_t status_flags = I2C_GetStatusFlags(i2c_addrs[obj->instance]);
if (status_flags & kI2C_SlaveSelected) {
if (((status_flags >> I2C_STAT_SLVSTATE_SHIFT) & I2C_STAT_SLVSTATE_MASK) == 0x1) {
// read addressed
return 1;
} else {
// write addressed
return 3;
}
} else {
// slave not addressed
return 0;
}
}
int i2c_slave_read(i2c_t *obj, char *data, int length)
{
I2C_Type *base = i2c_addrs[obj->instance];
I2C_SlaveReadBlocking(base, (uint8_t *)data, length);
return length;
}
int i2c_slave_write(i2c_t *obj, const char *data, int length)
{
I2C_Type *base = i2c_addrs[obj->instance];
I2C_SlaveWriteBlocking(base, (uint8_t *)data, length);
return length;
}
void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask)
{
if ((idx >= 0) && (idx <= 3)) {
I2C_SlaveSetAddress(i2c_addrs[obj->instance], (i2c_slave_address_register_t)idx, address, false);
}
}
#endif
#endif

View File

@ -0,0 +1,67 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_OBJECTS_H
#define MBED_OBJECTS_H
#include "cmsis.h"
#include "PortNames.h"
#include "PeripheralNames.h"
#include "PinNames.h"
#ifdef __cplusplus
extern "C" {
#endif
struct gpio_irq_s {
uint32_t port;
uint32_t pin;
uint32_t ch;
};
struct port_s {
PortName port;
uint32_t mask;
};
struct pwmout_s {
PWMName pwm_name;
};
struct serial_s {
int index;
};
struct analogin_s {
ADCName adc;
};
struct i2c_s {
uint32_t instance;
uint8_t next_repeated_start;
};
struct spi_s {
uint32_t instance;
uint8_t bits;
};
#include "gpio_object.h"
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,58 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "mbed_assert.h"
#include "pinmap.h"
#include "mbed_error.h"
#include "fsl_common.h"
void pin_function(PinName pin, int function)
{
MBED_ASSERT(pin != (PinName)NC);
clock_ip_name_t gpio_clocks[] = GPIO_CLOCKS;
uint32_t pin_number = pin & 0x1F;
uint8_t port_number = pin / 32;
uint32_t reg;
CLOCK_EnableClock(gpio_clocks[port_number]);
CLOCK_EnableClock(kCLOCK_Iocon);
reg = IOCON->PIO[port_number][pin_number];
reg = (reg & ~0x7) | (function & 0x7);
IOCON->PIO[port_number][pin_number] = reg;
}
void pin_mode(PinName pin, PinMode mode)
{
MBED_ASSERT(pin != (PinName)NC);
uint32_t pin_number = pin & 0x1F;
uint8_t port_number = pin / 32;
uint32_t reg = IOCON->PIO[port_number][pin_number] & ~IOCON_PIO_MODE_MASK;
switch (mode) {
case PullNone:
break;
case PullDown:
reg |= (1 << IOCON_PIO_MODE_SHIFT);
break;
case PullUp:
reg |= (2 << IOCON_PIO_MODE_SHIFT);
break;
default:
break;
}
IOCON->PIO[port_number][pin_number] = reg;
}

View File

@ -0,0 +1,82 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "port_api.h"
#if DEVICE_PORTIN || DEVICE_PORTOUT
#include "pinmap.h"
#include "gpio_api.h"
#include "fsl_gpio.h"
PinName port_pin(PortName port, int pin_n)
{
return (PinName)((port << PORT_SHIFT) | pin_n);;
}
void port_init(port_t *obj, PortName port, int mask, PinDirection dir)
{
uint32_t i;
obj->port = port;
obj->mask = mask;
GPIO->MASK[port] = ~mask;
// The function is set per pin: reuse gpio logic
for (i = 0; i < 32; i++) {
if (obj->mask & (1 << i)) {
gpio_set(port_pin(obj->port, i));
}
}
port_dir(obj, dir);
}
void port_mode(port_t *obj, PinMode mode)
{
uint32_t i;
// The mode is set per pin: reuse pinmap logic
for (i = 0; i < 32; i++) {
if (obj->mask & (1 << i)) {
pin_mode(port_pin(obj->port, i), mode);
}
}
}
void port_dir(port_t *obj, PinDirection dir)
{
switch (dir) {
case PIN_INPUT:
GPIO->DIR[obj->port] &= ~obj->mask;
break;
case PIN_OUTPUT:
GPIO->DIR[obj->port] |= obj->mask;
break;
}
}
void port_write(port_t *obj, int value)
{
GPIO_WriteMPort(GPIO, obj->port, value);
}
int port_read(port_t *obj)
{
return (int)(GPIO_ReadMPort(GPIO, obj->port));
}
#endif

View File

@ -0,0 +1,65 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "rtc_api.h"
#if DEVICE_RTC
#include "pinmap.h"
#include "fsl_rtc.h"
#include "PeripheralPins.h"
extern void rtc_setup_oscillator(void);
void rtc_init(void)
{
rtc_setup_oscillator();
RTC_Init(RTC);
RTC_StartTimer(RTC);
}
void rtc_free(void)
{
RTC_Deinit(RTC);
}
/*
* Little check routine to see if the RTC has been enabled
* 0 = Disabled, 1 = Enabled
*/
int rtc_isenabled(void)
{
CLOCK_EnableClock(kCLOCK_Rtc);
return (int)((RTC->CTRL & RTC_CTRL_RTC_EN_MASK) >> RTC_CTRL_RTC_EN_SHIFT);
}
time_t rtc_read(void)
{
return (time_t)RTC->COUNT;
}
void rtc_write(time_t t)
{
if (t == 0) {
t = 1;
}
RTC_StopTimer(RTC);
RTC->COUNT = t;
RTC_StartTimer(RTC);
}
#endif

View File

@ -0,0 +1,346 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "serial_api.h"
#if DEVICE_SERIAL
// math.h required for floating point operations for baud rate calculation
#include <math.h>
#include "mbed_assert.h"
#include <string.h>
#include "cmsis.h"
#include "pinmap.h"
#include "fsl_usart.h"
#include "PeripheralPins.h"
#include "clock_config.h"
static uint32_t serial_irq_ids[FSL_FEATURE_SOC_USART_COUNT] = {0};
static uart_irq_handler irq_handler;
/* Array of UART peripheral base address. */
static USART_Type *const uart_addrs[] = USART_BASE_PTRS;
int stdio_uart_inited = 0;
serial_t stdio_uart;
void serial_init(serial_t *obj, PinName tx, PinName rx)
{
uint32_t uart_tx = pinmap_peripheral(tx, PinMap_UART_TX);
uint32_t uart_rx = pinmap_peripheral(rx, PinMap_UART_RX);
obj->index = pinmap_merge(uart_tx, uart_rx);
MBED_ASSERT((int)obj->index != NC);
usart_config_t config;
switch (obj->index) {
case 0:
CLOCK_AttachClk(kFRO12M_to_FLEXCOMM0);
RESET_PeripheralReset(kFC0_RST_SHIFT_RSTn);
break;
case 1:
CLOCK_AttachClk(kFRO12M_to_FLEXCOMM1);
RESET_PeripheralReset(kFC1_RST_SHIFT_RSTn);
break;
case 2:
CLOCK_AttachClk(kFRO12M_to_FLEXCOMM2);
RESET_PeripheralReset(kFC2_RST_SHIFT_RSTn);
break;
case 3:
CLOCK_AttachClk(kFRO12M_to_FLEXCOMM3);
RESET_PeripheralReset(kFC3_RST_SHIFT_RSTn);
break;
case 4:
CLOCK_AttachClk(kFRO12M_to_FLEXCOMM4);
RESET_PeripheralReset(kFC4_RST_SHIFT_RSTn);
break;
case 5:
CLOCK_AttachClk(kFRO12M_to_FLEXCOMM5);
RESET_PeripheralReset(kFC5_RST_SHIFT_RSTn);
break;
case 6:
CLOCK_AttachClk(kFRO12M_to_FLEXCOMM6);
RESET_PeripheralReset(kFC6_RST_SHIFT_RSTn);
break;
case 7:
CLOCK_AttachClk(kFRO12M_to_FLEXCOMM7);
RESET_PeripheralReset(kFC7_RST_SHIFT_RSTn);
break;
}
USART_GetDefaultConfig(&config);
config.baudRate_Bps = 9600;
config.enableTx = true;
config.enableRx = true;
USART_Init(uart_addrs[obj->index], &config, 12000000);
pinmap_pinout(tx, PinMap_UART_TX);
pinmap_pinout(rx, PinMap_UART_RX);
if (tx != NC) {
pin_mode(tx, PullUp);
}
if (rx != NC) {
pin_mode(rx, PullUp);
}
if (obj->index == STDIO_UART) {
stdio_uart_inited = 1;
memcpy(&stdio_uart, obj, sizeof(serial_t));
}
}
void serial_free(serial_t *obj)
{
USART_Deinit(uart_addrs[obj->index]);
serial_irq_ids[obj->index] = 0;
}
void serial_baud(serial_t *obj, int baudrate)
{
USART_SetBaudRate(uart_addrs[obj->index], (uint32_t)baudrate, 12000000);
}
void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits)
{
USART_Type *base = uart_addrs[obj->index];
uint8_t temp;
/* Set bit count and parity mode. */
temp = base->CFG & ~(USART_CFG_PARITYSEL_MASK | USART_CFG_DATALEN_MASK | USART_CFG_STOPLEN_MASK);
if (parity != ParityNone)
{
/* Enable Parity */
if (parity == ParityOdd) {
temp |= USART_CFG_PARITYSEL(3U);
} else if (parity == ParityEven) {
temp |= USART_CFG_PARITYSEL(2U);
} else {
// Hardware does not support forced parity
MBED_ASSERT(0);
}
}
/* Set stop bits */
if (stop_bits == 2) {
temp |= USART_CFG_STOPLEN(1U);
}
/* Set Data size */
if (data_bits == 8) {
temp |= USART_CFG_DATALEN(1U);
} else {
temp |= USART_CFG_DATALEN(2U);
}
base->CFG = temp;
}
/******************************************************************************
* INTERRUPTS HANDLING
******************************************************************************/
static inline void uart_irq(uint32_t transmit_empty, uint32_t receive_full, uint32_t index)
{
if (serial_irq_ids[index] != 0) {
if (transmit_empty)
irq_handler(serial_irq_ids[index], TxIrq);
if (receive_full)
irq_handler(serial_irq_ids[index], RxIrq);
}
}
void uart0_irq()
{
uint32_t status_flags = USART0->FIFOSTAT;
uart_irq((status_flags & kUSART_TxFifoEmptyFlag), (status_flags & kUSART_RxFifoFullFlag), 0);
}
void uart1_irq()
{
uint32_t status_flags = USART1->FIFOSTAT;
uart_irq((status_flags & kUSART_TxFifoEmptyFlag), (status_flags & kUSART_RxFifoFullFlag), 1);
}
void uart2_irq()
{
uint32_t status_flags = USART2->FIFOSTAT;
uart_irq((status_flags & kUSART_TxFifoEmptyFlag), (status_flags & kUSART_RxFifoFullFlag), 2);
}
void uart3_irq()
{
uint32_t status_flags = USART3->FIFOSTAT;
uart_irq((status_flags & kUSART_TxFifoEmptyFlag), (status_flags & kUSART_RxFifoFullFlag), 3);
}
void uart4_irq()
{
uint32_t status_flags = USART4->FIFOSTAT;
uart_irq((status_flags & kUSART_TxFifoEmptyFlag), (status_flags & kUSART_RxFifoFullFlag), 4);
}
void uart5_irq()
{
uint32_t status_flags = USART5->FIFOSTAT;
uart_irq((status_flags & kUSART_TxFifoEmptyFlag), (status_flags & kUSART_RxFifoFullFlag), 5);
}
void uart6_irq()
{
uint32_t status_flags = USART6->FIFOSTAT;
uart_irq((status_flags & kUSART_TxFifoEmptyFlag), (status_flags & kUSART_RxFifoFullFlag), 6);
}
void uart7_irq()
{
uint32_t status_flags = USART7->FIFOSTAT;
uart_irq((status_flags & kUSART_TxFifoEmptyFlag), (status_flags & kUSART_RxFifoFullFlag), 7);
}
void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id)
{
irq_handler = handler;
serial_irq_ids[obj->index] = id;
}
void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable)
{
IRQn_Type uart_irqs[] = USART_IRQS;
uint32_t vector = 0;
switch (obj->index) {
case 0:
vector = (uint32_t)&uart0_irq;
break;
case 1:
vector = (uint32_t)&uart1_irq;
break;
case 2:
vector = (uint32_t)&uart2_irq;
break;
case 3:
vector = (uint32_t)&uart3_irq;
break;
case 4:
vector = (uint32_t)&uart4_irq;
break;
case 5:
vector = (uint32_t)&uart5_irq;
break;
case 6:
vector = (uint32_t)&uart6_irq;
break;
case 7:
vector = (uint32_t)&uart7_irq;
break;
default:
break;
}
if (enable) {
switch (irq) {
case RxIrq:
USART_EnableInterrupts(uart_addrs[obj->index], kUSART_RxLevelInterruptEnable);
break;
case TxIrq:
USART_EnableInterrupts(uart_addrs[obj->index], kUSART_TxLevelInterruptEnable);
break;
default:
break;
}
NVIC_SetVector(uart_irqs[obj->index], vector);
NVIC_EnableIRQ(uart_irqs[obj->index]);
} else { // disable
int all_disabled = 0;
SerialIrq other_irq = (irq == RxIrq) ? (TxIrq) : (RxIrq);
switch (irq) {
case RxIrq:
USART_DisableInterrupts(uart_addrs[obj->index], kUSART_RxLevelInterruptEnable);
break;
case TxIrq:
USART_DisableInterrupts(uart_addrs[obj->index], kUSART_TxLevelInterruptEnable);
break;
default:
break;
}
switch (other_irq) {
case RxIrq:
all_disabled = (((uart_addrs[obj->index]->FIFOINTENSET) & kUSART_RxLevelInterruptEnable) == 0);
break;
case TxIrq:
all_disabled = (((uart_addrs[obj->index]->FIFOINTENSET) & kUSART_TxLevelInterruptEnable)== 0);
break;
default:
break;
}
if (all_disabled)
NVIC_DisableIRQ(uart_irqs[obj->index]);
}
}
int serial_getc(serial_t *obj)
{
while (!serial_readable(obj));
uint8_t data;
data = USART_ReadByte(uart_addrs[obj->index]);
return data;
}
void serial_putc(serial_t *obj, int c)
{
while (!serial_writable(obj));
USART_WriteByte(uart_addrs[obj->index], (uint8_t)c);
}
int serial_readable(serial_t *obj)
{
uint32_t status_flags = USART_GetStatusFlags(uart_addrs[obj->index]);
return (status_flags & kUSART_RxFifoNotEmptyFlag);
}
int serial_writable(serial_t *obj)
{
uint32_t status_flags = USART_GetStatusFlags(uart_addrs[obj->index]);
return (status_flags & kUSART_TxFifoNotFullFlag);
}
void serial_clear(serial_t *obj)
{
}
void serial_pinout_tx(PinName tx)
{
pinmap_pinout(tx, PinMap_UART_TX);
}
void serial_break_set(serial_t *obj)
{
uart_addrs[obj->index]->CTL |= USART_CTL_TXBRKEN_MASK;
}
void serial_break_clear(serial_t *obj)
{
uart_addrs[obj->index]->CTL &= ~USART_CTL_TXBRKEN_MASK;
}
#endif

View File

@ -0,0 +1,33 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "sleep_api.h"
#include "cmsis.h"
#include "fsl_power.h"
#include "clock_config.h"
void hal_sleep(void)
{
SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
__WFI();
}
void hal_deepsleep(void)
{
BOARD_BootClockVLPR();
/* Enter Deep Sleep mode */
POWER_EnterDeepSleep(APP_EXCLUDE_FROM_DEEPSLEEP);
BOARD_BootClockRUN();
}

Some files were not shown because too many files have changed in this diff Show More