/**************************************************************************** * * Copyright 2020 Samsung Electronics All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 * * 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. * ****************************************************************************/ #if DEVICE_SERIAL #include <math.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include "mbed_assert.h" #include "serial_api.h" #include "cmsis.h" #include "pinmap.h" #include "PeripheralPins.h" /****************************************************************************** * INITIALIZATION ******************************************************************************/ #define UART_NUM 3 #define UART_HWCONTROL_NONE 0 #define UART_HWCONTROL_RTS 1 #define UART_HWCONTROL_CTS 2 #define UART_HWCONTROL_RTS_CTS 3 static uint32_t serial_irq_ids[UART_NUM] = {0}; static uart_irq_handler irq_handler; int stdio_uart_inited = 0; serial_t stdio_uart; //#define _USE_UART_FIFO #if DEVICE_SERIAL_ASYNCH #define serial_s(obj) (&((obj)->serial)) #else #define serial_s(obj) (obj) #endif void serial_init(serial_t *obj, PinName tx, PinName rx) { struct serial_s *objs = serial_s(obj); // determine the UART to use UARTName uart_tx = (UARTName)pinmap_peripheral(tx, PinMap_UART_TX); UARTName uart_rx = (UARTName)pinmap_peripheral(rx, PinMap_UART_RX); UARTName uart = (UARTName)pinmap_merge(uart_tx, uart_rx); MBED_ASSERT((int)uart != NC); /* Configure the TX and RX pins */ pinmap_pinout(tx, PinMap_UART_TX); pinmap_pinout(rx, PinMap_UART_RX); // Configure UART objs->baudrate = 115200; // baudrate default value if (uart == STDIO_UART) { #if MBED_CONF_PLATFORM_STDIO_BAUD_RATE objs->baudrate = MBED_CONF_PLATFORM_STDIO_BAUD_RATE; // baudrate takes value from platform/mbed_lib.json #endif /* MBED_CONF_PLATFORM_STDIO_BAUD_RATE */ } else { #if MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE objs->baudrate = MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE; // baudrate takes value from platform/mbed_lib.json #endif /* MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE */ } objs->databits = UART_WL_8BIT; objs->stopbits = UART_1_STOP_BIT; objs->parity = UART_NO_PARITY; #if DEVICE_SERIAL_FC objs->hw_flow_ctl = UART_HWCONTROL_NONE; #endif objs->pin_tx = uart_tx; objs->pin_rx = uart_rx; objs->index = 0; objs->uart = uart; switch (uart) { case UART_0: obj->index = 0; break; case UART_1: obj->index = 1; break; case UART_2: obj->index = 2; break; } bp6a_cmu_enable_clock(obj->index + CMU_UART0_CLK, true); modifyreg32(uart + UART_ULCON_OFFSET, UART_ULCON_WORD_LEN_MASK | UART_ULCON_N_STOP_BIT_MASK | UART_ULCON_PARITY_MODE_MASK, UART_ULCON_WORD_LEN(UART_WL_8BIT) | UART_ULCON_N_STOP_BIT(UART_1_STOP_BIT) | UART_ULCON_PARITY_MODE(UART_NO_PARITY)); modifyreg32(uart + UART_UCON_OFFSET, UART_UCON_RCV_MODE_MASK | UART_UCON_TX_MODE_MASK | UART_UCON_RX_TIMOUT_INT_INTER_MASK, UART_UCON_RCV_MODE(0x01) | UART_UCON_TX_MODE(0x01)); modifyreg32(uart + UART_UFCON_OFFSET, UART_UFCON_RX_FIFO_RESET_MASK | UART_UFCON_TX_FIFO_RESET_MASK, UART_UFCON_RX_FIFO_RESET(0x01) | UART_UFCON_TX_FIFO_RESET(0x01)); serial_baud(obj, objs->baudrate); if (uart == STDIO_UART) { stdio_uart_inited = 1; memcpy(&stdio_uart, obj, sizeof(serial_t)); } } void serial_free(serial_t *obj) { bp6a_cmu_enable_clock(obj->index + CMU_UART0_CLK, false); } void serial_baud(serial_t *obj, int baudrate) { struct serial_s *objs = serial_s(obj); float fFrac = 0; float fDiv = 0; uint32_t Peri_Clock = bp6a_cmu_get_clock_freq(CMU_UART0_CLK + obj->index); fDiv = ((float)Peri_Clock / ((float)baudrate * 16)) - (float)1.0; fFrac = (uint32_t)((fDiv - (int32_t)fDiv) * 16.0f); putreg32(objs->uart + UART_UBRDIV_OFFSET, (uint32_t)fDiv); putreg32(objs->uart + UART_UFRAC_OFFSET, (uint32_t)fFrac); } void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits) { struct serial_s *objs = serial_s(obj); uint8_t prity_bits[] = {UART_NO_PARITY, UART_ODD_PARITY, UART_EVEN_PARITY, \ UART_FORCE_1_PARITY, UART_FORCE_0_PARITY }; MBED_ASSERT((stop_bits == 1) || (stop_bits == 2)); // 0: 1 stop bits, 1: 2 stop bits MBED_ASSERT((data_bits > 4) && (data_bits < 9)); // 0: 5 data bits ... 3: 8 data bits modifyreg32(objs->uart + UART_ULCON_OFFSET, UART_ULCON_WORD_LEN_MASK | UART_ULCON_N_STOP_BIT_MASK | UART_ULCON_PARITY_MODE_MASK, UART_ULCON_WORD_LEN(data_bits - 5) | UART_ULCON_N_STOP_BIT(stop_bits - 1) | UART_ULCON_PARITY_MODE(prity_bits[parity])); } /****************************************************************************** * INTERRUPTS HANDLING ******************************************************************************/ static inline void _uart_irq_handler(SerialIrq irq_type, uint32_t index) { if (serial_irq_ids[index] != 0) { irq_handler(serial_irq_ids[index], irq_type); } } void uart0_irq(void) { uint32_t uints = getreg32(BP_UART0_BASE + UART_UINTP_OFFSET); if (uints & UART_UINTS_RXD_MASK) { _uart_irq_handler(RxIrq, 0); modifyreg32(BP_UART0_BASE + UART_UINTP_OFFSET, UART_UINTP_RXD_MASK, UART_UINTP_RXD(1)); } else if (uints & UART_UINTS_TXD_MASK) { _uart_irq_handler(TxIrq, 0); modifyreg32(BP_UART0_BASE + UART_UINTP_OFFSET, UART_UINTP_TXD_MASK, UART_UINTP_TXD(1)); } NVIC_ClearPendingIRQ((IRQn_Type)UARTR0_IRQn); } void uart1_irq(void) { uint32_t uints = getreg32(BP_UART1_BASE + UART_UINTP_OFFSET); if (uints & UART_UINTS_RXD_MASK) { _uart_irq_handler(RxIrq, 1); modifyreg32(BP_UART1_BASE + UART_UINTP_OFFSET, UART_UINTP_RXD_MASK, UART_UINTP_RXD(1)); } else if (uints & UART_UINTS_TXD_MASK) { _uart_irq_handler(TxIrq, 1); modifyreg32(BP_UART1_BASE + UART_UINTP_OFFSET, UART_UINTP_TXD_MASK, UART_UINTP_TXD(1)); } NVIC_ClearPendingIRQ((IRQn_Type)UARTR1_IRQn); } void uart2_irq(void) { uint32_t uints = getreg32(BP_UART2_BASE + UART_UINTP_OFFSET); if (uints & UART_UINTS_RXD_MASK) { _uart_irq_handler(RxIrq, 2); modifyreg32(BP_UART2_BASE + UART_UINTP_OFFSET, UART_UINTP_TXD_MASK, UART_UINTP_TXD(1)); } else if (uints & UART_UINTS_TXD_MASK) { _uart_irq_handler(TxIrq, 2); modifyreg32(BP_UART2_BASE + UART_UINTP_OFFSET, UART_UINTP_TXD_MASK, UART_UINTP_TXD(1)); } NVIC_ClearPendingIRQ((IRQn_Type)UARTR2_IRQn); } 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) { struct serial_s *objs = serial_s(obj); uint8_t en = (enable != 0) ? 1 : 0; uint32_t vector = 0; switch ((int)objs->uart) { case UART_0: vector = (uint32_t)&uart0_irq; break; case UART_1: vector = (uint32_t)&uart1_irq; break; case UART_2: vector = (uint32_t)&uart2_irq; break; } if (irq == RxIrq) { modifyreg32(obj->uart + UART_UCON_OFFSET, UART_UCON_RCV_MODE_MASK | UART_UCON_RX_INT_TYPE_MASK, UART_UCON_RCV_MODE(1) | UART_UCON_RX_INT_TYPE(1)); modifyreg32(obj->uart + UART_UINTM_OFFSET, UART_UINTM_RXD_MASK | UART_UINTM_TXD_MASK, UART_UINTM_RXD(!en) | UART_UINTM_TXD(en)); } else { modifyreg32(obj->uart + UART_UCON_OFFSET, UART_UCON_TX_MODE_MASK | UART_UCON_TX_INT_TYPE_MASK, UART_UCON_TX_MODE(1) | UART_UCON_TX_INT_TYPE(1)); modifyreg32(obj->uart + UART_UINTM_OFFSET, UART_UINTM_TXD_MASK | UART_UINTM_TXD_MASK, UART_UINTM_RXD(en) | UART_UINTM_TXD(!en)); } #ifdef _USE_UART_FIFO modifyreg32(obj->uart + UART_UFCON_OFFSET, UART_UFCON_FIFO_EN_MASK, UART_UFCON_FIFO_EN(1)); #endif if (enable) { NVIC_ClearPendingIRQ((IRQn_Type)(UARTR0_IRQn + objs->index)); NVIC_SetVector((IRQn_Type)(UARTR0_IRQn + objs->index), vector); NVIC_EnableIRQ((IRQn_Type)(UARTR0_IRQn + objs->index)); } else { uint32_t intm = getreg32(obj->uart + UART_UINTM_OFFSET); if (intm == 0) { NVIC_DisableIRQ((IRQn_Type)(UARTR0_IRQn + objs->index)); } } } /****************************************************************************** * READ/WRITE ******************************************************************************/ int serial_getc(serial_t *obj) { struct serial_s *objs = serial_s(obj); while (!serial_readable(obj)); return getreg8(objs->uart + UART_URXH_OFFSET); } void serial_putc(serial_t *obj, int c) { struct serial_s *objs = serial_s(obj); while (!serial_writable(obj)); putreg8(objs->uart + UART_UTXH_OFFSET, (uint8_t)c); } int serial_readable(serial_t *obj) { struct serial_s *objs = serial_s(obj); return (getreg32(objs->uart + UART_UTRSTAT_OFFSET) & UART_UTRSTAT_RCV_BUF_DATA_READY_MASK); } int serial_writable(serial_t *obj) { struct serial_s *objs = serial_s(obj); #ifdef _USE_UART_FIFO return !((getreg32(objs->uart + UART_UFSTAT_OFFSET) & UART_UFSTAT_TX_FIFO_FULL_MASK) >> UART_UFSTAT_TX_FIFO_FULL_SHIFT); #else return ((getreg32(objs->uart + UART_UTRSTAT_OFFSET) & UART_UTRSTAT_TX_BUF_EMPTY_MASK)); #endif } void serial_clear(serial_t *obj) { struct serial_s *objs = serial_s(obj); modifyreg32(objs->uart + UART_UFCON_OFFSET, UART_UFCON_RX_FIFO_RESET_MASK | UART_UFCON_TX_FIFO_RESET_MASK, UART_UFCON_RX_FIFO_RESET(1) | UART_UFCON_TX_FIFO_RESET(1)); } #if DEVICE_SERIAL_FC void serial_set_flow_control(serial_t *obj, FlowControl type, PinName rxflow, PinName txflow) { struct serial_s *objs = serial_s(obj); UARTName uart_rts = (UARTName)pinmap_peripheral(rxflow, PinMap_UART_RTS); UARTName uart_cts = (UARTName)pinmap_peripheral(txflow, PinMap_UART_CTS); if (((UARTName)pinmap_merge(uart_rts, objs->uart) == (UARTName)NC) || ((UARTName)pinmap_merge(uart_cts, objs->uart) == (UARTName)NC)) { MBED_ASSERT(0); return; } if (type == FlowControlNone) { // Disable hardware flow control objs->hw_flow_ctl = UART_HWCONTROL_NONE; } if (type == FlowControlRTS) { // Enable RTS MBED_ASSERT(uart_rts != (UARTName)NC); // Enable the pin for RTS function pinmap_pinout(rxflow, PinMap_UART_RTS); objs->pin_rts = rxflow; } if (type == FlowControlCTS) { // Enable CTS MBED_ASSERT(uart_cts != (UARTName)NC); // Enable the pin for CTS function pinmap_pinout(txflow, PinMap_UART_CTS); objs->hw_flow_ctl = UART_HWCONTROL_CTS; objs->pin_cts = txflow; } if (type == FlowControlRTSCTS) { // Enable CTS & RTS MBED_ASSERT(uart_rts != (UARTName)NC); MBED_ASSERT(uart_cts != (UARTName)NC); // Enable the pin for CTS function pinmap_pinout(txflow, PinMap_UART_CTS); // Enable the pin for RTS function pinmap_pinout(rxflow, PinMap_UART_RTS); objs->hw_flow_ctl = UART_HWCONTROL_RTS_CTS; objs->pin_rts = rxflow; objs->pin_cts = txflow; } modifyreg32(objs->uart + UART_UMCON_OFFSET, UART_UMCON_AFC_MASK | UART_UMCON_AFC_MASK, UART_UMCON_RTS(1) | UART_UMCON_AFC(1)); } #endif void serial_pinout_tx(PinName tx) { pinmap_pinout(tx, PinMap_UART_TX); } void serial_break_set(serial_t *obj) { struct serial_s *objs = serial_s(obj); modifyreg32(objs->uart + UART_UCON_OFFSET, UART_UCON_SND_BRK_SIG_MASK, UART_UCON_SND_BRK_SIG(1)); } void serial_break_clear(serial_t *obj) { struct serial_s *objs = serial_s(obj); modifyreg32(objs->uart + UART_UCON_OFFSET, UART_UCON_SND_BRK_SIG_MASK, UART_UCON_SND_BRK_SIG(0)); } const PinMap *serial_tx_pinmap() { return PinMap_UART_TX; } const PinMap *serial_rx_pinmap() { return PinMap_UART_RX; } const PinMap *serial_cts_pinmap() { #if !DEVICE_SERIAL_FC static const PinMap PinMap_UART_CTS[] = { {NC, NC, 0} }; #endif return PinMap_UART_CTS; } const PinMap *serial_rts_pinmap() { #if !DEVICE_SERIAL_FC static const PinMap PinMap_UART_RTS[] = { {NC, NC, 0} }; #endif return PinMap_UART_RTS; } #endif