Repository: raspberrypi/pico-sdk
File: src/rp2_common/hardware_uart/uart.c (C)

Code before:
    // - FIFOs can't be set to disabled whilst a character is in progress
    //   (else "FIFO integrity is not guaranteed")
    //
    // Combination of these means there is no general way to halt and poll for
    // end of TX character, if FIFOs may be enabled. Either way, there is no
    // way to poll for end of RX character.
    //
    // So... we're going to insert a 15 baud period delay before changing
    // settings (comfortably higher than max data + start + stop + parity).
    // Anything else would require API changes to permit a non-enabled UART
    // state after init() where settings can be changed safely.

    uint32_t cr_save = uart_get_hw(uart)->cr;
    hw_clear_bits(&uart_get_hw(uart)->cr,
        UART_UARTCR_UARTEN_BITS | UART_UARTCR_TXE_BITS | UART_UARTCR_RXE_BITS);

    uint32_t current_ibrd = uart_get_hw(uart)->ibrd;
    uint32_t current_fbrd = uart_get_hw(uart)->fbrd;

    // Note: Maximise precision here. Show working, the compiler will mop this up.
    // Create a 16.6 fixed-point fractional division ratio; then scale to 32-bits.
    uint32_t brdiv_ratio = 64u * current_ibrd + current_fbrd;
    brdiv_ratio <<= 10;
    // 3662 is ~(15 * 244.14) where 244.14 is 16e6 / 2^16
    uint32_t scaled_freq = clock_get_hz(clk_peri) / 3662ul;
    uint32_t wait_time_us = brdiv_ratio / scaled_freq;
    busy_wait_us(wait_time_us);

    return cr_save;
}

static void uart_write_lcr_bits_masked(uart_inst_t *uart, uint32_t values, uint32_t write_mask) {
    invalid_params_if(UART, uart != uart0 && uart != uart1);
    uint32_t cr_save;
    bool enabled = uart_is_enabled(uart);

    if (enabled) {
        // Need to cleanly disable UART before touching LCR
        cr_save = uart_disable_before_lcr_write(uart);
    }

    hw_write_masked(&uart_get_hw(uart)->lcr_h, values, write_mask);

    // Re-enable using saved control register value
    if (enabled) {
        uart_get_hw(uart)->cr = cr_save;
    }
}

/// \tag::uart_set_baudrate[]
uint uart_set_baudrate(uart_inst_t *uart, uint baudrate) {

Review comment (suggestion):
I'm not convinced this math is right yet (or the comments)

I calc for 133Mhz peri clock and 115200 baud rate, then brdiv_ratio should be 9236 ish.
Thhe above calc then gives me (I think) 260us

However 15 bauds is 130us

Code after:
    // - FIFOs can't be set to disabled whilst a character is in progress
    //   (else "FIFO integrity is not guaranteed")
    //
    // Combination of these means there is no general way to halt and poll for
    // end of TX character, if FIFOs may be enabled. Either way, there is no
    // way to poll for end of RX character.
    //
    // So, insert a 15 Baud period delay before changing the settings.
    // 15 Baud is comfortably higher than start + max data + parity + stop.
    // Anything else would require API changes to permit a non-enabled UART
    // state after init() where settings can be changed safely.
    uint32_t cr_save = uart_get_hw(uart)->cr;

    if (cr_save & UART_UARTCR_UARTEN_BITS) {
        hw_clear_bits(&uart_get_hw(uart)->cr,
            UART_UARTCR_UARTEN_BITS | UART_UARTCR_TXE_BITS | UART_UARTCR_RXE_BITS);

        uint32_t current_ibrd = uart_get_hw(uart)->ibrd;
        uint32_t current_fbrd = uart_get_hw(uart)->fbrd;

        // Note: Maximise precision here. Show working, the compiler will mop this up.
        // Create a 16.6 fixed-point fractional division ratio; then scale to 32-bits.
        uint32_t brdiv_ratio = 64u * current_ibrd + current_fbrd;
        brdiv_ratio <<= 10;
        // 3662 is ~(15 * 244.14) where 244.14 is 16e6 / 2^16
        uint32_t scaled_freq = clock_get_hz(clk_peri) / 3662ul;
        uint32_t wait_time_us = brdiv_ratio / scaled_freq;
        busy_wait_us(wait_time_us);
    }

    return cr_save;
}

static void uart_write_lcr_bits_masked(uart_inst_t *uart, uint32_t values, uint32_t write_mask) {
    invalid_params_if(UART, uart != uart0 && uart != uart1);

    // (Potentially) Cleanly handle disabling the UART before touching LCR
    uint32_t cr_save = uart_disable_before_lcr_write(uart);

    hw_write_masked(&uart_get_hw(uart)->lcr_h, values, write_mask);

    uart_get_hw(uart)->cr = cr_save;
}

/// \tag::uart_set_baudrate[]
uint uart_set_baudrate(uart_inst_t *uart, uint baudrate) {
    invalid_params_if(UART, baudrate == 0);
    uint32_t baud_rate_div = (8 * clock_get_hz(clk_peri) / baudrate);
    uint32_t baud_ibrd = baud_rate_div >> 7;
    uint32_t baud_fbrd;