Reply - Raw
This is a reply to WRBndyn-
import machine
import utime

REG_UART0_BASE = 0x3FF40000
REG_UART1_BASE = 0x3FF50000
REG_UART2_BASE = 0x3FF6E000

REG_UART_FIFO       = 0x000 #
REG_UART_INT_RAW    = 0x004 #
REG_UART_INT_STATUS = 0x008 #
REG_UART_INT_ENABLE = 0x00C #
REG_UART_INT_CLEAR  = 0x010 #
REG_UART_CLKDIV     = 0x014 #
REG_UART_AUTOBAUD   = 0x018 #
REG_UART_STATUS     = 0x01C #
REG_UART_CONF0      = 0x020 #
REG_UART_CONF1      = 0x024 #
REG_UART_LOWPULSE   = 0x028 #
REG_UART_HIGHPULSE  = 0x02C #
REG_UART_RXD_CNT    = 0x030 #
REG_UART_FLOW       = 0x034 #
REG_UART_SLEEP      = 0x038 #
REG_UART_SWFC       = 0x03C #
REG_UART_IDLE       = 0x040 #
REG_UART_RS485      = 0x044 #
# AT_CMD... 0x48,0x4c,0x50,0x54
REG_UART_MEM_CONF   = 0x058 #
REG_UART_MEM_CNT_STATUS = 0x064 #
REG_UART_POSPULSE       = 0x068 #
REG_UART_NEGPULSE       = 0x06C #


# UART INT Registers Bits
UI_XOFF= 10 # Software XOFF
UI_XON = 9  # Software XON
UITO   = 8  # RX FIFO TimeOut
UIBD   = 7  # Break Detected
UICTS  = 6  # CTS Changed
UIDSR  = 5  # DSR Change
UIOF   = 4  # RX FIFO OverFlow
UIFR   = 3  # Frame Error
UIPE   = 2  # Parity Error
UIFE   = 1  # TX FIFO Empty
UIFF   = 0  # RX FIFO Full

# UART CLKDIV
U_CLKDIV = 0
U_CLKDIV_FRAG = 20

# UART STATUS Registers Bits
USTX   = 31 # TX PIN Level
USRTS  = 30 # RTS PIN Level
USDTR  = 39 # DTR PIN Level
UART_ST_UTX=24 # (4b)
USTXC  = 16 # TX FIFO COUNT (8bit)
USRXD  = 15 # RX PIN Level
USCTS  = 14 # CTS PIN Level
USDSR  = 13 # DSR PIN Level
UART_ST_URX_OUT=8 # (4b)
USRXC  =  0 # RX FIFO COUNT (8bit)

# UART CONF0
UART_TICK_REF_ALWAYS_ON = 27
UCDTRI  = 24 # Invert DTR
UCRTSI  = 23 # Invert RTS
UCTXI   = 22 # Invert TX
UCDSRI  = 21 # Invert DSR
UCCTSI  = 20 # Invert CTS
UCRXI   = 19 # Invert RX
UCTXRST = 18 # Reset TX FIFO
UCRXRST = 17 # Reset RX FIFO
UCTXHFE = 15 # TX Harware Flow Enable
UCLBE   = 14 # LoopBack Enable
UCBRK   =  8 # Send Break on the TX line
UCSWDTR =  7 # Set this bit to assert DTR
UCSWRTS =  6 # Set this bit to assert RTS
UCSBN   =  4 # StopBits Count (2b) 0:disable, 1:1bit, 2:1.5bit, 3:2bit
UCBN    =  2 # DataBits Count (2b) 0:5bit, 1:6bit, 2:7bit, 3:8bit
UCPAE   =  1 # Parity Enable
UCPA    =  0 # Parity 0:even, 1:odd

# UART CONF1 Registers Bits
UCTOE   = 31 # RX TimeOut Enable
UCTOT   = 24 # RX TimeOut Treshold (7bit)
UCRXHFE = 23 # RX Harware Flow Enable
UCRXHFT = 16 # RX Harware Flow Treshold (7bit)
UCFET   =  8 # TX FIFO Empty Treshold (7bit)
UCFFT   =  0 # RX FIFO Full Treshold (7bit)


#REG_BASE = 0x3ff40000
REG_BASE = 0x60000000
REG_GPIO_BASE = REG_BASE + 0x4000
REG_GPIO_PIN_BASE = REG_GPIO_BASE + 0x88

REG_IO_MUX_GPIO16 = REG_BASE + 0x904C
REG_IO_MUX_GPIO17 = REG_BASE + 0x9050

#print(machine.mem32[REG_UART0_CONF1]>>UCFET & 0x7f)
print("HELLO, WORLD!")
#machine.mem32[REG_UART0_INT_ENABLE] = machine.mem32[REG_UART0_INT_ENABLE] | 1<<UIFE
#print(machine.mem32[REG_UART0_INT_STATUS]>>UIFE & 0x1)

GPIO_FUNC_IN_SEL_CFG_REG_BASE = REG_GPIO_BASE + 0x130
def signalInputSelectPin(signal, pin, invert=0, direct=0):
    machine.mem32[GPIO_FUNC_IN_SEL_CFG_REG_BASE + 4*signal] = pin | invert << 6 | direct << 7
    
GPIO_FUNC_OUT_SEL_CFG_REG_BASE = REG_GPIO_BASE + 0x530
def signalOutputSelectPin(signal, pin, invert=0, output=0, output_invert=0):
    machine.mem32[GPIO_FUNC_OUT_SEL_CFG_REG_BASE + 4*signal] = pin | invert << 9 | output << 10 | output_invert << 11


