From 1af7591e37d09ddcd734ea07d0e999cf61c8bc5e Mon Sep 17 00:00:00 2001 From: vetch Date: Mon, 13 Jan 2020 12:40:38 +0100 Subject: Great Reorganisation, modify structure and makefile --- src/arm/PL1/PL1_common/uart.c | 103 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 src/arm/PL1/PL1_common/uart.c (limited to 'src/arm/PL1/PL1_common/uart.c') diff --git a/src/arm/PL1/PL1_common/uart.c b/src/arm/PL1/PL1_common/uart.c new file mode 100644 index 0000000..4dd1c2b --- /dev/null +++ b/src/arm/PL1/PL1_common/uart.c @@ -0,0 +1,103 @@ +#include +#include +#include "uart.h" +#include "global.h" + +// Loop times in a way that the compiler won't optimize away +static inline void delay(int32_t count) +{ + asm volatile("__delay_%=: subs %[count], %[count], #1; bne __delay_%=\n" + : "=r"(count): [count]"0"(count) : "cc"); +} + +void uart_init() +{ + // Disable PL011_UART. + wr32(PL011_UART_CR, 0); + + // Setup the GPIO pin 14 && 15. + + // Disable pull up/down for all GPIO pins & delay for 150 cycles. + wr32(GPPUD, 0); + delay(150); + + // Disable pull up/down for pin 14,15 & delay for 150 cycles. + wr32(GPPUDCLK0, (1 << 14) | (1 << 15)); + delay(150); + + // Write 0 to GPPUDCLK0 to make it take effect. + wr32(GPPUDCLK0, 0); + + // Set integer & fractional part of baud rate. + // Divider = UART_CLOCK/(16 * Baud) + // Fraction part register = (Fractional part * 64) + 0.5 + // UART_CLOCK = 3000000; Baud = 115200. + + // Divider = 3000000 / (16 * 115200) = 1.627 = ~1. + wr32(PL011_UART_IBRD, 1); + // Fractional part register = (.627 * 64) + 0.5 = 40.6 = ~40. + wr32(PL011_UART_FBRD, 40); + + // Set 8 bit data transmission (1 stop bit, no parity) + // and disable FIFO to be able to receive interrupt every received + // char, not every 2 chars + wr32(PL011_UART_LCRH, (1 << 5) | (1 << 6)); + + // set interrupt to come when transmit FIFO becomes ≤ 1/8 full + // or receive FIFO becomes ≥ 1/8 full + // (not really matters, since we disabled FIFOs) + wr32(PL011_UART_IFLS, 0); + + // Enable PL011_UART, receive & transfer part of UART.2 + wr32(PL011_UART_CR, (1 << 0) | (1 << 8) | (1 << 9)); + + // At first, it's probably safer to disable interrupts :) + uart_irq_disable(); + + // The above disables the entire uart irq; + // Also disable single sources within it + wr32(PL011_UART_IMSC, 0); +} + +inline static _Bool can_transmit(void) +{ + return !(rd32(PL011_UART_FR) & (1 << 5)); +} + +inline static _Bool can_receive(void) +{ + return !(rd32(PL011_UART_FR) & (1 << 4)); +} + +void putchar(char c) +{ + while (!can_transmit()); + + wr32(PL011_UART_DR, c); +} + +char getchar(void) +{ + while (!can_receive()); + + return rd32(PL011_UART_DR); +} + +_Bool putchar_non_blocking(char c) +{ + if (can_transmit()) + { + wr32(PL011_UART_DR, c); + return 0; + } + + return 1; +} + +int getchar_non_blocking(void) +{ + if (can_receive()) + return rd32(PL011_UART_DR); + + return -1; +} -- cgit v1.2.3