You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
719 lines
20 KiB
719 lines
20 KiB
5 months ago
|
/* ****************************************************************************
|
||
|
* Copyright (C) 2014-2018 Maxim Integrated Products, Inc., All Rights Reserved.
|
||
|
*
|
||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||
|
* copy of this software and associated documentation files (the "Software"),
|
||
|
* to deal in the Software without restriction, including without limitation
|
||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||
|
* Software is furnished to do so, subject to the following conditions:
|
||
|
*
|
||
|
* The above copyright notice and this permission notice shall be included
|
||
|
* in all copies or substantial portions of the Software.
|
||
|
*
|
||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||
|
* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
|
||
|
* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||
|
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||
|
* OTHER DEALINGS IN THE SOFTWARE.
|
||
|
*
|
||
|
* Except as contained in this notice, the name of Maxim Integrated
|
||
|
* Products, Inc. shall not be used except as stated in the Maxim Integrated
|
||
|
* Products, Inc. Branding Policy.
|
||
|
*
|
||
|
* The mere transfer of this software does not imply any licenses
|
||
|
* of trade secrets, proprietary technology, copyrights, patents,
|
||
|
* trademarks, maskwork rights, or any other form of intellectual
|
||
|
* property whatsoever. Maxim Integrated Products, Inc. retains all
|
||
|
* ownership rights.
|
||
|
*
|
||
|
* $Date: 2020-09-08 13:28:39 -0500 (Tue, 08 Sep 2020) $
|
||
|
* $Revision: 55611 $
|
||
|
*
|
||
|
*************************************************************************** */
|
||
|
|
||
|
/* **** Includes **** */
|
||
|
#include <stdint.h>
|
||
|
#include <string.h>
|
||
|
#include "mxc_config.h"
|
||
|
#include "mxc_assert.h"
|
||
|
#include "uart_regs.h"
|
||
|
#include "uart.h"
|
||
|
#include "mxc_lock.h"
|
||
|
#include "mxc_sys.h"
|
||
|
|
||
|
/* **** Definitions **** */
|
||
|
|
||
|
#define UART_ER_IF (MXC_F_UART_INT_FL_RX_FRAME_ERROR | \
|
||
|
MXC_F_UART_INT_FL_RX_PARITY_ERROR | \
|
||
|
MXC_F_UART_INT_FL_RX_OVERRUN)
|
||
|
|
||
|
#define UART_ER_IE (MXC_F_UART_INT_EN_RX_FRAME_ERROR | \
|
||
|
MXC_F_UART_INT_EN_RX_PARITY_ERROR | \
|
||
|
MXC_F_UART_INT_EN_RX_OVERRUN )
|
||
|
|
||
|
#define UART_RX_IF (MXC_F_UART_INT_FL_RX_FIFO_THRESH)
|
||
|
|
||
|
#define UART_RX_IE (MXC_F_UART_INT_EN_RX_FIFO_THRESH)
|
||
|
|
||
|
#define UART_TX_IF (MXC_F_UART_INT_FL_TX_FIFO_ALMOST_EMPTY | \
|
||
|
MXC_F_UART_INT_FL_TX_FIFO_THRESH)
|
||
|
|
||
|
#define UART_TX_IE (MXC_F_UART_INT_EN_TX_FIFO_ALMOST_EMPTY | \
|
||
|
MXC_F_UART_INT_EN_TX_FIFO_THRESH)
|
||
|
|
||
|
#if (TARGET == 32660) || (TARGET == 32665)
|
||
|
#define MAX_FACTOR 3
|
||
|
#else
|
||
|
#define MAX_FACTOR 7
|
||
|
#endif
|
||
|
|
||
|
/* **** File Scope Data **** */
|
||
|
|
||
|
// Saves the state of the non-blocking read requests.
|
||
|
static uart_req_t *rx_states[MXC_UART_INSTANCES];
|
||
|
|
||
|
// Saves the state of the non-blocking write requests.
|
||
|
static uart_req_t *tx_states[MXC_UART_INSTANCES];
|
||
|
|
||
|
|
||
|
/* **** Functions **** */
|
||
|
static void UART_WriteHandler(mxc_uart_regs_t *uart, uart_req_t *req, int uart_num);
|
||
|
static void UART_ReadHandler(mxc_uart_regs_t *uart, uart_req_t *req, int uart_num,
|
||
|
uint32_t flags);
|
||
|
static uint32_t uart_error_check(mxc_uart_regs_t *uart);
|
||
|
static void uart_error_clear(mxc_uart_regs_t *uart);
|
||
|
|
||
|
/* ************************************************************************* */
|
||
|
uint32_t uart_error_check(mxc_uart_regs_t *uart)
|
||
|
{
|
||
|
return (uart->int_fl & UART_ER_IF);
|
||
|
}
|
||
|
|
||
|
/* ************************************************************************* */
|
||
|
void uart_error_clear(mxc_uart_regs_t *uart)
|
||
|
{
|
||
|
UART_ClearFlags(uart,UART_ER_IF);
|
||
|
}
|
||
|
|
||
|
/* ************************************************************************* */
|
||
|
int UART_Init(mxc_uart_regs_t *uart, const uart_cfg_t *cfg, const sys_cfg_uart_t* sys_cfg)
|
||
|
{
|
||
|
int err;
|
||
|
int uart_num;
|
||
|
|
||
|
uint32_t baud0 = 0, baud1 = 0,div;
|
||
|
int32_t factor = -1;
|
||
|
|
||
|
// Get the state array index
|
||
|
uart_num = MXC_UART_GET_IDX(uart);
|
||
|
if (uart_num == -1) {
|
||
|
return E_BAD_PARAM;
|
||
|
}
|
||
|
|
||
|
if ((err = SYS_UART_Init(uart, sys_cfg)) != E_NO_ERROR) {
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
// Initialize state pointers
|
||
|
rx_states[uart_num] = NULL;
|
||
|
tx_states[uart_num] = NULL;
|
||
|
|
||
|
// Drain FIFOs, enable UART, and set configuration
|
||
|
uart->ctrl = (MXC_F_UART_CTRL_ENABLE | cfg->parity | cfg->size | cfg->stop | cfg->flow | cfg->pol);
|
||
|
|
||
|
// Set the baud rate
|
||
|
// Calculate divisor
|
||
|
#if (TARGET != 32660)
|
||
|
uart->ctrl |= cfg->clksel;
|
||
|
if (cfg->clksel == UART_CLKSEL_ALTERNATE) {
|
||
|
div = UART_ALTERNATE_CLOCK_HZ / ((cfg->baud));
|
||
|
} else {
|
||
|
div = PeripheralClock / ((cfg->baud));
|
||
|
}
|
||
|
#else
|
||
|
div = PeripheralClock / ((cfg->baud));
|
||
|
#endif
|
||
|
// Search for integer and fractional baud rate registers based on divisor
|
||
|
do {
|
||
|
factor += 1;
|
||
|
baud0 = div >> (7-factor); // divide by 128,64,32,16 to extract integer part
|
||
|
baud1 = ((div << factor) - (baud0 << 7)); //subtract factor corrected div - integer parts
|
||
|
} while ((baud0 == 0) && (factor < MAX_FACTOR));
|
||
|
|
||
|
uart->baud0 = ((factor << MXC_F_UART_BAUD0_FACTOR_POS) | baud0);
|
||
|
#if (TARGET == 32660) || (TARGET == 32665) || (TARGET == 32650)
|
||
|
/* Erratum:
|
||
|
* Hardware bug causes exact baud rates to generate framing error. Slightly mis-adjust timing
|
||
|
* to help avoid this bug.
|
||
|
*/
|
||
|
if (baud1 > 3) {
|
||
|
uart->baud1 = baud1 - 3;
|
||
|
} else {
|
||
|
uart->baud1 = baud1 + 3;
|
||
|
}
|
||
|
#else
|
||
|
uart->baud1 = baud1;
|
||
|
#endif
|
||
|
|
||
|
// Clear pending requests
|
||
|
rx_states[uart_num] = NULL;
|
||
|
tx_states[uart_num] = NULL;
|
||
|
|
||
|
return E_NO_ERROR;
|
||
|
}
|
||
|
|
||
|
/* ************************************************************************* */
|
||
|
int UART_Shutdown(mxc_uart_regs_t *uart)
|
||
|
{
|
||
|
int uart_num;
|
||
|
uart_req_t *temp_req;
|
||
|
|
||
|
// Get the state array index
|
||
|
uart_num = MXC_UART_GET_IDX(uart);
|
||
|
if (uart_num < 0) {
|
||
|
return E_BAD_PARAM;
|
||
|
}
|
||
|
|
||
|
// Disable interrupts
|
||
|
uart->int_en = 0;
|
||
|
|
||
|
// Flush RX and TX FIFOS
|
||
|
uart->ctrl |= (MXC_F_UART_CTRL_TX_FLUSH | MXC_F_UART_CTRL_RX_FLUSH);
|
||
|
|
||
|
// Call all of the pending callbacks for this UART
|
||
|
if(rx_states[uart_num] != NULL) {
|
||
|
|
||
|
// Save the request
|
||
|
temp_req = rx_states[uart_num];
|
||
|
|
||
|
// Unlock this UART to read
|
||
|
mxc_free_lock((uint32_t*)&rx_states[uart_num]);
|
||
|
|
||
|
// Callback if not NULL
|
||
|
if (temp_req->callback != NULL) {
|
||
|
temp_req->callback(temp_req, E_SHUTDOWN);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (tx_states[uart_num] != NULL) {
|
||
|
|
||
|
// Save the request
|
||
|
temp_req = tx_states[uart_num];
|
||
|
|
||
|
// Unlock this UART to write
|
||
|
mxc_free_lock((uint32_t*)&tx_states[uart_num]);
|
||
|
|
||
|
// Callback if not NULL
|
||
|
if (temp_req->callback != NULL) {
|
||
|
temp_req->callback(temp_req, E_SHUTDOWN);
|
||
|
}
|
||
|
}
|
||
|
// Wait for not busy
|
||
|
while (uart->status & (MXC_F_UART_STATUS_TX_BUSY | MXC_F_UART_STATUS_RX_BUSY)) {
|
||
|
|
||
|
}
|
||
|
|
||
|
// Shutdown the UART
|
||
|
uart->ctrl = 0;
|
||
|
|
||
|
// Shutdown any system level setup
|
||
|
SYS_UART_Shutdown(uart);
|
||
|
|
||
|
// Clear pending requests
|
||
|
rx_states[uart_num] = NULL;
|
||
|
tx_states[uart_num] = NULL;
|
||
|
|
||
|
return E_NO_ERROR;
|
||
|
}
|
||
|
|
||
|
/* ************************************************************************* */
|
||
|
void UART_Handler(mxc_uart_regs_t *uart)
|
||
|
{
|
||
|
int uart_num; // Holds the current index of rx_states or tx_states
|
||
|
uint32_t intst;
|
||
|
|
||
|
// Get the state array index
|
||
|
uart_num = MXC_UART_GET_IDX(uart);
|
||
|
if (uart_num == -1) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Read and clear interrupts
|
||
|
intst = uart->int_fl;
|
||
|
uart->int_fl = intst;
|
||
|
|
||
|
// Read interrupt
|
||
|
if (intst & (UART_RX_IF | UART_ER_IF)) {
|
||
|
UART_ReadHandler(uart, rx_states[uart_num], uart_num, intst);
|
||
|
}
|
||
|
|
||
|
// Write Interrupt
|
||
|
if (intst & (UART_TX_IF | UART_ER_IF)) {
|
||
|
UART_WriteHandler(uart, tx_states[uart_num], uart_num);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* ************************************************************************* */
|
||
|
static void UART_WriteHandler(mxc_uart_regs_t *uart, uart_req_t *req, int uart_num)
|
||
|
{
|
||
|
int remain, avail;
|
||
|
req = tx_states[uart_num];
|
||
|
|
||
|
if (req == NULL) {
|
||
|
// Nothing to do
|
||
|
uart->int_en &= ~MXC_F_UART_INT_EN_TX_FIFO_ALMOST_EMPTY; // disable interrupt
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Refill the TX FIFO
|
||
|
avail = UART_NumWriteAvail(uart);
|
||
|
remain = req->len - req->num;
|
||
|
|
||
|
while (avail && remain) {
|
||
|
uart->fifo = req->data[req->num++];
|
||
|
remain--;
|
||
|
avail--;
|
||
|
}
|
||
|
|
||
|
// See if we've sent all of the characters
|
||
|
if (req->len == req->num) {
|
||
|
// Disable interrupts
|
||
|
uart->int_en &= ~MXC_F_UART_INT_EN_TX_FIFO_ALMOST_EMPTY;
|
||
|
|
||
|
// Deinit state before callback in case another is requested
|
||
|
tx_states[uart_num] = NULL;
|
||
|
mxc_free_lock((uint32_t*)&tx_states[uart_num]);
|
||
|
|
||
|
// Callback when we've written all the characters
|
||
|
if (req->callback != NULL) {
|
||
|
req->callback(req, E_NO_ERROR);
|
||
|
}
|
||
|
}
|
||
|
// Enable the interrupts
|
||
|
uart->int_en |= UART_TX_IE | UART_ER_IE;
|
||
|
|
||
|
}
|
||
|
|
||
|
/* ************************************************************************* */
|
||
|
static void UART_ReadHandler(mxc_uart_regs_t *uart, uart_req_t *req, int uart_num,
|
||
|
uint32_t flags)
|
||
|
{
|
||
|
int remain, avail;
|
||
|
|
||
|
if (req == NULL) {
|
||
|
// Nothing to do
|
||
|
uart->int_en &= ~(UART_RX_IE | UART_ER_IE); // disable interrupts
|
||
|
return;
|
||
|
}
|
||
|
// Save the data in the FIFO while we still need data
|
||
|
avail = UART_NumReadAvail(uart);
|
||
|
remain = req->len - req->num;
|
||
|
while (avail && remain) {
|
||
|
req->data[req->num++] = uart->fifo;
|
||
|
remain--;
|
||
|
avail--;
|
||
|
}
|
||
|
// Check for errors
|
||
|
if (flags & MXC_F_UART_INT_FL_RX_OVERRUN) {
|
||
|
|
||
|
// Unlock this UART to read
|
||
|
mxc_free_lock((uint32_t*)&rx_states[uart_num]);
|
||
|
|
||
|
if (req->callback != NULL) {
|
||
|
req->callback(req, E_OVERFLOW);
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
if (flags & (MXC_F_UART_INT_FL_RX_FRAME_ERROR |
|
||
|
MXC_F_UART_INT_FL_RX_PARITY_ERROR)) {
|
||
|
|
||
|
// Unlock this UART to read
|
||
|
mxc_free_lock((uint32_t*)&rx_states[uart_num]);
|
||
|
|
||
|
if (req->callback != NULL) {
|
||
|
req->callback(req, E_COMM_ERR);
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
// Check to see if we've received all of the characters.
|
||
|
if (req->num == req->len) {
|
||
|
// Disable interrupts
|
||
|
uart->int_en &= ~(UART_RX_IE | UART_ER_IE);
|
||
|
|
||
|
// Deinit state before callback in case another is requested
|
||
|
rx_states[uart_num] = NULL;
|
||
|
|
||
|
// Call the callback function
|
||
|
if (req->callback != NULL) {
|
||
|
req->callback(req, E_NO_ERROR);
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
} else if (req->num > (req->len - MXC_UART_FIFO_DEPTH)) {
|
||
|
// Set RX threshold less than FIFO_DEPTH characters if needed
|
||
|
uart->thresh_ctrl = ((req->len - req->num)<<
|
||
|
MXC_F_UART_THRESH_CTRL_RX_FIFO_THRESH_POS);
|
||
|
} else {
|
||
|
uart->thresh_ctrl = MXC_UART_FIFO_DEPTH<<
|
||
|
MXC_F_UART_THRESH_CTRL_RX_FIFO_THRESH_POS;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* ************************************************************************* */
|
||
|
int UART_Read(mxc_uart_regs_t *uart, uint8_t *data, int len, int *num)
|
||
|
{
|
||
|
int uart_num; // Holds the current index of rx_states
|
||
|
int char_read = 0; // Holds the number of characters successfully read
|
||
|
int error_code =0; // Holds the error to return while reading
|
||
|
|
||
|
// Get the state array index
|
||
|
uart_num = MXC_UART_GET_IDX(uart);
|
||
|
if (uart_num < 0) {
|
||
|
return E_BAD_PARAM;
|
||
|
}
|
||
|
|
||
|
// Check to make sure baud rate has been set
|
||
|
if (uart->baud0 == 0) {
|
||
|
return E_UNINITIALIZED;
|
||
|
}
|
||
|
|
||
|
// Check data pointer
|
||
|
if (data == NULL) {
|
||
|
return E_BAD_PARAM;
|
||
|
}
|
||
|
|
||
|
// Check if there is already a request in progress
|
||
|
if (rx_states[uart_num] != NULL) {
|
||
|
return E_BUSY;
|
||
|
}
|
||
|
|
||
|
// Lock this UART from reading
|
||
|
while (mxc_get_lock((uint32_t*)&rx_states[uart_num], 1) != E_NO_ERROR) {
|
||
|
|
||
|
}
|
||
|
|
||
|
// Get bytes FIFO
|
||
|
while (char_read < len) {
|
||
|
// Wait for RXFIFO to not be empty
|
||
|
while (uart->status & MXC_F_UART_STATUS_RX_EMPTY) {
|
||
|
// Check for error
|
||
|
if (uart_error_check(uart) != E_NO_ERROR) {
|
||
|
if (uart->int_fl & MXC_F_UART_INT_FL_RX_OVERRUN) {
|
||
|
error_code = E_OVERFLOW;
|
||
|
} else {
|
||
|
error_code = E_COMM_ERR;
|
||
|
}
|
||
|
|
||
|
uart_error_clear(uart);
|
||
|
mxc_free_lock((uint32_t*)&rx_states[uart_num]);
|
||
|
return error_code;
|
||
|
}
|
||
|
}
|
||
|
data[char_read] = uart->fifo;
|
||
|
char_read++;
|
||
|
}
|
||
|
if (num != NULL) {
|
||
|
*num = char_read;
|
||
|
}
|
||
|
// Unlock this UART to read
|
||
|
mxc_free_lock((uint32_t*)&rx_states[uart_num]);
|
||
|
|
||
|
return char_read;
|
||
|
}
|
||
|
|
||
|
/* ************************************************************************* */
|
||
|
uint8_t UART_ReadByte(mxc_uart_regs_t *uart)
|
||
|
{
|
||
|
|
||
|
while (uart->status & MXC_F_UART_STATUS_RX_EMPTY) {}
|
||
|
|
||
|
return uart->fifo;
|
||
|
}
|
||
|
|
||
|
/* ************************************************************************* */
|
||
|
int UART_Write(mxc_uart_regs_t *uart, const uint8_t *data, int len)
|
||
|
{
|
||
|
int uart_num; // Holds the current index of tx_states
|
||
|
int char_written = 0; // Holds the number of characters successfully written
|
||
|
|
||
|
// Get the state array index
|
||
|
uart_num = MXC_UART_GET_IDX(uart);
|
||
|
if (uart_num < 0) {
|
||
|
return E_BAD_PARAM;
|
||
|
}
|
||
|
|
||
|
// Check to make sure baud rate has been set
|
||
|
if (uart->baud0 == 0) {
|
||
|
return E_UNINITIALIZED;
|
||
|
}
|
||
|
|
||
|
// Check data pointer
|
||
|
if (data == NULL) {
|
||
|
return E_BAD_PARAM;
|
||
|
}
|
||
|
|
||
|
// Check if there is already a request in progress
|
||
|
if (tx_states[uart_num] != NULL) {
|
||
|
return E_BUSY;
|
||
|
}
|
||
|
|
||
|
// Lock this UART from writing
|
||
|
while (mxc_get_lock((uint32_t*)&tx_states[uart_num], 1) != E_NO_ERROR) {
|
||
|
|
||
|
}
|
||
|
|
||
|
// Clear errors
|
||
|
uart_error_clear(uart);
|
||
|
|
||
|
// Put bytes into FIFO
|
||
|
while (char_written < len) {
|
||
|
UART_WriteByte(uart,data[char_written]);
|
||
|
char_written++;
|
||
|
}
|
||
|
|
||
|
// Unlock this UART to write
|
||
|
mxc_free_lock((uint32_t*)&tx_states[uart_num]);
|
||
|
|
||
|
return char_written;
|
||
|
}
|
||
|
|
||
|
/* ************************************************************************* */
|
||
|
void UART_WriteByte(mxc_uart_regs_t *uart, uint8_t data)
|
||
|
{
|
||
|
|
||
|
// Wait for TXFIFO if full
|
||
|
while (uart->status & MXC_F_UART_STATUS_TX_FULL) {
|
||
|
|
||
|
}
|
||
|
|
||
|
// Put data into fifo
|
||
|
uart->fifo = data;
|
||
|
}
|
||
|
|
||
|
/* ************************************************************************* */
|
||
|
int UART_ReadAsync(mxc_uart_regs_t *uart, uart_req_t *req)
|
||
|
{
|
||
|
int uart_num; // Holds the current index of tx_states
|
||
|
uint32_t flags; // Holds the Interrupt flags
|
||
|
|
||
|
// Check data pointer
|
||
|
if (req == NULL) {
|
||
|
return E_BAD_PARAM;
|
||
|
}
|
||
|
|
||
|
// Get the state array index
|
||
|
uart_num = MXC_UART_GET_IDX(uart);
|
||
|
if (uart_num < 0) {
|
||
|
return E_BAD_PARAM;
|
||
|
}
|
||
|
|
||
|
if (req->data == NULL) {
|
||
|
return E_NULL_PTR;
|
||
|
}
|
||
|
// Check to make sure baud rate has been set
|
||
|
if (uart->baud0 == 0) {
|
||
|
return E_UNINITIALIZED;
|
||
|
}
|
||
|
|
||
|
// Check if there is already a request in progress
|
||
|
if (rx_states[uart_num] != NULL) {
|
||
|
return E_BUSY;
|
||
|
}
|
||
|
|
||
|
if (!(req->len > 0)) {
|
||
|
return E_NO_ERROR;
|
||
|
}
|
||
|
|
||
|
// Attempt to register this write request
|
||
|
if (mxc_get_lock((uint32_t*)&rx_states[uart_num], (uint32_t)req) != E_NO_ERROR) {
|
||
|
return E_BUSY;
|
||
|
}
|
||
|
|
||
|
// Clear the data counter
|
||
|
req->num = 0;
|
||
|
|
||
|
// Clear Interrupt Flags
|
||
|
flags = uart->int_fl;
|
||
|
uart->int_fl = flags;
|
||
|
UART_ReadHandler(uart,req,uart_num,flags);
|
||
|
|
||
|
// Enable the interrupts
|
||
|
uart->int_en |= UART_RX_IE | UART_ER_IE;
|
||
|
|
||
|
return E_NO_ERROR;
|
||
|
}
|
||
|
|
||
|
/* ************************************************************************* */
|
||
|
int UART_WriteAsync(mxc_uart_regs_t *uart, uart_req_t *req)
|
||
|
{
|
||
|
int uart_num; // Holds the current index of tx_states
|
||
|
|
||
|
// Check data pointer
|
||
|
if (req == NULL) {
|
||
|
return E_BAD_PARAM;
|
||
|
}
|
||
|
|
||
|
// Get the state array index
|
||
|
uart_num = MXC_UART_GET_IDX(uart);
|
||
|
if (uart_num < 0) {
|
||
|
return E_BAD_PARAM;
|
||
|
}
|
||
|
|
||
|
if (req->data == NULL) {
|
||
|
return E_NULL_PTR;
|
||
|
}
|
||
|
// Check to make sure baud rate has been set
|
||
|
if (uart->baud0 == 0) {
|
||
|
return E_UNINITIALIZED;
|
||
|
}
|
||
|
|
||
|
// Check if there is already a request in progress
|
||
|
if (tx_states[uart_num] != NULL) {
|
||
|
return E_BUSY;
|
||
|
}
|
||
|
if (!(req->len > 0)) {
|
||
|
return E_NO_ERROR;
|
||
|
}
|
||
|
// Attempt to register this write request
|
||
|
if (mxc_get_lock((uint32_t*)&tx_states[uart_num], (uint32_t)req) != E_NO_ERROR) {
|
||
|
return E_BUSY;
|
||
|
}
|
||
|
|
||
|
// Clear the data counter
|
||
|
req->num = 0;
|
||
|
UART_WriteHandler(uart, req, uart_num);
|
||
|
|
||
|
return E_NO_ERROR;
|
||
|
}
|
||
|
|
||
|
/* ************************************************************************* */
|
||
|
int UART_Busy(mxc_uart_regs_t *uart)
|
||
|
{
|
||
|
int uart_num = MXC_UART_GET_IDX(uart); // Holds the current index of tx_states
|
||
|
MXC_ASSERT(uart_num >= 0);
|
||
|
if ((uart->status & MXC_F_UART_STATUS_TX_BUSY) || (uart->status & MXC_F_UART_STATUS_RX_BUSY)) {
|
||
|
return E_BUSY;
|
||
|
}
|
||
|
// Check to see if there are any ongoing transactions and the UART has room in its FIFO
|
||
|
if ((tx_states[uart_num] == NULL) &&
|
||
|
!(uart->status & MXC_F_UART_STATUS_TX_FULL)) {
|
||
|
|
||
|
return E_NO_ERROR;
|
||
|
}
|
||
|
|
||
|
return E_BUSY;
|
||
|
}
|
||
|
|
||
|
/* ************************************************************************* */
|
||
|
int UART_PrepForSleep(mxc_uart_regs_t *uart)
|
||
|
{
|
||
|
if (UART_Busy(uart) != E_NO_ERROR) {
|
||
|
return E_BUSY;
|
||
|
}
|
||
|
|
||
|
// Leave read interrupts enabled, if already enabled
|
||
|
uart->int_en &= (UART_RX_IE | UART_ER_IE);
|
||
|
|
||
|
return E_NO_ERROR;
|
||
|
}
|
||
|
|
||
|
/* ************************************************************************* */
|
||
|
int UART_AbortAsync(uart_req_t *req)
|
||
|
{
|
||
|
int uart_num;
|
||
|
|
||
|
// Figure out if this was a read or write request, find the request, set to NULL
|
||
|
for (uart_num = 0; uart_num < MXC_UART_INSTANCES; uart_num++) {
|
||
|
if (req == rx_states[uart_num]) {
|
||
|
|
||
|
// Disable read interrupts, clear flags.
|
||
|
MXC_UART_GET_UART(uart_num)->int_en &= ~(UART_RX_IE | UART_ER_IE);
|
||
|
MXC_UART_GET_UART(uart_num)->int_fl = (UART_RX_IF | UART_ER_IF);
|
||
|
|
||
|
// Unlock this UART to read
|
||
|
mxc_free_lock((uint32_t*)&rx_states[uart_num]);
|
||
|
|
||
|
// Callback if not NULL
|
||
|
if (req->callback != NULL) {
|
||
|
req->callback(req, E_ABORT);
|
||
|
}
|
||
|
|
||
|
return E_NO_ERROR;
|
||
|
}
|
||
|
|
||
|
if (req == tx_states[uart_num]) {
|
||
|
|
||
|
// Disable write interrupts, clear flags.
|
||
|
MXC_UART_GET_UART(uart_num)->int_en &= ~(UART_TX_IE | UART_ER_IE);
|
||
|
MXC_UART_GET_UART(uart_num)->int_fl = (UART_TX_IF | UART_ER_IF);
|
||
|
|
||
|
// Unlock this UART to write
|
||
|
mxc_free_lock((uint32_t*)&tx_states[uart_num]);
|
||
|
|
||
|
// Callback if not NULL
|
||
|
if (req->callback != NULL) {
|
||
|
req->callback(req, E_ABORT);
|
||
|
}
|
||
|
|
||
|
return E_NO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return E_BAD_PARAM;
|
||
|
}
|
||
|
|
||
|
/* ************************************************************************* */
|
||
|
unsigned UART_NumWriteAvail(mxc_uart_regs_t *uart)
|
||
|
{
|
||
|
return MXC_UART_FIFO_DEPTH - ((uart->status & MXC_F_UART_STATUS_TX_FIFO_CNT) >>
|
||
|
MXC_F_UART_STATUS_TX_FIFO_CNT_POS);
|
||
|
}
|
||
|
|
||
|
/* ************************************************************************* */
|
||
|
unsigned UART_NumReadAvail(mxc_uart_regs_t *uart)
|
||
|
{
|
||
|
return ((uart->status & MXC_F_UART_STATUS_RX_FIFO_CNT) >>
|
||
|
MXC_F_UART_STATUS_RX_FIFO_CNT_POS);
|
||
|
}
|
||
|
|
||
|
/* ************************************************************************* */
|
||
|
unsigned UART_GetFlags(mxc_uart_regs_t *uart)
|
||
|
{
|
||
|
return (uart->int_fl);
|
||
|
}
|
||
|
|
||
|
/* ************************************************************************* */
|
||
|
void UART_ClearFlags(mxc_uart_regs_t *uart, uint32_t mask)
|
||
|
{
|
||
|
uart->int_fl = mask;
|
||
|
}
|
||
|
|
||
|
/* ************************************************************************* */
|
||
|
void UART_Enable(mxc_uart_regs_t *uart)
|
||
|
{
|
||
|
uart->ctrl |= MXC_F_UART_CTRL_ENABLE;
|
||
|
}
|
||
|
|
||
|
/* ************************************************************************* */
|
||
|
void UART_Disable(mxc_uart_regs_t *uart)
|
||
|
{
|
||
|
uart->ctrl &= ~MXC_F_UART_CTRL_ENABLE;
|
||
|
}
|
||
|
|
||
|
/* ************************************************************************* */
|
||
|
void UART_DrainRX(mxc_uart_regs_t *uart)
|
||
|
{
|
||
|
uart->ctrl |= MXC_F_UART_CTRL_RX_FLUSH;
|
||
|
}
|
||
|
|
||
|
/* ************************************************************************* */
|
||
|
void UART_DrainTX(mxc_uart_regs_t *uart)
|
||
|
{
|
||
|
uart->ctrl |= MXC_F_UART_CTRL_TX_FLUSH;
|
||
|
}
|