From e4e7b661172477aaa682a9cccfbac89adb1d01f6 Mon Sep 17 00:00:00 2001 From: Pixel Date: Sun, 23 Jan 2011 12:15:41 -0800 Subject: Adding basic CMSIS source code; v1.3.0 from the NXP website currently. --- arch/arm/lpc17xx/Drivers/source/debug_frmwrk.c | 305 ++++ arch/arm/lpc17xx/Drivers/source/lpc17xx_adc.c | 340 ++++ arch/arm/lpc17xx/Drivers/source/lpc17xx_can.c | 1891 ++++++++++++++++++++ arch/arm/lpc17xx/Drivers/source/lpc17xx_clkpwr.c | 338 ++++ arch/arm/lpc17xx/Drivers/source/lpc17xx_dac.c | 139 ++ arch/arm/lpc17xx/Drivers/source/lpc17xx_emac.c | 950 ++++++++++ arch/arm/lpc17xx/Drivers/source/lpc17xx_exti.c | 158 ++ arch/arm/lpc17xx/Drivers/source/lpc17xx_gpdma.c | 450 +++++ arch/arm/lpc17xx/Drivers/source/lpc17xx_gpio.c | 749 ++++++++ arch/arm/lpc17xx/Drivers/source/lpc17xx_i2c.c | 1373 ++++++++++++++ arch/arm/lpc17xx/Drivers/source/lpc17xx_i2s.c | 642 +++++++ .../Drivers/source/lpc17xx_libcfg_default.c | 64 + arch/arm/lpc17xx/Drivers/source/lpc17xx_mcpwm.c | 497 +++++ arch/arm/lpc17xx/Drivers/source/lpc17xx_nvic.c | 136 ++ arch/arm/lpc17xx/Drivers/source/lpc17xx_pinsel.c | 306 ++++ arch/arm/lpc17xx/Drivers/source/lpc17xx_pwm.c | 533 ++++++ arch/arm/lpc17xx/Drivers/source/lpc17xx_qei.c | 502 ++++++ arch/arm/lpc17xx/Drivers/source/lpc17xx_rit.c | 187 ++ arch/arm/lpc17xx/Drivers/source/lpc17xx_rtc.c | 771 ++++++++ arch/arm/lpc17xx/Drivers/source/lpc17xx_spi.c | 431 +++++ arch/arm/lpc17xx/Drivers/source/lpc17xx_ssp.c | 682 +++++++ arch/arm/lpc17xx/Drivers/source/lpc17xx_systick.c | 180 ++ arch/arm/lpc17xx/Drivers/source/lpc17xx_timer.c | 591 ++++++ arch/arm/lpc17xx/Drivers/source/lpc17xx_uart.c | 1366 ++++++++++++++ arch/arm/lpc17xx/Drivers/source/lpc17xx_wdt.c | 261 +++ arch/arm/lpc17xx/Drivers/source/makefile | 84 + 26 files changed, 13926 insertions(+) create mode 100644 arch/arm/lpc17xx/Drivers/source/debug_frmwrk.c create mode 100644 arch/arm/lpc17xx/Drivers/source/lpc17xx_adc.c create mode 100644 arch/arm/lpc17xx/Drivers/source/lpc17xx_can.c create mode 100644 arch/arm/lpc17xx/Drivers/source/lpc17xx_clkpwr.c create mode 100644 arch/arm/lpc17xx/Drivers/source/lpc17xx_dac.c create mode 100644 arch/arm/lpc17xx/Drivers/source/lpc17xx_emac.c create mode 100644 arch/arm/lpc17xx/Drivers/source/lpc17xx_exti.c create mode 100644 arch/arm/lpc17xx/Drivers/source/lpc17xx_gpdma.c create mode 100644 arch/arm/lpc17xx/Drivers/source/lpc17xx_gpio.c create mode 100644 arch/arm/lpc17xx/Drivers/source/lpc17xx_i2c.c create mode 100644 arch/arm/lpc17xx/Drivers/source/lpc17xx_i2s.c create mode 100644 arch/arm/lpc17xx/Drivers/source/lpc17xx_libcfg_default.c create mode 100644 arch/arm/lpc17xx/Drivers/source/lpc17xx_mcpwm.c create mode 100644 arch/arm/lpc17xx/Drivers/source/lpc17xx_nvic.c create mode 100644 arch/arm/lpc17xx/Drivers/source/lpc17xx_pinsel.c create mode 100644 arch/arm/lpc17xx/Drivers/source/lpc17xx_pwm.c create mode 100644 arch/arm/lpc17xx/Drivers/source/lpc17xx_qei.c create mode 100644 arch/arm/lpc17xx/Drivers/source/lpc17xx_rit.c create mode 100644 arch/arm/lpc17xx/Drivers/source/lpc17xx_rtc.c create mode 100644 arch/arm/lpc17xx/Drivers/source/lpc17xx_spi.c create mode 100644 arch/arm/lpc17xx/Drivers/source/lpc17xx_ssp.c create mode 100644 arch/arm/lpc17xx/Drivers/source/lpc17xx_systick.c create mode 100644 arch/arm/lpc17xx/Drivers/source/lpc17xx_timer.c create mode 100644 arch/arm/lpc17xx/Drivers/source/lpc17xx_uart.c create mode 100644 arch/arm/lpc17xx/Drivers/source/lpc17xx_wdt.c create mode 100644 arch/arm/lpc17xx/Drivers/source/makefile (limited to 'arch/arm/lpc17xx/Drivers/source') diff --git a/arch/arm/lpc17xx/Drivers/source/debug_frmwrk.c b/arch/arm/lpc17xx/Drivers/source/debug_frmwrk.c new file mode 100644 index 0000000..7e63e04 --- /dev/null +++ b/arch/arm/lpc17xx/Drivers/source/debug_frmwrk.c @@ -0,0 +1,305 @@ +/***********************************************************************//** + * @file debug_frmwrk.c + * @brief Contains some utilities that used for debugging through UART + * @version 2.0 + * @date 21. May. 2010 + * @author NXP MCU SW Application Team + *---------------------------------------------------------------------------- + * Software that is described herein is for illustrative purposes only + * which provides customers with programming information regarding the + * products. This software is supplied "AS IS" without any warranties. + * NXP Semiconductors assumes no responsibility or liability for the + * use of the software, conveys no license or title under any patent, + * copyright, or mask work right to the product. NXP Semiconductors + * reserves the right to make changes in the software without + * notification. NXP Semiconductors also make no representation or + * warranty that such application will be suitable for the specified + * use without further testing or modification. + **********************************************************************/ + +#include "debug_frmwrk.h" +#include "lpc17xx_pinsel.h" + +/* If this source file built with example, the LPC17xx FW library configuration + * file in each example directory ("lpc17xx_libcfg.h") must be included, + * otherwise the default FW library configuration file must be included instead + */ +#ifdef __BUILD_WITH_EXAMPLE__ +#include "lpc17xx_libcfg.h" +#else +#include "lpc17xx_libcfg_default.h" +#endif /* __BUILD_WITH_EXAMPLE__ */ + +#ifdef _DBGFWK +/* Debug framework */ + +void (*_db_msg)(LPC_UART_TypeDef *UARTx, const void *s); +void (*_db_msg_)(LPC_UART_TypeDef *UARTx, const void *s); +void (*_db_char)(LPC_UART_TypeDef *UARTx, uint8_t ch); +void (*_db_dec)(LPC_UART_TypeDef *UARTx, uint8_t decn); +void (*_db_dec_16)(LPC_UART_TypeDef *UARTx, uint16_t decn); +void (*_db_dec_32)(LPC_UART_TypeDef *UARTx, uint32_t decn); +void (*_db_hex)(LPC_UART_TypeDef *UARTx, uint8_t hexn); +void (*_db_hex_16)(LPC_UART_TypeDef *UARTx, uint16_t hexn); +void (*_db_hex_32)(LPC_UART_TypeDef *UARTx, uint32_t hexn); +uint8_t (*_db_get_char)(LPC_UART_TypeDef *UARTx); + + +/*********************************************************************//** + * @brief Puts a character to UART port + * @param[in] UARTx Pointer to UART peripheral + * @param[in] ch Character to put + * @return None + **********************************************************************/ +void UARTPutChar (LPC_UART_TypeDef *UARTx, uint8_t ch) +{ + UART_Send(UARTx, &ch, 1, BLOCKING); +} + + +/*********************************************************************//** + * @brief Get a character to UART port + * @param[in] UARTx Pointer to UART peripheral + * @return character value that returned + **********************************************************************/ +uint8_t UARTGetChar (LPC_UART_TypeDef *UARTx) +{ + uint8_t tmp = 0; + UART_Receive(UARTx, &tmp, 1, BLOCKING); + return(tmp); +} + + +/*********************************************************************//** + * @brief Puts a string to UART port + * @param[in] UARTx Pointer to UART peripheral + * @param[in] str string to put + * @return None + **********************************************************************/ +void UARTPuts(LPC_UART_TypeDef *UARTx, const void *str) +{ + uint8_t *s = (uint8_t *) str; + + while (*s) + { + UARTPutChar(UARTx, *s++); + } +} + + +/*********************************************************************//** + * @brief Puts a string to UART port and print new line + * @param[in] UARTx Pointer to UART peripheral + * @param[in] str String to put + * @return None + **********************************************************************/ +void UARTPuts_(LPC_UART_TypeDef *UARTx, const void *str) +{ + UARTPuts (UARTx, str); + UARTPuts (UARTx, "\n\r"); +} + + +/*********************************************************************//** + * @brief Puts a decimal number to UART port + * @param[in] UARTx Pointer to UART peripheral + * @param[in] decnum Decimal number (8-bit long) + * @return None + **********************************************************************/ +void UARTPutDec(LPC_UART_TypeDef *UARTx, uint8_t decnum) +{ + uint8_t c1=decnum%10; + uint8_t c2=(decnum/10)%10; + uint8_t c3=(decnum/100)%10; + UARTPutChar(UARTx, '0'+c3); + UARTPutChar(UARTx, '0'+c2); + UARTPutChar(UARTx, '0'+c1); +} + +/*********************************************************************//** + * @brief Puts a decimal number to UART port + * @param[in] UARTx Pointer to UART peripheral + * @param[in] decnum Decimal number (8-bit long) + * @return None + **********************************************************************/ +void UARTPutDec16(LPC_UART_TypeDef *UARTx, uint16_t decnum) +{ + uint8_t c1=decnum%10; + uint8_t c2=(decnum/10)%10; + uint8_t c3=(decnum/100)%10; + uint8_t c4=(decnum/1000)%10; + uint8_t c5=(decnum/10000)%10; + UARTPutChar(UARTx, '0'+c5); + UARTPutChar(UARTx, '0'+c4); + UARTPutChar(UARTx, '0'+c3); + UARTPutChar(UARTx, '0'+c2); + UARTPutChar(UARTx, '0'+c1); +} + +/*********************************************************************//** + * @brief Puts a decimal number to UART port + * @param[in] UARTx Pointer to UART peripheral + * @param[in] decnum Decimal number (8-bit long) + * @return None + **********************************************************************/ +void UARTPutDec32(LPC_UART_TypeDef *UARTx, uint32_t decnum) +{ + uint8_t c1=decnum%10; + uint8_t c2=(decnum/10)%10; + uint8_t c3=(decnum/100)%10; + uint8_t c4=(decnum/1000)%10; + uint8_t c5=(decnum/10000)%10; + uint8_t c6=(decnum/100000)%10; + uint8_t c7=(decnum/1000000)%10; + uint8_t c8=(decnum/10000000)%10; + uint8_t c9=(decnum/100000000)%10; + uint8_t c10=(decnum/100000000)%10; + UARTPutChar(UARTx, '0'+c10); + UARTPutChar(UARTx, '0'+c9); + UARTPutChar(UARTx, '0'+c8); + UARTPutChar(UARTx, '0'+c7); + UARTPutChar(UARTx, '0'+c6); + UARTPutChar(UARTx, '0'+c5); + UARTPutChar(UARTx, '0'+c4); + UARTPutChar(UARTx, '0'+c3); + UARTPutChar(UARTx, '0'+c2); + UARTPutChar(UARTx, '0'+c1); +} + +/*********************************************************************//** + * @brief Puts a hex number to UART port + * @param[in] UARTx Pointer to UART peripheral + * @param[in] hexnum Hex number (8-bit long) + * @return None + **********************************************************************/ +void UARTPutHex (LPC_UART_TypeDef *UARTx, uint8_t hexnum) +{ + uint8_t nibble, i; + + UARTPuts(UARTx, "0x"); + i = 1; + do { + nibble = (hexnum >> (4*i)) & 0x0F; + UARTPutChar(UARTx, (nibble > 9) ? ('A' + nibble - 10) : ('0' + nibble)); + } while (i--); +} + + +/*********************************************************************//** + * @brief Puts a hex number to UART port + * @param[in] UARTx Pointer to UART peripheral + * @param[in] hexnum Hex number (16-bit long) + * @return None + **********************************************************************/ +void UARTPutHex16 (LPC_UART_TypeDef *UARTx, uint16_t hexnum) +{ + uint8_t nibble, i; + + UARTPuts(UARTx, "0x"); + i = 3; + do { + nibble = (hexnum >> (4*i)) & 0x0F; + UARTPutChar(UARTx, (nibble > 9) ? ('A' + nibble - 10) : ('0' + nibble)); + } while (i--); +} + +/*********************************************************************//** + * @brief Puts a hex number to UART port + * @param[in] UARTx Pointer to UART peripheral + * @param[in] hexnum Hex number (32-bit long) + * @return None + **********************************************************************/ +void UARTPutHex32 (LPC_UART_TypeDef *UARTx, uint32_t hexnum) +{ + uint8_t nibble, i; + + UARTPuts(UARTx, "0x"); + i = 7; + do { + nibble = (hexnum >> (4*i)) & 0x0F; + UARTPutChar(UARTx, (nibble > 9) ? ('A' + nibble - 10) : ('0' + nibble)); + } while (i--); +} + +///*********************************************************************//** +// * @brief print function that supports format as same as printf() +// * function of library +// * @param[in] None +// * @return None +// **********************************************************************/ +//void _printf (const char *format, ...) +//{ +// static char buffer[512 + 1]; +// va_list vArgs; +// char *tmp; +// va_start(vArgs, format); +// vsprintf((char *)buffer, (char const *)format, vArgs); +// va_end(vArgs); +// +// _DBG(buffer); +//} + +/*********************************************************************//** + * @brief Initialize Debug frame work through initializing UART port + * @param[in] None + * @return None + **********************************************************************/ +void debug_frmwrk_init(void) +{ + UART_CFG_Type UARTConfigStruct; + PINSEL_CFG_Type PinCfg; + +#if (USED_UART_DEBUG_PORT==0) + /* + * Initialize UART0 pin connect + */ + PinCfg.Funcnum = 1; + PinCfg.OpenDrain = 0; + PinCfg.Pinmode = 0; + PinCfg.Pinnum = 2; + PinCfg.Portnum = 0; + PINSEL_ConfigPin(&PinCfg); + PinCfg.Pinnum = 3; + PINSEL_ConfigPin(&PinCfg); +#elif #if (USED_UART_DEBUG_PORT==1) + /* + * Initialize UART1 pin connect + */ + PinCfg.Funcnum = 1; + PinCfg.OpenDrain = 0; + PinCfg.Pinmode = 0; + PinCfg.Pinnum = 15; + PinCfg.Portnum = 0; + PINSEL_ConfigPin(&PinCfg); + PinCfg.Pinnum = 16; + PINSEL_ConfigPin(&PinCfg); +#endif + + /* Initialize UART Configuration parameter structure to default state: + * Baudrate = 9600bps + * 8 data bit + * 1 Stop bit + * None parity + */ + UART_ConfigStructInit(&UARTConfigStruct); + // Re-configure baudrate to 115200bps + UARTConfigStruct.Baud_rate = 115200; + + // Initialize DEBUG_UART_PORT peripheral with given to corresponding parameter + UART_Init(DEBUG_UART_PORT, &UARTConfigStruct); + + // Enable UART Transmit + UART_TxCmd(DEBUG_UART_PORT, ENABLE); + + _db_msg = UARTPuts; + _db_msg_ = UARTPuts_; + _db_char = UARTPutChar; + _db_hex = UARTPutHex; + _db_hex_16 = UARTPutHex16; + _db_hex_32 = UARTPutHex32; + _db_dec = UARTPutDec; + _db_dec_16 = UARTPutDec16; + _db_dec_32 = UARTPutDec32; + _db_get_char = UARTGetChar; +} +#endif /*_DBGFWK */ diff --git a/arch/arm/lpc17xx/Drivers/source/lpc17xx_adc.c b/arch/arm/lpc17xx/Drivers/source/lpc17xx_adc.c new file mode 100644 index 0000000..a49c2cf --- /dev/null +++ b/arch/arm/lpc17xx/Drivers/source/lpc17xx_adc.c @@ -0,0 +1,340 @@ +/***********************************************************************//** + * @file lpc17xx_adc.c + * @brief Contains all functions support for ADC firmware library on LPC17xx + * @version 3.0 + * @date 18. June. 2010 + * @author NXP MCU SW Application Team + ************************************************************************** + * Software that is described herein is for illustrative purposes only + * which provides customers with programming information regarding the + * products. This software is supplied "AS IS" without any warranties. + * NXP Semiconductors assumes no responsibility or liability for the + * use of the software, conveys no license or title under any patent, + * copyright, or mask work right to the product. NXP Semiconductors + * reserves the right to make changes in the software without + * notification. NXP Semiconductors also make no representation or + * warranty that such application will be suitable for the specified + * use without further testing or modification. + **********************************************************************/ + +/* Peripheral group ----------------------------------------------------------- */ +/** @addtogroup ADC + * @{ + */ + +/* Includes ------------------------------------------------------------------- */ +#include "lpc17xx_adc.h" +#include "lpc17xx_clkpwr.h" + +/* If this source file built with example, the LPC17xx FW library configuration + * file in each example directory ("lpc17xx_libcfg.h") must be included, + * otherwise the default FW library configuration file must be included instead + */ +#ifdef __BUILD_WITH_EXAMPLE__ +#include "lpc17xx_libcfg.h" +#else +#include "lpc17xx_libcfg_default.h" +#endif /* __BUILD_WITH_EXAMPLE__ */ + + +#ifdef _ADC + +/* Public Functions ----------------------------------------------------------- */ +/** @addtogroup ADC_Public_Functions + * @{ + */ + +/*********************************************************************//** + * @brief Initial for ADC + * + Set bit PCADC + * + Set clock for ADC + * + Set Clock Frequency + * @param[in] ADCx pointer to LPC_ADC_TypeDef, should be: LPC_ADC + * @param[in] rate ADC conversion rate, should be <=200KHz + * @return None + **********************************************************************/ +void ADC_Init(LPC_ADC_TypeDef *ADCx, uint32_t rate) +{ + uint32_t temp, tmp; + + CHECK_PARAM(PARAM_ADCx(ADCx)); + CHECK_PARAM(PARAM_ADC_RATE(rate)); + + // Turn on power and clock + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCAD, ENABLE); + + ADCx->ADCR = 0; + + //Enable PDN bit + tmp = ADC_CR_PDN; + // Set clock frequency + temp = CLKPWR_GetPCLK(CLKPWR_PCLKSEL_ADC); + /* The APB clock (PCLK_ADC0) is divided by (CLKDIV+1) to produce the clock for + * A/D converter, which should be less than or equal to 13MHz. + * A fully conversion requires 65 of these clocks. + * ADC clock = PCLK_ADC0 / (CLKDIV + 1); + * ADC rate = ADC clock / 65; + */ + temp = (temp /(rate * 65)) - 1; + tmp |= ADC_CR_CLKDIV(temp); + + ADCx->ADCR = tmp; +} + + +/*********************************************************************//** +* @brief Close ADC +* @param[in] ADCx pointer to LPC_ADC_TypeDef, should be: LPC_ADC +* @return None +**********************************************************************/ +void ADC_DeInit(LPC_ADC_TypeDef *ADCx) +{ + CHECK_PARAM(PARAM_ADCx(ADCx)); + + // Clear PDN bit + ADCx->ADCR &= ~ADC_CR_PDN; + // Turn on power and clock + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCAD, DISABLE); +} + + +/*********************************************************************//** +* @brief Get Result conversion from A/D data register +* @param[in] channel number which want to read back the result +* @return Result of conversion +*********************************************************************/ +uint32_t ADC_GetData(uint32_t channel) +{ + uint32_t adc_value; + + CHECK_PARAM(PARAM_ADC_CHANNEL_SELECTION(channel)); + + adc_value = *(uint32_t *)((&LPC_ADC->ADDR0) + channel); + return ADC_GDR_RESULT(adc_value); +} + +/*********************************************************************//** +* @brief Set start mode for ADC +* @param[in] ADCx pointer to LPC_ADC_TypeDef, should be: LPC_ADC +* @param[in] start_mode Start mode choose one of modes in +* 'ADC_START_OPT' enumeration type definition, should be: +* - ADC_START_CONTINUOUS +* - ADC_START_NOW +* - ADC_START_ON_EINT0 +* - ADC_START_ON_CAP01 +* - ADC_START_ON_MAT01 +* - ADC_START_ON_MAT03 +* - ADC_START_ON_MAT10 +* - ADC_START_ON_MAT11 +* @return None +*********************************************************************/ +void ADC_StartCmd(LPC_ADC_TypeDef *ADCx, uint8_t start_mode) +{ + CHECK_PARAM(PARAM_ADCx(ADCx)); + CHECK_PARAM(PARAM_ADC_START_OPT(start_mode)); + + ADCx->ADCR &= ~ADC_CR_START_MASK; + ADCx->ADCR |=ADC_CR_START_MODE_SEL((uint32_t)start_mode); +} + + +/*********************************************************************//** +* @brief ADC Burst mode setting +* @param[in] ADCx pointer to LPC_ADC_TypeDef, should be: LPC_ADC +* @param[in] NewState +* - 1: Set Burst mode +* - 0: reset Burst mode +* @return None +**********************************************************************/ +void ADC_BurstCmd(LPC_ADC_TypeDef *ADCx, FunctionalState NewState) +{ + CHECK_PARAM(PARAM_ADCx(ADCx)); + + ADCx->ADCR &= ~ADC_CR_BURST; + if (NewState){ + ADCx->ADCR |= ADC_CR_BURST; + } +} + +/*********************************************************************//** +* @brief Set AD conversion in power mode +* @param[in] ADCx pointer to LPC_ADC_TypeDef, should be: LPC_ADC +* @param[in] NewState +* - 1: AD converter is optional +* - 0: AD Converter is in power down mode +* @return None +**********************************************************************/ +void ADC_PowerdownCmd(LPC_ADC_TypeDef *ADCx, FunctionalState NewState) +{ + CHECK_PARAM(PARAM_ADCx(ADCx)); + + ADCx->ADCR &= ~ADC_CR_PDN; + if (NewState){ + ADCx->ADCR |= ADC_CR_PDN; + } +} + +/*********************************************************************//** +* @brief Set Edge start configuration +* @param[in] ADCx pointer to LPC_ADC_TypeDef, should be: LPC_ADC +* @param[in] EdgeOption is ADC_START_ON_RISING and ADC_START_ON_FALLING +* 0:ADC_START_ON_RISING +* 1:ADC_START_ON_FALLING +* @return None +**********************************************************************/ +void ADC_EdgeStartConfig(LPC_ADC_TypeDef *ADCx, uint8_t EdgeOption) +{ + CHECK_PARAM(PARAM_ADCx(ADCx)); + CHECK_PARAM(PARAM_ADC_START_ON_EDGE_OPT(EdgeOption)); + + ADCx->ADCR &= ~ADC_CR_EDGE; + if (EdgeOption){ + ADCx->ADCR |= ADC_CR_EDGE; + } +} + +/*********************************************************************//** +* @brief ADC interrupt configuration +* @param[in] ADCx pointer to LPC_ADC_TypeDef, should be: LPC_ADC +* @param[in] IntType: type of interrupt, should be: +* - ADC_ADINTEN0: Interrupt channel 0 +* - ADC_ADINTEN1: Interrupt channel 1 +* ... +* - ADC_ADINTEN7: Interrupt channel 7 +* - ADC_ADGINTEN: Individual channel/global flag done generate an interrupt +* @param[in] NewState: +* - SET : enable ADC interrupt +* - RESET: disable ADC interrupt +* @return None +**********************************************************************/ +void ADC_IntConfig (LPC_ADC_TypeDef *ADCx, ADC_TYPE_INT_OPT IntType, FunctionalState NewState) +{ + CHECK_PARAM(PARAM_ADCx(ADCx)); + CHECK_PARAM(PARAM_ADC_TYPE_INT_OPT(IntType)); + + ADCx->ADINTEN &= ~ADC_INTEN_CH(IntType); + if (NewState){ + ADCx->ADINTEN |= ADC_INTEN_CH(IntType); + } +} + +/*********************************************************************//** +* @brief Enable/Disable ADC channel number +* @param[in] ADCx pointer to LPC_ADC_TypeDef, should be: LPC_ADC +* @param[in] Channel channel number +* @param[in] NewState Enable or Disable +* +* @return None +**********************************************************************/ +void ADC_ChannelCmd (LPC_ADC_TypeDef *ADCx, uint8_t Channel, FunctionalState NewState) +{ + CHECK_PARAM(PARAM_ADCx(ADCx)); + CHECK_PARAM(PARAM_ADC_CHANNEL_SELECTION(Channel)); + + if (NewState == ENABLE) { + ADCx->ADCR |= ADC_CR_CH_SEL(Channel); + } else { + ADCx->ADCR &= ~ADC_CR_CH_SEL(Channel); + } +} + +/*********************************************************************//** +* @brief Get ADC result +* @param[in] ADCx pointer to LPC_ADC_TypeDef, should be: LPC_ADC +* @param[in] channel: channel number, should be 0...7 +* @return Data conversion +**********************************************************************/ +uint16_t ADC_ChannelGetData(LPC_ADC_TypeDef *ADCx, uint8_t channel) +{ + uint32_t adc_value; + + CHECK_PARAM(PARAM_ADCx(ADCx)); + CHECK_PARAM(PARAM_ADC_CHANNEL_SELECTION(channel)); + + adc_value = *(uint32_t *) ((&ADCx->ADDR0) + channel); + return ADC_DR_RESULT(adc_value); +} + +/*********************************************************************//** +* @brief Get ADC Chanel status from ADC data register +* @param[in] ADCx pointer to LPC_ADC_TypeDef, should be: LPC_ADC +* @param[in] channel: channel number, should be 0..7 +* @param[in] StatusType +* 0:Burst status +* 1:Done status +* @return SET / RESET +**********************************************************************/ +FlagStatus ADC_ChannelGetStatus(LPC_ADC_TypeDef *ADCx, uint8_t channel, uint32_t StatusType) +{ + uint32_t temp; + + CHECK_PARAM(PARAM_ADCx(ADCx)); + CHECK_PARAM(PARAM_ADC_CHANNEL_SELECTION(channel)); + CHECK_PARAM(PARAM_ADC_DATA_STATUS(StatusType)); + + temp = *(uint32_t *) ((&ADCx->ADDR0) + channel); + if (StatusType) { + temp &= ADC_DR_DONE_FLAG; + }else{ + temp &= ADC_DR_OVERRUN_FLAG; + } + if (temp) { + return SET; + } else { + return RESET; + } + +} + +/*********************************************************************//** +* @brief Get ADC Data from AD Global register +* @param[in] ADCx pointer to LPC_ADC_TypeDef, should be: LPC_ADC +* @return Result of conversion +**********************************************************************/ +uint32_t ADC_GlobalGetData(LPC_ADC_TypeDef *ADCx) +{ + CHECK_PARAM(PARAM_ADCx(ADCx)); + + return ((uint32_t)(ADCx->ADGDR)); +} + +/*********************************************************************//** +* @brief Get ADC Chanel status from AD global data register +* @param[in] ADCx pointer to LPC_ADC_TypeDef, should be: LPC_ADC +* @param[in] StatusType +* 0:Burst status +* 1:Done status +* @return SET / RESET +**********************************************************************/ +FlagStatus ADC_GlobalGetStatus(LPC_ADC_TypeDef *ADCx, uint32_t StatusType) +{ + uint32_t temp; + + CHECK_PARAM(PARAM_ADCx(ADCx)); + CHECK_PARAM(PARAM_ADC_DATA_STATUS(StatusType)); + + temp = ADCx->ADGDR; + if (StatusType){ + temp &= ADC_DR_DONE_FLAG; + }else{ + temp &= ADC_DR_OVERRUN_FLAG; + } + if (temp){ + return SET; + }else{ + return RESET; + } +} + +/** + * @} + */ + +#endif /* _ADC */ + +/** + * @} + */ + +/* --------------------------------- End Of File ------------------------------ */ + diff --git a/arch/arm/lpc17xx/Drivers/source/lpc17xx_can.c b/arch/arm/lpc17xx/Drivers/source/lpc17xx_can.c new file mode 100644 index 0000000..eef871f --- /dev/null +++ b/arch/arm/lpc17xx/Drivers/source/lpc17xx_can.c @@ -0,0 +1,1891 @@ +/***********************************************************************//** + * @file lpc17xx_can.c + * @brief Contains all functions support for CAN firmware library on LPC17xx + * @version 3.0 + * @date 18. June. 2010 + * @author NXP MCU SW Application Team + ************************************************************************** + * Software that is described herein is for illustrative purposes only + * which provides customers with programming information regarding the + * products. This software is supplied "AS IS" without any warranties. + * NXP Semiconductors assumes no responsibility or liability for the + * use of the software, conveys no license or title under any patent, + * copyright, or mask work right to the product. NXP Semiconductors + * reserves the right to make changes in the software without + * notification. NXP Semiconductors also make no representation or + * warranty that such application will be suitable for the specified + * use without further testing or modification. + **********************************************************************/ + +/* Peripheral group ----------------------------------------------------------- */ +/** @addtogroup CAN + * @{ + */ + +/* Includes ------------------------------------------------------------------- */ +#include "lpc17xx_can.h" +#include "lpc17xx_clkpwr.h" + +/* If this source file built with example, the LPC17xx FW library configuration + * file in each example directory ("lpc17xx_libcfg.h") must be included, + * otherwise the default FW library configuration file must be included instead + */ +#ifdef __BUILD_WITH_EXAMPLE__ +#include "lpc17xx_libcfg.h" +#else +#include "lpc17xx_libcfg_default.h" +#endif /* __BUILD_WITH_EXAMPLE__ */ + + +#ifdef _CAN + +/* Private Variables ---------------------------------------------------------- */ +/** @defgroup CAN_Private_Variables CAN Private Variables + * @{ + */ + +FunctionalState FULLCAN_ENABLE; + + +/* Counts number of filters (CAN message objects) used */ +uint16_t CANAF_FullCAN_cnt = 0; +uint16_t CANAF_std_cnt = 0; +uint16_t CANAF_gstd_cnt = 0; +uint16_t CANAF_ext_cnt = 0; +uint16_t CANAF_gext_cnt = 0; + +/* End of Private Variables ----------------------------------------------------*/ +/** + * @} + */ + +/* Private Variables ---------------------------------------------------------- */ +static void can_SetBaudrate (LPC_CAN_TypeDef *CANx, uint32_t baudrate); + +/*********************************************************************//** + * @brief Setting CAN baud rate (bps) + * @param[in] CANx point to LPC_CAN_TypeDef object, should be: + * - LPC_CAN1: CAN1 peripheral + * - LPC_CAN2: CAN2 peripheral + * @param[in] baudrate: is the baud rate value will be set + * @return None + ***********************************************************************/ +static void can_SetBaudrate (LPC_CAN_TypeDef *CANx, uint32_t baudrate) +{ + uint32_t result = 0; + uint8_t NT, TSEG1, TSEG2; + uint32_t CANPclk = 0; + uint32_t BRP; + CHECK_PARAM(PARAM_CANx(CANx)); + + if (CANx == LPC_CAN1) + { + CANPclk = CLKPWR_GetPCLK (CLKPWR_PCONP_PCAN1); + } + else + { + CANPclk = CLKPWR_GetPCLK (CLKPWR_PCONP_PCAN2); + } + result = CANPclk / baudrate; + /* Calculate suitable nominal time value + * NT (nominal time) = (TSEG1 + TSEG2 + 3) + * NT <= 24 + * TSEG1 >= 2*TSEG2 + */ + for(NT=24;NT>0;NT=NT-2) + { + if ((result%NT)==0) + { + BRP = result / NT - 1; + NT--; + TSEG2 = (NT/3) - 1; + TSEG1 = NT -(NT/3) - 1; + break; + } + } + /* Enter reset mode */ + CANx->MOD = 0x01; + /* Set bit timing + * Default: SAM = 0x00; + * SJW = 0x03; + */ + CANx->BTR = (TSEG2<<20)|(TSEG1<<16)|(3<<14)|BRP; + /* Return to normal operating */ + CANx->MOD = 0; +} +/* End of Private Functions ----------------------------------------------------*/ + + +/* Public Functions ----------------------------------------------------------- */ +/** @addtogroup CAN_Public_Functions + * @{ + */ + +/********************************************************************//** + * @brief Initialize CAN peripheral with given baudrate + * @param[in] CANx pointer to LPC_CAN_TypeDef, should be: + * - LPC_CAN1: CAN1 peripheral + * - LPC_CAN2: CAN2 peripheral + * @param[in] baudrate: the value of CAN baudrate will be set (bps) + * @return None + *********************************************************************/ +void CAN_Init(LPC_CAN_TypeDef *CANx, uint32_t baudrate) +{ + uint32_t temp; + uint16_t i; + CHECK_PARAM(PARAM_CANx(CANx)); + + if(CANx == LPC_CAN1) + { + /* Turn on power and clock for CAN1 */ + CLKPWR_ConfigPPWR(CLKPWR_PCONP_PCAN1, ENABLE); + /* Set clock divide for CAN1 */ + CLKPWR_SetPCLKDiv (CLKPWR_PCONP_PCAN1, CLKPWR_PCLKSEL_CCLK_DIV_4); + } + else + { + /* Turn on power and clock for CAN1 */ + CLKPWR_ConfigPPWR(CLKPWR_PCONP_PCAN2, ENABLE); + /* Set clock divide for CAN2 */ + CLKPWR_SetPCLKDiv (CLKPWR_PCONP_PCAN2, CLKPWR_PCLKSEL_CCLK_DIV_4); + } + + CANx->MOD = 1; // Enter Reset Mode + CANx->IER = 0; // Disable All CAN Interrupts + CANx->GSR = 0; + /* Request command to release Rx, Tx buffer and clear data overrun */ + //CANx->CMR = CAN_CMR_AT | CAN_CMR_RRB | CAN_CMR_CDO; + CANx->CMR = (1<<1)|(1<<2)|(1<<3); + /* Read to clear interrupt pending in interrupt capture register */ + temp = CANx->ICR; + CANx->MOD = 0;// Return Normal operating + + //Reset CANAF value + LPC_CANAF->AFMR = 0x01; + + //clear ALUT RAM + for (i = 0; i < 512; i++) { + LPC_CANAF_RAM->mask[i] = 0x00; + } + + LPC_CANAF->SFF_sa = 0x00; + LPC_CANAF->SFF_GRP_sa = 0x00; + LPC_CANAF->EFF_sa = 0x00; + LPC_CANAF->EFF_GRP_sa = 0x00; + LPC_CANAF->ENDofTable = 0x00; + + LPC_CANAF->AFMR = 0x00; + /* Set baudrate */ + can_SetBaudrate (CANx, baudrate); +} + +/********************************************************************//** + * @brief CAN deInit + * @param[in] CANx pointer to LPC_CAN_TypeDef, should be: + * - LPC_CAN1: CAN1 peripheral + * - LPC_CAN2: CAN2 peripheral + * @return None + *********************************************************************/ +void CAN_DeInit(LPC_CAN_TypeDef *CANx) +{ + CHECK_PARAM(PARAM_CANx(CANx)); + + if(CANx == LPC_CAN1) + { + /* Turn on power and clock for CAN1 */ + CLKPWR_ConfigPPWR(CLKPWR_PCONP_PCAN1, DISABLE); + } + else + { + /* Turn on power and clock for CAN1 */ + CLKPWR_ConfigPPWR(CLKPWR_PCONP_PCAN2, DISABLE); + } +} + +/********************************************************************//** + * @brief Setup Acceptance Filter Look-Up Table + * @param[in] CANAFx pointer to LPC_CANAF_TypeDef + * Should be: LPC_CANAF + * @param[in] AFSection the pointer to AF_SectionDef structure + * It contain information about 5 sections will be install in AFLUT + * @return CAN Error could be: + * - CAN_OBJECTS_FULL_ERROR: No more rx or tx objects available + * - CAN_AF_ENTRY_ERROR: table error-violation of ascending numerical order + * - CAN_OK: ID is added into table successfully + *********************************************************************/ +CAN_ERROR CAN_SetupAFLUT(LPC_CANAF_TypeDef* CANAFx, AF_SectionDef* AFSection) +{ + uint8_t ctrl1,ctrl2; + uint8_t dis1, dis2; + uint16_t SID, SID_temp,i, count = 0; + uint32_t EID, EID_temp, entry, buf; + uint16_t lowerSID, upperSID; + uint32_t lowerEID, upperEID; + + CHECK_PARAM(PARAM_CANAFx(CANAFx)); + CANAFx->AFMR = 0x01; + +/***** setup FullCAN Table *****/ + if(AFSection->FullCAN_Sec == NULL) + { + FULLCAN_ENABLE = DISABLE; + } + else + { + FULLCAN_ENABLE = ENABLE; + for(i=0;i<(AFSection->FC_NumEntry);i++) + { + if(count + 1 > 64) + { + return CAN_OBJECTS_FULL_ERROR; + } + ctrl1 = AFSection->FullCAN_Sec->controller; + SID = AFSection->FullCAN_Sec->id_11; + dis1 = AFSection->FullCAN_Sec->disable; + + CHECK_PARAM(PARAM_CTRL(ctrl1)); + CHECK_PARAM(PARAM_ID_11(SID)); + CHECK_PARAM(PARAM_MSG_DISABLE(dis1)); + entry = 0x00; //reset entry value + if((CANAF_FullCAN_cnt & 0x00000001)==0) + { + if(count!=0x00) + { + buf = LPC_CANAF_RAM->mask[count-1]; + SID_temp = (buf & 0x000003FF); + if(SID_temp > SID) + { + return CAN_AF_ENTRY_ERROR; + } + } + entry = (ctrl1<<29)|(dis1<<28)|(SID<<16)|(1<<27); + LPC_CANAF_RAM->mask[count] &= 0x0000FFFF; + LPC_CANAF_RAM->mask[count] |= entry; + CANAF_FullCAN_cnt++; + } + else + { + buf = LPC_CANAF_RAM->mask[count]; + SID_temp = (buf & 0x03FF0000)>>16; + if(SID_temp > SID) + { + return CAN_AF_ENTRY_ERROR; + } + entry = (ctrl1<<13)|(dis1<<12)|(SID<<0)|(1<<11); + LPC_CANAF_RAM->mask[count] &= 0xFFFF0000; + LPC_CANAF_RAM->mask[count]|= entry; + count++; + CANAF_FullCAN_cnt++; + } + AFSection->FullCAN_Sec = (FullCAN_Entry *)((uint32_t)(AFSection->FullCAN_Sec)+ sizeof(FullCAN_Entry)); + } + } + +/***** Setup Explicit Standard Frame Format Section *****/ + if(AFSection->SFF_Sec != NULL) + { + for(i=0;i<(AFSection->SFF_NumEntry);i++) + { + if(count + 1 > 512) + { + return CAN_OBJECTS_FULL_ERROR; + } + ctrl1 = AFSection->SFF_Sec->controller; + SID = AFSection->SFF_Sec->id_11; + dis1 = AFSection->SFF_Sec->disable; + + //check parameter + CHECK_PARAM(PARAM_CTRL(ctrl1)); + CHECK_PARAM(PARAM_ID_11(SID)); + CHECK_PARAM(PARAM_MSG_DISABLE(dis1)); + + entry = 0x00; //reset entry value + if((CANAF_std_cnt & 0x00000001)==0) + { + if(CANAF_std_cnt !=0 ) + { + buf = LPC_CANAF_RAM->mask[count-1]; + SID_temp = (buf & 0x00000FFF); + if(SID_temp > SID) + { + return CAN_AF_ENTRY_ERROR; + } + } + entry = (ctrl1<<29)|(dis1<<28)|(SID<<16); + LPC_CANAF_RAM->mask[count] &= 0x0000FFFF; + LPC_CANAF_RAM->mask[count] |= entry; + CANAF_std_cnt++; + } + else + { + buf = LPC_CANAF_RAM->mask[count]; + SID_temp = (buf & 0x0FFF0000)>>16; + if(SID_temp > SID) + { + return CAN_AF_ENTRY_ERROR; + } + entry = (ctrl1<<13)|(dis1<<12)|(SID<<0); + LPC_CANAF_RAM->mask[count] &= 0xFFFF0000; + LPC_CANAF_RAM->mask[count] |= entry; + count++; + CANAF_std_cnt++; + } + AFSection->SFF_Sec = (SFF_Entry *)((uint32_t)(AFSection->SFF_Sec)+ sizeof(SFF_Entry)); + } + } + +/***** Setup Group of Standard Frame Format Identifier Section *****/ + if(AFSection->SFF_GPR_Sec != NULL) + { + for(i=0;i<(AFSection->SFF_GPR_NumEntry);i++) + { + if(count + 1 > 512) + { + return CAN_OBJECTS_FULL_ERROR; + } + ctrl1 = AFSection->SFF_GPR_Sec->controller1; + ctrl2 = AFSection->SFF_GPR_Sec->controller2; + dis1 = AFSection->SFF_GPR_Sec->disable1; + dis2 = AFSection->SFF_GPR_Sec->disable2; + lowerSID = AFSection->SFF_GPR_Sec->lowerID; + upperSID = AFSection->SFF_GPR_Sec->upperID; + + /* check parameter */ + CHECK_PARAM(PARAM_CTRL(ctrl1)); + CHECK_PARAM(PARAM_CTRL(ctrl2)); + CHECK_PARAM(PARAM_MSG_DISABLE(dis1)); + CHECK_PARAM(PARAM_MSG_DISABLE(dis2)); + CHECK_PARAM(PARAM_ID_11(lowerSID)); + CHECK_PARAM(PARAM_ID_11(upperSID)); + + entry = 0x00; + if(CANAF_gstd_cnt!=0) + { + buf = LPC_CANAF_RAM->mask[count-1]; + SID_temp = buf & 0x00000FFF; + if(SID_temp > lowerSID) + { + return CAN_AF_ENTRY_ERROR; + } + } + entry = (ctrl1 << 29)|(dis1 << 28)|(lowerSID << 16)| \ + (ctrl2 << 13)|(dis2 << 12)|(upperSID << 0); + LPC_CANAF_RAM->mask[count] = entry; + CANAF_gstd_cnt++; + count++; + AFSection->SFF_GPR_Sec = (SFF_GPR_Entry *)((uint32_t)(AFSection->SFF_GPR_Sec)+ sizeof(SFF_GPR_Entry)); + } + } + +/***** Setup Explicit Extend Frame Format Identifier Section *****/ + if(AFSection->EFF_Sec != NULL) + { + for(i=0;i<(AFSection->EFF_NumEntry);i++) + { + if(count + 1 > 512) + { + return CAN_OBJECTS_FULL_ERROR; + } + EID = AFSection->EFF_Sec->ID_29; + ctrl1 = AFSection->EFF_Sec->controller; + + // check parameter + CHECK_PARAM(PARAM_ID_29(EID)); + CHECK_PARAM(PARAM_CTRL(ctrl1)); + + entry = 0x00; //reset entry value + if(CANAF_ext_cnt != 0) + { + buf = LPC_CANAF_RAM->mask[count-1]; + EID_temp = buf & 0x0FFFFFFF; + if(EID_temp > EID) + { + return CAN_AF_ENTRY_ERROR; + } + } + entry = (ctrl1 << 29)|(EID << 0); + LPC_CANAF_RAM->mask[count] = entry; + CANAF_ext_cnt ++; + count++; + AFSection->EFF_Sec = (EFF_Entry *)((uint32_t)(AFSection->EFF_Sec)+ sizeof(EFF_Entry)); + } + } + +/***** Setup Group of Extended Frame Format Identifier Section *****/ + if(AFSection->EFF_GPR_Sec != NULL) + { + for(i=0;i<(AFSection->EFF_GPR_NumEntry);i++) + { + if(count + 2 > 512) + { + return CAN_OBJECTS_FULL_ERROR; + } + ctrl1 = AFSection->EFF_GPR_Sec->controller1; + ctrl2 = AFSection->EFF_GPR_Sec->controller2; + lowerEID = AFSection->EFF_GPR_Sec->lowerEID; + upperEID = AFSection->EFF_GPR_Sec->upperEID; + + //check parameter + CHECK_PARAM(PARAM_CTRL(ctrl1)); + CHECK_PARAM(PARAM_CTRL(ctrl2)); + CHECK_PARAM(PARAM_ID_29(lowerEID)); + CHECK_PARAM(PARAM_ID_29(upperEID)); + + entry = 0x00; + if(CANAF_gext_cnt != 0) + { + buf = LPC_CANAF_RAM->mask[count-1]; + EID_temp = buf & 0x0FFFFFFF; + if(EID_temp > lowerEID) + { + return CAN_AF_ENTRY_ERROR; + } + } + entry = (ctrl1 << 29)|(lowerEID << 0); + LPC_CANAF_RAM->mask[count++] = entry; + entry = (ctrl2 << 29)|(upperEID << 0); + LPC_CANAF_RAM->mask[count++] = entry; + CANAF_gext_cnt++; + AFSection->EFF_GPR_Sec = (EFF_GPR_Entry *)((uint32_t)(AFSection->EFF_GPR_Sec)+ sizeof(EFF_GPR_Entry)); + } + } + //update address values + LPC_CANAF->SFF_sa = ((CANAF_FullCAN_cnt + 1)>>1)<<2; + LPC_CANAF->SFF_GRP_sa = LPC_CANAF->SFF_sa + (((CANAF_std_cnt+1)>>1)<< 2); + LPC_CANAF->EFF_sa = LPC_CANAF->SFF_GRP_sa + (CANAF_gstd_cnt << 2); + LPC_CANAF->EFF_GRP_sa = LPC_CANAF->EFF_sa + (CANAF_ext_cnt << 2); + LPC_CANAF->ENDofTable = LPC_CANAF->EFF_GRP_sa + (CANAF_gext_cnt << 3); + + if(FULLCAN_ENABLE == DISABLE) + { + LPC_CANAF->AFMR = 0x00; // Normal mode + } + else + { + LPC_CANAF->AFMR = 0x04; + } + return CAN_OK; +} +/********************************************************************//** + * @brief Add Explicit ID into AF Look-Up Table dynamically. + * @param[in] CANx pointer to LPC_CAN_TypeDef, should be: + * - LPC_CAN1: CAN1 peripheral + * - LPC_CAN2: CAN2 peripheral + * @param[in] id: The ID of entry will be added + * @param[in] format: is the type of ID Frame Format, should be: + * - STD_ID_FORMAT: 11-bit ID value + * - EXT_ID_FORMAT: 29-bit ID value + * @return CAN Error, could be: + * - CAN_OBJECTS_FULL_ERROR: No more rx or tx objects available + * - CAN_ID_EXIT_ERROR: ID exited in table + * - CAN_OK: ID is added into table successfully + *********************************************************************/ +CAN_ERROR CAN_LoadExplicitEntry(LPC_CAN_TypeDef* CANx, uint32_t id, CAN_ID_FORMAT_Type format) +{ + uint32_t tmp0 = 0; + uint32_t buf0=0, buf1=0; + int16_t cnt1=0, cnt2=0, bound1=0, total=0; + + + CHECK_PARAM(PARAM_CANx(CANx)); + CHECK_PARAM(PARAM_ID_FORMAT(format)); + + if (CANx == LPC_CAN1) + { + tmp0 = 0; + } + else if (CANx == LPC_CAN2) + { + tmp0 = 1; + } + + /* Acceptance Filter Memory full - return */ + total =((CANAF_FullCAN_cnt+1)>>1)+ CANAF_FullCAN_cnt*3 +((CANAF_std_cnt + 1) >> 1)+ \ + CANAF_gstd_cnt + CANAF_ext_cnt + (CANAF_gext_cnt<<1); + if (total >= 512){ //don't have enough space + return CAN_OBJECTS_FULL_ERROR; + } + + /* Setup Acceptance Filter Configuration + Acceptance Filter Mode Register = Off */ + LPC_CANAF->AFMR = 0x00000001; + +/*********** Add Explicit Standard Identifier Frame Format entry *********/ + if(format == STD_ID_FORMAT) + { + id &= 0x07FF; + id |= (tmp0 << 13); /* Add controller number */ + /* Move all remaining sections one place up + if new entry will increase FullCAN list */ + if ((CANAF_std_cnt & 0x0001) == 0) + { + cnt1 = ((CANAF_FullCAN_cnt+1)>>1)+((CANAF_std_cnt+1)>>1); + bound1 = total - cnt1; + buf0 = LPC_CANAF_RAM->mask[cnt1]; + while(bound1--) + { + cnt1++; + buf1 = LPC_CANAF_RAM->mask[cnt1]; + LPC_CANAF_RAM->mask[cnt1] = buf0; + buf0 = buf1; + } + } + if (CANAF_std_cnt == 0) + { + cnt2 = (CANAF_FullCAN_cnt + 1)>>1; + /* For entering first ID */ + LPC_CANAF_RAM->mask[cnt2] = 0x0000FFFF | (id << 16); + } + else if (CANAF_std_cnt == 1) + { + cnt2 = (CANAF_FullCAN_cnt + 1)>>1; + /* For entering second ID */ + if ((LPC_CANAF_RAM->mask[cnt2] >> 16) > id) + { + LPC_CANAF_RAM->mask[cnt2] = (LPC_CANAF_RAM->mask[cnt2] >> 16) | (id << 16); + } + else + { + LPC_CANAF_RAM->mask[cnt2] = (LPC_CANAF_RAM->mask[cnt2] & 0xFFFF0000) | id; + } + } + else + { + /* Find where to insert new ID */ + cnt1 = (CANAF_FullCAN_cnt+1)>>1; + cnt2 = CANAF_std_cnt; + bound1 = ((CANAF_FullCAN_cnt+1)>>1)+((CANAF_std_cnt+1)>>1); + while (cnt1 < bound1) + { + /* Loop through standard existing IDs */ + if ((LPC_CANAF_RAM->mask[cnt1] >> 16) > id) + { + cnt2 = cnt1 * 2; + break; + } + + if ((LPC_CANAF_RAM->mask[cnt1] & 0x0000FFFF) > id) + { + cnt2 = cnt1 * 2 + 1; + break; + } + + cnt1++; + } + /* cnt1 = U32 where to insert new ID */ + /* cnt2 = U16 where to insert new ID */ + + if (cnt1 == bound1) + { + /* Adding ID as last entry */ + /* Even number of IDs exists */ + if ((CANAF_std_cnt & 0x0001) == 0) + { + LPC_CANAF_RAM->mask[cnt1] = 0x0000FFFF | (id << 16); + } + /* Odd number of IDs exists */ + else + { + LPC_CANAF_RAM->mask[cnt1] = (LPC_CANAF_RAM->mask[cnt1] & 0xFFFF0000) | id; + } + } + else + { + buf0 = LPC_CANAF_RAM->mask[cnt1]; /* Remember current entry */ + if ((cnt2 & 0x0001) == 0) + { + /* Insert new mask to even address*/ + buf1 = (id << 16) | (buf0 >> 16); + } + else + { + /* Insert new mask to odd address */ + buf1 = (buf0 & 0xFFFF0000) | id; + } + LPC_CANAF_RAM->mask[cnt1] = buf1;/* Insert mask */ + bound1 = ((CANAF_FullCAN_cnt+1)>>1)+((CANAF_std_cnt+1)>>1)-1; + /* Move all remaining standard mask entries one place up */ + while (cnt1 < bound1) + { + cnt1++; + buf1 = LPC_CANAF_RAM->mask[cnt1]; + LPC_CANAF_RAM->mask[cnt1] = (buf1 >> 16) | (buf0 << 16); + buf0 = buf1; + } + + if ((CANAF_std_cnt & 0x0001) == 0) + { + /* Even number of IDs exists */ + LPC_CANAF_RAM->mask[cnt1+1] = (buf0 <<16) |(0x0000FFFF); + } + } + } + CANAF_std_cnt++; + //update address values + LPC_CANAF->SFF_GRP_sa +=0x04 ; + LPC_CANAF->EFF_sa +=0x04 ; + LPC_CANAF->EFF_GRP_sa +=0x04; + LPC_CANAF->ENDofTable +=0x04; + } + +/*********** Add Explicit Extended Identifier Frame Format entry *********/ + else + { + /* Add controller number */ + id |= (tmp0) << 29; + + cnt1 = ((CANAF_FullCAN_cnt+1)>>1)+(((CANAF_std_cnt + 1) >> 1) + CANAF_gstd_cnt); + cnt2 = 0; + while (cnt2 < CANAF_ext_cnt) + { + /* Loop through extended existing masks*/ + if (LPC_CANAF_RAM->mask[cnt1] > id) + { + break; + } + cnt1++;/* cnt1 = U32 where to insert new mask */ + cnt2++; + } + + buf0 = LPC_CANAF_RAM->mask[cnt1]; /* Remember current entry */ + LPC_CANAF_RAM->mask[cnt1] = id; /* Insert mask */ + + CANAF_ext_cnt++; + + bound1 = total; + /* Move all remaining extended mask entries one place up*/ + while (cnt2 < bound1) + { + cnt1++; + cnt2++; + buf1 = LPC_CANAF_RAM->mask[cnt1]; + LPC_CANAF_RAM->mask[cnt1] = buf0; + buf0 = buf1; + } + /* update address values */ + LPC_CANAF->EFF_GRP_sa += 4; + LPC_CANAF->ENDofTable += 4; + } + if(CANAF_FullCAN_cnt == 0) //not use FullCAN mode + { + LPC_CANAF->AFMR = 0x00;//not use FullCAN mode + } + else + { + LPC_CANAF->AFMR = 0x04; + } + + return CAN_OK; +} + +/********************************************************************//** + * @brief Load FullCAN entry into AFLUT + * @param[in] CANx: CAN peripheral selected, should be: + * - LPC_CAN1: CAN1 peripheral + * - LPC_CAN2: CAN2 peripheral + * @param[in] id: identifier of entry that will be added + * @return CAN_ERROR, could be: + * - CAN_OK: loading is successful + * - CAN_ID_EXIT_ERROR: ID exited in FullCAN Section + * - CAN_OBJECTS_FULL_ERROR: no more space available + *********************************************************************/ +CAN_ERROR CAN_LoadFullCANEntry (LPC_CAN_TypeDef* CANx, uint16_t id) +{ + uint32_t ctrl0 = 0; + uint32_t buf0=0, buf1=0, buf2=0; + uint32_t tmp0=0, tmp1=0, tmp2=0; + int16_t cnt1=0, cnt2=0, bound1=0, total=0; + + CHECK_PARAM(PARAM_CANx(CANx)); + + if (CANx == LPC_CAN1) + { + ctrl0 = 0; + } + else if (CANx == LPC_CAN2) + { + ctrl0 = 1; + } + + /* Acceptance Filter Memory full - return */ + total =((CANAF_FullCAN_cnt+1)>>1)+ CANAF_FullCAN_cnt*3 +((CANAF_std_cnt + 1) >> 1)+ \ + CANAF_gstd_cnt + CANAF_ext_cnt + (CANAF_gext_cnt<<1); + //don't have enough space for this fullCAN Entry and its Object(3*32 bytes) + if ((total >=508)||(CANAF_FullCAN_cnt>=64)){ + return CAN_OBJECTS_FULL_ERROR; + } + /* Setup Acceptance Filter Configuration + Acceptance Filter Mode Register = Off */ + LPC_CANAF->AFMR = 0x00000001; + + /* Add mask for standard identifiers */ + id &= 0x07FF; + id |= (ctrl0 << 13) | (1 << 11); /* Add controller number */ +// total = ((CANAF_std_cnt + 1) >> 1)+ CANAF_gstd_cnt + CANAF_ext_cnt + (CANAF_gext_cnt<<1); + /* Move all remaining sections one place up + if new entry will increase FullCAN list */ + if (((CANAF_FullCAN_cnt & 0x0001) == 0)&&(total!=0)) + { + //then remove remaining section + cnt1 = (CANAF_FullCAN_cnt >> 1); + bound1 = total; + buf0 = LPC_CANAF_RAM->mask[cnt1]; + + while (bound1--) + { + cnt1++; + buf1 = LPC_CANAF_RAM->mask[cnt1]; + LPC_CANAF_RAM->mask[cnt1] = buf0; + buf0 = buf1; + } + } + if (CANAF_FullCAN_cnt == 0) + { + /* For entering first ID */ + LPC_CANAF_RAM->mask[0] = 0x0000FFFF | (id << 16); + } + else if (CANAF_FullCAN_cnt == 1) + { + /* For entering second ID */ + if ((LPC_CANAF_RAM->mask[0] >> 16) > id) + { + LPC_CANAF_RAM->mask[0] = (LPC_CANAF_RAM->mask[0] >> 16) | (id << 16); + } + else + { + LPC_CANAF_RAM->mask[0] = (LPC_CANAF_RAM->mask[0] & 0xFFFF0000) | id; + } + } + else + { + /* Find where to insert new ID */ + cnt1 = 0; + cnt2 = CANAF_FullCAN_cnt; + bound1 = (CANAF_FullCAN_cnt - 1) >> 1; + while (cnt1 <= bound1) + { + /* Loop through standard existing IDs */ + if ((LPC_CANAF_RAM->mask[cnt1] >> 16) > id) + { + cnt2 = cnt1 * 2; + break; + } + + if ((LPC_CANAF_RAM->mask[cnt1] & 0x0000FFFF) > id) + { + cnt2 = cnt1 * 2 + 1; + break; + } + + cnt1++; + } + /* cnt1 = U32 where to insert new ID */ + /* cnt2 = U16 where to insert new ID */ + + if (cnt1 > bound1) + { + /* Adding ID as last entry */ + /* Even number of IDs exists */ + if ((CANAF_FullCAN_cnt & 0x0001) == 0) + { + LPC_CANAF_RAM->mask[cnt1] = 0x0000FFFF | (id << 16); + } + /* Odd number of IDs exists */ + else + { + LPC_CANAF_RAM->mask[cnt1] = (LPC_CANAF_RAM->mask[cnt1] & 0xFFFF0000) | id; + } + } + else + { + buf0 = LPC_CANAF_RAM->mask[cnt1]; /* Remember current entry */ + if ((cnt2 & 0x0001) == 0) + { + /* Insert new mask to even address*/ + buf1 = (id << 16) | (buf0 >> 16); + } + else + { + /* Insert new mask to odd address */ + buf1 = (buf0 & 0xFFFF0000) | id; + } + LPC_CANAF_RAM->mask[cnt1] = buf1;/* Insert mask */ + bound1 = CANAF_FullCAN_cnt >> 1; + /* Move all remaining standard mask entries one place up */ + while (cnt1 < bound1) + { + cnt1++; + buf1 = LPC_CANAF_RAM->mask[cnt1]; + LPC_CANAF_RAM->mask[cnt1] = (buf1 >> 16) | (buf0 << 16); + buf0 = buf1; + } + + if ((CANAF_FullCAN_cnt & 0x0001) == 0) + { + /* Even number of IDs exists */ + LPC_CANAF_RAM->mask[cnt1] = (LPC_CANAF_RAM->mask[cnt1] & 0xFFFF0000) + | (0x0000FFFF); + } + } + } + //restruct FulCAN Object Section + bound1 = CANAF_FullCAN_cnt - cnt2; + cnt1 = total - (CANAF_FullCAN_cnt)*3 + cnt2*3 + 1; + buf0 = LPC_CANAF_RAM->mask[cnt1]; + buf1 = LPC_CANAF_RAM->mask[cnt1+1]; + buf2 = LPC_CANAF_RAM->mask[cnt1+2]; + LPC_CANAF_RAM->mask[cnt1]=LPC_CANAF_RAM->mask[cnt1+1]= LPC_CANAF_RAM->mask[cnt1+2]=0x00; + cnt1+=3; + while(bound1--) + { + tmp0 = LPC_CANAF_RAM->mask[cnt1]; + tmp1 = LPC_CANAF_RAM->mask[cnt1+1]; + tmp2 = LPC_CANAF_RAM->mask[cnt1+2]; + LPC_CANAF_RAM->mask[cnt1]= buf0; + LPC_CANAF_RAM->mask[cnt1+1]= buf1; + LPC_CANAF_RAM->mask[cnt1+2]= buf2; + buf0 = tmp0; + buf1 = tmp1; + buf2 = tmp2; + cnt1+=3; + } + CANAF_FullCAN_cnt++; + //update address values + LPC_CANAF->SFF_sa +=0x04; + LPC_CANAF->SFF_GRP_sa +=0x04 ; + LPC_CANAF->EFF_sa +=0x04 ; + LPC_CANAF->EFF_GRP_sa +=0x04; + LPC_CANAF->ENDofTable +=0x04; + + LPC_CANAF->AFMR = 0x04; + return CAN_OK; +} + +/********************************************************************//** + * @brief Load Group entry into AFLUT + * @param[in] CANx: CAN peripheral selected, should be: + * - LPC_CAN1: CAN1 peripheral + * - LPC_CAN2: CAN2 peripheral + * @param[in] lowerID, upperID: lower and upper identifier of entry + * @param[in] format: type of ID format, should be: + * - STD_ID_FORMAT: Standard ID format (11-bit value) + * - EXT_ID_FORMAT: Extended ID format (29-bit value) + * @return CAN_ERROR, could be: + * - CAN_OK: loading is successful + * - CAN_CONFLICT_ID_ERROR: Conflict ID occurs + * - CAN_OBJECTS_FULL_ERROR: no more space available + *********************************************************************/ +CAN_ERROR CAN_LoadGroupEntry(LPC_CAN_TypeDef* CANx, uint32_t lowerID, \ + uint32_t upperID, CAN_ID_FORMAT_Type format) +{ + uint16_t tmp = 0; + uint32_t buf0, buf1, entry1, entry2, LID,UID; + int16_t cnt1, bound1, total; + + CHECK_PARAM(PARAM_CANx(CANx)); + CHECK_PARAM(PARAM_ID_FORMAT(format)); + + if(lowerID > upperID) return CAN_CONFLICT_ID_ERROR; + if(CANx == LPC_CAN1) + { + tmp = 0; + } + else + { + tmp = 1; + } + + total =((CANAF_FullCAN_cnt+1)>>1)+ CANAF_FullCAN_cnt*3 +((CANAF_std_cnt + 1) >> 1)+ \ + CANAF_gstd_cnt + CANAF_ext_cnt + (CANAF_gext_cnt<<1); + + /* Setup Acceptance Filter Configuration + Acceptance Filter Mode Register = Off */ + LPC_CANAF->AFMR = 0x00000001; + +/*********Add Group of Standard Identifier Frame Format************/ + if(format == STD_ID_FORMAT) + { + if ((total >= 512)){//don't have enough space + return CAN_OBJECTS_FULL_ERROR; + } + lowerID &=0x7FF; //mask ID + upperID &=0x7FF; + entry1 = (tmp << 29)|(lowerID << 16)|(tmp << 13)|(upperID << 0); + cnt1 = ((CANAF_FullCAN_cnt+1)>>1) + ((CANAF_std_cnt + 1) >> 1); + + //if this is the first Group standard ID entry + if(CANAF_gstd_cnt == 0) + { + LPC_CANAF_RAM->mask[cnt1] = entry1; + } + else + { + //find the position to add new Group entry + bound1 = ((CANAF_FullCAN_cnt+1)>>1) + ((CANAF_std_cnt + 1) >> 1) + CANAF_gstd_cnt; + while(cnt1 < bound1) + { + buf0 = LPC_CANAF_RAM->mask[cnt1]; + LID = (buf0 >> 16)&0x7FF; + UID = buf0 & 0x7FF; + if (upperID <= LID) + { + //add new entry before this entry + LPC_CANAF_RAM->mask[cnt1] = entry1; + break; + } + else if (lowerID >= UID) + { + //load next entry to compare + cnt1 ++; + } + else + return CAN_CONFLICT_ID_ERROR; + } + if(cnt1 >= bound1) + { + //add new entry at the last position in this list + buf0 = LPC_CANAF_RAM->mask[cnt1]; + LPC_CANAF_RAM->mask[cnt1] = entry1; + } + + //remove all remaining entry of this section one place up + bound1 = total - cnt1; + while(bound1--) + { + cnt1++; + buf1 = LPC_CANAF_RAM->mask[cnt1]; + LPC_CANAF_RAM->mask[cnt1] = buf0; + buf0 = buf1; + } + } + CANAF_gstd_cnt++; + //update address values + LPC_CANAF->EFF_sa +=0x04 ; + LPC_CANAF->EFF_GRP_sa +=0x04; + LPC_CANAF->ENDofTable +=0x04; + } + + +/*********Add Group of Extended Identifier Frame Format************/ + else + { + if ((total >= 511)){//don't have enough space + return CAN_OBJECTS_FULL_ERROR; + } + lowerID &= 0x1FFFFFFF; //mask ID + upperID &= 0x1FFFFFFF; + entry1 = (tmp << 29)|(lowerID << 0); + entry2 = (tmp << 29)|(upperID << 0); + + cnt1 = ((CANAF_FullCAN_cnt+1)>>1) + ((CANAF_std_cnt + 1) >> 1) + CANAF_gstd_cnt + CANAF_ext_cnt; + //if this is the first Group standard ID entry + if(CANAF_gext_cnt == 0) + { + LPC_CANAF_RAM->mask[cnt1] = entry1; + LPC_CANAF_RAM->mask[cnt1+1] = entry2; + } + else + { + //find the position to add new Group entry + bound1 = ((CANAF_FullCAN_cnt+1)>>1) + ((CANAF_std_cnt + 1) >> 1) + CANAF_gstd_cnt \ + + CANAF_ext_cnt + (CANAF_gext_cnt<<1); + while(cnt1 < bound1) + { + buf0 = LPC_CANAF_RAM->mask[cnt1]; + buf1 = LPC_CANAF_RAM->mask[cnt1+1]; + LID = buf0 & 0x1FFFFFFF; //mask ID + UID = buf1 & 0x1FFFFFFF; + if (upperID <= LID) + { + //add new entry before this entry + LPC_CANAF_RAM->mask[cnt1] = entry1; + LPC_CANAF_RAM->mask[++cnt1] = entry2; + break; + } + else if (lowerID >= UID) + { + //load next entry to compare + cnt1 +=2; + } + else + return CAN_CONFLICT_ID_ERROR; + } + if(cnt1 >= bound1) + { + //add new entry at the last position in this list + buf0 = LPC_CANAF_RAM->mask[cnt1]; + buf1 = LPC_CANAF_RAM->mask[cnt1+1]; + LPC_CANAF_RAM->mask[cnt1] = entry1; + LPC_CANAF_RAM->mask[++cnt1] = entry2; + } + //remove all remaining entry of this section two place up + bound1 = total - cnt1 + 1; + cnt1++; + while(bound1>0) + { + entry1 = LPC_CANAF_RAM->mask[cnt1]; + entry2 = LPC_CANAF_RAM->mask[cnt1+1]; + LPC_CANAF_RAM->mask[cnt1] = buf0; + LPC_CANAF_RAM->mask[cnt1+1] = buf1; + buf0 = entry1; + buf1 = entry2; + cnt1 +=2; + bound1 -=2; + } + } + CANAF_gext_cnt++; + //update address values + LPC_CANAF->ENDofTable +=0x08; + } + LPC_CANAF->AFMR = 0x04; + return CAN_OK; +} + +/********************************************************************//** + * @brief Remove AFLUT entry (FullCAN entry and Explicit Standard entry) + * @param[in] EntryType: the type of entry that want to remove, should be: + * - FULLCAN_ENTRY + * - EXPLICIT_STANDARD_ENTRY + * - GROUP_STANDARD_ENTRY + * - EXPLICIT_EXTEND_ENTRY + * - GROUP_EXTEND_ENTRY + * @param[in] position: the position of this entry in its section + * Note: the first position is 0 + * @return CAN_ERROR, could be: + * - CAN_OK: removing is successful + * - CAN_ENTRY_NOT_EXIT_ERROR: entry want to remove is not exit + *********************************************************************/ +CAN_ERROR CAN_RemoveEntry(AFLUT_ENTRY_Type EntryType, uint16_t position) +{ + uint16_t cnt, bound, total; + uint32_t buf0, buf1; + CHECK_PARAM(PARAM_AFLUT_ENTRY_TYPE(EntryType)); + CHECK_PARAM(PARAM_POSITION(position)); + + /* Setup Acceptance Filter Configuration + Acceptance Filter Mode Register = Off */ + LPC_CANAF->AFMR = 0x00000001; + total = ((CANAF_FullCAN_cnt+1)>>1)+((CANAF_std_cnt + 1) >> 1) + \ + CANAF_gstd_cnt + CANAF_ext_cnt + (CANAF_gext_cnt<<1); + + +/************** Remove FullCAN Entry *************/ + if(EntryType == FULLCAN_ENTRY) + { + if((CANAF_FullCAN_cnt==0)||(position >= CANAF_FullCAN_cnt)) + { + return CAN_ENTRY_NOT_EXIT_ERROR; + } + else + { + cnt = position >> 1; + buf0 = LPC_CANAF_RAM->mask[cnt]; + bound = (CANAF_FullCAN_cnt - position -1)>>1; + if((position & 0x0001) == 0) //event position + { + while(bound--) + { + //remove all remaining FullCAN entry one place down + buf1 = LPC_CANAF_RAM->mask[cnt+1]; + LPC_CANAF_RAM->mask[cnt] = (buf1 >> 16) | (buf0 << 16); + buf0 = buf1; + cnt++; + } + } + else //odd position + { + while(bound--) + { + //remove all remaining FullCAN entry one place down + buf1 = LPC_CANAF_RAM->mask[cnt+1]; + LPC_CANAF_RAM->mask[cnt] = (buf0 & 0xFFFF0000)|(buf1 >> 16); + LPC_CANAF_RAM->mask[cnt+1] = LPC_CANAF_RAM->mask[cnt+1] << 16; + buf0 = buf1<<16; + cnt++; + } + } + if((CANAF_FullCAN_cnt & 0x0001) == 0) + { + if((position & 0x0001)==0) + LPC_CANAF_RAM->mask[cnt] = (buf0 << 16) | (0x0000FFFF); + else + LPC_CANAF_RAM->mask[cnt] = buf0 | 0x0000FFFF; + } + else + { + //remove all remaining section one place down + cnt = (CANAF_FullCAN_cnt + 1)>>1; + bound = total + CANAF_FullCAN_cnt * 3; + while(bound>cnt) + { + LPC_CANAF_RAM->mask[cnt-1] = LPC_CANAF_RAM->mask[cnt]; + cnt++; + } + LPC_CANAF_RAM->mask[cnt-1]=0x00; + //update address values + LPC_CANAF->SFF_sa -=0x04; + LPC_CANAF->SFF_GRP_sa -=0x04 ; + LPC_CANAF->EFF_sa -=0x04 ; + LPC_CANAF->EFF_GRP_sa -=0x04; + LPC_CANAF->ENDofTable -=0x04; + } + CANAF_FullCAN_cnt--; + + //delete its FullCAN Object in the FullCAN Object section + //remove all remaining FullCAN Object three place down + cnt = total + position * 3; + bound = (CANAF_FullCAN_cnt - position + 1) * 3; + + while(bound) + { + LPC_CANAF_RAM->mask[cnt]=LPC_CANAF_RAM->mask[cnt+3];; + LPC_CANAF_RAM->mask[cnt+1]=LPC_CANAF_RAM->mask[cnt+4]; + LPC_CANAF_RAM->mask[cnt+2]=LPC_CANAF_RAM->mask[cnt+5]; + bound -=3; + cnt +=3; + } + } + } + +/************** Remove Explicit Standard ID Entry *************/ + else if(EntryType == EXPLICIT_STANDARD_ENTRY) + { + if((CANAF_std_cnt==0)||(position >= CANAF_std_cnt)) + { + return CAN_ENTRY_NOT_EXIT_ERROR; + } + else + { + cnt = ((CANAF_FullCAN_cnt+1)>>1)+ (position >> 1); + buf0 = LPC_CANAF_RAM->mask[cnt]; + bound = (CANAF_std_cnt - position - 1)>>1; + if((position & 0x0001) == 0) //event position + { + while(bound--) + { + //remove all remaining FullCAN entry one place down + buf1 = LPC_CANAF_RAM->mask[cnt+1]; + LPC_CANAF_RAM->mask[cnt] = (buf1 >> 16) | (buf0 << 16); + buf0 = buf1; + cnt++; + } + } + else //odd position + { + while(bound--) + { + //remove all remaining FullCAN entry one place down + buf1 = LPC_CANAF_RAM->mask[cnt+1]; + LPC_CANAF_RAM->mask[cnt] = (buf0 & 0xFFFF0000)|(buf1 >> 16); + LPC_CANAF_RAM->mask[cnt+1] = LPC_CANAF_RAM->mask[cnt+1] << 16; + buf0 = buf1<<16; + cnt++; + } + } + if((CANAF_std_cnt & 0x0001) == 0) + { + if((position & 0x0001)==0) + LPC_CANAF_RAM->mask[cnt] = (buf0 << 16) | (0x0000FFFF); + else + LPC_CANAF_RAM->mask[cnt] = buf0 | 0x0000FFFF; + } + else + { + //remove all remaining section one place down + cnt = ((CANAF_FullCAN_cnt + 1)>>1) + ((CANAF_std_cnt + 1) >> 1); + bound = total + CANAF_FullCAN_cnt * 3; + while(bound>cnt) + { + LPC_CANAF_RAM->mask[cnt-1] = LPC_CANAF_RAM->mask[cnt]; + cnt++; + } + LPC_CANAF_RAM->mask[cnt-1]=0x00; + //update address value + LPC_CANAF->SFF_GRP_sa -=0x04 ; + LPC_CANAF->EFF_sa -=0x04 ; + LPC_CANAF->EFF_GRP_sa -=0x04; + LPC_CANAF->ENDofTable -=0x04; + } + CANAF_std_cnt--; + } + } + +/************** Remove Group of Standard ID Entry *************/ + else if(EntryType == GROUP_STANDARD_ENTRY) + { + if((CANAF_gstd_cnt==0)||(position >= CANAF_gstd_cnt)) + { + return CAN_ENTRY_NOT_EXIT_ERROR; + } + else + { + cnt = ((CANAF_FullCAN_cnt + 1)>>1) + ((CANAF_std_cnt + 1) >> 1)+ position + 1; + bound = total + CANAF_FullCAN_cnt * 3; + while (cntmask[cnt-1] = LPC_CANAF_RAM->mask[cnt]; + cnt++; + } + LPC_CANAF_RAM->mask[cnt-1]=0x00; + } + CANAF_gstd_cnt--; + //update address value + LPC_CANAF->EFF_sa -=0x04; + LPC_CANAF->EFF_GRP_sa -=0x04; + LPC_CANAF->ENDofTable -=0x04; + } + +/************** Remove Explicit Extended ID Entry *************/ + else if(EntryType == EXPLICIT_EXTEND_ENTRY) + { + if((CANAF_ext_cnt==0)||(position >= CANAF_ext_cnt)) + { + return CAN_ENTRY_NOT_EXIT_ERROR; + } + else + { + cnt = ((CANAF_FullCAN_cnt + 1)>>1) + ((CANAF_std_cnt + 1) >> 1)+ CANAF_gstd_cnt + position + 1; + bound = total + CANAF_FullCAN_cnt * 3; + while (cntmask[cnt-1] = LPC_CANAF_RAM->mask[cnt]; + cnt++; + } + LPC_CANAF_RAM->mask[cnt-1]=0x00; + } + CANAF_ext_cnt--; + LPC_CANAF->EFF_GRP_sa -=0x04; + LPC_CANAF->ENDofTable -=0x04; + } + +/************** Remove Group of Extended ID Entry *************/ + else + { + if((CANAF_gext_cnt==0)||(position >= CANAF_gext_cnt)) + { + return CAN_ENTRY_NOT_EXIT_ERROR; + } + else + { + cnt = total - (CANAF_gext_cnt<<1) + (position<<1); + bound = total + CANAF_FullCAN_cnt * 3; + while (cntmask[cnt] = LPC_CANAF_RAM->mask[cnt+2]; + LPC_CANAF_RAM->mask[cnt+1] = LPC_CANAF_RAM->mask[cnt+3]; + cnt+=2; + } + } + CANAF_gext_cnt--; + LPC_CANAF->ENDofTable -=0x08; + } + LPC_CANAF->AFMR = 0x04; + return CAN_OK; +} + +/********************************************************************//** + * @brief Send message data + * @param[in] CANx pointer to LPC_CAN_TypeDef, should be: + * - LPC_CAN1: CAN1 peripheral + * - LPC_CAN2: CAN2 peripheral + * @param[in] CAN_Msg point to the CAN_MSG_Type Structure, it contains message + * information such as: ID, DLC, RTR, ID Format + * @return Status: + * - SUCCESS: send message successfully + * - ERROR: send message unsuccessfully + *********************************************************************/ +Status CAN_SendMsg (LPC_CAN_TypeDef *CANx, CAN_MSG_Type *CAN_Msg) +{ + uint32_t data; + CHECK_PARAM(PARAM_CANx(CANx)); + CHECK_PARAM(PARAM_ID_FORMAT(CAN_Msg->format)); + if(CAN_Msg->format==STD_ID_FORMAT) + { + CHECK_PARAM(PARAM_ID_11(CAN_Msg->id)); + } + else + { + CHECK_PARAM(PARAM_ID_29(CAN_Msg->id)); + } + CHECK_PARAM(PARAM_DLC(CAN_Msg->len)); + CHECK_PARAM(PARAM_FRAME_TYPE(CAN_Msg->type)); + + //Check status of Transmit Buffer 1 + if ((CANx->SR & 0x00000004)>>2) + { + /* Transmit Channel 1 is available */ + /* Write frame informations and frame data into its CANxTFI1, + * CANxTID1, CANxTDA1, CANxTDB1 register */ + CANx->TFI1 &= ~0x000F0000; + CANx->TFI1 |= (CAN_Msg->len)<<16; + if(CAN_Msg->type == REMOTE_FRAME) + { + CANx->TFI1 |= (1<<30); //set bit RTR + } + else + { + CANx->TFI1 &= ~(1<<30); + } + if(CAN_Msg->format == EXT_ID_FORMAT) + { + CANx->TFI1 |= (1<<31); //set bit FF + } + else + { + CANx->TFI1 &= ~(1<<31); + } + + /* Write CAN ID*/ + CANx->TID1 = CAN_Msg->id; + + /*Write first 4 data bytes*/ + data = (CAN_Msg->dataA[0])|(((CAN_Msg->dataA[1]))<<8)|((CAN_Msg->dataA[2])<<16)|((CAN_Msg->dataA[3])<<24); + CANx->TDA1 = data; + + /*Write second 4 data bytes*/ + data = (CAN_Msg->dataB[0])|(((CAN_Msg->dataB[1]))<<8)|((CAN_Msg->dataB[2])<<16)|((CAN_Msg->dataB[3])<<24); + CANx->TDB1 = data; + + /*Write transmission request*/ + CANx->CMR = 0x21; + return SUCCESS; + } + //check status of Transmit Buffer 2 + else if((CANx->SR & 0x00000004)>>10) + { + /* Transmit Channel 2 is available */ + /* Write frame informations and frame data into its CANxTFI2, + * CANxTID2, CANxTDA2, CANxTDB2 register */ + CANx->TFI2 &= ~0x000F0000; + CANx->TFI2 |= (CAN_Msg->len)<<16; + if(CAN_Msg->type == REMOTE_FRAME) + { + CANx->TFI2 |= (1<<30); //set bit RTR + } + else + { + CANx->TFI2 &= ~(1<<30); + } + if(CAN_Msg->format == EXT_ID_FORMAT) + { + CANx->TFI2 |= (1<<31); //set bit FF + } + else + { + CANx->TFI2 &= ~(1<<31); + } + + /* Write CAN ID*/ + CANx->TID2 = CAN_Msg->id; + + /*Write first 4 data bytes*/ + data = (CAN_Msg->dataA[0])|(((CAN_Msg->dataA[1]))<<8)|((CAN_Msg->dataA[2])<<16)|((CAN_Msg->dataA[3])<<24); + CANx->TDA2 = data; + + /*Write second 4 data bytes*/ + data = (CAN_Msg->dataB[0])|(((CAN_Msg->dataB[1]))<<8)|((CAN_Msg->dataB[2])<<16)|((CAN_Msg->dataB[3])<<24); + CANx->TDB2 = data; + + /*Write transmission request*/ + CANx->CMR = 0x41; + return SUCCESS; + } + //check status of Transmit Buffer 3 + else if ((CANx->SR & 0x00000004)>>18) + { + /* Transmit Channel 3 is available */ + /* Write frame informations and frame data into its CANxTFI3, + * CANxTID3, CANxTDA3, CANxTDB3 register */ + CANx->TFI3 &= ~0x000F0000; + CANx->TFI3 |= (CAN_Msg->len)<<16; + if(CAN_Msg->type == REMOTE_FRAME) + { + CANx->TFI3 |= (1<<30); //set bit RTR + } + else + { + CANx->TFI3 &= ~(1<<30); + } + if(CAN_Msg->format == EXT_ID_FORMAT) + { + CANx->TFI3 |= (1<<31); //set bit FF + } + else + { + CANx->TFI3 &= ~(1<<31); + } + + /* Write CAN ID*/ + CANx->TID3 = CAN_Msg->id; + + /*Write first 4 data bytes*/ + data = (CAN_Msg->dataA[0])|(((CAN_Msg->dataA[1]))<<8)|((CAN_Msg->dataA[2])<<16)|((CAN_Msg->dataA[3])<<24); + CANx->TDA3 = data; + + /*Write second 4 data bytes*/ + data = (CAN_Msg->dataB[0])|(((CAN_Msg->dataB[1]))<<8)|((CAN_Msg->dataB[2])<<16)|((CAN_Msg->dataB[3])<<24); + CANx->TDB3 = data; + + /*Write transmission request*/ + CANx->CMR = 0x81; + return SUCCESS; + } + else + { + return ERROR; + } +} + +/********************************************************************//** + * @brief Receive message data + * @param[in] CANx pointer to LPC_CAN_TypeDef, should be: + * - LPC_CAN1: CAN1 peripheral + * - LPC_CAN2: CAN2 peripheral + * @param[in] CAN_Msg point to the CAN_MSG_Type Struct, it will contain received + * message information such as: ID, DLC, RTR, ID Format + * @return Status: + * - SUCCESS: receive message successfully + * - ERROR: receive message unsuccessfully + *********************************************************************/ +Status CAN_ReceiveMsg (LPC_CAN_TypeDef *CANx, CAN_MSG_Type *CAN_Msg) +{ + uint32_t data; + + CHECK_PARAM(PARAM_CANx(CANx)); + + //check status of Receive Buffer + if((CANx->SR &0x00000001)) + { + /* Receive message is available */ + /* Read frame informations */ + CAN_Msg->format = (uint8_t)(((CANx->RFS) & 0x80000000)>>31); + CAN_Msg->type = (uint8_t)(((CANx->RFS) & 0x40000000)>>30); + CAN_Msg->len = (uint8_t)(((CANx->RFS) & 0x000F0000)>>16); + + + /* Read CAN message identifier */ + CAN_Msg->id = CANx->RID; + + /* Read the data if received message was DATA FRAME */ + if (CAN_Msg->type == DATA_FRAME) + { + /* Read first 4 data bytes */ + data = CANx->RDA; + *((uint8_t *) &CAN_Msg->dataA[0])= data & 0x000000FF; + *((uint8_t *) &CAN_Msg->dataA[1])= (data & 0x0000FF00)>>8;; + *((uint8_t *) &CAN_Msg->dataA[2])= (data & 0x00FF0000)>>16; + *((uint8_t *) &CAN_Msg->dataA[3])= (data & 0xFF000000)>>24; + + /* Read second 4 data bytes */ + data = CANx->RDB; + *((uint8_t *) &CAN_Msg->dataB[0])= data & 0x000000FF; + *((uint8_t *) &CAN_Msg->dataB[1])= (data & 0x0000FF00)>>8; + *((uint8_t *) &CAN_Msg->dataB[2])= (data & 0x00FF0000)>>16; + *((uint8_t *) &CAN_Msg->dataB[3])= (data & 0xFF000000)>>24; + + /*release receive buffer*/ + CANx->CMR = 0x04; + } + else + { + /* Received Frame is a Remote Frame, not have data, we just receive + * message information only */ + return SUCCESS; + } + } + else + { + // no receive message available + return ERROR; + } + return SUCCESS; +} + +/********************************************************************//** + * @brief Receive FullCAN Object + * @param[in] CANAFx: CAN Acceptance Filter register, should be: LPC_CANAF + * @param[in] CAN_Msg point to the CAN_MSG_Type Struct, it will contain received + * message information such as: ID, DLC, RTR, ID Format + * @return CAN_ERROR, could be: + * - CAN_FULL_OBJ_NOT_RCV: FullCAN Object is not be received + * - CAN_OK: Received FullCAN Object successful + * + *********************************************************************/ +CAN_ERROR FCAN_ReadObj (LPC_CANAF_TypeDef* CANAFx, CAN_MSG_Type *CAN_Msg) +{ + uint32_t *pSrc, data; + uint32_t interrut_word, msg_idx, test_bit, head_idx, tail_idx; + + CHECK_PARAM(PARAM_CANAFx(CANAFx)); + + interrut_word = 0; + + if (LPC_CANAF->FCANIC0 != 0) + { + interrut_word = LPC_CANAF->FCANIC0; + head_idx = 0; + tail_idx = 31; + } + else if (LPC_CANAF->FCANIC1 != 0) + { + interrut_word = LPC_CANAF->FCANIC1; + head_idx = 32; + tail_idx = 63; + } + + if (interrut_word != 0) + { + /* Detect for interrupt pending */ + msg_idx = 0; + for (msg_idx = head_idx; msg_idx <= tail_idx; msg_idx++) + { + test_bit = interrut_word & 0x1; + interrut_word = interrut_word >> 1; + + if (test_bit) + { + pSrc = (uint32_t *) (LPC_CANAF->ENDofTable + LPC_CANAF_RAM_BASE + msg_idx * 12); + + /* Has been finished updating the content */ + if ((*pSrc & 0x03000000L) == 0x03000000L) + { + /*clear semaphore*/ + *pSrc &= 0xFCFFFFFF; + + /*Set to DatA*/ + pSrc++; + /* Copy to dest buf */ + data = *pSrc; + *((uint8_t *) &CAN_Msg->dataA[0])= data & 0x000000FF; + *((uint8_t *) &CAN_Msg->dataA[1])= (data & 0x0000FF00)>>8; + *((uint8_t *) &CAN_Msg->dataA[2])= (data & 0x00FF0000)>>16; + *((uint8_t *) &CAN_Msg->dataA[3])= (data & 0xFF000000)>>24; + + /*Set to DatB*/ + pSrc++; + /* Copy to dest buf */ + data = *pSrc; + *((uint8_t *) &CAN_Msg->dataB[0])= data & 0x000000FF; + *((uint8_t *) &CAN_Msg->dataB[1])= (data & 0x0000FF00)>>8; + *((uint8_t *) &CAN_Msg->dataB[2])= (data & 0x00FF0000)>>16; + *((uint8_t *) &CAN_Msg->dataB[3])= (data & 0xFF000000)>>24; + /*Back to Dat1*/ + pSrc -= 2; + + CAN_Msg->id = *pSrc & 0x7FF; + CAN_Msg->len = (uint8_t) (*pSrc >> 16) & 0x0F; + CAN_Msg->format = 0; //FullCAN Object ID always is 11-bit value + CAN_Msg->type = (uint8_t)(*pSrc >> 30) &0x01; + /*Re-read semaphore*/ + if ((*pSrc & 0x03000000L) == 0) + { + return CAN_OK; + } + } + } + } + } + return CAN_FULL_OBJ_NOT_RCV; +} +/********************************************************************//** + * @brief Get CAN Control Status + * @param[in] CANx pointer to LPC_CAN_TypeDef, should be: + * - LPC_CAN1: CAN1 peripheral + * - LPC_CAN2: CAN2 peripheral + * @param[in] arg: type of CAN status to get from CAN status register + * Should be: + * - CANCTRL_GLOBAL_STS: CAN Global Status + * - CANCTRL_INT_CAP: CAN Interrupt and Capture + * - CANCTRL_ERR_WRN: CAN Error Warning Limit + * - CANCTRL_STS: CAN Control Status + * @return Current Control Status that you want to get value + *********************************************************************/ +uint32_t CAN_GetCTRLStatus (LPC_CAN_TypeDef* CANx, CAN_CTRL_STS_Type arg) +{ + CHECK_PARAM(PARAM_CANx(CANx)); + CHECK_PARAM(PARAM_CTRL_STS_TYPE(arg)); + + switch (arg) + { + case CANCTRL_GLOBAL_STS: + return CANx->GSR; + + case CANCTRL_INT_CAP: + return CANx->ICR; + + case CANCTRL_ERR_WRN: + return CANx->EWL; + + default: // CANCTRL_STS + return CANx->SR; + } +} +/********************************************************************//** + * @brief Get CAN Central Status + * @param[in] CANCRx point to LPC_CANCR_TypeDef, should be: LPC_CANCR + * @param[in] arg: type of CAN status to get from CAN Central status register + * Should be: + * - CANCR_TX_STS: Central CAN Tx Status + * - CANCR_RX_STS: Central CAN Rx Status + * - CANCR_MS: Central CAN Miscellaneous Status + * @return Current Central Status that you want to get value + *********************************************************************/ +uint32_t CAN_GetCRStatus (LPC_CANCR_TypeDef* CANCRx, CAN_CR_STS_Type arg) +{ + CHECK_PARAM(PARAM_CANCRx(CANCRx)); + CHECK_PARAM(PARAM_CR_STS_TYPE(arg)); + + switch (arg) + { + case CANCR_TX_STS: + return CANCRx->CANTxSR; + + case CANCR_RX_STS: + return CANCRx->CANRxSR; + + default: // CANCR_MS + return CANCRx->CANMSR; + } +} +/********************************************************************//** + * @brief Enable/Disable CAN Interrupt + * @param[in] CANx pointer to LPC_CAN_TypeDef, should be: + * - LPC_CAN1: CAN1 peripheral + * - LPC_CAN2: CAN2 peripheral + * @param[in] arg: type of CAN interrupt that you want to enable/disable + * Should be: + * - CANINT_RIE: CAN Receiver Interrupt Enable + * - CANINT_TIE1: CAN Transmit Interrupt Enable + * - CANINT_EIE: CAN Error Warning Interrupt Enable + * - CANINT_DOIE: CAN Data Overrun Interrupt Enable + * - CANINT_WUIE: CAN Wake-Up Interrupt Enable + * - CANINT_EPIE: CAN Error Passive Interrupt Enable + * - CANINT_ALIE: CAN Arbitration Lost Interrupt Enable + * - CANINT_BEIE: CAN Bus Error Interrupt Enable + * - CANINT_IDIE: CAN ID Ready Interrupt Enable + * - CANINT_TIE2: CAN Transmit Interrupt Enable for Buffer2 + * - CANINT_TIE3: CAN Transmit Interrupt Enable for Buffer3 + * - CANINT_FCE: FullCAN Interrupt Enable + * @param[in] NewState: New state of this function, should be: + * - ENABLE + * - DISABLE + * @return none + *********************************************************************/ +void CAN_IRQCmd (LPC_CAN_TypeDef* CANx, CAN_INT_EN_Type arg, FunctionalState NewState) +{ + CHECK_PARAM(PARAM_CANx(CANx)); + CHECK_PARAM(PARAM_INT_EN_TYPE(arg)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState)); + + if(NewState == ENABLE) + { + if(arg==CANINT_FCE) + { + LPC_CANAF->AFMR = 0x01; + LPC_CANAF->FCANIE = 0x01; + LPC_CANAF->AFMR = 0x04; + } + else + CANx->IER |= (1 << arg); + } + else + { + if(arg==CANINT_FCE){ + LPC_CANAF->AFMR = 0x01; + LPC_CANAF->FCANIE = 0x01; + LPC_CANAF->AFMR = 0x00; + } + else + CANx->IER &= ~(1 << arg); + } +} + +/********************************************************************//** + * @brief Setting Acceptance Filter mode + * @param[in] CANAFx point to LPC_CANAF_TypeDef object, should be: LPC_CANAF + * @param[in] AFMode: type of AF mode that you want to set, should be: + * - CAN_Normal: Normal mode + * - CAN_AccOff: Acceptance Filter Off Mode + * - CAN_AccBP: Acceptance Fileter Bypass Mode + * - CAN_eFCAN: FullCAN Mode Enhancement + * @return none + *********************************************************************/ +void CAN_SetAFMode (LPC_CANAF_TypeDef* CANAFx, CAN_AFMODE_Type AFMode) +{ + CHECK_PARAM(PARAM_CANAFx(CANAFx)); + CHECK_PARAM(PARAM_AFMODE_TYPE(AFMode)); + + switch(AFMode) + { + case CAN_Normal: + CANAFx->AFMR = 0x00; + break; + case CAN_AccOff: + CANAFx->AFMR = 0x01; + break; + case CAN_AccBP: + CANAFx->AFMR = 0x02; + break; + case CAN_eFCAN: + CANAFx->AFMR = 0x04; + break; + } +} + +/********************************************************************//** + * @brief Enable/Disable CAN Mode + * @param[in] CANx pointer to LPC_CAN_TypeDef, should be: + * - LPC_CAN1: CAN1 peripheral + * - LPC_CAN2: CAN2 peripheral + * @param[in] mode: type of CAN mode that you want to enable/disable, should be: + * - CAN_OPERATING_MODE: Normal Operating Mode + * - CAN_RESET_MODE: Reset Mode + * - CAN_LISTENONLY_MODE: Listen Only Mode + * - CAN_SELFTEST_MODE: Self Test Mode + * - CAN_TXPRIORITY_MODE: Transmit Priority Mode + * - CAN_SLEEP_MODE: Sleep Mode + * - CAN_RXPOLARITY_MODE: Receive Polarity Mode + * - CAN_TEST_MODE: Test Mode + * @param[in] NewState: New State of this function, should be: + * - ENABLE + * - DISABLE + * @return none + *********************************************************************/ +void CAN_ModeConfig(LPC_CAN_TypeDef* CANx, CAN_MODE_Type mode, FunctionalState NewState) +{ + CHECK_PARAM(PARAM_CANx(CANx)); + CHECK_PARAM(PARAM_MODE_TYPE(mode)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState)); + + switch(mode) + { + case CAN_OPERATING_MODE: + CANx->MOD = 0x00; + break; + case CAN_RESET_MODE: + if(NewState == ENABLE) + CANx->MOD |=CAN_MOD_RM; + else + CANx->MOD &= ~CAN_MOD_RM; + break; + case CAN_LISTENONLY_MODE: + CANx->MOD |=CAN_MOD_RM;//Enter Reset mode + if(NewState == ENABLE) + CANx->MOD |=CAN_MOD_LOM; + else + CANx->MOD &=~CAN_MOD_LOM; + CANx->MOD &=~CAN_MOD_RM;//Release Reset mode + break; + case CAN_SELFTEST_MODE: + CANx->MOD |=CAN_MOD_RM;//Enter Reset mode + if(NewState == ENABLE) + CANx->MOD |=CAN_MOD_STM; + else + CANx->MOD &=~CAN_MOD_STM; + CANx->MOD &=~CAN_MOD_RM;//Release Reset mode + break; + case CAN_TXPRIORITY_MODE: + if(NewState == ENABLE) + CANx->MOD |=CAN_MOD_TPM; + else + CANx->MOD &=~CAN_MOD_TPM; + break; + case CAN_SLEEP_MODE: + if(NewState == ENABLE) + CANx->MOD |=CAN_MOD_SM; + else + CANx->MOD &=~CAN_MOD_SM; + break; + case CAN_RXPOLARITY_MODE: + if(NewState == ENABLE) + CANx->MOD |=CAN_MOD_RPM; + else + CANx->MOD &=~CAN_MOD_RPM; + break; + case CAN_TEST_MODE: + if(NewState == ENABLE) + CANx->MOD |=CAN_MOD_TM; + else + CANx->MOD &=~CAN_MOD_TM; + break; + } +} +/*********************************************************************//** + * @brief Set CAN command request + * @param[in] CANx point to CAN peripheral selected, should be: + * - LPC_CAN1: CAN1 peripheral + * - LPC_CAN2: CAN2 peripheral + * @param[in] CMRType command request type, should be: + * - CAN_CMR_TR: Transmission request + * - CAN_CMR_AT: Abort Transmission request + * - CAN_CMR_RRB: Release Receive Buffer request + * - CAN_CMR_CDO: Clear Data Overrun request + * - CAN_CMR_SRR: Self Reception request + * - CAN_CMR_STB1: Select Tx Buffer 1 request + * - CAN_CMR_STB2: Select Tx Buffer 2 request + * - CAN_CMR_STB3: Select Tx Buffer 3 request + * @return CANICR (CAN interrupt and Capture register) value + **********************************************************************/ +void CAN_SetCommand(LPC_CAN_TypeDef* CANx, uint32_t CMRType) +{ + CHECK_PARAM(PARAM_CANx(CANx)); + CANx->CMR |= CMRType; +} + +/*********************************************************************//** + * @brief Get CAN interrupt status + * @param[in] CANx point to CAN peripheral selected, should be: + * - LPC_CAN1: CAN1 peripheral + * - LPC_CAN2: CAN2 peripheral + * @return CANICR (CAN interrupt and Capture register) value + **********************************************************************/ +uint32_t CAN_IntGetStatus(LPC_CAN_TypeDef* CANx) +{ + CHECK_PARAM(PARAM_CANx(CANx)); + return CANx->ICR; +} + +/*********************************************************************//** + * @brief Check if FullCAN interrupt enable or not + * @param[in] CANAFx point to LPC_CANAF_TypeDef object, should be: LPC_CANAF + * @return IntStatus, could be: + * - SET: if FullCAN interrupt is enable + * - RESET: if FullCAN interrupt is disable + **********************************************************************/ +IntStatus CAN_FullCANIntGetStatus (LPC_CANAF_TypeDef* CANAFx) +{ + CHECK_PARAM( PARAM_CANAFx(CANAFx)); + if (CANAFx->FCANIE) + return SET; + return RESET; +} + +/*********************************************************************//** + * @brief Get value of FullCAN interrupt and capture register + * @param[in] CANAFx point to LPC_CANAF_TypeDef object, should be: LPC_CANAF + * @param[in] type: FullCAN IC type, should be: + * - FULLCAN_IC0: FullCAN Interrupt Capture 0 + * - FULLCAN_IC1: FullCAN Interrupt Capture 1 + * @return FCANIC0 or FCANIC1 (FullCAN interrupt and Capture register) value + **********************************************************************/ +uint32_t CAN_FullCANPendGetStatus(LPC_CANAF_TypeDef* CANAFx, FullCAN_IC_Type type) +{ + CHECK_PARAM(PARAM_CANAFx(CANAFx)); + CHECK_PARAM( PARAM_FULLCAN_IC(type)); + if (type == FULLCAN_IC0) + return CANAFx->FCANIC0; + return CANAFx->FCANIC1; +} +/* End of Public Variables ---------------------------------------------------------- */ +/** + * @} + */ + +#endif /* _CAN */ + +/** + * @} + */ + +/* --------------------------------- End Of File ------------------------------ */ diff --git a/arch/arm/lpc17xx/Drivers/source/lpc17xx_clkpwr.c b/arch/arm/lpc17xx/Drivers/source/lpc17xx_clkpwr.c new file mode 100644 index 0000000..dde358b --- /dev/null +++ b/arch/arm/lpc17xx/Drivers/source/lpc17xx_clkpwr.c @@ -0,0 +1,338 @@ +/***********************************************************************//** + * @file lpc17xx_clkpwr.c + * @brief Contains all functions support for Clock and Power Control + * firmware library on LPC17xx + * @version 3.0 + * @date 18. June. 2010 + * @author NXP MCU SW Application Team + ************************************************************************** + * Software that is described herein is for illustrative purposes only + * which provides customers with programming information regarding the + * products. This software is supplied "AS IS" without any warranties. + * NXP Semiconductors assumes no responsibility or liability for the + * use of the software, conveys no license or title under any patent, + * copyright, or mask work right to the product. NXP Semiconductors + * reserves the right to make changes in the software without + * notification. NXP Semiconductors also make no representation or + * warranty that such application will be suitable for the specified + * use without further testing or modification. + **********************************************************************/ + +/* Peripheral group ----------------------------------------------------------- */ +/** @addtogroup CLKPWR + * @{ + */ + +/* Includes ------------------------------------------------------------------- */ +#include "lpc17xx_clkpwr.h" + + +/* Public Functions ----------------------------------------------------------- */ +/** @addtogroup CLKPWR_Public_Functions + * @{ + */ + +/*********************************************************************//** + * @brief Set value of each Peripheral Clock Selection + * @param[in] ClkType Peripheral Clock Selection of each type, + * should be one of the following: + * - CLKPWR_PCLKSEL_WDT : WDT + - CLKPWR_PCLKSEL_TIMER0 : Timer 0 + - CLKPWR_PCLKSEL_TIMER1 : Timer 1 + - CLKPWR_PCLKSEL_UART0 : UART 0 + - CLKPWR_PCLKSEL_UART1 : UART 1 + - CLKPWR_PCLKSEL_PWM1 : PWM 1 + - CLKPWR_PCLKSEL_I2C0 : I2C 0 + - CLKPWR_PCLKSEL_SPI : SPI + - CLKPWR_PCLKSEL_SSP1 : SSP 1 + - CLKPWR_PCLKSEL_DAC : DAC + - CLKPWR_PCLKSEL_ADC : ADC + - CLKPWR_PCLKSEL_CAN1 : CAN 1 + - CLKPWR_PCLKSEL_CAN2 : CAN 2 + - CLKPWR_PCLKSEL_ACF : ACF + - CLKPWR_PCLKSEL_QEI : QEI + - CLKPWR_PCLKSEL_PCB : PCB + - CLKPWR_PCLKSEL_I2C1 : I2C 1 + - CLKPWR_PCLKSEL_SSP0 : SSP 0 + - CLKPWR_PCLKSEL_TIMER2 : Timer 2 + - CLKPWR_PCLKSEL_TIMER3 : Timer 3 + - CLKPWR_PCLKSEL_UART2 : UART 2 + - CLKPWR_PCLKSEL_UART3 : UART 3 + - CLKPWR_PCLKSEL_I2C2 : I2C 2 + - CLKPWR_PCLKSEL_I2S : I2S + - CLKPWR_PCLKSEL_RIT : RIT + - CLKPWR_PCLKSEL_SYSCON : SYSCON + - CLKPWR_PCLKSEL_MC : MC + + * @param[in] DivVal Value of divider, should be: + * - CLKPWR_PCLKSEL_CCLK_DIV_4 : PCLK_peripheral = CCLK/4 + * - CLKPWR_PCLKSEL_CCLK_DIV_1 : PCLK_peripheral = CCLK/1 + * - CLKPWR_PCLKSEL_CCLK_DIV_2 : PCLK_peripheral = CCLK/2 + * + * @return none + **********************************************************************/ +void CLKPWR_SetPCLKDiv (uint32_t ClkType, uint32_t DivVal) +{ + uint32_t bitpos; + + bitpos = (ClkType < 32) ? (ClkType) : (ClkType - 32); + + /* PCLKSEL0 selected */ + if (ClkType < 32) + { + /* Clear two bit at bit position */ + LPC_SC->PCLKSEL0 &= (~(CLKPWR_PCLKSEL_BITMASK(bitpos))); + + /* Set two selected bit */ + LPC_SC->PCLKSEL0 |= (CLKPWR_PCLKSEL_SET(bitpos, DivVal)); + } + /* PCLKSEL1 selected */ + else + { + /* Clear two bit at bit position */ + LPC_SC->PCLKSEL1 &= ~(CLKPWR_PCLKSEL_BITMASK(bitpos)); + + /* Set two selected bit */ + LPC_SC->PCLKSEL1 |= (CLKPWR_PCLKSEL_SET(bitpos, DivVal)); + } +} + + +/*********************************************************************//** + * @brief Get current value of each Peripheral Clock Selection + * @param[in] ClkType Peripheral Clock Selection of each type, + * should be one of the following: + * - CLKPWR_PCLKSEL_WDT : WDT + - CLKPWR_PCLKSEL_TIMER0 : Timer 0 + - CLKPWR_PCLKSEL_TIMER1 : Timer 1 + - CLKPWR_PCLKSEL_UART0 : UART 0 + - CLKPWR_PCLKSEL_UART1 : UART 1 + - CLKPWR_PCLKSEL_PWM1 : PWM 1 + - CLKPWR_PCLKSEL_I2C0 : I2C 0 + - CLKPWR_PCLKSEL_SPI : SPI + - CLKPWR_PCLKSEL_SSP1 : SSP 1 + - CLKPWR_PCLKSEL_DAC : DAC + - CLKPWR_PCLKSEL_ADC : ADC + - CLKPWR_PCLKSEL_CAN1 : CAN 1 + - CLKPWR_PCLKSEL_CAN2 : CAN 2 + - CLKPWR_PCLKSEL_ACF : ACF + - CLKPWR_PCLKSEL_QEI : QEI + - CLKPWR_PCLKSEL_PCB : PCB + - CLKPWR_PCLKSEL_I2C1 : I2C 1 + - CLKPWR_PCLKSEL_SSP0 : SSP 0 + - CLKPWR_PCLKSEL_TIMER2 : Timer 2 + - CLKPWR_PCLKSEL_TIMER3 : Timer 3 + - CLKPWR_PCLKSEL_UART2 : UART 2 + - CLKPWR_PCLKSEL_UART3 : UART 3 + - CLKPWR_PCLKSEL_I2C2 : I2C 2 + - CLKPWR_PCLKSEL_I2S : I2S + - CLKPWR_PCLKSEL_RIT : RIT + - CLKPWR_PCLKSEL_SYSCON : SYSCON + - CLKPWR_PCLKSEL_MC : MC + + * @return Value of Selected Peripheral Clock Selection + **********************************************************************/ +uint32_t CLKPWR_GetPCLKSEL (uint32_t ClkType) +{ + uint32_t bitpos, retval; + + if (ClkType < 32) + { + bitpos = ClkType; + retval = LPC_SC->PCLKSEL0; + } + else + { + bitpos = ClkType - 32; + retval = LPC_SC->PCLKSEL1; + } + + retval = CLKPWR_PCLKSEL_GET(bitpos, retval); + return retval; +} + + + +/*********************************************************************//** + * @brief Get current value of each Peripheral Clock + * @param[in] ClkType Peripheral Clock Selection of each type, + * should be one of the following: + * - CLKPWR_PCLKSEL_WDT : WDT + - CLKPWR_PCLKSEL_TIMER0 : Timer 0 + - CLKPWR_PCLKSEL_TIMER1 : Timer 1 + - CLKPWR_PCLKSEL_UART0 : UART 0 + - CLKPWR_PCLKSEL_UART1 : UART 1 + - CLKPWR_PCLKSEL_PWM1 : PWM 1 + - CLKPWR_PCLKSEL_I2C0 : I2C 0 + - CLKPWR_PCLKSEL_SPI : SPI + - CLKPWR_PCLKSEL_SSP1 : SSP 1 + - CLKPWR_PCLKSEL_DAC : DAC + - CLKPWR_PCLKSEL_ADC : ADC + - CLKPWR_PCLKSEL_CAN1 : CAN 1 + - CLKPWR_PCLKSEL_CAN2 : CAN 2 + - CLKPWR_PCLKSEL_ACF : ACF + - CLKPWR_PCLKSEL_QEI : QEI + - CLKPWR_PCLKSEL_PCB : PCB + - CLKPWR_PCLKSEL_I2C1 : I2C 1 + - CLKPWR_PCLKSEL_SSP0 : SSP 0 + - CLKPWR_PCLKSEL_TIMER2 : Timer 2 + - CLKPWR_PCLKSEL_TIMER3 : Timer 3 + - CLKPWR_PCLKSEL_UART2 : UART 2 + - CLKPWR_PCLKSEL_UART3 : UART 3 + - CLKPWR_PCLKSEL_I2C2 : I2C 2 + - CLKPWR_PCLKSEL_I2S : I2S + - CLKPWR_PCLKSEL_RIT : RIT + - CLKPWR_PCLKSEL_SYSCON : SYSCON + - CLKPWR_PCLKSEL_MC : MC + + * @return Value of Selected Peripheral Clock + **********************************************************************/ +uint32_t CLKPWR_GetPCLK (uint32_t ClkType) +{ + uint32_t retval, div; + + retval = SystemCoreClock; + div = CLKPWR_GetPCLKSEL(ClkType); + + switch (div) + { + case 0: + div = 4; + break; + + case 1: + div = 1; + break; + + case 2: + div = 2; + break; + + case 3: + div = 8; + break; + } + retval /= div; + + return retval; +} + + + +/*********************************************************************//** + * @brief Configure power supply for each peripheral according to NewState + * @param[in] PPType Type of peripheral used to enable power, + * should be one of the following: + * - CLKPWR_PCONP_PCTIM0 : Timer 0 + - CLKPWR_PCONP_PCTIM1 : Timer 1 + - CLKPWR_PCONP_PCUART0 : UART 0 + - CLKPWR_PCONP_PCUART1 : UART 1 + - CLKPWR_PCONP_PCPWM1 : PWM 1 + - CLKPWR_PCONP_PCI2C0 : I2C 0 + - CLKPWR_PCONP_PCSPI : SPI + - CLKPWR_PCONP_PCRTC : RTC + - CLKPWR_PCONP_PCSSP1 : SSP 1 + - CLKPWR_PCONP_PCAD : ADC + - CLKPWR_PCONP_PCAN1 : CAN 1 + - CLKPWR_PCONP_PCAN2 : CAN 2 + - CLKPWR_PCONP_PCGPIO : GPIO + - CLKPWR_PCONP_PCRIT : RIT + - CLKPWR_PCONP_PCMC : MC + - CLKPWR_PCONP_PCQEI : QEI + - CLKPWR_PCONP_PCI2C1 : I2C 1 + - CLKPWR_PCONP_PCSSP0 : SSP 0 + - CLKPWR_PCONP_PCTIM2 : Timer 2 + - CLKPWR_PCONP_PCTIM3 : Timer 3 + - CLKPWR_PCONP_PCUART2 : UART 2 + - CLKPWR_PCONP_PCUART3 : UART 3 + - CLKPWR_PCONP_PCI2C2 : I2C 2 + - CLKPWR_PCONP_PCI2S : I2S + - CLKPWR_PCONP_PCGPDMA : GPDMA + - CLKPWR_PCONP_PCENET : Ethernet + - CLKPWR_PCONP_PCUSB : USB + * + * @param[in] NewState New state of Peripheral Power, should be: + * - ENABLE : Enable power for this peripheral + * - DISABLE : Disable power for this peripheral + * + * @return none + **********************************************************************/ +void CLKPWR_ConfigPPWR (uint32_t PPType, FunctionalState NewState) +{ + if (NewState == ENABLE) + { + LPC_SC->PCONP |= PPType & CLKPWR_PCONP_BITMASK; + } + else if (NewState == DISABLE) + { + LPC_SC->PCONP &= (~PPType) & CLKPWR_PCONP_BITMASK; + } +} + + +/*********************************************************************//** + * @brief Enter Sleep mode with co-operated instruction by the Cortex-M3. + * @param[in] None + * @return None + **********************************************************************/ +void CLKPWR_Sleep(void) +{ + LPC_SC->PCON = 0x00; + /* Sleep Mode*/ + __WFI(); +} + + +/*********************************************************************//** + * @brief Enter Deep Sleep mode with co-operated instruction by the Cortex-M3. + * @param[in] None + * @return None + **********************************************************************/ +void CLKPWR_DeepSleep(void) +{ + /* Deep-Sleep Mode, set SLEEPDEEP bit */ + SCB->SCR = 0x4; + LPC_SC->PCON = 0x8; + /* Deep Sleep Mode*/ + __WFI(); +} + + +/*********************************************************************//** + * @brief Enter Power Down mode with co-operated instruction by the Cortex-M3. + * @param[in] None + * @return None + **********************************************************************/ +void CLKPWR_PowerDown(void) +{ + /* Deep-Sleep Mode, set SLEEPDEEP bit */ + SCB->SCR = 0x4; + LPC_SC->PCON = 0x09; + /* Power Down Mode*/ + __WFI(); +} + + +/*********************************************************************//** + * @brief Enter Deep Power Down mode with co-operated instruction by the Cortex-M3. + * @param[in] None + * @return None + **********************************************************************/ +void CLKPWR_DeepPowerDown(void) +{ + /* Deep-Sleep Mode, set SLEEPDEEP bit */ + SCB->SCR = 0x4; + LPC_SC->PCON = 0x03; + /* Deep Power Down Mode*/ + __WFI(); +} + +/** + * @} + */ + +/** + * @} + */ + +/* --------------------------------- End Of File ------------------------------ */ diff --git a/arch/arm/lpc17xx/Drivers/source/lpc17xx_dac.c b/arch/arm/lpc17xx/Drivers/source/lpc17xx_dac.c new file mode 100644 index 0000000..5f2d7fb --- /dev/null +++ b/arch/arm/lpc17xx/Drivers/source/lpc17xx_dac.c @@ -0,0 +1,139 @@ +/** + * @file lpc17xx_dac.c + * @brief Contains all functions support for DAC firmware library on LPC17xx + * @version 2.0 + * @date 21. May. 2010 + * @author NXP MCU SW Application Team + ************************************************************************** + * Software that is described herein is for illustrative purposes only + * which provides customers with programming information regarding the + * products. This software is supplied "AS IS" without any warranties. + * NXP Semiconductors assumes no responsibility or liability for the + * use of the software, conveys no license or title under any patent, + * copyright, or mask work right to the product. NXP Semiconductors + * reserves the right to make changes in the software without + * notification. NXP Semiconductors also make no representation or + * warranty that such application will be suitable for the specified + * use without further testing or modification. + **********************************************************************/ + +/* Peripheral group ----------------------------------------------------------- */ +/** @addtogroup DAC + * @{ + */ + +/* Includes ------------------------------------------------------------------- */ +#include "lpc17xx_dac.h" +#include "lpc17xx_clkpwr.h" + +/* If this source file built with example, the LPC17xx FW library configuration + * file in each example directory ("lpc17xx_libcfg.h") must be included, + * otherwise the default FW library configuration file must be included instead + */ +#ifdef __BUILD_WITH_EXAMPLE__ +#include "lpc17xx_libcfg.h" +#else +#include "lpc17xx_libcfg_default.h" +#endif /* __BUILD_WITH_EXAMPLE__ */ + + +#ifdef _DAC + +/* Public Functions ----------------------------------------------------------- */ +/** @addtogroup DAC_Public_Functions + * @{ + */ + +/*********************************************************************//** + * @brief Initial ADC configuration + * - Maximum current is 700 uA + * - Value to AOUT is 0 + * @param[in] DACx pointer to LPC_DAC_TypeDef, should be: LPC_DAC + * @return None + ***********************************************************************/ +void DAC_Init(LPC_DAC_TypeDef *DACx) +{ + CHECK_PARAM(PARAM_DACx(DACx)); + /* Set default clock divider for DAC */ + // CLKPWR_SetPCLKDiv (CLKPWR_PCLKSEL_DAC, CLKPWR_PCLKSEL_CCLK_DIV_4); + //Set maximum current output + DAC_SetBias(LPC_DAC,DAC_MAX_CURRENT_700uA); +} + +/*********************************************************************//** + * @brief Update value to DAC + * @param[in] DACx pointer to LPC_DAC_TypeDef, should be: LPC_DAC + * @param[in] dac_value : value 10 bit to be converted to output + * @return None + ***********************************************************************/ +void DAC_UpdateValue (LPC_DAC_TypeDef *DACx,uint32_t dac_value) +{ + uint32_t tmp; + CHECK_PARAM(PARAM_DACx(DACx)); + tmp = DACx->DACR & DAC_BIAS_EN; + tmp |= DAC_VALUE(dac_value); + // Update value + DACx->DACR = tmp; +} + +/*********************************************************************//** + * @brief Set Maximum current for DAC + * @param[in] DACx pointer to LPC_DAC_TypeDef, should be: LPC_DAC + * @param[in] bias : 0 is 700 uA + * 1 350 uA + * @return None + ***********************************************************************/ +void DAC_SetBias (LPC_DAC_TypeDef *DACx,uint32_t bias) +{ + CHECK_PARAM(PARAM_DAC_CURRENT_OPT(bias)); + DACx->DACR &=~DAC_BIAS_EN; + if (bias == DAC_MAX_CURRENT_350uA) + { + DACx->DACR |= DAC_BIAS_EN; + } +} + +/*********************************************************************//** + * @brief To enable the DMA operation and control DMA timer + * @param[in] DACx pointer to LPC_DAC_TypeDef, should be: LPC_DAC + * @param[in] DAC_ConverterConfigStruct pointer to DAC_CONVERTER_CFG_Type + * - DBLBUF_ENA : enable/disable DACR double buffering feature + * - CNT_ENA : enable/disable timer out counter + * - DMA_ENA : enable/disable DMA access + * @return None + ***********************************************************************/ +void DAC_ConfigDAConverterControl (LPC_DAC_TypeDef *DACx,DAC_CONVERTER_CFG_Type *DAC_ConverterConfigStruct) +{ + CHECK_PARAM(PARAM_DACx(DACx)); + DACx->DACCTRL &= ~DAC_DACCTRL_MASK; + if (DAC_ConverterConfigStruct->DBLBUF_ENA) + DACx->DACCTRL |= DAC_DBLBUF_ENA; + if (DAC_ConverterConfigStruct->CNT_ENA) + DACx->DACCTRL |= DAC_CNT_ENA; + if (DAC_ConverterConfigStruct->DMA_ENA) + DACx->DACCTRL |= DAC_DMA_ENA; +} + +/*********************************************************************//** + * @brief Set reload value for interrupt/DMA counter + * @param[in] DACx pointer to LPC_DAC_TypeDef, should be: LPC_DAC + * @param[in] time_out time out to reload for interrupt/DMA counter + * @return None + ***********************************************************************/ +void DAC_SetDMATimeOut(LPC_DAC_TypeDef *DACx, uint32_t time_out) +{ + CHECK_PARAM(PARAM_DACx(DACx)); + DACx->DACCNTVAL = DAC_CCNT_VALUE(time_out); +} + +/** + * @} + */ + +#endif /* _DAC */ + +/** + * @} + */ + +/* --------------------------------- End Of File ------------------------------ */ diff --git a/arch/arm/lpc17xx/Drivers/source/lpc17xx_emac.c b/arch/arm/lpc17xx/Drivers/source/lpc17xx_emac.c new file mode 100644 index 0000000..0128f5b --- /dev/null +++ b/arch/arm/lpc17xx/Drivers/source/lpc17xx_emac.c @@ -0,0 +1,950 @@ +/** + * @file lpc17xx_emac.c + * @brief Contains all functions support for Ethernet MAC firmware library on LPC17xx + * @version 2.0 + * @date 21. May. 2010 + * @author NXP MCU SW Application Team + ************************************************************************** + * Software that is described herein is for illustrative purposes only + * which provides customers with programming information regarding the + * products. This software is supplied "AS IS" without any warranties. + * NXP Semiconductors assumes no responsibility or liability for the + * use of the software, conveys no license or title under any patent, + * copyright, or mask work right to the product. NXP Semiconductors + * reserves the right to make changes in the software without + * notification. NXP Semiconductors also make no representation or + * warranty that such application will be suitable for the specified + * use without further testing or modification. + **********************************************************************/ + +/* Peripheral group ----------------------------------------------------------- */ +/** @addtogroup EMAC + * @{ + */ + +/* Includes ------------------------------------------------------------------- */ +#include "lpc17xx_emac.h" +#include "lpc17xx_clkpwr.h" + +/* If this source file built with example, the LPC17xx FW library configuration + * file in each example directory ("lpc17xx_libcfg.h") must be included, + * otherwise the default FW library configuration file must be included instead + */ +#ifdef __BUILD_WITH_EXAMPLE__ +#include "lpc17xx_libcfg.h" +#else +#include "lpc17xx_libcfg_default.h" +#endif /* __BUILD_WITH_EXAMPLE__ */ + + +#ifdef _EMAC + +/* Private Variables ---------------------------------------------------------- */ +/** @defgroup EMAC_Private_Variables EMAC Private Variables + * @{ + */ + +/* MII Mgmt Configuration register - Clock divider setting */ +const uint8_t EMAC_clkdiv[] = { 4, 6, 8, 10, 14, 20, 28 }; + +/* EMAC local DMA Descriptors */ + +/** Rx Descriptor data array */ +static RX_Desc Rx_Desc[EMAC_NUM_RX_FRAG]; + +/** Rx Status data array - Must be 8-Byte aligned */ +#if defined ( __CC_ARM ) +static __align(8) RX_Stat Rx_Stat[EMAC_NUM_RX_FRAG]; +#elif defined ( __ICCARM__ ) +#pragma data_alignment=8 +static RX_Stat Rx_Stat[EMAC_NUM_RX_FRAG]; +#elif defined ( __GNUC__ ) +static __attribute__ ((aligned (8))) RX_Stat Rx_Stat[EMAC_NUM_RX_FRAG]; +#endif + +/** Tx Descriptor data array */ +static TX_Desc Tx_Desc[EMAC_NUM_TX_FRAG]; +/** Tx Status data array */ +static TX_Stat Tx_Stat[EMAC_NUM_TX_FRAG]; + +/* EMAC local DMA buffers */ +/** Rx buffer data */ +static uint32_t rx_buf[EMAC_NUM_RX_FRAG][EMAC_ETH_MAX_FLEN>>2]; +/** Tx buffer data */ +static uint32_t tx_buf[EMAC_NUM_TX_FRAG][EMAC_ETH_MAX_FLEN>>2]; + +/** + * @} + */ + +/* Private Functions ---------------------------------------------------------- */ +static void rx_descr_init (void); +static void tx_descr_init (void); +static int32_t write_PHY (uint32_t PhyReg, uint16_t Value); +static int32_t read_PHY (uint32_t PhyReg); + +static void setEmacAddr(uint8_t abStationAddr[]); +static int32_t emac_CRCCalc(uint8_t frame_no_fcs[], int32_t frame_len); + + +/*--------------------------- rx_descr_init ---------------------------------*/ +/*********************************************************************//** + * @brief Initializes RX Descriptor + * @param[in] None + * @return None + ***********************************************************************/ +static void rx_descr_init (void) +{ + /* Initialize Receive Descriptor and Status array. */ + uint32_t i; + + for (i = 0; i < EMAC_NUM_RX_FRAG; i++) { + Rx_Desc[i].Packet = (uint32_t)&rx_buf[i]; + Rx_Desc[i].Ctrl = EMAC_RCTRL_INT | (EMAC_ETH_MAX_FLEN - 1); + Rx_Stat[i].Info = 0; + Rx_Stat[i].HashCRC = 0; + } + + /* Set EMAC Receive Descriptor Registers. */ + LPC_EMAC->RxDescriptor = (uint32_t)&Rx_Desc[0]; + LPC_EMAC->RxStatus = (uint32_t)&Rx_Stat[0]; + LPC_EMAC->RxDescriptorNumber = EMAC_NUM_RX_FRAG - 1; + + /* Rx Descriptors Point to 0 */ + LPC_EMAC->RxConsumeIndex = 0; +} + + +/*--------------------------- tx_descr_init ---- ----------------------------*/ +/*********************************************************************//** + * @brief Initializes TX Descriptor + * @param[in] None + * @return None + ***********************************************************************/ +static void tx_descr_init (void) { + /* Initialize Transmit Descriptor and Status array. */ + uint32_t i; + + for (i = 0; i < EMAC_NUM_TX_FRAG; i++) { + Tx_Desc[i].Packet = (uint32_t)&tx_buf[i]; + Tx_Desc[i].Ctrl = 0; + Tx_Stat[i].Info = 0; + } + + /* Set EMAC Transmit Descriptor Registers. */ + LPC_EMAC->TxDescriptor = (uint32_t)&Tx_Desc[0]; + LPC_EMAC->TxStatus = (uint32_t)&Tx_Stat[0]; + LPC_EMAC->TxDescriptorNumber = EMAC_NUM_TX_FRAG - 1; + + /* Tx Descriptors Point to 0 */ + LPC_EMAC->TxProduceIndex = 0; +} + + +/*--------------------------- write_PHY -------------------------------------*/ +/*********************************************************************//** + * @brief Write value to PHY device + * @param[in] PhyReg: PHY Register address + * @param[in] Value: Value to write + * @return 0 - if success + * 1 - if fail + ***********************************************************************/ +static int32_t write_PHY (uint32_t PhyReg, uint16_t Value) +{ + /* Write a data 'Value' to PHY register 'PhyReg'. */ + uint32_t tout; + + LPC_EMAC->MADR = EMAC_DEF_ADR | PhyReg; + LPC_EMAC->MWTD = Value; + + /* Wait until operation completed */ + tout = 0; + for (tout = 0; tout < EMAC_MII_WR_TOUT; tout++) { + if ((LPC_EMAC->MIND & EMAC_MIND_BUSY) == 0) { + return (0); + } + } + // Time out! + return (-1); +} + + +/*--------------------------- read_PHY --------------------------------------*/ +/*********************************************************************//** + * @brief Read value from PHY device + * @param[in] PhyReg: PHY Register address + * @return 0 - if success + * 1 - if fail + ***********************************************************************/ +static int32_t read_PHY (uint32_t PhyReg) +{ + /* Read a PHY register 'PhyReg'. */ + uint32_t tout; + + LPC_EMAC->MADR = EMAC_DEF_ADR | PhyReg; + LPC_EMAC->MCMD = EMAC_MCMD_READ; + + /* Wait until operation completed */ + tout = 0; + for (tout = 0; tout < EMAC_MII_RD_TOUT; tout++) { + if ((LPC_EMAC->MIND & EMAC_MIND_BUSY) == 0) { + LPC_EMAC->MCMD = 0; + return (LPC_EMAC->MRDD); + } + } + // Time out! + return (-1); +} + +/*********************************************************************//** + * @brief Set Station MAC address for EMAC module + * @param[in] abStationAddr Pointer to Station address that contains 6-bytes + * of MAC address (should be in order from MAC Address 1 to MAC Address 6) + * @return None + **********************************************************************/ +static void setEmacAddr(uint8_t abStationAddr[]) +{ + /* Set the Ethernet MAC Address registers */ + LPC_EMAC->SA0 = ((uint32_t)abStationAddr[5] << 8) | (uint32_t)abStationAddr[4]; + LPC_EMAC->SA1 = ((uint32_t)abStationAddr[3] << 8) | (uint32_t)abStationAddr[2]; + LPC_EMAC->SA2 = ((uint32_t)abStationAddr[1] << 8) | (uint32_t)abStationAddr[0]; +} + + +/*********************************************************************//** + * @brief Calculates CRC code for number of bytes in the frame + * @param[in] frame_no_fcs Pointer to the first byte of the frame + * @param[in] frame_len length of the frame without the FCS + * @return the CRC as a 32 bit integer + **********************************************************************/ +static int32_t emac_CRCCalc(uint8_t frame_no_fcs[], int32_t frame_len) +{ + int i; // iterator + int j; // another iterator + char byte; // current byte + int crc; // CRC result + int q0, q1, q2, q3; // temporary variables + crc = 0xFFFFFFFF; + for (i = 0; i < frame_len; i++) { + byte = *frame_no_fcs++; + for (j = 0; j < 2; j++) { + if (((crc >> 28) ^ (byte >> 3)) & 0x00000001) { + q3 = 0x04C11DB7; + } else { + q3 = 0x00000000; + } + if (((crc >> 29) ^ (byte >> 2)) & 0x00000001) { + q2 = 0x09823B6E; + } else { + q2 = 0x00000000; + } + if (((crc >> 30) ^ (byte >> 1)) & 0x00000001) { + q1 = 0x130476DC; + } else { + q1 = 0x00000000; + } + if (((crc >> 31) ^ (byte >> 0)) & 0x00000001) { + q0 = 0x2608EDB8; + } else { + q0 = 0x00000000; + } + crc = (crc << 4) ^ q3 ^ q2 ^ q1 ^ q0; + byte >>= 4; + } + } + return crc; +} +/* End of Private Functions --------------------------------------------------- */ + + +/* Public Functions ----------------------------------------------------------- */ +/** @addtogroup EMAC_Public_Functions + * @{ + */ + + +/*********************************************************************//** + * @brief Initializes the EMAC peripheral according to the specified +* parameters in the EMAC_ConfigStruct. + * @param[in] EMAC_ConfigStruct Pointer to a EMAC_CFG_Type structure +* that contains the configuration information for the +* specified EMAC peripheral. + * @return None + * + * Note: This function will initialize EMAC module according to procedure below: + * - Remove the soft reset condition from the MAC + * - Configure the PHY via the MIIM interface of the MAC + * - Select RMII mode + * - Configure the transmit and receive DMA engines, including the descriptor arrays + * - Configure the host registers (MAC1,MAC2 etc.) in the MAC + * - Enable the receive and transmit data paths + * In default state after initializing, only Rx Done and Tx Done interrupt are enabled, + * all remain interrupts are disabled + * (Ref. from LPC17xx UM) + **********************************************************************/ +Status EMAC_Init(EMAC_CFG_Type *EMAC_ConfigStruct) +{ + /* Initialize the EMAC Ethernet controller. */ + int32_t regv,tout, tmp; + + /* Set up clock and power for Ethernet module */ + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCENET, ENABLE); + + /* Reset all EMAC internal modules */ + LPC_EMAC->MAC1 = EMAC_MAC1_RES_TX | EMAC_MAC1_RES_MCS_TX | EMAC_MAC1_RES_RX | + EMAC_MAC1_RES_MCS_RX | EMAC_MAC1_SIM_RES | EMAC_MAC1_SOFT_RES; + + LPC_EMAC->Command = EMAC_CR_REG_RES | EMAC_CR_TX_RES | EMAC_CR_RX_RES | EMAC_CR_PASS_RUNT_FRM; + + /* A short delay after reset. */ + for (tout = 100; tout; tout--); + + /* Initialize MAC control registers. */ + LPC_EMAC->MAC1 = EMAC_MAC1_PASS_ALL; + LPC_EMAC->MAC2 = EMAC_MAC2_CRC_EN | EMAC_MAC2_PAD_EN; + LPC_EMAC->MAXF = EMAC_ETH_MAX_FLEN; + /* + * Find the clock that close to desired target clock + */ + tmp = SystemCoreClock / EMAC_MCFG_MII_MAXCLK; + for (tout = 0; tout < sizeof (EMAC_clkdiv); tout++){ + if (EMAC_clkdiv[tout] >= tmp) break; + } + tout++; + // Write to MAC configuration register and reset + LPC_EMAC->MCFG = EMAC_MCFG_CLK_SEL(tout) | EMAC_MCFG_RES_MII; + // release reset + LPC_EMAC->MCFG &= ~(EMAC_MCFG_RES_MII); + LPC_EMAC->CLRT = EMAC_CLRT_DEF; + LPC_EMAC->IPGR = EMAC_IPGR_P2_DEF; + + /* Enable Reduced MII interface. */ + LPC_EMAC->Command = EMAC_CR_RMII | EMAC_CR_PASS_RUNT_FRM; + + /* Reset Reduced MII Logic. */ + LPC_EMAC->SUPP = EMAC_SUPP_RES_RMII; + + for (tout = 100; tout; tout--); + LPC_EMAC->SUPP = 0; + + /* Put the DP83848C in reset mode */ + write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_BMCR_RESET); + + /* Wait for hardware reset to end. */ + for (tout = EMAC_PHY_RESP_TOUT; tout; tout--) { + regv = read_PHY (EMAC_PHY_REG_BMCR); + if (!(regv & (EMAC_PHY_BMCR_RESET | EMAC_PHY_BMCR_POWERDOWN))) { + /* Reset complete, device not Power Down. */ + break; + } + if (tout == 0){ + // Time out, return ERROR + return (ERROR); + } + } + + // Set PHY mode + if (EMAC_SetPHYMode(EMAC_ConfigStruct->Mode) < 0){ + return (ERROR); + } + + // Set EMAC address + setEmacAddr(EMAC_ConfigStruct->pbEMAC_Addr); + + /* Initialize Tx and Rx DMA Descriptors */ + rx_descr_init (); + tx_descr_init (); + + // Set Receive Filter register: enable broadcast and multicast + LPC_EMAC->RxFilterCtrl = EMAC_RFC_MCAST_EN | EMAC_RFC_BCAST_EN | EMAC_RFC_PERFECT_EN; + + /* Enable Rx Done and Tx Done interrupt for EMAC */ + LPC_EMAC->IntEnable = EMAC_INT_RX_DONE | EMAC_INT_TX_DONE; + + /* Reset all interrupts */ + LPC_EMAC->IntClear = 0xFFFF; + + /* Enable receive and transmit mode of MAC Ethernet core */ + LPC_EMAC->Command |= (EMAC_CR_RX_EN | EMAC_CR_TX_EN); + LPC_EMAC->MAC1 |= EMAC_MAC1_REC_EN; + + return SUCCESS; +} + + +/*********************************************************************//** + * @brief De-initializes the EMAC peripheral registers to their +* default reset values. + * @param[in] None + * @return None + **********************************************************************/ +void EMAC_DeInit(void) +{ + // Disable all interrupt + LPC_EMAC->IntEnable = 0x00; + // Clear all pending interrupt + LPC_EMAC->IntClear = (0xFF) | (EMAC_INT_SOFT_INT | EMAC_INT_WAKEUP); + + /* TurnOff clock and power for Ethernet module */ + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCENET, DISABLE); +} + + +/*********************************************************************//** + * @brief Check specified PHY status in EMAC peripheral + * @param[in] ulPHYState Specified PHY Status Type, should be: + * - EMAC_PHY_STAT_LINK: Link Status + * - EMAC_PHY_STAT_SPEED: Speed Status + * - EMAC_PHY_STAT_DUP: Duplex Status + * @return Status of specified PHY status (0 or 1). + * (-1) if error. + * + * Note: + * For EMAC_PHY_STAT_LINK, return value: + * - 0: Link Down + * - 1: Link Up + * For EMAC_PHY_STAT_SPEED, return value: + * - 0: 10Mbps + * - 1: 100Mbps + * For EMAC_PHY_STAT_DUP, return value: + * - 0: Half-Duplex + * - 1: Full-Duplex + **********************************************************************/ +int32_t EMAC_CheckPHYStatus(uint32_t ulPHYState) +{ + int32_t regv, tmp; +#ifdef MCB_LPC_1768 + regv = read_PHY (EMAC_PHY_REG_STS); + switch(ulPHYState){ + case EMAC_PHY_STAT_LINK: + tmp = (regv & EMAC_PHY_SR_LINK) ? 1 : 0; + break; + case EMAC_PHY_STAT_SPEED: + tmp = (regv & EMAC_PHY_SR_SPEED) ? 0 : 1; + break; + case EMAC_PHY_STAT_DUP: + tmp = (regv & EMAC_PHY_SR_FULL_DUP) ? 1 : 0; + break; +#elif defined(IAR_LPC_1768) + /* Use IAR_LPC_1768 board: + * FSZ8721BL doesn't have Status Register + * so we read Basic Mode Status Register (0x01h) instead + */ + regv = read_PHY (EMAC_PHY_REG_BMSR); + switch(ulPHYState){ + case EMAC_PHY_STAT_LINK: + tmp = (regv & EMAC_PHY_BMSR_LINK_STATUS) ? 1 : 0; + break; + case EMAC_PHY_STAT_SPEED: + tmp = (regv & EMAC_PHY_SR_100_SPEED) ? 1 : 0; + break; + case EMAC_PHY_STAT_DUP: + tmp = (regv & EMAC_PHY_SR_FULL_DUP) ? 1 : 0; + break; +#endif + default: + tmp = -1; + break; + } + return (tmp); +} + + +/*********************************************************************//** + * @brief Set specified PHY mode in EMAC peripheral + * @param[in] ulPHYMode Specified PHY mode, should be: + * - EMAC_MODE_AUTO + * - EMAC_MODE_10M_FULL + * - EMAC_MODE_10M_HALF + * - EMAC_MODE_100M_FULL + * - EMAC_MODE_100M_HALF + * @return Return (0) if no error, otherwise return (-1) + **********************************************************************/ +int32_t EMAC_SetPHYMode(uint32_t ulPHYMode) +{ + int32_t id1, id2, tout, regv; + + /* Check if this is a DP83848C PHY. */ + id1 = read_PHY (EMAC_PHY_REG_IDR1); + id2 = read_PHY (EMAC_PHY_REG_IDR2); + +#ifdef MCB_LPC_1768 + if (((id1 << 16) | (id2 & 0xFFF0)) == EMAC_DP83848C_ID) { + switch(ulPHYMode){ + case EMAC_MODE_AUTO: + write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_AUTO_NEG); +#elif defined(IAR_LPC_1768) /* Use IAR LPC1768 KickStart board */ + if (((id1 << 16) | id2) == EMAC_KSZ8721BL_ID) { + /* Configure the PHY device */ + switch(ulPHYMode){ + case EMAC_MODE_AUTO: + /* Use auto-negotiation about the link speed. */ + write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_AUTO_NEG); +// write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_BMCR_AN); +#endif + /* Wait to complete Auto_Negotiation */ + for (tout = EMAC_PHY_RESP_TOUT; tout; tout--) { + regv = read_PHY (EMAC_PHY_REG_BMSR); + if (regv & EMAC_PHY_BMSR_AUTO_DONE) { + /* Auto-negotiation Complete. */ + break; + } + if (tout == 0){ + // Time out, return error + return (-1); + } + } + break; + case EMAC_MODE_10M_FULL: + /* Connect at 10MBit full-duplex */ + write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_FULLD_10M); + break; + case EMAC_MODE_10M_HALF: + /* Connect at 10MBit half-duplex */ + write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_HALFD_10M); + break; + case EMAC_MODE_100M_FULL: + /* Connect at 100MBit full-duplex */ + write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_FULLD_100M); + break; + case EMAC_MODE_100M_HALF: + /* Connect at 100MBit half-duplex */ + write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_HALFD_100M); + break; + default: + // un-supported + return (-1); + } + } + // It's not correct module ID + else { + return (-1); + } + + // Update EMAC configuration with current PHY status + if (EMAC_UpdatePHYStatus() < 0){ + return (-1); + } + + // Complete + return (0); +} + + +/*********************************************************************//** + * @brief Auto-Configures value for the EMAC configuration register to + * match with current PHY mode + * @param[in] None + * @return Return (0) if no error, otherwise return (-1) + * + * Note: The EMAC configuration will be auto-configured: + * - Speed mode. + * - Half/Full duplex mode + **********************************************************************/ +int32_t EMAC_UpdatePHYStatus(void) +{ + int32_t regv, tout; + + /* Check the link status. */ +#ifdef MCB_LPC_1768 + for (tout = EMAC_PHY_RESP_TOUT; tout; tout--) { + regv = read_PHY (EMAC_PHY_REG_STS); + if (regv & EMAC_PHY_SR_LINK) { + /* Link is on. */ + break; + } + if (tout == 0){ + // time out + return (-1); + } + } + /* Configure Full/Half Duplex mode. */ + if (regv & EMAC_PHY_SR_DUP) { + /* Full duplex is enabled. */ + LPC_EMAC->MAC2 |= EMAC_MAC2_FULL_DUP; + LPC_EMAC->Command |= EMAC_CR_FULL_DUP; + LPC_EMAC->IPGT = EMAC_IPGT_FULL_DUP; + } else { + /* Half duplex mode. */ + LPC_EMAC->IPGT = EMAC_IPGT_HALF_DUP; + } + if (regv & EMAC_PHY_SR_SPEED) { + /* 10MBit mode. */ + LPC_EMAC->SUPP = 0; + } else { + /* 100MBit mode. */ + LPC_EMAC->SUPP = EMAC_SUPP_SPEED; + } +#elif defined(IAR_LPC_1768) + for (tout = EMAC_PHY_RESP_TOUT; tout; tout--) { + regv = read_PHY (EMAC_PHY_REG_BMSR); + if (regv & EMAC_PHY_BMSR_LINK_STATUS) { + /* Link is on. */ + break; + } + if (tout == 0){ + // time out + return (-1); + } + } + + /* Configure Full/Half Duplex mode. */ + if (regv & EMAC_PHY_SR_FULL_DUP) { + /* Full duplex is enabled. */ + LPC_EMAC->MAC2 |= EMAC_MAC2_FULL_DUP; + LPC_EMAC->Command |= EMAC_CR_FULL_DUP; + LPC_EMAC->IPGT = EMAC_IPGT_FULL_DUP; + } else { + /* Half duplex mode. */ + LPC_EMAC->IPGT = EMAC_IPGT_HALF_DUP; + } + + /* Configure 100MBit/10MBit mode. */ + if (!(regv & EMAC_PHY_SR_100_SPEED)) { + /* 10MBit mode. */ + LPC_EMAC->SUPP = 0; + } else { + /* 100MBit mode. */ + LPC_EMAC->SUPP = EMAC_SUPP_SPEED; + } +#endif + // Complete + return (0); +} + + +/*********************************************************************//** + * @brief Enable/Disable hash filter functionality for specified destination + * MAC address in EMAC module + * @param[in] dstMAC_addr Pointer to the first MAC destination address, should + * be 6-bytes length, in order LSB to the MSB + * @param[in] NewState New State of this command, should be: + * - ENABLE. + * - DISABLE. + * @return None + * + * Note: + * The standard Ethernet cyclic redundancy check (CRC) function is calculated from + * the 6 byte destination address in the Ethernet frame (this CRC is calculated + * anyway as part of calculating the CRC of the whole frame), then bits [28:23] out of + * the 32 bits CRC result are taken to form the hash. The 6 bit hash is used to access + * the hash table: it is used as an index in the 64 bit HashFilter register that has been + * programmed with accept values. If the selected accept value is 1, the frame is + * accepted. + **********************************************************************/ +void EMAC_SetHashFilter(uint8_t dstMAC_addr[], FunctionalState NewState) +{ + uint32_t *pReg; + uint32_t tmp; + int32_t crc; + + // Calculate the CRC from the destination MAC address + crc = emac_CRCCalc(dstMAC_addr, 6); + // Extract the value from CRC to get index value for hash filter table + crc = (crc >> 23) & 0x3F; + + pReg = (crc > 31) ? ((uint32_t *)&LPC_EMAC->HashFilterH) \ + : ((uint32_t *)&LPC_EMAC->HashFilterL); + tmp = (crc > 31) ? (crc - 32) : crc; + if (NewState == ENABLE) { + (*pReg) |= (1UL << tmp); + } else { + (*pReg) &= ~(1UL << tmp); + } + // Enable Rx Filter + LPC_EMAC->Command &= ~EMAC_CR_PASS_RX_FILT; +} + +/*********************************************************************//** + * @brief Enable/Disable Filter mode for each specified type EMAC peripheral + * @param[in] ulFilterMode Filter mode, should be: + * - EMAC_RFC_UCAST_EN: all frames of unicast types + * will be accepted + * - EMAC_RFC_BCAST_EN: broadcast frame will be + * accepted + * - EMAC_RFC_MCAST_EN: all frames of multicast + * types will be accepted + * - EMAC_RFC_UCAST_HASH_EN: The imperfect hash + * filter will be applied to unicast addresses + * - EMAC_RFC_MCAST_HASH_EN: The imperfect hash + * filter will be applied to multicast addresses + * - EMAC_RFC_PERFECT_EN: the destination address + * will be compared with the 6 byte station address + * programmed in the station address by the filter + * - EMAC_RFC_MAGP_WOL_EN: the result of the magic + * packet filter will generate a WoL interrupt when + * there is a match + * - EMAC_RFC_PFILT_WOL_EN: the result of the perfect address + * matching filter and the imperfect hash filter will + * generate a WoL interrupt when there is a match + * @param[in] NewState New State of this command, should be: + * - ENABLE + * - DISABLE + * @return None + **********************************************************************/ +void EMAC_SetFilterMode(uint32_t ulFilterMode, FunctionalState NewState) +{ + if (NewState == ENABLE){ + LPC_EMAC->RxFilterCtrl |= ulFilterMode; + } else { + LPC_EMAC->RxFilterCtrl &= ~ulFilterMode; + } +} + +/*********************************************************************//** + * @brief Get status of Wake On LAN Filter for each specified + * type in EMAC peripheral, clear this status if it is set + * @param[in] ulWoLMode WoL Filter mode, should be: + * - EMAC_WOL_UCAST: unicast frames caused WoL + * - EMAC_WOL_UCAST: broadcast frame caused WoL + * - EMAC_WOL_MCAST: multicast frame caused WoL + * - EMAC_WOL_UCAST_HASH: unicast frame that passes the + * imperfect hash filter caused WoL + * - EMAC_WOL_MCAST_HASH: multicast frame that passes the + * imperfect hash filter caused WoL + * - EMAC_WOL_PERFECT:perfect address matching filter + * caused WoL + * - EMAC_WOL_RX_FILTER: the receive filter caused WoL + * - EMAC_WOL_MAG_PACKET: the magic packet filter caused WoL + * @return SET/RESET + **********************************************************************/ +FlagStatus EMAC_GetWoLStatus(uint32_t ulWoLMode) +{ + if (LPC_EMAC->RxFilterWoLStatus & ulWoLMode) { + LPC_EMAC->RxFilterWoLClear = ulWoLMode; + return SET; + } else { + return RESET; + } +} + + +/*********************************************************************//** + * @brief Write data to Tx packet data buffer at current index due to + * TxProduceIndex + * @param[in] pDataStruct Pointer to a EMAC_PACKETBUF_Type structure + * data that contain specified information about + * Packet data buffer. + * @return None + **********************************************************************/ +void EMAC_WritePacketBuffer(EMAC_PACKETBUF_Type *pDataStruct) +{ + uint32_t idx,len; + uint32_t *sp,*dp; + + idx = LPC_EMAC->TxProduceIndex; + sp = (uint32_t *)pDataStruct->pbDataBuf; + dp = (uint32_t *)Tx_Desc[idx].Packet; + /* Copy frame data to EMAC packet buffers. */ + for (len = (pDataStruct->ulDataLen + 3) >> 2; len; len--) { + *dp++ = *sp++; + } + Tx_Desc[idx].Ctrl = (pDataStruct->ulDataLen - 1) | (EMAC_TCTRL_INT | EMAC_TCTRL_LAST); +} + +/*********************************************************************//** + * @brief Read data from Rx packet data buffer at current index due + * to RxConsumeIndex + * @param[in] pDataStruct Pointer to a EMAC_PACKETBUF_Type structure + * data that contain specified information about + * Packet data buffer. + * @return None + **********************************************************************/ +void EMAC_ReadPacketBuffer(EMAC_PACKETBUF_Type *pDataStruct) +{ + uint32_t idx, len; + uint32_t *dp, *sp; + + idx = LPC_EMAC->RxConsumeIndex; + dp = (uint32_t *)pDataStruct->pbDataBuf; + sp = (uint32_t *)Rx_Desc[idx].Packet; + + if (pDataStruct->pbDataBuf != NULL) { + for (len = (pDataStruct->ulDataLen + 3) >> 2; len; len--) { + *dp++ = *sp++; + } + } +} + +/*********************************************************************//** + * @brief Enable/Disable interrupt for each type in EMAC + * @param[in] ulIntType Interrupt Type, should be: + * - EMAC_INT_RX_OVERRUN: Receive Overrun + * - EMAC_INT_RX_ERR: Receive Error + * - EMAC_INT_RX_FIN: Receive Descriptor Finish + * - EMAC_INT_RX_DONE: Receive Done + * - EMAC_INT_TX_UNDERRUN: Transmit Under-run + * - EMAC_INT_TX_ERR: Transmit Error + * - EMAC_INT_TX_FIN: Transmit descriptor finish + * - EMAC_INT_TX_DONE: Transmit Done + * - EMAC_INT_SOFT_INT: Software interrupt + * - EMAC_INT_WAKEUP: Wakeup interrupt + * @param[in] NewState New State of this function, should be: + * - ENABLE. + * - DISABLE. + * @return None + **********************************************************************/ +void EMAC_IntCmd(uint32_t ulIntType, FunctionalState NewState) +{ + if (NewState == ENABLE) { + LPC_EMAC->IntEnable |= ulIntType; + } else { + LPC_EMAC->IntEnable &= ~(ulIntType); + } +} + +/*********************************************************************//** + * @brief Check whether if specified interrupt flag is set or not + * for each interrupt type in EMAC and clear interrupt pending + * if it is set. + * @param[in] ulIntType Interrupt Type, should be: + * - EMAC_INT_RX_OVERRUN: Receive Overrun + * - EMAC_INT_RX_ERR: Receive Error + * - EMAC_INT_RX_FIN: Receive Descriptor Finish + * - EMAC_INT_RX_DONE: Receive Done + * - EMAC_INT_TX_UNDERRUN: Transmit Under-run + * - EMAC_INT_TX_ERR: Transmit Error + * - EMAC_INT_TX_FIN: Transmit descriptor finish + * - EMAC_INT_TX_DONE: Transmit Done + * - EMAC_INT_SOFT_INT: Software interrupt + * - EMAC_INT_WAKEUP: Wakeup interrupt + * @return New state of specified interrupt (SET or RESET) + **********************************************************************/ +IntStatus EMAC_IntGetStatus(uint32_t ulIntType) +{ + if (LPC_EMAC->IntStatus & ulIntType) { + LPC_EMAC->IntClear = ulIntType; + return SET; + } else { + return RESET; + } +} + + +/*********************************************************************//** + * @brief Check whether if the current RxConsumeIndex is not equal to the + * current RxProduceIndex. + * @param[in] None + * @return TRUE if they're not equal, otherwise return FALSE + * + * Note: In case the RxConsumeIndex is not equal to the RxProduceIndex, + * it means there're available data has been received. They should be read + * out and released the Receive Data Buffer by updating the RxConsumeIndex value. + **********************************************************************/ +Bool EMAC_CheckReceiveIndex(void) +{ + if (LPC_EMAC->RxConsumeIndex != LPC_EMAC->RxProduceIndex) { + return TRUE; + } else { + return FALSE; + } +} + + +/*********************************************************************//** + * @brief Check whether if the current TxProduceIndex is not equal to the + * current RxProduceIndex - 1. + * @param[in] None + * @return TRUE if they're not equal, otherwise return FALSE + * + * Note: In case the RxConsumeIndex is equal to the RxProduceIndex - 1, + * it means the transmit buffer is available and data can be written to transmit + * buffer to be sent. + **********************************************************************/ +Bool EMAC_CheckTransmitIndex(void) +{ + uint32_t tmp = LPC_EMAC->TxConsumeIndex -1; + if (LPC_EMAC->TxProduceIndex == tmp) { + return FALSE; + } else { + return TRUE; + } +} + + +/*********************************************************************//** + * @brief Get current status value of receive data (due to RxConsumeIndex) + * @param[in] ulRxStatType Received Status type, should be one of following: + * - EMAC_RINFO_CTRL_FRAME: Control Frame + * - EMAC_RINFO_VLAN: VLAN Frame + * - EMAC_RINFO_FAIL_FILT: RX Filter Failed + * - EMAC_RINFO_MCAST: Multicast Frame + * - EMAC_RINFO_BCAST: Broadcast Frame + * - EMAC_RINFO_CRC_ERR: CRC Error in Frame + * - EMAC_RINFO_SYM_ERR: Symbol Error from PHY + * - EMAC_RINFO_LEN_ERR: Length Error + * - EMAC_RINFO_RANGE_ERR: Range error(exceeded max size) + * - EMAC_RINFO_ALIGN_ERR: Alignment error + * - EMAC_RINFO_OVERRUN: Receive overrun + * - EMAC_RINFO_NO_DESCR: No new Descriptor available + * - EMAC_RINFO_LAST_FLAG: last Fragment in Frame + * - EMAC_RINFO_ERR: Error Occurred (OR of all error) + * @return Current value of receive data (due to RxConsumeIndex) + **********************************************************************/ +FlagStatus EMAC_CheckReceiveDataStatus(uint32_t ulRxStatType) +{ + uint32_t idx; + idx = LPC_EMAC->RxConsumeIndex; + return (((Rx_Stat[idx].Info) & ulRxStatType) ? SET : RESET); +} + + +/*********************************************************************//** + * @brief Get size of current Received data in received buffer (due to + * RxConsumeIndex) + * @param[in] None + * @return Size of received data + **********************************************************************/ +uint32_t EMAC_GetReceiveDataSize(void) +{ + uint32_t idx; + idx =LPC_EMAC->RxConsumeIndex; + return ((Rx_Stat[idx].Info) & EMAC_RINFO_SIZE); +} + +/*********************************************************************//** + * @brief Increase the RxConsumeIndex (after reading the Receive buffer + * to release the Receive buffer) and wrap-around the index if + * it reaches the maximum Receive Number + * @param[in] None + * @return None + **********************************************************************/ +void EMAC_UpdateRxConsumeIndex(void) +{ + // Get current Rx consume index + uint32_t idx = LPC_EMAC->RxConsumeIndex; + + /* Release frame from EMAC buffer */ + if (++idx == EMAC_NUM_RX_FRAG) idx = 0; + LPC_EMAC->RxConsumeIndex = idx; +} + +/*********************************************************************//** + * @brief Increase the TxProduceIndex (after writting to the Transmit buffer + * to enable the Transmit buffer) and wrap-around the index if + * it reaches the maximum Transmit Number + * @param[in] None + * @return None + **********************************************************************/ +void EMAC_UpdateTxProduceIndex(void) +{ + // Get current Tx produce index + uint32_t idx = LPC_EMAC->TxProduceIndex; + + /* Start frame transmission */ + if (++idx == EMAC_NUM_TX_FRAG) idx = 0; + LPC_EMAC->TxProduceIndex = idx; +} + + +/** + * @} + */ + +#endif /* _EMAC */ + +/** + * @} + */ + +/* --------------------------------- End Of File ------------------------------ */ diff --git a/arch/arm/lpc17xx/Drivers/source/lpc17xx_exti.c b/arch/arm/lpc17xx/Drivers/source/lpc17xx_exti.c new file mode 100644 index 0000000..fa06ba7 --- /dev/null +++ b/arch/arm/lpc17xx/Drivers/source/lpc17xx_exti.c @@ -0,0 +1,158 @@ +/** + * @file lpc17xx_exti.c + * @brief Contains all functions support for External interrupt firmware library on LPC17xx + * @version 3.0 + * @date 18. June. 2010 + * @author NXP MCU SW Application Team + ************************************************************************** + * Software that is described herein is for illustrative purposes only + * which provides customers with programming information regarding the + * products. This software is supplied "AS IS" without any warranties. + * NXP Semiconductors assumes no responsibility or liability for the + * use of the software, conveys no license or title under any patent, + * copyright, or mask work right to the product. NXP Semiconductors + * reserves the right to make changes in the software without + * notification. NXP Semiconductors also make no representation or + * warranty that such application will be suitable for the specified + * use without further testing or modification. + **********************************************************************/ + +/* Peripheral group ----------------------------------------------------------- */ +/** @addtogroup EXTI + * @{ + */ + +/* Includes ------------------------------------------------------------------- */ +#include "lpc17xx_exti.h" + +/* If this source file built with example, the LPC17xx FW library configuration + * file in each example directory ("lpc17xx_libcfg.h") must be included, + * otherwise the default FW library configuration file must be included instead + */ +#ifdef __BUILD_WITH_EXAMPLE__ +#include "lpc17xx_libcfg.h" +#else +#include "lpc17xx_libcfg_default.h" +#endif /* __BUILD_WITH_EXAMPLE__ */ + + +#ifdef _EXTI + +/* Public Functions ----------------------------------------------------------- */ +/** @addtogroup EXTI_Public_Functions + * @{ + */ + +/*********************************************************************//** + * @brief Initial for EXT + * - Set EXTINT, EXTMODE, EXTPOLAR registers to default value + * @param[in] None + * @return None + **********************************************************************/ +void EXTI_Init(void) +{ + LPC_SC->EXTINT = 0xF; + LPC_SC->EXTMODE = 0x0; + LPC_SC->EXTPOLAR = 0x0; +} + + +/*********************************************************************//** +* @brief Close EXT +* @param[in] None +* @return None +**********************************************************************/ +void EXTI_DeInit(void) +{ + ; +} + +/*********************************************************************//** + * @brief Configuration for EXT + * - Set EXTINT, EXTMODE, EXTPOLAR register + * @param[in] EXTICfg Pointer to a EXTI_InitTypeDef structure + * that contains the configuration information for the + * specified external interrupt + * @return None + **********************************************************************/ +void EXTI_Config(EXTI_InitTypeDef *EXTICfg) +{ + LPC_SC->EXTINT = 0x0; + EXTI_SetMode(EXTICfg->EXTI_Line, EXTICfg->EXTI_Mode); + EXTI_SetPolarity(EXTICfg->EXTI_Line, EXTICfg->EXTI_polarity); +} + +/*********************************************************************//** +* @brief Set mode for EXTI pin +* @param[in] EXTILine external interrupt line, should be: +* - EXTI_EINT0: external interrupt line 0 +* - EXTI_EINT1: external interrupt line 1 +* - EXTI_EINT2: external interrupt line 2 +* - EXTI_EINT3: external interrupt line 3 +* @param[in] mode external mode, should be: +* - EXTI_MODE_LEVEL_SENSITIVE +* - EXTI_MODE_EDGE_SENSITIVE +* @return None +*********************************************************************/ +void EXTI_SetMode(EXTI_LINE_ENUM EXTILine, EXTI_MODE_ENUM mode) +{ + if(mode == EXTI_MODE_EDGE_SENSITIVE) + { + LPC_SC->EXTMODE |= (1 << EXTILine); + } + else if(mode == EXTI_MODE_LEVEL_SENSITIVE) + { + LPC_SC->EXTMODE &= ~(1 << EXTILine); + } +} + +/*********************************************************************//** +* @brief Set polarity for EXTI pin +* @param[in] EXTILine external interrupt line, should be: +* - EXTI_EINT0: external interrupt line 0 +* - EXTI_EINT1: external interrupt line 1 +* - EXTI_EINT2: external interrupt line 2 +* - EXTI_EINT3: external interrupt line 3 +* @param[in] polarity external polarity value, should be: +* - EXTI_POLARITY_LOW_ACTIVE_OR_FALLING_EDGE +* - EXTI_POLARITY_LOW_ACTIVE_OR_FALLING_EDGE +* @return None +*********************************************************************/ +void EXTI_SetPolarity(EXTI_LINE_ENUM EXTILine, EXTI_POLARITY_ENUM polarity) +{ + if(polarity == EXTI_POLARITY_HIGH_ACTIVE_OR_RISING_EDGE) + { + LPC_SC->EXTPOLAR |= (1 << EXTILine); + } + else if(polarity == EXTI_POLARITY_LOW_ACTIVE_OR_FALLING_EDGE) + { + LPC_SC->EXTPOLAR &= ~(1 << EXTILine); + } +} + +/*********************************************************************//** +* @brief Clear External interrupt flag +* @param[in] EXTILine external interrupt line, should be: +* - EXTI_EINT0: external interrupt line 0 +* - EXTI_EINT1: external interrupt line 1 +* - EXTI_EINT2: external interrupt line 2 +* - EXTI_EINT3: external interrupt line 3 +* @return None +*********************************************************************/ +void EXTI_ClearEXTIFlag(EXTI_LINE_ENUM EXTILine) +{ + LPC_SC->EXTINT |= (1 << EXTILine); +} + +/** + * @} + */ + +#endif /* _EXTI */ + +/** + * @} + */ + +/* --------------------------------- End Of File ------------------------------ */ + diff --git a/arch/arm/lpc17xx/Drivers/source/lpc17xx_gpdma.c b/arch/arm/lpc17xx/Drivers/source/lpc17xx_gpdma.c new file mode 100644 index 0000000..a8a6299 --- /dev/null +++ b/arch/arm/lpc17xx/Drivers/source/lpc17xx_gpdma.c @@ -0,0 +1,450 @@ +/***********************************************************************//** + * @file lpc17xx_gpdma.c + * @brief Contains all functions support for GPDMA firmware library on LPC17xx + * @version 2.0 + * @date 21. May. 2010 + * @author NXP MCU SW Application Team + ************************************************************************** + * Software that is described herein is for illustrative purposes only + * which provides customers with programming information regarding the + * products. This software is supplied "AS IS" without any warranties. + * NXP Semiconductors assumes no responsibility or liability for the + * use of the software, conveys no license or title under any patent, + * copyright, or mask work right to the product. NXP Semiconductors + * reserves the right to make changes in the software without + * notification. NXP Semiconductors also make no representation or + * warranty that such application will be suitable for the specified + * use without further testing or modification. + **********************************************************************/ + +/* Peripheral group ----------------------------------------------------------- */ +/** @addtogroup GPDMA + * @{ + */ + +/* Includes ------------------------------------------------------------------- */ +#include "lpc17xx_gpdma.h" +#include "lpc17xx_clkpwr.h" + +/* If this source file built with example, the LPC17xx FW library configuration + * file in each example directory ("lpc17xx_libcfg.h") must be included, + * otherwise the default FW library configuration file must be included instead + */ +#ifdef __BUILD_WITH_EXAMPLE__ +#include "lpc17xx_libcfg.h" +#else +#include "lpc17xx_libcfg_default.h" +#endif /* __BUILD_WITH_EXAMPLE__ */ + +#ifdef _GPDMA + + +/* Private Variables ---------------------------------------------------------- */ +/** @defgroup GPDMA_Private_Variables GPDMA Private Variables + * @{ + */ + +/** + * @brief Lookup Table of Connection Type matched with + * Peripheral Data (FIFO) register base address + */ +#ifdef __IAR_SYSTEMS_ICC__ +volatile const void *GPDMA_LUTPerAddr[] = { + (&LPC_SSP0->DR), // SSP0 Tx + (&LPC_SSP0->DR), // SSP0 Rx + (&LPC_SSP1->DR), // SSP1 Tx + (&LPC_SSP1->DR), // SSP1 Rx + (&LPC_ADC->ADGDR), // ADC + (&LPC_I2S->I2STXFIFO), // I2S Tx + (&LPC_I2S->I2SRXFIFO), // I2S Rx + (&LPC_DAC->DACR), // DAC + (&LPC_UART0->/*RBTHDLR.*/THR), // UART0 Tx + (&LPC_UART0->/*RBTHDLR.*/RBR), // UART0 Rx + (&LPC_UART1->/*RBTHDLR.*/THR), // UART1 Tx + (&LPC_UART1->/*RBTHDLR.*/RBR), // UART1 Rx + (&LPC_UART2->/*RBTHDLR.*/THR), // UART2 Tx + (&LPC_UART2->/*RBTHDLR.*/RBR), // UART2 Rx + (&LPC_UART3->/*RBTHDLR.*/THR), // UART3 Tx + (&LPC_UART3->/*RBTHDLR.*/RBR), // UART3 Rx + (&LPC_TIM0->MR0), // MAT0.0 + (&LPC_TIM0->MR1), // MAT0.1 + (&LPC_TIM1->MR0), // MAT1.0 + (&LPC_TIM1->MR1), // MAT1.1 + (&LPC_TIM2->MR0), // MAT2.0 + (&LPC_TIM2->MR1), // MAT2.1 + (&LPC_TIM3->MR0), // MAT3.0 + (&LPC_TIM3->MR1), // MAT3.1 +}; +#else +const uint32_t GPDMA_LUTPerAddr[] = { + ((uint32_t)&LPC_SSP0->DR), // SSP0 Tx + ((uint32_t)&LPC_SSP0->DR), // SSP0 Rx + ((uint32_t)&LPC_SSP1->DR), // SSP1 Tx + ((uint32_t)&LPC_SSP1->DR), // SSP1 Rx + ((uint32_t)&LPC_ADC->ADGDR), // ADC + ((uint32_t)&LPC_I2S->I2STXFIFO), // I2S Tx + ((uint32_t)&LPC_I2S->I2SRXFIFO), // I2S Rx + ((uint32_t)&LPC_DAC->DACR), // DAC + ((uint32_t)&LPC_UART0->/*RBTHDLR.*/THR), // UART0 Tx + ((uint32_t)&LPC_UART0->/*RBTHDLR.*/RBR), // UART0 Rx + ((uint32_t)&LPC_UART1->/*RBTHDLR.*/THR), // UART1 Tx + ((uint32_t)&LPC_UART1->/*RBTHDLR.*/RBR), // UART1 Rx + ((uint32_t)&LPC_UART2->/*RBTHDLR.*/THR), // UART2 Tx + ((uint32_t)&LPC_UART2->/*RBTHDLR.*/RBR), // UART2 Rx + ((uint32_t)&LPC_UART3->/*RBTHDLR.*/THR), // UART3 Tx + ((uint32_t)&LPC_UART3->/*RBTHDLR.*/RBR), // UART3 Rx + ((uint32_t)&LPC_TIM0->MR0), // MAT0.0 + ((uint32_t)&LPC_TIM0->MR1), // MAT0.1 + ((uint32_t)&LPC_TIM1->MR0), // MAT1.0 + ((uint32_t)&LPC_TIM1->MR1), // MAT1.1 + ((uint32_t)&LPC_TIM2->MR0), // MAT2.0 + ((uint32_t)&LPC_TIM2->MR1), // MAT2.1 + ((uint32_t)&LPC_TIM3->MR0), // MAT3.0 + ((uint32_t)&LPC_TIM3->MR1), // MAT3.1 +}; +#endif +/** + * @brief Lookup Table of GPDMA Channel Number matched with + * GPDMA channel pointer + */ +const LPC_GPDMACH_TypeDef *pGPDMACh[8] = { + LPC_GPDMACH0, // GPDMA Channel 0 + LPC_GPDMACH1, // GPDMA Channel 1 + LPC_GPDMACH2, // GPDMA Channel 2 + LPC_GPDMACH3, // GPDMA Channel 3 + LPC_GPDMACH4, // GPDMA Channel 4 + LPC_GPDMACH5, // GPDMA Channel 5 + LPC_GPDMACH6, // GPDMA Channel 6 + LPC_GPDMACH7, // GPDMA Channel 7 +}; +/** + * @brief Optimized Peripheral Source and Destination burst size + */ +const uint8_t GPDMA_LUTPerBurst[] = { + GPDMA_BSIZE_4, // SSP0 Tx + GPDMA_BSIZE_4, // SSP0 Rx + GPDMA_BSIZE_4, // SSP1 Tx + GPDMA_BSIZE_4, // SSP1 Rx + GPDMA_BSIZE_4, // ADC + GPDMA_BSIZE_32, // I2S channel 0 + GPDMA_BSIZE_32, // I2S channel 1 + GPDMA_BSIZE_1, // DAC + GPDMA_BSIZE_1, // UART0 Tx + GPDMA_BSIZE_1, // UART0 Rx + GPDMA_BSIZE_1, // UART1 Tx + GPDMA_BSIZE_1, // UART1 Rx + GPDMA_BSIZE_1, // UART2 Tx + GPDMA_BSIZE_1, // UART2 Rx + GPDMA_BSIZE_1, // UART3 Tx + GPDMA_BSIZE_1, // UART3 Rx + GPDMA_BSIZE_1, // MAT0.0 + GPDMA_BSIZE_1, // MAT0.1 + GPDMA_BSIZE_1, // MAT1.0 + GPDMA_BSIZE_1, // MAT1.1 + GPDMA_BSIZE_1, // MAT2.0 + GPDMA_BSIZE_1, // MAT2.1 + GPDMA_BSIZE_1, // MAT3.0 + GPDMA_BSIZE_1, // MAT3.1 +}; +/** + * @brief Optimized Peripheral Source and Destination transfer width + */ +const uint8_t GPDMA_LUTPerWid[] = { + GPDMA_WIDTH_BYTE, // SSP0 Tx + GPDMA_WIDTH_BYTE, // SSP0 Rx + GPDMA_WIDTH_BYTE, // SSP1 Tx + GPDMA_WIDTH_BYTE, // SSP1 Rx + GPDMA_WIDTH_WORD, // ADC + GPDMA_WIDTH_WORD, // I2S channel 0 + GPDMA_WIDTH_WORD, // I2S channel 1 + GPDMA_WIDTH_BYTE, // DAC + GPDMA_WIDTH_BYTE, // UART0 Tx + GPDMA_WIDTH_BYTE, // UART0 Rx + GPDMA_WIDTH_BYTE, // UART1 Tx + GPDMA_WIDTH_BYTE, // UART1 Rx + GPDMA_WIDTH_BYTE, // UART2 Tx + GPDMA_WIDTH_BYTE, // UART2 Rx + GPDMA_WIDTH_BYTE, // UART3 Tx + GPDMA_WIDTH_BYTE, // UART3 Rx + GPDMA_WIDTH_WORD, // MAT0.0 + GPDMA_WIDTH_WORD, // MAT0.1 + GPDMA_WIDTH_WORD, // MAT1.0 + GPDMA_WIDTH_WORD, // MAT1.1 + GPDMA_WIDTH_WORD, // MAT2.0 + GPDMA_WIDTH_WORD, // MAT2.1 + GPDMA_WIDTH_WORD, // MAT3.0 + GPDMA_WIDTH_WORD, // MAT3.1 +}; + +/** + * @} + */ + +/* Public Functions ----------------------------------------------------------- */ +/** @addtogroup GPDMA_Public_Functions + * @{ + */ + +/********************************************************************//** + * @brief Initialize GPDMA controller + * @param None + * @return None + *********************************************************************/ +void GPDMA_Init(void) +{ + /* Enable GPDMA clock */ + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCGPDMA, ENABLE); + + // Reset all channel configuration register + LPC_GPDMACH0->DMACCConfig = 0; + LPC_GPDMACH1->DMACCConfig = 0; + LPC_GPDMACH2->DMACCConfig = 0; + LPC_GPDMACH3->DMACCConfig = 0; + LPC_GPDMACH4->DMACCConfig = 0; + LPC_GPDMACH5->DMACCConfig = 0; + LPC_GPDMACH6->DMACCConfig = 0; + LPC_GPDMACH7->DMACCConfig = 0; + + /* Clear all DMA interrupt and error flag */ + LPC_GPDMA->DMACIntTCClear = 0xFF; + LPC_GPDMA->DMACIntErrClr = 0xFF; +} + +/********************************************************************//** + * @brief Setup GPDMA channel peripheral according to the specified + * parameters in the GPDMAChannelConfig. + * @param[in] GPDMAChannelConfig Pointer to a GPDMA_CH_CFG_Type + * structure that contains the configuration + * information for the specified GPDMA channel peripheral. + * @return ERROR if selected channel is enabled before + * or SUCCESS if channel is configured successfully + *********************************************************************/ +Status GPDMA_Setup(GPDMA_Channel_CFG_Type *GPDMAChannelConfig) +{ + LPC_GPDMACH_TypeDef *pDMAch; + uint32_t tmp1, tmp2; + + if (LPC_GPDMA->DMACEnbldChns & (GPDMA_DMACEnbldChns_Ch(GPDMAChannelConfig->ChannelNum))) { + // This channel is enabled, return ERROR, need to release this channel first + return ERROR; + } + + // Get Channel pointer + pDMAch = (LPC_GPDMACH_TypeDef *) pGPDMACh[GPDMAChannelConfig->ChannelNum]; + + // Reset the Interrupt status + LPC_GPDMA->DMACIntTCClear = GPDMA_DMACIntTCClear_Ch(GPDMAChannelConfig->ChannelNum); + LPC_GPDMA->DMACIntErrClr = GPDMA_DMACIntErrClr_Ch(GPDMAChannelConfig->ChannelNum); + + // Clear DMA configure + pDMAch->DMACCControl = 0x00; + pDMAch->DMACCConfig = 0x00; + + /* Assign Linker List Item value */ + pDMAch->DMACCLLI = GPDMAChannelConfig->DMALLI; + + /* Set value to Channel Control Registers */ + switch (GPDMAChannelConfig->TransferType) + { + // Memory to memory + case GPDMA_TRANSFERTYPE_M2M: + // Assign physical source and destination address + pDMAch->DMACCSrcAddr = GPDMAChannelConfig->SrcMemAddr; + pDMAch->DMACCDestAddr = GPDMAChannelConfig->DstMemAddr; + pDMAch->DMACCControl + = GPDMA_DMACCxControl_TransferSize(GPDMAChannelConfig->TransferSize) \ + | GPDMA_DMACCxControl_SBSize(GPDMA_BSIZE_32) \ + | GPDMA_DMACCxControl_DBSize(GPDMA_BSIZE_32) \ + | GPDMA_DMACCxControl_SWidth(GPDMAChannelConfig->TransferWidth) \ + | GPDMA_DMACCxControl_DWidth(GPDMAChannelConfig->TransferWidth) \ + | GPDMA_DMACCxControl_SI \ + | GPDMA_DMACCxControl_DI \ + | GPDMA_DMACCxControl_I; + break; + // Memory to peripheral + case GPDMA_TRANSFERTYPE_M2P: + // Assign physical source + pDMAch->DMACCSrcAddr = GPDMAChannelConfig->SrcMemAddr; + // Assign peripheral destination address + pDMAch->DMACCDestAddr = (uint32_t)GPDMA_LUTPerAddr[GPDMAChannelConfig->DstConn]; + pDMAch->DMACCControl + = GPDMA_DMACCxControl_TransferSize((uint32_t)GPDMAChannelConfig->TransferSize) \ + | GPDMA_DMACCxControl_SBSize((uint32_t)GPDMA_LUTPerBurst[GPDMAChannelConfig->DstConn]) \ + | GPDMA_DMACCxControl_DBSize((uint32_t)GPDMA_LUTPerBurst[GPDMAChannelConfig->DstConn]) \ + | GPDMA_DMACCxControl_SWidth((uint32_t)GPDMA_LUTPerWid[GPDMAChannelConfig->DstConn]) \ + | GPDMA_DMACCxControl_DWidth((uint32_t)GPDMA_LUTPerWid[GPDMAChannelConfig->DstConn]) \ + | GPDMA_DMACCxControl_SI \ + | GPDMA_DMACCxControl_I; + break; + // Peripheral to memory + case GPDMA_TRANSFERTYPE_P2M: + // Assign peripheral source address + pDMAch->DMACCSrcAddr = (uint32_t)GPDMA_LUTPerAddr[GPDMAChannelConfig->SrcConn]; + // Assign memory destination address + pDMAch->DMACCDestAddr = GPDMAChannelConfig->DstMemAddr; + pDMAch->DMACCControl + = GPDMA_DMACCxControl_TransferSize((uint32_t)GPDMAChannelConfig->TransferSize) \ + | GPDMA_DMACCxControl_SBSize((uint32_t)GPDMA_LUTPerBurst[GPDMAChannelConfig->SrcConn]) \ + | GPDMA_DMACCxControl_DBSize((uint32_t)GPDMA_LUTPerBurst[GPDMAChannelConfig->SrcConn]) \ + | GPDMA_DMACCxControl_SWidth((uint32_t)GPDMA_LUTPerWid[GPDMAChannelConfig->SrcConn]) \ + | GPDMA_DMACCxControl_DWidth((uint32_t)GPDMA_LUTPerWid[GPDMAChannelConfig->SrcConn]) \ + | GPDMA_DMACCxControl_DI \ + | GPDMA_DMACCxControl_I; + break; + // Peripheral to peripheral + case GPDMA_TRANSFERTYPE_P2P: + // Assign peripheral source address + pDMAch->DMACCSrcAddr = (uint32_t)GPDMA_LUTPerAddr[GPDMAChannelConfig->SrcConn]; + // Assign peripheral destination address + pDMAch->DMACCDestAddr = (uint32_t)GPDMA_LUTPerAddr[GPDMAChannelConfig->DstConn]; + pDMAch->DMACCControl + = GPDMA_DMACCxControl_TransferSize((uint32_t)GPDMAChannelConfig->TransferSize) \ + | GPDMA_DMACCxControl_SBSize((uint32_t)GPDMA_LUTPerBurst[GPDMAChannelConfig->SrcConn]) \ + | GPDMA_DMACCxControl_DBSize((uint32_t)GPDMA_LUTPerBurst[GPDMAChannelConfig->DstConn]) \ + | GPDMA_DMACCxControl_SWidth((uint32_t)GPDMA_LUTPerWid[GPDMAChannelConfig->SrcConn]) \ + | GPDMA_DMACCxControl_DWidth((uint32_t)GPDMA_LUTPerWid[GPDMAChannelConfig->DstConn]) \ + | GPDMA_DMACCxControl_I; + break; + // Do not support any more transfer type, return ERROR + default: + return ERROR; + } + + /* Re-Configure DMA Request Select for source peripheral */ + if (GPDMAChannelConfig->SrcConn > 15) + { + DMAREQSEL |= (1<<(GPDMAChannelConfig->SrcConn - 16)); + } else { + DMAREQSEL &= ~(1<<(GPDMAChannelConfig->SrcConn - 8)); + } + + /* Re-Configure DMA Request Select for Destination peripheral */ + if (GPDMAChannelConfig->DstConn > 15) + { + DMAREQSEL |= (1<<(GPDMAChannelConfig->DstConn - 16)); + } else { + DMAREQSEL &= ~(1<<(GPDMAChannelConfig->DstConn - 8)); + } + + /* Enable DMA channels, little endian */ + LPC_GPDMA->DMACConfig = GPDMA_DMACConfig_E; + while (!(LPC_GPDMA->DMACConfig & GPDMA_DMACConfig_E)); + + // Calculate absolute value for Connection number + tmp1 = GPDMAChannelConfig->SrcConn; + tmp1 = ((tmp1 > 15) ? (tmp1 - 8) : tmp1); + tmp2 = GPDMAChannelConfig->DstConn; + tmp2 = ((tmp2 > 15) ? (tmp2 - 8) : tmp2); + + // Configure DMA Channel, enable Error Counter and Terminate counter + pDMAch->DMACCConfig = GPDMA_DMACCxConfig_IE | GPDMA_DMACCxConfig_ITC /*| GPDMA_DMACCxConfig_E*/ \ + | GPDMA_DMACCxConfig_TransferType((uint32_t)GPDMAChannelConfig->TransferType) \ + | GPDMA_DMACCxConfig_SrcPeripheral(tmp1) \ + | GPDMA_DMACCxConfig_DestPeripheral(tmp2); + + return SUCCESS; +} + + +/*********************************************************************//** + * @brief Enable/Disable DMA channel + * @param[in] channelNum GPDMA channel, should be in range from 0 to 7 + * @param[in] NewState New State of this command, should be: + * - ENABLE. + * - DISABLE. + * @return None + **********************************************************************/ +void GPDMA_ChannelCmd(uint8_t channelNum, FunctionalState NewState) +{ + LPC_GPDMACH_TypeDef *pDMAch; + + // Get Channel pointer + pDMAch = (LPC_GPDMACH_TypeDef *) pGPDMACh[channelNum]; + + if (NewState == ENABLE) { + pDMAch->DMACCConfig |= GPDMA_DMACCxConfig_E; + } else { + pDMAch->DMACCConfig &= ~GPDMA_DMACCxConfig_E; + } +} +/*********************************************************************//** + * @brief Check if corresponding channel does have an active interrupt + * request or not + * @param[in] type type of status, should be: + * - GPDMA_STAT_INT: GPDMA Interrupt Status + * - GPDMA_STAT_INTTC: GPDMA Interrupt Terminal Count Request Status + * - GPDMA_STAT_INTERR: GPDMA Interrupt Error Status + * - GPDMA_STAT_RAWINTTC: GPDMA Raw Interrupt Terminal Count Status + * - GPDMA_STAT_RAWINTERR: GPDMA Raw Error Interrupt Status + * - GPDMA_STAT_ENABLED_CH:GPDMA Enabled Channel Status + * @param[in] channel GPDMA channel, should be in range from 0 to 7 + * @return IntStatus status of DMA channel interrupt after masking + * Should be: + * - SET: the corresponding channel has no active interrupt request + * - RESET: the corresponding channel does have an active interrupt request + **********************************************************************/ +IntStatus GPDMA_IntGetStatus(GPDMA_Status_Type type, uint8_t channel) +{ + CHECK_PARAM(PARAM_GPDMA_STAT(type)); + CHECK_PARAM(PARAM_GPDMA_CHANNEL(channel)); + + switch (type) + { + case GPDMA_STAT_INT: //check status of DMA channel interrupts + if (LPC_GPDMA->DMACIntStat & (GPDMA_DMACIntStat_Ch(channel))) + return SET; + return RESET; + case GPDMA_STAT_INTTC: // check terminal count interrupt request status for DMA + if (LPC_GPDMA->DMACIntTCStat & GPDMA_DMACIntTCStat_Ch(channel)) + return SET; + return RESET; + case GPDMA_STAT_INTERR: //check interrupt status for DMA channels + if (LPC_GPDMA->DMACIntErrStat & GPDMA_DMACIntTCClear_Ch(channel)) + return SET; + return RESET; + case GPDMA_STAT_RAWINTTC: //check status of the terminal count interrupt for DMA channels + if (LPC_GPDMA->DMACRawIntErrStat & GPDMA_DMACRawIntTCStat_Ch(channel)) + return SET; + return RESET; + case GPDMA_STAT_RAWINTERR: //check status of the error interrupt for DMA channels + if (LPC_GPDMA->DMACRawIntTCStat & GPDMA_DMACRawIntErrStat_Ch(channel)) + return SET; + return RESET; + default: //check enable status for DMA channels + if (LPC_GPDMA->DMACEnbldChns & GPDMA_DMACEnbldChns_Ch(channel)) + return SET; + return RESET; + } +} + +/*********************************************************************//** + * @brief Clear one or more interrupt requests on DMA channels + * @param[in] type type of interrupt request, should be: + * - GPDMA_STATCLR_INTTC: GPDMA Interrupt Terminal Count Request Clear + * - GPDMA_STATCLR_INTERR: GPDMA Interrupt Error Clear + * @param[in] channel GPDMA channel, should be in range from 0 to 7 + * @return None + **********************************************************************/ +void GPDMA_ClearIntPending(GPDMA_StateClear_Type type, uint8_t channel) +{ + CHECK_PARAM(PARAM_GPDMA_STATCLR(type)); + CHECK_PARAM(PARAM_GPDMA_CHANNEL(channel)); + + if (type == GPDMA_STATCLR_INTTC) // clears the terminal count interrupt request on DMA channel + LPC_GPDMA->DMACIntTCClear = GPDMA_DMACIntTCClear_Ch(channel); + else // clear the error interrupt request + LPC_GPDMA->DMACIntErrClr = GPDMA_DMACIntErrClr_Ch(channel); +} + +/** + * @} + */ + +#endif /* _GPDMA */ + +/** + * @} + */ + +/* --------------------------------- End Of File ------------------------------ */ + diff --git a/arch/arm/lpc17xx/Drivers/source/lpc17xx_gpio.c b/arch/arm/lpc17xx/Drivers/source/lpc17xx_gpio.c new file mode 100644 index 0000000..8c037c6 --- /dev/null +++ b/arch/arm/lpc17xx/Drivers/source/lpc17xx_gpio.c @@ -0,0 +1,749 @@ +/***********************************************************************//** + * @file lpc17xx_gpio.c + * @brief Contains all functions support for GPIO firmware library on LPC17xx + * @version 2.0 + * @date 21. May. 2010 + * @author NXP MCU SW Application Team + ************************************************************************** + * Software that is described herein is for illustrative purposes only + * which provides customers with programming information regarding the + * products. This software is supplied "AS IS" without any warranties. + * NXP Semiconductors assumes no responsibility or liability for the + * use of the software, conveys no license or title under any patent, + * copyright, or mask work right to the product. NXP Semiconductors + * reserves the right to make changes in the software without + * notification. NXP Semiconductors also make no representation or + * warranty that such application will be suitable for the specified + * use without further testing or modification. + **********************************************************************/ + +/* Peripheral group ----------------------------------------------------------- */ +/** @addtogroup GPIO + * @{ + */ + +/* Includes ------------------------------------------------------------------- */ +#include "lpc17xx_gpio.h" + +/* If this source file built with example, the LPC17xx FW library configuration + * file in each example directory ("lpc17xx_libcfg.h") must be included, + * otherwise the default FW library configuration file must be included instead + */ +#ifdef __BUILD_WITH_EXAMPLE__ +#include "lpc17xx_libcfg.h" +#else +#include "lpc17xx_libcfg_default.h" +#endif /* __BUILD_WITH_EXAMPLE__ */ + + +#ifdef _GPIO + +/* Private Functions ---------------------------------------------------------- */ + +static LPC_GPIO_TypeDef *GPIO_GetPointer(uint8_t portNum); +static GPIO_HalfWord_TypeDef *FIO_HalfWordGetPointer(uint8_t portNum); +static GPIO_Byte_TypeDef *FIO_ByteGetPointer(uint8_t portNum); + +/*********************************************************************//** + * @brief Get pointer to GPIO peripheral due to GPIO port + * @param[in] portNum Port Number value, should be in range from 0 to 4. + * @return Pointer to GPIO peripheral + **********************************************************************/ +static LPC_GPIO_TypeDef *GPIO_GetPointer(uint8_t portNum) +{ + LPC_GPIO_TypeDef *pGPIO = NULL; + + switch (portNum) { + case 0: + pGPIO = LPC_GPIO0; + break; + case 1: + pGPIO = LPC_GPIO1; + break; + case 2: + pGPIO = LPC_GPIO2; + break; + case 3: + pGPIO = LPC_GPIO3; + break; + case 4: + pGPIO = LPC_GPIO4; + break; + default: + break; + } + + return pGPIO; +} + +/*********************************************************************//** + * @brief Get pointer to FIO peripheral in halfword accessible style + * due to FIO port + * @param[in] portNum Port Number value, should be in range from 0 to 4. + * @return Pointer to FIO peripheral + **********************************************************************/ +static GPIO_HalfWord_TypeDef *FIO_HalfWordGetPointer(uint8_t portNum) +{ + GPIO_HalfWord_TypeDef *pFIO = NULL; + + switch (portNum) { + case 0: + pFIO = GPIO0_HalfWord; + break; + case 1: + pFIO = GPIO1_HalfWord; + break; + case 2: + pFIO = GPIO2_HalfWord; + break; + case 3: + pFIO = GPIO3_HalfWord; + break; + case 4: + pFIO = GPIO4_HalfWord; + break; + default: + break; + } + + return pFIO; +} + +/*********************************************************************//** + * @brief Get pointer to FIO peripheral in byte accessible style + * due to FIO port + * @param[in] portNum Port Number value, should be in range from 0 to 4. + * @return Pointer to FIO peripheral + **********************************************************************/ +static GPIO_Byte_TypeDef *FIO_ByteGetPointer(uint8_t portNum) +{ + GPIO_Byte_TypeDef *pFIO = NULL; + + switch (portNum) { + case 0: + pFIO = GPIO0_Byte; + break; + case 1: + pFIO = GPIO1_Byte; + break; + case 2: + pFIO = GPIO2_Byte; + break; + case 3: + pFIO = GPIO3_Byte; + break; + case 4: + pFIO = GPIO4_Byte; + break; + default: + break; + } + + return pFIO; +} + +/* End of Private Functions --------------------------------------------------- */ + + +/* Public Functions ----------------------------------------------------------- */ +/** @addtogroup GPIO_Public_Functions + * @{ + */ + + +/* GPIO ------------------------------------------------------------------------------ */ + +/*********************************************************************//** + * @brief Set Direction for GPIO port. + * @param[in] portNum Port Number value, should be in range from 0 to 4 + * @param[in] bitValue Value that contains all bits to set direction, + * in range from 0 to 0xFFFFFFFF. + * example: value 0x5 to set direction for bit 0 and bit 1. + * @param[in] dir Direction value, should be: + * - 0: Input. + * - 1: Output. + * @return None + * + * Note: All remaining bits that are not activated in bitValue (value '0') + * will not be effected by this function. + **********************************************************************/ +void GPIO_SetDir(uint8_t portNum, uint32_t bitValue, uint8_t dir) +{ + LPC_GPIO_TypeDef *pGPIO = GPIO_GetPointer(portNum); + + if (pGPIO != NULL) { + // Enable Output + if (dir) { + pGPIO->FIODIR |= bitValue; + } + // Enable Input + else { + pGPIO->FIODIR &= ~bitValue; + } + } +} + + +/*********************************************************************//** + * @brief Set Value for bits that have output direction on GPIO port. + * @param[in] portNum Port number value, should be in range from 0 to 4 + * @param[in] bitValue Value that contains all bits on GPIO to set, + * in range from 0 to 0xFFFFFFFF. + * example: value 0x5 to set bit 0 and bit 1. + * @return None + * + * Note: + * - For all bits that has been set as input direction, this function will + * not effect. + * - For all remaining bits that are not activated in bitValue (value '0') + * will not be effected by this function. + **********************************************************************/ +void GPIO_SetValue(uint8_t portNum, uint32_t bitValue) +{ + LPC_GPIO_TypeDef *pGPIO = GPIO_GetPointer(portNum); + + if (pGPIO != NULL) { + pGPIO->FIOSET = bitValue; + } +} + +/*********************************************************************//** + * @brief Clear Value for bits that have output direction on GPIO port. + * @param[in] portNum Port number value, should be in range from 0 to 4 + * @param[in] bitValue Value that contains all bits on GPIO to clear, + * in range from 0 to 0xFFFFFFFF. + * example: value 0x5 to clear bit 0 and bit 1. + * @return None + * + * Note: + * - For all bits that has been set as input direction, this function will + * not effect. + * - For all remaining bits that are not activated in bitValue (value '0') + * will not be effected by this function. + **********************************************************************/ +void GPIO_ClearValue(uint8_t portNum, uint32_t bitValue) +{ + LPC_GPIO_TypeDef *pGPIO = GPIO_GetPointer(portNum); + + if (pGPIO != NULL) { + pGPIO->FIOCLR = bitValue; + } +} + +/*********************************************************************//** + * @brief Read Current state on port pin that have input direction of GPIO + * @param[in] portNum Port number to read value, in range from 0 to 4 + * @return Current value of GPIO port. + * + * Note: Return value contain state of each port pin (bit) on that GPIO regardless + * its direction is input or output. + **********************************************************************/ +uint32_t GPIO_ReadValue(uint8_t portNum) +{ + LPC_GPIO_TypeDef *pGPIO = GPIO_GetPointer(portNum); + + if (pGPIO != NULL) { + return pGPIO->FIOPIN; + } + + return (0); +} + +/*********************************************************************//** + * @brief Enable GPIO interrupt (just used for P0.0-P0.30, P2.0-P2.13) + * @param[in] portNum Port number to read value, should be: 0 or 2 + * @param[in] bitValue Value that contains all bits on GPIO to enable, + * in range from 0 to 0xFFFFFFFF. + * @param[in] edgeState state of edge, should be: + * - 0: Rising edge + * - 1: Falling edge + * @return None + **********************************************************************/ +void GPIO_IntCmd(uint8_t portNum, uint32_t bitValue, uint8_t edgeState) +{ + if((portNum == 0)&&(edgeState == 0)) + LPC_GPIOINT->IO0IntEnR = bitValue; + else if ((portNum == 2)&&(edgeState == 0)) + LPC_GPIOINT->IO2IntEnR = bitValue; + else if ((portNum == 0)&&(edgeState == 1)) + LPC_GPIOINT->IO0IntEnF = bitValue; + else if ((portNum == 2)&&(edgeState == 1)) + LPC_GPIOINT->IO2IntEnF = bitValue; + else + //Error + while(1); +} + +/*********************************************************************//** + * @brief Get GPIO Interrupt Status (just used for P0.0-P0.30, P2.0-P2.13) + * @param[in] portNum Port number to read value, should be: 0 or 2 + * @param[in] pinNum Pin number, should be: 0..30(with port 0) and 0..13 + * (with port 2) + * @param[in] edgeState state of edge, should be: + * - 0: Rising edge + * - 1: Falling edge + * @return Bool could be: + * - ENABLE: Interrupt has been generated due to a rising + * edge on P0.0 + * - DISABLE: A rising edge has not been detected on P0.0 + **********************************************************************/ +FunctionalState GPIO_GetIntStatus(uint8_t portNum, uint32_t pinNum, uint8_t edgeState) +{ + if((portNum == 0) && (edgeState == 0))//Rising Edge + return (((LPC_GPIOINT->IO0IntStatR)>>pinNum)& 0x1); + else if ((portNum == 2) && (edgeState == 0)) + return (((LPC_GPIOINT->IO2IntStatR)>>pinNum)& 0x1); + else if ((portNum == 0) && (edgeState == 1))//Falling Edge + return (((LPC_GPIOINT->IO0IntStatF)>>pinNum)& 0x1); + else if ((portNum == 2) && (edgeState == 1)) + return (((LPC_GPIOINT->IO2IntStatF)>>pinNum)& 0x1); + else + //Error + while(1); +} +/*********************************************************************//** + * @brief Clear GPIO interrupt (just used for P0.0-P0.30, P2.0-P2.13) + * @param[in] portNum Port number to read value, should be: 0 or 2 + * @param[in] bitValue Value that contains all bits on GPIO to enable, + * in range from 0 to 0xFFFFFFFF. + * @return None + **********************************************************************/ +void GPIO_ClearInt(uint8_t portNum, uint32_t bitValue) +{ + if(portNum == 0) + LPC_GPIOINT->IO0IntClr = bitValue; + else if (portNum == 2) + LPC_GPIOINT->IO2IntClr = bitValue; + else + //Invalid portNum + while(1); +} + +/* FIO word accessible ----------------------------------------------------------------- */ +/* Stub function for FIO (word-accessible) style */ + +/** + * @brief The same with GPIO_SetDir() + */ +void FIO_SetDir(uint8_t portNum, uint32_t bitValue, uint8_t dir) +{ + GPIO_SetDir(portNum, bitValue, dir); +} + +/** + * @brief The same with GPIO_SetValue() + */ +void FIO_SetValue(uint8_t portNum, uint32_t bitValue) +{ + GPIO_SetValue(portNum, bitValue); +} + +/** + * @brief The same with GPIO_ClearValue() + */ +void FIO_ClearValue(uint8_t portNum, uint32_t bitValue) +{ + GPIO_ClearValue(portNum, bitValue); +} + +/** + * @brief The same with GPIO_ReadValue() + */ +uint32_t FIO_ReadValue(uint8_t portNum) +{ + return (GPIO_ReadValue(portNum)); +} + +/** + * @brief The same with GPIO_IntCmd() + */ +void FIO_IntCmd(uint8_t portNum, uint32_t bitValue, uint8_t edgeState) +{ + GPIO_IntCmd(portNum, bitValue, edgeState); +} + +/** + * @brief The same with GPIO_GetIntStatus() + */ +FunctionalState FIO_GetIntStatus(uint8_t portNum, uint32_t pinNum, uint8_t edgeState) +{ + return (GPIO_GetIntStatus(portNum, pinNum, edgeState)); +} + +/** + * @brief The same with GPIO_ClearInt() + */ +void FIO_ClearInt(uint8_t portNum, uint32_t bitValue) +{ + GPIO_ClearInt(portNum, bitValue); +} +/*********************************************************************//** + * @brief Set mask value for bits in FIO port + * @param[in] portNum Port number, in range from 0 to 4 + * @param[in] bitValue Value that contains all bits in to set, + * in range from 0 to 0xFFFFFFFF. + * @param[in] maskValue Mask value contains state value for each bit: + * - 0: not mask. + * - 1: mask. + * @return None + * + * Note: + * - All remaining bits that are not activated in bitValue (value '0') + * will not be effected by this function. + * - After executing this function, in mask register, value '0' on each bit + * enables an access to the corresponding physical pin via a read or write access, + * while value '1' on bit (masked) that corresponding pin will not be changed + * with write access and if read, will not be reflected in the updated pin. + **********************************************************************/ +void FIO_SetMask(uint8_t portNum, uint32_t bitValue, uint8_t maskValue) +{ + LPC_GPIO_TypeDef *pFIO = GPIO_GetPointer(portNum); + if(pFIO != NULL) { + // Mask + if (maskValue){ + pFIO->FIOMASK |= bitValue; + } + // Un-mask + else { + pFIO->FIOMASK &= ~bitValue; + } + } +} + + +/* FIO halfword accessible ------------------------------------------------------------- */ + +/*********************************************************************//** + * @brief Set direction for FIO port in halfword accessible style + * @param[in] portNum Port number, in range from 0 to 4 + * @param[in] halfwordNum HalfWord part number, should be 0 (lower) or 1(upper) + * @param[in] bitValue Value that contains all bits in to set direction, + * in range from 0 to 0xFFFF. + * @param[in] dir Direction value, should be: + * - 0: Input. + * - 1: Output. + * @return None + * + * Note: All remaining bits that are not activated in bitValue (value '0') + * will not be effected by this function. + **********************************************************************/ +void FIO_HalfWordSetDir(uint8_t portNum, uint8_t halfwordNum, uint16_t bitValue, uint8_t dir) +{ + GPIO_HalfWord_TypeDef *pFIO = FIO_HalfWordGetPointer(portNum); + if(pFIO != NULL) { + // Output direction + if (dir) { + // Upper + if(halfwordNum) { + pFIO->FIODIRU |= bitValue; + } + // lower + else { + pFIO->FIODIRL |= bitValue; + } + } + // Input direction + else { + // Upper + if(halfwordNum) { + pFIO->FIODIRU &= ~bitValue; + } + // lower + else { + pFIO->FIODIRL &= ~bitValue; + } + } + } +} + + +/*********************************************************************//** + * @brief Set mask value for bits in FIO port in halfword accessible style + * @param[in] portNum Port number, in range from 0 to 4 + * @param[in] halfwordNum HalfWord part number, should be 0 (lower) or 1(upper) + * @param[in] bitValue Value that contains all bits in to set, + * in range from 0 to 0xFFFF. + * @param[in] maskValue Mask value contains state value for each bit: + * - 0: not mask. + * - 1: mask. + * @return None + * + * Note: + * - All remaining bits that are not activated in bitValue (value '0') + * will not be effected by this function. + * - After executing this function, in mask register, value '0' on each bit + * enables an access to the corresponding physical pin via a read or write access, + * while value '1' on bit (masked) that corresponding pin will not be changed + * with write access and if read, will not be reflected in the updated pin. + **********************************************************************/ +void FIO_HalfWordSetMask(uint8_t portNum, uint8_t halfwordNum, uint16_t bitValue, uint8_t maskValue) +{ + GPIO_HalfWord_TypeDef *pFIO = FIO_HalfWordGetPointer(portNum); + if(pFIO != NULL) { + // Mask + if (maskValue){ + // Upper + if(halfwordNum) { + pFIO->FIOMASKU |= bitValue; + } + // lower + else { + pFIO->FIOMASKL |= bitValue; + } + } + // Un-mask + else { + // Upper + if(halfwordNum) { + pFIO->FIOMASKU &= ~bitValue; + } + // lower + else { + pFIO->FIOMASKL &= ~bitValue; + } + } + } +} + + +/*********************************************************************//** + * @brief Set bits for FIO port in halfword accessible style + * @param[in] portNum Port number, in range from 0 to 4 + * @param[in] halfwordNum HalfWord part number, should be 0 (lower) or 1(upper) + * @param[in] bitValue Value that contains all bits in to set, + * in range from 0 to 0xFFFF. + * @return None + * + * Note: + * - For all bits that has been set as input direction, this function will + * not effect. + * - For all remaining bits that are not activated in bitValue (value '0') + * will not be effected by this function. + **********************************************************************/ +void FIO_HalfWordSetValue(uint8_t portNum, uint8_t halfwordNum, uint16_t bitValue) +{ + GPIO_HalfWord_TypeDef *pFIO = FIO_HalfWordGetPointer(portNum); + if(pFIO != NULL) { + // Upper + if(halfwordNum) { + pFIO->FIOSETU = bitValue; + } + // lower + else { + pFIO->FIOSETL = bitValue; + } + } +} + + +/*********************************************************************//** + * @brief Clear bits for FIO port in halfword accessible style + * @param[in] portNum Port number, in range from 0 to 4 + * @param[in] halfwordNum HalfWord part number, should be 0 (lower) or 1(upper) + * @param[in] bitValue Value that contains all bits in to clear, + * in range from 0 to 0xFFFF. + * @return None + * + * Note: + * - For all bits that has been set as input direction, this function will + * not effect. + * - For all remaining bits that are not activated in bitValue (value '0') + * will not be effected by this function. + **********************************************************************/ +void FIO_HalfWordClearValue(uint8_t portNum, uint8_t halfwordNum, uint16_t bitValue) +{ + GPIO_HalfWord_TypeDef *pFIO = FIO_HalfWordGetPointer(portNum); + if(pFIO != NULL) { + // Upper + if(halfwordNum) { + pFIO->FIOCLRU = bitValue; + } + // lower + else { + pFIO->FIOCLRL = bitValue; + } + } +} + + +/*********************************************************************//** + * @brief Read Current state on port pin that have input direction of GPIO + * in halfword accessible style. + * @param[in] portNum Port number, in range from 0 to 4 + * @param[in] halfwordNum HalfWord part number, should be 0 (lower) or 1(upper) + * @return Current value of FIO port pin of specified halfword. + * Note: Return value contain state of each port pin (bit) on that FIO regardless + * its direction is input or output. + **********************************************************************/ +uint16_t FIO_HalfWordReadValue(uint8_t portNum, uint8_t halfwordNum) +{ + GPIO_HalfWord_TypeDef *pFIO = FIO_HalfWordGetPointer(portNum); + if(pFIO != NULL) { + // Upper + if(halfwordNum) { + return (pFIO->FIOPINU); + } + // lower + else { + return (pFIO->FIOPINL); + } + } + return (0); +} + + +/* FIO Byte accessible ------------------------------------------------------------ */ + +/*********************************************************************//** + * @brief Set direction for FIO port in byte accessible style + * @param[in] portNum Port number, in range from 0 to 4 + * @param[in] byteNum Byte part number, should be in range from 0 to 3 + * @param[in] bitValue Value that contains all bits in to set direction, + * in range from 0 to 0xFF. + * @param[in] dir Direction value, should be: + * - 0: Input. + * - 1: Output. + * @return None + * + * Note: All remaining bits that are not activated in bitValue (value '0') + * will not be effected by this function. + **********************************************************************/ +void FIO_ByteSetDir(uint8_t portNum, uint8_t byteNum, uint8_t bitValue, uint8_t dir) +{ + GPIO_Byte_TypeDef *pFIO = FIO_ByteGetPointer(portNum); + if(pFIO != NULL) { + // Output direction + if (dir) { + if ((byteNum >= 0) && (byteNum <= 3)) { + pFIO->FIODIR[byteNum] |= bitValue; + } + } + // Input direction + else { + if ((byteNum >= 0) && (byteNum <= 3)) { + pFIO->FIODIR[byteNum] &= ~bitValue; + } + } + } +} + +/*********************************************************************//** + * @brief Set mask value for bits in FIO port in byte accessible style + * @param[in] portNum Port number, in range from 0 to 4 + * @param[in] byteNum Byte part number, should be in range from 0 to 3 + * @param[in] bitValue Value that contains all bits in to set mask, + * in range from 0 to 0xFF. + * @param[in] maskValue Mask value contains state value for each bit: + * - 0: not mask. + * - 1: mask. + * @return None + * + * Note: + * - All remaining bits that are not activated in bitValue (value '0') + * will not be effected by this function. + * - After executing this function, in mask register, value '0' on each bit + * enables an access to the corresponding physical pin via a read or write access, + * while value '1' on bit (masked) that corresponding pin will not be changed + * with write access and if read, will not be reflected in the updated pin. + **********************************************************************/ +void FIO_ByteSetMask(uint8_t portNum, uint8_t byteNum, uint8_t bitValue, uint8_t maskValue) +{ + GPIO_Byte_TypeDef *pFIO = FIO_ByteGetPointer(portNum); + if(pFIO != NULL) { + // Mask + if (maskValue) { + if ((byteNum >= 0) && (byteNum <= 3)) { + pFIO->FIOMASK[byteNum] |= bitValue; + } + } + // Un-mask + else { + if ((byteNum >= 0) && (byteNum <= 3)) { + pFIO->FIOMASK[byteNum] &= ~bitValue; + } + } + } +} + + +/*********************************************************************//** + * @brief Set bits for FIO port in byte accessible style + * @param[in] portNum Port number, in range from 0 to 4 + * @param[in] byteNum Byte part number, should be in range from 0 to 3 + * @param[in] bitValue Value that contains all bits in to set, + * in range from 0 to 0xFF. + * @return None + * + * Note: + * - For all bits that has been set as input direction, this function will + * not effect. + * - For all remaining bits that are not activated in bitValue (value '0') + * will not be effected by this function. + **********************************************************************/ +void FIO_ByteSetValue(uint8_t portNum, uint8_t byteNum, uint8_t bitValue) +{ + GPIO_Byte_TypeDef *pFIO = FIO_ByteGetPointer(portNum); + if (pFIO != NULL) { + if ((byteNum >= 0) && (byteNum <= 3)){ + pFIO->FIOSET[byteNum] = bitValue; + } + } +} + + +/*********************************************************************//** + * @brief Clear bits for FIO port in byte accessible style + * @param[in] portNum Port number, in range from 0 to 4 + * @param[in] byteNum Byte part number, should be in range from 0 to 3 + * @param[in] bitValue Value that contains all bits in to clear, + * in range from 0 to 0xFF. + * @return None + * + * Note: + * - For all bits that has been set as input direction, this function will + * not effect. + * - For all remaining bits that are not activated in bitValue (value '0') + * will not be effected by this function. + **********************************************************************/ +void FIO_ByteClearValue(uint8_t portNum, uint8_t byteNum, uint8_t bitValue) +{ + GPIO_Byte_TypeDef *pFIO = FIO_ByteGetPointer(portNum); + if (pFIO != NULL) { + if ((byteNum >= 0) && (byteNum <= 3)){ + pFIO->FIOCLR[byteNum] = bitValue; + } + } +} + + +/*********************************************************************//** + * @brief Read Current state on port pin that have input direction of GPIO + * in byte accessible style. + * @param[in] portNum Port number, in range from 0 to 4 + * @param[in] byteNum Byte part number, should be in range from 0 to 3 + * @return Current value of FIO port pin of specified byte part. + * Note: Return value contain state of each port pin (bit) on that FIO regardless + * its direction is input or output. + **********************************************************************/ +uint8_t FIO_ByteReadValue(uint8_t portNum, uint8_t byteNum) +{ + GPIO_Byte_TypeDef *pFIO = FIO_ByteGetPointer(portNum); + if (pFIO != NULL) { + if ((byteNum >= 0) && (byteNum <= 3)){ + return (pFIO->FIOPIN[byteNum]); + } + } + return (0); +} + +/** + * @} + */ + +#endif /* _GPIO */ + +/** + * @} + */ + +/* --------------------------------- End Of File ------------------------------ */ diff --git a/arch/arm/lpc17xx/Drivers/source/lpc17xx_i2c.c b/arch/arm/lpc17xx/Drivers/source/lpc17xx_i2c.c new file mode 100644 index 0000000..9b54228 --- /dev/null +++ b/arch/arm/lpc17xx/Drivers/source/lpc17xx_i2c.c @@ -0,0 +1,1373 @@ +/***********************************************************************//** + * @file lpc17xx_i2c.c + * @brief Contains all functions support for I2C firmware library on LPC17xx + * @version 2.0 + * @date 21. May. 2010 + * @author NXP MCU SW Application Team + ************************************************************************** + * Software that is described herein is for illustrative purposes only + * which provides customers with programming information regarding the + * products. This software is supplied "AS IS" without any warranties. + * NXP Semiconductors assumes no responsibility or liability for the + * use of the software, conveys no license or title under any patent, + * copyright, or mask work right to the product. NXP Semiconductors + * reserves the right to make changes in the software without + * notification. NXP Semiconductors also make no representation or + * warranty that such application will be suitable for the specified + * use without further testing or modification. + **********************************************************************/ + +/* Peripheral group ----------------------------------------------------------- */ +/** @addtogroup I2C + * @{ + */ + +/* Includes ------------------------------------------------------------------- */ +#include "lpc17xx_i2c.h" +#include "lpc17xx_clkpwr.h" +#include "lpc17xx_pinsel.h" + + +/* If this source file built with example, the LPC17xx FW library configuration + * file in each example directory ("lpc17xx_libcfg.h") must be included, + * otherwise the default FW library configuration file must be included instead + */ +#ifdef __BUILD_WITH_EXAMPLE__ +#include "lpc17xx_libcfg.h" +#else +#include "lpc17xx_libcfg_default.h" +#endif /* __BUILD_WITH_EXAMPLE__ */ + + +#ifdef _I2C + + +/* Private Types -------------------------------------------------------------- */ +/** @defgroup I2C_Private_Types I2C Private Types + * @{ + */ + +/** + * @brief I2C device configuration structure type + */ +typedef struct +{ + uint32_t txrx_setup; /* Transmission setup */ + int32_t dir; /* Current direction phase, 0 - write, 1 - read */ +} I2C_CFG_T; + +/** + * @} + */ + +/* Private Variables ---------------------------------------------------------- */ +/** + * @brief II2C driver data for I2C0, I2C1 and I2C2 + */ +static I2C_CFG_T i2cdat[3]; + +static uint32_t I2C_MasterComplete[3]; +static uint32_t I2C_SlaveComplete[3]; + +static uint32_t I2C_MonitorBufferIndex; + +/* Private Functions ---------------------------------------------------------- */ + +/* Get I2C number */ +static int32_t I2C_getNum(LPC_I2C_TypeDef *I2Cx); + +/* Generate a start condition on I2C bus (in master mode only) */ +static uint32_t I2C_Start (LPC_I2C_TypeDef *I2Cx); + +/* Generate a stop condition on I2C bus (in master mode only) */ +static void I2C_Stop (LPC_I2C_TypeDef *I2Cx); + +/* I2C send byte subroutine */ +static uint32_t I2C_SendByte (LPC_I2C_TypeDef *I2Cx, uint8_t databyte); + +/* I2C get byte subroutine */ +static uint32_t I2C_GetByte (LPC_I2C_TypeDef *I2Cx, uint8_t *retdat, Bool ack); + +/* I2C set clock (hz) */ +static void I2C_SetClock (LPC_I2C_TypeDef *I2Cx, uint32_t target_clock); + +/*--------------------------------------------------------------------------------*/ +/********************************************************************//** + * @brief Convert from I2C peripheral to number + * @param[in] I2Cx: I2C peripheral selected, should be: + * - LPC_I2C0 + * - LPC_I2C1 + * - LPC_I2C2 + * @return I2C number, could be: 0..2 + *********************************************************************/ +static int32_t I2C_getNum(LPC_I2C_TypeDef *I2Cx){ + if (I2Cx == LPC_I2C0) { + return (0); + } else if (I2Cx == LPC_I2C1) { + return (1); + } else if (I2Cx == LPC_I2C2) { + return (2); + } + return (-1); +} + +/********************************************************************//** + * @brief Generate a start condition on I2C bus (in master mode only) + * @param[in] I2Cx: I2C peripheral selected, should be: + * - LPC_I2C0 + * - LPC_I2C1 + * - LPC_I2C2 + * @return value of I2C status register after generate a start condition + *********************************************************************/ +static uint32_t I2C_Start (LPC_I2C_TypeDef *I2Cx) +{ + I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; + I2Cx->I2CONSET = I2C_I2CONSET_STA; + + // Wait for complete + while (!(I2Cx->I2CONSET & I2C_I2CONSET_SI)); + I2Cx->I2CONCLR = I2C_I2CONCLR_STAC; + return (I2Cx->I2STAT & I2C_STAT_CODE_BITMASK); +} + +/********************************************************************//** + * @brief Generate a stop condition on I2C bus (in master mode only) + * @param[in] I2Cx: I2C peripheral selected, should be: + * - LPC_I2C0 + * - LPC_I2C1 + * - LPC_I2C2 + * @return None + *********************************************************************/ +static void I2C_Stop (LPC_I2C_TypeDef *I2Cx) +{ + + /* Make sure start bit is not active */ + if (I2Cx->I2CONSET & I2C_I2CONSET_STA) + { + I2Cx->I2CONCLR = I2C_I2CONCLR_STAC; + } + I2Cx->I2CONSET = I2C_I2CONSET_STO; + I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; +} + +/********************************************************************//** + * @brief Send a byte + * @param[in] I2Cx: I2C peripheral selected, should be: + * - LPC_I2C0 + * - LPC_I2C1 + * - LPC_I2C2 + * @param[in] databyte: number of byte + * @return value of I2C status register after sending + *********************************************************************/ +static uint32_t I2C_SendByte (LPC_I2C_TypeDef *I2Cx, uint8_t databyte) +{ + /* Make sure start bit is not active */ + if (I2Cx->I2CONSET & I2C_I2CONSET_STA) + { + I2Cx->I2CONCLR = I2C_I2CONCLR_STAC; + } + I2Cx->I2DAT = databyte & I2C_I2DAT_BITMASK; + I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; + + while (!(I2Cx->I2CONSET & I2C_I2CONSET_SI)); + return (I2Cx->I2STAT & I2C_STAT_CODE_BITMASK); +} + +/********************************************************************//** + * @brief Get a byte + * @param[in] I2Cx: I2C peripheral selected, should be: + * - LPC_I2C0 + * - LPC_I2C1 + * - LPC_I2C2 + * @param[out] retdat pointer to return data + * @param[in] ack assert acknowledge or not, should be: TRUE/FALSE + * @return value of I2C status register after sending + *********************************************************************/ +static uint32_t I2C_GetByte (LPC_I2C_TypeDef *I2Cx, uint8_t *retdat, Bool ack) +{ + if (ack == TRUE) + { + I2Cx->I2CONSET = I2C_I2CONSET_AA; + } + else + { + I2Cx->I2CONCLR = I2C_I2CONCLR_AAC; + } + I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; + + while (!(I2Cx->I2CONSET & I2C_I2CONSET_SI)); + *retdat = (uint8_t) (I2Cx->I2DAT & I2C_I2DAT_BITMASK); + return (I2Cx->I2STAT & I2C_STAT_CODE_BITMASK); +} + +/*********************************************************************//** + * @brief Setup clock rate for I2C peripheral + * @param[in] I2Cx I2C peripheral selected, should be: + * - LPC_I2C0 + * - LPC_I2C1 + * - LPC_I2C2 + * @param[in] target_clock : clock of SSP (Hz) + * @return None + ***********************************************************************/ +static void I2C_SetClock (LPC_I2C_TypeDef *I2Cx, uint32_t target_clock) +{ + uint32_t temp; + + CHECK_PARAM(PARAM_I2Cx(I2Cx)); + + // Get PCLK of I2C controller + if (I2Cx == LPC_I2C0) + { + temp = CLKPWR_GetPCLK (CLKPWR_PCLKSEL_I2C0) / target_clock; + } + else if (I2Cx == LPC_I2C1) + { + temp = CLKPWR_GetPCLK (CLKPWR_PCLKSEL_I2C1) / target_clock; + } + else if (I2Cx == LPC_I2C2) + { + temp = CLKPWR_GetPCLK (CLKPWR_PCLKSEL_I2C1) / target_clock; + } + + /* Set the I2C clock value to register */ + I2Cx->I2SCLH = (uint32_t)(temp / 2); + I2Cx->I2SCLL = (uint32_t)(temp - I2Cx->I2SCLH); +} +/* End of Private Functions --------------------------------------------------- */ + + +/* Public Functions ----------------------------------------------------------- */ +/** @addtogroup I2C_Public_Functions + * @{ + */ + +/********************************************************************//** + * @brief Initializes the I2Cx peripheral with specified parameter. + * @param[in] I2Cx I2C peripheral selected, should be + * - LPC_I2C0 + * - LPC_I2C1 + * - LPC_I2C2 + * @param[in] clockrate Target clock rate value to initialized I2C + * peripheral (Hz) + * @return None + *********************************************************************/ +void I2C_Init(LPC_I2C_TypeDef *I2Cx, uint32_t clockrate) +{ + CHECK_PARAM(PARAM_I2Cx(I2Cx)); + + if (I2Cx==LPC_I2C0) + { + /* Set up clock and power for I2C0 module */ + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCI2C0, ENABLE); + /* As default, peripheral clock for I2C0 module + * is set to FCCLK / 2 */ + CLKPWR_SetPCLKDiv(CLKPWR_PCLKSEL_I2C0, CLKPWR_PCLKSEL_CCLK_DIV_2); + } + else if (I2Cx==LPC_I2C1) + { + /* Set up clock and power for I2C1 module */ + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCI2C1, ENABLE); + /* As default, peripheral clock for I2C1 module + * is set to FCCLK / 2 */ + CLKPWR_SetPCLKDiv(CLKPWR_PCLKSEL_I2C1, CLKPWR_PCLKSEL_CCLK_DIV_2); + } + else if (I2Cx==LPC_I2C2) + { + /* Set up clock and power for I2C2 module */ + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCI2C2, ENABLE); + /* As default, peripheral clock for I2C2 module + * is set to FCCLK / 2 */ + CLKPWR_SetPCLKDiv(CLKPWR_PCLKSEL_I2C2, CLKPWR_PCLKSEL_CCLK_DIV_2); + } + else { + // Up-Support this device + return; + } + + /* Set clock rate */ + I2C_SetClock(I2Cx, clockrate); + /* Set I2C operation to default */ + I2Cx->I2CONCLR = (I2C_I2CONCLR_AAC | I2C_I2CONCLR_STAC | I2C_I2CONCLR_I2ENC); +} + +/*********************************************************************//** + * @brief De-initializes the I2C peripheral registers to their + * default reset values. + * @param[in] I2Cx I2C peripheral selected, should be + * - LPC_I2C0 + * - LPC_I2C1 + * - LPC_I2C2 + * @return None + **********************************************************************/ +void I2C_DeInit(LPC_I2C_TypeDef* I2Cx) +{ + CHECK_PARAM(PARAM_I2Cx(I2Cx)); + + /* Disable I2C control */ + I2Cx->I2CONCLR = I2C_I2CONCLR_I2ENC; + + if (I2Cx==LPC_I2C0) + { + /* Disable power for I2C0 module */ + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCI2C0, DISABLE); + } + else if (I2Cx==LPC_I2C1) + { + /* Disable power for I2C1 module */ + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCI2C1, DISABLE); + } + else if (I2Cx==LPC_I2C2) + { + /* Disable power for I2C2 module */ + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCI2C2, DISABLE); + } +} + +/*********************************************************************//** + * @brief Enable or disable I2C peripheral's operation + * @param[in] I2Cx I2C peripheral selected, should be + * - LPC_I2C0 + * - LPC_I2C1 + * - LPC_I2C2 + * @param[in] NewState New State of I2Cx peripheral's operation + * @return none + **********************************************************************/ +void I2C_Cmd(LPC_I2C_TypeDef* I2Cx, FunctionalState NewState) +{ + CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState)); + CHECK_PARAM(PARAM_I2Cx(I2Cx)); + + if (NewState == ENABLE) + { + I2Cx->I2CONSET = I2C_I2CONSET_I2EN; + } + else + { + I2Cx->I2CONCLR = I2C_I2CONCLR_I2ENC; + } +} + +/*********************************************************************//** + * @brief Enable/Disable interrupt for I2C peripheral + * @param[in] I2Cx I2C peripheral selected, should be: + * - LPC_I2C0 + * - LPC_I2C1 + * - LPC_I2C2 + * @param[in] NewState New State of I2C peripheral interrupt in NVIC core + * should be: + * - ENABLE: enable interrupt for this I2C peripheral + * - DISABLE: disable interrupt for this I2C peripheral + * @return None + **********************************************************************/ +void I2C_IntCmd (LPC_I2C_TypeDef *I2Cx, Bool NewState) +{ + if (NewState) + { + if(I2Cx == LPC_I2C0) + { + NVIC_EnableIRQ(I2C0_IRQn); + } + else if (I2Cx == LPC_I2C1) + { + NVIC_EnableIRQ(I2C1_IRQn); + } + else if (I2Cx == LPC_I2C2) + { + NVIC_EnableIRQ(I2C2_IRQn); + } + } + else + { + if(I2Cx == LPC_I2C0) + { + NVIC_DisableIRQ(I2C0_IRQn); + } + else if (I2Cx == LPC_I2C1) + { + NVIC_DisableIRQ(I2C1_IRQn); + } + else if (I2Cx == LPC_I2C2) + { + NVIC_DisableIRQ(I2C2_IRQn); + } + } + return; +} + + +/*********************************************************************//** + * @brief General Master Interrupt handler for I2C peripheral + * @param[in] I2Cx I2C peripheral selected, should be: + * - LPC_I2C + * - LPC_I2C1 + * - LPC_I2C2 + * @return None + **********************************************************************/ +void I2C_MasterHandler (LPC_I2C_TypeDef *I2Cx) +{ + int32_t tmp; + uint8_t returnCode; + I2C_M_SETUP_Type *txrx_setup; + + tmp = I2C_getNum(I2Cx); + txrx_setup = (I2C_M_SETUP_Type *) i2cdat[tmp].txrx_setup; + + returnCode = (I2Cx->I2STAT & I2C_STAT_CODE_BITMASK); + // Save current status + txrx_setup->status = returnCode; + // there's no relevant information + if (returnCode == I2C_I2STAT_NO_INF){ + I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; + return; + } + + /* ----------------------------- TRANSMIT PHASE --------------------------*/ + if (i2cdat[tmp].dir == 0){ + switch (returnCode) + { + /* A start/repeat start condition has been transmitted -------------------*/ + case I2C_I2STAT_M_TX_START: + case I2C_I2STAT_M_TX_RESTART: + I2Cx->I2CONCLR = I2C_I2CONCLR_STAC; + /* + * If there's any transmit data, then start to + * send SLA+W right now, otherwise check whether if there's + * any receive data for next state. + */ + if ((txrx_setup->tx_data != NULL) && (txrx_setup->tx_length != 0)){ + I2Cx->I2DAT = (txrx_setup->sl_addr7bit << 1); + I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; + } else { + goto next_stage; + } + break; + + /* SLA+W has been transmitted, ACK has been received ----------------------*/ + case I2C_I2STAT_M_TX_SLAW_ACK: + /* Data has been transmitted, ACK has been received */ + case I2C_I2STAT_M_TX_DAT_ACK: + /* Send more data */ + if ((txrx_setup->tx_count < txrx_setup->tx_length) \ + && (txrx_setup->tx_data != NULL)){ + I2Cx->I2DAT = *(uint8_t *)(txrx_setup->tx_data + txrx_setup->tx_count); + txrx_setup->tx_count++; + I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; + } + // no more data, switch to next stage + else { +next_stage: + // change direction + i2cdat[tmp].dir = 1; + // Check if any data to receive + if ((txrx_setup->rx_length != 0) && (txrx_setup->rx_data != NULL)){ + // check whether if we need to issue an repeat start + if ((txrx_setup->tx_length != 0) && (txrx_setup->tx_data != NULL)){ + // Send out an repeat start command + I2Cx->I2CONSET = I2C_I2CONSET_STA; + I2Cx->I2CONCLR = I2C_I2CONCLR_AAC | I2C_I2CONCLR_SIC; + } + // Don't need issue an repeat start, just goto send SLA+R + else { + goto send_slar; + } + } + // no more data send, the go to end stage now + else { + // success, goto end stage + txrx_setup->status |= I2C_SETUP_STATUS_DONE; + goto end_stage; + } + } + break; + + /* SLA+W has been transmitted, NACK has been received ----------------------*/ + case I2C_I2STAT_M_TX_SLAW_NACK: + /* Data has been transmitted, NACK has been received -----------------------*/ + case I2C_I2STAT_M_TX_DAT_NACK: + // update status + txrx_setup->status |= I2C_SETUP_STATUS_NOACKF; + goto retry; + /* Arbitration lost in SLA+R/W or Data bytes -------------------------------*/ + case I2C_I2STAT_M_TX_ARB_LOST: + // update status + txrx_setup->status |= I2C_SETUP_STATUS_ARBF; + default: + goto retry; + } + } + + /* ----------------------------- RECEIVE PHASE --------------------------*/ + else if (i2cdat[tmp].dir == 1){ + switch (returnCode){ + /* A start/repeat start condition has been transmitted ---------------------*/ + case I2C_I2STAT_M_RX_START: + case I2C_I2STAT_M_RX_RESTART: + I2Cx->I2CONCLR = I2C_I2CONCLR_STAC; + /* + * If there's any receive data, then start to + * send SLA+R right now, otherwise check whether if there's + * any receive data for end of state. + */ + if ((txrx_setup->rx_data != NULL) && (txrx_setup->rx_length != 0)){ +send_slar: + I2Cx->I2DAT = (txrx_setup->sl_addr7bit << 1) | 0x01; + I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; + } else { + // Success, goto end stage + txrx_setup->status |= I2C_SETUP_STATUS_DONE; + goto end_stage; + } + break; + + /* SLA+R has been transmitted, ACK has been received -----------------*/ + case I2C_I2STAT_M_RX_SLAR_ACK: + if (txrx_setup->rx_count < (txrx_setup->rx_length - 1)) { + /*Data will be received, ACK will be return*/ + I2Cx->I2CONSET = I2C_I2CONSET_AA; + } + else { + /*Last data will be received, NACK will be return*/ + I2Cx->I2CONCLR = I2C_I2CONSET_AA; + } + I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; + break; + + /* Data has been received, ACK has been returned ----------------------*/ + case I2C_I2STAT_M_RX_DAT_ACK: + // Note save data and increase counter first, then check later + /* Save data */ + if ((txrx_setup->rx_data != NULL) && (txrx_setup->rx_count < txrx_setup->rx_length)){ + *(uint8_t *)(txrx_setup->rx_data + txrx_setup->rx_count) = (I2Cx->I2DAT & I2C_I2DAT_BITMASK); + txrx_setup->rx_count++; + } + if (txrx_setup->rx_count < (txrx_setup->rx_length - 1)) { + /*Data will be received, ACK will be return*/ + I2Cx->I2CONSET = I2C_I2CONSET_AA; + } + else { + /*Last data will be received, NACK will be return*/ + I2Cx->I2CONCLR = I2C_I2CONSET_AA; + } + + I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; + break; + + /* Data has been received, NACK has been return -------------------------*/ + case I2C_I2STAT_M_RX_DAT_NACK: + /* Save the last data */ + if ((txrx_setup->rx_data != NULL) && (txrx_setup->rx_count < txrx_setup->rx_length)){ + *(uint8_t *)(txrx_setup->rx_data + txrx_setup->rx_count) = (I2Cx->I2DAT & I2C_I2DAT_BITMASK); + txrx_setup->rx_count++; + } + // success, go to end stage + txrx_setup->status |= I2C_SETUP_STATUS_DONE; + goto end_stage; + + /* SLA+R has been transmitted, NACK has been received ------------------*/ + case I2C_I2STAT_M_RX_SLAR_NACK: + // update status + txrx_setup->status |= I2C_SETUP_STATUS_NOACKF; + goto retry; + + /* Arbitration lost ----------------------------------------------------*/ + case I2C_I2STAT_M_RX_ARB_LOST: + // update status + txrx_setup->status |= I2C_SETUP_STATUS_ARBF; + default: +retry: + // check if retransmission is available + if (txrx_setup->retransmissions_count < txrx_setup->retransmissions_max){ + // Clear tx count + txrx_setup->tx_count = 0; + I2Cx->I2CONSET = I2C_I2CONSET_STA; + I2Cx->I2CONCLR = I2C_I2CONCLR_AAC | I2C_I2CONCLR_SIC; + txrx_setup->retransmissions_count++; + } + // End of stage + else { +end_stage: + // Disable interrupt + I2C_IntCmd(I2Cx, 0); + // Send stop + I2C_Stop(I2Cx); + + I2C_MasterComplete[tmp] = TRUE; + } + break; + } + } +} + + +/*********************************************************************//** + * @brief General Slave Interrupt handler for I2C peripheral + * @param[in] I2Cx I2C peripheral selected, should be: + * - LPC_I2C0 + * - LPC_I2C1 + * - LPC_I2C2 + * @return None + **********************************************************************/ +void I2C_SlaveHandler (LPC_I2C_TypeDef *I2Cx) +{ + int32_t tmp; + uint8_t returnCode; + I2C_S_SETUP_Type *txrx_setup; + uint32_t timeout; + + tmp = I2C_getNum(I2Cx); + txrx_setup = (I2C_S_SETUP_Type *) i2cdat[tmp].txrx_setup; + + returnCode = (I2Cx->I2STAT & I2C_STAT_CODE_BITMASK); + // Save current status + txrx_setup->status = returnCode; + // there's no relevant information + if (returnCode == I2C_I2STAT_NO_INF){ + I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; + return; + } + + + switch (returnCode) + { + + /* No status information */ + case I2C_I2STAT_NO_INF: + I2Cx->I2CONSET = I2C_I2CONSET_AA; + I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; + break; + + /* Reading phase -------------------------------------------------------- */ + /* Own SLA+R has been received, ACK has been returned */ + case I2C_I2STAT_S_RX_SLAW_ACK: + /* General call address has been received, ACK has been returned */ + case I2C_I2STAT_S_RX_GENCALL_ACK: + I2Cx->I2CONSET = I2C_I2CONSET_AA; + I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; + break; + + /* Previously addressed with own SLA; + * DATA byte has been received; + * ACK has been returned */ + case I2C_I2STAT_S_RX_PRE_SLA_DAT_ACK: + /* DATA has been received, ACK hasn been return */ + case I2C_I2STAT_S_RX_PRE_GENCALL_DAT_ACK: + /* + * All data bytes that over-flow the specified receive + * data length, just ignore them. + */ + if ((txrx_setup->rx_count < txrx_setup->rx_length) \ + && (txrx_setup->rx_data != NULL)){ + *(uint8_t *)(txrx_setup->rx_data + txrx_setup->rx_count) = (uint8_t)I2Cx->I2DAT; + txrx_setup->rx_count++; + } + I2Cx->I2CONSET = I2C_I2CONSET_AA; + I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; + break; + + /* Previously addressed with own SLA; + * DATA byte has been received; + * NOT ACK has been returned */ + case I2C_I2STAT_S_RX_PRE_SLA_DAT_NACK: + /* DATA has been received, NOT ACK has been returned */ + case I2C_I2STAT_S_RX_PRE_GENCALL_DAT_NACK: + I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; + break; + + /* + * Note that: Return code only let us know a stop condition mixed + * with a repeat start condition in the same code value. + * So we should provide a time-out. In case this is really a stop + * condition, this will return back after time out condition. Otherwise, + * next session that is slave receive data will be completed. + */ + + /* A Stop or a repeat start condition */ + case I2C_I2STAT_S_RX_STA_STO_SLVREC_SLVTRX: + // Temporally lock the interrupt for timeout condition + I2C_IntCmd(I2Cx, 0); + I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; + // enable time out + timeout = I2C_SLAVE_TIME_OUT; + while(1){ + if (I2Cx->I2CONSET & I2C_I2CONSET_SI){ + // re-Enable interrupt + I2C_IntCmd(I2Cx, 1); + break; + } else { + timeout--; + if (timeout == 0){ + // timeout occur, it's really a stop condition + txrx_setup->status |= I2C_SETUP_STATUS_DONE; + goto s_int_end; + } + } + } + break; + + /* Writing phase -------------------------------------------------------- */ + /* Own SLA+R has been received, ACK has been returned */ + case I2C_I2STAT_S_TX_SLAR_ACK: + /* Data has been transmitted, ACK has been received */ + case I2C_I2STAT_S_TX_DAT_ACK: + /* + * All data bytes that over-flow the specified receive + * data length, just ignore them. + */ + if ((txrx_setup->tx_count < txrx_setup->tx_length) \ + && (txrx_setup->tx_data != NULL)){ + I2Cx->I2DAT = *(uint8_t *) (txrx_setup->tx_data + txrx_setup->tx_count); + txrx_setup->tx_count++; + } + I2Cx->I2CONSET = I2C_I2CONSET_AA; + I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; + break; + + /* Data has been transmitted, NACK has been received, + * that means there's no more data to send, exit now */ + /* + * Note: Don't wait for stop event since in slave transmit mode, + * since there no proof lets us know when a stop signal has been received + * on slave side. + */ + case I2C_I2STAT_S_TX_DAT_NACK: + I2Cx->I2CONSET = I2C_I2CONSET_AA; + I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; + txrx_setup->status |= I2C_SETUP_STATUS_DONE; + goto s_int_end; + + // Other status must be captured + default: +s_int_end: + // Disable interrupt + I2C_IntCmd(I2Cx, 0); + I2Cx->I2CONCLR = I2C_I2CONCLR_AAC | I2C_I2CONCLR_SIC | I2C_I2CONCLR_STAC; + I2C_SlaveComplete[tmp] = TRUE; + break; + } +} + +/*********************************************************************//** + * @brief Transmit and Receive data in master mode + * @param[in] I2Cx I2C peripheral selected, should be: + * - LPC_I2C0 + * - LPC_I2C1 + * - LPC_I2C2 + * @param[in] TransferCfg Pointer to a I2C_M_SETUP_Type structure that + * contains specified information about the + * configuration for master transfer. + * @param[in] Opt a I2C_TRANSFER_OPT_Type type that selected for + * interrupt or polling mode. + * @return SUCCESS or ERROR + * + * Note: + * - In case of using I2C to transmit data only, either transmit length set to 0 + * or transmit data pointer set to NULL. + * - In case of using I2C to receive data only, either receive length set to 0 + * or receive data pointer set to NULL. + * - In case of using I2C to transmit followed by receive data, transmit length, + * transmit data pointer, receive length and receive data pointer should be set + * corresponding. + **********************************************************************/ +Status I2C_MasterTransferData(LPC_I2C_TypeDef *I2Cx, I2C_M_SETUP_Type *TransferCfg, \ + I2C_TRANSFER_OPT_Type Opt) +{ + uint8_t *txdat; + uint8_t *rxdat; + uint32_t CodeStatus; + uint8_t tmp; + + // reset all default state + txdat = (uint8_t *) TransferCfg->tx_data; + rxdat = (uint8_t *) TransferCfg->rx_data; + // Reset I2C setup value to default state + TransferCfg->tx_count = 0; + TransferCfg->rx_count = 0; + TransferCfg->status = 0; + + if (Opt == I2C_TRANSFER_POLLING){ + + /* First Start condition -------------------------------------------------------------- */ + TransferCfg->retransmissions_count = 0; +retry: + // reset all default state + txdat = (uint8_t *) TransferCfg->tx_data; + rxdat = (uint8_t *) TransferCfg->rx_data; + // Reset I2C setup value to default state + TransferCfg->tx_count = 0; + TransferCfg->rx_count = 0; + CodeStatus = 0; + + // Start command + CodeStatus = I2C_Start(I2Cx); + if ((CodeStatus != I2C_I2STAT_M_TX_START) \ + && (CodeStatus != I2C_I2STAT_M_TX_RESTART)){ + TransferCfg->retransmissions_count++; + if (TransferCfg->retransmissions_count > TransferCfg->retransmissions_max){ + // save status + TransferCfg->status = CodeStatus; + goto error; + } else { + goto retry; + } + } + + /* In case of sending data first --------------------------------------------------- */ + if ((TransferCfg->tx_length != 0) && (TransferCfg->tx_data != NULL)){ + + /* Send slave address + WR direction bit = 0 ----------------------------------- */ + CodeStatus = I2C_SendByte(I2Cx, (TransferCfg->sl_addr7bit << 1)); + if (CodeStatus != I2C_I2STAT_M_TX_SLAW_ACK){ + TransferCfg->retransmissions_count++; + if (TransferCfg->retransmissions_count > TransferCfg->retransmissions_max){ + // save status + TransferCfg->status = CodeStatus | I2C_SETUP_STATUS_NOACKF; + goto error; + } else { + goto retry; + } + } + + /* Send a number of data bytes ---------------------------------------- */ + while (TransferCfg->tx_count < TransferCfg->tx_length) + { + CodeStatus = I2C_SendByte(I2Cx, *txdat); + if (CodeStatus != I2C_I2STAT_M_TX_DAT_ACK){ + TransferCfg->retransmissions_count++; + if (TransferCfg->retransmissions_count > TransferCfg->retransmissions_max){ + // save status + TransferCfg->status = CodeStatus | I2C_SETUP_STATUS_NOACKF; + goto error; + } else { + goto retry; + } + } + + txdat++; + TransferCfg->tx_count++; + } + } + + /* Second Start condition (Repeat Start) ------------------------------------------- */ + if ((TransferCfg->tx_length != 0) && (TransferCfg->tx_data != NULL) \ + && (TransferCfg->rx_length != 0) && (TransferCfg->rx_data != NULL)){ + + CodeStatus = I2C_Start(I2Cx); + if ((CodeStatus != I2C_I2STAT_M_RX_START) \ + && (CodeStatus != I2C_I2STAT_M_RX_RESTART)){ + TransferCfg->retransmissions_count++; + if (TransferCfg->retransmissions_count > TransferCfg->retransmissions_max){ + // Update status + TransferCfg->status = CodeStatus; + goto error; + } else { + goto retry; + } + } + } + + /* Then, start reading after sending data -------------------------------------- */ + if ((TransferCfg->rx_length != 0) && (TransferCfg->rx_data != NULL)){ + /* Send slave address + RD direction bit = 1 ----------------------------------- */ + + CodeStatus = I2C_SendByte(I2Cx, ((TransferCfg->sl_addr7bit << 1) | 0x01)); + if (CodeStatus != I2C_I2STAT_M_RX_SLAR_ACK){ + TransferCfg->retransmissions_count++; + if (TransferCfg->retransmissions_count > TransferCfg->retransmissions_max){ + // update status + TransferCfg->status = CodeStatus | I2C_SETUP_STATUS_NOACKF; + goto error; + } else { + goto retry; + } + } + + /* Receive a number of data bytes ------------------------------------------------- */ + while (TransferCfg->rx_count < TransferCfg->rx_length){ + + /* + * Note that: if data length is only one, the master should not + * issue an ACK signal on bus after reading to avoid of next data frame + * on slave side + */ + if (TransferCfg->rx_count < (TransferCfg->rx_length - 1)){ + // Issue an ACK signal for next data frame + CodeStatus = I2C_GetByte(I2Cx, &tmp, 1); + if (CodeStatus != I2C_I2STAT_M_RX_DAT_ACK){ + TransferCfg->retransmissions_count++; + if (TransferCfg->retransmissions_count > TransferCfg->retransmissions_max){ + // update status + TransferCfg->status = CodeStatus; + goto error; + } else { + goto retry; + } + } + } else { + // Do not issue an ACK signal + CodeStatus = I2C_GetByte(I2Cx, &tmp, 0); + if (CodeStatus != I2C_I2STAT_M_RX_DAT_NACK){ + TransferCfg->retransmissions_count++; + if (TransferCfg->retransmissions_count > TransferCfg->retransmissions_max){ + // update status + TransferCfg->status = CodeStatus; + goto error; + } else { + goto retry; + } + } + } + *rxdat++ = tmp; + TransferCfg->rx_count++; + } + } + + /* Send STOP condition ------------------------------------------------- */ + I2C_Stop(I2Cx); + return SUCCESS; + +error: + // Send stop condition + I2C_Stop(I2Cx); + return ERROR; + } + + else if (Opt == I2C_TRANSFER_INTERRUPT){ + // Setup tx_rx data, callback and interrupt handler + tmp = I2C_getNum(I2Cx); + i2cdat[tmp].txrx_setup = (uint32_t) TransferCfg; + // Set direction phase, write first + i2cdat[tmp].dir = 0; + + /* First Start condition -------------------------------------------------------------- */ + I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; + I2Cx->I2CONSET = I2C_I2CONSET_STA; + I2C_IntCmd(I2Cx, 1); + + return (SUCCESS); + } + + return ERROR; +} + +/*********************************************************************//** + * @brief Receive and Transmit data in slave mode + * @param[in] I2Cx I2C peripheral selected, should be + * - LPC_I2C0 + * - LPC_I2C1 + * - LPC_I2C2 + * @param[in] TransferCfg Pointer to a I2C_S_SETUP_Type structure that + * contains specified information about the + * configuration for master transfer. + * @param[in] Opt I2C_TRANSFER_OPT_Type type that selected for + * interrupt or polling mode. + * @return SUCCESS or ERROR + * + * Note: + * The mode of slave's operation depends on the command sent from master on + * the I2C bus. If the master send a SLA+W command, this sub-routine will + * use receive data length and receive data pointer. If the master send a SLA+R + * command, this sub-routine will use transmit data length and transmit data + * pointer. + * If the master issue an repeat start command or a stop command, the slave will + * enable an time out condition, during time out condition, if there's no activity + * on I2C bus, the slave will exit, otherwise (i.e. the master send a SLA+R/W), + * the slave then switch to relevant operation mode. The time out should be used + * because the return status code can not show difference from stop and repeat + * start command in slave operation. + * In case of the expected data length from master is greater than data length + * that slave can support: + * - In case of reading operation (from master): slave will return I2C_I2DAT_IDLE_CHAR + * value. + * - In case of writing operation (from master): slave will ignore remain data from master. + **********************************************************************/ +Status I2C_SlaveTransferData(LPC_I2C_TypeDef *I2Cx, I2C_S_SETUP_Type *TransferCfg, \ + I2C_TRANSFER_OPT_Type Opt) +{ + uint8_t *txdat; + uint8_t *rxdat; + uint32_t CodeStatus; + uint32_t timeout; + int32_t time_en; + int32_t tmp; + + // reset all default state + txdat = (uint8_t *) TransferCfg->tx_data; + rxdat = (uint8_t *) TransferCfg->rx_data; + // Reset I2C setup value to default state + TransferCfg->tx_count = 0; + TransferCfg->rx_count = 0; + TransferCfg->status = 0; + + + // Polling option + if (Opt == I2C_TRANSFER_POLLING){ + + /* Set AA bit to ACK command on I2C bus */ + I2Cx->I2CONSET = I2C_I2CONSET_AA; + /* Clear SI bit to be ready ... */ + I2Cx->I2CONCLR = (I2C_I2CONCLR_SIC | I2C_I2CONCLR_STAC); + + time_en = 0; + timeout = 0; + + while (1) + { + /* Check SI flag ready */ + if (I2Cx->I2CONSET & I2C_I2CONSET_SI) + { + time_en = 0; + + switch (CodeStatus = (I2Cx->I2STAT & I2C_STAT_CODE_BITMASK)) + { + + /* No status information */ + case I2C_I2STAT_NO_INF: + I2Cx->I2CONSET = I2C_I2CONSET_AA; + I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; + break; + + /* Reading phase -------------------------------------------------------- */ + /* Own SLA+R has been received, ACK has been returned */ + case I2C_I2STAT_S_RX_SLAW_ACK: + /* General call address has been received, ACK has been returned */ + case I2C_I2STAT_S_RX_GENCALL_ACK: + I2Cx->I2CONSET = I2C_I2CONSET_AA; + I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; + break; + + /* Previously addressed with own SLA; + * DATA byte has been received; + * ACK has been returned */ + case I2C_I2STAT_S_RX_PRE_SLA_DAT_ACK: + /* DATA has been received, ACK hasn been return */ + case I2C_I2STAT_S_RX_PRE_GENCALL_DAT_ACK: + /* + * All data bytes that over-flow the specified receive + * data length, just ignore them. + */ + if ((TransferCfg->rx_count < TransferCfg->rx_length) \ + && (TransferCfg->rx_data != NULL)){ + *rxdat++ = (uint8_t)I2Cx->I2DAT; + TransferCfg->rx_count++; + } + I2Cx->I2CONSET = I2C_I2CONSET_AA; + I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; + break; + + /* Previously addressed with own SLA; + * DATA byte has been received; + * NOT ACK has been returned */ + case I2C_I2STAT_S_RX_PRE_SLA_DAT_NACK: + /* DATA has been received, NOT ACK has been returned */ + case I2C_I2STAT_S_RX_PRE_GENCALL_DAT_NACK: + I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; + break; + + /* + * Note that: Return code only let us know a stop condition mixed + * with a repeat start condition in the same code value. + * So we should provide a time-out. In case this is really a stop + * condition, this will return back after time out condition. Otherwise, + * next session that is slave receive data will be completed. + */ + + /* A Stop or a repeat start condition */ + case I2C_I2STAT_S_RX_STA_STO_SLVREC_SLVTRX: + I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; + // enable time out + time_en = 1; + timeout = 0; + break; + + /* Writing phase -------------------------------------------------------- */ + /* Own SLA+R has been received, ACK has been returned */ + case I2C_I2STAT_S_TX_SLAR_ACK: + /* Data has been transmitted, ACK has been received */ + case I2C_I2STAT_S_TX_DAT_ACK: + /* + * All data bytes that over-flow the specified receive + * data length, just ignore them. + */ + if ((TransferCfg->tx_count < TransferCfg->tx_length) \ + && (TransferCfg->tx_data != NULL)){ + I2Cx->I2DAT = *txdat++; + TransferCfg->tx_count++; + } + I2Cx->I2CONSET = I2C_I2CONSET_AA; + I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; + break; + + /* Data has been transmitted, NACK has been received, + * that means there's no more data to send, exit now */ + /* + * Note: Don't wait for stop event since in slave transmit mode, + * since there no proof lets us know when a stop signal has been received + * on slave side. + */ + case I2C_I2STAT_S_TX_DAT_NACK: + I2Cx->I2CONSET = I2C_I2CONSET_AA; + I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; + // enable time out + time_en = 1; + timeout = 0; + break; + + // Other status must be captured + default: + I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; + goto s_error; + } + } else if (time_en){ + if (timeout++ > I2C_SLAVE_TIME_OUT){ + // it's really a stop condition, goto end stage + goto s_end_stage; + } + } + } + +s_end_stage: + /* Clear AA bit to disable ACK on I2C bus */ + I2Cx->I2CONCLR = I2C_I2CONCLR_AAC; + // Check if there's no error during operation + // Update status + TransferCfg->status = CodeStatus | I2C_SETUP_STATUS_DONE; + return SUCCESS; + +s_error: + /* Clear AA bit to disable ACK on I2C bus */ + I2Cx->I2CONCLR = I2C_I2CONCLR_AAC; + // Update status + TransferCfg->status = CodeStatus; + return ERROR; + } + + else if (Opt == I2C_TRANSFER_INTERRUPT){ + // Setup tx_rx data, callback and interrupt handler + tmp = I2C_getNum(I2Cx); + i2cdat[tmp].txrx_setup = (uint32_t) TransferCfg; + // Set direction phase, read first + i2cdat[tmp].dir = 1; + + // Enable AA + I2Cx->I2CONSET = I2C_I2CONSET_AA; + I2Cx->I2CONCLR = I2C_I2CONCLR_SIC | I2C_I2CONCLR_STAC; + I2C_IntCmd(I2Cx, 1); + + return (SUCCESS); + } + + return ERROR; +} + +/*********************************************************************//** + * @brief Set Own slave address in I2C peripheral corresponding to + * parameter specified in OwnSlaveAddrConfigStruct. + * @param[in] I2Cx I2C peripheral selected, should be + * - LPC_I2C0 + * - LPC_I2C1 + * - LPC_I2C2 + * @param[in] OwnSlaveAddrConfigStruct Pointer to a I2C_OWNSLAVEADDR_CFG_Type + * structure that contains the configuration information for the +* specified I2C slave address. + * @return None + **********************************************************************/ +void I2C_SetOwnSlaveAddr(LPC_I2C_TypeDef *I2Cx, I2C_OWNSLAVEADDR_CFG_Type *OwnSlaveAddrConfigStruct) +{ + uint32_t tmp; + CHECK_PARAM(PARAM_I2Cx(I2Cx)); + CHECK_PARAM(PARAM_I2C_SLAVEADDR_CH(OwnSlaveAddrConfigStruct->SlaveAddrChannel)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(OwnSlaveAddrConfigStruct->GeneralCallState)); + + tmp = (((uint32_t)(OwnSlaveAddrConfigStruct->SlaveAddr_7bit << 1)) \ + | ((OwnSlaveAddrConfigStruct->GeneralCallState == ENABLE) ? 0x01 : 0x00))& I2C_I2ADR_BITMASK; + switch (OwnSlaveAddrConfigStruct->SlaveAddrChannel) + { + case 0: + I2Cx->I2ADR0 = tmp; + I2Cx->I2MASK0 = I2C_I2MASK_MASK((uint32_t) \ + (OwnSlaveAddrConfigStruct->SlaveAddrMaskValue)); + break; + case 1: + I2Cx->I2ADR1 = tmp; + I2Cx->I2MASK1 = I2C_I2MASK_MASK((uint32_t) \ + (OwnSlaveAddrConfigStruct->SlaveAddrMaskValue)); + break; + case 2: + I2Cx->I2ADR2 = tmp; + I2Cx->I2MASK2 = I2C_I2MASK_MASK((uint32_t) \ + (OwnSlaveAddrConfigStruct->SlaveAddrMaskValue)); + break; + case 3: + I2Cx->I2ADR3 = tmp; + I2Cx->I2MASK3 = I2C_I2MASK_MASK((uint32_t) \ + (OwnSlaveAddrConfigStruct->SlaveAddrMaskValue)); + break; + } +} + + +/*********************************************************************//** + * @brief Configures functionality in I2C monitor mode + * @param[in] I2Cx I2C peripheral selected, should be + * - LPC_I2C0 + * - LPC_I2C1 + * - LPC_I2C2 + * @param[in] MonitorCfgType Monitor Configuration type, should be: + * - I2C_MONITOR_CFG_SCL_OUTPUT: I2C module can 'stretch' + * the clock line (hold it low) until it has had time to + * respond to an I2C interrupt. + * - I2C_MONITOR_CFG_MATCHALL: When this bit is set to '1' + * and the I2C is in monitor mode, an interrupt will be + * generated on ANY address received. + * @param[in] NewState New State of this function, should be: + * - ENABLE: Enable this function. + * - DISABLE: Disable this function. + * @return None + **********************************************************************/ +void I2C_MonitorModeConfig(LPC_I2C_TypeDef *I2Cx, uint32_t MonitorCfgType, FunctionalState NewState) +{ + CHECK_PARAM(PARAM_I2Cx(I2Cx)); + CHECK_PARAM(PARAM_I2C_MONITOR_CFG(MonitorCfgType)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState)); + + if (NewState == ENABLE) + { + I2Cx->MMCTRL |= MonitorCfgType; + } + else + { + I2Cx->MMCTRL &= (~MonitorCfgType) & I2C_I2MMCTRL_BITMASK; + } +} + + +/*********************************************************************//** + * @brief Enable/Disable I2C monitor mode + * @param[in] I2Cx I2C peripheral selected, should be + * - LPC_I2C0 + * - LPC_I2C1 + * - LPC_I2C2 + * @param[in] NewState New State of this function, should be: + * - ENABLE: Enable monitor mode. + * - DISABLE: Disable monitor mode. + * @return None + **********************************************************************/ +void I2C_MonitorModeCmd(LPC_I2C_TypeDef *I2Cx, FunctionalState NewState) +{ + CHECK_PARAM(PARAM_I2Cx(I2Cx)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState)); + + if (NewState == ENABLE) + { + I2Cx->MMCTRL |= I2C_I2MMCTRL_MM_ENA; + I2Cx->I2CONSET = I2C_I2CONSET_AA; + I2Cx->I2CONCLR = I2C_I2CONCLR_SIC | I2C_I2CONCLR_STAC; + } + else + { + I2Cx->MMCTRL &= (~I2C_I2MMCTRL_MM_ENA) & I2C_I2MMCTRL_BITMASK; + I2Cx->I2CONCLR = I2C_I2CONCLR_SIC | I2C_I2CONCLR_STAC | I2C_I2CONCLR_AAC; + } + I2C_MonitorBufferIndex = 0; +} + + +/*********************************************************************//** + * @brief Get data from I2C data buffer in monitor mode. + * @param[in] I2Cx I2C peripheral selected, should be + * - LPC_I2C0 + * - LPC_I2C1 + * - LPC_I2C2 + * @return None + * Note: In monitor mode, the I2C module may lose the ability to stretch + * the clock (stall the bus) if the ENA_SCL bit is not set. This means that + * the processor will have a limited amount of time to read the contents of + * the data received on the bus. If the processor reads the I2DAT shift + * register, as it ordinarily would, it could have only one bit-time to + * respond to the interrupt before the received data is overwritten by + * new data. + **********************************************************************/ +uint8_t I2C_MonitorGetDatabuffer(LPC_I2C_TypeDef *I2Cx) +{ + CHECK_PARAM(PARAM_I2Cx(I2Cx)); + return ((uint8_t)(I2Cx->I2DATA_BUFFER)); +} + +/*********************************************************************//** + * @brief Get data from I2C data buffer in monitor mode. + * @param[in] I2Cx I2C peripheral selected, should be + * - LPC_I2C0 + * - LPC_I2C1 + * - LPC_I2C2 + * @return None + * Note: In monitor mode, the I2C module may lose the ability to stretch + * the clock (stall the bus) if the ENA_SCL bit is not set. This means that + * the processor will have a limited amount of time to read the contents of + * the data received on the bus. If the processor reads the I2DAT shift + * register, as it ordinarily would, it could have only one bit-time to + * respond to the interrupt before the received data is overwritten by + * new data. + **********************************************************************/ +BOOL_8 I2C_MonitorHandler(LPC_I2C_TypeDef *I2Cx, uint8_t *buffer, uint32_t size) +{ + BOOL_8 ret=FALSE; + + I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; + + buffer[I2C_MonitorBufferIndex] = (uint8_t)(I2Cx->I2DATA_BUFFER); + I2C_MonitorBufferIndex++; + if(I2C_MonitorBufferIndex >= size) + { + ret = TRUE; + } + return ret; +} +/*********************************************************************//** + * @brief Get status of Master Transfer + * @param[in] I2Cx I2C peripheral selected, should be: + * - LPC_I2C0 + * - LPC_I2C1 + * - LPC_I2C2 + * @return Master transfer status, could be: + * - TRUE master transfer completed + * - FALSE master transfer have not completed yet + **********************************************************************/ +uint32_t I2C_MasterTransferComplete(LPC_I2C_TypeDef *I2Cx) +{ + uint32_t retval, tmp; + tmp = I2C_getNum(I2Cx); + retval = I2C_MasterComplete[tmp]; + I2C_MasterComplete[tmp] = FALSE; + return retval; +} + +/*********************************************************************//** + * @brief Get status of Slave Transfer + * @param[in] I2Cx I2C peripheral selected, should be: + * - LPC_I2C0 + * - LPC_I2C1 + * - LPC_I2C2 + * @return Complete status, could be: TRUE/FALSE + **********************************************************************/ +uint32_t I2C_SlaveTransferComplete(LPC_I2C_TypeDef *I2Cx) +{ + uint32_t retval, tmp; + tmp = I2C_getNum(I2Cx); + retval = I2C_SlaveComplete[tmp]; + I2C_SlaveComplete[tmp] = FALSE; + return retval; +} + + + +/** + * @} + */ + +#endif /* _I2C */ + +/** + * @} + */ + +/* --------------------------------- End Of File ------------------------------ */ diff --git a/arch/arm/lpc17xx/Drivers/source/lpc17xx_i2s.c b/arch/arm/lpc17xx/Drivers/source/lpc17xx_i2s.c new file mode 100644 index 0000000..e151edb --- /dev/null +++ b/arch/arm/lpc17xx/Drivers/source/lpc17xx_i2s.c @@ -0,0 +1,642 @@ +/***********************************************************************//** + * @file lpc17xx_i2s.c + * @brief Contains all functions support for I2S firmware library on LPC17xx + * @version 3.0 + * @date 18. June. 2010 + * @author NXP MCU SW Application Team + ************************************************************************** + * Software that is described herein is for illustrative purposes only + * which provides customers with programming information regarding the + * products. This software is supplied "AS IS" without any warranties. + * NXP Semiconductors assumes no responsibility or liability for the + * use of the software, conveys no license or title under any patent, + * copyright, or mask work right to the product. NXP Semiconductors + * reserves the right to make changes in the software without + * notification. NXP Semiconductors also make no representation or + * warranty that such application will be suitable for the specified + * use without further testing or modification. + **********************************************************************/ + +/* Peripheral group ----------------------------------------------------------- */ +/** @addtogroup I2S + * @{ + */ + +/* Includes ------------------------------------------------------------------- */ +#include "lpc17xx_i2s.h" +#include "lpc17xx_clkpwr.h" + + +/* If this source file built with example, the LPC17xx FW library configuration + * file in each example directory ("lpc17xx_libcfg.h") must be included, + * otherwise the default FW library configuration file must be included instead + */ +#ifdef __BUILD_WITH_EXAMPLE__ +#include "lpc17xx_libcfg.h" +#else +#include "lpc17xx_libcfg_default.h" +#endif /* __BUILD_WITH_EXAMPLE__ */ + + +#ifdef _I2S + +/* Private Functions ---------------------------------------------------------- */ + +static uint8_t i2s_GetWordWidth(LPC_I2S_TypeDef *I2Sx, uint8_t TRMode); +static uint8_t i2s_GetChannel(LPC_I2S_TypeDef *I2Sx, uint8_t TRMode); + +/********************************************************************//** + * @brief Get I2S wordwidth value + * @param[in] I2Sx I2S peripheral selected, should be: LPC_I2S + * @param[in] TRMode is the I2S mode, should be: + * - I2S_TX_MODE = 0: transmit mode + * - I2S_RX_MODE = 1: receive mode + * @return The wordwidth value, should be: 8,16 or 32 + *********************************************************************/ +static uint8_t i2s_GetWordWidth(LPC_I2S_TypeDef *I2Sx, uint8_t TRMode) { + uint8_t value; + + CHECK_PARAM(PARAM_I2Sx(I2Sx)); + CHECK_PARAM(PARAM_I2S_TRX(TRMode)); + + if (TRMode == I2S_TX_MODE) { + value = (I2Sx->I2SDAO) & 0x03; /* get wordwidth bit */ + } else { + value = (I2Sx->I2SDAI) & 0x03; /* get wordwidth bit */ + } + switch (value) { + case I2S_WORDWIDTH_8: + return 8; + case I2S_WORDWIDTH_16: + return 16; + default: + return 32; + } +} + +/********************************************************************//** + * @brief Get I2S channel value + * @param[in] I2Sx I2S peripheral selected, should be: LPC_I2S + * @param[in] TRMode is the I2S mode, should be: + * - I2S_TX_MODE = 0: transmit mode + * - I2S_RX_MODE = 1: receive mode + * @return The channel value, should be: 1(mono) or 2(stereo) + *********************************************************************/ +static uint8_t i2s_GetChannel(LPC_I2S_TypeDef *I2Sx, uint8_t TRMode) { + uint8_t value; + + CHECK_PARAM(PARAM_I2Sx(I2Sx)); + CHECK_PARAM(PARAM_I2S_TRX(TRMode)); + + if (TRMode == I2S_TX_MODE) { + value = (I2Sx->I2SDAO) & 0x04; /* get bit[2] */ + } else { + value = (I2Sx->I2SDAI) & 0x04; /* get bit[2] */ + } + if(value == I2S_MONO) return 1; + return 2; +} + +/* End of Private Functions --------------------------------------------------- */ + + +/* Public Functions ----------------------------------------------------------- */ +/** @addtogroup I2S_Public_Functions + * @{ + */ + +/********************************************************************//** + * @brief Initialize I2S + * - Turn on power and clock + * @param[in] I2Sx I2S peripheral selected, should be: LPC_I2S + * @return none + *********************************************************************/ +void I2S_Init(LPC_I2S_TypeDef *I2Sx) { + CHECK_PARAM(PARAM_I2Sx(I2Sx)); + + // Turn on power and clock + CLKPWR_ConfigPPWR(CLKPWR_PCONP_PCI2S, ENABLE); + LPC_I2S->I2SDAI = LPC_I2S->I2SDAO = 0x00; +} + +/********************************************************************//** + * @brief Configuration I2S, setting: + * - master/slave mode + * - wordwidth value + * - channel mode + * @param[in] I2Sx I2S peripheral selected, should be: LPC_I2S + * @param[in] TRMode transmit/receive mode, should be: + * - I2S_TX_MODE = 0: transmit mode + * - I2S_RX_MODE = 1: receive mode + * @param[in] ConfigStruct pointer to I2S_CFG_Type structure + * which will be initialized. + * @return none + *********************************************************************/ +void I2S_Config(LPC_I2S_TypeDef *I2Sx, uint8_t TRMode, I2S_CFG_Type* ConfigStruct) +{ + uint32_t bps, config; + + CHECK_PARAM(PARAM_I2Sx(I2Sx)); + + CHECK_PARAM(PARAM_I2S_WORDWIDTH(ConfigStruct->wordwidth)); + CHECK_PARAM(PARAM_I2S_CHANNEL(ConfigStruct->mono)); + CHECK_PARAM(PARAM_I2S_STOP(ConfigStruct->stop)); + CHECK_PARAM(PARAM_I2S_RESET(ConfigStruct->reset)); + CHECK_PARAM(PARAM_I2S_WS_SEL(ConfigStruct->ws_sel)); + CHECK_PARAM(PARAM_I2S_MUTE(ConfigStruct->mute)); + + /* Setup clock */ + bps = (ConfigStruct->wordwidth +1)*8; + + /* Calculate audio config */ + config = (bps - 1)<<6 | (ConfigStruct->ws_sel)<<5 | (ConfigStruct->reset)<<4 | + (ConfigStruct->stop)<<3 | (ConfigStruct->mono)<<2 | (ConfigStruct->wordwidth); + + if(TRMode == I2S_RX_MODE){ + LPC_I2S->I2SDAI = config; + }else{ + LPC_I2S->I2SDAO = config; + } +} + +/********************************************************************//** + * @brief DeInitial both I2S transmit or receive + * @param[in] I2Sx I2S peripheral selected, should be: LPC_I2S + * @return none + *********************************************************************/ +void I2S_DeInit(LPC_I2S_TypeDef *I2Sx) { + CHECK_PARAM(PARAM_I2Sx(I2Sx)); + + // Turn off power and clock + CLKPWR_ConfigPPWR(CLKPWR_PCONP_PCI2S, DISABLE); +} + +/********************************************************************//** + * @brief Get I2S Buffer Level + * @param[in] I2Sx I2S peripheral selected, should be: LPC_I2S + * @param[in] TRMode Transmit/receive mode, should be: + * - I2S_TX_MODE = 0: transmit mode + * - I2S_RX_MODE = 1: receive mode + * @return current level of Transmit/Receive Buffer + *********************************************************************/ +uint8_t I2S_GetLevel(LPC_I2S_TypeDef *I2Sx, uint8_t TRMode) +{ + CHECK_PARAM(PARAM_I2Sx(I2Sx)); + CHECK_PARAM(PARAM_I2S_TRX(TRMode)); + + if(TRMode == I2S_TX_MODE) + { + return ((I2Sx->I2SSTATE >> 16) & 0xFF); + } + else + { + return ((I2Sx->I2SSTATE >> 8) & 0xFF); + } +} + +/********************************************************************//** + * @brief I2S Start: clear all STOP,RESET and MUTE bit, ready to operate + * @param[in] I2Sx I2S peripheral selected, should be: LPC_I2S + * @return none + *********************************************************************/ +void I2S_Start(LPC_I2S_TypeDef *I2Sx) +{ + //Clear STOP,RESET and MUTE bit + I2Sx->I2SDAO &= ~I2S_DAI_RESET; + I2Sx->I2SDAI &= ~I2S_DAI_RESET; + I2Sx->I2SDAO &= ~I2S_DAI_STOP; + I2Sx->I2SDAI &= ~I2S_DAI_STOP; + I2Sx->I2SDAO &= ~I2S_DAI_MUTE; +} + +/********************************************************************//** + * @brief I2S Send data + * @param[in] I2Sx I2S peripheral selected, should be: LPC_I2S + * @param[in] BufferData pointer to uint32_t is the data will be send + * @return none + *********************************************************************/ +void I2S_Send(LPC_I2S_TypeDef *I2Sx, uint32_t BufferData) { + CHECK_PARAM(PARAM_I2Sx(I2Sx)); + + I2Sx->I2STXFIFO = BufferData; +} + +/********************************************************************//** + * @brief I2S Receive Data + * @param[in] I2Sx pointer to LPC_I2S_TypeDef + * @return received value + *********************************************************************/ +uint32_t I2S_Receive(LPC_I2S_TypeDef* I2Sx) { + CHECK_PARAM(PARAM_I2Sx(I2Sx)); + + return (I2Sx->I2SRXFIFO); + +} + +/********************************************************************//** + * @brief I2S Pause + * @param[in] I2Sx I2S peripheral selected, should be: LPC_I2S + * @param[in] TRMode is transmit/receive mode, should be: + * - I2S_TX_MODE = 0: transmit mode + * - I2S_RX_MODE = 1: receive mode + * @return none + *********************************************************************/ +void I2S_Pause(LPC_I2S_TypeDef *I2Sx, uint8_t TRMode) { + CHECK_PARAM(PARAM_I2Sx(I2Sx)); + CHECK_PARAM(PARAM_I2S_TRX(TRMode)); + + if (TRMode == I2S_TX_MODE) //Transmit mode + { + I2Sx->I2SDAO |= I2S_DAO_STOP; + } else //Receive mode + { + I2Sx->I2SDAI |= I2S_DAI_STOP; + } +} + +/********************************************************************//** + * @brief I2S Mute + * @param[in] I2Sx I2S peripheral selected, should be: LPC_I2S + * @param[in] TRMode is transmit/receive mode, should be: + * - I2S_TX_MODE = 0: transmit mode + * - I2S_RX_MODE = 1: receive mode + * @return none + *********************************************************************/ +void I2S_Mute(LPC_I2S_TypeDef *I2Sx, uint8_t TRMode) { + CHECK_PARAM(PARAM_I2Sx(I2Sx)); + CHECK_PARAM(PARAM_I2S_TRX(TRMode)); + + if (TRMode == I2S_TX_MODE) //Transmit mode + { + I2Sx->I2SDAO |= I2S_DAO_MUTE; + } else //Receive mode + { + I2Sx->I2SDAI |= I2S_DAI_MUTE; + } +} + +/********************************************************************//** + * @brief I2S Stop + * @param[in] I2Sx I2S peripheral selected, should be: LPC_I2S + * @param[in] TRMode is transmit/receive mode, should be: + * - I2S_TX_MODE = 0: transmit mode + * - I2S_RX_MODE = 1: receive mode + * @return none + *********************************************************************/ +void I2S_Stop(LPC_I2S_TypeDef *I2Sx, uint8_t TRMode) { + CHECK_PARAM(PARAM_I2Sx(I2Sx)); + CHECK_PARAM(PARAM_I2S_TRX(TRMode)); + + if (TRMode == I2S_TX_MODE) //Transmit mode + { + I2Sx->I2SDAO &= ~I2S_DAO_MUTE; + I2Sx->I2SDAO |= I2S_DAO_STOP; + I2Sx->I2SDAO |= I2S_DAO_RESET; + } else //Receive mode + { + I2Sx->I2SDAI |= I2S_DAI_STOP; + I2Sx->I2SDAI |= I2S_DAI_RESET; + } +} + +/********************************************************************//** + * @brief Set frequency for I2S + * @param[in] I2Sx I2S peripheral selected, should be: LPC_I2S + * @param[in] Freq is the frequency for I2S will be set. It can range + * from 16-96 kHz(16, 22.05, 32, 44.1, 48, 96kHz) + * @param[in] TRMode is transmit/receive mode, should be: + * - I2S_TX_MODE = 0: transmit mode + * - I2S_RX_MODE = 1: receive mode + * @return Status: ERROR or SUCCESS + *********************************************************************/ +Status I2S_FreqConfig(LPC_I2S_TypeDef *I2Sx, uint32_t Freq, uint8_t TRMode) { + + /* Calculate bit rate + * The formula is: + * bit_rate = channel*wordwidth - 1 + * 48kHz sample rate for 16 bit stereo date requires + * a bit rate of 48000*16*2=1536MHz (MCLK) + */ + uint32_t i2sPclk; + uint64_t divider; + uint8_t bitrate, channel, wordwidth; + uint32_t x, y; + uint16_t dif; + uint16_t error; + uint8_t x_divide, y_divide; + uint16_t ErrorOptimal = 0xFFFF; + + CHECK_PARAM(PARAM_I2Sx(I2Sx)); + CHECK_PARAM(PRAM_I2S_FREQ(Freq)); + CHECK_PARAM(PARAM_I2S_TRX(TRMode)); + + i2sPclk = CLKPWR_GetPCLK(CLKPWR_PCLKSEL_I2S); + if(TRMode == I2S_TX_MODE) + { + channel = i2s_GetChannel(I2Sx,I2S_TX_MODE); + wordwidth = i2s_GetWordWidth(I2Sx,I2S_TX_MODE); + } + else + { + channel = i2s_GetChannel(I2Sx,I2S_RX_MODE); + wordwidth = i2s_GetWordWidth(I2Sx,I2S_RX_MODE); + } + bitrate = channel * wordwidth - 1; + if (TRMode == I2S_TX_MODE)// Transmitter + { + I2Sx->I2STXBITRATE = bitrate; + } else //Receiver + { + I2Sx->I2SRXBITRATE = bitrate; + } + /* Calculate X and Y divider + * The MCLK rate for the I2S transmitter is determined by the value + * in the I2STXRATE/I2SRXRATE register. The required I2STXRATE/I2SRXRATE + * setting depends on the desired audio sample rate desired, the format + * (stereo/mono) used, and the data size. + * The formula is: + * I2S_MCLK = PCLK * (X/Y) / 2 + * We have: + * I2S_MCLK = Freq * bit_rate; + * So: (X/Y) = (Freq * bit_rate)/PCLK*2 + * We use a loop function to chose the most suitable X,Y value + */ + + divider = ((uint64_t)(Freq *( bitrate+1)* 2)<<16) / i2sPclk; + for (y = 255; y > 0; y--) { + x = y * divider; + dif = x & 0xFFFF; + if(dif>0x8000) error = 0x10000-dif; + else error = dif; + if (error == 0) + { + y_divide = y; + break; + } + else if (error < ErrorOptimal) + { + ErrorOptimal = error; + y_divide = y; + } + } + x_divide = (y_divide * Freq *( bitrate+1)* 2)/i2sPclk; + if (TRMode == I2S_TX_MODE)// Transmitter + { + I2Sx->I2STXRATE = y_divide | (x_divide << 8); + } else //Receiver + { + I2Sx->I2SRXRATE = y_divide | (x_divide << 8); + } + return SUCCESS; +} + +/********************************************************************//** + * @brief I2S set bitrate + * @param[in] I2Sx I2S peripheral selected, should be: LPC_I2S + * @param[in] bitrate value will be set, it can be calculate as follows: + * bitrate = channel * wordwidth - 1 + * bitrate value should be in range: 0 .. 63 + * @param[in] TRMode is transmit/receive mode, should be: + * - I2S_TX_MODE = 0: transmit mode + * - I2S_RX_MODE = 1: receive mode + * @return none + *********************************************************************/ +void I2S_SetBitRate(LPC_I2S_TypeDef *I2Sx, uint8_t bitrate, uint8_t TRMode) +{ + CHECK_PARAM(PARAM_I2Sx(I2Sx)); + CHECK_PARAM(PARAM_I2S_BITRATE(bitrate)); + CHECK_PARAM(PARAM_I2S_TRX(TRMode)); + + if(TRMode == I2S_TX_MODE) + { + I2Sx->I2STXBITRATE = bitrate; + } + else + { + I2Sx->I2SRXBITRATE = bitrate; + } +} + +/********************************************************************//** + * @brief Configuration operating mode for I2S + * @param[in] I2Sx I2S peripheral selected, should be: LPC_I2S + * @param[in] ModeConfig pointer to I2S_MODEConf_Type will be used to + * configure + * @param[in] TRMode is transmit/receive mode, should be: + * - I2S_TX_MODE = 0: transmit mode + * - I2S_RX_MODE = 1: receive mode + * @return none + *********************************************************************/ +void I2S_ModeConfig(LPC_I2S_TypeDef *I2Sx, I2S_MODEConf_Type* ModeConfig, + uint8_t TRMode) +{ + CHECK_PARAM(PARAM_I2Sx(I2Sx)); + CHECK_PARAM(PARAM_I2S_CLKSEL(ModeConfig->clksel)); + CHECK_PARAM(PARAM_I2S_4PIN(ModeConfig->fpin)); + CHECK_PARAM(PARAM_I2S_MCLK(ModeConfig->mcena)); + CHECK_PARAM(PARAM_I2S_TRX(TRMode)); + + if (TRMode == I2S_TX_MODE) { + I2Sx->I2STXMODE &= ~0x0F; //clear bit 3:0 in I2STXMODE register + if (ModeConfig->clksel == I2S_CLKSEL_MCLK) { + I2Sx->I2STXMODE |= 0x02; + } + if (ModeConfig->fpin == I2S_4PIN_ENABLE) { + I2Sx->I2STXMODE |= (1 << 2); + } + if (ModeConfig->mcena == I2S_MCLK_ENABLE) { + I2Sx->I2STXMODE |= (1 << 3); + } + } else { + I2Sx->I2SRXMODE &= ~0x0F; //clear bit 3:0 in I2STXMODE register + if (ModeConfig->clksel == I2S_CLKSEL_MCLK) { + I2Sx->I2SRXMODE |= 0x02; + } + if (ModeConfig->fpin == I2S_4PIN_ENABLE) { + I2Sx->I2SRXMODE |= (1 << 2); + } + if (ModeConfig->mcena == I2S_MCLK_ENABLE) { + I2Sx->I2SRXMODE |= (1 << 3); + } + } +} + +/********************************************************************//** + * @brief Configure DMA operation for I2S + * @param[in] I2Sx I2S peripheral selected, should be: LPC_I2S + * @param[in] DMAConfig pointer to I2S_DMAConf_Type will be used to configure + * @param[in] TRMode is transmit/receive mode, should be: + * - I2S_TX_MODE = 0: transmit mode + * - I2S_RX_MODE = 1: receive mode + * @return none + *********************************************************************/ +void I2S_DMAConfig(LPC_I2S_TypeDef *I2Sx, I2S_DMAConf_Type* DMAConfig, + uint8_t TRMode) +{ + CHECK_PARAM(PARAM_I2Sx(I2Sx)); + CHECK_PARAM(PARAM_I2S_DMA(DMAConfig->DMAIndex)); + CHECK_PARAM(PARAM_I2S_DMA_DEPTH(DMAConfig->depth)); + CHECK_PARAM(PARAM_I2S_TRX(TRMode)); + + if (TRMode == I2S_RX_MODE) { + if (DMAConfig->DMAIndex == I2S_DMA_1) { + LPC_I2S->I2SDMA1 = (DMAConfig->depth) << 8; + } else { + LPC_I2S->I2SDMA2 = (DMAConfig->depth) << 8; + } + } else { + if (DMAConfig->DMAIndex == I2S_DMA_1) { + LPC_I2S->I2SDMA1 = (DMAConfig->depth) << 16; + } else { + LPC_I2S->I2SDMA2 = (DMAConfig->depth) << 16; + } + } +} + +/********************************************************************//** + * @brief Enable/Disable DMA operation for I2S + * @param[in] I2Sx: I2S peripheral selected, should be: LPC_I2S + * @param[in] DMAIndex chose what DMA is used, should be: + * - I2S_DMA_1 = 0: DMA1 + * - I2S_DMA_2 = 1: DMA2 + * @param[in] TRMode is transmit/receive mode, should be: + * - I2S_TX_MODE = 0: transmit mode + * - I2S_RX_MODE = 1: receive mode + * @param[in] NewState is new state of DMA operation, should be: + * - ENABLE + * - DISABLE + * @return none + *********************************************************************/ +void I2S_DMACmd(LPC_I2S_TypeDef *I2Sx, uint8_t DMAIndex, uint8_t TRMode, + FunctionalState NewState) +{ + CHECK_PARAM(PARAM_I2Sx(I2Sx)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState)); + CHECK_PARAM(PARAM_I2S_DMA(DMAIndex)); + CHECK_PARAM(PARAM_I2S_TRX(TRMode)); + + if (TRMode == I2S_RX_MODE) { + if (DMAIndex == I2S_DMA_1) { + if (NewState == ENABLE) + I2Sx->I2SDMA1 |= 0x01; + else + I2Sx->I2SDMA1 &= ~0x01; + } else { + if (NewState == ENABLE) + I2Sx->I2SDMA2 |= 0x01; + else + I2Sx->I2SDMA2 &= ~0x01; + } + } else { + if (DMAIndex == I2S_DMA_1) { + if (NewState == ENABLE) + I2Sx->I2SDMA1 |= 0x02; + else + I2Sx->I2SDMA1 &= ~0x02; + } else { + if (NewState == ENABLE) + I2Sx->I2SDMA2 |= 0x02; + else + I2Sx->I2SDMA2 &= ~0x02; + } + } +} + +/********************************************************************//** + * @brief Configure IRQ for I2S + * @param[in] I2Sx I2S peripheral selected, should be: LPC_I2S + * @param[in] TRMode is transmit/receive mode, should be: + * - I2S_TX_MODE = 0: transmit mode + * - I2S_RX_MODE = 1: receive mode + * @param[in] level is the FIFO level that triggers IRQ request + * @return none + *********************************************************************/ +void I2S_IRQConfig(LPC_I2S_TypeDef *I2Sx, uint8_t TRMode, uint8_t level) { + CHECK_PARAM(PARAM_I2Sx(I2Sx)); + CHECK_PARAM(PARAM_I2S_TRX(TRMode)); + CHECK_PARAM(PARAM_I2S_IRQ_LEVEL(level)); + + if (TRMode == I2S_RX_MODE) { + I2Sx->I2SIRQ |= (level << 8); + } else { + I2Sx->I2SIRQ |= (level << 16); + } +} + +/********************************************************************//** + * @brief Enable/Disable IRQ for I2S + * @param[in] I2Sx I2S peripheral selected, should be: LPC_I2S + * @param[in] TRMode is transmit/receive mode, should be: + * - I2S_TX_MODE = 0: transmit mode + * - I2S_RX_MODE = 1: receive mode + * @param[in] NewState is new state of DMA operation, should be: + * - ENABLE + * - DISABLE + * @return none + *********************************************************************/ +void I2S_IRQCmd(LPC_I2S_TypeDef *I2Sx, uint8_t TRMode, FunctionalState NewState) { + CHECK_PARAM(PARAM_I2Sx(I2Sx)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState)); + + if (TRMode == I2S_RX_MODE) { + if (NewState == ENABLE) + I2Sx->I2SIRQ |= 0x01; + else + I2Sx->I2SIRQ &= ~0x01; + //Enable DMA + + } else { + if (NewState == ENABLE) + I2Sx->I2SIRQ |= 0x02; + else + I2Sx->I2SIRQ &= ~0x02; + } +} + +/********************************************************************//** + * @brief Get I2S interrupt status + * @param[in] I2Sx I2S peripheral selected, should be: LPC_I2S + * @param[in] TRMode is transmit/receive mode, should be: + * - I2S_TX_MODE = 0: transmit mode + * - I2S_RX_MODE = 1: receive mode + * @return FunctionState should be: + * - ENABLE: interrupt is enable + * - DISABLE: interrupt is disable + *********************************************************************/ +FunctionalState I2S_GetIRQStatus(LPC_I2S_TypeDef *I2Sx,uint8_t TRMode) +{ + CHECK_PARAM(PARAM_I2Sx(I2Sx)); + if(TRMode == I2S_TX_MODE) + return ((I2Sx->I2SIRQ >> 1)&0x01); + else + return ((I2Sx->I2SIRQ)&0x01); +} + +/********************************************************************//** + * @brief Get I2S interrupt depth + * @param[in] I2Sx I2S peripheral selected, should be: LPC_I2S + * @param[in] TRMode is transmit/receive mode, should be: + * - I2S_TX_MODE = 0: transmit mode + * - I2S_RX_MODE = 1: receive mode + * @return depth of FIFO level on which to create an irq request + *********************************************************************/ +uint8_t I2S_GetIRQDepth(LPC_I2S_TypeDef *I2Sx,uint8_t TRMode) +{ + CHECK_PARAM(PARAM_I2Sx(I2Sx)); + if(TRMode == I2S_TX_MODE) + return (((I2Sx->I2SIRQ)>>16)&0xFF); + else + return (((I2Sx->I2SIRQ)>>8)&0xFF); +} +/** + * @} + */ + +#endif /* _I2S */ + +/** + * @} + */ + +/* --------------------------------- End Of File ------------------------------ */ + diff --git a/arch/arm/lpc17xx/Drivers/source/lpc17xx_libcfg_default.c b/arch/arm/lpc17xx/Drivers/source/lpc17xx_libcfg_default.c new file mode 100644 index 0000000..8c7542f --- /dev/null +++ b/arch/arm/lpc17xx/Drivers/source/lpc17xx_libcfg_default.c @@ -0,0 +1,64 @@ +/***********************************************************************//** + * @file lpc17xx_libcfg_default.c + * @brief Library configuration source file (default), + * used to build library without examples. + * @version 2.0 + * @date 21. May. 2010 + * @author NXP MCU SW Application Team + ************************************************************************** + * Software that is described herein is for illustrative purposes only + * which provides customers with programming information regarding the + * products. This software is supplied "AS IS" without any warranties. + * NXP Semiconductors assumes no responsibility or liability for the + * use of the software, conveys no license or title under any patent, + * copyright, or mask work right to the product. NXP Semiconductors + * reserves the right to make changes in the software without + * notification. NXP Semiconductors also make no representation or + * warranty that such application will be suitable for the specified + * use without further testing or modification. + **************************************************************************/ + +/* Library group ----------------------------------------------------------- */ +/** @addtogroup LIBCFG_DEFAULT + * @{ + */ + +/* Includes ------------------------------------------------------------------- */ +#include "lpc17xx_libcfg_default.h" + +/* Public Functions ----------------------------------------------------------- */ +/** @addtogroup LIBCFG_DEFAULT_Public_Functions + * @{ + */ + +#ifndef __BUILD_WITH_EXAMPLE__ + +#ifdef DEBUG +/******************************************************************************* +* @brief Reports the name of the source file and the source line number +* where the CHECK_PARAM error has occurred. +* @param[in] file Pointer to the source file name +* @param[in] line assert_param error line source number +* @return None +*******************************************************************************/ +void check_failed(uint8_t *file, uint32_t line) +{ + /* User can add his own implementation to report the file name and line number, + ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ + + /* Infinite loop */ + while(1); +} +#endif /* DEBUG */ + +#endif /* __BUILD_WITH_EXAMPLE__ */ + +/** + * @} + */ + +/** + * @} + */ + +/* --------------------------------- End Of File ------------------------------ */ diff --git a/arch/arm/lpc17xx/Drivers/source/lpc17xx_mcpwm.c b/arch/arm/lpc17xx/Drivers/source/lpc17xx_mcpwm.c new file mode 100644 index 0000000..d4692d1 --- /dev/null +++ b/arch/arm/lpc17xx/Drivers/source/lpc17xx_mcpwm.c @@ -0,0 +1,497 @@ +/***********************************************************************//** + * @file lpc17xx_mcpwm.c + * @brief Contains all functions support for Motor Control PWM firmware + * library on LPC17xx + * @version 2.0 + * @date 21. May. 2010 + * @author NXP MCU SW Application Team + ************************************************************************** + * Software that is described herein is for illustrative purposes only + * which provides customers with programming information regarding the + * products. This software is supplied "AS IS" without any warranties. + * NXP Semiconductors assumes no responsibility or liability for the + * use of the software, conveys no license or title under any patent, + * copyright, or mask work right to the product. NXP Semiconductors + * reserves the right to make changes in the software without + * notification. NXP Semiconductors also make no representation or + * warranty that such application will be suitable for the specified + * use without further testing or modification. + **********************************************************************/ + +/* Peripheral group ----------------------------------------------------------- */ +/** @addtogroup MCPWM + * @{ + */ + +/* Includes ------------------------------------------------------------------- */ +#include "lpc17xx_mcpwm.h" +#include "lpc17xx_clkpwr.h" + +/* If this source file built with example, the LPC17xx FW library configuration + * file in each example directory ("lpc17xx_libcfg.h") must be included, + * otherwise the default FW library configuration file must be included instead + */ +#ifdef __BUILD_WITH_EXAMPLE__ +#include "lpc17xx_libcfg.h" +#else +#include "lpc17xx_libcfg_default.h" +#endif /* __BUILD_WITH_EXAMPLE__ */ + + +#ifdef _MCPWM + +/* Public Functions ----------------------------------------------------------- */ +/** @addtogroup MCPWM_Public_Functions + * @{ + */ + +/*********************************************************************//** + * @brief Initializes the MCPWM peripheral + * @param[in] MCPWMx Motor Control PWM peripheral selected, + * Should be: LPC_MCPWM + * @return None + **********************************************************************/ +void MCPWM_Init(LPC_MCPWM_TypeDef *MCPWMx) +{ + + /* Turn On MCPWM PCLK */ + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCMC, ENABLE); + /* As default, peripheral clock for MCPWM module + * is set to FCCLK / 2 */ + // CLKPWR_SetPCLKDiv(CLKPWR_PCLKSEL_MC, CLKPWR_PCLKSEL_CCLK_DIV_2); + + MCPWMx->MCCAP_CLR = MCPWM_CAPCLR_CAP(0) | MCPWM_CAPCLR_CAP(1) | MCPWM_CAPCLR_CAP(2); + MCPWMx->MCINTFLAG_CLR = MCPWM_INT_ILIM(0) | MCPWM_INT_ILIM(1) | MCPWM_INT_ILIM(2) \ + | MCPWM_INT_IMAT(0) | MCPWM_INT_IMAT(1) | MCPWM_INT_IMAT(2) \ + | MCPWM_INT_ICAP(0) | MCPWM_INT_ICAP(1) | MCPWM_INT_ICAP(2); + MCPWMx->MCINTEN_CLR = MCPWM_INT_ILIM(0) | MCPWM_INT_ILIM(1) | MCPWM_INT_ILIM(2) \ + | MCPWM_INT_IMAT(0) | MCPWM_INT_IMAT(1) | MCPWM_INT_IMAT(2) \ + | MCPWM_INT_ICAP(0) | MCPWM_INT_ICAP(1) | MCPWM_INT_ICAP(2); +} + + +/*********************************************************************//** + * @brief Configures each channel in MCPWM peripheral according to the + * specified parameters in the MCPWM_CHANNEL_CFG_Type. + * @param[in] MCPWMx Motor Control PWM peripheral selected + * should be: LPC_MCPWM + * @param[in] channelNum Channel number, should be: 0..2. + * @param[in] channelSetup Pointer to a MCPWM_CHANNEL_CFG_Type structure +* that contains the configuration information for the +* specified MCPWM channel. + * @return None + **********************************************************************/ +void MCPWM_ConfigChannel(LPC_MCPWM_TypeDef *MCPWMx, uint32_t channelNum, + MCPWM_CHANNEL_CFG_Type * channelSetup) +{ + if ((channelNum >= 0) && (channelNum <= 2)) { + if (channelNum == 0) { + MCPWMx->MCTIM0 = channelSetup->channelTimercounterValue; + MCPWMx->MCPER0 = channelSetup->channelPeriodValue; + MCPWMx->MCPW0 = channelSetup->channelPulsewidthValue; + } else if (channelNum == 1) { + MCPWMx->MCTIM1 = channelSetup->channelTimercounterValue; + MCPWMx->MCPER1 = channelSetup->channelPeriodValue; + MCPWMx->MCPW1 = channelSetup->channelPulsewidthValue; + } else if (channelNum == 2) { + MCPWMx->MCTIM2 = channelSetup->channelTimercounterValue; + MCPWMx->MCPER2 = channelSetup->channelPeriodValue; + MCPWMx->MCPW2 = channelSetup->channelPulsewidthValue; + } else { + return; + } + + if (channelSetup->channelType /* == MCPWM_CHANNEL_CENTER_MODE */){ + MCPWMx->MCCON_SET = MCPWM_CON_CENTER(channelNum); + } else { + MCPWMx->MCCON_CLR = MCPWM_CON_CENTER(channelNum); + } + + if (channelSetup->channelPolarity /* == MCPWM_CHANNEL_PASSIVE_HI */){ + MCPWMx->MCCON_SET = MCPWM_CON_POLAR(channelNum); + } else { + MCPWMx->MCCON_CLR = MCPWM_CON_POLAR(channelNum); + } + + if (channelSetup->channelDeadtimeEnable /* == ENABLE */){ + MCPWMx->MCCON_SET = MCPWM_CON_DTE(channelNum); + MCPWMx->MCDEADTIME &= ~(MCPWM_DT(channelNum, 0x3FF)); + MCPWMx->MCDEADTIME |= MCPWM_DT(channelNum, channelSetup->channelDeadtimeValue); + } else { + MCPWMx->MCCON_CLR = MCPWM_CON_DTE(channelNum); + } + + if (channelSetup->channelUpdateEnable /* == ENABLE */){ + MCPWMx->MCCON_CLR = MCPWM_CON_DISUP(channelNum); + } else { + MCPWMx->MCCON_SET = MCPWM_CON_DISUP(channelNum); + } + } +} + + +/*********************************************************************//** + * @brief Write to MCPWM shadow registers - Update the value for period + * and pulse width in MCPWM peripheral. + * @param[in] MCPWMx Motor Control PWM peripheral selected + * Should be: LPC_MCPWM + * @param[in] channelNum Channel Number, should be: 0..2. + * @param[in] channelSetup Pointer to a MCPWM_CHANNEL_CFG_Type structure +* that contains the configuration information for the +* specified MCPWM channel. + * @return None + **********************************************************************/ +void MCPWM_WriteToShadow(LPC_MCPWM_TypeDef *MCPWMx, uint32_t channelNum, + MCPWM_CHANNEL_CFG_Type *channelSetup) +{ + if (channelNum == 0){ + MCPWMx->MCPER0 = channelSetup->channelPeriodValue; + MCPWMx->MCPW0 = channelSetup->channelPulsewidthValue; + } else if (channelNum == 1) { + MCPWMx->MCPER1 = channelSetup->channelPeriodValue; + MCPWMx->MCPW1 = channelSetup->channelPulsewidthValue; + } else if (channelNum == 2) { + MCPWMx->MCPER2 = channelSetup->channelPeriodValue; + MCPWMx->MCPW2 = channelSetup->channelPulsewidthValue; + } +} + + + +/*********************************************************************//** + * @brief Configures capture function in MCPWM peripheral + * @param[in] MCPWMx Motor Control PWM peripheral selected + * Should be: LPC_MCPWM + * @param[in] channelNum MCI (Motor Control Input pin) number + * Should be: 0..2 + * @param[in] captureConfig Pointer to a MCPWM_CAPTURE_CFG_Type structure +* that contains the configuration information for the +* specified MCPWM capture. + * @return + **********************************************************************/ +void MCPWM_ConfigCapture(LPC_MCPWM_TypeDef *MCPWMx, uint32_t channelNum, + MCPWM_CAPTURE_CFG_Type *captureConfig) +{ + if ((channelNum >= 0) && (channelNum <= 2)) { + + if (captureConfig->captureFalling /* == ENABLE */) { + MCPWMx->MCCAPCON_SET = MCPWM_CAPCON_CAPMCI_FE(captureConfig->captureChannel, channelNum); + } else { + MCPWMx->MCCAPCON_CLR = MCPWM_CAPCON_CAPMCI_FE(captureConfig->captureChannel, channelNum); + } + + if (captureConfig->captureRising /* == ENABLE */) { + MCPWMx->MCCAPCON_SET = MCPWM_CAPCON_CAPMCI_RE(captureConfig->captureChannel, channelNum); + } else { + MCPWMx->MCCAPCON_CLR = MCPWM_CAPCON_CAPMCI_RE(captureConfig->captureChannel, channelNum); + } + + if (captureConfig->timerReset /* == ENABLE */){ + MCPWMx->MCCAPCON_SET = MCPWM_CAPCON_RT(captureConfig->captureChannel); + } else { + MCPWMx->MCCAPCON_CLR = MCPWM_CAPCON_RT(captureConfig->captureChannel); + } + + if (captureConfig->hnfEnable /* == ENABLE */){ + MCPWMx->MCCAPCON_SET = MCPWM_CAPCON_HNFCAP(channelNum); + } else { + MCPWMx->MCCAPCON_CLR = MCPWM_CAPCON_HNFCAP(channelNum); + } + } +} + + +/*********************************************************************//** + * @brief Clears current captured value in specified capture channel + * @param[in] MCPWMx Motor Control PWM peripheral selected + * Should be: LPC_MCPWM + * @param[in] captureChannel Capture channel number, should be: 0..2 + * @return None + **********************************************************************/ +void MCPWM_ClearCapture(LPC_MCPWM_TypeDef *MCPWMx, uint32_t captureChannel) +{ + MCPWMx->MCCAP_CLR = MCPWM_CAPCLR_CAP(captureChannel); +} + +/*********************************************************************//** + * @brief Get current captured value in specified capture channel + * @param[in] MCPWMx Motor Control PWM peripheral selected, + * Should be: LPC_MCPWM + * @param[in] captureChannel Capture channel number, should be: 0..2 + * @return None + **********************************************************************/ +uint32_t MCPWM_GetCapture(LPC_MCPWM_TypeDef *MCPWMx, uint32_t captureChannel) +{ + if (captureChannel == 0){ + return (MCPWMx->MCCR0); + } else if (captureChannel == 1) { + return (MCPWMx->MCCR1); + } else if (captureChannel == 2) { + return (MCPWMx->MCCR2); + } + return (0); +} + + +/*********************************************************************//** + * @brief Configures Count control in MCPWM peripheral + * @param[in] MCPWMx Motor Control PWM peripheral selected + * Should be: LPC_MCPWM + * @param[in] channelNum Channel number, should be: 0..2 + * @param[in] countMode Count mode, should be: + * - ENABLE: Enables count mode. + * - DISABLE: Disable count mode, the channel is in timer mode. + * @param[in] countConfig Pointer to a MCPWM_COUNT_CFG_Type structure +* that contains the configuration information for the +* specified MCPWM count control. + * @return None + **********************************************************************/ +void MCPWM_CountConfig(LPC_MCPWM_TypeDef *MCPWMx, uint32_t channelNum, + uint32_t countMode, MCPWM_COUNT_CFG_Type *countConfig) +{ + if ((channelNum >= 0) && (channelNum <= 2)) { + if (countMode /* == ENABLE */){ + MCPWMx->MCCNTCON_SET = MCPWM_CNTCON_CNTR(channelNum); + if (countConfig->countFalling /* == ENABLE */) { + MCPWMx->MCCNTCON_SET = MCPWM_CNTCON_TCMCI_FE(countConfig->counterChannel,channelNum); + } else { + MCPWMx->MCCNTCON_CLR = MCPWM_CNTCON_TCMCI_FE(countConfig->counterChannel,channelNum); + } + if (countConfig->countRising /* == ENABLE */) { + MCPWMx->MCCNTCON_SET = MCPWM_CNTCON_TCMCI_RE(countConfig->counterChannel,channelNum); + } else { + MCPWMx->MCCNTCON_CLR = MCPWM_CNTCON_TCMCI_RE(countConfig->counterChannel,channelNum); + } + } else { + MCPWMx->MCCNTCON_CLR = MCPWM_CNTCON_CNTR(channelNum); + } + } +} + + +/*********************************************************************//** + * @brief Start MCPWM activity for each MCPWM channel + * @param[in] MCPWMx Motor Control PWM peripheral selected + * Should be: LPC_MCPWM + * @param[in] channel0 State of this command on channel 0: + * - ENABLE: 'Start' command will effect on channel 0 + * - DISABLE: 'Start' command will not effect on channel 0 + * @param[in] channel1 State of this command on channel 1: + * - ENABLE: 'Start' command will effect on channel 1 + * - DISABLE: 'Start' command will not effect on channel 1 + * @param[in] channel2 State of this command on channel 2: + * - ENABLE: 'Start' command will effect on channel 2 + * - DISABLE: 'Start' command will not effect on channel 2 + * @return None + **********************************************************************/ +void MCPWM_Start(LPC_MCPWM_TypeDef *MCPWMx, uint32_t channel0, + uint32_t channel1, uint32_t channel2) +{ + uint32_t regVal = 0; + regVal = (channel0 ? MCPWM_CON_RUN(0) : 0) | (channel1 ? MCPWM_CON_RUN(1) : 0) \ + | (channel2 ? MCPWM_CON_RUN(2) : 0); + MCPWMx->MCCON_SET = regVal; +} + + +/*********************************************************************//** + * @brief Stop MCPWM activity for each MCPWM channel + * @param[in] MCPWMx Motor Control PWM peripheral selected + * Should be: LPC_MCPWM + * @param[in] channel0 State of this command on channel 0: + * - ENABLE: 'Stop' command will effect on channel 0 + * - DISABLE: 'Stop' command will not effect on channel 0 + * @param[in] channel1 State of this command on channel 1: + * - ENABLE: 'Stop' command will effect on channel 1 + * - DISABLE: 'Stop' command will not effect on channel 1 + * @param[in] channel2 State of this command on channel 2: + * - ENABLE: 'Stop' command will effect on channel 2 + * - DISABLE: 'Stop' command will not effect on channel 2 + * @return None + **********************************************************************/ +void MCPWM_Stop(LPC_MCPWM_TypeDef *MCPWMx, uint32_t channel0, + uint32_t channel1, uint32_t channel2) +{ + uint32_t regVal = 0; + regVal = (channel0 ? MCPWM_CON_RUN(0) : 0) | (channel1 ? MCPWM_CON_RUN(1) : 0) \ + | (channel2 ? MCPWM_CON_RUN(2) : 0); + MCPWMx->MCCON_CLR = regVal; +} + + +/*********************************************************************//** + * @brief Enables/Disables 3-phase AC motor mode on MCPWM peripheral + * @param[in] MCPWMx Motor Control PWM peripheral selected + * Should be: LPC_MCPWM + * @param[in] acMode State of this command, should be: + * - ENABLE. + * - DISABLE. + * @return None + **********************************************************************/ +void MCPWM_ACMode(LPC_MCPWM_TypeDef *MCPWMx, uint32_t acMode) +{ + if (acMode){ + MCPWMx->MCCON_SET = MCPWM_CON_ACMODE; + } else { + MCPWMx->MCCON_CLR = MCPWM_CON_ACMODE; + } +} + + +/*********************************************************************//** + * @brief Enables/Disables 3-phase DC motor mode on MCPWM peripheral + * @param[in] MCPWMx Motor Control PWM peripheral selected + * Should be: LPC_MCPWM + * @param[in] dcMode State of this command, should be: + * - ENABLE. + * - DISABLE. + * @param[in] outputInvered Polarity of the MCOB outputs for all 3 channels, + * should be: + * - ENABLE: The MCOB outputs have opposite polarity + * from the MCOA outputs. + * - DISABLE: The MCOB outputs have the same basic + * polarity as the MCOA outputs. + * @param[in] outputPattern A value contains bits that enables/disables the specified + * output pins route to the internal MCOA0 signal, should be: + - MCPWM_PATENT_A0: MCOA0 tracks internal MCOA0 + - MCPWM_PATENT_B0: MCOB0 tracks internal MCOA0 + - MCPWM_PATENT_A1: MCOA1 tracks internal MCOA0 + - MCPWM_PATENT_B1: MCOB1 tracks internal MCOA0 + - MCPWM_PATENT_A2: MCOA2 tracks internal MCOA0 + - MCPWM_PATENT_B2: MCOB2 tracks internal MCOA0 + * @return None + * + * Note: all these outputPatent values above can be ORed together for using as input parameter. + **********************************************************************/ +void MCPWM_DCMode(LPC_MCPWM_TypeDef *MCPWMx, uint32_t dcMode, + uint32_t outputInvered, uint32_t outputPattern) +{ + if (dcMode){ + MCPWMx->MCCON_SET = MCPWM_CON_DCMODE; + } else { + MCPWMx->MCCON_CLR = MCPWM_CON_DCMODE; + } + + if (outputInvered) { + MCPWMx->MCCON_SET = MCPWM_CON_INVBDC; + } else { + MCPWMx->MCCON_CLR = MCPWM_CON_INVBDC; + } + + MCPWMx->MCCCP = outputPattern; +} + + +/*********************************************************************//** + * @brief Configures the specified interrupt in MCPWM peripheral + * @param[in] MCPWMx Motor Control PWM peripheral selected + * Should be: LPC_MCPWM + * @param[in] ulIntType Interrupt type, should be: + * - MCPWM_INTFLAG_LIM0: Limit interrupt for channel (0) + * - MCPWM_INTFLAG_MAT0: Match interrupt for channel (0) + * - MCPWM_INTFLAG_CAP0: Capture interrupt for channel (0) + * - MCPWM_INTFLAG_LIM1: Limit interrupt for channel (1) + * - MCPWM_INTFLAG_MAT1: Match interrupt for channel (1) + * - MCPWM_INTFLAG_CAP1: Capture interrupt for channel (1) + * - MCPWM_INTFLAG_LIM2: Limit interrupt for channel (2) + * - MCPWM_INTFLAG_MAT2: Match interrupt for channel (2) + * - MCPWM_INTFLAG_CAP2: Capture interrupt for channel (2) + * - MCPWM_INTFLAG_ABORT: Fast abort interrupt + * @param[in] NewState New State of this command, should be: + * - ENABLE. + * - DISABLE. + * @return None + * + * Note: all these ulIntType values above can be ORed together for using as input parameter. + **********************************************************************/ +void MCPWM_IntConfig(LPC_MCPWM_TypeDef *MCPWMx, uint32_t ulIntType, FunctionalState NewState) +{ + if (NewState) { + MCPWMx->MCINTEN_SET = ulIntType; + } else { + MCPWMx->MCINTEN_CLR = ulIntType; + } +} + + +/*********************************************************************//** + * @brief Sets/Forces the specified interrupt for MCPWM peripheral + * @param[in] MCPWMx Motor Control PWM peripheral selected + * Should be LPC_MCPWM + * @param[in] ulIntType Interrupt type, should be: + * - MCPWM_INTFLAG_LIM0: Limit interrupt for channel (0) + * - MCPWM_INTFLAG_MAT0: Match interrupt for channel (0) + * - MCPWM_INTFLAG_CAP0: Capture interrupt for channel (0) + * - MCPWM_INTFLAG_LIM1: Limit interrupt for channel (1) + * - MCPWM_INTFLAG_MAT1: Match interrupt for channel (1) + * - MCPWM_INTFLAG_CAP1: Capture interrupt for channel (1) + * - MCPWM_INTFLAG_LIM2: Limit interrupt for channel (2) + * - MCPWM_INTFLAG_MAT2: Match interrupt for channel (2) + * - MCPWM_INTFLAG_CAP2: Capture interrupt for channel (2) + * - MCPWM_INTFLAG_ABORT: Fast abort interrupt + * @return None + * Note: all these ulIntType values above can be ORed together for using as input parameter. + **********************************************************************/ +void MCPWM_IntSet(LPC_MCPWM_TypeDef *MCPWMx, uint32_t ulIntType) +{ + MCPWMx->MCINTFLAG_SET = ulIntType; +} + + +/*********************************************************************//** + * @brief Clear the specified interrupt pending for MCPWM peripheral + * @param[in] MCPWMx Motor Control PWM peripheral selected, + * should be: LPC_MCPWM + * @param[in] ulIntType Interrupt type, should be: + * - MCPWM_INTFLAG_LIM0: Limit interrupt for channel (0) + * - MCPWM_INTFLAG_MAT0: Match interrupt for channel (0) + * - MCPWM_INTFLAG_CAP0: Capture interrupt for channel (0) + * - MCPWM_INTFLAG_LIM1: Limit interrupt for channel (1) + * - MCPWM_INTFLAG_MAT1: Match interrupt for channel (1) + * - MCPWM_INTFLAG_CAP1: Capture interrupt for channel (1) + * - MCPWM_INTFLAG_LIM2: Limit interrupt for channel (2) + * - MCPWM_INTFLAG_MAT2: Match interrupt for channel (2) + * - MCPWM_INTFLAG_CAP2: Capture interrupt for channel (2) + * - MCPWM_INTFLAG_ABORT: Fast abort interrupt + * @return None + * Note: all these ulIntType values above can be ORed together for using as input parameter. + **********************************************************************/ +void MCPWM_IntClear(LPC_MCPWM_TypeDef *MCPWMx, uint32_t ulIntType) +{ + MCPWMx->MCINTFLAG_CLR = ulIntType; +} + + +/*********************************************************************//** + * @brief Check whether if the specified interrupt in MCPWM is set or not + * @param[in] MCPWMx Motor Control PWM peripheral selected, + * should be: LPC_MCPWM + * @param[in] ulIntType Interrupt type, should be: + * - MCPWM_INTFLAG_LIM0: Limit interrupt for channel (0) + * - MCPWM_INTFLAG_MAT0: Match interrupt for channel (0) + * - MCPWM_INTFLAG_CAP0: Capture interrupt for channel (0) + * - MCPWM_INTFLAG_LIM1: Limit interrupt for channel (1) + * - MCPWM_INTFLAG_MAT1: Match interrupt for channel (1) + * - MCPWM_INTFLAG_CAP1: Capture interrupt for channel (1) + * - MCPWM_INTFLAG_LIM2: Limit interrupt for channel (2) + * - MCPWM_INTFLAG_MAT2: Match interrupt for channel (2) + * - MCPWM_INTFLAG_CAP2: Capture interrupt for channel (2) + * - MCPWM_INTFLAG_ABORT: Fast abort interrupt + * @return None + **********************************************************************/ +FlagStatus MCPWM_GetIntStatus(LPC_MCPWM_TypeDef *MCPWMx, uint32_t ulIntType) +{ + return ((MCPWMx->MCINTFLAG & ulIntType) ? SET : RESET); +} + +/** + * @} + */ + +#endif /* _MCPWM */ + +/** + * @} + */ + +/* --------------------------------- End Of File ------------------------------ */ diff --git a/arch/arm/lpc17xx/Drivers/source/lpc17xx_nvic.c b/arch/arm/lpc17xx/Drivers/source/lpc17xx_nvic.c new file mode 100644 index 0000000..fba9177 --- /dev/null +++ b/arch/arm/lpc17xx/Drivers/source/lpc17xx_nvic.c @@ -0,0 +1,136 @@ +/***********************************************************************//** + * @file lpc17xx_nvic.c + * @brief Contains all expansion functions support for + * NVIC firmware library on LPC17xx. The main + * NVIC functions are defined in core_cm3.h + * @version 2.0 + * @date 21. May. 2010 + * @author NXP MCU SW Application Team + ************************************************************************** + * Software that is described herein is for illustrative purposes only + * which provides customers with programming information regarding the + * products. This software is supplied "AS IS" without any warranties. + * NXP Semiconductors assumes no responsibility or liability for the + * use of the software, conveys no license or title under any patent, + * copyright, or mask work right to the product. NXP Semiconductors + * reserves the right to make changes in the software without + * notification. NXP Semiconductors also make no representation or + * warranty that such application will be suitable for the specified + * use without further testing or modification. + **********************************************************************/ + +/* Peripheral group ----------------------------------------------------------- */ +/** @addtogroup NVIC + * @{ + */ + +/* Includes ------------------------------------------------------------------- */ +#include "lpc17xx_nvic.h" + + +/* Private Macros ------------------------------------------------------------- */ +/** @addtogroup NVIC_Private_Macros + * @{ + */ + +/* Vector table offset bit mask */ +#define NVIC_VTOR_MASK 0x3FFFFF80 + +/** + * @} + */ + + +/* Public Functions ----------------------------------------------------------- */ +/** @addtogroup NVIC_Public_Functions + * @{ + */ + + +/*****************************************************************************//** + * @brief De-initializes the NVIC peripheral registers to their default + * reset values. + * @param None + * @return None + * + * These following NVIC peripheral registers will be de-initialized: + * - Disable Interrupt (32 IRQ interrupt sources that matched with LPC17xx) + * - Clear all Pending Interrupts (32 IRQ interrupt source that matched with LPC17xx) + * - Clear all Interrupt Priorities (32 IRQ interrupt source that matched with LPC17xx) + *******************************************************************************/ +void NVIC_DeInit(void) +{ + uint8_t tmp; + + /* Disable all interrupts */ + NVIC->ICER[0] = 0xFFFFFFFF; + NVIC->ICER[1] = 0x00000001; + /* Clear all pending interrupts */ + NVIC->ICPR[0] = 0xFFFFFFFF; + NVIC->ICPR[1] = 0x00000001; + + /* Clear all interrupt priority */ + for (tmp = 0; tmp < 32; tmp++) { + NVIC->IP[tmp] = 0x00; + } +} + +/*****************************************************************************//** + * @brief De-initializes the SCB peripheral registers to their default + * reset values. + * @param none + * @return none + * + * These following SCB NVIC peripheral registers will be de-initialized: + * - Interrupt Control State register + * - Interrupt Vector Table Offset register + * - Application Interrupt/Reset Control register + * - System Control register + * - Configuration Control register + * - System Handlers Priority Registers + * - System Handler Control and State Register + * - Configurable Fault Status Register + * - Hard Fault Status Register + * - Debug Fault Status Register + *******************************************************************************/ +void NVIC_SCBDeInit(void) +{ + uint8_t tmp; + + SCB->ICSR = 0x0A000000; + SCB->VTOR = 0x00000000; + SCB->AIRCR = 0x05FA0000; + SCB->SCR = 0x00000000; + SCB->CCR = 0x00000000; + + for (tmp = 0; tmp < 32; tmp++) { + SCB->SHP[tmp] = 0x00; + } + + SCB->SHCSR = 0x00000000; + SCB->CFSR = 0xFFFFFFFF; + SCB->HFSR = 0xFFFFFFFF; + SCB->DFSR = 0xFFFFFFFF; +} + + +/*****************************************************************************//** + * @brief Set Vector Table Offset value + * @param offset Offset value + * @return None + *******************************************************************************/ +void NVIC_SetVTOR(uint32_t offset) +{ +// SCB->VTOR = (offset & NVIC_VTOR_MASK); + SCB->VTOR = offset; +} + +/** + * @} + */ + +/** + * @} + */ + +/* --------------------------------- End Of File ------------------------------ */ diff --git a/arch/arm/lpc17xx/Drivers/source/lpc17xx_pinsel.c b/arch/arm/lpc17xx/Drivers/source/lpc17xx_pinsel.c new file mode 100644 index 0000000..8361ec4 --- /dev/null +++ b/arch/arm/lpc17xx/Drivers/source/lpc17xx_pinsel.c @@ -0,0 +1,306 @@ +/***********************************************************************//** + * @file lpc17xx_pinsel.c + * @brief Contains all functions support for Pin connect block firmware + * library on LPC17xx + * @version 2.0 + * @date 21. May. 2010 + * @author NXP MCU SW Application Team + ************************************************************************** + * Software that is described herein is for illustrative purposes only + * which provides customers with programming information regarding the + * products. This software is supplied "AS IS" without any warranties. + * NXP Semiconductors assumes no responsibility or liability for the + * use of the software, conveys no license or title under any patent, + * copyright, or mask work right to the product. NXP Semiconductors + * reserves the right to make changes in the software without + * notification. NXP Semiconductors also make no representation or + * warranty that such application will be suitable for the specified + * use without further testing or modification. + **********************************************************************/ + +/* Peripheral group ----------------------------------------------------------- */ +/** @addtogroup PINSEL + * @{ + */ + +/* Includes ------------------------------------------------------------------- */ +#include "lpc17xx_pinsel.h" + +/* Public Functions ----------------------------------------------------------- */ + +static void set_PinFunc ( uint8_t portnum, uint8_t pinnum, uint8_t funcnum); +static void set_ResistorMode ( uint8_t portnum, uint8_t pinnum, uint8_t modenum); +static void set_OpenDrainMode( uint8_t portnum, uint8_t pinnum, uint8_t modenum); + +/*********************************************************************//** + * @brief Setup the pin selection function + * @param[in] portnum PORT number, + * should be one of the following: + * - PINSEL_PORT_0 : Port 0 + * - PINSEL_PORT_1 : Port 1 + * - PINSEL_PORT_2 : Port 2 + * - PINSEL_PORT_3 : Port 3 + * + * @param[in] pinnum Pin number, + * should be one of the following: + - PINSEL_PIN_0 : Pin 0 + - PINSEL_PIN_1 : Pin 1 + - PINSEL_PIN_2 : Pin 2 + - PINSEL_PIN_3 : Pin 3 + - PINSEL_PIN_4 : Pin 4 + - PINSEL_PIN_5 : Pin 5 + - PINSEL_PIN_6 : Pin 6 + - PINSEL_PIN_7 : Pin 7 + - PINSEL_PIN_8 : Pin 8 + - PINSEL_PIN_9 : Pin 9 + - PINSEL_PIN_10 : Pin 10 + - PINSEL_PIN_11 : Pin 11 + - PINSEL_PIN_12 : Pin 12 + - PINSEL_PIN_13 : Pin 13 + - PINSEL_PIN_14 : Pin 14 + - PINSEL_PIN_15 : Pin 15 + - PINSEL_PIN_16 : Pin 16 + - PINSEL_PIN_17 : Pin 17 + - PINSEL_PIN_18 : Pin 18 + - PINSEL_PIN_19 : Pin 19 + - PINSEL_PIN_20 : Pin 20 + - PINSEL_PIN_21 : Pin 21 + - PINSEL_PIN_22 : Pin 22 + - PINSEL_PIN_23 : Pin 23 + - PINSEL_PIN_24 : Pin 24 + - PINSEL_PIN_25 : Pin 25 + - PINSEL_PIN_26 : Pin 26 + - PINSEL_PIN_27 : Pin 27 + - PINSEL_PIN_28 : Pin 28 + - PINSEL_PIN_29 : Pin 29 + - PINSEL_PIN_30 : Pin 30 + - PINSEL_PIN_31 : Pin 31 + + * @param[in] funcnum Function number, + * should be one of the following: + * - PINSEL_FUNC_0 : default function + * - PINSEL_FUNC_1 : first alternate function + * - PINSEL_FUNC_2 : second alternate function + * - PINSEL_FUNC_3 : third alternate function + * + * @return None + **********************************************************************/ +static void set_PinFunc ( uint8_t portnum, uint8_t pinnum, uint8_t funcnum) +{ + uint32_t pinnum_t = pinnum; + uint32_t pinselreg_idx = 2 * portnum; + uint32_t *pPinCon = (uint32_t *)&LPC_PINCON->PINSEL0; + + if (pinnum_t >= 16) { + pinnum_t -= 16; + pinselreg_idx++; + } + *(uint32_t *)(pPinCon + pinselreg_idx) &= ~(0x03UL << (pinnum_t * 2)); + *(uint32_t *)(pPinCon + pinselreg_idx) |= ((uint32_t)funcnum) << (pinnum_t * 2); +} + +/*********************************************************************//** + * @brief Setup resistor mode for each pin + * @param[in] portnum PORT number, + * should be one of the following: + * - PINSEL_PORT_0 : Port 0 + * - PINSEL_PORT_1 : Port 1 + * - PINSEL_PORT_2 : Port 2 + * - PINSEL_PORT_3 : Port 3 + * @param[in] pinnum Pin number, + * should be one of the following: + - PINSEL_PIN_0 : Pin 0 + - PINSEL_PIN_1 : Pin 1 + - PINSEL_PIN_2 : Pin 2 + - PINSEL_PIN_3 : Pin 3 + - PINSEL_PIN_4 : Pin 4 + - PINSEL_PIN_5 : Pin 5 + - PINSEL_PIN_6 : Pin 6 + - PINSEL_PIN_7 : Pin 7 + - PINSEL_PIN_8 : Pin 8 + - PINSEL_PIN_9 : Pin 9 + - PINSEL_PIN_10 : Pin 10 + - PINSEL_PIN_11 : Pin 11 + - PINSEL_PIN_12 : Pin 12 + - PINSEL_PIN_13 : Pin 13 + - PINSEL_PIN_14 : Pin 14 + - PINSEL_PIN_15 : Pin 15 + - PINSEL_PIN_16 : Pin 16 + - PINSEL_PIN_17 : Pin 17 + - PINSEL_PIN_18 : Pin 18 + - PINSEL_PIN_19 : Pin 19 + - PINSEL_PIN_20 : Pin 20 + - PINSEL_PIN_21 : Pin 21 + - PINSEL_PIN_22 : Pin 22 + - PINSEL_PIN_23 : Pin 23 + - PINSEL_PIN_24 : Pin 24 + - PINSEL_PIN_25 : Pin 25 + - PINSEL_PIN_26 : Pin 26 + - PINSEL_PIN_27 : Pin 27 + - PINSEL_PIN_28 : Pin 28 + - PINSEL_PIN_29 : Pin 29 + - PINSEL_PIN_30 : Pin 30 + - PINSEL_PIN_31 : Pin 31 + + * @param[in] modenum: Mode number, + * should be one of the following: + - PINSEL_PINMODE_PULLUP : Internal pull-up resistor + - PINSEL_PINMODE_TRISTATE : Tri-state + - PINSEL_PINMODE_PULLDOWN : Internal pull-down resistor + + * @return None + **********************************************************************/ +void set_ResistorMode ( uint8_t portnum, uint8_t pinnum, uint8_t modenum) +{ + uint32_t pinnum_t = pinnum; + uint32_t pinmodereg_idx = 2 * portnum; + uint32_t *pPinCon = (uint32_t *)&LPC_PINCON->PINMODE0; + + if (pinnum_t >= 16) { + pinnum_t -= 16; + pinmodereg_idx++ ; + } + + *(uint32_t *)(pPinCon + pinmodereg_idx) &= ~(0x03UL << (pinnum_t * 2)); + *(uint32_t *)(pPinCon + pinmodereg_idx) |= ((uint32_t)modenum) << (pinnum_t * 2); +} + +/*********************************************************************//** + * @brief Setup Open drain mode for each pin + * @param[in] portnum PORT number, + * should be one of the following: + * - PINSEL_PORT_0 : Port 0 + * - PINSEL_PORT_1 : Port 1 + * - PINSEL_PORT_2 : Port 2 + * - PINSEL_PORT_3 : Port 3 + * + * @param[in] pinnum Pin number, + * should be one of the following: + - PINSEL_PIN_0 : Pin 0 + - PINSEL_PIN_1 : Pin 1 + - PINSEL_PIN_2 : Pin 2 + - PINSEL_PIN_3 : Pin 3 + - PINSEL_PIN_4 : Pin 4 + - PINSEL_PIN_5 : Pin 5 + - PINSEL_PIN_6 : Pin 6 + - PINSEL_PIN_7 : Pin 7 + - PINSEL_PIN_8 : Pin 8 + - PINSEL_PIN_9 : Pin 9 + - PINSEL_PIN_10 : Pin 10 + - PINSEL_PIN_11 : Pin 11 + - PINSEL_PIN_12 : Pin 12 + - PINSEL_PIN_13 : Pin 13 + - PINSEL_PIN_14 : Pin 14 + - PINSEL_PIN_15 : Pin 15 + - PINSEL_PIN_16 : Pin 16 + - PINSEL_PIN_17 : Pin 17 + - PINSEL_PIN_18 : Pin 18 + - PINSEL_PIN_19 : Pin 19 + - PINSEL_PIN_20 : Pin 20 + - PINSEL_PIN_21 : Pin 21 + - PINSEL_PIN_22 : Pin 22 + - PINSEL_PIN_23 : Pin 23 + - PINSEL_PIN_24 : Pin 24 + - PINSEL_PIN_25 : Pin 25 + - PINSEL_PIN_26 : Pin 26 + - PINSEL_PIN_27 : Pin 27 + - PINSEL_PIN_28 : Pin 28 + - PINSEL_PIN_29 : Pin 29 + - PINSEL_PIN_30 : Pin 30 + - PINSEL_PIN_31 : Pin 31 + + * @param[in] modenum Open drain mode number, + * should be one of the following: + * - PINSEL_PINMODE_NORMAL : Pin is in the normal (not open drain) mode + * - PINSEL_PINMODE_OPENDRAIN : Pin is in the open drain mode + * + * @return None + **********************************************************************/ +void set_OpenDrainMode( uint8_t portnum, uint8_t pinnum, uint8_t modenum) +{ + uint32_t *pPinCon = (uint32_t *)&LPC_PINCON->PINMODE_OD0; + + if (modenum == PINSEL_PINMODE_OPENDRAIN){ + *(uint32_t *)(pPinCon + portnum) |= (0x01UL << pinnum); + } else { + *(uint32_t *)(pPinCon + portnum) &= ~(0x01UL << pinnum); + } +} + +/* End of Public Functions ---------------------------------------------------- */ + +/* Public Functions ----------------------------------------------------------- */ +/** @addtogroup PINSEL_Public_Functions + * @{ + */ +/*********************************************************************//** + * @brief Configure trace function + * @param[in] NewState State of the Trace function configuration, + * should be one of the following: + * - ENABLE : Enable Trace Function + * - DISABLE : Disable Trace Function + * + * @return None + **********************************************************************/ +void PINSEL_ConfigTraceFunc(FunctionalState NewState) +{ + if (NewState == ENABLE) { + LPC_PINCON->PINSEL10 |= (0x01UL << 3); + } else if (NewState == DISABLE) { + LPC_PINCON->PINSEL10 &= ~(0x01UL << 3); + } +} + +/*********************************************************************//** + * @brief Setup I2C0 pins + * @param[in] i2cPinMode I2C pin mode, + * should be one of the following: + * - PINSEL_I2C_Normal_Mode : The standard drive mode + * - PINSEL_I2C_Fast_Mode : Fast Mode Plus drive mode + * + * @param[in] filterSlewRateEnable should be: + * - ENABLE: Enable filter and slew rate. + * - DISABLE: Disable filter and slew rate. + * + * @return None + **********************************************************************/ +void PINSEL_SetI2C0Pins(uint8_t i2cPinMode, FunctionalState filterSlewRateEnable) +{ + uint32_t regVal; + + if (i2cPinMode == PINSEL_I2C_Fast_Mode){ + regVal = PINSEL_I2CPADCFG_SCLDRV0 | PINSEL_I2CPADCFG_SDADRV0; + } + + if (filterSlewRateEnable == DISABLE){ + regVal = PINSEL_I2CPADCFG_SCLI2C0 | PINSEL_I2CPADCFG_SDAI2C0; + } + LPC_PINCON->I2CPADCFG = regVal; +} + + +/*********************************************************************//** + * @brief Configure Pin corresponding to specified parameters passed + * in the PinCfg + * @param[in] PinCfg Pointer to a PINSEL_CFG_Type structure + * that contains the configuration information for the + * specified pin. + * @return None + **********************************************************************/ +void PINSEL_ConfigPin(PINSEL_CFG_Type *PinCfg) +{ + set_PinFunc(PinCfg->Portnum, PinCfg->Pinnum, PinCfg->Funcnum); + set_ResistorMode(PinCfg->Portnum, PinCfg->Pinnum, PinCfg->Pinmode); + set_OpenDrainMode(PinCfg->Portnum, PinCfg->Pinnum, PinCfg->OpenDrain); +} + + +/** + * @} + */ + +/** + * @} + */ + +/* --------------------------------- End Of File ------------------------------ */ diff --git a/arch/arm/lpc17xx/Drivers/source/lpc17xx_pwm.c b/arch/arm/lpc17xx/Drivers/source/lpc17xx_pwm.c new file mode 100644 index 0000000..f11e99f --- /dev/null +++ b/arch/arm/lpc17xx/Drivers/source/lpc17xx_pwm.c @@ -0,0 +1,533 @@ +/***********************************************************************//** + * @file lpc17xx_pwm.c + * @brief Contains all functions support for PWM firmware library on LPC17xx + * @version 2.0 + * @date 21. May. 2010 + * @author NXP MCU SW Application Team + ************************************************************************** + * Software that is described herein is for illustrative purposes only + * which provides customers with programming information regarding the + * products. This software is supplied "AS IS" without any warranties. + * NXP Semiconductors assumes no responsibility or liability for the + * use of the software, conveys no license or title under any patent, + * copyright, or mask work right to the product. NXP Semiconductors + * reserves the right to make changes in the software without + * notification. NXP Semiconductors also make no representation or + * warranty that such application will be suitable for the specified + * use without further testing or modification. + **********************************************************************/ + +/* Peripheral group ----------------------------------------------------------- */ +/** @addtogroup PWM + * @{ + */ + +/* Includes ------------------------------------------------------------------- */ +#include "lpc17xx_pwm.h" +#include "lpc17xx_clkpwr.h" + +/* If this source file built with example, the LPC17xx FW library configuration + * file in each example directory ("lpc17xx_libcfg.h") must be included, + * otherwise the default FW library configuration file must be included instead + */ +#ifdef __BUILD_WITH_EXAMPLE__ +#include "lpc17xx_libcfg.h" +#else +#include "lpc17xx_libcfg_default.h" +#endif /* __BUILD_WITH_EXAMPLE__ */ + + +#ifdef _PWM + + +/* Public Functions ----------------------------------------------------------- */ +/** @addtogroup PWM_Public_Functions + * @{ + */ + + +/*********************************************************************//** + * @brief Check whether specified interrupt flag in PWM is set or not + * @param[in] PWMx: PWM peripheral, should be LPC_PWM1 + * @param[in] IntFlag: PWM interrupt flag, should be: + * - PWM_INTSTAT_MR0: Interrupt flag for PWM match channel 0 + * - PWM_INTSTAT_MR1: Interrupt flag for PWM match channel 1 + * - PWM_INTSTAT_MR2: Interrupt flag for PWM match channel 2 + * - PWM_INTSTAT_MR3: Interrupt flag for PWM match channel 3 + * - PWM_INTSTAT_MR4: Interrupt flag for PWM match channel 4 + * - PWM_INTSTAT_MR5: Interrupt flag for PWM match channel 5 + * - PWM_INTSTAT_MR6: Interrupt flag for PWM match channel 6 + * - PWM_INTSTAT_CAP0: Interrupt flag for capture input 0 + * - PWM_INTSTAT_CAP1: Interrupt flag for capture input 1 + * @return New State of PWM interrupt flag (SET or RESET) + **********************************************************************/ +IntStatus PWM_GetIntStatus(LPC_PWM_TypeDef *PWMx, uint32_t IntFlag) +{ + CHECK_PARAM(PARAM_PWMx(PWMx)); + CHECK_PARAM(PARAM_PWM_INTSTAT(IntFlag)); + + return ((PWMx->IR & IntFlag) ? SET : RESET); +} + + + +/*********************************************************************//** + * @brief Clear specified PWM Interrupt pending + * @param[in] PWMx: PWM peripheral, should be LPC_PWM1 + * @param[in] IntFlag: PWM interrupt flag, should be: + * - PWM_INTSTAT_MR0: Interrupt flag for PWM match channel 0 + * - PWM_INTSTAT_MR1: Interrupt flag for PWM match channel 1 + * - PWM_INTSTAT_MR2: Interrupt flag for PWM match channel 2 + * - PWM_INTSTAT_MR3: Interrupt flag for PWM match channel 3 + * - PWM_INTSTAT_MR4: Interrupt flag for PWM match channel 4 + * - PWM_INTSTAT_MR5: Interrupt flag for PWM match channel 5 + * - PWM_INTSTAT_MR6: Interrupt flag for PWM match channel 6 + * - PWM_INTSTAT_CAP0: Interrupt flag for capture input 0 + * - PWM_INTSTAT_CAP1: Interrupt flag for capture input 1 + * @return None + **********************************************************************/ +void PWM_ClearIntPending(LPC_PWM_TypeDef *PWMx, uint32_t IntFlag) +{ + CHECK_PARAM(PARAM_PWMx(PWMx)); + CHECK_PARAM(PARAM_PWM_INTSTAT(IntFlag)); + PWMx->IR = IntFlag; +} + + + +/*****************************************************************************//** +* @brief Fills each PWM_InitStruct member with its default value: +* - If PWMCounterMode = PWM_MODE_TIMER: +* + PrescaleOption = PWM_TIMER_PRESCALE_USVAL +* + PrescaleValue = 1 +* - If PWMCounterMode = PWM_MODE_COUNTER: +* + CountInputSelect = PWM_COUNTER_PCAP1_0 +* + CounterOption = PWM_COUNTER_RISING +* @param[in] PWMTimerCounterMode Timer or Counter mode, should be: +* - PWM_MODE_TIMER: Counter of PWM peripheral is in Timer mode +* - PWM_MODE_COUNTER: Counter of PWM peripheral is in Counter mode +* @param[in] PWM_InitStruct Pointer to structure (PWM_TIMERCFG_Type or +* PWM_COUNTERCFG_Type) which will be initialized. +* @return None +* Note: PWM_InitStruct pointer will be assigned to corresponding structure +* (PWM_TIMERCFG_Type or PWM_COUNTERCFG_Type) due to PWMTimerCounterMode. +*******************************************************************************/ +void PWM_ConfigStructInit(uint8_t PWMTimerCounterMode, void *PWM_InitStruct) +{ + PWM_TIMERCFG_Type *pTimeCfg; + PWM_COUNTERCFG_Type *pCounterCfg; + CHECK_PARAM(PARAM_PWM_TC_MODE(PWMTimerCounterMode)); + + pTimeCfg = (PWM_TIMERCFG_Type *) PWM_InitStruct; + pCounterCfg = (PWM_COUNTERCFG_Type *) PWM_InitStruct; + + if (PWMTimerCounterMode == PWM_MODE_TIMER ) + { + pTimeCfg->PrescaleOption = PWM_TIMER_PRESCALE_USVAL; + pTimeCfg->PrescaleValue = 1; + } + else if (PWMTimerCounterMode == PWM_MODE_COUNTER) + { + pCounterCfg->CountInputSelect = PWM_COUNTER_PCAP1_0; + pCounterCfg->CounterOption = PWM_COUNTER_RISING; + } +} + + +/*********************************************************************//** + * @brief Initializes the PWMx peripheral corresponding to the specified + * parameters in the PWM_ConfigStruct. + * @param[in] PWMx PWM peripheral, should be LPC_PWM1 + * @param[in] PWMTimerCounterMode Timer or Counter mode, should be: + * - PWM_MODE_TIMER: Counter of PWM peripheral is in Timer mode + * - PWM_MODE_COUNTER: Counter of PWM peripheral is in Counter mode + * @param[in] PWM_ConfigStruct Pointer to structure (PWM_TIMERCFG_Type or + * PWM_COUNTERCFG_Type) which will be initialized. + * @return None + * Note: PWM_ConfigStruct pointer will be assigned to corresponding structure + * (PWM_TIMERCFG_Type or PWM_COUNTERCFG_Type) due to PWMTimerCounterMode. + **********************************************************************/ +void PWM_Init(LPC_PWM_TypeDef *PWMx, uint32_t PWMTimerCounterMode, void *PWM_ConfigStruct) +{ + PWM_TIMERCFG_Type *pTimeCfg; + PWM_COUNTERCFG_Type *pCounterCfg; + uint64_t clkdlycnt; + + CHECK_PARAM(PARAM_PWMx(PWMx)); + CHECK_PARAM(PARAM_PWM_TC_MODE(PWMTimerCounterMode)); + + pTimeCfg = (PWM_TIMERCFG_Type *)PWM_ConfigStruct; + pCounterCfg = (PWM_COUNTERCFG_Type *)PWM_ConfigStruct; + + + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCPWM1, ENABLE); + CLKPWR_SetPCLKDiv (CLKPWR_PCLKSEL_PWM1, CLKPWR_PCLKSEL_CCLK_DIV_4); + // Get peripheral clock of PWM1 + clkdlycnt = (uint64_t) CLKPWR_GetPCLK (CLKPWR_PCLKSEL_PWM1); + + + // Clear all interrupts pending + PWMx->IR = 0xFF & PWM_IR_BITMASK; + PWMx->TCR = 0x00; + PWMx->CTCR = 0x00; + PWMx->MCR = 0x00; + PWMx->CCR = 0x00; + PWMx->PCR = 0x00; + PWMx->LER = 0x00; + + if (PWMTimerCounterMode == PWM_MODE_TIMER) + { + CHECK_PARAM(PARAM_PWM_TIMER_PRESCALE(pTimeCfg->PrescaleOption)); + + /* Absolute prescale value */ + if (pTimeCfg->PrescaleOption == PWM_TIMER_PRESCALE_TICKVAL) + { + PWMx->PR = pTimeCfg->PrescaleValue - 1; + } + /* uSecond prescale value */ + else + { + clkdlycnt = (clkdlycnt * pTimeCfg->PrescaleValue) / 1000000; + PWMx->PR = ((uint32_t) clkdlycnt) - 1; + } + + } + else if (PWMTimerCounterMode == PWM_MODE_COUNTER) + { + CHECK_PARAM(PARAM_PWM_COUNTER_INPUTSEL(pCounterCfg->CountInputSelect)); + CHECK_PARAM(PARAM_PWM_COUNTER_EDGE(pCounterCfg->CounterOption)); + + PWMx->CTCR |= (PWM_CTCR_MODE((uint32_t)pCounterCfg->CounterOption)) \ + | (PWM_CTCR_SELECT_INPUT((uint32_t)pCounterCfg->CountInputSelect)); + } +} + +/*********************************************************************//** + * @brief De-initializes the PWM peripheral registers to their +* default reset values. + * @param[in] PWMx PWM peripheral selected, should be LPC_PWM1 + * @return None + **********************************************************************/ +void PWM_DeInit (LPC_PWM_TypeDef *PWMx) +{ + CHECK_PARAM(PARAM_PWMx(PWMx)); + + // Disable PWM control (timer, counter and PWM) + PWMx->TCR = 0x00; + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCPWM1, DISABLE); + +} + + +/*********************************************************************//** + * @brief Enable/Disable PWM peripheral + * @param[in] PWMx PWM peripheral selected, should be LPC_PWM1 + * @param[in] NewState New State of this function, should be: + * - ENABLE: Enable PWM peripheral + * - DISABLE: Disable PWM peripheral + * @return None + **********************************************************************/ +void PWM_Cmd(LPC_PWM_TypeDef *PWMx, FunctionalState NewState) +{ + CHECK_PARAM(PARAM_PWMx(PWMx)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState)); + + if (NewState == ENABLE) + { + PWMx->TCR |= PWM_TCR_PWM_ENABLE; + } + else + { + PWMx->TCR &= (~PWM_TCR_PWM_ENABLE) & PWM_TCR_BITMASK; + } +} + + +/*********************************************************************//** + * @brief Enable/Disable Counter in PWM peripheral + * @param[in] PWMx PWM peripheral selected, should be LPC_PWM1 + * @param[in] NewState New State of this function, should be: + * - ENABLE: Enable Counter in PWM peripheral + * - DISABLE: Disable Counter in PWM peripheral + * @return None + **********************************************************************/ +void PWM_CounterCmd(LPC_PWM_TypeDef *PWMx, FunctionalState NewState) +{ + CHECK_PARAM(PARAM_PWMx(PWMx)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState)); + if (NewState == ENABLE) + { + PWMx->TCR |= PWM_TCR_COUNTER_ENABLE; + } + else + { + PWMx->TCR &= (~PWM_TCR_COUNTER_ENABLE) & PWM_TCR_BITMASK; + } +} + + +/*********************************************************************//** + * @brief Reset Counter in PWM peripheral + * @param[in] PWMx PWM peripheral selected, should be LPC_PWM1 + * @return None + **********************************************************************/ +void PWM_ResetCounter(LPC_PWM_TypeDef *PWMx) +{ + CHECK_PARAM(PARAM_PWMx(PWMx)); + PWMx->TCR |= PWM_TCR_COUNTER_RESET; + PWMx->TCR &= (~PWM_TCR_COUNTER_RESET) & PWM_TCR_BITMASK; +} + + +/*********************************************************************//** + * @brief Configures match for PWM peripheral + * @param[in] PWMx PWM peripheral selected, should be LPC_PWM1 + * @param[in] PWM_MatchConfigStruct Pointer to a PWM_MATCHCFG_Type structure +* that contains the configuration information for the +* specified PWM match function. + * @return None + **********************************************************************/ +void PWM_ConfigMatch(LPC_PWM_TypeDef *PWMx, PWM_MATCHCFG_Type *PWM_MatchConfigStruct) +{ + CHECK_PARAM(PARAM_PWMx(PWMx)); + CHECK_PARAM(PARAM_PWM1_MATCH_CHANNEL(PWM_MatchConfigStruct->MatchChannel)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(PWM_MatchConfigStruct->IntOnMatch)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(PWM_MatchConfigStruct->ResetOnMatch)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(PWM_MatchConfigStruct->StopOnMatch)); + + //interrupt on MRn + if (PWM_MatchConfigStruct->IntOnMatch == ENABLE) + { + PWMx->MCR |= PWM_MCR_INT_ON_MATCH(PWM_MatchConfigStruct->MatchChannel); + } + else + { + PWMx->MCR &= (~PWM_MCR_INT_ON_MATCH(PWM_MatchConfigStruct->MatchChannel)) \ + & PWM_MCR_BITMASK; + } + + //reset on MRn + if (PWM_MatchConfigStruct->ResetOnMatch == ENABLE) + { + PWMx->MCR |= PWM_MCR_RESET_ON_MATCH(PWM_MatchConfigStruct->MatchChannel); + } + else + { + PWMx->MCR &= (~PWM_MCR_RESET_ON_MATCH(PWM_MatchConfigStruct->MatchChannel)) \ + & PWM_MCR_BITMASK; + } + + //stop on MRn + if (PWM_MatchConfigStruct->StopOnMatch == ENABLE) + { + PWMx->MCR |= PWM_MCR_STOP_ON_MATCH(PWM_MatchConfigStruct->MatchChannel); + } + else + { + PWMx->MCR &= (~PWM_MCR_STOP_ON_MATCH(PWM_MatchConfigStruct->MatchChannel)) \ + & PWM_MCR_BITMASK; + } +} + + +/*********************************************************************//** + * @brief Configures capture input for PWM peripheral + * @param[in] PWMx PWM peripheral selected, should be LPC_PWM1 + * @param[in] PWM_CaptureConfigStruct Pointer to a PWM_CAPTURECFG_Type structure +* that contains the configuration information for the +* specified PWM capture input function. + * @return None + **********************************************************************/ +void PWM_ConfigCapture(LPC_PWM_TypeDef *PWMx, PWM_CAPTURECFG_Type *PWM_CaptureConfigStruct) +{ + CHECK_PARAM(PARAM_PWMx(PWMx)); + CHECK_PARAM(PARAM_PWM1_CAPTURE_CHANNEL(PWM_CaptureConfigStruct->CaptureChannel)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(PWM_CaptureConfigStruct->FallingEdge)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(PWM_CaptureConfigStruct->IntOnCaption)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(PWM_CaptureConfigStruct->RisingEdge)); + + if (PWM_CaptureConfigStruct->RisingEdge == ENABLE) + { + PWMx->CCR |= PWM_CCR_CAP_RISING(PWM_CaptureConfigStruct->CaptureChannel); + } + else + { + PWMx->CCR &= (~PWM_CCR_CAP_RISING(PWM_CaptureConfigStruct->CaptureChannel)) \ + & PWM_CCR_BITMASK; + } + + if (PWM_CaptureConfigStruct->FallingEdge == ENABLE) + { + PWMx->CCR |= PWM_CCR_CAP_FALLING(PWM_CaptureConfigStruct->CaptureChannel); + } + else + { + PWMx->CCR &= (~PWM_CCR_CAP_FALLING(PWM_CaptureConfigStruct->CaptureChannel)) \ + & PWM_CCR_BITMASK; + } + + if (PWM_CaptureConfigStruct->IntOnCaption == ENABLE) + { + PWMx->CCR |= PWM_CCR_INT_ON_CAP(PWM_CaptureConfigStruct->CaptureChannel); + } + else + { + PWMx->CCR &= (~PWM_CCR_INT_ON_CAP(PWM_CaptureConfigStruct->CaptureChannel)) \ + & PWM_CCR_BITMASK; + } +} + + +/*********************************************************************//** + * @brief Read value of capture register PWM peripheral + * @param[in] PWMx PWM peripheral selected, should be LPC_PWM1 + * @param[in] CaptureChannel: capture channel number, should be in + * range 0 to 1 + * @return Value of capture register + **********************************************************************/ +uint32_t PWM_GetCaptureValue(LPC_PWM_TypeDef *PWMx, uint8_t CaptureChannel) +{ + CHECK_PARAM(PARAM_PWMx(PWMx)); + CHECK_PARAM(PARAM_PWM1_CAPTURE_CHANNEL(CaptureChannel)); + + switch (CaptureChannel) + { + case 0: + return PWMx->CR0; + + case 1: + return PWMx->CR1; + + default: + return (0); + } +} + + +/********************************************************************//** + * @brief Update value for each PWM channel with update type option + * @param[in] PWMx PWM peripheral selected, should be LPC_PWM1 + * @param[in] MatchChannel Match channel + * @param[in] MatchValue Match value + * @param[in] UpdateType Type of Update, should be: + * - PWM_MATCH_UPDATE_NOW: The update value will be updated for + * this channel immediately + * - PWM_MATCH_UPDATE_NEXT_RST: The update value will be updated for + * this channel on next reset by a PWM Match event. + * @return None + *********************************************************************/ +void PWM_MatchUpdate(LPC_PWM_TypeDef *PWMx, uint8_t MatchChannel, \ + uint32_t MatchValue, uint8_t UpdateType) +{ + CHECK_PARAM(PARAM_PWMx(PWMx)); + CHECK_PARAM(PARAM_PWM1_MATCH_CHANNEL(MatchChannel)); + CHECK_PARAM(PARAM_PWM_MATCH_UPDATE(UpdateType)); + + switch (MatchChannel) + { + case 0: + PWMx->MR0 = MatchValue; + break; + + case 1: + PWMx->MR1 = MatchValue; + break; + + case 2: + PWMx->MR2 = MatchValue; + break; + + case 3: + PWMx->MR3 = MatchValue; + break; + + case 4: + PWMx->MR4 = MatchValue; + break; + + case 5: + PWMx->MR5 = MatchValue; + break; + + case 6: + PWMx->MR6 = MatchValue; + break; + } + + // Write Latch register + PWMx->LER |= PWM_LER_EN_MATCHn_LATCH(MatchChannel); + + // In case of update now + if (UpdateType == PWM_MATCH_UPDATE_NOW) + { + PWMx->TCR |= PWM_TCR_COUNTER_RESET; + PWMx->TCR &= (~PWM_TCR_COUNTER_RESET) & PWM_TCR_BITMASK; + } +} + + +/********************************************************************//** + * @brief Configure Edge mode for each PWM channel + * @param[in] PWMx PWM peripheral selected, should be LPC_PWM1 + * @param[in] PWMChannel PWM channel, should be in range from 2 to 6 + * @param[in] ModeOption PWM mode option, should be: + * - PWM_CHANNEL_SINGLE_EDGE: Single Edge mode + * - PWM_CHANNEL_DUAL_EDGE: Dual Edge mode + * @return None + * Note: PWM Channel 1 can not be selected for mode option + *********************************************************************/ +void PWM_ChannelConfig(LPC_PWM_TypeDef *PWMx, uint8_t PWMChannel, uint8_t ModeOption) +{ + CHECK_PARAM(PARAM_PWMx(PWMx)); + CHECK_PARAM(PARAM_PWM1_EDGE_MODE_CHANNEL(PWMChannel)); + CHECK_PARAM(PARAM_PWM_CHANNEL_EDGE(ModeOption)); + + // Single edge mode + if (ModeOption == PWM_CHANNEL_SINGLE_EDGE) + { + PWMx->PCR &= (~PWM_PCR_PWMSELn(PWMChannel)) & PWM_PCR_BITMASK; + } + // Double edge mode + else if (PWM_CHANNEL_DUAL_EDGE) + { + PWMx->PCR |= PWM_PCR_PWMSELn(PWMChannel); + } +} + + + +/********************************************************************//** + * @brief Enable/Disable PWM channel output + * @param[in] PWMx PWM peripheral selected, should be LPC_PWM1 + * @param[in] PWMChannel PWM channel, should be in range from 1 to 6 + * @param[in] NewState New State of this function, should be: + * - ENABLE: Enable this PWM channel output + * - DISABLE: Disable this PWM channel output + * @return None + *********************************************************************/ +void PWM_ChannelCmd(LPC_PWM_TypeDef *PWMx, uint8_t PWMChannel, FunctionalState NewState) +{ + CHECK_PARAM(PARAM_PWMx(PWMx)); + CHECK_PARAM(PARAM_PWM1_CHANNEL(PWMChannel)); + + if (NewState == ENABLE) + { + PWMx->PCR |= PWM_PCR_PWMENAn(PWMChannel); + } + else + { + PWMx->PCR &= (~PWM_PCR_PWMENAn(PWMChannel)) & PWM_PCR_BITMASK; + } +} + +/** + * @} + */ + +#endif /* _PWM */ + +/** + * @} + */ + +/* --------------------------------- End Of File ------------------------------ */ diff --git a/arch/arm/lpc17xx/Drivers/source/lpc17xx_qei.c b/arch/arm/lpc17xx/Drivers/source/lpc17xx_qei.c new file mode 100644 index 0000000..b8c9926 --- /dev/null +++ b/arch/arm/lpc17xx/Drivers/source/lpc17xx_qei.c @@ -0,0 +1,502 @@ +/***********************************************************************//** + * @file lpc17xx_qei.c + * @brief Contains all functions support for QEI firmware library on LPC17xx + * @version 2.0 + * @date 21. May. 2010 + * @author NXP MCU SW Application Team + ************************************************************************** + * Software that is described herein is for illustrative purposes only + * which provides customers with programming information regarding the + * products. This software is supplied "AS IS" without any warranties. + * NXP Semiconductors assumes no responsibility or liability for the + * use of the software, conveys no license or title under any patent, + * copyright, or mask work right to the product. NXP Semiconductors + * reserves the right to make changes in the software without + * notification. NXP Semiconductors also make no representation or + * warranty that such application will be suitable for the specified + * use without further testing or modification. + **********************************************************************/ + +/* Peripheral group ----------------------------------------------------------- */ +/** @addtogroup QEI + * @{ + */ + +/* Includes ------------------------------------------------------------------- */ +#include "lpc17xx_qei.h" +#include "lpc17xx_clkpwr.h" + + +/* If this source file built with example, the LPC17xx FW library configuration + * file in each example directory ("lpc17xx_libcfg.h") must be included, + * otherwise the default FW library configuration file must be included instead + */ +#ifdef __BUILD_WITH_EXAMPLE__ +#include "lpc17xx_libcfg.h" +#else +#include "lpc17xx_libcfg_default.h" +#endif /* __BUILD_WITH_EXAMPLE__ */ + + +#ifdef _QEI + +/* Private Types -------------------------------------------------------------- */ +/** @defgroup QEI_Private_Types QEI Private Types + * @{ + */ + +/** + * @brief QEI configuration union type definition + */ +typedef union { + QEI_CFG_Type bmQEIConfig; + uint32_t ulQEIConfig; +} QEI_CFGOPT_Type; + +/** + * @} + */ + + +/* Public Functions ----------------------------------------------------------- */ +/** @addtogroup QEI_Public_Functions + * @{ + */ + +/*********************************************************************//** + * @brief Resets value for each type of QEI value, such as velocity, + * counter, position, etc.. + * @param[in] QEIx QEI peripheral, should be LPC_QEI + * @param[in] ulResetType QEI Reset Type, should be one of the following: + * - QEI_RESET_POS: Reset Position Counter + * - QEI_RESET_POSOnIDX: Reset Position Counter on Index signal + * - QEI_RESET_VEL: Reset Velocity + * - QEI_RESET_IDX: Reset Index Counter + * @return None + **********************************************************************/ +void QEI_Reset(LPC_QEI_TypeDef *QEIx, uint32_t ulResetType) +{ + CHECK_PARAM(PARAM_QEIx(QEIx)); + CHECK_PARAM(PARAM_QEI_RESET(ulResetType)); + + QEIx->QEICON = ulResetType; +} + +/*********************************************************************//** + * @brief Initializes the QEI peripheral according to the specified +* parameters in the QEI_ConfigStruct. + * @param[in] QEIx QEI peripheral, should be LPC_QEI + * @param[in] QEI_ConfigStruct Pointer to a QEI_CFG_Type structure +* that contains the configuration information for the +* specified QEI peripheral + * @return None + **********************************************************************/ +void QEI_Init(LPC_QEI_TypeDef *QEIx, QEI_CFG_Type *QEI_ConfigStruct) +{ + + CHECK_PARAM(PARAM_QEIx(QEIx)); + CHECK_PARAM(PARAM_QEI_DIRINV(QEI_ConfigStruct->DirectionInvert)); + CHECK_PARAM(PARAM_QEI_SIGNALMODE(QEI_ConfigStruct->SignalMode)); + CHECK_PARAM(PARAM_QEI_CAPMODE(QEI_ConfigStruct->CaptureMode)); + CHECK_PARAM(PARAM_QEI_INVINX(QEI_ConfigStruct->InvertIndex)); + + /* Set up clock and power for QEI module */ + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCQEI, ENABLE); + + /* As default, peripheral clock for QEI module + * is set to FCCLK / 2 */ + CLKPWR_SetPCLKDiv(CLKPWR_PCLKSEL_QEI, CLKPWR_PCLKSEL_CCLK_DIV_1); + + // Reset all remaining value in QEI peripheral + QEIx->QEICON = QEI_CON_RESP | QEI_CON_RESV | QEI_CON_RESI; + QEIx->QEIMAXPOS = 0x00; + QEIx->CMPOS0 = 0x00; + QEIx->CMPOS1 = 0x00; + QEIx->CMPOS2 = 0x00; + QEIx->INXCMP = 0x00; + QEIx->QEILOAD = 0x00; + QEIx->VELCOMP = 0x00; + QEIx->FILTER = 0x00; + // Disable all Interrupt + QEIx->QEIIEC = QEI_IECLR_BITMASK; + // Clear all Interrupt pending + QEIx->QEICLR = QEI_INTCLR_BITMASK; + // Set QEI configuration value corresponding to its setting up value + QEIx->QEICONF = ((QEI_CFGOPT_Type *)QEI_ConfigStruct)->ulQEIConfig; +} + + +/*********************************************************************//** + * @brief De-initializes the QEI peripheral registers to their +* default reset values. + * @param[in] QEIx QEI peripheral, should be LPC_QEI + * @return None + **********************************************************************/ +void QEI_DeInit(LPC_QEI_TypeDef *QEIx) +{ + CHECK_PARAM(PARAM_QEIx(QEIx)); + + /* Turn off clock and power for QEI module */ + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCQEI, DISABLE); +} + + +/*****************************************************************************//** +* @brief Fills each QIE_InitStruct member with its default value: +* - DirectionInvert = QEI_DIRINV_NONE +* - SignalMode = QEI_SIGNALMODE_QUAD +* - CaptureMode = QEI_CAPMODE_4X +* - InvertIndex = QEI_INVINX_NONE +* @param[in] QIE_InitStruct Pointer to a QEI_CFG_Type structure +* which will be initialized. +* @return None +*******************************************************************************/ +void QEI_ConfigStructInit(QEI_CFG_Type *QIE_InitStruct) +{ + QIE_InitStruct->CaptureMode = QEI_CAPMODE_4X; + QIE_InitStruct->DirectionInvert = QEI_DIRINV_NONE; + QIE_InitStruct->InvertIndex = QEI_INVINX_NONE; + QIE_InitStruct->SignalMode = QEI_SIGNALMODE_QUAD; +} + + +/*********************************************************************//** + * @brief Check whether if specified flag status is set or not + * @param[in] QEIx QEI peripheral, should be LPC_QEI + * @param[in] ulFlagType Status Flag Type, should be one of the following: + * - QEI_STATUS_DIR: Direction Status + * @return New Status of this status flag (SET or RESET) + **********************************************************************/ +FlagStatus QEI_GetStatus(LPC_QEI_TypeDef *QEIx, uint32_t ulFlagType) +{ + CHECK_PARAM(PARAM_QEIx(QEIx)); + CHECK_PARAM(PARAM_QEI_STATUS(ulFlagType)); + return ((QEIx->QEISTAT & ulFlagType) ? SET : RESET); +} + +/*********************************************************************//** + * @brief Get current position value in QEI peripheral + * @param[in] QEIx QEI peripheral, should be LPC_QEI + * @return Current position value of QEI peripheral + **********************************************************************/ +uint32_t QEI_GetPosition(LPC_QEI_TypeDef *QEIx) +{ + CHECK_PARAM(PARAM_QEIx(QEIx)); + return (QEIx->QEIPOS); +} + +/*********************************************************************//** + * @brief Set max position value for QEI peripheral + * @param[in] QEIx QEI peripheral, should be LPC_QEI + * @param[in] ulMaxPos Max position value to set + * @return None + **********************************************************************/ +void QEI_SetMaxPosition(LPC_QEI_TypeDef *QEIx, uint32_t ulMaxPos) +{ + CHECK_PARAM(PARAM_QEIx(QEIx)); + QEIx->QEIMAXPOS = ulMaxPos; +} + +/*********************************************************************//** + * @brief Set position compare value for QEI peripheral + * @param[in] QEIx QEI peripheral, should be LPC_QEI + * @param[in] bPosCompCh Compare Position channel, should be: + * - QEI_COMPPOS_CH_0: QEI compare position channel 0 + * - QEI_COMPPOS_CH_1: QEI compare position channel 1 + * - QEI_COMPPOS_CH_2: QEI compare position channel 2 + * @param[in] ulPosComp Compare Position value to set + * @return None + **********************************************************************/ +void QEI_SetPositionComp(LPC_QEI_TypeDef *QEIx, uint8_t bPosCompCh, uint32_t ulPosComp) +{ + uint32_t *tmp; + + CHECK_PARAM(PARAM_QEIx(QEIx)); + CHECK_PARAM(PARAM_QEI_COMPPOS_CH(bPosCompCh)); + tmp = (uint32_t *) (&(QEIx->CMPOS0) + bPosCompCh * 4); + *tmp = ulPosComp; + +} + +/*********************************************************************//** + * @brief Get current index counter of QEI peripheral + * @param[in] QEIx QEI peripheral, should be LPC_QEI + * @return Current value of QEI index counter + **********************************************************************/ +uint32_t QEI_GetIndex(LPC_QEI_TypeDef *QEIx) +{ + CHECK_PARAM(PARAM_QEIx(QEIx)); + return (QEIx->INXCNT); +} + +/*********************************************************************//** + * @brief Set value for index compare in QEI peripheral + * @param[in] QEIx QEI peripheral, should be LPC_QEI + * @param[in] ulIndexComp Compare Index Value to set + * @return None + **********************************************************************/ +void QEI_SetIndexComp(LPC_QEI_TypeDef *QEIx, uint32_t ulIndexComp) +{ + CHECK_PARAM(PARAM_QEIx(QEIx)); + QEIx->INXCMP = ulIndexComp; +} + +/*********************************************************************//** + * @brief Set timer reload value for QEI peripheral. When the velocity timer is + * over-flow, the value that set for Timer Reload register will be loaded + * into the velocity timer for next period. The calculated velocity in RPM + * therefore will be affect by this value. + * @param[in] QEIx QEI peripheral, should be LPC_QEI + * @param[in] QEIReloadStruct QEI reload structure + * @return None + **********************************************************************/ +void QEI_SetTimerReload(LPC_QEI_TypeDef *QEIx, QEI_RELOADCFG_Type *QEIReloadStruct) +{ + uint64_t pclk; + + CHECK_PARAM(PARAM_QEIx(QEIx)); + CHECK_PARAM(PARAM_QEI_TIMERRELOAD(QEIReloadStruct->ReloadOption)); + + if (QEIReloadStruct->ReloadOption == QEI_TIMERRELOAD_TICKVAL) { + QEIx->QEILOAD = QEIReloadStruct->ReloadValue - 1; + } else { + pclk = (uint64_t)CLKPWR_GetPCLK(CLKPWR_PCLKSEL_QEI); + pclk = (pclk /(1000000/QEIReloadStruct->ReloadValue)) - 1; + QEIx->QEILOAD = (uint32_t)pclk; + } +} + +/*********************************************************************//** + * @brief Get current timer counter in QEI peripheral + * @param[in] QEIx QEI peripheral, should be LPC_QEI + * @return Current timer counter in QEI peripheral + **********************************************************************/ +uint32_t QEI_GetTimer(LPC_QEI_TypeDef *QEIx) +{ + CHECK_PARAM(PARAM_QEIx(QEIx)); + return (QEIx->QEITIME); +} + +/*********************************************************************//** + * @brief Get current velocity pulse counter in current time period + * @param[in] QEIx QEI peripheral, should be LPC_QEI + * @return Current velocity pulse counter value + **********************************************************************/ +uint32_t QEI_GetVelocity(LPC_QEI_TypeDef *QEIx) +{ + CHECK_PARAM(PARAM_QEIx(QEIx)); + return (QEIx->QEIVEL); +} + +/*********************************************************************//** + * @brief Get the most recently measured velocity of the QEI. When + * the Velocity timer in QEI is over-flow, the current velocity + * value will be loaded into Velocity Capture register. + * @param[in] QEIx QEI peripheral, should be LPC_QEI + * @return The most recently measured velocity value + **********************************************************************/ +uint32_t QEI_GetVelocityCap(LPC_QEI_TypeDef *QEIx) +{ + CHECK_PARAM(PARAM_QEIx(QEIx)); + return (QEIx->QEICAP); +} + +/*********************************************************************//** + * @brief Set Velocity Compare value for QEI peripheral + * @param[in] QEIx QEI peripheral, should be LPC_QEI + * @param[in] ulVelComp Compare Velocity value to set + * @return None + **********************************************************************/ +void QEI_SetVelocityComp(LPC_QEI_TypeDef *QEIx, uint32_t ulVelComp) +{ + CHECK_PARAM(PARAM_QEIx(QEIx)); + QEIx->VELCOMP = ulVelComp; +} + +/*********************************************************************//** + * @brief Set value of sampling count for the digital filter in + * QEI peripheral + * @param[in] QEIx QEI peripheral, should be LPC_QEI + * @param[in] ulSamplingPulse Value of sampling count to set + * @return None + **********************************************************************/ +void QEI_SetDigiFilter(LPC_QEI_TypeDef *QEIx, uint32_t ulSamplingPulse) +{ + CHECK_PARAM(PARAM_QEIx(QEIx)); + QEIx->FILTER = ulSamplingPulse; +} + +/*********************************************************************//** + * @brief Check whether if specified interrupt flag status in QEI + * peripheral is set or not + * @param[in] QEIx QEI peripheral, should be LPC_QEI + * @param[in] ulIntType Interrupt Flag Status type, should be: + - QEI_INTFLAG_INX_Int: index pulse was detected interrupt + - QEI_INTFLAG_TIM_Int: Velocity timer over flow interrupt + - QEI_INTFLAG_VELC_Int: Capture velocity is less than compare interrupt + - QEI_INTFLAG_DIR_Int: Change of direction interrupt + - QEI_INTFLAG_ERR_Int: An encoder phase error interrupt + - QEI_INTFLAG_ENCLK_Int: An encoder clock pulse was detected interrupt + - QEI_INTFLAG_POS0_Int: position 0 compare value is equal to the + current position interrupt + - QEI_INTFLAG_POS1_Int: position 1 compare value is equal to the + current position interrupt + - QEI_INTFLAG_POS2_Int: position 2 compare value is equal to the + current position interrupt + - QEI_INTFLAG_REV_Int: Index compare value is equal to the current + index count interrupt + - QEI_INTFLAG_POS0REV_Int: Combined position 0 and revolution count interrupt + - QEI_INTFLAG_POS1REV_Int: Combined position 1 and revolution count interrupt + - QEI_INTFLAG_POS2REV_Int: Combined position 2 and revolution count interrupt + * @return New State of specified interrupt flag status (SET or RESET) + **********************************************************************/ +FlagStatus QEI_GetIntStatus(LPC_QEI_TypeDef *QEIx, uint32_t ulIntType) +{ + CHECK_PARAM(PARAM_QEIx(QEIx)); + CHECK_PARAM(PARAM_QEI_INTFLAG(ulIntType)); + + return((QEIx->QEIINTSTAT & ulIntType) ? SET : RESET); +} + +/*********************************************************************//** + * @brief Enable/Disable specified interrupt in QEI peripheral + * @param[in] QEIx QEI peripheral, should be LPC_QEI + * @param[in] ulIntType Interrupt Flag Status type, should be: + * - QEI_INTFLAG_INX_Int: index pulse was detected interrupt + * - QEI_INTFLAG_TIM_Int: Velocity timer over flow interrupt + * - QEI_INTFLAG_VELC_Int: Capture velocity is less than compare interrupt + * - QEI_INTFLAG_DIR_Int: Change of direction interrupt + * - QEI_INTFLAG_ERR_Int: An encoder phase error interrupt + * - QEI_INTFLAG_ENCLK_Int: An encoder clock pulse was detected interrupt + * - QEI_INTFLAG_POS0_Int: position 0 compare value is equal to the + * current position interrupt + * - QEI_INTFLAG_POS1_Int: position 1 compare value is equal to the + * current position interrupt + * - QEI_INTFLAG_POS2_Int: position 2 compare value is equal to the + * current position interrupt + * - QEI_INTFLAG_REV_Int: Index compare value is equal to the current + * index count interrupt + * - QEI_INTFLAG_POS0REV_Int: Combined position 0 and revolution count interrupt + * - QEI_INTFLAG_POS1REV_Int: Combined position 1 and revolution count interrupt + * - QEI_INTFLAG_POS2REV_Int: Combined position 2 and revolution count interrupt + * @param[in] NewState New function state, should be: + * - DISABLE + * - ENABLE + * @return None + **********************************************************************/ +void QEI_IntCmd(LPC_QEI_TypeDef *QEIx, uint32_t ulIntType, FunctionalState NewState) +{ + CHECK_PARAM(PARAM_QEIx(QEIx)); + CHECK_PARAM(PARAM_QEI_INTFLAG(ulIntType)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState)); + + if (NewState == ENABLE) { + QEIx->QEIIES = ulIntType; + } else { + QEIx->QEIIEC = ulIntType; + } +} + + +/*********************************************************************//** + * @brief Sets (forces) specified interrupt in QEI peripheral + * @param[in] QEIx QEI peripheral, should be LPC_QEI + * @param[in] ulIntType Interrupt Flag Status type, should be: + - QEI_INTFLAG_INX_Int: index pulse was detected interrupt + - QEI_INTFLAG_TIM_Int: Velocity timer over flow interrupt + - QEI_INTFLAG_VELC_Int: Capture velocity is less than compare interrupt + - QEI_INTFLAG_DIR_Int: Change of direction interrupt + - QEI_INTFLAG_ERR_Int: An encoder phase error interrupt + - QEI_INTFLAG_ENCLK_Int: An encoder clock pulse was detected interrupt + - QEI_INTFLAG_POS0_Int: position 0 compare value is equal to the + current position interrupt + - QEI_INTFLAG_POS1_Int: position 1 compare value is equal to the + current position interrupt + - QEI_INTFLAG_POS2_Int: position 2 compare value is equal to the + current position interrupt + - QEI_INTFLAG_REV_Int: Index compare value is equal to the current + index count interrupt + - QEI_INTFLAG_POS0REV_Int: Combined position 0 and revolution count interrupt + - QEI_INTFLAG_POS1REV_Int: Combined position 1 and revolution count interrupt + - QEI_INTFLAG_POS2REV_Int: Combined position 2 and revolution count interrupt + * @return None + **********************************************************************/ +void QEI_IntSet(LPC_QEI_TypeDef *QEIx, uint32_t ulIntType) +{ + CHECK_PARAM(PARAM_QEIx(QEIx)); + CHECK_PARAM(PARAM_QEI_INTFLAG(ulIntType)); + + QEIx->QEISET = ulIntType; +} + +/*********************************************************************//** + * @brief Clear (force) specified interrupt (pending) in QEI peripheral + * @param[in] QEIx QEI peripheral, should be LPC_QEI + * @param[in] ulIntType Interrupt Flag Status type, should be: + - QEI_INTFLAG_INX_Int: index pulse was detected interrupt + - QEI_INTFLAG_TIM_Int: Velocity timer over flow interrupt + - QEI_INTFLAG_VELC_Int: Capture velocity is less than compare interrupt + - QEI_INTFLAG_DIR_Int: Change of direction interrupt + - QEI_INTFLAG_ERR_Int: An encoder phase error interrupt + - QEI_INTFLAG_ENCLK_Int: An encoder clock pulse was detected interrupt + - QEI_INTFLAG_POS0_Int: position 0 compare value is equal to the + current position interrupt + - QEI_INTFLAG_POS1_Int: position 1 compare value is equal to the + current position interrupt + - QEI_INTFLAG_POS2_Int: position 2 compare value is equal to the + current position interrupt + - QEI_INTFLAG_REV_Int: Index compare value is equal to the current + index count interrupt + - QEI_INTFLAG_POS0REV_Int: Combined position 0 and revolution count interrupt + - QEI_INTFLAG_POS1REV_Int: Combined position 1 and revolution count interrupt + - QEI_INTFLAG_POS2REV_Int: Combined position 2 and revolution count interrupt + * @return None + **********************************************************************/ +void QEI_IntClear(LPC_QEI_TypeDef *QEIx, uint32_t ulIntType) +{ + CHECK_PARAM(PARAM_QEIx(QEIx)); + CHECK_PARAM(PARAM_QEI_INTFLAG(ulIntType)); + + QEIx->QEICLR = ulIntType; +} + + +/*********************************************************************//** + * @brief Calculates the actual velocity in RPM passed via velocity + * capture value and Pulse Per Round (of the encoder) value + * parameter input. + * @param[in] QEIx QEI peripheral, should be LPC_QEI + * @param[in] ulVelCapValue Velocity capture input value that can + * be got from QEI_GetVelocityCap() function + * @param[in] ulPPR Pulse per round of encoder + * @return The actual value of velocity in RPM (Round per minute) + **********************************************************************/ +uint32_t QEI_CalculateRPM(LPC_QEI_TypeDef *QEIx, uint32_t ulVelCapValue, uint32_t ulPPR) +{ + uint64_t rpm, clock, Load, edges; + + // Get current Clock rate for timer input + clock = (uint64_t)CLKPWR_GetPCLK(CLKPWR_PCLKSEL_QEI); + // Get Timer load value (velocity capture period) + Load = (uint64_t)(QEIx->QEILOAD + 1); + // Get Edge + edges = (uint64_t)((QEIx->QEICONF & QEI_CONF_CAPMODE) ? 4 : 2); + // Calculate RPM + rpm = ((clock * ulVelCapValue * 60) / (Load * ulPPR * edges)); + + return (uint32_t)(rpm); +} + + +/** + * @} + */ + +#endif /* _QEI */ + +/** + * @} + */ + +/* --------------------------------- End Of File ------------------------------ */ + diff --git a/arch/arm/lpc17xx/Drivers/source/lpc17xx_rit.c b/arch/arm/lpc17xx/Drivers/source/lpc17xx_rit.c new file mode 100644 index 0000000..4df19ac --- /dev/null +++ b/arch/arm/lpc17xx/Drivers/source/lpc17xx_rit.c @@ -0,0 +1,187 @@ +/***********************************************************************//** + * @file lpc17xx_rit.c + * @brief Contains all functions support for RIT firmware library on LPC17xx + * @version 2.0 + * @date 21. May. 2010 + * @author NXP MCU SW Application Team + ************************************************************************** + * Software that is described herein is for illustrative purposes only + * which provides customers with programming information regarding the + * products. This software is supplied "AS IS" without any warranties. + * NXP Semiconductors assumes no responsibility or liability for the + * use of the software, conveys no license or title under any patent, + * copyright, or mask work right to the product. NXP Semiconductors + * reserves the right to make changes in the software without + * notification. NXP Semiconductors also make no representation or + * warranty that such application will be suitable for the specified + * use without further testing or modification. + **********************************************************************/ + +/* Peripheral group ----------------------------------------------------------- */ +/** @addtogroup RIT + * @{ + */ + +/* Includes ------------------------------------------------------------------- */ +#include "lpc17xx_rit.h" +#include "lpc17xx_clkpwr.h" + +/* If this source file built with example, the LPC17xx FW library configuration + * file in each example directory ("lpc17xx_libcfg.h") must be included, + * otherwise the default FW library configuration file must be included instead + */ +#ifdef __BUILD_WITH_EXAMPLE__ +#include "lpc17xx_libcfg.h" +#else +#include "lpc17xx_libcfg_default.h" +#endif /* __BUILD_WITH_EXAMPLE__ */ + +#ifdef _RIT + +/* Public Functions ----------------------------------------------------------- */ +/** @addtogroup RIT_Public_Functions + * @{ + */ + +/******************************************************************************//* + * @brief Initial for RIT + * - Turn on power and clock + * - Setup default register values + * @param[in] RITx is RIT peripheral selected, should be: LPC_RIT + * @return None + *******************************************************************************/ +void RIT_Init(LPC_RIT_TypeDef *RITx) +{ + CHECK_PARAM(PARAM_RITx(RITx)); + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCRIT, ENABLE); + //Set up default register values + RITx->RICOMPVAL = 0xFFFFFFFF; + RITx->RIMASK = 0x00000000; + RITx->RICTRL = 0x0C; + RITx->RICOUNTER = 0x00000000; + // Turn on power and clock + +} +/******************************************************************************//* + * @brief DeInitial for RIT + * - Turn off power and clock + * - ReSetup default register values + * @param[in] RITx is RIT peripheral selected, should be: LPC_RIT + * @return None + *******************************************************************************/ +void RIT_DeInit(LPC_RIT_TypeDef *RITx) +{ + CHECK_PARAM(PARAM_RITx(RITx)); + + // Turn off power and clock + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCRIT, DISABLE); + //ReSetup default register values + RITx->RICOMPVAL = 0xFFFFFFFF; + RITx->RIMASK = 0x00000000; + RITx->RICTRL = 0x0C; + RITx->RICOUNTER = 0x00000000; +} + +/******************************************************************************//* + * @brief Set compare value, mask value and time counter value + * @param[in] RITx is RIT peripheral selected, should be: LPC_RIT + * @param[in] time_interval: timer interval value (ms) + * @return None + *******************************************************************************/ +void RIT_TimerConfig(LPC_RIT_TypeDef *RITx, uint32_t time_interval) +{ + uint32_t clock_rate, cmp_value; + CHECK_PARAM(PARAM_RITx(RITx)); + + // Get PCLK value of RIT + clock_rate = CLKPWR_GetPCLK(CLKPWR_PCLKSEL_RIT); + + /* calculate compare value for RIT to generate interrupt at + * specified time interval + * COMPVAL = (RIT_PCLK * time_interval)/1000 + * (with time_interval unit is millisecond) + */ + cmp_value = (clock_rate /1000) * time_interval; + RITx->RICOMPVAL = cmp_value; + + /* Set timer enable clear bit to clear timer to 0 whenever + * counter value equals the contents of RICOMPVAL + */ + RITx->RICTRL |= (1<<1); +} + + +/******************************************************************************//* + * @brief Enable/Disable Timer + * @param[in] RITx is RIT peripheral selected, should be: LPC_RIT + * @param[in] NewState New State of this function + * -ENABLE: Enable Timer + * -DISABLE: Disable Timer + * @return None + *******************************************************************************/ +void RIT_Cmd(LPC_RIT_TypeDef *RITx, FunctionalState NewState) +{ + CHECK_PARAM(PARAM_RITx(RITx)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState)); + + //Enable or Disable Timer + if(NewState==ENABLE) + { + RITx->RICTRL |= RIT_CTRL_TEN; + } + else + { + RITx->RICTRL &= ~RIT_CTRL_TEN; + } +} + +/******************************************************************************//* + * @brief Timer Enable/Disable on debug + * @param[in] RITx is RIT peripheral selected, should be: LPC_RIT + * @param[in] NewState New State of this function + * -ENABLE: The timer is halted whenever a hardware break condition occurs + * -DISABLE: Hardware break has no effect on the timer operation + * @return None + *******************************************************************************/ +void RIT_TimerDebugCmd(LPC_RIT_TypeDef *RITx, FunctionalState NewState) +{ + CHECK_PARAM(PARAM_RITx(RITx)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState)); + + //Timer Enable/Disable on break + if(NewState==ENABLE) + { + RITx->RICTRL |= RIT_CTRL_ENBR; + } + else + { + RITx->RICTRL &= ~RIT_CTRL_ENBR; + } +} +/******************************************************************************//* + * @brief Check whether interrupt flag is set or not + * @param[in] RITx is RIT peripheral selected, should be: LPC_RIT + * @return Current interrupt status, could be: SET/RESET + *******************************************************************************/ +IntStatus RIT_GetIntStatus(LPC_RIT_TypeDef *RITx) +{ + uint8_t result; + CHECK_PARAM(PARAM_RITx(RITx)); + if((RITx->RICTRL&RIT_CTRL_INTEN)==1) result= SET; + else return RESET; + //clear interrupt flag + RITx->RICTRL |= RIT_CTRL_INTEN; + return result; +} + +/** + * @} + */ + +#endif /* _RIT */ + +/** + * @} + */ + +/* --------------------------------- End Of File ------------------------------ */ diff --git a/arch/arm/lpc17xx/Drivers/source/lpc17xx_rtc.c b/arch/arm/lpc17xx/Drivers/source/lpc17xx_rtc.c new file mode 100644 index 0000000..c7c2cdb --- /dev/null +++ b/arch/arm/lpc17xx/Drivers/source/lpc17xx_rtc.c @@ -0,0 +1,771 @@ +/***********************************************************************//** + * @file lpc17xx_rtc.c + * @brief Contains all functions support for RTC firmware library on LPC17xx + * @version 3.0 + * @date 18. June. 2010 + * @author NXP MCU SW Application Team + ************************************************************************** + * Software that is described herein is for illustrative purposes only + * which provides customers with programming information regarding the + * products. This software is supplied "AS IS" without any warranties. + * NXP Semiconductors assumes no responsibility or liability for the + * use of the software, conveys no license or title under any patent, + * copyright, or mask work right to the product. NXP Semiconductors + * reserves the right to make changes in the software without + * notification. NXP Semiconductors also make no representation or + * warranty that such application will be suitable for the specified + * use without further testing or modification. + **********************************************************************/ + + +/* Peripheral group ----------------------------------------------------------- */ +/** @addtogroup RTC + * @{ + */ + +/* Includes ------------------------------------------------------------------- */ +#include "lpc17xx_rtc.h" +#include "lpc17xx_clkpwr.h" + + +/* If this source file built with example, the LPC17xx FW library configuration + * file in each example directory ("lpc17xx_libcfg.h") must be included, + * otherwise the default FW library configuration file must be included instead + */ +#ifdef __BUILD_WITH_EXAMPLE__ +#include "lpc17xx_libcfg.h" +#else +#include "lpc17xx_libcfg_default.h" +#endif /* __BUILD_WITH_EXAMPLE__ */ + + +#ifdef _RTC + +/* Public Functions ----------------------------------------------------------- */ +/** @addtogroup RTC_Public_Functions + * @{ + */ + +/********************************************************************//** + * @brief Initializes the RTC peripheral. + * @param[in] RTCx RTC peripheral selected, should be LPC_RTC + * @return None + *********************************************************************/ +void RTC_Init (LPC_RTC_TypeDef *RTCx) +{ + CHECK_PARAM(PARAM_RTCx(RTCx)); + + /* Set up clock and power for RTC module */ + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCRTC, ENABLE); + + // Clear all register to be default + RTCx->ILR = 0x00; + RTCx->CCR = 0x00; + RTCx->CIIR = 0x00; + RTCx->AMR = 0xFF; + RTCx->CALIBRATION = 0x00; +} + + +/*********************************************************************//** + * @brief De-initializes the RTC peripheral registers to their +* default reset values. + * @param[in] RTCx RTC peripheral selected, should be LPC_RTC + * @return None + **********************************************************************/ +void RTC_DeInit(LPC_RTC_TypeDef *RTCx) +{ + CHECK_PARAM(PARAM_RTCx(RTCx)); + + RTCx->CCR = 0x00; + // Disable power and clock for RTC module + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCRTC, DISABLE); +} + +/*********************************************************************//** + * @brief Reset clock tick counter in RTC peripheral + * @param[in] RTCx RTC peripheral selected, should be LPC_RTC + * @return None + **********************************************************************/ +void RTC_ResetClockTickCounter(LPC_RTC_TypeDef *RTCx) +{ + CHECK_PARAM(PARAM_RTCx(RTCx)); + + RTCx->CCR |= RTC_CCR_CTCRST; + RTCx->CCR &= (~RTC_CCR_CTCRST) & RTC_CCR_BITMASK; +} + +/*********************************************************************//** + * @brief Start/Stop RTC peripheral + * @param[in] RTCx RTC peripheral selected, should be LPC_RTC + * @param[in] NewState New State of this function, should be: + * - ENABLE: The time counters are enabled + * - DISABLE: The time counters are disabled + * @return None + **********************************************************************/ +void RTC_Cmd (LPC_RTC_TypeDef *RTCx, FunctionalState NewState) +{ + CHECK_PARAM(PARAM_RTCx(RTCx)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState)); + + if (NewState == ENABLE) + { + RTCx->CCR |= RTC_CCR_CLKEN; + } + else + { + RTCx->CCR &= (~RTC_CCR_CLKEN) & RTC_CCR_BITMASK; + } +} + + +/*********************************************************************//** + * @brief Enable/Disable Counter increment interrupt for each time type + * in RTC peripheral + * @param[in] RTCx RTC peripheral selected, should be LPC_RTC + * @param[in] CntIncrIntType: Counter Increment Interrupt type, + * an increment of this type value below will generates + * an interrupt, should be: + * - RTC_TIMETYPE_SECOND + * - RTC_TIMETYPE_MINUTE + * - RTC_TIMETYPE_HOUR + * - RTC_TIMETYPE_DAYOFWEEK + * - RTC_TIMETYPE_DAYOFMONTH + * - RTC_TIMETYPE_DAYOFYEAR + * - RTC_TIMETYPE_MONTH + * - RTC_TIMETYPE_YEAR + * @param[in] NewState New State of this function, should be: + * - ENABLE: Counter Increment interrupt for this + * time type are enabled + * - DISABLE: Counter Increment interrupt for this + * time type are disabled + * @return None + **********************************************************************/ +void RTC_CntIncrIntConfig (LPC_RTC_TypeDef *RTCx, uint32_t CntIncrIntType, \ + FunctionalState NewState) +{ + CHECK_PARAM(PARAM_RTCx(RTCx)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState)); + CHECK_PARAM(PARAM_RTC_TIMETYPE(CntIncrIntType)); + + if (NewState == ENABLE) + { + switch (CntIncrIntType) + { + case RTC_TIMETYPE_SECOND: + RTCx->CIIR |= RTC_CIIR_IMSEC; + break; + case RTC_TIMETYPE_MINUTE: + RTCx->CIIR |= RTC_CIIR_IMMIN; + break; + case RTC_TIMETYPE_HOUR: + RTCx->CIIR |= RTC_CIIR_IMHOUR; + break; + case RTC_TIMETYPE_DAYOFWEEK: + RTCx->CIIR |= RTC_CIIR_IMDOW; + break; + case RTC_TIMETYPE_DAYOFMONTH: + RTCx->CIIR |= RTC_CIIR_IMDOM; + break; + case RTC_TIMETYPE_DAYOFYEAR: + RTCx->CIIR |= RTC_CIIR_IMDOY; + break; + case RTC_TIMETYPE_MONTH: + RTCx->CIIR |= RTC_CIIR_IMMON; + break; + case RTC_TIMETYPE_YEAR: + RTCx->CIIR |= RTC_CIIR_IMYEAR; + break; + } + } + else + { + switch (CntIncrIntType) + { + case RTC_TIMETYPE_SECOND: + RTCx->CIIR &= (~RTC_CIIR_IMSEC) & RTC_CIIR_BITMASK; + break; + case RTC_TIMETYPE_MINUTE: + RTCx->CIIR &= (~RTC_CIIR_IMMIN) & RTC_CIIR_BITMASK; + break; + case RTC_TIMETYPE_HOUR: + RTCx->CIIR &= (~RTC_CIIR_IMHOUR) & RTC_CIIR_BITMASK; + break; + case RTC_TIMETYPE_DAYOFWEEK: + RTCx->CIIR &= (~RTC_CIIR_IMDOW) & RTC_CIIR_BITMASK; + break; + case RTC_TIMETYPE_DAYOFMONTH: + RTCx->CIIR &= (~RTC_CIIR_IMDOM) & RTC_CIIR_BITMASK; + break; + case RTC_TIMETYPE_DAYOFYEAR: + RTCx->CIIR &= (~RTC_CIIR_IMDOY) & RTC_CIIR_BITMASK; + break; + case RTC_TIMETYPE_MONTH: + RTCx->CIIR &= (~RTC_CIIR_IMMON) & RTC_CIIR_BITMASK; + break; + case RTC_TIMETYPE_YEAR: + RTCx->CIIR &= (~RTC_CIIR_IMYEAR) & RTC_CIIR_BITMASK; + break; + } + } +} + + +/*********************************************************************//** + * @brief Enable/Disable Alarm interrupt for each time type + * in RTC peripheral + * @param[in] RTCx RTC peripheral selected, should be LPC_RTC + * @param[in] AlarmTimeType: Alarm Time Interrupt type, + * an matching of this type value below with current time + * in RTC will generates an interrupt, should be: + * - RTC_TIMETYPE_SECOND + * - RTC_TIMETYPE_MINUTE + * - RTC_TIMETYPE_HOUR + * - RTC_TIMETYPE_DAYOFWEEK + * - RTC_TIMETYPE_DAYOFMONTH + * - RTC_TIMETYPE_DAYOFYEAR + * - RTC_TIMETYPE_MONTH + * - RTC_TIMETYPE_YEAR + * @param[in] NewState New State of this function, should be: + * - ENABLE: Alarm interrupt for this + * time type are enabled + * - DISABLE: Alarm interrupt for this + * time type are disabled + * @return None + **********************************************************************/ +void RTC_AlarmIntConfig (LPC_RTC_TypeDef *RTCx, uint32_t AlarmTimeType, \ + FunctionalState NewState) +{ + CHECK_PARAM(PARAM_RTCx(RTCx)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState)); + CHECK_PARAM(PARAM_RTC_TIMETYPE(AlarmTimeType)); + + if (NewState == ENABLE) + { + switch (AlarmTimeType) + { + case RTC_TIMETYPE_SECOND: + RTCx->AMR &= (~RTC_AMR_AMRSEC) & RTC_AMR_BITMASK; + break; + case RTC_TIMETYPE_MINUTE: + RTCx->AMR &= (~RTC_AMR_AMRMIN) & RTC_AMR_BITMASK; + break; + case RTC_TIMETYPE_HOUR: + RTCx->AMR &= (~RTC_AMR_AMRHOUR) & RTC_AMR_BITMASK; + break; + case RTC_TIMETYPE_DAYOFWEEK: + RTCx->AMR &= (~RTC_AMR_AMRDOW) & RTC_AMR_BITMASK; + break; + case RTC_TIMETYPE_DAYOFMONTH: + RTCx->AMR &= (~RTC_AMR_AMRDOM) & RTC_AMR_BITMASK; + break; + case RTC_TIMETYPE_DAYOFYEAR: + RTCx->AMR &= (~RTC_AMR_AMRDOY) & RTC_AMR_BITMASK; + break; + case RTC_TIMETYPE_MONTH: + RTCx->AMR &= (~RTC_AMR_AMRMON) & RTC_AMR_BITMASK; + break; + case RTC_TIMETYPE_YEAR: + RTCx->AMR &= (~RTC_AMR_AMRYEAR) & RTC_AMR_BITMASK; + break; + } + } + else + { + switch (AlarmTimeType) + { + case RTC_TIMETYPE_SECOND: + RTCx->AMR |= (RTC_AMR_AMRSEC); + break; + case RTC_TIMETYPE_MINUTE: + RTCx->AMR |= (RTC_AMR_AMRMIN); + break; + case RTC_TIMETYPE_HOUR: + RTCx->AMR |= (RTC_AMR_AMRHOUR); + break; + case RTC_TIMETYPE_DAYOFWEEK: + RTCx->AMR |= (RTC_AMR_AMRDOW); + break; + case RTC_TIMETYPE_DAYOFMONTH: + RTCx->AMR |= (RTC_AMR_AMRDOM); + break; + case RTC_TIMETYPE_DAYOFYEAR: + RTCx->AMR |= (RTC_AMR_AMRDOY); + break; + case RTC_TIMETYPE_MONTH: + RTCx->AMR |= (RTC_AMR_AMRMON); + break; + case RTC_TIMETYPE_YEAR: + RTCx->AMR |= (RTC_AMR_AMRYEAR); + break; + } + } +} + + +/*********************************************************************//** + * @brief Set current time value for each time type in RTC peripheral + * @param[in] RTCx RTC peripheral selected, should be LPC_RTC + * @param[in] Timetype: Time Type, should be: + * - RTC_TIMETYPE_SECOND + * - RTC_TIMETYPE_MINUTE + * - RTC_TIMETYPE_HOUR + * - RTC_TIMETYPE_DAYOFWEEK + * - RTC_TIMETYPE_DAYOFMONTH + * - RTC_TIMETYPE_DAYOFYEAR + * - RTC_TIMETYPE_MONTH + * - RTC_TIMETYPE_YEAR + * @param[in] TimeValue Time value to set + * @return None + **********************************************************************/ +void RTC_SetTime (LPC_RTC_TypeDef *RTCx, uint32_t Timetype, uint32_t TimeValue) +{ + CHECK_PARAM(PARAM_RTCx(RTCx)); + CHECK_PARAM(PARAM_RTC_TIMETYPE(Timetype)); + + switch ( Timetype) + { + case RTC_TIMETYPE_SECOND: + CHECK_PARAM(TimeValue < RTC_SECOND_MAX); + + RTCx->SEC = TimeValue & RTC_SEC_MASK; + break; + + case RTC_TIMETYPE_MINUTE: + CHECK_PARAM(TimeValue < RTC_MINUTE_MAX); + + RTCx->MIN = TimeValue & RTC_MIN_MASK; + break; + + case RTC_TIMETYPE_HOUR: + CHECK_PARAM(TimeValue < RTC_HOUR_MAX); + + RTCx->HOUR = TimeValue & RTC_HOUR_MASK; + break; + + case RTC_TIMETYPE_DAYOFWEEK: + CHECK_PARAM(TimeValue < RTC_DAYOFWEEK_MAX); + + RTCx->DOW = TimeValue & RTC_DOW_MASK; + break; + + case RTC_TIMETYPE_DAYOFMONTH: + CHECK_PARAM((TimeValue < RTC_DAYOFMONTH_MAX) \ + && (TimeValue > RTC_DAYOFMONTH_MIN)); + + RTCx->DOM = TimeValue & RTC_DOM_MASK; + break; + + case RTC_TIMETYPE_DAYOFYEAR: + CHECK_PARAM((TimeValue > RTC_DAYOFYEAR_MIN) \ + && (TimeValue < RTC_DAYOFYEAR_MAX)); + + RTCx->DOY = TimeValue & RTC_DOY_MASK; + break; + + case RTC_TIMETYPE_MONTH: + CHECK_PARAM((TimeValue > RTC_MONTH_MIN) \ + && (TimeValue < RTC_MONTH_MAX)); + + RTCx->MONTH = TimeValue & RTC_MONTH_MASK; + break; + + case RTC_TIMETYPE_YEAR: + CHECK_PARAM(TimeValue < RTC_YEAR_MAX); + + RTCx->YEAR = TimeValue & RTC_YEAR_MASK; + break; + } +} + +/*********************************************************************//** + * @brief Get current time value for each type time type + * @param[in] RTCx RTC peripheral selected, should be LPC_RTC + * @param[in] Timetype: Time Type, should be: + * - RTC_TIMETYPE_SECOND + * - RTC_TIMETYPE_MINUTE + * - RTC_TIMETYPE_HOUR + * - RTC_TIMETYPE_DAYOFWEEK + * - RTC_TIMETYPE_DAYOFMONTH + * - RTC_TIMETYPE_DAYOFYEAR + * - RTC_TIMETYPE_MONTH + * - RTC_TIMETYPE_YEAR + * @return Value of time according to specified time type + **********************************************************************/ +uint32_t RTC_GetTime(LPC_RTC_TypeDef *RTCx, uint32_t Timetype) +{ + CHECK_PARAM(PARAM_RTCx(RTCx)); + CHECK_PARAM(PARAM_RTC_TIMETYPE(Timetype)); + + switch (Timetype) + { + case RTC_TIMETYPE_SECOND: + return (RTCx->SEC & RTC_SEC_MASK); + case RTC_TIMETYPE_MINUTE: + return (RTCx->MIN & RTC_MIN_MASK); + case RTC_TIMETYPE_HOUR: + return (RTCx->HOUR & RTC_HOUR_MASK); + case RTC_TIMETYPE_DAYOFWEEK: + return (RTCx->DOW & RTC_DOW_MASK); + case RTC_TIMETYPE_DAYOFMONTH: + return (RTCx->DOM & RTC_DOM_MASK); + case RTC_TIMETYPE_DAYOFYEAR: + return (RTCx->DOY & RTC_DOY_MASK); + case RTC_TIMETYPE_MONTH: + return (RTCx->MONTH & RTC_MONTH_MASK); + case RTC_TIMETYPE_YEAR: + return (RTCx->YEAR & RTC_YEAR_MASK); + default: + return (0); + } +} + + +/*********************************************************************//** + * @brief Set full of time in RTC peripheral + * @param[in] RTCx RTC peripheral selected, should be LPC_RTC + * @param[in] pFullTime Pointer to a RTC_TIME_Type structure that + * contains time value in full. + * @return None + **********************************************************************/ +void RTC_SetFullTime (LPC_RTC_TypeDef *RTCx, RTC_TIME_Type *pFullTime) +{ + CHECK_PARAM(PARAM_RTCx(RTCx)); + + RTCx->DOM = pFullTime->DOM & RTC_DOM_MASK; + RTCx->DOW = pFullTime->DOW & RTC_DOW_MASK; + RTCx->DOY = pFullTime->DOY & RTC_DOY_MASK; + RTCx->HOUR = pFullTime->HOUR & RTC_HOUR_MASK; + RTCx->MIN = pFullTime->MIN & RTC_MIN_MASK; + RTCx->SEC = pFullTime->SEC & RTC_SEC_MASK; + RTCx->MONTH = pFullTime->MONTH & RTC_MONTH_MASK; + RTCx->YEAR = pFullTime->YEAR & RTC_YEAR_MASK; +} + + +/*********************************************************************//** + * @brief Get full of time in RTC peripheral + * @param[in] RTCx RTC peripheral selected, should be LPC_RTC + * @param[in] pFullTime Pointer to a RTC_TIME_Type structure that + * will be stored time in full. + * @return None + **********************************************************************/ +void RTC_GetFullTime (LPC_RTC_TypeDef *RTCx, RTC_TIME_Type *pFullTime) +{ + CHECK_PARAM(PARAM_RTCx(RTCx)); + + pFullTime->DOM = RTCx->DOM & RTC_DOM_MASK; + pFullTime->DOW = RTCx->DOW & RTC_DOW_MASK; + pFullTime->DOY = RTCx->DOY & RTC_DOY_MASK; + pFullTime->HOUR = RTCx->HOUR & RTC_HOUR_MASK; + pFullTime->MIN = RTCx->MIN & RTC_MIN_MASK; + pFullTime->SEC = RTCx->SEC & RTC_SEC_MASK; + pFullTime->MONTH = RTCx->MONTH & RTC_MONTH_MASK; + pFullTime->YEAR = RTCx->YEAR & RTC_YEAR_MASK; +} + + +/*********************************************************************//** + * @brief Set alarm time value for each time type + * @param[in] RTCx RTC peripheral selected, should be LPC_RTC + * @param[in] Timetype: Time Type, should be: + * - RTC_TIMETYPE_SECOND + * - RTC_TIMETYPE_MINUTE + * - RTC_TIMETYPE_HOUR + * - RTC_TIMETYPE_DAYOFWEEK + * - RTC_TIMETYPE_DAYOFMONTH + * - RTC_TIMETYPE_DAYOFYEAR + * - RTC_TIMETYPE_MONTH + * - RTC_TIMETYPE_YEAR + * @param[in] ALValue Alarm time value to set + * @return None + **********************************************************************/ +void RTC_SetAlarmTime (LPC_RTC_TypeDef *RTCx, uint32_t Timetype, uint32_t ALValue) +{ + CHECK_PARAM(PARAM_RTCx(RTCx)); + + switch (Timetype) + { + case RTC_TIMETYPE_SECOND: + CHECK_PARAM(ALValue < RTC_SECOND_MAX); + + RTCx->ALSEC = ALValue & RTC_SEC_MASK; + break; + + case RTC_TIMETYPE_MINUTE: + CHECK_PARAM(ALValue < RTC_MINUTE_MAX); + + RTCx->ALMIN = ALValue & RTC_MIN_MASK; + break; + + case RTC_TIMETYPE_HOUR: + CHECK_PARAM(ALValue < RTC_HOUR_MAX); + + RTCx->ALHOUR = ALValue & RTC_HOUR_MASK; + break; + + case RTC_TIMETYPE_DAYOFWEEK: + CHECK_PARAM(ALValue < RTC_DAYOFWEEK_MAX); + + RTCx->ALDOW = ALValue & RTC_DOW_MASK; + break; + + case RTC_TIMETYPE_DAYOFMONTH: + CHECK_PARAM((ALValue < RTC_DAYOFMONTH_MAX) \ + && (ALValue > RTC_DAYOFMONTH_MIN)); + + RTCx->ALDOM = ALValue & RTC_DOM_MASK; + break; + + case RTC_TIMETYPE_DAYOFYEAR: + CHECK_PARAM((ALValue > RTC_DAYOFYEAR_MIN) \ + && (ALValue < RTC_DAYOFYEAR_MAX)); + + RTCx->ALDOY = ALValue & RTC_DOY_MASK; + break; + + case RTC_TIMETYPE_MONTH: + CHECK_PARAM((ALValue > RTC_MONTH_MIN) \ + && (ALValue < RTC_MONTH_MAX)); + + RTCx->ALMON = ALValue & RTC_MONTH_MASK; + break; + + case RTC_TIMETYPE_YEAR: + CHECK_PARAM(ALValue < RTC_YEAR_MAX); + + RTCx->ALYEAR = ALValue & RTC_YEAR_MASK; + break; + } +} + + + +/*********************************************************************//** + * @brief Get alarm time value for each time type + * @param[in] RTCx RTC peripheral selected, should be LPC_RTC + * @param[in] Timetype: Time Type, should be: + * - RTC_TIMETYPE_SECOND + * - RTC_TIMETYPE_MINUTE + * - RTC_TIMETYPE_HOUR + * - RTC_TIMETYPE_DAYOFWEEK + * - RTC_TIMETYPE_DAYOFMONTH + * - RTC_TIMETYPE_DAYOFYEAR + * - RTC_TIMETYPE_MONTH + * - RTC_TIMETYPE_YEAR + * @return Value of Alarm time according to specified time type + **********************************************************************/ +uint32_t RTC_GetAlarmTime (LPC_RTC_TypeDef *RTCx, uint32_t Timetype) +{ + switch (Timetype) + { + case RTC_TIMETYPE_SECOND: + return (RTCx->ALSEC & RTC_SEC_MASK); + case RTC_TIMETYPE_MINUTE: + return (RTCx->ALMIN & RTC_MIN_MASK); + case RTC_TIMETYPE_HOUR: + return (RTCx->ALHOUR & RTC_HOUR_MASK); + case RTC_TIMETYPE_DAYOFWEEK: + return (RTCx->ALDOW & RTC_DOW_MASK); + case RTC_TIMETYPE_DAYOFMONTH: + return (RTCx->ALDOM & RTC_DOM_MASK); + case RTC_TIMETYPE_DAYOFYEAR: + return (RTCx->ALDOY & RTC_DOY_MASK); + case RTC_TIMETYPE_MONTH: + return (RTCx->ALMON & RTC_MONTH_MASK); + case RTC_TIMETYPE_YEAR: + return (RTCx->ALYEAR & RTC_YEAR_MASK); + default: + return (0); + } +} + + +/*********************************************************************//** + * @brief Set full of alarm time in RTC peripheral + * @param[in] RTCx RTC peripheral selected, should be LPC_RTC + * @param[in] pFullTime Pointer to a RTC_TIME_Type structure that + * contains alarm time value in full. + * @return None + **********************************************************************/ +void RTC_SetFullAlarmTime (LPC_RTC_TypeDef *RTCx, RTC_TIME_Type *pFullTime) +{ + CHECK_PARAM(PARAM_RTCx(RTCx)); + + RTCx->ALDOM = pFullTime->DOM & RTC_DOM_MASK; + RTCx->ALDOW = pFullTime->DOW & RTC_DOW_MASK; + RTCx->ALDOY = pFullTime->DOY & RTC_DOY_MASK; + RTCx->ALHOUR = pFullTime->HOUR & RTC_HOUR_MASK; + RTCx->ALMIN = pFullTime->MIN & RTC_MIN_MASK; + RTCx->ALSEC = pFullTime->SEC & RTC_SEC_MASK; + RTCx->ALMON = pFullTime->MONTH & RTC_MONTH_MASK; + RTCx->ALYEAR = pFullTime->YEAR & RTC_YEAR_MASK; +} + + +/*********************************************************************//** + * @brief Get full of alarm time in RTC peripheral + * @param[in] RTCx RTC peripheral selected, should be LPC_RTC + * @param[in] pFullTime Pointer to a RTC_TIME_Type structure that + * will be stored alarm time in full. + * @return None + **********************************************************************/ +void RTC_GetFullAlarmTime (LPC_RTC_TypeDef *RTCx, RTC_TIME_Type *pFullTime) +{ + CHECK_PARAM(PARAM_RTCx(RTCx)); + + pFullTime->DOM = RTCx->ALDOM & RTC_DOM_MASK; + pFullTime->DOW = RTCx->ALDOW & RTC_DOW_MASK; + pFullTime->DOY = RTCx->ALDOY & RTC_DOY_MASK; + pFullTime->HOUR = RTCx->ALHOUR & RTC_HOUR_MASK; + pFullTime->MIN = RTCx->ALMIN & RTC_MIN_MASK; + pFullTime->SEC = RTCx->ALSEC & RTC_SEC_MASK; + pFullTime->MONTH = RTCx->ALMON & RTC_MONTH_MASK; + pFullTime->YEAR = RTCx->ALYEAR & RTC_YEAR_MASK; +} + + +/*********************************************************************//** + * @brief Check whether if specified Location interrupt in + * RTC peripheral is set or not + * @param[in] RTCx RTC peripheral selected, should be LPC_RTC + * @param[in] IntType Interrupt location type, should be: + * - RTC_INT_COUNTER_INCREASE: Counter Increment Interrupt + * block generated an interrupt. + * - RTC_INT_ALARM: Alarm generated an + * interrupt. + * @return New state of specified Location interrupt in RTC peripheral + * (SET or RESET) + **********************************************************************/ +IntStatus RTC_GetIntPending (LPC_RTC_TypeDef *RTCx, uint32_t IntType) +{ + CHECK_PARAM(PARAM_RTCx(RTCx)); + CHECK_PARAM(PARAM_RTC_INT(IntType)); + + return ((RTCx->ILR & IntType) ? SET : RESET); +} + + +/*********************************************************************//** + * @brief Clear specified Location interrupt pending in + * RTC peripheral + * @param[in] RTCx RTC peripheral selected, should be LPC_RTC + * @param[in] IntType Interrupt location type, should be: + * - RTC_INT_COUNTER_INCREASE: Clear Counter Increment + * Interrupt pending. + * - RTC_INT_ALARM: Clear alarm interrupt pending + * @return None + **********************************************************************/ +void RTC_ClearIntPending (LPC_RTC_TypeDef *RTCx, uint32_t IntType) +{ + CHECK_PARAM(PARAM_RTCx(RTCx)); + CHECK_PARAM(PARAM_RTC_INT(IntType)); + + RTCx->ILR |= IntType; +} + +/*********************************************************************//** + * @brief Enable/Disable calibration counter in RTC peripheral + * @param[in] RTCx RTC peripheral selected, should be LPC_RTC + * @param[in] NewState New State of this function, should be: + * - ENABLE: The calibration counter is enabled and counting + * - DISABLE: The calibration counter is disabled and reset to zero + * @return None + **********************************************************************/ +void RTC_CalibCounterCmd(LPC_RTC_TypeDef *RTCx, FunctionalState NewState) +{ + CHECK_PARAM(PARAM_RTCx(RTCx)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState)); + + if (NewState == ENABLE) + { + RTCx->CCR &= (~RTC_CCR_CCALEN) & RTC_CCR_BITMASK; + } + else + { + RTCx->CCR |= RTC_CCR_CCALEN; + } +} + + +/*********************************************************************//** + * @brief Configures Calibration in RTC peripheral + * @param[in] RTCx RTC peripheral selected, should be LPC_RTC + * @param[in] CalibValue Calibration value, should be in range from + * 0 to 131,072 + * @param[in] CalibDir Calibration Direction, should be: + * - RTC_CALIB_DIR_FORWARD: Forward calibration + * - RTC_CALIB_DIR_BACKWARD: Backward calibration + * @return None + **********************************************************************/ +void RTC_CalibConfig(LPC_RTC_TypeDef *RTCx, uint32_t CalibValue, uint8_t CalibDir) +{ + CHECK_PARAM(PARAM_RTCx(RTCx)); + CHECK_PARAM(PARAM_RTC_CALIB_DIR(CalibDir)); + CHECK_PARAM(CalibValue < RTC_CALIBRATION_MAX); + + RTCx->CALIBRATION = ((CalibValue - 1) & RTC_CALIBRATION_CALVAL_MASK) \ + | ((CalibDir == RTC_CALIB_DIR_BACKWARD) ? RTC_CALIBRATION_LIBDIR : 0); +} + + +/*********************************************************************//** + * @brief Write value to General purpose registers + * @param[in] RTCx RTC peripheral selected, should be LPC_RTC + * @param[in] Channel General purpose registers Channel number, + * should be in range from 0 to 4. + * @param[in] Value Value to write + * @return None + * Note: These General purpose registers can be used to store important + * information when the main power supply is off. The value in these + * registers is not affected by chip reset. + **********************************************************************/ +void RTC_WriteGPREG (LPC_RTC_TypeDef *RTCx, uint8_t Channel, uint32_t Value) +{ + uint32_t *preg; + + CHECK_PARAM(PARAM_RTCx(RTCx)); + CHECK_PARAM(PARAM_RTC_GPREG_CH(Channel)); + + preg = (uint32_t *)&RTCx->GPREG0; + preg += Channel; + *preg = Value; +} + + +/*********************************************************************//** + * @brief Read value from General purpose registers + * @param[in] RTCx RTC peripheral selected, should be LPC_RTC + * @param[in] Channel General purpose registers Channel number, + * should be in range from 0 to 4. + * @return Read Value + * Note: These General purpose registers can be used to store important + * information when the main power supply is off. The value in these + * registers is not affected by chip reset. + **********************************************************************/ +uint32_t RTC_ReadGPREG (LPC_RTC_TypeDef *RTCx, uint8_t Channel) +{ + uint32_t *preg; + uint32_t value; + + CHECK_PARAM(PARAM_RTCx(RTCx)); + CHECK_PARAM(PARAM_RTC_GPREG_CH(Channel)); + + preg = (uint32_t *)&RTCx->GPREG0; + preg += Channel; + value = *preg; + return (value); +} + +/** + * @} + */ + +#endif /* _RTC */ + +/** + * @} + */ + +/* --------------------------------- End Of File ------------------------------ */ + diff --git a/arch/arm/lpc17xx/Drivers/source/lpc17xx_spi.c b/arch/arm/lpc17xx/Drivers/source/lpc17xx_spi.c new file mode 100644 index 0000000..7643de7 --- /dev/null +++ b/arch/arm/lpc17xx/Drivers/source/lpc17xx_spi.c @@ -0,0 +1,431 @@ +/***********************************************************************//** + * @file lpc17xx_spi.c + * @brief Contains all functions support for SPI firmware library on LPC17xx + * @version 2.0 + * @date 21. May. 2010 + * @author NXP MCU SW Application Team + ************************************************************************** + * Software that is described herein is for illustrative purposes only + * which provides customers with programming information regarding the + * products. This software is supplied "AS IS" without any warranties. + * NXP Semiconductors assumes no responsibility or liability for the + * use of the software, conveys no license or title under any patent, + * copyright, or mask work right to the product. NXP Semiconductors + * reserves the right to make changes in the software without + * notification. NXP Semiconductors also make no representation or + * warranty that such application will be suitable for the specified + * use without further testing or modification. + **********************************************************************/ + +/* Peripheral group ----------------------------------------------------------- */ +/** @addtogroup SPI + * @{ + */ + +/* Includes ------------------------------------------------------------------- */ +#include "lpc17xx_spi.h" +#include "lpc17xx_clkpwr.h" + +/* If this source file built with example, the LPC17xx FW library configuration + * file in each example directory ("lpc17xx_libcfg.h") must be included, + * otherwise the default FW library configuration file must be included instead + */ +#ifdef __BUILD_WITH_EXAMPLE__ +#include "lpc17xx_libcfg.h" +#else +#include "lpc17xx_libcfg_default.h" +#endif /* __BUILD_WITH_EXAMPLE__ */ + +#ifdef _SPI + + +/* Public Functions ----------------------------------------------------------- */ +/** @addtogroup SPI_Public_Functions + * @{ + */ + +/*********************************************************************//** + * @brief Setup clock rate for SPI device + * @param[in] SPIx SPI peripheral definition, should be LPC_SPI + * @param[in] target_clock : clock of SPI (Hz) + * @return None + ***********************************************************************/ +void SPI_SetClock (LPC_SPI_TypeDef *SPIx, uint32_t target_clock) +{ + uint32_t spi_pclk; + uint32_t prescale, temp; + + CHECK_PARAM(PARAM_SPIx(SPIx)); + + if (SPIx == LPC_SPI){ + spi_pclk = CLKPWR_GetPCLK (CLKPWR_PCLKSEL_SPI); + } else { + return; + } + + prescale = 8; + // Find closest clock to target clock + while (1){ + temp = target_clock * prescale; + if (temp >= spi_pclk){ + break; + } + prescale += 2; + if(prescale >= 254){ + break; + } + } + + // Write to register + SPIx->SPCCR = SPI_SPCCR_COUNTER(prescale); +} + + +/*********************************************************************//** + * @brief De-initializes the SPIx peripheral registers to their +* default reset values. + * @param[in] SPIx SPI peripheral selected, should be LPC_SPI + * @return None + **********************************************************************/ +void SPI_DeInit(LPC_SPI_TypeDef *SPIx) +{ + CHECK_PARAM(PARAM_SPIx(SPIx)); + + if (SPIx == LPC_SPI){ + /* Set up clock and power for SPI module */ + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCSPI, DISABLE); + } +} + +/*********************************************************************//** + * @brief Get data bit size per transfer + * @param[in] SPIx SPI peripheral selected, should be LPC_SPI + * @return number of bit per transfer, could be 8-16 + **********************************************************************/ +uint8_t SPI_GetDataSize (LPC_SPI_TypeDef *SPIx) +{ + CHECK_PARAM(PARAM_SPIx(SPIx)); + return ((SPIx->SPCR)>>8 & 0xF); +} + +/********************************************************************//** + * @brief Initializes the SPIx peripheral according to the specified +* parameters in the UART_ConfigStruct. + * @param[in] SPIx SPI peripheral selected, should be LPC_SPI + * @param[in] SPI_ConfigStruct Pointer to a SPI_CFG_Type structure +* that contains the configuration information for the +* specified SPI peripheral. + * @return None + *********************************************************************/ +void SPI_Init(LPC_SPI_TypeDef *SPIx, SPI_CFG_Type *SPI_ConfigStruct) +{ + uint32_t tmp; + + CHECK_PARAM(PARAM_SPIx(SPIx)); + + if(SPIx == LPC_SPI){ + /* Set up clock and power for UART module */ + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCSPI, ENABLE); + } else { + return; + } + + // Configure SPI, interrupt is disable as default + tmp = ((SPI_ConfigStruct->CPHA) | (SPI_ConfigStruct->CPOL) \ + | (SPI_ConfigStruct->DataOrder) | (SPI_ConfigStruct->Databit) \ + | (SPI_ConfigStruct->Mode) | SPI_SPCR_BIT_EN) & SPI_SPCR_BITMASK; + // write back to SPI control register + SPIx->SPCR = tmp; + + // Set clock rate for SPI peripheral + SPI_SetClock(SPIx, SPI_ConfigStruct->ClockRate); + + // If interrupt flag is set, Write '1' to Clear interrupt flag + if (SPIx->SPINT & SPI_SPINT_INTFLAG){ + SPIx->SPINT = SPI_SPINT_INTFLAG; + } +} + + + +/*****************************************************************************//** +* @brief Fills each SPI_InitStruct member with its default value: +* - CPHA = SPI_CPHA_FIRST +* - CPOL = SPI_CPOL_HI +* - ClockRate = 1000000 +* - DataOrder = SPI_DATA_MSB_FIRST +* - Databit = SPI_DATABIT_8 +* - Mode = SPI_MASTER_MODE +* @param[in] SPI_InitStruct Pointer to a SPI_CFG_Type structure +* which will be initialized. +* @return None +*******************************************************************************/ +void SPI_ConfigStructInit(SPI_CFG_Type *SPI_InitStruct) +{ + SPI_InitStruct->CPHA = SPI_CPHA_FIRST; + SPI_InitStruct->CPOL = SPI_CPOL_HI; + SPI_InitStruct->ClockRate = 1000000; + SPI_InitStruct->DataOrder = SPI_DATA_MSB_FIRST; + SPI_InitStruct->Databit = SPI_DATABIT_8; + SPI_InitStruct->Mode = SPI_MASTER_MODE; +} + +/*********************************************************************//** + * @brief Transmit a single data through SPIx peripheral + * @param[in] SPIx SPI peripheral selected, should be LPC_SPI + * @param[in] Data Data to transmit (must be 16 or 8-bit long, + * this depend on SPI data bit number configured) + * @return none + **********************************************************************/ +void SPI_SendData(LPC_SPI_TypeDef* SPIx, uint16_t Data) +{ + CHECK_PARAM(PARAM_SPIx(SPIx)); + + SPIx->SPDR = Data & SPI_SPDR_BITMASK; +} + + + +/*********************************************************************//** + * @brief Receive a single data from SPIx peripheral + * @param[in] SPIx SPI peripheral selected, should be LPC_SPI + * @return Data received (16-bit long) + **********************************************************************/ +uint16_t SPI_ReceiveData(LPC_SPI_TypeDef* SPIx) +{ + CHECK_PARAM(PARAM_SPIx(SPIx)); + + return ((uint16_t) (SPIx->SPDR & SPI_SPDR_BITMASK)); +} + +/*********************************************************************//** + * @brief SPI Read write data function + * @param[in] SPIx Pointer to SPI peripheral, should be LPC_SPI + * @param[in] dataCfg Pointer to a SPI_DATA_SETUP_Type structure that + * contains specified information about transmit + * data configuration. + * @param[in] xfType Transfer type, should be: + * - SPI_TRANSFER_POLLING: Polling mode + * - SPI_TRANSFER_INTERRUPT: Interrupt mode + * @return Actual Data length has been transferred in polling mode. + * In interrupt mode, always return (0) + * Return (-1) if error. + * Note: This function can be used in both master and slave mode. + ***********************************************************************/ +int32_t SPI_ReadWrite (LPC_SPI_TypeDef *SPIx, SPI_DATA_SETUP_Type *dataCfg, \ + SPI_TRANSFER_Type xfType) +{ + uint8_t *rdata8; + uint8_t *wdata8; + uint16_t *rdata16; + uint16_t *wdata16; + uint32_t stat; + uint32_t temp; + uint8_t dataword; + + //read for empty buffer + temp = SPIx->SPDR; + //dummy to clear status + temp = SPIx->SPSR; + dataCfg->counter = 0; + dataCfg->status = 0; + + if(SPI_GetDataSize (SPIx) == 8) + dataword = 0; + else dataword = 1; + if (xfType == SPI_TRANSFER_POLLING){ + + if (dataword == 0){ + rdata8 = (uint8_t *)dataCfg->rx_data; + wdata8 = (uint8_t *)dataCfg->tx_data; + } else { + rdata16 = (uint16_t *)dataCfg->rx_data; + wdata16 = (uint16_t *)dataCfg->tx_data; + } + + while(dataCfg->counter < dataCfg->length) + { + // Write data to buffer + if(dataCfg->tx_data == NULL){ + if (dataword == 0){ + SPI_SendData(SPIx, 0xFF); + } else { + SPI_SendData(SPIx, 0xFFFF); + } + } else { + if (dataword == 0){ + SPI_SendData(SPIx, *wdata8); + wdata8++; + } else { + SPI_SendData(SPIx, *wdata16); + wdata16++; + } + } + // Wait for transfer complete + while (!((stat = SPIx->SPSR) & SPI_SPSR_SPIF)); + // Check for error + if (stat & (SPI_SPSR_ABRT | SPI_SPSR_MODF | SPI_SPSR_ROVR | SPI_SPSR_WCOL)){ + // save status + dataCfg->status = stat | SPI_STAT_ERROR; + return (dataCfg->counter); + } + // Read data from SPI dat + temp = (uint32_t) SPI_ReceiveData(SPIx); + + // Store data to destination + if (dataCfg->rx_data != NULL) + { + if (dataword == 0){ + *(rdata8) = (uint8_t) temp; + rdata8++; + } else { + *(rdata16) = (uint16_t) temp; + rdata16++; + } + } + // Increase counter + if (dataword == 0){ + dataCfg->counter++; + } else { + dataCfg->counter += 2; + } + } + + // Return length of actual data transferred + // save status + dataCfg->status = stat | SPI_STAT_DONE; + return (dataCfg->counter); + } + // Interrupt mode + else { + + // Check if interrupt flag is already set + if(SPIx->SPINT & SPI_SPINT_INTFLAG){ + SPIx->SPINT = SPI_SPINT_INTFLAG; + } + if (dataCfg->counter < dataCfg->length){ + // Write data to buffer + if(dataCfg->tx_data == NULL){ + if (dataword == 0){ + SPI_SendData(SPIx, 0xFF); + } else { + SPI_SendData(SPIx, 0xFFFF); + } + } else { + if (dataword == 0){ + SPI_SendData(SPIx, (*(uint8_t *)dataCfg->tx_data)); + } else { + SPI_SendData(SPIx, (*(uint16_t *)dataCfg->tx_data)); + } + } + SPI_IntCmd(SPIx, ENABLE); + } else { + // Save status + dataCfg->status = SPI_STAT_DONE; + } + return (0); + } +} + + +/********************************************************************//** + * @brief Enable or disable SPIx interrupt. + * @param[in] SPIx SPI peripheral selected, should be LPC_SPI + * @param[in] NewState New state of specified UART interrupt type, + * should be: + * - ENALBE: Enable this SPI interrupt. +* - DISALBE: Disable this SPI interrupt. + * @return None + *********************************************************************/ +void SPI_IntCmd(LPC_SPI_TypeDef *SPIx, FunctionalState NewState) +{ + CHECK_PARAM(PARAM_SPIx(SPIx)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState)); + + if (NewState == ENABLE) + { + SPIx->SPCR |= SPI_SPCR_SPIE; + } + else + { + SPIx->SPCR &= (~SPI_SPCR_SPIE) & SPI_SPCR_BITMASK; + } +} + + +/********************************************************************//** + * @brief Checks whether the SPI interrupt flag is set or not. + * @param[in] SPIx SPI peripheral selected, should be LPC_SPI + * @return The new state of SPI Interrupt Flag (SET or RESET) + *********************************************************************/ +IntStatus SPI_GetIntStatus (LPC_SPI_TypeDef *SPIx) +{ + CHECK_PARAM(PARAM_SPIx(SPIx)); + + return ((SPIx->SPINT & SPI_SPINT_INTFLAG) ? SET : RESET); +} + +/********************************************************************//** + * @brief Clear SPI interrupt flag. + * @param[in] SPIx SPI peripheral selected, should be LPC_SPI + * @return None + *********************************************************************/ +void SPI_ClearIntPending(LPC_SPI_TypeDef *SPIx) +{ + CHECK_PARAM(PARAM_SPIx(SPIx)); + + SPIx->SPINT = SPI_SPINT_INTFLAG; +} + +/********************************************************************//** + * @brief Get current value of SPI Status register in SPIx peripheral. + * @param[in] SPIx SPI peripheral selected, should be LPC_SPI + * @return Current value of SPI Status register in SPI peripheral. + * Note: The return value of this function must be used with + * SPI_CheckStatus() to determine current flag status + * corresponding to each SPI status type. Because some flags in + * SPI Status register will be cleared after reading, the next reading + * SPI Status register could not be correct. So this function used to + * read SPI status register in one time only, then the return value + * used to check all flags. + *********************************************************************/ +uint32_t SPI_GetStatus(LPC_SPI_TypeDef* SPIx) +{ + CHECK_PARAM(PARAM_SPIx(SPIx)); + + return (SPIx->SPSR & SPI_SPSR_BITMASK); +} + +/********************************************************************//** + * @brief Checks whether the specified SPI Status flag is set or not + * via inputSPIStatus parameter. + * @param[in] inputSPIStatus Value to check status of each flag type. + * This value is the return value from SPI_GetStatus(). + * @param[in] SPIStatus Specifies the SPI status flag to check, + * should be one of the following: + - SPI_STAT_ABRT: Slave abort. + - SPI_STAT_MODF: Mode fault. + - SPI_STAT_ROVR: Read overrun. + - SPI_STAT_WCOL: Write collision. + - SPI_STAT_SPIF: SPI transfer complete. + * @return The new state of SPIStatus (SET or RESET) + *********************************************************************/ +FlagStatus SPI_CheckStatus (uint32_t inputSPIStatus, uint8_t SPIStatus) +{ + CHECK_PARAM(PARAM_SPI_STAT(SPIStatus)); + + return ((inputSPIStatus & SPIStatus) ? SET : RESET); +} + + +/** + * @} + */ + +#endif /* _SPI */ + +/** + * @} + */ + +/* --------------------------------- End Of File ------------------------------ */ diff --git a/arch/arm/lpc17xx/Drivers/source/lpc17xx_ssp.c b/arch/arm/lpc17xx/Drivers/source/lpc17xx_ssp.c new file mode 100644 index 0000000..bbf03a6 --- /dev/null +++ b/arch/arm/lpc17xx/Drivers/source/lpc17xx_ssp.c @@ -0,0 +1,682 @@ +/***********************************************************************//** + * @file lpc17xx_ssp.c + * @brief Contains all functions support for SSP firmware library on LPC17xx + * @version 3.0 + * @date 18. June. 2010 + * @author NXP MCU SW Application Team + ************************************************************************** + * Software that is described herein is for illustrative purposes only + * which provides customers with programming information regarding the + * products. This software is supplied "AS IS" without any warranties. + * NXP Semiconductors assumes no responsibility or liability for the + * use of the software, conveys no license or title under any patent, + * copyright, or mask work right to the product. NXP Semiconductors + * reserves the right to make changes in the software without + * notification. NXP Semiconductors also make no representation or + * warranty that such application will be suitable for the specified + * use without further testing or modification. + **********************************************************************/ + +/* Peripheral group ----------------------------------------------------------- */ +/** @addtogroup SSP + * @{ + */ + +/* Includes ------------------------------------------------------------------- */ +#include "lpc17xx_ssp.h" +#include "lpc17xx_clkpwr.h" + + +/* If this source file built with example, the LPC17xx FW library configuration + * file in each example directory ("lpc17xx_libcfg.h") must be included, + * otherwise the default FW library configuration file must be included instead + */ +#ifdef __BUILD_WITH_EXAMPLE__ +#include "lpc17xx_libcfg.h" +#else +#include "lpc17xx_libcfg_default.h" +#endif /* __BUILD_WITH_EXAMPLE__ */ + + +#ifdef _SSP + +/* Public Functions ----------------------------------------------------------- */ +/** @addtogroup SSP_Public_Functions + * @{ + */ +static void setSSPclock (LPC_SSP_TypeDef *SSPx, uint32_t target_clock); + +/*********************************************************************//** + * @brief Setup clock rate for SSP device + * @param[in] SSPx SSP peripheral definition, should be: + * - LPC_SSP0: SSP0 peripheral + * - LPC_SSP1: SSP1 peripheral + * @param[in] target_clock : clock of SSP (Hz) + * @return None + ***********************************************************************/ +static void setSSPclock (LPC_SSP_TypeDef *SSPx, uint32_t target_clock) +{ + uint32_t prescale, cr0_div, cmp_clk, ssp_clk; + + CHECK_PARAM(PARAM_SSPx(SSPx)); + + /* The SSP clock is derived from the (main system oscillator / 2), + so compute the best divider from that clock */ + if (SSPx == LPC_SSP0){ + ssp_clk = CLKPWR_GetPCLK (CLKPWR_PCLKSEL_SSP0); + } else if (SSPx == LPC_SSP1) { + ssp_clk = CLKPWR_GetPCLK (CLKPWR_PCLKSEL_SSP1); + } else { + return; + } + + /* Find closest divider to get at or under the target frequency. + Use smallest prescale possible and rely on the divider to get + the closest target frequency */ + cr0_div = 0; + cmp_clk = 0xFFFFFFFF; + prescale = 2; + while (cmp_clk > target_clock) + { + cmp_clk = ssp_clk / ((cr0_div + 1) * prescale); + if (cmp_clk > target_clock) + { + cr0_div++; + if (cr0_div > 0xFF) + { + cr0_div = 0; + prescale += 2; + } + } + } + + /* Write computed prescaler and divider back to register */ + SSPx->CR0 &= (~SSP_CR0_SCR(0xFF)) & SSP_CR0_BITMASK; + SSPx->CR0 |= (SSP_CR0_SCR(cr0_div)) & SSP_CR0_BITMASK; + SSPx->CPSR = prescale & SSP_CPSR_BITMASK; +} + +/** + * @} + */ + +/* Public Functions ----------------------------------------------------------- */ +/** @addtogroup SSP_Public_Functions + * @{ + */ + +/********************************************************************//** + * @brief Initializes the SSPx peripheral according to the specified +* parameters in the SSP_ConfigStruct. + * @param[in] SSPx SSP peripheral selected, should be: + * - LPC_SSP0: SSP0 peripheral + * - LPC_SSP1: SSP1 peripheral + * @param[in] SSP_ConfigStruct Pointer to a SSP_CFG_Type structure +* that contains the configuration information for the +* specified SSP peripheral. + * @return None + *********************************************************************/ +void SSP_Init(LPC_SSP_TypeDef *SSPx, SSP_CFG_Type *SSP_ConfigStruct) +{ + uint32_t tmp; + + CHECK_PARAM(PARAM_SSPx(SSPx)); + + if(SSPx == LPC_SSP0) { + /* Set up clock and power for SSP0 module */ + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCSSP0, ENABLE); + } else if(SSPx == LPC_SSP1) { + /* Set up clock and power for SSP1 module */ + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCSSP1, ENABLE); + } else { + return; + } + + /* Configure SSP, interrupt is disable, LoopBack mode is disable, + * SSP is disable, Slave output is disable as default + */ + tmp = ((SSP_ConfigStruct->CPHA) | (SSP_ConfigStruct->CPOL) \ + | (SSP_ConfigStruct->FrameFormat) | (SSP_ConfigStruct->Databit)) + & SSP_CR0_BITMASK; + // write back to SSP control register + SSPx->CR0 = tmp; + + tmp = SSP_ConfigStruct->Mode & SSP_CR1_BITMASK; + // Write back to CR1 + SSPx->CR1 = tmp; + + // Set clock rate for SSP peripheral + setSSPclock(SSPx, SSP_ConfigStruct->ClockRate); +} + +/*********************************************************************//** + * @brief De-initializes the SSPx peripheral registers to their +* default reset values. + * @param[in] SSPx SSP peripheral selected, should be: + * - LPC_SSP0: SSP0 peripheral + * - LPC_SSP1: SSP1 peripheral + * @return None + **********************************************************************/ +void SSP_DeInit(LPC_SSP_TypeDef* SSPx) +{ + CHECK_PARAM(PARAM_SSPx(SSPx)); + + if (SSPx == LPC_SSP0){ + /* Set up clock and power for SSP0 module */ + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCSSP0, DISABLE); + } else if (SSPx == LPC_SSP1) { + /* Set up clock and power for SSP1 module */ + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCSSP1, DISABLE); + } +} + +/*****************************************************************************//** +* @brief Get data size bit selected +* @param[in] SSPx pointer to LPC_SSP_TypeDef structure, should be: +* - LPC_SSP0: SSP0 peripheral +* - LPC_SSP1: SSP1 peripheral +* @return Data size, could be: +* - SSP_DATABIT_4: 4 bit transfer +* - SSP_DATABIT_5: 5 bit transfer +* ... +* - SSP_DATABIT_16: 16 bit transfer +*******************************************************************************/ +uint8_t SSP_GetDataSize(LPC_SSP_TypeDef* SSPx) +{ + CHECK_PARAM(PARAM_SSPx(SSPx)); + return (SSPx->CR0 & (0xF)); +} + +/*****************************************************************************//** +* @brief Fills each SSP_InitStruct member with its default value: +* - CPHA = SSP_CPHA_FIRST +* - CPOL = SSP_CPOL_HI +* - ClockRate = 1000000 +* - Databit = SSP_DATABIT_8 +* - Mode = SSP_MASTER_MODE +* - FrameFormat = SSP_FRAME_SSP +* @param[in] SSP_InitStruct Pointer to a SSP_CFG_Type structure +* which will be initialized. +* @return None +*******************************************************************************/ +void SSP_ConfigStructInit(SSP_CFG_Type *SSP_InitStruct) +{ + SSP_InitStruct->CPHA = SSP_CPHA_FIRST; + SSP_InitStruct->CPOL = SSP_CPOL_HI; + SSP_InitStruct->ClockRate = 1000000; + SSP_InitStruct->Databit = SSP_DATABIT_8; + SSP_InitStruct->Mode = SSP_MASTER_MODE; + SSP_InitStruct->FrameFormat = SSP_FRAME_SPI; +} + + +/*********************************************************************//** + * @brief Enable or disable SSP peripheral's operation + * @param[in] SSPx SSP peripheral, should be: + * - LPC_SSP0: SSP0 peripheral + * - LPC_SSP1: SSP1 peripheral + * @param[in] NewState New State of SSPx peripheral's operation + * @return none + **********************************************************************/ +void SSP_Cmd(LPC_SSP_TypeDef* SSPx, FunctionalState NewState) +{ + CHECK_PARAM(PARAM_SSPx(SSPx)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState)); + + if (NewState == ENABLE) + { + SSPx->CR1 |= SSP_CR1_SSP_EN; + } + else + { + SSPx->CR1 &= (~SSP_CR1_SSP_EN) & SSP_CR1_BITMASK; + } +} + +/*********************************************************************//** + * @brief Enable or disable Loop Back mode function in SSP peripheral + * @param[in] SSPx SSP peripheral selected, should be: + * - LPC_SSP0: SSP0 peripheral + * - LPC_SSP1: SSP1 peripheral + * @param[in] NewState New State of Loop Back mode, should be: + * - ENABLE: Enable this function + * - DISABLE: Disable this function + * @return None + **********************************************************************/ +void SSP_LoopBackCmd(LPC_SSP_TypeDef* SSPx, FunctionalState NewState) +{ + CHECK_PARAM(PARAM_SSPx(SSPx)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState)); + + if (NewState == ENABLE) + { + SSPx->CR1 |= SSP_CR1_LBM_EN; + } + else + { + SSPx->CR1 &= (~SSP_CR1_LBM_EN) & SSP_CR1_BITMASK; + } +} + +/*********************************************************************//** + * @brief Enable or disable Slave Output function in SSP peripheral + * @param[in] SSPx SSP peripheral selected, should be: + * - LPC_SSP0: SSP0 peripheral + * - LPC_SSP1: SSP1 peripheral + * @param[in] NewState New State of Slave Output function, should be: + * - ENABLE: Slave Output in normal operation + * - DISABLE: Slave Output is disabled. This blocks + * SSP controller from driving the transmit data + * line (MISO) + * Note: This function is available when SSP peripheral in Slave mode + * @return None + **********************************************************************/ +void SSP_SlaveOutputCmd(LPC_SSP_TypeDef* SSPx, FunctionalState NewState) +{ + CHECK_PARAM(PARAM_SSPx(SSPx)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState)); + + if (NewState == ENABLE) + { + SSPx->CR1 &= (~SSP_CR1_SO_DISABLE) & SSP_CR1_BITMASK; + } + else + { + SSPx->CR1 |= SSP_CR1_SO_DISABLE; + } +} + + + +/*********************************************************************//** + * @brief Transmit a single data through SSPx peripheral + * @param[in] SSPx SSP peripheral selected, should be: + * - LPC_SSP0: SSP0 peripheral + * - LPC_SSP1: SSP1 peripheral + * @param[in] Data Data to transmit (must be 16 or 8-bit long, + * this depend on SSP data bit number configured) + * @return none + **********************************************************************/ +void SSP_SendData(LPC_SSP_TypeDef* SSPx, uint16_t Data) +{ + CHECK_PARAM(PARAM_SSPx(SSPx)); + + SSPx->DR = SSP_DR_BITMASK(Data); +} + + + +/*********************************************************************//** + * @brief Receive a single data from SSPx peripheral + * @param[in] SSPx SSP peripheral selected, should be + * - LPC_SSP0: SSP0 peripheral + * - LPC_SSP1: SSP1 peripheral + * @return Data received (16-bit long) + **********************************************************************/ +uint16_t SSP_ReceiveData(LPC_SSP_TypeDef* SSPx) +{ + CHECK_PARAM(PARAM_SSPx(SSPx)); + + return ((uint16_t) (SSP_DR_BITMASK(SSPx->DR))); +} + +/*********************************************************************//** + * @brief SSP Read write data function + * @param[in] SSPx Pointer to SSP peripheral, should be + * - LPC_SSP0: SSP0 peripheral + * - LPC_SSP1: SSP1 peripheral + * @param[in] dataCfg Pointer to a SSP_DATA_SETUP_Type structure that + * contains specified information about transmit + * data configuration. + * @param[in] xfType Transfer type, should be: + * - SSP_TRANSFER_POLLING: Polling mode + * - SSP_TRANSFER_INTERRUPT: Interrupt mode + * @return Actual Data length has been transferred in polling mode. + * In interrupt mode, always return (0) + * Return (-1) if error. + * Note: This function can be used in both master and slave mode. + ***********************************************************************/ +int32_t SSP_ReadWrite (LPC_SSP_TypeDef *SSPx, SSP_DATA_SETUP_Type *dataCfg, \ + SSP_TRANSFER_Type xfType) +{ + uint8_t *rdata8; + uint8_t *wdata8; + uint16_t *rdata16; + uint16_t *wdata16; + uint32_t stat; + uint32_t tmp; + int32_t dataword; + + dataCfg->rx_cnt = 0; + dataCfg->tx_cnt = 0; + dataCfg->status = 0; + + + /* Clear all remaining data in RX FIFO */ + while (SSPx->SR & SSP_SR_RNE){ + tmp = (uint32_t) SSP_ReceiveData(SSPx); + } + + // Clear status + SSPx->ICR = SSP_ICR_BITMASK; + if(SSP_GetDataSize(SSPx)>8) + dataword = 1; + else dataword = 0; + + // Polling mode ---------------------------------------------------------------------- + if (xfType == SSP_TRANSFER_POLLING){ + if (dataword == 0){ + rdata8 = (uint8_t *)dataCfg->rx_data; + wdata8 = (uint8_t *)dataCfg->tx_data; + } else { + rdata16 = (uint16_t *)dataCfg->rx_data; + wdata16 = (uint16_t *)dataCfg->tx_data; + } + while ((dataCfg->tx_cnt != dataCfg->length) || (dataCfg->rx_cnt != dataCfg->length)){ + if ((SSPx->SR & SSP_SR_TNF) && (dataCfg->tx_cnt != dataCfg->length)){ + // Write data to buffer + if(dataCfg->tx_data == NULL){ + if (dataword == 0){ + SSP_SendData(SSPx, 0xFF); + dataCfg->tx_cnt++; + } else { + SSP_SendData(SSPx, 0xFFFF); + dataCfg->tx_cnt += 2; + } + } else { + if (dataword == 0){ + SSP_SendData(SSPx, *wdata8); + wdata8++; + dataCfg->tx_cnt++; + } else { + SSP_SendData(SSPx, *wdata16); + wdata16++; + dataCfg->tx_cnt += 2; + } + } + } + + // Check overrun error + if ((stat = SSPx->RIS) & SSP_RIS_ROR){ + // save status and return + dataCfg->status = stat | SSP_STAT_ERROR; + return (-1); + } + + // Check for any data available in RX FIFO + while ((SSPx->SR & SSP_SR_RNE) && (dataCfg->rx_cnt != dataCfg->length)){ + // Read data from SSP data + tmp = SSP_ReceiveData(SSPx); + + // Store data to destination + if (dataCfg->rx_data != NULL) + { + if (dataword == 0){ + *(rdata8) = (uint8_t) tmp; + rdata8++; + } else { + *(rdata16) = (uint16_t) tmp; + rdata16++; + } + } + // Increase counter + if (dataword == 0){ + dataCfg->rx_cnt++; + } else { + dataCfg->rx_cnt += 2; + } + } + } + + // save status + dataCfg->status = SSP_STAT_DONE; + + if (dataCfg->tx_data != NULL){ + return dataCfg->tx_cnt; + } else if (dataCfg->rx_data != NULL){ + return dataCfg->rx_cnt; + } else { + return (0); + } + } + + // Interrupt mode ---------------------------------------------------------------------- + else if (xfType == SSP_TRANSFER_INTERRUPT){ + + while ((SSPx->SR & SSP_SR_TNF) && (dataCfg->tx_cnt != dataCfg->length)){ + // Write data to buffer + if(dataCfg->tx_data == NULL){ + if (dataword == 0){ + SSP_SendData(SSPx, 0xFF); + dataCfg->tx_cnt++; + } else { + SSP_SendData(SSPx, 0xFFFF); + dataCfg->tx_cnt += 2; + } + } else { + if (dataword == 0){ + SSP_SendData(SSPx, (*(uint8_t *)((uint32_t)dataCfg->tx_data + dataCfg->tx_cnt))); + dataCfg->tx_cnt++; + } else { + SSP_SendData(SSPx, (*(uint16_t *)((uint32_t)dataCfg->tx_data + dataCfg->tx_cnt))); + dataCfg->tx_cnt += 2; + } + } + + // Check error + if ((stat = SSPx->RIS) & SSP_RIS_ROR){ + // save status and return + dataCfg->status = stat | SSP_STAT_ERROR; + return (-1); + } + + // Check for any data available in RX FIFO + while ((SSPx->SR & SSP_SR_RNE) && (dataCfg->rx_cnt != dataCfg->length)){ + // Read data from SSP data + tmp = SSP_ReceiveData(SSPx); + + // Store data to destination + if (dataCfg->rx_data != NULL) + { + if (dataword == 0){ + *(uint8_t *)((uint32_t)dataCfg->rx_data + dataCfg->rx_cnt) = (uint8_t) tmp; + } else { + *(uint16_t *)((uint32_t)dataCfg->rx_data + dataCfg->rx_cnt) = (uint16_t) tmp; + } + } + // Increase counter + if (dataword == 0){ + dataCfg->rx_cnt++; + } else { + dataCfg->rx_cnt += 2; + } + } + } + + // If there more data to sent or receive + if ((dataCfg->rx_cnt != dataCfg->length) || (dataCfg->tx_cnt != dataCfg->length)){ + // Enable all interrupt + SSPx->IMSC = SSP_IMSC_BITMASK; + } else { + // Save status + dataCfg->status = SSP_STAT_DONE; + } + return (0); + } + + return (-1); +} + +/*********************************************************************//** + * @brief Checks whether the specified SSP status flag is set or not + * @param[in] SSPx SSP peripheral selected, should be: + * - LPC_SSP0: SSP0 peripheral + * - LPC_SSP1: SSP1 peripheral + * @param[in] FlagType Type of flag to check status, should be one + * of following: + * - SSP_STAT_TXFIFO_EMPTY: TX FIFO is empty + * - SSP_STAT_TXFIFO_NOTFULL: TX FIFO is not full + * - SSP_STAT_RXFIFO_NOTEMPTY: RX FIFO is not empty + * - SSP_STAT_RXFIFO_FULL: RX FIFO is full + * - SSP_STAT_BUSY: SSP peripheral is busy + * @return New State of specified SSP status flag + **********************************************************************/ +FlagStatus SSP_GetStatus(LPC_SSP_TypeDef* SSPx, uint32_t FlagType) +{ + CHECK_PARAM(PARAM_SSPx(SSPx)); + CHECK_PARAM(PARAM_SSP_STAT(FlagType)); + + return ((SSPx->SR & FlagType) ? SET : RESET); +} + +/*********************************************************************//** + * @brief Enable or disable specified interrupt type in SSP peripheral + * @param[in] SSPx SSP peripheral selected, should be: + * - LPC_SSP0: SSP0 peripheral + * - LPC_SSP1: SSP1 peripheral + * @param[in] IntType Interrupt type in SSP peripheral, should be: + * - SSP_INTCFG_ROR: Receive Overrun interrupt + * - SSP_INTCFG_RT: Receive Time out interrupt + * - SSP_INTCFG_RX: RX FIFO is at least half full interrupt + * - SSP_INTCFG_TX: TX FIFO is at least half empty interrupt + * @param[in] NewState New State of specified interrupt type, should be: + * - ENABLE: Enable this interrupt type + * - DISABLE: Disable this interrupt type + * @return None + * Note: We can enable/disable multi-interrupt type by OR multi value + **********************************************************************/ +void SSP_IntConfig(LPC_SSP_TypeDef *SSPx, uint32_t IntType, FunctionalState NewState) +{ + CHECK_PARAM(PARAM_SSPx(SSPx)); + + if (NewState == ENABLE) + { + SSPx->IMSC |= IntType; + } + else + { + SSPx->IMSC &= (~IntType) & SSP_IMSC_BITMASK; + } +} + +/*********************************************************************//** + * @brief Check whether the specified Raw interrupt status flag is + * set or not + * @param[in] SSPx SSP peripheral selected, should be: + * - LPC_SSP0: SSP0 peripheral + * - LPC_SSP1: SSP1 peripheral + * @param[in] RawIntType Raw Interrupt Type, should be: + * - SSP_INTSTAT_RAW_ROR: Receive Overrun interrupt + * - SSP_INTSTAT_RAW_RT: Receive Time out interrupt + * - SSP_INTSTAT_RAW_RX: RX FIFO is at least half full interrupt + * - SSP_INTSTAT_RAW_TX: TX FIFO is at least half empty interrupt + * @return New State of specified Raw interrupt status flag in SSP peripheral + * Note: Enabling/Disabling specified interrupt in SSP peripheral does not + * effect to Raw Interrupt Status flag. + **********************************************************************/ +IntStatus SSP_GetRawIntStatus(LPC_SSP_TypeDef *SSPx, uint32_t RawIntType) +{ + CHECK_PARAM(PARAM_SSPx(SSPx)); + CHECK_PARAM(PARAM_SSP_INTSTAT_RAW(RawIntType)); + + return ((SSPx->RIS & RawIntType) ? SET : RESET); +} + +/*********************************************************************//** + * @brief Get Raw Interrupt Status register + * @param[in] SSPx SSP peripheral selected, should be: + * - LPC_SSP0: SSP0 peripheral + * - LPC_SSP1: SSP1 peripheral + * @return Raw Interrupt Status (RIS) register value + **********************************************************************/ +uint32_t SSP_GetRawIntStatusReg(LPC_SSP_TypeDef *SSPx) +{ + CHECK_PARAM(PARAM_SSPx(SSPx)); + return (SSPx->RIS); +} + +/*********************************************************************//** + * @brief Check whether the specified interrupt status flag is + * set or not + * @param[in] SSPx SSP peripheral selected, should be: + * - LPC_SSP0: SSP0 peripheral + * - LPC_SSP1: SSP1 peripheral + * @param[in] IntType Raw Interrupt Type, should be: + * - SSP_INTSTAT_ROR: Receive Overrun interrupt + * - SSP_INTSTAT_RT: Receive Time out interrupt + * - SSP_INTSTAT_RX: RX FIFO is at least half full interrupt + * - SSP_INTSTAT_TX: TX FIFO is at least half empty interrupt + * @return New State of specified interrupt status flag in SSP peripheral + * Note: Enabling/Disabling specified interrupt in SSP peripheral effects + * to Interrupt Status flag. + **********************************************************************/ +IntStatus SSP_GetIntStatus (LPC_SSP_TypeDef *SSPx, uint32_t IntType) +{ + CHECK_PARAM(PARAM_SSPx(SSPx)); + CHECK_PARAM(PARAM_SSP_INTSTAT(IntType)); + + return ((SSPx->MIS & IntType) ? SET :RESET); +} + +/*********************************************************************//** + * @brief Clear specified interrupt pending in SSP peripheral + * @param[in] SSPx SSP peripheral selected, should be: + * - LPC_SSP0: SSP0 peripheral + * - LPC_SSP1: SSP1 peripheral + * @param[in] IntType Interrupt pending to clear, should be: + * - SSP_INTCLR_ROR: clears the "frame was received when + * RxFIFO was full" interrupt. + * - SSP_INTCLR_RT: clears the "Rx FIFO was not empty and + * has not been read for a timeout period" interrupt. + * @return None + **********************************************************************/ +void SSP_ClearIntPending(LPC_SSP_TypeDef *SSPx, uint32_t IntType) +{ + CHECK_PARAM(PARAM_SSPx(SSPx)); + CHECK_PARAM(PARAM_SSP_INTCLR(IntType)); + + SSPx->ICR = IntType; +} + +/*********************************************************************//** + * @brief Enable/Disable DMA function for SSP peripheral + * @param[in] SSPx SSP peripheral selected, should be: + * - LPC_SSP0: SSP0 peripheral + * - LPC_SSP1: SSP1 peripheral + * @param[in] DMAMode Type of DMA, should be: + * - SSP_DMA_TX: DMA for the transmit FIFO + * - SSP_DMA_RX: DMA for the Receive FIFO + * @param[in] NewState New State of DMA function on SSP peripheral, + * should be: + * - ENALBE: Enable this function + * - DISABLE: Disable this function + * @return None + **********************************************************************/ +void SSP_DMACmd(LPC_SSP_TypeDef *SSPx, uint32_t DMAMode, FunctionalState NewState) +{ + CHECK_PARAM(PARAM_SSPx(SSPx)); + CHECK_PARAM(PARAM_SSP_DMA(DMAMode)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState)); + + if (NewState == ENABLE) + { + SSPx->DMACR |= DMAMode; + } + else + { + SSPx->DMACR &= (~DMAMode) & SSP_DMA_BITMASK; + } +} + +/** + * @} + */ + +#endif /* _SSP */ + +/** + * @} + */ + +/* --------------------------------- End Of File ------------------------------ */ + diff --git a/arch/arm/lpc17xx/Drivers/source/lpc17xx_systick.c b/arch/arm/lpc17xx/Drivers/source/lpc17xx_systick.c new file mode 100644 index 0000000..5112679 --- /dev/null +++ b/arch/arm/lpc17xx/Drivers/source/lpc17xx_systick.c @@ -0,0 +1,180 @@ +/***********************************************************************//** + * @file lpc17xx_systick.c + * @brief Contains all functions support for SYSTICK firmware library on LPC17xx + * @version 2.0 + * @date 21. May. 2010 + * @author NXP MCU SW Application Team + ************************************************************************** + * Software that is described herein is for illustrative purposes only + * which provides customers with programming information regarding the + * products. This software is supplied "AS IS" without any warranties. + * NXP Semiconductors assumes no responsibility or liability for the + * use of the software, conveys no license or title under any patent, + * copyright, or mask work right to the product. NXP Semiconductors + * reserves the right to make changes in the software without + * notification. NXP Semiconductors also make no representation or + * warranty that such application will be suitable for the specified + * use without further testing or modification. + **********************************************************************/ + +/* Peripheral group ----------------------------------------------------------- */ +/** @addtogroup SYSTICK + * @{ + */ + +/* Includes ------------------------------------------------------------------- */ +#include "lpc17xx_systick.h" +#include "lpc17xx_clkpwr.h" + +/* If this source file built with example, the LPC17xx FW library configuration + * file in each example directory ("lpc17xx_libcfg.h") must be included, + * otherwise the default FW library configuration file must be included instead + */ +#ifdef __BUILD_WITH_EXAMPLE__ +#include "lpc17xx_libcfg.h" +#else +#include "lpc17xx_libcfg_default.h" +#endif /* __BUILD_WITH_EXAMPLE__ */ + + +#ifdef _SYSTICK + +/* Public Functions ----------------------------------------------------------- */ +/** @addtogroup SYSTICK_Public_Functions + * @{ + */ +/*********************************************************************//** + * @brief Initial System Tick with using internal CPU clock source + * @param[in] time time interval(ms) + * @return None + **********************************************************************/ +void SYSTICK_InternalInit(uint32_t time) +{ + uint32_t cclk; + float maxtime; + + cclk = SystemCoreClock; + /* With internal CPU clock frequency for LPC17xx is 'SystemCoreClock' + * And limit 24 bit for RELOAD value + * So the maximum time can be set: + * 1/SystemCoreClock * (2^24) * 1000 (ms) + */ + //check time value is available or not + maxtime = (1<<24)/(SystemCoreClock / 1000) ; + if(time > maxtime) + //Error loop + while(1); + else + { + //Select CPU clock is System Tick clock source + SysTick->CTRL |= ST_CTRL_CLKSOURCE; + /* Set RELOAD value + * RELOAD = (SystemCoreClock/1000) * time - 1 + * with time base is millisecond + */ + SysTick->RELOAD = (cclk/1000)*time - 1; + } +} + +/*********************************************************************//** + * @brief Initial System Tick with using external clock source + * @param[in] freq external clock frequency(Hz) + * @param[in] time time interval(ms) + * @return None + **********************************************************************/ +void SYSTICK_ExternalInit(uint32_t freq, uint32_t time) +{ + float maxtime; + + /* With external clock frequency for LPC17xx is 'freq' + * And limit 24 bit for RELOAD value + * So the maximum time can be set: + * 1/freq * (2^24) * 1000 (ms) + */ + //check time value is available or not + maxtime = (1<<24)/(freq / 1000) ; + if (time>maxtime) + //Error Loop + while(1); + else + { + //Select external clock is System Tick clock source + SysTick->CTRL &= ~ ST_CTRL_CLKSOURCE; + /* Set RELOAD value + * RELOAD = (freq/1000) * time - 1 + * with time base is millisecond + */ + maxtime = (freq/1000)*time - 1; + SysTick->RELOAD = (freq/1000)*time - 1; + } +} + +/*********************************************************************//** + * @brief Enable/disable System Tick counter + * @param[in] NewState System Tick counter status, should be: + * - ENABLE + * - DISABLE + * @return None + **********************************************************************/ +void SYSTICK_Cmd(FunctionalState NewState) +{ + CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState)); + + if(NewState == ENABLE) + //Enable System Tick counter + SysTick->CTRL |= ST_CTRL_ENABLE; + else + //Disable System Tick counter + SysTick->CTRL &= ~ST_CTRL_ENABLE; +} + +/*********************************************************************//** + * @brief Enable/disable System Tick interrupt + * @param[in] NewState System Tick interrupt status, should be: + * - ENABLE + * - DISABLE + * @return None + **********************************************************************/ +void SYSTICK_IntCmd(FunctionalState NewState) +{ + CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState)); + + if(NewState == ENABLE) + //Enable System Tick counter + SysTick->CTRL |= ST_CTRL_TICKINT; + else + //Disable System Tick counter + SysTick->CTRL &= ~ST_CTRL_TICKINT; +} + +/*********************************************************************//** + * @brief Get current value of System Tick counter + * @param[in] None + * @return current value of System Tick counter + **********************************************************************/ +uint32_t SYSTICK_GetCurrentValue(void) +{ + return (SysTick->CURR); +} + +/*********************************************************************//** + * @brief Clear Counter flag + * @param[in] None + * @return None + **********************************************************************/ +void SYSTICK_ClearCounterFlag(void) +{ + SysTick->CTRL &= ~ST_CTRL_COUNTFLAG; +} +/** + * @} + */ + +#endif /* _SYSTICK */ + +/** + * @} + */ + +/* --------------------------------- End Of File ------------------------------ */ + diff --git a/arch/arm/lpc17xx/Drivers/source/lpc17xx_timer.c b/arch/arm/lpc17xx/Drivers/source/lpc17xx_timer.c new file mode 100644 index 0000000..163cccd --- /dev/null +++ b/arch/arm/lpc17xx/Drivers/source/lpc17xx_timer.c @@ -0,0 +1,591 @@ +/***********************************************************************//** + * @file lpc17xx_timer.c + * @brief Contains all functions support for Timer firmware library on LPC17xx + * @version 3.0 + * @date 18. June. 2010 + * @author NXP MCU SW Application Team + ************************************************************************** + * Software that is described herein is for illustrative purposes only + * which provides customers with programming information regarding the + * products. This software is supplied "AS IS" without any warranties. + * NXP Semiconductors assumes no responsibility or liability for the + * use of the software, conveys no license or title under any patent, + * copyright, or mask work right to the product. NXP Semiconductors + * reserves the right to make changes in the software without + * notification. NXP Semiconductors also make no representation or + * warranty that such application will be suitable for the specified + * use without further testing or modification. + **********************************************************************/ + +/* Peripheral group ----------------------------------------------------------- */ +/** @addtogroup TIM + * @{ + */ + +/* Includes ------------------------------------------------------------------- */ +#include "lpc17xx_timer.h" +#include "lpc17xx_clkpwr.h" +#include "lpc17xx_pinsel.h" + +/* If this source file built with example, the LPC17xx FW library configuration + * file in each example directory ("lpc17xx_libcfg.h") must be included, + * otherwise the default FW library configuration file must be included instead + */ +#ifdef __BUILD_WITH_EXAMPLE__ +#include "lpc17xx_libcfg.h" +#else +#include "lpc17xx_libcfg_default.h" +#endif /* __BUILD_WITH_EXAMPLE__ */ + +#ifdef _TIM + +/* Private Functions ---------------------------------------------------------- */ + +static uint32_t getPClock (uint32_t timernum); +static uint32_t converUSecToVal (uint32_t timernum, uint32_t usec); +static uint32_t converPtrToTimeNum (LPC_TIM_TypeDef *TIMx); + + +/*********************************************************************//** + * @brief Get peripheral clock of each timer controller + * @param[in] timernum Timer number + * @return Peripheral clock of timer + **********************************************************************/ +static uint32_t getPClock (uint32_t timernum) +{ + uint32_t clkdlycnt; + switch (timernum) + { + case 0: + clkdlycnt = CLKPWR_GetPCLK (CLKPWR_PCLKSEL_TIMER0); + break; + + case 1: + clkdlycnt = CLKPWR_GetPCLK (CLKPWR_PCLKSEL_TIMER1); + break; + + case 2: + clkdlycnt = CLKPWR_GetPCLK (CLKPWR_PCLKSEL_TIMER2); + break; + + case 3: + clkdlycnt = CLKPWR_GetPCLK (CLKPWR_PCLKSEL_TIMER3); + break; + } + return clkdlycnt; +} + + +/*********************************************************************//** + * @brief Convert a time to a timer count value + * @param[in] timernum Timer number + * @param[in] usec Time in microseconds + * @return The number of required clock ticks to give the time delay + **********************************************************************/ +uint32_t converUSecToVal (uint32_t timernum, uint32_t usec) +{ + uint64_t clkdlycnt; + + // Get Pclock of timer + clkdlycnt = (uint64_t) getPClock(timernum); + + clkdlycnt = (clkdlycnt * usec) / 1000000; + return (uint32_t) clkdlycnt; +} + + +/*********************************************************************//** + * @brief Convert a timer register pointer to a timer number + * @param[in] TIMx Pointer to LPC_TIM_TypeDef, should be: + * - LPC_TIM0: TIMER0 peripheral + * - LPC_TIM1: TIMER1 peripheral + * - LPC_TIM2: TIMER2 peripheral + * - LPC_TIM3: TIMER3 peripheral + * @return The timer number (0 to 3) or -1 if register pointer is bad + **********************************************************************/ +uint32_t converPtrToTimeNum (LPC_TIM_TypeDef *TIMx) +{ + uint32_t tnum = -1; + + if (TIMx == LPC_TIM0) + { + tnum = 0; + } + else if (TIMx == LPC_TIM1) + { + tnum = 1; + } + else if (TIMx == LPC_TIM2) + { + tnum = 2; + } + else if (TIMx == LPC_TIM3) + { + tnum = 3; + } + + return tnum; +} + +/* End of Private Functions ---------------------------------------------------- */ + + +/* Public Functions ----------------------------------------------------------- */ +/** @addtogroup TIM_Public_Functions + * @{ + */ + +/*********************************************************************//** + * @brief Get Interrupt Status + * @param[in] TIMx Timer selection, should be: + * - LPC_TIM0: TIMER0 peripheral + * - LPC_TIM1: TIMER1 peripheral + * - LPC_TIM2: TIMER2 peripheral + * - LPC_TIM3: TIMER3 peripheral + * @param[in] IntFlag: interrupt type, should be: + * - TIM_MR0_INT: Interrupt for Match channel 0 + * - TIM_MR1_INT: Interrupt for Match channel 1 + * - TIM_MR2_INT: Interrupt for Match channel 2 + * - TIM_MR3_INT: Interrupt for Match channel 3 + * - TIM_CR0_INT: Interrupt for Capture channel 0 + * - TIM_CR1_INT: Interrupt for Capture channel 1 + * @return FlagStatus + * - SET : interrupt + * - RESET : no interrupt + **********************************************************************/ +FlagStatus TIM_GetIntStatus(LPC_TIM_TypeDef *TIMx, TIM_INT_TYPE IntFlag) +{ + uint8_t temp; + CHECK_PARAM(PARAM_TIMx(TIMx)); + CHECK_PARAM(PARAM_TIM_INT_TYPE(IntFlag)); + temp = (TIMx->IR)& TIM_IR_CLR(IntFlag); + if (temp) + return SET; + + return RESET; + +} +/*********************************************************************//** + * @brief Get Capture Interrupt Status + * @param[in] TIMx Timer selection, should be: + * - LPC_TIM0: TIMER0 peripheral + * - LPC_TIM1: TIMER1 peripheral + * - LPC_TIM2: TIMER2 peripheral + * - LPC_TIM3: TIMER3 peripheral + * @param[in] IntFlag: interrupt type, should be: + * - TIM_MR0_INT: Interrupt for Match channel 0 + * - TIM_MR1_INT: Interrupt for Match channel 1 + * - TIM_MR2_INT: Interrupt for Match channel 2 + * - TIM_MR3_INT: Interrupt for Match channel 3 + * - TIM_CR0_INT: Interrupt for Capture channel 0 + * - TIM_CR1_INT: Interrupt for Capture channel 1 + * @return FlagStatus + * - SET : interrupt + * - RESET : no interrupt + **********************************************************************/ +FlagStatus TIM_GetIntCaptureStatus(LPC_TIM_TypeDef *TIMx, TIM_INT_TYPE IntFlag) +{ + uint8_t temp; + CHECK_PARAM(PARAM_TIMx(TIMx)); + CHECK_PARAM(PARAM_TIM_INT_TYPE(IntFlag)); + temp = (TIMx->IR) & (1<<(4+IntFlag)); + if(temp) + return SET; + return RESET; +} +/*********************************************************************//** + * @brief Clear Interrupt pending + * @param[in] TIMx Timer selection, should be: + * - LPC_TIM0: TIMER0 peripheral + * - LPC_TIM1: TIMER1 peripheral + * - LPC_TIM2: TIMER2 peripheral + * - LPC_TIM3: TIMER3 peripheral + * @param[in] IntFlag: interrupt type, should be: + * - TIM_MR0_INT: Interrupt for Match channel 0 + * - TIM_MR1_INT: Interrupt for Match channel 1 + * - TIM_MR2_INT: Interrupt for Match channel 2 + * - TIM_MR3_INT: Interrupt for Match channel 3 + * - TIM_CR0_INT: Interrupt for Capture channel 0 + * - TIM_CR1_INT: Interrupt for Capture channel 1 + * @return None + **********************************************************************/ +void TIM_ClearIntPending(LPC_TIM_TypeDef *TIMx, TIM_INT_TYPE IntFlag) +{ + CHECK_PARAM(PARAM_TIMx(TIMx)); + CHECK_PARAM(PARAM_TIM_INT_TYPE(IntFlag)); + TIMx->IR |= TIM_IR_CLR(IntFlag); +} + +/*********************************************************************//** + * @brief Clear Capture Interrupt pending + * @param[in] TIMx Timer selection, should be + * - LPC_TIM0: TIMER0 peripheral + * - LPC_TIM1: TIMER1 peripheral + * - LPC_TIM2: TIMER2 peripheral + * - LPC_TIM3: TIMER3 peripheral + * @param[in] IntFlag interrupt type, should be: + * - TIM_MR0_INT: Interrupt for Match channel 0 + * - TIM_MR1_INT: Interrupt for Match channel 1 + * - TIM_MR2_INT: Interrupt for Match channel 2 + * - TIM_MR3_INT: Interrupt for Match channel 3 + * - TIM_CR0_INT: Interrupt for Capture channel 0 + * - TIM_CR1_INT: Interrupt for Capture channel 1 + * @return None + **********************************************************************/ +void TIM_ClearIntCapturePending(LPC_TIM_TypeDef *TIMx, TIM_INT_TYPE IntFlag) +{ + CHECK_PARAM(PARAM_TIMx(TIMx)); + CHECK_PARAM(PARAM_TIM_INT_TYPE(IntFlag)); + TIMx->IR |= (1<<(4+IntFlag)); +} + +/*********************************************************************//** + * @brief Configuration for Timer at initial time + * @param[in] TimerCounterMode timer counter mode, should be: + * - TIM_TIMER_MODE: Timer mode + * - TIM_COUNTER_RISING_MODE: Counter rising mode + * - TIM_COUNTER_FALLING_MODE: Counter falling mode + * - TIM_COUNTER_ANY_MODE:Counter on both edges + * @param[in] TIM_ConfigStruct pointer to TIM_TIMERCFG_Type or + * TIM_COUNTERCFG_Type + * @return None + **********************************************************************/ +void TIM_ConfigStructInit(TIM_MODE_OPT TimerCounterMode, void *TIM_ConfigStruct) +{ + if (TimerCounterMode == TIM_TIMER_MODE ) + { + TIM_TIMERCFG_Type * pTimeCfg = (TIM_TIMERCFG_Type *)TIM_ConfigStruct; + pTimeCfg->PrescaleOption = TIM_PRESCALE_USVAL; + pTimeCfg->PrescaleValue = 1; + } + else + { + TIM_COUNTERCFG_Type * pCounterCfg = (TIM_COUNTERCFG_Type *)TIM_ConfigStruct; + pCounterCfg->CountInputSelect = TIM_COUNTER_INCAP0; + } +} + +/*********************************************************************//** + * @brief Initial Timer/Counter device + * Set Clock frequency for Timer + * Set initial configuration for Timer + * @param[in] TIMx Timer selection, should be: + * - LPC_TIM0: TIMER0 peripheral + * - LPC_TIM1: TIMER1 peripheral + * - LPC_TIM2: TIMER2 peripheral + * - LPC_TIM3: TIMER3 peripheral + * @param[in] TimerCounterMode Timer counter mode, should be: + * - TIM_TIMER_MODE: Timer mode + * - TIM_COUNTER_RISING_MODE: Counter rising mode + * - TIM_COUNTER_FALLING_MODE: Counter falling mode + * - TIM_COUNTER_ANY_MODE:Counter on both edges + * @param[in] TIM_ConfigStruct pointer to TIM_TIMERCFG_Type + * that contains the configuration information for the + * specified Timer peripheral. + * @return None + **********************************************************************/ +void TIM_Init(LPC_TIM_TypeDef *TIMx, TIM_MODE_OPT TimerCounterMode, void *TIM_ConfigStruct) +{ + TIM_TIMERCFG_Type *pTimeCfg; + TIM_COUNTERCFG_Type *pCounterCfg; + + CHECK_PARAM(PARAM_TIMx(TIMx)); + CHECK_PARAM(PARAM_TIM_MODE_OPT(TimerCounterMode)); + + //set power + if (TIMx== LPC_TIM0) + { + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCTIM0, ENABLE); + CLKPWR_SetPCLKDiv (CLKPWR_PCLKSEL_TIMER0, CLKPWR_PCLKSEL_CCLK_DIV_4); + } + else if (TIMx== LPC_TIM1) + { + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCTIM1, ENABLE); + CLKPWR_SetPCLKDiv (CLKPWR_PCLKSEL_TIMER1, CLKPWR_PCLKSEL_CCLK_DIV_4); + + } + + else if (TIMx== LPC_TIM2) + { + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCTIM2, ENABLE); + CLKPWR_SetPCLKDiv (CLKPWR_PCLKSEL_TIMER2, CLKPWR_PCLKSEL_CCLK_DIV_4); + } + else if (TIMx== LPC_TIM3) + { + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCTIM3, ENABLE); + CLKPWR_SetPCLKDiv (CLKPWR_PCLKSEL_TIMER3, CLKPWR_PCLKSEL_CCLK_DIV_4); + + } + + TIMx->CCR &= ~TIM_CTCR_MODE_MASK; + TIMx->CCR |= TIM_TIMER_MODE; + + TIMx->TC =0; + TIMx->PC =0; + TIMx->PR =0; + TIMx->TCR |= (1<<1); //Reset Counter + TIMx->TCR &= ~(1<<1); //release reset + if (TimerCounterMode == TIM_TIMER_MODE ) + { + pTimeCfg = (TIM_TIMERCFG_Type *)TIM_ConfigStruct; + if (pTimeCfg->PrescaleOption == TIM_PRESCALE_TICKVAL) + { + TIMx->PR = pTimeCfg->PrescaleValue -1 ; + } + else + { + TIMx->PR = converUSecToVal (converPtrToTimeNum(TIMx),pTimeCfg->PrescaleValue)-1; + } + } + else + { + + pCounterCfg = (TIM_COUNTERCFG_Type *)TIM_ConfigStruct; + TIMx->CCR &= ~TIM_CTCR_INPUT_MASK; + if (pCounterCfg->CountInputSelect == TIM_COUNTER_INCAP1) + TIMx->CCR |= _BIT(2); + } + + // Clear interrupt pending + TIMx->IR = 0xFFFFFFFF; + +} + +/*********************************************************************//** + * @brief Close Timer/Counter device + * @param[in] TIMx Pointer to timer device, should be: + * - LPC_TIM0: TIMER0 peripheral + * - LPC_TIM1: TIMER1 peripheral + * - LPC_TIM2: TIMER2 peripheral + * - LPC_TIM3: TIMER3 peripheral + * @return None + **********************************************************************/ +void TIM_DeInit (LPC_TIM_TypeDef *TIMx) +{ + CHECK_PARAM(PARAM_TIMx(TIMx)); + // Disable timer/counter + TIMx->TCR = 0x00; + + // Disable power + if (TIMx== LPC_TIM0) + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCTIM0, DISABLE); + + else if (TIMx== LPC_TIM1) + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCTIM1, DISABLE); + + else if (TIMx== LPC_TIM2) + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCTIM2, DISABLE); + + else if (TIMx== LPC_TIM3) + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCTIM2, DISABLE); + +} + +/*********************************************************************//** + * @brief Start/Stop Timer/Counter device + * @param[in] TIMx Pointer to timer device, should be: + * - LPC_TIM0: TIMER0 peripheral + * - LPC_TIM1: TIMER1 peripheral + * - LPC_TIM2: TIMER2 peripheral + * - LPC_TIM3: TIMER3 peripheral + * @param[in] NewState + * - ENABLE : set timer enable + * - DISABLE : disable timer + * @return None + **********************************************************************/ +void TIM_Cmd(LPC_TIM_TypeDef *TIMx, FunctionalState NewState) +{ + CHECK_PARAM(PARAM_TIMx(TIMx)); + if (NewState == ENABLE) + { + TIMx->TCR |= TIM_ENABLE; + } + else + { + TIMx->TCR &= ~TIM_ENABLE; + } +} + +/*********************************************************************//** + * @brief Reset Timer/Counter device, + * Make TC and PC are synchronously reset on the next + * positive edge of PCLK + * @param[in] TIMx Pointer to timer device, should be: + * - LPC_TIM0: TIMER0 peripheral + * - LPC_TIM1: TIMER1 peripheral + * - LPC_TIM2: TIMER2 peripheral + * - LPC_TIM3: TIMER3 peripheral + * @return None + **********************************************************************/ +void TIM_ResetCounter(LPC_TIM_TypeDef *TIMx) +{ + CHECK_PARAM(PARAM_TIMx(TIMx)); + TIMx->TCR |= TIM_RESET; + TIMx->TCR &= ~TIM_RESET; +} + +/*********************************************************************//** + * @brief Configuration for Match register + * @param[in] TIMx Pointer to timer device, should be: + * - LPC_TIM0: TIMER0 peripheral + * - LPC_TIM1: TIMER1 peripheral + * - LPC_TIM2: TIMER2 peripheral + * - LPC_TIM3: TIMER3 peripheral + * @param[in] TIM_MatchConfigStruct Pointer to TIM_MATCHCFG_Type + * - MatchChannel : choose channel 0 or 1 + * - IntOnMatch : if SET, interrupt will be generated when MRxx match + * the value in TC + * - StopOnMatch : if SET, TC and PC will be stopped whenM Rxx match + * the value in TC + * - ResetOnMatch : if SET, Reset on MR0 when MRxx match + * the value in TC + * -ExtMatchOutputType: Select output for external match + * + 0: Do nothing for external output pin if match + * + 1: Force external output pin to low if match + * + 2: Force external output pin to high if match + * + 3: Toggle external output pin if match + * MatchValue: Set the value to be compared with TC value + * @return None + **********************************************************************/ +void TIM_ConfigMatch(LPC_TIM_TypeDef *TIMx, TIM_MATCHCFG_Type *TIM_MatchConfigStruct) +{ + + CHECK_PARAM(PARAM_TIMx(TIMx)); + CHECK_PARAM(PARAM_TIM_EXTMATCH_OPT(TIM_MatchConfigStruct->ExtMatchOutputType)); + + switch(TIM_MatchConfigStruct->MatchChannel) + { + case 0: + TIMx->MR0 = TIM_MatchConfigStruct->MatchValue; + break; + case 1: + TIMx->MR1 = TIM_MatchConfigStruct->MatchValue; + break; + case 2: + TIMx->MR2 = TIM_MatchConfigStruct->MatchValue; + break; + case 3: + TIMx->MR3 = TIM_MatchConfigStruct->MatchValue; + break; + default: + //Error match value + //Error loop + while(1); + } + //interrupt on MRn + TIMx->MCR &=~TIM_MCR_CHANNEL_MASKBIT(TIM_MatchConfigStruct->MatchChannel); + + if (TIM_MatchConfigStruct->IntOnMatch) + TIMx->MCR |= TIM_INT_ON_MATCH(TIM_MatchConfigStruct->MatchChannel); + + //reset on MRn + if (TIM_MatchConfigStruct->ResetOnMatch) + TIMx->MCR |= TIM_RESET_ON_MATCH(TIM_MatchConfigStruct->MatchChannel); + + //stop on MRn + if (TIM_MatchConfigStruct->StopOnMatch) + TIMx->MCR |= TIM_STOP_ON_MATCH(TIM_MatchConfigStruct->MatchChannel); + + // match output type + + TIMx->EMR &= ~TIM_EM_MASK(TIM_MatchConfigStruct->MatchChannel); + TIMx->EMR |= TIM_EM_SET(TIM_MatchConfigStruct->MatchChannel,TIM_MatchConfigStruct->ExtMatchOutputType); +} +/*********************************************************************//** + * @brief Update Match value + * @param[in] TIMx Pointer to timer device, should be: + * - LPC_TIM0: TIMER0 peripheral + * - LPC_TIM1: TIMER1 peripheral + * - LPC_TIM2: TIMER2 peripheral + * - LPC_TIM3: TIMER3 peripheral + * @param[in] MatchChannel Match channel, should be: 0..3 + * @param[in] MatchValue updated match value + * @return None + **********************************************************************/ +void TIM_UpdateMatchValue(LPC_TIM_TypeDef *TIMx,uint8_t MatchChannel, uint32_t MatchValue) +{ + CHECK_PARAM(PARAM_TIMx(TIMx)); + switch(MatchChannel) + { + case 0: + TIMx->MR0 = MatchValue; + break; + case 1: + TIMx->MR1 = MatchValue; + break; + case 2: + TIMx->MR2 = MatchValue; + break; + case 3: + TIMx->MR3 = MatchValue; + break; + default: + //Error Loop + while(1); + } + +} +/*********************************************************************//** + * @brief Configuration for Capture register + * @param[in] TIMx Pointer to timer device, should be: + * - LPC_TIM0: TIMER0 peripheral + * - LPC_TIM1: TIMER1 peripheral + * - LPC_TIM2: TIMER2 peripheral + * - LPC_TIM3: TIMER3 peripheral + * - CaptureChannel: set the channel to capture data + * - RisingEdge : if SET, Capture at rising edge + * - FallingEdge : if SET, Capture at falling edge + * - IntOnCaption : if SET, Capture generate interrupt + * @param[in] TIM_CaptureConfigStruct Pointer to TIM_CAPTURECFG_Type + * @return None + **********************************************************************/ +void TIM_ConfigCapture(LPC_TIM_TypeDef *TIMx, TIM_CAPTURECFG_Type *TIM_CaptureConfigStruct) +{ + + CHECK_PARAM(PARAM_TIMx(TIMx)); + TIMx->CCR &= ~TIM_CCR_CHANNEL_MASKBIT(TIM_CaptureConfigStruct->CaptureChannel); + + if (TIM_CaptureConfigStruct->RisingEdge) + TIMx->CCR |= TIM_CAP_RISING(TIM_CaptureConfigStruct->CaptureChannel); + + if (TIM_CaptureConfigStruct->FallingEdge) + TIMx->CCR |= TIM_CAP_FALLING(TIM_CaptureConfigStruct->CaptureChannel); + + if (TIM_CaptureConfigStruct->IntOnCaption) + TIMx->CCR |= TIM_INT_ON_CAP(TIM_CaptureConfigStruct->CaptureChannel); +} + +/*********************************************************************//** + * @brief Read value of capture register in timer/counter device + * @param[in] TIMx Pointer to timer/counter device, should be: + * - LPC_TIM0: TIMER0 peripheral + * - LPC_TIM1: TIMER1 peripheral + * - LPC_TIM2: TIMER2 peripheral + * - LPC_TIM3: TIMER3 peripheral + * @param[in] CaptureChannel: capture channel number, should be: + * - TIM_COUNTER_INCAP0: CAPn.0 input pin for TIMERn + * - TIM_COUNTER_INCAP1: CAPn.1 input pin for TIMERn + * @return Value of capture register + **********************************************************************/ +uint32_t TIM_GetCaptureValue(LPC_TIM_TypeDef *TIMx, TIM_COUNTER_INPUT_OPT CaptureChannel) +{ + CHECK_PARAM(PARAM_TIMx(TIMx)); + CHECK_PARAM(PARAM_TIM_COUNTER_INPUT_OPT(CaptureChannel)); + + if(CaptureChannel==0) + return TIMx->CR0; + else + return TIMx->CR1; +} + +/** + * @} + */ + +#endif /* _TIMER */ + +/** + * @} + */ + +/* --------------------------------- End Of File ------------------------------ */ diff --git a/arch/arm/lpc17xx/Drivers/source/lpc17xx_uart.c b/arch/arm/lpc17xx/Drivers/source/lpc17xx_uart.c new file mode 100644 index 0000000..5f4ee0c --- /dev/null +++ b/arch/arm/lpc17xx/Drivers/source/lpc17xx_uart.c @@ -0,0 +1,1366 @@ +/***********************************************************************//** + * @file lpc17xx_uart.c + * @brief Contains all functions support for UART firmware library on LPC17xx + * @version 3.0 + * @date 18. June. 2010 + * @author NXP MCU SW Application Team + ************************************************************************** + * Software that is described herein is for illustrative purposes only + * which provides customers with programming information regarding the + * products. This software is supplied "AS IS" without any warranties. + * NXP Semiconductors assumes no responsibility or liability for the + * use of the software, conveys no license or title under any patent, + * copyright, or mask work right to the product. NXP Semiconductors + * reserves the right to make changes in the software without + * notification. NXP Semiconductors also make no representation or + * warranty that such application will be suitable for the specified + * use without further testing or modification. + **********************************************************************/ + +/* Peripheral group ----------------------------------------------------------- */ +/** @addtogroup UART + * @{ + */ + +/* Includes ------------------------------------------------------------------- */ +#include "lpc17xx_uart.h" +#include "lpc17xx_clkpwr.h" + +/* If this source file built with example, the LPC17xx FW library configuration + * file in each example directory ("lpc17xx_libcfg.h") must be included, + * otherwise the default FW library configuration file must be included instead + */ +#ifdef __BUILD_WITH_EXAMPLE__ +#include "lpc17xx_libcfg.h" +#else +#include "lpc17xx_libcfg_default.h" +#endif /* __BUILD_WITH_EXAMPLE__ */ + + +#ifdef _UART + +/* Private Functions ---------------------------------------------------------- */ + +static Status uart_set_divisors(LPC_UART_TypeDef *UARTx, uint32_t baudrate); + + +/*********************************************************************//** + * @brief Determines best dividers to get a target clock rate + * @param[in] UARTx Pointer to selected UART peripheral, should be: + * - LPC_UART0: UART0 peripheral + * - LPC_UART1: UART1 peripheral + * - LPC_UART2: UART2 peripheral + * - LPC_UART3: UART3 peripheral + * @param[in] baudrate Desired UART baud rate. + * @return Error status, could be: + * - SUCCESS + * - ERROR + **********************************************************************/ +static Status uart_set_divisors(LPC_UART_TypeDef *UARTx, uint32_t baudrate) +{ + Status errorStatus = ERROR; + + uint32_t uClk; + uint32_t calcBaudrate = 0; + uint32_t temp = 0; + + uint32_t mulFracDiv, dividerAddFracDiv; + uint32_t diviser = 0 ; + uint32_t mulFracDivOptimal = 1; + uint32_t dividerAddOptimal = 0; + uint32_t diviserOptimal = 0; + + uint32_t relativeError = 0; + uint32_t relativeOptimalError = 100000; + + /* get UART block clock */ + if (UARTx == LPC_UART0) + { + uClk = CLKPWR_GetPCLK (CLKPWR_PCLKSEL_UART0); + } + else if (UARTx == (LPC_UART_TypeDef *)LPC_UART1) + { + uClk = CLKPWR_GetPCLK (CLKPWR_PCLKSEL_UART1); + } + else if (UARTx == LPC_UART2) + { + uClk = CLKPWR_GetPCLK (CLKPWR_PCLKSEL_UART2); + } + else if (UARTx == LPC_UART3) + { + uClk = CLKPWR_GetPCLK (CLKPWR_PCLKSEL_UART3); + } + + + uClk = uClk >> 4; /* div by 16 */ + /* In the Uart IP block, baud rate is calculated using FDR and DLL-DLM registers + * The formula is : + * BaudRate= uClk * (mulFracDiv/(mulFracDiv+dividerAddFracDiv) / (16 * (DLL) + * It involves floating point calculations. That's the reason the formulae are adjusted with + * Multiply and divide method.*/ + /* The value of mulFracDiv and dividerAddFracDiv should comply to the following expressions: + * 0 < mulFracDiv <= 15, 0 <= dividerAddFracDiv <= 15 */ + for (mulFracDiv = 1 ; mulFracDiv <= 15 ;mulFracDiv++) + { + for (dividerAddFracDiv = 0 ; dividerAddFracDiv <= 15 ;dividerAddFracDiv++) + { + temp = (mulFracDiv * uClk) / ((mulFracDiv + dividerAddFracDiv)); + + diviser = temp / baudrate; + if ((temp % baudrate) > (baudrate / 2)) + diviser++; + + if (diviser > 2 && diviser < 65536) + { + calcBaudrate = temp / diviser; + + if (calcBaudrate <= baudrate) + relativeError = baudrate - calcBaudrate; + else + relativeError = calcBaudrate - baudrate; + + if ((relativeError < relativeOptimalError)) + { + mulFracDivOptimal = mulFracDiv ; + dividerAddOptimal = dividerAddFracDiv; + diviserOptimal = diviser; + relativeOptimalError = relativeError; + if (relativeError == 0) + break; + } + } /* End of if */ + } /* end of inner for loop */ + if (relativeError == 0) + break; + } /* end of outer for loop */ + + if (relativeOptimalError < ((baudrate * UART_ACCEPTED_BAUDRATE_ERROR)/100)) + { + if (((LPC_UART1_TypeDef *)UARTx) == LPC_UART1) + { + ((LPC_UART1_TypeDef *)UARTx)->LCR |= UART_LCR_DLAB_EN; + ((LPC_UART1_TypeDef *)UARTx)->/*DLIER.*/DLM = UART_LOAD_DLM(diviserOptimal); + ((LPC_UART1_TypeDef *)UARTx)->/*RBTHDLR.*/DLL = UART_LOAD_DLL(diviserOptimal); + /* Then reset DLAB bit */ + ((LPC_UART1_TypeDef *)UARTx)->LCR &= (~UART_LCR_DLAB_EN) & UART_LCR_BITMASK; + ((LPC_UART1_TypeDef *)UARTx)->FDR = (UART_FDR_MULVAL(mulFracDivOptimal) \ + | UART_FDR_DIVADDVAL(dividerAddOptimal)) & UART_FDR_BITMASK; + } + else + { + UARTx->LCR |= UART_LCR_DLAB_EN; + UARTx->/*DLIER.*/DLM = UART_LOAD_DLM(diviserOptimal); + UARTx->/*RBTHDLR.*/DLL = UART_LOAD_DLL(diviserOptimal); + /* Then reset DLAB bit */ + UARTx->LCR &= (~UART_LCR_DLAB_EN) & UART_LCR_BITMASK; + UARTx->FDR = (UART_FDR_MULVAL(mulFracDivOptimal) \ + | UART_FDR_DIVADDVAL(dividerAddOptimal)) & UART_FDR_BITMASK; + } + errorStatus = SUCCESS; + } + + return errorStatus; +} + +/* End of Private Functions ---------------------------------------------------- */ + + +/* Public Functions ----------------------------------------------------------- */ +/** @addtogroup UART_Public_Functions + * @{ + */ +/* UART Init/DeInit functions -------------------------------------------------*/ +/********************************************************************//** + * @brief Initializes the UARTx peripheral according to the specified + * parameters in the UART_ConfigStruct. + * @param[in] UARTx UART peripheral selected, should be: + * - LPC_UART0: UART0 peripheral + * - LPC_UART1: UART1 peripheral + * - LPC_UART2: UART2 peripheral + * - LPC_UART3: UART3 peripheral + * @param[in] UART_ConfigStruct Pointer to a UART_CFG_Type structure +* that contains the configuration information for the +* specified UART peripheral. + * @return None + *********************************************************************/ +void UART_Init(LPC_UART_TypeDef *UARTx, UART_CFG_Type *UART_ConfigStruct) +{ + uint32_t tmp; + + // For debug mode + CHECK_PARAM(PARAM_UARTx(UARTx)); + CHECK_PARAM(PARAM_UART_DATABIT(UART_ConfigStruct->Databits)); + CHECK_PARAM(PARAM_UART_STOPBIT(UART_ConfigStruct->Stopbits)); + CHECK_PARAM(PARAM_UART_PARITY(UART_ConfigStruct->Parity)); + +#ifdef _UART0 + if(UARTx == LPC_UART0) + { + /* Set up clock and power for UART module */ + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCUART0, ENABLE); + } +#endif + +#ifdef _UART1 + if(((LPC_UART1_TypeDef *)UARTx) == LPC_UART1) + { + /* Set up clock and power for UART module */ + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCUART1, ENABLE); + } +#endif + +#ifdef _UART2 + if(UARTx == LPC_UART2) + { + /* Set up clock and power for UART module */ + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCUART2, ENABLE); + } +#endif + +#ifdef _UART3 + if(UARTx == LPC_UART3) + { + /* Set up clock and power for UART module */ + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCUART3, ENABLE); + } +#endif + + if (((LPC_UART1_TypeDef *)UARTx) == LPC_UART1) + { + /* FIFOs are empty */ + ((LPC_UART1_TypeDef *)UARTx)->/*IIFCR.*/FCR = ( UART_FCR_FIFO_EN \ + | UART_FCR_RX_RS | UART_FCR_TX_RS); + // Disable FIFO + ((LPC_UART1_TypeDef *)UARTx)->/*IIFCR.*/FCR = 0; + + // Dummy reading + while (((LPC_UART1_TypeDef *)UARTx)->LSR & UART_LSR_RDR) + { + tmp = ((LPC_UART1_TypeDef *)UARTx)->/*RBTHDLR.*/RBR; + } + + ((LPC_UART1_TypeDef *)UARTx)->TER = UART_TER_TXEN; + // Wait for current transmit complete + while (!(((LPC_UART1_TypeDef *)UARTx)->LSR & UART_LSR_THRE)); + // Disable Tx + ((LPC_UART1_TypeDef *)UARTx)->TER = 0; + + // Disable interrupt + ((LPC_UART1_TypeDef *)UARTx)->/*DLIER.*/IER = 0; + // Set LCR to default state + ((LPC_UART1_TypeDef *)UARTx)->LCR = 0; + // Set ACR to default state + ((LPC_UART1_TypeDef *)UARTx)->ACR = 0; + // Set Modem Control to default state + ((LPC_UART1_TypeDef *)UARTx)->MCR = 0; + // Set RS485 control to default state + ((LPC_UART1_TypeDef *)UARTx)->RS485CTRL = 0; + // Set RS485 delay timer to default state + ((LPC_UART1_TypeDef *)UARTx)->RS485DLY = 0; + // Set RS485 addr match to default state + ((LPC_UART1_TypeDef *)UARTx)->ADRMATCH = 0; + //Dummy Reading to Clear Status + tmp = ((LPC_UART1_TypeDef *)UARTx)->MSR; + tmp = ((LPC_UART1_TypeDef *)UARTx)->LSR; + } + else + { + /* FIFOs are empty */ + UARTx->/*IIFCR.*/FCR = ( UART_FCR_FIFO_EN | UART_FCR_RX_RS | UART_FCR_TX_RS); + // Disable FIFO + UARTx->/*IIFCR.*/FCR = 0; + + // Dummy reading + while (UARTx->LSR & UART_LSR_RDR) + { + tmp = UARTx->/*RBTHDLR.*/RBR; + } + + UARTx->TER = UART_TER_TXEN; + // Wait for current transmit complete + while (!(UARTx->LSR & UART_LSR_THRE)); + // Disable Tx + UARTx->TER = 0; + + // Disable interrupt + UARTx->/*DLIER.*/IER = 0; + // Set LCR to default state + UARTx->LCR = 0; + // Set ACR to default state + UARTx->ACR = 0; + // Dummy reading + tmp = UARTx->LSR; + } + + if (UARTx == LPC_UART3) + { + // Set IrDA to default state + UARTx->ICR = 0; + } + + // Set Line Control register ---------------------------- + + uart_set_divisors(UARTx, (UART_ConfigStruct->Baud_rate)); + + if (((LPC_UART1_TypeDef *)UARTx) == LPC_UART1) + { + tmp = (((LPC_UART1_TypeDef *)UARTx)->LCR & (UART_LCR_DLAB_EN | UART_LCR_BREAK_EN)) \ + & UART_LCR_BITMASK; + } + else + { + tmp = (UARTx->LCR & (UART_LCR_DLAB_EN | UART_LCR_BREAK_EN)) & UART_LCR_BITMASK; + } + + switch (UART_ConfigStruct->Databits){ + case UART_DATABIT_5: + tmp |= UART_LCR_WLEN5; + break; + case UART_DATABIT_6: + tmp |= UART_LCR_WLEN6; + break; + case UART_DATABIT_7: + tmp |= UART_LCR_WLEN7; + break; + case UART_DATABIT_8: + default: + tmp |= UART_LCR_WLEN8; + break; + } + + if (UART_ConfigStruct->Parity == UART_PARITY_NONE) + { + // Do nothing... + } + else + { + tmp |= UART_LCR_PARITY_EN; + switch (UART_ConfigStruct->Parity) + { + case UART_PARITY_ODD: + tmp |= UART_LCR_PARITY_ODD; + break; + + case UART_PARITY_EVEN: + tmp |= UART_LCR_PARITY_EVEN; + break; + + case UART_PARITY_SP_1: + tmp |= UART_LCR_PARITY_F_1; + break; + + case UART_PARITY_SP_0: + tmp |= UART_LCR_PARITY_F_0; + break; + default: + break; + } + } + + switch (UART_ConfigStruct->Stopbits){ + case UART_STOPBIT_2: + tmp |= UART_LCR_STOPBIT_SEL; + break; + case UART_STOPBIT_1: + default: + // Do no thing + break; + } + + + // Write back to LCR, configure FIFO and Disable Tx + if (((LPC_UART1_TypeDef *)UARTx) == LPC_UART1) + { + ((LPC_UART1_TypeDef *)UARTx)->LCR = (uint8_t)(tmp & UART_LCR_BITMASK); + } + else + { + UARTx->LCR = (uint8_t)(tmp & UART_LCR_BITMASK); + } +} + +/*********************************************************************//** + * @brief De-initializes the UARTx peripheral registers to their + * default reset values. + * @param[in] UARTx UART peripheral selected, should be: + * - LPC_UART0: UART0 peripheral + * - LPC_UART1: UART1 peripheral + * - LPC_UART2: UART2 peripheral + * - LPC_UART3: UART3 peripheral + * @return None + **********************************************************************/ +void UART_DeInit(LPC_UART_TypeDef* UARTx) +{ + // For debug mode + CHECK_PARAM(PARAM_UARTx(UARTx)); + + UART_TxCmd(UARTx, DISABLE); + +#ifdef _UART0 + if (UARTx == LPC_UART0) + { + /* Set up clock and power for UART module */ + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCUART0, DISABLE); + } +#endif + +#ifdef _UART1 + if (((LPC_UART1_TypeDef *)UARTx) == LPC_UART1) + { + /* Set up clock and power for UART module */ + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCUART1, DISABLE); + } +#endif + +#ifdef _UART2 + if (UARTx == LPC_UART2) + { + /* Set up clock and power for UART module */ + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCUART2, DISABLE); + } +#endif + +#ifdef _UART3 + if (UARTx == LPC_UART3) + { + /* Set up clock and power for UART module */ + CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCUART3, DISABLE); + } +#endif +} + +/*****************************************************************************//** +* @brief Fills each UART_InitStruct member with its default value: +* - 9600 bps +* - 8-bit data +* - 1 Stopbit +* - None Parity +* @param[in] UART_InitStruct Pointer to a UART_CFG_Type structure +* which will be initialized. +* @return None +*******************************************************************************/ +void UART_ConfigStructInit(UART_CFG_Type *UART_InitStruct) +{ + UART_InitStruct->Baud_rate = 9600; + UART_InitStruct->Databits = UART_DATABIT_8; + UART_InitStruct->Parity = UART_PARITY_NONE; + UART_InitStruct->Stopbits = UART_STOPBIT_1; +} + +/* UART Send/Recieve functions -------------------------------------------------*/ +/*********************************************************************//** + * @brief Transmit a single data through UART peripheral + * @param[in] UARTx UART peripheral selected, should be: + * - LPC_UART0: UART0 peripheral + * - LPC_UART1: UART1 peripheral + * - LPC_UART2: UART2 peripheral + * - LPC_UART3: UART3 peripheral + * @param[in] Data Data to transmit (must be 8-bit long) + * @return None + **********************************************************************/ +void UART_SendByte(LPC_UART_TypeDef* UARTx, uint8_t Data) +{ + CHECK_PARAM(PARAM_UARTx(UARTx)); + + if (((LPC_UART1_TypeDef *)UARTx) == LPC_UART1) + { + ((LPC_UART1_TypeDef *)UARTx)->/*RBTHDLR.*/THR = Data & UART_THR_MASKBIT; + } + else + { + UARTx->/*RBTHDLR.*/THR = Data & UART_THR_MASKBIT; + } + +} + + +/*********************************************************************//** + * @brief Receive a single data from UART peripheral + * @param[in] UARTx UART peripheral selected, should be: + * - LPC_UART0: UART0 peripheral + * - LPC_UART1: UART1 peripheral + * - LPC_UART2: UART2 peripheral + * - LPC_UART3: UART3 peripheral + * @return Data received + **********************************************************************/ +uint8_t UART_ReceiveByte(LPC_UART_TypeDef* UARTx) +{ + CHECK_PARAM(PARAM_UARTx(UARTx)); + + if (((LPC_UART1_TypeDef *)UARTx) == LPC_UART1) + { + return (((LPC_UART1_TypeDef *)UARTx)->/*RBTHDLR.*/RBR & UART_RBR_MASKBIT); + } + else + { + return (UARTx->/*RBTHDLR.*/RBR & UART_RBR_MASKBIT); + } +} + +/*********************************************************************//** + * @brief Send a block of data via UART peripheral + * @param[in] UARTx Selected UART peripheral used to send data, should be: + * - LPC_UART0: UART0 peripheral + * - LPC_UART1: UART1 peripheral + * - LPC_UART2: UART2 peripheral + * - LPC_UART3: UART3 peripheral + * @param[in] txbuf Pointer to Transmit buffer + * @param[in] buflen Length of Transmit buffer + * @param[in] flag Flag used in UART transfer, should be + * NONE_BLOCKING or BLOCKING + * @return Number of bytes sent. + * + * Note: when using UART in BLOCKING mode, a time-out condition is used + * via defined symbol UART_BLOCKING_TIMEOUT. + **********************************************************************/ +uint32_t UART_Send(LPC_UART_TypeDef *UARTx, uint8_t *txbuf, + uint32_t buflen, TRANSFER_BLOCK_Type flag) +{ + uint32_t bToSend, bSent, timeOut, fifo_cnt; + uint8_t *pChar = txbuf; + + bToSend = buflen; + + // blocking mode + if (flag == BLOCKING) { + bSent = 0; + while (bToSend){ + timeOut = UART_BLOCKING_TIMEOUT; + // Wait for THR empty with timeout + while (!(UARTx->LSR & UART_LSR_THRE)) { + if (timeOut == 0) break; + timeOut--; + } + // Time out! + if(timeOut == 0) break; + fifo_cnt = UART_TX_FIFO_SIZE; + while (fifo_cnt && bToSend){ + UART_SendByte(UARTx, (*pChar++)); + fifo_cnt--; + bToSend--; + bSent++; + } + } + } + // None blocking mode + else { + bSent = 0; + while (bToSend) { + if (!(UARTx->LSR & UART_LSR_THRE)){ + break; + } + fifo_cnt = UART_TX_FIFO_SIZE; + while (fifo_cnt && bToSend) { + UART_SendByte(UARTx, (*pChar++)); + bToSend--; + fifo_cnt--; + bSent++; + } + } + } + return bSent; +} + +/*********************************************************************//** + * @brief Receive a block of data via UART peripheral + * @param[in] UARTx Selected UART peripheral used to send data, + * should be: + * - LPC_UART0: UART0 peripheral + * - LPC_UART1: UART1 peripheral + * - LPC_UART2: UART2 peripheral + * - LPC_UART3: UART3 peripheral + * @param[out] rxbuf Pointer to Received buffer + * @param[in] buflen Length of Received buffer + * @param[in] flag Flag mode, should be NONE_BLOCKING or BLOCKING + + * @return Number of bytes received + * + * Note: when using UART in BLOCKING mode, a time-out condition is used + * via defined symbol UART_BLOCKING_TIMEOUT. + **********************************************************************/ +uint32_t UART_Receive(LPC_UART_TypeDef *UARTx, uint8_t *rxbuf, \ + uint32_t buflen, TRANSFER_BLOCK_Type flag) +{ + uint32_t bToRecv, bRecv, timeOut; + uint8_t *pChar = rxbuf; + + bToRecv = buflen; + + // Blocking mode + if (flag == BLOCKING) { + bRecv = 0; + while (bToRecv){ + timeOut = UART_BLOCKING_TIMEOUT; + while (!(UARTx->LSR & UART_LSR_RDR)){ + if (timeOut == 0) break; + timeOut--; + } + // Time out! + if(timeOut == 0) break; + // Get data from the buffer + (*pChar++) = UART_ReceiveByte(UARTx); + bToRecv--; + bRecv++; + } + } + // None blocking mode + else { + bRecv = 0; + while (bToRecv) { + if (!(UARTx->LSR & UART_LSR_RDR)) { + break; + } else { + (*pChar++) = UART_ReceiveByte(UARTx); + bRecv++; + bToRecv--; + } + } + } + return bRecv; +} + +/*********************************************************************//** + * @brief Force BREAK character on UART line, output pin UARTx TXD is + forced to logic 0. + * @param[in] UARTx UART peripheral selected, should be: + * - LPC_UART0: UART0 peripheral + * - LPC_UART1: UART1 peripheral + * - LPC_UART2: UART2 peripheral + * - LPC_UART3: UART3 peripheral + * @return None + **********************************************************************/ +void UART_ForceBreak(LPC_UART_TypeDef* UARTx) +{ + CHECK_PARAM(PARAM_UARTx(UARTx)); + + if (((LPC_UART1_TypeDef *)UARTx) == LPC_UART1) + { + ((LPC_UART1_TypeDef *)UARTx)->LCR |= UART_LCR_BREAK_EN; + } + else + { + UARTx->LCR |= UART_LCR_BREAK_EN; + } +} + + +/********************************************************************//** + * @brief Enable or disable specified UART interrupt. + * @param[in] UARTx UART peripheral selected, should be + * - LPC_UART0: UART0 peripheral + * - LPC_UART1: UART1 peripheral + * - LPC_UART2: UART2 peripheral + * - LPC_UART3: UART3 peripheral + * @param[in] UARTIntCfg Specifies the interrupt flag, + * should be one of the following: + - UART_INTCFG_RBR : RBR Interrupt enable + - UART_INTCFG_THRE : THR Interrupt enable + - UART_INTCFG_RLS : RX line status interrupt enable + - UART1_INTCFG_MS : Modem status interrupt enable (UART1 only) + - UART1_INTCFG_CTS : CTS1 signal transition interrupt enable (UART1 only) + - UART_INTCFG_ABEO : Enables the end of auto-baud interrupt + - UART_INTCFG_ABTO : Enables the auto-baud time-out interrupt + * @param[in] NewState New state of specified UART interrupt type, + * should be: + * - ENALBE: Enable this UART interrupt type. +* - DISALBE: Disable this UART interrupt type. + * @return None + *********************************************************************/ +void UART_IntConfig(LPC_UART_TypeDef *UARTx, UART_INT_Type UARTIntCfg, FunctionalState NewState) +{ + uint32_t tmp; + + CHECK_PARAM(PARAM_UARTx(UARTx)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState)); + + switch(UARTIntCfg){ + case UART_INTCFG_RBR: + tmp = UART_IER_RBRINT_EN; + break; + case UART_INTCFG_THRE: + tmp = UART_IER_THREINT_EN; + break; + case UART_INTCFG_RLS: + tmp = UART_IER_RLSINT_EN; + break; + case UART1_INTCFG_MS: + tmp = UART1_IER_MSINT_EN; + break; + case UART1_INTCFG_CTS: + tmp = UART1_IER_CTSINT_EN; + break; + case UART_INTCFG_ABEO: + tmp = UART_IER_ABEOINT_EN; + break; + case UART_INTCFG_ABTO: + tmp = UART_IER_ABTOINT_EN; + break; + } + + if ((LPC_UART1_TypeDef *) UARTx == LPC_UART1) + { + CHECK_PARAM((PARAM_UART_INTCFG(UARTIntCfg)) || (PARAM_UART1_INTCFG(UARTIntCfg))); + } + else + { + CHECK_PARAM(PARAM_UART_INTCFG(UARTIntCfg)); + } + + if (NewState == ENABLE) + { + if ((LPC_UART1_TypeDef *) UARTx == LPC_UART1) + { + ((LPC_UART1_TypeDef *)UARTx)->/*DLIER.*/IER |= tmp; + } + else + { + UARTx->/*DLIER.*/IER |= tmp; + } + } + else + { + if ((LPC_UART1_TypeDef *) UARTx == LPC_UART1) + { + ((LPC_UART1_TypeDef *)UARTx)->/*DLIER.*/IER &= (~tmp) & UART1_IER_BITMASK; + } + else + { + UARTx->/*DLIER.*/IER &= (~tmp) & UART_IER_BITMASK; + } + } +} + + +/********************************************************************//** + * @brief Get current value of Line Status register in UART peripheral. + * @param[in] UARTx UART peripheral selected, should be: + * - LPC_UART0: UART0 peripheral + * - LPC_UART1: UART1 peripheral + * - LPC_UART2: UART2 peripheral + * - LPC_UART3: UART3 peripheral + * @return Current value of Line Status register in UART peripheral. + * Note: The return value of this function must be ANDed with each member in + * UART_LS_Type enumeration to determine current flag status + * corresponding to each Line status type. Because some flags in + * Line Status register will be cleared after reading, the next reading + * Line Status register could not be correct. So this function used to + * read Line status register in one time only, then the return value + * used to check all flags. + *********************************************************************/ +uint8_t UART_GetLineStatus(LPC_UART_TypeDef* UARTx) +{ + CHECK_PARAM(PARAM_UARTx(UARTx)); + + if (((LPC_UART1_TypeDef *)UARTx) == LPC_UART1) + { + return ((((LPC_UART1_TypeDef *)LPC_UART1)->LSR) & UART_LSR_BITMASK); + } + else + { + return ((UARTx->LSR) & UART_LSR_BITMASK); + } +} + +/********************************************************************//** + * @brief Get Interrupt Identification value + * @param[in] UARTx UART peripheral selected, should be: + * - LPC_UART0: UART0 peripheral + * - LPC_UART1: UART1 peripheral + * - LPC_UART2: UART2 peripheral + * - LPC_UART3: UART3 peripheral + * @return Current value of UART UIIR register in UART peripheral. + *********************************************************************/ +uint32_t UART_GetIntId(LPC_UART_TypeDef* UARTx) +{ + CHECK_PARAM(PARAM_UARTx(UARTx)); + return (UARTx->IIR & 0x03CF); +} + +/*********************************************************************//** + * @brief Check whether if UART is busy or not + * @param[in] UARTx UART peripheral selected, should be: + * - LPC_UART0: UART0 peripheral + * - LPC_UART1: UART1 peripheral + * - LPC_UART2: UART2 peripheral + * - LPC_UART3: UART3 peripheral + * @return RESET if UART is not busy, otherwise return SET. + **********************************************************************/ +FlagStatus UART_CheckBusy(LPC_UART_TypeDef *UARTx) +{ + if (UARTx->LSR & UART_LSR_TEMT){ + return RESET; + } else { + return SET; + } +} + + +/*********************************************************************//** + * @brief Configure FIFO function on selected UART peripheral + * @param[in] UARTx UART peripheral selected, should be: + * - LPC_UART0: UART0 peripheral + * - LPC_UART1: UART1 peripheral + * - LPC_UART2: UART2 peripheral + * - LPC_UART3: UART3 peripheral + * @param[in] FIFOCfg Pointer to a UART_FIFO_CFG_Type Structure that + * contains specified information about FIFO configuration + * @return none + **********************************************************************/ +void UART_FIFOConfig(LPC_UART_TypeDef *UARTx, UART_FIFO_CFG_Type *FIFOCfg) +{ + uint8_t tmp = 0; + + CHECK_PARAM(PARAM_UARTx(UARTx)); + CHECK_PARAM(PARAM_UART_FIFO_LEVEL(FIFOCfg->FIFO_Level)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(FIFOCfg->FIFO_DMAMode)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(FIFOCfg->FIFO_ResetRxBuf)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(FIFOCfg->FIFO_ResetTxBuf)); + + tmp |= UART_FCR_FIFO_EN; + switch (FIFOCfg->FIFO_Level){ + case UART_FIFO_TRGLEV0: + tmp |= UART_FCR_TRG_LEV0; + break; + case UART_FIFO_TRGLEV1: + tmp |= UART_FCR_TRG_LEV1; + break; + case UART_FIFO_TRGLEV2: + tmp |= UART_FCR_TRG_LEV2; + break; + case UART_FIFO_TRGLEV3: + default: + tmp |= UART_FCR_TRG_LEV3; + break; + } + + if (FIFOCfg->FIFO_ResetTxBuf == ENABLE) + { + tmp |= UART_FCR_TX_RS; + } + if (FIFOCfg->FIFO_ResetRxBuf == ENABLE) + { + tmp |= UART_FCR_RX_RS; + } + if (FIFOCfg->FIFO_DMAMode == ENABLE) + { + tmp |= UART_FCR_DMAMODE_SEL; + } + + + //write to FIFO control register + if (((LPC_UART1_TypeDef *)UARTx) == LPC_UART1) + { + ((LPC_UART1_TypeDef *)UARTx)->/*IIFCR.*/FCR = tmp & UART_FCR_BITMASK; + } + else + { + UARTx->/*IIFCR.*/FCR = tmp & UART_FCR_BITMASK; + } +} + +/*****************************************************************************//** +* @brief Fills each UART_FIFOInitStruct member with its default value: +* - FIFO_DMAMode = DISABLE +* - FIFO_Level = UART_FIFO_TRGLEV0 +* - FIFO_ResetRxBuf = ENABLE +* - FIFO_ResetTxBuf = ENABLE +* - FIFO_State = ENABLE + +* @param[in] UART_FIFOInitStruct Pointer to a UART_FIFO_CFG_Type structure +* which will be initialized. +* @return None +*******************************************************************************/ +void UART_FIFOConfigStructInit(UART_FIFO_CFG_Type *UART_FIFOInitStruct) +{ + UART_FIFOInitStruct->FIFO_DMAMode = DISABLE; + UART_FIFOInitStruct->FIFO_Level = UART_FIFO_TRGLEV0; + UART_FIFOInitStruct->FIFO_ResetRxBuf = ENABLE; + UART_FIFOInitStruct->FIFO_ResetTxBuf = ENABLE; +} + + +/*********************************************************************//** + * @brief Start/Stop Auto Baudrate activity + * @param[in] UARTx UART peripheral selected, should be + * - LPC_UART0: UART0 peripheral + * - LPC_UART1: UART1 peripheral + * - LPC_UART2: UART2 peripheral + * - LPC_UART3: UART3 peripheral + * @param[in] ABConfigStruct A pointer to UART_AB_CFG_Type structure that + * contains specified information about UART + * auto baudrate configuration + * @param[in] NewState New State of Auto baudrate activity, should be: + * - ENABLE: Start this activity + * - DISABLE: Stop this activity + * Note: Auto-baudrate mode enable bit will be cleared once this mode + * completed. + * @return none + **********************************************************************/ +void UART_ABCmd(LPC_UART_TypeDef *UARTx, UART_AB_CFG_Type *ABConfigStruct, \ + FunctionalState NewState) +{ + uint32_t tmp; + + CHECK_PARAM(PARAM_UARTx(UARTx)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState)); + + tmp = 0; + if (NewState == ENABLE) { + if (ABConfigStruct->ABMode == UART_AUTOBAUD_MODE1){ + tmp |= UART_ACR_MODE; + } + if (ABConfigStruct->AutoRestart == ENABLE){ + tmp |= UART_ACR_AUTO_RESTART; + } + } + + if (((LPC_UART1_TypeDef *)UARTx) == LPC_UART1) + { + if (NewState == ENABLE) + { + // Clear DLL and DLM value + ((LPC_UART1_TypeDef *)UARTx)->LCR |= UART_LCR_DLAB_EN; + ((LPC_UART1_TypeDef *)UARTx)->DLL = 0; + ((LPC_UART1_TypeDef *)UARTx)->DLM = 0; + ((LPC_UART1_TypeDef *)UARTx)->LCR &= ~UART_LCR_DLAB_EN; + // FDR value must be reset to default value + ((LPC_UART1_TypeDef *)UARTx)->FDR = 0x10; + ((LPC_UART1_TypeDef *)UARTx)->ACR = UART_ACR_START | tmp; + } + else + { + ((LPC_UART1_TypeDef *)UARTx)->ACR = 0; + } + } + else + { + if (NewState == ENABLE) + { + // Clear DLL and DLM value + UARTx->LCR |= UART_LCR_DLAB_EN; + UARTx->DLL = 0; + UARTx->DLM = 0; + UARTx->LCR &= ~UART_LCR_DLAB_EN; + // FDR value must be reset to default value + UARTx->FDR = 0x10; + UARTx->ACR = UART_ACR_START | tmp; + } + else + { + UARTx->ACR = 0; + } + } +} + +/*********************************************************************//** + * @brief Clear Autobaud Interrupt Pending + * @param[in] UARTx UART peripheral selected, should be + * - LPC_UART0: UART0 peripheral + * - LPC_UART1: UART1 peripheral + * - LPC_UART2: UART2 peripheral + * - LPC_UART3: UART3 peripheral + * @param[in] ABIntType type of auto-baud interrupt, should be: + * - UART_AUTOBAUD_INTSTAT_ABEO: End of Auto-baud interrupt + * - UART_AUTOBAUD_INTSTAT_ABTO: Auto-baud time out interrupt + * @return none + **********************************************************************/ +void UART_ABClearIntPending(LPC_UART_TypeDef *UARTx, UART_ABEO_Type ABIntType) +{ + CHECK_PARAM(PARAM_UARTx(UARTx)); + if (((LPC_UART1_TypeDef *)UARTx) == LPC_UART1) + { + UARTx->ACR |= ABIntType; + } + else + UARTx->ACR |= ABIntType; +} + +/*********************************************************************//** + * @brief Enable/Disable transmission on UART TxD pin + * @param[in] UARTx UART peripheral selected, should be: + * - LPC_UART0: UART0 peripheral + * - LPC_UART1: UART1 peripheral + * - LPC_UART2: UART2 peripheral + * - LPC_UART3: UART3 peripheral + * @param[in] NewState New State of Tx transmission function, should be: + * - ENABLE: Enable this function + - DISABLE: Disable this function + * @return none + **********************************************************************/ +void UART_TxCmd(LPC_UART_TypeDef *UARTx, FunctionalState NewState) +{ + CHECK_PARAM(PARAM_UARTx(UARTx)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState)); + + if (NewState == ENABLE) + { + if (((LPC_UART1_TypeDef *)UARTx) == LPC_UART1) + { + ((LPC_UART1_TypeDef *)UARTx)->TER |= UART_TER_TXEN; + } + else + { + UARTx->TER |= UART_TER_TXEN; + } + } + else + { + if (((LPC_UART1_TypeDef *)UARTx) == LPC_UART1) + { + ((LPC_UART1_TypeDef *)UARTx)->TER &= (~UART_TER_TXEN) & UART_TER_BITMASK; + } + else + { + UARTx->TER &= (~UART_TER_TXEN) & UART_TER_BITMASK; + } + } +} + +/* UART IrDA functions ---------------------------------------------------*/ + +#ifdef _UART3 + +/*********************************************************************//** + * @brief Enable or disable inverting serial input function of IrDA + * on UART peripheral. + * @param[in] UARTx UART peripheral selected, should be LPC_UART3 (only) + * @param[in] NewState New state of inverting serial input, should be: + * - ENABLE: Enable this function. + * - DISABLE: Disable this function. + * @return none + **********************************************************************/ +void UART_IrDAInvtInputCmd(LPC_UART_TypeDef* UARTx, FunctionalState NewState) +{ + CHECK_PARAM(PARAM_UART_IrDA(UARTx)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState)); + + if (NewState == ENABLE) + { + UARTx->ICR |= UART_ICR_IRDAINV; + } + else if (NewState == DISABLE) + { + UARTx->ICR &= (~UART_ICR_IRDAINV) & UART_ICR_BITMASK; + } +} + + +/*********************************************************************//** + * @brief Enable or disable IrDA function on UART peripheral. + * @param[in] UARTx UART peripheral selected, should be LPC_UART3 (only) + * @param[in] NewState New state of IrDA function, should be: + * - ENABLE: Enable this function. + * - DISABLE: Disable this function. + * @return none + **********************************************************************/ +void UART_IrDACmd(LPC_UART_TypeDef* UARTx, FunctionalState NewState) +{ + CHECK_PARAM(PARAM_UART_IrDA(UARTx)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState)); + + if (NewState == ENABLE) + { + UARTx->ICR |= UART_ICR_IRDAEN; + } + else + { + UARTx->ICR &= (~UART_ICR_IRDAEN) & UART_ICR_BITMASK; + } +} + + +/*********************************************************************//** + * @brief Configure Pulse divider for IrDA function on UART peripheral. + * @param[in] UARTx UART peripheral selected, should be LPC_UART3 (only) + * @param[in] PulseDiv Pulse Divider value from Peripheral clock, + * should be one of the following: + - UART_IrDA_PULSEDIV2 : Pulse width = 2 * Tpclk + - UART_IrDA_PULSEDIV4 : Pulse width = 4 * Tpclk + - UART_IrDA_PULSEDIV8 : Pulse width = 8 * Tpclk + - UART_IrDA_PULSEDIV16 : Pulse width = 16 * Tpclk + - UART_IrDA_PULSEDIV32 : Pulse width = 32 * Tpclk + - UART_IrDA_PULSEDIV64 : Pulse width = 64 * Tpclk + - UART_IrDA_PULSEDIV128 : Pulse width = 128 * Tpclk + - UART_IrDA_PULSEDIV256 : Pulse width = 256 * Tpclk + + * @return none + **********************************************************************/ +void UART_IrDAPulseDivConfig(LPC_UART_TypeDef *UARTx, UART_IrDA_PULSE_Type PulseDiv) +{ + uint32_t tmp, tmp1; + CHECK_PARAM(PARAM_UART_IrDA(UARTx)); + CHECK_PARAM(PARAM_UART_IrDA_PULSEDIV(PulseDiv)); + + tmp1 = UART_ICR_PULSEDIV(PulseDiv); + tmp = UARTx->ICR & (~UART_ICR_PULSEDIV(7)); + tmp |= tmp1 | UART_ICR_FIXPULSE_EN; + UARTx->ICR = tmp & UART_ICR_BITMASK; +} + +#endif + + +/* UART1 FullModem function ---------------------------------------------*/ + +#ifdef _UART1 + +/*********************************************************************//** + * @brief Force pin DTR/RTS corresponding to given state (Full modem mode) + * @param[in] UARTx LPC_UART1 (only) + * @param[in] Pin Pin that NewState will be applied to, should be: + * - UART1_MODEM_PIN_DTR: DTR pin. + * - UART1_MODEM_PIN_RTS: RTS pin. + * @param[in] NewState New State of DTR/RTS pin, should be: + * - INACTIVE: Force the pin to inactive signal. + - ACTIVE: Force the pin to active signal. + * @return none + **********************************************************************/ +void UART_FullModemForcePinState(LPC_UART1_TypeDef *UARTx, UART_MODEM_PIN_Type Pin, \ + UART1_SignalState NewState) +{ + uint8_t tmp = 0; + + CHECK_PARAM(PARAM_UART1_MODEM(UARTx)); + CHECK_PARAM(PARAM_UART1_MODEM_PIN(Pin)); + CHECK_PARAM(PARAM_UART1_SIGNALSTATE(NewState)); + + switch (Pin){ + case UART1_MODEM_PIN_DTR: + tmp = UART1_MCR_DTR_CTRL; + break; + case UART1_MODEM_PIN_RTS: + tmp = UART1_MCR_RTS_CTRL; + break; + default: + break; + } + + if (NewState == ACTIVE){ + UARTx->MCR |= tmp; + } else { + UARTx->MCR &= (~tmp) & UART1_MCR_BITMASK; + } +} + + +/*********************************************************************//** + * @brief Configure Full Modem mode for UART peripheral + * @param[in] UARTx LPC_UART1 (only) + * @param[in] Mode Full Modem mode, should be: + * - UART1_MODEM_MODE_LOOPBACK: Loop back mode. + * - UART1_MODEM_MODE_AUTO_RTS: Auto-RTS mode. + * - UART1_MODEM_MODE_AUTO_CTS: Auto-CTS mode. + * @param[in] NewState New State of this mode, should be: + * - ENABLE: Enable this mode. + - DISABLE: Disable this mode. + * @return none + **********************************************************************/ +void UART_FullModemConfigMode(LPC_UART1_TypeDef *UARTx, UART_MODEM_MODE_Type Mode, \ + FunctionalState NewState) +{ + uint8_t tmp; + + CHECK_PARAM(PARAM_UART1_MODEM(UARTx)); + CHECK_PARAM(PARAM_UART1_MODEM_MODE(Mode)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState)); + + switch(Mode){ + case UART1_MODEM_MODE_LOOPBACK: + tmp = UART1_MCR_LOOPB_EN; + break; + case UART1_MODEM_MODE_AUTO_RTS: + tmp = UART1_MCR_AUTO_RTS_EN; + break; + case UART1_MODEM_MODE_AUTO_CTS: + tmp = UART1_MCR_AUTO_CTS_EN; + break; + default: + break; + } + + if (NewState == ENABLE) + { + UARTx->MCR |= tmp; + } + else + { + UARTx->MCR &= (~tmp) & UART1_MCR_BITMASK; + } +} + + +/*********************************************************************//** + * @brief Get current status of modem status register + * @param[in] UARTx LPC_UART1 (only) + * @return Current value of modem status register + * Note: The return value of this function must be ANDed with each member + * UART_MODEM_STAT_type enumeration to determine current flag status + * corresponding to each modem flag status. Because some flags in + * modem status register will be cleared after reading, the next reading + * modem register could not be correct. So this function used to + * read modem status register in one time only, then the return value + * used to check all flags. + **********************************************************************/ +uint8_t UART_FullModemGetStatus(LPC_UART1_TypeDef *UARTx) +{ + CHECK_PARAM(PARAM_UART1_MODEM(UARTx)); + return ((UARTx->MSR) & UART1_MSR_BITMASK); +} + + +/* UART RS485 functions --------------------------------------------------------------*/ + +/*********************************************************************//** + * @brief Configure UART peripheral in RS485 mode according to the specified +* parameters in the RS485ConfigStruct. + * @param[in] UARTx LPC_UART1 (only) + * @param[in] RS485ConfigStruct Pointer to a UART1_RS485_CTRLCFG_Type structure +* that contains the configuration information for specified UART +* in RS485 mode. + * @return None + **********************************************************************/ +void UART_RS485Config(LPC_UART1_TypeDef *UARTx, UART1_RS485_CTRLCFG_Type *RS485ConfigStruct) +{ + uint32_t tmp; + + CHECK_PARAM(PARAM_UART1_MODEM(UARTx)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(RS485ConfigStruct->AutoAddrDetect_State)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(RS485ConfigStruct->AutoDirCtrl_State)); + CHECK_PARAM(PARAM_UART1_RS485_CFG_DELAYVALUE(RS485ConfigStruct->DelayValue)); + CHECK_PARAM(PARAM_SETSTATE(RS485ConfigStruct->DirCtrlPol_Level)); + CHECK_PARAM(PARAM_UART_RS485_DIRCTRL_PIN(RS485ConfigStruct->DirCtrlPin)); + CHECK_PARAM(PARAM_UART1_RS485_CFG_MATCHADDRVALUE(RS485ConfigStruct->MatchAddrValue)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(RS485ConfigStruct->NormalMultiDropMode_State)); + CHECK_PARAM(PARAM_FUNCTIONALSTATE(RS485ConfigStruct->Rx_State)); + + tmp = 0; + // If Auto Direction Control is enabled - This function is used in Master mode + if (RS485ConfigStruct->AutoDirCtrl_State == ENABLE) + { + tmp |= UART1_RS485CTRL_DCTRL_EN; + + // Set polar + if (RS485ConfigStruct->DirCtrlPol_Level == SET) + { + tmp |= UART1_RS485CTRL_OINV_1; + } + + // Set pin according to + if (RS485ConfigStruct->DirCtrlPin == UART1_RS485_DIRCTRL_DTR) + { + tmp |= UART1_RS485CTRL_SEL_DTR; + } + + // Fill delay time + UARTx->RS485DLY = RS485ConfigStruct->DelayValue & UART1_RS485DLY_BITMASK; + } + + // MultiDrop mode is enable + if (RS485ConfigStruct->NormalMultiDropMode_State == ENABLE) + { + tmp |= UART1_RS485CTRL_NMM_EN; + } + + // Auto Address Detect function + if (RS485ConfigStruct->AutoAddrDetect_State == ENABLE) + { + tmp |= UART1_RS485CTRL_AADEN; + // Fill Match Address + UARTx->ADRMATCH = RS485ConfigStruct->MatchAddrValue & UART1_RS485ADRMATCH_BITMASK; + } + + + // Receiver is disable + if (RS485ConfigStruct->Rx_State == DISABLE) + { + tmp |= UART1_RS485CTRL_RX_DIS; + } + + // write back to RS485 control register + UARTx->RS485CTRL = tmp & UART1_RS485CTRL_BITMASK; + + // Enable Parity function and leave parity in stick '0' parity as default + UARTx->LCR |= (UART_LCR_PARITY_F_0 | UART_LCR_PARITY_EN); +} + +/*********************************************************************//** + * @brief Enable/Disable receiver in RS485 module in UART1 + * @param[in] UARTx LPC_UART1 (only) + * @param[in] NewState New State of command, should be: + * - ENABLE: Enable this function. + * - DISABLE: Disable this function. + * @return None + **********************************************************************/ +void UART_RS485ReceiverCmd(LPC_UART1_TypeDef *UARTx, FunctionalState NewState) +{ + if (NewState == ENABLE){ + UARTx->RS485CTRL &= ~UART1_RS485CTRL_RX_DIS; + } else { + UARTx->RS485CTRL |= UART1_RS485CTRL_RX_DIS; + } +} + +/*********************************************************************//** + * @brief Send data on RS485 bus with specified parity stick value (9-bit mode). + * @param[in] UARTx LPC_UART1 (only) + * @param[in] pDatFrm Pointer to data frame. + * @param[in] size Size of data. + * @param[in] ParityStick Parity Stick value, should be 0 or 1. + * @return None + **********************************************************************/ +uint32_t UART_RS485Send(LPC_UART1_TypeDef *UARTx, uint8_t *pDatFrm, \ + uint32_t size, uint8_t ParityStick) +{ + uint8_t tmp, save; + uint32_t cnt; + + if (ParityStick){ + save = tmp = UARTx->LCR & UART_LCR_BITMASK; + tmp &= ~(UART_LCR_PARITY_EVEN); + UARTx->LCR = tmp; + cnt = UART_Send((LPC_UART_TypeDef *)UARTx, pDatFrm, size, BLOCKING); + while (!(UARTx->LSR & UART_LSR_TEMT)); + UARTx->LCR = save; + } else { + cnt = UART_Send((LPC_UART_TypeDef *)UARTx, pDatFrm, size, BLOCKING); + while (!(UARTx->LSR & UART_LSR_TEMT)); + } + return cnt; +} + +/*********************************************************************//** + * @brief Send Slave address frames on RS485 bus. + * @param[in] UARTx LPC_UART1 (only) + * @param[in] SlvAddr Slave Address. + * @return None + **********************************************************************/ +void UART_RS485SendSlvAddr(LPC_UART1_TypeDef *UARTx, uint8_t SlvAddr) +{ + UART_RS485Send(UARTx, &SlvAddr, 1, 1); +} + +/*********************************************************************//** + * @brief Send Data frames on RS485 bus. + * @param[in] UARTx LPC_UART1 (only) + * @param[in] pData Pointer to data to be sent. + * @param[in] size Size of data frame to be sent. + * @return None + **********************************************************************/ +uint32_t UART_RS485SendData(LPC_UART1_TypeDef *UARTx, uint8_t *pData, uint32_t size) +{ + return (UART_RS485Send(UARTx, pData, size, 0)); +} + +#endif /* _UART1 */ + +#endif /* _UART */ + +/** + * @} + */ + +/** + * @} + */ +/* --------------------------------- End Of File ------------------------------ */ + diff --git a/arch/arm/lpc17xx/Drivers/source/lpc17xx_wdt.c b/arch/arm/lpc17xx/Drivers/source/lpc17xx_wdt.c new file mode 100644 index 0000000..1d8b407 --- /dev/null +++ b/arch/arm/lpc17xx/Drivers/source/lpc17xx_wdt.c @@ -0,0 +1,261 @@ +/***********************************************************************//** + * @file lpc17xx_wdt.c + * @brief Contains all functions support for WDT firmware library on LPC17xx + * @version 2.0 + * @date 21. May. 2010 + * @author NXP MCU SW Application Team + ************************************************************************** + * Software that is described herein is for illustrative purposes only + * which provides customers with programming information regarding the + * products. This software is supplied "AS IS" without any warranties. + * NXP Semiconductors assumes no responsibility or liability for the + * use of the software, conveys no license or title under any patent, + * copyright, or mask work right to the product. NXP Semiconductors + * reserves the right to make changes in the software without + * notification. NXP Semiconductors also make no representation or + * warranty that such application will be suitable for the specified + * use without further testing or modification. + **********************************************************************/ + +/* Peripheral group ----------------------------------------------------------- */ +/** @addtogroup WDT + * @{ + */ + +/* Includes ------------------------------------------------------------------- */ +#include "lpc17xx_wdt.h" +#include "lpc17xx_clkpwr.h" +#include "lpc17xx_pinsel.h" + + +/* If this source file built with example, the LPC17xx FW library configuration + * file in each example directory ("lpc17xx_libcfg.h") must be included, + * otherwise the default FW library configuration file must be included instead + */ +#ifdef __BUILD_WITH_EXAMPLE__ +#include "lpc17xx_libcfg.h" +#else +#include "lpc17xx_libcfg_default.h" +#endif /* __BUILD_WITH_EXAMPLE__ */ + + +#ifdef _WDT + +/* Private Functions ---------------------------------------------------------- */ + +static uint8_t WDT_SetTimeOut (uint8_t clk_source, uint32_t timeout); + +/********************************************************************//** + * @brief Set WDT time out value and WDT mode + * @param[in] clk_source select Clock source for WDT device + * @param[in] timeout value of time-out for WDT (us) + * @return None + *********************************************************************/ +static uint8_t WDT_SetTimeOut (uint8_t clk_source, uint32_t timeout) +{ + + uint32_t pclk_wdt = 0; + uint32_t tempval = 0; + + switch ((WDT_CLK_OPT) clk_source) + { + case WDT_CLKSRC_IRC: + pclk_wdt = 4000000; + // Calculate TC in WDT + tempval = (((pclk_wdt) / WDT_US_INDEX) * (timeout / 4)); + // Check if it valid + if ((tempval >= WDT_TIMEOUT_MIN) && (tempval <= WDT_TIMEOUT_MAX)) + { + LPC_WDT->WDTC = tempval; + return SUCCESS; + } + + break; + + case WDT_CLKSRC_PCLK: + + // Get WDT clock with CCLK divider = 4 + pclk_wdt = SystemCoreClock / 4; + // Calculate TC in WDT + tempval = (((pclk_wdt) / WDT_US_INDEX) * (timeout / 4)); + + if ((tempval >= WDT_TIMEOUT_MIN) && (tempval <= WDT_TIMEOUT_MAX)) + { + CLKPWR_SetPCLKDiv (CLKPWR_PCLKSEL_WDT, CLKPWR_PCLKSEL_CCLK_DIV_4); + LPC_WDT->WDTC = (uint32_t) tempval; + return SUCCESS; + } + + // Get WDT clock with CCLK divider = 2 + pclk_wdt = SystemCoreClock / 2; + // Calculate TC in WDT + tempval = (((pclk_wdt) / WDT_US_INDEX) * (timeout / 4)); + + if ((tempval >= WDT_TIMEOUT_MIN) && (tempval <= WDT_TIMEOUT_MAX)) + { + CLKPWR_SetPCLKDiv (CLKPWR_PCLKSEL_WDT, CLKPWR_PCLKSEL_CCLK_DIV_2); + LPC_WDT->WDTC = (uint32_t) tempval; + return SUCCESS; + } + + // Get WDT clock with CCLK divider = 1 + pclk_wdt = SystemCoreClock; + // Calculate TC in WDT + tempval = (((pclk_wdt) / WDT_US_INDEX) * (timeout / 4)); + + if ((tempval >= WDT_TIMEOUT_MIN) && (tempval <= WDT_TIMEOUT_MAX)) + { + CLKPWR_SetPCLKDiv (CLKPWR_PCLKSEL_WDT, CLKPWR_PCLKSEL_CCLK_DIV_1); + LPC_WDT->WDTC = (uint32_t) tempval; + return SUCCESS; + } + break ; + + + case WDT_CLKSRC_RTC: + pclk_wdt = 32768; + // Calculate TC in WDT + tempval = (((pclk_wdt) / WDT_US_INDEX) * (timeout / 4)); + // Check if it valid + if ((tempval >= WDT_TIMEOUT_MIN) && (tempval <= WDT_TIMEOUT_MAX)) + { + LPC_WDT->WDTC = (uint32_t) tempval; + return SUCCESS; + } + + break; + +// Error parameter + default: + break; +} + + return ERROR; +} + +/* End of Private Functions --------------------------------------------------- */ + + +/* Public Functions ----------------------------------------------------------- */ +/** @addtogroup WDT_Public_Functions + * @{ + */ + + +/*********************************************************************//** +* @brief Initial for Watchdog function +* Clock source = RTC , +* @param[in] ClkSrc Select clock source, should be: +* - WDT_CLKSRC_IRC: Clock source from Internal RC oscillator +* - WDT_CLKSRC_PCLK: Selects the APB peripheral clock (PCLK) +* - WDT_CLKSRC_RTC: Selects the RTC oscillator +* @param[in] WDTMode WDT mode, should be: +* - WDT_MODE_INT_ONLY: Use WDT to generate interrupt only +* - WDT_MODE_RESET: Use WDT to generate interrupt and reset MCU +* @return None + **********************************************************************/ +void WDT_Init (WDT_CLK_OPT ClkSrc, WDT_MODE_OPT WDTMode) +{ + CHECK_PARAM(PARAM_WDT_CLK_OPT(ClkSrc)); + CHECK_PARAM(PARAM_WDT_MODE_OPT(WDTMode)); + CLKPWR_SetPCLKDiv (CLKPWR_PCLKSEL_WDT, CLKPWR_PCLKSEL_CCLK_DIV_4); + + //Set clock source + LPC_WDT->WDCLKSEL &= ~WDT_WDCLKSEL_MASK; + LPC_WDT->WDCLKSEL |= ClkSrc; + //Set WDT mode + if (WDTMode == WDT_MODE_RESET){ + LPC_WDT->WDMOD |= WDT_WDMOD(WDTMode); + } +} + +/*********************************************************************//** +* @brief Start WDT activity with given timeout value +* @param[in] TimeOut WDT reset after timeout if it is not feed +* @return None + **********************************************************************/ +void WDT_Start(uint32_t TimeOut) +{ + uint32_t ClkSrc; + + ClkSrc = LPC_WDT->WDCLKSEL; + ClkSrc &=WDT_WDCLKSEL_MASK; + WDT_SetTimeOut(ClkSrc,TimeOut); + //enable watchdog + LPC_WDT->WDMOD |= WDT_WDMOD_WDEN; + WDT_Feed(); +} + +/********************************************************************//** + * @brief Read WDT Time out flag + * @param[in] None + * @return Time out flag status of WDT + *********************************************************************/ +FlagStatus WDT_ReadTimeOutFlag (void) +{ + return ((FlagStatus)((LPC_WDT->WDMOD & WDT_WDMOD_WDTOF) >>2)); +} + +/********************************************************************//** + * @brief Clear WDT Time out flag + * @param[in] None + * @return None + *********************************************************************/ +void WDT_ClrTimeOutFlag (void) +{ + LPC_WDT->WDMOD &=~WDT_WDMOD_WDTOF; +} + +/********************************************************************//** + * @brief Update WDT timeout value and feed + * @param[in] TimeOut TimeOut value to be updated + * @return None + *********************************************************************/ +void WDT_UpdateTimeOut ( uint32_t TimeOut) +{ + uint32_t ClkSrc; + ClkSrc = LPC_WDT->WDCLKSEL; + ClkSrc &=WDT_WDCLKSEL_MASK; + WDT_SetTimeOut(ClkSrc,TimeOut); + WDT_Feed(); +} + + +/********************************************************************//** + * @brief After set WDTEN, call this function to start Watchdog + * or reload the Watchdog timer + * @param[in] None + * + * @return None + *********************************************************************/ +void WDT_Feed (void) +{ + // Disable irq interrupt + __disable_irq(); + LPC_WDT->WDFEED = 0xAA; + LPC_WDT->WDFEED = 0x55; + // Then enable irq interrupt + __enable_irq(); +} + +/********************************************************************//** + * @brief Get the current value of WDT + * @param[in] None + * @return current value of WDT + *********************************************************************/ +uint32_t WDT_GetCurrentCount(void) +{ + return LPC_WDT->WDTV; +} + +/** + * @} + */ + +#endif /* _WDT */ + +/** + * @} + */ + +/* --------------------------------- End Of File ------------------------------ */ diff --git a/arch/arm/lpc17xx/Drivers/source/makefile b/arch/arm/lpc17xx/Drivers/source/makefile new file mode 100644 index 0000000..8cf581c --- /dev/null +++ b/arch/arm/lpc17xx/Drivers/source/makefile @@ -0,0 +1,84 @@ +######################################################################## +# $Id:: makefile 814 2008-06-19 19:57:32Z pdurgesh $ +# +# Project: Standard compile makefile +# +# Description: +# Makefile +# +######################################################################## +# Software that is described herein is for illustrative purposes only +# which provides customers with programming information regarding the +# products. This software is supplied "AS IS" without any warranties. +# NXP Semiconductors assumes no responsibility or liability for the +# use of the software, conveys no license or title under any patent, +# copyright, or mask work right to the product. NXP Semiconductors +# reserves the right to make changes in the software without +# notification. NXP Semiconductors also make no representation or +# warranty that such application will be suitable for the specified +# use without further testing or modification. +######################################################################## + +######################################################################## +# +# Pick up the configuration file in make section +# +######################################################################## +include ../../makesection/makeconfig + +######################################################################## +# +# Pick up the default build rules +# +######################################################################## + +include $(PROJ_ROOT)/makesection/makerule/$(DEVICE)/make.$(DEVICE).$(TOOL) + +######################################################################## +# +# Pick up the assembler and C source files in the directory +# +######################################################################## +include $(PROJ_ROOT)\makesection\makerule\common\make.rules.ftypes +AFLAGS +=-I../include +CFLAGS +=-I../include + + +######################################################################## +# +# Build the library +# +######################################################################## + +$(TARGET_FWLIB_LIB) : .vias $(OBJS) $(FWLIB_LIB_DIR) + $(ECHO) "creating" $(FWLIB) "Firmware support package library" + $(AR) $@ $(OBJS) + +$(FWLIB_LIB_DIR): + $(MKDIR) $(FWLIB_LIB_DIR) + +# delete all targets this Makefile can make +lib_clean: + -@$(RM) $(TARGET_FWLIB_LIB) + +# delete all targets this Makefile can make and all built libraries +# linked in +lib_realclean: + -@$(RM) $(FWLIB_LIB_DIR)/*.a + -@$(RMDIR) $(FWLIB_LIB_DIR) + +clean: lib_clean +realclean: lib_realclean + +######################################################################## +# +# Compile the code base +# +######################################################################## + +include $(PROJ_ROOT)/makesection/makerule/common/make.rules.build + +.PHONY: all lib_clean lib_realclean + + + -- cgit v1.2.3