blob: cba54d878016b51470e15d131dd2d2b2e640a403 [file] [log] [blame]
Kristofer Jonsson43ce4912020-11-20 09:42:53 +01001/*
2 * Copyright (c) 2019-2020 Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Licensed under the Apache License, Version 2.0 (the License); you may
7 * not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
14 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19#include "uart.h"
20#include "uart_config.h"
21#include <stdint.h>
22#include <stdio.h>
23
24#define CNTLQ 0x11
25#define CNTLS 0x13
26#define DEL 0x7F
27#define BACKSPACE 0x08
28#define CR 0x0D
29#define LF 0x0A
30#define ESC 0x1B
31
32/*------------- Universal Asynchronous Receiver Transmitter (UART) -----------*/
33
34#define __IO volatile
35#define __I volatile const
36#define __O volatile
37
38typedef struct {
39 __IO uint32_t DATA; /* Offset: 0x000 (R/W) Data Register */
40 __IO uint32_t STATE; /* Offset: 0x004 (R/W) Status Register */
41 __IO uint32_t CTRL; /* Offset: 0x008 (R/W) Control Register */
42 union {
43 __I uint32_t INTSTATUS; /* Offset: 0x00C (R/ ) Interrupt Status Register */
44 __O uint32_t INTCLEAR; /* Offset: 0x00C ( /W) Interrupt Clear Register */
45 };
46 __IO uint32_t BAUDDIV; /* Offset: 0x010 (R/W) Baudrate Divider Register */
47} CMSDK_UART_TypeDef;
48
49#define CMSDK_UART0_BASE UART0_BASE
50#define CMSDK_UART0 ((CMSDK_UART_TypeDef *)CMSDK_UART0_BASE)
51#define CMSDK_UART0_BAUDRATE UART0_BAUDRATE
52
53void uart_init(void) {
54 // SystemCoreClock / 9600
55 CMSDK_UART0->BAUDDIV = SYSTEM_CORE_CLOCK / CMSDK_UART0_BAUDRATE;
56
57 CMSDK_UART0->CTRL = ((1ul << 0) | /* TX enable */
58 (1ul << 1)); /* RX enable */
59}
60
61// Output a character
62unsigned char uart_putc(unsigned char my_ch) {
63 while ((CMSDK_UART0->STATE & 1))
64 ; // Wait if Transmit Holding register is full
65
66 if (my_ch == '\n') {
67 CMSDK_UART0->DATA = '\r';
68 while ((CMSDK_UART0->STATE & 1))
69 ; // Wait if Transmit Holding register is full
70 }
71
72 CMSDK_UART0->DATA = my_ch; // write to transmit holding register
73
74 return (my_ch);
75}
76
77// Get a character
78unsigned char uart_getc(void) {
79 unsigned char my_ch;
80 // unsigned int cnt;
81
82 while ((CMSDK_UART0->STATE & 2) == 0) // Wait if Receive Holding register is empty
83 {
84#if 0
85 cnt = MPS3_FPGAIO->CLK100HZ / 50;
86 if (cnt & 0x8)
87 MPS3_FPGAIO->LED = 0x01 << (cnt & 0x7);
88 else
89 MPS3_FPGAIO->LED = 0x80 >> (cnt & 0x7);
90#endif
91 }
92
93 my_ch = CMSDK_UART0->DATA;
94
95 // Convert CR to LF
96 if (my_ch == '\r')
97 my_ch = '\n';
98
99 return (my_ch);
100}
101
102// Get line from terminal
103unsigned int uart_getline(char *lp, unsigned int len) {
104 unsigned int cnt = 0;
105 char c;
106
107 do {
108 c = uart_getc();
109 switch (c) {
110 case CNTLQ: /* ignore Control S/Q */
111 case CNTLS:
112 break;
113 case BACKSPACE:
114 case DEL:
115 if (cnt == 0) {
116 break;
117 }
118 cnt--; /* decrement count */
119 lp--; /* and line pointer */
120 uart_putc(0x08); /* echo backspace */
121 uart_putc(' ');
122 uart_putc(0x08);
123 fflush(stdout);
124 break;
125 case ESC:
126 case 0:
127 *lp = 0; /* ESC - stop editing line */
128 return 0;
129 case CR: /* CR - done, stop editing line */
130 *lp = c;
131 lp++; /* increment line pointer */
132 cnt++; /* and count */
133 c = LF;
134 default:
135 uart_putc(*lp = c); /* echo and store character */
136 fflush(stdout);
137 lp++; /* increment line pointer */
138 cnt++; /* and count */
139 break;
140 }
141 } while (cnt < len - 2 && c != LF); /* check limit and CR */
142 *lp = 0; /* mark end of string */
143 return 1;
144}