From df55d45cc19558b142ef6de42054b6e28dd7b91d Mon Sep 17 00:00:00 2001 From: Kevin Stefanik Date: Thu, 2 Apr 2020 12:34:44 -0400 Subject: [PATCH] pac55xx: add usart definitions and basic support code. --- include/libopencm3/pac55xx/usart.h | 214 +++++++++++++++++++++++++++++ lib/pac55xx/Makefile | 1 + lib/pac55xx/usart.c | 200 +++++++++++++++++++++++++++ 3 files changed, 415 insertions(+) create mode 100644 include/libopencm3/pac55xx/usart.h create mode 100644 lib/pac55xx/usart.c diff --git a/include/libopencm3/pac55xx/usart.h b/include/libopencm3/pac55xx/usart.h new file mode 100644 index 00000000..d7ce72ef --- /dev/null +++ b/include/libopencm3/pac55xx/usart.h @@ -0,0 +1,214 @@ +/** + * @brief USART definitions for the Qorvo PAC55xx series of microcontrollers + * + * @addtogroup PAC55xx_usart USART + * @ingroup PAC55xx_defines + * @author Kevin Stefanik + * LGPL License Terms @ref lgpl_license + * @date 25 Feb 2020 + * + * Definitions in this file come from the PAC55XX Family User Guide Rev 1.23 + * by Active-Semi dated November 19, 2019. TX and RX hardware buffer sizes + * are both 16 bytes. + */ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2020 Kevin Stefanik + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ +#ifndef LIBOPENCM3_PAC55XX_USART_H_ +#define LIBOPENCM3_PAC55XX_USART_H_ + +#include +#include + +/**@{*/ + +/** @defgroup usart_registers Registers +@{*/ +/** Receive Buffer Register RO, only bits 7:0 used */ +#define USART_RBR(usart_base) MMIO32((usart_base) + 0x0000) +/** Transmit Holding Register WO, only bits 7:0 used */ +#define USART_THR(usart_base) MMIO32((usart_base) + 0x0004) +/** Divisor Latch Register RW, default 0000 0001h, only bits 15:0 used.*/ +#define USART_DLR(usart_base) MMIO32((usart_base) + 0x0008) +/** Interrupt Enable Register RW, default 0000 0000h */ +#define USART_IER(usart_base) MMIO32((usart_base) + 0x000C) +/** Interrupt Identification Register RO, default 0000 0001h */ +#define USART_IIR(usart_base) MMIO32((usart_base) + 0x0010) +/** FIFO Control Register RW, default 0000 0000h */ +#define USART_FCR(usart_base) MMIO32((usart_base) + 0x0014) +/** Line control Register RW, default 0000 0000h */ +#define USART_LCR(usart_base) MMIO32((usart_base) + 0x0018) +/** Line Status Register RO, default 0000 0060h */ +#define USART_LSR(usart_base) MMIO32((usart_base) + 0x0020) +/** Scratch Pad Register RW, only bits 7:0 used */ +#define USART_SCR(usart_base) MMIO32((usart_base) + 0x0028) +/** Enhanced Mode Register RW, default 0000 000h */ +#define USART_EFR(usart_base) MMIO32((usart_base) + 0x002C) +/**@}*/ + +/** @defgroup usart_ier_bits Interrupt Enable Register bits +@{*/ +/** Enable RX line status interrupt */ +#define USART_IER_RLSIE BIT2 +/** Enable the TX Holding Empty interrupt */ +#define USART_IER_THRIE BIT1 +/** Enable the RX Buffer Register Interrupt */ +#define USART_IER_RBRIE BIT0 +/**@}*/ + +/** @defgroup usart_iir_bits Interrupt ID Register bits +@{*/ +/** This bit is active low to indicate an interrupt is pending */ +#define USART_IIR_INTSTATUS BIT0 +/** TX Holding Register Empty */ +#define USART_IIR_TXEMPTY (0x02) +/** Receive Data Available */ +#define USART_IIR_RXAVAIL (0x04) +/** Receive Line Status */ +#define USART_IIR_RXLINESTAT (0x06) +/** Receive FIFO Character Time-out */ +#define USART_IIR_RXTIMEOUT (0x0C) +/**@}*/ + +/** @defgroup usart_fcr_bits FIFO Control Register bits +@{*/ +/** Enable both UART RX and TX FIFOs, must be set before writing rest of FCR */ +#define USART_FCR_FIFOEN BIT0 +/** RX FIFO Reset. Write 1 to clear. This bit is self-clearing. */ +#define USART_FCR_RXFIFORST BIT1 +/** TX FIFO Reset. Write 1 to clear. This bit is self-clearing. */ +#define USART_FCR_TXFIFORST BIT2 +#define USART_FCR_TXTL_MASK (3) +#define USART_FCR_TXTL_SHIFT 4 +/** TX Trigger Level */ +#define USART_FCR_TXTL(txtl) (((txtl) & USART_FCR_TXTL_MASK) << USART_FCR_TXTL_SHIFT) +#define USART_FCR_RXTL_MASK (3) +#define USART_FCR_RXTL_SHIFT 6 +/** RX Trigger Level */ +#define USART_FCR_RXTL(rxtl) (((rxtl) & USART_FCR_RXTL_MASK) << USART_FCR_RXTL_SHIFT) +#define USART_FIFO_TRIG_1CHAR (0) +#define USART_FIFO_TRIG_4CHAR (1) +#define USART_FIFO_TRIG_8CHAR (2) +#define USART_FIFO_TRIG_14CHAR (3) +/**@}*/ + +/** @defgroup usart_lcr_bits Line Control Register bits +@{*/ +/** LCR:WLS 5-bit character length */ +#define USART_DATABITS_5 (0) +/** LCR:WLS 6-bit character length */ +#define USART_DATABITS_6 (0x01) +/** LCR:WLS 7-bit character length */ +#define USART_DATABITS_7 (0x02) +/** LCR:WLS 8-bit character length */ +#define USART_DATABITS_8 (0x03) +/** LCR:PSEL & LCR:PEN Odd parity */ +#define USART_PSELPEN_ODD (0x01) +/** LCR:PSEL & LCR:PEN Even parity */ +#define USART_PSELPEN_EVEN (0x03) +/** LCR:PSEL & LCR:PEN Force 1 stick parity */ +#define USART_PSELPEN_FORCE1 (0x05) +/** LCR:PSEL & LCR:PEN Force 0 stick parity */ +#define USART_PSELPEN_FORCE0 (0x07) +/** LCR:PSEL & LCR:PEN Disable parity */ +#define USART_PARITY_DISABLE (0) +/** LCR:PSEL & LCR:PEN Odd parity */ +#define USART_PARITY_ODD USART_PSELPEN_ODD +/** LCR:PSEL & LCR:PEN Even parity */ +#define USART_PARITY_EVEN USART_PSELPEN_EVEN +/** LCR:PSEL & LCR:PEN Force 1 stick parity */ +#define USART_PARITY_FORCE1 USART_PSELPEN_FORCE1 +/** LCR:PSEL & LCR:PEN Force 0 stick parity */ +#define USART_PARITY_FORCE0 USART_PSELPEN_FORCE0 +/** LCR:SBS Use 1 stop bit */ +#define USART_STOPBITS_1 (0) +/** LCR:SBS Use 1.5 stop bit when databits is 5 */ +#define USART_STOPBITS_1P5 USART_LCR_SBS +/** LCR:SBS Use 2 stop bits */ +#define USART_STOPBITS_2 USART_LCR_SBS +#define USART_LCR_WLS_MASK (3) +/** Word length select: 5-8 databits */ +#define USART_LCR_WLS(wls) ((wls) & USART_LCR_WLS_MASK) +/** Set LCR:SBS for 1.5 or 2 stop bits, Clear for 1 stop bit */ +#define USART_LCR_SBS BIT2 +/** Enable parity checking */ +#define USART_LCR_PEN BIT3 +#define USART_LCR_PSELPEN_MASK (7) +#define USART_LCR_PSELPEN_SHIFT 3 +/** LCR:PSEL and LCR:PEN control parity */ +#define USART_LCR_PSELPEN(psel) (((psel) & USART_LCR_PSELPEN_MASK) << USART_LCR_PSELPEN_SHIFT) +/** Break Control: Enabling this bit forces TX to logic 0 */ +#define USART_LCR_BCON BIT6 +/**@}*/ + +/** @defgroup usart_lsr_bits Line Status Register bits +@{*/ +/** Receiver Data Ready */ +#define USART_LSR_RDR BIT0 +/** Overrun Error */ +#define USART_LSR_OE BIT1 +/** Parity Error */ +#define USART_LSR_PE BIT2 +/** Framing Error */ +#define USART_LSR_FE BIT3 +/** Break Interrupt */ +#define USART_LSR_BI BIT4 +/** Transmitter Holding Register Empty */ +#define USART_LSR_THRE BIT5 +/** Transmitter Empty */ +#define USART_LSR_TEMT BIT6 +/** Error in RX FIFO */ +#define USART_LSR_RXFE BIT7 +/**@}*/ + +/** TX FIFO depth */ +#define USART_TX_FIFO_DEPTH (16) +/** RX FIFO depth */ +#define USART_RX_FIFO_DETPH (16) + +/** Enable Enhanced Mode to use TX and RX FIFO trigger level interrupts */ +#define USART_EFR_ENMODE BIT4 + +/**@}*/ + +BEGIN_DECLS + +uint32_t usart_set_baudrate(uint32_t usart, uint32_t baud); +void usart_configure_lcr(uint32_t usart, uint8_t data_bits, uint8_t stop_bits, + uint8_t parity); +void usart_break_enable(uint32_t usart); +void usart_break_disable(uint32_t usart); +void usart_enhanced_enable(uint32_t usart); +void usart_enhanced_disable(uint32_t usart); +void usart_set_fifo_depth(uint32_t usart, uint8_t tx_depth, uint8_t rx_depth); +void usart_send(uint32_t usart, uint8_t data); +uint8_t usart_recv(uint32_t usart); +void usart_enable_rx_interrupt(uint32_t usart); +void usart_disable_rx_interrupt(uint32_t usart); +void usart_enable_tx_interrupt(uint32_t usart); +void usart_disable_tx_interrupt(uint32_t usart); +void usart_enable_rls_interrupt(uint32_t usart); +void usart_disable_rls_interrupt(uint32_t usart); +void usart_fifo_enable(uint32_t usart); +void usart_fifo_disable(uint32_t usart); +void usart_clear_tx_fifo(uint32_t usart); +void usart_clear_rx_fifo(uint32_t usart); + +END_DECLS + +#endif /* LIBOPENCM3_PAC55XX_USART_H_ */ diff --git a/lib/pac55xx/Makefile b/lib/pac55xx/Makefile index eee1dfdd..eac14dab 100644 --- a/lib/pac55xx/Makefile +++ b/lib/pac55xx/Makefile @@ -39,6 +39,7 @@ OBJS += can.o OBJS += ccs.o OBJS += gpio.o OBJS += memctl.o +OBJS += usart.o VPATH += ../cm3 diff --git a/lib/pac55xx/usart.c b/lib/pac55xx/usart.c new file mode 100644 index 00000000..61794fac --- /dev/null +++ b/lib/pac55xx/usart.c @@ -0,0 +1,200 @@ +/** + * @defgroup usart_api USART peripheral API + * @ingroup peripheral_apis + * @brief PAC55xxxx USART Driver + * @author @htmlonly © @endhtmlonly 2020 Kevin Stefanik + * @date February 25, 2020 + * + * This library supports the USART module in the PAC55xx SoC from Qorvo. + * + * LGPL License Terms @ref lgpl_license + */ +/* + * This file is part of the libopencm3 project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ +#include +#include + +/**@{*/ + +/** @brief USART Set Baudrate +The baud rate is computed assuming a peripheral clock of 150MHz. +@param[in] usart unsigned 32 bit. USART block register address base @ref usart_reg_base +@param[in] baud unsigned 32 bit. Baud rate specified in Hz. +@return Actual baud rate. +*/ +uint32_t usart_set_baudrate(uint32_t usart, uint32_t baud) { + /* TODO Assumes 150MHz PCLK. Update this to ccs_get_peripheral_freq() like on other platforms */ + const uint32_t pclk = 150000000; + uint32_t denom = (baud << 4); /* denominator is baud * 16. */ + uint32_t dlr = 0xFFFFu & ((pclk + denom / 2) / denom); + USART_DLR(usart) = dlr; + return pclk / (dlr << 4); /* Baud Rate = PCLK / (16 * UARTADLR) */ +} + +/** @brief USART Configure Line Control Register +This register sets the data bits, stop bits, and parity +@param[in] usart unsigned 32 bit. USART block register address base @ref usart_reg_base +@param[in] data_bits unsigned 8 bit. One of USART_DATABITS_5/6/7/8. +@param[in] stop_bits unsigned 8 bit. One of USART_STOPBITS_1/1P5/2. +@param[in] parity unsigned 8 bit. One of USART_PARITY_DISABLE/ODD/EVEN/FORCE1/FORCE0 +*/ +void usart_configure_lcr(uint32_t usart, uint8_t data_bits, uint8_t stop_bits, + uint8_t parity) { + USART_LCR(usart) = USART_LCR_WLS(data_bits) + | ((stop_bits==USART_STOPBITS_2) ? USART_LCR_SBS : 0) + | USART_LCR_PSELPEN(parity); +} + +/** @brief Enable Break Control +Enables break control bit that forces TX pin to logic low. +@param[in] usart unsigned 32 bit. USART block register address base @ref usart_reg_base +*/ +void usart_break_enable(uint32_t usart) { + USART_LCR(usart) |= USART_LCR_BCON; +} + +/** @brief Disable Break Control +Disables break control bit that forces TX pin to logic low. +@param[in] usart unsigned 32 bit. USART block register address base @ref usart_reg_base +*/ +void usart_break_disable(uint32_t usart) { + USART_LCR(usart) &= ~USART_LCR_BCON; +} + +/** @brief Enable Enhanced Mode +Enable enhanced mode to generate interrupts when FIFO thresholds in FCR are reached. +@param[in] usart unsigned 32 bit. USART block register address base @ref usart_reg_base +*/ +void usart_enhanced_enable(uint32_t usart) { + USART_EFR(usart) = USART_EFR_ENMODE; +} + +/** @brief Disable Enhanced Mode +Disable enhanced mode to generate interrupts when FIFO thresholds in FCR are reached. +@param[in] usart unsigned 32 bit. USART block register address base @ref usart_reg_base +*/ +void usart_enhanced_disable(uint32_t usart) { + USART_EFR(usart) &= ~USART_EFR_ENMODE; +} + +/** @brief Enable FIFOs +Enable both TX and RX FIFOs. This must be set before setting the trigger levels. +@param[in] usart unsigned 32 bit. USART block register address base @ref usart_reg_base +*/ +void usart_fifo_enable(uint32_t usart) { + USART_FCR(usart) |= USART_FCR_FIFOEN; +} + +/** @brief Disable FIFOs +Disable both TX and RX FIFOs. +@param[in] usart unsigned 32 bit. USART block register address base @ref usart_reg_base +*/ +void usart_fifo_disable(uint32_t usart) { + USART_FCR(usart) &= ~USART_FCR_FIFOEN; +} + +/** Set the TX and RX FIFO depth. This function also enables the FIFOs if not already. +@param[in] usart unsigned 32 bit. USART block register address base @ref usart_reg_base +@param[in] tx_depth unsigned 8 bit. One of USART_FIFO_TRIG_1/2/4/14CHAR. +@param[in] rx_depth unsigned 8 bit. One of USART_FIFO_TRIG_1/2/4/14CHAR. +*/ +void usart_set_fifo_depth(uint32_t usart, uint8_t tx_depth, uint8_t rx_depth) { + USART_FCR(usart) |= USART_FCR_FIFOEN; + USART_FCR(usart) = USART_FCR_TXTL(tx_depth) | USART_FCR_RXTL(rx_depth) | USART_FCR_FIFOEN; +} + +/** @brief Write byte to TX FIFO +@param[in] usart unsigned 32 bit. USART block register address base @ref usart_reg_base +@param[in] data unsigned 8 bit. Data to write to the TX FIFO. +*/ +void usart_send(uint32_t usart, uint8_t data) { + USART_THR(usart) = (uint32_t)data; +} + +/** @brief Read byte from the RX FIFO +@param[in] usart unsigned 32 bit. USART block register address base @ref usart_reg_base +@return Data read from the RX FIFO. +*/ +uint8_t usart_recv(uint32_t usart) { + return (uint8_t)USART_RBR(usart); +} + +/** @brief Enable RX Interrupts +Enable both the Receive Data Available and Character Timeout interrupts. +@param[in] usart unsigned 32 bit. USART block register address base @ref usart_reg_base +*/ +void usart_enable_rx_interrupt(uint32_t usart) { + USART_IER(usart) |= USART_IER_RBRIE; +} + +/** @brief Disable RX Interrupts +Disable both the Receive Data Available and Character Timeout interrupts. +@param[in] usart unsigned 32 bit. USART block register address base @ref usart_reg_base +*/ +void usart_disable_rx_interrupt(uint32_t usart) { + USART_IER(usart) &= ~USART_IER_RBRIE; +} + +/** @brief Enable TX Interrupt +Enable the TX Holding Register Empty interrupt. +@param[in] usart unsigned 32 bit. USART block register address base @ref usart_reg_base +*/ +void usart_enable_tx_interrupt(uint32_t usart) { + USART_IER(usart) |= USART_IER_THRIE; +} + +/** @brief Disable TX Interrupt +Disable the TX Holding Register Empty interrupt. +@param[in] usart unsigned 32 bit. USART block register address base @ref usart_reg_base +*/ +void usart_disable_tx_interrupt(uint32_t usart) { + USART_IER(usart) &= ~USART_IER_THRIE; +} + +/** @brief Enable RX Line Status Interrupt +Enable the RX Line Status interrupt. +@param[in] usart unsigned 32 bit. USART block register address base @ref usart_reg_base +*/ +void usart_enable_rls_interrupt(uint32_t usart) { + USART_IER(usart) |= USART_IER_RLSIE; +} + +/** @brief Disable RX Line Status Interrupt +Disable the RX Line Status interrupt. +@param[in] usart unsigned 32 bit. USART block register address base @ref usart_reg_base +*/ +void usart_disable_rls_interrupt(uint32_t usart) { + USART_IER(usart) &= ~USART_IER_RLSIE; +} + +/** @brief Clear the TX FIFO +Clears the TX FIFO. The bit is self-clearing. +@param[in] usart unsigned 32 bit. USART block register address base @ref usart_reg_base +*/ +void usart_clear_tx_fifo(uint32_t usart) { + USART_FCR(usart) |= USART_FCR_TXFIFORST; +} + +/** @brief Clear the RX FIFO +Clears the RX FIFO. The bit is self-clearing. +@param[in] usart unsigned 32 bit. USART block register address base @ref usart_reg_base +*/ +void usart_clear_rx_fifo(uint32_t usart) { + USART_FCR(usart) |= USART_FCR_RXFIFORST; +} + +/**@}*/