From 245761f894bb0495fa50f73e18828d1249017881 Mon Sep 17 00:00:00 2001 From: Kevin Stefanik Date: Thu, 13 Feb 2020 18:39:54 -0500 Subject: [PATCH] pac55xx: implemented CAN module interface for qorvo pac55xx. --- include/libopencm3/pac55xx/can.h | 307 +++++++++++++++++++++ lib/pac55xx/Makefile | 1 + lib/pac55xx/can.c | 460 +++++++++++++++++++++++++++++++ 3 files changed, 768 insertions(+) create mode 100644 include/libopencm3/pac55xx/can.h create mode 100644 lib/pac55xx/can.c diff --git a/include/libopencm3/pac55xx/can.h b/include/libopencm3/pac55xx/can.h new file mode 100644 index 00000000..2ef38d7d --- /dev/null +++ b/include/libopencm3/pac55xx/can.h @@ -0,0 +1,307 @@ +/** + * @brief CAN definitions for the Qorvo PAC55xx series of microcontrollers. + * + * @addtogroup PAC55xx_can CAN + * @ingroup PAC55xx_defines + * @author Kevin Stefanik + * LGPL License Terms @ref lgpl_license + * @date February 13, 2020 + * + * Definitions in this file come from the PAC55XX Family User Guide Rev 1.23 + * by Active-Semi dated November 19, 2019. + * + * Note: all memory-mapped writes must be performed using 32-bit registers. + * Any 8-bit memory-mapped registers below may only be used to read. + */ +/* + * 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_CAN_H_ +#define LIBOPENCM3_PAC55XX_CAN_H_ + +#include +#include + +/**@{*/ + +/** + * @defgroup can_isr_sr_cmr_mr CAN ISR/SR/CMR/MR Registers + * @{*/ +/** This is the 32-bit memory mapped read/write accessor for: + * - ISR - bits 31:24 - Interrupt Status/ACK Register RW, default 00h + * - SR - bits 23:16 - Status Register RO, default 00h + * - CMR - bits 15:8 - Command RW, default 00h + * - MR - bits 7:0 - Mode RW, default 04h + * When writing, be sure to use CAN_ISR_SR_CMR_MR_SET and CAN_ISR_SR_CMR_MR_CLEAR + * so as to avoid inadvertently Acknowledging an ISR bit. Writing '1' to one + * of the ISR bits when it is triggered/set will ACK/clear the bit. + */ +#define CAN_ISR_SR_CMR_MR(can_base) MMIO32((can_base) + 0x0000) +#define CAN_ISR_SR_CMR_MR_SET(can_base, bits) (CAN_ISR_SR_CMR_MR(can_base) = \ + (CAN_ISR_SR_CMR_MR(can_base) & 0x00FFFFFF) | (bits)) +#define CAN_ISR_SR_CMR_MR_CLEAR(can_base, bits) (CAN_ISR_SR_CMR_MR(can_base) = \ + (CAN_ISR_SR_CMR_MR(can_base) & 0x00FFFFFF) & ~(bits)) +/**@}*/ + +/** + * @defgroup can_btr01_rmc_imr CAN BTR1/BTR0/RMC/IMR Registers + * @{*/ +/** This is the 32-bit memory mapped read/write accessor for: + * - BTR1 - bits 31:24 - Bus Timing 1 Register RW, default 00h + * - BTR0 - bits 23:16 - Bus Timing 0 Register RW, default 00h + * - RMC - bits 15:8 - Receive Message Counter RO, default 00h + * - IMR - bits 7:0 - Interrupt Mask Register RW, default 00h + */ +#define CAN_BTR1_BTR0_RMC_IMR(can_base) MMIO32((can_base) + 0x0004) +/**@}*/ + +/** CAN Transmit Buffer Register RW, default 00000000h */ +#define CAN_TXBUF(can_base) MMIO32((can_base) + 0x0008) +/** CAN Receive Buffer Register RO, default 00000000h */ +#define CAN_RXBUF(can_base) MMIO32((can_base) + 0x000C) +/** CAN Acceptance Code Register RW, default 00000000h */ +#define CAN_ACR(can_base) MMIO32((can_base) + 0x0010) +/** CAN Acceptance Mask Register RW, default 00000000h */ +#define CAN_AMR(can_base) MMIO32((can_base) + 0x0014) + +/** + * @defgroup can_alc_txrxerr_ecc CAN ALC/TXERR/RXERR/ECC Registers + * @{*/ +#define CAN_ALC_TXERR_RXERR_ECC(can_base) MMIO32((can_base) + 0x0018) +/** CAN Error Code Capture Register RO, default 00h */ +#define CAN_ECC(can_base) (CAN_ALC_TXERR_RXERR_ECC(can_base) & 0xFF) +/** CAN RX Error Counter Register RO, default 00h */ +#define CAN_RXERR(can_base) ((CAN_ALC_TXERR_RXERR_ECC(can_base) >> 8) & 0xFF) +/** CAN TX Error Counter Register RO, default 00h */ +#define CAN_TXERR(can_base) ((CAN_ALC_TXERR_RXERR_ECC(can_base) >> 16) & 0xFF) +/** CAN Arbitration Lost Code Capture Register RO, default 00h */ +#define CAN_ALC(can_base) ((CAN_ALC_TXERR_RXERR_ECC(can_base) >> 24) & 0xFF) +/**@}*/ + +/** CAN Mode Register bit definitions. This register controls high level modes of the CAN peripheral. + * @defgroup can_mr_bits CAN Mode Register + * @{*/ +/** AFM: Acceptance Filter Mode */ +#define CAN_MR_AFM BIT0 +/** LOM: Listen only mode */ +#define CAN_MR_LOM BIT1 +/** RM: Reset Mode */ +#define CAN_MR_RM BIT2 +/**@}*/ + +/** CAN Command Register. This register commands the CAN peripheral to either transmit or abort. + * @defgroup can_cmr_bits CAN Command Register + * @{*/ +/** AT: Abort transmission */ +#define CAN_CMR_AT BIT9 +/** TR: Transmit Request */ +#define CAN_CMR_TR BIT10 +/**@}*/ + +/** CAN Status Register. This register provides read-only status of the CAN peripheral. + * @defgroup can_sr_bits CAN Status Register + * @{*/ +/** BS: Bus Off Status */ +#define CAN_SR_BS BIT16 +/** ES: Error Status */ +#define CAN_SR_ES BIT17 +/** TS: Transmit Status */ +#define CAN_SR_TS BIT18 +/** RS: Receive Status */ +#define CAN_SR_RS BIT19 +/** TBS: Transmit Buffer Status */ +#define CAN_SR_TBS BIT21 +/** DSO: Data Overrun Status */ +#define CAN_SR_DSO BIT22 +/** RBS: Receive Buffer Status */ +#define CAN_SR_RBS BIT23 +/**@}*/ + +/** CAN Interrupt Status Register bit definitions. + * - 1: interrupt triggered + * - 0: no interrupt + * - Writing a 1 to a triggered interrupt clears the bit. + * @defgroup can_isr_bits CAN Interrupt Status Register + * @{*/ +/** DOI: Data Overflow Interrupt */ +#define CAN_ISR_DOI BIT24 +/** BEI: Bus Error Interrupt */ +#define CAN_ISR_BEI BIT25 +/** TI: Transmit Interrupt */ +#define CAN_ISR_TI BIT26 +/** RI: Receive Interrupt */ +#define CAN_ISR_RI BIT27 +/** EPI: Error Passive Interrupt */ +#define CAN_ISR_EPI BIT28 +/** EWI: Error Warning Interrupt */ +#define CAN_ISR_EWI BIT29 +/** ALI: Arbitration Lost Interrupt */ +#define CAN_ISR_ALI BIT30 +/** This is a helper to acknowledge an ISR */ +#define CAN_ISR_ACKNOWLEDGE(can_base, isr) CAN_ISR_SR_CMR_MR_SET(can_base, ((isr) & 0x7F000000)) +/**@}*/ + +/** CAN Interrupt Mask Register bit definitions. + * 0: disables/masks interrupt + * 1: enables interrupt + * @defgroup can_imr_bits CAN Mask Register + * @{*/ +/** DOIM: DOI Interrupt Mask */ +#define CAN_IMR_DOIM BIT0 +/** BEIM: BEI Interrupt Mask */ +#define CAN_IMR_BEIM BIT1 +/** TIM: TI Interrupt Mask */ +#define CAN_IMR_TIM BIT2 +/** RIM: RI Interrupt Mask */ +#define CAN_IMR_RIM BIT3 +/** EPIM: EPI Interrupt Mask */ +#define CAN_IMR_EPIM BIT4 +/** EWIM: EWI Interrupt Mask */ +#define CAN_IMR_EWIM BIT5 +/** ALIM: ALI Interrupt Mask */ +#define CAN_IMR_ALIM BIT6 +/**@}*/ + +/** CAN Receive Message Counter Register bit definitions. + * @defgroup can_rmc_bits CAN Receive Message Counter Register. + * @{*/ +#define CAN_RMC(can_base) ((CAN_BTR1_BTR0_RMC_IMR(can_base) >> 8) & 0x1F) +/**@}*/ + +/** CAN Bus Timing 0 Register bit definitions. + * @defgroup can_btr0_bits CAN Bus Timing 0 Register. + * @{*/ +#define CAN_BTR0_BRP_MASK (0x3F) +#define CAN_BTR0_BRP_SHIFT 16 +#define CAN_BTR0_BRP(val) (((val) & CAN_BTR0_BRP_MASK) << CAN_BTR0_BRP_SHIFT) +#define CAN_BTR0_SJW_MASK (0x03) +#define CAN_BTR0_SJW_SHIFT 22 +#define CAN_BTR0_SJW(val) (((val) & CAN_BTR0_SJW_MASK) << CAN_BTR0_SJW_SHIFT) +/**@}*/ + +/** CAN Bus Timing 1 Register bit definitions. + * @defgroup can_btr1_bits CAN Bus Timing 1 Register + * @{*/ +#define CAN_BTR1_TSEG1_MASK (0x0F) +#define CAN_BTR1_TSEG1_SHIFT 24 +#define CAN_BTR1_TSEG1(val) (((val) & CAN_BTR1_TSEG1_MASK) << CAN_BTR1_TSEG1_SHIFT) + +#define CAN_BTR1_TSEG2_MASK (0x07) +#define CAN_BTR1_TSEG2_SHIFT 28 +#define CAN_BTR1_TSEG2(val) (((val) & CAN_BTR1_TSEG2_MASK) << CAN_BTR1_TSEG2_SHIFT) +#define CAN_BTR1_SAM BIT31 +/**@}*/ + +/** CAN Error Code Capture Register bit definitions. + * @defgroup can_ecc_bits CAN Error Code Capture Register + * @{*/ +/** BER: Bit error ocurred */ +#define CAN_ECC_BER BIT0 +/** STFER: Stuff error occurred */ +#define CAN_ECC_STFER BIT1 +/** CRCER: CRC error occurred */ +#define CAN_ECC_CRCER BIT2 +/** FRMER: Form error occurred */ +#define CAN_ECC_FRMER BIT3 +/** ACKER: ACK error occurred */ +#define CAN_ECC_ACKER BIT4 +/** EDIR: Direction of transfer 0:TX, 1:RX */ +#define CAN_ECC_EDIR BIT5 +/** TXWRN: set when CAN_TXERR >= 96 */ +#define CAN_ECC_TXWRN BIT6 +/** RXWRN: set when CAN_RXERR >= 96 */ +#define CAN_ECC_RXWRN BIT7 +/**@}*/ + +/** CAN Acceptance Code/Mask Register. This is used for filtering messages. + * Mask value of 1 ignores the bit. Mask value of 0 checks the bit. + * @defgroup can_acr_bits CAN Acceptance Code Register + * @{*/ +#define CAN_ACR_DUAL_DB_UPPER 0x000F0000U /* 19:16 */ +#define CAN_ACR_DUAL_DB_LOWER 0x0000000FU /* 3:0 */ +#define CAN_ACR_DUAL_ID1 0xFFE00000U /* 31:21 */ +#define CAN_ACR_DUAL_ID2 0x0000FFE0U /* 15:5 */ +#define CAN_ACR_DUAL_RTR1 0x00100000U /* 20 */ +#define CAN_ACR_DUAL_RTR2 0x00000010U /* 4 */ + +#define CAN_ACR_SINGLE_STD_ID 0xFFE00000U /* 31:21 */ +#define CAN_ACR_SINGLE_STD_RTR 0x00100000U /* 20 */ +#define CAN_ACR_SINGLE_STD_DB1 0x0000FF00U /* 15:8 */ +#define CAN_ACR_SINGLE_STD_DB2 0x000000FFU /* 7:0 */ + +#define CAN_ACR_SINGLE_EXT_ID 0xFFFFFFF8U /* 31:3 */ +#define CAN_ACR_SINGLE_EXT_RTR 0x00000004U /* 2 */ +/**@}*/ + +/** + * @defgroup can_bit_masks CAN Miscellaneous Bit Masks + * @{*/ +#define CAN_BITS_2_0 (0x07) +#define CAN_BITS_3_0 (0x0F) +#define CAN_BITS_4_0 (0x1F) +#define CAN_BITS_7_3 (0xF8) +#define CAN_BITS_10_3 (0x07F8) +#define CAN_BITS_12_5 (0x00001FE0U) +#define CAN_BITS_20_13 (0x001FE000U) +#define CAN_BITS_28_21 (0x1FE00000U) +#define CAN_BITS_15_8 (0x0000FF00U) +#define CAN_BITS_23_16 (0x00FF0000U) +#define CAN_BITS_31_24 (0xFF000000U) +#define CAN_BITS_23_21 (0x00E00000U) +/**@}*/ + +/**@}*/ + +BEGIN_DECLS +/** CAN Application Programming Interface. + * @addtogroup can_api CAN Peripheral API + * @ingroup peripheral_apis + @{*/ +void can_enable(uint32_t canport); +void can_disable(uint32_t canport); +void can_init(uint32_t canport, bool listen_only, uint32_t sjw, + uint32_t tseg1, uint32_t tseg2, + bool sam3, uint32_t brp); +void can_filter_clear(uint32_t canport); +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); +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); +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); +void can_filter_single_ext(uint32_t canport, uint32_t id, uint32_t id_mask); +void can_filter_single_ext_rtr(uint32_t canport, uint32_t id, uint32_t id_mask); +void can_enable_irq(uint32_t canport, uint8_t imr); +void can_disable_irq(uint32_t canport, uint8_t imr); + +bool can_transmit_std(uint32_t canport, uint32_t id, bool rtr, uint8_t length, + const uint8_t *data); +bool can_transmit_ext(uint32_t canport, uint32_t id, bool rtr, uint8_t length, + const uint8_t *data); +void can_abort_transmit(uint32_t canport); + +void can_receive(uint32_t canport, uint32_t *id, bool *ext, bool *rtr, uint8_t *length, + uint8_t *data); +/**@}*/ + +END_DECLS + +#endif /* LIBOPENCM3_PAC55XX_CAN_H_ */ diff --git a/lib/pac55xx/Makefile b/lib/pac55xx/Makefile index 36e2fdb2..463340ba 100644 --- a/lib/pac55xx/Makefile +++ b/lib/pac55xx/Makefile @@ -35,6 +35,7 @@ TGT_CFLAGS += $(DEBUG_FLAGS) TGT_CFLAGS += $(STANDARD_FLAGS) ARFLAGS = rcs +OBJS += can.o OBJS += gpio.o VPATH += ../cm3 diff --git a/lib/pac55xx/can.c b/lib/pac55xx/can.c new file mode 100644 index 00000000..467e8192 --- /dev/null +++ b/lib/pac55xx/can.c @@ -0,0 +1,460 @@ +/** + * @addtogroup can_api CAN Peripheral API + * @ingroup peripheral_apis + * @brief PAC55xxxx CAN Driver + * @author @htmlonly © @endhtmlonly 2020 Kevin Stefanik + * @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 . + */ +#include +#include + +/*---------------------------------------------------------------------------*/ +/** @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; +}