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.
Fork of mbed-dev by
targets/TARGET_ublox/TARGET_HI2110/serial_api.c
- Committer:
- AnnaBridge
- Date:
- 2017-11-08
- Revision:
- 178:d650f5d4c87a
- Parent:
- 150:02e0a0aed4ec
File content as of revision 178:d650f5d4c87a:
/* 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; }