mirror of
https://bitbucket.org/librepilot/librepilot.git
synced 2024-12-04 12:24:11 +01:00
3c021c09d9
find ./flight/PiOS/inc/ \! \( -name '*~' -a -prune \) -type f | xargs -I{} bash -c 'echo {}; dos2unix {}; gnuindent -npro -kr -i8 -ts8 -sob -ss -ncs -cp1 -il0 -hnl -l150 {};' git-svn-id: svn://svn.openpilot.org/OpenPilot/trunk@1777 ebee16cc-31ac-478f-84a7-5cbb03baadba
522 lines
14 KiB
C
522 lines
14 KiB
C
/**
|
|
******************************************************************************
|
|
* @addtogroup PIOS PIOS Core hardware abstraction layer
|
|
* @{
|
|
* @addtogroup PIOS_USART USART Functions
|
|
* @brief PIOS interface for USART port
|
|
* @{
|
|
*
|
|
* @file pios_usart.c
|
|
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
|
* Parts by Thorsten Klose (tk@midibox.org) (tk@midibox.org)
|
|
* @brief USART commands. Inits USARTs, controls USARTs & Interupt handlers. (STM32 dependent)
|
|
* @see The GNU Public License (GPL) Version 3
|
|
*
|
|
*****************************************************************************/
|
|
/*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
/* Project Includes */
|
|
#include "pios.h"
|
|
|
|
#if defined(PIOS_INCLUDE_USART)
|
|
|
|
#include <pios_usart_priv.h>
|
|
|
|
/* Provide a COM driver */
|
|
const struct pios_com_driver pios_usart_com_driver = {
|
|
.set_baud = PIOS_USART_ChangeBaud,
|
|
.tx_nb = PIOS_USART_TxBufferPutMoreNonBlocking,
|
|
.tx = PIOS_USART_TxBufferPutMore,
|
|
.rx = PIOS_USART_RxBufferGet,
|
|
.rx_avail = PIOS_USART_RxBufferUsed,
|
|
};
|
|
|
|
static struct pios_usart_dev *find_usart_dev_by_id(uint8_t usart)
|
|
{
|
|
if (usart >= pios_usart_num_devices) {
|
|
/* Undefined USART port for this board (see pios_board.c) */
|
|
return NULL;
|
|
}
|
|
|
|
/* Get a handle for the device configuration */
|
|
return &(pios_usart_devs[usart]);
|
|
}
|
|
|
|
/**
|
|
* Initialise the onboard USARTs
|
|
*/
|
|
void PIOS_USART_Init(void)
|
|
{
|
|
struct pios_usart_dev *usart_dev;
|
|
uint8_t i;
|
|
|
|
for (i = 0; i < pios_usart_num_devices; i++) {
|
|
/* Get a handle for the device configuration */
|
|
usart_dev = find_usart_dev_by_id(i);
|
|
PIOS_DEBUG_Assert(usart_dev);
|
|
|
|
/* Clear buffer counters */
|
|
usart_dev->rx.head = usart_dev->rx.tail = usart_dev->rx.size = 0;
|
|
usart_dev->tx.head = usart_dev->tx.tail = usart_dev->tx.size = 0;
|
|
|
|
/* Enable the USART Pins Software Remapping */
|
|
if (usart_dev->cfg->remap) {
|
|
GPIO_PinRemapConfig(usart_dev->cfg->remap, ENABLE);
|
|
}
|
|
|
|
/* Initialize the USART Rx and Tx pins */
|
|
GPIO_Init(usart_dev->cfg->rx.gpio, &usart_dev->cfg->rx.init);
|
|
GPIO_Init(usart_dev->cfg->tx.gpio, &usart_dev->cfg->tx.init);
|
|
|
|
/* Enable USART clock */
|
|
switch ((uint32_t) usart_dev->cfg->regs) {
|
|
case (uint32_t) USART1:
|
|
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
|
|
break;
|
|
case (uint32_t) USART2:
|
|
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
|
|
break;
|
|
case (uint32_t) USART3:
|
|
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
|
|
break;
|
|
}
|
|
|
|
/* Enable USART */
|
|
USART_Init(usart_dev->cfg->regs, &usart_dev->cfg->init);
|
|
|
|
/* Configure USART Interrupts */
|
|
NVIC_Init(&usart_dev->cfg->irq.init);
|
|
USART_ITConfig(usart_dev->cfg->regs, USART_IT_RXNE, ENABLE);
|
|
USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, ENABLE);
|
|
|
|
/* Enable USART */
|
|
USART_Cmd(usart_dev->cfg->regs, ENABLE);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Changes the baud rate of the USART peripheral without re-initialising.
|
|
* \param[in] usart USART name (GPS, TELEM, AUX)
|
|
* \param[in] baud Requested baud rate
|
|
*/
|
|
void PIOS_USART_ChangeBaud(uint8_t usart, uint32_t baud)
|
|
{
|
|
struct pios_usart_dev *usart_dev;
|
|
USART_InitTypeDef USART_InitStructure;
|
|
|
|
/* Get a handle for the device configuration */
|
|
usart_dev = find_usart_dev_by_id(usart);
|
|
|
|
#if 0
|
|
if (!usart_dev) {
|
|
/* Undefined USART port for this board (see pios_board.c) */
|
|
return -2;
|
|
}
|
|
#endif
|
|
|
|
/* Start with a copy of the default configuration for the peripheral */
|
|
USART_InitStructure = usart_dev->cfg->init;
|
|
|
|
/* Adjust the baud rate */
|
|
USART_InitStructure.USART_BaudRate = baud;
|
|
|
|
/* Write back the new configuration */
|
|
USART_Init(usart_dev->cfg->regs, &USART_InitStructure);
|
|
}
|
|
|
|
/**
|
|
* Returns number of free bytes in receive buffer
|
|
* \param[in] USART USART name
|
|
* \return USART number of free bytes
|
|
* \return 1: USART available
|
|
* \return 0: USART not available
|
|
*/
|
|
int32_t PIOS_USART_RxBufferFree(uint8_t usart)
|
|
{
|
|
struct pios_usart_dev *usart_dev;
|
|
|
|
/* Get a handle for the device configuration */
|
|
usart_dev = find_usart_dev_by_id(usart);
|
|
|
|
if (!usart_dev) {
|
|
/* Undefined USART port for this board (see pios_board.c) */
|
|
return -2;
|
|
}
|
|
|
|
return (sizeof(usart_dev->rx.buf) - usart_dev->rx.size);
|
|
}
|
|
|
|
/**
|
|
* Returns number of used bytes in receive buffer
|
|
* \param[in] USART USART name
|
|
* \return > 0: number of used bytes
|
|
* \return 0 if USART not available
|
|
* \note Applications shouldn't call these functions directly, instead please use \ref PIOS_COM layer functions
|
|
*/
|
|
int32_t PIOS_USART_RxBufferUsed(uint8_t usart)
|
|
{
|
|
struct pios_usart_dev *usart_dev;
|
|
|
|
/* Get a handle for the device configuration */
|
|
usart_dev = find_usart_dev_by_id(usart);
|
|
|
|
if (!usart_dev) {
|
|
/* Undefined USART port for this board (see pios_board.c) */
|
|
return -2;
|
|
}
|
|
|
|
return (usart_dev->rx.size);
|
|
}
|
|
|
|
/**
|
|
* Gets a byte from the receive buffer
|
|
* \param[in] USART USART name
|
|
* \return -1 if USART not available
|
|
* \return -2 if no new byte available
|
|
* \return >= 0: number of received bytes
|
|
* \note Applications shouldn't call these functions directly, instead please use \ref PIOS_COM layer functions
|
|
*/
|
|
int32_t PIOS_USART_RxBufferGet(uint8_t usart)
|
|
{
|
|
struct pios_usart_dev *usart_dev;
|
|
|
|
/* Get a handle for the device configuration */
|
|
usart_dev = find_usart_dev_by_id(usart);
|
|
|
|
if (!usart_dev) {
|
|
/* Undefined USART port for this board (see pios_board.c) */
|
|
return -2;
|
|
}
|
|
|
|
if (!usart_dev->rx.size) {
|
|
/* Nothing new in the buffer */
|
|
return -1;
|
|
}
|
|
|
|
/* get byte - this operation should be atomic! */
|
|
PIOS_IRQ_Disable();
|
|
uint8_t b = usart_dev->rx.buf[usart_dev->rx.tail++];
|
|
if (usart_dev->rx.tail >= sizeof(usart_dev->rx.buf)) {
|
|
usart_dev->rx.tail = 0;
|
|
}
|
|
usart_dev->rx.size--;
|
|
PIOS_IRQ_Enable();
|
|
|
|
/* Return received byte */
|
|
return b;
|
|
}
|
|
|
|
/**
|
|
* Returns the next byte of the receive buffer without taking it
|
|
* \param[in] USART USART name
|
|
* \return -1 if USART not available
|
|
* \return -2 if no new byte available
|
|
* \return >= 0: number of received bytes
|
|
* \note Applications shouldn't call these functions directly, instead please use \ref PIOS_COM layer functions
|
|
*/
|
|
int32_t PIOS_USART_RxBufferPeek(uint8_t usart)
|
|
{
|
|
struct pios_usart_dev *usart_dev;
|
|
|
|
/* Get a handle for the device configuration */
|
|
usart_dev = find_usart_dev_by_id(usart);
|
|
|
|
if (!usart_dev) {
|
|
/* Undefined USART port for this board (see pios_board.c) */
|
|
return -2;
|
|
}
|
|
|
|
if (!usart_dev->rx.size) {
|
|
/* Nothing new in the buffer */
|
|
return -1;
|
|
}
|
|
|
|
/* get byte - this operation should be atomic! */
|
|
PIOS_IRQ_Disable();
|
|
uint8_t b = usart_dev->rx.buf[usart_dev->rx.tail];
|
|
PIOS_IRQ_Enable();
|
|
|
|
/* Return received byte */
|
|
return b;
|
|
}
|
|
|
|
/**
|
|
* puts a byte onto the receive buffer
|
|
* \param[in] USART USART name
|
|
* \param[in] b byte which should be put into Rx buffer
|
|
* \return 0 if no error
|
|
* \return -1 if USART not available
|
|
* \return -2 if buffer full (retry)
|
|
* \note Applications shouldn't call these functions directly, instead please use \ref PIOS_COM layer functions
|
|
*/
|
|
int32_t PIOS_USART_RxBufferPut(uint8_t usart, uint8_t b)
|
|
{
|
|
struct pios_usart_dev *usart_dev;
|
|
|
|
/* Get a handle for the device configuration */
|
|
usart_dev = find_usart_dev_by_id(usart);
|
|
|
|
if (!usart_dev) {
|
|
/* Undefined USART port for this board (see pios_board.c) */
|
|
return -1;
|
|
}
|
|
|
|
if (usart_dev->rx.size >= sizeof(usart_dev->rx.buf)) {
|
|
/* Buffer full (retry) */
|
|
return -2;
|
|
}
|
|
|
|
/* Copy received byte into receive buffer */
|
|
/* This operation should be atomic! */
|
|
PIOS_IRQ_Disable();
|
|
usart_dev->rx.buf[usart_dev->rx.head++] = b;
|
|
if (usart_dev->rx.head >= sizeof(usart_dev->rx.buf)) {
|
|
usart_dev->rx.head = 0;
|
|
}
|
|
usart_dev->rx.size++;
|
|
PIOS_IRQ_Enable();
|
|
|
|
/* No error */
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* returns number of free bytes in transmit buffer
|
|
* \param[in] USART USART name
|
|
* \return number of free bytes
|
|
* \return 0 if USART not available
|
|
* \note Applications shouldn't call these functions directly, instead please use \ref PIOS_COM layer functions
|
|
*/
|
|
int32_t PIOS_USART_TxBufferFree(uint8_t usart)
|
|
{
|
|
struct pios_usart_dev *usart_dev;
|
|
|
|
/* Get a handle for the device configuration */
|
|
usart_dev = find_usart_dev_by_id(usart);
|
|
|
|
if (!usart_dev) {
|
|
/* Undefined USART port for this board (see pios_board.c) */
|
|
return 0;
|
|
}
|
|
|
|
return (sizeof(usart_dev->tx.buf) - usart_dev->tx.size);
|
|
}
|
|
|
|
/**
|
|
* returns number of used bytes in transmit buffer
|
|
* \param[in] USART USART name
|
|
* \return number of used bytes
|
|
* \return 0 if USART not available
|
|
* \note Applications shouldn't call these functions directly, instead please use \ref PIOS_COM layer functions
|
|
*/
|
|
int32_t PIOS_USART_TxBufferUsed(uint8_t usart)
|
|
{
|
|
struct pios_usart_dev *usart_dev;
|
|
|
|
/* Get a handle for the device configuration */
|
|
usart_dev = find_usart_dev_by_id(usart);
|
|
|
|
if (!usart_dev) {
|
|
/* Undefined USART port for this board (see pios_board.c) */
|
|
return 0;
|
|
}
|
|
|
|
return (usart_dev->tx.size);
|
|
}
|
|
|
|
/**
|
|
* gets a byte from the transmit buffer
|
|
* \param[in] USART USART name
|
|
* \return -1 if USART not available
|
|
* \return -2 if no new byte available
|
|
* \return >= 0: transmitted byte
|
|
* \note Applications shouldn't call these functions directly, instead please use \ref PIOS_COM layer functions
|
|
*/
|
|
int32_t PIOS_USART_TxBufferGet(uint8_t usart)
|
|
{
|
|
struct pios_usart_dev *usart_dev;
|
|
|
|
/* Get a handle for the device configuration */
|
|
usart_dev = find_usart_dev_by_id(usart);
|
|
|
|
if (!usart_dev) {
|
|
/* Undefined USART port for this board (see pios_board.c) */
|
|
return -1;
|
|
}
|
|
|
|
if (!usart_dev->tx.size) {
|
|
/* Nothing new in the buffer */
|
|
return -2;
|
|
}
|
|
|
|
/* get byte - this operation should be atomic! */
|
|
PIOS_IRQ_Disable();
|
|
uint8_t b = usart_dev->tx.buf[usart_dev->tx.tail++];
|
|
if (usart_dev->tx.tail >= sizeof(usart_dev->tx.buf)) {
|
|
usart_dev->tx.tail = 0;
|
|
}
|
|
usart_dev->tx.size--;
|
|
PIOS_IRQ_Enable();
|
|
|
|
/* Return received byte */
|
|
return b;
|
|
}
|
|
|
|
/**
|
|
* puts more than one byte onto the transmit buffer (used for atomic sends)
|
|
* \param[in] USART USART name
|
|
* \param[in] *buffer pointer to buffer to be sent
|
|
* \param[in] len number of bytes to be sent
|
|
* \return 0 if no error
|
|
* \return -1 if USART not available
|
|
* \return -2 if buffer full or cannot get all requested bytes (retry)
|
|
* \return -3 if USART not supported by USARTTxBufferPut Routine
|
|
* \note Applications shouldn't call these functions directly, instead please use \ref PIOS_COM layer functions
|
|
*/
|
|
int32_t PIOS_USART_TxBufferPutMoreNonBlocking(uint8_t usart, const uint8_t * buffer, uint16_t len)
|
|
{
|
|
struct pios_usart_dev *usart_dev;
|
|
|
|
/* Get a handle for the device configuration */
|
|
usart_dev = find_usart_dev_by_id(usart);
|
|
|
|
if (!usart_dev) {
|
|
/* Undefined USART port for this board (see pios_board.c) */
|
|
return -1;
|
|
}
|
|
|
|
if (usart_dev->tx.size + len >= sizeof(usart_dev->tx.buf)) {
|
|
/* Buffer cannot accept all requested bytes (retry) */
|
|
return -2;
|
|
}
|
|
|
|
/* Copy bytes to be transmitted into transmit buffer */
|
|
/* This operation should be atomic! */
|
|
PIOS_IRQ_Disable();
|
|
|
|
uint16_t i;
|
|
for (i = 0; i < len; ++i) {
|
|
usart_dev->tx.buf[usart_dev->tx.head++] = *buffer++;
|
|
if (usart_dev->tx.head >= sizeof(usart_dev->tx.buf)) {
|
|
usart_dev->tx.head = 0;
|
|
}
|
|
|
|
usart_dev->tx.size++;
|
|
if (usart_dev->tx.size == 1) {
|
|
/* Buffer has just become non-empty, enable tx interrupt. */
|
|
USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, ENABLE);
|
|
}
|
|
}
|
|
|
|
PIOS_IRQ_Enable();
|
|
|
|
/* No error */
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* puts more than one byte onto the transmit buffer (used for atomic sends)<BR>
|
|
* (blocking function)
|
|
* \param[in] USART USART name
|
|
* \param[in] *buffer pointer to buffer to be sent
|
|
* \param[in] len number of bytes to be sent
|
|
* \return 0 if no error
|
|
* \return -1 if USART not available
|
|
* \return -3 if USART not supported by USARTTxBufferPut Routine
|
|
* \note Applications shouldn't call these functions directly, instead please use \ref PIOS_COM layer functions
|
|
*/
|
|
int32_t PIOS_USART_TxBufferPutMore(uint8_t usart, const uint8_t * buffer, uint16_t len)
|
|
{
|
|
int32_t rc;
|
|
|
|
while ((rc = PIOS_USART_TxBufferPutMoreNonBlocking(usart, buffer, len)) == -2) ;
|
|
|
|
return rc;
|
|
}
|
|
|
|
/**
|
|
* puts a byte onto the transmit buffer
|
|
* \param[in] USART USART name
|
|
* \param[in] b byte which should be put into Tx buffer
|
|
* \return 0 if no error
|
|
* \return -1 if USART not available
|
|
* \return -2 if buffer full (retry)
|
|
* \return -3 if USART not supported by USARTTxBufferPut Routine
|
|
* \note Applications shouldn't call these functions directly, instead please use \ref PIOS_COM layer functions
|
|
*/
|
|
int32_t PIOS_USART_TxBufferPut_NonBlocking(uint8_t usart, uint8_t b)
|
|
{
|
|
return PIOS_USART_TxBufferPutMoreNonBlocking(usart, &b, 1);
|
|
}
|
|
|
|
/**
|
|
* puts a byte onto the transmit buffer<BR>
|
|
* (blocking function)
|
|
* \param[in] USART USART name
|
|
* \param[in] b byte which should be put into Tx buffer
|
|
* \return 0 if no error
|
|
* \return -1 if USART not available
|
|
* \return -3 if USART not supported by USARTTxBufferPut Routine
|
|
* \note Applications shouldn't call these functions directly, instead please use \ref PIOS_COM layer functions
|
|
*/
|
|
int32_t PIOS_USART_TxBufferPut(uint8_t usart, uint8_t b)
|
|
{
|
|
return PIOS_USART_TxBufferPutMore(usart, &b, 1);
|
|
}
|
|
|
|
void PIOS_USART_IRQ_Handler(uint8_t usart)
|
|
{
|
|
struct pios_usart_dev *usart_dev;
|
|
|
|
/* Get a handle for the device configuration */
|
|
usart_dev = find_usart_dev_by_id(usart);
|
|
PIOS_DEBUG_Assert(usart_dev);
|
|
|
|
/* Check if RXNE flag is set */
|
|
if (usart_dev->cfg->regs->SR & USART_SR_RXNE) {
|
|
uint8_t b = usart_dev->cfg->regs->DR;
|
|
|
|
if (PIOS_USART_RxBufferPut(usart, b) < 0) {
|
|
/* Here we could add some error handling */
|
|
}
|
|
}
|
|
|
|
/* Check if TXE flag is set */
|
|
if (usart_dev->cfg->regs->SR & USART_SR_TXE) {
|
|
if (PIOS_USART_TxBufferUsed(usart) > 0) {
|
|
int32_t b = PIOS_USART_TxBufferGet(usart);
|
|
|
|
if (b < 0) {
|
|
/* Here we could add some error handling */
|
|
usart_dev->cfg->regs->DR = 0xff;
|
|
} else {
|
|
usart_dev->cfg->regs->DR = b & 0xff;
|
|
}
|
|
} else {
|
|
/* Disable TXE interrupt (TXEIE=0) */
|
|
USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, DISABLE);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/**
|
|
* @}
|
|
* @}
|
|
*/
|