/* ---------------------------------------------------------------------------- | |
* SAM Software Package License | |
* ---------------------------------------------------------------------------- | |
* Copyright (c) 2015, Atmel Corporation | |
* | |
* All rights reserved. | |
* | |
* Redistribution and use in source and binary forms, with or without | |
* modification, are permitted provided that the following conditions are met: | |
* | |
* - Redistributions of source code must retain the above copyright notice, | |
* this list of conditions and the disclaimer below. | |
* | |
* Atmel's name may not be used to endorse or promote products derived from | |
* this software without specific prior written permission. | |
* | |
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR | |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE | |
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, | |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, | |
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, | |
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
* ---------------------------------------------------------------------------- | |
*/ | |
/** | |
* \file | |
* | |
* \section Purpose | |
* | |
* Controller Area Network with Flexible Data-rate. | |
* Interface for configuring and using the MCAN peripheral. | |
*/ | |
#ifndef _MCAN_H_ | |
#define _MCAN_H_ | |
/*---------------------------------------------------------------------------- | |
* Headers | |
*----------------------------------------------------------------------------*/ | |
#include "chip.h" | |
#include <assert.h> | |
#ifdef __cplusplus | |
extern "C" { | |
#endif | |
/*---------------------------------------------------------------------------- | |
* Definitions | |
*----------------------------------------------------------------------------*/ | |
enum mcan_can_mode | |
{ | |
/* ISO 11898-1 CAN mode */ | |
MCAN_MODE_CAN, | |
/* Long CAN FD frame. | |
* - TX and RX payloads up to 64 bytes. | |
* - Slow transmitter: TX frames are sent at constant bit rate. | |
* - Fast receiver: both constant-rate (slow) and dual-rate (fast) | |
* RX frames are supported and received. */ | |
MCAN_MODE_EXT_LEN_CONST_RATE, | |
/* Long and fast CAN FD frame. | |
* - TX and RX payloads up to 64 bytes. | |
* - Fast transmitter: control, data and CRC fields are transmitted at a | |
* higher bit rate. | |
* - Fast receiver. */ | |
MCAN_MODE_EXT_LEN_DUAL_RATE, | |
}; | |
/* Flag signalling a standard (11-bit) message identifiers */ | |
#define CAN_STD_MSG_ID (0x0u << 30) | |
/* Flag to be bitwise or'ed to extended (29-bit) message identifiers */ | |
#define CAN_EXT_MSG_ID (0x1u << 30) | |
struct mcan_msg_info | |
{ | |
uint32_t id; | |
uint32_t timestamp; | |
uint8_t *data; | |
uint8_t full_len; | |
uint8_t data_len; | |
}; | |
struct mcan_config | |
{ | |
uint32_t id; /* peripheral ID (ID_xxx) */ | |
Mcan *regs; /* set of MCAN hardware registers */ | |
uint32_t *msg_ram; /* base address of the Message RAM to be | |
* assigned to this MCAN instance */ | |
uint8_t array_size_filt_std; /* # of 11-bit Message ID Rx Filters */ | |
uint8_t array_size_filt_ext; /* # of 29-bit Message ID Rx Filters */ | |
uint8_t fifo_size_rx0; /* # of Rx Buffers in Rx FIFO 0 */ | |
uint8_t fifo_size_rx1; /* # of Rx Buffers in Rx FIFO 1 */ | |
uint8_t array_size_rx; /* # of dedicated Rx Buffers */ | |
uint8_t fifo_size_tx_evt; /* # of Tx Event Elements in the Tx Event | |
* FIFO */ | |
uint8_t array_size_tx; /* # of dedicated Tx Buffers */ | |
uint8_t fifo_size_tx; /* # of Tx Buffers in the Tx FIFO or Tx | |
* Queue */ | |
uint8_t buf_size_rx_fifo0; /* size of the data field in each Rx | |
* Buffer of Rx FIFO 0, in bytes */ | |
uint8_t buf_size_rx_fifo1; /* size of the data field in each Rx | |
* Buffer of Rx FIFO 1, in bytes */ | |
uint8_t buf_size_rx; /* size of the data field in each | |
* dedicated Rx Buffer, in bytes */ | |
uint8_t buf_size_tx; /* size of the data field in each Tx | |
* Buffer, in bytes. Applies to all Tx | |
* Buffers, dedicated and in Tx FIFO / | |
* Queue. */ | |
uint32_t bit_rate; /* requested CAN bit rate in CAN mode, | |
* in bps */ | |
uint16_t quanta_before_sp; /* duration of the time segment before the | |
* sample point (Sync_Seg + Prop_Seg + | |
* Phase_Seg1), while in CAN mode, | |
* expressed in CAN time quanta */ | |
uint8_t quanta_after_sp; /* duration of the time segment after the | |
* sample point (Phase_Seg2), while in CAN | |
* mode, expressed in CAN time quanta */ | |
uint32_t bit_rate_fd; /* requested CAN bit rate in fast CAN FD | |
* mode, in bps */ | |
uint8_t quanta_before_sp_fd; /* duration of the time segment before the | |
* sample point (Sync_Seg + Prop_Seg + | |
* Phase_Seg1), while in fast CAN FD mode, | |
* expressed in CAN time quanta */ | |
uint8_t quanta_after_sp_fd; /* duration of the time segment after the | |
* sample point (Phase_Seg2), while in | |
* fast CAN FD mode, expressed in CAN time | |
* quanta */ | |
uint8_t quanta_sync_jump; /* duration of a (re)synchronization jump, | |
* while in CAN mode, expressed in CAN | |
* time quanta */ | |
uint8_t quanta_sync_jump_fd; /* duration of a (re)synchronization jump, | |
* while in fast CAN FD mode, expressed in | |
* CAN time quanta */ | |
}; | |
/* This structure is private to the MCAN Driver. | |
* Allocate it but ignore its members. */ | |
struct mcan_set | |
{ | |
struct mcan_config cfg; | |
uint32_t *ram_filt_std; | |
uint32_t *ram_filt_ext; | |
uint32_t *ram_fifo_rx0; | |
uint32_t *ram_fifo_rx1; | |
uint32_t *ram_array_rx; | |
uint32_t *ram_fifo_tx_evt; | |
uint32_t *ram_array_tx; | |
}; | |
/*---------------------------------------------------------------------------- | |
* Exported symbols | |
*----------------------------------------------------------------------------*/ | |
static inline bool mcan_is_enabled(const struct mcan_set *set) | |
{ | |
Mcan *mcan = set->cfg.regs; | |
return ((mcan->MCAN_CCCR & MCAN_CCCR_INIT) == MCAN_CCCR_INIT_DISABLED); | |
} | |
static inline bool mcan_is_extended_id(uint32_t msg_id) | |
{ | |
return msg_id & CAN_EXT_MSG_ID ? true : false; | |
} | |
static inline uint32_t mcan_get_id(uint32_t msg_id) | |
{ | |
return msg_id & CAN_EXT_MSG_ID ? msg_id & 0x1fffffff : msg_id & 0x7ff; | |
} | |
static inline bool mcan_is_tx_complete(const struct mcan_set *set) | |
{ | |
Mcan *mcan = set->cfg.regs; | |
return mcan->MCAN_IR & MCAN_IR_TC ? true : false; | |
} | |
static inline void mcan_clear_tx_flag(const struct mcan_set *set) | |
{ | |
Mcan *mcan = set->cfg.regs; | |
mcan->MCAN_IR = MCAN_IR_TC; | |
} | |
static inline bool mcan_rx_array_data(const struct mcan_set *set) | |
{ | |
Mcan *mcan = set->cfg.regs; | |
return mcan->MCAN_IR & MCAN_IR_DRX ? true : false; | |
} | |
static inline void mcan_clear_rx_array_flag(const struct mcan_set *set) | |
{ | |
Mcan *mcan = set->cfg.regs; | |
mcan->MCAN_IR = MCAN_IR_DRX; | |
} | |
static inline bool mcan_rx_fifo_data(const struct mcan_set *set, uint8_t fifo) | |
{ | |
assert(fifo == 0 || fifo == 1); | |
Mcan *mcan = set->cfg.regs; | |
return mcan->MCAN_IR & (fifo ? MCAN_IR_RF1N : MCAN_IR_RF0N) ? true | |
: false; | |
} | |
static inline void mcan_clear_rx_fifo_flag(const struct mcan_set *set, | |
uint8_t fifo) | |
{ | |
assert(fifo == 0 || fifo == 1); | |
Mcan *mcan = set->cfg.regs; | |
mcan->MCAN_IR = fifo ? MCAN_IR_RF1N : MCAN_IR_RF0N; | |
} | |
/** | |
* \brief Compute the size of the Message RAM to be assigned to the MCAN. | |
* \param cfg MCAN configuration to be considered. Only integer size parameters | |
* need to be configured. The other parameters can be left blank at this stage. | |
* \param size address where the required size of the Message RAM will be | |
* written, expressed in (32-bit) words. | |
* \return true if successful, false if a parameter is set to an unsupported | |
* value. | |
*/ | |
bool mcan_configure_msg_ram(const struct mcan_config *cfg, uint32_t *size); | |
/** | |
* \brief Initialize the MCAN hardware for the given peripheral. | |
* Default: Non-FD, ISO 11898-1 CAN mode; mixed mode TX Buffer + FIFO. | |
* \param set Pointer to uninitialized driver instance data. | |
* \param cfg MCAN configuration to be used. | |
* \return true if successful, false if a parameter is set to an unsupported | |
* value. | |
*/ | |
bool mcan_initialize(struct mcan_set *set, const struct mcan_config *cfg); | |
/** | |
* \brief Unlock the peripheral configuration so it can be altered. | |
* Prerequisite: the peripheral shall be disabled. In case the device has been | |
* enabled, call mcan_disable. | |
* \param set Pointer to driver instance data. | |
*/ | |
void mcan_reconfigure(struct mcan_set *set); | |
/** | |
* \brief Select either the legacy ISO 11898-1 CAN mode or the CAN-FD mode, | |
* along with the FD variant in the latter case. | |
* Should be called further to mcan_initialize() or mcan_reconfigure(), before | |
* mcan_enable(). | |
* \param set Pointer to driver instance data. | |
* \param mode CAN mode, and FD variant in case of FD mode. | |
*/ | |
void mcan_set_mode(struct mcan_set *set, enum mcan_can_mode mode); | |
/** | |
* \brief Query the current CAN mode. | |
* \param set Pointer to driver instance data. | |
* \return Currently selected CAN mode, and FD variant in case of CAN FD mode. | |
*/ | |
enum mcan_can_mode mcan_get_mode(const struct mcan_set *set); | |
/** | |
* \brief Select the TX Queue mode, disable TX FIFO mode. | |
* INIT must be set - so this should be called between mcan_initialize() and | |
* mcan_enable(). | |
* \param set Pointer to driver instance data. | |
*/ | |
void mcan_set_tx_queue_mode(struct mcan_set *set); | |
/** | |
* \brief Initialize the MCAN in loop back mode. | |
* INIT must be set - so this should be called between mcan_initialize() and | |
* mcan_enable(). | |
* \param set Pointer to driver instance data. | |
*/ | |
void mcan_init_loopback(struct mcan_set *set); | |
/** | |
* \brief Enable the peripheral I/O stage. Synchronize with the bus. | |
* INIT must be set - so this should be called after mcan_initialize(). | |
* \param set Pointer to driver instance data. | |
*/ | |
void mcan_enable(struct mcan_set *set); | |
/** | |
* \brief Disable the peripheral I/O stage. Go Bus_Off. | |
* \note Subsequent operations may include reconfiguring the peripheral | |
* (mcan_reconfigure) and/or re-enabling it (mcan_enable). | |
* \param set Pointer to driver instance data. | |
*/ | |
void mcan_disable(struct mcan_set *set); | |
/** | |
* \brief Turn the loop-back mode ON. | |
* \note TEST must be set in MCAN_CCCR. This mode should have been enabled upon | |
* initialization. | |
* \param set Pointer to driver instance data. | |
*/ | |
void mcan_loopback_on(struct mcan_set *set); | |
/** | |
* \brief Turn the loop-back mode OFF. | |
* \param set Pointer to driver instance data. | |
*/ | |
void mcan_loopback_off(struct mcan_set *set); | |
/** | |
* \brief Select either the m_can_int0 or the m_can_int1 interrupt line. | |
* Also, enable the 'Message stored to Dedicated Receive Buffer' specific | |
* interrupt. | |
* \param set Pointer to driver instance data. | |
* \param int_line The interrupt line to be enabled: | |
* 0 -> m_can_int0 | |
* 1 -> m_can_int1. | |
*/ | |
void mcan_enable_rx_array_flag(struct mcan_set *set, uint8_t int_line); | |
/** | |
* \brief Configure a Dedicated TX Buffer. | |
* \param set Pointer to driver instance data. | |
* \param buf_idx Index of the dedicated transmit buffer to be used. | |
* \param id Message ID. | |
* \param len Data length, in bytes. | |
* \return Address of data byte 0, part of the transmit buffer. | |
*/ | |
uint8_t * mcan_prepare_tx_buffer(struct mcan_set *set, uint8_t buf_idx, | |
uint32_t id, uint8_t len); | |
/** | |
* \brief Start the transmission of a Dedicated TX Buffer. | |
* \param set Pointer to driver instance data. | |
* \param buf_idx Index of the dedicated transmit buffer to be used. | |
*/ | |
void mcan_send_tx_buffer(struct mcan_set *set, uint8_t buf_idx); | |
/** | |
* \brief Append the provided message to the TX FIFO, or to the TX Queue, | |
* depending on whether mcan_set_tx_queue_mode() has been invoked or not. | |
* \param set Pointer to driver instance data. | |
* \param id Message ID. | |
* \param len Data length, in bytes. | |
* \param data Pointer to data. | |
* \return Index of the assigned transmit buffer, part of the FIFO / queue. | |
* Or 0xff if the TX FIFO / queue was full, or an error occurred. | |
*/ | |
uint8_t mcan_enqueue_outgoing_msg(struct mcan_set *set, uint32_t id, | |
uint8_t len, const uint8_t *data); | |
/** | |
* \brief Check if message transmitted from the specified TX Buffer, either | |
* dedicated or part of the TX FIFO or TX Queue. | |
* \param set Pointer to driver instance data. | |
* \param buf_idx Index of the transmit buffer to be queried. | |
* \return true if the message has been successfully transmitted, false | |
* otherwise. | |
*/ | |
bool mcan_is_buffer_sent(const struct mcan_set *set, uint8_t buf_idx); | |
/** | |
* \brief Configure RX buffer filter. | |
* \param set Pointer to driver instance data. | |
* \param buf_idx Index of the receive buffer to be used as the recipient. | |
* \param filter Index of the filter to be configured. | |
* \param id Single message identifier. Incoming message need to match exactly | |
* to be accepted. | |
*/ | |
void mcan_filter_single_id(struct mcan_set *set, uint8_t buf_idx, | |
uint8_t filter, uint32_t id); | |
/** | |
* \brief Configure classic RX filter. | |
* The classic filters direct the accepted messages to a FIFO, and include both | |
* an ID and an ID mask. | |
* \param set Pointer to driver instance data. | |
* \param fifo Index of the RX FIFO to be used as the recipient. | |
* \param filter Index of the filter to be configured. | |
* \param id Message identifier. | |
* \param mask Message identifier mask to be matched. | |
*/ | |
void mcan_filter_id_mask(struct mcan_set *set, uint8_t fifo, uint8_t filter, | |
uint32_t id, uint32_t mask); | |
/** | |
* \brief Check whether some data has been received into the specified RX | |
* Buffer. | |
* \param set Pointer to driver instance data. | |
* \param buf_idx Index of the receive buffer to be queried. | |
* \return true if the receive buffer is flagged as containing an unfetched | |
* frame, and false otherwise. | |
*/ | |
bool mcan_rx_buffer_data(const struct mcan_set *set, uint8_t buf_idx); | |
/** | |
* \brief Get RX buffer. | |
* \param set Pointer to driver instance data. | |
* \param buf_idx Index of the receive buffer to be read. | |
* \param msg Address where the CAN message properties will be written. | |
* The msg->data and msg->data_len parameters shall be initialized prior to | |
* calling this function. Message contents will be copied to msg->data if | |
* msg->data is not null and if msg->data_len is large enough. | |
*/ | |
void mcan_read_rx_buffer(struct mcan_set *set, uint8_t buf_idx, | |
struct mcan_msg_info *msg); | |
/** | |
* \brief Detach one received message from the specified RX FIFO, and copy it to | |
* a buffer owned by the application. | |
* \param set Pointer to driver instance data. | |
* \param fifo Index of the RX FIFO to dequeue from. | |
* \param msg Address where the CAN message properties will be written. | |
* The msg->data and msg->data_len parameters shall be initialized prior to | |
* calling this function. Message contents will be copied to msg->data if | |
* msg->data is not null and if msg->data_len is large enough. | |
* \return: # of FIFO entries at the time the function was entered: | |
* 0 -> The FIFO was initially empty. | |
* 1 -> The FIFO had 1 entry upon entry, but is empty upon exit. | |
* 2 to 64 -> The FIFO had several entries upon entry, and still holds one | |
* or more entries upon exit. | |
*/ | |
uint8_t mcan_dequeue_received_msg(struct mcan_set *set, uint8_t fifo, | |
struct mcan_msg_info *msg); | |
#ifdef __cplusplus | |
} | |
#endif | |
#endif /* #ifndef _MCAN_H_ */ |