ESP32-S3 Bare metal UART not working

VaporGame
Posts: 2
Joined: Sat Aug 16, 2025 1:47 pm

ESP32-S3 Bare metal UART not working

Postby VaporGame » Sat Aug 16, 2025 1:52 pm

I have been trying to write code for the ESP32-S3 without using the IDF that initializes the uart and writes something to it, but i have been unable to get it to work with many attempts.

Here is my current code:

Code: Select all

#define UART_TX_PIN 1
#define UART_RX_PIN 2

void uart_init(uint32_t baud_rate) {
    // ESP32-S3 TRM (Version 1.7)
    // 26.5.2.1 Initializing UARTn

    // Reset uart peripheral
    system->PERIP_CLK_EN0 |= 1UL << 24; // Set bit 24 (SYSTEM_UART_MEM_CLK_EN)
    system->PERIP_CLK_EN0 |= 1UL << 2;// Enable APB_CLK for UART

    // system->PERIP_RST_EN0 |= 1UL << 2; // Write 1 to SYSTEM_UART_RST
    system->PERIP_RST_EN0 &= ~(1UL << 2); // Clear SYSTEM_UART_RST

    uart0->CLK_CONF |= 1UL << 23; // Write 1 to UART_RST_CORE

    system->PERIP_RST_EN0 |= 1UL << 2; // Write 1 to SYSTEM_UART_RST

    system->PERIP_RST_EN0 &= ~(1UL << 2); // Clear SYSTEM_UART_RST

    uart0->CLK_CONF &= ~(1UL << 23); // Clear UART_RST_CORE

    // Enable register synchronization
    uart0->ID &= ~(1UL << 30); // clear UART_UPDATE_CTRL

    // 26.5.2.2 Configuring UARTn Communication
    while (uart0->ID & (1UL << 31)); // wait for UART_REG_UPDATE to become 0
    
    // Configure static registers here if needed
    uart0->CLK_CONF &= ~(1UL << 21);
    uart0->CLK_CONF |= 1UL << 20;
    // For now it will be hardcoded at 115200 baud
    // Setting the clock divisor is not needed, but recommended to save power
    // configure the baud rate for transmission
    const uint32_t uart_clock_freq = 80000000;
    const uint32_t divider = (uart_clock_freq / baud_rate);
    const uint32_t fractional_part = ((uart_clock_freq % baud_rate) * 65536 / baud_rate);
    uart0->CLKDIV = (divider << 0) | (fractional_part << 20);

    // the bit width is set to 3 by default (REG-5 so 8-5 = 3)
    // the parity is disabled by default
    // the stop bits are set to 1 by default
    uart0->ID |= 1UL << 31; // Synchronize the values by writing 1 to UART_REG_UPDATE

    // 26.5.2.3 Enabling UARTn
    // I dont think ill be using interrupts

    // Set up pins
    // Set GPIO1 to be a digital output
    // The GPIO_ENABLE register controls output enable for each pin.
    
    // Set the mux values
    gpio->FUNC_OUT_SEL_CFG[UART_TX_PIN] = 12 | (1UL << 10); //U0TXD_out | OEN_SEL
    // gpio->FUNC_OUT_SEL_CFG[UART_TX_PIN] = 12; //U0TXD_out | OEN_SEL
    gpio->ENABLE_W1TS = (1UL << UART_TX_PIN);


    // gpio->ENABLE_W1TC = (1UL << UART_RX_PIN);
    // // Set the mux values
    // gpio->FUNC_IN_SEL_CFG[UART_RX_PIN ] = 12 | (1UL << 10); //U0TXD_out | OEN_SEL
}

void uartTx(unsigned const char x) {
    uart0->CONF1 &= ~(0xFFFFFUL << 10);
    uart0->CONF1 |= (0x01UL << 10);
    uart0->INT_ENA &= ~(1UL << 1);

    while (((uart0->STATUS >> 16) & 0x1FF) >= 128); // Wait until there's space in the TX FIFO
    uart0->FIFO = (x & 0xFF);

    uart0->INT_CLR |= (1UL << 1);
    uart0->INT_ENA |= (1UL << 1);
}

// void uartTx(unsigned const char x) {
//     extern int uart_tx_one_char(int);
//     (void) uart_tx_one_char(x);
// }
I am sorry if this is not the right place to ask, but I am new to these forums and didn't see a forum specifically for esp32 development without the IDF. Sorry if i didn't provide enough information.

VaporGame
Posts: 2
Joined: Sat Aug 16, 2025 1:47 pm

Re: ESP32-S3 Bare metal UART not working

Postby VaporGame » Mon Aug 18, 2025 5:13 am

I have gotten it to transmit by fixing my register accesses, but now when i try to switch it to the APB clock, for some reason with the correct divisor for 115200 baud at 80Mhz it doesnt work, but it works with the divisor for 115200 baud at 20Mhz. From what i read the APB clock should always be at 80Mhz if the cpu is configured to have the PLL as its source, so i'm really confused.

Who is online

Users browsing this forum: Barkrowler, Bytespider and 4 guests