blob: d7b66eadcdc4c01af71167d65ed9ddcd975927b9 [file] [log] [blame]
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2013, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are 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 <assert.h>
#include <string.h>
/*----------------------------------------------------------------------------
* 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;
/*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;
}
}