XMC4xxx: Add USIC baudrate calculation.

This commit is contained in:
Gregory Nutt 2017-03-19 18:11:38 -06:00
parent ae32905fe8
commit 5df421488c
5 changed files with 202 additions and 38 deletions

View File

@ -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 */

View File

@ -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;
}

View File

@ -40,6 +40,7 @@
#include <nuttx/config.h>
#include <stdint.h>
#include <errno.h>
#include <arch/irq.h>
#include <arch/board/board.h>
@ -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

View File

@ -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 <sys/types.h>
#include <stdint.h>
#include <errno.h>
#include <assert.h>
#include <arch/xmc4/chip.h>
#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;
}
}
/****************************************************************************
* 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;
}

View File

@ -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 */