diff --git a/arch/arm/src/xmc4/xmc4_clockconfig.h b/arch/arm/src/xmc4/xmc4_clockconfig.h index 6e03989cad0..5001683accb 100644 --- a/arch/arm/src/xmc4/xmc4_clockconfig.h +++ b/arch/arm/src/xmc4/xmc4_clockconfig.h @@ -70,10 +70,21 @@ void xmc4_clock_configure(void); * Name: xmc4_get_coreclock * * Description: - * Return the current core clock frequency. + * Return the current core clock frequency, fCPU. * ****************************************************************************/ uint32_t xmc4_get_coreclock(void); +/**************************************************************************** + * Name: xmc4_get_periphclock + * + * Description: + * The peripheral clock is either fCPU or fCPU/2, depending on the state + * of the peripheral divider. + * + ****************************************************************************/ + +uint32_t xmc4_get_periphclock(void); + #endif /* __ARCH_ARM_SRC_XMC4_XMC4_CLOCKCONFIG_H */ diff --git a/arch/arm/src/xmc4/xmc4_clockutils.c b/arch/arm/src/xmc4/xmc4_clockutils.c index cf9649099ed..4d334eaef53 100644 --- a/arch/arm/src/xmc4/xmc4_clockutils.c +++ b/arch/arm/src/xmc4/xmc4_clockutils.c @@ -101,36 +101,36 @@ uint32_t xmc4_get_coreclock(void) temp = BOARD_XTAL_FREQUENCY; } - /* Check if PLL is locked */ + /* Check if PLL is locked */ - regval = getreg32(XMC4_SCU_PLLSTAT); - if ((regval & SCU_PLLSTAT_VCOLOCK) != 0) - { - /* PLL normal mode */ + regval = getreg32(XMC4_SCU_PLLSTAT); + if ((regval & SCU_PLLSTAT_VCOLOCK) != 0) + { + /* PLL normal mode */ - regval = getreg32(XMC4_SCU_PLLCON1); - pdiv = ((regval & SCU_PLLCON1_PDIV_MASK) >> SCU_PLLCON1_PDIV_SHIFT) + 1; - ndiv = ((regval & SCU_PLLCON1_NDIV_MASK) >> SCU_PLLCON1_NDIV_SHIFT) + 1; - kdiv = ((regval & SCU_PLLCON1_K2DIV_MASK) >> SCU_PLLCON1_K2DIV_SHIFT) + 1; + regval = getreg32(XMC4_SCU_PLLCON1); + pdiv = ((regval & SCU_PLLCON1_PDIV_MASK) >> SCU_PLLCON1_PDIV_SHIFT) + 1; + ndiv = ((regval & SCU_PLLCON1_NDIV_MASK) >> SCU_PLLCON1_NDIV_SHIFT) + 1; + kdiv = ((regval & SCU_PLLCON1_K2DIV_MASK) >> SCU_PLLCON1_K2DIV_SHIFT) + 1; - temp = (temp / (pdiv * kdiv)) * ndiv; + temp = (temp / (pdiv * kdiv)) * ndiv; + } + else + { + /* PLL prescalar mode */ + + regval = getreg32(XMC4_SCU_PLLCON1); + kdiv = ((regval & SCU_PLLCON1_K1DIV_MASK) >> SCU_PLLCON1_K1DIV_SHIFT) + 1; + + temp = (temp / kdiv); + } } - else - { - /* PLL prescalar mode */ - - regval = getreg32(XMC4_SCU_PLLCON1); - kdiv = ((regval & SCU_PLLCON1_K1DIV_MASK) >> SCU_PLLCON1_K1DIV_SHIFT) + 1; - - temp = (temp / kdiv); - } - } else - { - /* fOFI is clock source for fSYS */ + { + /* fOFI is clock source for fSYS */ - temp = OFI_FREQUENCY; - } + temp = OFI_FREQUENCY; + } /* Divide by SYSDIV to get fSYS */ @@ -148,3 +148,35 @@ uint32_t xmc4_get_coreclock(void) return temp; } + +/**************************************************************************** + * Name: xmc4_get_periphclock + * + * Description: + * The peripheral clock is either fCPU or fCPU/2, depending on the state + * of the peripheral divider. + * + ****************************************************************************/ + +uint32_t xmc4_get_periphclock(void) +{ + uint32_t periphclock; + + /* Get the CPU clock frequency. Unless it is divided down, this also the + * peripheral clock frequency. + */ + + periphclock = xmc4_get_coreclock(); + + /* Get the peripheral clock divider */ + + periphclock = getreg32(XMC4_SCU_PBCLKCR); + if ((periphclock & SCU_PBCLKCR_PBDIV) != 0) + { + /* The peripheral clock is fCPU/2 */ + + periphclock <<= 1; + } + + return periphclock; +} diff --git a/arch/arm/src/xmc4/xmc4_lowputc.c b/arch/arm/src/xmc4/xmc4_lowputc.c index 305a43f657a..0c7a4fdc5ef 100644 --- a/arch/arm/src/xmc4/xmc4_lowputc.c +++ b/arch/arm/src/xmc4/xmc4_lowputc.c @@ -40,6 +40,7 @@ #include #include +#include #include #include @@ -50,6 +51,7 @@ #include "xmc4_config.h" #include "chip/xmc4_usic.h" #include "chip/xmc4_pinmux.h" +#include "xmc4_usic.h" #include "xmc4_lowputc.h" /**************************************************************************** @@ -60,42 +62,42 @@ #if defined(HAVE_UART_CONSOLE) # if defined(CONFIG_UART0_SERIAL_CONSOLE) -# define CONSOLE_BASE XMC4_USIC0_CH0_BASE +# define CONSOLE_CHAN USIC0_CHAN0 # define CONSOLE_FREQ BOARD_CORECLK_FREQ # define CONSOLE_BAUD CONFIG_UART0_BAUD # define CONSOLE_BITS CONFIG_UART0_BITS # define CONSOLE_2STOP CONFIG_UART0_2STOP # define CONSOLE_PARITY CONFIG_UART0_PARITY # elif defined(CONFIG_UART1_SERIAL_CONSOLE) -# define CONSOLE_BASE XMC4_USIC0_CH1_BASE +# define CONSOLE_CHAN USIC0_CHAN1 # define CONSOLE_FREQ BOARD_CORECLK_FREQ # define CONSOLE_BAUD CONFIG_UART1_BAUD # define CONSOLE_BITS CONFIG_UART1_BITS # define CONSOLE_2STOP CONFIG_UART1_2STOP # define CONSOLE_PARITY CONFIG_UART1_PARITY # elif defined(CONFIG_UART2_SERIAL_CONSOLE) -# define CONSOLE_BASE XMC4_USIC1_CH0_BASE +# define CONSOLE_CHAN USIC1_CHAN0 # define CONSOLE_FREQ BOARD_BUS_FREQ # define CONSOLE_BAUD CONFIG_UART2_BAUD # define CONSOLE_BITS CONFIG_UART2_BITS # define CONSOLE_2STOP CONFIG_UART2_2STOP # define CONSOLE_PARITY CONFIG_UART2_PARITY # elif defined(CONFIG_UART3_SERIAL_CONSOLE) -# define CONSOLE_BASE XMC4_USIC1_CH1_BASE +# define CONSOLE_CHAN USIC1_CHAN1 # define CONSOLE_FREQ BOARD_BUS_FREQ # define CONSOLE_BAUD CONFIG_UART3_BAUD # define CONSOLE_BITS CONFIG_UART3_BITS # define CONSOLE_2STOP CONFIG_UART3_2STOP # define CONSOLE_PARITY CONFIG_UART3_PARITY # elif defined(CONFIG_UART4_SERIAL_CONSOLE) -# define CONSOLE_BASE XMC4_USIC2_CH0_BASE +# define CONSOLE_CHAN USIC2_CHAN0 # define CONSOLE_FREQ BOARD_BUS_FREQ # define CONSOLE_BAUD CONFIG_UART4_BAUD # define CONSOLE_BITS CONFIG_UART4_BITS # define CONSOLE_2STOP CONFIG_UART4_2STOP # define CONSOLE_PARITY CONFIG_UART4_PARITY # elif defined(CONFIG_UART5_SERIAL_CONSOLE) -# define CONSOLE_BASE XMC4_USIC2_CH1_BASE +# define CONSOLE_CHAN USIC2_CHAN1 # define CONSOLE_FREQ BOARD_BUS_FREQ # define CONSOLE_BAUD CONFIG_UART5_BAUD # define CONSOLE_BITS CONFIG_UART5_BITS @@ -107,7 +109,7 @@ #endif /* HAVE_UART_CONSOLE */ /**************************************************************************** - * Private Data + * Private Functions ****************************************************************************/ /**************************************************************************** @@ -169,7 +171,7 @@ void xmc4_lowsetup(void) * when the serial driver is opened. */ - xmc4_uart_configure(CONSOLE_BASE, CONSOLE_BAUD, CONSOLE_FREQ, \ + xmc4_uart_configure(CONSOLE_CHAN, CONSOLE_BAUD, CONSOLE_FREQ, \ CONSOLE_PARITY, CONSOLE_BITS, CONSOLE_2STOP); #endif /* HAVE_UART_DEVICE */ } @@ -210,11 +212,12 @@ int xmc4_uart_configure(enum usic_channel_e channel, uint32_t baud, unsigned int nbits, unsigned int stop2) { uintptr_t base; + uint32_t oversampling; int ret; /* Get the base address of the USIC registers associated with this channel */ - base = uintptr_t xmc4_channel_baseaddress(channel); + base = xmc4_channel_baseaddress(channel); if (base == 0) { return -EINVAL; @@ -228,6 +231,8 @@ int xmc4_uart_configure(enum usic_channel_e channel, uint32_t baud, return ret; } + ret = xmc4_uisc_baudrate(channel, baud, oversampling); + /* Configure number of bits, stop bits and parity */ #warning Missing logic diff --git a/arch/arm/src/xmc4/xmc4_usic.c b/arch/arm/src/xmc4/xmc4_usic.c index 1480cdb7a8c..26347642403 100644 --- a/arch/arm/src/xmc4/xmc4_usic.c +++ b/arch/arm/src/xmc4/xmc4_usic.c @@ -31,6 +31,20 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * + * May include some logic from sample code provided by Infineon: + * + * Copyright (C) 2011-2015 Infineon Technologies AG. All rights reserved. + * + * Infineon Technologies AG (Infineon) is supplying this software for use with + * Infineon's microcontrollers. This file can be freely distributed within + * development tools that are supporting such microcontrollers. + * + * THIS SOFTWARE IS PROVIDED AS IS. NO WARRANTIES, WHETHER EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. + * INFINEON SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, + * OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. + * ****************************************************************************/ /**************************************************************************** @@ -42,12 +56,14 @@ #include #include #include +#include #include #include "up_arch.h" #include "chip/xmc4_usic.h" #include "chip/xmc4_scu.h" +#include "xmc4_clockconfig.h" #include "xmc4_usic.h" /**************************************************************************** @@ -226,7 +242,7 @@ int xmc4_disable_usic(enum usic_e usic) uintptr_t xmc4_channel_baseaddress(enum usic_channel_e channel) { - if ((usigned int)channel < (2 * XM4C_NUSICS)) + if ((unsigned int)channel < (2 * XMC4_NUSIC)) { return g_channel_baseaddress[channel]; } @@ -264,7 +280,7 @@ int xmc4_enable_usic_channel(enum usic_channel_e channel) /* Enable the USIC module */ - xmc4_enable_usic(xmc4_channel2usic(channel)); + ret = xmc4_enable_usic(xmc4_channel2usic(channel)); if (ret < 0) { return ret; @@ -330,7 +346,7 @@ int xmc4_disable_usic_channel(enum usic_channel_e channel) /* Get the base address of other channel for this USIC module */ other = xmc4_channel_baseaddress(channel ^ 1); - DEBUASSERT(other != 0); + DEBUGASSERT(other != 0); /* Check if the other channel has also been disabled */ @@ -343,4 +359,89 @@ int xmc4_disable_usic_channel(enum usic_channel_e channel) } return OK; -} \ No newline at end of file +} + +/**************************************************************************** + * Name: xmc4_uisc_baudrate + * + * Description: + * Set the USIC baudrate for the USIC channel + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned to + * indicate the nature of any failure. + * + ****************************************************************************/ + +int xmc4_uisc_baudrate(enum usic_channel_e channel, uint32_t baud, + uint32_t oversampling) +{ + uintptr_t base; + uint32_t periphclock; + uint32_t clkdiv; + uint32_t clkdiv_min; + uint32_t pdiv; + uint32_t pdiv_int; + uint32_t pdiv_int_min; + uint32_t pdiv_frac; + uint32_t pdiv_frac_min; + uint32_t regval; + int ret; + + /* Get the base address of the registers for this channel */ + + base = xmc4_channel_baseaddress(channel); + if (base == 0) + { + return -EINVAL; + } + + /* The baud and peripheral clock are divided by 100 to be able to use only + * 32-bit arithmetic. + */ + + if (baud >= 100 && oversampling != 0) + { + periphclock = xmc4_get_periphclock() / 100; + baud = baud / 100; + + clkdiv_min = 1; + pdiv_int_min = 1; + pdiv_frac_min = 0x3ff; + + for (clkdiv = 1023; clkdiv > 0; --clkdiv) + { + pdiv = ((periphclock * clkdiv) / (baud * oversampling)); + pdiv_int = pdiv >> 10; + pdiv_frac = pdiv & 0x3ff; + + if (pdiv_int < 1024 && pdiv_frac < pdiv_frac_min) + { + pdiv_frac_min = pdiv_frac; + pdiv_int_min = pdiv_int; + clkdiv_min = clkdiv; + } + } + + /* Select and setup the fractional divider */ + + regval = USIC_FDR_DM_FRACTIONAL | (clkdiv_min << USIC_FDR_STEP_SHIFT); + putreg32(regval, base + XMC4_USIC_FDR_OFFSET); + + /* Setup and enable the baud rate generator */ + + regval = getreg32(base + XMC4_USIC_BRG_OFFSET); + regval &= ~(USIC_BRG_DCTQ_MASK | USIC_BRG_PDIV_MASK | USIC_BRG_PCTQ_MASK | USIC_BRG_PPPEN); + regval |= (USIC_BRG_DCTQ(oversampling - 1) | USIC_BRG_PDIV(pdiv_int_min - 1)); + putreg32(regval, base + XMC4_USIC_BRG_OFFSET); + + ret = OK; + } + else + { + ret = -ERANGE; + } + + return ret; +} + diff --git a/arch/arm/src/xmc4/xmc4_usic.h b/arch/arm/src/xmc4/xmc4_usic.h index 07ab1fc2de4..5c5e78fdb90 100644 --- a/arch/arm/src/xmc4/xmc4_usic.h +++ b/arch/arm/src/xmc4/xmc4_usic.h @@ -167,4 +167,19 @@ int xmc4_enable_usic_channel(enum usic_channel_e channel); int xmc4_disable_usic_channel(enum usic_channel_e channel); +/**************************************************************************** + * Name: xmc4_uisc_baudrate + * + * Description: + * Set the USIC baudrate for the USIC channel + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned to + * indicate the nature of any failure. + * + ****************************************************************************/ + +int xmc4_uisc_baudrate(enum usic_channel_e channel, uint32_t baud, + uint32_t oversampling); + #endif /* __ARCH_ARM_SRC_XMC4_XMC4_USIC_H */