mirror of
https://github.com/oopuuu/zTC1.git
synced 2025-12-17 23:48:13 +08:00
376 lines
11 KiB
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);
|
|
}
|