/* ---------------------------------------------------------------------------- */ /* Atmel Microcontroller Software Support */ /* SAM Software Package License */ /* ---------------------------------------------------------------------------- */ /* Copyright (c) 2015, Atmel Corporation */ /* */ /* All rights reserved. */ /* */ /* Redistribution and use in source and binary forms, with or without */ /* modification, are permitted provided that the following condition is met: */ /* */ /* - Redistributions of source code must retain the above copyright notice, */ /* this list of conditions and the disclaimer below. */ /* */ /* Atmel's name may not be used to endorse or promote products derived from */ /* this software without specific prior written permission. */ /* */ /* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR */ /* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */ /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE */ /* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, */ /* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, */ /* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF */ /* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING */ /* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, */ /* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* ---------------------------------------------------------------------------- */ /** * \file * * Implementation of USART (Universal Synchronous Asynchronous Receiver * Transmitter) controller. * */ /*------------------------------------------------------------------------------ * Headers *-----------------------------------------------------------------------------*/ #include "chip.h" #include #include /*---------------------------------------------------------------------------- * Local definitions *----------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------ * Exported functions *-----------------------------------------------------------------------------*/ /** * \brief Configures an USART baudrate. * * * \param pUsart Pointer to the USART peripheral to configure. * \param baudrate Baudrate at which the USART should operate (in Hz). * \param masterClock Frequency of the system master clock (in Hz). */ void USART_SetBaudrate(Usart *pUsart, uint8_t OverSamp, uint32_t baudrate, uint32_t masterClock) { unsigned int CD, FP, BaudError, ActualBaudRate; /* Configure baudrate*/ BaudError = 10; OverSamp = 0; #ifdef __rtems__ CD = 0; FP = 0; #endif /* __rtems__ */ /*Asynchronous*/ if ((pUsart->US_MR & US_MR_SYNC) == 0) { /* 7816 mode */ if (((pUsart->US_MR & US_MR_USART_MODE_IS07816_T_0) == US_MR_USART_MODE_IS07816_T_0) || ((pUsart->US_MR & US_MR_USART_MODE_IS07816_T_1) == US_MR_USART_MODE_IS07816_T_1)) { /* Define the baud rate divisor register */ /* CD = MCK / SCK */ /* SCK = FIDI x BAUD = 372 x 9600 */ /* BOARD_MCK */ /* CD = MCK/(FIDI x BAUD) = 150000000 / (372x9600) = 42 */ CD = masterClock / (pUsart->US_FIDI * baudrate); FP = 0; } else { while (BaudError > 5) { CD = (masterClock / (baudrate * 8 * (2 - OverSamp))); FP = ((masterClock / (baudrate * (2 - OverSamp))) - CD * 8); ActualBaudRate = (masterClock / (CD * 8 + FP)) / (2 - OverSamp); BaudError = (100 - ((baudrate * 100 / ActualBaudRate))); if (BaudError > 5) { OverSamp++; if (OverSamp >= 2) { TRACE_ERROR("Canont set this baudrate \n\r"); break; } } } } } /*Synchronous SPI */ if ((pUsart->US_MR & US_MR_USART_MODE_SPI_MASTER) == US_MR_USART_MODE_SPI_MASTER || ((pUsart->US_MR & US_MR_SYNC) == US_MR_SYNC)) { if ((pUsart->US_MR & US_MR_USCLKS_Msk) == US_MR_USCLKS_MCK) { CD = masterClock / baudrate; FP = ((masterClock / baudrate) - CD); } } pUsart->US_BRGR = (US_BRGR_CD(CD) | US_BRGR_FP(FP)); /* Configure OverSamp*/ pUsart->US_MR |= (OverSamp << 19); } /** * \brief Configures an USART peripheral with the specified parameters. * * * \param pUsart Pointer to the USART peripheral to configure. * \param mode Desired value for the USART mode register (see the datasheet). * \param baudrate Baudrate at which the USART should operate (in Hz). * \param masterClock Frequency of the system master clock (in Hz). */ void USART_Configure(Usart *pUsart, uint32_t mode, uint32_t baudrate, uint32_t masterClock) { /* Reset and disable receiver & transmitter*/ pUsart->US_CR = US_CR_RSTRX | US_CR_RSTTX | US_CR_RXDIS | US_CR_TXDIS | US_CR_RSTSTA; pUsart->US_IDR = 0xFFFFFFFF; pUsart->US_MR = mode; /* Configure baudrate*/ USART_SetBaudrate(pUsart, 0, baudrate, masterClock); /* Enable receiver and transmitter */ pUsart->US_CR = US_CR_RXEN | US_CR_TXEN; /* Disable buffering for printf(). */ #if (defined (__GNUC__) && !defined (__SAMBA__)) setvbuf(stdout, (char *)NULL, _IONBF, 0); #endif } /** * \brief Enables or disables the transmitter of an USART peripheral. * * * \param pUsart Pointer to an USART peripheral * \param enabled If true, the transmitter is enabled; otherwise it is * disabled. */ void USART_SetTransmitterEnabled(Usart *pUsart, uint8_t enabled) { if (enabled) pUsart->US_CR = US_CR_TXEN; else pUsart->US_CR = US_CR_TXDIS; } /** * \brief Disables the Receiver of an USART peripheral. * * \param pUsart Pointer to an USART peripheral */ void USART_DisableRx(Usart *pUsart) { pUsart->US_CR = US_CR_RXDIS; } /** * \brief Disables the transmitter of an USART peripheral. * * \param pUsart Pointer to an USART peripheral */ void USART_DisableTx(Usart *pUsart) { pUsart->US_CR = US_CR_TXDIS; } /** * \brief Enables the Receiver of an USART peripheral. * * \param pUsart Pointer to an USART peripheral */ void USART_EnableRx(Usart *pUsart) { pUsart->US_CR = US_CR_RXEN; } /** * \brief Enables the transmitter of an USART peripheral * * \param pUsart Pointer to an USART peripheral */ void USART_EnableTx(Usart *pUsart) { pUsart->US_CR = US_CR_TXEN; } /** * \brief Resets or disables the Receiver of an USART peripheral. * * * \param pUsart Pointer to an USART peripheral */ void USART_ResetRx(Usart *pUsart) { pUsart->US_CR = US_CR_RSTRX | US_CR_RXDIS; } /** * \brief resets and disables the transmitter of an USART peripheral. * * * \param pUsart Pointer to an USART peripheral */ void USART_ResetTx(Usart *pUsart) { pUsart->US_CR = US_CR_RSTTX | US_CR_TXDIS; } /** * \brief Enables or disables the receiver of an USART peripheral * * * \param pUsart Pointer to an USART peripheral * \param enabled If true, the receiver is enabled; otherwise it is disabled. */ void USART_SetReceiverEnabled(Usart *pUsart, uint8_t enabled) { if (enabled) pUsart->US_CR = US_CR_RXEN; else pUsart->US_CR = US_CR_RXDIS; } /** * \brief Enables or disables the Request To Send (RTS) of an USART peripheral * * * \param pUsart Pointer to an USART peripheral * \param enabled If true, the RTS is enabled (0); otherwise it is disabled. */ void USART_SetRTSEnabled(Usart *pUsart, uint8_t enabled) { if (enabled) pUsart->US_CR = US_CR_RTSEN; else pUsart->US_CR = US_CR_RTSDIS; } /** * \brief Sends one packet of data through the specified USART peripheral. This * function operates synchronously, so it only returns when the data has been * actually sent. * * * \param pUsart Pointer to an USART peripheral. * \param data Data to send including 9nth bit and sync field if necessary (in * the same format as the US_THR register in the datasheet). * \param timeOut Time out value (0 = no timeout). */ void USART_Write(Usart *pUsart, uint16_t data, volatile uint32_t timeOut) { if (timeOut == 0) { while ((pUsart->US_CSR & US_CSR_TXEMPTY) == 0); } else { while ((pUsart->US_CSR & US_CSR_TXEMPTY) == 0) { if (timeOut == 0) { TRACE_ERROR("USART_Write: Timed out.\n\r"); return; } timeOut--; } } pUsart->US_THR = data; } /** * \brief Reads and return a packet of data on the specified USART peripheral. * This function operates asynchronously, so it waits until some data has been * received. * * \param pUsart Pointer to an USART peripheral. * \param timeOut Time out value (0 -> no timeout). */ uint16_t USART_Read(Usart *pUsart, volatile uint32_t timeOut) { if (timeOut == 0) { while ((pUsart->US_CSR & US_CSR_RXRDY) == 0); } else { while ((pUsart->US_CSR & US_CSR_RXRDY) == 0) { if (timeOut == 0) { TRACE_ERROR("USART_Read: Timed out.\n\r"); return 0; } timeOut--; } } return pUsart->US_RHR; } /** * \brief Returns 1 if some data has been received and can be read from an * USART; otherwise returns 0. * * \param pUsart Pointer to an USART instance. */ uint8_t USART_IsDataAvailable(Usart *pUsart) { if ((pUsart->US_CSR & US_CSR_RXRDY) != 0) return 1; else return 0; } /** * \brief Sends one packet of data through the specified USART peripheral. This * function operates synchronously, so it only returns when the data has been * actually sent. * * \param pUsart Pointer to an USART peripheral. * \param c Character to send */ void USART_PutChar(Usart *pUsart, uint8_t c) { /* Wait for the transmitter to be ready*/ while ((pUsart->US_CSR & US_CSR_TXEMPTY) == 0); /* Send character*/ pUsart->US_THR = c; /* Wait for the transfer to complete*/ while ((pUsart->US_CSR & US_CSR_TXEMPTY) == 0); } /** * \brief Return 1 if a character can be read in USART * \param pUsart Pointer to an USART peripheral. */ uint32_t USART_IsRxReady(Usart *pUsart) { return (pUsart->US_CSR & US_CSR_RXRDY); } /** * \brief Get present status * \param pUsart Pointer to an USART peripheral. */ uint32_t USART_GetStatus(Usart *pUsart) { return pUsart->US_CSR; } /** * \brief Enable interrupt * \param pUsart Pointer to an USART peripheral. * \param mode Interrupt mode. */ void USART_EnableIt(Usart *pUsart, uint32_t mode) { pUsart->US_IER = mode; } /** * \brief Disable interrupt * \param pUsart Pointer to an USART peripheral. * \param mode Interrupt mode. */ void USART_DisableIt(Usart *pUsart, uint32_t mode) { pUsart->US_IDR = mode; } /** * \brief Return interrupt mask * \param pUsart Pointer to an USART peripheral. */ uint32_t USART_GetItMask(Usart *pUsart) { return pUsart->US_IMR; } /** * \brief Reads and returns a character from the USART. * * \note This function is synchronous (i.e. uses polling). * \param pUsart Pointer to an USART peripheral. * \return Character received. */ uint8_t USART_GetChar(Usart *pUsart) { while ((pUsart->US_CSR & US_CSR_RXRDY) == 0); return pUsart->US_RHR; } /** * \brief Enable Rx Timeout for USART. * * \param pUsart Pointer to an USART peripheral. * \param Timeout Timeout value * \return None */ void USART_EnableRecvTimeOut(Usart *pUsart, uint32_t Timeout) { if (Timeout <= MAX_RX_TIMEOUT) pUsart->US_RTOR = Timeout; else if (Timeout == 0) { TRACE_DEBUG("Timeout is disabled\n\r"); } else { TRACE_INFO_WP("\n\r"); TRACE_FATAL("Timeout value is out of range\n\r"); } } /** * \brief Enable Tx Timeout for USART. * * \param pUsart Pointer to an USART peripheral. * \param TimeGaurd TimeGaurd value * \return None */ void USART_EnableTxTimeGaurd(Usart *pUsart, uint32_t TimeGaurd) { if (((pUsart->US_MR & US_MR_USART_MODE_LON) && TimeGaurd <= 16777215) || ((pUsart->US_MR & US_MR_USART_MODE_LON) && TimeGaurd <= 255)) pUsart->US_TTGR = TimeGaurd; else TRACE_ERROR(" TimeGaurd Value is too big for mode"); } /** * \brief Acknowledge Rx timeout and sets to Idle or periodic repetitive state. * * \param pUsart Pointer to an USART peripheral. * \param Periodic If timeout is periodic or should wait for new char * \return None */ void USART_AcknowledgeRxTimeOut(Usart *pUsart, uint8_t Periodic) { if (Periodic) { pUsart->US_CR = US_CR_RETTO; // Restart timeout timer } else { // Puts USARt in Idle mode and waits for a char after timeout pUsart->US_CR = US_CR_STTTO; } }