blob: 23dc63f0a04d52de94dbdd127ad2e8831e785780 [file] [log] [blame]
/* ----------------------------------------------------------------------------
* 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_ */