mbed-os/targets/TARGET_ublox/TARGET_HI2110/serial_api.c

820 lines
24 KiB
C

/* mbed Microcontroller Library
* Copyright (c) 2016 u-blox
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* The serial driver connects UART HW to mbed and also associates the UART
* HW with physical pins. Any physical pin can be linked to any UART,
* however the mbed serial port initialisation API makes no mention of
* which UART HW is to be used (only the pins) and hence the driver needs
* to make some decisions for itself.
*
* There are two and a half UARTs on the chip: UART0, UART1 and a
* lower-power, receive-only UART that is clocked from 32 kHz and can
* therefore be awake while the rest of the chip is sleeping peacefully.
* This provides maximal power saving, however the LP UART can only run
* at 9600 bits/s (which is quite sufficient for all NB-IoT needs).
*
* So, if the baud rate is 9600 the driver code configures the LP UART
* for Rx and UART0 for Tx. If the baud rate is not 9600 then it configures
* UART0 for both Rx and Tx. Unless... the Tx pin is the pin UART1_TX (it
* is an mbed convention to use the Tx pin), which is p6, in which case UART1
* is configured instead. This latter is not the normal case as this pin
* is intended to be used as a GPIO.
*
* If the baud rate is changed the driver reconfigures to match.
*
* TODO: implement asynchronous and flow control APIs.
*/
#include "mbed_assert.h"
#include "serial_api.h"
#include "pinmap.h"
#include "cmsis.h"
/* ----------------------------------------------------------------
* MACROS
* ----------------------------------------------------------------*/
/* Registers banks for the standard UARTs */
#define UART0_REG (*(volatile uart_ctrl_t *) UART0_BASE)
#define UART1_REG (*(volatile uart_ctrl_t *) UART1_BASE)
/* Masks for the UART control bits in the reset and clock enable registers */
#define UART0_CTRL (1 << 3)
#define UART1_CTRL (1 << 4)
#define UARTLP_CTRL (1 << 6)
/* Convert number of data bits to register values */
#define MIN_NUM_UART_DATA_BITS 5
#define MAX_NUM_UART_DATA_BITS 8
#define REGISTER_DATA_BITS(x) ((x) - MIN_NUM_UART_DATA_BITS)
/* Number of stop bits */
#define NUM_UART_STOP_BITS_1 1
#define NUM_UART_STOP_BITS_2 2
/* ----------------------------------------------------------------
* TYPES
* ----------------------------------------------------------------*/
/* Enum to identify the interrupt to the UART handler */
typedef enum {
IRQ_UART_ID_0_AND_LP,
IRQ_UART_ID_1,
NUM_IRQ_IDS
} irq_uart_id_t;
/* ----------------------------------------------------------------
* GLOBAL VARIABLES
* ----------------------------------------------------------------*/
/* The IRQ configuration variables, set up and named by mbed */
static uint32_t serial_irq_ids[NUM_IRQ_IDS] = {0};
static uart_irq_handler irq_handler = NULL;
/* RTX needs these */
int stdio_uart_inited = 0;
serial_t stdio_uart;
/* ----------------------------------------------------------------
* FUNCTION PROTOTYPES
* ----------------------------------------------------------------*/
static void init_config(serial_t *obj);
static void deinit_config(serial_t *obj);
static void set_baud(serial_t *obj, uint32_t baud_rate);
static void irq_enable(serial_t *obj);
static void irq_disable(serial_t *obj);
/* ----------------------------------------------------------------
* NON-API FUNCTIONS
* ----------------------------------------------------------------*/
/* Initialise the given serial config by setting the pin functions
* and then resetting the relevant HW */
static void init_config(serial_t *obj)
{
uint32_t x;
switch (obj->config) {
case SERIAL_CONFIG_UARTLP_RX_UART0_TX:
{
pin_function(obj->rx_pin, PIN_FUNCTION_LP_UART);
pin_function(obj->tx_pin, PIN_FUNCTION_UART0_TXD);
CLKEN_REG_BITSET = UARTLP_CTRL | UART0_CTRL;
obj->reg_base = &UART0_REG;
obj->index = IRQ_UART_ID_0_AND_LP;
/* Reset the LPUART and UART0 HW */
/* NOTE: RESET_REG_BITTOG doesn't have the desired
* effect, need to use BITSET and then BITCLR */
RESET_REG_BITSET |= 1ul << 6;
RESET_REG_BITCLR |= 1ul << 6;
RESET_REG_BITSET |= 1ul << 3;
RESET_REG_BITCLR |= 1ul << 3;
}
break;
case SERIAL_CONFIG_UART0_RX_UART0_TX:
{
pin_function(obj->rx_pin, PIN_FUNCTION_UART0_RXD);
pin_function(obj->tx_pin, PIN_FUNCTION_UART0_TXD);
CLKEN_REG_BITSET = UART0_CTRL;
obj->reg_base = &UART0_REG;
obj->index = IRQ_UART_ID_0_AND_LP;
/* Reset the UART0 HW */
RESET_REG_BITSET |= 1ul << 3;
RESET_REG_BITCLR |= 1ul << 3;
}
break;
case SERIAL_CONFIG_UART1_RX_UART1_TX:
{
pin_function(obj->rx_pin, PIN_FUNCTION_UART1_RXD);
pin_function(obj->tx_pin, PIN_FUNCTION_UART1_TXD);
CLKEN_REG_BITSET = UART1_CTRL;
obj->reg_base = &UART1_REG;
obj->index = IRQ_UART_ID_1;
/* Reset the UART1 HW */
RESET_REG_BITSET |= 1ul << 4;
RESET_REG_BITCLR |= 1ul << 4;
}
break;
default:
{
MBED_ASSERT(false);
}
break;
}
/* Tickle the UART control register to make sure it is updated */
x = obj->reg_base->UARTLCR_H;
obj->reg_base->UARTLCR_H = x;
/* Set the FIFO. The meaning of the three FIFO interrupt-level
* bits are as follows:
*
* 0 = 1/8 full
* 1 = 1/4 full
* 2 = 1/2 full
* 3 = 3/4 full
* 4 = 7/8 full
*
* Set up the Rx FIFO to be used fully (but we will also set
* a timeout to get immediate notice) and also the Tx FIFO
* to be fully used. */
obj->reg_base->UARTIFLS = (obj->reg_base->UARTIFLS & ~(0x07 << 0)) | (4 << 0);
obj->reg_base->UARTIFLS = (obj->reg_base->UARTIFLS & ~(0x07 << 3)) | (4 << 3);
obj->reg_base->UARTLCR_H |= 1 << 4;
/* Enable for Tx and Rx (TODO: add CTS when we add flow control) */
obj->reg_base->UARTCR |= (1 << 8) | (1 << 9);
/* Now enable it */
obj->reg_base->UARTCR |= 1 << 0;
obj->format_set = false;
obj->baud_rate = 0;
obj->irq_rx_setting = IRQ_NOT_SET;
obj->irq_tx_setting = IRQ_NOT_SET;
}
/* Release a serial port */
static void deinit_config(serial_t *obj)
{
pin_function(obj->rx_pin, PIN_FUNCTION_UNCLAIMED);
pin_function(obj->tx_pin, PIN_FUNCTION_UNCLAIMED);
/* Disable UART */
obj->reg_base->UARTCR &= ~(1 << 0);
/* Flush transmit FIFO */
obj->reg_base->UARTLCR_H = 0;
/* Disable everything */
obj->reg_base->UARTCR = 0;
switch (obj->config) {
case SERIAL_CONFIG_UARTLP_RX_UART0_TX:
{
CLKEN_REG_BITCLR = UARTLP_CTRL | UART0_CTRL;
LP_UART_CTRL &= ~(0xF << 20); /* Disable all LP interrupts */
}
break;
case SERIAL_CONFIG_UART0_RX_UART0_TX:
{
CLKEN_REG_BITCLR = UART0_CTRL;
}
break;
case SERIAL_CONFIG_UART1_RX_UART1_TX:
{
CLKEN_REG_BITCLR = UART1_CTRL;
}
break;
default:
{
MBED_ASSERT(false);
}
break;
}
obj->config = MAX_NUM_SERIAL_CONFIGS;
obj->reg_base = NULL;
}
/* Set the baud rate for either of the two (non-LP) UARTS */
static void set_baud(serial_t *obj, uint32_t baud_rate)
{
uint32_t baud_rate_divider_i;
uint32_t baud_rate_divider_f;
uint32_t remainder;
uint32_t core_clock;
uint32_t x;
/* Baud rate divider calculation:
*
* The integer part is: clock / (16 * baud)
*
* The fractional part is: round (decimal_part * 64),
* ...where decimal part is, for example, 0.085
*
* decimal_part is: remainder / (16 * baud),
* ...where: remainder = core_clock % (baud * 16),
*
* So the fractional part becomes:
* round (decimal_part * 64) = round (remainder * 64 / (16 * baud)) = round (remainder * 4 / baud)
*/
/* Get the mean clock frequency */
core_clock = (CLK_FREQ_HIGHTARGET >> 1) + (CLK_FREQ_LOWTARGET >> 1);
/* Work out the actual clock frequency */
core_clock = (core_clock * CLOCKS_REFERENCE_CLOCK_FREQ) / (((CLK_FREQ_NREFCLKS + 1) & 0xFFFF) * (CLK_GATE_SYS & 0xFF));
baud_rate_divider_i = core_clock / (baud_rate << 4);
remainder = core_clock % (baud_rate << 4);
baud_rate_divider_f = ((remainder << 3) / baud_rate) >> 1;
/* Round it */
baud_rate_divider_f += ((remainder << 3) / baud_rate) & 1;
/* Disable UART while writing to control registers */
obj->reg_base->UARTCR &= ~(1 << 0);
obj->reg_base->UARTIBRD = baud_rate_divider_i;
obj->reg_base->UARTFBRD = baud_rate_divider_f;
/* Make IBRD and FBRD update */
x = obj->reg_base->UARTLCR_H;
obj->reg_base->UARTLCR_H = x;
/* Now enable the UART again */
obj->reg_base->UARTCR |= 1 << 0;
}
/* Set the NVIC bits */
static void irq_enable(serial_t *obj)
{
switch (obj->config) {
case SERIAL_CONFIG_UARTLP_RX_UART0_TX:
{
NVIC_EnableIRQ(UART0_IRQn);
NVIC_EnableIRQ(LPUART_IRQn);
}
break;
case SERIAL_CONFIG_UART0_RX_UART0_TX:
{
NVIC_EnableIRQ(UART0_IRQn);
}
break;
case SERIAL_CONFIG_UART1_RX_UART1_TX:
{
NVIC_EnableIRQ(UART1_IRQn);
}
break;
default:
{
MBED_ASSERT(false);
}
break;
}
}
/* Unset the NVIC bits */
static void irq_disable(serial_t *obj)
{
switch (obj->config) {
case SERIAL_CONFIG_UARTLP_RX_UART0_TX:
{
NVIC_DisableIRQ(UART0_IRQn);
NVIC_DisableIRQ(LPUART_IRQn);
}
break;
case SERIAL_CONFIG_UART0_RX_UART0_TX:
{
NVIC_DisableIRQ(UART0_IRQn);
}
break;
case SERIAL_CONFIG_UART1_RX_UART1_TX:
{
NVIC_DisableIRQ(UART1_IRQn);
}
break;
default:
{
MBED_ASSERT(false);
}
break;
}
}
/* UART0 IRQ */
void IRQ7_UART0_Handler()
{
uint32_t id = serial_irq_ids[IRQ_UART_ID_0_AND_LP];
/* Check Rx and Rx Timeout bit */
if (UART0_REG.UARTMIS & ((1 << 4) | (1 << 6))) {
if (id != 0) {
irq_handler(id, RxIrq);
/* Reading the character clears the interrupt,
* no way to protect against another arriving
* while processing one */
}
}
/* Check Tx bit */
if (UART0_REG.UARTMIS & (1 << 5)) {
if (id != 0) {
irq_handler(id, TxIrq);
}
/* Not sure what clears the interrupt so clear it explicitly */
NVIC_ClearPendingIRQ(UART1_IRQn);
}
}
/* UART1 IRQ */
void IRQ8_UART1_Handler()
{
uint32_t id = serial_irq_ids[IRQ_UART_ID_1];
/* Check Rx and Rx Timeout bit */
if (UART1_REG.UARTMIS & ((1 << 4) | (1 << 6))) {
if (id != 0) {
irq_handler(id, RxIrq);
}
/* Reading the character clears the interrupt,
* no way to protect against another arriving
* while processing one */
}
/* Check Tx bit */
if (UART1_REG.UARTMIS & (1 << 5)) {
if (id != 0) {
irq_handler(id, TxIrq);
}
/* Not sure what clears the interrupt so clear it explicitly */
NVIC_ClearPendingIRQ(UART1_IRQn);
}
}
/* LP UART IRQ, receive only */
void IRQ16_LPUART_Handler()
{
uint32_t id = serial_irq_ids[IRQ_UART_ID_0_AND_LP];
if (id != 0) {
irq_handler(id, RxIrq);
/* Another character might have arrived while
* we are processing the last, so
* check status bits 8 to 10 again and pend
* interrupt if there's something there */
if (((LP_UART_STATUS >> 8) & 0x07) != 0) {
NVIC_SetPendingIRQ(LPUART_IRQn);
} else {
LP_UART_CTRL |= 1 << 27; /* Clear the interrupt */
}
}
}
/* ----------------------------------------------------------------
* MBED API CALLS: SETUP FUNCTIONS
* ----------------------------------------------------------------*/
void serial_init(serial_t *obj, PinName tx, PinName rx)
{
uint32_t clock = CLK_FREQ_DIG_CLKS;
/* There are two and a half UARTs on the chip. The normal
* configuration is to use the LP_UART for Rx and UART0 for
* Tx. This gives maximal power saving in that the chip can
* wake up on receipt of data. However, this only works if the
* data rate is 9600 because that's the only data rate that
* the 32 kHz (i.e. RTC) clock driving the LP UART can support.
*
* So, if the data rate is 9600, use the LP_UART/UART0
* combination, otherwise use UART0 for both Rx and Tx. However,
* we don't know the data rate at this point so assume LP_UART
* (as this works at the default baud rate) and we can change
* our minds later.
*
* There is another serial port, UART1, which is normally used
* by the modem processor to send out debug. We only initialise
* that here if the Tx pin is UART1_TX. */
/* Wait for the clock to be stable */
while ((clock < CLK_FREQ_LOWTARGET) || (clock > CLK_FREQ_HIGHTARGET)) {
clock = CLK_FREQ_DIG_CLKS;
}
if (tx == UART1_TX) {
/* Use UART1 for Rx and Tx */
obj->config = SERIAL_CONFIG_UART1_RX_UART1_TX;
} else {
/* Use LP_UART for Rx, UART0 for Tx */
obj->config = SERIAL_CONFIG_UARTLP_RX_UART0_TX;
}
obj->rx_pin = rx;
obj->tx_pin = tx;
init_config(obj);
/* TODO: set rx pin Pull mode ? */
/* set default baud rate and format */
serial_baud(obj, 9600);
serial_format(obj, 8, ParityNone, 1);
if (tx == UART0_TX) {
/* The UART0 pins are the stdio pins */
stdio_uart_inited = 1;
stdio_uart = *obj;
}
}
void serial_free(serial_t *obj)
{
if (obj->tx_pin == UART0_TX) {
stdio_uart_inited = 0;
}
serial_irq_ids[obj->index] = 0;
/* Release the port HW */
deinit_config(obj);
}
void serial_baud(serial_t *obj, int baudrate)
{
bool switch_port_config = false;
bool format_set = obj->format_set;
uint8_t stop_bits = obj->format.stop_bits;
uint8_t data_bits = obj->format.data_bits;
SerialParity parity = (SerialParity) obj->format.parity;
irq_setting_t irq_rx_setting = obj->irq_rx_setting;
irq_setting_t irq_tx_setting = obj->irq_tx_setting;
if ((obj->config == SERIAL_CONFIG_UARTLP_RX_UART0_TX) && (baudrate != 9600)) {
/* If we were on LP UART but the baud rate is not 9600 then
* switch to the standard UART (as the LP UART can't go any higher
* because it's clocked from 32 kHz) */
deinit_config(obj);
obj->config = SERIAL_CONFIG_UART0_RX_UART0_TX;
init_config(obj);
switch_port_config = true;
} else if ((obj->config == SERIAL_CONFIG_UART0_RX_UART0_TX) && (baudrate == 9600)) {
/* If we were on UART0 but the baud rate is 9600 then switch to the
* LP UART for receive */
deinit_config(obj);
obj->config = SERIAL_CONFIG_UARTLP_RX_UART0_TX;
init_config(obj);
switch_port_config = true;
}
/* Disable UART while writing to control registers */
obj->reg_base->UARTCR &= ~(1 << 0);
if (switch_port_config) {
/* If the port was switched, switch the port configuration also */
if (format_set) {
/* This serial port has been previously set up so switch the
* settings across to this new configuration */
serial_format(obj, data_bits, parity, stop_bits);
}
if (irq_rx_setting != IRQ_NOT_SET) {
/* Do the same for Rx interrupts, if they were set */
serial_irq_set(obj, RxIrq, (irq_rx_setting == IRQ_ON));
}
if (irq_tx_setting != IRQ_NOT_SET) {
/* Do the same for Tx interrupts, if they were set */
serial_irq_set(obj, TxIrq, (irq_tx_setting == IRQ_ON));
}
}
switch (obj->config) {
case SERIAL_CONFIG_UARTLP_RX_UART0_TX:
{
/* Set LP UART to 9600 (numerator 75 (0x4B), denominator 256 (00 == 256)) */
LP_UART_CTRL = (LP_UART_CTRL & ~0xFFFF) | 0x004B;
set_baud(obj, baudrate);
}
break;
case SERIAL_CONFIG_UART0_RX_UART0_TX:
case SERIAL_CONFIG_UART1_RX_UART1_TX:
{
set_baud(obj, baudrate);
}
break;
default:
{
MBED_ASSERT(false);
}
break;
}
/* Enable the UART again */
obj->reg_base->UARTCR |= 1 << 0;
obj->baud_rate = baudrate;
}
void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits)
{
bool lp_also = false;
MBED_ASSERT(data_bits >= MIN_NUM_UART_DATA_BITS);
MBED_ASSERT(data_bits <= MAX_NUM_UART_DATA_BITS);
MBED_ASSERT(stop_bits >= NUM_UART_STOP_BITS_1);
MBED_ASSERT(stop_bits <= NUM_UART_STOP_BITS_2);
/* The LP UART is different to UARTs 0 and 1 so deal with it
* explicitly when required */
if (obj->config == SERIAL_CONFIG_UARTLP_RX_UART0_TX) {
lp_also = true;
}
/* Disable UART while writing to control registers */
obj->reg_base->UARTCR &= ~(1 << 0);
/* Set data bits (bits 5 and 6 of the UART0/1 register, bits 18 and 19 of the LP UART register) */
obj->reg_base->UARTLCR_H = (obj->reg_base->UARTLCR_H & ~(0x03 << 5)) | (REGISTER_DATA_BITS(data_bits) << 5);
if (lp_also) {
LP_UART_CTRL = (LP_UART_CTRL & ~(0x03 << 18)) | (REGISTER_DATA_BITS(data_bits) << 18);
}
obj->format.data_bits = (uint8_t) data_bits;
/* Set stop bits (bit 7 of the UART0/1 register) (there is no such setting for the LP UART) */
if (stop_bits == NUM_UART_STOP_BITS_1) {
/* Clear 2-stop-bits bit */
obj->reg_base->UARTLCR_H &= ~(1 << 7);
} else {
/* Set 2-stop-bits bit */
obj->reg_base->UARTLCR_H |= 1 << 7;
}
obj->format.stop_bits = (uint8_t) stop_bits;
/* Set parity */
switch (parity) {
case ParityNone:
{
/* Disable parity */
obj->reg_base->UARTLCR_H &= ~0x02;
if (lp_also)
{
LP_UART_CTRL &= ~(1 << 24);
}
}
break;
case ParityOdd:
{
/* Set even bit and enable parity */
obj->reg_base->UARTLCR_H = (obj->reg_base->UARTLCR_H | (1 << 3)) | (1 << 2);
if (lp_also)
{
LP_UART_CTRL |= (1 << 24) | (1 << 25);
}
}
break;
case ParityEven:
{
/* Clear even bit and enable parity */
obj->reg_base->UARTLCR_H = (obj->reg_base->UARTLCR_H & ~(1 << 3)) | (1 << 2);
if (lp_also)
{
LP_UART_CTRL &= ~(1 << 25);
LP_UART_CTRL |= 1 << 24;
}
}
break;
default:
{
MBED_ASSERT(false);
}
break;
}
/* Enable the UART again */
obj->reg_base->UARTCR |= 1 << 0;
obj->format.parity = (uint8_t) parity;
obj->format_set = true;
}
/* ----------------------------------------------------------------
* MBED API CALLS: INTERRUPT FUNCTIONS
* ----------------------------------------------------------------*/
void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id)
{
irq_handler = handler;
serial_irq_ids[obj->index] = id;
}
void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable)
{
bool lp_also = false;
if (obj->config == SERIAL_CONFIG_UARTLP_RX_UART0_TX) {
lp_also = true;
}
/* Disable UART while writing to control registers */
obj->reg_base->UARTCR &= ~(1 << 0);
if (enable) {
switch (irq) {
case RxIrq:
{
/* Bit 4 for Rx and bit 6 for Rx Timeout */
obj->reg_base->UARTIMSC |= (1 << 4) | (1 << 6);
if (lp_also)
{
/* "Word Received" IRQ */
LP_UART_CTRL |= 1 << 23;
}
obj->irq_rx_setting = IRQ_ON;
irq_enable(obj);
}
break;
case TxIrq:
{
/* Bit 5 */
obj->reg_base->UARTIMSC |= 1 << 5;
obj->irq_tx_setting = IRQ_ON;
irq_enable(obj);
}
break;
default:
{
MBED_ASSERT(false);
}
break;
}
} else {
switch (irq) {
case RxIrq:
{
/* Bit 4 for Rx and bit 6 for Rx Timeout */
obj->reg_base->UARTIMSC &= ~((1 << 4) | (1 << 6));
if (lp_also)
{
/* "Word Received" IRQ */
LP_UART_CTRL &= ~(1 << 23);
}
obj->irq_rx_setting = IRQ_OFF;
}
break;
case TxIrq:
{
/* Bit 5 */
obj->reg_base->UARTIMSC &= ~(1 << 5);
obj->irq_tx_setting = IRQ_OFF;
}
break;
default:
{
MBED_ASSERT(false);
}
break;
}
if ((obj->irq_rx_setting == IRQ_OFF) && (obj->irq_tx_setting == IRQ_OFF)) {
irq_disable(obj);
}
}
/* Enable the UART again */
obj->reg_base->UARTCR |= 1 << 0;
}
/* ----------------------------------------------------------------
* MBED API CALLS: TRANSMIT AND RECEIVE FUNCTIONS
* ----------------------------------------------------------------*/
int serial_getc(serial_t *obj)
{
uint8_t data = 0;
/* Block until there is data to read */
while (!serial_readable(obj)) {}
/* Read the data */
switch (obj->config) {
case SERIAL_CONFIG_UARTLP_RX_UART0_TX:
{
data = (uint8_t) LP_UART_DATA;
}
break;
case SERIAL_CONFIG_UART0_RX_UART0_TX:
case SERIAL_CONFIG_UART1_RX_UART1_TX:
{
data = (uint8_t) obj->reg_base->UARTDR;
}
break;
default:
{
MBED_ASSERT(false);
}
break;
}
return (int) data;
}
void serial_putc(serial_t *obj, int c)
{
/* Block until there is room to write */
while (!serial_writable(obj)) {}
/* Write the data */
obj->reg_base->UARTDR = (uint8_t) c;
}
int serial_readable(serial_t *obj)
{
bool readable = false;
switch (obj->config) {
case SERIAL_CONFIG_UARTLP_RX_UART0_TX:
{
/* Check the status register, bits 8 to 10 indicate
* the number of Rx bytes (make sure it's the status
* register not the data register as a read from that
* register would clear the Rx interrupt) */
readable = (((LP_UART_STATUS >> 8) & 0x07) != 0);
}
break;
case SERIAL_CONFIG_UART0_RX_UART0_TX:
case SERIAL_CONFIG_UART1_RX_UART1_TX:
{
/* Check the Rx FIFO Empty bit */
readable = ((obj->reg_base->UARTFR & (1 << 4)) != (1 << 4));
}
break;
default:
{
MBED_ASSERT(false);
}
break;
}
return (int) readable;
}
int serial_writable(serial_t *obj)
{
/* Check the "UART TX FIFO full" bit:
* only if this is 0 can we transmit */
return (obj->reg_base->UARTFR & (1 << 5)) != (1 << 5);
}
void serial_break_set(serial_t *obj)
{
/* Disable UART while writing to control registers */
obj->reg_base->UARTCR &= ~(1 << 0);
/* Set bit 1 of the line control register */
obj->reg_base->UARTLCR_H |= 1 << 0;
/* Enable the UART again */
obj->reg_base->UARTCR |= 1 << 0;
}
void serial_break_clear(serial_t *obj)
{
/* Disable UART while writing to control registers */
obj->reg_base->UARTCR &= ~(1 << 0);
/* Clear bit 1 of the line control register */
obj->reg_base->UARTLCR_H &= ~(1 << 0);
/* Enable the UART again */
obj->reg_base->UARTCR |= 1 << 0;
}