mirror of
https://github.com/arduino/Arduino.git
synced 2024-12-11 22:24:13 +01:00
410 lines
12 KiB
C
410 lines
12 KiB
C
/* ----------------------------------------------------------------------------
|
|
* ATMEL Microcontroller Software Support
|
|
* ----------------------------------------------------------------------------
|
|
* Copyright (c) 2009, 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.
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
/** \addtogroup usart_module Working with USART
|
|
* The USART driver provides the interface to configure and use the USART peripheral.\n
|
|
*
|
|
* The USART supports several kinds of comminication modes such as full-duplex asynchronous/
|
|
* synchronous serial commnunication,RS485 with driver control signal,ISO7816,SPI and Test modes.
|
|
*
|
|
* To start a USART transfer with \ref AT91SAM3S_PDC "PDC" support, the user could follow these steps:
|
|
* <ul>
|
|
* <li> Configure USART with expected mode and baudrate(see \ref USART_Configure), which could be done by:
|
|
* -# Resetting and disabling transmitter and receiver by setting US_CR(Control Register). </li>
|
|
* -# Conifguring the USART in a specific mode by setting USART_MODE bits in US_MR(Mode Register) </li>
|
|
* -# Setting baudrate which is different from mode to mode.
|
|
</li>
|
|
* <li> Enable transmitter or receiver respectively by set US_CR_TXEN or US_CR_RXEN in US_CR.</li>
|
|
* <li> Read from or write to the peripheral with \ref USART_ReadBuffer or \ref USART_WriteBuffer.
|
|
These operations could be done by polling or interruption. </li>
|
|
* <li> For polling, check the status bit US_CSR_ENDRX/US_CSR_RXBUFF (READ) or US_CSR_ENDTX/
|
|
US_CSR_TXBUFE (WRITE). </li>
|
|
* <li> For interruption,"enable" the status bit through US_IER and
|
|
realize the hanler with USARTx_IrqHandler according to IRQ vector
|
|
table which is defined in board_cstartup_<toolchain>.c
|
|
To enable the interruption of USART,it should be configured with priority and enabled first through
|
|
NVIC .</li>
|
|
* </ul>
|
|
*
|
|
* For more accurate information, please look at the USART section of the
|
|
* Datasheet.
|
|
*
|
|
* Related files :\n
|
|
* \ref usart.c\n
|
|
* \ref usart.h\n
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
* \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 peripheral with the specified parameters.
|
|
*
|
|
*
|
|
* \param usart 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 *usart,
|
|
uint32_t mode,
|
|
uint32_t baudrate,
|
|
uint32_t masterClock)
|
|
{
|
|
/* Reset and disable receiver & transmitter*/
|
|
usart->US_CR = US_CR_RSTRX | US_CR_RSTTX
|
|
| US_CR_RXDIS | US_CR_TXDIS;
|
|
|
|
/* Configure mode*/
|
|
usart->US_MR = mode;
|
|
|
|
/* Configure baudrate*/
|
|
/* Asynchronous, no oversampling*/
|
|
if ( ((mode & US_MR_SYNC) == 0) && ((mode & US_MR_OVER) == 0) )
|
|
{
|
|
usart->US_BRGR = (masterClock / baudrate) / 16;
|
|
}
|
|
|
|
if( ((mode & US_MR_USART_MODE_SPI_MASTER) == US_MR_USART_MODE_SPI_MASTER)
|
|
|| ((mode & US_MR_SYNC) == US_MR_SYNC))
|
|
{
|
|
if( (mode & US_MR_USCLKS_Msk) == US_MR_USCLKS_MCK)
|
|
{
|
|
usart->US_BRGR = masterClock / baudrate;
|
|
}
|
|
else
|
|
{
|
|
if ( (mode & US_MR_USCLKS_DIV) == US_MR_USCLKS_DIV)
|
|
{
|
|
usart->US_BRGR = masterClock / baudrate / 8;
|
|
}
|
|
}
|
|
}
|
|
/* TODO other modes*/
|
|
}
|
|
/**
|
|
* \brief Enables or disables the transmitter of an USART peripheral.
|
|
*
|
|
*
|
|
* \param usart Pointer to an USART peripheral
|
|
* \param enabled If true, the transmitter is enabled; otherwise it is
|
|
* disabled.
|
|
*/
|
|
void USART_SetTransmitterEnabled(Usart *usart, uint8_t enabled)
|
|
{
|
|
if (enabled) {
|
|
|
|
usart->US_CR = US_CR_TXEN;
|
|
}
|
|
else {
|
|
|
|
usart->US_CR = US_CR_TXDIS;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* \brief Enables or disables the receiver of an USART peripheral
|
|
*
|
|
*
|
|
* \param usart Pointer to an USART peripheral
|
|
* \param enabled If true, the receiver is enabled; otherwise it is disabled.
|
|
*/
|
|
void USART_SetReceiverEnabled(Usart *usart,
|
|
uint8_t enabled)
|
|
{
|
|
if (enabled) {
|
|
|
|
usart->US_CR = US_CR_RXEN;
|
|
}
|
|
else {
|
|
|
|
usart->US_CR = US_CR_RXDIS;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* \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 usart 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 *usart,
|
|
uint16_t data,
|
|
volatile uint32_t timeOut)
|
|
{
|
|
if (timeOut == 0) {
|
|
|
|
while ((usart->US_CSR & US_CSR_TXEMPTY) == 0);
|
|
}
|
|
else {
|
|
|
|
while ((usart->US_CSR & US_CSR_TXEMPTY) == 0) {
|
|
|
|
if (timeOut == 0) {
|
|
|
|
// TRACE_ERROR("USART_Write: Timed out.\n\r");
|
|
return;
|
|
}
|
|
timeOut--;
|
|
}
|
|
}
|
|
|
|
usart->US_THR = data;
|
|
}
|
|
|
|
/**
|
|
* \brief Sends the contents of a data buffer through the specified USART peripheral.
|
|
* This function returns immediately (1 if the buffer has been queued, 0
|
|
* otherwise); poll the ENDTX and TXBUFE bits of the USART status register
|
|
* to check for the transfer completion.
|
|
*
|
|
* \param usart Pointer to an USART peripheral.
|
|
* \param buffer Pointer to the data buffer to send.
|
|
* \param size Size of the data buffer (in bytes).
|
|
*/
|
|
uint8_t USART_WriteBuffer(
|
|
Usart *usart,
|
|
void *buffer,
|
|
uint32_t size)
|
|
{
|
|
/* Check if the first PDC bank is free*/
|
|
if ((usart->US_TCR == 0) && (usart->US_TNCR == 0)) {
|
|
|
|
usart->US_TPR = (uint32_t) buffer;
|
|
usart->US_TCR = size;
|
|
usart->US_PTCR = US_PTCR_TXTEN;
|
|
|
|
return 1;
|
|
}
|
|
/* Check if the second PDC bank is free*/
|
|
else if (usart->US_TNCR == 0) {
|
|
|
|
usart->US_TNPR = (uint32_t) buffer;
|
|
usart->US_TNCR = size;
|
|
|
|
return 1;
|
|
}
|
|
else {
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* \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 usart Pointer to an USART peripheral.
|
|
* \param timeOut Time out value (0 -> no timeout).
|
|
*/
|
|
uint16_t USART_Read(
|
|
Usart *usart,
|
|
volatile uint32_t timeOut)
|
|
{
|
|
if (timeOut == 0) {
|
|
|
|
while ((usart->US_CSR & US_CSR_RXRDY) == 0);
|
|
}
|
|
else {
|
|
|
|
while ((usart->US_CSR & US_CSR_RXRDY) == 0) {
|
|
|
|
if (timeOut == 0) {
|
|
|
|
// TRACE_ERROR( "USART_Read: Timed out.\n\r" ) ;
|
|
return 0;
|
|
}
|
|
timeOut--;
|
|
}
|
|
}
|
|
|
|
return usart->US_RHR;
|
|
}
|
|
|
|
/**
|
|
* \brief Reads data from an USART peripheral, filling the provided buffer until it
|
|
* becomes full. This function returns immediately with 1 if the buffer has
|
|
* been queued for transmission; otherwise 0.
|
|
*
|
|
* \param usart Pointer to an USART peripheral.
|
|
* \param buffer Pointer to the buffer where the received data will be stored.
|
|
* \param size Size of the data buffer (in bytes).
|
|
*/
|
|
uint8_t USART_ReadBuffer(Usart *usart,
|
|
void *buffer,
|
|
uint32_t size)
|
|
{
|
|
/* Check if the first PDC bank is free*/
|
|
if ((usart->US_RCR == 0) && (usart->US_RNCR == 0)) {
|
|
|
|
usart->US_RPR = (uint32_t) buffer;
|
|
usart->US_RCR = size;
|
|
usart->US_PTCR = US_PTCR_RXTEN;
|
|
|
|
return 1;
|
|
}
|
|
/* Check if the second PDC bank is free*/
|
|
else if (usart->US_RNCR == 0) {
|
|
|
|
usart->US_RNPR = (uint32_t) buffer;
|
|
usart->US_RNCR = size;
|
|
|
|
return 1;
|
|
}
|
|
else {
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* \brief Returns 1 if some data has been received and can be read from an USART;
|
|
* otherwise returns 0.
|
|
*
|
|
* \param usart Pointer to an Usart instance.
|
|
*/
|
|
uint8_t USART_IsDataAvailable(Usart *usart)
|
|
{
|
|
if ((usart->US_CSR & US_CSR_RXRDY) != 0) {
|
|
|
|
return 1;
|
|
}
|
|
else {
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* \brief Sets the filter value for the IRDA demodulator.
|
|
*
|
|
* \param pUsart Pointer to an Usart instance.
|
|
* \param filter Filter value.
|
|
*/
|
|
void USART_SetIrdaFilter(Usart *pUsart, uint8_t filter)
|
|
{
|
|
assert( pUsart != NULL ) ;
|
|
|
|
pUsart->US_IF = filter;
|
|
}
|
|
|
|
/**
|
|
* \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 usart Pointer to an USART peripheral.
|
|
* \param c Character to send
|
|
*/
|
|
void USART_PutChar(
|
|
Usart *usart,
|
|
uint8_t c)
|
|
{
|
|
/* Wait for the transmitter to be ready*/
|
|
while ((usart->US_CSR & US_CSR_TXEMPTY) == 0);
|
|
|
|
/* Send character*/
|
|
usart->US_THR = c;
|
|
|
|
/* Wait for the transfer to complete*/
|
|
while ((usart->US_CSR & US_CSR_TXEMPTY) == 0);
|
|
}
|
|
|
|
/**
|
|
* \brief Return 1 if a character can be read in USART
|
|
*/
|
|
uint32_t USART_IsRxReady(Usart *usart)
|
|
{
|
|
return (usart->US_CSR & US_CSR_RXRDY);
|
|
}
|
|
/**
|
|
* \brief Get present status
|
|
*/
|
|
uint32_t USART_GetStatus(Usart *usart)
|
|
{
|
|
return usart->US_CSR;
|
|
}
|
|
/**
|
|
* \brief Enable interrupt
|
|
*/
|
|
void USART_EnableIt(Usart *usart,uint32_t mode)
|
|
{
|
|
usart->US_IER = mode;
|
|
}
|
|
/**
|
|
* \brief Disable interrupt
|
|
*/
|
|
void USART_DisableIt(Usart *usart,uint32_t mode)
|
|
{
|
|
usart->US_IDR = mode;
|
|
}
|
|
/**
|
|
* \brief Reads and returns a character from the USART.
|
|
*
|
|
* \note This function is synchronous (i.e. uses polling).
|
|
* \param usart Pointer to an USART peripheral.
|
|
* \return Character received.
|
|
*/
|
|
uint8_t USART_GetChar(Usart *usart)
|
|
{
|
|
while ((usart->US_CSR & US_CSR_RXRDY) == 0);
|
|
return usart->US_RHR;
|
|
}
|