/**
* @file xmc_can.c
* @date 2019-06-26
*
* @cond
*********************************************************************************************************************
* XMClib v2.1.24 - XMC Peripheral Driver Library
*
* Copyright (c) 2015-2019, Infineon Technologies AG
* 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 following
* disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided with the distribution.
*
* Neither the name of the copyright holders nor the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 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.
*
* To improve the quality of the software, users are encouraged to share modifications, enhancements or bug fixes with
* Infineon Technologies AG dave@infineon.com).
*********************************************************************************************************************
*
* Change History
* --------------
*
* 2015-02-20:
* - Initial draft
*
* 2015-05-20:
* - New API added: XMC_CAN_MO_ReceiveData()
* - XMC_CAN_MO_Config() signature has changed
* - Minor fix in XMC_CAN_TXFIFO_ConfigMOSlaveObject().
*
* 2015-06-20:
* - Removed version macros and declaration of GetDriverVersion API
*
* 2015-09-01:
* - Removed fCANB clock support
*
* 2015-09-08:
* - Fixed bug in XMC_CAN_Init()
*
* 2016-06-07:
* - Changed XMC_CAN_AllocateMOtoNodeList to wait for ready status of list controller
*
* 2016-06-20:
* - Fixed bug in XMC_CAN_MO_Config()
*
* 2017-11-09:
* - Added XMC_CAN_InitEx() and XMC_CAN_NODE_NominalBitTimeConfigureEx()
* - Make XMC_CAN_GetBaudrateClockSource(), XMC_CAN_SetBaudrateClockSource() and XMC_CAN_GetBaudrateClockFrequency() available to all devices
* - Changed refactoring XMC_CAN_MO_Config() to configure MOCTR depending on transmit or receive message type
*
* 2018-06-21:
* - Fixed XMC_CAN_NODE_NominalBitTimeConfigureEx()
*
* 2018-11-12:
* - Fixed assertion at XMC_CAN_InitEx()
*
* 2019-05-07:
* - Fixed compilation warnings
*
* 2019-06-26:
* - Fixed XMC_CAN_NODE_NominalBitTimeConfigureEx() non returning, decrementing ntq before continuing with next iteration
* - Added XMC_CAN_GetClockFrequency()
* - Fixed XMC_CAN_InitEx() so that XMC_CAN_SetBaudrateClockSource() is invoked before XMC_CAN_GetBaudrateClockFrequency()
*
* @endcond
*
*/
/*******************************************************************************
* HEADER FILES
*******************************************************************************/
#include "xmc_can.h"
#if defined(CAN)
#include "xmc_scu.h"
__STATIC_INLINE uint32_t max(uint32_t a, uint32_t b)
{
return (a > b) ? a : b;
}
__STATIC_INLINE uint32_t min(uint32_t a, uint32_t b)
{
return (a < b) ? a : b;
}
/*******************************************************************************
* API IMPLEMENTATION
*******************************************************************************/
/* The max prescaler is the equal to max BRP setting (64) multiply by 8 (DIV8) */
#define XMC_CAN_NODE_MAX_PRESCALER 512
/* maximum TSEG1 is 16 and maximum TSEG2 is 8, plus one fix sync tq */
#define XMC_CAN_NODE_MAX_NTQ 25
#define XMC_CAN_NODE_MIN_NTQ 8
#define XMC_CAN_NODE_MIN_TSEG1 3
#define XMC_CAN_NODE_MIN_TSEG2 2
#define XMC_CAN_NODE_MAX_TSEG1 15
#define XMC_CAN_NODE_MAX_TSEG2 7
int32_t XMC_CAN_NODE_NominalBitTimeConfigureEx(XMC_CAN_NODE_t *const can_node,
const XMC_CAN_NODE_NOMINAL_BIT_TIME_CONFIG_t *const bit_time_config)
{
/* Check that the CAN frequency is a multiple of the required baudrate */
if ((bit_time_config->can_frequency % bit_time_config->baudrate) == 0)
{
uint32_t prescaler;
uint32_t div8 = 0;
/* Calculate the factor between can frequency and required baudrate, this is equal to (prescaler x ntq) */
uint32_t fcan_div = bit_time_config->can_frequency / bit_time_config->baudrate;
/* start with highest ntq, i.e as much as possible time quanta should be used to construct a bit time */
uint32_t ntq = XMC_CAN_NODE_MAX_NTQ;
uint32_t tseg1 = 0;
uint32_t tseg2 = 0;
while (ntq >= XMC_CAN_NODE_MIN_NTQ)
{
/* consider this ntq, only if fcan_div is multiple of ntq */
if ((fcan_div % ntq) == 0)
{
div8 = 0;
prescaler = fcan_div / ntq;
if ((prescaler > 0) && (prescaler <= XMC_CAN_NODE_MAX_PRESCALER))
{
if (prescaler >= 64)
{
/* consider prescaler >=64, if it is integer divisible by 8*/
if ((prescaler & 0x7U) != 0)
{
--ntq;
continue;
}
else
{
div8 = 1;
}
}
tseg1 = ((ntq - 1) * bit_time_config->sample_point) / 10000;
tseg2 = ntq - tseg1 - 1;
if ((XMC_CAN_NODE_MIN_TSEG1 <= tseg1) && (tseg1 <= XMC_CAN_NODE_MAX_TSEG1) &&
(XMC_CAN_NODE_MIN_TSEG2 <= tseg2) && (tseg2 < XMC_CAN_NODE_MAX_TSEG2) && (tseg2 >= bit_time_config->sjw))
{
break;
}
}
}
--ntq;
}
if (ntq >= XMC_CAN_NODE_MIN_NTQ)
{
XMC_CAN_NODE_EnableConfigurationChange(can_node);
/* Configure bit timing register */
can_node->NBTR = (((tseg2 - 1u) << CAN_NODE_NBTR_TSEG2_Pos) & (uint32_t)CAN_NODE_NBTR_TSEG2_Msk) |
(((bit_time_config->sjw - 1U) << CAN_NODE_NBTR_SJW_Pos) & (uint32_t)CAN_NODE_NBTR_SJW_Msk) |
(((tseg1 - 1U) << CAN_NODE_NBTR_TSEG1_Pos) & (uint32_t)CAN_NODE_NBTR_TSEG1_Msk) |
((((prescaler >> (3 * div8)) - 1U) << CAN_NODE_NBTR_BRP_Pos) & (uint32_t)CAN_NODE_NBTR_BRP_Msk) |
((div8 << CAN_NODE_NBTR_DIV8_Pos) & (uint32_t)CAN_NODE_NBTR_DIV8_Msk);
XMC_CAN_NODE_DisableConfigurationChange(can_node);
return XMC_CAN_STATUS_SUCCESS;
}
}
return XMC_CAN_STATUS_ERROR;
}
/* Baudrate Configuration */
void XMC_CAN_NODE_NominalBitTimeConfigure (XMC_CAN_NODE_t *const can_node,
const XMC_CAN_NODE_NOMINAL_BIT_TIME_CONFIG_t *const can_bit_time)
{
uint32_t temp_brp = 12U ;
uint32_t temp_tseg1 = 12U;
uint32_t best_brp = 0U;
uint32_t best_tseg1 = 1U;
uint32_t best_tseg2 = 0U;
uint32_t best_tbaud = 0U;
uint32_t best_error = 10000U;
XMC_ASSERT("XMC_CAN_NODE_NOMINAL_BIT_TIME_Configure: rate not supported", (can_bit_time->baudrate < 1000000U) ||
(can_bit_time->baudrate >= 100000U));
XMC_ASSERT("XMC_CAN_NODE_NOMINAL_BIT_TIME_Configure: fCAN not supported",
can_bit_time->can_frequency <= 120000000U);
XMC_ASSERT("XMC_CAN_NODE_NOMINAL_BIT_TIME_Configure: fCAN not supported",
can_bit_time->can_frequency > 5000000U);
XMC_ASSERT("XMC_CAN_NODE_NOMINAL_BIT_TIME_Configure: sample point not supported",
(can_bit_time->sample_point < 10000U) && ((can_bit_time->sample_point > 0U)));
/*
* Bit timing & sampling
* Tq = (BRP+1)/Fcan if DIV8 = 0
* Tq = 8*(BRP+1)/Fcan if DIV8 = 1
* TSync = 1.Tq
* TSeg1 = (TSEG1+1)*Tq >= 3Tq
* TSeg2 = (TSEG2+1)*Tq >= 2Tq
* Bit Time = TSync + TSeg1 + TSeg2 >= 8Tq
*
* Resynchronization:
*
* Tsjw = (SJW + 1)*Tq
* TSeg1 >= Tsjw + Tprop
* TSeg2 >= Tsjw
*/
/* search for best baudrate */
for (temp_brp = 1U; temp_brp <= 64U; temp_brp++)
{
uint32_t f_quanta = (uint32_t)((can_bit_time->can_frequency * 10U) / temp_brp);
uint32_t temp_tbaud = (uint32_t)(f_quanta / (can_bit_time->baudrate));
uint32_t temp_baudrate;
uint32_t error;
if((temp_tbaud % 10U) > 5U)
{
temp_tbaud = (uint32_t)(temp_tbaud / 10U);
temp_tbaud++;
}
else
{
temp_tbaud = (uint32_t)(temp_tbaud / 10U);
}
if(temp_tbaud > 0U)
{
temp_baudrate = (uint32_t) (f_quanta / (temp_tbaud * 10U));
}
else
{
temp_baudrate = f_quanta / 10U;
temp_tbaud = 1;
}
if(temp_baudrate >= can_bit_time->baudrate)
{
error = temp_baudrate - can_bit_time->baudrate;
}
else
{
error = can_bit_time->baudrate - temp_baudrate;
}
if ((temp_tbaud <= 20U) && (best_error > error))
{
best_brp = temp_brp;
best_tbaud = temp_tbaud;
best_error = (error);
if (error < 1000U)
{
break;
}
}
}
/* search for best sample point */
best_error = 10000U;
for (temp_tseg1 = 64U; temp_tseg1 >= 3U; temp_tseg1--)
{
uint32_t tempSamplePoint = ((temp_tseg1 + 1U) * 10000U) / best_tbaud;
uint32_t error;
if (tempSamplePoint >= can_bit_time->sample_point)
{
error = tempSamplePoint - can_bit_time->sample_point;
}
else
{
error = can_bit_time->sample_point - tempSamplePoint;
}
if (best_error > error)
{
best_tseg1 = temp_tseg1;
best_error = error;
}
if (tempSamplePoint < (can_bit_time->sample_point))
{
break;
}
}
best_tseg2 = best_tbaud - best_tseg1 - 1U;
XMC_CAN_NODE_EnableConfigurationChange(can_node);
/* Configure bit timing register */
can_node->NBTR = (((uint32_t)(best_tseg2 - 1u) << CAN_NODE_NBTR_TSEG2_Pos) & (uint32_t)CAN_NODE_NBTR_TSEG2_Msk) |
((((uint32_t)((uint32_t)(can_bit_time->sjw)-1U) << CAN_NODE_NBTR_SJW_Pos)) & (uint32_t)CAN_NODE_NBTR_SJW_Msk)|
(((uint32_t)(best_tseg1-1U) << CAN_NODE_NBTR_TSEG1_Pos) & (uint32_t)CAN_NODE_NBTR_TSEG1_Msk)|
(((uint32_t)(best_brp - 1U) << CAN_NODE_NBTR_BRP_Pos) & (uint32_t)CAN_NODE_NBTR_BRP_Msk)|
(((uint32_t)0U << CAN_NODE_NBTR_DIV8_Pos) & (uint32_t)CAN_NODE_NBTR_DIV8_Msk);
XMC_CAN_NODE_DisableConfigurationChange(can_node);
}
/* Function to allocate message object from free list to node list */
void XMC_CAN_AllocateMOtoNodeList(XMC_CAN_t *const obj, const uint8_t node_num, const uint8_t mo_num)
{
/* wait while panel operation is in progress. */
while (XMC_CAN_IsPanelControlReady(obj) == false)
{
/*Do nothing*/
};
/* Panel Command for allocation of MO to node list */
XMC_CAN_PanelControl(obj, XMC_CAN_PANCMD_STATIC_ALLOCATE,mo_num,(node_num + 1U));
}
/* Disable XMC_CAN Peripheral */
void XMC_CAN_Disable(XMC_CAN_t *const obj)
{
/* Disable CAN Module */
obj->CLC = CAN_CLC_DISR_Msk;
#if defined(PERIPHERAL_RESET_SUPPORTED)
XMC_SCU_RESET_AssertPeripheralReset(XMC_SCU_PERIPHERAL_RESET_MCAN);
#endif
#if defined(CLOCK_GATING_SUPPORTED)
XMC_SCU_CLOCK_GatePeripheralClock(XMC_SCU_PERIPHERAL_CLOCK_MCAN);
#endif
}
/* Enable XMC_CAN Peripheral */
void XMC_CAN_Enable(XMC_CAN_t *const obj)
{
#if defined(CLOCK_GATING_SUPPORTED)
XMC_SCU_CLOCK_UngatePeripheralClock(XMC_SCU_PERIPHERAL_CLOCK_MCAN);
#endif
#if defined(PERIPHERAL_RESET_SUPPORTED)
XMC_SCU_RESET_DeassertPeripheralReset(XMC_SCU_PERIPHERAL_RESET_MCAN);
#endif
/* Enable CAN Module */
obj->CLC &= ~(uint32_t)CAN_CLC_DISR_Msk;
while (obj->CLC & CAN_CLC_DISS_Msk)
{
/*Do nothing*/
};
}
#if defined(MULTICAN_PLUS)
void XMC_CAN_Init(XMC_CAN_t *const obj, XMC_CAN_CANCLKSRC_t clksrc, uint32_t can_frequency)
{
uint32_t step_n, step_f;
bool normal_divider;
uint32_t freq_n, freq_f;
uint32_t step;
uint32_t can_frequency_khz;
uint32_t peripheral_frequency_khz;
XMC_CAN_DM_t can_divider_mode;
uint32_t peripheral_frequency;
/*Enabling the module*/
XMC_CAN_Enable(obj);
XMC_CAN_SetBaudrateClockSource(obj, clksrc);
peripheral_frequency = XMC_CAN_GetBaudrateClockFrequency(obj);
XMC_ASSERT("XMC_CAN_Init: frequency not supported", can_frequency <= peripheral_frequency);
/* Normal divider mode */
step_n = (uint32_t)min(max(0U, (1024U - (peripheral_frequency / can_frequency))), 1023U);
freq_n = (uint32_t) (peripheral_frequency / (1024U - step_n));
/* Fractional divider mode */
can_frequency_khz = (uint32_t) (can_frequency >> 6);
peripheral_frequency_khz = (uint32_t)(peripheral_frequency >> 6);
step_f = (uint32_t)(min( (((1024U * can_frequency_khz) / peripheral_frequency_khz) ), 1023U ));
freq_f = (uint32_t)((peripheral_frequency_khz * step_f) / 1024U);
freq_f = freq_f << 6;
normal_divider = (uint32_t)(can_frequency - freq_n) <= (can_frequency - freq_f);
step = (normal_divider != 0U) ? step_n : step_f;
can_divider_mode = (normal_divider != 0U) ? XMC_CAN_DM_NORMAL : XMC_CAN_DM_FRACTIONAL;
obj->FDR &= (uint32_t) ~(CAN_FDR_DM_Msk | CAN_FDR_STEP_Msk);
obj->FDR |= ((uint32_t)can_divider_mode << CAN_FDR_DM_Pos) | ((uint32_t)step << CAN_FDR_STEP_Pos);
}
#else
/* Initialization of XMC_CAN GLOBAL Object */
void XMC_CAN_Init(XMC_CAN_t *const obj, uint32_t can_frequency)
{
uint32_t step_n, step_f;
bool normal_divider;
uint32_t freq_n, freq_f;
uint32_t step;
uint32_t can_frequency_khz;
uint32_t peripheral_frequency_khz;
XMC_CAN_DM_t can_divider_mode;
uint32_t peripheral_frequency = (XMC_SCU_CLOCK_GetPeripheralClockFrequency());
XMC_ASSERT("XMC_CAN_Init: frequency not supported", can_frequency <= peripheral_frequency);
/*Enabling the module*/
XMC_CAN_Enable(obj);
/* Normal divider mode */
step_n = (uint32_t)min(max(0U, (1024U - (peripheral_frequency / can_frequency))), 1023U);
freq_n = (uint32_t) (peripheral_frequency / (1024U - step_n));
/* Fractional divider mode */
can_frequency_khz = (uint32_t) (can_frequency >> 6);
peripheral_frequency_khz = (uint32_t)(peripheral_frequency >> 6);
step_f = (uint32_t)(min( (((1024U * can_frequency_khz) / peripheral_frequency_khz) ), 1023U ));
freq_f = (uint32_t)((peripheral_frequency_khz * step_f) / 1024U);
freq_f = freq_f << 6;
normal_divider = (uint32_t)(can_frequency - freq_n) <= (can_frequency - freq_f);
step = (normal_divider != 0U) ? step_n : step_f;
can_divider_mode = (normal_divider != 0U) ? XMC_CAN_DM_NORMAL : XMC_CAN_DM_FRACTIONAL;
obj->FDR &= (uint32_t) ~(CAN_FDR_DM_Msk | CAN_FDR_STEP_Msk);
obj->FDR |= ((uint32_t)can_divider_mode << CAN_FDR_DM_Pos) | ((uint32_t)step << CAN_FDR_STEP_Pos);
}
#endif
void XMC_CAN_SetBaudrateClockSource(XMC_CAN_t *const obj,const XMC_CAN_CANCLKSRC_t source)
{
#if defined(MULTICAN_PLUS)
obj->MCR = (obj->MCR & ~CAN_MCR_CLKSEL_Msk) | source ;
#else
XMC_UNUSED_ARG(obj);
XMC_UNUSED_ARG(source);
#endif
}
XMC_CAN_CANCLKSRC_t XMC_CAN_GetBaudrateClockSource(XMC_CAN_t *const obj)
{
#if defined(MULTICAN_PLUS)
return ((XMC_CAN_CANCLKSRC_t)((obj->MCR & CAN_MCR_CLKSEL_Msk) >> CAN_MCR_CLKSEL_Pos));
#elif (UC_FAMILY == XMC4)
XMC_UNUSED_ARG(obj);
return XMC_CAN_CANCLKSRC_FPERI;
#endif
}
uint32_t XMC_CAN_GetBaudrateClockFrequency(XMC_CAN_t *const obj)
{
uint32_t frequency;
#if defined(MULTICAN_PLUS)
switch(XMC_CAN_GetBaudrateClockSource(obj))
{
#if UC_FAMILY == XMC4
case XMC_CAN_CANCLKSRC_FPERI:
frequency = XMC_SCU_CLOCK_GetPeripheralClockFrequency();
break;
#else
case XMC_CAN_CANCLKSRC_MCLK:
frequency = XMC_SCU_CLOCK_GetPeripheralClockFrequency();
break;
#endif
case XMC_CAN_CANCLKSRC_FOHP:
frequency = OSCHP_GetFrequency();
break;
default:
frequency = 0;
break;
}
#else
XMC_UNUSED_ARG(obj);
frequency = XMC_SCU_CLOCK_GetPeripheralClockFrequency();
#endif
return frequency;
}
uint32_t XMC_CAN_InitEx(XMC_CAN_t *const obj, XMC_CAN_CANCLKSRC_t clksrc, uint32_t can_frequency)
{
uint32_t step_n;
uint32_t freq_n;
uint32_t peripheral_frequency;
/*Enabling the module*/
XMC_CAN_Enable(obj);
XMC_CAN_SetBaudrateClockSource(obj, clksrc);
peripheral_frequency = XMC_CAN_GetBaudrateClockFrequency(obj);
XMC_ASSERT("XMC_CAN_Init: frequency not supported", can_frequency <= peripheral_frequency);
/* Normal divider mode */
step_n = (uint32_t)min(max(0U, (1024U - (peripheral_frequency / can_frequency))), 1023U);
freq_n = (uint32_t)(peripheral_frequency / (1024U - step_n));
obj->FDR &= (uint32_t) ~(CAN_FDR_DM_Msk | CAN_FDR_STEP_Msk);
obj->FDR |= ((uint32_t)XMC_CAN_DM_NORMAL << CAN_FDR_DM_Pos) | ((uint32_t)step_n << CAN_FDR_STEP_Pos);
return freq_n;
}
uint32_t XMC_CAN_GetClockFrequency(XMC_CAN_t *const obj)
{
uint32_t step_n = (obj->FDR & CAN_FDR_STEP_Msk) >> CAN_FDR_STEP_Pos;
return (XMC_CAN_GetBaudrateClockFrequency(obj) * (1024U - step_n));
}
/* Sets the Identifier of the MO */
void XMC_CAN_MO_SetIdentifier(XMC_CAN_MO_t *const can_mo, const uint32_t can_identifier)
{
if ((can_mo->can_mo_ptr->MOAR & CAN_MO_MOAR_IDE_Msk) != (uint32_t)CAN_MO_MOAR_IDE_Msk)
{
can_mo->can_mo_ptr->MOAR = ((can_mo->can_mo_ptr->MOAR) & ~(uint32_t)(CAN_MO_MOAR_ID_Msk)) |
((can_identifier << XMC_CAN_MO_MOAR_STDID_Pos) & (uint32_t)CAN_MO_MOAR_ID_Msk);
}
else
{
can_mo->can_mo_ptr->MOAR = ((can_mo->can_mo_ptr->MOAR) & ~(uint32_t)(CAN_MO_MOAR_ID_Msk)) |
(can_identifier & (uint32_t)CAN_MO_MOAR_ID_Msk);
}
can_mo->can_identifier = can_identifier;
}
/* Gets the Identifier of the MO */
uint32_t XMC_CAN_MO_GetIdentifier(const XMC_CAN_MO_t *const can_mo)
{
uint32_t identifier;
if ((can_mo->can_mo_ptr->MOAR & CAN_MO_MOAR_IDE_Msk) != (uint32_t)CAN_MO_MOAR_IDE_Msk)
{
identifier = ((can_mo->can_mo_ptr->MOAR) & (uint32_t)(CAN_MO_MOAR_ID_Msk)) >> XMC_CAN_MO_MOAR_STDID_Pos;
}
else
{
identifier = ((can_mo->can_mo_ptr->MOAR) & (uint32_t)(CAN_MO_MOAR_ID_Msk));
}
return identifier;
}
/* Gets the acceptance mask for the CAN MO. */
uint32_t XMC_CAN_MO_GetAcceptanceMask(const XMC_CAN_MO_t *const can_mo)
{
uint32_t identifier_mask;
if (((can_mo->can_mo_ptr->MOAMR & CAN_MO_MOAMR_MIDE_Msk) != (uint32_t)CAN_MO_MOAMR_MIDE_Msk)
&& ((can_mo->can_mo_ptr->MOAR & CAN_MO_MOAR_IDE_Msk) != (uint32_t)CAN_MO_MOAR_IDE_Msk))
{
identifier_mask = ((can_mo->can_mo_ptr->MOAMR) & (uint32_t)(CAN_MO_MOAMR_AM_Msk)) >> XMC_CAN_MO_MOAR_STDID_Pos;
}
else
{
identifier_mask = ((can_mo->can_mo_ptr->MOAMR) & (uint32_t)(CAN_MO_MOAMR_AM_Msk));
}
return identifier_mask;
}
/* Gets the acceptance mask of the MO */
void XMC_CAN_MO_SetAcceptanceMask(XMC_CAN_MO_t *const can_mo,const uint32_t can_id_mask)
{
if (((can_mo->can_mo_ptr->MOAMR & CAN_MO_MOAMR_MIDE_Msk) != (uint32_t)CAN_MO_MOAMR_MIDE_Msk)
&& ((can_mo->can_mo_ptr->MOAR & CAN_MO_MOAR_IDE_Msk) != (uint32_t)CAN_MO_MOAR_IDE_Msk))
{
can_mo->can_mo_ptr->MOAMR = ((can_mo->can_mo_ptr->MOAMR) & ~(uint32_t)(CAN_MO_MOAMR_AM_Msk)) |
(can_id_mask << XMC_CAN_MO_MOAR_STDID_Pos);
}
else
{
can_mo->can_mo_ptr->MOAMR = ((can_mo->can_mo_ptr->MOAMR) & ~(uint32_t)(CAN_MO_MOAMR_AM_Msk)) |
(can_id_mask & (uint32_t)CAN_MO_MOAMR_AM_Msk);
}
can_mo->can_id_mask = can_id_mask;
}
/* Initialization of XMC_CAN MO Object */
void XMC_CAN_MO_Config(const XMC_CAN_MO_t *const can_mo)
{
uint32_t reg;
/* Configure MPN */
uint32_t num = ((uint32_t)(can_mo->can_mo_ptr) - CAN_BASE - 0x1000U)/0x0020U;
uint32_t set = (((uint32_t)(num/32) << (CAN_MO_MOIPR_MPN_Pos + 5U)) | ((uint32_t)(num%32) << CAN_MO_MOIPR_MPN_Pos));
can_mo->can_mo_ptr->MOIPR &= ~(CAN_MO_MOIPR_MPN_Msk);
can_mo->can_mo_ptr->MOIPR |= set;
if (((can_mo->can_id_mode != (uint32_t) XMC_CAN_FRAME_TYPE_STANDARD_11BITS) &&
(can_mo->can_id_mode != (uint32_t) XMC_CAN_FRAME_TYPE_EXTENDED_29BITS)) ||
((can_mo->can_mo_type != XMC_CAN_MO_TYPE_RECMSGOBJ) &&
(can_mo->can_mo_type != XMC_CAN_MO_TYPE_TRANSMSGOBJ)))
{
; /*Do nothing*/
}
else
{
/* Disable Message object */
can_mo->can_mo_ptr->MOCTR = CAN_MO_MOCTR_RESMSGVAL_Msk;
if (can_mo->can_id_mode == (uint32_t)XMC_CAN_FRAME_TYPE_STANDARD_11BITS)
{
reg = can_mo->mo_ar;
reg &= (uint32_t) ~(CAN_MO_MOAR_ID_Msk);
reg |= (can_mo->can_identifier << XMC_CAN_MO_MOAR_STDID_Pos);
can_mo->can_mo_ptr->MOAR = reg;
reg = can_mo->mo_amr;
reg &= (uint32_t) ~(CAN_MO_MOAMR_AM_Msk);
reg |= (can_mo->can_id_mask << XMC_CAN_MO_MOAR_STDID_Pos);
can_mo->can_mo_ptr->MOAMR = reg;
}
else
{
can_mo->can_mo_ptr->MOAR = can_mo->mo_ar;
can_mo->can_mo_ptr->MOAMR = can_mo->mo_amr;
}
/* Check whether message object is transmit message object */
if (can_mo->can_mo_type == XMC_CAN_MO_TYPE_TRANSMSGOBJ)
{
/* Set MO as Transmit message object */
XMC_CAN_MO_UpdateData(can_mo);
can_mo->can_mo_ptr->MOCTR = CAN_MO_MOCTR_SETDIR_Msk;
/* Reset RTSEL and Set MSGVAL, TXEN0 and TXEN1 bits */
can_mo->can_mo_ptr->MOCTR = (CAN_MO_MOCTR_SETTXEN0_Msk | CAN_MO_MOCTR_SETTXEN1_Msk | CAN_MO_MOCTR_SETMSGVAL_Msk |
CAN_MO_MOCTR_RESRXEN_Msk | CAN_MO_MOCTR_RESRTSEL_Msk);
}
else
{
/* Set MO as Receive message object and set RXEN bit */
can_mo->can_mo_ptr->MOCTR = CAN_MO_MOCTR_RESDIR_Msk;
/* Reset RTSEL, TXEN1 and TXEN2 and Set MSGVAL and RXEN bits */
can_mo->can_mo_ptr->MOCTR = (CAN_MO_MOCTR_RESTXEN0_Msk | CAN_MO_MOCTR_RESTXEN1_Msk | CAN_MO_MOCTR_SETMSGVAL_Msk |
CAN_MO_MOCTR_SETRXEN_Msk | CAN_MO_MOCTR_RESRTSEL_Msk);
}
}
}
/* Update of XMC_CAN Object */
XMC_CAN_STATUS_t XMC_CAN_MO_UpdateData(const XMC_CAN_MO_t *const can_mo)
{
XMC_CAN_STATUS_t error = XMC_CAN_STATUS_MO_NOT_ACCEPTABLE;
/* Check whether message object is transmit message object */
if (can_mo->can_mo_type == XMC_CAN_MO_TYPE_TRANSMSGOBJ)
{
can_mo->can_mo_ptr->MOCTR = CAN_MO_MOCTR_RESMSGVAL_Msk;
/* Configure data length */
can_mo->can_mo_ptr->MOFCR = ((can_mo->can_mo_ptr->MOFCR) & ~(uint32_t)(CAN_MO_MOFCR_DLC_Msk)) |
(((uint32_t) can_mo->can_data_length << CAN_MO_MOFCR_DLC_Pos) & (uint32_t)CAN_MO_MOFCR_DLC_Msk);
/* Configure Data registers*/
can_mo->can_mo_ptr->MODATAL = can_mo->can_data[0];
can_mo->can_mo_ptr->MODATAH = can_mo->can_data[1];
/* Reset RTSEL and Set MSGVAL ,TXEN0 and TXEN1 bits */
can_mo->can_mo_ptr->MOCTR = (CAN_MO_MOCTR_SETNEWDAT_Msk| CAN_MO_MOCTR_SETMSGVAL_Msk |CAN_MO_MOCTR_RESRTSEL_Msk);
error = XMC_CAN_STATUS_SUCCESS;
}
else
{
error = XMC_CAN_STATUS_MO_NOT_ACCEPTABLE;
}
return error;
}
/* This function is will put a transmit request to transmit message object */
XMC_CAN_STATUS_t XMC_CAN_MO_Transmit(const XMC_CAN_MO_t *const can_mo)
{
XMC_CAN_STATUS_t error = XMC_CAN_STATUS_ERROR;
uint32_t mo_type = (uint32_t)(((can_mo->can_mo_ptr->MOSTAT) & CAN_MO_MOSTAT_MSGVAL_Msk) >> CAN_MO_MOSTAT_MSGVAL_Pos);
uint32_t mo_transmission_ongoing = (uint32_t) ((can_mo->can_mo_ptr->MOSTAT) & CAN_MO_MOSTAT_TXRQ_Msk) >> CAN_MO_MOSTAT_TXRQ_Pos;
/* check if message is disabled */
if (mo_type == 0U)
{
error = XMC_CAN_STATUS_MO_DISABLED;
}
/* check if transmission is ongoing on message object */
else if (mo_transmission_ongoing == 1U)
{
error = XMC_CAN_STATUS_BUSY;
}
else
{
/* set TXRQ bit */
can_mo->can_mo_ptr-> MOCTR = CAN_MO_MOCTR_SETTXRQ_Msk | CAN_MO_MOCTR_SETTXEN0_Msk | CAN_MO_MOCTR_SETTXEN1_Msk;
error = XMC_CAN_STATUS_SUCCESS;
}
return error;
}
/* This function is will read the message object data bytes */
XMC_CAN_STATUS_t XMC_CAN_MO_ReceiveData (XMC_CAN_MO_t *can_mo)
{
XMC_CAN_STATUS_t error = XMC_CAN_STATUS_ERROR;
uint8_t rx_pnd = 0U;
uint8_t new_data = 0U;
uint32_t mo_type = (uint32_t)((can_mo->can_mo_ptr->MOSTAT) & CAN_MO_MOSTAT_DIR_Msk) >> CAN_MO_MOSTAT_DIR_Pos;
uint32_t mo_recepcion_ongoing = (uint32_t)((can_mo->can_mo_ptr->MOSTAT) & CAN_MO_MOSTAT_RXUPD_Msk) >> CAN_MO_MOSTAT_RXUPD_Pos;
/* check if message object is a receive message object */
if (mo_type != (uint32_t)XMC_CAN_MO_TYPE_RECMSGOBJ)
{
error = XMC_CAN_STATUS_MO_NOT_ACCEPTABLE;
}
/* check if reception is ongoing on message object */
else if (mo_recepcion_ongoing == 1U)
{
error = XMC_CAN_STATUS_BUSY;
}
else
{
/* read message parameters */
do
{
can_mo->can_data[0] = can_mo->can_mo_ptr->MODATAL;
can_mo->can_data[1] = can_mo->can_mo_ptr->MODATAH;
rx_pnd = (uint8_t)((uint32_t)((can_mo->can_mo_ptr->MOSTAT) & CAN_MO_MOSTAT_RXUPD_Msk) >> CAN_MO_MOSTAT_RXUPD_Pos);
new_data = (uint8_t)((uint32_t)((can_mo->can_mo_ptr->MOSTAT) & CAN_MO_MOSTAT_NEWDAT_Msk) >> CAN_MO_MOSTAT_NEWDAT_Pos);
} while ((rx_pnd != 0U) && (new_data != 0U));
error = XMC_CAN_STATUS_SUCCESS;
}
return error;
}
/* This function is will read the message object data bytes */
XMC_CAN_STATUS_t XMC_CAN_MO_Receive (XMC_CAN_MO_t *can_mo)
{
XMC_CAN_STATUS_t error = XMC_CAN_STATUS_ERROR;
uint8_t rx_pnd = 0U;
uint8_t new_data = 0U;
uint32_t mo_type = (uint32_t)((can_mo->can_mo_ptr->MOSTAT) & CAN_MO_MOSTAT_DIR_Msk) >> CAN_MO_MOSTAT_DIR_Pos;
uint32_t mo_recepcion_ongoing = (uint32_t)((can_mo->can_mo_ptr->MOSTAT) & CAN_MO_MOSTAT_RXUPD_Msk) >> CAN_MO_MOSTAT_RXUPD_Pos;
/* check if message object is a receive message object */
if (mo_type != (uint32_t)XMC_CAN_MO_TYPE_RECMSGOBJ)
{
error = XMC_CAN_STATUS_MO_NOT_ACCEPTABLE;
}
/* check if reception is ongoing on message object */
else if (mo_recepcion_ongoing == 1U)
{
error = XMC_CAN_STATUS_BUSY;
}
else
{
/* read message parameters */
do
{
can_mo->can_mo_ptr->MOCTR = CAN_MO_MOCTR_RESNEWDAT_Msk;
if ((((can_mo->can_mo_ptr->MOAR) & CAN_MO_MOAR_IDE_Msk) >> CAN_MO_MOAR_IDE_Pos) == 0U)
{
can_mo->can_id_mode = (uint32_t)XMC_CAN_FRAME_TYPE_STANDARD_11BITS;
can_mo->can_identifier = (can_mo->can_mo_ptr->MOAR & XMC_CAN_MO_MOAR_STDID_Msk) >> XMC_CAN_MO_MOAR_STDID_Pos;
can_mo->can_ide_mask = (uint32_t)(can_mo->can_mo_ptr->MOAMR & CAN_MO_MOAMR_MIDE_Msk) >> CAN_MO_MOAMR_MIDE_Pos;
if(can_mo->can_ide_mask == 1U)
{
can_mo->can_id_mask = (uint32_t)(can_mo->can_mo_ptr->MOAMR & XMC_CAN_MO_MOAR_STDID_Msk) >> XMC_CAN_MO_MOAR_STDID_Pos;
}
else
{
can_mo->can_id_mask = (uint32_t)(can_mo->can_mo_ptr->MOAMR & CAN_MO_MOAMR_AM_Msk);
}
}
else
{
can_mo->can_id_mode = (uint32_t)XMC_CAN_FRAME_TYPE_EXTENDED_29BITS;
can_mo->can_identifier = (can_mo->can_mo_ptr->MOAR & CAN_MO_MOAR_ID_Msk);
can_mo->can_id_mask = (uint32_t)(can_mo->can_mo_ptr->MOAMR & CAN_MO_MOAMR_AM_Msk);
can_mo->can_ide_mask = (uint32_t)(can_mo->can_mo_ptr->MOAMR & CAN_MO_MOAMR_MIDE_Msk) >> CAN_MO_MOAMR_MIDE_Pos;
}
can_mo->can_data_length = (uint8_t)((uint32_t)((can_mo->can_mo_ptr->MOFCR) & CAN_MO_MOFCR_DLC_Msk) >> CAN_MO_MOFCR_DLC_Pos);
can_mo->can_data[0] = can_mo->can_mo_ptr->MODATAL;
can_mo->can_data[1] = can_mo->can_mo_ptr->MODATAH;
rx_pnd = (uint8_t)((uint32_t)((can_mo->can_mo_ptr->MOSTAT) & CAN_MO_MOSTAT_RXUPD_Msk) >> CAN_MO_MOSTAT_RXUPD_Pos);
new_data = (uint8_t)((uint32_t)((can_mo->can_mo_ptr->MOSTAT) & CAN_MO_MOSTAT_NEWDAT_Msk) >> CAN_MO_MOSTAT_NEWDAT_Pos);
} while ((rx_pnd != 0U) && (new_data != 0U));
can_mo->can_mo_type = XMC_CAN_MO_TYPE_RECMSGOBJ;
error = XMC_CAN_STATUS_SUCCESS;
}
return error;
}
/* Function to enable node event */
void XMC_CAN_NODE_EnableEvent(XMC_CAN_NODE_t *const can_node, const XMC_CAN_NODE_EVENT_t event)
{
if(event != XMC_CAN_NODE_EVENT_CFCIE)
{
can_node->NCR |= (uint32_t)event;
}
else
{
can_node->NFCR |= (uint32_t)event;
}
}
/* Function to disable node event */
void XMC_CAN_NODE_DisableEvent(XMC_CAN_NODE_t *const can_node, const XMC_CAN_NODE_EVENT_t event)
{
if(event != XMC_CAN_NODE_EVENT_CFCIE)
{
can_node->NCR &= ~(uint32_t)event;
}
else
{
can_node->NFCR &= ~(uint32_t)event;
}
}
/* Function to transmit MO from the FIFO */
XMC_CAN_STATUS_t XMC_CAN_TXFIFO_Transmit(const XMC_CAN_MO_t *const can_mo)
{
XMC_CAN_STATUS_t error = XMC_CAN_STATUS_ERROR;
uint32_t mo_type = ((uint32_t)((can_mo->can_mo_ptr->MOSTAT) & CAN_MO_MOSTAT_MSGVAL_Msk) >> CAN_MO_MOSTAT_MSGVAL_Pos);
uint32_t mo_transmission_ongoing = (uint32_t)((can_mo->can_mo_ptr->MOSTAT) & CAN_MO_MOSTAT_TXRQ_Msk) >> CAN_MO_MOSTAT_TXRQ_Pos;
uint32_t mo_cur = (uint32_t)(can_mo->can_mo_ptr-> MOFGPR & CAN_MO_MOFGPR_CUR_Msk) >> CAN_MO_MOFGPR_CUR_Pos;
CAN_MO_TypeDef* mo = (CAN_MO_TypeDef *)(CAN_BASE + 0x1000UL + (mo_cur * 0x0020UL));
/* check if message is disabled */
if (mo_type == 0U)
{
error = XMC_CAN_STATUS_MO_DISABLED;
}
/* check if transmission is ongoing on message object */
else if (mo_transmission_ongoing == 1U)
{
error = XMC_CAN_STATUS_BUSY;
}
else
{
mo->MOCTR = CAN_MO_MOCTR_SETTXRQ_Msk | CAN_MO_MOCTR_SETTXEN0_Msk | CAN_MO_MOCTR_SETTXEN1_Msk;
error = XMC_CAN_STATUS_SUCCESS;
}
return error;
}
/* Function to initialize the transmit FIFO MO base object */
void XMC_CAN_TXFIFO_ConfigMOBaseObject(const XMC_CAN_MO_t *const can_mo,const XMC_CAN_FIFO_CONFIG_t can_fifo)
{
can_mo->can_mo_ptr->MOFCR = ((can_mo->can_mo_ptr->MOFCR ) & ~(uint32_t)(CAN_MO_MOFCR_MMC_Msk)) |
(((uint32_t)0x2U << CAN_MO_MOFCR_MMC_Pos) & (uint32_t)CAN_MO_MOFCR_MMC_Msk);
can_mo->can_mo_ptr->MOFGPR = ((can_mo->can_mo_ptr->MOFGPR ) & ~(uint32_t)(CAN_MO_MOFGPR_BOT_Msk |
CAN_MO_MOFGPR_TOP_Msk |
CAN_MO_MOFGPR_CUR_Msk)) |
(((uint32_t)can_fifo.fifo_bottom << CAN_MO_MOFGPR_BOT_Pos) & (uint32_t)CAN_MO_MOFGPR_BOT_Msk) |
(((uint32_t)can_fifo.fifo_base << CAN_MO_MOFGPR_CUR_Pos) & (uint32_t) CAN_MO_MOFGPR_CUR_Msk) |
(((uint32_t)can_fifo.fifo_top << CAN_MO_MOFGPR_TOP_Pos) & (uint32_t) CAN_MO_MOFGPR_TOP_Msk);
}
/* Function to Initialize the receive FIFO MO base object */
void XMC_CAN_RXFIFO_ConfigMOBaseObject(const XMC_CAN_MO_t *const can_mo,const XMC_CAN_FIFO_CONFIG_t can_fifo)
{
can_mo->can_mo_ptr->MOFCR = ((can_mo->can_mo_ptr->MOFCR ) & ~(uint32_t)(CAN_MO_MOFCR_MMC_Msk)) |
(((uint32_t)0x1U << CAN_MO_MOFCR_MMC_Pos) & (uint32_t)CAN_MO_MOFCR_MMC_Msk);
can_mo->can_mo_ptr->MOFGPR = ((can_mo->can_mo_ptr->MOFGPR ) & ~( uint32_t)(CAN_MO_MOFGPR_BOT_Msk |
CAN_MO_MOFGPR_TOP_Msk |
CAN_MO_MOFGPR_CUR_Msk)) |
(((uint32_t)can_fifo.fifo_bottom << CAN_MO_MOFGPR_BOT_Pos) & (uint32_t)CAN_MO_MOFGPR_BOT_Msk) |
(((uint32_t)can_fifo.fifo_base << CAN_MO_MOFGPR_CUR_Pos) & (uint32_t)CAN_MO_MOFGPR_CUR_Msk) |
(((uint32_t)can_fifo.fifo_top << CAN_MO_MOFGPR_TOP_Pos) & (uint32_t)CAN_MO_MOFGPR_TOP_Msk);
}
/* Function to Initialize the FIFO MO slave object */
void XMC_CAN_TXFIFO_ConfigMOSlaveObject(const XMC_CAN_MO_t *const can_mo,const XMC_CAN_FIFO_CONFIG_t can_fifo)
{
can_mo->can_mo_ptr->MOFCR = ((can_mo->can_mo_ptr->MOFCR ) & ~(uint32_t)(CAN_MO_MOFCR_MMC_Msk)) |
(((uint32_t)0x3U << CAN_MO_MOFCR_MMC_Pos) & (uint32_t)CAN_MO_MOFCR_MMC_Msk);
can_mo->can_mo_ptr->MOFGPR = ((can_mo->can_mo_ptr->MOFGPR ) & ~(uint32_t)(CAN_MO_MOFGPR_CUR_Msk)) |
(((uint32_t)can_fifo.fifo_base << CAN_MO_MOFGPR_CUR_Pos) & (uint32_t)CAN_MO_MOFGPR_CUR_Msk);
can_mo->can_mo_ptr->MOCTR = CAN_MO_MOCTR_SETTXEN0_Msk|
CAN_MO_MOCTR_RESTXEN1_Msk;
}
/* Function to Initialize the Gateway Source Object */
void XMC_CAN_GATEWAY_InitSourceObject(const XMC_CAN_MO_t *const can_mo,const XMC_CAN_GATEWAY_CONFIG_t can_gateway)
{
can_mo->can_mo_ptr->MOFCR = (((uint32_t)0x4U << CAN_MO_MOFCR_MMC_Pos) & (uint32_t)CAN_MO_MOFCR_MMC_Msk) |
((((uint32_t)can_gateway.gateway_data_frame_send) << CAN_MO_MOFCR_GDFS_Pos) & (uint32_t)CAN_MO_MOFCR_GDFS_Msk) |
((((uint32_t)can_gateway.gateway_data_length_code_copy) << CAN_MO_MOFCR_DLCC_Pos) & (uint32_t)CAN_MO_MOFCR_DLCC_Msk) |
((((uint32_t)can_gateway.gateway_identifier_copy) << CAN_MO_MOFCR_IDC_Pos) & (uint32_t)CAN_MO_MOFCR_IDC_Msk) |
((((uint32_t)can_gateway.gateway_data_copy) << CAN_MO_MOFCR_DATC_Pos) & (uint32_t)CAN_MO_MOFCR_DATC_Msk) ;
can_mo->can_mo_ptr->MOFGPR = (uint32_t)((((uint32_t)can_gateway.gateway_bottom << CAN_MO_MOFGPR_BOT_Pos) & (uint32_t)CAN_MO_MOFGPR_BOT_Msk) |
(((uint32_t)can_gateway.gateway_base << CAN_MO_MOFGPR_CUR_Pos) & (uint32_t)CAN_MO_MOFGPR_CUR_Msk) |
(((uint32_t)can_gateway.gateway_top << CAN_MO_MOFGPR_TOP_Pos) & (uint32_t)CAN_MO_MOFGPR_TOP_Msk));
}
#endif /* XMC_CAN_H */