📄 hal_uart.c
字号:
/**************************************************************************************************
Filename: _hal_uart.c
Revised: $Date: 2007-11-01 08:44:53 -0700 (Thu, 01 Nov 2007) $
Revision: $Revision: 15821 $
Description: This file contains the interface to the H/W UART driver.
Copyright 2006-2007 Texas Instruments Incorporated. All rights reserved.
IMPORTANT: Your use of this Software is limited to those specific rights
granted under the terms of a software license agreement between the user
who downloaded the software, his/her employer (which must be your employer)
and Texas Instruments Incorporated (the "License"). You may not use this
Software unless you agree to abide by the terms of the License. The License
limits your use, and you acknowledge, that the Software may not be modified,
copied or distributed unless embedded on a Texas Instruments microcontroller
or used solely and exclusively in conjunction with a Texas Instruments radio
frequency transceiver, which is integrated into your product. Other than for
the foregoing purpose, you may not use, reproduce, copy, prepare derivative
works of, modify, distribute, perform, display or sell this Software and/or
its documentation for any purpose.
YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE
PROVIDED 揂S IS?WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,
INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE,
NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL
TEXAS INSTRUMENTS OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT,
NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER
LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE
OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT
OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
(INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.
Should you have any questions regarding your right to use this Software,
contact Texas Instruments Incorporated at www.TI.com.
**************************************************************************************************/
/*********************************************************************
* INCLUDES
*/
#include "hal_types.h"
#include "hal_assert.h"
#include "hal_board.h"
#include "hal_defs.h"
#if defined( HAL_UART_DMA ) && HAL_UART_DMA
#include "hal_dma.h"
#endif
#include "hal_mcu.h"
#include "hal_uart.h"
#include "osal.h"
/*********************************************************************
* MACROS
*/
#if !defined ( HAL_UART_DEBUG )
#define HAL_UART_DEBUG FALSE
#endif
#if !defined ( HAL_UART_CLOSE )
#define HAL_UART_CLOSE FALSE
#endif
#if !defined ( HAL_UART_BIG_TX_BUF )
#define HAL_UART_BIG_TX_BUF FALSE
#endif
/*
* The MAC_ASSERT macro is for use during debugging.
* The given expression must evaluate as "true" or else fatal error occurs.
* At that point, the call stack feature of the debugger can pinpoint where
* the problem occurred.
*
* To disable this feature and save code size, the project should define
* HAL_UART_DEBUG to FALSE.
*/
#if ( HAL_UART_DEBUG )
#define HAL_UART_ASSERT( expr) HAL_ASSERT( expr )
#else
#define HAL_UART_ASSERT( expr )
#endif
#define P2DIR_PRIPO 0xC0
#if HAL_UART_0_ENABLE
#define HAL_UART_PRIPO 0x00
#else
#define HAL_UART_PRIPO 0x40
#endif
#define HAL_UART_0_PERCFG_BIT 0x01 // USART0 on P0, so clear this bit.
#define HAL_UART_0_P0_RX_TX 0x0c // Peripheral I/O Select for Rx/Tx.
#define HAL_UART_0_P0_RTS 0x10 // Peripheral I/O Select for RTS.
#define HAL_UART_0_P0_CTS 0x20 // Peripheral I/O Select for CTS.
#define HAL_UART_1_PERCFG_BIT 0x02 // USART1 on P1, so set this bit.
#define HAL_UART_1_P1_RTS 0x10 // Peripheral I/O Select for RTS.
#define HAL_UART_1_P1_CTS 0x20 // Peripheral I/O Select for CTS.
#define HAL_UART_1_P1_RX_TX 0xC0 // Peripheral I/O Select for Rx/Tx.
#define TX_AVAIL( cfg ) \
((cfg->txTail == cfg->txHead) ? (cfg->txMax-1) : \
((cfg->txTail > cfg->txHead) ? (cfg->txTail - cfg->txHead - 1) : \
(cfg->txMax - cfg->txHead + cfg->txTail)))
#define RX0_FLOW_ON ( P0 &= ~HAL_UART_0_P0_CTS )
#define RX0_FLOW_OFF ( P0 |= HAL_UART_0_P0_CTS )
#define RX1_FLOW_ON ( P1 &= ~HAL_UART_1_P1_CTS)
#define RX1_FLOW_OFF ( P1 |= HAL_UART_1_P1_CTS )
#define RX_STOP_FLOW( cfg ) { \
if ( !(cfg->flag & UART_CFG_U1F) ) \
{ \
RX0_FLOW_OFF; \
} \
else \
{ \
RX1_FLOW_OFF; \
} \
if ( cfg->flag & UART_CFG_DMA ) \
{ \
cfg->rxTick = DMA_RX_DLY; \
} \
cfg->flag |= UART_CFG_RXF; \
}
#define RX_STRT_FLOW( cfg ) { \
if ( !(cfg->flag & UART_CFG_U1F) ) \
{ \
RX0_FLOW_ON; \
} \
else \
{ \
RX1_FLOW_ON; \
} \
cfg->flag &= ~UART_CFG_RXF; \
}
#define UART_RX_AVAIL( cfg ) \
( (cfg->rxHead >= cfg->rxTail) ? (cfg->rxHead - cfg->rxTail) : \
(cfg->rxMax - cfg->rxTail + cfg->rxHead +1 ) )
/* Need to leave enough of the Rx buffer free to handle the incoming bytes
* after asserting flow control, but before the transmitter has obeyed it.
* At the max expected baud rate of 115.2k, 16 bytes will only take ~1.3 msecs,
* but at the min expected baud rate of 38.4k, they could take ~4.2 msecs.
* SAFE_RX_MIN and DMA_RX_DLY must both be consistent according to
* the min & max expected baud rate.
*/
#if !defined( SAFE_RX_MIN )
#define SAFE_RX_MIN 48 // bytes - max expected per poll @ 115.2k
// 16 bytes @ 38.4 kBaud -> 4.16 msecs -> 138 32-kHz ticks.
#define DMA_RX_DLY 140
// 2 bytes @ 38.4 kBaud -> 0.52 msecs -> 17 32-kHz ticks.
#define DMA_TX_DLY 20
#endif
// The timeout tick is at 32-kHz, so multiply msecs by 33.
#define RX_MSECS_TO_TICKS 33
// The timeout only supports 1 byte.
#if !defined( HAL_UART_RX_IDLE )
#define HAL_UART_RX_IDLE (6 * RX_MSECS_TO_TICKS)
#endif
// Only supporting 1 of the 2 USART modules to be driven by DMA at a time.
#if HAL_UART_DMA == 1
#define DMATRIG_RX HAL_DMA_TRIG_URX0
#define DMATRIG_TX HAL_DMA_TRIG_UTX0
#define DMA_UDBUF HAL_DMA_U0DBUF
#define DMA_PAD U0BAUD
#elif HAL_UART_DMA == 2
#define DMATRIG_RX HAL_DMA_TRIG_URX1
#define DMATRIG_TX HAL_DMA_TRIG_UTX1
#define DMA_UDBUF HAL_DMA_U1DBUF
#define DMA_PAD U1BAUD
#endif
#define DMA_RX( cfg ) { \
volatile uint8 ft2430 = U0DBUF; \
\
halDMADesc_t *ch = HAL_DMA_GET_DESC1234( HAL_DMA_CH_RX ); \
\
HAL_DMA_SET_DEST( ch, cfg->rxBuf ); \
\
HAL_DMA_SET_LEN( ch, cfg->rxMax ); \
\
HAL_DMA_CLEAR_IRQ( HAL_DMA_CH_RX ); \
\
HAL_DMA_ARM_CH( HAL_DMA_CH_RX ); \
}
#define DMA_TX( cfg ) { \
halDMADesc_t *ch = HAL_DMA_GET_DESC1234( HAL_DMA_CH_TX ); \
\
HAL_DMA_SET_SOURCE( ch, (cfg->txBuf + cfg->txTail) ); \
\
HAL_DMA_SET_LEN( ch, cfg->txCnt ); \
\
HAL_DMA_CLEAR_IRQ( HAL_DMA_CH_TX ); \
\
HAL_DMA_ARM_CH( HAL_DMA_CH_TX ); \
\
HAL_DMA_START_CH( HAL_DMA_CH_TX ); \
}
/*********************************************************************
* TYPEDEFS
*/
typedef struct
{
uint8 *rxBuf;
uint8 rxHead;
uint8 rxTail;
uint8 rxMax;
uint8 rxCnt;
uint8 rxTick;
uint8 rxHigh;
uint8 *txBuf;
#if HAL_UART_BIG_TX_BUF
uint16 txHead;
uint16 txTail;
uint16 txMax;
uint16 txCnt;
#else
uint8 txHead;
uint8 txTail;
uint8 txMax;
uint8 txCnt;
#endif
uint8 txTick;
uint8 flag;
halUARTCBack_t rxCB;
} uartCfg_t;
/*********************************************************************
* CONSTANTS
*/
// Used by DMA macros to shift 1 to create a mask for DMA registers.
#define HAL_DMA_CH_TX 3
#define HAL_DMA_CH_RX 4
#define HAL_DMA_U0DBUF 0xDFC1
#define HAL_DMA_U1DBUF 0xDFF9
// UxCSR - USART Control and Status Register.
#define CSR_MODE 0x80
#define CSR_RE 0x40
#define CSR_SLAVE 0x20
#define CSR_FE 0x10
#define CSR_ERR 0x08
#define CSR_RX_BYTE 0x04
#define CSR_TX_BYTE 0x02
#define CSR_ACTIVE 0x01
// UxUCR - USART UART Control Register.
#define UCR_FLUSH 0x80
#define UCR_FLOW 0x40
#define UCR_D9 0x20
#define UCR_BIT9 0x10
#define UCR_PARITY 0x08
#define UCR_SPB 0x04
#define UCR_STOP 0x02
#define UCR_START 0x01
#define UTX0IE 0x04
#define UTX1IE 0x08
#define UART_CFG_U1F 0x80 // USART1 flag bit.
#define UART_CFG_DMA 0x40 // Port is using DMA.
#define UART_CFG_FLW 0x20 // Port is using flow control.
#define UART_CFG_SP4 0x10
#define UART_CFG_SP3 0x08
#define UART_CFG_SP2 0x04
#define UART_CFG_RXF 0x02 // Rx flow is disabled.
#define UART_CFG_TXF 0x01 // Tx is in process.
/*********************************************************************
* GLOBAL VARIABLES
*/
/*********************************************************************
* GLOBAL FUNCTIONS
*/
/*********************************************************************
* LOCAL VARIABLES
*/
#if HAL_UART_0_ENABLE
static uartCfg_t *cfg0;
#endif
#if HAL_UART_1_ENABLE
static uartCfg_t *cfg1;
#endif
/*********************************************************************
* LOCAL FUNCTIONS
*/
#if HAL_UART_DMA
static void pollDMA( uartCfg_t *cfg );
#endif
#if HAL_UART_ISR
static void pollISR( uartCfg_t *cfg );
#endif
#if HAL_UART_DMA
/******************************************************************************
* @fn pollDMA
*
* @brief Poll a USART module implemented by DMA.
*
* @param cfg - USART configuration structure.
*
* @return none
*****************************************************************************/
static void pollDMA( uartCfg_t *cfg )
{
const uint8 cnt = cfg->rxHead;
uint8 *pad = cfg->rxBuf+(cfg->rxHead*2);
// Pack the received bytes to the front of the queue.
while ( (*pad == DMA_PAD) && (cfg->rxHead < cfg->rxMax) )
{
cfg->rxBuf[cfg->rxHead++] = *(pad+1);
pad += 2;
}
if ( !(cfg->flag & UART_CFG_RXF) )
{
/* It is necessary to stop Rx flow and wait for H/W-enqueued bytes still
* incoming to stop before resetting the DMA Rx engine. If DMA Rx is
* aborted during incoming data, a byte may be lost inside the engine
* during the 2-step transfer process of read/write.
*/
if ( cfg->rxHead >= (cfg->rxMax - SAFE_RX_MIN) )
{
RX_STOP_FLOW( cfg );
}
// If anything received, reset the Rx idle timer.
else if ( cfg->rxHead != cnt )
{
cfg->rxTick = HAL_UART_RX_IDLE;
}
}
else if ( !cfg->rxTick && (cfg->rxHead == cfg->rxTail) )
{
HAL_DMA_ABORT_CH( HAL_DMA_CH_RX );
cfg->rxHead = cfg->rxTail = 0;
osal_memset( cfg->rxBuf, ~DMA_PAD, cfg->rxMax*2 );
DMA_RX( cfg );
RX_STRT_FLOW( cfg );
}
if ( HAL_DMA_CHECK_IRQ( HAL_DMA_CH_TX ) )
{
HAL_DMA_CLEAR_IRQ( HAL_DMA_CH_TX );
cfg->flag &= ~UART_CFG_TXF;
cfg->txTick = DMA_TX_DLY;
if ( (cfg->txMax - cfg->txCnt) < cfg->txTail )
{
cfg->txTail = 0; // DMA can only run to the end of the Tx buffer.
}
else
{
cfg->txTail += cfg->txCnt;
}
}
else if ( !(cfg->flag & UART_CFG_TXF) && !cfg->txTick )
{
if ( cfg->txTail != cfg->txHead )
{
if ( cfg->txTail < cfg->txHead )
{
cfg->txCnt = cfg->txHead - cfg->txTail;
}
else // Can only run DMA engine up to max, then restart at zero.
{
cfg->txCnt = cfg->txMax - cfg->txTail + 1;
}
cfg->flag |= UART_CFG_TXF;
DMA_TX( cfg );
}
}
}
#endif
#if HAL_UART_ISR
/******************************************************************************
* @fn pollISR
*
* @brief Poll a USART module implemented by ISR.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -