Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: cobaLCDJoyMotor_Thread odometry_omni_3roda_v3 odometry_omni_3roda_v1 odometry_omni_3roda_v2 ... more
Diff: targets/TARGET_Maxim/TARGET_MAX32630/mxc/uart.c
- Revision:
- 0:b74591d5ab33
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/targets/TARGET_Maxim/TARGET_MAX32630/mxc/uart.c Mon Dec 11 17:54:04 2017 +0000
@@ -0,0 +1,661 @@
+/**
+ * @file
+ * @brief This file contains the function implementations for the UART
+ * serial communications peripheral module.
+ */
+/* *****************************************************************************
+ * Copyright (C) 2016 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: 2016-09-08 17:00:36 -0500 (Thu, 08 Sep 2016) $
+ * $Revision: 24319 $
+ *
+ **************************************************************************** */
+
+/* **** Includes **** */
+#include <string.h>
+#include "mxc_config.h"
+#include "mxc_assert.h"
+#include "mxc_lock.h"
+#include "mxc_sys.h"
+#include "uart.h"
+
+/**
+ * @ingroup uart_comm
+ * @{
+ */
+/* **** Definitions **** */
+///@cond
+#define UART_ERRORS (MXC_F_UART_INTEN_RX_FIFO_OVERFLOW | \
+ MXC_F_UART_INTEN_RX_FRAMING_ERR | \
+ MXC_F_UART_INTEN_RX_PARITY_ERR)
+
+#define UART_READ_INTS (MXC_F_UART_INTEN_RX_FIFO_AF | \
+ MXC_F_UART_INTEN_RX_FIFO_NOT_EMPTY | \
+ MXC_F_UART_INTEN_RX_STALLED | \
+ UART_ERRORS)
+
+#define UART_WRITE_INTS (MXC_F_UART_INTEN_TX_UNSTALLED | \
+ MXC_F_UART_INTEN_TX_FIFO_AE)
+
+#define UART_RXFIFO_USABLE (MXC_UART_FIFO_DEPTH-3)
+///@endcond
+//
+/* **** Globals **** */
+
+// Saves the state of the non-blocking read requests
+static uart_req_t *rx_states[MXC_CFG_UART_INSTANCES];
+
+// Saves the state of the non-blocking write requests
+static uart_req_t *tx_states[MXC_CFG_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);
+
+/* ************************************************************************* */
+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 uart_clk;
+ uint8_t baud_shift;
+ uint16_t baud_div;
+ uint32_t baud, diff_baud;
+ uint32_t baud_1, diff_baud_1;
+
+ // Check the input parameters
+ uart_num = MXC_UART_GET_IDX(uart);
+ MXC_ASSERT(uart_num >= 0);
+
+ // Set system level configurations
+ if(sys_cfg != NULL) {
+ if ((err = SYS_UART_Init(uart, cfg, sys_cfg)) != E_NO_ERROR) {
+ return err;
+ }
+ }
+
+ // Initialize state pointers
+ rx_states[uart_num] = NULL;
+ tx_states[uart_num] = NULL;
+
+ // Drain FIFOs and enable UART
+ uart->ctrl = 0;
+ uart->ctrl = (MXC_F_UART_CTRL_UART_EN | MXC_F_UART_CTRL_TX_FIFO_EN |
+ MXC_F_UART_CTRL_RX_FIFO_EN |
+ (UART_RXFIFO_USABLE << MXC_F_UART_CTRL_RTS_LEVEL_POS));
+
+ // Configure data size, stop bit, parity, cts, and rts
+ uart->ctrl |= ((cfg->size << MXC_F_UART_CTRL_DATA_SIZE_POS) |
+ (cfg->extra_stop << MXC_F_UART_CTRL_EXTRA_STOP_POS) |
+ (cfg->parity << MXC_F_UART_CTRL_PARITY_POS) |
+ (cfg->cts << MXC_F_UART_CTRL_CTS_EN_POS) |
+ (cfg->rts << MXC_F_UART_CTRL_RTS_EN_POS));
+
+ // Configure the baud rate and divisor
+ uart_clk = SYS_UART_GetFreq(uart);
+ MXC_ASSERT(uart_clk > 0);
+
+ baud_shift = 2;
+ baud_div = (uart_clk / (cfg->baud * 4));
+
+ // Can not support higher frequencies
+ if(!baud_div) {
+ return E_NOT_SUPPORTED;
+ }
+
+ // Decrease the divisor if baud_div is overflowing
+ while(baud_div > 0xFF) {
+ if(baud_shift == 0) {
+ return E_NOT_SUPPORTED;
+ }
+ baud_shift--;
+ baud_div = (uart_clk / (cfg->baud * (16 >> baud_shift)));
+ }
+
+ // Adjust baud_div so we don't overflow with the calculations below
+ if(baud_div == 0xFF) {
+ baud_div = 0xFE;
+ }
+ if(baud_div == 0) {
+ baud_div = 1;
+ }
+
+ // Figure out if the truncation increased the error
+ baud = (uart_clk / (baud_div * (16 >> baud_shift)));
+ baud_1 = (uart_clk / ((baud_div+1) * (16 >> baud_shift)));
+
+ if(cfg->baud > baud) {
+ diff_baud = cfg->baud - baud;
+ } else {
+ diff_baud = baud - cfg->baud;
+ }
+
+ if(cfg->baud > baud_1) {
+ diff_baud_1 = cfg->baud - baud_1;
+ } else {
+ diff_baud_1 = baud_1 - cfg->baud;
+ }
+
+ if(diff_baud < diff_baud_1) {
+ uart->baud = ((baud_div & MXC_F_UART_BAUD_BAUD_DIVISOR) |
+ (baud_shift << MXC_F_UART_BAUD_BAUD_MODE_POS));
+ } else {
+ uart->baud = (((baud_div+1) & MXC_F_UART_BAUD_BAUD_DIVISOR) |
+ (baud_shift << MXC_F_UART_BAUD_BAUD_MODE_POS));
+ }
+
+ return E_NO_ERROR;
+}
+
+/* ************************************************************************* */
+int UART_Shutdown(mxc_uart_regs_t *uart)
+{
+ int uart_num, err;
+ uart_req_t *temp_req;
+
+ uart_num = MXC_UART_GET_IDX(uart);
+ MXC_ASSERT(uart_num >= 0);
+
+ // Disable and clear interrupts
+ uart->inten = 0;
+ uart->intfl = uart->intfl;
+
+ // Disable UART and FIFOS
+ uart->ctrl &= ~(MXC_F_UART_CTRL_UART_EN | MXC_F_UART_CTRL_TX_FIFO_EN |
+ MXC_F_UART_CTRL_RX_FIFO_EN);
+
+ // 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);
+ }
+ }
+
+ // Clears system level configurations
+ if ((err = SYS_UART_Shutdown(uart)) != E_NO_ERROR) {
+ return err;
+ }
+
+ return E_NO_ERROR;
+}
+
+/* ************************************************************************* */
+int UART_Write(mxc_uart_regs_t *uart, uint8_t* data, int len)
+{
+ int num, uart_num;
+ mxc_uart_fifo_regs_t *fifo;
+
+ uart_num = MXC_UART_GET_IDX(uart);
+ MXC_ASSERT(uart_num >= 0);
+
+ if(data == NULL) {
+ return E_NULL_PTR;
+ }
+
+ // Make sure the UART has been initialized
+ if(!(uart->ctrl & MXC_F_UART_CTRL_UART_EN)) {
+ return E_UNINITIALIZED;
+ }
+
+ if(!(len > 0)) {
+ return E_NO_ERROR;
+ }
+
+ // Lock this UART from writing
+ while(mxc_get_lock((uint32_t*)&tx_states[uart_num], 1) != E_NO_ERROR) {}
+
+ // Get the FIFO for this UART
+ fifo = MXC_UART_GET_FIFO(uart_num);
+
+ num = 0;
+
+ while(num < len) {
+
+ // Wait for TXFIFO to not be full
+ while((uart->tx_fifo_ctrl & MXC_F_UART_TX_FIFO_CTRL_FIFO_ENTRY) ==
+ MXC_F_UART_TX_FIFO_CTRL_FIFO_ENTRY) {}
+
+ // Write the data to the FIFO
+#if(MXC_UART_REV == 0)
+ uart->intfl = MXC_F_UART_INTFL_TX_DONE;
+#endif
+ fifo->tx = data[num++];
+ }
+
+ // Unlock this UART to write
+ mxc_free_lock((uint32_t*)&tx_states[uart_num]);
+
+ return num;
+}
+
+/* ************************************************************************* */
+int UART_Read(mxc_uart_regs_t *uart, uint8_t* data, int len, int *num)
+{
+ int num_local, remain, uart_num;
+ mxc_uart_fifo_regs_t *fifo;
+
+ uart_num = MXC_UART_GET_IDX(uart);
+ MXC_ASSERT(uart_num >= 0);
+
+ if(data == NULL) {
+ return E_NULL_PTR;
+ }
+
+ // Make sure the UART has been initialized
+ if(!(uart->ctrl & MXC_F_UART_CTRL_UART_EN)) {
+ return E_UNINITIALIZED;
+ }
+
+ if(!(len > 0)) {
+ return E_NO_ERROR;
+ }
+
+ // Lock this UART from reading
+ while(mxc_get_lock((uint32_t*)&rx_states[uart_num], 1) != E_NO_ERROR) {}
+
+ // Get the FIFO for this UART
+ fifo = MXC_UART_GET_FIFO(uart_num);
+
+ num_local = 0;
+ remain = len;
+ while(remain) {
+
+ // Save the data in the FIFO
+ while((uart->rx_fifo_ctrl & MXC_F_UART_RX_FIFO_CTRL_FIFO_ENTRY) && remain) {
+ data[num_local] = fifo->rx;
+ num_local++;
+ remain--;
+ }
+
+ // Break if there is an error
+ if(uart->intfl & UART_ERRORS) {
+ break;
+ }
+ }
+
+ // Save the number of bytes read if pointer is valid
+ if(num != NULL) {
+ *num = num_local;
+ }
+
+ // Check for errors
+ if(uart->intfl & MXC_F_UART_INTFL_RX_FIFO_OVERFLOW) {
+
+ // Clear errors and return error code
+ uart->intfl = UART_ERRORS;
+
+
+ // Unlock this UART to read
+ mxc_free_lock((uint32_t*)&rx_states[uart_num]);
+
+ return E_OVERFLOW;
+
+ } else if(uart->intfl & (MXC_F_UART_INTFL_RX_FRAMING_ERR |
+ MXC_F_UART_INTFL_RX_PARITY_ERR)) {
+
+ // Clear errors and return error code
+ uart->intfl = UART_ERRORS;
+
+
+ // Unlock this UART to read
+ mxc_free_lock((uint32_t*)&rx_states[uart_num]);
+
+ return E_COMM_ERR;
+ }
+
+ // Unlock this UART to read
+ mxc_free_lock((uint32_t*)&rx_states[uart_num]);
+
+ return num_local;
+}
+
+/* ************************************************************************* */
+int UART_WriteAsync(mxc_uart_regs_t *uart, uart_req_t *req)
+{
+ int uart_num = MXC_UART_GET_IDX(uart);
+ MXC_ASSERT(uart_num >= 0);
+
+ // Check the input parameters
+ if(req->data == NULL) {
+ return E_NULL_PTR;
+ }
+
+ // Make sure the UART has been initialized
+ if(!(uart->ctrl & MXC_F_UART_CTRL_UART_EN)) {
+ return E_UNINITIALIZED;
+ }
+
+ 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 number of bytes counter
+ req->num = 0;
+
+ // Start the write
+ UART_WriteHandler(uart, req, uart_num);
+
+ return E_NO_ERROR;
+}
+
+/* ************************************************************************* */
+int UART_ReadAsync(mxc_uart_regs_t *uart, uart_req_t *req)
+{
+ int uart_num;
+ uint32_t flags;
+
+ uart_num = MXC_UART_GET_IDX(uart);
+ MXC_ASSERT(uart_num >= 0);
+
+ if(req->data == NULL) {
+ return E_NULL_PTR;
+ }
+
+ // Make sure the UART has been initialized
+ if(!(uart->ctrl & MXC_F_UART_CTRL_UART_EN)) {
+ return E_UNINITIALIZED;
+ }
+
+ 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 number of bytes counter
+ req->num = 0;
+
+ // Start the read
+ flags = uart->intfl;
+ uart->intfl = flags;
+ UART_ReadHandler(uart, req, uart_num, flags);
+
+ 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_CFG_UART_INSTANCES; uart_num++) {
+ if(req == rx_states[uart_num]) {
+
+ // Disable read interrupts, clear flags.
+ MXC_UART_GET_UART(uart_num)->inten &= ~UART_READ_INTS;
+ MXC_UART_GET_UART(uart_num)->intfl = UART_READ_INTS;
+
+ // 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)->inten &= ~(UART_WRITE_INTS);
+ MXC_UART_GET_UART(uart_num)->intfl = UART_WRITE_INTS;
+
+ // 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;
+}
+
+/* ************************************************************************* */
+void UART_Handler(mxc_uart_regs_t *uart)
+{
+ int uart_num;
+ uint32_t flags;
+
+ uart_num = MXC_UART_GET_IDX(uart);
+ MXC_ASSERT(uart_num >= 0);
+
+ flags = uart->intfl;
+ uart->intfl = flags;
+
+ // Figure out if this UART has an active Read request
+ if((rx_states[uart_num] != NULL) && (flags & UART_READ_INTS)) {
+ UART_ReadHandler(uart, rx_states[uart_num], uart_num, flags);
+ }
+
+ // Figure out if this UART has an active Write request
+ if((tx_states[uart_num] != NULL) && (flags & (UART_WRITE_INTS))) {
+
+ UART_WriteHandler(uart, tx_states[uart_num], uart_num);
+ }
+}
+/* ************************************************************************* */
+int UART_Busy(mxc_uart_regs_t *uart)
+{
+ int uart_num = MXC_UART_GET_IDX(uart);
+ MXC_ASSERT(uart_num >= 0);
+
+ // Check to see if there are any ongoing transactions or if the UART is disabled
+ if(((tx_states[uart_num] == NULL) &&
+ !(uart->tx_fifo_ctrl & MXC_F_UART_TX_FIFO_CTRL_FIFO_ENTRY) &&
+#if(MXC_UART_REV == 0)
+ (uart->intfl & MXC_F_UART_INTFL_TX_DONE)) ||
+#else
+ (uart->idle & MXC_F_UART_IDLE_TX_RX_IDLE)) ||
+#endif
+ !(uart->ctrl & MXC_F_UART_CTRL_UART_EN)) {
+
+ 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->inten &= UART_READ_INTS;
+
+ return E_NO_ERROR;
+}
+
+/* ************************************************************************* */
+static void UART_WriteHandler(mxc_uart_regs_t *uart, uart_req_t *req, int uart_num)
+{
+ int avail, remain;
+ mxc_uart_fifo_regs_t *fifo;
+
+ // Disable write interrupts
+ uart->inten &= ~(UART_WRITE_INTS);
+
+ // Get the FIFO for this UART
+ fifo = MXC_UART_GET_FIFO(uart_num);
+
+ // Refill the TX FIFO
+ avail = UART_NumWriteAvail(uart);
+ remain = req->len - req->num;
+
+ while(avail && remain) {
+
+ // Write the data to the FIFO
+#if(MXC_UART_REV == 0)
+ uart->intfl = MXC_F_UART_INTFL_TX_DONE;
+#endif
+ fifo->tx = req->data[req->num++];
+ remain--;
+ avail--;
+ }
+
+ // All of the bytes have been written to the FIFO
+ if(!remain) {
+
+ // Unlock this UART to write
+ mxc_free_lock((uint32_t*)&tx_states[uart_num]);
+
+ if(req->callback != NULL) {
+ req->callback(req, E_NO_ERROR);
+ }
+
+ } else {
+
+ // Interrupt when there is one byte left in the TXFIFO
+ uart->tx_fifo_ctrl = ((MXC_UART_FIFO_DEPTH - 1) << MXC_F_UART_TX_FIFO_CTRL_FIFO_AE_LVL_POS);
+
+ // Enable almost empty interrupt
+ uart->inten |= (MXC_F_UART_INTEN_TX_FIFO_AE);
+ }
+}
+
+/* ************************************************************************* */
+static void UART_ReadHandler(mxc_uart_regs_t *uart, uart_req_t *req, int uart_num,
+ uint32_t flags)
+{
+ int avail, remain;
+ mxc_uart_fifo_regs_t *fifo;
+
+ // Disable interrupts
+ uart->inten &= ~UART_READ_INTS;
+
+ // Get the FIFO for this UART, uart_num
+ fifo = MXC_UART_GET_FIFO(uart_num);
+
+ // 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++] = fifo->rx;
+ remain--;
+ avail--;
+ }
+
+ // Check for errors
+ if(flags & MXC_F_UART_INTFL_RX_FIFO_OVERFLOW) {
+
+ // 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_INTFL_RX_FRAMING_ERR |
+ MXC_F_UART_INTFL_RX_PARITY_ERR)) {
+
+ // 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're done receiving
+ if(remain == 0) {
+
+ // Unlock this UART to read
+ mxc_free_lock((uint32_t*)&rx_states[uart_num]);
+
+ if(req->callback != NULL) {
+ req->callback(req, E_NO_ERROR);
+ }
+
+ return;
+ }
+
+ if(remain == 1) {
+ uart->inten |= (MXC_F_UART_INTEN_RX_FIFO_NOT_EMPTY | UART_ERRORS);
+
+ } else {
+ // Set the RX FIFO AF threshold
+ if(remain < UART_RXFIFO_USABLE) {
+ uart->rx_fifo_ctrl = ((remain - 1) <<
+ MXC_F_UART_RX_FIFO_CTRL_FIFO_AF_LVL_POS);
+ } else {
+ uart->rx_fifo_ctrl = (UART_RXFIFO_USABLE <<
+ MXC_F_UART_RX_FIFO_CTRL_FIFO_AF_LVL_POS);
+ }
+ uart->inten |= (MXC_F_UART_INTEN_RX_FIFO_AF | UART_ERRORS);
+ }
+}
+/**@} end of ingroup uart_comm */