RISC-V operating system
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

170 lines
6.4 KiB

#ifndef _PLATFORM_UART_H
#define _PLATFORM_UART_H
#include <stdint.h>
#include <macro.h>
// <Description> <[Doc Page]>
// UART Base Addesses [141]
#define UART_0_ADDR 0x10010000L
#define UART_1_ADDR 0x10010000L
// UART Control Register Offsets [142]
#define UART_TXDATA_OFF 0x00 // Transmit data register
#define UART_RXDATA_OFF 0x04 // Receive data register
#define UART_TXCTRL_OFF 0x08 // Transmit control register
#define UART_RXCTRL_OFF 0x0C // Receive control register
#define UART_IE_OFF 0x10 // UART interrupt enable
#define UART_IP_OFF 0x14 // UART interrupt pending
#define UART_DIV_OFF 0x18 // Baud rate divisor
#define UART_NUMBER 2
#define DEFAULT_BAUD 115200
// UART ids
typedef enum {
UART0 = 0,
UART1 = 1,
} uart_id;
/* Transmit Data Register (txdata) [142]
* Writing to the txdata register enqueues the character contained in the data
* field to the transmit FIFO if the FIFO is able to accept new entries. Reading
* from txdata returns the current value of the full flag and zero in the data
* field. The full flag indicates whether the transmit FIFO is able to accept
* new entries; when set, writes to data are ignored. A RISC‐V amoor.w
* instruction can be used to both read the full status and attempt to enqueue
* data, with a non-zero return value indicating the character was not accepted.
*/
struct S_PACKED uart_txdata_reg {
uint32_t data:8;
uint32_t reserved:23;
uint32_t full:1;
};
static_assert((sizeof(struct uart_txdata_reg) == sizeof(uint32_t)),
"uart_txdata_reg is not the right size");
/* Receive Data Register (rxdata) [143]
* Reading the rxdata register dequeues a character from the receive FIFO and
* returns the value in the data field. The empty flag indicates if the receive
* FIFO was empty; when set, the data field does not contain a valid character.
* Writes to rxdata are ignored.
*/
struct S_PACKED uart_rxdata_reg {
uint32_t data:8;
uint32_t reserved:23;
uint32_t empty:1;
};
static_assert((sizeof(struct uart_rxdata_reg) == sizeof(uint32_t)),
"uart_rxdata_reg is not the right size");
/* Transmit Control Register (txctrl) [143]
* The read-write txctrl register controls the operation of the transmit channel.
* The txen bit con- trols whether the Tx channel is active. When cleared,
* transmission of Tx FIFO contents is suppressed, and the txd pin is driven
* high. The nstop field specifies the number of stop bits: 0 for one stop bit
* and 1 for two stop bits. The txcnt field specifies the threshold at which the
* Tx FIFO watermark interrupt triggers. The txctrl register is reset to 0.
*/
struct S_PACKED uart_txctrl_reg {
uint32_t txen:1;
uint32_t nstop:1;
uint32_t reserved0:14;
uint32_t txcnt:3;
uint32_t reserved1:13;
};
static_assert((sizeof(struct uart_txctrl_reg) == sizeof(uint32_t)),
"uart_txctrl_reg is not the right size");
/* Receive Control Register (rxctrl) [144]
* The read-write rxctrl register controls the operation of the receive channel.
* The rxen bit controls whether the Rx channel is active. When cleared, the
* state of the rxd pin is ignored, and no characters will be enqueued into the
* Rx FIFO. The rxcnt field specifies the threshold at which the Rx FIFO
* watermark interrupt triggers. The rxctrl register is reset to 0. Characters
* are enqueued when a zero (low) start bit is seen.
*/
struct S_PACKED uart_rxctrl_reg {
uint32_t rxen:1;
uint32_t reserved0:15;
uint32_t rxcnt:3;
uint32_t reserved1:13;
};
static_assert((sizeof(struct uart_rxctrl_reg) == sizeof(uint32_t)),
"uart_rxctrl_reg is not the right size");
/* Interrupt Registers (ip and ie) [144]
* The ip register is a read-only register indicating the pending interrupt
* conditions, and the read- write ie register controls which UART interrupts
* are enabled. ie is reset to 0. The txwm condition becomes raised when the
* number of entries in the transmit FIFO is strictly less than the count
* specified by the txcnt field of the txctrl register. The pending bit is
* cleared when sufficient entries have been enqueued to exceed the watermark.
* The rxwm condition becomes raised when the number of entries in the receive
* FIFO is strictly greater than the count specified by the rxcnt field of the
* rxctrl register. The pending bit is cleared when sufficient entries have been
* dequeued to fall below the watermark.
*/
struct S_PACKED uart_ie_reg {
uint32_t txwm:1;
uint32_t rxwm:1;
uint32_t reserved:30;
};
static_assert((sizeof(struct uart_ie_reg) == sizeof(uint32_t)),
"uart_ie_reg is not the right size");
struct S_PACKED uart_ip_reg {
uint32_t txwm:1;
uint32_t rxwm:1;
uint32_t reserved:30;
};
static_assert((sizeof(struct uart_ip_reg) == sizeof(uint32_t)),
"uart_ip_reg is not the right size");
/* Baud Rate Divisor Register (div) [145]
* The read-write, div_width-bit div register specifies the divisor used by baud
* rate generation for both Tx and Rx channels. The relationship between the
* input clock and baud rate is given by the following formula: The input clock
* is the bus clock pclk. The reset value of the register is set to div_init,
* which is tuned to provide a 115200 baud output out of reset given the
* expected frequency of pclk. Table 85 shows divisors for some common core
* clock rates and commonly used baud rates. Note that the table shows the
* divide ratios, which are one greater than the value stored in the div
* register. The receive channel is sampled at 16× the baud rate, and a majority
* vote over 3 neighboring bits is used to determine the received value. For
* this reason, the divisor must be ≥16 for a receive channel.
*/
struct S_PACKED uart_div_reg {
uint32_t div:16;
uint32_t reserved:16;
};
static_assert((sizeof(struct uart_div_reg) == sizeof(uint32_t)),
"uart_div_reg is not the right size");
struct S_PACKED uart_memory_map {
struct uart_txdata_reg txdata;
struct uart_rxdata_reg rxdata;
struct uart_txctrl_reg txctrl;
struct uart_rxctrl_reg rxctrl;
struct uart_ie_reg ie;
struct uart_ip_reg ip;
struct uart_div_reg div;
};
static_assert((sizeof(struct uart_memory_map) == sizeof(uint32_t[7])),
"uart_memory_map is not the right size");
int uart_set_baudrate(uart_id id, int baud);
int uart_init(uart_id id, uint32_t baud, int stop_bits);
void uart_tx_byte(uart_id id, unsigned char b);
void uart_tx_full(uart_id id);
void uart_tx_buf(uart_id id, unsigned char *buf, unsigned int size);
#endif