blob: cba54d878016b51470e15d131dd2d2b2e640a403 [file] [log] [blame]
/*
* Copyright (c) 2019-2020 Arm Limited. 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
*
* 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 "uart.h"
#include "uart_config.h"
#include <stdint.h>
#include <stdio.h>
#define CNTLQ 0x11
#define CNTLS 0x13
#define DEL 0x7F
#define BACKSPACE 0x08
#define CR 0x0D
#define LF 0x0A
#define ESC 0x1B
/*------------- Universal Asynchronous Receiver Transmitter (UART) -----------*/
#define __IO volatile
#define __I volatile const
#define __O volatile
typedef struct {
__IO uint32_t DATA; /* Offset: 0x000 (R/W) Data Register */
__IO uint32_t STATE; /* Offset: 0x004 (R/W) Status Register */
__IO uint32_t CTRL; /* Offset: 0x008 (R/W) Control Register */
union {
__I uint32_t INTSTATUS; /* Offset: 0x00C (R/ ) Interrupt Status Register */
__O uint32_t INTCLEAR; /* Offset: 0x00C ( /W) Interrupt Clear Register */
};
__IO uint32_t BAUDDIV; /* Offset: 0x010 (R/W) Baudrate Divider Register */
} CMSDK_UART_TypeDef;
#define CMSDK_UART0_BASE UART0_BASE
#define CMSDK_UART0 ((CMSDK_UART_TypeDef *)CMSDK_UART0_BASE)
#define CMSDK_UART0_BAUDRATE UART0_BAUDRATE
void uart_init(void) {
// SystemCoreClock / 9600
CMSDK_UART0->BAUDDIV = SYSTEM_CORE_CLOCK / CMSDK_UART0_BAUDRATE;
CMSDK_UART0->CTRL = ((1ul << 0) | /* TX enable */
(1ul << 1)); /* RX enable */
}
// Output a character
unsigned char uart_putc(unsigned char my_ch) {
while ((CMSDK_UART0->STATE & 1))
; // Wait if Transmit Holding register is full
if (my_ch == '\n') {
CMSDK_UART0->DATA = '\r';
while ((CMSDK_UART0->STATE & 1))
; // Wait if Transmit Holding register is full
}
CMSDK_UART0->DATA = my_ch; // write to transmit holding register
return (my_ch);
}
// Get a character
unsigned char uart_getc(void) {
unsigned char my_ch;
// unsigned int cnt;
while ((CMSDK_UART0->STATE & 2) == 0) // Wait if Receive Holding register is empty
{
#if 0
cnt = MPS3_FPGAIO->CLK100HZ / 50;
if (cnt & 0x8)
MPS3_FPGAIO->LED = 0x01 << (cnt & 0x7);
else
MPS3_FPGAIO->LED = 0x80 >> (cnt & 0x7);
#endif
}
my_ch = CMSDK_UART0->DATA;
// Convert CR to LF
if (my_ch == '\r')
my_ch = '\n';
return (my_ch);
}
// Get line from terminal
unsigned int uart_getline(char *lp, unsigned int len) {
unsigned int cnt = 0;
char c;
do {
c = uart_getc();
switch (c) {
case CNTLQ: /* ignore Control S/Q */
case CNTLS:
break;
case BACKSPACE:
case DEL:
if (cnt == 0) {
break;
}
cnt--; /* decrement count */
lp--; /* and line pointer */
uart_putc(0x08); /* echo backspace */
uart_putc(' ');
uart_putc(0x08);
fflush(stdout);
break;
case ESC:
case 0:
*lp = 0; /* ESC - stop editing line */
return 0;
case CR: /* CR - done, stop editing line */
*lp = c;
lp++; /* increment line pointer */
cnt++; /* and count */
c = LF;
default:
uart_putc(*lp = c); /* echo and store character */
fflush(stdout);
lp++; /* increment line pointer */
cnt++; /* and count */
break;
}
} while (cnt < len - 2 && c != LF); /* check limit and CR */
*lp = 0; /* mark end of string */
return 1;
}