From 305df5ccf1ca89a4d748f4852d3886308ddefe96 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sat, 15 Feb 2014 17:53:55 -0600 Subject: [PATCH] SAMD20: More SERCOM USART configuration logic --- arch/arm/src/samd/sam_lowputc.c | 238 +++++++++++++++++++++++++++++++- arch/arm/src/samd/sam_lowputc.h | 6 +- arch/arm/src/samd/sam_usart.c | 6 + arch/arm/src/samd/sam_usart.h | 1 + 4 files changed, 243 insertions(+), 8 deletions(-) diff --git a/arch/arm/src/samd/sam_lowputc.c b/arch/arm/src/samd/sam_lowputc.c index 58c043fc7a..7c10b61ecd 100644 --- a/arch/arm/src/samd/sam_lowputc.c +++ b/arch/arm/src/samd/sam_lowputc.c @@ -4,6 +4,15 @@ * Copyright (C) 2014 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * + * References: + * 1. "Atmel SAM D20J / SAM D20G / SAM D20E ARM-Based Microcontroller + * Datasheet", 42129J–SAM–12/2013 + * 2. Atmel sample code. This code has an ASF license with is compatible + * with the NuttX BSD license, but includes the provision that this + * code not be used in non-Atmel products. That sample code was used + * only as a reference so I believe that only the NuttX BSD license + * applies. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -41,14 +50,23 @@ #include #include +#include + +#include "up_arch.h" #include "sam_config.h" +#include "chip/sam_pm.h" +#include "chip/sam_usart.h" #include "sam_usart.h" /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ +#ifndef OK +# define OK 0 +#endif + /**************************************************************************** * Private Data ****************************************************************************/ @@ -57,17 +75,196 @@ * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: sam_wait_synchronization + * + * Description: + * Wait until the SERCOM USART reports that it is synchronized. + * + ****************************************************************************/ + +#ifdef HAVE_USART +static void +sam_wait_synchronization(const struct sam_usart_config_s * const config) +{ + while ((getreg16(config->base + SAM_USART_STATUS_OFFSET) & USART_STATUS_SYNCBUSY) != 0); +} +#endif + +/**************************************************************************** + * Name: sam_gclk_configure + * + * Description: + * Configure the SERCOM USART source clock. + * + ****************************************************************************/ + +#ifdef HAVE_USART +static inline int +sam_gclk_configure(const struct sam_usart_config_s * const config) +{ +#warning Missing logic + return -ENOSYS; +} +#endif + +/**************************************************************************** + * Name: sam_usart_configure + * + * Description: + * Configure the SERCOM USART operating mode (as a normal UART). + * + ****************************************************************************/ + +#ifdef HAVE_USART +static inline int +sam_usart_configure(const struct sam_usart_config_s * const config) +{ + uint32_t ctrla; + uint32_t ctrlb; + uint32_t baud; + + /* Check if baud is within the valid range. */ + + if (config->baud > (config->frequency >> 1)) + { + return -ERANGE; + } + + /* Calculate BAUD divider from the source clock frequency and desired baud */ + + baud = (config->frequency / (2 * config->baud)) - 1; + + /* Verify that the calculated result is within range */ + + if (baud > UINT16_MAX) + { + return -ERANGE; + } + + /* Wait until synchronization is complete */ + + sam_wait_synchronization(config); + + /* Set baud val */ + + putreg16((uint16_t)baud, config->base + SAM_USART_BAUD_OFFSET); + + /* Configure the USART CTRLA and CTRLB registers */ + + ctrla = (USART_CTRLA_MODE_INTUSART | (uint32_t)config->muxconfig | + USART_CTRLA_ASYNCH | USART_CTRLA_CPOL_NORMAL | + USART_CTRLA_LSBFIRST); + ctrlb = (USART_CTRLB_TXEN | USART_CTRLB_RXEN); + + /* Set the number of stop bits */ + + if (config->stopbits2) + { + ctrlb |= USART_CTRLB_SBMODE; + } + + /* Set the USART word size */ + + switch (config->bits) + { + case 5: + ctrlb |= USART_CTRLB_CHSIZE_5BITS; + break; + + case 6: + ctrlb |= USART_CTRLB_CHSIZE_6BITS; + break; + + case 7: + ctrlb |= USART_CTRLB_CHSIZE_7BITS; + break; + + default: + case 8: + break; + + case 9: + ctrlb |= USART_CTRLB_CHSIZE_9BITS; + break; + } + + /* Set parity mode */ + + switch (config->parity) + { + default: + case 0: /* None */ + break; + + case 1: /* Odd */ + ctrlb |= USART_CTRLB_PODD; + /* Fall through */ + + case 2: /* Even */ + ctrla |= USART_CTRLA_FORM_PARITY; + break; + } + +#if 0 /* Not supported */ + /* Set run mode during device sleep */ + + if (config->runinstandby) + { + /* Enable in sleep mode */ + + ctrla |= USART_CTRLA_RUNSTDBY; + } +#endif + + /* Wait until synchronization is complete */ + + sam_wait_synchronization(config); + + /* Write configuration to CTRLB */ + + putreg32(ctrlb, SAM_USART5_CTRLB); + + /* Wait until synchronization is complete */ + + sam_wait_synchronization(config); + + /* Write configuration to CTRLA */ + + putreg32(ctrlb, SAM_USART5_CTRLA); + return OK; +} +#endif + +/**************************************************************************** + * Name: sam_pad_configure + * + * Description: + * Configure the SERCOM USART pads. + * + ****************************************************************************/ + +#ifdef HAVE_USART +static inline int +sam_pad_configure(const struct sam_usart_config_s * const config) +{ +#warning Missing logic + return -ENOSYS; +} +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ -/************************************************************************************ +/**************************************************************************** * Name: sam_lowsetup * * Description: - * Called at the very beginning of _start. Performs low level initialization. + * Called at the very beginning of _start. Performs low level + * initialization. * - ************************************************************************************/ + ****************************************************************************/ void sam_lowsetup(void) { @@ -75,17 +272,46 @@ void sam_lowsetup(void) } /**************************************************************************** - * Name: sam_usartconfig + * Name: sam_usart_initialize * * Description: * Set the configuration of a SERCOM for provided USART configuration. + * This configures the SERCOM as a USART, but does not configure USART + * interrupts or enable the USART. * *****************************************************************************/ #ifdef HAVE_USART -void sam_usartconfig(const struct sam_usart_config_s *config) +int sam_usart_initialize(const struct sam_usart_config_s * const config) { -#warning Missing logic + uint32_t regval; + int ret; + + /* Enable clocking to the SERCOM module in PM */ + + regval = getreg32(SAM_PM_APBCMASK); + regval |= PM_APBCMASK_SERCOM(config->sercom); + putreg32(regval, SAM_PM_APBCMASK); + + /* Configure the GCCLK for the SERCOM module */ + + ret = sam_gclk_configure(config); + if (ret < 0) + { + return ret; + } + + /* Set configuration according to the board configuration */ + + ret = sam_usart_configure(config); + if(ret < 0) + { + return ret; + } + + /* Configure USART pins */ + + return sam_pad_configure(config); } #endif diff --git a/arch/arm/src/samd/sam_lowputc.h b/arch/arm/src/samd/sam_lowputc.h index af553fae5e..cefd3ea03a 100644 --- a/arch/arm/src/samd/sam_lowputc.h +++ b/arch/arm/src/samd/sam_lowputc.h @@ -81,16 +81,18 @@ extern "C" void sam_lowsetup(void); /**************************************************************************** - * Name: sam_usartconfig + * Name: sam_usart_initialize * * Description: * Set the configuration of a SERCOM for provided USART configuration. + * This configures the SERCOM as a USART, but does not configure USART + * interrupts or enable the USART. * *****************************************************************************/ #ifdef HAVE_USART struct sam_usart_config_s; -void sam_usartconfig(const struct sam_usart_config_s *config); +int sam_usart_initialize(const struct sam_usart_config_s * const config); #endif /**************************************************************************** diff --git a/arch/arm/src/samd/sam_usart.c b/arch/arm/src/samd/sam_usart.c index 2d9180eb98..dae8c851bd 100644 --- a/arch/arm/src/samd/sam_usart.c +++ b/arch/arm/src/samd/sam_usart.c @@ -73,6 +73,7 @@ const struct sam_usart_config_s g_usart0config = .pad2 = BOARD_SERCOM0_PINMAP_PAD2, .pad3 = BOARD_SERCOM0_PINMAP_PAD3, .muxconfig = BOARD_SERCOM0_MUXCONFIG, + .frequency = BOARD_SERCOM0_FREQUENCY, .base = SAM_SERCOM0_BASE, }; #endif @@ -92,6 +93,7 @@ const struct sam_usart_config_s g_usart1config = .pad2 = BOARD_SERCOM1_PINMAP_PAD2, .pad3 = BOARD_SERCOM1_PINMAP_PAD3, .muxconfig = BOARD_SERCOM1_MUXCONFIG, + .frequency = BOARD_SERCOM1_FREQUENCY, .base = SAM_SERCOM1_BASE, }; #endif @@ -111,6 +113,7 @@ const struct sam_usart_config_s g_usart2config = .pad2 = BOARD_SERCOM2_PINMAP_PAD2, .pad3 = BOARD_SERCOM2_PINMAP_PAD3, .muxconfig = BOARD_SERCOM2_MUXCONFIG, + .frequency = BOARD_SERCOM2_FREQUENCY, .base = SAM_SERCOM2_BASE, }; #endif @@ -130,6 +133,7 @@ const struct sam_usart_config_s g_usart3config = .pad2 = BOARD_SERCOM3_PINMAP_PAD2, .pad3 = BOARD_SERCOM3_PINMAP_PAD3, .muxconfig = BOARD_SERCOM3_MUXCONFIG, + .frequency = BOARD_SERCOM3_FREQUENCY, .base = SAM_SERCOM3_BASE, }; #endif @@ -149,6 +153,7 @@ const struct sam_usart_config_s g_usart4config = .pad2 = BOARD_SERCOM4_PINMAP_PAD2, .pad3 = BOARD_SERCOM4_PINMAP_PAD3, .muxconfig = BOARD_SERCOM4_MUXCONFIG, + .frequency = BOARD_SERCOM4_FREQUENCY, .base = SAM_SERCOM4_BASE, }; #endif @@ -168,6 +173,7 @@ const struct sam_usart_config_s g_usart5config = .pad2 = BOARD_SERCOM5_PINMAP_PAD2, .pad3 = BOARD_SERCOM5_PINMAP_PAD3, .muxconfig = BOARD_SERCOM5_MUXCONFIG, + .frequency = BOARD_SERCOM5_FREQUENCY, .base = SAM_SERCOM5_BASE, }; #endif diff --git a/arch/arm/src/samd/sam_usart.h b/arch/arm/src/samd/sam_usart.h index b61a45b46a..9d63e35636 100644 --- a/arch/arm/src/samd/sam_usart.h +++ b/arch/arm/src/samd/sam_usart.h @@ -91,6 +91,7 @@ struct sam_usart_config_s port_pinset_t pad2; /* Pin configuration for PAD2 */ port_pinset_t pad3; /* Pin configuration for PAD3 */ uint32_t muxconfig; /* Pad multiplexing configuration */ + uint32_t frequency; /* Source clock frequency */ uintptr_t base; /* SERCOM base address */ };