1671 lines
49 KiB
C
1671 lines
49 KiB
C
/***************************************************************************//**
|
|
* @file drv_usart.c
|
|
* @brief USART driver of RT-Thread RTOS for EFM32
|
|
* COPYRIGHT (C) 2012, RT-Thread Development Team
|
|
* @author onelife
|
|
* @version 1.0
|
|
*******************************************************************************
|
|
* @section License
|
|
* The license and distribution terms for this file may be found in the file
|
|
* LICENSE in this distribution or at http://www.rt-thread.org/license/LICENSE
|
|
*******************************************************************************
|
|
* @section Change Logs of serial.c
|
|
* Date Author Notes
|
|
* 2009-02-05 Bernard first version
|
|
* 2009-10-25 Bernard fix rt_serial_read bug when there is no data in the
|
|
* buffer.
|
|
* 2010-03-29 Bernard cleanup code.
|
|
*
|
|
* @section Change Logs
|
|
* Date Author Notes
|
|
* 2010-12-22 onelife Initial creation for EFM32
|
|
* 2011-01-17 onelife Merge with serial.c
|
|
* 2011-05-06 onelife Add sync mode (SPI) support
|
|
* 2011-06-14 onelife Fix a bug of TX by DMA
|
|
* 2011-06-16 onelife Modify init function for EFM32 library v2.0.0
|
|
* upgrading
|
|
* 2011-07-07 onelife Modify write function to avoid sleep in ISR
|
|
* 2011-07-26 onelife Add lock (semaphore) to prevent simultaneously
|
|
* access
|
|
* 2011-11-29 onelife Modify init function for EFM32 library v2.2.2
|
|
* upgrading
|
|
* 2011-12-09 onelife Add giant gecko support
|
|
* 2011-12-09 onelife Add UART module support
|
|
* 2011-12-20 onelife Add 9-bit SPI mode support
|
|
* 2011-12-20 onelife Change SPI write format (same as SPI read)
|
|
* 2011-12-20 onelife Change USART status format
|
|
* 2011-12-27 onelife Utilize "USART_PRESENT", "USART_COUNT",
|
|
* "UART_PRESENT" and "UART_COUNT"
|
|
* 2012-05-16 onelife Fix a bug in rt_hw_usart_init()
|
|
******************************************************************************/
|
|
|
|
/***************************************************************************//**
|
|
* @addtogroup efm32
|
|
* @{
|
|
******************************************************************************/
|
|
|
|
/* Includes ------------------------------------------------------------------*/
|
|
#include "board.h"
|
|
#include "hdl_interrupt.h"
|
|
#include "drv_usart.h"
|
|
|
|
#if (defined(RT_USING_USART0) || defined(RT_USING_USART1) || \
|
|
defined(RT_USING_USART2) || defined(RT_USING_UART0) || \
|
|
defined(RT_USING_UART1))
|
|
#if ((defined(RT_USING_USART0) || defined(RT_USING_USART1) || \
|
|
defined(RT_USING_USART2)) && !defined(USART_PRESENT))
|
|
#error "USART module is not available"
|
|
#endif
|
|
#if ((defined(RT_USING_UART0) || defined(RT_USING_UART1)) && \
|
|
!defined(UART_PRESENT))
|
|
#error "UART module is not available"
|
|
#endif
|
|
/* Private typedef -----------------------------------------------------------*/
|
|
/* Private define ------------------------------------------------------------*/
|
|
/* Private macro -------------------------------------------------------------*/
|
|
#ifdef RT_USART_DEBUG
|
|
#define usart_debug(format,args...) rt_kprintf(format, ##args)
|
|
#else
|
|
#define usart_debug(format,args...)
|
|
#endif
|
|
|
|
/* Private variables ---------------------------------------------------------*/
|
|
#ifdef RT_USING_USART0
|
|
#if (RT_USING_USART0 >= EFM32_USART_LOCATION_COUNT)
|
|
#error "Wrong location number"
|
|
#endif
|
|
struct rt_device usart0_device;
|
|
static struct rt_semaphore usart0_lock;
|
|
#endif
|
|
|
|
#ifdef RT_USING_USART1
|
|
#if (USART_COUNT <= 1)
|
|
#error "Wrong unit number"
|
|
#endif
|
|
#if (RT_USING_USART1 >= EFM32_USART_LOCATION_COUNT)
|
|
#error "Wrong location number"
|
|
#endif
|
|
struct rt_device usart1_device;
|
|
static struct rt_semaphore usart1_lock;
|
|
#endif
|
|
|
|
#ifdef RT_USING_USART2
|
|
#if (USART_COUNT <= 2)
|
|
#error "Wrong unit number"
|
|
#endif
|
|
#if (RT_USING_USART2 >= EFM32_USART_LOCATION_COUNT)
|
|
#error "Wrong location number"
|
|
#endif
|
|
struct rt_device usart2_device;
|
|
static struct rt_semaphore usart2_lock;
|
|
#endif
|
|
|
|
#ifdef RT_USING_UART0
|
|
#if (RT_USING_UART0 >= EFM32_UART_LOCATION_COUNT)
|
|
#error "Wrong location number"
|
|
#endif
|
|
struct rt_device uart0_device;
|
|
static struct rt_semaphore uart0_lock;
|
|
#endif
|
|
|
|
#ifdef RT_USING_UART1
|
|
#if (UART_COUNT <= 1)
|
|
#error "Wrong unit number"
|
|
#endif
|
|
#if (RT_USING_UART1 >= EFM32_UART_LOCATION_COUNT)
|
|
#error "Wrong location number"
|
|
#endif
|
|
struct rt_device uart1_device;
|
|
static struct rt_semaphore uart1_lock;
|
|
#endif
|
|
|
|
/* Private function prototypes -----------------------------------------------*/
|
|
/* Private functions ---------------------------------------------------------*/
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Initialize USART device
|
|
*
|
|
* @details
|
|
*
|
|
* @note
|
|
*
|
|
* @param[in] dev
|
|
* Pointer to device descriptor
|
|
*
|
|
* @return
|
|
* Error code
|
|
******************************************************************************/
|
|
static rt_err_t rt_usart_init (rt_device_t dev)
|
|
{
|
|
struct efm32_usart_device_t *usart;
|
|
|
|
usart = (struct efm32_usart_device_t *)(dev->user_data);
|
|
|
|
if (!(dev->flag & RT_DEVICE_FLAG_ACTIVATED))
|
|
{
|
|
if (dev->flag & RT_DEVICE_FLAG_DMA_TX)
|
|
{
|
|
struct efm32_usart_dma_mode_t *dma_tx;
|
|
|
|
dma_tx = (struct efm32_usart_dma_mode_t *)(usart->tx_mode);
|
|
|
|
usart->state |= USART_STATE_RX_BUSY;
|
|
}
|
|
|
|
if (dev->flag & RT_DEVICE_FLAG_INT_RX)
|
|
{
|
|
struct efm32_usart_int_mode_t *int_rx;
|
|
|
|
int_rx = (struct efm32_usart_int_mode_t *)(usart->rx_mode);
|
|
|
|
int_rx->data_ptr = RT_NULL;
|
|
}
|
|
|
|
/* Enable USART */
|
|
USART_Enable(usart->usart_device, usartEnable);
|
|
|
|
dev->flag |= RT_DEVICE_FLAG_ACTIVATED;
|
|
}
|
|
|
|
return RT_EOK;
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Open USART device
|
|
*
|
|
* @details
|
|
*
|
|
* @note
|
|
*
|
|
* @param[in] dev
|
|
* Pointer to device descriptor
|
|
*
|
|
* @param[in] oflag
|
|
* Device open flag
|
|
*
|
|
* @return
|
|
* Error code
|
|
******************************************************************************/
|
|
static rt_err_t rt_usart_open(rt_device_t dev, rt_uint16_t oflag)
|
|
{
|
|
RT_ASSERT(dev != RT_NULL);
|
|
|
|
struct efm32_usart_device_t *usart;
|
|
|
|
usart = (struct efm32_usart_device_t *)(dev->user_data);
|
|
|
|
if (dev->flag & RT_DEVICE_FLAG_INT_RX)
|
|
{
|
|
IRQn_Type rxIrq;
|
|
|
|
//if (usart->state & USART_STATE_CONSOLE)
|
|
{ /* Allocate new RX buffer */
|
|
struct efm32_usart_int_mode_t *int_mode;
|
|
|
|
int_mode = (struct efm32_usart_int_mode_t *)(usart->rx_mode);
|
|
|
|
if ((int_mode->data_ptr = rt_malloc(USART_RX_BUFFER_SIZE)) == RT_NULL)
|
|
{
|
|
usart_debug("USART%d err: no mem for RX BUF\n", usart->unit);
|
|
return -RT_ENOMEM;
|
|
}
|
|
rt_memset(int_mode->data_ptr, 0, USART_RX_BUFFER_SIZE);
|
|
int_mode->data_size = USART_RX_BUFFER_SIZE;
|
|
int_mode->read_index = 0;
|
|
int_mode->save_index = 0;
|
|
}
|
|
|
|
/* Enable RX interrupt */
|
|
#if defined(UART_PRESENT)
|
|
if (usart->state & USART_STATE_ASYNC_ONLY)
|
|
{
|
|
usart->usart_device->IEN = UART_IEN_RXDATAV;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
usart->usart_device->IEN = USART_IEN_RXDATAV;
|
|
}
|
|
|
|
/* Enable IRQ */
|
|
switch (usart->unit)
|
|
{
|
|
case 0:
|
|
#if defined(UART_PRESENT)
|
|
if (usart->state & USART_STATE_ASYNC_ONLY)
|
|
{
|
|
rxIrq = UART0_RX_IRQn;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
rxIrq = USART0_RX_IRQn;
|
|
}
|
|
break;
|
|
#if ((defined(USART_PRESENT) && (USART_COUNT > 1)) || \
|
|
(defined(UART_PRESENT) && (UART_COUNT > 1)))
|
|
case 1:
|
|
#if (defined(UART_PRESENT) && (UART_COUNT > 1))
|
|
if (usart->state & USART_STATE_ASYNC_ONLY)
|
|
{
|
|
rxIrq = UART1_RX_IRQn;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
rxIrq = USART1_RX_IRQn;
|
|
}
|
|
break;
|
|
#endif
|
|
#if ((defined(USART_PRESENT) && (USART_COUNT > 2)) || \
|
|
(defined(UART_PRESENT) && (UART_COUNT > 2)))
|
|
case 2:
|
|
#if (defined(UART_PRESENT) && (UART_COUNT > 2))
|
|
if (usart->state & USART_STATE_ASYNC_ONLY)
|
|
{
|
|
rxIrq = UART2_RX_IRQn;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
rxIrq = USART2_RX_IRQn;
|
|
}
|
|
break;
|
|
#endif
|
|
}
|
|
if (oflag != RT_DEVICE_OFLAG_WRONLY)
|
|
{
|
|
NVIC_ClearPendingIRQ(rxIrq);
|
|
NVIC_SetPriority(rxIrq, EFM32_IRQ_PRI_DEFAULT);
|
|
NVIC_EnableIRQ(rxIrq);
|
|
}
|
|
}
|
|
|
|
/* Clear Flag */
|
|
#if defined(UART_PRESENT)
|
|
if (usart->state & USART_STATE_ASYNC_ONLY)
|
|
{
|
|
usart->usart_device->IFC = _UART_IFC_MASK;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
usart->usart_device->IFC = _USART_IFC_MASK;
|
|
}
|
|
|
|
if ((dev->flag & RT_DEVICE_FLAG_DMA_TX) && (oflag != RT_DEVICE_OFLAG_RDONLY))
|
|
{
|
|
/* DMA IRQ is enabled by DMA_Init() */
|
|
NVIC_SetPriority(DMA_IRQn, EFM32_IRQ_PRI_DEFAULT);
|
|
}
|
|
|
|
usart->counter++;
|
|
usart_debug("USART%d: Open with flag %x\n", usart->unit, oflag);
|
|
return RT_EOK;
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Close USART device
|
|
*
|
|
* @details
|
|
*
|
|
* @note
|
|
*
|
|
* @param[in] dev
|
|
* Pointer to device descriptor
|
|
*
|
|
* @return
|
|
* Error code
|
|
******************************************************************************/
|
|
static rt_err_t rt_usart_close(rt_device_t dev)
|
|
{
|
|
RT_ASSERT(dev != RT_NULL);
|
|
|
|
struct efm32_usart_device_t *usart;
|
|
|
|
usart = (struct efm32_usart_device_t *)(dev->user_data);
|
|
|
|
if (--usart->counter == 0)
|
|
{
|
|
if (dev->flag & RT_DEVICE_FLAG_INT_RX)
|
|
{
|
|
struct efm32_usart_int_mode_t *int_rx;
|
|
|
|
int_rx = (struct efm32_usart_int_mode_t *)usart->rx_mode;
|
|
|
|
rt_free(int_rx->data_ptr);
|
|
int_rx->data_ptr = RT_NULL;
|
|
}
|
|
}
|
|
|
|
return RT_EOK;
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Read from USART device
|
|
*
|
|
* @details
|
|
*
|
|
* @note
|
|
* 9-bit SPI mode and SPI slave mode is untested
|
|
*
|
|
* @param[in] dev
|
|
* Pointer to device descriptor
|
|
*
|
|
* @param[in] pos
|
|
* Offset
|
|
*
|
|
* @param[in] buffer
|
|
* Poniter to the buffer
|
|
*
|
|
* @param[in] size
|
|
* Buffer size in byte
|
|
*
|
|
* @return
|
|
* Number of read bytes
|
|
******************************************************************************/
|
|
static rt_size_t rt_usart_read (
|
|
rt_device_t dev,
|
|
rt_off_t pos,
|
|
void *buffer,
|
|
rt_size_t size)
|
|
{
|
|
rt_err_t err_code;
|
|
struct efm32_usart_device_t *usart;
|
|
rt_size_t read_len, len;
|
|
rt_uint8_t *ptr;
|
|
rt_uint32_t rx_flag, tx_flag, b8_flag;
|
|
|
|
usart = (struct efm32_usart_device_t *)(dev->user_data);
|
|
#if defined(UART_PRESENT)
|
|
if (usart->state & USART_STATE_ASYNC_ONLY)
|
|
{
|
|
rx_flag = UART_STATUS_RXDATAV;
|
|
tx_flag = UART_STATUS_TXBL;
|
|
b8_flag = UART_CTRL_BIT8DV;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
rx_flag = USART_STATUS_RXDATAV;
|
|
tx_flag = USART_STATUS_TXBL;
|
|
b8_flag = USART_CTRL_BIT8DV;
|
|
}
|
|
|
|
/* Lock device */
|
|
if (rt_hw_interrupt_check())
|
|
{
|
|
err_code = rt_sem_take(usart->lock, RT_WAITING_NO);
|
|
}
|
|
else
|
|
{
|
|
err_code = rt_sem_take(usart->lock, RT_WAITING_FOREVER);
|
|
}
|
|
if (err_code != RT_EOK)
|
|
{
|
|
rt_set_errno(err_code);
|
|
return 0;
|
|
}
|
|
|
|
if (dev->flag & RT_DEVICE_FLAG_INT_RX)
|
|
{
|
|
len = size;
|
|
ptr = buffer;
|
|
/* interrupt mode Rx */
|
|
while (len)
|
|
{
|
|
rt_base_t level;
|
|
struct efm32_usart_int_mode_t *int_rx;
|
|
|
|
int_rx = (struct efm32_usart_int_mode_t *)\
|
|
(((struct efm32_usart_device_t *)(dev->user_data))->rx_mode);
|
|
|
|
/* disable interrupt */
|
|
level = rt_hw_interrupt_disable();
|
|
|
|
if (int_rx->read_index != int_rx->save_index)
|
|
{
|
|
/* read a character */
|
|
*ptr++ = int_rx->data_ptr[int_rx->read_index];
|
|
len--;
|
|
|
|
/* move to next position */
|
|
int_rx->read_index ++;
|
|
if (int_rx->read_index >= USART_RX_BUFFER_SIZE)
|
|
{
|
|
int_rx->read_index = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* set error code */
|
|
err_code = -RT_EEMPTY;
|
|
|
|
/* enable interrupt */
|
|
rt_hw_interrupt_enable(level);
|
|
break;
|
|
}
|
|
|
|
/* enable interrupt */
|
|
rt_hw_interrupt_enable(level);
|
|
}
|
|
|
|
read_len = (rt_uint32_t)ptr - (rt_uint32_t)buffer;
|
|
}
|
|
else
|
|
{
|
|
if (usart->state & USART_STATE_SYNC)
|
|
{
|
|
/* SPI read */
|
|
rt_uint8_t inst_len = *((rt_uint8_t *)buffer);
|
|
rt_uint8_t *inst_ptr = (rt_uint8_t *)(buffer + 1);
|
|
rt_uint8_t *rx_buf = *((rt_uint8_t **)(buffer + inst_len + 1));
|
|
rt_off_t i;
|
|
|
|
ptr = inst_ptr;
|
|
len = inst_len;
|
|
/* Write instructions */
|
|
if (len)
|
|
{
|
|
if (usart->state & USART_STATE_9BIT)
|
|
{
|
|
usart->usart_device->CTRL &= ~b8_flag;
|
|
}
|
|
while (len)
|
|
{
|
|
while (!(usart->usart_device->STATUS & tx_flag));
|
|
usart->usart_device->TXDATA = (rt_uint32_t)*(ptr++);
|
|
len--;
|
|
}
|
|
if (usart->state & USART_STATE_9BIT)
|
|
{
|
|
usart->usart_device->CTRL |= b8_flag;
|
|
}
|
|
}
|
|
|
|
/* Flushing RX */
|
|
usart->usart_device->CMD = USART_CMD_CLEARRX;
|
|
/* Skip some bytes if necessary */
|
|
for (i = 0; i < pos; i++)
|
|
{
|
|
/* dummy write */
|
|
while (!(usart->usart_device->STATUS & tx_flag));
|
|
usart->usart_device->TXDATA = (rt_uint32_t)0xff;
|
|
/* dummy read */
|
|
while (!(usart->usart_device->STATUS & rx_flag));
|
|
*((rt_uint32_t *)0x00) = usart->usart_device->RXDATA;
|
|
}
|
|
|
|
ptr = rx_buf;
|
|
len = size;
|
|
/* Read data */
|
|
while (len)
|
|
{
|
|
/* dummy write */
|
|
while (!(usart->usart_device->STATUS & tx_flag));
|
|
usart->usart_device->TXDATA = (rt_uint32_t)0xff;
|
|
/* read a byte of data */
|
|
while (!(usart->usart_device->STATUS & rx_flag));
|
|
*(ptr++) = usart->usart_device->RXDATA & 0xff;
|
|
len--;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ptr = buffer;
|
|
len = size;
|
|
/* polling mode */
|
|
while (len)
|
|
{
|
|
while (usart->usart_device->STATUS & rx_flag)
|
|
{
|
|
*(ptr++) = usart->usart_device->RXDATA & 0xff;
|
|
}
|
|
len--;
|
|
}
|
|
}
|
|
|
|
read_len = size - len;
|
|
}
|
|
|
|
/* Unlock device */
|
|
rt_sem_release(usart->lock);
|
|
|
|
/* set error code */
|
|
rt_set_errno(err_code);
|
|
|
|
return read_len;
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Write to USART device
|
|
*
|
|
* @details
|
|
*
|
|
* @note
|
|
*
|
|
* @param[in] dev
|
|
* Pointer to device descriptor
|
|
*
|
|
* @param[in] pos
|
|
* Offset
|
|
*
|
|
* @param[in] buffer
|
|
* Poniter to the buffer
|
|
*
|
|
* @param[in] size
|
|
* Buffer size in byte
|
|
*
|
|
* @return
|
|
* Number of written bytes
|
|
******************************************************************************/
|
|
static rt_size_t rt_usart_write (
|
|
rt_device_t dev,
|
|
rt_off_t pos,
|
|
const void* buffer,
|
|
rt_size_t size)
|
|
{
|
|
rt_err_t err_code;
|
|
struct efm32_usart_device_t* usart = (struct efm32_usart_device_t*)(dev->user_data);
|
|
rt_size_t read_len, len;
|
|
rt_uint8_t *ptr;
|
|
rt_size_t write_size = 0;
|
|
rt_uint32_t tx_flag, b8_flag;
|
|
|
|
#if defined(UART_PRESENT)
|
|
if (usart->state & USART_STATE_ASYNC_ONLY)
|
|
{
|
|
tx_flag = UART_STATUS_TXBL;
|
|
b8_flag = UART_CTRL_BIT8DV;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
tx_flag = USART_STATUS_TXBL;
|
|
b8_flag = USART_CTRL_BIT8DV;
|
|
}
|
|
|
|
/* Lock device */
|
|
if (rt_hw_interrupt_check())
|
|
{
|
|
err_code = rt_sem_take(usart->lock, RT_WAITING_NO);
|
|
}
|
|
else
|
|
{
|
|
err_code = rt_sem_take(usart->lock, RT_WAITING_FOREVER);
|
|
}
|
|
if (err_code != RT_EOK)
|
|
{
|
|
rt_set_errno(err_code);
|
|
return 0;
|
|
}
|
|
|
|
if (usart->state & USART_STATE_SYNC)
|
|
{ /* SPI write */
|
|
rt_uint8_t inst_len = *((rt_uint8_t *)buffer);
|
|
rt_uint8_t *inst_ptr = (rt_uint8_t *)(buffer + 1);
|
|
rt_uint8_t *tx_buf = *((rt_uint8_t **)(buffer + inst_len + 1));
|
|
|
|
ptr = inst_ptr;
|
|
len = inst_len;
|
|
/* Write instructions */
|
|
if (len)
|
|
{
|
|
if (usart->state & USART_STATE_9BIT)
|
|
{
|
|
usart->usart_device->CTRL &= ~b8_flag;
|
|
}
|
|
if ((dev->flag & RT_DEVICE_FLAG_DMA_TX) && (len > 2))
|
|
{ /* DMA mode Tx */
|
|
struct efm32_usart_dma_mode_t *dma_tx;
|
|
|
|
usart_debug("USART: DMA TX INS (%d)\n", len);
|
|
dma_tx = (struct efm32_usart_dma_mode_t *)(usart->tx_mode);
|
|
dma_tx->data_ptr = (rt_uint32_t *)ptr;
|
|
dma_tx->data_size = len;
|
|
|
|
usart->state |= USART_STATE_TX_BUSY;
|
|
DMA_ActivateBasic(
|
|
dma_tx->dma_channel,
|
|
true,
|
|
false,
|
|
(void *)&(usart->usart_device->TXDATA),
|
|
(void *)ptr,
|
|
(rt_uint32_t)(len - 1));
|
|
/* Wait, otherwise the TX buffer is overwrite */
|
|
// TODO: This function blocks the process => goto low power mode?
|
|
// if (usart->state & USART_STATE_CONSOLE)
|
|
// {
|
|
while(usart->state & USART_STATE_TX_BUSY);
|
|
// }
|
|
// else
|
|
// {
|
|
// while(usart->state & USART_STATE_TX_BUSY)
|
|
// {
|
|
// rt_thread_sleep(USART_WAIT_TIME_TX);
|
|
// }
|
|
// }
|
|
}
|
|
else
|
|
{ /* polling mode */
|
|
usart_debug("USART: Polling TX INS (%d)\n", len);
|
|
while (len)
|
|
{
|
|
while (!(usart->usart_device->STATUS & tx_flag));
|
|
usart->usart_device->TXDATA = (rt_uint32_t)*(ptr++);
|
|
len--;
|
|
}
|
|
}
|
|
if (usart->state & USART_STATE_9BIT)
|
|
{
|
|
usart->usart_device->CTRL |= b8_flag;
|
|
}
|
|
}
|
|
|
|
ptr = tx_buf;
|
|
}
|
|
else
|
|
{
|
|
ptr = (rt_uint8_t *)buffer;
|
|
}
|
|
|
|
len = size;
|
|
/* Write data */
|
|
if (dev->flag & RT_DEVICE_FLAG_STREAM)
|
|
{
|
|
if (*(ptr + len - 1) == '\n')
|
|
{
|
|
*(ptr + len - 1) = '\r';
|
|
*(ptr + len++) = '\n';
|
|
*(ptr + len) = 0;
|
|
}
|
|
}
|
|
if ((dev->flag & RT_DEVICE_FLAG_DMA_TX) && (len > 2))
|
|
{ /* DMA mode Tx */
|
|
struct efm32_usart_dma_mode_t *dma_tx;
|
|
|
|
usart_debug("USART: DMA TX data (%d)\n", len);
|
|
dma_tx = (struct efm32_usart_dma_mode_t *)(usart->tx_mode);
|
|
dma_tx->data_ptr = (rt_uint32_t *)ptr;
|
|
dma_tx->data_size = len;
|
|
|
|
usart->state |= USART_STATE_TX_BUSY;
|
|
DMA_ActivateBasic(
|
|
dma_tx->dma_channel,
|
|
true,
|
|
false,
|
|
(void *)&(usart->usart_device->TXDATA),
|
|
(void *)ptr,
|
|
(rt_uint32_t)(len - 1));
|
|
|
|
/* Wait, otherwise the TX buffer is overwrite */
|
|
// TODO: This function blocks the process => goto low power mode?
|
|
// if (usart->state & USART_STATE_CONSOLE)
|
|
// {
|
|
while(usart->state & USART_STATE_TX_BUSY);
|
|
// }
|
|
// else
|
|
// {
|
|
// while(usart->state & USART_STATE_TX_BUSY)
|
|
// {
|
|
// rt_thread_sleep(USART_WAIT_TIME_TX);
|
|
// }
|
|
// }
|
|
write_size = size;
|
|
}
|
|
else
|
|
{ /* polling mode */
|
|
usart_debug("USART: Polling TX data (%d)\n", len);
|
|
while (len)
|
|
{
|
|
while (!(usart->usart_device->STATUS & tx_flag));
|
|
usart->usart_device->TXDATA = (rt_uint32_t)*(ptr++);
|
|
len--;
|
|
}
|
|
|
|
write_size = size - len;
|
|
}
|
|
|
|
/* Unlock device */
|
|
rt_sem_release(usart->lock);
|
|
|
|
/* set error code */
|
|
rt_set_errno(err_code);
|
|
|
|
return write_size;
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Configure USART device
|
|
*
|
|
* @details
|
|
*
|
|
* @note
|
|
*
|
|
* @param[in] dev
|
|
* Pointer to device descriptor
|
|
*
|
|
* @param[in] cmd
|
|
* IIC control command
|
|
*
|
|
* @param[in] args
|
|
* Arguments
|
|
*
|
|
* @return
|
|
* Error code
|
|
******************************************************************************/
|
|
static rt_err_t rt_usart_control (
|
|
rt_device_t dev,
|
|
rt_uint8_t cmd,
|
|
void *args)
|
|
{
|
|
RT_ASSERT(dev != RT_NULL);
|
|
|
|
rt_err_t err_code;
|
|
struct efm32_usart_device_t *usart;
|
|
|
|
usart = (struct efm32_usart_device_t *)(dev->user_data);
|
|
|
|
/* Lock device */
|
|
if (rt_hw_interrupt_check())
|
|
{
|
|
err_code = rt_sem_take(usart->lock, RT_WAITING_NO);
|
|
}
|
|
else
|
|
{
|
|
err_code = rt_sem_take(usart->lock, RT_WAITING_FOREVER);
|
|
}
|
|
if (err_code != RT_EOK)
|
|
{
|
|
return err_code;
|
|
}
|
|
|
|
switch (cmd)
|
|
{
|
|
case RT_DEVICE_CTRL_SUSPEND:
|
|
/* Suspend device */
|
|
dev->flag |= RT_DEVICE_FLAG_SUSPENDED;
|
|
USART_Enable(usart->usart_device, usartDisable);
|
|
break;
|
|
|
|
case RT_DEVICE_CTRL_RESUME:
|
|
/* Resume device */
|
|
dev->flag &= ~RT_DEVICE_FLAG_SUSPENDED;
|
|
USART_Enable(usart->usart_device, usartEnable);
|
|
break;
|
|
|
|
case RT_DEVICE_CTRL_USART_RBUFFER:
|
|
/* Set RX buffer */
|
|
{
|
|
struct efm32_usart_int_mode_t *int_rx;
|
|
rt_uint8_t size;
|
|
|
|
int_rx = (struct efm32_usart_int_mode_t *)(usart->rx_mode);
|
|
size = (rt_uint8_t)((rt_uint32_t)args & 0xFFUL);
|
|
|
|
/* Free previous RX buffer */
|
|
if (int_rx->data_ptr != RT_NULL)
|
|
{
|
|
if (size == 0)
|
|
{ /* Free RX buffer */
|
|
rt_free(int_rx->data_ptr);
|
|
int_rx->data_ptr = RT_NULL;
|
|
}
|
|
else if (size != int_rx->data_size)
|
|
{
|
|
/* Re-allocate RX buffer */
|
|
if ((int_rx->data_ptr = rt_realloc(int_rx->data_ptr, size)) \
|
|
== RT_NULL)
|
|
{
|
|
usart_debug("USART%d err: no mem for RX BUF\n", usart->unit);
|
|
err_code = -RT_ENOMEM;
|
|
break;
|
|
}
|
|
// TODO: Is the following line necessary?
|
|
//rt_memset(int_rx->data_ptr, 0, size);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Allocate new RX buffer */
|
|
if ((int_rx->data_ptr = rt_malloc(size)) == RT_NULL)
|
|
{
|
|
usart_debug("USART%d err: no mem for RX BUF\n", usart->unit);
|
|
err_code = -RT_ENOMEM;
|
|
break;
|
|
}
|
|
}
|
|
int_rx->data_size = size;
|
|
int_rx->read_index = 0;
|
|
int_rx->save_index = 0;
|
|
}
|
|
break;
|
|
|
|
}
|
|
|
|
/* Unlock device */
|
|
rt_sem_release(usart->lock);
|
|
|
|
return err_code;
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* USART RX data valid interrupt handler
|
|
*
|
|
* @details
|
|
*
|
|
* @note
|
|
* 9-bit SPI mode has not implemented yet and SPI slave mode is untested
|
|
*
|
|
* @param[in] dev
|
|
* Pointer to device descriptor
|
|
******************************************************************************/
|
|
void rt_hw_usart_rx_isr(rt_device_t dev)
|
|
{
|
|
struct efm32_usart_device_t *usart;
|
|
struct efm32_usart_int_mode_t *int_rx;
|
|
rt_uint32_t flag;
|
|
|
|
/* interrupt mode receive */
|
|
RT_ASSERT(dev->flag & RT_DEVICE_FLAG_INT_RX);
|
|
usart = (struct efm32_usart_device_t *)(dev->user_data);
|
|
int_rx = (struct efm32_usart_int_mode_t *)(usart->rx_mode);
|
|
RT_ASSERT(int_rx->data_ptr != RT_NULL);
|
|
#if defined(UART_PRESENT)
|
|
if (usart->state & USART_STATE_ASYNC_ONLY)
|
|
{
|
|
flag = UART_STATUS_RXDATAV;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
flag = USART_STATUS_RXDATAV;
|
|
}
|
|
|
|
/* Set status */
|
|
usart->state |= USART_STATE_RX_BUSY;
|
|
|
|
/* save into rx buffer */
|
|
while (usart->usart_device->STATUS & flag)
|
|
{
|
|
rt_base_t level;
|
|
|
|
/* disable interrupt */
|
|
level = rt_hw_interrupt_disable();
|
|
|
|
/* save character */
|
|
int_rx->data_ptr[int_rx->save_index] = \
|
|
(rt_uint8_t)(usart->usart_device->RXDATA & 0xFFUL);
|
|
int_rx->save_index ++;
|
|
if (int_rx->save_index >= USART_RX_BUFFER_SIZE)
|
|
int_rx->save_index = 0;
|
|
|
|
/* if the next position is read index, discard this 'read char' */
|
|
if (int_rx->save_index == int_rx->read_index)
|
|
{
|
|
int_rx->read_index ++;
|
|
if (int_rx->read_index >= USART_RX_BUFFER_SIZE)
|
|
{
|
|
int_rx->read_index = 0;
|
|
}
|
|
}
|
|
|
|
/* enable interrupt */
|
|
rt_hw_interrupt_enable(level);
|
|
}
|
|
|
|
/* invoke callback */
|
|
if (dev->rx_indicate != RT_NULL)
|
|
{
|
|
rt_size_t rx_length;
|
|
|
|
/* get rx length */
|
|
rx_length = int_rx->read_index > int_rx->save_index ?
|
|
USART_RX_BUFFER_SIZE - int_rx->read_index + int_rx->save_index : \
|
|
int_rx->save_index - int_rx->read_index;
|
|
|
|
dev->rx_indicate(dev, rx_length);
|
|
}
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* DMA for USART TX interrupt handler
|
|
*
|
|
* @details
|
|
*
|
|
* @note
|
|
*
|
|
* @param[in] dev
|
|
* Pointer to device descriptor
|
|
******************************************************************************/
|
|
void rt_hw_usart_dma_tx_isr(rt_device_t dev)
|
|
{
|
|
/* DMA mode receive */
|
|
struct efm32_usart_device_t *usart;
|
|
struct efm32_usart_dma_mode_t *dma_tx;
|
|
|
|
RT_ASSERT(dev->flag & RT_DEVICE_FLAG_DMA_TX);
|
|
|
|
usart = (struct efm32_usart_device_t *)(dev->user_data);
|
|
dma_tx = (struct efm32_usart_dma_mode_t *)(usart->tx_mode);
|
|
|
|
/* invoke call to notify tx complete */
|
|
if (dev->tx_complete != RT_NULL)
|
|
{
|
|
dev->tx_complete(dev, dma_tx->data_ptr);
|
|
}
|
|
|
|
/* Set status */
|
|
usart->state &= ~(rt_uint32_t)USART_STATE_TX_BUSY;
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Register USART device
|
|
*
|
|
* @details
|
|
*
|
|
* @note
|
|
*
|
|
* @param[in] device
|
|
* Pointer to device descriptor
|
|
*
|
|
* @param[in] name
|
|
* Device name
|
|
*
|
|
* @param[in] flag
|
|
* Configuration flags
|
|
*
|
|
* @param[in] usart
|
|
* Pointer to USART device descriptor
|
|
*
|
|
* @return
|
|
* Error code
|
|
******************************************************************************/
|
|
rt_err_t rt_hw_usart_register(
|
|
rt_device_t device,
|
|
const char *name,
|
|
rt_uint32_t flag,
|
|
struct efm32_usart_device_t *usart)
|
|
{
|
|
RT_ASSERT(device != RT_NULL);
|
|
|
|
if ((flag & RT_DEVICE_FLAG_DMA_RX) ||
|
|
(flag & RT_DEVICE_FLAG_INT_TX))
|
|
{
|
|
RT_ASSERT(0);
|
|
}
|
|
|
|
if (usart->state & USART_STATE_SYNC)
|
|
{
|
|
device->type = RT_Device_Class_SPIBUS;
|
|
}
|
|
else
|
|
{
|
|
device->type = RT_Device_Class_Char;
|
|
}
|
|
device->rx_indicate = RT_NULL;
|
|
device->tx_complete = RT_NULL;
|
|
device->init = rt_usart_init;
|
|
device->open = rt_usart_open;
|
|
device->close = rt_usart_close;
|
|
device->read = rt_usart_read;
|
|
device->write = rt_usart_write;
|
|
device->control = rt_usart_control;
|
|
device->user_data = usart;
|
|
|
|
/* register a character device */
|
|
return rt_device_register(device, name, RT_DEVICE_FLAG_RDWR | flag);
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Initialize the specified USART unit
|
|
*
|
|
* @details
|
|
*
|
|
* @note
|
|
*
|
|
* @param[in] device
|
|
* Pointer to device descriptor
|
|
*
|
|
* @param[in] unitNumber
|
|
* Unit number
|
|
*
|
|
* @param[in] location
|
|
* Pin location number
|
|
*
|
|
* @param[in] flag
|
|
* Configuration flag
|
|
*
|
|
* @param[in] dmaChannel
|
|
* DMA channel number for TX
|
|
*
|
|
* @param[in] console
|
|
* Indicate if using as console
|
|
*
|
|
* @return
|
|
* Pointer to USART device
|
|
******************************************************************************/
|
|
static struct efm32_usart_device_t *rt_hw_usart_unit_init(
|
|
rt_device_t device,
|
|
rt_uint8_t unitNumber,
|
|
rt_uint8_t location,
|
|
rt_uint32_t flag,
|
|
rt_uint32_t dmaChannel,
|
|
rt_uint8_t config)
|
|
{
|
|
struct efm32_usart_device_t *usart;
|
|
struct efm32_usart_dma_mode_t *dma_mode;
|
|
DMA_CB_TypeDef *callback;
|
|
CMU_Clock_TypeDef usartClock;
|
|
rt_uint32_t txDmaSelect;
|
|
GPIO_Port_TypeDef port_tx, port_rx, port_clk, port_cs;
|
|
rt_uint32_t pin_tx, pin_rx, pin_clk, pin_cs;
|
|
efm32_irq_hook_init_t hook;
|
|
|
|
do
|
|
{
|
|
/* Allocate device */
|
|
usart = rt_malloc(sizeof(struct efm32_usart_device_t));
|
|
if (usart == RT_NULL)
|
|
{
|
|
usart_debug("USART%d err: no mem\n", usart->unit);
|
|
break;
|
|
}
|
|
usart->counter = 0;
|
|
usart->unit = unitNumber;
|
|
usart->state = config;
|
|
usart->tx_mode = RT_NULL;
|
|
usart->rx_mode = RT_NULL;
|
|
|
|
/* Allocate TX */
|
|
dma_mode = RT_NULL;
|
|
if (flag & RT_DEVICE_FLAG_DMA_TX)
|
|
{
|
|
usart->tx_mode = dma_mode = rt_malloc(sizeof(struct efm32_usart_dma_mode_t));
|
|
if (dma_mode == RT_NULL)
|
|
{
|
|
usart_debug("USART%d err: no mem for DMA TX\n", usart->unit);
|
|
break;
|
|
}
|
|
dma_mode->dma_channel = dmaChannel;
|
|
}
|
|
|
|
/* Allocate RX */
|
|
if (flag & RT_DEVICE_FLAG_INT_RX)
|
|
{
|
|
usart->rx_mode = rt_malloc(sizeof(struct efm32_usart_int_mode_t));
|
|
if (usart->rx_mode == RT_NULL)
|
|
{
|
|
usart_debug("USART%d err: no mem for INT RX\n", usart->unit);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Initialization */
|
|
#if defined(UART_PRESENT)
|
|
if ((!(config & USART_STATE_ASYNC_ONLY) && (unitNumber >= USART_COUNT)) || \
|
|
((config & USART_STATE_ASYNC_ONLY) && (unitNumber >= UART_COUNT)))
|
|
#else
|
|
if (unitNumber >= USART_COUNT)
|
|
#endif
|
|
{
|
|
break;
|
|
}
|
|
switch (unitNumber)
|
|
{
|
|
case 0:
|
|
#if defined(UART_PRESENT)
|
|
if (config & USART_STATE_ASYNC_ONLY)
|
|
{
|
|
usart->usart_device = UART0;
|
|
usartClock = (CMU_Clock_TypeDef)cmuClock_UART0;
|
|
txDmaSelect = DMAREQ_UART0_TXBL;
|
|
port_tx = AF_UART0_TX_PORT(location);
|
|
pin_tx = AF_UART0_TX_PIN(location);
|
|
port_rx = AF_UART0_RX_PORT(location);
|
|
pin_rx = AF_UART0_RX_PIN(location);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
usart->usart_device = USART0;
|
|
usartClock = (CMU_Clock_TypeDef)cmuClock_USART0;
|
|
txDmaSelect = DMAREQ_USART0_TXBL;
|
|
port_tx = AF_USART0_TX_PORT(location);
|
|
pin_tx = AF_USART0_TX_PIN(location);
|
|
port_rx = AF_USART0_RX_PORT(location);
|
|
pin_rx = AF_USART0_RX_PIN(location);
|
|
port_clk = AF_USART0_CLK_PORT(location);
|
|
pin_clk = AF_USART0_CLK_PIN(location);
|
|
port_cs = AF_USART0_CS_PORT(location);
|
|
pin_cs = AF_USART0_CS_PIN(location);
|
|
}
|
|
break;
|
|
#if ((defined(USART_PRESENT) && (USART_COUNT > 1)) || \
|
|
(defined(UART_PRESENT) && (UART_COUNT > 1)))
|
|
case 1:
|
|
#if (defined(UART_PRESENT) && (UART_COUNT > 1))
|
|
if (config & USART_STATE_ASYNC_ONLY)
|
|
{
|
|
usart->usart_device = UART1;
|
|
usartClock = (CMU_Clock_TypeDef)cmuClock_UART1;
|
|
txDmaSelect = DMAREQ_UART1_TXBL;
|
|
port_tx = AF_UART1_TX_PORT(location);
|
|
pin_tx = AF_UART1_TX_PIN(location);
|
|
port_rx = AF_UART1_RX_PORT(location);
|
|
pin_rx = AF_UART1_RX_PIN(location);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
usart->usart_device = USART1;
|
|
usartClock = (CMU_Clock_TypeDef)cmuClock_USART1;
|
|
txDmaSelect = DMAREQ_USART1_TXBL;
|
|
port_tx = AF_USART1_TX_PORT(location);
|
|
pin_tx = AF_USART1_TX_PIN(location);
|
|
port_rx = AF_USART1_RX_PORT(location);
|
|
pin_rx = AF_USART1_RX_PIN(location);
|
|
port_clk = AF_USART1_CLK_PORT(location);
|
|
pin_clk = AF_USART1_CLK_PIN(location);
|
|
port_cs = AF_USART1_CS_PORT(location);
|
|
pin_cs = AF_USART1_CS_PIN(location);
|
|
}
|
|
break;
|
|
#endif
|
|
#if ((defined(USART_PRESENT) && (USART_COUNT > 2)) || \
|
|
(defined(UART_PRESENT) && (UART_COUNT > 2)))
|
|
case 2:
|
|
#if (defined(UART_PRESENT) && (UART_COUNT > 2))
|
|
if (config & USART_STATE_ASYNC_ONLY)
|
|
{
|
|
usart->usart_device = UART2;
|
|
usartClock = (CMU_Clock_TypeDef)cmuClock_UART2;
|
|
txDmaSelect = DMAREQ_UART2_TXBL;
|
|
port_tx = AF_UART2_TX_PORT(location);
|
|
pin_tx = AF_UART2_TX_PIN(location);
|
|
port_rx = AF_UART2_RX_PORT(location);
|
|
pin_rx = AF_UART2_RX_PIN(location);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
usart->usart_device = USART2;
|
|
usartClock = (CMU_Clock_TypeDef)cmuClock_USART2;
|
|
txDmaSelect = DMAREQ_USART2_TXBL;
|
|
port_tx = AF_USART2_TX_PORT(location);
|
|
pin_tx = AF_USART2_TX_PIN(location);
|
|
port_rx = AF_USART2_RX_PORT(location);
|
|
pin_rx = AF_USART2_RX_PIN(location);
|
|
port_clk = AF_USART2_CLK_PORT(location);
|
|
pin_clk = AF_USART2_CLK_PIN(location);
|
|
port_cs = AF_USART2_CS_PORT(location);
|
|
pin_cs = AF_USART2_CS_PIN(location);
|
|
}
|
|
break;
|
|
#endif
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/* Enable USART clock */
|
|
CMU_ClockEnable(usartClock, true);
|
|
|
|
/* Config GPIO */
|
|
GPIO_PinModeSet(
|
|
port_tx,
|
|
pin_tx,
|
|
gpioModePushPull,
|
|
0);
|
|
GPIO_PinModeSet(
|
|
port_rx,
|
|
pin_rx,
|
|
gpioModeInputPull,
|
|
1);
|
|
if (config & USART_STATE_SYNC)
|
|
{
|
|
GPIO_PinModeSet(
|
|
port_clk,
|
|
pin_clk,
|
|
gpioModePushPull,
|
|
0);
|
|
}
|
|
if (config & USART_STATE_AUTOCS)
|
|
{
|
|
GPIO_PinModeSet(
|
|
port_cs,
|
|
pin_cs,
|
|
gpioModePushPull,
|
|
1);
|
|
}
|
|
|
|
/* Config interrupt and NVIC */
|
|
if (flag & RT_DEVICE_FLAG_INT_RX)
|
|
{
|
|
hook.type = efm32_irq_type_usart;
|
|
hook.unit = unitNumber * 2 + 1;
|
|
#if defined(UART_PRESENT)
|
|
if (config & USART_STATE_ASYNC_ONLY)
|
|
{
|
|
hook.unit += USART_COUNT * 2;
|
|
}
|
|
#endif
|
|
hook.cbFunc = rt_hw_usart_rx_isr;
|
|
hook.userPtr = device;
|
|
efm32_irq_hook_register(&hook);
|
|
}
|
|
|
|
/* Config DMA */
|
|
if (flag & RT_DEVICE_FLAG_DMA_TX)
|
|
{
|
|
DMA_CfgChannel_TypeDef chnlCfg;
|
|
DMA_CfgDescr_TypeDef descrCfg;
|
|
|
|
hook.type = efm32_irq_type_dma;
|
|
hook.unit = dmaChannel;
|
|
hook.cbFunc = rt_hw_usart_dma_tx_isr;
|
|
hook.userPtr = device;
|
|
efm32_irq_hook_register(&hook);
|
|
|
|
callback = (DMA_CB_TypeDef *)rt_malloc(sizeof(DMA_CB_TypeDef));
|
|
if (callback == RT_NULL)
|
|
{
|
|
usart_debug("USART%d err: no mem for callback\n", usart->unit);
|
|
break;
|
|
}
|
|
callback->cbFunc = DMA_IRQHandler_All;
|
|
callback->userPtr = RT_NULL;
|
|
callback->primary = 0;
|
|
|
|
/* Setting up DMA channel */
|
|
chnlCfg.highPri = false; /* Can't use with peripherals */
|
|
chnlCfg.enableInt = true; /* Interrupt for callback function */
|
|
chnlCfg.select = txDmaSelect;
|
|
chnlCfg.cb = callback;
|
|
DMA_CfgChannel(dmaChannel, &chnlCfg);
|
|
|
|
/* Setting up DMA channel descriptor */
|
|
descrCfg.dstInc = dmaDataIncNone;
|
|
descrCfg.srcInc = dmaDataInc1;
|
|
descrCfg.size = dmaDataSize1;
|
|
descrCfg.arbRate = dmaArbitrate1;
|
|
descrCfg.hprot = 0;
|
|
DMA_CfgDescr(dmaChannel, true, &descrCfg);
|
|
}
|
|
|
|
/* Init specified USART unit */
|
|
if (config & USART_STATE_SYNC)
|
|
{
|
|
USART_InitSync_TypeDef init_sync = USART_INITSYNC_DEFAULT;
|
|
|
|
init_sync.enable = usartEnable;
|
|
init_sync.refFreq = 0;
|
|
init_sync.baudrate = SPI_BAUDRATE;
|
|
if (config & USART_STATE_9BIT)
|
|
{
|
|
init_sync.databits = usartDatabits9;
|
|
}
|
|
else
|
|
{
|
|
init_sync.databits = usartDatabits8;
|
|
}
|
|
if (config & USART_STATE_MASTER)
|
|
{
|
|
init_sync.master = true;
|
|
}
|
|
else
|
|
{
|
|
init_sync.master = false;
|
|
}
|
|
init_sync.msbf = true;
|
|
|
|
switch (USART_CLK_MODE_GET(config))
|
|
{
|
|
case 0:
|
|
init_sync.clockMode = usartClockMode0;
|
|
break;
|
|
case 1:
|
|
init_sync.clockMode = usartClockMode1;
|
|
break;
|
|
case 2:
|
|
init_sync.clockMode = usartClockMode2;
|
|
break;
|
|
case 3:
|
|
init_sync.clockMode = usartClockMode3;
|
|
break;
|
|
}
|
|
USART_InitSync(usart->usart_device, &init_sync);
|
|
}
|
|
else
|
|
{
|
|
USART_InitAsync_TypeDef init_async = USART_INITASYNC_DEFAULT;
|
|
|
|
init_async.enable = usartEnable;
|
|
init_async.refFreq = 0;
|
|
init_async.baudrate = UART_BAUDRATE;
|
|
init_async.oversampling = USART_CTRL_OVS_X4;
|
|
init_async.databits = USART_FRAME_DATABITS_EIGHT;
|
|
init_async.parity = USART_FRAME_PARITY_NONE;
|
|
init_async.stopbits = USART_FRAME_STOPBITS_ONE;
|
|
USART_InitAsync(usart->usart_device, &init_async);
|
|
}
|
|
|
|
/* Enable RX and TX pins and set location */
|
|
usart->usart_device->ROUTE = USART_ROUTE_RXPEN | USART_ROUTE_TXPEN | \
|
|
(location << _USART_ROUTE_LOCATION_SHIFT);
|
|
if (config & USART_STATE_SYNC)
|
|
{
|
|
usart->usart_device->ROUTE |= USART_ROUTE_CLKPEN;
|
|
}
|
|
if (config & USART_STATE_AUTOCS)
|
|
{
|
|
usart->usart_device->ROUTE |= USART_ROUTE_CSPEN;
|
|
if (config & USART_STATE_MASTER)
|
|
{
|
|
usart->usart_device->CTRL |= USART_CTRL_AUTOCS;
|
|
}
|
|
}
|
|
|
|
/* Clear RX/TX buffers */
|
|
usart->usart_device->CMD = USART_CMD_CLEARRX | USART_CMD_CLEARTX;
|
|
|
|
return usart;
|
|
} while(0);
|
|
|
|
if (usart->rx_mode)
|
|
{
|
|
rt_free(usart->rx_mode);
|
|
}
|
|
if (usart->tx_mode)
|
|
{
|
|
rt_free(usart->tx_mode);
|
|
}
|
|
if (usart)
|
|
{
|
|
rt_free(usart);
|
|
}
|
|
if (callback)
|
|
{
|
|
rt_free(callback);
|
|
}
|
|
|
|
#if defined(UART_PRESENT)
|
|
if (config & USART_STATE_ASYNC_ONLY)
|
|
{
|
|
usart_debug("UART%d err: init failed!\n", unitNumber);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
usart_debug("USART%d err: init failed!\n", unitNumber);
|
|
}
|
|
return RT_NULL;
|
|
}
|
|
|
|
/***************************************************************************//**
|
|
* @brief
|
|
* Initialize all USART module related hardware and register USART device to
|
|
* kernel
|
|
*
|
|
* @details
|
|
*
|
|
* @note
|
|
******************************************************************************/
|
|
void rt_hw_usart_init(void)
|
|
{
|
|
struct efm32_usart_device_t *usart;
|
|
rt_uint32_t flag;
|
|
rt_uint8_t config;
|
|
|
|
do
|
|
{
|
|
#if (defined(USART_PRESENT) && defined(RT_USING_USART0))
|
|
config = 0x00;
|
|
flag = RT_DEVICE_FLAG_RDWR;
|
|
|
|
#ifdef RT_USART0_SYNC_MODE
|
|
config |= USART_STATE_SYNC;
|
|
config |= (RT_USART0_SYNC_MODE & SYNC_SETTING_MASK) << SYNC_SETTING_SHIFT;
|
|
#if (!((RT_USART0_SYNC_MODE << SYNC_SETTING_SHIFT) & USART_STATE_MASTER))
|
|
flag |= RT_DEVICE_FLAG_INT_RX;
|
|
#endif
|
|
#else
|
|
flag |= RT_DEVICE_FLAG_INT_RX;
|
|
#endif
|
|
|
|
#if (RT_CONSOLE_DEVICE == EFM_USART0)
|
|
config |= USART_STATE_CONSOLE;
|
|
flag |= RT_DEVICE_FLAG_STREAM;
|
|
#endif
|
|
|
|
#ifdef RT_USART0_USING_DMA
|
|
RT_ASSERT(RT_USART0_USING_DMA < DMA_CHAN_COUNT);
|
|
flag |= RT_DEVICE_FLAG_DMA_TX;
|
|
#else
|
|
#define RT_USART0_USING_DMA EFM32_NO_DMA
|
|
#endif
|
|
|
|
/* Initialize and Register usart0 */
|
|
if ((usart = rt_hw_usart_unit_init(
|
|
&usart0_device,
|
|
0,
|
|
RT_USING_USART0,
|
|
flag,
|
|
RT_USART0_USING_DMA,
|
|
config)) != RT_NULL)
|
|
{
|
|
rt_hw_usart_register(&usart0_device, RT_USART0_NAME, flag, usart);
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
/* Initialize lock for usart0 */
|
|
usart->lock = &usart0_lock;
|
|
if (rt_sem_init(usart->lock, RT_USART0_NAME, 1, RT_IPC_FLAG_FIFO) != RT_EOK)
|
|
{
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
#if (defined(USART_PRESENT) && (USART_COUNT > 1) && defined(RT_USING_USART1))
|
|
config = 0x00;
|
|
flag = RT_DEVICE_FLAG_RDWR;
|
|
|
|
#ifdef RT_USART1_SYNC_MODE
|
|
config |= USART_STATE_SYNC;
|
|
config |= (RT_USART1_SYNC_MODE & SYNC_SETTING_MASK) << SYNC_SETTING_SHIFT;
|
|
#if (!((RT_USART1_SYNC_MODE << SYNC_SETTING_SHIFT) & USART_STATE_MASTER))
|
|
flag |= RT_DEVICE_FLAG_INT_RX;
|
|
#endif
|
|
#else
|
|
flag |= RT_DEVICE_FLAG_INT_RX;
|
|
#endif
|
|
|
|
#if (RT_CONSOLE_DEVICE == EFM_USART1)
|
|
config |= USART_STATE_CONSOLE;
|
|
flag |= RT_DEVICE_FLAG_STREAM;
|
|
#endif
|
|
|
|
#ifdef RT_USART1_USING_DMA
|
|
RT_ASSERT(RT_USART1_USING_DMA < DMA_CHAN_COUNT);
|
|
flag |= RT_DEVICE_FLAG_DMA_TX;
|
|
#else
|
|
|
|
#define RT_USART1_USING_DMA EFM32_NO_DMA
|
|
#endif
|
|
|
|
/* Initialize and Register usart1 */
|
|
if ((usart = rt_hw_usart_unit_init(
|
|
&usart1_device,
|
|
1,
|
|
RT_USING_USART1,
|
|
flag,
|
|
RT_USART1_USING_DMA,
|
|
config)) != RT_NULL)
|
|
{
|
|
rt_hw_usart_register(&usart1_device, RT_USART1_NAME, flag, usart);
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
/* Initialize lock for usart1 */
|
|
usart->lock = &usart1_lock;
|
|
if (rt_sem_init(usart->lock, RT_USART1_NAME, 1, RT_IPC_FLAG_FIFO) != RT_EOK)
|
|
{
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
#if (defined(USART_PRESENT) && (USART_COUNT > 2) && defined(RT_USING_USART2))
|
|
config = 0x00;
|
|
flag = RT_DEVICE_FLAG_RDWR;
|
|
|
|
#ifdef RT_USART2_SYNC_MODE
|
|
config |= USART_STATE_SYNC;
|
|
config |= (RT_USART2_SYNC_MODE & SYNC_SETTING_MASK) << SYNC_SETTING_SHIFT;
|
|
#if (!((RT_USART2_SYNC_MODE << SYNC_SETTING_SHIFT) & USART_STATE_MASTER))
|
|
flag |= RT_DEVICE_FLAG_INT_RX;
|
|
#endif
|
|
#else
|
|
flag |= RT_DEVICE_FLAG_INT_RX;
|
|
#endif
|
|
|
|
#if (RT_CONSOLE_DEVICE == EFM_USART2)
|
|
config |= USART_STATE_CONSOLE;
|
|
flag |= RT_DEVICE_FLAG_STREAM;
|
|
#endif
|
|
|
|
#ifdef RT_USART2_USING_DMA
|
|
RT_ASSERT(RT_USART2_USING_DMA < DMA_CHAN_COUNT);
|
|
flag |= RT_DEVICE_FLAG_DMA_TX;
|
|
|
|
#else
|
|
|
|
#define RT_USART2_USING_DMA EFM32_NO_DMA
|
|
#endif
|
|
|
|
/* Initialize and Register usart2 */
|
|
if ((usart = rt_hw_usart_unit_init(
|
|
&usart2_device,
|
|
2,
|
|
RT_USING_USART2,
|
|
flag,
|
|
RT_USART2_USING_DMA,
|
|
config)) != RT_NULL)
|
|
{
|
|
rt_hw_usart_register(&usart2_device, RT_USART2_NAME, flag, usart);
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
/* Initialize lock for usart2 */
|
|
usart->lock = &usart2_lock;
|
|
if (rt_sem_init(usart->lock, RT_USART2_NAME, 1, RT_IPC_FLAG_FIFO) != RT_EOK)
|
|
{
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
#if (defined(UART_PRESENT) && defined(RT_USING_UART0))
|
|
config = USART_STATE_ASYNC_ONLY;
|
|
flag = RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX;
|
|
|
|
#if (RT_CONSOLE_DEVICE == EFM_UART0)
|
|
config |= USART_STATE_CONSOLE;
|
|
flag |= RT_DEVICE_FLAG_STREAM;
|
|
#endif
|
|
|
|
#ifdef RT_UART0_USING_DMA
|
|
RT_ASSERT(RT_UART0_USING_DMA < DMA_CHAN_COUNT);
|
|
flag |= RT_DEVICE_FLAG_DMA_TX;
|
|
#else
|
|
#define RT_UART0_USING_DMA EFM32_NO_DMA
|
|
#endif
|
|
|
|
/* Initialize and Register uart0 */
|
|
if ((usart = rt_hw_usart_unit_init(
|
|
&uart0_device,
|
|
0,
|
|
RT_USING_UART0,
|
|
flag,
|
|
RT_UART0_USING_DMA,
|
|
config)) != RT_NULL)
|
|
{
|
|
rt_hw_usart_register(&uart0_device, RT_UART0_NAME, flag, usart);
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
/* Initialize lock for uart0 */
|
|
usart->lock = &uart0_lock;
|
|
if (rt_sem_init(usart->lock, RT_UART0_NAME, 1, RT_IPC_FLAG_FIFO) != RT_EOK)
|
|
{
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
#if (defined(UART_PRESENT) && (UART_COUNT > 1) && defined(RT_USING_UART1))
|
|
config = USART_STATE_ASYNC_ONLY;
|
|
flag = RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX;
|
|
|
|
#if (RT_CONSOLE_DEVICE == EFM_UART1)
|
|
config |= USART_STATE_CONSOLE;
|
|
flag |= RT_DEVICE_FLAG_STREAM;
|
|
#endif
|
|
|
|
#ifdef RT_UART1_USING_DMA
|
|
RT_ASSERT(RT_UART1_USING_DMA < DMA_CHAN_COUNT);
|
|
flag |= RT_DEVICE_FLAG_DMA_TX;
|
|
#else
|
|
#define RT_UART1_USING_DMA EFM32_NO_DMA
|
|
#endif
|
|
|
|
/* Initialize and Register uart1 */
|
|
if ((usart = rt_hw_usart_unit_init(
|
|
&uart1_device,
|
|
1,
|
|
RT_USING_UART1,
|
|
flag,
|
|
RT_UART1_USING_DMA,
|
|
config)) != RT_NULL)
|
|
{
|
|
rt_hw_usart_register(&uart1_device, RT_UART1_NAME, flag, usart);
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
/* Initialize lock for uart1 */
|
|
usart->lock = &uart1_lock;
|
|
if (rt_sem_init(usart->lock, RT_UART1_NAME, 1, RT_IPC_FLAG_FIFO) != RT_EOK)
|
|
{
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
usart_debug("USART: H/W init OK!\n");
|
|
return;
|
|
} while (0);
|
|
|
|
rt_kprintf("USART: H/W init failed!\n");
|
|
}
|
|
|
|
#endif /* (defined(RT_USING_USART0) || defined(RT_USING_USART1) || \
|
|
defined(RT_USING_USART2) || defined(RT_USING_UART0) || \
|
|
defined(RT_USING_UART1)) */
|
|
/***************************************************************************//**
|
|
* @}
|
|
******************************************************************************/
|