⚠️ [sw/lib] update UART HAL

This commit is contained in:
stnolting 2023-03-05 18:59:36 +01:00
parent 08391368aa
commit 344aeff3b6
4 changed files with 149 additions and 276 deletions

View file

@ -52,38 +52,36 @@
* @name UART0: Backward compatibility Wrapper, #neorv32_uart_h
**************************************************************************/
/**@{*/
#define neorv32_uart0_available() neorv32_uart_available(NEORV32_UART0)
#define neorv32_uart0_setup(baudrate, parity, flow_con) neorv32_uart_setup(NEORV32_UART0, baudrate, parity, flow_con)
#define neorv32_uart0_disable() neorv32_uart_disable(NEORV32_UART0)
#define neorv32_uart0_enable() neorv32_uart_enable(NEORV32_UART0)
#define neorv32_uart0_putc(c) neorv32_uart_putc(NEORV32_UART0, c)
#define neorv32_uart0_tx_busy() neorv32_uart_tx_busy(NEORV32_UART0)
#define neorv32_uart0_getc() neorv32_uart_getc(NEORV32_UART0)
#define neorv32_uart0_char_received() neorv32_uart_char_received(NEORV32_UART0)
#define neorv32_uart0_getc_safe(data) neorv32_uart_getc_safe(NEORV32_UART0, *data)
#define neorv32_uart0_char_received_get() neorv32_uart_char_received_get(NEORV32_UART0)
#define neorv32_uart0_puts(s) neorv32_uart_puts(NEORV32_UART0, s)
#define neorv32_uart0_printf(...) neorv32_uart_printf(NEORV32_UART0, __VA_ARGS__)
#define neorv32_uart0_scan(buffer, max_size, echo) neorv32_uart_scan(NEORV32_UART0, buffer, max_size, echo)
#define neorv32_uart0_available() neorv32_uart_available(NEORV32_UART0)
#define neorv32_uart0_setup(baudrate, irq_mask) neorv32_uart_setup(NEORV32_UART0, baudrate, irq_mask)
#define neorv32_uart0_disable() neorv32_uart_disable(NEORV32_UART0)
#define neorv32_uart0_enable() neorv32_uart_enable(NEORV32_UART0)
#define neorv32_uart0_putc(c) neorv32_uart_putc(NEORV32_UART0, c)
#define neorv32_uart0_tx_busy() neorv32_uart_tx_busy(NEORV32_UART0)
#define neorv32_uart0_getc() neorv32_uart_getc(NEORV32_UART0)
#define neorv32_uart0_char_received() neorv32_uart_char_received(NEORV32_UART0)
#define neorv32_uart0_char_received_get() neorv32_uart_char_received_get(NEORV32_UART0)
#define neorv32_uart0_puts(s) neorv32_uart_puts(NEORV32_UART0, s)
#define neorv32_uart0_printf(...) neorv32_uart_printf(NEORV32_UART0, __VA_ARGS__)
#define neorv32_uart0_scan(buffer, max_size, echo) neorv32_uart_scan(NEORV32_UART0, buffer, max_size, echo)
/**@}*/
/**********************************************************************//**
* @name UART1: Backward compatibility Wrapper, #neorv32_uart_h
**************************************************************************/
/**@{*/
#define neorv32_uart1_available() neorv32_uart_available(NEORV32_UART1)
#define neorv32_uart1_setup(baudrate, parity, flow_con) neorv32_uart_setup(NEORV32_UART1, baudrate, parity, flow_con)
#define neorv32_uart1_disable() neorv32_uart_disable(NEORV32_UART1)
#define neorv32_uart1_enable() neorv32_uart_enable(NEORV32_UART1)
#define neorv32_uart1_putc(c) neorv32_uart_putc(NEORV32_UART1, c)
#define neorv32_uart1_tx_busy() neorv32_uart_tx_busy(NEORV32_UART1)
#define neorv32_uart1_getc() neorv32_uart_getc(NEORV32_UART1)
#define neorv32_uart1_char_received() neorv32_uart_char_received(NEORV32_UART1)
#define neorv32_uart1_getc_safe(data) neorv32_uart_getc_safe(NEORV32_UART1, *data)
#define neorv32_uart1_char_received_get() neorv32_uart_char_received_get(NEORV32_UART1)
#define neorv32_uart1_puts(s) neorv32_uart_puts(NEORV32_UART1, s)
#define neorv32_uart1_printf(...) neorv32_uart_printf(NEORV32_UART1, __VA_ARGS__)
#define neorv32_uart1_scan(buffer, max_size, echo) neorv32_uart_scan(NEORV32_UART1, buffer, max_size, echo)
#define neorv32_uart1_available() neorv32_uart_available(NEORV32_UART1)
#define neorv32_uart1_setup(baudrate, irq_mask) neorv32_uart_setup(NEORV32_UART1, baudrate, irq_mask)
#define neorv32_uart1_disable() neorv32_uart_disable(NEORV32_UART1)
#define neorv32_uart1_enable() neorv32_uart_enable(NEORV32_UART1)
#define neorv32_uart1_putc(c) neorv32_uart_putc(NEORV32_UART1, c)
#define neorv32_uart1_tx_busy() neorv32_uart_tx_busy(NEORV32_UART1)
#define neorv32_uart1_getc() neorv32_uart_getc(NEORV32_UART1)
#define neorv32_uart1_char_received() neorv32_uart_char_received(NEORV32_UART1)
#define neorv32_uart1_char_received_get() neorv32_uart_char_received_get(NEORV32_UART1)
#define neorv32_uart1_puts(s) neorv32_uart_puts(NEORV32_UART1, s)
#define neorv32_uart1_printf(...) neorv32_uart_printf(NEORV32_UART1, __VA_ARGS__)
#define neorv32_uart1_scan(buffer, max_size, echo) neorv32_uart_scan(NEORV32_UART1, buffer, max_size, echo)
/**@}*/
/**********************************************************************//**

View file

@ -970,7 +970,7 @@ typedef volatile struct __attribute__((packed,aligned(4))) {
/** UART module prototype */
typedef volatile struct __attribute__((packed,aligned(4))) {
uint32_t CTRL; /**< offset 0: control register (#NEORV32_UART_CTRL_enum) */
uint32_t DATA; /**< offset 4: data register (#NEORV32_UART_DATA_enum) */
uint32_t DATA; /**< offset 4: data register */
} neorv32_uart_t;
/** UART0 module base address */
@ -985,66 +985,39 @@ typedef volatile struct __attribute__((packed,aligned(4))) {
/** UART1 module hardware access (#neorv32_uart_t) */
#define NEORV32_UART1 ((neorv32_uart_t*) (NEORV32_UART1_BASE))
/** UART0/UART1 control register bits */
/** UART control register bits */
enum NEORV32_UART_CTRL_enum {
UART_CTRL_BAUD00 = 0, /**< UART control register(0) (r/w): BAUD rate config value lsb (12-bit, bit 0) */
UART_CTRL_BAUD01 = 1, /**< UART control register(1) (r/w): BAUD rate config value (12-bit, bit 1) */
UART_CTRL_BAUD02 = 2, /**< UART control register(2) (r/w): BAUD rate config value (12-bit, bit 2) */
UART_CTRL_BAUD03 = 3, /**< UART control register(3) (r/w): BAUD rate config value (12-bit, bit 3) */
UART_CTRL_BAUD04 = 4, /**< UART control register(4) (r/w): BAUD rate config value (12-bit, bit 4) */
UART_CTRL_BAUD05 = 5, /**< UART control register(5) (r/w): BAUD rate config value (12-bit, bit 4) */
UART_CTRL_BAUD06 = 6, /**< UART control register(6) (r/w): BAUD rate config value (12-bit, bit 5) */
UART_CTRL_BAUD07 = 7, /**< UART control register(7) (r/w): BAUD rate config value (12-bit, bit 6) */
UART_CTRL_BAUD08 = 8, /**< UART control register(8) (r/w): BAUD rate config value (12-bit, bit 7) */
UART_CTRL_BAUD09 = 9, /**< UART control register(9) (r/w): BAUD rate config value (12-bit, bit 8) */
UART_CTRL_BAUD10 = 10, /**< UART control register(10) (r/w): BAUD rate config value (12-bit, bit 9) */
UART_CTRL_BAUD11 = 11, /**< UART control register(11) (r/w): BAUD rate config value msb (12-bit, bit 0) */
UART_CTRL_SIM_MODE = 12, /**< UART control register(12) (r/w): Simulation output override enable, for use in simulation only */
UART_CTRL_RX_EMPTY = 13, /**< UART control register(13) (r/-): RX FIFO is empty */
UART_CTRL_RX_HALF = 14, /**< UART control register(14) (r/-): RX FIFO is at least half-full */
UART_CTRL_RX_FULL = 15, /**< UART control register(15) (r/-): RX FIFO is full */
UART_CTRL_TX_EMPTY = 16, /**< UART control register(16) (r/-): TX FIFO is empty */
UART_CTRL_TX_HALF = 17, /**< UART control register(17) (r/-): TX FIFO is at least half-full */
UART_CTRL_TX_FULL = 18, /**< UART control register(18) (r/-): TX FIFO is full */
UART_CTRL_EN = 0, /**< UART control register(0) (r/w): UART global enable */
UART_CTRL_SIM_MODE = 1, /**< UART control register(1) (r/w): Simulation output override enable */
UART_CTRL_PRSC0 = 2, /**< UART control register(2) (r/w): clock prescaler select bit 0 */
UART_CTRL_PRSC1 = 3, /**< UART control register(3) (r/w): clock prescaler select bit 1 */
UART_CTRL_PRSC2 = 4, /**< UART control register(4) (r/w): clock prescaler select bit 2 */
UART_CTRL_BAUD0 = 5, /**< UART control register(5) (r/w): BAUD rate divisor, bit 0 */
UART_CTRL_BAUD1 = 6, /**< UART control register(6) (r/w): BAUD rate divisor, bit 1 */
UART_CTRL_BAUD2 = 7, /**< UART control register(7) (r/w): BAUD rate divisor, bit 2 */
UART_CTRL_BAUD3 = 8, /**< UART control register(8) (r/w): BAUD rate divisor, bit 3 */
UART_CTRL_BAUD4 = 9, /**< UART control register(9) (r/w): BAUD rate divisor, bit 4 */
UART_CTRL_BAUD5 = 10, /**< UART control register(10) (r/w): BAUD rate divisor, bit 5 */
UART_CTRL_BAUD6 = 11, /**< UART control register(11) (r/w): BAUD rate divisor, bit 6 */
UART_CTRL_BAUD7 = 12, /**< UART control register(12) (r/w): BAUD rate divisor, bit 7 */
UART_CTRL_BAUD8 = 13, /**< UART control register(13) (r/w): BAUD rate divisor, bit 8 */
UART_CTRL_BAUD9 = 14, /**< UART control register(14) (r/w): BAUD rate divisor, bit 9 */
UART_CTRL_RTS_EN = 20, /**< UART control register(20) (r/w): Enable hardware flow control: Assert RTS output if UART.RX is ready to receive */
UART_CTRL_CTS_EN = 21, /**< UART control register(21) (r/w): Enable hardware flow control: UART.TX starts sending only if CTS input is asserted */
UART_CTRL_PMODE0 = 22, /**< UART control register(22) (r/w): Parity configuration (0=even; 1=odd) */
UART_CTRL_PMODE1 = 23, /**< UART control register(23) (r/w): Parity bit enabled when set */
UART_CTRL_PRSC0 = 24, /**< UART control register(24) (r/w): BAUD rate clock prescaler select bit 0 */
UART_CTRL_PRSC1 = 25, /**< UART control register(25) (r/w): BAUD rate clock prescaler select bit 1 */
UART_CTRL_PRSC2 = 26, /**< UART control register(26) (r/w): BAUD rate clock prescaler select bit 2 */
UART_CTRL_CTS = 27, /**< UART control register(27) (r/-): current state of CTS input */
UART_CTRL_EN = 28, /**< UART control register(28) (r/w): UART global enable */
UART_CTRL_RX_IRQ = 29, /**< UART control register(29) (r/w): RX IRQ mode: 1=FIFO at least half-full; 0=FIFO not empty */
UART_CTRL_TX_IRQ = 30, /**< UART control register(30) (r/w): TX IRQ mode: 1=FIFO less than half-full; 0=FIFO not full */
UART_CTRL_TX_BUSY = 31 /**< UART control register(31) (r/-): Transmitter is busy when set */
};
UART_CTRL_RX_NEMPTY = 16, /**< UART control register(16) (r/-): RX FIFO not empty */
UART_CTRL_RX_HALF = 17, /**< UART control register(17) (r/-): RX FIFO at least half-full */
UART_CTRL_RX_FULL = 18, /**< UART control register(18) (r/-): RX FIFO full */
UART_CTRL_TX_EMPTY = 19, /**< UART control register(19) (r/-): TX FIFO empty */
UART_CTRL_TX_NHALF = 20, /**< UART control register(20) (r/-): TX FIFO not at least half-full */
UART_CTRL_TX_FULL = 21, /**< UART control register(21) (r/-): TX FIFO full */
/** UART0/UART1 parity configuration */
enum NEORV32_UART_PARITY_enum {
PARITY_NONE = 0b00, /**< 0b00: No parity bit at all */
PARITY_EVEN = 0b10, /**< 0b10: Even parity */
PARITY_ODD = 0b11 /**< 0b11: Odd parity */
};
UART_CTRL_IRQ_RX_NEMPTY = 22, /**< UART control register(22) (r/w): Fire IRQ if RX FIFO not empty */
UART_CTRL_IRQ_RX_HALF = 23, /**< UART control register(23) (r/w): Fire IRQ if RX FIFO at least half-full */
UART_CTRL_IRQ_RX_FULL = 24, /**< UART control register(24) (r/w): Fire IRQ if RX FIFO full */
UART_CTRL_IRQ_TX_EMPTY = 25, /**< UART control register(25) (r/w): Fire IRQ if TX FIFO empty */
UART_CTRL_IRQ_TX_NHALF = 26, /**< UART control register(26) (r/w): Fire IRQ if TX FIFO not at least half-full */
/** UART0/UART1 hardware flow control configuration */
enum NEORV32_UART_FLOW_CONTROL_enum {
FLOW_CONTROL_NONE = 0b00, /**< 0b00: No hardware flow control */
FLOW_CONTROL_RTS = 0b01, /**< 0b01: Assert RTS output if UART.RX is ready to receive */
FLOW_CONTROL_CTS = 0b10, /**< 0b10: UART.TX starts sending only if CTS input is asserted */
FLOW_CONTROL_RTSCTS = 0b11 /**< 0b11: Assert RTS output if UART.RX is ready to receive & UART.TX starts sending only if CTS input is asserted */
};
/** UART0/UART1 receive/transmit data register bits */
enum NEORV32_UART_DATA_enum {
UART_DATA_LSB = 0, /**< UART receive/transmit data register(0) (r/w): Receive/transmit data LSB (bit 0) */
UART_DATA_MSB = 7, /**< UART receive/transmit data register(7) (r/w): Receive/transmit data MSB (bit 7) */
UART_DATA_PERR = 28, /**< UART receive/transmit data register(18) (r/-): RX parity error detected when set */
UART_DATA_FERR = 29, /**< UART receive/transmit data register(29) (r/-): RX frame error (no valid stop bit) detected when set */
UART_DATA_OVERR = 30, /**< UART receive/transmit data register(30) (r/-): RX data overrun when set */
UART_DATA_AVAIL = 31 /**< UART receive/transmit data register(31) (r/-): RX data available when set */
UART_CTRL_RX_OVER = 30, /**< UART control register(30) (r/-): RX FIFO overflow */
UART_CTRL_TX_BUSY = 31 /**< UART control register(31) (r/-): Transmitter busy or TX FIFO not empty */
};
/**@}*/

View file

@ -36,10 +36,6 @@
/**********************************************************************//**
* @file neorv32_uart.h
* @brief Universal asynchronous receiver/transmitter (UART0/UART1) HW driver header file
*
* @warning UART0 (primary UART) is used as default user console interface for all NEORV32 software framework/library functions.
*
* @note These functions should only be used if the UART0/UART1 unit was synthesized (IO_UART0_EN = true / IO_UART1_EN = true).
**************************************************************************/
#ifndef neorv32_uart_h
@ -50,13 +46,12 @@
// prototypes for common used UART functions, applicable to UART0 and UART1
int neorv32_uart_available(neorv32_uart_t *UARTx);
void neorv32_uart_setup(neorv32_uart_t *UARTx, uint32_t baudrate, uint8_t parity, uint8_t flow_con);
void neorv32_uart_setup(neorv32_uart_t *UARTx, uint32_t baudrate, uint32_t irq_mask);
void neorv32_uart_enable(neorv32_uart_t *UARTx);
void neorv32_uart_disable(neorv32_uart_t *UARTx);
void neorv32_uart_putc(neorv32_uart_t *UARTx, char c);
int neorv32_uart_tx_busy(neorv32_uart_t *UARTx);
char neorv32_uart_getc(neorv32_uart_t *UARTx);
int neorv32_uart_getc_safe(neorv32_uart_t *UARTx, char *data);
int neorv32_uart_char_received(neorv32_uart_t *UARTx);
char neorv32_uart_char_received_get(neorv32_uart_t *UARTx);
void neorv32_uart_puts(neorv32_uart_t *UARTx, const char *s);

View file

@ -37,9 +37,7 @@
* @file neorv32_uart.c
* @brief Universal asynchronous receiver/transmitter (UART0/UART1) HW driver source file.
*
* @warning UART0 (primary UART) is used as default user console interface for all NEORV32 software framework/library functions.
*
* @note These functions should only be used if the UART0/UART1 unit was synthesized (IO_UART0_EN = true / IO_UART1_EN = true).
* @note These functions should only be used if the UART0/UART1 unit was synthesized.
**************************************************************************/
#include "neorv32.h"
@ -47,50 +45,16 @@
#include <string.h>
#include <stdarg.h>
/// \cond
// Private functions
static void __neorv32_uart_itoa(uint32_t x, char *res) __attribute__((unused)); // GCC: do not output a warning when this variable is unused
static void __neorv32_uart_tohex(uint32_t x, char *res) __attribute__((unused)); // GCC: do not output a warning when this variable is unused
static void __neorv32_uart_touppercase(uint32_t len, char *ptr) __attribute__((unused)); // GCC: do not output a warning when this variable is unused
/// \endcond
// #################################################################################################
// Override default STDIO functions
// #################################################################################################
/**********************************************************************//**
* Send char via UART0
*
* @param[in] Char to be send.
* @return Char that has been sent.
**************************************************************************/
int putchar(int ch) {
neorv32_uart0_putc((char)ch);
return ch;
}
/**********************************************************************//**
* Read char from UART0.
* Check if UART unit was synthesized.
*
* @return Read char.
**************************************************************************/
int getchar(void) {
return (int)neorv32_uart0_getc();
}
// #################################################################################################
// Common used UART, assigned to UART0/1 in legacy.h
// #################################################################################################
/**********************************************************************//**
* Check if UART0/1 unit was synthesized.
*
* @param[in,out] hardware handle to UART register, #neorv32_uart_t.
* @param[in,out] Hardware handle to UART register, #neorv32_uart_t.
* @return 0 if UART0/1 was not synthesized, 1 if UART0/1 is available.
**************************************************************************/
int neorv32_uart_available (neorv32_uart_t *UARTx) {
@ -108,97 +72,68 @@ int neorv32_uart_available (neorv32_uart_t *UARTx) {
/**********************************************************************//**
* Enable and configure primary UART (UART0).
* Reset, configure and enable UART.
*
* @note The 'UART0_SIM_MODE' compiler flag will configure UART0 for simulation mode. All UART0 TX data will be redirected to simulation output. Use this for simulations only!
* @note The 'UART1_SIM_MODE' compiler flag will configure UART1 for simulation mode. All UART1 TX data will be redirected to simulation output. Use this for simulations only!
* @note To enable simulation mode add <USER_FLAGS+=-DUART0_SIM_MODE> when compiling.
* @note To enable simulation mode add <USER_FLAGS+=-DUART1_SIM_MODE> when compiling.
*
* @warning The baud rate is computed using INTEGER operations (truncation errors might occur).
*
* @param[in,out] hardware handle to UART register, #neorv32_uart_t.
* @param[in] baudrate Targeted BAUD rate (e.g. 9600).
* @param[in] parity Parity configuration (00=off, 10=even, 11=odd), see #NEORV32_UART_PARITY_enum.
* @param[in] flow_con Hardware flow control configuration (00=off, 01=RTS, 10=CTS, 11=RTS/CTS), see #NEORV32_UART_FLOW_CONTROL_enum.
* @param[in,out] UARTx Hardware handle to UART register, #neorv32_uart_t.
* @param[in] baudrate Targeted BAUD rate (e.g. 19200).
* @param[in] irq_mask Interrupt configuration mask (CTRL's irq_* bits).
**************************************************************************/
void neorv32_uart_setup(neorv32_uart_t *UARTx, uint32_t baudrate, uint8_t parity, uint8_t flow_con) {
void neorv32_uart_setup(neorv32_uart_t *UARTx, uint32_t baudrate, uint32_t irq_mask) {
uint32_t clock = NEORV32_SYSINFO->CLK; // get system clock
uint16_t i = 0; // BAUD rate divisor
uint8_t p = 0; // initial prsc = CLK/2
uint32_t sim_mode = 0; // redirect output to stdio
uint32_t prsc_sel = 0;
uint32_t baud_div = 0;
// Sim mode requested?
/* Enable UART0/1 for SIM mode. */
/* USE THIS ONLY FOR SIMULATION! */
#ifdef UART_SIM_MODE
#warning <UART_SIM_MODE> is obsolete (but still supported for compatibility). Please consider using the new flag <UART0_SIM_MODE>.
// reset
UARTx->CTRL = 0;
// raw clock prescaler
uint32_t clock = NEORV32_SYSINFO->CLK; // system clock in Hz
#ifndef make_bootloader // use div instructions
baud_div = clock / (2*baudrate);
#else // division via repeated subtraction (minimal size, only for bootloader)
while (clock >= 2*baudrate) {
clock -= 2*baudrate;
baud_div++;
}
#endif
// find baud prescaler (10-bit wide))
while (baud_div >= 0x3ffU) {
if ((prsc_sel == 2) || (prsc_sel == 4))
baud_div >>= 3;
else
baud_div >>= 1;
prsc_sel++;
}
uint32_t tmp = 0;
tmp |= (uint32_t)(1 & 1U) << UART_CTRL_EN;
tmp |= (uint32_t)(prsc_sel & 3U) << UART_CTRL_PRSC0;
tmp |= (uint32_t)((baud_div - 1) & 0x3ffU) << UART_CTRL_BAUD0;
tmp |= (uint32_t)(irq_mask & (0x1fU << UART_CTRL_IRQ_RX_NEMPTY));
#ifdef UART0_SIM_MODE
#warning UART0_SIM_MODE (primary UART) enabled! Sending all UART0.TX data to text.io simulation output instead of real UART0 transmitter. Use this for simulations only!
if (((uint32_t)UARTx) == NEORV32_UART0_BASE) {
sim_mode = 1 << UART_CTRL_SIM_MODE;
tmp |= 1U << UART_CTRL_SIM_MODE;
}
#endif
#ifdef UART1_SIM_MODE
#warning UART1_SIM_MODE (secondary UART) enabled! Sending all UART1.TX data to text.io simulation output instead of real UART1 transmitter. Use this for simulations only!
if (((uint32_t)UARTx) == NEORV32_UART1_BASE) {
sim_mode = 1 << UART_CTRL_SIM_MODE;
tmp |= 1U << UART_CTRL_SIM_MODE;
}
#endif
// reset
UARTx->CTRL = 0;
// raw clock prescaler
#ifndef make_bootloader
// use div instructions
i = (uint16_t)(clock / (2*baudrate));
#else
// division via repeated subtraction (minimal size, only for bootloader)
while (clock >= 2*baudrate) {
clock -= 2*baudrate;
i++;
}
#endif
// find baud prescaler (12-bit wide))
while (i >= 0x0fff) {
if ((p == 2) || (p == 4))
i >>= 3;
else
i >>= 1;
p++;
}
uint32_t clk_prsc = (uint32_t)p;
clk_prsc = clk_prsc << UART_CTRL_PRSC0;
uint32_t baud_prsc = (uint32_t)i;
baud_prsc = baud_prsc - 1;
baud_prsc = baud_prsc << UART_CTRL_BAUD00;
uint32_t uart_en = 1;
uart_en = uart_en << UART_CTRL_EN;
uint32_t parity_config = (uint32_t)(parity & 3);
parity_config = parity_config << UART_CTRL_PMODE0;
uint32_t flow_control = (uint32_t)(flow_con & 3);
flow_control = flow_control << UART_CTRL_RTS_EN;
UARTx->CTRL = clk_prsc | baud_prsc | uart_en | parity_config | sim_mode | flow_control;
UARTx->CTRL = tmp;
}
/**********************************************************************//**
* Enable UART
* Enable UART.
*
* @param[in,out] hardware handle to UART register, #neorv32_uart_t.
* @param[in,out] UARTx Hardware handle to UART register, #neorv32_uart_t.
**************************************************************************/
void neorv32_uart_enable(neorv32_uart_t *UARTx) {
@ -207,9 +142,9 @@ void neorv32_uart_enable(neorv32_uart_t *UARTx) {
/**********************************************************************//**
* Disable UART
* Disable UART.
*
* @param[in,out] hardware handle to UART register, #neorv32_uart_t.
* @param[in,out] UARTx Hardware handle to UART register, #neorv32_uart_t.
**************************************************************************/
void neorv32_uart_disable(neorv32_uart_t *UARTx) {
@ -218,122 +153,70 @@ void neorv32_uart_disable(neorv32_uart_t *UARTx) {
/**********************************************************************//**
* Send single char via UART
* Send single char via UART.
*
* @note This function is blocking.
*
* @param[in,out] hardware handle to UART register, #neorv32_uart_t.
* @param[in,out] UARTx Hardware handle to UART register, #neorv32_uart_t.
* @param[in] c Char to be send.
**************************************************************************/
void neorv32_uart_putc(neorv32_uart_t *UARTx, char c) {
// wait for previous transfer to finish
while ((UARTx->CTRL & (1<<UART_CTRL_TX_FULL)) != 0); // wait for space in TX FIFO
UARTx->DATA = ((uint32_t)c) << UART_DATA_LSB;
while ((UARTx->CTRL & (1<<UART_CTRL_TX_FULL))); // wait for free space in TX FIFO
UARTx->DATA = (uint32_t)c;
}
/**********************************************************************//**
* Check if UART TX is busy (transmitter busy or data left in TX buffer).
*
* @note This function is blocking.
*
* @param[in,out] hardware handle to UART register, #neorv32_uart_t.
* @param[in,out] UARTx Hardware handle to UART register, #neorv32_uart_t.
* @return 0 if idle, 1 if busy
**************************************************************************/
int neorv32_uart_tx_busy(neorv32_uart_t *UARTx) {
uint32_t ctrl = UARTx->CTRL;
if (((ctrl & (1<<UART_CTRL_TX_BUSY)) != 0) || // TX engine busy
((ctrl & (1<<UART_CTRL_TX_EMPTY)) == 0)) { // TX buffer not empty
if (UARTx->CTRL & (1 << UART_CTRL_TX_BUSY)) { // TX engine busy
return 1;
}
return 0;
else {
return 0;
}
}
/**********************************************************************//**
* Get char from UART.
*
* @note This function is blocking and does not check for UART frame/parity errors.
* @note This function is blocking.
*
* @param[in,out] hardware handle to UART register, #neorv32_uart_t.
* @param[in,out] UARTx Hardware handle to UART register, #neorv32_uart_t.
* @return Received char.
**************************************************************************/
char neorv32_uart_getc(neorv32_uart_t *UARTx) {
uint32_t d = 0;
while (1) {
d = UARTx->DATA;
if ((d & (1<<UART_DATA_AVAIL)) != 0) { // char received?
return (char)d;
if (UARTx->CTRL & (1<<UART_CTRL_RX_NEMPTY)) { // data available?
return (char)UARTx->DATA;
}
}
}
/**********************************************************************//**
* Get char from UART (and check errors).
*
* @note This function is non-blocking and checks for frame and parity errors.
*
* @param[in,out] hardware handle to UART register, #neorv32_uart_t.
* @param[in,out] data Received char.
* @return Status code:
* 0 = char received without errors
* -1 = nothing received
* -2 = char received with frame error
* -3 = char received with parity error
* -4 = char received with overrun error.
**************************************************************************/
int neorv32_uart_getc_safe(neorv32_uart_t *UARTx, char *data) {
uint32_t uart_rx = UARTx->DATA;
// get received byte (if there is any)
*data = (char)uart_rx;
// check if no data available at all
if ((uart_rx & (1<<UART_DATA_AVAIL)) == 0) {
return -1;
}
// check for frame error
if (uart_rx & (1<<UART_DATA_FERR)) {
return -2;
}
// check for parity error
if (uart_rx & (1<<UART_DATA_PERR)) {
return -3;
}
// check for overrun error
if (uart_rx & (1<<UART_DATA_OVERR)) {
return -4;
}
return 0; // all fine
}
/**********************************************************************//**
* Check if UART has received a char.
*
* @note This function is non-blocking.
* @note Use neorv32_uart_char_received_get(void) to get the char.
*
* @param[in,out] hardware handle to UART register, #neorv32_uart_t.
* @return =!0 when a char has been received.
* @param[in,out] UARTx Hardware handle to UART register, #neorv32_uart_t.
* @return 1 when a char has been received, 0 otherwise.
**************************************************************************/
int neorv32_uart_char_received(neorv32_uart_t *UARTx) {
if (UARTx->CTRL & (1<<UART_CTRL_RX_EMPTY)) {
return 0;
if (UARTx->CTRL & (1<<UART_CTRL_RX_NEMPTY)) {
return 1;
}
else {
return 1;
return 0;
}
}
@ -344,7 +227,7 @@ int neorv32_uart_char_received(neorv32_uart_t *UARTx) {
* @note This function is non-blocking.
* @note Should only be used in combination with neorv32_uart_char_received(void).
*
* @param[in,out] hardware handle to UART register, #neorv32_uart_t.
* @param[in,out] UARTx Hardware handle to UART register, #neorv32_uart_t.
* @return Received char.
**************************************************************************/
char neorv32_uart_char_received_get(neorv32_uart_t *UARTx) {
@ -358,7 +241,7 @@ char neorv32_uart_char_received_get(neorv32_uart_t *UARTx) {
*
* @note This function is blocking.
*
* @param[in,out] hardware handle to UART register, #neorv32_uart_t.
* @param[in,out] UARTx Hardware handle to UART register, #neorv32_uart_t.
* @param[in] s Pointer to string.
**************************************************************************/
void neorv32_uart_puts(neorv32_uart_t *UARTx, const char *s) {
@ -378,7 +261,7 @@ void neorv32_uart_puts(neorv32_uart_t *UARTx, const char *s) {
*
* @note This function is blocking.
*
* @param[in,out] hardware handle to UART register, #neorv32_uart_t.
* @param[in,out] UARTx Hardware handle to UART register, #neorv32_uart_t.
* @param[in] format Pointer to format string.
*
* <TABLE>
@ -457,7 +340,7 @@ void neorv32_uart_printf(neorv32_uart_t *UARTx, const char *format, ...) {
*
* @note This function is blocking.
*
* @param[in,out] hardware handle to UART register, #neorv32_uart_t.
* @param[in,out] UARTx Hardware handle to UART register, #neorv32_uart_t.
* @param[in,out] buffer Pointer to array of chars to store string.
* @param[in] max_size Maximum number of chars to sample.
* @param[in] echo Echo UART input when 1.
@ -495,10 +378,6 @@ int neorv32_uart_scan(neorv32_uart_t *UARTx, char *buffer, int max_size, int ech
}
// #################################################################################################
// Shared functions
// #################################################################################################
/**********************************************************************//**
* Private function for 'neorv32_printf' to convert into decimal.
*
@ -578,3 +457,31 @@ static void __neorv32_uart_touppercase(uint32_t len, char *ptr) {
len--;
}
}
// ================================================================================================
// ================================================================================================
/**********************************************************************//**
* STDIO: Send char via UART0
*
* @param[in] Char to be send.
* @return Char that has been sent.
**************************************************************************/
int putchar(int ch) {
neorv32_uart_putc(NEORV32_UART0, (char)ch);
return ch;
}
/**********************************************************************//**
* STDIO: Read char from UART0.
*
* @return Read char.
**************************************************************************/
int getchar(void) {
return (int)neorv32_uart_getc(NEORV32_UART0);
}