aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2021-09-07 12:52:57 +0200
committerBad Diode <bd@badd10de.dev>2021-09-07 12:52:57 +0200
commit11a95bd16da3ba212ebbd64300c9136cee555bc1 (patch)
tree4c61e05a28efaef64fa42e1fc8226144e3f4356c
parentd1e735682640c4f8ddedb0c699da33aa7f399426 (diff)
downloaduxnrpi-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.h219
-rw-r--r--src/main.c2
-rw-r--r--src/start.s8
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.
13void delay(u64 ticks);
14
15// Clear N bytes at the given address. Implemented in start.s.
16void 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)) 24typedef 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)) 29typedef 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)) 46typedef 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
44void uart_init() 57#define GPIO ((GpioRegs *)(MEM_BASE + 0x00200000))
45{ 58
46 register unsigned int r; 59static inline void
47 60gpio_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/** 71static inline void
70 * Send a character 72gpio_pin_enable(u8 pin) {
71 */ 73 GPIO->pupd_enable = 0;
72void 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//
82char uart_getc() { 84
83 char r; 85typedef 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
104static inline void
105uart_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/** 123static inline void
93 * Display a string 124uart_putc(char c) {
94 */ 125 while(!(AUX->mu_lsr & (1 << 5)));
95void uart_puts(char *s) { 126 AUX->mu_io = c;
127 return;
128}
129
130static inline char
131uart_getc() {
132 while(!(AUX->mu_lsr & 1));
133 u8 c = AUX->mu_io & 0xFF;
134 return c == '\r' ? '\n' : c;
135}
136
137static inline void
138uart_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
diff --git a/src/main.c b/src/main.c
index da354c1..aac605b 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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
13memzero: 14memzero:
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
22delay:
23 subs x0, x0, #1
24 bne delay
25 ret
26
19master: 27master:
20 // Clear bss. 28 // Clear bss.
21 ldr x0, =__bss_start 29 ldr x0, =__bss_start