Mini UART 使用 System Clock,PL011 UART (UART0) 則擁有自己的 Clock,可以透過 Mailbox 對其做設定。在設定完 Clock 後,其餘剩下的流程與 Mini UART 就非常相似了。
PL011 UART Registers
流程:
- Configure the UART clock frequency by mailbox. (clock-id)
- Enable GPIO (almost same as mini UART).
- Set IBRD and FBRD to configure baud rate.
- Set LCRH to configure line control.
- Set CR to enable UART.
注意: PL011 UART 的 alternate function 需設定為 ALT0 (See UART Introduction)
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
| void uart_init() {
*UART0_CR = 0; // turn off UART0
/* Configure UART0 Clock Frequency */
unsigned int __attribute__((aligned(16))) mbox[9];
mbox[0] = 9 * 4;
mbox[1] = MBOX_CODE_BUF_REQ;
// tags begin
mbox[2] = MBOX_TAG_SET_CLOCK_RATE;
mbox[3] = 12;
mbox[4] = MBOX_CODE_TAG_REQ;
mbox[5] = 2; // UART clock
mbox[6] = 4000000; // 4MHz
mbox[7] = 0; // clear turbo
mbox[8] = 0x0; // end tag
// tags end
mbox_call(mbox, 8);
/* Map UART to GPIO Pins */
// 1. Change GPIO 14, 15 to alternate function
register unsigned int r = *GPFSEL1;
r &= ~((7 << 12) | (7 << 15)); // Reset GPIO 14, 15
r |= (4 << 12) | (4 << 15); // Set ALT0
*GPFSEL1 = r;
// 2. Disable GPIO pull up/down (Because these GPIO pins use alternate functions, not basic input-output)
// Set control signal to disable
*GPPUD = 0;
// Wait 150 cycles
r = 150;
while (r--) {
asm volatile("nop");
}
// Clock the control signal into the GPIO pads
*GPPUDCLK0 = (1 << 14) | (1 << 15);
// Wait 150 cycles
r = 150;
while (r--) {
asm volatile("nop");
}
// Remove the clock
*GPPUDCLK0 = 0;
/* Configure UART0 */
*UART0_IBRD = 0x2; // Set 115200 Baud
*UART0_FBRD = 0xB; // Set 115200 Baud
*UART0_LCRH = 0b11 << 5; // Set word length to 8-bits
*UART0_ICR = 0x7FF; // Clear Interrupts
/* Enable UART */
*UART0_CR = 0x301;
}
|
流程:
- Check FR
- Read from DR
1
2
3
4
5
6
7
8
9
10
| char uart_read() {
// Check data ready field
do {
asm volatile("nop");
} while (*UART0_FR & 0x10);
// Read
char r = (char)(*UART0_DR);
// Convert carrige return to newline
return r == '\r' ? '\n' : r;
}
|
流程:
- Check FR
- Write to DR
1
2
3
4
5
6
7
8
| void uart_write(unsigned int c) {
// Check transmitter idle field
do {
asm volatile("nop");
} while (*UART0_FR & 0x20);
// Write
*UART0_DR = c;
}
|
PrimeCell® UART (PL011)
https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface