116 lines
2.9 KiB
C
116 lines
2.9 KiB
C
|
#ifndef _UART_H_
|
||
|
#define _UART_H_
|
||
|
|
||
|
#include <stdbool.h>
|
||
|
#include <stddef.h>
|
||
|
#include <stdint.h>
|
||
|
|
||
|
#define UART_BASE 0x40004000
|
||
|
|
||
|
#ifndef __ASSEMBLER__
|
||
|
|
||
|
#include <stdint.h>
|
||
|
|
||
|
#define DECL_REG(addr, name) \
|
||
|
volatile uint32_t *const(name) = (volatile uint32_t *)(addr)
|
||
|
|
||
|
#define __time_critical __attribute__((section(".time_critical")))
|
||
|
|
||
|
typedef volatile uint32_t io_rw_32;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
// #include "addressmap.h"
|
||
|
#include "uart_regs.h"
|
||
|
|
||
|
DECL_REG(UART_BASE + UART_CSR_OFFS, UART_CSR);
|
||
|
DECL_REG(UART_BASE + UART_DIV_OFFS, UART_DIV);
|
||
|
DECL_REG(UART_BASE + UART_FSTAT_OFFS, UART_FSTAT);
|
||
|
DECL_REG(UART_BASE + UART_TX_OFFS, UART_TX);
|
||
|
DECL_REG(UART_BASE + UART_RX_OFFS, UART_RX);
|
||
|
|
||
|
static inline void uart_enable(bool en) {
|
||
|
*UART_CSR = *UART_CSR & ~UART_CSR_EN_MASK | (!!en << UART_CSR_EN_LSB);
|
||
|
}
|
||
|
|
||
|
// 10.4 fixed point format.
|
||
|
// Encodes number of clock cycles per clock enable.
|
||
|
// Each baud period is 16 clock enables (default modparam)
|
||
|
static inline void uart_clkdiv(uint32_t div) { *UART_DIV = div; }
|
||
|
|
||
|
// Use constant arguments:
|
||
|
#define uart_clkdiv_baud(clk_mhz, baud) \
|
||
|
uart_clkdiv((uint32_t)((clk_mhz) * 1e6 * (16.0 / 8.0) / (float)(baud)))
|
||
|
|
||
|
static inline bool uart_tx_full() {
|
||
|
return !!(*UART_FSTAT & UART_FSTAT_TXFULL_MASK);
|
||
|
}
|
||
|
|
||
|
static inline bool uart_tx_empty() {
|
||
|
return !!(*UART_FSTAT & UART_FSTAT_TXEMPTY_MASK);
|
||
|
}
|
||
|
|
||
|
static inline size_t uart_tx_level() {
|
||
|
return (*UART_FSTAT & UART_FSTAT_TXLEVEL_MASK) >> UART_FSTAT_TXLEVEL_LSB;
|
||
|
}
|
||
|
|
||
|
static inline bool uart_rx_full() {
|
||
|
return !!(*UART_FSTAT & UART_FSTAT_RXFULL_MASK);
|
||
|
}
|
||
|
|
||
|
static inline bool uart_rx_empty() {
|
||
|
return !!(*UART_FSTAT & UART_FSTAT_RXEMPTY_MASK);
|
||
|
}
|
||
|
|
||
|
static inline size_t uart_rx_level() {
|
||
|
return (*UART_FSTAT & UART_FSTAT_RXLEVEL_MASK) >> UART_FSTAT_RXLEVEL_LSB;
|
||
|
}
|
||
|
|
||
|
static inline void uart_put(uint8_t x) {
|
||
|
while (uart_tx_full());
|
||
|
*(volatile uint8_t *const)UART_TX = x;
|
||
|
}
|
||
|
|
||
|
static inline uint8_t uart_get() {
|
||
|
while (uart_rx_empty());
|
||
|
return *(volatile uint8_t *const)UART_RX;
|
||
|
}
|
||
|
|
||
|
static inline void uart_puts(const char *s) {
|
||
|
while (*s) {
|
||
|
if (*s == '\n') uart_put('\r');
|
||
|
uart_put((uint8_t)(*s++));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Have you seen how big printf is?
|
||
|
static const char hextable[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
|
||
|
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||
|
|
||
|
static inline void uart_putint(uint32_t x) {
|
||
|
for (int i = 0; i < 8; ++i) {
|
||
|
uart_put((uint8_t)(hextable[x >> 28]));
|
||
|
x <<= 4;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static inline void uart_putbyte(uint8_t x) {
|
||
|
uart_put((uint8_t)(hextable[x >> 4]));
|
||
|
uart_put((uint8_t)(hextable[x & 0xf]));
|
||
|
}
|
||
|
|
||
|
static inline void uart_wait_done() { while (*UART_CSR & UART_CSR_BUSY_MASK); }
|
||
|
|
||
|
static inline void uart_init() {
|
||
|
*UART_CSR = 0;
|
||
|
while (*UART_CSR & UART_CSR_BUSY_MASK);
|
||
|
while (!uart_rx_empty()) (void)uart_get();
|
||
|
uart_enable(true);
|
||
|
}
|
||
|
|
||
|
static inline void uart_enable_cts(bool en) {
|
||
|
*UART_CSR = *UART_CSR & ~UART_CSR_CTSEN_MASK | (!!en << UART_CSR_CTSEN_LSB);
|
||
|
}
|
||
|
|
||
|
#endif // _UART_H_
|