📄 hal_uart.c
字号:
*
* @param cfg - USART configuration structure.
*
* @return none
*****************************************************************************/
static void pollISR( uartCfg_t *cfg )
{
uint8 cnt = UART_RX_AVAIL( cfg );
if ( !(cfg->flag & UART_CFG_RXF) )
{
// If anything received, reset the Rx idle timer.
if ( cfg->rxCnt != cnt )
{
cfg->rxTick = HAL_UART_RX_IDLE;
cfg->rxCnt = cnt;
}
/* It is necessary to stop Rx flow in advance of a full Rx buffer because
* bytes can keep coming while sending H/W fifo flushes.
*/
if ( cfg->rxCnt >= (cfg->rxMax - SAFE_RX_MIN) )
{
RX_STOP_FLOW( cfg );
}
}
}
#endif
/******************************************************************************
* @fn HalUARTInit
*
* @brief Initialize the UART
*
* @param none
*
* @return none
*****************************************************************************/
void HalUARTInit( void )
{
#if HAL_UART_DMA
halDMADesc_t *ch;
#endif
// Set P2 priority - USART0 over USART1 if both are defined.
P2DIR &= ~P2DIR_PRIPO;
P2DIR |= HAL_UART_PRIPO;
#if HAL_UART_0_ENABLE
// Set UART0 I/O location to P0.
PERCFG &= ~HAL_UART_0_PERCFG_BIT;
/* Enable Tx and Rx on P0 */
P0SEL |= HAL_UART_0_P0_RX_TX;
/* Make sure ADC doesnt use this */
ADCCFG &= ~HAL_UART_0_P0_RX_TX;
/* Mode is UART Mode */
U0CSR = CSR_MODE;
/* Flush it */
U0UCR = UCR_FLUSH;
#endif
#if HAL_UART_1_ENABLE
// Set UART1 I/O location to P1.
PERCFG |= HAL_UART_1_PERCFG_BIT;
/* Enable Tx and Rx on P1 */
P1SEL |= HAL_UART_1_P1_RX_TX;
/* Make sure ADC doesnt use this */
ADCCFG &= ~HAL_UART_1_P1_RX_TX;
/* Mode is UART Mode */
U1CSR = CSR_MODE;
/* Flush it */
U1UCR = UCR_FLUSH;
#endif
#if HAL_UART_DMA
// Setup Tx by DMA.
ch = HAL_DMA_GET_DESC1234( HAL_DMA_CH_TX );
// The start address of the destination.
HAL_DMA_SET_DEST( ch, DMA_UDBUF );
// Using the length field to determine how many bytes to transfer.
HAL_DMA_SET_VLEN( ch, HAL_DMA_VLEN_USE_LEN );
// One byte is transferred each time.
HAL_DMA_SET_WORD_SIZE( ch, HAL_DMA_WORDSIZE_BYTE );
// The bytes are transferred 1-by-1 on Tx Complete trigger.
HAL_DMA_SET_TRIG_MODE( ch, HAL_DMA_TMODE_SINGLE );
HAL_DMA_SET_TRIG_SRC( ch, DMATRIG_TX );
// The source address is decremented by 1 byte after each transfer.
HAL_DMA_SET_SRC_INC( ch, HAL_DMA_SRCINC_1 );
// The destination address is constant - the Tx Data Buffer.
HAL_DMA_SET_DST_INC( ch, HAL_DMA_DSTINC_0 );
// The DMA is to be polled and shall not issue an IRQ upon completion.
HAL_DMA_SET_IRQ( ch, HAL_DMA_IRQMASK_DISABLE );
// Xfer all 8 bits of a byte xfer.
HAL_DMA_SET_M8( ch, HAL_DMA_M8_USE_8_BITS );
// DMA Tx has shared priority for memory access - every other one.
HAL_DMA_SET_PRIORITY( ch, HAL_DMA_PRI_HIGH );
// Setup Rx by DMA.
ch = HAL_DMA_GET_DESC1234( HAL_DMA_CH_RX );
// The start address of the source.
HAL_DMA_SET_SOURCE( ch, DMA_UDBUF );
// Using the length field to determine how many bytes to transfer.
HAL_DMA_SET_VLEN( ch, HAL_DMA_VLEN_USE_LEN );
/* The trick is to cfg DMA to xfer 2 bytes for every 1 byte of Rx.
* The byte after the Rx Data Buffer is the Baud Cfg Register,
* which always has a known value. So init Rx buffer to inverse of that
* known value. DMA word xfer will flip the bytes, so every valid Rx byte
* in the Rx buffer will be preceded by a DMA_PAD char equal to the
* Baud Cfg Register value.
*/
HAL_DMA_SET_WORD_SIZE( ch, HAL_DMA_WORDSIZE_WORD );
// The bytes are transferred 1-by-1 on Rx Complete trigger.
HAL_DMA_SET_TRIG_MODE( ch, HAL_DMA_TMODE_SINGLE );
HAL_DMA_SET_TRIG_SRC( ch, DMATRIG_RX );
// The source address is constant - the Rx Data Buffer.
HAL_DMA_SET_SRC_INC( ch, HAL_DMA_SRCINC_0 );
// The destination address is incremented by 1 word after each transfer.
HAL_DMA_SET_DST_INC( ch, HAL_DMA_DSTINC_1 );
// The DMA is to be polled and shall not issue an IRQ upon completion.
HAL_DMA_SET_IRQ( ch, HAL_DMA_IRQMASK_DISABLE );
// Xfer all 8 bits of a byte xfer.
HAL_DMA_SET_M8( ch, HAL_DMA_M8_USE_8_BITS );
// DMA has highest priority for memory access.
HAL_DMA_SET_PRIORITY( ch, HAL_DMA_PRI_HIGH );
#endif
}
/******************************************************************************
* @fn HalUARTOpen
*
* @brief Open a port according tp the configuration specified by parameter.
*
* @param port - UART port
* config - contains configuration information
*
* @return Status of the function call
*****************************************************************************/
uint8 HalUARTOpen( uint8 port, halUARTCfg_t *config )
{
uartCfg_t **cfgPP = NULL;
uartCfg_t *cfg;
#if HAL_UART_0_ENABLE
if ( port == HAL_UART_PORT_0 )
{
cfgPP = &cfg0;
}
#endif
#if HAL_UART_1_ENABLE
if ( port == HAL_UART_PORT_1 )
{
cfgPP = &cfg1;
}
#endif
HAL_UART_ASSERT( cfgPP );
#if HAL_UART_CLOSE
// Protect against user re-opening port before closing it.
HalUARTClose( port );
#else
HAL_UART_ASSERT( *cfgPP == NULL );
#endif
HAL_UART_ASSERT( (config->baudRate == HAL_UART_BR_38400) ||
(config->baudRate == HAL_UART_BR_115200) );
/* Whereas runtime heap alloc can be expected to fail - one-shot system
* initialization must succeed, so no check for alloc fail.
*/
*cfgPP = (uartCfg_t *)osal_mem_alloc( sizeof( uartCfg_t ) );
cfg = *cfgPP;
HAL_UART_ASSERT( cfg );
cfg->rxMax = config->rx.maxBufSize;
#if !HAL_UART_BIG_TX_BUF
HAL_UART_ASSERT( (config->tx.maxBufSize < 256) );
#endif
cfg->txMax = config->tx.maxBufSize;
cfg->txBuf = osal_mem_alloc( cfg->txMax+1 );
cfg->rxHead = cfg->rxTail = 0;
cfg->txHead = cfg->txTail = 0;
cfg->rxHigh = config->rx.maxBufSize - config->flowControlThreshold;
cfg->rxCB = config->callBackFunc;
#if HAL_UART_0_ENABLE
if ( port == HAL_UART_PORT_0 )
{
// Only supporting 38400 or 115200 for code size - other is possible.
U0BAUD = (config->baudRate == HAL_UART_BR_38400) ? 59 : 216;
U0GCR = (config->baudRate == HAL_UART_BR_38400) ? 10 : 11;
U0CSR |= CSR_RE;
#if HAL_UART_DMA == 1
cfg->flag = UART_CFG_DMA;
HAL_UART_ASSERT( (config->rx.maxBufSize <= 128) );
HAL_UART_ASSERT( (config->rx.maxBufSize > SAFE_RX_MIN) );
cfg->rxBuf = osal_mem_alloc( cfg->rxMax*2 );
osal_memset( cfg->rxBuf, ~DMA_PAD, cfg->rxMax*2 );
DMA_RX( cfg );
#else
cfg->flag = 0;
HAL_UART_ASSERT( (config->rx.maxBufSize < 256) );
cfg->rxBuf = osal_mem_alloc( cfg->rxMax+1 );
URX0IE = 1;
IEN2 |= UTX0IE;
#endif
// 8 bits/char; no parity; 1 stop bit; stop bit hi.
if ( config->flowControl )
{
cfg->flag |= UART_CFG_FLW;
U0UCR = UCR_STOP; //UCR_FLOW |
// Must rely on H/W for RTS (i.e. Tx stops when receiver negates CTS.)
//P0SEL |= HAL_UART_0_P0_RTS;
// Cannot use H/W for CTS as DMA does not clear the Rx bytes properly.
//P0DIR |= HAL_UART_0_P0_CTS;
//RX0_FLOW_ON;
}
else
{
U0UCR = UCR_STOP;
}
}
#endif
#if HAL_UART_1_ENABLE
if ( port == HAL_UART_PORT_1 )
{
// Only supporting 38400 or 115200 for code size - other is possible.
U1BAUD = (config->baudRate == HAL_UART_BR_38400) ? 59 : 216;
U1GCR = (config->baudRate == HAL_UART_BR_38400) ? 10 : 11;
U1CSR |= CSR_RE;
#if HAL_UART_DMA == 2
cfg->flag = (UART_CFG_U1F | UART_CFG_DMA);
HAL_UART_ASSERT( (config->rx.maxBufSize <= 128) );
HAL_UART_ASSERT( (config->rx.maxBufSize > SAFE_RX_MIN) );
cfg->rxBuf = osal_mem_alloc( cfg->rxMax*2 );
osal_memset( cfg->rxBuf, ~DMA_PAD, cfg->rxMax*2 );
DMA_RX( cfg );
#else
cfg->flag = UART_CFG_U1F;
HAL_UART_ASSERT( (config->rx.maxBufSize < 256) );
cfg->rxBuf = osal_mem_alloc( cfg->rxMax+1 );
URX1IE = 1;
IEN2 |= UTX1IE;
#endif
// 8 bits/char; no parity; 1 stop bit; stop bit hi.
if ( config->flowControl )
{
cfg->flag |= UART_CFG_FLW;
U1UCR = UCR_STOP; //UCR_FLOW |
// Must rely on H/W for RTS (i.e. Tx stops when receiver negates CTS.)
//P1SEL |= HAL_UART_1_P1_RTS;
// Cannot use H/W for CTS as DMA does not clear the Rx bytes properly.
// P1DIR |= HAL_UART_1_P1_CTS;
//RX1_FLOW_ON;
}
else
{
U1UCR = UCR_STOP;
}
}
#endif
return HAL_UART_SUCCESS;
}
/******************************************************************************
* @fn HalUARTClose
*
* @brief Close the UART
*
* @param port - UART port
*
* @return none
*****************************************************************************/
void HalUARTClose( uint8 port )
{
#if HAL_UART_CLOSE
uartCfg_t *cfg;
#if HAL_UART_0_ENABLE
if ( port == HAL_UART_PORT_0 )
{
U0CSR &= ~CSR_RE;
#if HAL_UART_DMA == 1
HAL_DMA_ABORT_CH( HAL_DMA_CH_RX );
HAL_DMA_ABORT_CH( HAL_DMA_CH_TX );
#else
URX0IE = 0;
#endif
cfg = cfg0;
cfg0 = NULL;
}
#endif
#if HAL_UART_1_ENABLE
if ( port == HAL_UART_PORT_1 )
{
U1CSR &= ~CSR_RE;
#if HAL_UART_DMA == 2
HAL_DMA_ABORT_CH( HAL_DMA_CH_RX );
HAL_DMA_ABORT_CH( HAL_DMA_CH_TX );
#else
URX1IE = 0;
#endif
cfg = cfg1;
cfg1 = NULL;
}
#endif
if ( cfg )
{
if ( cfg->rxBuf )
{
osal_mem_free( cfg->rxBuf );
}
if ( cfg->txBuf )
{
osal_mem_free( cfg->txBuf );
}
osal_mem_free( cfg );
}
#endif
}
/******************************************************************************
* @fn HalUARTPoll
*
* @brief Poll the UART.
*
* @param none
*
* @return none
*****************************************************************************/
void HalUARTPoll( void )
{
#if ( HAL_UART_0_ENABLE | HAL_UART_1_ENABLE )
static uint8 tickShdw;
uartCfg_t *cfg;
uint8 tick;
#if HAL_UART_0_ENABLE
if ( cfg0 )
{
cfg = cfg0;
}
#endif
#if HAL_UART_1_ENABLE
if ( cfg1 )
{
cfg = cfg1;
}
#endif
// Use the LSB of the sleep timer (ST0 must be read first anyway).
tick = ST0 - tickShdw;
tickShdw = ST0;
do
{
if ( cfg->txTick > tick )
{
cfg->txTick -= tick;
}
else
{
cfg->txTick = 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -