pac55xx: implemented CAN module interface for qorvo pac55xx.
This commit is contained in:
committed by
Karl Palsson
parent
cb83273416
commit
245761f894
307
include/libopencm3/pac55xx/can.h
Normal file
307
include/libopencm3/pac55xx/can.h
Normal file
@@ -0,0 +1,307 @@
|
||||
/**
|
||||
* @brief CAN definitions for the Qorvo PAC55xx series of microcontrollers.
|
||||
*
|
||||
* @addtogroup PAC55xx_can CAN
|
||||
* @ingroup PAC55xx_defines
|
||||
* @author Kevin Stefanik <kevin@allocor.tech>
|
||||
* 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 <kevin@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/>.
|
||||
*/
|
||||
#ifndef LIBOPENCM3_PAC55XX_CAN_H_
|
||||
#define LIBOPENCM3_PAC55XX_CAN_H_
|
||||
|
||||
#include <libopencm3/pac55xx/memorymap.h>
|
||||
#include <libopencm3/cm3/common.h>
|
||||
|
||||
/**@{*/
|
||||
|
||||
/**
|
||||
* @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_ */
|
||||
@@ -35,6 +35,7 @@ TGT_CFLAGS += $(DEBUG_FLAGS)
|
||||
TGT_CFLAGS += $(STANDARD_FLAGS)
|
||||
ARFLAGS = rcs
|
||||
|
||||
OBJS += can.o
|
||||
OBJS += gpio.o
|
||||
|
||||
VPATH += ../cm3
|
||||
|
||||
460
lib/pac55xx/can.c
Normal file
460
lib/pac55xx/can.c
Normal file
@@ -0,0 +1,460 @@
|
||||
/**
|
||||
* @addtogroup can_api CAN Peripheral API
|
||||
* @ingroup peripheral_apis
|
||||
* @brief <b>PAC55xxxx CAN Driver</b>
|
||||
* @author @htmlonly © @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;
|
||||
}
|
||||
Reference in New Issue
Block a user