Files
zTC1/mico-os/platform/MCU/MTK7697/peripherals/platform_uart.c

376 lines
11 KiB
C

/**
******************************************************************************
* @file platform_uart.c
* @author William Xu
* @version V1.0.0
* @date 05-May-2014
* @brief This file provide UART driver functions.
******************************************************************************
* UNPUBLISHED PROPRIETARY SOURCE CODE
* Copyright (c) 2016 MXCHIP Inc.
*
* The contents of this file may not be disclosed to third parties, copied or
* duplicated in any form, in whole or in part, without the prior written
* permission of MXCHIP Corporation.
******************************************************************************
*/
#include "platform.h"
#include "platform_core.h"
#include "platform_peripheral.h"
#include "debug.h"
/******************************************************
* Constants
******************************************************/
/******************************************************
* Enumerations
******************************************************/
/******************************************************
* Type Definitions
******************************************************/
#define VFIFO_SIZE (1024)
static uint8_t uart0_tx_fifo[VFIFO_SIZE];
static uint8_t uart0_rx_fifo[VFIFO_SIZE];
static uint8_t uart1_tx_fifo[VFIFO_SIZE];
static uint8_t uart1_rx_fifo[VFIFO_SIZE];
typedef struct
{
hal_gpio_pin_t tx_pin;
uint8_t tx_func;
uint8_t *tx_fifo_buf;
uint16_t tx_size;
mico_semaphore_t tx_semphr;
mico_mutex_t tx_mutex;
void (*tx_callback)(void);
hal_gpio_pin_t rx_pin;
uint8_t rx_func;
uint8_t *rx_fifo_buf;
uint16_t rx_size;
mico_semaphore_t rx_semphr;
void (*rx_callback)(void);
} uart_config_t;
/******************************************************
* Structures
******************************************************/
/******************************************************
* Variables Definitions
******************************************************/
extern uint32_t mico_rtos_get_time(void);
/******************************************************
* Static Function Declarations
******************************************************/
static void uart0_rx_callback(void);
static void uart0_tx_callback(void);
static void uart1_rx_callback(void);
static void uart1_tx_callback(void);
/******************************************************
* Function Definitions
******************************************************/
uart_config_t uart_config[HAL_UART_MAX] =
{
[HAL_UART_0] =
{
.rx_pin = HAL_GPIO_2,
.rx_func = HAL_GPIO_2_UART1_RX_CM4,
.rx_size = 0,
.rx_fifo_buf = uart0_rx_fifo,
.rx_callback = uart0_rx_callback,
.tx_pin = HAL_GPIO_3,
.tx_func = HAL_GPIO_3_UART1_TX_CM4,
.tx_size = 0,
.tx_fifo_buf = uart0_tx_fifo,
.tx_callback = uart0_tx_callback,
},
[HAL_UART_1] =
{
.rx_pin = HAL_GPIO_36,
.rx_func = HAL_GPIO_36_UART2_RX_CM4,
.rx_size = 0,
.rx_fifo_buf = uart1_rx_fifo,
.rx_callback = uart1_rx_callback,
.tx_pin = HAL_GPIO_37,
.tx_func = HAL_GPIO_37_UART2_TX_CM4,
.tx_size = 0,
.tx_fifo_buf = uart1_tx_fifo,
.tx_callback = uart1_tx_callback,
},
};
/**
* Initialise the specified UART port
*
* @return @ref OSStatus
*/
OSStatus platform_uart_init(platform_uart_driver_t* driver,
const platform_uart_t* peripheral, const platform_uart_config_t* config,
ring_buffer_t* optional_ring_buffer)
{
driver->peripheral = (platform_uart_t*) peripheral;
if (driver->initialized == false) {
mico_rtos_init_semaphore(&uart_config[peripheral->port].rx_semphr, 1);
mico_rtos_init_semaphore(&uart_config[peripheral->port].tx_semphr, 1);
mico_rtos_init_mutex(&uart_config[peripheral->port].tx_mutex);
hal_gpio_init(uart_config[peripheral->port].rx_pin);
hal_pinmux_set_function(uart_config[peripheral->port].rx_pin,
uart_config[peripheral->port].rx_func);
hal_gpio_init(uart_config[peripheral->port].tx_pin);
hal_pinmux_set_function(uart_config[peripheral->port].tx_pin,
uart_config[peripheral->port].tx_func);
/* Configure UART port to dma mode */
hal_uart_dma_config_t dma_config;
dma_config.receive_vfifo_alert_size = 0;
dma_config.receive_vfifo_buffer = uart_config[peripheral->port].rx_fifo_buf;
dma_config.receive_vfifo_buffer_size = VFIFO_SIZE;
dma_config.receive_vfifo_threshold_size = VFIFO_SIZE;
dma_config.send_vfifo_buffer = uart_config[peripheral->port].tx_fifo_buf;
dma_config.send_vfifo_buffer_size = VFIFO_SIZE;
dma_config.send_vfifo_threshold_size = 0;
hal_uart_dma_init(peripheral->port, &dma_config);
hal_uart_dma_register_rx_callback(peripheral->port,
uart_config[peripheral->port].rx_callback);
hal_uart_dma_register_tx_callback(peripheral->port,
uart_config[peripheral->port].tx_callback);
}
/* Configure UART port with basic function */
hal_uart_config_t basic_config;
switch (config->baud_rate) {
case 9600:
basic_config.baudrate = HAL_UART_BAUDRATE_9600;
break;
case 38400:
basic_config.baudrate = HAL_UART_BAUDRATE_38400;
break;
case 57600:
basic_config.baudrate = HAL_UART_BAUDRATE_57600;
break;
case 115200:
basic_config.baudrate = HAL_UART_BAUDRATE_115200;
break;
case 230400:
basic_config.baudrate = HAL_UART_BAUDRATE_230400;
break;
case 460800:
basic_config.baudrate = HAL_UART_BAUDRATE_460800;
break;
case 921600:
basic_config.baudrate = HAL_UART_BAUDRATE_921600;
break;
default:
return kParamErr;
}
switch (config->parity) {
case NO_PARITY:
basic_config.parity = HAL_UART_PARITY_NONE;
break;
case ODD_PARITY:
basic_config.parity = HAL_UART_PARITY_ODD;
break;
case EVEN_PARITY:
basic_config.parity = HAL_UART_PARITY_EVEN;
break;
default:
return kParamErr;
}
switch (config->stop_bits) {
case STOP_BITS_1:
basic_config.stop_bit = HAL_UART_STOP_BIT_1;
break;
case STOP_BITS_2:
basic_config.stop_bit = HAL_UART_STOP_BIT_2;
break;
default:
return kParamErr;
}
switch (config->data_width) {
case DATA_WIDTH_5BIT:
basic_config.word_length = HAL_UART_WORD_LENGTH_5;
break;
case DATA_WIDTH_6BIT:
basic_config.word_length = HAL_UART_WORD_LENGTH_6;
break;
case DATA_WIDTH_7BIT:
basic_config.word_length = HAL_UART_WORD_LENGTH_7;
break;
case DATA_WIDTH_8BIT:
basic_config.word_length = HAL_UART_WORD_LENGTH_8;
break;
default:
return kParamErr;
}
hal_uart_init(peripheral->port, &basic_config);
driver->initialized = true;
return kNoErr;
}
/**
* Deinitialise the specified UART port
*
* @return @ref OSStatus
*/
OSStatus platform_uart_deinit(platform_uart_driver_t* driver)
{
hal_uart_deinit(driver->peripheral->port);
//Disable DMA interrupt, note that we use the DMA interrupt to process UART data
NVIC_DisableIRQ((IRQn_Type) CM4_DMA_IRQ);
mico_rtos_deinit_semaphore(&uart_config[driver->peripheral->port].rx_semphr);
mico_rtos_deinit_semaphore(&uart_config[driver->peripheral->port].tx_semphr);
mico_rtos_deinit_mutex(&uart_config[driver->peripheral->port].tx_mutex);
driver->initialized = false;
return kNoErr;
}
/**
* Transmit data over the specified UART port
*
* @return @ref OSStatus
*/
OSStatus platform_uart_transmit_bytes(platform_uart_driver_t* driver,
const uint8_t* data_out, uint32_t size)
{
platform_uart_port_t port = driver->peripheral->port;
uart_config_t *config = &uart_config[port];
uint8_t in_interrupt = platform_is_in_interrupt_context() == MICO_TRUE ? 1 : 0;
if(in_interrupt == 0){
mico_rtos_lock_mutex(&config->tx_mutex);
}
uint8_t *send_start = (uint8_t*) data_out;
uint32_t need_to_send = size;
uint32_t send_size;
if (need_to_send > hal_uart_get_available_send_space(port)) {
while (1) {
if (need_to_send > VFIFO_SIZE) {
send_size = VFIFO_SIZE;
}
else {
send_size = need_to_send;
}
if(in_interrupt == 0){
hal_uart_dma_set_tx_threshold(port, VFIFO_SIZE - send_size + 1);
hal_uart_dma_set_tx_interrupt(port, 1);
mico_rtos_get_semaphore(&config->tx_semphr, MICO_NEVER_TIMEOUT);
}else{
while(!(hal_uart_get_available_send_space(port) > send_size));
}
send_size = hal_uart_dma_tx(port, send_start, send_size);
send_start += send_size;
need_to_send -= send_size;
if (need_to_send == 0) {
break;
}
}
}
else {
hal_uart_dma_tx(port, send_start, need_to_send);
}
if(in_interrupt == 0){
mico_rtos_unlock_mutex(&config->tx_mutex);
}
return kNoErr;
}
/**
* Receive data over the specified UART port
*
* @return @ref OSStatus
*/
OSStatus platform_uart_receive_bytes(platform_uart_driver_t* driver,
uint8_t* data_in, uint32_t expected_data_size, uint32_t timeout_ms)
{
platform_uart_port_t port = driver->peripheral->port;
uart_config_t *config = &uart_config[port];
uint8_t *receive_start = data_in;
uint32_t need_to_receive = expected_data_size;
uint32_t receive_size;
if (need_to_receive > hal_uart_get_available_receive_bytes(port)) {
uint32_t start_time = mico_rtos_get_time();
uint32_t wait_time = timeout_ms;
mico_rtos_get_semaphore(&config->rx_semphr, MICO_NO_WAIT);
while (1) {
if (need_to_receive > VFIFO_SIZE) {
receive_size = VFIFO_SIZE;
}
else {
receive_size = need_to_receive;
}
hal_uart_dma_set_rx_threshold(port, receive_size - 1);
hal_uart_dma_set_rx_interrupt(port, 1);
if (mico_rtos_get_semaphore(&config->rx_semphr, wait_time) == kTimeoutErr) {
return kTimeoutErr;
}
receive_size = hal_uart_dma_rx(port, receive_start, receive_size);
if (timeout_ms != MICO_WAIT_FOREVER) {
wait_time -= mico_rtos_get_time() - start_time;
}
receive_start += receive_size;
need_to_receive -= receive_size;
if (need_to_receive == 0) {
break;
}
}
}
else {
hal_uart_dma_rx(port, receive_start, need_to_receive);
}
return kNoErr;
}
/**
* Get the received data length in ring buffer over the specified UART port
*
* @return
*/
uint32_t platform_uart_get_length_in_buffer(platform_uart_driver_t* driver)
{
return hal_uart_get_available_receive_bytes(driver->peripheral->port);
}
static void uart0_rx_callback(void)
{
mico_rtos_set_semaphore(&uart_config[HAL_UART_0].rx_semphr);
hal_uart_dma_set_rx_interrupt(HAL_UART_0, 0);
}
static void uart0_tx_callback(void)
{
mico_rtos_set_semaphore(&uart_config[HAL_UART_0].tx_semphr);
hal_uart_dma_set_tx_interrupt(HAL_UART_0, 0);
}
static void uart1_rx_callback(void)
{
mico_rtos_set_semaphore(&uart_config[HAL_UART_1].rx_semphr);
hal_uart_dma_set_rx_interrupt(HAL_UART_1, 0);
}
static void uart1_tx_callback(void)
{
mico_rtos_set_semaphore(&uart_config[HAL_UART_1].tx_semphr);
hal_uart_dma_set_tx_interrupt(HAL_UART_1, 0);
}