2014-07-09 08:47:59 +00:00
|
|
|
/* uart.c - UART initialization & communication */
|
|
|
|
/* Reference material:
|
|
|
|
* http://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf
|
|
|
|
* Chapter 13: UART
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <mmio.h>
|
|
|
|
#include <uart.h>
|
|
|
|
|
|
|
|
enum {
|
|
|
|
// The GPIO registers base address.
|
|
|
|
GPIO_BASE = 0x20200000,
|
|
|
|
|
|
|
|
// The offsets for reach register.
|
|
|
|
|
|
|
|
// Controls actuation of pull up/down to ALL GPIO pins.
|
|
|
|
GPPUD = (GPIO_BASE + 0x94),
|
|
|
|
|
|
|
|
// Controls actuation of pull up/down for specific GPIO pin.
|
|
|
|
GPPUDCLK0 = (GPIO_BASE + 0x98),
|
|
|
|
|
|
|
|
// The base address for UART.
|
|
|
|
UART0_BASE = 0x20201000,
|
|
|
|
|
|
|
|
// The offsets for reach register for the UART.
|
|
|
|
UART0_DR = (UART0_BASE + 0x00),
|
|
|
|
UART0_RSRECR = (UART0_BASE + 0x04),
|
|
|
|
UART0_FR = (UART0_BASE + 0x18),
|
|
|
|
UART0_ILPR = (UART0_BASE + 0x20),
|
|
|
|
UART0_IBRD = (UART0_BASE + 0x24),
|
|
|
|
UART0_FBRD = (UART0_BASE + 0x28),
|
|
|
|
UART0_LCRH = (UART0_BASE + 0x2C),
|
|
|
|
UART0_CR = (UART0_BASE + 0x30),
|
|
|
|
UART0_IFLS = (UART0_BASE + 0x34),
|
|
|
|
UART0_IMSC = (UART0_BASE + 0x38),
|
|
|
|
UART0_RIS = (UART0_BASE + 0x3C),
|
|
|
|
UART0_MIS = (UART0_BASE + 0x40),
|
|
|
|
UART0_ICR = (UART0_BASE + 0x44),
|
|
|
|
UART0_DMACR = (UART0_BASE + 0x48),
|
|
|
|
UART0_ITCR = (UART0_BASE + 0x80),
|
|
|
|
UART0_ITIP = (UART0_BASE + 0x84),
|
|
|
|
UART0_ITOP = (UART0_BASE + 0x88),
|
|
|
|
UART0_TDR = (UART0_BASE + 0x8C),
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* delay function
|
2018-11-03 00:51:23 +00:00
|
|
|
* gI32 delay: number of cycles to delay
|
2014-07-09 08:47:59 +00:00
|
|
|
*
|
|
|
|
* This just loops <delay> times in a way that the compiler
|
|
|
|
* wont optimize away.
|
|
|
|
*/
|
2018-11-03 00:51:23 +00:00
|
|
|
static void delay(gI32 count) {
|
2014-07-09 08:47:59 +00:00
|
|
|
asm volatile("__delay_%=: subs %[count], %[count], #1; bne __delay_%=\n"
|
|
|
|
: : [count]"r"(count) : "cc");
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize UART0.
|
|
|
|
*/
|
|
|
|
void uart_init() {
|
|
|
|
// Disable UART0.
|
|
|
|
mmio_write(UART0_CR, 0x00000000);
|
|
|
|
// Setup the GPIO pin 14 && 15.
|
|
|
|
|
|
|
|
// Disable pull up/down for all GPIO pins & delay for 150 cycles.
|
|
|
|
mmio_write(GPPUD, 0x00000000);
|
|
|
|
delay(150);
|
|
|
|
|
|
|
|
// Disable pull up/down for pin 14,15 & delay for 150 cycles.
|
|
|
|
mmio_write(GPPUDCLK0, (1 << 14) | (1 << 15));
|
|
|
|
delay(150);
|
|
|
|
|
|
|
|
// Write 0 to GPPUDCLK0 to make it take effect.
|
|
|
|
mmio_write(GPPUDCLK0, 0x00000000);
|
|
|
|
|
|
|
|
// Clear pending interrupts.
|
|
|
|
mmio_write(UART0_ICR, 0x7FF);
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
// Fractional part register = (.627 * 64) + 0.5 = 40.6 = ~40.
|
|
|
|
mmio_write(UART0_IBRD, 1);
|
|
|
|
mmio_write(UART0_FBRD, 40);
|
|
|
|
|
|
|
|
// Enable FIFO & 8 bit data transmissio (1 stop bit, no parity).
|
|
|
|
mmio_write(UART0_LCRH, (1 << 4) | (1 << 5) | (1 << 6));
|
|
|
|
|
|
|
|
// Mask all interrupts.
|
|
|
|
mmio_write(UART0_IMSC, (1 << 1) | (1 << 4) | (1 << 5) |
|
|
|
|
(1 << 6) | (1 << 7) | (1 << 8) |
|
|
|
|
(1 << 9) | (1 << 10));
|
|
|
|
|
|
|
|
// Enable UART0, receive & transfer part of UART.
|
|
|
|
mmio_write(UART0_CR, (1 << 0) | (1 << 8) | (1 << 9));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Transmit a byte via UART0.
|
2018-11-03 00:51:23 +00:00
|
|
|
* gU8 Byte: byte to send.
|
2014-07-09 08:47:59 +00:00
|
|
|
*/
|
2018-11-03 00:51:23 +00:00
|
|
|
void uart_putc(gU8 byte) {
|
2014-07-09 08:47:59 +00:00
|
|
|
// wait for UART to become ready to transmit
|
|
|
|
while (1) {
|
|
|
|
if (!(mmio_read(UART0_FR) & (1 << 5))) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mmio_write(UART0_DR, byte);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* print a string to the UART one character at a time
|
|
|
|
* const char *str: 0-terminated string
|
|
|
|
*/
|
|
|
|
void uart_puts(const char *str) {
|
|
|
|
while (*str) {
|
|
|
|
uart_putc(*str++);
|
|
|
|
}
|
|
|
|
}
|