📄 serial.c
字号:
error = ERR_MEM;
}
else if( dev->rx_sem == ( xSemaphoreHandle ) 0 )
{
error = ERR_MEM;
}
else
{
/* UART parameter correct and hardware device available. */
UART_OnOffConfig( dev->UARTx, ENABLE );
UART_FifoConfig( dev->UARTx, ENABLE );
UART_FifoReset( dev->UARTx, UART_RxFIFO );
UART_FifoReset( dev->UARTx, UART_TxFIFO );
UART_LoopBackConfig( dev->UARTx, DISABLE );
UART_Config( dev->UARTx, baudrate, eUARTParity, eUARTStopBits, eUARTMode );
UART_TimeOutPeriodConfig( dev->UARTx, 0xFF );
UART_ItConfig( dev->UARTx, UART_RxBufFull, ENABLE );
UART_RxConfig( dev->UARTx, ENABLE );
/* Device is now ready for use. */
dev->ready = 1;
}
if( error != ERR_OK )
{
sio_close( dev );
}
vPortExitCritical( );
}
}
else
{
error = ERR_VAL;
}
return error == ERR_OK ? ( void * )dev : SIO_FD_NULL;
}
sio_fd_t
sio_open( u8_t devnr )
{
return sio_open_new( devnr, DEFAULT_BAUDRATE, DEFAULT_DATABITS,
DEFAULT_STOPBITS, DEFAULT_PARITY );
}
void
sio_send_noisr( u8_t data, sio_fd_t fd )
{
serdev_t *dev = fd;
if( dev->ready )
{
UART_ByteSend( dev->UARTx, &data );
}
}
u32_t
sio_write_noisr( sio_fd_t fd, u8_t * buf, u32_t size )
{
u32_t left = size;
u8_t send;
serdev_t *dev = fd;
if( dev->ready )
{
left = size;
while( left > 0 )
{
send = size % 256;
UART_DataSend( dev->UARTx, ( u8 * ) buf, ( u8 ) send );
left -= send;
}
}
return size - left;
}
void
sio_send( u8_t data, sio_fd_t fd )
{
while( sio_write( fd, &data, 1 ) != 1 );
}
u8_t
sio_recv( sio_fd_t fd )
{
u8_t data;
serdev_t *dev = fd;
if( dev->ready )
{
while( sio_read( fd, &data, 1 ) != 1 );
}
else
{
LWIP_ASSERT( "sio_recv: dev->ready != 0 ", dev->ready != 0 );
data = '\0';
}
return data;
}
u32_t
sio_read( sio_fd_t fd, u8_t * buf, u32_t size )
{
u32_t ch_left = size;
u32_t ch_received = 0;
volatile serdev_t *dev = fd;
if( dev->ready )
{
dev->abort = 0;
while( ch_left && !dev->abort )
{
vPortEnterCritical( );
while( ( dev->rx_buf_cnt > 0 ) && ( ch_left > 0 ) )
{
/* Fetch character from the ring buffer. */
*buf++ = dev->rx_buf[dev->rx_buf_rdpos];
dev->rx_buf_rdpos = ( dev->rx_buf_rdpos + 1 ) % DEFAULT_RX_BUFSIZE;
dev->rx_buf_cnt--;
/* Count character received and left for read. */
ch_left--;
ch_received++;
}
vPortExitCritical( );
/* If we want more data block on the semaphore and wait until
* something happens.
*/
if( ch_left )
{
if( xSemaphoreTake( dev->rx_sem, MS_TO_TICKS( DEFAULT_READTIMEOUT_MS ) ) ==
pdFALSE )
{
/* A timeout. Abort the read and return the characters
* received so far.
*/
dev->abort = 1;
}
}
}
}
return ch_received;
}
u32_t
sio_write( sio_fd_t fd, u8_t * buf, u32_t size )
{
u32_t ch_left;
volatile serdev_t *dev = fd;
if( dev->ready )
{
ch_left = size;
while( ch_left > 0 )
{
vPortEnterCritical( );
while( ( dev->tx_buf_cnt < DEFAULT_TX_BUFSIZE ) && ( ch_left > 0 ) )
{
dev->tx_buf[dev->tx_buf_wrpos] = *buf++;
dev->tx_buf_wrpos = ( dev->tx_buf_wrpos + 1 ) % DEFAULT_TX_BUFSIZE;
dev->tx_buf_cnt++;
ch_left--;
}
/* Enable transmit FIFO empty interrupts and block. */
UART_ItConfig( dev->UARTx, UART_TxHalfEmpty, ENABLE );
vPortExitCritical( );
/* Not all characters sent within one write. Block on a semaphore
* which is triggered when the buffer is empty again.
*/
if( ch_left != 0 )
{
while( xSemaphoreTake( dev->tx_sem, portMAX_DELAY ) != pdTRUE );
}
}
}
return size;
}
void
sio_read_abort( sio_fd_t fd )
{
volatile serdev_t *dev = fd;
dev->abort = 1;
}
void
sio_serial_isr( UART_TypeDef * UARTx, u8_t * need_ctx_switch )
{
int i;
u16 status;
volatile serdev_t *dev = SIO_FD_NULL;
portBASE_TYPE rx_woken = pdFALSE;
portBASE_TYPE tx_woken = pdFALSE;
for( i = 0; i < UART_DEVICES_MAX; i++ )
{
if( devices[i].ready && ( devices[i].UARTx == UARTx ) )
{
dev = &devices[i];
break;
}
}
if( dev != SIO_FD_NULL )
{
status = UART_FlagStatus( dev->UARTx );
/* If there are characters in the UART fifo place them into the
* ring buffer. In case the buffer is filled half or the requested
* number of bytes has been read wakeup the receiver.
*/
if( status & UART_RxBufFull )
{
do
{
/* Store the character in the ring buffer and advance write
* position. */
dev->rx_buf[dev->rx_buf_wrpos] = dev->UARTx->RxBUFR;
dev->rx_buf_wrpos = ( dev->rx_buf_wrpos + 1 ) % DEFAULT_RX_BUFSIZE;
/* Increment the receiver buffer counter. Check for a buffer
* overrun. In that case we have overwritten a old character.
* Therefore we have to advance the read position. Note that
* in this error case we must not increment the read counter
* because an old character was lost.
*/
if( dev->rx_buf_cnt >= DEFAULT_RX_BUFSIZE )
{
/* LWIP_ASSERT( "sio_serial_isr: receiver buffer overflow", 0 ); */
dev->rx_buf_rdpos = ( dev->rx_buf_rdpos + 1 ) % DEFAULT_RX_BUFSIZE;
}
else
{
dev->rx_buf_cnt++;
}
/* Get the new status from the UART. */
status = UART_FlagStatus( dev->UARTx );
}
while( status & UART_RxBufFull );
/* Wakeup receiver if buffer is starting to fill. */
if( dev->rx_buf_cnt > ( DEFAULT_RX_BUFSIZE / 2 ) )
{
rx_woken = xSemaphoreGiveFromISR( dev->rx_sem, rx_woken );
}
}
/* Check if we must send characters. */
if( ( dev->tx_buf_cnt > 0 ) && ( status & UART_TxHalfEmpty ) )
{
do
{
/* Fetch character from the ring buffer and place them into
* the FIFO. */
dev->UARTx->TxBUFR = dev->tx_buf[dev->tx_buf_rdpos];
dev->tx_buf_rdpos = ( dev->tx_buf_rdpos + 1 ) % DEFAULT_TX_BUFSIZE;
dev->tx_buf_cnt--;
/* Get the new status from the UART. */
status = UART_FlagStatus( dev->UARTx );
}
while( ( dev->tx_buf_cnt > 0 ) && ( status & UART_TxHalfEmpty ) );
if( dev->tx_buf_cnt == 0 )
{
tx_woken = xSemaphoreGiveFromISR( dev->tx_sem, tx_woken );
UART_ItConfig( dev->UARTx, UART_TxHalfEmpty, DISABLE );
}
}
if( tx_woken || rx_woken )
{
*need_ctx_switch = 1;
}
}
}
void
sio_uart0_irq( void )
{
/* Save context to stack. */
portENTER_SWITCHING_ISR( );
static u8_t need_ctx_switch;
sio_serial_isr( UART0, &need_ctx_switch );
/* End the interrupt in the EIC. */
EIC->IPR |= 1 << EIC_CurrentIRQChannelValue( );
/* End the ISR. */
portEXIT_SWITCHING_ISR( need_ctx_switch ? pdTRUE : pdFALSE );
}
void
sio_uart1_irq( void )
{
/* Save context to stack. */
portENTER_SWITCHING_ISR( );
static u8_t need_ctx_switch;
sio_serial_isr( UART1, &need_ctx_switch );
/* End the interrupt in the EIC. */
EIC->IPR |= 1 << EIC_CurrentIRQChannelValue( );
/* End the ISR. */
portEXIT_SWITCHING_ISR( need_ctx_switch ? pdTRUE : pdFALSE );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -