mbed-os/targets/TARGET_TOSHIBA/TARGET_TMPM3H6/serial_api.c

372 lines
9.8 KiB
C

/* mbed Microcontroller Library
* (C)Copyright TOSHIBA ELECTRONIC DEVICES & STORAGE CORPORATION 2018 All rights reserved
*
* 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.
*/
#include <string.h>
#include "serial_api.h"
#include "pinmap.h"
#include "mbed_error.h"
#include "gpio_include.h"
#include "objects.h"
static const PinMap PinMap_UART_TX[] = {
{PA1, SERIAL_0, PIN_DATA(1, 1)},
{PJ2, SERIAL_1, PIN_DATA(2, 1)},
{PL1, SERIAL_2, PIN_DATA(2, 1)},
{NC, NC, 0}
};
static const PinMap PinMap_UART_RX[] = {
{PA2, SERIAL_0, PIN_DATA(1, 0)},
{PJ1, SERIAL_1, PIN_DATA(2, 0)},
{PL0, SERIAL_2, PIN_DATA(2, 0)},
{NC, NC, 0}
};
static uint32_t serial_irq_ids[UART_NUM] = {0};
static uart_irq_handler irq_handler;
int stdio_uart_inited = 0;
serial_t stdio_uart;
static void uart_init(TSB_UART_TypeDef *UARTx, uart_inittypedef_t *InitStruct);
static void uart_get_boudrate_setting(uart_boudrate_t *brddiviser, uint32_t boudrate);
static void uart_swreset(TSB_UART_TypeDef *UARTx);
void serial_init(serial_t *obj, PinName tx, PinName rx)
{
int is_stdio_uart = 0;
UARTName uart_tx = (UARTName)pinmap_peripheral(tx, PinMap_UART_TX);
UARTName uart_rx = (UARTName)pinmap_peripheral(rx, PinMap_UART_RX);
UARTName uart_name = (UARTName)pinmap_merge(uart_tx, uart_rx);
MBED_ASSERT((int)uart_name != NC);
obj->index = uart_name;
switch (uart_name) {
case SERIAL_0:
obj->UARTx = TSB_UART0;
TSB_CG_FSYSENA_IPENA23 = ENABLE;
TSB_CG_FSYSENA_IPENA00 = ENABLE;
break;
case SERIAL_1:
obj->UARTx = TSB_UART1;
TSB_CG_FSYSENA_IPENA24 = ENABLE;
TSB_CG_FSYSENA_IPENA08 = ENABLE;
TSB_CG_FSYSENA_IPENA09 = ENABLE;
break;
case SERIAL_2:
obj->UARTx = TSB_UART2;
TSB_CG_FSYSENA_IPENA25 = ENABLE;
TSB_CG_FSYSENA_IPENA10 = ENABLE;
break;
default:
error("UART is not available");
break;
}
pinmap_pinout(tx, PinMap_UART_TX);
pinmap_pinout(rx, PinMap_UART_RX);
if (tx != NC && rx != NC) {
obj->uart_config.Mode = UART_ENABLE_RX | UART_ENABLE_TX;
} else {
if (tx != NC) {
obj->uart_config.Mode = UART_ENABLE_TX;
} else {
if (rx != NC) {
obj->uart_config.Mode = UART_ENABLE_RX;
}
}
}
obj->uart_config.BaudRate = 9600;
obj->uart_config.DataBits = 8;
obj->uart_config.StopBits = 0;
obj->uart_config.Parity = ParityNone;
obj->uart_config.FlowCtrl = FlowControlNone;
uart_init(obj->UARTx, &obj->uart_config);
is_stdio_uart = (uart_name == 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)
{
obj->UARTx->TRANS = 0;
obj->UARTx->CR0 = 0;
obj->UARTx->CR1 = 0;
uart_swreset(obj->UARTx);
obj->uart_config.BaudRate = 0;
obj->uart_config.DataBits = 0;
obj->uart_config.StopBits = 0;
obj->uart_config.Parity = 0;
obj->uart_config.Mode = 0;
obj->uart_config.FlowCtrl = 0;
}
void serial_baud(serial_t *obj, int baudrate)
{
obj->uart_config.BaudRate = baudrate;
uart_init(obj->UARTx, &obj->uart_config);
}
void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits)
{
MBED_ASSERT((stop_bits == 1) || (stop_bits == 2)); // 0: 1 stop bits, 1: 2 stop bits
MBED_ASSERT((parity == ParityNone) || (parity == ParityOdd) || (parity == ParityEven));
MBED_ASSERT((data_bits > 6) && (data_bits < 10)); // 0: 7 data bits ... 2: 9 data bits
obj->uart_config.DataBits = data_bits;
obj->uart_config.StopBits = stop_bits;
obj->uart_config.Parity = parity;
uart_init(obj->UARTx, &obj->uart_config);
}
void INTUART0TX_IRQHandler(void)
{
irq_handler(serial_irq_ids[SERIAL_0], TxIrq);
}
void INTUART0RX_IRQHandler(void)
{
irq_handler(serial_irq_ids[SERIAL_0], RxIrq);
}
void INTUART1TX_IRQHandler(void)
{
irq_handler(serial_irq_ids[SERIAL_1], TxIrq);
}
void INTUART1RX_IRQHandler(void)
{
irq_handler(serial_irq_ids[SERIAL_1], RxIrq);
}
void INTUART2TX_IRQHandler(void)
{
irq_handler(serial_irq_ids[SERIAL_2], TxIrq);
}
void INTUART2RX_IRQHandler(void)
{
irq_handler(serial_irq_ids[SERIAL_2], RxIrq);
}
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)
{
IRQn_Type irq_n = (IRQn_Type)0;
switch (obj->index) {
case SERIAL_0:
if (irq == RxIrq) {
irq_n = INTUART0RX_IRQn;
} else {
irq_n = INTUART0TX_IRQn;
}
break;
case SERIAL_1:
if (irq == RxIrq) {
irq_n = INTUART1RX_IRQn;
} else {
irq_n = INTUART1TX_IRQn;
}
break;
case SERIAL_2:
if (irq == RxIrq) {
irq_n = INTUART2RX_IRQn;
} else {
irq_n = INTUART2TX_IRQn;
}
break;
default:
break;
}
NVIC_ClearPendingIRQ(irq_n);
if (enable) {
NVIC_EnableIRQ(irq_n);
} else {
NVIC_DisableIRQ(irq_n);
}
}
int serial_getc(serial_t *obj)
{
int data = 0;
while (!serial_readable(obj)) { // Wait until Rx buffer is full
// Do nothing
}
if (obj->uart_config.Mode & UART_ENABLE_TX) {
obj->UARTx->TRANS &= 0x0D;
}
data = data | (obj->UARTx->DR & 0xFFU);
if (obj->uart_config.Mode & UART_ENABLE_TX) {
obj->UARTx->TRANS |= UART_ENABLE_TX;
}
return data;
}
void serial_putc(serial_t *obj, int c)
{
while (!serial_writable(obj)) {
// Do nothing
}
if (obj->uart_config.Mode & UART_ENABLE_RX) {
obj->UARTx->TRANS &= 0x0E;
}
obj->UARTx->DR = c & 0xFFU;
if (obj->uart_config.Mode & UART_ENABLE_RX) {
obj->UARTx->TRANS |= UART_ENABLE_RX;
}
}
int serial_readable(serial_t *obj)
{
int ret = 0;
if ((obj->UARTx->SR & 0x0000000F) != 0) {
ret = 1;
}
return ret;
}
int serial_writable(serial_t *obj)
{
int ret = 0;
if ((obj->UARTx->SR & 0x8000) == 0) {
ret = 1;
}
return ret;
}
void serial_clear(serial_t *obj)
{
obj->UARTx->FIFOCLR = 0x03;
}
void serial_pinout_tx(PinName tx)
{
pinmap_pinout(tx, PinMap_UART_TX);
}
void serial_break_set(serial_t *obj)
{
obj->UARTx->TRANS |= 0x08;
}
void serial_break_clear(serial_t *obj)
{
obj->UARTx->TRANS &= ~(0x08);
}
static void uart_swreset(TSB_UART_TypeDef *UARTx)
{
while (((UARTx->SWRST) & UARTxSWRST_SWRSTF_MASK) == UARTxSWRST_SWRSTF_RUN) {
// No process
}
UARTx->SWRST = UARTxSWRST_SWRST_10;
UARTx->SWRST = UARTxSWRST_SWRST_01;
while (((UARTx->SWRST) & UARTxSWRST_SWRSTF_MASK) == UARTxSWRST_SWRSTF_RUN) {
// No process
}
}
static void uart_get_boudrate_setting(uart_boudrate_t *brddiviser, uint32_t boudrate)
{
uint32_t clock = 0;
uint32_t k = 0;
uint64_t tx = 0;
uint64_t work = 1;
uint64_t p_range64 = 0;
uint64_t boud64 = 0;
uint64_t tx64 = 0;
uint64_t work64 = 1;
SystemCoreClockUpdate(); // Get the peripheral I/O clock frequency
clock = SystemCoreClock;
tx = (uint64_t)((uint64_t)clock << 6);
tx /= work;
tx64 = (uint64_t)((uint64_t)clock << 8);
tx64 /= work64;
work = ((uint64_t)boudrate);
tx /= work;
tx >>= 4;
boud64 = (64U * boudrate);
p_range64 = ((boud64 / 100) * 3);
for (k = UART_RANGE_K_MIN; (k <= UART_RANGE_K_MAX); k++) {
work = tx + k;
if (work >= (uint64_t)((uint64_t)1 << 6)) {
work -= (uint64_t)((uint64_t)1 << 6);
work >>= 6;
if ((UART_RANGE_N_MIN <= (uint32_t)work) && ((uint32_t)work <= UART_RANGE_N_MAX)) {
work64 = work <<6;
work64 = (uint64_t)(work64 + (64 - (uint64_t)k));
work64 = (tx64 / work64);
if (((boud64 - p_range64) <= work64) && (work64 <= (boud64 + p_range64))) {
brddiviser->brn = work;
brddiviser->brk = k;
break;
}
}
}
}
}
static void uart_init(TSB_UART_TypeDef *UARTx, uart_inittypedef_t *InitStruct)
{
uart_boudrate_t UTx_brd = {0};
uint32_t brk = 0;
uint32_t tmp = 0;
uint32_t parity_check = 0;
uint32_t data_length = 0;
UARTx->CLK = UART_PLESCALER_1; // Register Setting
uart_get_boudrate_setting(&UTx_brd, InitStruct->BaudRate);
UTx_brd.ken = UART_DIVISION_ENABLE;
brk = (UTx_brd.brk << 16);
UARTx->BRD = (UTx_brd.ken | brk | UTx_brd.brn);
parity_check = (InitStruct->Parity == ParityOdd) ? 1 : ((InitStruct->Parity == ParityEven) ? 3 : 0);
data_length = (InitStruct->DataBits) == 8 ? 1 : (((InitStruct->DataBits) == 7) ? 0 : 2);
tmp = (((InitStruct->FlowCtrl) << 9) | ((InitStruct->StopBits) << 4) | (parity_check << 2) | data_length);
UARTx->CR0 = tmp;
UARTx->CR1 = (UART_RX_FIFO_FILL_LEVEL | UART_TX_INT_ENABLE | UART_RX_INT_ENABLE);
UARTx->FIFOCLR = (UARTxFIFOCLR_TFCLR_CLEAR | UARTxFIFOCLR_RFCLR_CLEAR);
UARTx->TRANS = InitStruct->Mode;
}