def setIoMux(mux_pad, function, drive=0, input=0, pullup=0, pulldown=0, sleep_drive=0, sleep_input=0, sleep_pullup=0, sleep_pulldown=0, sleep_enable=0, sleep_output=0):
    machine.mem32[mux_pad] = (function-1) << 12 | drive << 10 | input << 9 | pullup << 8 | pulldown << 7 | sleep_drive << 5 | sleep_input << 4 | sleep_pullup << 3 | sleep_pulldown << 2 | sleep_enable << 1 | sleep_output

REG_OUT_ENABLE  = REG_GPIO_BASE + 0x20
REG_OUT_ENABLE1 = REG_GPIO_BASE + 0x2C
def outputEnable(pin, output):
    if pin < 32:
        reg=REG_OUT_ENABLE
    else:
        pin-=32
        reg=REG_OUT_ENABLE1
    if output:
        machine.mem32[reg+0x4] = 1 << pin
    else:
        machine.mem32[reg+0x8] = 1 << pin
        
# UART2 RXD = GPIO 16
# UART2 TXD = GPIO 17
# UART2 SIG = SIG 198
def uart2_enable():
    # Signal  Input       Output      Direct-IO_MUX
    # 198     U2RXD_in    U2TXD_out   YES
    # Connect signal UART2 to GPIO16, --bypass GPIO Matrix--
    signalInputSelectPin(198, 16)
    outputEnable(16, False)
    #print(bin(machine.mem32[GPIO_FUNC_IN_SEL_UART2]))

    setIoMux(REG_IO_MUX_GPIO16, 1, input=True)
    #print(hex(machine.mem32[REG_IO_MUX_GPIO16]), bin(machine.mem32[REG_IO_MUX_GPIO16]))
    
    #0x3FF44530 REG_IO_MUX_GPIO17
    signalOutputSelectPin(198, 17, output=True)
    outputEnable(17, True)
    setIoMux(REG_IO_MUX_GPIO17, 1)
    
    
print(bin(machine.mem32[0x3FF44020])) # GPIO_ENABLE - 1=out,0=in
print(bin(machine.mem32[0x3FF4402C])) # GPIO_ENABLE1
print(bin(machine.mem32[0x60004020])) # 
print(bin(machine.mem32[0x6000402c])) # 

#for pin in range(40): # 0-39
#    print("GPIO_PIN{}: {:032b}".format(pin, machine.mem32[REG_BASE+0x4088+(4*pin)]))
#for i in range(256):
#    print("GPIO_FUNC{}: {:032b}".format(i, machine.mem32[REG_BASE+0x4130+(4*i)]))
print("0b{:032b}".format(machine.mem32[0x3FF6e020]&(0xffffffff>>1)))

uart2_enable()

def n2uart(u):
    if u == 0:
        return REG_UART0_BASE
    elif u == 1:
        return REG_UART1_BASE
    elif u == 2:
        return REG_UART2_BASE

APB_CLK=80000000

def uarttxq(u):
    return machine.mem32[n2uart(u)+REG_UART_STATUS]>>USTXC & 0xff
#bin(machine.mem32[n2uart(2)+REG_UART_STATUS]&0x7fffffff)
def uartrxq(u):
    return machine.mem32[n2uart(u)+REG_UART_STATUS]>>USRXC & 0xff

def uartbaud(u, new=None):
    if new:
        clk_div = round((APB_CLK<<4) / new)
        machine.mem32[n2uart(u)+REG_UART_CLKDIV] = (clk_div >> 4) | ((clk_div & 0xf) << U_CLKDIV_FRAG)
    clk_reg = machine.mem32[n2uart(u)+REG_UART_CLKDIV]
    return (APB_CLK<<4) / (((clk_reg & 0xfffff) << 4) | ((clk_reg >> U_CLKDIV_FRAG) & 0xf))

def uartsync(u):
    while uarttxq(u): utime.sleep_us(8)
    utime.sleep_ms(10)

def uartwritechar(u, c):
    if type(c) in [str, bytes]:
        c = ord(c)
    while uarttxq(u) >= 127: pass
    machine.mem32[n2uart(u)] = c & 0xff

def uartwrite(u, s, encoding="UTF-8"):
    if type(s) is str:
        s = s.encode(encoding)
    if type(s) in [bytes, list]:
        for c in s:
            uartwritechar(u, c)
    else:
        uartwritechar(u, s)

def uartreadchar(u): # TODO: Implement non-blocking and timeout.
    while not uartrxq(u): utime.sleep_us(1)
    return chr(machine.mem32[n2uart(u)])

def uartread(u, num=1):
    return ''.join([uartreadchar(u) for i in range(num)])
    
print("U0TXQ", uarttxq(0))
print("U0RXQ", uartrxq(0))
print("U0BDR", uartbaud(0, 115200))

print("U2TXQ", uarttxq(2))
print("U2RXQ", uartrxq(2))
print("U2BDR", uartbaud(2, 9600))

# Enable loopback test mode on UART2
machine.mem32[0x3FF6E020] = machine.mem32[0x3FF6E020] | 1 << 14
uartwrite(2, "Foobar\n")
uartread(2, 7)

"""
u = machine.UART(0)

gps = machine.Pin(4, mode=machine.Pin.OUT, value=0)

print(u)
print(dir(u))
u.write('test\n')

uartsync(0)
u.init(baudrate=9600, timeout=10000)

gps(1)
line = u.read(100)
gps(0)

uartsync(0)
u.init(baudrate=115200)

print(line)
"""