115 lines
3.4 KiB
C
115 lines
3.4 KiB
C
/*
|
|
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include "hardware/address_mapped.h"
|
|
#include "hardware/platform_defs.h"
|
|
#include "hardware/uart.h"
|
|
|
|
#include "hardware/structs/uart.h"
|
|
#include "hardware/resets.h"
|
|
#include "hardware/clocks.h"
|
|
#include "hardware/timer.h"
|
|
|
|
#include "pico/assert.h"
|
|
#include "pico.h"
|
|
|
|
check_hw_layout(uart_hw_t, fr, UART_UARTFR_OFFSET);
|
|
check_hw_layout(uart_hw_t, dmacr, UART_UARTDMACR_OFFSET);
|
|
|
|
#if PICO_UART_ENABLE_CRLF_SUPPORT
|
|
short uart_char_to_line_feed[NUM_UARTS];
|
|
#endif
|
|
|
|
/// \tag::uart_reset[]
|
|
static inline void uart_reset(uart_inst_t *uart) {
|
|
invalid_params_if(UART, uart != uart0 && uart != uart1);
|
|
reset_block(uart_get_index(uart) ? RESETS_RESET_UART1_BITS : RESETS_RESET_UART0_BITS);
|
|
}
|
|
|
|
static inline void uart_unreset(uart_inst_t *uart) {
|
|
invalid_params_if(UART, uart != uart0 && uart != uart1);
|
|
unreset_block_wait(uart_get_index(uart) ? RESETS_RESET_UART1_BITS : RESETS_RESET_UART0_BITS);
|
|
}
|
|
/// \end::uart_reset[]
|
|
|
|
/// \tag::uart_init[]
|
|
uint uart_init(uart_inst_t *uart, uint baudrate) {
|
|
invalid_params_if(UART, uart != uart0 && uart != uart1);
|
|
|
|
if (clock_get_hz(clk_peri) == 0)
|
|
return 0;
|
|
|
|
uart_reset(uart);
|
|
uart_unreset(uart);
|
|
|
|
#if PICO_UART_ENABLE_CRLF_SUPPORT
|
|
uart_set_translate_crlf(uart, PICO_UART_DEFAULT_CRLF);
|
|
#endif
|
|
|
|
// Any LCR writes need to take place before enabling the UART
|
|
uint baud = uart_set_baudrate(uart, baudrate);
|
|
uart_set_format(uart, 8, 1, UART_PARITY_NONE);
|
|
|
|
// Enable the UART, both TX and RX
|
|
uart_get_hw(uart)->cr = UART_UARTCR_UARTEN_BITS | UART_UARTCR_TXE_BITS | UART_UARTCR_RXE_BITS;
|
|
// Enable FIFOs
|
|
hw_set_bits(&uart_get_hw(uart)->lcr_h, UART_UARTLCR_H_FEN_BITS);
|
|
// Always enable DREQ signals -- no harm in this if DMA is not listening
|
|
uart_get_hw(uart)->dmacr = UART_UARTDMACR_TXDMAE_BITS | UART_UARTDMACR_RXDMAE_BITS;
|
|
|
|
return baud;
|
|
}
|
|
/// \end::uart_init[]
|
|
|
|
void uart_deinit(uart_inst_t *uart) {
|
|
invalid_params_if(UART, uart != uart0 && uart != uart1);
|
|
uart_reset(uart);
|
|
}
|
|
|
|
/// \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 = ((baud_rate_div & 0x7f) + 1) / 2;
|
|
|
|
if (baud_ibrd == 0) {
|
|
baud_ibrd = 1;
|
|
baud_fbrd = 0;
|
|
} else if (baud_ibrd >= 65535) {
|
|
baud_ibrd = 65535;
|
|
baud_fbrd = 0;
|
|
}
|
|
|
|
// Load PL011's baud divisor registers
|
|
uart_get_hw(uart)->ibrd = baud_ibrd;
|
|
uart_get_hw(uart)->fbrd = baud_fbrd;
|
|
|
|
// PL011 needs a (dummy) line control register write to latch in the
|
|
// divisors. We don't want to actually change LCR contents here.
|
|
hw_set_bits(&uart_get_hw(uart)->lcr_h, 0);
|
|
|
|
// See datasheet
|
|
return (4 * clock_get_hz(clk_peri)) / (64 * baud_ibrd + baud_fbrd);
|
|
}
|
|
/// \end::uart_set_baudrate[]
|
|
|
|
void uart_set_translate_crlf(uart_inst_t *uart, bool crlf) {
|
|
#if PICO_UART_ENABLE_CRLF_SUPPORT
|
|
uart_char_to_line_feed[uart_get_index(uart)] = crlf ? '\n' : 0x100;
|
|
#else
|
|
panic_unsupported();
|
|
#endif
|
|
}
|
|
|
|
bool uart_is_readable_within_us(uart_inst_t *uart, uint32_t us) {
|
|
uint32_t t = time_us_32();
|
|
do {
|
|
if (uart_is_readable(uart)) return true;
|
|
} while ((time_us_32() - t) <= us);
|
|
return false;
|
|
}
|