From d1e735682640c4f8ddedb0c699da33aa7f399426 Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Tue, 7 Sep 2021 11:54:53 +0200 Subject: Add initial support for UART I/O Resources: - https://github.com/bztsrc/raspi3-tutorial/tree/master/03_uart1 - https://www.youtube.com/watch?v=r3Ye08ktcMo --- .gitignore | 1 + Makefile | 16 +++++---- src/common.h | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.c | 12 ++++++- src/shorthand.h | 46 +++++++++++++++++++++++++ src/start.s | 29 ++++++++++++++-- 6 files changed, 196 insertions(+), 10 deletions(-) create mode 100644 .gitignore create mode 100644 src/common.h create mode 100644 src/shorthand.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..378eac2 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build diff --git a/Makefile b/Makefile index 475c160..f531a02 100644 --- a/Makefile +++ b/Makefile @@ -3,17 +3,18 @@ .PHONY: clean run # Compiler. -AS := arm-none-eabi-as -CC := arm-none-eabi-gcc -OBJCOPY := arm-none-eabi-objcopy +AS := aarch64-elf-as +CC := aarch64-elf-gcc +LD := aarch64-elf-ld +OBJCOPY := aarch64-elf-objcopy # Paths. SRC_DIR := src BUILD_DIR := build # Output files. -ELF := $(BUILD_DIR)/kernel7.elf -IMG := $(BUILD_DIR)/kernel7.img +ELF := $(BUILD_DIR)/kernel8.elf +IMG := $(BUILD_DIR)/kernel8.img # Bootstrapping files. OBJ_START = $(BUILD_DIR)/start.o @@ -22,6 +23,7 @@ SRC_LINK = $(SRC_DIR)/linker.ld CFLAGS := -Wall -ffreestanding -O2 -nostdlib -lgcc -mgeneral-regs-only AFLAGS := +LDFLAGS := default: $(IMG) @@ -35,7 +37,7 @@ $(IMG): $(BUILD_DIR) $(ELF) $(OBJCOPY) $(ELF) -O binary $(IMG) $(ELF): $(OBJ_START) $(OBJ_MAIN) - $(CC) $(CFLAGS) -T $(SRC_LINK) -o $(ELF) $(OBJ_START) $(OBJ_MAIN) + $(LD) $(LDFLAGS) -T $(SRC_LINK) -o $(ELF) $(OBJ_START) $(OBJ_MAIN) clean: rm -rf $(BUILD_DIR) @@ -44,4 +46,4 @@ $(BUILD_DIR): mkdir -p $(BUILD_DIR) run: $(IMG) - qemu-system-aarch64 -M raspi3 -kernel $(IMG) -d in_asm -serial null -serial stdio + qemu-system-aarch64 -M raspi3 -kernel $(IMG) -serial null -serial stdio diff --git a/src/common.h b/src/common.h new file mode 100644 index 0000000..c306c6c --- /dev/null +++ b/src/common.h @@ -0,0 +1,102 @@ +// Header definitions for memory mapped IO and common utilities. + +#include "shorthand.h" + +#define MEM_BASE 0x3F000000 + +// GPIO registers. +#define GPIO_GPFSEL0 ((vu32*)(MEM_BASE + 0x00200000)) +#define GPIO_GPFSEL1 ((vu32*)(MEM_BASE + 0x00200004)) +#define GPIO_GPFSEL2 ((vu32*)(MEM_BASE + 0x00200008)) +#define GPIO_GPFSEL3 ((vu32*)(MEM_BASE + 0x0020000C)) +#define GPIO_GPFSEL4 ((vu32*)(MEM_BASE + 0x00200010)) +#define GPIO_GPFSEL5 ((vu32*)(MEM_BASE + 0x00200014)) +#define GPIO_GPSET0 ((vu32*)(MEM_BASE + 0x0020001C)) +#define GPIO_GPSET1 ((vu32*)(MEM_BASE + 0x00200020)) +#define GPIO_GPCLR0 ((vu32*)(MEM_BASE + 0x00200028)) +#define GPIO_GPLEV0 ((vu32*)(MEM_BASE + 0x00200034)) +#define GPIO_GPLEV1 ((vu32*)(MEM_BASE + 0x00200038)) +#define GPIO_GPEDS0 ((vu32*)(MEM_BASE + 0x00200040)) +#define GPIO_GPEDS1 ((vu32*)(MEM_BASE + 0x00200044)) +#define GPIO_GPHEN0 ((vu32*)(MEM_BASE + 0x00200064)) +#define GPIO_GPHEN1 ((vu32*)(MEM_BASE + 0x00200068)) +#define GPIO_GPPUD ((vu32*)(MEM_BASE + 0x00200094)) +#define GPIO_GPPUDCLK0 ((vu32*)(MEM_BASE + 0x00200098)) +#define GPIO_GPPUDCLK1 ((vu32*)(MEM_BASE + 0x0020009C)) + +// Auxiliary registers (Mini UART and SPI). +#define AUX_ENABLE ((vu8*) (MEM_BASE + 0x00215004)) +#define AUX_MU_IO ((vu8*) (MEM_BASE + 0x00215040)) +#define AUX_MU_IER ((vu8*) (MEM_BASE + 0x00215044)) +#define AUX_MU_IIR ((vu8*) (MEM_BASE + 0x00215048)) +#define AUX_MU_LCR ((vu8*) (MEM_BASE + 0x0021504C)) +#define AUX_MU_MCR ((vu8*) (MEM_BASE + 0x00215050)) +#define AUX_MU_LSR ((vu8*) (MEM_BASE + 0x00215054)) +#define AUX_MU_MSR ((vu8*) (MEM_BASE + 0x00215058)) +#define AUX_MU_SCRATCH ((vu8*) (MEM_BASE + 0x0021505C)) +#define AUX_MU_CNTL ((vu8*) (MEM_BASE + 0x00215060)) +#define AUX_MU_STAT ((vu32*)(MEM_BASE + 0x00215064)) +#define AUX_MU_BAUD ((vu16*)(MEM_BASE + 0x00215068)) + +/** + * Set baud rate and characteristics (115200 8N1) and map to GPIO + */ +void uart_init() +{ + register unsigned int r; + + /* initialize UART */ + *AUX_ENABLE |=1; // enable UART1, AUX mini uart + *AUX_MU_CNTL = 0; + *AUX_MU_LCR = 3; // 8 bits + *AUX_MU_MCR = 0; + *AUX_MU_IER = 0; + *AUX_MU_IIR = 0xc6; // disable interrupts + *AUX_MU_BAUD = 270; // 115200 baud + /* map UART1 to GPIO pins */ + r=*GPIO_GPFSEL1; + r&=~((7<<12)|(7<<15)); // gpio14, gpio15 + r|=(2<<12)|(2<<15); // alt5 + *GPIO_GPFSEL1 = r; + *GPIO_GPPUD = 0; // enable pins 14 and 15 + r=150; while(r--) { asm volatile("nop"); } + *GPIO_GPPUDCLK0 = (1<<14)|(1<<15); + r=150; while(r--) { asm volatile("nop"); } + *GPIO_GPPUDCLK0 = 0; // flush GPIO setup + *AUX_MU_CNTL = 3; // enable Tx, Rx +} + +/** + * Send a character + */ +void uart_send(unsigned int c) { + /* wait until we can send */ + do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x20)); + /* write the character to the buffer */ + *AUX_MU_IO=c; +} + +/** + * Receive a character + */ +char uart_getc() { + char r; + /* wait until something is in the buffer */ + do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x01)); + /* read it and return */ + r=(char)(*AUX_MU_IO); + /* convert carrige return to newline */ + return r=='\r'?'\n':r; +} + +/** + * Display a string + */ +void uart_puts(char *s) { + while(*s) { + /* convert newline to carrige return + newline */ + if(*s=='\n') + uart_send('\r'); + uart_send(*s++); + } +} diff --git a/src/main.c b/src/main.c index 1ce2dd1..da354c1 100644 --- a/src/main.c +++ b/src/main.c @@ -1,3 +1,13 @@ +#include "common.h" + void main(void) { - while(1); + // Initialize uart. + uart_init(); + + uart_puts("Hello World!\n"); + + // Echo input to standard output. + while(1) { + uart_send(uart_getc()); + } } diff --git a/src/shorthand.h b/src/shorthand.h new file mode 100644 index 0000000..0897824 --- /dev/null +++ b/src/shorthand.h @@ -0,0 +1,46 @@ +/* +Copyright (c) 2021 Bad Diode + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE. +*/ + +#ifndef UTILS_SHORTHAND_H +#define UTILS_SHORTHAND_H + +#include +#include +#include + +// +// This simple header just typedefs the basic C define types to a shorter name, +// loads the quality of life bool macro for _Bool and defines shorthand macros +// for byte sizes. + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; +typedef volatile u8 vu8; +typedef volatile u16 vu16; +typedef volatile u32 vu32; +typedef volatile u64 vu64; +typedef volatile s8 vs8; +typedef volatile s16 vs16; +typedef volatile s32 vs32; +typedef volatile s64 vs64; + +#define KB(N) ((u64)(N) * 1024) +#define MB(N) ((u64)KB(N) * 1024) +#define GB(N) ((u64)MB(N) * 1024) +#define TB(N) ((u64)GB(N) * 1024) + +#endif // UTILS_SHORTHAND_H diff --git a/src/start.s b/src/start.s index 0fd2a5f..b142397 100644 --- a/src/start.s +++ b/src/start.s @@ -3,8 +3,33 @@ .global _start _start: - ldr r3, =main - blx r3 + // Stop all cores except one. + mrs x0, mpidr_el1 + and x0, x0, #0xFF + cbz x0, master + b halt + +// Helper function to clear x1 bytes starting at the x0 memory address. +memzero: + str xzr, [x0], #8 + subs x1, x1, #8 + b.gt memzero + ret + +master: + // Clear bss. + ldr x0, =__bss_start + ldr x1, =__bss_size + sub x1, x1, x0 + bl memzero + + // Set stack before our code. + ldr x0, =_start + mov sp, x0 + + // Start C code, should not return. + bl main + b halt halt: wfe -- cgit v1.2.1