-
Notifications
You must be signed in to change notification settings - Fork 199
/
Copy pathconsole.c
184 lines (153 loc) · 4.1 KB
/
console.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
/*
* console.c
*
* printf-style interface to USART.
*
* Written & released by Keir Fraser <[email protected]>
*
* This is free and unencumbered software released into the public domain.
* See the file COPYING for more details, or visit <http://unlicense.org>.
*/
#define BAUD 3000000 /* 3Mbaud */
#define USART1_IRQ 37
#define USART3_IRQ 39
#if 1
#define usart usart1
#define USART_IRQ USART1_IRQ
#define usart_gpio gpioa
#define usart_tx_pin 9
#define usart_rx_pin 10
#define PCLK (APB2_MHZ * 1000000)
#else
#define usart usart3
#define USART_IRQ USART3_IRQ
#define usart_gpio gpioc
#define usart_tx_pin 10
#define usart_rx_pin 11
#define PCLK (APB1_MHZ * 1000000)
#endif
/* Normally flush to serial is asynchronously executed in a low-pri IRQ. */
#define CONSOLE_SOFTIRQ SOFTIRQ_1
DEFINE_IRQ(CONSOLE_SOFTIRQ, "SOFTIRQ_console");
/* We stage serial output in a ring buffer. */
static char ring[2048];
#define MASK(x) ((x)&(sizeof(ring)-1))
static unsigned int cons, prod;
/* The console can be set into synchronous mode in which case IRQ is disabled
* and the transmit-empty flag is polled manually for each byte. */
static bool_t sync_console;
static void flush_ring_to_serial(void)
{
unsigned int c = cons, p = prod;
barrier();
while (c != p) {
while (!(usart->sr & USART_SR_TXE))
cpu_relax();
usart->dr = ring[MASK(c++)];
}
barrier();
cons = c;
}
static void SOFTIRQ_console(void)
{
flush_ring_to_serial();
}
static void kick_tx(void)
{
if (sync_console) {
flush_ring_to_serial();
} else if (cons != prod) {
IRQx_set_pending(CONSOLE_SOFTIRQ);
}
}
int vprintk(const char *format, va_list ap)
{
static char str[128];
char *p, c;
int n;
IRQ_global_disable();
n = vsnprintf(str, sizeof(str), format, ap);
p = str;
while (((c = *p++) != '\0') && ((prod-cons) != (sizeof(ring) - 1))) {
switch (c) {
case '\r': /* CR: ignore as we generate our own CR/LF */
break;
case '\n': /* LF: convert to CR/LF (usual terminal behaviour) */
ring[MASK(prod++)] = '\r';
/* fall through */
default:
ring[MASK(prod++)] = c;
break;
}
}
kick_tx();
if (!sync_console)
IRQ_global_enable();
return n;
}
int printk(const char *format, ...)
{
va_list ap;
int n;
va_start(ap, format);
n = vprintk(format, ap);
va_end(ap);
return n;
}
void console_sync(void)
{
if (sync_console)
return;
IRQ_global_disable();
sync_console = TRUE;
kick_tx();
/* Leave IRQs globally disabled. */
}
void console_init(void)
{
/* Turn on the clocks. */
#if USART_IRQ == USART1_IRQ
rcc->apb2enr |= RCC_APB2ENR_USART1EN;
#else
rcc->apb1enr |= RCC_APB1ENR_USART3EN;
#endif
/* Enable TX pin for USART output, RX pin as input. */
#if MCU == STM32F105
gpio_configure_pin(usart_gpio, usart_tx_pin, AFO_pushpull(_10MHz));
gpio_configure_pin(usart_gpio, usart_rx_pin, GPI_pull_up);
#elif MCU == AT32F435
gpio_set_af(usart_gpio, usart_tx_pin, 7);
gpio_set_af(usart_gpio, usart_rx_pin, 7);
gpio_configure_pin(usart_gpio, usart_tx_pin, AFO_pushpull(_10MHz));
gpio_configure_pin(usart_gpio, usart_rx_pin, AFI(PUPD_up));
#endif
/* BAUD, 8n1. */
usart->brr = PCLK / BAUD;
usart->cr1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE;
usart->cr3 = 0;
IRQx_set_prio(CONSOLE_SOFTIRQ, CONSOLE_IRQ_PRI);
IRQx_enable(CONSOLE_SOFTIRQ);
}
/* Debug helper: if we get stuck somewhere, calling this beforehand will cause
* any serial input to cause a crash dump of the stuck context. */
void console_crash_on_input(void)
{
if (mcu_package == MCU_QFN32) {
/* Unavailable: PA10 is reassigned from SER_RX to K4 (rotary select
* on the KC30 header). */
return;
}
(void)usart->dr; /* clear UART_SR_RXNE */
usart->cr1 |= USART_CR1_RXNEIE;
IRQx_set_prio(USART_IRQ, RESET_IRQ_PRI);
IRQx_enable(USART_IRQ);
}
/*
* Local variables:
* mode: C
* c-file-style: "Linux"
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: nil
* End:
*/