#ifndef _PLATFORM_UART_H #define _PLATFORM_UART_H #include #include // <[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