123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718 |
- /* ****************************************************************************
- * 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;
- }
|