subrepo:
  subdir:   "libopencm3"
  merged:   "f5813a54"
upstream:
  origin:   "https://github.com/libopencm3/libopencm3"
  branch:   "master"
  commit:   "f5813a54"
git-subrepo:
  version:  "0.4.3"
  origin:   "???"
  commit:   "???"
This commit is contained in:
2021-09-30 16:34:10 +03:00
parent 1a441e5806
commit 244fdbc35c
1125 changed files with 185440 additions and 0 deletions

View File

@@ -0,0 +1,47 @@
##
## This file is part of the libopencm3 project.
##
## Copyright (C) 2019 Brian Viele <vielster@allocor.tech>
##
## 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 <http://www.gnu.org/licenses/>.
##
## The PAC55xx by Qorvo (formerly ActiveSemi) is a Cortex-M4F based device
## which is specialized for motor control and PSC applications.
LIBNAME = libopencm3_pac55xx
SRCLIBDIR ?= ..
FP_FLAGS ?= -mfloat-abi=hard -mfpu=fpv4-sp-d16
CC = $(PREFIX)gcc
AR = $(PREFIX)ar
TGT_CFLAGS = -Os \
-Wall -Wextra -Wimplicit-function-declaration \
-Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \
-Wundef -Wshadow \
-I../../include -fno-common \
-mcpu=cortex-m4 -mthumb $(FP_FLAGS) -Wstrict-prototypes \
-ffunction-sections -fdata-sections -MD -DPAC55XX
TGT_CFLAGS += $(DEBUG_FLAGS)
TGT_CFLAGS += $(STANDARD_FLAGS)
ARFLAGS = rcs
OBJS += can.o
OBJS += ccs.o
OBJS += gpio.o
OBJS += memctl.o
OBJS += usart.o
VPATH += ../cm3
include ../Makefile.include

View File

