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
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
|
|
|