-
Notifications
You must be signed in to change notification settings - Fork 3
/
serial.c
274 lines (250 loc) · 6.17 KB
/
serial.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
/*
* serial.c -- Raspberry Pi serial i/o (UART) routines written in C
*
* Copyright 2014 Dale Schumacher, Tristan Slominski
*
* 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.
*
* Some of this code was inspired by bare-metal examples
* from David Welch at https://github.com/dwelch67/raspberrypi
*/
#include "serial.h"
#define USE_SERIAL_UART0 /* select full UART for serial i/o */
//#define USE_SERIAL_UART1 /* select mini UART for serial i/o */
#define GPIO_BASE 0x20200000
#define GPFSEL1 (*((volatile u32*)(GPIO_BASE + 0x04)))
#define GPSET0 (*((volatile u32*)(GPIO_BASE + 0x1c)))
#define GPCLR0 (*((volatile u32*)(GPIO_BASE + 0x28)))
#define GPPUD (*((volatile u32*)(GPIO_BASE + 0x94)))
#define GPPUDCLK0 (*((volatile u32*)(GPIO_BASE + 0x98)))
struct uart0 {
u32 DR; //_00;
u32 RSRECR; //_04;
u32 _08;
u32 _0c;
u32 _10;
u32 _14;
u32 FR; //_18;
u32 _1c;
u32 ILPR; //_20;
u32 IBRD; //_24;
u32 FBRD; //_28;
u32 LCRH; //_2c;
u32 CR; //_30;
u32 IFLS; //_34;
u32 IMSC; //_38;
u32 RIS; //_3c;
u32 MIS; //_40;
u32 ICR; //_44;
u32 DMACR; //_48;
};
#define UART0 ((volatile struct uart0 *)0x20201000)
struct uart1 {
u32 _00;
u32 AUXENB; //_04;
u32 _08;
u32 _0c;
u32 _10;
u32 _14;
u32 _18;
u32 _1c;
u32 _20;
u32 _24;
u32 _28;
u32 _2c;
u32 _30;
u32 _34;
u32 _38;
u32 _3c;
u32 IO; //_40;
u32 IER; //_44;
u32 IIR; //_48;
u32 LCR; //_4c;
u32 MCR; //_50;
u32 LSR; //_54;
u32 MSR; //_58;
u32 _5c;
u32 CNTL; //_60;
u32 STAT; //_64;
u32 BAUD; //_68;
};
#define UART1 ((volatile struct uart1 *)0x20215000)
/*
* Initialize serial UART to use GPIO pins 14 (TX) and 15 (RX)
*/
void
serial_init()
{
#ifdef USE_SERIAL_UART0
u32 r0;
UART0->CR = 0;
r0 = GPFSEL1;
r0 &= ~(7 << 12); // gpio pin 14
r0 |= 4 << 12; // alt0 = full UART transmit (TX)
r0 &= ~(7 << 15); // gpio pin 15
r0 |= 4 << 15; // alt0 = full UART receive (RX)
GPFSEL1 = r0;
GPPUD = 0;
SPIN(150); // wait for (at least) 150 clock cycles
r0 = (1 << 14) | (1 << 15);
GPPUDCLK0 = r0;
SPIN(150); // wait for (at least) 150 clock cycles
GPPUDCLK0 = 0;
UART0->ICR = 0x7FF;
UART0->IBRD = 1;
UART0->FBRD = 40;
UART0->LCRH = 0x70;
UART0->CR = 0x301;
#endif /* USE_SERIAL_UART0 */
#ifdef USE_SERIAL_UART1
u32 r0;
r0 = GPFSEL1;
r0 &= ~(7 << 12); // gpio pin 14
r0 |= 2 << 12; // alt5 = mini UART transmit (TX)
r0 &= ~(7 << 15); // gpio pin 15
r0 |= 2 << 15; // alt5 = mini UART receive (RX)
GPFSEL1 = r0;
GPPUD = 0;
// SPIN(150); // wait for (at least) 150 clock cycles
SPIN(250); // wait for (at least) 250 clock cycles
r0 = (1 << 14) | (1 << 15);
GPPUDCLK0 = r0;
// SPIN(150); // wait for (at least) 150 clock cycles
SPIN(250); // wait for (at least) 250 clock cycles
GPPUDCLK0 = 0;
UART1->AUXENB = 1;
UART1->IER = 0;
UART1->CNTL = 0;
UART1->LCR = 3;
UART1->MCR = 0;
UART1->IER = 0;
UART1->IIR = 0xc6;
/* ((250,000,000 / 115200) / 8) - 1 = 270 */
UART1->BAUD = 270;
SPIN(250); // wait for (at least) 250 clock cycles
UART1->CNTL = 3;
#endif /* USE_SERIAL_UART1 */
}
/*
* Serial input ready != 0, wait == 0
*/
int
serial_in_ready()
{
#ifdef USE_SERIAL_UART0
return (UART0->FR & 0x10) == 0;
#endif /* USE_SERIAL_UART0 */
#ifdef USE_SERIAL_UART1
return (UART1->LSR & 0x01) != 0;
#endif /* USE_SERIAL_UART1 */
}
/*
* Raw input from serial port
*/
int
serial_in()
{
#ifdef USE_SERIAL_UART0
return UART0->DR & 0xff;
#endif /* USE_SERIAL_UART0 */
#ifdef USE_SERIAL_UART1
return UART1->IO & 0xff;
#endif /* USE_SERIAL_UART1 */
}
/*
* Consume input until !ready
*/
void
serial_in_flush() {
while (serial_in_ready()) {
serial_in();
}
}
/*
* Serial output ready != 0, wait == 0
*/
int
serial_out_ready()
{
#ifdef USE_SERIAL_UART0
return (UART0->FR & 0x20) == 0;
#endif /* USE_SERIAL_UART0 */
#ifdef USE_SERIAL_UART1
return (UART1->LSR & 0x20) != 0;
#endif /* USE_SERIAL_UART1 */
}
/*
* Raw output to serial port
*/
int
serial_out(u8 data)
{
#ifdef USE_SERIAL_UART0
UART0->DR = (u32)data;
return (int)data;
#endif /* USE_SERIAL_UART0 */
#ifdef USE_SERIAL_UART1
UART1->IO = (u32)data;
return (int)data;
#endif /* USE_SERIAL_UART1 */
}
/*
* Blocking read from serial port
*/
int
serial_read()
{
while (!serial_in_ready())
;
return serial_in();
}
/*
* Blocking write to serial port
*/
int
serial_write(u8 data)
{
while (!serial_out_ready())
;
return serial_out(data);
}
/*
* Print a C-string, character-by-character
*/
void
serial_puts(char* s)
{
int c;
while ((c = *s++) != '\0') {
serial_write((u8)c);
}
}
/*
* Print n repetitions of character c
*/
void
serial_rep(int c, int n)
{
while (n-- > 0) {
serial_write((u8)c);
}
}
/*
* Print end-of-line
*/
void
serial_eol()
{
serial_write((u8)'\r');
serial_write((u8)'\n');
}