#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; }