mirror of https://github.com/ARMmbed/mbed-os.git
807 lines
25 KiB
C
807 lines
25 KiB
C
/* mbed Microcontroller Library
|
|
* Copyright (c) 2006-2020 ARM Limited
|
|
* 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.
|
|
*/
|
|
// math.h required for floating point operations for baud rate calculation
|
|
|
|
#if DEVICE_SERIAL
|
|
#include "mbed_assert.h"
|
|
#include <math.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "serial_api.h"
|
|
#include "cmsis.h"
|
|
#include "PeripheralPins.h"
|
|
#include "gpio_api.h"
|
|
#include "RZ_A2_Init.h"
|
|
|
|
#include "iodefine.h"
|
|
#include "mbed_drv_cfg.h"
|
|
#include "mbed_critical.h"
|
|
|
|
/******************************************************************************
|
|
* INITIALIZATION
|
|
******************************************************************************/
|
|
|
|
#define UART_NUM 5
|
|
#define IRQ_NUM 3
|
|
|
|
static void uart0_tx_irq(void);
|
|
static void uart0_rx_irq(void);
|
|
static void uart0_er_irq(void);
|
|
static void uart1_tx_irq(void);
|
|
static void uart1_rx_irq(void);
|
|
static void uart1_er_irq(void);
|
|
static void uart2_tx_irq(void);
|
|
static void uart2_rx_irq(void);
|
|
static void uart2_er_irq(void);
|
|
static void uart3_tx_irq(void);
|
|
static void uart3_rx_irq(void);
|
|
static void uart3_er_irq(void);
|
|
static void uart4_tx_irq(void);
|
|
static void uart4_rx_irq(void);
|
|
static void uart4_er_irq(void);
|
|
|
|
static uint8_t serial_available_buffer(serial_t *obj);
|
|
static void serial_irq_err_set(serial_t *obj, uint32_t enable);
|
|
|
|
static volatile struct st_scifa *SCIFA[UART_NUM] = {
|
|
&SCIFA0, &SCIFA1, &SCIFA2, &SCIFA3, &SCIFA4
|
|
};
|
|
|
|
int stdio_uart_inited = 0;
|
|
serial_t stdio_uart;
|
|
static uart_irq_handler irq_handler;
|
|
|
|
struct serial_global_data_s {
|
|
uint32_t serial_irq_id;
|
|
gpio_t sw_rts, sw_cts;
|
|
serial_t *tranferring_obj, *receiving_obj;
|
|
uint32_t async_tx_callback, async_rx_callback;
|
|
int event, wanted_rx_events;
|
|
};
|
|
|
|
static struct serial_global_data_s uart_data[UART_NUM];
|
|
|
|
static const IRQn_Type irq_set_tbl[UART_NUM][IRQ_NUM] = {
|
|
{RXI0_IRQn, TXI0_IRQn, ERI0_IRQn},
|
|
{RXI1_IRQn, TXI1_IRQn, ERI1_IRQn},
|
|
{RXI2_IRQn, TXI2_IRQn, ERI2_IRQn},
|
|
{RXI3_IRQn, TXI3_IRQn, ERI3_IRQn},
|
|
{RXI4_IRQn, TXI4_IRQn, ERI4_IRQn},
|
|
};
|
|
|
|
static const IRQHandler hander_set_tbl[UART_NUM][IRQ_NUM] = {
|
|
{uart0_rx_irq, uart0_tx_irq, uart0_er_irq},
|
|
{uart1_rx_irq, uart1_tx_irq, uart1_er_irq},
|
|
{uart2_rx_irq, uart2_tx_irq, uart2_er_irq},
|
|
{uart3_rx_irq, uart3_tx_irq, uart3_er_irq},
|
|
{uart4_rx_irq, uart4_tx_irq, uart4_er_irq},
|
|
};
|
|
|
|
|
|
void serial_init(serial_t *obj, PinName tx, PinName rx)
|
|
{
|
|
volatile uint8_t dummy_buf;
|
|
int is_stdio_uart = 0;
|
|
// determine the UART to use
|
|
uint32_t uart_tx = pinmap_peripheral(tx, PinMap_UART_TX);
|
|
uint32_t uart_rx = pinmap_peripheral(rx, PinMap_UART_RX);
|
|
uint32_t ch_no = pinmap_merge(uart_tx, uart_rx);
|
|
|
|
#if defined(PRINTF_NOT_USE)
|
|
if ((int)ch_no == NC) {
|
|
obj->serial.ch = ch_no;
|
|
return;
|
|
}
|
|
#else
|
|
MBED_ASSERT((int)ch_no != NC);
|
|
#endif
|
|
|
|
// pinout the chosen uart
|
|
pinmap_pinout(tx, PinMap_UART_TX);
|
|
pinmap_pinout(rx, PinMap_UART_RX);
|
|
|
|
obj->serial.ch = ch_no;
|
|
obj->serial.uart = SCIFA[ch_no];
|
|
|
|
/* ==== Module standby clear ==== */
|
|
CPG.STBCR4.BYTE &= ~(0x80 >> ch_no);
|
|
dummy_buf = CPG.STBCR4.BYTE;
|
|
(void)dummy_buf;
|
|
|
|
/* ==== SCIF initial setting ==== */
|
|
/* --- Serial control register(SCR) setting --- */
|
|
obj->serial.uart->SCR.WORD = 0x0000; /* SCIFA transmitting and receiving operations stop */
|
|
|
|
/* ---- FIFO control register (FCR) setting ---- */
|
|
if ((int)uart_tx != NC) { /* Use transmit */
|
|
/* Transmit FIFO reset */
|
|
obj->serial.uart->FCR.BIT.TFRST = 0x01;
|
|
}
|
|
|
|
if ((int)uart_rx != NC) { /* Use receive */
|
|
/* Receive FIFO data register reset */
|
|
obj->serial.uart->FCR.BIT.RFRST = 0x1;
|
|
}
|
|
|
|
/* ---- Serial status register (FSR) setting ---- */
|
|
obj->serial.uart->FSR.BIT.DR = 0x0; /* ER bit clear */
|
|
obj->serial.uart->FSR.BIT.BRK = 0x0; /* BRK bit clear */
|
|
obj->serial.uart->FSR.BIT.ER = 0x0; /* ER bit clear */
|
|
|
|
/* ---- Line status register (LSR) setting ---- */
|
|
obj->serial.uart->LSR.BIT.ORER = 0x0; /* ORER bit clear */
|
|
|
|
/* ---- Serial control register (SCR) setting ---- */
|
|
obj->serial.uart->SCR.BIT.CKE = 0x0; /* B'00 : Internal CLK */
|
|
|
|
serial_baud(obj, 9600);
|
|
serial_format(obj, 8, ParityNone, 1);
|
|
|
|
/* ---- Serial extension mode register (SEMR) setting ----
|
|
b7 BGDM - Baud rate generator double-speed mode : Normal mode
|
|
b0 ABCS - Base clock select in asynchronous mode : Base clock is 16 times the bit rate */
|
|
|
|
obj->serial.uart->SEMR.BIT.ABCS0 = 0x0; /* Base clock select in asynchronous mode : Base clock is 16 times the bit rate */
|
|
obj->serial.uart->SEMR.BIT.NFEN = 0x1; /* Noise Filter : Enable */
|
|
obj->serial.uart->SEMR.BIT.DIR = 0x0; /* LSB first */
|
|
obj->serial.uart->SEMR.BIT.MDDRS = 0x0; /* Select BRR register */
|
|
obj->serial.uart->SEMR.BIT.BRME = 0x0; /* Bit Modulation Enable : Disable */
|
|
obj->serial.uart->SEMR.BIT.BGDM = 0x0; /* Baud rate generator double-speed mode : Normal mode*/
|
|
|
|
obj->serial.uart->FCR.BIT.LOOP = 0x0; /* Loop-back test : Disabled */
|
|
if ((int)uart_rx != NC) {
|
|
obj->serial.uart->FCR.BIT.RFRST = 0x0; /* Receive FIFO data register reset : Disabled */
|
|
obj->serial.uart->SCR.BIT.TE = 0x1; /* transmitting operations is enabled */
|
|
} else {
|
|
obj->serial.uart->FCR.BIT.RFRST = 0x1; /* Receive FIFO data register reset : Enable */
|
|
}
|
|
if ((int)uart_tx != NC) { /* Use transmit */
|
|
obj->serial.uart->FCR.BIT.TFRST = 0x0; /* Transmit FIFO data register reset : Disabled */
|
|
obj->serial.uart->SCR.BIT.RE = 0x1; /* receiving operations is enabled */
|
|
} else {
|
|
obj->serial.uart->FCR.BIT.TFRST = 0x1; /* Transmit FIFO data register reset : Enable */
|
|
}
|
|
obj->serial.uart->FCR.BIT.MCE = 0x0; /* Modem control enable : Disabled */
|
|
obj->serial.uart->FCR.BIT.TTRG = 0x3; /* Transmit FIFO data trigger : 0-data */
|
|
obj->serial.uart->FCR.BIT.RTRG = 0x0; /* Receive FIFO data trigger : 1-data */
|
|
obj->serial.uart->FCR.BIT.RSTRG = 0x0; /* RTS output active trigger : Initial value */
|
|
|
|
/* ---- Serial port register (SCR, SPTR) setting ---- */
|
|
/* b1 SPB2IO - Serial port break output : Enabled
|
|
b0 SPB2DT - Serial port break data : High-level */
|
|
|
|
obj->serial.uart->SPTR.WORD |= 0x3; /* b1 SPB2IO - Serial port break output : Enabled */
|
|
/* b0 SPB2DT - Serial port break data : High-level */
|
|
|
|
if ((int)uart_rx != NC) {
|
|
obj->serial.uart->SCR.BIT.TIE = 0x1;
|
|
obj->serial.uart->SCR.BIT.TE = 0x1; /* transmitting operations is enabled */
|
|
}
|
|
if ((int)uart_tx != NC) { /* Use transmit */
|
|
obj->serial.uart->SCR.BIT.RIE = 0x1;
|
|
obj->serial.uart->SCR.BIT.RE = 0x1; /* receiving operations is enabled */
|
|
}
|
|
|
|
is_stdio_uart = (ch_no == STDIO_UART) ? (1) : (0);
|
|
|
|
if (is_stdio_uart) {
|
|
stdio_uart_inited = 1;
|
|
memcpy(&stdio_uart, obj, sizeof(serial_t));
|
|
}
|
|
}
|
|
|
|
void serial_free(serial_t *obj)
|
|
{
|
|
|
|
}
|
|
|
|
// serial_baud
|
|
// set the baud rate, taking in to account the current SystemFrequency
|
|
void serial_baud(serial_t *obj, int baudrate)
|
|
{
|
|
uint32_t idx;
|
|
uint32_t brr;
|
|
uint32_t mddr;
|
|
uint32_t wk_data = 8;
|
|
float wk_error;
|
|
|
|
#if defined(PRINTF_NOT_USE)
|
|
if ((int)obj->serial.ch == NC) {
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
if (baudrate <= 0) {
|
|
return;
|
|
}
|
|
|
|
for (idx = 0; idx <= 4; idx++) {
|
|
/* Calculate Bit Rate */
|
|
brr = CM0_RENESAS_RZ_A2_P1_CLK / (wk_data * baudrate);
|
|
if (brr > 0) {
|
|
/* The maximum baud rate is (CM0_RENESAS_RZ_A2_P1_CLK / 8) */
|
|
/* If the baud rate is more, brr is set to 0 */
|
|
brr -= 1;
|
|
}
|
|
|
|
/* When idx is 4 (CKS=3), it allows up to the limit value which can be adjusted with MDDR */
|
|
if ((brr <= 255) || (idx == 4)) {
|
|
if (brr > 255) {
|
|
brr = 255;
|
|
}
|
|
|
|
/* Calculate Modulation Duty */
|
|
wk_error = (float)CM0_RENESAS_RZ_A2_P1_CLK / (float)(wk_data * baudrate * (brr + 1));
|
|
mddr = (uint32_t)((256.0f / wk_error) + 0.5f);
|
|
if (mddr < 128) {
|
|
mddr = 128; /* MDDR >= 128 (Executed only when idx is 4) */
|
|
}
|
|
|
|
/* idx= 0: BGDM=1 ABCS0=1 CKS=0 */
|
|
/* 1: BGDM=0 ABCS0=0 CKS=0 */
|
|
/* 2: BGDM=0 ABCS0=0 CKS=1 */
|
|
/* 3: BGDM=1 ABCS0=1 CKS=3 (Do not use CKS=2) */
|
|
/* 4: BGDM=0 ABCS0=0 CKS=3 */
|
|
if ((idx == 0) || (idx == 3)) {
|
|
obj->serial.uart->SEMR.BIT.BGDM = 0x1; /* Baud rate generator double-speed mode */
|
|
obj->serial.uart->SEMR.BIT.ABCS0 = 0x1; /* 8 times the transfer rate as the base clock */
|
|
obj->serial.uart->SMR.BIT.CKS = idx; /* Clock Select 0(1/1), 1(1/4), 2(1/16), 3(1/64) */
|
|
} else {
|
|
obj->serial.uart->SEMR.BIT.BGDM = 0x0; /* Baud rate generator normal mode */
|
|
obj->serial.uart->SEMR.BIT.ABCS0 = 0x0; /* 16 times the transfer rate as the base clock */
|
|
obj->serial.uart->SMR.BIT.CKS = idx - 1; /* Clock Select 0(1/1), 1(1/4), 2(1/16), 3(1/64) */
|
|
}
|
|
obj->serial.uart->SEMR.BIT.MDDRS = 0x0; /* Select BRR register */
|
|
obj->serial.uart->BRR_MDDR.BRR.BYTE = (uint8_t)brr; /* Bit Rate */
|
|
obj->serial.uart->SEMR.BIT.BRME = 0x0; /* Bit rate modulation is disabled */
|
|
if (mddr <= 255) {
|
|
obj->serial.uart->SEMR.BIT.MDDRS = 0x1; /* Select MDDR register */
|
|
obj->serial.uart->BRR_MDDR.MDDR.BYTE = (uint8_t)mddr; /* Modulation Duty */
|
|
obj->serial.uart->SEMR.BIT.BRME = 0x1; /* Bit rate modulation is enabled */
|
|
}
|
|
break;
|
|
}
|
|
wk_data = (wk_data << 2);
|
|
}
|
|
}
|
|
|
|
void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits)
|
|
{
|
|
#if defined(PRINTF_NOT_USE)
|
|
if ((int)obj->serial.ch == NC) {
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
MBED_ASSERT((stop_bits == 1) || (stop_bits == 2));
|
|
MBED_ASSERT((data_bits == 8) || (data_bits == 7));
|
|
MBED_ASSERT((parity == ParityNone) || (parity == ParityOdd) || (parity == ParityEven) ||
|
|
(parity == ParityForced1) || (parity == ParityForced0));
|
|
|
|
if (stop_bits == 1) {
|
|
obj->serial.uart->SMR.BIT.STOP = 0x0; /* Stop bit length : 1 stop bit */
|
|
} else {
|
|
obj->serial.uart->SMR.BIT.STOP = 0x1; /* Stop bit length : 2 stop bits */
|
|
}
|
|
|
|
switch (parity) {
|
|
case ParityNone:
|
|
obj->serial.uart->SMR.BIT.PE = 0x0; /* Parity enable : Add and check are disabled */
|
|
obj->serial.uart->SMR.BIT.PM = 0x0; /* Parity mode : even */
|
|
break;
|
|
case ParityOdd:
|
|
obj->serial.uart->SMR.BIT.PE = 0x1; /* Parity enable : Add and check are enabled */
|
|
obj->serial.uart->SMR.BIT.PM = 0x1; /* Parity mode : odd */
|
|
break;
|
|
case ParityEven:
|
|
obj->serial.uart->SMR.BIT.PE = 0x1; /* Parity enable : Add and check are enabled */
|
|
obj->serial.uart->SMR.BIT.PM = 0x0; /* Parity mode : even */
|
|
break;
|
|
case ParityForced1:
|
|
case ParityForced0:
|
|
default:
|
|
obj->serial.uart->SMR.BIT.PE = 0x0; /* Parity enable : Add and check are disabled */
|
|
obj->serial.uart->SMR.BIT.PM = 0x0; /* Parity mode : even */
|
|
break;
|
|
}
|
|
|
|
if (data_bits == 8) {
|
|
obj->serial.uart->SMR.BIT.CHR = 0x0; /* Character length : 8-bit data */
|
|
} else {
|
|
obj->serial.uart->SMR.BIT.CHR = 0x1; /* Character length : 7-bit data */
|
|
}
|
|
obj->serial.uart->SMR.BIT.CM = 0x0; /* Communication mode : Asynchronous mode */
|
|
}
|
|
|
|
/******************************************************************************
|
|
* INTERRUPTS HANDLING
|
|
******************************************************************************/
|
|
|
|
static void uart_tx_irq(uint32_t ch)
|
|
{
|
|
serial_t *obj = uart_data[ch].tranferring_obj;
|
|
if (obj) {
|
|
int i = obj->tx_buff.length - obj->tx_buff.pos;
|
|
if (0 < i) {
|
|
if (serial_available_buffer(obj) < i) {
|
|
i = serial_available_buffer(obj);
|
|
}
|
|
do {
|
|
uint8_t c = *(uint8_t *)obj->tx_buff.buffer;
|
|
obj->tx_buff.buffer = (uint8_t *)obj->tx_buff.buffer + 1;
|
|
++obj->tx_buff.pos;
|
|
obj->serial.uart->FTDR.BYTE = c;
|
|
obj->serial.uart->FSR.WORD &= ~0x0060u;
|
|
} while (--i);
|
|
} else {
|
|
uart_data[ch].tranferring_obj = NULL;
|
|
uart_data[ch].event = SERIAL_EVENT_TX_COMPLETE;
|
|
((void (*)())uart_data[ch].async_tx_callback)();
|
|
}
|
|
}
|
|
|
|
irq_handler(uart_data[ch].serial_irq_id, TxIrq);
|
|
}
|
|
|
|
static void uart_rx_irq(uint32_t ch)
|
|
{
|
|
serial_t *obj = uart_data[ch].receiving_obj;
|
|
if (obj) {
|
|
if (obj->serial.uart->LSR.BIT.ORER == 1) {
|
|
obj->serial.uart->LSR.BIT.ORER = 0;
|
|
if (uart_data[ch].wanted_rx_events & SERIAL_EVENT_RX_OVERRUN_ERROR) {
|
|
serial_rx_abort_asynch(obj);
|
|
uart_data[ch].event = SERIAL_EVENT_RX_OVERRUN_ERROR;
|
|
((void (*)())uart_data[ch].async_rx_callback)();
|
|
}
|
|
return;
|
|
}
|
|
int c = serial_getc(obj);
|
|
if (c != -1) {
|
|
((uint8_t *)obj->rx_buff.buffer)[obj->rx_buff.pos] = c;
|
|
++obj->rx_buff.pos;
|
|
if (c == obj->char_match && ! obj->char_found) {
|
|
obj->char_found = 1;
|
|
if (obj->rx_buff.pos == obj->rx_buff.length) {
|
|
if (uart_data[ch].wanted_rx_events & SERIAL_EVENT_RX_COMPLETE) {
|
|
uart_data[ch].event = SERIAL_EVENT_RX_COMPLETE;
|
|
}
|
|
}
|
|
if (uart_data[ch].wanted_rx_events & SERIAL_EVENT_RX_CHARACTER_MATCH) {
|
|
uart_data[ch].event |= SERIAL_EVENT_RX_CHARACTER_MATCH;
|
|
}
|
|
if (uart_data[ch].event) {
|
|
uart_data[ch].receiving_obj = NULL;
|
|
((void (*)())uart_data[ch].async_rx_callback)();
|
|
}
|
|
} else if (obj->rx_buff.pos == obj->rx_buff.length) {
|
|
uart_data[ch].receiving_obj = NULL;
|
|
if (uart_data[ch].wanted_rx_events & SERIAL_EVENT_RX_COMPLETE) {
|
|
uart_data[ch].event = SERIAL_EVENT_RX_COMPLETE;
|
|
((void (*)())uart_data[ch].async_rx_callback)();
|
|
}
|
|
}
|
|
} else {
|
|
serial_rx_abort_asynch(obj);
|
|
if (uart_data[ch].wanted_rx_events & (SERIAL_EVENT_RX_PARITY_ERROR | SERIAL_EVENT_RX_FRAMING_ERROR)) {
|
|
uart_data[ch].event = SERIAL_EVENT_RX_PARITY_ERROR | SERIAL_EVENT_RX_FRAMING_ERROR;
|
|
if (obj->serial.uart->FSR.BIT.PER == 1) {
|
|
uart_data[ch].event = SERIAL_EVENT_RX_PARITY_ERROR;
|
|
} else if (obj->serial.uart->FSR.BIT.FER == 1) {
|
|
uart_data[ch].event = SERIAL_EVENT_RX_FRAMING_ERROR;
|
|
}
|
|
((void (*)())uart_data[ch].async_rx_callback)();
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
irq_handler(uart_data[ch].serial_irq_id, RxIrq);
|
|
}
|
|
|
|
static void uart_err_irq(uint32_t ch)
|
|
{
|
|
serial_t *obj = uart_data[ch].receiving_obj;
|
|
if (obj) {
|
|
serial_irq_err_set(obj, 0);
|
|
if (uart_data[ch].wanted_rx_events & (SERIAL_EVENT_RX_PARITY_ERROR | SERIAL_EVENT_RX_FRAMING_ERROR)) {
|
|
uart_data[ch].event = SERIAL_EVENT_RX_PARITY_ERROR | SERIAL_EVENT_RX_FRAMING_ERROR;
|
|
if (obj->serial.uart->FSR.BIT.PER == 1) {
|
|
uart_data[ch].event = SERIAL_EVENT_RX_PARITY_ERROR;
|
|
} else if (obj->serial.uart->FSR.BIT.FER == 1) {
|
|
uart_data[ch].event = SERIAL_EVENT_RX_FRAMING_ERROR;
|
|
}
|
|
((void (*)())uart_data[ch].async_rx_callback)();
|
|
}
|
|
serial_rx_abort_asynch(obj);
|
|
|
|
core_util_critical_section_enter();
|
|
if (obj->serial.uart->FSR.WORD & 0x009Cu) {
|
|
obj->serial.uart->FSR.WORD &= ~0x009Cu;
|
|
}
|
|
if (obj->serial.uart->LSR.BIT.ORER == 1) {
|
|
obj->serial.uart->LSR.BIT.ORER = 0;
|
|
}
|
|
core_util_critical_section_exit();
|
|
}
|
|
}
|
|
|
|
static void uart0_tx_irq(void)
|
|
{
|
|
uart_tx_irq(0);
|
|
}
|
|
static void uart0_rx_irq(void)
|
|
{
|
|
uart_rx_irq(0);
|
|
}
|
|
static void uart0_er_irq(void)
|
|
{
|
|
uart_err_irq(0);
|
|
}
|
|
|
|
static void uart1_tx_irq(void)
|
|
{
|
|
uart_tx_irq(1);
|
|
}
|
|
static void uart1_rx_irq(void)
|
|
{
|
|
uart_rx_irq(1);
|
|
}
|
|
static void uart1_er_irq(void)
|
|
{
|
|
uart_err_irq(1);
|
|
}
|
|
|
|
static void uart2_tx_irq(void)
|
|
{
|
|
uart_tx_irq(2);
|
|
}
|
|
static void uart2_rx_irq(void)
|
|
{
|
|
uart_rx_irq(2);
|
|
}
|
|
static void uart2_er_irq(void)
|
|
{
|
|
uart_err_irq(2);
|
|
}
|
|
|
|
static void uart3_tx_irq(void)
|
|
{
|
|
uart_tx_irq(3);
|
|
}
|
|
static void uart3_rx_irq(void)
|
|
{
|
|
uart_rx_irq(3);
|
|
}
|
|
static void uart3_er_irq(void)
|
|
{
|
|
uart_err_irq(3);
|
|
}
|
|
|
|
static void uart4_tx_irq(void)
|
|
{
|
|
uart_tx_irq(4);
|
|
}
|
|
static void uart4_rx_irq(void)
|
|
{
|
|
uart_rx_irq(4);
|
|
}
|
|
static void uart4_er_irq(void)
|
|
{
|
|
uart_err_irq(4);
|
|
}
|
|
|
|
void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id)
|
|
{
|
|
irq_handler = handler;
|
|
uart_data[obj->serial.ch].serial_irq_id = id;
|
|
}
|
|
|
|
static void serial_irq_set_irq(IRQn_Type IRQn, IRQHandler handler, uint32_t enable)
|
|
{
|
|
if (enable) {
|
|
InterruptHandlerRegister(IRQn, (void (*)(uint32_t))handler);
|
|
GIC_SetPriority(IRQn, 5);
|
|
GIC_EnableIRQ(IRQn);
|
|
} else {
|
|
GIC_DisableIRQ(IRQn);
|
|
}
|
|
}
|
|
|
|
static void serial_irq_err_set(serial_t *obj, uint32_t enable)
|
|
{
|
|
serial_irq_set_irq(irq_set_tbl[obj->serial.ch][2], hander_set_tbl[obj->serial.ch][2], enable);
|
|
}
|
|
|
|
void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable)
|
|
{
|
|
IRQn_Type IRQn;
|
|
IRQHandler handler;
|
|
|
|
IRQn = irq_set_tbl[obj->serial.ch][irq];
|
|
handler = hander_set_tbl[obj->serial.ch][irq];
|
|
|
|
if (obj->serial.ch < UART_NUM) {
|
|
serial_irq_set_irq(IRQn, handler, enable);
|
|
}
|
|
}
|
|
|
|
/******************************************************************************
|
|
* READ/WRITE
|
|
******************************************************************************/
|
|
int serial_getc(serial_t *obj)
|
|
{
|
|
int data;
|
|
|
|
#if defined(PRINTF_NOT_USE)
|
|
if ((int)obj->serial.ch == NC) {
|
|
return 0;
|
|
}
|
|
#endif
|
|
/* Confirming receive error(ER,BRK,FER,PER,ORER) */
|
|
if (((obj->serial.uart->FSR.WORD & 0x009Cu) != 0) ||
|
|
(obj->serial.uart->LSR.BIT.ORER == 1)) {
|
|
/* ---- Detect receive error ---- */
|
|
/* Disable reception */
|
|
/* Reset receiving FIFO */
|
|
/* Clearing FIFO reception reset */
|
|
/* Error bit clear */
|
|
/* Enable reception */
|
|
obj->serial.uart->SCR.BIT.RE = 0;
|
|
obj->serial.uart->FCR.BIT.RFRST = 1;
|
|
obj->serial.uart->FCR.BIT.RFRST = 0;
|
|
obj->serial.uart->FSR.WORD &= ~0x009Cu;
|
|
obj->serial.uart->LSR.BIT.ORER = 0;
|
|
obj->serial.uart->SCR.BIT.RE = 1;
|
|
return -1;
|
|
}
|
|
|
|
/* Is there receive FIFO data? */
|
|
while (obj->serial.uart->FSR.BIT.RDF == 0) {
|
|
/* Wait */
|
|
}
|
|
|
|
/* Read receive data */
|
|
data = (int)((obj->serial.uart->FRDR.BYTE) & 0xFFu);
|
|
/* Clear DR,RDF */
|
|
obj->serial.uart->FSR.BIT.RDF = 0;
|
|
|
|
return data;
|
|
}
|
|
|
|
void serial_putc(serial_t *obj, int c)
|
|
{
|
|
#if defined(PRINTF_NOT_USE)
|
|
if ((int)obj->serial.ch == NC) {
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
/* Check if it is possible to transmit (TDFE flag) */
|
|
while (obj->serial.uart->FSR.BIT.TDFE == 0) {
|
|
/* Wait */
|
|
}
|
|
|
|
/* Write the receiving data in TDR */
|
|
obj->serial.uart->FTDR.BYTE = (uint8_t)c;
|
|
|
|
/* Clear TDFE and TEND flag */
|
|
obj->serial.uart->FSR.WORD &= ~0x0060u;
|
|
}
|
|
|
|
int serial_readable(serial_t *obj)
|
|
{
|
|
if (obj->serial.uart->FSR.BIT.RDF == 0) {
|
|
return 0;
|
|
} else {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
int serial_writable(serial_t *obj)
|
|
{
|
|
#if defined(PRINTF_NOT_USE)
|
|
if ((int)obj->serial.ch == NC) {
|
|
return 0;
|
|
}
|
|
#endif
|
|
if (obj->serial.uart->FSR.BIT.TDFE == 0) {
|
|
return 0;
|
|
} else {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
void serial_clear(serial_t *obj)
|
|
{
|
|
#if defined(PRINTF_NOT_USE)
|
|
if ((int)obj->serial.ch == NC) {
|
|
return;
|
|
}
|
|
#endif
|
|
core_util_critical_section_enter();
|
|
obj->serial.uart->FCR.WORD |= 0x0006u; // TFRST = 1, RFRST = 1
|
|
obj->serial.uart->FCR.WORD &= ~0x0006u; // TFRST = 0, RFRST = 0
|
|
obj->serial.uart->FSR.WORD &= ~0x0093u; // ER, BRK, RDF, DR = 0
|
|
core_util_critical_section_exit();
|
|
}
|
|
|
|
void serial_pinout_tx(PinName tx)
|
|
{
|
|
pinmap_pinout(tx, PinMap_UART_TX);
|
|
}
|
|
|
|
void serial_break_set(serial_t *obj)
|
|
{
|
|
core_util_critical_section_enter();
|
|
obj->serial.uart->SCR.BIT.TE = 0;
|
|
core_util_critical_section_exit();
|
|
}
|
|
|
|
void serial_break_clear(serial_t *obj)
|
|
{
|
|
#if defined(PRINTF_NOT_USE)
|
|
if ((int)obj->serial.ch == NC) {
|
|
return;
|
|
}
|
|
#endif
|
|
core_util_critical_section_enter();
|
|
obj->serial.uart->SCR.BIT.TE = 1;
|
|
core_util_critical_section_exit();
|
|
}
|
|
|
|
#if DEVICE_SERIAL_FC
|
|
void serial_set_flow_control(serial_t *obj, FlowControl type, PinName rxflow, PinName txflow)
|
|
{
|
|
// determine the UART to use
|
|
|
|
if (type == FlowControlRTSCTS) {
|
|
core_util_critical_section_enter();
|
|
obj->serial.uart->FCR.BIT.MCE = 0x1; // CTS/RTS enable
|
|
core_util_critical_section_exit();
|
|
pinmap_pinout(rxflow, PinMap_UART_RTS);
|
|
pinmap_pinout(txflow, PinMap_UART_CTS);
|
|
} else {
|
|
core_util_critical_section_enter();
|
|
obj->serial.uart->FCR.BIT.MCE = 0x0; // CTS/RTS diable
|
|
core_util_critical_section_exit();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static uint8_t serial_available_buffer(serial_t *obj)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
const PinMap *serial_tx_pinmap()
|
|
{
|
|
return PinMap_UART_TX;
|
|
}
|
|
|
|
const PinMap *serial_rx_pinmap()
|
|
{
|
|
return PinMap_UART_RX;
|
|
}
|
|
|
|
const PinMap *serial_cts_pinmap()
|
|
{
|
|
return PinMap_UART_CTS;
|
|
}
|
|
|
|
const PinMap *serial_rts_pinmap()
|
|
{
|
|
return PinMap_UART_RTS;
|
|
}
|
|
|
|
#if DEVICE_SERIAL_ASYNCH
|
|
|
|
/******************************************************************************
|
|
* ASYNCHRONOUS HAL
|
|
******************************************************************************/
|
|
int serial_tx_asynch(serial_t *obj, const void *tx, size_t tx_length, uint8_t tx_width, uint32_t handler, uint32_t event, DMAUsage hint)
|
|
{
|
|
int i;
|
|
buffer_t *buf = &obj->tx_buff;
|
|
struct serial_global_data_s *data = uart_data + obj->serial.ch;
|
|
|
|
if (tx_length == 0) {
|
|
return 0;
|
|
}
|
|
|
|
buf->buffer = (void *)tx;
|
|
buf->length = tx_length * tx_width / 8;
|
|
buf->pos = 0;
|
|
buf->width = tx_width;
|
|
data->tranferring_obj = obj;
|
|
data->async_tx_callback = handler;
|
|
serial_irq_set(obj, TxIrq, 1);
|
|
|
|
while (!serial_writable(obj));
|
|
i = buf->length;
|
|
if (serial_available_buffer(obj) < i) {
|
|
i = serial_available_buffer(obj);
|
|
}
|
|
do {
|
|
uint8_t c = *(uint8_t *)buf->buffer;
|
|
obj->tx_buff.buffer = (uint8_t *)obj->tx_buff.buffer + 1;
|
|
++buf->pos;
|
|
obj->serial.uart->FTDR.BYTE = c;
|
|
obj->serial.uart->FSR.WORD &= ~0x0060u;
|
|
} while (--i);
|
|
|
|
return buf->length;
|
|
}
|
|
|
|
void serial_rx_asynch(serial_t *obj, void *rx, size_t rx_length, uint8_t rx_width,
|
|
uint32_t handler, uint32_t event, uint8_t char_match, DMAUsage hint)
|
|
{
|
|
buffer_t *buf = &obj->rx_buff;
|
|
struct serial_global_data_s *data = uart_data + obj->serial.ch;
|
|
|
|
if (rx_length == 0) {
|
|
return;
|
|
}
|
|
|
|
buf->buffer = rx;
|
|
buf->length = rx_length * rx_width / 8;
|
|
buf->pos = 0;
|
|
buf->width = rx_width;
|
|
obj->char_match = char_match;
|
|
obj->char_found = 0;
|
|
data->receiving_obj = obj;
|
|
data->async_rx_callback = handler;
|
|
data->event = 0;
|
|
data->wanted_rx_events = event;
|
|
|
|
serial_irq_set(obj, RxIrq, 1);
|
|
serial_irq_err_set(obj, 1);
|
|
}
|
|
|
|
uint8_t serial_tx_active(serial_t *obj)
|
|
{
|
|
return uart_data[obj->serial.ch].tranferring_obj != NULL;
|
|
}
|
|
|
|
uint8_t serial_rx_active(serial_t *obj)
|
|
{
|
|
return uart_data[obj->serial.ch].receiving_obj != NULL;
|
|
}
|
|
|
|
int serial_irq_handler_asynch(serial_t *obj)
|
|
{
|
|
return uart_data[obj->serial.ch].event;
|
|
}
|
|
|
|
void serial_tx_abort_asynch(serial_t *obj)
|
|
{
|
|
uart_data[obj->serial.ch].tranferring_obj = NULL;
|
|
obj->serial.uart->FCR.BIT.TFRST = 1;
|
|
obj->serial.uart->FCR.BIT.TFRST = 0;
|
|
}
|
|
|
|
void serial_rx_abort_asynch(serial_t *obj)
|
|
{
|
|
uart_data[obj->serial.ch].receiving_obj = NULL;
|
|
obj->serial.uart->FCR.BIT.RFRST = 1;
|
|
obj->serial.uart->FCR.BIT.RFRST = 0;
|
|
}
|
|
|
|
#endif
|
|
#endif
|