@@ -0,0 +1,460 @@
/**
* @addtogroup can_api CAN Peripheral API
* @ingroup peripheral_apis
* @brief <b>PAC55xxxx CAN Driver</b>
* @author @htmlonly &copy; @endhtmlonly 2020 Kevin Stefanik <kevin@allocor.tech>
* @date February 13, 2020
*
* This library supports the CAN module in the PAC55xx SoC from Qorvo.
*
* Note: Acceptance Code Mask Register values of 1 indicate the filter is to
* ignore the bit. However, standard CAN driver APIs use a positive logic for the
* mask. The implementations in this file inverts masks as appropriate to
* the mask to make this more portable/intuitive.
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/pac55xx/can.h>
#include <libopencm3/cm3/common.h>
/*---------------------------------------------------------------------------*/
/** @brief CAN Enable
Enable the CAN peripheral and its associated FIFOs/counters/interrupts.
@param[in] canport Unsigned int32. CAN block register base address.
*/
void can_enable(uint32_t canport) {
CAN_ISR_SR_CMR_MR_CLEAR(canport, CAN_MR_RM);
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Disable
Disable the CAN peripheral and all associated FIFOs/counters/interrupts.
@param[in] canport Unsigned int32. CAN block register base address.
*/
void can_disable(uint32_t canport) {
CAN_ISR_SR_CMR_MR_SET(canport, CAN_MR_RM);
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Init
Initialize the selected CAN peripheral block.
@param[in] canport Unsigned int32. CAN block register base address.
@param[in] listen_only bool. Enable listen only mode.
@param[in] sjw Unsigned int32. Resynchronization time quanta jump width.
@param[in] tseg1 Unsigned int32. Time segment 1 time quanta width.
@param[in] tseg2 Unsigned int32. Time segment 2 time quanta width.
@param[in] sam3 bool. Use best 2 out of 3 samples.
@param[in] brp Unsigned int32. Baud rate prescaler.
*/
void can_init(uint32_t canport, bool listen_only, uint32_t sjw,
uint32_t tseg1, uint32_t tseg2,
bool sam3, uint32_t brp) {
/* Put CAN module in reset and clear out ISR/SR/CMR/MR */
CAN_ISR_SR_CMR_MR(canport) = CAN_MR_RM;
/* Setup single filter scheme */
CAN_ISR_SR_CMR_MR_SET(canport, CAN_MR_AFM);
/* enable listen-only mode */
if (listen_only) {
CAN_ISR_SR_CMR_MR_SET(canport, CAN_MR_LOM);
}
/* Set Baud Rate Prescaler, sync jump width, tseg1/2 */
CAN_BTR1_BTR0_RMC_IMR(canport) = CAN_BTR0_BRP(brp) | CAN_BTR0_SJW(sjw)
| CAN_BTR1_TSEG1(tseg1) | CAN_BTR1_TSEG2(tseg2);
if (sam3) {
/* enable sample bus 3 times */
CAN_BTR1_BTR0_RMC_IMR(canport) |= CAN_BTR1_SAM;
}
/* Filter: Accept incoming messages with any identifier */
CAN_ACR(canport) = 0;
/* Note: when mask bits are 1, the bits are ignored */
CAN_AMR(canport) = 0xFFFFFFFFu;
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Filter Clear
Clear the message filters to receive all messages.
@param[in] canport Unsigned int32. CAN block register base address.
*/
void can_filter_clear(uint32_t canport) {
/* Filter: Accept incoming messages with any identifier */
CAN_ACR(canport) = 0;
/* Note: when mask bits are 1, the bits are ignored */
CAN_AMR(canport) = 0xFFFFFFFFu;
/* Setup single filter scheme */
CAN_ISR_SR_CMR_MR_SET(canport, CAN_MR_AFM);
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Dual Filter Standard Frame
Notes:
- Acceptance Code Mask Register values of 1 indicate the filter is to ignore
the bit. However standard CAN driver APIs use a positive logic for the mask.
So this function inverts the mask to make this more portable/intuitive.
- Register definition byte order is opposite what is shown in Rev 1.23 of
the PAC55XX Family User Guide. Since both data and ID values cross byte
boundaries, the bswap32 function is used to correct for the discrepancy.
@param[in] canport Unsigned int32. CAN block register base address.
@param[in] id1 Unsigned int32. CAN ID 1. Only bits 10:0 are used.
@param[in] id1_mask Unsigned int32. CAN ID 1 mask. Only bits 10:0 are used.
@param[in] id2 Unsigned int32. CAN ID 2. Only bits 10:0 are used.
@param[in] id2_mask Unsigned int32. CAN ID 2 mask. Only bits 10:0 are used.
@param[in] db bool. CAN first data byte value.
@param[in] db_mask bool. CAN first data byte mask.
*/
void can_filter_dual(uint32_t canport, uint32_t id1, uint32_t id1_mask,
uint32_t id2, uint32_t id2_mask,
uint8_t db, uint8_t db_mask) {
/* set value */
uint32_t word = ((id1 << 21) & CAN_ACR_DUAL_ID1)
| ((id2 << 5) & CAN_ACR_DUAL_ID2)
| ((db << 12) & CAN_ACR_DUAL_DB_UPPER) | (db & CAN_ACR_DUAL_DB_LOWER);
CAN_ACR(canport) = __builtin_bswap32(word);
/* set mask */
word = ((~id1_mask << 21) & CAN_ACR_DUAL_ID1)
| ((~id2_mask << 5) & CAN_ACR_DUAL_ID2)
| ((~db_mask << 12) & CAN_ACR_DUAL_DB_UPPER)
| ((~db_mask) & CAN_ACR_DUAL_DB_LOWER)
| CAN_ACR_DUAL_RTR1 | CAN_ACR_DUAL_RTR2;
CAN_AMR(canport) = __builtin_bswap32(word);
/* 0: dual filter */
CAN_ISR_SR_CMR_MR_CLEAR(canport, CAN_MR_AFM);
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Filter Single Standard Frame
Notes:
- Acceptance Code Mask Register values of 1 indicate the filter is to ignore
the bit. However standard CAN driver APIs use a positive logic for the mask.
So this function inverts the mask to make this more portable/intuitive.
- Register definition byte order is opposite what is shown in Rev 1.23 of
the PAC55XX Family User Guide. Since both data and ID values cross byte
boundaries, the bswap32 function is used to correct for the discrepancy.
@param[in] canport Unsigned int32. CAN block register base address.
@param[in] id Unsigned int32. CAN ID. Only bits 10:0 are used.
@param[in] id_mask Unsigned int32. CAN ID mask. Only bits 10:0 are used.
@param[in] db1 bool. CAN first data byte value.
@param[in] db1_mask bool. CAN first data byte mask.
@param[in] db2 bool. CAN second data byte value.
@param[in] db2_mask bool. CAN second data byte mask.
*/
void can_filter_single_std(uint32_t canport, uint32_t id, uint32_t id_mask,
uint8_t db1, uint8_t db1_mask,
uint8_t db2, uint8_t db2_mask) {
/* set value */
uint32_t word = ((id << 21) & CAN_ACR_SINGLE_STD_ID)
| ((db1 << 8) & CAN_ACR_SINGLE_STD_DB1)
| ((db2 << 0) & CAN_ACR_SINGLE_STD_DB2);
CAN_ACR(canport) = __builtin_bswap32(word);
/* set mask */
word = ((~id_mask << 21) & CAN_ACR_SINGLE_STD_ID)
| CAN_ACR_SINGLE_STD_RTR | CAN_ACR_DUAL_DB_UPPER
| ((~db1_mask << 8) & CAN_ACR_SINGLE_STD_DB1)
| ((~db2_mask << 0) & CAN_ACR_SINGLE_STD_DB2);
CAN_AMR(canport) = __builtin_bswap32(word);
/* 1: single filter */
CAN_ISR_SR_CMR_MR_SET(canport, CAN_MR_AFM);
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Filter Single Standard Frame w/RTR set
Notes:
- Acceptance Code Mask Register values of 1 indicate the filter is to ignore
the bit. However standard CAN driver APIs use a positive logic for the mask.
So this function inverts the mask to make this more portable/intuitive.
- Register definition byte order is opposite what is shown in Rev 1.23 of
the PAC55XX Family User Guide. Since both data and ID values cross byte
boundaries, the bswap32 function is used to correct for the discrepancy.
@param[in] canport Unsigned int32. CAN block register base address.
@param[in] id Unsigned int32. CAN ID. Only bits 10:0 are used.
@param[in] id_mask Unsigned int32. CAN ID mask. Only bits 10:0 are used.
@param[in] db1 bool. CAN first data byte value.
@param[in] db1_mask bool. CAN first data byte mask.
@param[in] db2 bool. CAN second data byte value.
@param[in] db2_mask bool. CAN second data byte mask.
*/
void can_filter_single_std_rtr(uint32_t canport, uint32_t id, uint32_t id_mask,
uint8_t db1, uint8_t db1_mask,
uint8_t db2, uint8_t db2_mask) {
/* set value */
uint32_t word = ((id << 21) & CAN_ACR_SINGLE_STD_ID)
| CAN_ACR_SINGLE_STD_RTR | ((db1 << 8) & CAN_ACR_SINGLE_STD_DB1)
| ((db2 << 0) & CAN_ACR_SINGLE_STD_DB2);
CAN_ACR(canport) = __builtin_bswap32(word);
/* set mask */
word = ((~id_mask << 21) & CAN_ACR_SINGLE_STD_ID)
| ((~db1_mask << 8) & CAN_ACR_SINGLE_STD_DB1)
| ((~db2_mask << 0) & CAN_ACR_SINGLE_STD_DB2);
CAN_AMR(canport) = __builtin_bswap32(word);
/* 1: single filter */
CAN_ISR_SR_CMR_MR_SET(canport, CAN_MR_AFM);
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Filter Single Extended Frame
Notes:
- Acceptance Code Mask Register values of 1 indicate the filter is to ignore
the bit. However standard CAN driver APIs use a positive logic for the mask.
So this function inverts the mask to make this more portable/intuitive.
- Register definition byte order is opposite what is shown in Rev 1.23 of
the PAC55XX Family User Guide. Since both data and ID values cross byte
boundaries, the bswap32 function is used to correct for the discrepancy.
@param[in] canport Unsigned int32. CAN block register base address.
@param[in] id Unsigned int32. CAN ID. Only bits 28:0 are used.
@param[in] id_mask Unsigned int32. CAN ID mask. Only bits 28:0 are used.
*/
void can_filter_single_ext(uint32_t canport, uint32_t id, uint32_t id_mask) {
/* set value */
uint32_t word = ((id << 3) & CAN_ACR_SINGLE_EXT_ID);
CAN_ACR(canport) = __builtin_bswap32(word);
/* set mask */
word = ((~id_mask << 3) & CAN_ACR_SINGLE_EXT_ID) | CAN_ACR_SINGLE_EXT_RTR;
CAN_AMR(canport) = __builtin_bswap32(word);
/* 1: single filter */
CAN_ISR_SR_CMR_MR_SET(canport, CAN_MR_AFM);
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Filter Single Extended Frame w/RTR set
Notes:
- Acceptance Code Mask Register values of 1 indicate the filter is to ignore
the bit. However standard CAN driver APIs use a positive logic for the mask.
So this function inverts the mask to make this more portable/intuitive.
- Register definition byte order is opposite what is shown in Rev 1.23 of
the PAC55XX Family User Guide. Since both data and ID values cross byte
boundaries, the bswap32 function is used to correct for the discrepancy.
@param[in] canport Unsigned int32. CAN block register base address.
@param[in] id Unsigned int32. CAN ID. Only bits 28:0 are used.
@param[in] id_mask Unsigned int32. CAN ID mask. Only bits 28:0 are used.
*/
void can_filter_single_ext_rtr(uint32_t canport, uint32_t id, uint32_t id_mask) {
/* set value */
uint32_t word = ((id << 3) & CAN_ACR_SINGLE_EXT_ID) | CAN_ACR_SINGLE_EXT_RTR;
CAN_ACR(canport) = __builtin_bswap32(word);
/* set mask */
word = ((~id_mask << 3) & CAN_ACR_SINGLE_EXT_ID);
CAN_AMR(canport) = __builtin_bswap32(word);
/* 1: single filter */
CAN_ISR_SR_CMR_MR_SET(canport, CAN_MR_AFM);
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Enable IRQ
@param[in] canport Unsigned int32. CAN block register base address.
@param[in] irq Unsigned int8. IRQ bit(s).
*/
void can_enable_irq(uint32_t canport, uint8_t irq) {
/* set to 1 (not masked) to enable */
CAN_BTR1_BTR0_RMC_IMR(canport) |= (uint32_t)irq;
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Disable IRQ
@param[in] canport Unsigned int32. CAN block register base address.
@param[in] irq Unsigned int8. IRQ bit(s).
*/
void can_disable_irq(uint32_t canport, uint8_t irq) {
/* set to 0 (masked) to disable */
CAN_BTR1_BTR0_RMC_IMR(canport) &= ~(uint32_t)irq;
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Transmit Standard Frame
@param[in] canport Unsigned int32. CAN block register base address.
@param[in] id Unsigned int32. Message ID bits 10:0 used.
@param[in] rtr bool. Remote Request bit value.
@param[in] length Unsigned int8. Message payload length.
@param[in] data Unsigned int8[]. Message payload data.
@returns true if able to transmit, false otherwise.
*/
bool can_transmit_std(uint32_t canport, uint32_t id, bool rtr, uint8_t length,
const uint8_t *data) {
/* if TBS is 0, then not ready to transmit */
if ((CAN_ISR_SR_CMR_MR(canport) & CAN_SR_TBS) == 0) {
return false;
}
uint32_t word = (length & CAN_BITS_3_0)
| (rtr ? BIT6 : 0) /* DLC/RTR/FF ==> 7:0 */
| ((id & CAN_BITS_10_3) << 5) /* ID 10:3 ==> 15:8 */
| ((id & CAN_BITS_2_0) << 21) /* ID 2:0 ==> 23:21 */
| (((length > 0) ? data[0] : 0) << 24);
CAN_TXBUF(canport) = word;
if (length > 1) {
word = (data[1] << 0) | (data[2] << 8)
| (data[3] << 16) | (data[4] << 24);
CAN_TXBUF(canport) = word;
}
if (length > 5) {
word = (data[5] << 0) | (data[6] << 8) | (data[7] << 16);
CAN_TXBUF(canport) = word;
}
/* Request transmit */
CAN_ISR_SR_CMR_MR_SET(canport, CAN_CMR_TR);
return true;
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Transmit Extended Frame
@param[in] canport Unsigned int32. CAN block register base address.
@param[in] id Unsigned int32. Message ID bits 28:0 used.
@param[in] rtr bool. Remote Request bit value.
@param[in] length Unsigned int8. Message payload length, 0-8.
@param[in] data Unsigned int8[]. Message payload data.
@returns true if able to transmit, false otherwise.
*/
bool can_transmit_ext(uint32_t canport, uint32_t id, bool rtr, uint8_t length,
const uint8_t *data) {
/* if TBS is 0, then not ready to transmit */
if ((CAN_ISR_SR_CMR_MR(canport) & CAN_SR_TBS) == 0) {
return false;
}
uint32_t word = (length & CAN_BITS_3_0)
| (rtr ? BIT6 : 0) | BIT7 /* DLC/RTR/FF ==> 7:0 */
| ((id & CAN_BITS_28_21) >> 13) /* ID 28:21 ==> 15:8 */
| ((id & CAN_BITS_20_13) << 3) /* ID 20:13 ==> 23:16 */
| ((id & CAN_BITS_12_5) << 19); /* ID 12:5 ==> 31:24 */
CAN_TXBUF(canport) = word; /* write first 32-bit word to FIFO */
word = ((id & CAN_BITS_4_0) << 3); /* ID 4:0 ==> 7:3 */
if (length > 0) {
word |= (data[0] << 8) | (data[1] << 16) | (data[2] << 24);
}
/* for extended frame, always write second 32-bit word to FIFO */
CAN_TXBUF(canport) = word;
if (length > 3) {
word = (data[3] << 0) | (data[4] << 8)
| (data[5] << 16) | (data[6] << 24);
CAN_TXBUF(canport) = word;
}
if (length > 7) {
word = data[7];
CAN_TXBUF(canport) = word;
}
/* Request transmit */
CAN_ISR_SR_CMR_MR_SET(canport, CAN_CMR_TR);
return true;
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Abort Transmit
Aborts the current transmission.
@param[in] canport Unsigned int32. CAN block register base address.
*/
void can_abort_transmit(uint32_t canport) {
CAN_ISR_SR_CMR_MR_SET(canport, CAN_CMR_AT);
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Receive Message
If no data is in the RX buffer, id and length are set to 0.
@param[in] canport Unsigned int32. CAN block register base address.
@param[out] id Unsigned int32 pointer. Message ID.
@param[out] ext bool pointer. The message ID is extended.
@param[out] rtr bool pointer. Remote Request bit value.
@param[out] length Unsigned int8 pointer. Length of message payload.
@param[out] data Unsigned int8[]. Message payload data, min length 8.
*/
void can_receive(uint32_t canport, uint32_t *id, bool *ext, bool *rtr, uint8_t *length,
uint8_t *data) {
if ((CAN_ISR_SR_CMR_MR(canport) & CAN_ISR_RI) == 0 || CAN_RMC(canport) == 0) {
*id = 0;
*length = 0;
return; /* empty RX FIFO */
}
uint32_t can_buffer = CAN_RXBUF(canport); /* read 32-bit word */
uint8_t rx_length = can_buffer & CAN_BITS_3_0;
bool is_extended = can_buffer & BIT7;
if (ext) {
*ext = is_extended;
}
if (rtr) {
*rtr = can_buffer & BIT6;
}
if (length) {
*length = rx_length;
}
uint32_t _id;
if (is_extended) {
/* Parse extended message ID from RXBUF */
_id = ((can_buffer & CAN_BITS_15_8) << 13) /* ID 28:21 <== 15:8 */
| ((can_buffer & CAN_BITS_23_16) >> 3) /* ID 20:13 <== 23:16 */
| ((can_buffer & CAN_BITS_31_24) >> 19); /* ID 12:5 <== 31:24 */
can_buffer = CAN_RXBUF(canport);
_id |= ((can_buffer & CAN_BITS_7_3) >> 3); /* ID 4:0 <== 7:3 */
/* Parse extended message data from RXBUF */
data[0] = can_buffer >> 8;
data[1] = can_buffer >> 16;
data[2] = can_buffer >> 24;
if (rx_length > 3) {
can_buffer = CAN_RXBUF(canport);
data[3] = can_buffer;
data[4] = can_buffer >> 8;
data[5] = can_buffer >> 16;
data[6] = can_buffer >> 24;
}
if (rx_length > 7) {
can_buffer = CAN_RXBUF(canport);
data[7] = can_buffer;
}
} else {
/* Parse standard message ID from RXBUF */
_id = ((can_buffer & CAN_BITS_15_8) >> 5) /* ID 10:3 <== 15:8 */
| ((can_buffer & CAN_BITS_23_21) >> 21); /* ID 2:0 <== 23:21 */
/* Parse standard message data from RXBUF */
data[0] = can_buffer >> 24;
if (rx_length > 1) {
can_buffer = CAN_RXBUF(canport);
data[1] = can_buffer;
data[2] = can_buffer >> 8;
data[3] = can_buffer >> 16;
data[4] = can_buffer >> 24;
if (rx_length > 5) {
/* buffer contains data5,data6,data7 */
can_buffer = CAN_RXBUF(canport);
data[5] = can_buffer;
data[6] = can_buffer >> 8;
data[7] = can_buffer >> 16;
}
}
}
if (id) {
*id = _id;
}
/*
* Write 1 to acknowledge/clear the interrupt
* Note: ensure not to let the other interrupt masks be written as 1, so as
* to avoid acknowledging them.
* Note: CAN_ISR_RI is already high, but we still write '1' to it to clear it.
*/
CAN_ISR_ACKNOWLEDGE(canport, CAN_ISR_RI);
return;
}

View File

@@ -0,0 +1,261 @@
/**
* @brief <b>PAC55xxxx CCS Driver</b>
* @author @htmlonly &copy; @endhtmlonly 2020 Kevin Stefanik <kevin@allocor.tech>
* @date March 7, 2020
*
* This library supports the CCS 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 <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/pac55xx/ccs.h>
#include <libopencm3/pac55xx/memorymap.h>
#include <libopencm3/pac55xx/memctl.h>
#include <libopencm3/cm3/assert.h>
static volatile uint32_t ccs_extclk_frequency = 0;
static volatile uint32_t ccs_frclk_frequency = CCS_ROSC_FREQ;
static volatile uint32_t ccs_sclk_frequency = CCS_ROSC_FREQ;
static volatile uint32_t ccs_pll_clk_frequency = 0;
static volatile uint32_t ccs_hclk_frequency = CCS_ROSC_FREQ;
static volatile uint32_t ccs_aclk_frequency = CCS_ROSC_FREQ;
static volatile uint32_t ccs_pclk_frequency = CCS_ROSC_FREQ;
void ccs_frclkmux_select(uint32_t sel) {
CCSCTL = (CCSCTL & ~CCS_CTL_FRCLKMUXSEL(CCS_CTL_FRCLKMUXSEL_MASK)) | CCS_CTL_FRCLKMUXSEL(sel);
}
void ccs_rosc_enable(void) {
CCSCTL |= CCS_CTL_ROSCEN;
}
void ccs_rosc_disable(void) {
CCSCTL &= ~CCS_CTL_ROSCEN;
}
void ccs_sclkmux_select_frclk(void) {
CCSCTL &= ~CCS_CTL_SCLKMUXSEL;
}
void ccs_sclkmux_select_pllclk(void) {
CCSCTL |= CCS_CTL_SCLKMUXSEL;
}
void ccs_clkfail_enable(void) {
CCSCTL |= CCS_CTL_CLKFAILEN;
}
void ccs_clkfail_disable(void) {
CCSCTL &= ~CCS_CTL_CLKFAILEN;
}
void ccs_clkfailmux_select_frclk(void) {
CCSCTL &= ~CCS_CTL_CLKFAILMUXSEL;
}
void ccs_clkfailmux_select_pllclk(void) {
CCSCTL |= CCS_CTL_CLKFAILMUXSEL;
}
void ccs_ldo_enable(void) {
CCSCTL |= CCS_CTL_LDOEN;
}
void ccs_ldo_disable(void) {
CCSCTL &= ~CCS_CTL_LDOEN;
}
void ccs_pclk_enable(void) {
CCSCTL |= CCS_CTL_PCLKEN;
}
void ccs_pclk_disable(void) {
CCSCTL &= ~CCS_CTL_PCLKEN;
}
void ccs_aclk_enable(void) {
CCSCTL |= CCS_CTL_ACLKEN;
}
void ccs_aclk_disable(void) {
CCSCTL &= ~CCS_CTL_ACLKEN;
}
void ccs_adcclk_enable(void) {
CCSCTL |= CCS_CTL_ADCCLKEN;
}
void ccs_adcclk_disable(void) {
CCSCTL &= ~CCS_CTL_ADCCLKEN;
}
void ccs_stclk_sleep_enable(void) {
CCSCTL |= CCS_CTL_STCLKSLPEN;
}
void ccs_stclk_sleep_disable(void) {
CCSCTL &= ~CCS_CTL_STCLKSLPEN;
}
void ccs_set_pclkdiv(uint32_t div) {
CCSCTL = (CCSCTL & ~CCS_CTL_PCLKDIV(8)) | CCS_CTL_PCLKDIV(div);
}
void ccs_set_aclkdiv(uint32_t div) {
CCSCTL = (CCSCTL & ~CCS_CTL_ACLKDIV(8)) | CCS_CTL_ACLKDIV(div);
}
void ccs_set_hclkdiv(uint32_t div) {
CCSCTL = (CCSCTL & ~CCS_CTL_HCLKDIV(8)) | CCS_CTL_HCLKDIV(div);
}
void ccs_pll_enable(void) {
CCSPLLCTL |= CCS_PLLCTL_PLLEN;
}
void ccs_pll_disable(void) {
CCSPLLCTL &= ~CCS_PLLCTL_PLLEN;
}
bool ccs_pll_locked(void) {
return (CCSPLLCTL & CCS_PLLCTL_PLLLOCK) == CCS_PLLCTL_PLLLOCK;
}
void ccs_pll_bypass_enable(void) {
CCSPLLCTL |= CCS_PLLCTL_PLLBP;
}
void ccs_pll_bypass_disable(void) {
CCSPLLCTL &= ~CCS_PLLCTL_PLLBP;
}
void ccs_pll_set_outdiv(uint32_t div) {
CCSPLLCTL = (CCSPLLCTL & ~CCS_PLLCTL_PLLOUTDIV(CCS_PLLCTL_PLLOUTDIV_MASK)) | CCS_PLLCTL_PLLOUTDIV(div);
}
void ccs_pll_set_indiv(uint32_t div) {
if (div <= 15 && div >= 1) {
CCSPLLCTL = (CCSPLLCTL & ~CCS_PLLCTL_PLLINDIV(CCS_PLLCTL_PLLINDIV_MASK)) | CCS_PLLCTL_PLLINDIV(div);
} else {
cm3_assert_not_reached();
}
}
void ccs_pll_set_fbdiv(uint32_t div) {
if (div <= 16383 && div >= 4) {
CCSPLLCTL = (CCSPLLCTL & ~CCS_PLLCTL_PLLFBDIV(CCS_PLLCTL_PLLFBDIV_MASK)) | CCS_PLLCTL_PLLFBDIV(div);
} else {
cm3_assert_not_reached();
}
}
void css_pll_config_enable(uint32_t indiv, uint32_t fbdiv, uint32_t outdiv) {
ccs_pll_disable();
ccs_pll_set_fbdiv(fbdiv);
ccs_pll_set_outdiv(outdiv);
ccs_pll_set_indiv(indiv);
ccs_pll_enable();
while (!ccs_pll_locked()) ; /* Wait for PLL lock ~500us */
}
uint32_t ccs_get_peripheral_clk_freq(uint32_t periph, uint32_t select) {
switch (periph) {
case ADC_BASE:
return ccs_sclk_frequency;
case I2C_BASE: /* fall through */
case USARTA_BASE: /* fall through */
case USARTB_BASE: /* fall through */
case USARTC_BASE: /* fall through */
case USARTD_BASE: /* fall through */
case CAN_BASE: /* fall through */
case GPTIMERA_BASE: /* fall through */
case GPTIMERB_BASE:
return ccs_pclk_frequency;
case TIMERA_BASE: /* fall through */
case TIMERB_BASE: /* fall through */
case TIMERC_BASE: /* fall through */
case TIMERD_BASE:
return (select == 0) ? ccs_pclk_frequency : ccs_aclk_frequency;
case MEMCTL_BASE:
return (select == 0) ? CCS_ROSC_FREQ : ccs_hclk_frequency;
case WWDT_BASE:
return (select == 0) ? ccs_frclk_frequency : CCS_ROSC_FREQ;
case RTC_BASE:
return ccs_frclk_frequency;
case CRC_BASE: /* fall through */
case SYS_TICK_BASE:
return ccs_hclk_frequency;
default:
cm3_assert_not_reached();
}
}
void ccs_reset_clocks(void) {
CCSCTL = CCS_CTL_LDOEN | CCS_CTL_ROSCEN |
CCS_CTL_PCLKEN | CCS_CTL_ACLKEN |
CCS_CTL_ADCCLKEN | CCS_CTL_STCLKSLPEN;
CCSPLLCTL = 0;
}
void ccs_configure_clocks(const struct ccs_clk_config *config) {
MEMCTL_FLASHLOCK = MEMCTL_FLASHLOCK_ALLOW_MEMCTL_WRITE;
ccs_reset_clocks(); /* set safe defaults */
ccs_frclkmux_select(CCS_CTL_FRCLKMUXSEL_ROSC);
ccs_sclkmux_select_frclk();
memctl_flash_select_roscclk();
if (config->mem_enable_cache) {
memctl_flash_cache_enable();
} else {
memctl_flash_cache_disable();
}
ccs_frclkmux_select(CCS_CTL_FRCLKMUXSEL_CLKREF); /* switch frclk to 4MHz CLKREF */
switch (config->frclk_source) {
case CCS_CTL_FRCLKMUXSEL_ROSC:
ccs_frclkmux_select(CCS_CTL_FRCLKMUXSEL_ROSC);
ccs_frclk_frequency = CCS_ROSC_FREQ;
break;
case CCS_CTL_FRCLKMUXSEL_CLKREF:
ccs_frclkmux_select(CCS_CTL_FRCLKMUXSEL_CLKREF);
ccs_frclk_frequency = CCS_CLKREF_FREQ;
break;
case CCS_CTL_FRCLKMUXSEL_EXTCLK:
if (config->extclk_frequency > CCS_EXTCLK_MAX_FREQ
|| config->extclk_frequency == 0) {
cm3_assert_not_reached();
}
ccs_frclkmux_select(CCS_CTL_FRCLKMUXSEL_EXTCLK);
ccs_frclk_frequency = ccs_extclk_frequency = config->extclk_frequency;
break;
default:
cm3_assert_not_reached();
}
if (config->sclk_source == CCS_CTL_SCLKMUXSEL_FRCLK) {
ccs_set_hclkdiv(config->hclkdiv);
ccs_set_aclkdiv(config->aclkdiv);
memctl_flash_set_wstate(config->mem_wstate);
ccs_sclkmux_select_frclk();
memctl_flash_set_mclkdiv(config->mem_mclkdiv);
if (config->mem_mclksel == false) {
memctl_flash_select_roscclk();
} else {
memctl_flash_select_mclk();
}
ccs_sclk_frequency = ccs_frclk_frequency;
} else if (config->sclk_source == CCS_CTL_SCLKMUXSEL_PLLCLK) {
css_pll_config_enable(config->pll_indiv, config->pll_fbdiv, config->pll_outdiv);
ccs_set_hclkdiv(config->hclkdiv);
ccs_set_aclkdiv(config->aclkdiv);
memctl_flash_set_wstate(config->mem_wstate);
ccs_sclkmux_select_pllclk();
memctl_flash_set_mclkdiv(config->mem_mclkdiv);
if (config->mem_mclksel == false) {
memctl_flash_select_roscclk();
} else {
memctl_flash_select_mclk();
}
ccs_pll_clk_frequency = ((ccs_frclk_frequency * config->pll_fbdiv) / config->pll_indiv) >> config->pll_outdiv;
ccs_sclk_frequency = ccs_pll_clk_frequency;
} else {
cm3_assert_not_reached();
}
ccs_set_pclkdiv(config->pclkdiv);
ccs_pclk_enable();
ccs_aclk_enable();
ccs_adcclk_enable();
ccs_stclk_sleep_disable();
ccs_hclk_frequency = ccs_sclk_frequency / config->hclkdiv;
ccs_aclk_frequency = ccs_sclk_frequency / config->aclkdiv;
ccs_pclk_frequency = ccs_hclk_frequency / config->pclkdiv;
MEMCTL_FLASHLOCK = MEMCTL_FLASHLOCK_CLEAR;
}

View File

@@ -0,0 +1,163 @@
/**
* @ingroup PAC55xx_gpio
* @brief <b>PAC55xxxx General-Purpose Input/Output (GPIO)</b>
* @author @htmlonly &copy; @endhtmlonly 2019 Brian Viele <vielster@allocor.tech>
* @date December 1, 2019
*
* This library supports the GPIO 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 <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/pac55xx/gpio.h>
static uint32_t get_ccs_port_base(uint32_t gpioport) {
switch (gpioport) {
case GPIOA:
return CCS_PORTA;
case GPIOB:
return CCS_PORTB;
case GPIOC:
return CCS_PORTC;
case GPIOD:
return CCS_PORTD;
case GPIOE:
return CCS_PORTE;
case GPIOF:
return CCS_PORTF;
case GPIOG:
return CCS_PORTG;
default:
return 0U;
}
}
void gpio_mode_setup(uint32_t gpioport, gpio_mode_t mode,
ccs_pull_updown_t pull_up_down, uint16_t gpios) {
/* Read the current value of the register. */
uint32_t reg = GPIO_MODER(gpioport);
uint32_t port = get_ccs_port_base(gpioport);
/* Loop through only set bits, utilize built-ins for optimized assembly. */
int ffs = __builtin_ffs(gpios);
while (ffs) {
const int pin = ffs - 1;
const int bit = (1 << pin);
/* Update the cached mode value by clearing then setting values. */
reg &= ~GPIO_MODER_MASK_PIN(pin);
reg |= GPIO_MODER_MODE(pin, mode);
/* Set the pinmux configurations for the pull-up / pull-down. */
if (pull_up_down == CCS_IO_PULL_UP) {
CCS_PDENR(port) &= ~bit;
CCS_PUENR(port) |= bit;
} else if (pull_up_down == CCS_IO_PULL_DOWN) {
CCS_PUENR(port) &= ~bit;
CCS_PDENR(port) |= bit;
} else {
CCS_PDENR(port) &= ~bit;
CCS_PUENR(port) &= ~bit;
}
gpios ^= bit; /* Clear the bit we just serviced. */
ffs = __builtin_ffs(gpios);
}
GPIO_MODER(gpioport) = reg;
}
void gpio_set_outmask(uint32_t gpioport, bool enable, uint16_t gpios) {
uint32_t reg = GPIO_OUTMASKR(gpioport);
if (enable) {
reg |= gpios;
} else {
reg &= ~gpios;
}
GPIO_OUTMASKR(gpioport) = reg;
}
void gpio_set(uint32_t gpioport, uint16_t gpios) {
GPIO_DOSETR(gpioport) = gpios;
}
void gpio_clear(uint32_t gpioport, uint16_t gpios) {
GPIO_DOCLEARR(gpioport) = gpios;
}
uint16_t gpio_get(uint32_t gpioport, uint16_t gpios) {
return GPIO_INR(gpioport) & gpios;
}
void gpio_set_af(uint32_t gpioport, ccs_muxsel_func_t muxsel, uint16_t gpios) {
uint32_t port = get_ccs_port_base(gpioport);
/* Update each of the pin configs. */
uint32_t reg = CCS_MUXSELR(port);
int ffs = __builtin_ffs(gpios);
while (ffs) {
const int pin = ffs - 1;
reg &= ~CCS_MUXSELR_MASK_PIN(pin);
reg |= CCS_MUXSELR_VAL(pin, muxsel);
/* Set the pinmux configurations for the pull-up / pull-down. */
gpios ^= (1 << pin); /* Clear the bit we just serviced. */
ffs = __builtin_ffs(gpios);
}
CCS_MUXSELR(port) = reg;
}
void gpio_set_output_options(uint32_t gpioport, ccs_drive_strength_t strength,
uint16_t gpios) {
uint32_t port = get_ccs_port_base(gpioport);
/* Update each of the pin configs. */
uint32_t reg = CCS_DSR(port);
int ffs = __builtin_ffs(gpios);
while (ffs) {
const int pin = ffs - 1;
reg &= ~CCS_DSR_MASK_PIN(pin);
reg |= CCS_DSR_DS_VAL(pin, strength);
/* Set the pinmux configurations for the pull-up / pull-down. */
gpios ^= (1 << pin); /* Clear the bit we just serviced. */
ffs = __builtin_ffs(gpios);
}
CCS_DSR(port) = reg;
}
void gpio_set_schmidt_trigger(uint32_t gpioport, bool enable, uint16_t gpios) {
uint32_t port = get_ccs_port_base(gpioport);
/* Update each of the pin configs. */
uint32_t reg = CCS_DSR(port);
int ffs = __builtin_ffs(gpios);
while (ffs) {
const int pin = ffs - 1;
if (enable) {
reg |= CCS_DSR_SCHMIDT_PIN(pin);
} else {
reg &= ~CCS_DSR_SCHMIDT_PIN(pin);
}
/* Set the pinmux configurations for the pull-up / pull-down. */
gpios ^= (1 << pin); /* Clear the bit we just serviced. */
ffs = __builtin_ffs(gpios);
}
CCS_DSR(port) = reg;
}

View File

@@ -0,0 +1,78 @@
/**
* @brief <b>PAC55xxxx Memory Controller Driver</b>
* @author @htmlonly &copy; @endhtmlonly 2020 Kevin Stefanik <kevin@allocor.tech>
* @date April 1, 2020
*
* This library supports the Memory Controller 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 <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/pac55xx/memctl.h>
void memctl_flash_set_wstate(uint32_t wstate) {
MEMCTL_MEMCTLR = (MEMCTL_MEMCTLR & ~MEMCTL_MEMCTLR_WSTATE(MEMCTL_MEMCTLR_WSTATE_MASK)) | MEMCTL_MEMCTLR_WSTATE(wstate);
}
void memctl_flash_set_mclkdiv(uint32_t div) {
MEMCTL_MEMCTLR = (MEMCTL_MEMCTLR & ~MEMCTL_MEMCTLR_MCLKDIV(16)) | MEMCTL_MEMCTLR_MCLKDIV(div);
}
void memctl_flash_reset_write_buffer(void) {
MEMCTL_MEMCTLR = (MEMCTL_MEMCTLR & ~MEMCTL_MEMCTLR_WRITEWORDCNT(MEMCTL_MEMCTLR_WRITEWORDCNT_MASK));
}
void memctl_flash_standby_mode_enable(void) {
MEMCTL_MEMCTLR |= MEMCTL_MEMCTLR_STBY;
}
void memctl_flash_standby_mode_disable(void) {
MEMCTL_MEMCTLR &= ~MEMCTL_MEMCTLR_STBY;
}
void memctl_flash_cache_enable(void) {
MEMCTL_MEMCTLR &= ~MEMCTL_MEMCTLR_CACHEDIS;
}
void memctl_flash_cache_disable(void) {
MEMCTL_MEMCTLR |= MEMCTL_MEMCTLR_CACHEDIS;
}
void memctl_flash_select_roscclk(void) {
MEMCTL_MEMCTLR &= ~MEMCTL_MEMCTLR_MCLKSEL;
}
void memctl_flash_select_mclk(void) {
MEMCTL_MEMCTLR |= MEMCTL_MEMCTLR_MCLKSEL;
}
void memctl_sram_ecc_enable(void) {
MEMCTL_MEMCTLR &= ~MEMCTL_MEMCTLR_ECCDIS;
}
void memctl_sram_ecc_disable(void) {
MEMCTL_MEMCTLR |= MEMCTL_MEMCTLR_ECCDIS;
}
void memctl_sram_ecc_single_bit_interrupt_enable(void) {
MEMCTL_MEMCTLR |= MEMCTL_MEMCTLR_SEIE;
}
void memctl_sram_ecc_single_bit_interrupt_disable(void) {
MEMCTL_MEMCTLR &= ~MEMCTL_MEMCTLR_SEIE;
}
void memctl_sram_ecc_dual_bit_interrupt_enable(void) {
MEMCTL_MEMCTLR |= MEMCTL_MEMCTLR_DEIE;
}
void memctl_sram_ecc_dual_bit_interrupt_disable(void) {
MEMCTL_MEMCTLR &= ~MEMCTL_MEMCTLR_DEIE;
}
void memctl_invaddr_interrupt_enable(void) {
MEMCTL_MEMCTLR |= MEMCTL_MEMCTLR_INVADDRIE;
}
void memctl_invaddr_interrupt_disable(void) {
MEMCTL_MEMCTLR &= ~MEMCTL_MEMCTLR_INVADDRIE;
}

View File

@@ -0,0 +1,200 @@
/**
* @defgroup usart_api USART peripheral API
* @ingroup peripheral_apis
* @brief <b>PAC55xxxx USART Driver</b>
* @author @htmlonly &copy; @endhtmlonly 2020 Kevin Stefanik <kevin@allocor.tech>
* @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 <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/pac55xx/usart.h>
#include <libopencm3/cm3/common.h>
/**@{*/
/** @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;
}
/**@}*/

View File

@@ -0,0 +1,24 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2019 Brian Viele <vielster@allocor.tech>
*
* 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 <http://www.gnu.org/licenses/>.
*/
/* Standard Cortex-M4F initialization of FPU. */
static void pre_main(void) {
/* Enable FPU */
SCB_CPACR |= SCB_CPACR_FULL * (SCB_CPACR_CP10 | SCB_CPACR_CP11);
}