diff options
author | Bad Diode <bd@badd10de.dev> | 2021-09-07 12:52:57 +0200 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2021-09-07 12:52:57 +0200 |
commit | 11a95bd16da3ba212ebbd64300c9136cee555bc1 (patch) | |
tree | 4c61e05a28efaef64fa42e1fc8226144e3f4356c | |
parent | d1e735682640c4f8ddedb0c699da33aa7f399426 (diff) | |
download | uxnrpi-11a95bd16da3ba212ebbd64300c9136cee555bc1.tar.gz uxnrpi-11a95bd16da3ba212ebbd64300c9136cee555bc1.zip |
Cleanup UART code using structs for registers
Resources:
- https://www.youtube.com/watch?v=58f8Qfh-T6Q
-rw-r--r-- | src/common.h | 219 | ||||
-rw-r--r-- | src/main.c | 2 | ||||
-rw-r--r-- | src/start.s | 8 |
3 files changed, 141 insertions, 88 deletions
diff --git a/src/common.h b/src/common.h index c306c6c..a6af346 100644 --- a/src/common.h +++ b/src/common.h | |||
@@ -1,102 +1,147 @@ | |||
1 | #ifndef COMMON_RPIBM_H | ||
2 | #define COMMON_RPIBM_H | ||
3 | |||
1 | // Header definitions for memory mapped IO and common utilities. | 4 | // Header definitions for memory mapped IO and common utilities. |
2 | 5 | ||
3 | #include "shorthand.h" | 6 | #include "shorthand.h" |
4 | 7 | ||
8 | // | ||
9 | // Utils. | ||
10 | // | ||
11 | |||
12 | // Wait for N processor cycles before returning. Implemented in start.s. | ||
13 | void delay(u64 ticks); | ||
14 | |||
15 | // Clear N bytes at the given address. Implemented in start.s. | ||
16 | void memzero(u64 src, u32 n); | ||
17 | |||
5 | #define MEM_BASE 0x3F000000 | 18 | #define MEM_BASE 0x3F000000 |
6 | 19 | ||
7 | // GPIO registers. | 20 | // |
8 | #define GPIO_GPFSEL0 ((vu32*)(MEM_BASE + 0x00200000)) | 21 | // GPIO Registers. |
9 | #define GPIO_GPFSEL1 ((vu32*)(MEM_BASE + 0x00200004)) | 22 | // |
10 | #define GPIO_GPFSEL2 ((vu32*)(MEM_BASE + 0x00200008)) | 23 | |
11 | #define GPIO_GPFSEL3 ((vu32*)(MEM_BASE + 0x0020000C)) | 24 | typedef struct GpioPinData { |
12 | #define GPIO_GPFSEL4 ((vu32*)(MEM_BASE + 0x00200010)) | 25 | vu32 reserved; |
13 | #define GPIO_GPFSEL5 ((vu32*)(MEM_BASE + 0x00200014)) | 26 | vu32 data[2]; |
14 | #define GPIO_GPSET0 ((vu32*)(MEM_BASE + 0x0020001C)) | 27 | } GpioPinData; |
15 | #define GPIO_GPSET1 ((vu32*)(MEM_BASE + 0x00200020)) | 28 | |
16 | #define GPIO_GPCLR0 ((vu32*)(MEM_BASE + 0x00200028)) | 29 | typedef struct GpioRegs { |
17 | #define GPIO_GPLEV0 ((vu32*)(MEM_BASE + 0x00200034)) | 30 | vu32 func_select[6]; |
18 | #define GPIO_GPLEV1 ((vu32*)(MEM_BASE + 0x00200038)) | 31 | GpioPinData output_set; |
19 | #define GPIO_GPEDS0 ((vu32*)(MEM_BASE + 0x00200040)) | 32 | GpioPinData output_clear; |
20 | #define GPIO_GPEDS1 ((vu32*)(MEM_BASE + 0x00200044)) | 33 | GpioPinData level; |
21 | #define GPIO_GPHEN0 ((vu32*)(MEM_BASE + 0x00200064)) | 34 | GpioPinData ev_detect_status; |
22 | #define GPIO_GPHEN1 ((vu32*)(MEM_BASE + 0x00200068)) | 35 | GpioPinData re_detect_enable; |
23 | #define GPIO_GPPUD ((vu32*)(MEM_BASE + 0x00200094)) | 36 | GpioPinData fe_detect_enable; |
24 | #define GPIO_GPPUDCLK0 ((vu32*)(MEM_BASE + 0x00200098)) | 37 | GpioPinData hi_detect_enable; |
25 | #define GPIO_GPPUDCLK1 ((vu32*)(MEM_BASE + 0x0020009C)) | 38 | GpioPinData lo_detect_enable; |
26 | 39 | GpioPinData async_re_detect; | |
27 | // Auxiliary registers (Mini UART and SPI). | 40 | GpioPinData async_fe_detect; |
28 | #define AUX_ENABLE ((vu8*) (MEM_BASE + 0x00215004)) | 41 | vu32 reserved; |
29 | #define AUX_MU_IO ((vu8*) (MEM_BASE + 0x00215040)) | 42 | vu32 pupd_enable; |
30 | #define AUX_MU_IER ((vu8*) (MEM_BASE + 0x00215044)) | 43 | vu32 pupd_enable_clocks[2]; |
31 | #define AUX_MU_IIR ((vu8*) (MEM_BASE + 0x00215048)) | 44 | } GpioRegs; |
32 | #define AUX_MU_LCR ((vu8*) (MEM_BASE + 0x0021504C)) | 45 | |
33 | #define AUX_MU_MCR ((vu8*) (MEM_BASE + 0x00215050)) | 46 | typedef enum GpioFunc { |
34 | #define AUX_MU_LSR ((vu8*) (MEM_BASE + 0x00215054)) | 47 | GPIO_INPUT = 0, |
35 | #define AUX_MU_MSR ((vu8*) (MEM_BASE + 0x00215058)) | 48 | GPIO_OUTPUT = 1, |
36 | #define AUX_MU_SCRATCH ((vu8*) (MEM_BASE + 0x0021505C)) | 49 | GPIO_ALT0 = 4, |
37 | #define AUX_MU_CNTL ((vu8*) (MEM_BASE + 0x00215060)) | 50 | GPIO_ALT1 = 5, |
38 | #define AUX_MU_STAT ((vu32*)(MEM_BASE + 0x00215064)) | 51 | GPIO_ALT2 = 6, |
39 | #define AUX_MU_BAUD ((vu16*)(MEM_BASE + 0x00215068)) | 52 | GPIO_ALT3 = 7, |
40 | 53 | GPIO_ALT4 = 3, | |
41 | /** | 54 | GPIO_ALT5 = 2, |
42 | * Set baud rate and characteristics (115200 8N1) and map to GPIO | 55 | } GpioFunc; |
43 | */ | 56 | |
44 | void uart_init() | 57 | #define GPIO ((GpioRegs *)(MEM_BASE + 0x00200000)) |
45 | { | 58 | |
46 | register unsigned int r; | 59 | static inline void |
47 | 60 | gpio_pin_set_func(u8 pin, GpioFunc func) { | |
48 | /* initialize UART */ | 61 | u8 start = (pin * 3) % 30; |
49 | *AUX_ENABLE |=1; // enable UART1, AUX mini uart | 62 | u8 reg = pin / 10; |
50 | *AUX_MU_CNTL = 0; | 63 | |
51 | *AUX_MU_LCR = 3; // 8 bits | 64 | u32 selector = GPIO->func_select[reg]; |
52 | *AUX_MU_MCR = 0; | 65 | selector &= ~(7 << start); |
53 | *AUX_MU_IER = 0; | 66 | selector |= (func << start); |
54 | *AUX_MU_IIR = 0xc6; // disable interrupts | 67 | |
55 | *AUX_MU_BAUD = 270; // 115200 baud | 68 | GPIO->func_select[reg] = selector; |
56 | /* map UART1 to GPIO pins */ | ||
57 | r=*GPIO_GPFSEL1; | ||
58 | r&=~((7<<12)|(7<<15)); // gpio14, gpio15 | ||
59 | r|=(2<<12)|(2<<15); // alt5 | ||
60 | *GPIO_GPFSEL1 = r; | ||
61 | *GPIO_GPPUD = 0; // enable pins 14 and 15 | ||
62 | r=150; while(r--) { asm volatile("nop"); } | ||
63 | *GPIO_GPPUDCLK0 = (1<<14)|(1<<15); | ||
64 | r=150; while(r--) { asm volatile("nop"); } | ||
65 | *GPIO_GPPUDCLK0 = 0; // flush GPIO setup | ||
66 | *AUX_MU_CNTL = 3; // enable Tx, Rx | ||
67 | } | 69 | } |
68 | 70 | ||
69 | /** | 71 | static inline void |
70 | * Send a character | 72 | gpio_pin_enable(u8 pin) { |
71 | */ | 73 | GPIO->pupd_enable = 0; |
72 | void uart_send(unsigned int c) { | 74 | delay(150); |
73 | /* wait until we can send */ | 75 | GPIO->pupd_enable_clocks[pin / 32] = 1 << (pin % 32); |
74 | do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x20)); | 76 | delay(150); |
75 | /* write the character to the buffer */ | 77 | GPIO->pupd_enable = 0; |
76 | *AUX_MU_IO=c; | 78 | GPIO->pupd_enable_clocks[pin / 32] = 0; |
77 | } | 79 | } |
78 | 80 | ||
79 | /** | 81 | // |
80 | * Receive a character | 82 | // AUX Registers. |
81 | */ | 83 | // |
82 | char uart_getc() { | 84 | |
83 | char r; | 85 | typedef struct AuxRegs { |
84 | /* wait until something is in the buffer */ | 86 | vu32 irq_status; |
85 | do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x01)); | 87 | vu32 enables; |
86 | /* read it and return */ | 88 | vu32 reserved[14]; |
87 | r=(char)(*AUX_MU_IO); | 89 | vu32 mu_io; |
88 | /* convert carrige return to newline */ | 90 | vu32 mu_ier; |
89 | return r=='\r'?'\n':r; | 91 | vu32 mu_iir; |
92 | vu32 mu_lcr; | ||
93 | vu32 mu_mcr; | ||
94 | vu32 mu_lsr; | ||
95 | vu32 mu_msr; | ||
96 | vu32 mu_scratch; | ||
97 | vu32 mu_control; | ||
98 | vu32 mu_status; | ||
99 | vu32 mu_baud_rate; | ||
100 | } AuxRegs; | ||
101 | |||
102 | #define AUX ((AuxRegs *)(MEM_BASE + 0x00215000)) | ||
103 | |||
104 | static inline void | ||
105 | uart_init() { | ||
106 | gpio_pin_set_func(14, GPIO_ALT5); | ||
107 | gpio_pin_set_func(15, GPIO_ALT5); | ||
108 | gpio_pin_enable(14); | ||
109 | gpio_pin_enable(15); | ||
110 | |||
111 | AUX->enables = 1; | ||
112 | AUX->mu_control = 0; | ||
113 | AUX->mu_ier = 0; | ||
114 | AUX->mu_lcr = 3; | ||
115 | AUX->mu_mcr = 0; | ||
116 | |||
117 | AUX->mu_baud_rate = 270; // RPI3: 115200 @ 250 MHz | ||
118 | // AUX->mu_baud_rate = 541; // RPI4: 115200 @ 500 MHz | ||
119 | AUX->mu_control = 3; | ||
120 | return; | ||
90 | } | 121 | } |
91 | 122 | ||
92 | /** | 123 | static inline void |
93 | * Display a string | 124 | uart_putc(char c) { |
94 | */ | 125 | while(!(AUX->mu_lsr & (1 << 5))); |
95 | void uart_puts(char *s) { | 126 | AUX->mu_io = c; |
127 | return; | ||
128 | } | ||
129 | |||
130 | static inline char | ||
131 | uart_getc() { | ||
132 | while(!(AUX->mu_lsr & 1)); | ||
133 | u8 c = AUX->mu_io & 0xFF; | ||
134 | return c == '\r' ? '\n' : c; | ||
135 | } | ||
136 | |||
137 | static inline void | ||
138 | uart_puts(char *s) { | ||
96 | while(*s) { | 139 | while(*s) { |
97 | /* convert newline to carrige return + newline */ | 140 | if(*s == '\n') { |
98 | if(*s=='\n') | 141 | uart_putc('\r'); |
99 | uart_send('\r'); | 142 | } |
100 | uart_send(*s++); | 143 | uart_putc(*s++); |
101 | } | 144 | } |
102 | } | 145 | } |
146 | |||
147 | #endif // COMMON_RPIBM_H | ||
@@ -8,6 +8,6 @@ void main(void) { | |||
8 | 8 | ||
9 | // Echo input to standard output. | 9 | // Echo input to standard output. |
10 | while(1) { | 10 | while(1) { |
11 | uart_send(uart_getc()); | 11 | uart_putc(uart_getc()); |
12 | } | 12 | } |
13 | } | 13 | } |
diff --git a/src/start.s b/src/start.s index b142397..f6598ce 100644 --- a/src/start.s +++ b/src/start.s | |||
@@ -10,12 +10,20 @@ _start: | |||
10 | b halt | 10 | b halt |
11 | 11 | ||
12 | // Helper function to clear x1 bytes starting at the x0 memory address. | 12 | // Helper function to clear x1 bytes starting at the x0 memory address. |
13 | .globl memzero | ||
13 | memzero: | 14 | memzero: |
14 | str xzr, [x0], #8 | 15 | str xzr, [x0], #8 |
15 | subs x1, x1, #8 | 16 | subs x1, x1, #8 |
16 | b.gt memzero | 17 | b.gt memzero |
17 | ret | 18 | ret |
18 | 19 | ||
20 | // Helper function wait for N cycles before returning. | ||
21 | .globl delay | ||
22 | delay: | ||
23 | subs x0, x0, #1 | ||
24 | bne delay | ||
25 | ret | ||
26 | |||
19 | master: | 27 | master: |
20 | // Clear bss. | 28 | // Clear bss. |
21 | ldr x0, =__bss_start | 29 | ldr x0, =__bss_start |